1 |
|
2 |
|
3 |
|
4 |
|
5 | (function () {
|
6 | 'use strict';
|
7 |
|
8 | var typeOf$1 = function (x) {
|
9 | if (x === null) {
|
10 | return 'null';
|
11 | }
|
12 | if (x === undefined) {
|
13 | return 'undefined';
|
14 | }
|
15 | var t = typeof x;
|
16 | if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
|
17 | return 'array';
|
18 | }
|
19 | if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
|
20 | return 'string';
|
21 | }
|
22 | return t;
|
23 | };
|
24 | var isEquatableType = function (x) {
|
25 | return [
|
26 | 'undefined',
|
27 | 'boolean',
|
28 | 'number',
|
29 | 'string',
|
30 | 'function',
|
31 | 'xml',
|
32 | 'null'
|
33 | ].indexOf(x) !== -1;
|
34 | };
|
35 |
|
36 | var sort$1 = function (xs, compareFn) {
|
37 | var clone = Array.prototype.slice.call(xs);
|
38 | return clone.sort(compareFn);
|
39 | };
|
40 |
|
41 | var contramap = function (eqa, f) {
|
42 | return eq$2(function (x, y) {
|
43 | return eqa.eq(f(x), f(y));
|
44 | });
|
45 | };
|
46 | var eq$2 = function (f) {
|
47 | return { eq: f };
|
48 | };
|
49 | var tripleEq = eq$2(function (x, y) {
|
50 | return x === y;
|
51 | });
|
52 | var eqString = tripleEq;
|
53 | var eqArray = function (eqa) {
|
54 | return eq$2(function (x, y) {
|
55 | if (x.length !== y.length) {
|
56 | return false;
|
57 | }
|
58 | var len = x.length;
|
59 | for (var i = 0; i < len; i++) {
|
60 | if (!eqa.eq(x[i], y[i])) {
|
61 | return false;
|
62 | }
|
63 | }
|
64 | return true;
|
65 | });
|
66 | };
|
67 | var eqSortedArray = function (eqa, compareFn) {
|
68 | return contramap(eqArray(eqa), function (xs) {
|
69 | return sort$1(xs, compareFn);
|
70 | });
|
71 | };
|
72 | var eqRecord = function (eqa) {
|
73 | return eq$2(function (x, y) {
|
74 | var kx = Object.keys(x);
|
75 | var ky = Object.keys(y);
|
76 | if (!eqSortedArray(eqString).eq(kx, ky)) {
|
77 | return false;
|
78 | }
|
79 | var len = kx.length;
|
80 | for (var i = 0; i < len; i++) {
|
81 | var q = kx[i];
|
82 | if (!eqa.eq(x[q], y[q])) {
|
83 | return false;
|
84 | }
|
85 | }
|
86 | return true;
|
87 | });
|
88 | };
|
89 | var eqAny = eq$2(function (x, y) {
|
90 | if (x === y) {
|
91 | return true;
|
92 | }
|
93 | var tx = typeOf$1(x);
|
94 | var ty = typeOf$1(y);
|
95 | if (tx !== ty) {
|
96 | return false;
|
97 | }
|
98 | if (isEquatableType(tx)) {
|
99 | return x === y;
|
100 | } else if (tx === 'array') {
|
101 | return eqArray(eqAny).eq(x, y);
|
102 | } else if (tx === 'object') {
|
103 | return eqRecord(eqAny).eq(x, y);
|
104 | }
|
105 | return false;
|
106 | });
|
107 |
|
108 | const getPrototypeOf$2 = Object.getPrototypeOf;
|
109 | const hasProto = (v, constructor, predicate) => {
|
110 | var _a;
|
111 | if (predicate(v, constructor.prototype)) {
|
112 | return true;
|
113 | } else {
|
114 | return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
|
115 | }
|
116 | };
|
117 | const typeOf = x => {
|
118 | const t = typeof x;
|
119 | if (x === null) {
|
120 | return 'null';
|
121 | } else if (t === 'object' && Array.isArray(x)) {
|
122 | return 'array';
|
123 | } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
|
124 | return 'string';
|
125 | } else {
|
126 | return t;
|
127 | }
|
128 | };
|
129 | const isType$1 = type => value => typeOf(value) === type;
|
130 | const isSimpleType = type => value => typeof value === type;
|
131 | const eq$1 = t => a => t === a;
|
132 | const is$4 = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf$2(o) === proto);
|
133 | const isString = isType$1('string');
|
134 | const isObject = isType$1('object');
|
135 | const isPlainObject = value => is$4(value, Object);
|
136 | const isArray$1 = isType$1('array');
|
137 | const isNull = eq$1(null);
|
138 | const isBoolean = isSimpleType('boolean');
|
139 | const isUndefined = eq$1(undefined);
|
140 | const isNullable = a => a === null || a === undefined;
|
141 | const isNonNullable = a => !isNullable(a);
|
142 | const isFunction = isSimpleType('function');
|
143 | const isNumber = isSimpleType('number');
|
144 | const isArrayOf = (value, pred) => {
|
145 | if (isArray$1(value)) {
|
146 | for (let i = 0, len = value.length; i < len; ++i) {
|
147 | if (!pred(value[i])) {
|
148 | return false;
|
149 | }
|
150 | }
|
151 | return true;
|
152 | }
|
153 | return false;
|
154 | };
|
155 |
|
156 | const noop = () => {
|
157 | };
|
158 | const compose = (fa, fb) => {
|
159 | return (...args) => {
|
160 | return fa(fb.apply(null, args));
|
161 | };
|
162 | };
|
163 | const compose1 = (fbc, fab) => a => fbc(fab(a));
|
164 | const constant = value => {
|
165 | return () => {
|
166 | return value;
|
167 | };
|
168 | };
|
169 | const identity = x => {
|
170 | return x;
|
171 | };
|
172 | const tripleEquals = (a, b) => {
|
173 | return a === b;
|
174 | };
|
175 | function curry(fn, ...initialArgs) {
|
176 | return (...restArgs) => {
|
177 | const all = initialArgs.concat(restArgs);
|
178 | return fn.apply(null, all);
|
179 | };
|
180 | }
|
181 | const not = f => t => !f(t);
|
182 | const die = msg => {
|
183 | return () => {
|
184 | throw new Error(msg);
|
185 | };
|
186 | };
|
187 | const apply$1 = f => {
|
188 | return f();
|
189 | };
|
190 | const call = f => {
|
191 | f();
|
192 | };
|
193 | const never = constant(false);
|
194 | const always = constant(true);
|
195 |
|
196 | class Optional {
|
197 | constructor(tag, value) {
|
198 | this.tag = tag;
|
199 | this.value = value;
|
200 | }
|
201 | static some(value) {
|
202 | return new Optional(true, value);
|
203 | }
|
204 | static none() {
|
205 | return Optional.singletonNone;
|
206 | }
|
207 | fold(onNone, onSome) {
|
208 | if (this.tag) {
|
209 | return onSome(this.value);
|
210 | } else {
|
211 | return onNone();
|
212 | }
|
213 | }
|
214 | isSome() {
|
215 | return this.tag;
|
216 | }
|
217 | isNone() {
|
218 | return !this.tag;
|
219 | }
|
220 | map(mapper) {
|
221 | if (this.tag) {
|
222 | return Optional.some(mapper(this.value));
|
223 | } else {
|
224 | return Optional.none();
|
225 | }
|
226 | }
|
227 | bind(binder) {
|
228 | if (this.tag) {
|
229 | return binder(this.value);
|
230 | } else {
|
231 | return Optional.none();
|
232 | }
|
233 | }
|
234 | exists(predicate) {
|
235 | return this.tag && predicate(this.value);
|
236 | }
|
237 | forall(predicate) {
|
238 | return !this.tag || predicate(this.value);
|
239 | }
|
240 | filter(predicate) {
|
241 | if (!this.tag || predicate(this.value)) {
|
242 | return this;
|
243 | } else {
|
244 | return Optional.none();
|
245 | }
|
246 | }
|
247 | getOr(replacement) {
|
248 | return this.tag ? this.value : replacement;
|
249 | }
|
250 | or(replacement) {
|
251 | return this.tag ? this : replacement;
|
252 | }
|
253 | getOrThunk(thunk) {
|
254 | return this.tag ? this.value : thunk();
|
255 | }
|
256 | orThunk(thunk) {
|
257 | return this.tag ? this : thunk();
|
258 | }
|
259 | getOrDie(message) {
|
260 | if (!this.tag) {
|
261 | throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
|
262 | } else {
|
263 | return this.value;
|
264 | }
|
265 | }
|
266 | static from(value) {
|
267 | return isNonNullable(value) ? Optional.some(value) : Optional.none();
|
268 | }
|
269 | getOrNull() {
|
270 | return this.tag ? this.value : null;
|
271 | }
|
272 | getOrUndefined() {
|
273 | return this.value;
|
274 | }
|
275 | each(worker) {
|
276 | if (this.tag) {
|
277 | worker(this.value);
|
278 | }
|
279 | }
|
280 | toArray() {
|
281 | return this.tag ? [this.value] : [];
|
282 | }
|
283 | toString() {
|
284 | return this.tag ? `some(${ this.value })` : 'none()';
|
285 | }
|
286 | }
|
287 | Optional.singletonNone = new Optional(false);
|
288 |
|
289 | const nativeSlice = Array.prototype.slice;
|
290 | const nativeIndexOf = Array.prototype.indexOf;
|
291 | const nativePush = Array.prototype.push;
|
292 | const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
|
293 | const indexOf$1 = (xs, x) => {
|
294 | const r = rawIndexOf(xs, x);
|
295 | return r === -1 ? Optional.none() : Optional.some(r);
|
296 | };
|
297 | const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
|
298 | const exists = (xs, pred) => {
|
299 | for (let i = 0, len = xs.length; i < len; i++) {
|
300 | const x = xs[i];
|
301 | if (pred(x, i)) {
|
302 | return true;
|
303 | }
|
304 | }
|
305 | return false;
|
306 | };
|
307 | const map$3 = (xs, f) => {
|
308 | const len = xs.length;
|
309 | const r = new Array(len);
|
310 | for (let i = 0; i < len; i++) {
|
311 | const x = xs[i];
|
312 | r[i] = f(x, i);
|
313 | }
|
314 | return r;
|
315 | };
|
316 | const each$e = (xs, f) => {
|
317 | for (let i = 0, len = xs.length; i < len; i++) {
|
318 | const x = xs[i];
|
319 | f(x, i);
|
320 | }
|
321 | };
|
322 | const eachr = (xs, f) => {
|
323 | for (let i = xs.length - 1; i >= 0; i--) {
|
324 | const x = xs[i];
|
325 | f(x, i);
|
326 | }
|
327 | };
|
328 | const partition$2 = (xs, pred) => {
|
329 | const pass = [];
|
330 | const fail = [];
|
331 | for (let i = 0, len = xs.length; i < len; i++) {
|
332 | const x = xs[i];
|
333 | const arr = pred(x, i) ? pass : fail;
|
334 | arr.push(x);
|
335 | }
|
336 | return {
|
337 | pass,
|
338 | fail
|
339 | };
|
340 | };
|
341 | const filter$5 = (xs, pred) => {
|
342 | const r = [];
|
343 | for (let i = 0, len = xs.length; i < len; i++) {
|
344 | const x = xs[i];
|
345 | if (pred(x, i)) {
|
346 | r.push(x);
|
347 | }
|
348 | }
|
349 | return r;
|
350 | };
|
351 | const foldr = (xs, f, acc) => {
|
352 | eachr(xs, (x, i) => {
|
353 | acc = f(acc, x, i);
|
354 | });
|
355 | return acc;
|
356 | };
|
357 | const foldl = (xs, f, acc) => {
|
358 | each$e(xs, (x, i) => {
|
359 | acc = f(acc, x, i);
|
360 | });
|
361 | return acc;
|
362 | };
|
363 | const findUntil$1 = (xs, pred, until) => {
|
364 | for (let i = 0, len = xs.length; i < len; i++) {
|
365 | const x = xs[i];
|
366 | if (pred(x, i)) {
|
367 | return Optional.some(x);
|
368 | } else if (until(x, i)) {
|
369 | break;
|
370 | }
|
371 | }
|
372 | return Optional.none();
|
373 | };
|
374 | const find$2 = (xs, pred) => {
|
375 | return findUntil$1(xs, pred, never);
|
376 | };
|
377 | const findIndex$2 = (xs, pred) => {
|
378 | for (let i = 0, len = xs.length; i < len; i++) {
|
379 | const x = xs[i];
|
380 | if (pred(x, i)) {
|
381 | return Optional.some(i);
|
382 | }
|
383 | }
|
384 | return Optional.none();
|
385 | };
|
386 | const flatten = xs => {
|
387 | const r = [];
|
388 | for (let i = 0, len = xs.length; i < len; ++i) {
|
389 | if (!isArray$1(xs[i])) {
|
390 | throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
|
391 | }
|
392 | nativePush.apply(r, xs[i]);
|
393 | }
|
394 | return r;
|
395 | };
|
396 | const bind$3 = (xs, f) => flatten(map$3(xs, f));
|
397 | const forall = (xs, pred) => {
|
398 | for (let i = 0, len = xs.length; i < len; ++i) {
|
399 | const x = xs[i];
|
400 | if (pred(x, i) !== true) {
|
401 | return false;
|
402 | }
|
403 | }
|
404 | return true;
|
405 | };
|
406 | const reverse = xs => {
|
407 | const r = nativeSlice.call(xs, 0);
|
408 | r.reverse();
|
409 | return r;
|
410 | };
|
411 | const difference = (a1, a2) => filter$5(a1, x => !contains$2(a2, x));
|
412 | const mapToObject = (xs, f) => {
|
413 | const r = {};
|
414 | for (let i = 0, len = xs.length; i < len; i++) {
|
415 | const x = xs[i];
|
416 | r[String(x)] = f(x, i);
|
417 | }
|
418 | return r;
|
419 | };
|
420 | const sort = (xs, comparator) => {
|
421 | const copy = nativeSlice.call(xs, 0);
|
422 | copy.sort(comparator);
|
423 | return copy;
|
424 | };
|
425 | const get$b = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
|
426 | const head = xs => get$b(xs, 0);
|
427 | const last$2 = xs => get$b(xs, xs.length - 1);
|
428 | const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
|
429 | const findMap = (arr, f) => {
|
430 | for (let i = 0; i < arr.length; i++) {
|
431 | const r = f(arr[i], i);
|
432 | if (r.isSome()) {
|
433 | return r;
|
434 | }
|
435 | }
|
436 | return Optional.none();
|
437 | };
|
438 | const unique$1 = (xs, comparator) => {
|
439 | const r = [];
|
440 | const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$2(r, x);
|
441 | for (let i = 0, len = xs.length; i < len; i++) {
|
442 | const x = xs[i];
|
443 | if (!isDuplicated(x)) {
|
444 | r.push(x);
|
445 | }
|
446 | }
|
447 | return r;
|
448 | };
|
449 |
|
450 | const keys = Object.keys;
|
451 | const hasOwnProperty$1 = Object.hasOwnProperty;
|
452 | const each$d = (obj, f) => {
|
453 | const props = keys(obj);
|
454 | for (let k = 0, len = props.length; k < len; k++) {
|
455 | const i = props[k];
|
456 | const x = obj[i];
|
457 | f(x, i);
|
458 | }
|
459 | };
|
460 | const map$2 = (obj, f) => {
|
461 | return tupleMap(obj, (x, i) => ({
|
462 | k: i,
|
463 | v: f(x, i)
|
464 | }));
|
465 | };
|
466 | const tupleMap = (obj, f) => {
|
467 | const r = {};
|
468 | each$d(obj, (x, i) => {
|
469 | const tuple = f(x, i);
|
470 | r[tuple.k] = tuple.v;
|
471 | });
|
472 | return r;
|
473 | };
|
474 | const objAcc = r => (x, i) => {
|
475 | r[i] = x;
|
476 | };
|
477 | const internalFilter = (obj, pred, onTrue, onFalse) => {
|
478 | each$d(obj, (x, i) => {
|
479 | (pred(x, i) ? onTrue : onFalse)(x, i);
|
480 | });
|
481 | };
|
482 | const bifilter = (obj, pred) => {
|
483 | const t = {};
|
484 | const f = {};
|
485 | internalFilter(obj, pred, objAcc(t), objAcc(f));
|
486 | return {
|
487 | t,
|
488 | f
|
489 | };
|
490 | };
|
491 | const filter$4 = (obj, pred) => {
|
492 | const t = {};
|
493 | internalFilter(obj, pred, objAcc(t), noop);
|
494 | return t;
|
495 | };
|
496 | const mapToArray = (obj, f) => {
|
497 | const r = [];
|
498 | each$d(obj, (value, name) => {
|
499 | r.push(f(value, name));
|
500 | });
|
501 | return r;
|
502 | };
|
503 | const values = obj => {
|
504 | return mapToArray(obj, identity);
|
505 | };
|
506 | const get$a = (obj, key) => {
|
507 | return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
|
508 | };
|
509 | const has$2 = (obj, key) => hasOwnProperty$1.call(obj, key);
|
510 | const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
|
511 | const equal$1 = (a1, a2, eq = eqAny) => eqRecord(eq).eq(a1, a2);
|
512 |
|
513 | const stringArray = a => {
|
514 | const all = {};
|
515 | each$e(a, key => {
|
516 | all[key] = {};
|
517 | });
|
518 | return keys(all);
|
519 | };
|
520 |
|
521 | const isArrayLike = o => o.length !== undefined;
|
522 | const isArray = Array.isArray;
|
523 | const toArray$1 = obj => {
|
524 | if (!isArray(obj)) {
|
525 | const array = [];
|
526 | for (let i = 0, l = obj.length; i < l; i++) {
|
527 | array[i] = obj[i];
|
528 | }
|
529 | return array;
|
530 | } else {
|
531 | return obj;
|
532 | }
|
533 | };
|
534 | const each$c = (o, cb, s) => {
|
535 | if (!o) {
|
536 | return false;
|
537 | }
|
538 | s = s || o;
|
539 | if (isArrayLike(o)) {
|
540 | for (let n = 0, l = o.length; n < l; n++) {
|
541 | if (cb.call(s, o[n], n, o) === false) {
|
542 | return false;
|
543 | }
|
544 | }
|
545 | } else {
|
546 | for (const n in o) {
|
547 | if (has$2(o, n)) {
|
548 | if (cb.call(s, o[n], n, o) === false) {
|
549 | return false;
|
550 | }
|
551 | }
|
552 | }
|
553 | }
|
554 | return true;
|
555 | };
|
556 | const map$1 = (array, callback) => {
|
557 | const out = [];
|
558 | each$c(array, (item, index) => {
|
559 | out.push(callback(item, index, array));
|
560 | });
|
561 | return out;
|
562 | };
|
563 | const filter$3 = (a, f) => {
|
564 | const o = [];
|
565 | each$c(a, (v, index) => {
|
566 | if (!f || f(v, index, a)) {
|
567 | o.push(v);
|
568 | }
|
569 | });
|
570 | return o;
|
571 | };
|
572 | const indexOf = (a, v) => {
|
573 | if (a) {
|
574 | for (let i = 0, l = a.length; i < l; i++) {
|
575 | if (a[i] === v) {
|
576 | return i;
|
577 | }
|
578 | }
|
579 | }
|
580 | return -1;
|
581 | };
|
582 | const reduce = (collection, iteratee, accumulator, thisArg) => {
|
583 | let acc = isUndefined(accumulator) ? collection[0] : accumulator;
|
584 | for (let i = 0; i < collection.length; i++) {
|
585 | acc = iteratee.call(thisArg, acc, collection[i], i);
|
586 | }
|
587 | return acc;
|
588 | };
|
589 | const findIndex$1 = (array, predicate, thisArg) => {
|
590 | for (let i = 0, l = array.length; i < l; i++) {
|
591 | if (predicate.call(thisArg, array[i], i, array)) {
|
592 | return i;
|
593 | }
|
594 | }
|
595 | return -1;
|
596 | };
|
597 | const last$1 = collection => collection[collection.length - 1];
|
598 |
|
599 | const cached = f => {
|
600 | let called = false;
|
601 | let r;
|
602 | return (...args) => {
|
603 | if (!called) {
|
604 | called = true;
|
605 | r = f.apply(null, args);
|
606 | }
|
607 | return r;
|
608 | };
|
609 | };
|
610 |
|
611 | const DeviceType = (os, browser, userAgent, mediaMatch) => {
|
612 | const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
|
613 | const isiPhone = os.isiOS() && !isiPad;
|
614 | const isMobile = os.isiOS() || os.isAndroid();
|
615 | const isTouch = isMobile || mediaMatch('(pointer:coarse)');
|
616 | const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
|
617 | const isPhone = isiPhone || isMobile && !isTablet;
|
618 | const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
|
619 | const isDesktop = !isPhone && !isTablet && !iOSwebview;
|
620 | return {
|
621 | isiPad: constant(isiPad),
|
622 | isiPhone: constant(isiPhone),
|
623 | isTablet: constant(isTablet),
|
624 | isPhone: constant(isPhone),
|
625 | isTouch: constant(isTouch),
|
626 | isAndroid: os.isAndroid,
|
627 | isiOS: os.isiOS,
|
628 | isWebView: constant(iOSwebview),
|
629 | isDesktop: constant(isDesktop)
|
630 | };
|
631 | };
|
632 |
|
633 | const firstMatch = (regexes, s) => {
|
634 | for (let i = 0; i < regexes.length; i++) {
|
635 | const x = regexes[i];
|
636 | if (x.test(s)) {
|
637 | return x;
|
638 | }
|
639 | }
|
640 | return undefined;
|
641 | };
|
642 | const find$1 = (regexes, agent) => {
|
643 | const r = firstMatch(regexes, agent);
|
644 | if (!r) {
|
645 | return {
|
646 | major: 0,
|
647 | minor: 0
|
648 | };
|
649 | }
|
650 | const group = i => {
|
651 | return Number(agent.replace(r, '$' + i));
|
652 | };
|
653 | return nu$3(group(1), group(2));
|
654 | };
|
655 | const detect$4 = (versionRegexes, agent) => {
|
656 | const cleanedAgent = String(agent).toLowerCase();
|
657 | if (versionRegexes.length === 0) {
|
658 | return unknown$2();
|
659 | }
|
660 | return find$1(versionRegexes, cleanedAgent);
|
661 | };
|
662 | const unknown$2 = () => {
|
663 | return nu$3(0, 0);
|
664 | };
|
665 | const nu$3 = (major, minor) => {
|
666 | return {
|
667 | major,
|
668 | minor
|
669 | };
|
670 | };
|
671 | const Version = {
|
672 | nu: nu$3,
|
673 | detect: detect$4,
|
674 | unknown: unknown$2
|
675 | };
|
676 |
|
677 | const detectBrowser$1 = (browsers, userAgentData) => {
|
678 | return findMap(userAgentData.brands, uaBrand => {
|
679 | const lcBrand = uaBrand.brand.toLowerCase();
|
680 | return find$2(browsers, browser => {
|
681 | var _a;
|
682 | return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
|
683 | }).map(info => ({
|
684 | current: info.name,
|
685 | version: Version.nu(parseInt(uaBrand.version, 10), 0)
|
686 | }));
|
687 | });
|
688 | };
|
689 |
|
690 | const detect$3 = (candidates, userAgent) => {
|
691 | const agent = String(userAgent).toLowerCase();
|
692 | return find$2(candidates, candidate => {
|
693 | return candidate.search(agent);
|
694 | });
|
695 | };
|
696 | const detectBrowser = (browsers, userAgent) => {
|
697 | return detect$3(browsers, userAgent).map(browser => {
|
698 | const version = Version.detect(browser.versionRegexes, userAgent);
|
699 | return {
|
700 | current: browser.name,
|
701 | version
|
702 | };
|
703 | });
|
704 | };
|
705 | const detectOs = (oses, userAgent) => {
|
706 | return detect$3(oses, userAgent).map(os => {
|
707 | const version = Version.detect(os.versionRegexes, userAgent);
|
708 | return {
|
709 | current: os.name,
|
710 | version
|
711 | };
|
712 | });
|
713 | };
|
714 |
|
715 | const removeFromStart = (str, numChars) => {
|
716 | return str.substring(numChars);
|
717 | };
|
718 |
|
719 | const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
|
720 | const removeLeading = (str, prefix) => {
|
721 | return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
|
722 | };
|
723 | const contains$1 = (str, substr, start = 0, end) => {
|
724 | const idx = str.indexOf(substr, start);
|
725 | if (idx !== -1) {
|
726 | return isUndefined(end) ? true : idx + substr.length <= end;
|
727 | } else {
|
728 | return false;
|
729 | }
|
730 | };
|
731 | const startsWith = (str, prefix) => {
|
732 | return checkRange(str, prefix, 0);
|
733 | };
|
734 | const endsWith = (str, suffix) => {
|
735 | return checkRange(str, suffix, str.length - suffix.length);
|
736 | };
|
737 | const blank = r => s => s.replace(r, '');
|
738 | const trim$4 = blank(/^\s+|\s+$/g);
|
739 | const lTrim = blank(/^\s+/g);
|
740 | const rTrim = blank(/\s+$/g);
|
741 | const isNotEmpty = s => s.length > 0;
|
742 | const isEmpty$3 = s => !isNotEmpty(s);
|
743 | const repeat = (s, count) => count <= 0 ? '' : new Array(count + 1).join(s);
|
744 | const toInt = (value, radix = 10) => {
|
745 | const num = parseInt(value, radix);
|
746 | return isNaN(num) ? Optional.none() : Optional.some(num);
|
747 | };
|
748 |
|
749 | const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
|
750 | const checkContains = target => {
|
751 | return uastring => {
|
752 | return contains$1(uastring, target);
|
753 | };
|
754 | };
|
755 | const browsers = [
|
756 | {
|
757 | name: 'Edge',
|
758 | versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
|
759 | search: uastring => {
|
760 | return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
|
761 | }
|
762 | },
|
763 | {
|
764 | name: 'Chromium',
|
765 | brand: 'Chromium',
|
766 | versionRegexes: [
|
767 | /.*?chrome\/([0-9]+)\.([0-9]+).*/,
|
768 | normalVersionRegex
|
769 | ],
|
770 | search: uastring => {
|
771 | return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
|
772 | }
|
773 | },
|
774 | {
|
775 | name: 'IE',
|
776 | versionRegexes: [
|
777 | /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
|
778 | /.*?rv:([0-9]+)\.([0-9]+).*/
|
779 | ],
|
780 | search: uastring => {
|
781 | return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
|
782 | }
|
783 | },
|
784 | {
|
785 | name: 'Opera',
|
786 | versionRegexes: [
|
787 | normalVersionRegex,
|
788 | /.*?opera\/([0-9]+)\.([0-9]+).*/
|
789 | ],
|
790 | search: checkContains('opera')
|
791 | },
|
792 | {
|
793 | name: 'Firefox',
|
794 | versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
|
795 | search: checkContains('firefox')
|
796 | },
|
797 | {
|
798 | name: 'Safari',
|
799 | versionRegexes: [
|
800 | normalVersionRegex,
|
801 | /.*?cpu os ([0-9]+)_([0-9]+).*/
|
802 | ],
|
803 | search: uastring => {
|
804 | return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
|
805 | }
|
806 | }
|
807 | ];
|
808 | const oses = [
|
809 | {
|
810 | name: 'Windows',
|
811 | search: checkContains('win'),
|
812 | versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
|
813 | },
|
814 | {
|
815 | name: 'iOS',
|
816 | search: uastring => {
|
817 | return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
|
818 | },
|
819 | versionRegexes: [
|
820 | /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
|
821 | /.*cpu os ([0-9]+)_([0-9]+).*/,
|
822 | /.*cpu iphone os ([0-9]+)_([0-9]+).*/
|
823 | ]
|
824 | },
|
825 | {
|
826 | name: 'Android',
|
827 | search: checkContains('android'),
|
828 | versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
|
829 | },
|
830 | {
|
831 | name: 'macOS',
|
832 | search: checkContains('mac os x'),
|
833 | versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
|
834 | },
|
835 | {
|
836 | name: 'Linux',
|
837 | search: checkContains('linux'),
|
838 | versionRegexes: []
|
839 | },
|
840 | {
|
841 | name: 'Solaris',
|
842 | search: checkContains('sunos'),
|
843 | versionRegexes: []
|
844 | },
|
845 | {
|
846 | name: 'FreeBSD',
|
847 | search: checkContains('freebsd'),
|
848 | versionRegexes: []
|
849 | },
|
850 | {
|
851 | name: 'ChromeOS',
|
852 | search: checkContains('cros'),
|
853 | versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
|
854 | }
|
855 | ];
|
856 | const PlatformInfo = {
|
857 | browsers: constant(browsers),
|
858 | oses: constant(oses)
|
859 | };
|
860 |
|
861 | const edge = 'Edge';
|
862 | const chromium = 'Chromium';
|
863 | const ie = 'IE';
|
864 | const opera = 'Opera';
|
865 | const firefox = 'Firefox';
|
866 | const safari = 'Safari';
|
867 | const unknown$1 = () => {
|
868 | return nu$2({
|
869 | current: undefined,
|
870 | version: Version.unknown()
|
871 | });
|
872 | };
|
873 | const nu$2 = info => {
|
874 | const current = info.current;
|
875 | const version = info.version;
|
876 | const isBrowser = name => () => current === name;
|
877 | return {
|
878 | current,
|
879 | version,
|
880 | isEdge: isBrowser(edge),
|
881 | isChromium: isBrowser(chromium),
|
882 | isIE: isBrowser(ie),
|
883 | isOpera: isBrowser(opera),
|
884 | isFirefox: isBrowser(firefox),
|
885 | isSafari: isBrowser(safari)
|
886 | };
|
887 | };
|
888 | const Browser = {
|
889 | unknown: unknown$1,
|
890 | nu: nu$2,
|
891 | edge: constant(edge),
|
892 | chromium: constant(chromium),
|
893 | ie: constant(ie),
|
894 | opera: constant(opera),
|
895 | firefox: constant(firefox),
|
896 | safari: constant(safari)
|
897 | };
|
898 |
|
899 | const windows = 'Windows';
|
900 | const ios = 'iOS';
|
901 | const android = 'Android';
|
902 | const linux = 'Linux';
|
903 | const macos = 'macOS';
|
904 | const solaris = 'Solaris';
|
905 | const freebsd = 'FreeBSD';
|
906 | const chromeos = 'ChromeOS';
|
907 | const unknown = () => {
|
908 | return nu$1({
|
909 | current: undefined,
|
910 | version: Version.unknown()
|
911 | });
|
912 | };
|
913 | const nu$1 = info => {
|
914 | const current = info.current;
|
915 | const version = info.version;
|
916 | const isOS = name => () => current === name;
|
917 | return {
|
918 | current,
|
919 | version,
|
920 | isWindows: isOS(windows),
|
921 | isiOS: isOS(ios),
|
922 | isAndroid: isOS(android),
|
923 | isMacOS: isOS(macos),
|
924 | isLinux: isOS(linux),
|
925 | isSolaris: isOS(solaris),
|
926 | isFreeBSD: isOS(freebsd),
|
927 | isChromeOS: isOS(chromeos)
|
928 | };
|
929 | };
|
930 | const OperatingSystem = {
|
931 | unknown,
|
932 | nu: nu$1,
|
933 | windows: constant(windows),
|
934 | ios: constant(ios),
|
935 | android: constant(android),
|
936 | linux: constant(linux),
|
937 | macos: constant(macos),
|
938 | solaris: constant(solaris),
|
939 | freebsd: constant(freebsd),
|
940 | chromeos: constant(chromeos)
|
941 | };
|
942 |
|
943 | const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => {
|
944 | const browsers = PlatformInfo.browsers();
|
945 | const oses = PlatformInfo.oses();
|
946 | const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
|
947 | const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
|
948 | const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
|
949 | return {
|
950 | browser,
|
951 | os,
|
952 | deviceType
|
953 | };
|
954 | };
|
955 | const PlatformDetection = { detect: detect$2 };
|
956 |
|
957 | const mediaMatch = query => window.matchMedia(query).matches;
|
958 | let platform$4 = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
|
959 | const detect$1 = () => platform$4();
|
960 |
|
961 | const userAgent = navigator.userAgent;
|
962 | const platform$3 = detect$1();
|
963 | const browser$3 = platform$3.browser;
|
964 | const os$1 = platform$3.os;
|
965 | const deviceType = platform$3.deviceType;
|
966 | const windowsPhone = userAgent.indexOf('Windows Phone') !== -1;
|
967 | const Env = {
|
968 | transparentSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
|
969 | documentMode: browser$3.isIE() ? document.documentMode || 7 : 10,
|
970 | cacheSuffix: null,
|
971 | container: null,
|
972 | canHaveCSP: !browser$3.isIE(),
|
973 | windowsPhone,
|
974 | browser: {
|
975 | current: browser$3.current,
|
976 | version: browser$3.version,
|
977 | isChromium: browser$3.isChromium,
|
978 | isEdge: browser$3.isEdge,
|
979 | isFirefox: browser$3.isFirefox,
|
980 | isIE: browser$3.isIE,
|
981 | isOpera: browser$3.isOpera,
|
982 | isSafari: browser$3.isSafari
|
983 | },
|
984 | os: {
|
985 | current: os$1.current,
|
986 | version: os$1.version,
|
987 | isAndroid: os$1.isAndroid,
|
988 | isChromeOS: os$1.isChromeOS,
|
989 | isFreeBSD: os$1.isFreeBSD,
|
990 | isiOS: os$1.isiOS,
|
991 | isLinux: os$1.isLinux,
|
992 | isMacOS: os$1.isMacOS,
|
993 | isSolaris: os$1.isSolaris,
|
994 | isWindows: os$1.isWindows
|
995 | },
|
996 | deviceType: {
|
997 | isDesktop: deviceType.isDesktop,
|
998 | isiPad: deviceType.isiPad,
|
999 | isiPhone: deviceType.isiPhone,
|
1000 | isPhone: deviceType.isPhone,
|
1001 | isTablet: deviceType.isTablet,
|
1002 | isTouch: deviceType.isTouch,
|
1003 | isWebView: deviceType.isWebView
|
1004 | }
|
1005 | };
|
1006 |
|
1007 | const whiteSpaceRegExp$1 = /^\s*|\s*$/g;
|
1008 | const trim$3 = str => {
|
1009 | return isNullable(str) ? '' : ('' + str).replace(whiteSpaceRegExp$1, '');
|
1010 | };
|
1011 | const is$3 = (obj, type) => {
|
1012 | if (!type) {
|
1013 | return obj !== undefined;
|
1014 | }
|
1015 | if (type === 'array' && isArray(obj)) {
|
1016 | return true;
|
1017 | }
|
1018 | return typeof obj === type;
|
1019 | };
|
1020 | const makeMap$4 = (items, delim, map = {}) => {
|
1021 | const resolvedItems = isString(items) ? items.split(delim || ',') : items || [];
|
1022 | let i = resolvedItems.length;
|
1023 | while (i--) {
|
1024 | map[resolvedItems[i]] = {};
|
1025 | }
|
1026 | return map;
|
1027 | };
|
1028 | const hasOwnProperty = has$2;
|
1029 | const extend$3 = (obj, ...exts) => {
|
1030 | for (let i = 0; i < exts.length; i++) {
|
1031 | const ext = exts[i];
|
1032 | for (const name in ext) {
|
1033 | if (has$2(ext, name)) {
|
1034 | const value = ext[name];
|
1035 | if (value !== undefined) {
|
1036 | obj[name] = value;
|
1037 | }
|
1038 | }
|
1039 | }
|
1040 | }
|
1041 | return obj;
|
1042 | };
|
1043 | const walk$4 = function (o, f, n, s) {
|
1044 | s = s || this;
|
1045 | if (o) {
|
1046 | if (n) {
|
1047 | o = o[n];
|
1048 | }
|
1049 | each$c(o, (o, i) => {
|
1050 | if (f.call(s, o, i, n) === false) {
|
1051 | return false;
|
1052 | } else {
|
1053 | walk$4(o, f, n, s);
|
1054 | return true;
|
1055 | }
|
1056 | });
|
1057 | }
|
1058 | };
|
1059 | const resolve$3 = (n, o = window) => {
|
1060 | const path = n.split('.');
|
1061 | for (let i = 0, l = path.length; i < l; i++) {
|
1062 | o = o[path[i]];
|
1063 | if (!o) {
|
1064 | break;
|
1065 | }
|
1066 | }
|
1067 | return o;
|
1068 | };
|
1069 | const explode$3 = (s, d) => {
|
1070 | if (isArray$1(s)) {
|
1071 | return s;
|
1072 | } else if (s === '') {
|
1073 | return [];
|
1074 | } else {
|
1075 | return map$1(s.split(d || ','), trim$3);
|
1076 | }
|
1077 | };
|
1078 | const _addCacheSuffix = url => {
|
1079 | const cacheSuffix = Env.cacheSuffix;
|
1080 | if (cacheSuffix) {
|
1081 | url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
|
1082 | }
|
1083 | return url;
|
1084 | };
|
1085 | const Tools = {
|
1086 | trim: trim$3,
|
1087 | isArray: isArray,
|
1088 | is: is$3,
|
1089 | toArray: toArray$1,
|
1090 | makeMap: makeMap$4,
|
1091 | each: each$c,
|
1092 | map: map$1,
|
1093 | grep: filter$3,
|
1094 | inArray: indexOf,
|
1095 | hasOwn: hasOwnProperty,
|
1096 | extend: extend$3,
|
1097 | walk: walk$4,
|
1098 | resolve: resolve$3,
|
1099 | explode: explode$3,
|
1100 | _addCacheSuffix
|
1101 | };
|
1102 |
|
1103 | const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
|
1104 | const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
|
1105 | const cat = arr => {
|
1106 | const r = [];
|
1107 | const push = x => {
|
1108 | r.push(x);
|
1109 | };
|
1110 | for (let i = 0; i < arr.length; i++) {
|
1111 | arr[i].each(push);
|
1112 | }
|
1113 | return r;
|
1114 | };
|
1115 | const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
|
1116 | const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
|
1117 | const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
|
1118 |
|
1119 | const Global = typeof window !== 'undefined' ? window : Function('return this;')();
|
1120 |
|
1121 | const path = (parts, scope) => {
|
1122 | let o = scope !== undefined && scope !== null ? scope : Global;
|
1123 | for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
|
1124 | o = o[parts[i]];
|
1125 | }
|
1126 | return o;
|
1127 | };
|
1128 | const resolve$2 = (p, scope) => {
|
1129 | const parts = p.split('.');
|
1130 | return path(parts, scope);
|
1131 | };
|
1132 |
|
1133 | const unsafe = (name, scope) => {
|
1134 | return resolve$2(name, scope);
|
1135 | };
|
1136 | const getOrDie = (name, scope) => {
|
1137 | const actual = unsafe(name, scope);
|
1138 | if (actual === undefined || actual === null) {
|
1139 | throw new Error(name + ' not available on this browser');
|
1140 | }
|
1141 | return actual;
|
1142 | };
|
1143 |
|
1144 | const getPrototypeOf$1 = Object.getPrototypeOf;
|
1145 | const sandHTMLElement = scope => {
|
1146 | return getOrDie('HTMLElement', scope);
|
1147 | };
|
1148 | const isPrototypeOf = x => {
|
1149 | const scope = resolve$2('ownerDocument.defaultView', x);
|
1150 | return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name));
|
1151 | };
|
1152 |
|
1153 | const COMMENT = 8;
|
1154 | const DOCUMENT = 9;
|
1155 | const DOCUMENT_FRAGMENT = 11;
|
1156 | const ELEMENT = 1;
|
1157 | const TEXT = 3;
|
1158 |
|
1159 | const name = element => {
|
1160 | const r = element.dom.nodeName;
|
1161 | return r.toLowerCase();
|
1162 | };
|
1163 | const type$1 = element => element.dom.nodeType;
|
1164 | const isType = t => element => type$1(element) === t;
|
1165 | const isComment$1 = element => type$1(element) === COMMENT || name(element) === '#comment';
|
1166 | const isHTMLElement$1 = element => isElement$7(element) && isPrototypeOf(element.dom);
|
1167 | const isElement$7 = isType(ELEMENT);
|
1168 | const isText$c = isType(TEXT);
|
1169 | const isDocument$2 = isType(DOCUMENT);
|
1170 | const isDocumentFragment$1 = isType(DOCUMENT_FRAGMENT);
|
1171 | const isTag = tag => e => isElement$7(e) && name(e) === tag;
|
1172 |
|
1173 | const rawSet = (dom, key, value) => {
|
1174 | if (isString(value) || isBoolean(value) || isNumber(value)) {
|
1175 | dom.setAttribute(key, value + '');
|
1176 | } else {
|
1177 | console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
|
1178 | throw new Error('Attribute value was not simple');
|
1179 | }
|
1180 | };
|
1181 | const set$3 = (element, key, value) => {
|
1182 | rawSet(element.dom, key, value);
|
1183 | };
|
1184 | const setAll$1 = (element, attrs) => {
|
1185 | const dom = element.dom;
|
1186 | each$d(attrs, (v, k) => {
|
1187 | rawSet(dom, k, v);
|
1188 | });
|
1189 | };
|
1190 | const get$9 = (element, key) => {
|
1191 | const v = element.dom.getAttribute(key);
|
1192 | return v === null ? undefined : v;
|
1193 | };
|
1194 | const getOpt = (element, key) => Optional.from(get$9(element, key));
|
1195 | const has$1 = (element, key) => {
|
1196 | const dom = element.dom;
|
1197 | return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
|
1198 | };
|
1199 | const remove$9 = (element, key) => {
|
1200 | element.dom.removeAttribute(key);
|
1201 | };
|
1202 | const hasNone = element => {
|
1203 | const attrs = element.dom.attributes;
|
1204 | return attrs === undefined || attrs === null || attrs.length === 0;
|
1205 | };
|
1206 | const clone$4 = element => foldl(element.dom.attributes, (acc, attr) => {
|
1207 | acc[attr.name] = attr.value;
|
1208 | return acc;
|
1209 | }, {});
|
1210 |
|
1211 | const read$4 = (element, attr) => {
|
1212 | const value = get$9(element, attr);
|
1213 | return value === undefined || value === '' ? [] : value.split(' ');
|
1214 | };
|
1215 | const add$4 = (element, attr, id) => {
|
1216 | const old = read$4(element, attr);
|
1217 | const nu = old.concat([id]);
|
1218 | set$3(element, attr, nu.join(' '));
|
1219 | return true;
|
1220 | };
|
1221 | const remove$8 = (element, attr, id) => {
|
1222 | const nu = filter$5(read$4(element, attr), v => v !== id);
|
1223 | if (nu.length > 0) {
|
1224 | set$3(element, attr, nu.join(' '));
|
1225 | } else {
|
1226 | remove$9(element, attr);
|
1227 | }
|
1228 | return false;
|
1229 | };
|
1230 |
|
1231 | const supports = element => element.dom.classList !== undefined;
|
1232 | const get$8 = element => read$4(element, 'class');
|
1233 | const add$3 = (element, clazz) => add$4(element, 'class', clazz);
|
1234 | const remove$7 = (element, clazz) => remove$8(element, 'class', clazz);
|
1235 | const toggle$2 = (element, clazz) => {
|
1236 | if (contains$2(get$8(element), clazz)) {
|
1237 | return remove$7(element, clazz);
|
1238 | } else {
|
1239 | return add$3(element, clazz);
|
1240 | }
|
1241 | };
|
1242 |
|
1243 | const add$2 = (element, clazz) => {
|
1244 | if (supports(element)) {
|
1245 | element.dom.classList.add(clazz);
|
1246 | } else {
|
1247 | add$3(element, clazz);
|
1248 | }
|
1249 | };
|
1250 | const cleanClass = element => {
|
1251 | const classList = supports(element) ? element.dom.classList : get$8(element);
|
1252 | if (classList.length === 0) {
|
1253 | remove$9(element, 'class');
|
1254 | }
|
1255 | };
|
1256 | const remove$6 = (element, clazz) => {
|
1257 | if (supports(element)) {
|
1258 | const classList = element.dom.classList;
|
1259 | classList.remove(clazz);
|
1260 | } else {
|
1261 | remove$7(element, clazz);
|
1262 | }
|
1263 | cleanClass(element);
|
1264 | };
|
1265 | const toggle$1 = (element, clazz) => {
|
1266 | const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$2(element, clazz);
|
1267 | cleanClass(element);
|
1268 | return result;
|
1269 | };
|
1270 | const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
|
1271 |
|
1272 | const fromHtml$1 = (html, scope) => {
|
1273 | const doc = scope || document;
|
1274 | const div = doc.createElement('div');
|
1275 | div.innerHTML = html;
|
1276 | if (!div.hasChildNodes() || div.childNodes.length > 1) {
|
1277 | const message = 'HTML does not have a single root node';
|
1278 | console.error(message, html);
|
1279 | throw new Error(message);
|
1280 | }
|
1281 | return fromDom$2(div.childNodes[0]);
|
1282 | };
|
1283 | const fromTag = (tag, scope) => {
|
1284 | const doc = scope || document;
|
1285 | const node = doc.createElement(tag);
|
1286 | return fromDom$2(node);
|
1287 | };
|
1288 | const fromText = (text, scope) => {
|
1289 | const doc = scope || document;
|
1290 | const node = doc.createTextNode(text);
|
1291 | return fromDom$2(node);
|
1292 | };
|
1293 | const fromDom$2 = node => {
|
1294 | if (node === null || node === undefined) {
|
1295 | throw new Error('Node cannot be null or undefined');
|
1296 | }
|
1297 | return { dom: node };
|
1298 | };
|
1299 | const fromPoint$2 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$2);
|
1300 | const SugarElement = {
|
1301 | fromHtml: fromHtml$1,
|
1302 | fromTag,
|
1303 | fromText,
|
1304 | fromDom: fromDom$2,
|
1305 | fromPoint: fromPoint$2
|
1306 | };
|
1307 |
|
1308 | const toArray = (target, f) => {
|
1309 | const r = [];
|
1310 | const recurse = e => {
|
1311 | r.push(e);
|
1312 | return f(e);
|
1313 | };
|
1314 | let cur = f(target);
|
1315 | do {
|
1316 | cur = cur.bind(recurse);
|
1317 | } while (cur.isSome());
|
1318 | return r;
|
1319 | };
|
1320 |
|
1321 | const is$1 = (element, selector) => {
|
1322 | const dom = element.dom;
|
1323 | if (dom.nodeType !== ELEMENT) {
|
1324 | return false;
|
1325 | } else {
|
1326 | const elem = dom;
|
1327 | if (elem.matches !== undefined) {
|
1328 | return elem.matches(selector);
|
1329 | } else if (elem.msMatchesSelector !== undefined) {
|
1330 | return elem.msMatchesSelector(selector);
|
1331 | } else if (elem.webkitMatchesSelector !== undefined) {
|
1332 | return elem.webkitMatchesSelector(selector);
|
1333 | } else if (elem.mozMatchesSelector !== undefined) {
|
1334 | return elem.mozMatchesSelector(selector);
|
1335 | } else {
|
1336 | throw new Error('Browser lacks native selectors');
|
1337 | }
|
1338 | }
|
1339 | };
|
1340 | const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
|
1341 | const all = (selector, scope) => {
|
1342 | const base = scope === undefined ? document : scope.dom;
|
1343 | return bypassSelector(base) ? [] : map$3(base.querySelectorAll(selector), SugarElement.fromDom);
|
1344 | };
|
1345 | const one = (selector, scope) => {
|
1346 | const base = scope === undefined ? document : scope.dom;
|
1347 | return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
|
1348 | };
|
1349 |
|
1350 | const eq = (e1, e2) => e1.dom === e2.dom;
|
1351 | const contains = (e1, e2) => {
|
1352 | const d1 = e1.dom;
|
1353 | const d2 = e2.dom;
|
1354 | return d1 === d2 ? false : d1.contains(d2);
|
1355 | };
|
1356 |
|
1357 | const owner$1 = element => SugarElement.fromDom(element.dom.ownerDocument);
|
1358 | const documentOrOwner = dos => isDocument$2(dos) ? dos : owner$1(dos);
|
1359 | const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
|
1360 | const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
|
1361 | const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
|
1362 | const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
|
1363 | const parents$1 = (element, isRoot) => {
|
1364 | const stop = isFunction(isRoot) ? isRoot : never;
|
1365 | let dom = element.dom;
|
1366 | const ret = [];
|
1367 | while (dom.parentNode !== null && dom.parentNode !== undefined) {
|
1368 | const rawParent = dom.parentNode;
|
1369 | const p = SugarElement.fromDom(rawParent);
|
1370 | ret.push(p);
|
1371 | if (stop(p) === true) {
|
1372 | break;
|
1373 | } else {
|
1374 | dom = rawParent;
|
1375 | }
|
1376 | }
|
1377 | return ret;
|
1378 | };
|
1379 | const siblings = element => {
|
1380 | const filterSelf = elements => filter$5(elements, x => !eq(element, x));
|
1381 | return parent(element).map(children$1).map(filterSelf).getOr([]);
|
1382 | };
|
1383 | const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
|
1384 | const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
|
1385 | const prevSiblings = element => reverse(toArray(element, prevSibling));
|
1386 | const nextSiblings = element => toArray(element, nextSibling);
|
1387 | const children$1 = element => map$3(element.dom.childNodes, SugarElement.fromDom);
|
1388 | const child$1 = (element, index) => {
|
1389 | const cs = element.dom.childNodes;
|
1390 | return Optional.from(cs[index]).map(SugarElement.fromDom);
|
1391 | };
|
1392 | const firstChild = element => child$1(element, 0);
|
1393 | const lastChild = element => child$1(element, element.dom.childNodes.length - 1);
|
1394 | const childNodesCount = element => element.dom.childNodes.length;
|
1395 | const hasChildNodes = element => element.dom.hasChildNodes();
|
1396 |
|
1397 | const getHead = doc => {
|
1398 | const b = doc.dom.head;
|
1399 | if (b === null || b === undefined) {
|
1400 | throw new Error('Head is not available yet');
|
1401 | }
|
1402 | return SugarElement.fromDom(b);
|
1403 | };
|
1404 |
|
1405 | const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
|
1406 | const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
|
1407 | const isSupported$1 = constant(supported);
|
1408 | const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
|
1409 | const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
|
1410 | const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
|
1411 | const getShadowRoot = e => {
|
1412 | const r = getRootNode(e);
|
1413 | return isShadowRoot(r) ? Optional.some(r) : Optional.none();
|
1414 | };
|
1415 | const getShadowHost = e => SugarElement.fromDom(e.dom.host);
|
1416 | const getOriginalEventTarget = event => {
|
1417 | if (isSupported$1() && isNonNullable(event.target)) {
|
1418 | const el = SugarElement.fromDom(event.target);
|
1419 | if (isElement$7(el) && isOpenShadowHost(el)) {
|
1420 | if (event.composed && event.composedPath) {
|
1421 | const composedPath = event.composedPath();
|
1422 | if (composedPath) {
|
1423 | return head(composedPath);
|
1424 | }
|
1425 | }
|
1426 | }
|
1427 | }
|
1428 | return Optional.from(event.target);
|
1429 | };
|
1430 | const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
|
1431 |
|
1432 | const inBody = element => {
|
1433 | const dom = isText$c(element) ? element.dom.parentNode : element.dom;
|
1434 | if (dom === undefined || dom === null || dom.ownerDocument === null) {
|
1435 | return false;
|
1436 | }
|
1437 | const doc = dom.ownerDocument;
|
1438 | return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
|
1439 | };
|
1440 |
|
1441 | var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
|
1442 | if (is(scope, a)) {
|
1443 | return Optional.some(scope);
|
1444 | } else if (isFunction(isRoot) && isRoot(scope)) {
|
1445 | return Optional.none();
|
1446 | } else {
|
1447 | return ancestor(scope, a, isRoot);
|
1448 | }
|
1449 | };
|
1450 |
|
1451 | const ancestor$4 = (scope, predicate, isRoot) => {
|
1452 | let element = scope.dom;
|
1453 | const stop = isFunction(isRoot) ? isRoot : never;
|
1454 | while (element.parentNode) {
|
1455 | element = element.parentNode;
|
1456 | const el = SugarElement.fromDom(element);
|
1457 | if (predicate(el)) {
|
1458 | return Optional.some(el);
|
1459 | } else if (stop(el)) {
|
1460 | break;
|
1461 | }
|
1462 | }
|
1463 | return Optional.none();
|
1464 | };
|
1465 | const closest$4 = (scope, predicate, isRoot) => {
|
1466 | const is = (s, test) => test(s);
|
1467 | return ClosestOrAncestor(is, ancestor$4, scope, predicate, isRoot);
|
1468 | };
|
1469 | const sibling$1 = (scope, predicate) => {
|
1470 | const element = scope.dom;
|
1471 | if (!element.parentNode) {
|
1472 | return Optional.none();
|
1473 | }
|
1474 | return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
|
1475 | };
|
1476 | const child = (scope, predicate) => {
|
1477 | const pred = node => predicate(SugarElement.fromDom(node));
|
1478 | const result = find$2(scope.dom.childNodes, pred);
|
1479 | return result.map(SugarElement.fromDom);
|
1480 | };
|
1481 | const descendant$2 = (scope, predicate) => {
|
1482 | const descend = node => {
|
1483 | for (let i = 0; i < node.childNodes.length; i++) {
|
1484 | const child = SugarElement.fromDom(node.childNodes[i]);
|
1485 | if (predicate(child)) {
|
1486 | return Optional.some(child);
|
1487 | }
|
1488 | const res = descend(node.childNodes[i]);
|
1489 | if (res.isSome()) {
|
1490 | return res;
|
1491 | }
|
1492 | }
|
1493 | return Optional.none();
|
1494 | };
|
1495 | return descend(scope.dom);
|
1496 | };
|
1497 |
|
1498 | const ancestor$3 = (scope, selector, isRoot) => ancestor$4(scope, e => is$1(e, selector), isRoot);
|
1499 | const descendant$1 = (scope, selector) => one(selector, scope);
|
1500 | const closest$3 = (scope, selector, isRoot) => {
|
1501 | const is = (element, selector) => is$1(element, selector);
|
1502 | return ClosestOrAncestor(is, ancestor$3, scope, selector, isRoot);
|
1503 | };
|
1504 |
|
1505 | const closest$2 = target => closest$3(target, '[contenteditable]');
|
1506 | const isEditable$2 = (element, assumeEditable = false) => {
|
1507 | if (inBody(element)) {
|
1508 | return element.dom.isContentEditable;
|
1509 | } else {
|
1510 | return closest$2(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
|
1511 | }
|
1512 | };
|
1513 | const getRaw$1 = element => element.dom.contentEditable;
|
1514 |
|
1515 | const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
|
1516 |
|
1517 | const internalSet = (dom, property, value) => {
|
1518 | if (!isString(value)) {
|
1519 | console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
|
1520 | throw new Error('CSS value must be a string: ' + value);
|
1521 | }
|
1522 | if (isSupported(dom)) {
|
1523 | dom.style.setProperty(property, value);
|
1524 | }
|
1525 | };
|
1526 | const internalRemove = (dom, property) => {
|
1527 | if (isSupported(dom)) {
|
1528 | dom.style.removeProperty(property);
|
1529 | }
|
1530 | };
|
1531 | const set$2 = (element, property, value) => {
|
1532 | const dom = element.dom;
|
1533 | internalSet(dom, property, value);
|
1534 | };
|
1535 | const setAll = (element, css) => {
|
1536 | const dom = element.dom;
|
1537 | each$d(css, (v, k) => {
|
1538 | internalSet(dom, k, v);
|
1539 | });
|
1540 | };
|
1541 | const get$7 = (element, property) => {
|
1542 | const dom = element.dom;
|
1543 | const styles = window.getComputedStyle(dom);
|
1544 | const r = styles.getPropertyValue(property);
|
1545 | return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
|
1546 | };
|
1547 | const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
|
1548 | const getRaw = (element, property) => {
|
1549 | const dom = element.dom;
|
1550 | const raw = getUnsafeProperty(dom, property);
|
1551 | return Optional.from(raw).filter(r => r.length > 0);
|
1552 | };
|
1553 | const getAllRaw = element => {
|
1554 | const css = {};
|
1555 | const dom = element.dom;
|
1556 | if (isSupported(dom)) {
|
1557 | for (let i = 0; i < dom.style.length; i++) {
|
1558 | const ruleName = dom.style.item(i);
|
1559 | css[ruleName] = dom.style[ruleName];
|
1560 | }
|
1561 | }
|
1562 | return css;
|
1563 | };
|
1564 | const remove$5 = (element, property) => {
|
1565 | const dom = element.dom;
|
1566 | internalRemove(dom, property);
|
1567 | if (is$2(getOpt(element, 'style').map(trim$4), '')) {
|
1568 | remove$9(element, 'style');
|
1569 | }
|
1570 | };
|
1571 | const reflow = e => e.dom.offsetWidth;
|
1572 |
|
1573 | const before$3 = (marker, element) => {
|
1574 | const parent$1 = parent(marker);
|
1575 | parent$1.each(v => {
|
1576 | v.dom.insertBefore(element.dom, marker.dom);
|
1577 | });
|
1578 | };
|
1579 | const after$4 = (marker, element) => {
|
1580 | const sibling = nextSibling(marker);
|
1581 | sibling.fold(() => {
|
1582 | const parent$1 = parent(marker);
|
1583 | parent$1.each(v => {
|
1584 | append$1(v, element);
|
1585 | });
|
1586 | }, v => {
|
1587 | before$3(v, element);
|
1588 | });
|
1589 | };
|
1590 | const prepend = (parent, element) => {
|
1591 | const firstChild$1 = firstChild(parent);
|
1592 | firstChild$1.fold(() => {
|
1593 | append$1(parent, element);
|
1594 | }, v => {
|
1595 | parent.dom.insertBefore(element.dom, v.dom);
|
1596 | });
|
1597 | };
|
1598 | const append$1 = (parent, element) => {
|
1599 | parent.dom.appendChild(element.dom);
|
1600 | };
|
1601 | const wrap$2 = (element, wrapper) => {
|
1602 | before$3(element, wrapper);
|
1603 | append$1(wrapper, element);
|
1604 | };
|
1605 |
|
1606 | const after$3 = (marker, elements) => {
|
1607 | each$e(elements, (x, i) => {
|
1608 | const e = i === 0 ? marker : elements[i - 1];
|
1609 | after$4(e, x);
|
1610 | });
|
1611 | };
|
1612 | const append = (parent, elements) => {
|
1613 | each$e(elements, x => {
|
1614 | append$1(parent, x);
|
1615 | });
|
1616 | };
|
1617 |
|
1618 | const empty = element => {
|
1619 | element.dom.textContent = '';
|
1620 | each$e(children$1(element), rogue => {
|
1621 | remove$4(rogue);
|
1622 | });
|
1623 | };
|
1624 | const remove$4 = element => {
|
1625 | const dom = element.dom;
|
1626 | if (dom.parentNode !== null) {
|
1627 | dom.parentNode.removeChild(dom);
|
1628 | }
|
1629 | };
|
1630 | const unwrap = wrapper => {
|
1631 | const children = children$1(wrapper);
|
1632 | if (children.length > 0) {
|
1633 | after$3(wrapper, children);
|
1634 | }
|
1635 | remove$4(wrapper);
|
1636 | };
|
1637 |
|
1638 | const fromHtml = (html, scope) => {
|
1639 | const doc = scope || document;
|
1640 | const div = doc.createElement('div');
|
1641 | div.innerHTML = html;
|
1642 | return children$1(SugarElement.fromDom(div));
|
1643 | };
|
1644 | const fromDom$1 = nodes => map$3(nodes, SugarElement.fromDom);
|
1645 |
|
1646 | const get$6 = element => element.dom.innerHTML;
|
1647 | const set$1 = (element, content) => {
|
1648 | const owner = owner$1(element);
|
1649 | const docDom = owner.dom;
|
1650 | const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
|
1651 | const contentElements = fromHtml(content, docDom);
|
1652 | append(fragment, contentElements);
|
1653 | empty(element);
|
1654 | append$1(element, fragment);
|
1655 | };
|
1656 | const getOuter = element => {
|
1657 | const container = SugarElement.fromTag('div');
|
1658 | const clone = SugarElement.fromDom(element.dom.cloneNode(true));
|
1659 | append$1(container, clone);
|
1660 | return get$6(container);
|
1661 | };
|
1662 |
|
1663 | const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
|
1664 | target,
|
1665 | x,
|
1666 | y,
|
1667 | stop,
|
1668 | prevent,
|
1669 | kill,
|
1670 | raw
|
1671 | });
|
1672 | const fromRawEvent = rawEvent => {
|
1673 | const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
|
1674 | const stop = () => rawEvent.stopPropagation();
|
1675 | const prevent = () => rawEvent.preventDefault();
|
1676 | const kill = compose(prevent, stop);
|
1677 | return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
|
1678 | };
|
1679 | const handle$1 = (filter, handler) => rawEvent => {
|
1680 | if (filter(rawEvent)) {
|
1681 | handler(fromRawEvent(rawEvent));
|
1682 | }
|
1683 | };
|
1684 | const binder = (element, event, filter, handler, useCapture) => {
|
1685 | const wrapped = handle$1(filter, handler);
|
1686 | element.dom.addEventListener(event, wrapped, useCapture);
|
1687 | return { unbind: curry(unbind, element, event, wrapped, useCapture) };
|
1688 | };
|
1689 | const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
|
1690 | const unbind = (element, event, handler, useCapture) => {
|
1691 | element.dom.removeEventListener(event, handler, useCapture);
|
1692 | };
|
1693 |
|
1694 | const r = (left, top) => {
|
1695 | const translate = (x, y) => r(left + x, top + y);
|
1696 | return {
|
1697 | left,
|
1698 | top,
|
1699 | translate
|
1700 | };
|
1701 | };
|
1702 | const SugarPosition = r;
|
1703 |
|
1704 | const boxPosition = dom => {
|
1705 | const box = dom.getBoundingClientRect();
|
1706 | return SugarPosition(box.left, box.top);
|
1707 | };
|
1708 | const firstDefinedOrZero = (a, b) => {
|
1709 | if (a !== undefined) {
|
1710 | return a;
|
1711 | } else {
|
1712 | return b !== undefined ? b : 0;
|
1713 | }
|
1714 | };
|
1715 | const absolute = element => {
|
1716 | const doc = element.dom.ownerDocument;
|
1717 | const body = doc.body;
|
1718 | const win = doc.defaultView;
|
1719 | const html = doc.documentElement;
|
1720 | if (body === element.dom) {
|
1721 | return SugarPosition(body.offsetLeft, body.offsetTop);
|
1722 | }
|
1723 | const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
|
1724 | const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
|
1725 | const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
|
1726 | const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
|
1727 | return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
|
1728 | };
|
1729 | const viewport = element => {
|
1730 | const dom = element.dom;
|
1731 | const doc = dom.ownerDocument;
|
1732 | const body = doc.body;
|
1733 | if (body === dom) {
|
1734 | return SugarPosition(body.offsetLeft, body.offsetTop);
|
1735 | }
|
1736 | if (!inBody(element)) {
|
1737 | return SugarPosition(0, 0);
|
1738 | }
|
1739 | return boxPosition(dom);
|
1740 | };
|
1741 |
|
1742 | const get$5 = _DOC => {
|
1743 | const doc = _DOC !== undefined ? _DOC.dom : document;
|
1744 | const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
|
1745 | const y = doc.body.scrollTop || doc.documentElement.scrollTop;
|
1746 | return SugarPosition(x, y);
|
1747 | };
|
1748 | const to = (x, y, _DOC) => {
|
1749 | const doc = _DOC !== undefined ? _DOC.dom : document;
|
1750 | const win = doc.defaultView;
|
1751 | if (win) {
|
1752 | win.scrollTo(x, y);
|
1753 | }
|
1754 | };
|
1755 | const intoView = (element, alignToTop) => {
|
1756 | const isSafari = detect$1().browser.isSafari();
|
1757 | if (isSafari && isFunction(element.dom.scrollIntoViewIfNeeded)) {
|
1758 | element.dom.scrollIntoViewIfNeeded(false);
|
1759 | } else {
|
1760 | element.dom.scrollIntoView(alignToTop);
|
1761 | }
|
1762 | };
|
1763 |
|
1764 | const get$4 = _win => {
|
1765 | const win = _win === undefined ? window : _win;
|
1766 | if (detect$1().browser.isFirefox()) {
|
1767 | return Optional.none();
|
1768 | } else {
|
1769 | return Optional.from(win.visualViewport);
|
1770 | }
|
1771 | };
|
1772 | const bounds = (x, y, width, height) => ({
|
1773 | x,
|
1774 | y,
|
1775 | width,
|
1776 | height,
|
1777 | right: x + width,
|
1778 | bottom: y + height
|
1779 | });
|
1780 | const getBounds = _win => {
|
1781 | const win = _win === undefined ? window : _win;
|
1782 | const doc = win.document;
|
1783 | const scroll = get$5(SugarElement.fromDom(doc));
|
1784 | return get$4(win).fold(() => {
|
1785 | const html = win.document.documentElement;
|
1786 | const width = html.clientWidth;
|
1787 | const height = html.clientHeight;
|
1788 | return bounds(scroll.left, scroll.top, width, height);
|
1789 | }, visualViewport => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
|
1790 | };
|
1791 |
|
1792 | const children = (scope, predicate) => filter$5(children$1(scope), predicate);
|
1793 | const descendants$1 = (scope, predicate) => {
|
1794 | let result = [];
|
1795 | each$e(children$1(scope), x => {
|
1796 | if (predicate(x)) {
|
1797 | result = result.concat([x]);
|
1798 | }
|
1799 | result = result.concat(descendants$1(x, predicate));
|
1800 | });
|
1801 | return result;
|
1802 | };
|
1803 |
|
1804 | const descendants = (scope, selector) => all(selector, scope);
|
1805 |
|
1806 | const ancestor$2 = (scope, predicate, isRoot) => ancestor$4(scope, predicate, isRoot).isSome();
|
1807 | const sibling = (scope, predicate) => sibling$1(scope, predicate).isSome();
|
1808 | const descendant = (scope, predicate) => descendant$2(scope, predicate).isSome();
|
1809 |
|
1810 | class DomTreeWalker {
|
1811 | constructor(startNode, rootNode) {
|
1812 | this.node = startNode;
|
1813 | this.rootNode = rootNode;
|
1814 | this.current = this.current.bind(this);
|
1815 | this.next = this.next.bind(this);
|
1816 | this.prev = this.prev.bind(this);
|
1817 | this.prev2 = this.prev2.bind(this);
|
1818 | }
|
1819 | current() {
|
1820 | return this.node;
|
1821 | }
|
1822 | next(shallow) {
|
1823 | this.node = this.findSibling(this.node, 'firstChild', 'nextSibling', shallow);
|
1824 | return this.node;
|
1825 | }
|
1826 | prev(shallow) {
|
1827 | this.node = this.findSibling(this.node, 'lastChild', 'previousSibling', shallow);
|
1828 | return this.node;
|
1829 | }
|
1830 | prev2(shallow) {
|
1831 | this.node = this.findPreviousNode(this.node, shallow);
|
1832 | return this.node;
|
1833 | }
|
1834 | findSibling(node, startName, siblingName, shallow) {
|
1835 | if (node) {
|
1836 | if (!shallow && node[startName]) {
|
1837 | return node[startName];
|
1838 | }
|
1839 | if (node !== this.rootNode) {
|
1840 | let sibling = node[siblingName];
|
1841 | if (sibling) {
|
1842 | return sibling;
|
1843 | }
|
1844 | for (let parent = node.parentNode; parent && parent !== this.rootNode; parent = parent.parentNode) {
|
1845 | sibling = parent[siblingName];
|
1846 | if (sibling) {
|
1847 | return sibling;
|
1848 | }
|
1849 | }
|
1850 | }
|
1851 | }
|
1852 | return undefined;
|
1853 | }
|
1854 | findPreviousNode(node, shallow) {
|
1855 | if (node) {
|
1856 | const sibling = node.previousSibling;
|
1857 | if (this.rootNode && sibling === this.rootNode) {
|
1858 | return;
|
1859 | }
|
1860 | if (sibling) {
|
1861 | if (!shallow) {
|
1862 | for (let child = sibling.lastChild; child; child = child.lastChild) {
|
1863 | if (!child.lastChild) {
|
1864 | return child;
|
1865 | }
|
1866 | }
|
1867 | }
|
1868 | return sibling;
|
1869 | }
|
1870 | const parent = node.parentNode;
|
1871 | if (parent && parent !== this.rootNode) {
|
1872 | return parent;
|
1873 | }
|
1874 | }
|
1875 | return undefined;
|
1876 | }
|
1877 | }
|
1878 |
|
1879 | const zeroWidth = '\uFEFF';
|
1880 | const nbsp = '\xA0';
|
1881 | const isZwsp$2 = char => char === zeroWidth;
|
1882 | const removeZwsp = s => s.replace(/\uFEFF/g, '');
|
1883 |
|
1884 | const whiteSpaceRegExp = /^[ \t\r\n]*$/;
|
1885 | const isWhitespaceText = text => whiteSpaceRegExp.test(text);
|
1886 | const isZwsp$1 = text => {
|
1887 | for (const c of text) {
|
1888 | if (!isZwsp$2(c)) {
|
1889 | return false;
|
1890 | }
|
1891 | }
|
1892 | return true;
|
1893 | };
|
1894 | const isCollapsibleWhitespace$1 = c => ' \f\t\x0B'.indexOf(c) !== -1;
|
1895 | const isNewLineChar = c => c === '\n' || c === '\r';
|
1896 | const isNewline = (text, idx) => idx < text.length && idx >= 0 ? isNewLineChar(text[idx]) : false;
|
1897 | const normalize$4 = (text, tabSpaces = 4, isStartOfContent = true, isEndOfContent = true) => {
|
1898 | const tabSpace = repeat(' ', tabSpaces);
|
1899 | const normalizedText = text.replace(/\t/g, tabSpace);
|
1900 | const result = foldl(normalizedText, (acc, c) => {
|
1901 | if (isCollapsibleWhitespace$1(c) || c === nbsp) {
|
1902 | if (acc.pcIsSpace || acc.str === '' && isStartOfContent || acc.str.length === normalizedText.length - 1 && isEndOfContent || isNewline(normalizedText, acc.str.length + 1)) {
|
1903 | return {
|
1904 | pcIsSpace: false,
|
1905 | str: acc.str + nbsp
|
1906 | };
|
1907 | } else {
|
1908 | return {
|
1909 | pcIsSpace: true,
|
1910 | str: acc.str + ' '
|
1911 | };
|
1912 | }
|
1913 | } else {
|
1914 | return {
|
1915 | pcIsSpace: isNewLineChar(c),
|
1916 | str: acc.str + c
|
1917 | };
|
1918 | }
|
1919 | }, {
|
1920 | pcIsSpace: false,
|
1921 | str: ''
|
1922 | });
|
1923 | return result.str;
|
1924 | };
|
1925 |
|
1926 | const isNodeType = type => {
|
1927 | return node => {
|
1928 | return !!node && node.nodeType === type;
|
1929 | };
|
1930 | };
|
1931 | const isRestrictedNode = node => !!node && !Object.getPrototypeOf(node);
|
1932 | const isElement$6 = isNodeType(1);
|
1933 | const isHTMLElement = node => isElement$6(node) && isHTMLElement$1(SugarElement.fromDom(node));
|
1934 | const isSVGElement = node => isElement$6(node) && node.namespaceURI === 'http://www.w3.org/2000/svg';
|
1935 | const matchNodeName = name => {
|
1936 | const lowerCasedName = name.toLowerCase();
|
1937 | return node => isNonNullable(node) && node.nodeName.toLowerCase() === lowerCasedName;
|
1938 | };
|
1939 | const matchNodeNames = names => {
|
1940 | const lowerCasedNames = names.map(s => s.toLowerCase());
|
1941 | return node => {
|
1942 | if (node && node.nodeName) {
|
1943 | const nodeName = node.nodeName.toLowerCase();
|
1944 | return contains$2(lowerCasedNames, nodeName);
|
1945 | }
|
1946 | return false;
|
1947 | };
|
1948 | };
|
1949 | const matchStyleValues = (name, values) => {
|
1950 | const items = values.toLowerCase().split(' ');
|
1951 | return node => {
|
1952 | if (isElement$6(node)) {
|
1953 | const win = node.ownerDocument.defaultView;
|
1954 | if (win) {
|
1955 | for (let i = 0; i < items.length; i++) {
|
1956 | const computed = win.getComputedStyle(node, null);
|
1957 | const cssValue = computed ? computed.getPropertyValue(name) : null;
|
1958 | if (cssValue === items[i]) {
|
1959 | return true;
|
1960 | }
|
1961 | }
|
1962 | }
|
1963 | }
|
1964 | return false;
|
1965 | };
|
1966 | };
|
1967 | const hasAttribute = attrName => {
|
1968 | return node => {
|
1969 | return isElement$6(node) && node.hasAttribute(attrName);
|
1970 | };
|
1971 | };
|
1972 | const isBogus$1 = node => isElement$6(node) && node.hasAttribute('data-mce-bogus');
|
1973 | const isBogusAll = node => isElement$6(node) && node.getAttribute('data-mce-bogus') === 'all';
|
1974 | const isTable$2 = node => isElement$6(node) && node.tagName === 'TABLE';
|
1975 | const hasContentEditableState = value => {
|
1976 | return node => {
|
1977 | if (isHTMLElement(node)) {
|
1978 | if (node.contentEditable === value) {
|
1979 | return true;
|
1980 | }
|
1981 | if (node.getAttribute('data-mce-contenteditable') === value) {
|
1982 | return true;
|
1983 | }
|
1984 | }
|
1985 | return false;
|
1986 | };
|
1987 | };
|
1988 | const isTextareaOrInput = matchNodeNames([
|
1989 | 'textarea',
|
1990 | 'input'
|
1991 | ]);
|
1992 | const isText$b = isNodeType(3);
|
1993 | const isCData = isNodeType(4);
|
1994 | const isPi = isNodeType(7);
|
1995 | const isComment = isNodeType(8);
|
1996 | const isDocument$1 = isNodeType(9);
|
1997 | const isDocumentFragment = isNodeType(11);
|
1998 | const isBr$6 = matchNodeName('br');
|
1999 | const isImg = matchNodeName('img');
|
2000 | const isContentEditableTrue$3 = hasContentEditableState('true');
|
2001 | const isContentEditableFalse$b = hasContentEditableState('false');
|
2002 | const isTableCell$3 = matchNodeNames([
|
2003 | 'td',
|
2004 | 'th'
|
2005 | ]);
|
2006 | const isTableCellOrCaption = matchNodeNames([
|
2007 | 'td',
|
2008 | 'th',
|
2009 | 'caption'
|
2010 | ]);
|
2011 | const isMedia$2 = matchNodeNames([
|
2012 | 'video',
|
2013 | 'audio',
|
2014 | 'object',
|
2015 | 'embed'
|
2016 | ]);
|
2017 | const isListItem$2 = matchNodeName('li');
|
2018 | const isDetails = matchNodeName('details');
|
2019 | const isSummary$1 = matchNodeName('summary');
|
2020 |
|
2021 | const defaultOptionValues = {
|
2022 | skipBogus: true,
|
2023 | includeZwsp: false,
|
2024 | checkRootAsContent: false
|
2025 | };
|
2026 | const hasWhitespacePreserveParent = (node, rootNode, schema) => {
|
2027 | const rootElement = SugarElement.fromDom(rootNode);
|
2028 | const startNode = SugarElement.fromDom(node);
|
2029 | const whitespaceElements = schema.getWhitespaceElements();
|
2030 | const predicate = node => has$2(whitespaceElements, name(node));
|
2031 | return ancestor$2(startNode, predicate, curry(eq, rootElement));
|
2032 | };
|
2033 | const isNamedAnchor = node => {
|
2034 | return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id'));
|
2035 | };
|
2036 | const isNonEmptyElement$1 = (node, schema) => {
|
2037 | return isElement$6(node) && has$2(schema.getNonEmptyElements(), node.nodeName);
|
2038 | };
|
2039 | const isBookmark = hasAttribute('data-mce-bookmark');
|
2040 | const hasNonEditableParent = node => parentElement(SugarElement.fromDom(node)).exists(parent => !isEditable$2(parent));
|
2041 | const isWhitespace$1 = (node, rootNode, schema) => isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode, schema);
|
2042 | const isText$a = (node, rootNode, schema, options) => isText$b(node) && !isWhitespace$1(node, rootNode, schema) && (!options.includeZwsp || !isZwsp$1(node.data));
|
2043 | const isContentNode = (schema, node, rootNode, options) => {
|
2044 | return isFunction(options.isContent) && options.isContent(node) || isNonEmptyElement$1(node, schema) || isBookmark(node) || isNamedAnchor(node) || isText$a(node, rootNode, schema, options) || isContentEditableFalse$b(node) || isContentEditableTrue$3(node) && hasNonEditableParent(node);
|
2045 | };
|
2046 | const isEmptyNode = (schema, targetNode, opts) => {
|
2047 | const options = {
|
2048 | ...defaultOptionValues,
|
2049 | ...opts
|
2050 | };
|
2051 | if (options.checkRootAsContent) {
|
2052 | if (isContentNode(schema, targetNode, targetNode, options)) {
|
2053 | return false;
|
2054 | }
|
2055 | }
|
2056 | let node = targetNode.firstChild;
|
2057 | let brCount = 0;
|
2058 | if (!node) {
|
2059 | return true;
|
2060 | }
|
2061 | const walker = new DomTreeWalker(node, targetNode);
|
2062 | do {
|
2063 | if (options.skipBogus && isElement$6(node)) {
|
2064 | const bogusValue = node.getAttribute('data-mce-bogus');
|
2065 | if (bogusValue) {
|
2066 | node = walker.next(bogusValue === 'all');
|
2067 | continue;
|
2068 | }
|
2069 | }
|
2070 | if (isComment(node)) {
|
2071 | node = walker.next(true);
|
2072 | continue;
|
2073 | }
|
2074 | if (isBr$6(node)) {
|
2075 | brCount++;
|
2076 | node = walker.next();
|
2077 | continue;
|
2078 | }
|
2079 | if (isContentNode(schema, node, targetNode, options)) {
|
2080 | return false;
|
2081 | }
|
2082 | node = walker.next();
|
2083 | } while (node);
|
2084 | return brCount <= 1;
|
2085 | };
|
2086 | const isEmpty$2 = (schema, elm, options) => {
|
2087 | return isEmptyNode(schema, elm.dom, {
|
2088 | checkRootAsContent: true,
|
2089 | ...options
|
2090 | });
|
2091 | };
|
2092 | const isContent$1 = (schema, node, options) => {
|
2093 | return isContentNode(schema, node, node, {
|
2094 | includeZwsp: defaultOptionValues.includeZwsp,
|
2095 | ...options
|
2096 | });
|
2097 | };
|
2098 |
|
2099 | const Cell = initial => {
|
2100 | let value = initial;
|
2101 | const get = () => {
|
2102 | return value;
|
2103 | };
|
2104 | const set = v => {
|
2105 | value = v;
|
2106 | };
|
2107 | return {
|
2108 | get,
|
2109 | set
|
2110 | };
|
2111 | };
|
2112 |
|
2113 | const singleton = doRevoke => {
|
2114 | const subject = Cell(Optional.none());
|
2115 | const revoke = () => subject.get().each(doRevoke);
|
2116 | const clear = () => {
|
2117 | revoke();
|
2118 | subject.set(Optional.none());
|
2119 | };
|
2120 | const isSet = () => subject.get().isSome();
|
2121 | const get = () => subject.get();
|
2122 | const set = s => {
|
2123 | revoke();
|
2124 | subject.set(Optional.some(s));
|
2125 | };
|
2126 | return {
|
2127 | clear,
|
2128 | isSet,
|
2129 | get,
|
2130 | set
|
2131 | };
|
2132 | };
|
2133 | const repeatable = delay => {
|
2134 | const intervalId = Cell(Optional.none());
|
2135 | const revoke = () => intervalId.get().each(id => clearInterval(id));
|
2136 | const clear = () => {
|
2137 | revoke();
|
2138 | intervalId.set(Optional.none());
|
2139 | };
|
2140 | const isSet = () => intervalId.get().isSome();
|
2141 | const get = () => intervalId.get();
|
2142 | const set = functionToRepeat => {
|
2143 | revoke();
|
2144 | intervalId.set(Optional.some(setInterval(functionToRepeat, delay)));
|
2145 | };
|
2146 | return {
|
2147 | clear,
|
2148 | isSet,
|
2149 | get,
|
2150 | set
|
2151 | };
|
2152 | };
|
2153 | const value$2 = () => {
|
2154 | const subject = singleton(noop);
|
2155 | const on = f => subject.get().each(f);
|
2156 | return {
|
2157 | ...subject,
|
2158 | on
|
2159 | };
|
2160 | };
|
2161 |
|
2162 | const nodeNameToNamespaceType = name => {
|
2163 | const lowerCaseName = name.toLowerCase();
|
2164 | if (lowerCaseName === 'svg') {
|
2165 | return 'svg';
|
2166 | } else if (lowerCaseName === 'math') {
|
2167 | return 'math';
|
2168 | } else {
|
2169 | return 'html';
|
2170 | }
|
2171 | };
|
2172 | const isNonHtmlElementRootName = name => nodeNameToNamespaceType(name) !== 'html';
|
2173 | const isNonHtmlElementRoot = node => isNonHtmlElementRootName(node.nodeName);
|
2174 | const toScopeType = node => nodeNameToNamespaceType(node.nodeName);
|
2175 | const namespaceElements = [
|
2176 | 'svg',
|
2177 | 'math'
|
2178 | ];
|
2179 | const createNamespaceTracker = () => {
|
2180 | const currentScope = value$2();
|
2181 | const current = () => currentScope.get().map(toScopeType).getOr('html');
|
2182 | const track = node => {
|
2183 | if (isNonHtmlElementRoot(node)) {
|
2184 | currentScope.set(node);
|
2185 | } else if (currentScope.get().exists(scopeNode => !scopeNode.contains(node))) {
|
2186 | currentScope.clear();
|
2187 | }
|
2188 | return current();
|
2189 | };
|
2190 | const reset = () => {
|
2191 | currentScope.clear();
|
2192 | };
|
2193 | return {
|
2194 | track,
|
2195 | current,
|
2196 | reset
|
2197 | };
|
2198 | };
|
2199 |
|
2200 | const transparentBlockAttr = 'data-mce-block';
|
2201 | const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key));
|
2202 | const makeSelectorFromSchemaMap = map => map$3(elementNames(map), name => {
|
2203 | const escapedName = CSS.escape(name);
|
2204 | return `${ escapedName }:` + map$3(namespaceElements, ns => `not(${ ns } ${ escapedName })`).join(':');
|
2205 | }).join(',');
|
2206 | const updateTransparent = (blocksSelector, transparent) => {
|
2207 | if (isNonNullable(transparent.querySelector(blocksSelector))) {
|
2208 | transparent.setAttribute(transparentBlockAttr, 'true');
|
2209 | if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') {
|
2210 | transparent.removeAttribute('data-mce-selected');
|
2211 | }
|
2212 | return true;
|
2213 | } else {
|
2214 | transparent.removeAttribute(transparentBlockAttr);
|
2215 | return false;
|
2216 | }
|
2217 | };
|
2218 | const updateBlockStateOnChildren = (schema, scope) => {
|
2219 | const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements());
|
2220 | const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
|
2221 | return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent));
|
2222 | };
|
2223 | const trimEdge = (schema, el, leftSide) => {
|
2224 | var _a;
|
2225 | const childPropertyName = leftSide ? 'lastChild' : 'firstChild';
|
2226 | for (let child = el[childPropertyName]; child; child = child[childPropertyName]) {
|
2227 | if (isEmptyNode(schema, child, { checkRootAsContent: true })) {
|
2228 | (_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
|
2229 | return;
|
2230 | }
|
2231 | }
|
2232 | };
|
2233 | const split$2 = (schema, parentElm, splitElm) => {
|
2234 | const range = document.createRange();
|
2235 | const parentNode = parentElm.parentNode;
|
2236 | if (parentNode) {
|
2237 | range.setStartBefore(parentElm);
|
2238 | range.setEndBefore(splitElm);
|
2239 | const beforeFragment = range.extractContents();
|
2240 | trimEdge(schema, beforeFragment, true);
|
2241 | range.setStartAfter(splitElm);
|
2242 | range.setEndAfter(parentElm);
|
2243 | const afterFragment = range.extractContents();
|
2244 | trimEdge(schema, afterFragment, false);
|
2245 | if (!isEmptyNode(schema, beforeFragment, { checkRootAsContent: true })) {
|
2246 | parentNode.insertBefore(beforeFragment, parentElm);
|
2247 | }
|
2248 | if (!isEmptyNode(schema, splitElm, { checkRootAsContent: true })) {
|
2249 | parentNode.insertBefore(splitElm, parentElm);
|
2250 | }
|
2251 | if (!isEmptyNode(schema, afterFragment, { checkRootAsContent: true })) {
|
2252 | parentNode.insertBefore(afterFragment, parentElm);
|
2253 | }
|
2254 | parentNode.removeChild(parentElm);
|
2255 | }
|
2256 | };
|
2257 | const splitInvalidChildren = (schema, scope, transparentBlocks) => {
|
2258 | const blocksElements = schema.getBlockElements();
|
2259 | const rootNode = SugarElement.fromDom(scope);
|
2260 | const isBlock = el => name(el) in blocksElements;
|
2261 | const isRoot = el => eq(el, rootNode);
|
2262 | each$e(fromDom$1(transparentBlocks), transparentBlock => {
|
2263 | ancestor$4(transparentBlock, isBlock, isRoot).each(parentBlock => {
|
2264 | const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
|
2265 | if (invalidChildren.length > 0) {
|
2266 | const stateScope = parentElement(parentBlock);
|
2267 | each$e(invalidChildren, child => {
|
2268 | ancestor$4(child, isBlock, isRoot).each(parentBlock => {
|
2269 | split$2(schema, parentBlock.dom, child.dom);
|
2270 | });
|
2271 | });
|
2272 | stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom));
|
2273 | }
|
2274 | });
|
2275 | });
|
2276 | };
|
2277 | const unwrapInvalidChildren = (schema, scope, transparentBlocks) => {
|
2278 | each$e([
|
2279 | ...transparentBlocks,
|
2280 | ...isTransparentBlock(schema, scope) ? [scope] : []
|
2281 | ], block => each$e(descendants(SugarElement.fromDom(block), block.nodeName.toLowerCase()), elm => {
|
2282 | if (isTransparentInline(schema, elm.dom)) {
|
2283 | unwrap(elm);
|
2284 | }
|
2285 | }));
|
2286 | };
|
2287 | const updateChildren = (schema, scope) => {
|
2288 | const transparentBlocks = updateBlockStateOnChildren(schema, scope);
|
2289 | splitInvalidChildren(schema, scope, transparentBlocks);
|
2290 | unwrapInvalidChildren(schema, scope, transparentBlocks);
|
2291 | };
|
2292 | const updateElement = (schema, target) => {
|
2293 | if (isTransparentElement(schema, target)) {
|
2294 | const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
|
2295 | updateTransparent(blocksSelector, target);
|
2296 | }
|
2297 | };
|
2298 | const updateCaret = (schema, root, caretParent) => {
|
2299 | const isRoot = el => eq(el, SugarElement.fromDom(root));
|
2300 | const parents = parents$1(SugarElement.fromDom(caretParent), isRoot);
|
2301 | get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom));
|
2302 | };
|
2303 | const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr);
|
2304 | const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name);
|
2305 | const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName);
|
2306 | const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node);
|
2307 | const isTransparentInline = (schema, node) => isTransparentElement(schema, node) && !hasBlockAttr(node);
|
2308 | const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr));
|
2309 |
|
2310 | const browser$2 = detect$1().browser;
|
2311 | const firstElement = nodes => find$2(nodes, isElement$7);
|
2312 | const getTableCaptionDeltaY = elm => {
|
2313 | if (browser$2.isFirefox() && name(elm) === 'table') {
|
2314 | return firstElement(children$1(elm)).filter(elm => {
|
2315 | return name(elm) === 'caption';
|
2316 | }).bind(caption => {
|
2317 | return firstElement(nextSiblings(caption)).map(body => {
|
2318 | const bodyTop = body.dom.offsetTop;
|
2319 | const captionTop = caption.dom.offsetTop;
|
2320 | const captionHeight = caption.dom.offsetHeight;
|
2321 | return bodyTop <= captionTop ? -captionHeight : 0;
|
2322 | });
|
2323 | }).getOr(0);
|
2324 | } else {
|
2325 | return 0;
|
2326 | }
|
2327 | };
|
2328 | const hasChild = (elm, child) => elm.children && contains$2(elm.children, child);
|
2329 | const getPos = (body, elm, rootElm) => {
|
2330 | let x = 0, y = 0;
|
2331 | const doc = body.ownerDocument;
|
2332 | rootElm = rootElm ? rootElm : body;
|
2333 | if (elm) {
|
2334 | if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') {
|
2335 | const pos = elm.getBoundingClientRect();
|
2336 | x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
|
2337 | y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
|
2338 | return {
|
2339 | x,
|
2340 | y
|
2341 | };
|
2342 | }
|
2343 | let offsetParent = elm;
|
2344 | while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
|
2345 | const castOffsetParent = offsetParent;
|
2346 | x += castOffsetParent.offsetLeft || 0;
|
2347 | y += castOffsetParent.offsetTop || 0;
|
2348 | offsetParent = castOffsetParent.offsetParent;
|
2349 | }
|
2350 | offsetParent = elm.parentNode;
|
2351 | while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
|
2352 | x -= offsetParent.scrollLeft || 0;
|
2353 | y -= offsetParent.scrollTop || 0;
|
2354 | offsetParent = offsetParent.parentNode;
|
2355 | }
|
2356 | y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
|
2357 | }
|
2358 | return {
|
2359 | x,
|
2360 | y
|
2361 | };
|
2362 | };
|
2363 |
|
2364 | const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
|
2365 | let idCount = 0;
|
2366 | const loadedStates = {};
|
2367 | const edos = SugarElement.fromDom(documentOrShadowRoot);
|
2368 | const doc = documentOrOwner(edos);
|
2369 | const _setReferrerPolicy = referrerPolicy => {
|
2370 | settings.referrerPolicy = referrerPolicy;
|
2371 | };
|
2372 | const _setContentCssCors = contentCssCors => {
|
2373 | settings.contentCssCors = contentCssCors;
|
2374 | };
|
2375 | const addStyle = element => {
|
2376 | append$1(getStyleContainer(edos), element);
|
2377 | };
|
2378 | const removeStyle = id => {
|
2379 | const styleContainer = getStyleContainer(edos);
|
2380 | descendant$1(styleContainer, '#' + id).each(remove$4);
|
2381 | };
|
2382 | const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({
|
2383 | id: 'mce-u' + idCount++,
|
2384 | passed: [],
|
2385 | failed: [],
|
2386 | count: 0
|
2387 | }));
|
2388 | const load = url => new Promise((success, failure) => {
|
2389 | let link;
|
2390 | const urlWithSuffix = Tools._addCacheSuffix(url);
|
2391 | const state = getOrCreateState(urlWithSuffix);
|
2392 | loadedStates[urlWithSuffix] = state;
|
2393 | state.count++;
|
2394 | const resolve = (callbacks, status) => {
|
2395 | each$e(callbacks, call);
|
2396 | state.status = status;
|
2397 | state.passed = [];
|
2398 | state.failed = [];
|
2399 | if (link) {
|
2400 | link.onload = null;
|
2401 | link.onerror = null;
|
2402 | link = null;
|
2403 | }
|
2404 | };
|
2405 | const passed = () => resolve(state.passed, 2);
|
2406 | const failed = () => resolve(state.failed, 3);
|
2407 | if (success) {
|
2408 | state.passed.push(success);
|
2409 | }
|
2410 | if (failure) {
|
2411 | state.failed.push(failure);
|
2412 | }
|
2413 | if (state.status === 1) {
|
2414 | return;
|
2415 | }
|
2416 | if (state.status === 2) {
|
2417 | passed();
|
2418 | return;
|
2419 | }
|
2420 | if (state.status === 3) {
|
2421 | failed();
|
2422 | return;
|
2423 | }
|
2424 | state.status = 1;
|
2425 | const linkElem = SugarElement.fromTag('link', doc.dom);
|
2426 | setAll$1(linkElem, {
|
2427 | rel: 'stylesheet',
|
2428 | type: 'text/css',
|
2429 | id: state.id
|
2430 | });
|
2431 | if (settings.contentCssCors) {
|
2432 | set$3(linkElem, 'crossOrigin', 'anonymous');
|
2433 | }
|
2434 | if (settings.referrerPolicy) {
|
2435 | set$3(linkElem, 'referrerpolicy', settings.referrerPolicy);
|
2436 | }
|
2437 | link = linkElem.dom;
|
2438 | link.onload = passed;
|
2439 | link.onerror = failed;
|
2440 | addStyle(linkElem);
|
2441 | set$3(linkElem, 'href', urlWithSuffix);
|
2442 | });
|
2443 | const loadRawCss = (key, css) => {
|
2444 | const state = getOrCreateState(key);
|
2445 | loadedStates[key] = state;
|
2446 | state.count++;
|
2447 | const styleElem = SugarElement.fromTag('style', doc.dom);
|
2448 | setAll$1(styleElem, {
|
2449 | rel: 'stylesheet',
|
2450 | type: 'text/css',
|
2451 | id: state.id
|
2452 | });
|
2453 | styleElem.dom.innerHTML = css;
|
2454 | addStyle(styleElem);
|
2455 | };
|
2456 | const loadAll = urls => {
|
2457 | const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url))));
|
2458 | return loadedUrls.then(results => {
|
2459 | const parts = partition$2(results, r => r.status === 'fulfilled');
|
2460 | if (parts.fail.length > 0) {
|
2461 | return Promise.reject(map$3(parts.fail, result => result.reason));
|
2462 | } else {
|
2463 | return map$3(parts.pass, result => result.value);
|
2464 | }
|
2465 | });
|
2466 | };
|
2467 | const unload = url => {
|
2468 | const urlWithSuffix = Tools._addCacheSuffix(url);
|
2469 | get$a(loadedStates, urlWithSuffix).each(state => {
|
2470 | const count = --state.count;
|
2471 | if (count === 0) {
|
2472 | delete loadedStates[urlWithSuffix];
|
2473 | removeStyle(state.id);
|
2474 | }
|
2475 | });
|
2476 | };
|
2477 | const unloadRawCss = key => {
|
2478 | get$a(loadedStates, key).each(state => {
|
2479 | const count = --state.count;
|
2480 | if (count === 0) {
|
2481 | delete loadedStates[key];
|
2482 | removeStyle(state.id);
|
2483 | }
|
2484 | });
|
2485 | };
|
2486 | const unloadAll = urls => {
|
2487 | each$e(urls, url => {
|
2488 | unload(url);
|
2489 | });
|
2490 | };
|
2491 | return {
|
2492 | load,
|
2493 | loadRawCss,
|
2494 | loadAll,
|
2495 | unload,
|
2496 | unloadRawCss,
|
2497 | unloadAll,
|
2498 | _setReferrerPolicy,
|
2499 | _setContentCssCors
|
2500 | };
|
2501 | };
|
2502 |
|
2503 | const create$c = () => {
|
2504 | const map = new WeakMap();
|
2505 | const forElement = (referenceElement, settings) => {
|
2506 | const root = getRootNode(referenceElement);
|
2507 | const rootDom = root.dom;
|
2508 | return Optional.from(map.get(rootDom)).getOrThunk(() => {
|
2509 | const sl = StyleSheetLoader(rootDom, settings);
|
2510 | map.set(rootDom, sl);
|
2511 | return sl;
|
2512 | });
|
2513 | };
|
2514 | return { forElement };
|
2515 | };
|
2516 | const instance = create$c();
|
2517 |
|
2518 | const isSpan = node => node.nodeName.toLowerCase() === 'span';
|
2519 | const isInlineContent = (node, schema) => isNonNullable(node) && (isContent$1(schema, node) || schema.isInline(node.nodeName.toLowerCase()));
|
2520 | const surroundedByInlineContent = (node, root, schema) => {
|
2521 | const prev = new DomTreeWalker(node, root).prev(false);
|
2522 | const next = new DomTreeWalker(node, root).next(false);
|
2523 | const prevIsInline = isUndefined(prev) || isInlineContent(prev, schema);
|
2524 | const nextIsInline = isUndefined(next) || isInlineContent(next, schema);
|
2525 | return prevIsInline && nextIsInline;
|
2526 | };
|
2527 | const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark';
|
2528 | const isKeepTextNode = (node, root, schema) => isText$b(node) && node.data.length > 0 && surroundedByInlineContent(node, root, schema);
|
2529 | const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false;
|
2530 | const isDocument = node => isDocumentFragment(node) || isDocument$1(node);
|
2531 | const trimNode = (dom, node, schema, root) => {
|
2532 | var _a;
|
2533 | const rootNode = root || node;
|
2534 | if (isElement$6(node) && isBookmarkNode$2(node)) {
|
2535 | return node;
|
2536 | }
|
2537 | const children = node.childNodes;
|
2538 | for (let i = children.length - 1; i >= 0; i--) {
|
2539 | trimNode(dom, children[i], schema, rootNode);
|
2540 | }
|
2541 | if (isElement$6(node)) {
|
2542 | const currentChildren = node.childNodes;
|
2543 | if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
|
2544 | (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node);
|
2545 | }
|
2546 | }
|
2547 | if (!isDocument(node) && !isContent$1(schema, node) && !isKeepElement(node) && !isKeepTextNode(node, rootNode, schema)) {
|
2548 | dom.remove(node);
|
2549 | }
|
2550 | return node;
|
2551 | };
|
2552 |
|
2553 | const makeMap$3 = Tools.makeMap;
|
2554 | const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
2555 | const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
2556 | const rawCharsRegExp = /[<>&\"\']/g;
|
2557 | const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
|
2558 | const asciiMap = {
|
2559 | 128: '\u20AC',
|
2560 | 130: '\u201A',
|
2561 | 131: '\u0192',
|
2562 | 132: '\u201E',
|
2563 | 133: '\u2026',
|
2564 | 134: '\u2020',
|
2565 | 135: '\u2021',
|
2566 | 136: '\u02c6',
|
2567 | 137: '\u2030',
|
2568 | 138: '\u0160',
|
2569 | 139: '\u2039',
|
2570 | 140: '\u0152',
|
2571 | 142: '\u017d',
|
2572 | 145: '\u2018',
|
2573 | 146: '\u2019',
|
2574 | 147: '\u201C',
|
2575 | 148: '\u201D',
|
2576 | 149: '\u2022',
|
2577 | 150: '\u2013',
|
2578 | 151: '\u2014',
|
2579 | 152: '\u02DC',
|
2580 | 153: '\u2122',
|
2581 | 154: '\u0161',
|
2582 | 155: '\u203A',
|
2583 | 156: '\u0153',
|
2584 | 158: '\u017e',
|
2585 | 159: '\u0178'
|
2586 | };
|
2587 | const baseEntities = {
|
2588 | '"': '"',
|
2589 | '\'': ''',
|
2590 | '<': '<',
|
2591 | '>': '>',
|
2592 | '&': '&',
|
2593 | '`': '`'
|
2594 | };
|
2595 | const reverseEntities = {
|
2596 | '<': '<',
|
2597 | '>': '>',
|
2598 | '&': '&',
|
2599 | '"': '"',
|
2600 | ''': `'`
|
2601 | };
|
2602 | const nativeDecode = text => {
|
2603 | const elm = SugarElement.fromTag('div').dom;
|
2604 | elm.innerHTML = text;
|
2605 | return elm.textContent || elm.innerText || text;
|
2606 | };
|
2607 | const buildEntitiesLookup = (items, radix) => {
|
2608 | const lookup = {};
|
2609 | if (items) {
|
2610 | const itemList = items.split(',');
|
2611 | radix = radix || 10;
|
2612 | for (let i = 0; i < itemList.length; i += 2) {
|
2613 | const chr = String.fromCharCode(parseInt(itemList[i], radix));
|
2614 | if (!baseEntities[chr]) {
|
2615 | const entity = '&' + itemList[i + 1] + ';';
|
2616 | lookup[chr] = entity;
|
2617 | lookup[entity] = chr;
|
2618 | }
|
2619 | }
|
2620 | return lookup;
|
2621 | } else {
|
2622 | return undefined;
|
2623 | }
|
2624 | };
|
2625 | const namedEntities = buildEntitiesLookup('50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32);
|
2626 | const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
2627 | return baseEntities[chr] || chr;
|
2628 | });
|
2629 | const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => {
|
2630 | return baseEntities[chr] || chr;
|
2631 | });
|
2632 | const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
2633 | if (chr.length > 1) {
|
2634 | return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
|
2635 | }
|
2636 | return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
|
2637 | });
|
2638 | const encodeNamed = (text, attr, entities) => {
|
2639 | const resolveEntities = entities || namedEntities;
|
2640 | return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
2641 | return baseEntities[chr] || resolveEntities[chr] || chr;
|
2642 | });
|
2643 | };
|
2644 | const getEncodeFunc = (name, entities) => {
|
2645 | const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
|
2646 | const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
2647 | if (baseEntities[chr] !== undefined) {
|
2648 | return baseEntities[chr];
|
2649 | }
|
2650 | if (entitiesMap[chr] !== undefined) {
|
2651 | return entitiesMap[chr];
|
2652 | }
|
2653 | if (chr.length > 1) {
|
2654 | return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
|
2655 | }
|
2656 | return '&#' + chr.charCodeAt(0) + ';';
|
2657 | });
|
2658 | const encodeCustomNamed = (text, attr) => {
|
2659 | return encodeNamed(text, attr, entitiesMap);
|
2660 | };
|
2661 | const nameMap = makeMap$3(name.replace(/\+/g, ','));
|
2662 | if (nameMap.named && nameMap.numeric) {
|
2663 | return encodeNamedAndNumeric;
|
2664 | }
|
2665 | if (nameMap.named) {
|
2666 | if (entities) {
|
2667 | return encodeCustomNamed;
|
2668 | }
|
2669 | return encodeNamed;
|
2670 | }
|
2671 | if (nameMap.numeric) {
|
2672 | return encodeNumeric;
|
2673 | }
|
2674 | return encodeRaw;
|
2675 | };
|
2676 | const decode = text => text.replace(entityRegExp, (all, numeric) => {
|
2677 | if (numeric) {
|
2678 | if (numeric.charAt(0).toLowerCase() === 'x') {
|
2679 | numeric = parseInt(numeric.substr(1), 16);
|
2680 | } else {
|
2681 | numeric = parseInt(numeric, 10);
|
2682 | }
|
2683 | if (numeric > 65535) {
|
2684 | numeric -= 65536;
|
2685 | return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
|
2686 | }
|
2687 | return asciiMap[numeric] || String.fromCharCode(numeric);
|
2688 | }
|
2689 | return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
|
2690 | });
|
2691 | const Entities = {
|
2692 | encodeRaw,
|
2693 | encodeAllRaw,
|
2694 | encodeNumeric,
|
2695 | encodeNamed,
|
2696 | getEncodeFunc,
|
2697 | decode
|
2698 | };
|
2699 |
|
2700 | const split$1 = (items, delim) => {
|
2701 | items = Tools.trim(items);
|
2702 | return items ? items.split(delim || ' ') : [];
|
2703 | };
|
2704 | const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
|
2705 | const isRegExp$1 = obj => isObject(obj) && obj.source && Object.prototype.toString.call(obj) === '[object RegExp]';
|
2706 | const deepCloneElementRule = obj => {
|
2707 | const helper = value => {
|
2708 | if (isArray$1(value)) {
|
2709 | return map$3(value, helper);
|
2710 | } else if (isRegExp$1(value)) {
|
2711 | return new RegExp(value.source, value.flags);
|
2712 | } else if (isObject(value)) {
|
2713 | return map$2(value, helper);
|
2714 | } else {
|
2715 | return value;
|
2716 | }
|
2717 | };
|
2718 | return helper(obj);
|
2719 | };
|
2720 |
|
2721 | const parseCustomElementsRules = value => {
|
2722 | const customElementRegExp = /^(~)?(.+)$/;
|
2723 | return bind$3(split$1(value, ','), rule => {
|
2724 | const matches = customElementRegExp.exec(rule);
|
2725 | if (matches) {
|
2726 | const inline = matches[1] === '~';
|
2727 | const cloneName = inline ? 'span' : 'div';
|
2728 | const name = matches[2];
|
2729 | return [{
|
2730 | cloneName,
|
2731 | name
|
2732 | }];
|
2733 | } else {
|
2734 | return [];
|
2735 | }
|
2736 | });
|
2737 | };
|
2738 |
|
2739 | const getGlobalAttributeSet = type => {
|
2740 | return Object.freeze([
|
2741 | 'id',
|
2742 | 'accesskey',
|
2743 | 'class',
|
2744 | 'dir',
|
2745 | 'lang',
|
2746 | 'style',
|
2747 | 'tabindex',
|
2748 | 'title',
|
2749 | 'role',
|
2750 | ...type !== 'html4' ? [
|
2751 | 'contenteditable',
|
2752 | 'contextmenu',
|
2753 | 'draggable',
|
2754 | 'dropzone',
|
2755 | 'hidden',
|
2756 | 'spellcheck',
|
2757 | 'translate',
|
2758 | 'itemprop',
|
2759 | 'itemscope',
|
2760 | 'itemtype'
|
2761 | ] : [],
|
2762 | ...type !== 'html5-strict' ? ['xml:lang'] : []
|
2763 | ]);
|
2764 | };
|
2765 |
|
2766 | const getElementSetsAsStrings = type => {
|
2767 | let blockContent;
|
2768 | let phrasingContent;
|
2769 | blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
|
2770 | phrasingContent = 'a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd ' + 'label map noscript object q s samp script select small span strong sub sup ' + 'textarea u var #text #comment';
|
2771 | if (type !== 'html4') {
|
2772 | const transparentContent = 'a ins del canvas map';
|
2773 | blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent;
|
2774 | phrasingContent += ' audio canvas command data datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen svg';
|
2775 | }
|
2776 | if (type !== 'html5-strict') {
|
2777 | const html4PhrasingContent = 'acronym applet basefont big font strike tt';
|
2778 | phrasingContent = [
|
2779 | phrasingContent,
|
2780 | html4PhrasingContent
|
2781 | ].join(' ');
|
2782 | const html4BlockContent = 'center dir isindex noframes';
|
2783 | blockContent = [
|
2784 | blockContent,
|
2785 | html4BlockContent
|
2786 | ].join(' ');
|
2787 | }
|
2788 | const flowContent = [
|
2789 | blockContent,
|
2790 | phrasingContent
|
2791 | ].join(' ');
|
2792 | return {
|
2793 | blockContent,
|
2794 | phrasingContent,
|
2795 | flowContent
|
2796 | };
|
2797 | };
|
2798 | const getElementSets = type => {
|
2799 | const {blockContent, phrasingContent, flowContent} = getElementSetsAsStrings(type);
|
2800 | const toArr = value => {
|
2801 | return Object.freeze(value.split(' '));
|
2802 | };
|
2803 | return Object.freeze({
|
2804 | blockContent: toArr(blockContent),
|
2805 | phrasingContent: toArr(phrasingContent),
|
2806 | flowContent: toArr(flowContent)
|
2807 | });
|
2808 | };
|
2809 |
|
2810 | const cachedSets = {
|
2811 | 'html4': cached(() => getElementSets('html4')),
|
2812 | 'html5': cached(() => getElementSets('html5')),
|
2813 | 'html5-strict': cached(() => getElementSets('html5-strict'))
|
2814 | };
|
2815 | const getElementsPreset = (type, name) => {
|
2816 | const {blockContent, phrasingContent, flowContent} = cachedSets[type]();
|
2817 | if (name === 'blocks') {
|
2818 | return Optional.some(blockContent);
|
2819 | } else if (name === 'phrasing') {
|
2820 | return Optional.some(phrasingContent);
|
2821 | } else if (name === 'flow') {
|
2822 | return Optional.some(flowContent);
|
2823 | } else {
|
2824 | return Optional.none();
|
2825 | }
|
2826 | };
|
2827 |
|
2828 | const makeSchema = type => {
|
2829 | const globalAttributes = getGlobalAttributeSet(type);
|
2830 | const {phrasingContent, flowContent} = getElementSetsAsStrings(type);
|
2831 | const schema = {};
|
2832 | const addElement = (name, attributes, children) => {
|
2833 | schema[name] = {
|
2834 | attributes: mapToObject(attributes, constant({})),
|
2835 | attributesOrder: attributes,
|
2836 | children: mapToObject(children, constant({}))
|
2837 | };
|
2838 | };
|
2839 | const add = (name, attributes = '', children = '') => {
|
2840 | const childNames = split$1(children);
|
2841 | const names = split$1(name);
|
2842 | let ni = names.length;
|
2843 | const allAttributes = [
|
2844 | ...globalAttributes,
|
2845 | ...split$1(attributes)
|
2846 | ];
|
2847 | while (ni--) {
|
2848 | addElement(names[ni], allAttributes.slice(), childNames);
|
2849 | }
|
2850 | };
|
2851 | const addAttrs = (name, attributes) => {
|
2852 | const names = split$1(name);
|
2853 | const attrs = split$1(attributes);
|
2854 | let ni = names.length;
|
2855 | while (ni--) {
|
2856 | const schemaItem = schema[names[ni]];
|
2857 | for (let i = 0, l = attrs.length; i < l; i++) {
|
2858 | schemaItem.attributes[attrs[i]] = {};
|
2859 | schemaItem.attributesOrder.push(attrs[i]);
|
2860 | }
|
2861 | }
|
2862 | };
|
2863 | if (type !== 'html5-strict') {
|
2864 | const html4PhrasingContent = 'acronym applet basefont big font strike tt';
|
2865 | each$e(split$1(html4PhrasingContent), name => {
|
2866 | add(name, '', phrasingContent);
|
2867 | });
|
2868 | const html4BlockContent = 'center dir isindex noframes';
|
2869 | each$e(split$1(html4BlockContent), name => {
|
2870 | add(name, '', flowContent);
|
2871 | });
|
2872 | }
|
2873 | add('html', 'manifest', 'head body');
|
2874 | add('head', '', 'base command link meta noscript script style title');
|
2875 | add('title hr noscript br');
|
2876 | add('base', 'href target');
|
2877 | add('link', 'href rel media hreflang type sizes hreflang');
|
2878 | add('meta', 'name http-equiv content charset');
|
2879 | add('style', 'media type scoped');
|
2880 | add('script', 'src async defer type charset');
|
2881 | add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
|
2882 | add('dd div', '', flowContent);
|
2883 | add('address dt caption', '', type === 'html4' ? phrasingContent : flowContent);
|
2884 | add('h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn', '', phrasingContent);
|
2885 | add('blockquote', 'cite', flowContent);
|
2886 | add('ol', 'reversed start type', 'li');
|
2887 | add('ul', '', 'li');
|
2888 | add('li', 'value', flowContent);
|
2889 | add('dl', '', 'dt dd');
|
2890 | add('a', 'href target rel media hreflang type', type === 'html4' ? phrasingContent : flowContent);
|
2891 | add('q', 'cite', phrasingContent);
|
2892 | add('ins del', 'cite datetime', flowContent);
|
2893 | add('img', 'src sizes srcset alt usemap ismap width height');
|
2894 | add('iframe', 'src name width height', flowContent);
|
2895 | add('embed', 'src type width height');
|
2896 | add('object', 'data type typemustmatch name usemap form width height', [
|
2897 | flowContent,
|
2898 | 'param'
|
2899 | ].join(' '));
|
2900 | add('param', 'name value');
|
2901 | add('map', 'name', [
|
2902 | flowContent,
|
2903 | 'area'
|
2904 | ].join(' '));
|
2905 | add('area', 'alt coords shape href target rel media hreflang type');
|
2906 | add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
|
2907 | add('colgroup', 'span', 'col');
|
2908 | add('col', 'span');
|
2909 | add('tbody thead tfoot', '', 'tr');
|
2910 | add('tr', '', 'td th');
|
2911 | add('td', 'colspan rowspan headers', flowContent);
|
2912 | add('th', 'colspan rowspan headers scope abbr', flowContent);
|
2913 | add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
|
2914 | add('fieldset', 'disabled form name', [
|
2915 | flowContent,
|
2916 | 'legend'
|
2917 | ].join(' '));
|
2918 | add('label', 'form for', phrasingContent);
|
2919 | add('input', 'accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate ' + 'formtarget height list max maxlength min multiple name pattern readonly required size src step type value width');
|
2920 | add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
|
2921 | add('select', 'disabled form multiple name required size', 'option optgroup');
|
2922 | add('optgroup', 'disabled label', 'option');
|
2923 | add('option', 'disabled label selected value');
|
2924 | add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
|
2925 | add('menu', 'type label', [
|
2926 | flowContent,
|
2927 | 'li'
|
2928 | ].join(' '));
|
2929 | add('noscript', '', flowContent);
|
2930 | if (type !== 'html4') {
|
2931 | add('wbr');
|
2932 | add('ruby', '', [
|
2933 | phrasingContent,
|
2934 | 'rt rp'
|
2935 | ].join(' '));
|
2936 | add('figcaption', '', flowContent);
|
2937 | add('mark rt rp bdi', '', phrasingContent);
|
2938 | add('summary', '', [
|
2939 | phrasingContent,
|
2940 | 'h1 h2 h3 h4 h5 h6'
|
2941 | ].join(' '));
|
2942 | add('canvas', 'width height', flowContent);
|
2943 | add('data', 'value', phrasingContent);
|
2944 | add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
|
2945 | flowContent,
|
2946 | 'track source'
|
2947 | ].join(' '));
|
2948 | add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
|
2949 | flowContent,
|
2950 | 'track source'
|
2951 | ].join(' '));
|
2952 | add('picture', '', 'img source');
|
2953 | add('source', 'src srcset type media sizes');
|
2954 | add('track', 'kind src srclang label default');
|
2955 | add('datalist', '', [
|
2956 | phrasingContent,
|
2957 | 'option'
|
2958 | ].join(' '));
|
2959 | add('article section nav aside main header footer', '', flowContent);
|
2960 | add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
|
2961 | add('figure', '', [
|
2962 | flowContent,
|
2963 | 'figcaption'
|
2964 | ].join(' '));
|
2965 | add('time', 'datetime', phrasingContent);
|
2966 | add('dialog', 'open', flowContent);
|
2967 | add('command', 'type label icon disabled checked radiogroup command');
|
2968 | add('output', 'for form name', phrasingContent);
|
2969 | add('progress', 'value max', phrasingContent);
|
2970 | add('meter', 'value min max low high optimum', phrasingContent);
|
2971 | add('details', 'open', [
|
2972 | flowContent,
|
2973 | 'summary'
|
2974 | ].join(' '));
|
2975 | add('keygen', 'autofocus challenge disabled form keytype name');
|
2976 | addElement('svg', 'id tabindex lang xml:space class style x y width height viewBox preserveAspectRatio zoomAndPan transform'.split(' '), []);
|
2977 | }
|
2978 | if (type !== 'html5-strict') {
|
2979 | addAttrs('script', 'language xml:space');
|
2980 | addAttrs('style', 'xml:space');
|
2981 | addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
|
2982 | addAttrs('embed', 'align name hspace vspace');
|
2983 | addAttrs('param', 'valuetype type');
|
2984 | addAttrs('a', 'charset name rev shape coords');
|
2985 | addAttrs('br', 'clear');
|
2986 | addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
|
2987 | addAttrs('img', 'name longdesc align border hspace vspace');
|
2988 | addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
|
2989 | addAttrs('font basefont', 'size color face');
|
2990 | addAttrs('input', 'usemap align');
|
2991 | addAttrs('select');
|
2992 | addAttrs('textarea');
|
2993 | addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
|
2994 | addAttrs('ul', 'type compact');
|
2995 | addAttrs('li', 'type');
|
2996 | addAttrs('ol dl menu dir', 'compact');
|
2997 | addAttrs('pre', 'width xml:space');
|
2998 | addAttrs('hr', 'align noshade size width');
|
2999 | addAttrs('isindex', 'prompt');
|
3000 | addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
|
3001 | addAttrs('col', 'width align char charoff valign');
|
3002 | addAttrs('colgroup', 'width align char charoff valign');
|
3003 | addAttrs('thead', 'align char charoff valign');
|
3004 | addAttrs('tr', 'align char charoff valign bgcolor');
|
3005 | addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
|
3006 | addAttrs('form', 'accept');
|
3007 | addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
|
3008 | addAttrs('tfoot', 'align char charoff valign');
|
3009 | addAttrs('tbody', 'align char charoff valign');
|
3010 | addAttrs('area', 'nohref');
|
3011 | addAttrs('body', 'background bgcolor text link vlink alink');
|
3012 | }
|
3013 | if (type !== 'html4') {
|
3014 | addAttrs('input button select textarea', 'autofocus');
|
3015 | addAttrs('input textarea', 'placeholder');
|
3016 | addAttrs('a', 'download');
|
3017 | addAttrs('link script img', 'crossorigin');
|
3018 | addAttrs('img', 'loading');
|
3019 | addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading');
|
3020 | }
|
3021 | if (type !== 'html4') {
|
3022 | each$e([
|
3023 | schema.video,
|
3024 | schema.audio
|
3025 | ], item => {
|
3026 | delete item.children.audio;
|
3027 | delete item.children.video;
|
3028 | });
|
3029 | }
|
3030 | each$e(split$1('a form meter progress dfn'), name => {
|
3031 | if (schema[name]) {
|
3032 | delete schema[name].children[name];
|
3033 | }
|
3034 | });
|
3035 | delete schema.caption.children.table;
|
3036 | delete schema.script;
|
3037 | return schema;
|
3038 | };
|
3039 |
|
3040 | const prefixToOperation = prefix => prefix === '-' ? 'remove' : 'add';
|
3041 | const parseValidChild = name => {
|
3042 | const validChildRegExp = /^(@?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)$/;
|
3043 | return Optional.from(validChildRegExp.exec(name)).map(matches => ({
|
3044 | preset: matches[1] === '@',
|
3045 | name: matches[2]
|
3046 | }));
|
3047 | };
|
3048 | const parseValidChildrenRules = value => {
|
3049 | const childRuleRegExp = /^([+\-]?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)\[([^\]]+)]$/;
|
3050 | return bind$3(split$1(value, ','), rule => {
|
3051 | const matches = childRuleRegExp.exec(rule);
|
3052 | if (matches) {
|
3053 | const prefix = matches[1];
|
3054 | const operation = prefix ? prefixToOperation(prefix) : 'replace';
|
3055 | const name = matches[2];
|
3056 | const validChildren = bind$3(split$1(matches[3], '|'), validChild => parseValidChild(validChild).toArray());
|
3057 | return [{
|
3058 | operation,
|
3059 | name,
|
3060 | validChildren
|
3061 | }];
|
3062 | } else {
|
3063 | return [];
|
3064 | }
|
3065 | });
|
3066 | };
|
3067 |
|
3068 | const parseValidElementsAttrDataIntoElement = (attrData, targetElement) => {
|
3069 | const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/;
|
3070 | const hasPatternsRegExp = /[*?+]/;
|
3071 | const {attributes, attributesOrder} = targetElement;
|
3072 | return each$e(split$1(attrData, '|'), rule => {
|
3073 | const matches = attrRuleRegExp.exec(rule);
|
3074 | if (matches) {
|
3075 | const attr = {};
|
3076 | const attrType = matches[1];
|
3077 | const attrName = matches[2].replace(/[\\:]:/g, ':');
|
3078 | const attrPrefix = matches[3];
|
3079 | const value = matches[4];
|
3080 | if (attrType === '!') {
|
3081 | targetElement.attributesRequired = targetElement.attributesRequired || [];
|
3082 | targetElement.attributesRequired.push(attrName);
|
3083 | attr.required = true;
|
3084 | }
|
3085 | if (attrType === '-') {
|
3086 | delete attributes[attrName];
|
3087 | attributesOrder.splice(Tools.inArray(attributesOrder, attrName), 1);
|
3088 | return;
|
3089 | }
|
3090 | if (attrPrefix) {
|
3091 | if (attrPrefix === '=') {
|
3092 | targetElement.attributesDefault = targetElement.attributesDefault || [];
|
3093 | targetElement.attributesDefault.push({
|
3094 | name: attrName,
|
3095 | value
|
3096 | });
|
3097 | attr.defaultValue = value;
|
3098 | } else if (attrPrefix === '~') {
|
3099 | targetElement.attributesForced = targetElement.attributesForced || [];
|
3100 | targetElement.attributesForced.push({
|
3101 | name: attrName,
|
3102 | value
|
3103 | });
|
3104 | attr.forcedValue = value;
|
3105 | } else if (attrPrefix === '<') {
|
3106 | attr.validValues = Tools.makeMap(value, '?');
|
3107 | }
|
3108 | }
|
3109 | if (hasPatternsRegExp.test(attrName)) {
|
3110 | const attrPattern = attr;
|
3111 | targetElement.attributePatterns = targetElement.attributePatterns || [];
|
3112 | attrPattern.pattern = patternToRegExp(attrName);
|
3113 | targetElement.attributePatterns.push(attrPattern);
|
3114 | } else {
|
3115 | if (!attributes[attrName]) {
|
3116 | attributesOrder.push(attrName);
|
3117 | }
|
3118 | attributes[attrName] = attr;
|
3119 | }
|
3120 | }
|
3121 | });
|
3122 | };
|
3123 | const cloneAttributesInto = (from, to) => {
|
3124 | each$d(from.attributes, (value, key) => {
|
3125 | to.attributes[key] = value;
|
3126 | });
|
3127 | to.attributesOrder.push(...from.attributesOrder);
|
3128 | };
|
3129 | const parseValidElementsRules = (globalElement, validElements) => {
|
3130 | const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;
|
3131 | return bind$3(split$1(validElements, ','), rule => {
|
3132 | const matches = elementRuleRegExp.exec(rule);
|
3133 | if (matches) {
|
3134 | const prefix = matches[1];
|
3135 | const elementName = matches[2];
|
3136 | const outputName = matches[3];
|
3137 | const attrsPrefix = matches[4];
|
3138 | const attrData = matches[5];
|
3139 | const element = {
|
3140 | attributes: {},
|
3141 | attributesOrder: []
|
3142 | };
|
3143 | globalElement.each(el => cloneAttributesInto(el, element));
|
3144 | if (prefix === '#') {
|
3145 | element.paddEmpty = true;
|
3146 | } else if (prefix === '-') {
|
3147 | element.removeEmpty = true;
|
3148 | }
|
3149 | if (attrsPrefix === '!') {
|
3150 | element.removeEmptyAttrs = true;
|
3151 | }
|
3152 | if (attrData) {
|
3153 | parseValidElementsAttrDataIntoElement(attrData, element);
|
3154 | }
|
3155 | if (outputName) {
|
3156 | element.outputName = elementName;
|
3157 | }
|
3158 | if (elementName === '@') {
|
3159 | if (globalElement.isNone()) {
|
3160 | globalElement = Optional.some(element);
|
3161 | } else {
|
3162 | return [];
|
3163 | }
|
3164 | }
|
3165 | return [outputName ? {
|
3166 | name: elementName,
|
3167 | element,
|
3168 | aliasName: outputName
|
3169 | } : {
|
3170 | name: elementName,
|
3171 | element
|
3172 | }];
|
3173 | } else {
|
3174 | return [];
|
3175 | }
|
3176 | });
|
3177 | };
|
3178 |
|
3179 | const mapCache = {};
|
3180 | const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode;
|
3181 | const createMap = (defaultValue, extendWith = {}) => {
|
3182 | const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
|
3183 | return extend$2(value, extendWith);
|
3184 | };
|
3185 | const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements());
|
3186 | const compileElementMap = (value, mode) => {
|
3187 | if (value) {
|
3188 | const styles = {};
|
3189 | if (isString(value)) {
|
3190 | value = { '*': value };
|
3191 | }
|
3192 | each$b(value, (value, key) => {
|
3193 | styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/);
|
3194 | });
|
3195 | return styles;
|
3196 | } else {
|
3197 | return undefined;
|
3198 | }
|
3199 | };
|
3200 | const Schema = (settings = {}) => {
|
3201 | var _a;
|
3202 | const elements = {};
|
3203 | const children = {};
|
3204 | let patternElements = [];
|
3205 | const customElementsMap = {};
|
3206 | const specialElements = {};
|
3207 | const createLookupTable = (option, defaultValue, extendWith) => {
|
3208 | const value = settings[option];
|
3209 | if (!value) {
|
3210 | let newValue = mapCache[option];
|
3211 | if (!newValue) {
|
3212 | newValue = createMap(defaultValue, extendWith);
|
3213 | mapCache[option] = newValue;
|
3214 | }
|
3215 | return newValue;
|
3216 | } else {
|
3217 | return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
|
3218 | }
|
3219 | };
|
3220 | const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5';
|
3221 | const schemaItems = makeSchema(schemaType);
|
3222 | if (settings.verify_html === false) {
|
3223 | settings.valid_elements = '*[*]';
|
3224 | }
|
3225 | const validStyles = compileElementMap(settings.valid_styles);
|
3226 | const invalidStyles = compileElementMap(settings.invalid_styles, 'map');
|
3227 | const validClasses = compileElementMap(settings.valid_classes, 'map');
|
3228 | const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
|
3229 | const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
|
3230 | const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
|
3231 | const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen');
|
3232 | const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code';
|
3233 | const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre svg textarea summary', voidElementsMap);
|
3234 | const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap);
|
3235 | const headings = 'h1 h2 h3 h4 h5 h6';
|
3236 | const textBlockElementsMap = createLookupTable('text_block_elements', headings + ' p div address pre form ' + 'blockquote center dir fieldset header footer article section hgroup aside main nav figure');
|
3237 | const blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' + 'th tr td li ol ul caption dl dt dd noscript menu isindex option ' + 'datalist select optgroup figcaption details summary html body multicol listing', textBlockElementsMap);
|
3238 | const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp');
|
3239 | const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map');
|
3240 | const wrapBlockElementsMap = createLookupTable('wrap_block_elements', 'pre ' + headings);
|
3241 | each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => {
|
3242 | specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
|
3243 | });
|
3244 | const addValidElements = validElements => {
|
3245 | const globalElement = Optional.from(elements['@']);
|
3246 | const hasPatternsRegExp = /[*?+]/;
|
3247 | each$e(parseValidElementsRules(globalElement, validElements !== null && validElements !== void 0 ? validElements : ''), ({name, element, aliasName}) => {
|
3248 | if (aliasName) {
|
3249 | elements[aliasName] = element;
|
3250 | }
|
3251 | if (hasPatternsRegExp.test(name)) {
|
3252 | const patternElement = element;
|
3253 | patternElement.pattern = patternToRegExp(name);
|
3254 | patternElements.push(patternElement);
|
3255 | } else {
|
3256 | elements[name] = element;
|
3257 | }
|
3258 | });
|
3259 | };
|
3260 | const setValidElements = validElements => {
|
3261 | patternElements = [];
|
3262 | each$e(keys(elements), name => {
|
3263 | delete elements[name];
|
3264 | });
|
3265 | addValidElements(validElements);
|
3266 | };
|
3267 | const addCustomElement = (name, spec) => {
|
3268 | var _a, _b;
|
3269 | delete mapCache.text_block_elements;
|
3270 | delete mapCache.block_elements;
|
3271 | const inline = spec.extends ? !isBlock(spec.extends) : false;
|
3272 | const cloneName = spec.extends;
|
3273 | children[name] = cloneName ? children[cloneName] : {};
|
3274 | customElementsMap[name] = cloneName !== null && cloneName !== void 0 ? cloneName : name;
|
3275 | nonEmptyElementsMap[name.toUpperCase()] = {};
|
3276 | nonEmptyElementsMap[name] = {};
|
3277 | if (!inline) {
|
3278 | blockElementsMap[name.toUpperCase()] = {};
|
3279 | blockElementsMap[name] = {};
|
3280 | }
|
3281 | if (cloneName && !elements[name] && elements[cloneName]) {
|
3282 | const customRule = deepCloneElementRule(elements[cloneName]);
|
3283 | delete customRule.removeEmptyAttrs;
|
3284 | delete customRule.removeEmpty;
|
3285 | elements[name] = customRule;
|
3286 | } else {
|
3287 | elements[name] = {
|
3288 | attributesOrder: [],
|
3289 | attributes: {}
|
3290 | };
|
3291 | }
|
3292 | if (isArray$1(spec.attributes)) {
|
3293 | const processAttrName = name => {
|
3294 | customRule.attributesOrder.push(name);
|
3295 | customRule.attributes[name] = {};
|
3296 | };
|
3297 | const customRule = (_a = elements[name]) !== null && _a !== void 0 ? _a : {};
|
3298 | delete customRule.attributesDefault;
|
3299 | delete customRule.attributesForced;
|
3300 | delete customRule.attributePatterns;
|
3301 | delete customRule.attributesRequired;
|
3302 | customRule.attributesOrder = [];
|
3303 | customRule.attributes = {};
|
3304 | each$e(spec.attributes, attrName => {
|
3305 | const globalAttrs = getGlobalAttributeSet(schemaType);
|
3306 | parseValidChild(attrName).each(({preset, name}) => {
|
3307 | if (preset) {
|
3308 | if (name === 'global') {
|
3309 | each$e(globalAttrs, processAttrName);
|
3310 | }
|
3311 | } else {
|
3312 | processAttrName(name);
|
3313 | }
|
3314 | });
|
3315 | });
|
3316 | elements[name] = customRule;
|
3317 | }
|
3318 | if (isBoolean(spec.padEmpty)) {
|
3319 | const customRule = (_b = elements[name]) !== null && _b !== void 0 ? _b : {};
|
3320 | customRule.paddEmpty = spec.padEmpty;
|
3321 | elements[name] = customRule;
|
3322 | }
|
3323 | if (isArray$1(spec.children)) {
|
3324 | const customElementChildren = {};
|
3325 | const processNodeName = name => {
|
3326 | customElementChildren[name] = {};
|
3327 | };
|
3328 | const processPreset = name => {
|
3329 | getElementsPreset(schemaType, name).each(names => {
|
3330 | each$e(names, processNodeName);
|
3331 | });
|
3332 | };
|
3333 | each$e(spec.children, child => {
|
3334 | parseValidChild(child).each(({preset, name}) => {
|
3335 | if (preset) {
|
3336 | processPreset(name);
|
3337 | } else {
|
3338 | processNodeName(name);
|
3339 | }
|
3340 | });
|
3341 | });
|
3342 | children[name] = customElementChildren;
|
3343 | }
|
3344 | if (cloneName) {
|
3345 | each$d(children, (element, elmName) => {
|
3346 | if (element[cloneName]) {
|
3347 | children[elmName] = element = extend$2({}, children[elmName]);
|
3348 | element[name] = element[cloneName];
|
3349 | }
|
3350 | });
|
3351 | }
|
3352 | };
|
3353 | const addCustomElementsFromString = customElements => {
|
3354 | each$e(parseCustomElementsRules(customElements !== null && customElements !== void 0 ? customElements : ''), ({name, cloneName}) => {
|
3355 | addCustomElement(name, { extends: cloneName });
|
3356 | });
|
3357 | };
|
3358 | const addCustomElements = customElements => {
|
3359 | if (isObject(customElements)) {
|
3360 | each$d(customElements, (spec, name) => addCustomElement(name, spec));
|
3361 | } else if (isString(customElements)) {
|
3362 | addCustomElementsFromString(customElements);
|
3363 | }
|
3364 | };
|
3365 | const addValidChildren = validChildren => {
|
3366 | each$e(parseValidChildrenRules(validChildren !== null && validChildren !== void 0 ? validChildren : ''), ({operation, name, validChildren}) => {
|
3367 | const parent = operation === 'replace' ? { '#comment': {} } : children[name];
|
3368 | const processNodeName = name => {
|
3369 | if (operation === 'remove') {
|
3370 | delete parent[name];
|
3371 | } else {
|
3372 | parent[name] = {};
|
3373 | }
|
3374 | };
|
3375 | const processPreset = name => {
|
3376 | getElementsPreset(schemaType, name).each(names => {
|
3377 | each$e(names, processNodeName);
|
3378 | });
|
3379 | };
|
3380 | each$e(validChildren, ({preset, name}) => {
|
3381 | if (preset) {
|
3382 | processPreset(name);
|
3383 | } else {
|
3384 | processNodeName(name);
|
3385 | }
|
3386 | });
|
3387 | children[name] = parent;
|
3388 | });
|
3389 | };
|
3390 | const getElementRule = name => {
|
3391 | const element = elements[name];
|
3392 | if (element) {
|
3393 | return element;
|
3394 | }
|
3395 | let i = patternElements.length;
|
3396 | while (i--) {
|
3397 | const patternElement = patternElements[i];
|
3398 | if (patternElement.pattern.test(name)) {
|
3399 | return patternElement;
|
3400 | }
|
3401 | }
|
3402 | return undefined;
|
3403 | };
|
3404 | const setup = () => {
|
3405 | if (!settings.valid_elements) {
|
3406 | each$b(schemaItems, (element, name) => {
|
3407 | elements[name] = {
|
3408 | attributes: element.attributes,
|
3409 | attributesOrder: element.attributesOrder
|
3410 | };
|
3411 | children[name] = element.children;
|
3412 | });
|
3413 | each$b(split$1('strong/b em/i'), item => {
|
3414 | const items = split$1(item, '/');
|
3415 | elements[items[1]].outputName = items[0];
|
3416 | });
|
3417 | each$b(textInlineElementsMap, (_val, name) => {
|
3418 | if (elements[name]) {
|
3419 | if (settings.padd_empty_block_inline_children) {
|
3420 | elements[name].paddInEmptyBlock = true;
|
3421 | }
|
3422 | elements[name].removeEmpty = true;
|
3423 | }
|
3424 | });
|
3425 | each$b(split$1('ol ul blockquote a table tbody'), name => {
|
3426 | if (elements[name]) {
|
3427 | elements[name].removeEmpty = true;
|
3428 | }
|
3429 | });
|
3430 | each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary'), name => {
|
3431 | if (elements[name]) {
|
3432 | elements[name].paddEmpty = true;
|
3433 | }
|
3434 | });
|
3435 | each$b(split$1('span'), name => {
|
3436 | elements[name].removeEmptyAttrs = true;
|
3437 | });
|
3438 | } else {
|
3439 | setValidElements(settings.valid_elements);
|
3440 | each$b(schemaItems, (element, name) => {
|
3441 | children[name] = element.children;
|
3442 | });
|
3443 | }
|
3444 | delete elements.svg;
|
3445 | addCustomElements(settings.custom_elements);
|
3446 | addValidChildren(settings.valid_children);
|
3447 | addValidElements(settings.extended_valid_elements);
|
3448 | addValidChildren('+ol[ul|ol],+ul[ul|ol]');
|
3449 | each$b({
|
3450 | dd: 'dl',
|
3451 | dt: 'dl',
|
3452 | li: 'ul ol',
|
3453 | td: 'tr',
|
3454 | th: 'tr',
|
3455 | tr: 'tbody thead tfoot',
|
3456 | tbody: 'table',
|
3457 | thead: 'table',
|
3458 | tfoot: 'table',
|
3459 | legend: 'fieldset',
|
3460 | area: 'map',
|
3461 | param: 'video audio object'
|
3462 | }, (parents, item) => {
|
3463 | if (elements[item]) {
|
3464 | elements[item].parentsRequired = split$1(parents);
|
3465 | }
|
3466 | });
|
3467 | if (settings.invalid_elements) {
|
3468 | each$b(explode$2(settings.invalid_elements), item => {
|
3469 | if (elements[item]) {
|
3470 | delete elements[item];
|
3471 | }
|
3472 | });
|
3473 | }
|
3474 | if (!getElementRule('span')) {
|
3475 | addValidElements('span[!data-mce-type|*]');
|
3476 | }
|
3477 | };
|
3478 | const getValidStyles = constant(validStyles);
|
3479 | const getInvalidStyles = constant(invalidStyles);
|
3480 | const getValidClasses = constant(validClasses);
|
3481 | const getBoolAttrs = constant(boolAttrMap);
|
3482 | const getBlockElements = constant(blockElementsMap);
|
3483 | const getTextBlockElements = constant(textBlockElementsMap);
|
3484 | const getTextInlineElements = constant(textInlineElementsMap);
|
3485 | const getVoidElements = constant(Object.seal(voidElementsMap));
|
3486 | const getSelfClosingElements = constant(selfClosingElementsMap);
|
3487 | const getNonEmptyElements = constant(nonEmptyElementsMap);
|
3488 | const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
|
3489 | const getWhitespaceElements = constant(whitespaceElementsMap);
|
3490 | const getTransparentElements = constant(transparentElementsMap);
|
3491 | const getWrapBlockElements = constant(wrapBlockElementsMap);
|
3492 | const getSpecialElements = constant(Object.seal(specialElements));
|
3493 | const isValidChild = (name, child) => {
|
3494 | const parent = children[name.toLowerCase()];
|
3495 | return !!(parent && parent[child.toLowerCase()]);
|
3496 | };
|
3497 | const isValid = (name, attr) => {
|
3498 | const rule = getElementRule(name);
|
3499 | if (rule) {
|
3500 | if (attr) {
|
3501 | if (rule.attributes[attr]) {
|
3502 | return true;
|
3503 | }
|
3504 | const attrPatterns = rule.attributePatterns;
|
3505 | if (attrPatterns) {
|
3506 | let i = attrPatterns.length;
|
3507 | while (i--) {
|
3508 | if (attrPatterns[i].pattern.test(attr)) {
|
3509 | return true;
|
3510 | }
|
3511 | }
|
3512 | }
|
3513 | } else {
|
3514 | return true;
|
3515 | }
|
3516 | }
|
3517 | return false;
|
3518 | };
|
3519 | const isBlock = name => has$2(getBlockElements(), name);
|
3520 | const isInline = name => !startsWith(name, '#') && isValid(name) && !isBlock(name);
|
3521 | const isWrapper = name => has$2(getWrapBlockElements(), name) || isInline(name);
|
3522 | const getCustomElements = constant(customElementsMap);
|
3523 | setup();
|
3524 | return {
|
3525 | type: schemaType,
|
3526 | children,
|
3527 | elements,
|
3528 | getValidStyles,
|
3529 | getValidClasses,
|
3530 | getBlockElements,
|
3531 | getInvalidStyles,
|
3532 | getVoidElements,
|
3533 | getTextBlockElements,
|
3534 | getTextInlineElements,
|
3535 | getBoolAttrs,
|
3536 | getElementRule,
|
3537 | getSelfClosingElements,
|
3538 | getNonEmptyElements,
|
3539 | getMoveCaretBeforeOnEnterElements,
|
3540 | getWhitespaceElements,
|
3541 | getTransparentElements,
|
3542 | getSpecialElements,
|
3543 | isValidChild,
|
3544 | isValid,
|
3545 | isBlock,
|
3546 | isInline,
|
3547 | isWrapper,
|
3548 | getCustomElements,
|
3549 | addValidElements,
|
3550 | setValidElements,
|
3551 | addCustomElements,
|
3552 | addValidChildren
|
3553 | };
|
3554 | };
|
3555 |
|
3556 | const hexColour = value => ({ value: normalizeHex(value) });
|
3557 | const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
|
3558 | const toHex = component => {
|
3559 | const hex = component.toString(16);
|
3560 | return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
|
3561 | };
|
3562 | const fromRgba = rgbaColour => {
|
3563 | const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
|
3564 | return hexColour(value);
|
3565 | };
|
3566 |
|
3567 | const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
|
3568 | const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
|
3569 | const rgbaColour = (red, green, blue, alpha) => ({
|
3570 | red,
|
3571 | green,
|
3572 | blue,
|
3573 | alpha
|
3574 | });
|
3575 | const fromStringValues = (red, green, blue, alpha) => {
|
3576 | const r = parseInt(red, 10);
|
3577 | const g = parseInt(green, 10);
|
3578 | const b = parseInt(blue, 10);
|
3579 | const a = parseFloat(alpha);
|
3580 | return rgbaColour(r, g, b, a);
|
3581 | };
|
3582 | const fromString = rgbaString => {
|
3583 | if (rgbaString === 'transparent') {
|
3584 | return Optional.some(rgbaColour(0, 0, 0, 0));
|
3585 | }
|
3586 | const rgbMatch = rgbRegex.exec(rgbaString);
|
3587 | if (rgbMatch !== null) {
|
3588 | return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
|
3589 | }
|
3590 | const rgbaMatch = rgbaRegex.exec(rgbaString);
|
3591 | if (rgbaMatch !== null) {
|
3592 | return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
|
3593 | }
|
3594 | return Optional.none();
|
3595 | };
|
3596 | const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
|
3597 |
|
3598 | const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
|
3599 |
|
3600 | const Styles = (settings = {}, schema) => {
|
3601 | const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
|
3602 | const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
|
3603 | const trimRightRegExp = /\s+$/;
|
3604 | const rgbaRegExp = /rgba *\(/i;
|
3605 | const encodingLookup = {};
|
3606 | let validStyles;
|
3607 | let invalidStyles;
|
3608 | const invisibleChar = zeroWidth;
|
3609 | if (schema) {
|
3610 | validStyles = schema.getValidStyles();
|
3611 | invalidStyles = schema.getInvalidStyles();
|
3612 | }
|
3613 | const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' ');
|
3614 | for (let i = 0; i < encodingItems.length; i++) {
|
3615 | encodingLookup[encodingItems[i]] = invisibleChar + i;
|
3616 | encodingLookup[invisibleChar + i] = encodingItems[i];
|
3617 | }
|
3618 | const self = {
|
3619 | parse: css => {
|
3620 | const styles = {};
|
3621 | let isEncoded = false;
|
3622 | const urlConverter = settings.url_converter;
|
3623 | const urlConverterScope = settings.url_converter_scope || self;
|
3624 | const compress = (prefix, suffix, noJoin) => {
|
3625 | const top = styles[prefix + '-top' + suffix];
|
3626 | if (!top) {
|
3627 | return;
|
3628 | }
|
3629 | const right = styles[prefix + '-right' + suffix];
|
3630 | if (!right) {
|
3631 | return;
|
3632 | }
|
3633 | const bottom = styles[prefix + '-bottom' + suffix];
|
3634 | if (!bottom) {
|
3635 | return;
|
3636 | }
|
3637 | const left = styles[prefix + '-left' + suffix];
|
3638 | if (!left) {
|
3639 | return;
|
3640 | }
|
3641 | const box = [
|
3642 | top,
|
3643 | right,
|
3644 | bottom,
|
3645 | left
|
3646 | ];
|
3647 | let i = box.length - 1;
|
3648 | while (i--) {
|
3649 | if (box[i] !== box[i + 1]) {
|
3650 | break;
|
3651 | }
|
3652 | }
|
3653 | if (i > -1 && noJoin) {
|
3654 | return;
|
3655 | }
|
3656 | styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
|
3657 | delete styles[prefix + '-top' + suffix];
|
3658 | delete styles[prefix + '-right' + suffix];
|
3659 | delete styles[prefix + '-bottom' + suffix];
|
3660 | delete styles[prefix + '-left' + suffix];
|
3661 | };
|
3662 | const canCompress = key => {
|
3663 | const value = styles[key];
|
3664 | if (!value) {
|
3665 | return;
|
3666 | }
|
3667 | const values = value.indexOf(',') > -1 ? [value] : value.split(' ');
|
3668 | let i = values.length;
|
3669 | while (i--) {
|
3670 | if (values[i] !== values[0]) {
|
3671 | return false;
|
3672 | }
|
3673 | }
|
3674 | styles[key] = values[0];
|
3675 | return true;
|
3676 | };
|
3677 | const compress2 = (target, a, b, c) => {
|
3678 | if (!canCompress(a)) {
|
3679 | return;
|
3680 | }
|
3681 | if (!canCompress(b)) {
|
3682 | return;
|
3683 | }
|
3684 | if (!canCompress(c)) {
|
3685 | return;
|
3686 | }
|
3687 | styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
|
3688 | delete styles[a];
|
3689 | delete styles[b];
|
3690 | delete styles[c];
|
3691 | };
|
3692 | const encode = str => {
|
3693 | isEncoded = true;
|
3694 | return encodingLookup[str];
|
3695 | };
|
3696 | const decode = (str, keepSlashes) => {
|
3697 | if (isEncoded) {
|
3698 | str = str.replace(/\uFEFF[0-9]/g, str => {
|
3699 | return encodingLookup[str];
|
3700 | });
|
3701 | }
|
3702 | if (!keepSlashes) {
|
3703 | str = str.replace(/\\([\'\";:])/g, '$1');
|
3704 | }
|
3705 | return str;
|
3706 | };
|
3707 | const decodeSingleHexSequence = escSeq => {
|
3708 | return String.fromCharCode(parseInt(escSeq.slice(1), 16));
|
3709 | };
|
3710 | const decodeHexSequences = value => {
|
3711 | return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
|
3712 | };
|
3713 | const processUrl = (match, url, url2, url3, str, str2) => {
|
3714 | str = str || str2;
|
3715 | if (str) {
|
3716 | str = decode(str);
|
3717 | return `'` + str.replace(/\'/g, `\\'`) + `'`;
|
3718 | }
|
3719 | url = decode(url || url2 || url3 || '');
|
3720 | if (!settings.allow_script_urls) {
|
3721 | const scriptUrl = url.replace(/[\s\r\n]+/g, '');
|
3722 | if (/(java|vb)script:/i.test(scriptUrl)) {
|
3723 | return '';
|
3724 | }
|
3725 | if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
|
3726 | return '';
|
3727 | }
|
3728 | }
|
3729 | if (urlConverter) {
|
3730 | url = urlConverter.call(urlConverterScope, url, 'style');
|
3731 | }
|
3732 | return `url('` + url.replace(/\'/g, `\\'`) + `')`;
|
3733 | };
|
3734 | if (css) {
|
3735 | css = css.replace(/[\u0000-\u001F]/g, '');
|
3736 | css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => {
|
3737 | return str.replace(/[;:]/g, encode);
|
3738 | });
|
3739 | let matches;
|
3740 | while (matches = styleRegExp.exec(css)) {
|
3741 | styleRegExp.lastIndex = matches.index + matches[0].length;
|
3742 | let name = matches[1].replace(trimRightRegExp, '').toLowerCase();
|
3743 | let value = matches[2].replace(trimRightRegExp, '');
|
3744 | if (name && value) {
|
3745 | name = decodeHexSequences(name);
|
3746 | value = decodeHexSequences(value);
|
3747 | if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
|
3748 | continue;
|
3749 | }
|
3750 | if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
|
3751 | continue;
|
3752 | }
|
3753 | if (name === 'font-weight' && value === '700') {
|
3754 | value = 'bold';
|
3755 | } else if (name === 'color' || name === 'background-color') {
|
3756 | value = value.toLowerCase();
|
3757 | }
|
3758 | if (!rgbaRegExp.test(value)) {
|
3759 | fromString(value).each(rgba => {
|
3760 | value = rgbaToHexString(toString(rgba)).toLowerCase();
|
3761 | });
|
3762 | }
|
3763 | value = value.replace(urlOrStrRegExp, processUrl);
|
3764 | styles[name] = isEncoded ? decode(value, true) : value;
|
3765 | }
|
3766 | }
|
3767 | compress('border', '', true);
|
3768 | compress('border', '-width');
|
3769 | compress('border', '-color');
|
3770 | compress('border', '-style');
|
3771 | compress('padding', '');
|
3772 | compress('margin', '');
|
3773 | compress2('border', 'border-width', 'border-style', 'border-color');
|
3774 | if (styles.border === 'medium none') {
|
3775 | delete styles.border;
|
3776 | }
|
3777 | if (styles['border-image'] === 'none') {
|
3778 | delete styles['border-image'];
|
3779 | }
|
3780 | }
|
3781 | return styles;
|
3782 | },
|
3783 | serialize: (styles, elementName) => {
|
3784 | let css = '';
|
3785 | const serializeStyles = (elemName, validStyleList) => {
|
3786 | const styleList = validStyleList[elemName];
|
3787 | if (styleList) {
|
3788 | for (let i = 0, l = styleList.length; i < l; i++) {
|
3789 | const name = styleList[i];
|
3790 | const value = styles[name];
|
3791 | if (value) {
|
3792 | css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
3793 | }
|
3794 | }
|
3795 | }
|
3796 | };
|
3797 | const isValid = (name, elemName) => {
|
3798 | if (!invalidStyles || !elemName) {
|
3799 | return true;
|
3800 | }
|
3801 | let styleMap = invalidStyles['*'];
|
3802 | if (styleMap && styleMap[name]) {
|
3803 | return false;
|
3804 | }
|
3805 | styleMap = invalidStyles[elemName];
|
3806 | return !(styleMap && styleMap[name]);
|
3807 | };
|
3808 | if (elementName && validStyles) {
|
3809 | serializeStyles('*', validStyles);
|
3810 | serializeStyles(elementName, validStyles);
|
3811 | } else {
|
3812 | each$d(styles, (value, name) => {
|
3813 | if (value && isValid(name, elementName)) {
|
3814 | css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
3815 | }
|
3816 | });
|
3817 | }
|
3818 | return css;
|
3819 | }
|
3820 | };
|
3821 | return self;
|
3822 | };
|
3823 |
|
3824 | const deprecated = {
|
3825 | keyLocation: true,
|
3826 | layerX: true,
|
3827 | layerY: true,
|
3828 | returnValue: true,
|
3829 | webkitMovementX: true,
|
3830 | webkitMovementY: true,
|
3831 | keyIdentifier: true,
|
3832 | mozPressure: true
|
3833 | };
|
3834 | const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent);
|
3835 | const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
|
3836 | const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event);
|
3837 | const clone$3 = (originalEvent, data) => {
|
3838 | const event = data !== null && data !== void 0 ? data : {};
|
3839 | for (const name in originalEvent) {
|
3840 | if (!has$2(deprecated, name)) {
|
3841 | event[name] = originalEvent[name];
|
3842 | }
|
3843 | }
|
3844 | if (isNonNullable(originalEvent.composedPath)) {
|
3845 | event.composedPath = () => originalEvent.composedPath();
|
3846 | }
|
3847 | if (isNonNullable(originalEvent.getModifierState)) {
|
3848 | event.getModifierState = keyArg => originalEvent.getModifierState(keyArg);
|
3849 | }
|
3850 | if (isNonNullable(originalEvent.getTargetRanges)) {
|
3851 | event.getTargetRanges = () => originalEvent.getTargetRanges();
|
3852 | }
|
3853 | return event;
|
3854 | };
|
3855 | const normalize$3 = (type, originalEvent, fallbackTarget, data) => {
|
3856 | var _a;
|
3857 | const event = clone$3(originalEvent, data);
|
3858 | event.type = type;
|
3859 | if (isNullable(event.target)) {
|
3860 | event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
|
3861 | }
|
3862 | if (needsNormalizing(originalEvent)) {
|
3863 | event.preventDefault = () => {
|
3864 | event.defaultPrevented = true;
|
3865 | event.isDefaultPrevented = always;
|
3866 | if (isFunction(originalEvent.preventDefault)) {
|
3867 | originalEvent.preventDefault();
|
3868 | }
|
3869 | };
|
3870 | event.stopPropagation = () => {
|
3871 | event.cancelBubble = true;
|
3872 | event.isPropagationStopped = always;
|
3873 | if (isFunction(originalEvent.stopPropagation)) {
|
3874 | originalEvent.stopPropagation();
|
3875 | }
|
3876 | };
|
3877 | event.stopImmediatePropagation = () => {
|
3878 | event.isImmediatePropagationStopped = always;
|
3879 | event.stopPropagation();
|
3880 | };
|
3881 | if (!hasIsDefaultPrevented(event)) {
|
3882 | event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
|
3883 | event.isPropagationStopped = event.cancelBubble === true ? always : never;
|
3884 | event.isImmediatePropagationStopped = never;
|
3885 | }
|
3886 | }
|
3887 | return event;
|
3888 | };
|
3889 |
|
3890 | const eventExpandoPrefix = 'mce-data-';
|
3891 | const mouseEventRe = /^(?:mouse|contextmenu)|click/;
|
3892 | const addEvent = (target, name, callback, capture) => {
|
3893 | target.addEventListener(name, callback, capture || false);
|
3894 | };
|
3895 | const removeEvent = (target, name, callback, capture) => {
|
3896 | target.removeEventListener(name, callback, capture || false);
|
3897 | };
|
3898 | const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type);
|
3899 | const fix = (originalEvent, data) => {
|
3900 | const event = normalize$3(originalEvent.type, originalEvent, document, data);
|
3901 | if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
|
3902 | const eventDoc = event.target.ownerDocument || document;
|
3903 | const doc = eventDoc.documentElement;
|
3904 | const body = eventDoc.body;
|
3905 | const mouseEvent = event;
|
3906 | mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
|
3907 | mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
|
3908 | }
|
3909 | return event;
|
3910 | };
|
3911 | const bindOnReady = (win, callback, eventUtils) => {
|
3912 | const doc = win.document, event = { type: 'ready' };
|
3913 | if (eventUtils.domLoaded) {
|
3914 | callback(event);
|
3915 | return;
|
3916 | }
|
3917 | const isDocReady = () => {
|
3918 | return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
|
3919 | };
|
3920 | const readyHandler = () => {
|
3921 | removeEvent(win, 'DOMContentLoaded', readyHandler);
|
3922 | removeEvent(win, 'load', readyHandler);
|
3923 | if (!eventUtils.domLoaded) {
|
3924 | eventUtils.domLoaded = true;
|
3925 | callback(event);
|
3926 | }
|
3927 | win = null;
|
3928 | };
|
3929 | if (isDocReady()) {
|
3930 | readyHandler();
|
3931 | } else {
|
3932 | addEvent(win, 'DOMContentLoaded', readyHandler);
|
3933 | }
|
3934 | if (!eventUtils.domLoaded) {
|
3935 | addEvent(win, 'load', readyHandler);
|
3936 | }
|
3937 | };
|
3938 | class EventUtils {
|
3939 | constructor() {
|
3940 | this.domLoaded = false;
|
3941 | this.events = {};
|
3942 | this.count = 1;
|
3943 | this.expando = eventExpandoPrefix + (+new Date()).toString(32);
|
3944 | this.hasFocusIn = 'onfocusin' in document.documentElement;
|
3945 | this.count = 1;
|
3946 | }
|
3947 | bind(target, names, callback, scope) {
|
3948 | const self = this;
|
3949 | let callbackList;
|
3950 | const win = window;
|
3951 | const defaultNativeHandler = evt => {
|
3952 | self.executeHandlers(fix(evt || win.event), id);
|
3953 | };
|
3954 | if (!target || isText$b(target) || isComment(target)) {
|
3955 | return callback;
|
3956 | }
|
3957 | let id;
|
3958 | if (!target[self.expando]) {
|
3959 | id = self.count++;
|
3960 | target[self.expando] = id;
|
3961 | self.events[id] = {};
|
3962 | } else {
|
3963 | id = target[self.expando];
|
3964 | }
|
3965 | scope = scope || target;
|
3966 | const namesList = names.split(' ');
|
3967 | let i = namesList.length;
|
3968 | while (i--) {
|
3969 | let name = namesList[i];
|
3970 | let nativeHandler = defaultNativeHandler;
|
3971 | let capture = false;
|
3972 | let fakeName = false;
|
3973 | if (name === 'DOMContentLoaded') {
|
3974 | name = 'ready';
|
3975 | }
|
3976 | if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
|
3977 | callback.call(scope, fix({ type: name }));
|
3978 | continue;
|
3979 | }
|
3980 | if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
|
3981 | capture = true;
|
3982 | fakeName = name === 'focusin' ? 'focus' : 'blur';
|
3983 | nativeHandler = evt => {
|
3984 | const event = fix(evt || win.event);
|
3985 | event.type = event.type === 'focus' ? 'focusin' : 'focusout';
|
3986 | self.executeHandlers(event, id);
|
3987 | };
|
3988 | }
|
3989 | callbackList = self.events[id][name];
|
3990 | if (!callbackList) {
|
3991 | self.events[id][name] = callbackList = [{
|
3992 | func: callback,
|
3993 | scope
|
3994 | }];
|
3995 | callbackList.fakeName = fakeName;
|
3996 | callbackList.capture = capture;
|
3997 | callbackList.nativeHandler = nativeHandler;
|
3998 | if (name === 'ready') {
|
3999 | bindOnReady(target, nativeHandler, self);
|
4000 | } else {
|
4001 | addEvent(target, fakeName || name, nativeHandler, capture);
|
4002 | }
|
4003 | } else {
|
4004 | if (name === 'ready' && self.domLoaded) {
|
4005 | callback(fix({ type: name }));
|
4006 | } else {
|
4007 | callbackList.push({
|
4008 | func: callback,
|
4009 | scope
|
4010 | });
|
4011 | }
|
4012 | }
|
4013 | }
|
4014 | target = callbackList = null;
|
4015 | return callback;
|
4016 | }
|
4017 | unbind(target, names, callback) {
|
4018 | if (!target || isText$b(target) || isComment(target)) {
|
4019 | return this;
|
4020 | }
|
4021 | const id = target[this.expando];
|
4022 | if (id) {
|
4023 | let eventMap = this.events[id];
|
4024 | if (names) {
|
4025 | const namesList = names.split(' ');
|
4026 | let i = namesList.length;
|
4027 | while (i--) {
|
4028 | const name = namesList[i];
|
4029 | const callbackList = eventMap[name];
|
4030 | if (callbackList) {
|
4031 | if (callback) {
|
4032 | let ci = callbackList.length;
|
4033 | while (ci--) {
|
4034 | if (callbackList[ci].func === callback) {
|
4035 | const nativeHandler = callbackList.nativeHandler;
|
4036 | const fakeName = callbackList.fakeName, capture = callbackList.capture;
|
4037 | const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
|
4038 | newCallbackList.nativeHandler = nativeHandler;
|
4039 | newCallbackList.fakeName = fakeName;
|
4040 | newCallbackList.capture = capture;
|
4041 | eventMap[name] = newCallbackList;
|
4042 | }
|
4043 | }
|
4044 | }
|
4045 | if (!callback || callbackList.length === 0) {
|
4046 | delete eventMap[name];
|
4047 | removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
|
4048 | }
|
4049 | }
|
4050 | }
|
4051 | } else {
|
4052 | each$d(eventMap, (callbackList, name) => {
|
4053 | removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
|
4054 | });
|
4055 | eventMap = {};
|
4056 | }
|
4057 | for (const name in eventMap) {
|
4058 | if (has$2(eventMap, name)) {
|
4059 | return this;
|
4060 | }
|
4061 | }
|
4062 | delete this.events[id];
|
4063 | try {
|
4064 | delete target[this.expando];
|
4065 | } catch (ex) {
|
4066 | target[this.expando] = null;
|
4067 | }
|
4068 | }
|
4069 | return this;
|
4070 | }
|
4071 | fire(target, name, args) {
|
4072 | return this.dispatch(target, name, args);
|
4073 | }
|
4074 | dispatch(target, name, args) {
|
4075 | if (!target || isText$b(target) || isComment(target)) {
|
4076 | return this;
|
4077 | }
|
4078 | const event = fix({
|
4079 | type: name,
|
4080 | target
|
4081 | }, args);
|
4082 | do {
|
4083 | const id = target[this.expando];
|
4084 | if (id) {
|
4085 | this.executeHandlers(event, id);
|
4086 | }
|
4087 | target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
|
4088 | } while (target && !event.isPropagationStopped());
|
4089 | return this;
|
4090 | }
|
4091 | clean(target) {
|
4092 | if (!target || isText$b(target) || isComment(target)) {
|
4093 | return this;
|
4094 | }
|
4095 | if (target[this.expando]) {
|
4096 | this.unbind(target);
|
4097 | }
|
4098 | if (!target.getElementsByTagName) {
|
4099 | target = target.document;
|
4100 | }
|
4101 | if (target && target.getElementsByTagName) {
|
4102 | this.unbind(target);
|
4103 | const children = target.getElementsByTagName('*');
|
4104 | let i = children.length;
|
4105 | while (i--) {
|
4106 | target = children[i];
|
4107 | if (target[this.expando]) {
|
4108 | this.unbind(target);
|
4109 | }
|
4110 | }
|
4111 | }
|
4112 | return this;
|
4113 | }
|
4114 | destroy() {
|
4115 | this.events = {};
|
4116 | }
|
4117 | cancel(e) {
|
4118 | if (e) {
|
4119 | e.preventDefault();
|
4120 | e.stopImmediatePropagation();
|
4121 | }
|
4122 | return false;
|
4123 | }
|
4124 | executeHandlers(evt, id) {
|
4125 | const container = this.events[id];
|
4126 | const callbackList = container && container[evt.type];
|
4127 | if (callbackList) {
|
4128 | for (let i = 0, l = callbackList.length; i < l; i++) {
|
4129 | const callback = callbackList[i];
|
4130 | if (callback && callback.func.call(callback.scope, evt) === false) {
|
4131 | evt.preventDefault();
|
4132 | }
|
4133 | if (evt.isImmediatePropagationStopped()) {
|
4134 | return;
|
4135 | }
|
4136 | }
|
4137 | }
|
4138 | }
|
4139 | }
|
4140 | EventUtils.Event = new EventUtils();
|
4141 |
|
4142 | const each$a = Tools.each;
|
4143 | const grep = Tools.grep;
|
4144 | const internalStyleName = 'data-mce-style';
|
4145 | const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' ');
|
4146 | const legacySetAttribute = (elm, name, value) => {
|
4147 | if (isNullable(value) || value === '') {
|
4148 | remove$9(elm, name);
|
4149 | } else {
|
4150 | set$3(elm, name, value);
|
4151 | }
|
4152 | };
|
4153 | const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase());
|
4154 | const findNodeIndex = (node, normalized) => {
|
4155 | let idx = 0;
|
4156 | if (node) {
|
4157 | for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) {
|
4158 | const nodeType = tempNode.nodeType;
|
4159 | if (normalized && isText$b(tempNode)) {
|
4160 | if (nodeType === lastNodeType || !tempNode.data.length) {
|
4161 | continue;
|
4162 | }
|
4163 | }
|
4164 | idx++;
|
4165 | lastNodeType = nodeType;
|
4166 | }
|
4167 | }
|
4168 | return idx;
|
4169 | };
|
4170 | const updateInternalStyleAttr = (styles, elm) => {
|
4171 | const rawValue = get$9(elm, 'style');
|
4172 | const value = styles.serialize(styles.parse(rawValue), name(elm));
|
4173 | legacySetAttribute(elm, internalStyleName, value);
|
4174 | };
|
4175 | const convertStyleToString = (cssValue, cssName) => {
|
4176 | if (isNumber(cssValue)) {
|
4177 | return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px';
|
4178 | } else {
|
4179 | return cssValue;
|
4180 | }
|
4181 | };
|
4182 | const applyStyle$1 = ($elm, cssName, cssValue) => {
|
4183 | const normalizedName = camelCaseToHyphens(cssName);
|
4184 | if (isNullable(cssValue) || cssValue === '') {
|
4185 | remove$5($elm, normalizedName);
|
4186 | } else {
|
4187 | set$2($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
|
4188 | }
|
4189 | };
|
4190 | const setupAttrHooks = (styles, settings, getContext) => {
|
4191 | const keepValues = settings.keep_values;
|
4192 | const keepUrlHook = {
|
4193 | set: (elm, value, name) => {
|
4194 | const sugarElm = SugarElement.fromDom(elm);
|
4195 | if (isFunction(settings.url_converter) && isNonNullable(value)) {
|
4196 | value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm);
|
4197 | }
|
4198 | const internalName = 'data-mce-' + name;
|
4199 | legacySetAttribute(sugarElm, internalName, value);
|
4200 | legacySetAttribute(sugarElm, name, value);
|
4201 | },
|
4202 | get: (elm, name) => {
|
4203 | const sugarElm = SugarElement.fromDom(elm);
|
4204 | return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name);
|
4205 | }
|
4206 | };
|
4207 | const attrHooks = {
|
4208 | style: {
|
4209 | set: (elm, value) => {
|
4210 | const sugarElm = SugarElement.fromDom(elm);
|
4211 | if (keepValues) {
|
4212 | legacySetAttribute(sugarElm, internalStyleName, value);
|
4213 | }
|
4214 | remove$9(sugarElm, 'style');
|
4215 | if (isString(value)) {
|
4216 | setAll(sugarElm, styles.parse(value));
|
4217 | }
|
4218 | },
|
4219 | get: elm => {
|
4220 | const sugarElm = SugarElement.fromDom(elm);
|
4221 | const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style');
|
4222 | return styles.serialize(styles.parse(value), name(sugarElm));
|
4223 | }
|
4224 | }
|
4225 | };
|
4226 | if (keepValues) {
|
4227 | attrHooks.href = attrHooks.src = keepUrlHook;
|
4228 | }
|
4229 | return attrHooks;
|
4230 | };
|
4231 | const DOMUtils = (doc, settings = {}) => {
|
4232 | const addedStyles = {};
|
4233 | const win = window;
|
4234 | const files = {};
|
4235 | let counter = 0;
|
4236 | const stdMode = true;
|
4237 | const boxModel = true;
|
4238 | const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
|
4239 | contentCssCors: settings.contentCssCors,
|
4240 | referrerPolicy: settings.referrerPolicy
|
4241 | });
|
4242 | const boundEvents = [];
|
4243 | const schema = settings.schema ? settings.schema : Schema({});
|
4244 | const styles = Styles({
|
4245 | url_converter: settings.url_converter,
|
4246 | url_converter_scope: settings.url_converter_scope
|
4247 | }, settings.schema);
|
4248 | const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
|
4249 | const blockElementsMap = schema.getBlockElements();
|
4250 | const isBlock = node => {
|
4251 | if (isString(node)) {
|
4252 | return has$2(blockElementsMap, node);
|
4253 | } else {
|
4254 | return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node));
|
4255 | }
|
4256 | };
|
4257 | const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
|
4258 | const _get = elm => {
|
4259 | const value = get(elm);
|
4260 | return isNonNullable(value) ? SugarElement.fromDom(value) : null;
|
4261 | };
|
4262 | const getAttrib = (elm, name, defaultVal = '') => {
|
4263 | let value;
|
4264 | const $elm = _get(elm);
|
4265 | if (isNonNullable($elm) && isElement$7($elm)) {
|
4266 | const hook = attrHooks[name];
|
4267 | if (hook && hook.get) {
|
4268 | value = hook.get($elm.dom, name);
|
4269 | } else {
|
4270 | value = get$9($elm, name);
|
4271 | }
|
4272 | }
|
4273 | return isNonNullable(value) ? value : defaultVal;
|
4274 | };
|
4275 | const getAttribs = elm => {
|
4276 | const node = get(elm);
|
4277 | return isNullable(node) ? [] : node.attributes;
|
4278 | };
|
4279 | const setAttrib = (elm, name, value) => {
|
4280 | run(elm, e => {
|
4281 | if (isElement$6(e)) {
|
4282 | const $elm = SugarElement.fromDom(e);
|
4283 | const val = value === '' ? null : value;
|
4284 | const originalValue = get$9($elm, name);
|
4285 | const hook = attrHooks[name];
|
4286 | if (hook && hook.set) {
|
4287 | hook.set($elm.dom, val, name);
|
4288 | } else {
|
4289 | legacySetAttribute($elm, name, val);
|
4290 | }
|
4291 | if (originalValue !== val && settings.onSetAttrib) {
|
4292 | settings.onSetAttrib({
|
4293 | attrElm: $elm.dom,
|
4294 | attrName: name,
|
4295 | attrValue: val
|
4296 | });
|
4297 | }
|
4298 | }
|
4299 | });
|
4300 | };
|
4301 | const clone = (node, deep) => {
|
4302 | return node.cloneNode(deep);
|
4303 | };
|
4304 | const getRoot = () => settings.root_element || doc.body;
|
4305 | const getViewPort = argWin => {
|
4306 | const vp = getBounds(argWin);
|
4307 | return {
|
4308 | x: vp.x,
|
4309 | y: vp.y,
|
4310 | w: vp.width,
|
4311 | h: vp.height
|
4312 | };
|
4313 | };
|
4314 | const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm);
|
4315 | const setStyle = (elm, name, value) => {
|
4316 | run(elm, e => {
|
4317 | const $elm = SugarElement.fromDom(e);
|
4318 | applyStyle$1($elm, name, value);
|
4319 | if (settings.update_styles) {
|
4320 | updateInternalStyleAttr(styles, $elm);
|
4321 | }
|
4322 | });
|
4323 | };
|
4324 | const setStyles = (elm, stylesArg) => {
|
4325 | run(elm, e => {
|
4326 | const $elm = SugarElement.fromDom(e);
|
4327 | each$d(stylesArg, (v, n) => {
|
4328 | applyStyle$1($elm, n, v);
|
4329 | });
|
4330 | if (settings.update_styles) {
|
4331 | updateInternalStyleAttr(styles, $elm);
|
4332 | }
|
4333 | });
|
4334 | };
|
4335 | const getStyle = (elm, name, computed) => {
|
4336 | const $elm = get(elm);
|
4337 | if (isNullable($elm) || !isHTMLElement($elm) && !isSVGElement($elm)) {
|
4338 | return undefined;
|
4339 | }
|
4340 | if (computed) {
|
4341 | return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name));
|
4342 | } else {
|
4343 | name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase());
|
4344 | if (name === 'float') {
|
4345 | name = 'cssFloat';
|
4346 | }
|
4347 | return $elm.style ? $elm.style[name] : undefined;
|
4348 | }
|
4349 | };
|
4350 | const getSize = elm => {
|
4351 | const $elm = get(elm);
|
4352 | if (!$elm) {
|
4353 | return {
|
4354 | w: 0,
|
4355 | h: 0
|
4356 | };
|
4357 | }
|
4358 | let w = getStyle($elm, 'width');
|
4359 | let h = getStyle($elm, 'height');
|
4360 | if (!w || w.indexOf('px') === -1) {
|
4361 | w = '0';
|
4362 | }
|
4363 | if (!h || h.indexOf('px') === -1) {
|
4364 | h = '0';
|
4365 | }
|
4366 | return {
|
4367 | w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
|
4368 | h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight
|
4369 | };
|
4370 | };
|
4371 | const getRect = elm => {
|
4372 | const $elm = get(elm);
|
4373 | const pos = getPos$1($elm);
|
4374 | const size = getSize($elm);
|
4375 | return {
|
4376 | x: pos.x,
|
4377 | y: pos.y,
|
4378 | w: size.w,
|
4379 | h: size.h
|
4380 | };
|
4381 | };
|
4382 | const is = (elm, selector) => {
|
4383 | if (!elm) {
|
4384 | return false;
|
4385 | }
|
4386 | const elms = isArray$1(elm) ? elm : [elm];
|
4387 | return exists(elms, e => {
|
4388 | return is$1(SugarElement.fromDom(e), selector);
|
4389 | });
|
4390 | };
|
4391 | const getParents = (elm, selector, root, collect) => {
|
4392 | const result = [];
|
4393 | let node = get(elm);
|
4394 | collect = collect === undefined;
|
4395 | const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
|
4396 | if (isString(selector)) {
|
4397 | if (selector === '*') {
|
4398 | selector = isElement$6;
|
4399 | } else {
|
4400 | const selectorVal = selector;
|
4401 | selector = node => is(node, selectorVal);
|
4402 | }
|
4403 | }
|
4404 | while (node) {
|
4405 | if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
|
4406 | break;
|
4407 | }
|
4408 | if (!selector || selector(node)) {
|
4409 | if (collect) {
|
4410 | result.push(node);
|
4411 | } else {
|
4412 | return [node];
|
4413 | }
|
4414 | }
|
4415 | node = node.parentNode;
|
4416 | }
|
4417 | return collect ? result : null;
|
4418 | };
|
4419 | const getParent = (node, selector, root) => {
|
4420 | const parents = getParents(node, selector, root, false);
|
4421 | return parents && parents.length > 0 ? parents[0] : null;
|
4422 | };
|
4423 | const _findSib = (node, selector, name) => {
|
4424 | let func = selector;
|
4425 | if (node) {
|
4426 | if (isString(selector)) {
|
4427 | func = node => {
|
4428 | return is(node, selector);
|
4429 | };
|
4430 | }
|
4431 | for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) {
|
4432 | if (isFunction(func) && func(tempNode)) {
|
4433 | return tempNode;
|
4434 | }
|
4435 | }
|
4436 | }
|
4437 | return null;
|
4438 | };
|
4439 | const getNext = (node, selector) => _findSib(node, selector, 'nextSibling');
|
4440 | const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling');
|
4441 | const isParentNode = node => isFunction(node.querySelectorAll);
|
4442 | const select = (selector, scope) => {
|
4443 | var _a, _b;
|
4444 | const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
|
4445 | return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : [];
|
4446 | };
|
4447 | const run = function (elm, func, scope) {
|
4448 | const context = scope !== null && scope !== void 0 ? scope : this;
|
4449 | if (isArray$1(elm)) {
|
4450 | const result = [];
|
4451 | each$a(elm, (e, i) => {
|
4452 | const node = get(e);
|
4453 | if (node) {
|
4454 | result.push(func.call(context, node, i));
|
4455 | }
|
4456 | });
|
4457 | return result;
|
4458 | } else {
|
4459 | const node = get(elm);
|
4460 | return !node ? false : func.call(context, node);
|
4461 | }
|
4462 | };
|
4463 | const setAttribs = (elm, attrs) => {
|
4464 | run(elm, $elm => {
|
4465 | each$d(attrs, (value, name) => {
|
4466 | setAttrib($elm, name, value);
|
4467 | });
|
4468 | });
|
4469 | };
|
4470 | const setHTML = (elm, html) => {
|
4471 | run(elm, e => {
|
4472 | const $elm = SugarElement.fromDom(e);
|
4473 | set$1($elm, html);
|
4474 | });
|
4475 | };
|
4476 | const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => {
|
4477 | const newElm = isString(name) ? doc.createElement(name) : name;
|
4478 | if (isNonNullable(attrs)) {
|
4479 | setAttribs(newElm, attrs);
|
4480 | }
|
4481 | if (html) {
|
4482 | if (!isString(html) && html.nodeType) {
|
4483 | newElm.appendChild(html);
|
4484 | } else if (isString(html)) {
|
4485 | setHTML(newElm, html);
|
4486 | }
|
4487 | }
|
4488 | return !create ? parentElm.appendChild(newElm) : newElm;
|
4489 | });
|
4490 | const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true);
|
4491 | const decode = Entities.decode;
|
4492 | const encode = Entities.encodeAllRaw;
|
4493 | const createHTML = (name, attrs, html = '') => {
|
4494 | let outHtml = '<' + name;
|
4495 | for (const key in attrs) {
|
4496 | if (hasNonNullableKey(attrs, key)) {
|
4497 | outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
|
4498 | }
|
4499 | }
|
4500 | if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) {
|
4501 | return outHtml + ' />';
|
4502 | } else {
|
4503 | return outHtml + '>' + html + '</' + name + '>';
|
4504 | }
|
4505 | };
|
4506 | const createFragment = html => {
|
4507 | const container = doc.createElement('div');
|
4508 | const frag = doc.createDocumentFragment();
|
4509 | frag.appendChild(container);
|
4510 | if (html) {
|
4511 | container.innerHTML = html;
|
4512 | }
|
4513 | let node;
|
4514 | while (node = container.firstChild) {
|
4515 | frag.appendChild(node);
|
4516 | }
|
4517 | frag.removeChild(container);
|
4518 | return frag;
|
4519 | };
|
4520 | const remove = (node, keepChildren) => {
|
4521 | return run(node, n => {
|
4522 | const $node = SugarElement.fromDom(n);
|
4523 | if (keepChildren) {
|
4524 | each$e(children$1($node), child => {
|
4525 | if (isText$c(child) && child.dom.length === 0) {
|
4526 | remove$4(child);
|
4527 | } else {
|
4528 | before$3($node, child);
|
4529 | }
|
4530 | });
|
4531 | }
|
4532 | remove$4($node);
|
4533 | return $node.dom;
|
4534 | });
|
4535 | };
|
4536 | const removeAllAttribs = e => run(e, e => {
|
4537 | const attrs = e.attributes;
|
4538 | for (let i = attrs.length - 1; i >= 0; i--) {
|
4539 | e.removeAttributeNode(attrs.item(i));
|
4540 | }
|
4541 | });
|
4542 | const parseStyle = cssText => styles.parse(cssText);
|
4543 | const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name);
|
4544 | const addStyle = cssText => {
|
4545 | if (self !== DOMUtils.DOM && doc === document) {
|
4546 | if (addedStyles[cssText]) {
|
4547 | return;
|
4548 | }
|
4549 | addedStyles[cssText] = true;
|
4550 | }
|
4551 | let styleElm = doc.getElementById('mceDefaultStyles');
|
4552 | if (!styleElm) {
|
4553 | styleElm = doc.createElement('style');
|
4554 | styleElm.id = 'mceDefaultStyles';
|
4555 | styleElm.type = 'text/css';
|
4556 | const head = doc.head;
|
4557 | if (head.firstChild) {
|
4558 | head.insertBefore(styleElm, head.firstChild);
|
4559 | } else {
|
4560 | head.appendChild(styleElm);
|
4561 | }
|
4562 | }
|
4563 | if (styleElm.styleSheet) {
|
4564 | styleElm.styleSheet.cssText += cssText;
|
4565 | } else {
|
4566 | styleElm.appendChild(doc.createTextNode(cssText));
|
4567 | }
|
4568 | };
|
4569 | const loadCSS = urls => {
|
4570 | if (!urls) {
|
4571 | urls = '';
|
4572 | }
|
4573 | each$e(urls.split(','), url => {
|
4574 | files[url] = true;
|
4575 | styleSheetLoader.load(url).catch(noop);
|
4576 | });
|
4577 | };
|
4578 | const toggleClass = (elm, cls, state) => {
|
4579 | run(elm, e => {
|
4580 | if (isElement$6(e)) {
|
4581 | const $elm = SugarElement.fromDom(e);
|
4582 | const classes = cls.split(' ');
|
4583 | each$e(classes, c => {
|
4584 | if (isNonNullable(state)) {
|
4585 | const fn = state ? add$2 : remove$6;
|
4586 | fn($elm, c);
|
4587 | } else {
|
4588 | toggle$1($elm, c);
|
4589 | }
|
4590 | });
|
4591 | }
|
4592 | });
|
4593 | };
|
4594 | const addClass = (elm, cls) => {
|
4595 | toggleClass(elm, cls, true);
|
4596 | };
|
4597 | const removeClass = (elm, cls) => {
|
4598 | toggleClass(elm, cls, false);
|
4599 | };
|
4600 | const hasClass = (elm, cls) => {
|
4601 | const $elm = _get(elm);
|
4602 | const classes = cls.split(' ');
|
4603 | return isNonNullable($elm) && forall(classes, c => has($elm, c));
|
4604 | };
|
4605 | const show = elm => {
|
4606 | run(elm, e => remove$5(SugarElement.fromDom(e), 'display'));
|
4607 | };
|
4608 | const hide = elm => {
|
4609 | run(elm, e => set$2(SugarElement.fromDom(e), 'display', 'none'));
|
4610 | };
|
4611 | const isHidden = elm => {
|
4612 | const $elm = _get(elm);
|
4613 | return isNonNullable($elm) && is$2(getRaw($elm, 'display'), 'none');
|
4614 | };
|
4615 | const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++;
|
4616 | const getOuterHTML = elm => {
|
4617 | const $elm = _get(elm);
|
4618 | if (isNonNullable($elm)) {
|
4619 | return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
|
4620 | } else {
|
4621 | return '';
|
4622 | }
|
4623 | };
|
4624 | const setOuterHTML = (elm, html) => {
|
4625 | run(elm, $elm => {
|
4626 | if (isElement$6($elm)) {
|
4627 | $elm.outerHTML = html;
|
4628 | }
|
4629 | });
|
4630 | };
|
4631 | const insertAfter = (node, reference) => {
|
4632 | const referenceNode = get(reference);
|
4633 | return run(node, node => {
|
4634 | const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode;
|
4635 | const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling;
|
4636 | if (parent) {
|
4637 | if (nextSibling) {
|
4638 | parent.insertBefore(node, nextSibling);
|
4639 | } else {
|
4640 | parent.appendChild(node);
|
4641 | }
|
4642 | }
|
4643 | return node;
|
4644 | });
|
4645 | };
|
4646 | const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => {
|
4647 | var _a;
|
4648 | const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm;
|
4649 | if (keepChildren) {
|
4650 | each$a(grep(elm.childNodes), node => {
|
4651 | replacee.appendChild(node);
|
4652 | });
|
4653 | }
|
4654 | (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm);
|
4655 | return elm;
|
4656 | });
|
4657 | const rename = (elm, name) => {
|
4658 | if (elm.nodeName !== name.toUpperCase()) {
|
4659 | const newElm = create(name);
|
4660 | each$a(getAttribs(elm), attrNode => {
|
4661 | setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
|
4662 | });
|
4663 | replace(newElm, elm, true);
|
4664 | return newElm;
|
4665 | } else {
|
4666 | return elm;
|
4667 | }
|
4668 | };
|
4669 | const findCommonAncestor = (a, b) => {
|
4670 | let ps = a;
|
4671 | while (ps) {
|
4672 | let pe = b;
|
4673 | while (pe && ps !== pe) {
|
4674 | pe = pe.parentNode;
|
4675 | }
|
4676 | if (ps === pe) {
|
4677 | break;
|
4678 | }
|
4679 | ps = ps.parentNode;
|
4680 | }
|
4681 | if (!ps && a.ownerDocument) {
|
4682 | return a.ownerDocument.documentElement;
|
4683 | } else {
|
4684 | return ps;
|
4685 | }
|
4686 | };
|
4687 | const isEmpty = (node, elements, options) => {
|
4688 | if (isPlainObject(elements)) {
|
4689 | const isContent = node => {
|
4690 | const name = node.nodeName.toLowerCase();
|
4691 | return Boolean(elements[name]);
|
4692 | };
|
4693 | return isEmptyNode(schema, node, {
|
4694 | ...options,
|
4695 | isContent
|
4696 | });
|
4697 | } else {
|
4698 | return isEmptyNode(schema, node, options);
|
4699 | }
|
4700 | };
|
4701 | const createRng = () => doc.createRange();
|
4702 | const split = (parentElm, splitElm, replacementElm) => {
|
4703 | let range = createRng();
|
4704 | let beforeFragment;
|
4705 | let afterFragment;
|
4706 | if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) {
|
4707 | const parentNode = parentElm.parentNode;
|
4708 | range.setStart(parentNode, findNodeIndex(parentElm));
|
4709 | range.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
|
4710 | beforeFragment = range.extractContents();
|
4711 | range = createRng();
|
4712 | range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
|
4713 | range.setEnd(parentNode, findNodeIndex(parentElm) + 1);
|
4714 | afterFragment = range.extractContents();
|
4715 | parentNode.insertBefore(trimNode(self, beforeFragment, schema), parentElm);
|
4716 | if (replacementElm) {
|
4717 | parentNode.insertBefore(replacementElm, parentElm);
|
4718 | } else {
|
4719 | parentNode.insertBefore(splitElm, parentElm);
|
4720 | }
|
4721 | parentNode.insertBefore(trimNode(self, afterFragment, schema), parentElm);
|
4722 | remove(parentElm);
|
4723 | return replacementElm || splitElm;
|
4724 | } else {
|
4725 | return undefined;
|
4726 | }
|
4727 | };
|
4728 | const bind = (target, name, func, scope) => {
|
4729 | if (isArray$1(target)) {
|
4730 | let i = target.length;
|
4731 | const rv = [];
|
4732 | while (i--) {
|
4733 | rv[i] = bind(target[i], name, func, scope);
|
4734 | }
|
4735 | return rv;
|
4736 | } else {
|
4737 | if (settings.collect && (target === doc || target === win)) {
|
4738 | boundEvents.push([
|
4739 | target,
|
4740 | name,
|
4741 | func,
|
4742 | scope
|
4743 | ]);
|
4744 | }
|
4745 | return events.bind(target, name, func, scope || self);
|
4746 | }
|
4747 | };
|
4748 | const unbind = (target, name, func) => {
|
4749 | if (isArray$1(target)) {
|
4750 | let i = target.length;
|
4751 | const rv = [];
|
4752 | while (i--) {
|
4753 | rv[i] = unbind(target[i], name, func);
|
4754 | }
|
4755 | return rv;
|
4756 | } else {
|
4757 | if (boundEvents.length > 0 && (target === doc || target === win)) {
|
4758 | let i = boundEvents.length;
|
4759 | while (i--) {
|
4760 | const [boundTarget, boundName, boundFunc] = boundEvents[i];
|
4761 | if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) {
|
4762 | events.unbind(boundTarget, boundName, boundFunc);
|
4763 | }
|
4764 | }
|
4765 | }
|
4766 | return events.unbind(target, name, func);
|
4767 | }
|
4768 | };
|
4769 | const dispatch = (target, name, evt) => events.dispatch(target, name, evt);
|
4770 | const fire = (target, name, evt) => events.dispatch(target, name, evt);
|
4771 | const getContentEditable = node => {
|
4772 | if (node && isHTMLElement(node)) {
|
4773 | const contentEditable = node.getAttribute('data-mce-contenteditable');
|
4774 | if (contentEditable && contentEditable !== 'inherit') {
|
4775 | return contentEditable;
|
4776 | }
|
4777 | return node.contentEditable !== 'inherit' ? node.contentEditable : null;
|
4778 | } else {
|
4779 | return null;
|
4780 | }
|
4781 | };
|
4782 | const getContentEditableParent = node => {
|
4783 | const root = getRoot();
|
4784 | let state = null;
|
4785 | for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
|
4786 | state = getContentEditable(tempNode);
|
4787 | if (state !== null) {
|
4788 | break;
|
4789 | }
|
4790 | }
|
4791 | return state;
|
4792 | };
|
4793 | const isEditable = node => {
|
4794 | if (isNonNullable(node)) {
|
4795 | const scope = isElement$6(node) ? node : node.parentElement;
|
4796 | return isNonNullable(scope) && isHTMLElement(scope) && isEditable$2(SugarElement.fromDom(scope));
|
4797 | } else {
|
4798 | return false;
|
4799 | }
|
4800 | };
|
4801 | const destroy = () => {
|
4802 | if (boundEvents.length > 0) {
|
4803 | let i = boundEvents.length;
|
4804 | while (i--) {
|
4805 | const [boundTarget, boundName, boundFunc] = boundEvents[i];
|
4806 | events.unbind(boundTarget, boundName, boundFunc);
|
4807 | }
|
4808 | }
|
4809 | each$d(files, (_, url) => {
|
4810 | styleSheetLoader.unload(url);
|
4811 | delete files[url];
|
4812 | });
|
4813 | };
|
4814 | const isChildOf = (node, parent) => {
|
4815 | return node === parent || parent.contains(node);
|
4816 | };
|
4817 | const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
|
4818 | const self = {
|
4819 | doc,
|
4820 | settings,
|
4821 | win,
|
4822 | files,
|
4823 | stdMode,
|
4824 | boxModel,
|
4825 | styleSheetLoader,
|
4826 | boundEvents,
|
4827 | styles,
|
4828 | schema,
|
4829 | events,
|
4830 | isBlock: isBlock,
|
4831 | root: null,
|
4832 | clone,
|
4833 | getRoot,
|
4834 | getViewPort,
|
4835 | getRect,
|
4836 | getSize,
|
4837 | getParent,
|
4838 | getParents: getParents,
|
4839 | get,
|
4840 | getNext,
|
4841 | getPrev,
|
4842 | select,
|
4843 | is,
|
4844 | add,
|
4845 | create,
|
4846 | createHTML,
|
4847 | createFragment,
|
4848 | remove,
|
4849 | setStyle,
|
4850 | getStyle: getStyle,
|
4851 | setStyles,
|
4852 | removeAllAttribs,
|
4853 | setAttrib,
|
4854 | setAttribs,
|
4855 | getAttrib,
|
4856 | getPos: getPos$1,
|
4857 | parseStyle,
|
4858 | serializeStyle,
|
4859 | addStyle,
|
4860 | loadCSS,
|
4861 | addClass,
|
4862 | removeClass,
|
4863 | hasClass,
|
4864 | toggleClass,
|
4865 | show,
|
4866 | hide,
|
4867 | isHidden,
|
4868 | uniqueId,
|
4869 | setHTML,
|
4870 | getOuterHTML,
|
4871 | setOuterHTML,
|
4872 | decode,
|
4873 | encode,
|
4874 | insertAfter,
|
4875 | replace,
|
4876 | rename,
|
4877 | findCommonAncestor,
|
4878 | run,
|
4879 | getAttribs,
|
4880 | isEmpty,
|
4881 | createRng,
|
4882 | nodeIndex: findNodeIndex,
|
4883 | split,
|
4884 | bind: bind,
|
4885 | unbind: unbind,
|
4886 | fire,
|
4887 | dispatch,
|
4888 | getContentEditable,
|
4889 | getContentEditableParent,
|
4890 | isEditable,
|
4891 | destroy,
|
4892 | isChildOf,
|
4893 | dumpRng
|
4894 | };
|
4895 | const attrHooks = setupAttrHooks(styles, settings, constant(self));
|
4896 | return self;
|
4897 | };
|
4898 | DOMUtils.DOM = DOMUtils(document);
|
4899 | DOMUtils.nodeIndex = findNodeIndex;
|
4900 |
|
4901 | const DOM$b = DOMUtils.DOM;
|
4902 | const QUEUED = 0;
|
4903 | const LOADING = 1;
|
4904 | const LOADED = 2;
|
4905 | const FAILED = 3;
|
4906 | class ScriptLoader {
|
4907 | constructor(settings = {}) {
|
4908 | this.states = {};
|
4909 | this.queue = [];
|
4910 | this.scriptLoadedCallbacks = {};
|
4911 | this.queueLoadedCallbacks = [];
|
4912 | this.loading = false;
|
4913 | this.settings = settings;
|
4914 | }
|
4915 | _setReferrerPolicy(referrerPolicy) {
|
4916 | this.settings.referrerPolicy = referrerPolicy;
|
4917 | }
|
4918 | loadScript(url) {
|
4919 | return new Promise((resolve, reject) => {
|
4920 | const dom = DOM$b;
|
4921 | let elm;
|
4922 | const cleanup = () => {
|
4923 | dom.remove(id);
|
4924 | if (elm) {
|
4925 | elm.onerror = elm.onload = elm = null;
|
4926 | }
|
4927 | };
|
4928 | const done = () => {
|
4929 | cleanup();
|
4930 | resolve();
|
4931 | };
|
4932 | const error = () => {
|
4933 | cleanup();
|
4934 | reject('Failed to load script: ' + url);
|
4935 | };
|
4936 | const id = dom.uniqueId();
|
4937 | elm = document.createElement('script');
|
4938 | elm.id = id;
|
4939 | elm.type = 'text/javascript';
|
4940 | elm.src = Tools._addCacheSuffix(url);
|
4941 | if (this.settings.referrerPolicy) {
|
4942 | dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
|
4943 | }
|
4944 | elm.onload = done;
|
4945 | elm.onerror = error;
|
4946 | (document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
|
4947 | });
|
4948 | }
|
4949 | isDone(url) {
|
4950 | return this.states[url] === LOADED;
|
4951 | }
|
4952 | markDone(url) {
|
4953 | this.states[url] = LOADED;
|
4954 | }
|
4955 | add(url) {
|
4956 | const self = this;
|
4957 | self.queue.push(url);
|
4958 | const state = self.states[url];
|
4959 | if (state === undefined) {
|
4960 | self.states[url] = QUEUED;
|
4961 | }
|
4962 | return new Promise((resolve, reject) => {
|
4963 | if (!self.scriptLoadedCallbacks[url]) {
|
4964 | self.scriptLoadedCallbacks[url] = [];
|
4965 | }
|
4966 | self.scriptLoadedCallbacks[url].push({
|
4967 | resolve,
|
4968 | reject
|
4969 | });
|
4970 | });
|
4971 | }
|
4972 | load(url) {
|
4973 | return this.add(url);
|
4974 | }
|
4975 | remove(url) {
|
4976 | delete this.states[url];
|
4977 | delete this.scriptLoadedCallbacks[url];
|
4978 | }
|
4979 | loadQueue() {
|
4980 | const queue = this.queue;
|
4981 | this.queue = [];
|
4982 | return this.loadScripts(queue);
|
4983 | }
|
4984 | loadScripts(scripts) {
|
4985 | const self = this;
|
4986 | const execCallbacks = (name, url) => {
|
4987 | get$a(self.scriptLoadedCallbacks, url).each(callbacks => {
|
4988 | each$e(callbacks, callback => callback[name](url));
|
4989 | });
|
4990 | delete self.scriptLoadedCallbacks[url];
|
4991 | };
|
4992 | const processResults = results => {
|
4993 | const failures = filter$5(results, result => result.status === 'rejected');
|
4994 | if (failures.length > 0) {
|
4995 | return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason]));
|
4996 | } else {
|
4997 | return Promise.resolve();
|
4998 | }
|
4999 | };
|
5000 | const load = urls => Promise.allSettled(map$3(urls, url => {
|
5001 | if (self.states[url] === LOADED) {
|
5002 | execCallbacks('resolve', url);
|
5003 | return Promise.resolve();
|
5004 | } else if (self.states[url] === FAILED) {
|
5005 | execCallbacks('reject', url);
|
5006 | return Promise.reject(url);
|
5007 | } else {
|
5008 | self.states[url] = LOADING;
|
5009 | return self.loadScript(url).then(() => {
|
5010 | self.states[url] = LOADED;
|
5011 | execCallbacks('resolve', url);
|
5012 | const queue = self.queue;
|
5013 | if (queue.length > 0) {
|
5014 | self.queue = [];
|
5015 | return load(queue).then(processResults);
|
5016 | } else {
|
5017 | return Promise.resolve();
|
5018 | }
|
5019 | }, () => {
|
5020 | self.states[url] = FAILED;
|
5021 | execCallbacks('reject', url);
|
5022 | return Promise.reject(url);
|
5023 | });
|
5024 | }
|
5025 | }));
|
5026 | const processQueue = urls => {
|
5027 | self.loading = true;
|
5028 | return load(urls).then(results => {
|
5029 | self.loading = false;
|
5030 | const nextQueuedItem = self.queueLoadedCallbacks.shift();
|
5031 | Optional.from(nextQueuedItem).each(call);
|
5032 | return processResults(results);
|
5033 | });
|
5034 | };
|
5035 | const uniqueScripts = stringArray(scripts);
|
5036 | if (self.loading) {
|
5037 | return new Promise((resolve, reject) => {
|
5038 | self.queueLoadedCallbacks.push(() => {
|
5039 | processQueue(uniqueScripts).then(resolve, reject);
|
5040 | });
|
5041 | });
|
5042 | } else {
|
5043 | return processQueue(uniqueScripts);
|
5044 | }
|
5045 | }
|
5046 | }
|
5047 | ScriptLoader.ScriptLoader = new ScriptLoader();
|
5048 |
|
5049 | const isDuplicated = (items, item) => {
|
5050 | const firstIndex = items.indexOf(item);
|
5051 | return firstIndex !== -1 && items.indexOf(item, firstIndex + 1) > firstIndex;
|
5052 | };
|
5053 | const isRaw = str => isObject(str) && has$2(str, 'raw');
|
5054 | const isTokenised = str => isArray$1(str) && str.length > 1;
|
5055 | const data = {};
|
5056 | const currentCode = Cell('en');
|
5057 | const getLanguageData = () => get$a(data, currentCode.get());
|
5058 | const getData$1 = () => map$2(data, value => ({ ...value }));
|
5059 | const setCode = newCode => {
|
5060 | if (newCode) {
|
5061 | currentCode.set(newCode);
|
5062 | }
|
5063 | };
|
5064 | const getCode = () => currentCode.get();
|
5065 | const add$1 = (code, items) => {
|
5066 | let langData = data[code];
|
5067 | if (!langData) {
|
5068 | data[code] = langData = {};
|
5069 | }
|
5070 | const lcNames = map$3(keys(items), name => name.toLowerCase());
|
5071 | each$d(items, (translation, name) => {
|
5072 | const lcName = name.toLowerCase();
|
5073 | if (lcName !== name && isDuplicated(lcNames, lcName)) {
|
5074 | if (!has$2(items, lcName)) {
|
5075 | langData[lcName] = translation;
|
5076 | }
|
5077 | langData[name] = translation;
|
5078 | } else {
|
5079 | langData[lcName] = translation;
|
5080 | }
|
5081 | });
|
5082 | };
|
5083 | const translate = text => {
|
5084 | const langData = getLanguageData().getOr({});
|
5085 | const toString = obj => {
|
5086 | if (isFunction(obj)) {
|
5087 | return Object.prototype.toString.call(obj);
|
5088 | }
|
5089 | return !isEmpty(obj) ? '' + obj : '';
|
5090 | };
|
5091 | const isEmpty = text => text === '' || text === null || text === undefined;
|
5092 | const getLangData = text => {
|
5093 | const textStr = toString(text);
|
5094 | return has$2(langData, textStr) ? toString(langData[textStr]) : get$a(langData, textStr.toLowerCase()).map(toString).getOr(textStr);
|
5095 | };
|
5096 | const removeContext = str => str.replace(/{context:\w+}$/, '');
|
5097 | if (isEmpty(text)) {
|
5098 | return '';
|
5099 | }
|
5100 | if (isRaw(text)) {
|
5101 | return toString(text.raw);
|
5102 | }
|
5103 | if (isTokenised(text)) {
|
5104 | const values = text.slice(1);
|
5105 | const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1);
|
5106 | return removeContext(substitued);
|
5107 | }
|
5108 | return removeContext(getLangData(text));
|
5109 | };
|
5110 | const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl');
|
5111 | const hasCode = code => has$2(data, code);
|
5112 | const I18n = {
|
5113 | getData: getData$1,
|
5114 | setCode,
|
5115 | getCode,
|
5116 | add: add$1,
|
5117 | translate,
|
5118 | isRtl: isRtl$1,
|
5119 | hasCode
|
5120 | };
|
5121 |
|
5122 | const AddOnManager = () => {
|
5123 | const items = [];
|
5124 | const urls = {};
|
5125 | const lookup = {};
|
5126 | const _listeners = [];
|
5127 | const runListeners = (name, state) => {
|
5128 | const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state);
|
5129 | each$e(matchedListeners, listener => listener.resolve());
|
5130 | };
|
5131 | const isLoaded = name => has$2(urls, name);
|
5132 | const isAdded = name => has$2(lookup, name);
|
5133 | const get = name => {
|
5134 | if (lookup[name]) {
|
5135 | return lookup[name].instance;
|
5136 | }
|
5137 | return undefined;
|
5138 | };
|
5139 | const loadLanguagePack = (name, languages) => {
|
5140 | const language = I18n.getCode();
|
5141 | const wrappedLanguages = ',' + (languages || '') + ',';
|
5142 | if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) {
|
5143 | return;
|
5144 | }
|
5145 | ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
|
5146 | };
|
5147 | const requireLangPack = (name, languages) => {
|
5148 | if (AddOnManager.languageLoad !== false) {
|
5149 | if (isLoaded(name)) {
|
5150 | loadLanguagePack(name, languages);
|
5151 | } else {
|
5152 | waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages));
|
5153 | }
|
5154 | }
|
5155 | };
|
5156 | const add = (id, addOn) => {
|
5157 | items.push(addOn);
|
5158 | lookup[id] = { instance: addOn };
|
5159 | runListeners(id, 'added');
|
5160 | return addOn;
|
5161 | };
|
5162 | const remove = name => {
|
5163 | delete urls[name];
|
5164 | delete lookup[name];
|
5165 | };
|
5166 | const createUrl = (baseUrl, dep) => {
|
5167 | if (isString(dep)) {
|
5168 | return isString(baseUrl) ? {
|
5169 | prefix: '',
|
5170 | resource: dep,
|
5171 | suffix: ''
|
5172 | } : {
|
5173 | prefix: baseUrl.prefix,
|
5174 | resource: dep,
|
5175 | suffix: baseUrl.suffix
|
5176 | };
|
5177 | } else {
|
5178 | return dep;
|
5179 | }
|
5180 | };
|
5181 | const load = (name, addOnUrl) => {
|
5182 | if (urls[name]) {
|
5183 | return Promise.resolve();
|
5184 | }
|
5185 | let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
|
5186 | if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
|
5187 | urlString = AddOnManager.baseURL + '/' + urlString;
|
5188 | }
|
5189 | urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
|
5190 | const done = () => {
|
5191 | runListeners(name, 'loaded');
|
5192 | return Promise.resolve();
|
5193 | };
|
5194 | if (lookup[name]) {
|
5195 | return done();
|
5196 | } else {
|
5197 | return ScriptLoader.ScriptLoader.add(urlString).then(done);
|
5198 | }
|
5199 | };
|
5200 | const waitFor = (name, state = 'added') => {
|
5201 | if (state === 'added' && isAdded(name)) {
|
5202 | return Promise.resolve();
|
5203 | } else if (state === 'loaded' && isLoaded(name)) {
|
5204 | return Promise.resolve();
|
5205 | } else {
|
5206 | return new Promise(resolve => {
|
5207 | _listeners.push({
|
5208 | name,
|
5209 | state,
|
5210 | resolve
|
5211 | });
|
5212 | });
|
5213 | }
|
5214 | };
|
5215 | return {
|
5216 | items,
|
5217 | urls,
|
5218 | lookup,
|
5219 | get,
|
5220 | requireLangPack,
|
5221 | add,
|
5222 | remove,
|
5223 | createUrl,
|
5224 | load,
|
5225 | waitFor
|
5226 | };
|
5227 | };
|
5228 | AddOnManager.languageLoad = true;
|
5229 | AddOnManager.baseURL = '';
|
5230 | AddOnManager.PluginManager = AddOnManager();
|
5231 | AddOnManager.ThemeManager = AddOnManager();
|
5232 | AddOnManager.ModelManager = AddOnManager();
|
5233 |
|
5234 | const first$1 = (fn, rate) => {
|
5235 | let timer = null;
|
5236 | const cancel = () => {
|
5237 | if (!isNull(timer)) {
|
5238 | clearTimeout(timer);
|
5239 | timer = null;
|
5240 | }
|
5241 | };
|
5242 | const throttle = (...args) => {
|
5243 | if (isNull(timer)) {
|
5244 | timer = setTimeout(() => {
|
5245 | timer = null;
|
5246 | fn.apply(null, args);
|
5247 | }, rate);
|
5248 | }
|
5249 | };
|
5250 | return {
|
5251 | cancel,
|
5252 | throttle
|
5253 | };
|
5254 | };
|
5255 | const last = (fn, rate) => {
|
5256 | let timer = null;
|
5257 | const cancel = () => {
|
5258 | if (!isNull(timer)) {
|
5259 | clearTimeout(timer);
|
5260 | timer = null;
|
5261 | }
|
5262 | };
|
5263 | const throttle = (...args) => {
|
5264 | cancel();
|
5265 | timer = setTimeout(() => {
|
5266 | timer = null;
|
5267 | fn.apply(null, args);
|
5268 | }, rate);
|
5269 | };
|
5270 | return {
|
5271 | cancel,
|
5272 | throttle
|
5273 | };
|
5274 | };
|
5275 |
|
5276 | const ancestor$1 = (scope, selector, isRoot) => ancestor$3(scope, selector, isRoot).isSome();
|
5277 |
|
5278 | const annotation = constant('mce-annotation');
|
5279 | const dataAnnotation = constant('data-mce-annotation');
|
5280 | const dataAnnotationId = constant('data-mce-annotation-uid');
|
5281 | const dataAnnotationActive = constant('data-mce-annotation-active');
|
5282 | const dataAnnotationClasses = constant('data-mce-annotation-classes');
|
5283 | const dataAnnotationAttributes = constant('data-mce-annotation-attrs');
|
5284 |
|
5285 | const isRoot$1 = root => node => eq(node, root);
|
5286 | const identify = (editor, annotationName) => {
|
5287 | const rng = editor.selection.getRng();
|
5288 | const start = SugarElement.fromDom(rng.startContainer);
|
5289 | const root = SugarElement.fromDom(editor.getBody());
|
5290 | const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`);
|
5291 | const newStart = child$1(start, rng.startOffset).getOr(start);
|
5292 | const closest = closest$3(newStart, selector, isRoot$1(root));
|
5293 | return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => {
|
5294 | const elements = findMarkers(editor, uid);
|
5295 | return {
|
5296 | uid,
|
5297 | name,
|
5298 | elements
|
5299 | };
|
5300 | })));
|
5301 | };
|
5302 | const isAnnotation = elem => isElement$7(elem) && has(elem, annotation());
|
5303 | const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root));
|
5304 | const findMarkers = (editor, uid) => {
|
5305 | const body = SugarElement.fromDom(editor.getBody());
|
5306 | const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`);
|
5307 | return filter$5(descendants$1, descendant => !isBogusElement(descendant, body));
|
5308 | };
|
5309 | const findAll = (editor, name) => {
|
5310 | const body = SugarElement.fromDom(editor.getBody());
|
5311 | const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`);
|
5312 | const directory = {};
|
5313 | each$e(markers, m => {
|
5314 | if (!isBogusElement(m, body)) {
|
5315 | const uid = get$9(m, dataAnnotationId());
|
5316 | const nodesAlready = get$a(directory, uid).getOr([]);
|
5317 | directory[uid] = nodesAlready.concat([m]);
|
5318 | }
|
5319 | });
|
5320 | return directory;
|
5321 | };
|
5322 |
|
5323 | const setup$y = (editor, registry) => {
|
5324 | const changeCallbacks = Cell({});
|
5325 | const initData = () => ({
|
5326 | listeners: [],
|
5327 | previous: value$2()
|
5328 | });
|
5329 | const withCallbacks = (name, f) => {
|
5330 | updateCallbacks(name, data => {
|
5331 | f(data);
|
5332 | return data;
|
5333 | });
|
5334 | };
|
5335 | const updateCallbacks = (name, f) => {
|
5336 | const callbackMap = changeCallbacks.get();
|
5337 | const data = get$a(callbackMap, name).getOrThunk(initData);
|
5338 | const outputData = f(data);
|
5339 | callbackMap[name] = outputData;
|
5340 | changeCallbacks.set(callbackMap);
|
5341 | };
|
5342 | const fireCallbacks = (name, uid, elements) => {
|
5343 | withCallbacks(name, data => {
|
5344 | each$e(data.listeners, f => f(true, name, {
|
5345 | uid,
|
5346 | nodes: map$3(elements, elem => elem.dom)
|
5347 | }));
|
5348 | });
|
5349 | };
|
5350 | const fireNoAnnotation = name => {
|
5351 | withCallbacks(name, data => {
|
5352 | each$e(data.listeners, f => f(false, name));
|
5353 | });
|
5354 | };
|
5355 | const toggleActiveAttr = (uid, state) => {
|
5356 | each$e(findMarkers(editor, uid), elem => {
|
5357 | if (state) {
|
5358 | set$3(elem, dataAnnotationActive(), 'true');
|
5359 | } else {
|
5360 | remove$9(elem, dataAnnotationActive());
|
5361 | }
|
5362 | });
|
5363 | };
|
5364 | const onNodeChange = last(() => {
|
5365 | const annotations = sort(registry.getNames());
|
5366 | each$e(annotations, name => {
|
5367 | updateCallbacks(name, data => {
|
5368 | const prev = data.previous.get();
|
5369 | identify(editor, Optional.some(name)).fold(() => {
|
5370 | prev.each(uid => {
|
5371 | fireNoAnnotation(name);
|
5372 | data.previous.clear();
|
5373 | toggleActiveAttr(uid, false);
|
5374 | });
|
5375 | }, ({uid, name, elements}) => {
|
5376 | if (!is$2(prev, uid)) {
|
5377 | prev.each(uid => toggleActiveAttr(uid, false));
|
5378 | fireCallbacks(name, uid, elements);
|
5379 | data.previous.set(uid);
|
5380 | toggleActiveAttr(uid, true);
|
5381 | }
|
5382 | });
|
5383 | return {
|
5384 | previous: data.previous,
|
5385 | listeners: data.listeners
|
5386 | };
|
5387 | });
|
5388 | });
|
5389 | }, 30);
|
5390 | editor.on('remove', () => {
|
5391 | onNodeChange.cancel();
|
5392 | });
|
5393 | editor.on('NodeChange', () => {
|
5394 | onNodeChange.throttle();
|
5395 | });
|
5396 | const addListener = (name, f) => {
|
5397 | updateCallbacks(name, data => ({
|
5398 | previous: data.previous,
|
5399 | listeners: data.listeners.concat([f])
|
5400 | }));
|
5401 | };
|
5402 | return { addListener };
|
5403 | };
|
5404 |
|
5405 | const setup$x = (editor, registry) => {
|
5406 | const dataAnnotation$1 = dataAnnotation();
|
5407 | const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup);
|
5408 | const removeDirectAnnotation = node => {
|
5409 | var _a, _b;
|
5410 | node.attr(dataAnnotationId(), null);
|
5411 | node.attr(dataAnnotation(), null);
|
5412 | node.attr(dataAnnotationActive(), null);
|
5413 | const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]);
|
5414 | const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]);
|
5415 | each$e(customAttrNames, name => node.attr(name, null));
|
5416 | const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
|
5417 | const newClassList = difference(classList, [annotation()].concat(customClasses));
|
5418 | node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null);
|
5419 | node.attr(dataAnnotationClasses(), null);
|
5420 | node.attr(dataAnnotationAttributes(), null);
|
5421 | };
|
5422 | editor.serializer.addTempAttr(dataAnnotationActive());
|
5423 | editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => {
|
5424 | for (const node of nodes) {
|
5425 | identifyParserNode(node).each(settings => {
|
5426 | if (settings.persistent === false) {
|
5427 | if (node.name === 'span') {
|
5428 | node.unwrap();
|
5429 | } else {
|
5430 | removeDirectAnnotation(node);
|
5431 | }
|
5432 | }
|
5433 | });
|
5434 | }
|
5435 | });
|
5436 | };
|
5437 |
|
5438 | const create$b = () => {
|
5439 | const annotations = {};
|
5440 | const register = (name, settings) => {
|
5441 | annotations[name] = {
|
5442 | name,
|
5443 | settings
|
5444 | };
|
5445 | };
|
5446 | const lookup = name => get$a(annotations, name).map(a => a.settings);
|
5447 | const getNames = () => keys(annotations);
|
5448 | return {
|
5449 | register,
|
5450 | lookup,
|
5451 | getNames
|
5452 | };
|
5453 | };
|
5454 |
|
5455 | let unique = 0;
|
5456 | const generate$1 = prefix => {
|
5457 | const date = new Date();
|
5458 | const time = date.getTime();
|
5459 | const random = Math.floor(Math.random() * 1000000000);
|
5460 | unique++;
|
5461 | return prefix + '_' + random + unique + String(time);
|
5462 | };
|
5463 |
|
5464 | const add = (element, classes) => {
|
5465 | each$e(classes, x => {
|
5466 | add$2(element, x);
|
5467 | });
|
5468 | };
|
5469 | const remove$3 = (element, classes) => {
|
5470 | each$e(classes, x => {
|
5471 | remove$6(element, x);
|
5472 | });
|
5473 | };
|
5474 |
|
5475 | const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
|
5476 | const shallow$1 = original => clone$2(original, false);
|
5477 | const deep$1 = original => clone$2(original, true);
|
5478 | const shallowAs = (original, tag) => {
|
5479 | const nu = SugarElement.fromTag(tag);
|
5480 | const attributes = clone$4(original);
|
5481 | setAll$1(nu, attributes);
|
5482 | return nu;
|
5483 | };
|
5484 | const mutate = (original, tag) => {
|
5485 | const nu = shallowAs(original, tag);
|
5486 | after$4(original, nu);
|
5487 | const children = children$1(original);
|
5488 | append(nu, children);
|
5489 | remove$4(original);
|
5490 | return nu;
|
5491 | };
|
5492 |
|
5493 | const TextWalker = (startNode, rootNode, isBoundary = never) => {
|
5494 | const walker = new DomTreeWalker(startNode, rootNode);
|
5495 | const walk = direction => {
|
5496 | let next;
|
5497 | do {
|
5498 | next = walker[direction]();
|
5499 | } while (next && !isText$b(next) && !isBoundary(next));
|
5500 | return Optional.from(next).filter(isText$b);
|
5501 | };
|
5502 | return {
|
5503 | current: () => Optional.from(walker.current()).filter(isText$b),
|
5504 | next: () => walk('next'),
|
5505 | prev: () => walk('prev'),
|
5506 | prev2: () => walk('prev2')
|
5507 | };
|
5508 | };
|
5509 |
|
5510 | const TextSeeker = (dom, isBoundary) => {
|
5511 | const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node);
|
5512 | const walk = (node, offset, walker, process) => {
|
5513 | if (isText$b(node)) {
|
5514 | const newOffset = process(node, offset, node.data);
|
5515 | if (newOffset !== -1) {
|
5516 | return Optional.some({
|
5517 | container: node,
|
5518 | offset: newOffset
|
5519 | });
|
5520 | }
|
5521 | }
|
5522 | return walker().bind(next => walk(next.container, next.offset, walker, process));
|
5523 | };
|
5524 | const backwards = (node, offset, process, root) => {
|
5525 | const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
|
5526 | return walk(node, offset, () => walker.prev().map(prev => ({
|
5527 | container: prev,
|
5528 | offset: prev.length
|
5529 | })), process).getOrNull();
|
5530 | };
|
5531 | const forwards = (node, offset, process, root) => {
|
5532 | const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
|
5533 | return walk(node, offset, () => walker.next().map(next => ({
|
5534 | container: next,
|
5535 | offset: 0
|
5536 | })), process).getOrNull();
|
5537 | };
|
5538 | return {
|
5539 | backwards,
|
5540 | forwards
|
5541 | };
|
5542 | };
|
5543 |
|
5544 | const NodeValue = (is, name) => {
|
5545 | const get = element => {
|
5546 | if (!is(element)) {
|
5547 | throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
|
5548 | }
|
5549 | return getOption(element).getOr('');
|
5550 | };
|
5551 | const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
|
5552 | const set = (element, value) => {
|
5553 | if (!is(element)) {
|
5554 | throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
|
5555 | }
|
5556 | element.dom.nodeValue = value;
|
5557 | };
|
5558 | return {
|
5559 | get,
|
5560 | getOption,
|
5561 | set
|
5562 | };
|
5563 | };
|
5564 |
|
5565 | const api$1 = NodeValue(isText$c, 'text');
|
5566 | const get$3 = element => api$1.get(element);
|
5567 | const getOption = element => api$1.getOption(element);
|
5568 | const set = (element, value) => api$1.set(element, value);
|
5569 |
|
5570 | const tableCells = [
|
5571 | 'td',
|
5572 | 'th'
|
5573 | ];
|
5574 | const tableSections = [
|
5575 | 'thead',
|
5576 | 'tbody',
|
5577 | 'tfoot'
|
5578 | ];
|
5579 | const textBlocks = [
|
5580 | 'h1',
|
5581 | 'h2',
|
5582 | 'h3',
|
5583 | 'h4',
|
5584 | 'h5',
|
5585 | 'h6',
|
5586 | 'p',
|
5587 | 'div',
|
5588 | 'address',
|
5589 | 'pre',
|
5590 | 'form',
|
5591 | 'blockquote',
|
5592 | 'center',
|
5593 | 'dir',
|
5594 | 'fieldset',
|
5595 | 'header',
|
5596 | 'footer',
|
5597 | 'article',
|
5598 | 'section',
|
5599 | 'hgroup',
|
5600 | 'aside',
|
5601 | 'nav',
|
5602 | 'figure'
|
5603 | ];
|
5604 | const listItems$1 = [
|
5605 | 'li',
|
5606 | 'dd',
|
5607 | 'dt'
|
5608 | ];
|
5609 | const lists = [
|
5610 | 'ul',
|
5611 | 'ol',
|
5612 | 'dl'
|
5613 | ];
|
5614 | const wsElements = [
|
5615 | 'pre',
|
5616 | 'script',
|
5617 | 'textarea',
|
5618 | 'style'
|
5619 | ];
|
5620 | const lazyLookup = items => {
|
5621 | let lookup;
|
5622 | return node => {
|
5623 | lookup = lookup ? lookup : mapToObject(items, always);
|
5624 | return has$2(lookup, name(node));
|
5625 | };
|
5626 | };
|
5627 | const isTable$1 = node => name(node) === 'table';
|
5628 | const isBr$5 = node => isElement$7(node) && name(node) === 'br';
|
5629 | const isTextBlock$2 = lazyLookup(textBlocks);
|
5630 | const isList = lazyLookup(lists);
|
5631 | const isListItem$1 = lazyLookup(listItems$1);
|
5632 | const isTableSection = lazyLookup(tableSections);
|
5633 | const isTableCell$2 = lazyLookup(tableCells);
|
5634 | const isWsPreserveElement = lazyLookup(wsElements);
|
5635 |
|
5636 | const getLastChildren$1 = elm => {
|
5637 | const children = [];
|
5638 | let rawNode = elm.dom;
|
5639 | while (rawNode) {
|
5640 | children.push(SugarElement.fromDom(rawNode));
|
5641 | rawNode = rawNode.lastChild;
|
5642 | }
|
5643 | return children;
|
5644 | };
|
5645 | const removeTrailingBr = elm => {
|
5646 | const allBrs = descendants(elm, 'br');
|
5647 | const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5);
|
5648 | if (allBrs.length === brs.length) {
|
5649 | each$e(brs, remove$4);
|
5650 | }
|
5651 | };
|
5652 | const createPaddingBr = () => {
|
5653 | const br = SugarElement.fromTag('br');
|
5654 | set$3(br, 'data-mce-bogus', '1');
|
5655 | return br;
|
5656 | };
|
5657 | const fillWithPaddingBr = elm => {
|
5658 | empty(elm);
|
5659 | append$1(elm, createPaddingBr());
|
5660 | };
|
5661 | const trimBlockTrailingBr = (elm, schema) => {
|
5662 | lastChild(elm).each(lastChild => {
|
5663 | prevSibling(lastChild).each(lastChildPrevSibling => {
|
5664 | if (schema.isBlock(name(elm)) && isBr$5(lastChild) && schema.isBlock(name(lastChildPrevSibling))) {
|
5665 | remove$4(lastChild);
|
5666 | }
|
5667 | });
|
5668 | });
|
5669 | };
|
5670 |
|
5671 | const ZWSP$1 = zeroWidth;
|
5672 | const isZwsp = isZwsp$2;
|
5673 | const trim$2 = removeZwsp;
|
5674 | const insert$5 = editor => editor.insertContent(ZWSP$1, { preserve_zwsp: true });
|
5675 |
|
5676 | const isElement$5 = isElement$6;
|
5677 | const isText$9 = isText$b;
|
5678 | const isCaretContainerBlock$1 = node => {
|
5679 | if (isText$9(node)) {
|
5680 | node = node.parentNode;
|
5681 | }
|
5682 | return isElement$5(node) && node.hasAttribute('data-mce-caret');
|
5683 | };
|
5684 | const isCaretContainerInline = node => isText$9(node) && isZwsp(node.data);
|
5685 | const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
|
5686 | const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
|
5687 | const insertInline$1 = (node, before) => {
|
5688 | var _a;
|
5689 | const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
5690 | const textNode = doc.createTextNode(ZWSP$1);
|
5691 | const parentNode = node.parentNode;
|
5692 | if (!before) {
|
5693 | const sibling = node.nextSibling;
|
5694 | if (isText$9(sibling)) {
|
5695 | if (isCaretContainer$2(sibling)) {
|
5696 | return sibling;
|
5697 | }
|
5698 | if (startsWithCaretContainer$1(sibling)) {
|
5699 | sibling.splitText(1);
|
5700 | return sibling;
|
5701 | }
|
5702 | }
|
5703 | if (node.nextSibling) {
|
5704 | parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling);
|
5705 | } else {
|
5706 | parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode);
|
5707 | }
|
5708 | } else {
|
5709 | const sibling = node.previousSibling;
|
5710 | if (isText$9(sibling)) {
|
5711 | if (isCaretContainer$2(sibling)) {
|
5712 | return sibling;
|
5713 | }
|
5714 | if (endsWithCaretContainer$1(sibling)) {
|
5715 | return sibling.splitText(sibling.data.length - 1);
|
5716 | }
|
5717 | }
|
5718 | parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node);
|
5719 | }
|
5720 | return textNode;
|
5721 | };
|
5722 | const isBeforeInline = pos => {
|
5723 | const container = pos.container();
|
5724 | if (!isText$b(container)) {
|
5725 | return false;
|
5726 | }
|
5727 | return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
|
5728 | };
|
5729 | const isAfterInline = pos => {
|
5730 | const container = pos.container();
|
5731 | if (!isText$b(container)) {
|
5732 | return false;
|
5733 | }
|
5734 | return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
|
5735 | };
|
5736 | const insertBlock = (blockName, node, before) => {
|
5737 | var _a;
|
5738 | const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
5739 | const blockNode = doc.createElement(blockName);
|
5740 | blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
|
5741 | blockNode.setAttribute('data-mce-bogus', 'all');
|
5742 | blockNode.appendChild(createPaddingBr().dom);
|
5743 | const parentNode = node.parentNode;
|
5744 | if (!before) {
|
5745 | if (node.nextSibling) {
|
5746 | parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling);
|
5747 | } else {
|
5748 | parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode);
|
5749 | }
|
5750 | } else {
|
5751 | parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node);
|
5752 | }
|
5753 | return blockNode;
|
5754 | };
|
5755 | const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1;
|
5756 | const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1;
|
5757 | const trimBogusBr = elm => {
|
5758 | var _a;
|
5759 | const brs = elm.getElementsByTagName('br');
|
5760 | const lastBr = brs[brs.length - 1];
|
5761 | if (isBogus$1(lastBr)) {
|
5762 | (_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr);
|
5763 | }
|
5764 | };
|
5765 | const showCaretContainerBlock = caretContainer => {
|
5766 | if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
|
5767 | trimBogusBr(caretContainer);
|
5768 | caretContainer.removeAttribute('data-mce-caret');
|
5769 | caretContainer.removeAttribute('data-mce-bogus');
|
5770 | caretContainer.removeAttribute('style');
|
5771 | caretContainer.removeAttribute('data-mce-style');
|
5772 | caretContainer.removeAttribute('_moz_abspos');
|
5773 | return caretContainer;
|
5774 | }
|
5775 | return null;
|
5776 | };
|
5777 | const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer);
|
5778 |
|
5779 | const round$2 = Math.round;
|
5780 | const clone$1 = rect => {
|
5781 | if (!rect) {
|
5782 | return {
|
5783 | left: 0,
|
5784 | top: 0,
|
5785 | bottom: 0,
|
5786 | right: 0,
|
5787 | width: 0,
|
5788 | height: 0
|
5789 | };
|
5790 | }
|
5791 | return {
|
5792 | left: round$2(rect.left),
|
5793 | top: round$2(rect.top),
|
5794 | bottom: round$2(rect.bottom),
|
5795 | right: round$2(rect.right),
|
5796 | width: round$2(rect.width),
|
5797 | height: round$2(rect.height)
|
5798 | };
|
5799 | };
|
5800 | const collapse = (rect, toStart) => {
|
5801 | rect = clone$1(rect);
|
5802 | if (toStart) {
|
5803 | rect.right = rect.left;
|
5804 | } else {
|
5805 | rect.left = rect.left + rect.width;
|
5806 | rect.right = rect.left;
|
5807 | }
|
5808 | rect.width = 0;
|
5809 | return rect;
|
5810 | };
|
5811 | const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
|
5812 | const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
|
5813 | const isAbove$1 = (rect1, rect2) => {
|
5814 | const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
|
5815 | if (rect1.bottom - halfHeight < rect2.top) {
|
5816 | return true;
|
5817 | }
|
5818 | if (rect1.top > rect2.bottom) {
|
5819 | return false;
|
5820 | }
|
5821 | return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
|
5822 | };
|
5823 | const isBelow$1 = (rect1, rect2) => {
|
5824 | if (rect1.top > rect2.bottom) {
|
5825 | return true;
|
5826 | }
|
5827 | if (rect1.bottom < rect2.top) {
|
5828 | return false;
|
5829 | }
|
5830 | return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
|
5831 | };
|
5832 | const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
|
5833 | const boundingClientRectFromRects = rects => {
|
5834 | return foldl(rects, (acc, rect) => {
|
5835 | return acc.fold(() => Optional.some(rect), prevRect => {
|
5836 | const left = Math.min(rect.left, prevRect.left);
|
5837 | const top = Math.min(rect.top, prevRect.top);
|
5838 | const right = Math.max(rect.right, prevRect.right);
|
5839 | const bottom = Math.max(rect.bottom, prevRect.bottom);
|
5840 | return Optional.some({
|
5841 | top,
|
5842 | right,
|
5843 | bottom,
|
5844 | left,
|
5845 | width: right - left,
|
5846 | height: bottom - top
|
5847 | });
|
5848 | });
|
5849 | }, Optional.none());
|
5850 | };
|
5851 | const distanceToRectEdgeFromXY = (rect, x, y) => {
|
5852 | const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
|
5853 | const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
|
5854 | return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
|
5855 | };
|
5856 | const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
|
5857 |
|
5858 | const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
|
5859 |
|
5860 | const getSelectedNode = range => {
|
5861 | const startContainer = range.startContainer, startOffset = range.startOffset;
|
5862 | if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
|
5863 | return startContainer.childNodes[startOffset];
|
5864 | }
|
5865 | return null;
|
5866 | };
|
5867 | const getNode$1 = (container, offset) => {
|
5868 | if (isElement$6(container) && container.hasChildNodes()) {
|
5869 | const childNodes = container.childNodes;
|
5870 | const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
|
5871 | return childNodes[safeOffset];
|
5872 | } else {
|
5873 | return container;
|
5874 | }
|
5875 | };
|
5876 | const getNodeUnsafe = (container, offset) => {
|
5877 | if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
|
5878 | return undefined;
|
5879 | } else {
|
5880 | return getNode$1(container, offset);
|
5881 | }
|
5882 | };
|
5883 |
|
5884 | const extendingChars = new RegExp('[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a' + '\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0' + '\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c' + '\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3' + '\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc' + '\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57' + '\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56' + '\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44' + '\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9' + '\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97' + '\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074' + '\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17b4-\u17b5' + '\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18' + '\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1ABE\u1b00-\u1b03\u1b34' + '\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1be6\u1be8-\u1be9' + '\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9' + '\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20DD-\u20E0\u20e1\u20E2-\u20E4\u20e5-\u20f0\u2cef-\u2cf1' + '\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\uA670-\uA672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1' + '\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc' + '\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1' + '\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff9e-\uff9f]');
|
5885 | const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
|
5886 |
|
5887 | const or = (...args) => {
|
5888 | return x => {
|
5889 | for (let i = 0; i < args.length; i++) {
|
5890 | if (args[i](x)) {
|
5891 | return true;
|
5892 | }
|
5893 | }
|
5894 | return false;
|
5895 | };
|
5896 | };
|
5897 | const and = (...args) => {
|
5898 | return x => {
|
5899 | for (let i = 0; i < args.length; i++) {
|
5900 | if (!args[i](x)) {
|
5901 | return false;
|
5902 | }
|
5903 | }
|
5904 | return true;
|
5905 | };
|
5906 | };
|
5907 |
|
5908 | const isContentEditableTrue$2 = isContentEditableTrue$3;
|
5909 | const isContentEditableFalse$a = isContentEditableFalse$b;
|
5910 | const isBr$4 = isBr$6;
|
5911 | const isText$8 = isText$b;
|
5912 | const isInvalidTextElement = matchNodeNames([
|
5913 | 'script',
|
5914 | 'style',
|
5915 | 'textarea'
|
5916 | ]);
|
5917 | const isAtomicInline = matchNodeNames([
|
5918 | 'img',
|
5919 | 'input',
|
5920 | 'textarea',
|
5921 | 'hr',
|
5922 | 'iframe',
|
5923 | 'video',
|
5924 | 'audio',
|
5925 | 'object',
|
5926 | 'embed'
|
5927 | ]);
|
5928 | const isTable = matchNodeNames(['table']);
|
5929 | const isCaretContainer$1 = isCaretContainer$2;
|
5930 | const isCaretCandidate$3 = node => {
|
5931 | if (isCaretContainer$1(node)) {
|
5932 | return false;
|
5933 | }
|
5934 | if (isText$8(node)) {
|
5935 | return !isInvalidTextElement(node.parentNode);
|
5936 | }
|
5937 | return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node);
|
5938 | };
|
5939 | const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true';
|
5940 | const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$a(node);
|
5941 | const isInEditable = (node, root) => {
|
5942 | for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
|
5943 | if (isNonUiContentEditableFalse(tempNode)) {
|
5944 | return false;
|
5945 | }
|
5946 | if (isContentEditableTrue$2(tempNode)) {
|
5947 | return true;
|
5948 | }
|
5949 | }
|
5950 | return true;
|
5951 | };
|
5952 | const isAtomicContentEditableFalse = node => {
|
5953 | if (!isNonUiContentEditableFalse(node)) {
|
5954 | return false;
|
5955 | }
|
5956 | return !foldl(from(node.getElementsByTagName('*')), (result, elm) => {
|
5957 | return result || isContentEditableTrue$2(elm);
|
5958 | }, false);
|
5959 | };
|
5960 | const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node);
|
5961 | const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
|
5962 |
|
5963 | const isElement$4 = isElement$6;
|
5964 | const isCaretCandidate$2 = isCaretCandidate$3;
|
5965 | const isBlock$2 = matchStyleValues('display', 'block table');
|
5966 | const isFloated = matchStyleValues('float', 'left right');
|
5967 | const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
|
5968 | const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap'));
|
5969 | const isText$7 = isText$b;
|
5970 | const isBr$3 = isBr$6;
|
5971 | const nodeIndex$1 = DOMUtils.nodeIndex;
|
5972 | const resolveIndex$1 = getNodeUnsafe;
|
5973 | const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng();
|
5974 | const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr);
|
5975 | const isRange = rng => !!rng.setStart && !!rng.setEnd;
|
5976 | const isHiddenWhiteSpaceRange = range => {
|
5977 | const container = range.startContainer;
|
5978 | const offset = range.startOffset;
|
5979 | if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$b(container)) {
|
5980 | const text = container.data;
|
5981 | if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) {
|
5982 | return true;
|
5983 | }
|
5984 | }
|
5985 | return false;
|
5986 | };
|
5987 | const getBrClientRect = brNode => {
|
5988 | const doc = brNode.ownerDocument;
|
5989 | const rng = createRange$1(doc);
|
5990 | const nbsp$1 = doc.createTextNode(nbsp);
|
5991 | const parentNode = brNode.parentNode;
|
5992 | parentNode.insertBefore(nbsp$1, brNode);
|
5993 | rng.setStart(nbsp$1, 0);
|
5994 | rng.setEnd(nbsp$1, 1);
|
5995 | const clientRect = clone$1(rng.getBoundingClientRect());
|
5996 | parentNode.removeChild(nbsp$1);
|
5997 | return clientRect;
|
5998 | };
|
5999 | const getBoundingClientRectWebKitText = rng => {
|
6000 | const sc = rng.startContainer;
|
6001 | const ec = rng.endContainer;
|
6002 | const so = rng.startOffset;
|
6003 | const eo = rng.endOffset;
|
6004 | if (sc === ec && isText$b(ec) && so === 0 && eo === 1) {
|
6005 | const newRng = rng.cloneRange();
|
6006 | newRng.setEndAfter(ec);
|
6007 | return getBoundingClientRect$1(newRng);
|
6008 | } else {
|
6009 | return null;
|
6010 | }
|
6011 | };
|
6012 | const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
|
6013 | const getBoundingClientRect$1 = item => {
|
6014 | var _a;
|
6015 | let clientRect;
|
6016 | const clientRects = item.getClientRects();
|
6017 | if (clientRects.length > 0) {
|
6018 | clientRect = clone$1(clientRects[0]);
|
6019 | } else {
|
6020 | clientRect = clone$1(item.getBoundingClientRect());
|
6021 | }
|
6022 | if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
|
6023 | return getBrClientRect(item);
|
6024 | }
|
6025 | if (isZeroRect(clientRect) && isRange(item)) {
|
6026 | return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect;
|
6027 | }
|
6028 | return clientRect;
|
6029 | };
|
6030 | const collapseAndInflateWidth = (clientRect, toStart) => {
|
6031 | const newClientRect = collapse(clientRect, toStart);
|
6032 | newClientRect.width = 1;
|
6033 | newClientRect.right = newClientRect.left + 1;
|
6034 | return newClientRect;
|
6035 | };
|
6036 | const getCaretPositionClientRects = caretPosition => {
|
6037 | const clientRects = [];
|
6038 | const addUniqueAndValidRect = clientRect => {
|
6039 | if (clientRect.height === 0) {
|
6040 | return;
|
6041 | }
|
6042 | if (clientRects.length > 0) {
|
6043 | if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
|
6044 | return;
|
6045 | }
|
6046 | }
|
6047 | clientRects.push(clientRect);
|
6048 | };
|
6049 | const addCharacterOffset = (container, offset) => {
|
6050 | const range = createRange$1(container.ownerDocument);
|
6051 | if (offset < container.data.length) {
|
6052 | if (isExtendingChar(container.data[offset])) {
|
6053 | return;
|
6054 | }
|
6055 | if (isExtendingChar(container.data[offset - 1])) {
|
6056 | range.setStart(container, offset);
|
6057 | range.setEnd(container, offset + 1);
|
6058 | if (!isHiddenWhiteSpaceRange(range)) {
|
6059 | addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
|
6060 | return;
|
6061 | }
|
6062 | }
|
6063 | }
|
6064 | if (offset > 0) {
|
6065 | range.setStart(container, offset - 1);
|
6066 | range.setEnd(container, offset);
|
6067 | if (!isHiddenWhiteSpaceRange(range)) {
|
6068 | addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
|
6069 | }
|
6070 | }
|
6071 | if (offset < container.data.length) {
|
6072 | range.setStart(container, offset);
|
6073 | range.setEnd(container, offset + 1);
|
6074 | if (!isHiddenWhiteSpaceRange(range)) {
|
6075 | addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true));
|
6076 | }
|
6077 | }
|
6078 | };
|
6079 | const container = caretPosition.container();
|
6080 | const offset = caretPosition.offset();
|
6081 | if (isText$7(container)) {
|
6082 | addCharacterOffset(container, offset);
|
6083 | return clientRects;
|
6084 | }
|
6085 | if (isElement$4(container)) {
|
6086 | if (caretPosition.isAtEnd()) {
|
6087 | const node = resolveIndex$1(container, offset);
|
6088 | if (isText$7(node)) {
|
6089 | addCharacterOffset(node, node.data.length);
|
6090 | }
|
6091 | if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
|
6092 | addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
|
6093 | }
|
6094 | } else {
|
6095 | const node = resolveIndex$1(container, offset);
|
6096 | if (isText$7(node)) {
|
6097 | addCharacterOffset(node, 0);
|
6098 | }
|
6099 | if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
|
6100 | addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
|
6101 | return clientRects;
|
6102 | }
|
6103 | const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
|
6104 | if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
|
6105 | if (isBlock$2(beforeNode) || isBlock$2(node) || !isValidElementCaretCandidate(node)) {
|
6106 | addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
|
6107 | }
|
6108 | }
|
6109 | if (isValidElementCaretCandidate(node)) {
|
6110 | addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
|
6111 | }
|
6112 | }
|
6113 | }
|
6114 | return clientRects;
|
6115 | };
|
6116 | const CaretPosition = (container, offset, clientRects) => {
|
6117 | const isAtStart = () => {
|
6118 | if (isText$7(container)) {
|
6119 | return offset === 0;
|
6120 | }
|
6121 | return offset === 0;
|
6122 | };
|
6123 | const isAtEnd = () => {
|
6124 | if (isText$7(container)) {
|
6125 | return offset >= container.data.length;
|
6126 | }
|
6127 | return offset >= container.childNodes.length;
|
6128 | };
|
6129 | const toRange = () => {
|
6130 | const range = createRange$1(container.ownerDocument);
|
6131 | range.setStart(container, offset);
|
6132 | range.setEnd(container, offset);
|
6133 | return range;
|
6134 | };
|
6135 | const getClientRects = () => {
|
6136 | if (!clientRects) {
|
6137 | clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
|
6138 | }
|
6139 | return clientRects;
|
6140 | };
|
6141 | const isVisible = () => getClientRects().length > 0;
|
6142 | const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
|
6143 | const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset);
|
6144 | return {
|
6145 | container: constant(container),
|
6146 | offset: constant(offset),
|
6147 | toRange,
|
6148 | getClientRects,
|
6149 | isVisible,
|
6150 | isAtStart,
|
6151 | isAtEnd,
|
6152 | isEqual,
|
6153 | getNode
|
6154 | };
|
6155 | };
|
6156 | CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset);
|
6157 | CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset);
|
6158 | CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
|
6159 | CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node));
|
6160 | CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$2(pos1.getClientRects()), isAbove$1).getOr(false);
|
6161 | CaretPosition.isBelow = (pos1, pos2) => lift2(last$2(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
|
6162 | CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false;
|
6163 | CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false;
|
6164 | CaretPosition.isTextPosition = pos => pos ? isText$b(pos.container()) : false;
|
6165 | CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos);
|
6166 |
|
6167 | const trimEmptyTextNode$1 = (dom, node) => {
|
6168 | if (isText$b(node) && node.data.length === 0) {
|
6169 | dom.remove(node);
|
6170 | }
|
6171 | };
|
6172 | const insertNode = (dom, rng, node) => {
|
6173 | rng.insertNode(node);
|
6174 | trimEmptyTextNode$1(dom, node.previousSibling);
|
6175 | trimEmptyTextNode$1(dom, node.nextSibling);
|
6176 | };
|
6177 | const insertFragment = (dom, rng, frag) => {
|
6178 | const firstChild = Optional.from(frag.firstChild);
|
6179 | const lastChild = Optional.from(frag.lastChild);
|
6180 | rng.insertNode(frag);
|
6181 | firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling));
|
6182 | lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling));
|
6183 | };
|
6184 | const rangeInsertNode = (dom, rng, node) => {
|
6185 | if (isDocumentFragment(node)) {
|
6186 | insertFragment(dom, rng, node);
|
6187 | } else {
|
6188 | insertNode(dom, rng, node);
|
6189 | }
|
6190 | };
|
6191 |
|
6192 | const isText$6 = isText$b;
|
6193 | const isBogus = isBogus$1;
|
6194 | const nodeIndex = DOMUtils.nodeIndex;
|
6195 | const normalizedParent = node => {
|
6196 | const parentNode = node.parentNode;
|
6197 | if (isBogus(parentNode)) {
|
6198 | return normalizedParent(parentNode);
|
6199 | }
|
6200 | return parentNode;
|
6201 | };
|
6202 | const getChildNodes = node => {
|
6203 | if (!node) {
|
6204 | return [];
|
6205 | }
|
6206 | return reduce(node.childNodes, (result, node) => {
|
6207 | if (isBogus(node) && node.nodeName !== 'BR') {
|
6208 | result = result.concat(getChildNodes(node));
|
6209 | } else {
|
6210 | result.push(node);
|
6211 | }
|
6212 | return result;
|
6213 | }, []);
|
6214 | };
|
6215 | const normalizedTextOffset = (node, offset) => {
|
6216 | let tempNode = node;
|
6217 | while (tempNode = tempNode.previousSibling) {
|
6218 | if (!isText$6(tempNode)) {
|
6219 | break;
|
6220 | }
|
6221 | offset += tempNode.data.length;
|
6222 | }
|
6223 | return offset;
|
6224 | };
|
6225 | const equal = a => b => a === b;
|
6226 | const normalizedNodeIndex = node => {
|
6227 | let nodes, index;
|
6228 | nodes = getChildNodes(normalizedParent(node));
|
6229 | index = findIndex$1(nodes, equal(node), node);
|
6230 | nodes = nodes.slice(0, index + 1);
|
6231 | const numTextFragments = reduce(nodes, (result, node, i) => {
|
6232 | if (isText$6(node) && isText$6(nodes[i - 1])) {
|
6233 | result++;
|
6234 | }
|
6235 | return result;
|
6236 | }, 0);
|
6237 | nodes = filter$3(nodes, matchNodeNames([node.nodeName]));
|
6238 | index = findIndex$1(nodes, equal(node), node);
|
6239 | return index - numTextFragments;
|
6240 | };
|
6241 | const createPathItem = node => {
|
6242 | const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase();
|
6243 | return name + '[' + normalizedNodeIndex(node) + ']';
|
6244 | };
|
6245 | const parentsUntil$1 = (root, node, predicate) => {
|
6246 | const parents = [];
|
6247 | for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
|
6248 | if (predicate && predicate(tempNode)) {
|
6249 | break;
|
6250 | }
|
6251 | parents.push(tempNode);
|
6252 | }
|
6253 | return parents;
|
6254 | };
|
6255 | const create$a = (root, caretPosition) => {
|
6256 | let path = [];
|
6257 | let container = caretPosition.container();
|
6258 | let offset = caretPosition.offset();
|
6259 | let outputOffset;
|
6260 | if (isText$6(container)) {
|
6261 | outputOffset = normalizedTextOffset(container, offset);
|
6262 | } else {
|
6263 | const childNodes = container.childNodes;
|
6264 | if (offset >= childNodes.length) {
|
6265 | outputOffset = 'after';
|
6266 | offset = childNodes.length - 1;
|
6267 | } else {
|
6268 | outputOffset = 'before';
|
6269 | }
|
6270 | container = childNodes[offset];
|
6271 | }
|
6272 | path.push(createPathItem(container));
|
6273 | let parents = parentsUntil$1(root, container);
|
6274 | parents = filter$3(parents, not(isBogus$1));
|
6275 | path = path.concat(map$1(parents, node => {
|
6276 | return createPathItem(node);
|
6277 | }));
|
6278 | return path.reverse().join('/') + ',' + outputOffset;
|
6279 | };
|
6280 | const resolvePathItem = (node, name, index) => {
|
6281 | let nodes = getChildNodes(node);
|
6282 | nodes = filter$3(nodes, (node, index) => {
|
6283 | return !isText$6(node) || !isText$6(nodes[index - 1]);
|
6284 | });
|
6285 | nodes = filter$3(nodes, matchNodeNames([name]));
|
6286 | return nodes[index];
|
6287 | };
|
6288 | const findTextPosition = (container, offset) => {
|
6289 | let node = container;
|
6290 | let targetOffset = 0;
|
6291 | while (isText$6(node)) {
|
6292 | const dataLen = node.data.length;
|
6293 | if (offset >= targetOffset && offset <= targetOffset + dataLen) {
|
6294 | container = node;
|
6295 | offset = offset - targetOffset;
|
6296 | break;
|
6297 | }
|
6298 | if (!isText$6(node.nextSibling)) {
|
6299 | container = node;
|
6300 | offset = dataLen;
|
6301 | break;
|
6302 | }
|
6303 | targetOffset += dataLen;
|
6304 | node = node.nextSibling;
|
6305 | }
|
6306 | if (isText$6(container) && offset > container.data.length) {
|
6307 | offset = container.data.length;
|
6308 | }
|
6309 | return CaretPosition(container, offset);
|
6310 | };
|
6311 | const resolve$1 = (root, path) => {
|
6312 | if (!path) {
|
6313 | return null;
|
6314 | }
|
6315 | const parts = path.split(',');
|
6316 | const paths = parts[0].split('/');
|
6317 | const offset = parts.length > 1 ? parts[1] : 'before';
|
6318 | const container = reduce(paths, (result, value) => {
|
6319 | const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
|
6320 | if (!match) {
|
6321 | return null;
|
6322 | }
|
6323 | if (match[1] === 'text()') {
|
6324 | match[1] = '#text';
|
6325 | }
|
6326 | return resolvePathItem(result, match[1], parseInt(match[2], 10));
|
6327 | }, root);
|
6328 | if (!container) {
|
6329 | return null;
|
6330 | }
|
6331 | if (!isText$6(container) && container.parentNode) {
|
6332 | let nodeOffset;
|
6333 | if (offset === 'after') {
|
6334 | nodeOffset = nodeIndex(container) + 1;
|
6335 | } else {
|
6336 | nodeOffset = nodeIndex(container);
|
6337 | }
|
6338 | return CaretPosition(container.parentNode, nodeOffset);
|
6339 | }
|
6340 | return findTextPosition(container, parseInt(offset, 10));
|
6341 | };
|
6342 |
|
6343 | const isContentEditableFalse$9 = isContentEditableFalse$b;
|
6344 | const getNormalizedTextOffset$1 = (trim, container, offset) => {
|
6345 | let trimmedOffset = trim(container.data.slice(0, offset)).length;
|
6346 | for (let node = container.previousSibling; node && isText$b(node); node = node.previousSibling) {
|
6347 | trimmedOffset += trim(node.data).length;
|
6348 | }
|
6349 | return trimmedOffset;
|
6350 | };
|
6351 | const getPoint = (dom, trim, normalized, rng, start) => {
|
6352 | const container = start ? rng.startContainer : rng.endContainer;
|
6353 | let offset = start ? rng.startOffset : rng.endOffset;
|
6354 | const point = [];
|
6355 | const root = dom.getRoot();
|
6356 | if (isText$b(container)) {
|
6357 | point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset);
|
6358 | } else {
|
6359 | let after = 0;
|
6360 | const childNodes = container.childNodes;
|
6361 | if (offset >= childNodes.length && childNodes.length) {
|
6362 | after = 1;
|
6363 | offset = Math.max(0, childNodes.length - 1);
|
6364 | }
|
6365 | point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
|
6366 | }
|
6367 | for (let node = container; node && node !== root; node = node.parentNode) {
|
6368 | point.push(dom.nodeIndex(node, normalized));
|
6369 | }
|
6370 | return point;
|
6371 | };
|
6372 | const getLocation = (trim, selection, normalized, rng) => {
|
6373 | const dom = selection.dom;
|
6374 | const start = getPoint(dom, trim, normalized, rng, true);
|
6375 | const forward = selection.isForward();
|
6376 | const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
|
6377 | if (!selection.isCollapsed()) {
|
6378 | const end = getPoint(dom, trim, normalized, rng, false);
|
6379 | return {
|
6380 | start,
|
6381 | end,
|
6382 | forward,
|
6383 | ...fakeCaret
|
6384 | };
|
6385 | } else {
|
6386 | return {
|
6387 | start,
|
6388 | forward,
|
6389 | ...fakeCaret
|
6390 | };
|
6391 | }
|
6392 | };
|
6393 | const findIndex = (dom, name, element) => {
|
6394 | let count = 0;
|
6395 | Tools.each(dom.select(name), node => {
|
6396 | if (node.getAttribute('data-mce-bogus') === 'all') {
|
6397 | return;
|
6398 | } else if (node === element) {
|
6399 | return false;
|
6400 | } else {
|
6401 | count++;
|
6402 | return;
|
6403 | }
|
6404 | });
|
6405 | return count;
|
6406 | };
|
6407 | const moveEndPoint$1 = (rng, start) => {
|
6408 | let container = start ? rng.startContainer : rng.endContainer;
|
6409 | let offset = start ? rng.startOffset : rng.endOffset;
|
6410 | if (isElement$6(container) && container.nodeName === 'TR') {
|
6411 | const childNodes = container.childNodes;
|
6412 | container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
|
6413 | if (container) {
|
6414 | offset = start ? 0 : container.childNodes.length;
|
6415 | if (start) {
|
6416 | rng.setStart(container, offset);
|
6417 | } else {
|
6418 | rng.setEnd(container, offset);
|
6419 | }
|
6420 | }
|
6421 | }
|
6422 | };
|
6423 | const normalizeTableCellSelection = rng => {
|
6424 | moveEndPoint$1(rng, true);
|
6425 | moveEndPoint$1(rng, false);
|
6426 | return rng;
|
6427 | };
|
6428 | const findSibling = (node, offset) => {
|
6429 | if (isElement$6(node)) {
|
6430 | node = getNode$1(node, offset);
|
6431 | if (isContentEditableFalse$9(node)) {
|
6432 | return node;
|
6433 | }
|
6434 | }
|
6435 | if (isCaretContainer$2(node)) {
|
6436 | if (isText$b(node) && isCaretContainerBlock$1(node)) {
|
6437 | node = node.parentNode;
|
6438 | }
|
6439 | let sibling = node.previousSibling;
|
6440 | if (isContentEditableFalse$9(sibling)) {
|
6441 | return sibling;
|
6442 | }
|
6443 | sibling = node.nextSibling;
|
6444 | if (isContentEditableFalse$9(sibling)) {
|
6445 | return sibling;
|
6446 | }
|
6447 | }
|
6448 | return undefined;
|
6449 | };
|
6450 | const findAdjacentContentEditableFalseElm = rng => {
|
6451 | return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
|
6452 | };
|
6453 | const getOffsetBookmark = (trim, normalized, selection) => {
|
6454 | const element = selection.getNode();
|
6455 | const rng = selection.getRng();
|
6456 | if (element.nodeName === 'IMG' || isContentEditableFalse$9(element)) {
|
6457 | const name = element.nodeName;
|
6458 | return {
|
6459 | name,
|
6460 | index: findIndex(selection.dom, name, element)
|
6461 | };
|
6462 | }
|
6463 | const sibling = findAdjacentContentEditableFalseElm(rng);
|
6464 | if (sibling) {
|
6465 | const name = sibling.tagName;
|
6466 | return {
|
6467 | name,
|
6468 | index: findIndex(selection.dom, name, sibling)
|
6469 | };
|
6470 | }
|
6471 | return getLocation(trim, selection, normalized, rng);
|
6472 | };
|
6473 | const getCaretBookmark = selection => {
|
6474 | const rng = selection.getRng();
|
6475 | return {
|
6476 | start: create$a(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
|
6477 | end: create$a(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
|
6478 | forward: selection.isForward()
|
6479 | };
|
6480 | };
|
6481 | const getRangeBookmark = selection => {
|
6482 | return {
|
6483 | rng: selection.getRng(),
|
6484 | forward: selection.isForward()
|
6485 | };
|
6486 | };
|
6487 | const createBookmarkSpan = (dom, id, filled) => {
|
6488 | const args = {
|
6489 | 'data-mce-type': 'bookmark',
|
6490 | id,
|
6491 | 'style': 'overflow:hidden;line-height:0px'
|
6492 | };
|
6493 | return filled ? dom.create('span', args, '') : dom.create('span', args);
|
6494 | };
|
6495 | const getPersistentBookmark = (selection, filled) => {
|
6496 | const dom = selection.dom;
|
6497 | let rng = selection.getRng();
|
6498 | const id = dom.uniqueId();
|
6499 | const collapsed = selection.isCollapsed();
|
6500 | const element = selection.getNode();
|
6501 | const name = element.nodeName;
|
6502 | const forward = selection.isForward();
|
6503 | if (name === 'IMG') {
|
6504 | return {
|
6505 | name,
|
6506 | index: findIndex(dom, name, element)
|
6507 | };
|
6508 | }
|
6509 | const rng2 = normalizeTableCellSelection(rng.cloneRange());
|
6510 | if (!collapsed) {
|
6511 | rng2.collapse(false);
|
6512 | const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
|
6513 | rangeInsertNode(dom, rng2, endBookmarkNode);
|
6514 | }
|
6515 | rng = normalizeTableCellSelection(rng);
|
6516 | rng.collapse(true);
|
6517 | const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
|
6518 | rangeInsertNode(dom, rng, startBookmarkNode);
|
6519 | selection.moveToBookmark({
|
6520 | id,
|
6521 | keep: true,
|
6522 | forward
|
6523 | });
|
6524 | return {
|
6525 | id,
|
6526 | forward
|
6527 | };
|
6528 | };
|
6529 | const getBookmark$2 = (selection, type, normalized = false) => {
|
6530 | if (type === 2) {
|
6531 | return getOffsetBookmark(trim$2, normalized, selection);
|
6532 | } else if (type === 3) {
|
6533 | return getCaretBookmark(selection);
|
6534 | } else if (type) {
|
6535 | return getRangeBookmark(selection);
|
6536 | } else {
|
6537 | return getPersistentBookmark(selection, false);
|
6538 | }
|
6539 | };
|
6540 | const getUndoBookmark = curry(getOffsetBookmark, identity, true);
|
6541 |
|
6542 | const value$1 = value => {
|
6543 | const applyHelper = fn => fn(value);
|
6544 | const constHelper = constant(value);
|
6545 | const outputHelper = () => output;
|
6546 | const output = {
|
6547 | tag: true,
|
6548 | inner: value,
|
6549 | fold: (_onError, onValue) => onValue(value),
|
6550 | isValue: always,
|
6551 | isError: never,
|
6552 | map: mapper => Result.value(mapper(value)),
|
6553 | mapError: outputHelper,
|
6554 | bind: applyHelper,
|
6555 | exists: applyHelper,
|
6556 | forall: applyHelper,
|
6557 | getOr: constHelper,
|
6558 | or: outputHelper,
|
6559 | getOrThunk: constHelper,
|
6560 | orThunk: outputHelper,
|
6561 | getOrDie: constHelper,
|
6562 | each: fn => {
|
6563 | fn(value);
|
6564 | },
|
6565 | toOptional: () => Optional.some(value)
|
6566 | };
|
6567 | return output;
|
6568 | };
|
6569 | const error = error => {
|
6570 | const outputHelper = () => output;
|
6571 | const output = {
|
6572 | tag: false,
|
6573 | inner: error,
|
6574 | fold: (onError, _onValue) => onError(error),
|
6575 | isValue: never,
|
6576 | isError: always,
|
6577 | map: outputHelper,
|
6578 | mapError: mapper => Result.error(mapper(error)),
|
6579 | bind: outputHelper,
|
6580 | exists: never,
|
6581 | forall: always,
|
6582 | getOr: identity,
|
6583 | or: identity,
|
6584 | getOrThunk: apply$1,
|
6585 | orThunk: apply$1,
|
6586 | getOrDie: die(String(error)),
|
6587 | each: noop,
|
6588 | toOptional: Optional.none
|
6589 | };
|
6590 | return output;
|
6591 | };
|
6592 | const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
|
6593 | const Result = {
|
6594 | value: value$1,
|
6595 | error,
|
6596 | fromOption
|
6597 | };
|
6598 |
|
6599 | const generate = cases => {
|
6600 | if (!isArray$1(cases)) {
|
6601 | throw new Error('cases must be an array');
|
6602 | }
|
6603 | if (cases.length === 0) {
|
6604 | throw new Error('there must be at least one case');
|
6605 | }
|
6606 | const constructors = [];
|
6607 | const adt = {};
|
6608 | each$e(cases, (acase, count) => {
|
6609 | const keys$1 = keys(acase);
|
6610 | if (keys$1.length !== 1) {
|
6611 | throw new Error('one and only one name per case');
|
6612 | }
|
6613 | const key = keys$1[0];
|
6614 | const value = acase[key];
|
6615 | if (adt[key] !== undefined) {
|
6616 | throw new Error('duplicate key detected:' + key);
|
6617 | } else if (key === 'cata') {
|
6618 | throw new Error('cannot have a case named cata (sorry)');
|
6619 | } else if (!isArray$1(value)) {
|
6620 | throw new Error('case arguments must be an array');
|
6621 | }
|
6622 | constructors.push(key);
|
6623 | adt[key] = (...args) => {
|
6624 | const argLength = args.length;
|
6625 | if (argLength !== value.length) {
|
6626 | throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
|
6627 | }
|
6628 | const match = branches => {
|
6629 | const branchKeys = keys(branches);
|
6630 | if (constructors.length !== branchKeys.length) {
|
6631 | throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
|
6632 | }
|
6633 | const allReqd = forall(constructors, reqKey => {
|
6634 | return contains$2(branchKeys, reqKey);
|
6635 | });
|
6636 | if (!allReqd) {
|
6637 | throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
|
6638 | }
|
6639 | return branches[key].apply(null, args);
|
6640 | };
|
6641 | return {
|
6642 | fold: (...foldArgs) => {
|
6643 | if (foldArgs.length !== cases.length) {
|
6644 | throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
|
6645 | }
|
6646 | const target = foldArgs[count];
|
6647 | return target.apply(null, args);
|
6648 | },
|
6649 | match,
|
6650 | log: label => {
|
6651 | console.log(label, {
|
6652 | constructors,
|
6653 | constructor: key,
|
6654 | params: args
|
6655 | });
|
6656 | }
|
6657 | };
|
6658 | };
|
6659 | });
|
6660 | return adt;
|
6661 | };
|
6662 | const Adt = { generate };
|
6663 |
|
6664 | Adt.generate([
|
6665 | {
|
6666 | bothErrors: [
|
6667 | 'error1',
|
6668 | 'error2'
|
6669 | ]
|
6670 | },
|
6671 | {
|
6672 | firstError: [
|
6673 | 'error1',
|
6674 | 'value2'
|
6675 | ]
|
6676 | },
|
6677 | {
|
6678 | secondError: [
|
6679 | 'value1',
|
6680 | 'error2'
|
6681 | ]
|
6682 | },
|
6683 | {
|
6684 | bothValues: [
|
6685 | 'value1',
|
6686 | 'value2'
|
6687 | ]
|
6688 | }
|
6689 | ]);
|
6690 | const partition$1 = results => {
|
6691 | const errors = [];
|
6692 | const values = [];
|
6693 | each$e(results, result => {
|
6694 | result.fold(err => {
|
6695 | errors.push(err);
|
6696 | }, value => {
|
6697 | values.push(value);
|
6698 | });
|
6699 | });
|
6700 | return {
|
6701 | errors,
|
6702 | values
|
6703 | };
|
6704 | };
|
6705 |
|
6706 | const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format';
|
6707 | const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format';
|
6708 | const hasBlockTrigger = (pattern, trigger) => (pattern.type === 'block-command' || pattern.type === 'block-format') && pattern.trigger === trigger;
|
6709 | const normalizePattern = pattern => {
|
6710 | var _a;
|
6711 | const err = message => Result.error({
|
6712 | message,
|
6713 | pattern
|
6714 | });
|
6715 | const formatOrCmd = (name, onFormat, onCommand) => {
|
6716 | if (pattern.format !== undefined) {
|
6717 | let formats;
|
6718 | if (isArray$1(pattern.format)) {
|
6719 | if (!forall(pattern.format, isString)) {
|
6720 | return err(name + ' pattern has non-string items in the `format` array');
|
6721 | }
|
6722 | formats = pattern.format;
|
6723 | } else if (isString(pattern.format)) {
|
6724 | formats = [pattern.format];
|
6725 | } else {
|
6726 | return err(name + ' pattern has non-string `format` parameter');
|
6727 | }
|
6728 | return Result.value(onFormat(formats));
|
6729 | } else if (pattern.cmd !== undefined) {
|
6730 | if (!isString(pattern.cmd)) {
|
6731 | return err(name + ' pattern has non-string `cmd` parameter');
|
6732 | }
|
6733 | return Result.value(onCommand(pattern.cmd, pattern.value));
|
6734 | } else {
|
6735 | return err(name + ' pattern is missing both `format` and `cmd` parameters');
|
6736 | }
|
6737 | };
|
6738 | if (!isObject(pattern)) {
|
6739 | return err('Raw pattern is not an object');
|
6740 | }
|
6741 | if (!isString(pattern.start)) {
|
6742 | return err('Raw pattern is missing `start` parameter');
|
6743 | }
|
6744 | if (pattern.end !== undefined) {
|
6745 | if (!isString(pattern.end)) {
|
6746 | return err('Inline pattern has non-string `end` parameter');
|
6747 | }
|
6748 | if (pattern.start.length === 0 && pattern.end.length === 0) {
|
6749 | return err('Inline pattern has empty `start` and `end` parameters');
|
6750 | }
|
6751 | let start = pattern.start;
|
6752 | let end = pattern.end;
|
6753 | if (end.length === 0) {
|
6754 | end = start;
|
6755 | start = '';
|
6756 | }
|
6757 | return formatOrCmd('Inline', format => ({
|
6758 | type: 'inline-format',
|
6759 | start,
|
6760 | end,
|
6761 | format
|
6762 | }), (cmd, value) => ({
|
6763 | type: 'inline-command',
|
6764 | start,
|
6765 | end,
|
6766 | cmd,
|
6767 | value
|
6768 | }));
|
6769 | } else if (pattern.replacement !== undefined) {
|
6770 | if (!isString(pattern.replacement)) {
|
6771 | return err('Replacement pattern has non-string `replacement` parameter');
|
6772 | }
|
6773 | if (pattern.start.length === 0) {
|
6774 | return err('Replacement pattern has empty `start` parameter');
|
6775 | }
|
6776 | return Result.value({
|
6777 | type: 'inline-command',
|
6778 | start: '',
|
6779 | end: pattern.start,
|
6780 | cmd: 'mceInsertContent',
|
6781 | value: pattern.replacement
|
6782 | });
|
6783 | } else {
|
6784 | const trigger = (_a = pattern.trigger) !== null && _a !== void 0 ? _a : 'space';
|
6785 | if (pattern.start.length === 0) {
|
6786 | return err('Block pattern has empty `start` parameter');
|
6787 | }
|
6788 | return formatOrCmd('Block', formats => ({
|
6789 | type: 'block-format',
|
6790 | start: pattern.start,
|
6791 | format: formats[0],
|
6792 | trigger
|
6793 | }), (command, commandValue) => ({
|
6794 | type: 'block-command',
|
6795 | start: pattern.start,
|
6796 | cmd: command,
|
6797 | value: commandValue,
|
6798 | trigger
|
6799 | }));
|
6800 | }
|
6801 | };
|
6802 | const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern);
|
6803 | const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern);
|
6804 | const createPatternSet = (patterns, dynamicPatternsLookup) => ({
|
6805 | inlinePatterns: getInlinePatterns(patterns),
|
6806 | blockPatterns: getBlockPatterns(patterns),
|
6807 | dynamicPatternsLookup
|
6808 | });
|
6809 | const filterByTrigger = (patterns, trigger) => {
|
6810 | return {
|
6811 | ...patterns,
|
6812 | blockPatterns: filter$5(patterns.blockPatterns, pattern => hasBlockTrigger(pattern, trigger))
|
6813 | };
|
6814 | };
|
6815 | const fromRawPatterns = patterns => {
|
6816 | const normalized = partition$1(map$3(patterns, normalizePattern));
|
6817 | each$e(normalized.errors, err => console.error(err.message, err.pattern));
|
6818 | return normalized.values;
|
6819 | };
|
6820 | const fromRawPatternsLookup = lookupFn => {
|
6821 | return ctx => {
|
6822 | const rawPatterns = lookupFn(ctx);
|
6823 | return fromRawPatterns(rawPatterns);
|
6824 | };
|
6825 | };
|
6826 |
|
6827 | const deviceDetection$1 = detect$1().deviceType;
|
6828 | const isTouch = deviceDetection$1.isTouch();
|
6829 | const DOM$a = DOMUtils.DOM;
|
6830 | const getHash = value => {
|
6831 | const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(',');
|
6832 | return foldl(items, (output, item) => {
|
6833 | const arr = item.split('=');
|
6834 | const key = arr[0];
|
6835 | const val = arr.length > 1 ? arr[1] : key;
|
6836 | output[trim$4(key)] = trim$4(val);
|
6837 | return output;
|
6838 | }, {});
|
6839 | };
|
6840 | const isRegExp = x => is$4(x, RegExp);
|
6841 | const option = name => editor => editor.options.get(name);
|
6842 | const stringOrObjectProcessor = value => isString(value) || isObject(value);
|
6843 | const bodyOptionProcessor = (editor, defaultValue = '') => value => {
|
6844 | const valid = isString(value);
|
6845 | if (valid) {
|
6846 | if (value.indexOf('=') !== -1) {
|
6847 | const bodyObj = getHash(value);
|
6848 | return {
|
6849 | value: get$a(bodyObj, editor.id).getOr(defaultValue),
|
6850 | valid
|
6851 | };
|
6852 | } else {
|
6853 | return {
|
6854 | value,
|
6855 | valid
|
6856 | };
|
6857 | }
|
6858 | } else {
|
6859 | return {
|
6860 | valid: false,
|
6861 | message: 'Must be a string.'
|
6862 | };
|
6863 | }
|
6864 | };
|
6865 | const register$7 = editor => {
|
6866 | const registerOption = editor.options.register;
|
6867 | registerOption('id', {
|
6868 | processor: 'string',
|
6869 | default: editor.id
|
6870 | });
|
6871 | registerOption('selector', { processor: 'string' });
|
6872 | registerOption('target', { processor: 'object' });
|
6873 | registerOption('suffix', { processor: 'string' });
|
6874 | registerOption('cache_suffix', { processor: 'string' });
|
6875 | registerOption('base_url', { processor: 'string' });
|
6876 | registerOption('referrer_policy', {
|
6877 | processor: 'string',
|
6878 | default: ''
|
6879 | });
|
6880 | registerOption('language_load', {
|
6881 | processor: 'boolean',
|
6882 | default: true
|
6883 | });
|
6884 | registerOption('inline', {
|
6885 | processor: 'boolean',
|
6886 | default: false
|
6887 | });
|
6888 | registerOption('iframe_attrs', {
|
6889 | processor: 'object',
|
6890 | default: {}
|
6891 | });
|
6892 | registerOption('doctype', {
|
6893 | processor: 'string',
|
6894 | default: '<!DOCTYPE html>'
|
6895 | });
|
6896 | registerOption('document_base_url', {
|
6897 | processor: 'string',
|
6898 | default: editor.documentBaseUrl
|
6899 | });
|
6900 | registerOption('body_id', {
|
6901 | processor: bodyOptionProcessor(editor, 'tinymce'),
|
6902 | default: 'tinymce'
|
6903 | });
|
6904 | registerOption('body_class', {
|
6905 | processor: bodyOptionProcessor(editor),
|
6906 | default: ''
|
6907 | });
|
6908 | registerOption('content_security_policy', {
|
6909 | processor: 'string',
|
6910 | default: ''
|
6911 | });
|
6912 | registerOption('br_in_pre', {
|
6913 | processor: 'boolean',
|
6914 | default: true
|
6915 | });
|
6916 | registerOption('forced_root_block', {
|
6917 | processor: value => {
|
6918 | const valid = isString(value) && isNotEmpty(value);
|
6919 | if (valid) {
|
6920 | return {
|
6921 | value,
|
6922 | valid
|
6923 | };
|
6924 | } else {
|
6925 | return {
|
6926 | valid: false,
|
6927 | message: 'Must be a non-empty string.'
|
6928 | };
|
6929 | }
|
6930 | },
|
6931 | default: 'p'
|
6932 | });
|
6933 | registerOption('forced_root_block_attrs', {
|
6934 | processor: 'object',
|
6935 | default: {}
|
6936 | });
|
6937 | registerOption('newline_behavior', {
|
6938 | processor: value => {
|
6939 | const valid = contains$2([
|
6940 | 'block',
|
6941 | 'linebreak',
|
6942 | 'invert',
|
6943 | 'default'
|
6944 | ], value);
|
6945 | return valid ? {
|
6946 | value,
|
6947 | valid
|
6948 | } : {
|
6949 | valid: false,
|
6950 | message: 'Must be one of: block, linebreak, invert or default.'
|
6951 | };
|
6952 | },
|
6953 | default: 'default'
|
6954 | });
|
6955 | registerOption('br_newline_selector', {
|
6956 | processor: 'string',
|
6957 | default: '.mce-toc h2,figcaption,caption'
|
6958 | });
|
6959 | registerOption('no_newline_selector', {
|
6960 | processor: 'string',
|
6961 | default: ''
|
6962 | });
|
6963 | registerOption('keep_styles', {
|
6964 | processor: 'boolean',
|
6965 | default: true
|
6966 | });
|
6967 | registerOption('end_container_on_empty_block', {
|
6968 | processor: value => {
|
6969 | if (isBoolean(value)) {
|
6970 | return {
|
6971 | valid: true,
|
6972 | value
|
6973 | };
|
6974 | } else if (isString(value)) {
|
6975 | return {
|
6976 | valid: true,
|
6977 | value
|
6978 | };
|
6979 | } else {
|
6980 | return {
|
6981 | valid: false,
|
6982 | message: 'Must be boolean or a string'
|
6983 | };
|
6984 | }
|
6985 | },
|
6986 | default: 'blockquote'
|
6987 | });
|
6988 | registerOption('font_size_style_values', {
|
6989 | processor: 'string',
|
6990 | default: 'xx-small,x-small,small,medium,large,x-large,xx-large'
|
6991 | });
|
6992 | registerOption('font_size_legacy_values', {
|
6993 | processor: 'string',
|
6994 | default: 'xx-small,small,medium,large,x-large,xx-large,300%'
|
6995 | });
|
6996 | registerOption('font_size_classes', {
|
6997 | processor: 'string',
|
6998 | default: ''
|
6999 | });
|
7000 | registerOption('automatic_uploads', {
|
7001 | processor: 'boolean',
|
7002 | default: true
|
7003 | });
|
7004 | registerOption('images_reuse_filename', {
|
7005 | processor: 'boolean',
|
7006 | default: false
|
7007 | });
|
7008 | registerOption('images_replace_blob_uris', {
|
7009 | processor: 'boolean',
|
7010 | default: true
|
7011 | });
|
7012 | registerOption('icons', {
|
7013 | processor: 'string',
|
7014 | default: ''
|
7015 | });
|
7016 | registerOption('icons_url', {
|
7017 | processor: 'string',
|
7018 | default: ''
|
7019 | });
|
7020 | registerOption('images_upload_url', {
|
7021 | processor: 'string',
|
7022 | default: ''
|
7023 | });
|
7024 | registerOption('images_upload_base_path', {
|
7025 | processor: 'string',
|
7026 | default: ''
|
7027 | });
|
7028 | registerOption('images_upload_credentials', {
|
7029 | processor: 'boolean',
|
7030 | default: false
|
7031 | });
|
7032 | registerOption('images_upload_handler', { processor: 'function' });
|
7033 | registerOption('language', {
|
7034 | processor: 'string',
|
7035 | default: 'en'
|
7036 | });
|
7037 | registerOption('language_url', {
|
7038 | processor: 'string',
|
7039 | default: ''
|
7040 | });
|
7041 | registerOption('entity_encoding', {
|
7042 | processor: 'string',
|
7043 | default: 'named'
|
7044 | });
|
7045 | registerOption('indent', {
|
7046 | processor: 'boolean',
|
7047 | default: true
|
7048 | });
|
7049 | registerOption('indent_before', {
|
7050 | processor: 'string',
|
7051 | default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,details,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist'
|
7052 | });
|
7053 | registerOption('indent_after', {
|
7054 | processor: 'string',
|
7055 | default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,details,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist'
|
7056 | });
|
7057 | registerOption('indent_use_margin', {
|
7058 | processor: 'boolean',
|
7059 | default: false
|
7060 | });
|
7061 | registerOption('indentation', {
|
7062 | processor: 'string',
|
7063 | default: '40px'
|
7064 | });
|
7065 | registerOption('content_css', {
|
7066 | processor: value => {
|
7067 | const valid = value === false || isString(value) || isArrayOf(value, isString);
|
7068 | if (valid) {
|
7069 | if (isString(value)) {
|
7070 | return {
|
7071 | value: map$3(value.split(','), trim$4),
|
7072 | valid
|
7073 | };
|
7074 | } else if (isArray$1(value)) {
|
7075 | return {
|
7076 | value,
|
7077 | valid
|
7078 | };
|
7079 | } else if (value === false) {
|
7080 | return {
|
7081 | value: [],
|
7082 | valid
|
7083 | };
|
7084 | } else {
|
7085 | return {
|
7086 | value,
|
7087 | valid
|
7088 | };
|
7089 | }
|
7090 | } else {
|
7091 | return {
|
7092 | valid: false,
|
7093 | message: 'Must be false, a string or an array of strings.'
|
7094 | };
|
7095 | }
|
7096 | },
|
7097 | default: isInline$1(editor) ? [] : ['default']
|
7098 | });
|
7099 | registerOption('content_style', { processor: 'string' });
|
7100 | registerOption('content_css_cors', {
|
7101 | processor: 'boolean',
|
7102 | default: false
|
7103 | });
|
7104 | registerOption('font_css', {
|
7105 | processor: value => {
|
7106 | const valid = isString(value) || isArrayOf(value, isString);
|
7107 | if (valid) {
|
7108 | const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$4);
|
7109 | return {
|
7110 | value: newValue,
|
7111 | valid
|
7112 | };
|
7113 | } else {
|
7114 | return {
|
7115 | valid: false,
|
7116 | message: 'Must be a string or an array of strings.'
|
7117 | };
|
7118 | }
|
7119 | },
|
7120 | default: []
|
7121 | });
|
7122 | registerOption('inline_boundaries', {
|
7123 | processor: 'boolean',
|
7124 | default: true
|
7125 | });
|
7126 | registerOption('inline_boundaries_selector', {
|
7127 | processor: 'string',
|
7128 | default: 'a[href],code,span.mce-annotation'
|
7129 | });
|
7130 | registerOption('object_resizing', {
|
7131 | processor: value => {
|
7132 | const valid = isBoolean(value) || isString(value);
|
7133 | if (valid) {
|
7134 | if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
|
7135 | return {
|
7136 | value: '',
|
7137 | valid
|
7138 | };
|
7139 | } else {
|
7140 | return {
|
7141 | value: value === true ? 'table,img,figure.image,div,video,iframe' : value,
|
7142 | valid
|
7143 | };
|
7144 | }
|
7145 | } else {
|
7146 | return {
|
7147 | valid: false,
|
7148 | message: 'Must be boolean or a string'
|
7149 | };
|
7150 | }
|
7151 | },
|
7152 | default: !isTouch
|
7153 | });
|
7154 | registerOption('resize_img_proportional', {
|
7155 | processor: 'boolean',
|
7156 | default: true
|
7157 | });
|
7158 | registerOption('event_root', { processor: 'string' });
|
7159 | registerOption('service_message', { processor: 'string' });
|
7160 | registerOption('theme', {
|
7161 | processor: value => value === false || isString(value) || isFunction(value),
|
7162 | default: 'silver'
|
7163 | });
|
7164 | registerOption('theme_url', { processor: 'string' });
|
7165 | registerOption('formats', { processor: 'object' });
|
7166 | registerOption('format_empty_lines', {
|
7167 | processor: 'boolean',
|
7168 | default: false
|
7169 | });
|
7170 | registerOption('format_noneditable_selector', {
|
7171 | processor: 'string',
|
7172 | default: ''
|
7173 | });
|
7174 | registerOption('preview_styles', {
|
7175 | processor: value => {
|
7176 | const valid = value === false || isString(value);
|
7177 | if (valid) {
|
7178 | return {
|
7179 | value: value === false ? '' : value,
|
7180 | valid
|
7181 | };
|
7182 | } else {
|
7183 | return {
|
7184 | valid: false,
|
7185 | message: 'Must be false or a string'
|
7186 | };
|
7187 | }
|
7188 | },
|
7189 | default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow'
|
7190 | });
|
7191 | registerOption('custom_ui_selector', {
|
7192 | processor: 'string',
|
7193 | default: ''
|
7194 | });
|
7195 | registerOption('hidden_input', {
|
7196 | processor: 'boolean',
|
7197 | default: true
|
7198 | });
|
7199 | registerOption('submit_patch', {
|
7200 | processor: 'boolean',
|
7201 | default: true
|
7202 | });
|
7203 | registerOption('encoding', { processor: 'string' });
|
7204 | registerOption('add_form_submit_trigger', {
|
7205 | processor: 'boolean',
|
7206 | default: true
|
7207 | });
|
7208 | registerOption('add_unload_trigger', {
|
7209 | processor: 'boolean',
|
7210 | default: true
|
7211 | });
|
7212 | registerOption('custom_undo_redo_levels', {
|
7213 | processor: 'number',
|
7214 | default: 0
|
7215 | });
|
7216 | registerOption('disable_nodechange', {
|
7217 | processor: 'boolean',
|
7218 | default: false
|
7219 | });
|
7220 | registerOption('readonly', {
|
7221 | processor: 'boolean',
|
7222 | default: false
|
7223 | });
|
7224 | registerOption('editable_root', {
|
7225 | processor: 'boolean',
|
7226 | default: true
|
7227 | });
|
7228 | registerOption('plugins', {
|
7229 | processor: 'string[]',
|
7230 | default: []
|
7231 | });
|
7232 | registerOption('external_plugins', { processor: 'object' });
|
7233 | registerOption('forced_plugins', { processor: 'string[]' });
|
7234 | registerOption('model', {
|
7235 | processor: 'string',
|
7236 | default: editor.hasPlugin('rtc') ? 'plugin' : 'dom'
|
7237 | });
|
7238 | registerOption('model_url', { processor: 'string' });
|
7239 | registerOption('block_unsupported_drop', {
|
7240 | processor: 'boolean',
|
7241 | default: true
|
7242 | });
|
7243 | registerOption('visual', {
|
7244 | processor: 'boolean',
|
7245 | default: true
|
7246 | });
|
7247 | registerOption('visual_table_class', {
|
7248 | processor: 'string',
|
7249 | default: 'mce-item-table'
|
7250 | });
|
7251 | registerOption('visual_anchor_class', {
|
7252 | processor: 'string',
|
7253 | default: 'mce-item-anchor'
|
7254 | });
|
7255 | registerOption('iframe_aria_text', {
|
7256 | processor: 'string',
|
7257 | default: 'Rich Text Area. Press ALT-0 for help.'
|
7258 | });
|
7259 | registerOption('setup', { processor: 'function' });
|
7260 | registerOption('init_instance_callback', { processor: 'function' });
|
7261 | registerOption('url_converter', {
|
7262 | processor: 'function',
|
7263 | default: editor.convertURL
|
7264 | });
|
7265 | registerOption('url_converter_scope', {
|
7266 | processor: 'object',
|
7267 | default: editor
|
7268 | });
|
7269 | registerOption('urlconverter_callback', { processor: 'function' });
|
7270 | registerOption('allow_conditional_comments', {
|
7271 | processor: 'boolean',
|
7272 | default: false
|
7273 | });
|
7274 | registerOption('allow_html_data_urls', {
|
7275 | processor: 'boolean',
|
7276 | default: false
|
7277 | });
|
7278 | registerOption('allow_svg_data_urls', { processor: 'boolean' });
|
7279 | registerOption('allow_html_in_named_anchor', {
|
7280 | processor: 'boolean',
|
7281 | default: false
|
7282 | });
|
7283 | registerOption('allow_script_urls', {
|
7284 | processor: 'boolean',
|
7285 | default: false
|
7286 | });
|
7287 | registerOption('allow_unsafe_link_target', {
|
7288 | processor: 'boolean',
|
7289 | default: false
|
7290 | });
|
7291 | registerOption('convert_fonts_to_spans', {
|
7292 | processor: 'boolean',
|
7293 | default: true,
|
7294 | deprecated: true
|
7295 | });
|
7296 | registerOption('fix_list_elements', {
|
7297 | processor: 'boolean',
|
7298 | default: false
|
7299 | });
|
7300 | registerOption('preserve_cdata', {
|
7301 | processor: 'boolean',
|
7302 | default: false
|
7303 | });
|
7304 | registerOption('remove_trailing_brs', {
|
7305 | processor: 'boolean',
|
7306 | default: true
|
7307 | });
|
7308 | registerOption('pad_empty_with_br', {
|
7309 | processor: 'boolean',
|
7310 | default: false
|
7311 | });
|
7312 | registerOption('inline_styles', {
|
7313 | processor: 'boolean',
|
7314 | default: true,
|
7315 | deprecated: true
|
7316 | });
|
7317 | registerOption('element_format', {
|
7318 | processor: 'string',
|
7319 | default: 'html'
|
7320 | });
|
7321 | registerOption('entities', { processor: 'string' });
|
7322 | registerOption('schema', {
|
7323 | processor: 'string',
|
7324 | default: 'html5'
|
7325 | });
|
7326 | registerOption('convert_urls', {
|
7327 | processor: 'boolean',
|
7328 | default: true
|
7329 | });
|
7330 | registerOption('relative_urls', {
|
7331 | processor: 'boolean',
|
7332 | default: true
|
7333 | });
|
7334 | registerOption('remove_script_host', {
|
7335 | processor: 'boolean',
|
7336 | default: true
|
7337 | });
|
7338 | registerOption('custom_elements', { processor: stringOrObjectProcessor });
|
7339 | registerOption('extended_valid_elements', { processor: 'string' });
|
7340 | registerOption('invalid_elements', { processor: 'string' });
|
7341 | registerOption('invalid_styles', { processor: stringOrObjectProcessor });
|
7342 | registerOption('valid_children', { processor: 'string' });
|
7343 | registerOption('valid_classes', { processor: stringOrObjectProcessor });
|
7344 | registerOption('valid_elements', { processor: 'string' });
|
7345 | registerOption('valid_styles', { processor: stringOrObjectProcessor });
|
7346 | registerOption('verify_html', {
|
7347 | processor: 'boolean',
|
7348 | default: true
|
7349 | });
|
7350 | registerOption('auto_focus', { processor: value => isString(value) || value === true });
|
7351 | registerOption('browser_spellcheck', {
|
7352 | processor: 'boolean',
|
7353 | default: false
|
7354 | });
|
7355 | registerOption('protect', { processor: 'array' });
|
7356 | registerOption('images_file_types', {
|
7357 | processor: 'string',
|
7358 | default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'
|
7359 | });
|
7360 | registerOption('deprecation_warnings', {
|
7361 | processor: 'boolean',
|
7362 | default: true
|
7363 | });
|
7364 | registerOption('a11y_advanced_options', {
|
7365 | processor: 'boolean',
|
7366 | default: false
|
7367 | });
|
7368 | registerOption('api_key', { processor: 'string' });
|
7369 | registerOption('license_key', { processor: 'string' });
|
7370 | registerOption('paste_block_drop', {
|
7371 | processor: 'boolean',
|
7372 | default: false
|
7373 | });
|
7374 | registerOption('paste_data_images', {
|
7375 | processor: 'boolean',
|
7376 | default: true
|
7377 | });
|
7378 | registerOption('paste_preprocess', { processor: 'function' });
|
7379 | registerOption('paste_postprocess', { processor: 'function' });
|
7380 | registerOption('paste_webkit_styles', {
|
7381 | processor: 'string',
|
7382 | default: 'none'
|
7383 | });
|
7384 | registerOption('paste_remove_styles_if_webkit', {
|
7385 | processor: 'boolean',
|
7386 | default: true
|
7387 | });
|
7388 | registerOption('paste_merge_formats', {
|
7389 | processor: 'boolean',
|
7390 | default: true
|
7391 | });
|
7392 | registerOption('smart_paste', {
|
7393 | processor: 'boolean',
|
7394 | default: true
|
7395 | });
|
7396 | registerOption('paste_as_text', {
|
7397 | processor: 'boolean',
|
7398 | default: false
|
7399 | });
|
7400 | registerOption('paste_tab_spaces', {
|
7401 | processor: 'number',
|
7402 | default: 4
|
7403 | });
|
7404 | registerOption('text_patterns', {
|
7405 | processor: value => {
|
7406 | if (isArrayOf(value, isObject) || value === false) {
|
7407 | const patterns = value === false ? [] : value;
|
7408 | return {
|
7409 | value: fromRawPatterns(patterns),
|
7410 | valid: true
|
7411 | };
|
7412 | } else {
|
7413 | return {
|
7414 | valid: false,
|
7415 | message: 'Must be an array of objects or false.'
|
7416 | };
|
7417 | }
|
7418 | },
|
7419 | default: [
|
7420 | {
|
7421 | start: '*',
|
7422 | end: '*',
|
7423 | format: 'italic'
|
7424 | },
|
7425 | {
|
7426 | start: '**',
|
7427 | end: '**',
|
7428 | format: 'bold'
|
7429 | },
|
7430 | {
|
7431 | start: '#',
|
7432 | format: 'h1',
|
7433 | trigger: 'space'
|
7434 | },
|
7435 | {
|
7436 | start: '##',
|
7437 | format: 'h2',
|
7438 | trigger: 'space'
|
7439 | },
|
7440 | {
|
7441 | start: '###',
|
7442 | format: 'h3',
|
7443 | trigger: 'space'
|
7444 | },
|
7445 | {
|
7446 | start: '####',
|
7447 | format: 'h4',
|
7448 | trigger: 'space'
|
7449 | },
|
7450 | {
|
7451 | start: '#####',
|
7452 | format: 'h5',
|
7453 | trigger: 'space'
|
7454 | },
|
7455 | {
|
7456 | start: '######',
|
7457 | format: 'h6',
|
7458 | trigger: 'space'
|
7459 | },
|
7460 | {
|
7461 | start: '1.',
|
7462 | cmd: 'InsertOrderedList',
|
7463 | trigger: 'space'
|
7464 | },
|
7465 | {
|
7466 | start: '*',
|
7467 | cmd: 'InsertUnorderedList',
|
7468 | trigger: 'space'
|
7469 | },
|
7470 | {
|
7471 | start: '-',
|
7472 | cmd: 'InsertUnorderedList',
|
7473 | trigger: 'space'
|
7474 | },
|
7475 | {
|
7476 | start: '>',
|
7477 | cmd: 'mceBlockQuote',
|
7478 | trigger: 'space'
|
7479 | },
|
7480 | {
|
7481 | start: '---',
|
7482 | cmd: 'InsertHorizontalRule',
|
7483 | trigger: 'space'
|
7484 | }
|
7485 | ]
|
7486 | });
|
7487 | registerOption('text_patterns_lookup', {
|
7488 | processor: value => {
|
7489 | if (isFunction(value)) {
|
7490 | return {
|
7491 | value: fromRawPatternsLookup(value),
|
7492 | valid: true
|
7493 | };
|
7494 | } else {
|
7495 | return {
|
7496 | valid: false,
|
7497 | message: 'Must be a single function'
|
7498 | };
|
7499 | }
|
7500 | },
|
7501 | default: _ctx => []
|
7502 | });
|
7503 | registerOption('noneditable_class', {
|
7504 | processor: 'string',
|
7505 | default: 'mceNonEditable'
|
7506 | });
|
7507 | registerOption('editable_class', {
|
7508 | processor: 'string',
|
7509 | default: 'mceEditable'
|
7510 | });
|
7511 | registerOption('noneditable_regexp', {
|
7512 | processor: value => {
|
7513 | if (isArrayOf(value, isRegExp)) {
|
7514 | return {
|
7515 | value,
|
7516 | valid: true
|
7517 | };
|
7518 | } else if (isRegExp(value)) {
|
7519 | return {
|
7520 | value: [value],
|
7521 | valid: true
|
7522 | };
|
7523 | } else {
|
7524 | return {
|
7525 | valid: false,
|
7526 | message: 'Must be a RegExp or an array of RegExp.'
|
7527 | };
|
7528 | }
|
7529 | },
|
7530 | default: []
|
7531 | });
|
7532 | registerOption('table_tab_navigation', {
|
7533 | processor: 'boolean',
|
7534 | default: true
|
7535 | });
|
7536 | registerOption('highlight_on_focus', {
|
7537 | processor: 'boolean',
|
7538 | default: true
|
7539 | });
|
7540 | registerOption('xss_sanitization', {
|
7541 | processor: 'boolean',
|
7542 | default: true
|
7543 | });
|
7544 | registerOption('details_initial_state', {
|
7545 | processor: value => {
|
7546 | const valid = contains$2([
|
7547 | 'inherited',
|
7548 | 'collapsed',
|
7549 | 'expanded'
|
7550 | ], value);
|
7551 | return valid ? {
|
7552 | value,
|
7553 | valid
|
7554 | } : {
|
7555 | valid: false,
|
7556 | message: 'Must be one of: inherited, collapsed, or expanded.'
|
7557 | };
|
7558 | },
|
7559 | default: 'inherited'
|
7560 | });
|
7561 | registerOption('details_serialized_state', {
|
7562 | processor: value => {
|
7563 | const valid = contains$2([
|
7564 | 'inherited',
|
7565 | 'collapsed',
|
7566 | 'expanded'
|
7567 | ], value);
|
7568 | return valid ? {
|
7569 | value,
|
7570 | valid
|
7571 | } : {
|
7572 | valid: false,
|
7573 | message: 'Must be one of: inherited, collapsed, or expanded.'
|
7574 | };
|
7575 | },
|
7576 | default: 'inherited'
|
7577 | });
|
7578 | registerOption('init_content_sync', {
|
7579 | processor: 'boolean',
|
7580 | default: false
|
7581 | });
|
7582 | registerOption('newdocument_content', {
|
7583 | processor: 'string',
|
7584 | default: ''
|
7585 | });
|
7586 | registerOption('sandbox_iframes', {
|
7587 | processor: 'boolean',
|
7588 | default: true
|
7589 | });
|
7590 | registerOption('sandbox_iframes_exclusions', {
|
7591 | processor: 'string[]',
|
7592 | default: [
|
7593 | 'youtube.com',
|
7594 | 'youtu.be',
|
7595 | 'vimeo.com',
|
7596 | 'player.vimeo.com',
|
7597 | 'dailymotion.com',
|
7598 | 'embed.music.apple.com',
|
7599 | 'open.spotify.com',
|
7600 | 'giphy.com',
|
7601 | 'dai.ly',
|
7602 | 'codepen.io'
|
7603 | ]
|
7604 | });
|
7605 | registerOption('convert_unsafe_embeds', {
|
7606 | processor: 'boolean',
|
7607 | default: true
|
7608 | });
|
7609 | editor.on('ScriptsLoaded', () => {
|
7610 | registerOption('directionality', {
|
7611 | processor: 'string',
|
7612 | default: I18n.isRtl() ? 'rtl' : undefined
|
7613 | });
|
7614 | registerOption('placeholder', {
|
7615 | processor: 'string',
|
7616 | default: DOM$a.getAttrib(editor.getElement(), 'placeholder')
|
7617 | });
|
7618 | });
|
7619 | };
|
7620 | const getIframeAttrs = option('iframe_attrs');
|
7621 | const getDocType = option('doctype');
|
7622 | const getDocumentBaseUrl = option('document_base_url');
|
7623 | const getBodyId = option('body_id');
|
7624 | const getBodyClass = option('body_class');
|
7625 | const getContentSecurityPolicy = option('content_security_policy');
|
7626 | const shouldPutBrInPre$1 = option('br_in_pre');
|
7627 | const getForcedRootBlock = option('forced_root_block');
|
7628 | const getForcedRootBlockAttrs = option('forced_root_block_attrs');
|
7629 | const getNewlineBehavior = option('newline_behavior');
|
7630 | const getBrNewLineSelector = option('br_newline_selector');
|
7631 | const getNoNewLineSelector = option('no_newline_selector');
|
7632 | const shouldKeepStyles = option('keep_styles');
|
7633 | const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
|
7634 | const isAutomaticUploadsEnabled = option('automatic_uploads');
|
7635 | const shouldReuseFileName = option('images_reuse_filename');
|
7636 | const shouldReplaceBlobUris = option('images_replace_blob_uris');
|
7637 | const getIconPackName = option('icons');
|
7638 | const getIconsUrl = option('icons_url');
|
7639 | const getImageUploadUrl = option('images_upload_url');
|
7640 | const getImageUploadBasePath = option('images_upload_base_path');
|
7641 | const getImagesUploadCredentials = option('images_upload_credentials');
|
7642 | const getImagesUploadHandler = option('images_upload_handler');
|
7643 | const shouldUseContentCssCors = option('content_css_cors');
|
7644 | const getReferrerPolicy = option('referrer_policy');
|
7645 | const getLanguageCode = option('language');
|
7646 | const getLanguageUrl = option('language_url');
|
7647 | const shouldIndentUseMargin = option('indent_use_margin');
|
7648 | const getIndentation = option('indentation');
|
7649 | const getContentCss = option('content_css');
|
7650 | const getContentStyle = option('content_style');
|
7651 | const getFontCss = option('font_css');
|
7652 | const getDirectionality = option('directionality');
|
7653 | const getInlineBoundarySelector = option('inline_boundaries_selector');
|
7654 | const getObjectResizing = option('object_resizing');
|
7655 | const getResizeImgProportional = option('resize_img_proportional');
|
7656 | const getPlaceholder = option('placeholder');
|
7657 | const getEventRoot = option('event_root');
|
7658 | const getServiceMessage = option('service_message');
|
7659 | const getTheme = option('theme');
|
7660 | const getThemeUrl = option('theme_url');
|
7661 | const getModel = option('model');
|
7662 | const getModelUrl = option('model_url');
|
7663 | const isInlineBoundariesEnabled = option('inline_boundaries');
|
7664 | const getFormats = option('formats');
|
7665 | const getPreviewStyles = option('preview_styles');
|
7666 | const canFormatEmptyLines = option('format_empty_lines');
|
7667 | const getFormatNoneditableSelector = option('format_noneditable_selector');
|
7668 | const getCustomUiSelector = option('custom_ui_selector');
|
7669 | const isInline$1 = option('inline');
|
7670 | const hasHiddenInput = option('hidden_input');
|
7671 | const shouldPatchSubmit = option('submit_patch');
|
7672 | const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
|
7673 | const shouldAddUnloadTrigger = option('add_unload_trigger');
|
7674 | const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
|
7675 | const shouldDisableNodeChange = option('disable_nodechange');
|
7676 | const isReadOnly$1 = option('readonly');
|
7677 | const hasEditableRoot$1 = option('editable_root');
|
7678 | const hasContentCssCors = option('content_css_cors');
|
7679 | const getPlugins = option('plugins');
|
7680 | const getExternalPlugins$1 = option('external_plugins');
|
7681 | const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
|
7682 | const isVisualAidsEnabled = option('visual');
|
7683 | const getVisualAidsTableClass = option('visual_table_class');
|
7684 | const getVisualAidsAnchorClass = option('visual_anchor_class');
|
7685 | const getIframeAriaText = option('iframe_aria_text');
|
7686 | const getSetupCallback = option('setup');
|
7687 | const getInitInstanceCallback = option('init_instance_callback');
|
7688 | const getUrlConverterCallback = option('urlconverter_callback');
|
7689 | const getAutoFocus = option('auto_focus');
|
7690 | const shouldBrowserSpellcheck = option('browser_spellcheck');
|
7691 | const getProtect = option('protect');
|
7692 | const shouldPasteBlockDrop = option('paste_block_drop');
|
7693 | const shouldPasteDataImages = option('paste_data_images');
|
7694 | const getPastePreProcess = option('paste_preprocess');
|
7695 | const getPastePostProcess = option('paste_postprocess');
|
7696 | const getNewDocumentContent = option('newdocument_content');
|
7697 | const getPasteWebkitStyles = option('paste_webkit_styles');
|
7698 | const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
|
7699 | const shouldPasteMergeFormats = option('paste_merge_formats');
|
7700 | const isSmartPasteEnabled = option('smart_paste');
|
7701 | const isPasteAsTextEnabled = option('paste_as_text');
|
7702 | const getPasteTabSpaces = option('paste_tab_spaces');
|
7703 | const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
|
7704 | const getTextPatterns = option('text_patterns');
|
7705 | const getTextPatternsLookup = option('text_patterns_lookup');
|
7706 | const getNonEditableClass = option('noneditable_class');
|
7707 | const getEditableClass = option('editable_class');
|
7708 | const getNonEditableRegExps = option('noneditable_regexp');
|
7709 | const shouldPreserveCData = option('preserve_cdata');
|
7710 | const shouldHighlightOnFocus = option('highlight_on_focus');
|
7711 | const shouldSanitizeXss = option('xss_sanitization');
|
7712 | const shouldUseDocumentWrite = option('init_content_sync');
|
7713 | const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup');
|
7714 | const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values'));
|
7715 | const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes'));
|
7716 | const isEncodingXml = editor => editor.options.get('encoding') === 'xml';
|
7717 | const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types'));
|
7718 | const hasTableTabNavigation = option('table_tab_navigation');
|
7719 | const getDetailsInitialState = option('details_initial_state');
|
7720 | const getDetailsSerializedState = option('details_serialized_state');
|
7721 | const shouldSandboxIframes = option('sandbox_iframes');
|
7722 | const getSandboxIframesExclusions = editor => editor.options.get('sandbox_iframes_exclusions');
|
7723 | const shouldConvertUnsafeEmbeds = option('convert_unsafe_embeds');
|
7724 | const getLicenseKey = option('license_key');
|
7725 | const getApiKey = option('api_key');
|
7726 |
|
7727 | const isElement$3 = isElement$6;
|
7728 | const isText$5 = isText$b;
|
7729 | const removeNode$1 = node => {
|
7730 | const parentNode = node.parentNode;
|
7731 | if (parentNode) {
|
7732 | parentNode.removeChild(node);
|
7733 | }
|
7734 | };
|
7735 | const trimCount = text => {
|
7736 | const trimmedText = trim$2(text);
|
7737 | return {
|
7738 | count: text.length - trimmedText.length,
|
7739 | text: trimmedText
|
7740 | };
|
7741 | };
|
7742 | const deleteZwspChars = caretContainer => {
|
7743 | let idx;
|
7744 | while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
|
7745 | caretContainer.deleteData(idx, 1);
|
7746 | }
|
7747 | };
|
7748 | const removeUnchanged = (caretContainer, pos) => {
|
7749 | remove$2(caretContainer);
|
7750 | return pos;
|
7751 | };
|
7752 | const removeTextAndReposition = (caretContainer, pos) => {
|
7753 | const before = trimCount(caretContainer.data.substr(0, pos.offset()));
|
7754 | const after = trimCount(caretContainer.data.substr(pos.offset()));
|
7755 | const text = before.text + after.text;
|
7756 | if (text.length > 0) {
|
7757 | deleteZwspChars(caretContainer);
|
7758 | return CaretPosition(caretContainer, pos.offset() - before.count);
|
7759 | } else {
|
7760 | return pos;
|
7761 | }
|
7762 | };
|
7763 | const removeElementAndReposition = (caretContainer, pos) => {
|
7764 | const parentNode = pos.container();
|
7765 | const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => {
|
7766 | return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
|
7767 | }).getOr(pos);
|
7768 | remove$2(caretContainer);
|
7769 | return newPosition;
|
7770 | };
|
7771 | const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
|
7772 | const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
|
7773 | const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
|
7774 | const remove$2 = caretContainerNode => {
|
7775 | if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
|
7776 | if (hasContent(caretContainerNode)) {
|
7777 | caretContainerNode.removeAttribute('data-mce-caret');
|
7778 | } else {
|
7779 | removeNode$1(caretContainerNode);
|
7780 | }
|
7781 | }
|
7782 | if (isText$5(caretContainerNode)) {
|
7783 | deleteZwspChars(caretContainerNode);
|
7784 | if (caretContainerNode.data.length === 0) {
|
7785 | removeNode$1(caretContainerNode);
|
7786 | }
|
7787 | }
|
7788 | };
|
7789 |
|
7790 | const isContentEditableFalse$8 = isContentEditableFalse$b;
|
7791 | const isMedia$1 = isMedia$2;
|
7792 | const isTableCell$1 = isTableCell$3;
|
7793 | const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object';
|
7794 | const getAbsoluteClientRect = (root, element, before) => {
|
7795 | const clientRect = collapse(element.getBoundingClientRect(), before);
|
7796 | let scrollX;
|
7797 | let scrollY;
|
7798 | if (root.tagName === 'BODY') {
|
7799 | const docElm = root.ownerDocument.documentElement;
|
7800 | scrollX = root.scrollLeft || docElm.scrollLeft;
|
7801 | scrollY = root.scrollTop || docElm.scrollTop;
|
7802 | } else {
|
7803 | const rootRect = root.getBoundingClientRect();
|
7804 | scrollX = root.scrollLeft - rootRect.left;
|
7805 | scrollY = root.scrollTop - rootRect.top;
|
7806 | }
|
7807 | clientRect.left += scrollX;
|
7808 | clientRect.right += scrollX;
|
7809 | clientRect.top += scrollY;
|
7810 | clientRect.bottom += scrollY;
|
7811 | clientRect.width = 1;
|
7812 | let margin = element.offsetWidth - element.clientWidth;
|
7813 | if (margin > 0) {
|
7814 | if (before) {
|
7815 | margin *= -1;
|
7816 | }
|
7817 | clientRect.left += margin;
|
7818 | clientRect.right += margin;
|
7819 | }
|
7820 | return clientRect;
|
7821 | };
|
7822 | const trimInlineCaretContainers = root => {
|
7823 | var _a, _b;
|
7824 | const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
|
7825 | for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
|
7826 | const node = fakeCaretTargetNodes[i].dom;
|
7827 | let sibling = node.previousSibling;
|
7828 | if (endsWithCaretContainer$1(sibling)) {
|
7829 | const data = sibling.data;
|
7830 | if (data.length === 1) {
|
7831 | (_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling);
|
7832 | } else {
|
7833 | sibling.deleteData(data.length - 1, 1);
|
7834 | }
|
7835 | }
|
7836 | sibling = node.nextSibling;
|
7837 | if (startsWithCaretContainer$1(sibling)) {
|
7838 | const data = sibling.data;
|
7839 | if (data.length === 1) {
|
7840 | (_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling);
|
7841 | } else {
|
7842 | sibling.deleteData(0, 1);
|
7843 | }
|
7844 | }
|
7845 | }
|
7846 | };
|
7847 | const FakeCaret = (editor, root, isBlock, hasFocus) => {
|
7848 | const lastVisualCaret = value$2();
|
7849 | let cursorInterval;
|
7850 | let caretContainerNode;
|
7851 | const caretBlock = getForcedRootBlock(editor);
|
7852 | const dom = editor.dom;
|
7853 | const show = (before, element) => {
|
7854 | let rng;
|
7855 | hide();
|
7856 | if (isTableCell$1(element)) {
|
7857 | return null;
|
7858 | }
|
7859 | if (isBlock(element)) {
|
7860 | const caretContainer = insertBlock(caretBlock, element, before);
|
7861 | const clientRect = getAbsoluteClientRect(root, element, before);
|
7862 | dom.setStyle(caretContainer, 'top', clientRect.top);
|
7863 | dom.setStyle(caretContainer, 'caret-color', 'transparent');
|
7864 | caretContainerNode = caretContainer;
|
7865 | const caret = dom.create('div', {
|
7866 | 'class': 'mce-visual-caret',
|
7867 | 'data-mce-bogus': 'all'
|
7868 | });
|
7869 | dom.setStyles(caret, { ...clientRect });
|
7870 | dom.add(root, caret);
|
7871 | lastVisualCaret.set({
|
7872 | caret,
|
7873 | element,
|
7874 | before
|
7875 | });
|
7876 | if (before) {
|
7877 | dom.addClass(caret, 'mce-visual-caret-before');
|
7878 | }
|
7879 | startBlink();
|
7880 | rng = element.ownerDocument.createRange();
|
7881 | rng.setStart(caretContainer, 0);
|
7882 | rng.setEnd(caretContainer, 0);
|
7883 | } else {
|
7884 | caretContainerNode = insertInline$1(element, before);
|
7885 | rng = element.ownerDocument.createRange();
|
7886 | if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
|
7887 | rng.setStart(caretContainerNode, 0);
|
7888 | rng.setEnd(caretContainerNode, 0);
|
7889 | } else {
|
7890 | rng.setStart(caretContainerNode, 1);
|
7891 | rng.setEnd(caretContainerNode, 1);
|
7892 | }
|
7893 | return rng;
|
7894 | }
|
7895 | return rng;
|
7896 | };
|
7897 | const hide = () => {
|
7898 | trimInlineCaretContainers(root);
|
7899 | if (caretContainerNode) {
|
7900 | remove$2(caretContainerNode);
|
7901 | caretContainerNode = null;
|
7902 | }
|
7903 | lastVisualCaret.on(caretState => {
|
7904 | dom.remove(caretState.caret);
|
7905 | lastVisualCaret.clear();
|
7906 | });
|
7907 | if (cursorInterval) {
|
7908 | clearInterval(cursorInterval);
|
7909 | cursorInterval = undefined;
|
7910 | }
|
7911 | };
|
7912 | const startBlink = () => {
|
7913 | cursorInterval = setInterval(() => {
|
7914 | lastVisualCaret.on(caretState => {
|
7915 | if (hasFocus()) {
|
7916 | dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden');
|
7917 | } else {
|
7918 | dom.addClass(caretState.caret, 'mce-visual-caret-hidden');
|
7919 | }
|
7920 | });
|
7921 | }, 500);
|
7922 | };
|
7923 | const reposition = () => {
|
7924 | lastVisualCaret.on(caretState => {
|
7925 | const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
|
7926 | dom.setStyles(caretState.caret, { ...clientRect });
|
7927 | });
|
7928 | };
|
7929 | const destroy = () => clearInterval(cursorInterval);
|
7930 | const getCss = () => '.mce-visual-caret {' + 'position: absolute;' + 'background-color: black;' + 'background-color: currentcolor;' + '}' + '.mce-visual-caret-hidden {' + 'display: none;' + '}' + '*[data-mce-caret] {' + 'position: absolute;' + 'left: -1000px;' + 'right: auto;' + 'top: 0;' + 'margin: 0;' + 'padding: 0;' + '}';
|
7931 | return {
|
7932 | show,
|
7933 | hide,
|
7934 | getCss,
|
7935 | reposition,
|
7936 | destroy
|
7937 | };
|
7938 | };
|
7939 | const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
|
7940 | const isInlineFakeCaretTarget = node => isContentEditableFalse$8(node) || isMedia$1(node);
|
7941 | const isFakeCaretTarget = node => {
|
7942 | const isTarget = isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser();
|
7943 | return isTarget && parentElement(SugarElement.fromDom(node)).exists(isEditable$2);
|
7944 | };
|
7945 |
|
7946 | const isContentEditableTrue$1 = isContentEditableTrue$3;
|
7947 | const isContentEditableFalse$7 = isContentEditableFalse$b;
|
7948 | const isMedia = isMedia$2;
|
7949 | const isBlockLike = matchStyleValues('display', 'block table table-cell table-caption list-item');
|
7950 | const isCaretContainer = isCaretContainer$2;
|
7951 | const isCaretContainerBlock = isCaretContainerBlock$1;
|
7952 | const isElement$2 = isElement$6;
|
7953 | const isText$4 = isText$b;
|
7954 | const isCaretCandidate$1 = isCaretCandidate$3;
|
7955 | const isForwards = direction => direction > 0;
|
7956 | const isBackwards = direction => direction < 0;
|
7957 | const skipCaretContainers = (walk, shallow) => {
|
7958 | let node;
|
7959 | while (node = walk(shallow)) {
|
7960 | if (!isCaretContainerBlock(node)) {
|
7961 | return node;
|
7962 | }
|
7963 | }
|
7964 | return null;
|
7965 | };
|
7966 | const findNode = (node, direction, predicateFn, rootNode, shallow) => {
|
7967 | const walker = new DomTreeWalker(node, rootNode);
|
7968 | const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node);
|
7969 | let tempNode;
|
7970 | if (isBackwards(direction)) {
|
7971 | if (isCefOrCaretContainer) {
|
7972 | tempNode = skipCaretContainers(walker.prev.bind(walker), true);
|
7973 | if (predicateFn(tempNode)) {
|
7974 | return tempNode;
|
7975 | }
|
7976 | }
|
7977 | while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) {
|
7978 | if (predicateFn(tempNode)) {
|
7979 | return tempNode;
|
7980 | }
|
7981 | }
|
7982 | }
|
7983 | if (isForwards(direction)) {
|
7984 | if (isCefOrCaretContainer) {
|
7985 | tempNode = skipCaretContainers(walker.next.bind(walker), true);
|
7986 | if (predicateFn(tempNode)) {
|
7987 | return tempNode;
|
7988 | }
|
7989 | }
|
7990 | while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) {
|
7991 | if (predicateFn(tempNode)) {
|
7992 | return tempNode;
|
7993 | }
|
7994 | }
|
7995 | }
|
7996 | return null;
|
7997 | };
|
7998 | const getEditingHost = (node, rootNode) => {
|
7999 | const isCETrue = node => isContentEditableTrue$1(node.dom);
|
8000 | const isRoot = node => node.dom === rootNode;
|
8001 | return ancestor$4(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode);
|
8002 | };
|
8003 | const getParentBlock$3 = (node, rootNode) => {
|
8004 | while (node && node !== rootNode) {
|
8005 | if (isBlockLike(node)) {
|
8006 | return node;
|
8007 | }
|
8008 | node = node.parentNode;
|
8009 | }
|
8010 | return null;
|
8011 | };
|
8012 | const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
|
8013 | const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
|
8014 | if (!caretPosition) {
|
8015 | return Optional.none();
|
8016 | }
|
8017 | const container = caretPosition.container();
|
8018 | const offset = caretPosition.offset();
|
8019 | if (!isElement$2(container)) {
|
8020 | return Optional.none();
|
8021 | }
|
8022 | return Optional.from(container.childNodes[offset + relativeOffset]);
|
8023 | };
|
8024 | const beforeAfter = (before, node) => {
|
8025 | var _a;
|
8026 | const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
8027 | const range = doc.createRange();
|
8028 | if (before) {
|
8029 | range.setStartBefore(node);
|
8030 | range.setEndBefore(node);
|
8031 | } else {
|
8032 | range.setStartAfter(node);
|
8033 | range.setEndAfter(node);
|
8034 | }
|
8035 | return range;
|
8036 | };
|
8037 | const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
|
8038 | const lean = (left, root, node) => {
|
8039 | const siblingName = left ? 'previousSibling' : 'nextSibling';
|
8040 | let tempNode = node;
|
8041 | while (tempNode && tempNode !== root) {
|
8042 | let sibling = tempNode[siblingName];
|
8043 | if (sibling && isCaretContainer(sibling)) {
|
8044 | sibling = sibling[siblingName];
|
8045 | }
|
8046 | if (isContentEditableFalse$7(sibling) || isMedia(sibling)) {
|
8047 | if (isNodesInSameBlock(root, sibling, tempNode)) {
|
8048 | return sibling;
|
8049 | }
|
8050 | break;
|
8051 | }
|
8052 | if (isCaretCandidate$1(sibling)) {
|
8053 | break;
|
8054 | }
|
8055 | tempNode = tempNode.parentNode;
|
8056 | }
|
8057 | return null;
|
8058 | };
|
8059 | const before$2 = curry(beforeAfter, true);
|
8060 | const after$2 = curry(beforeAfter, false);
|
8061 | const normalizeRange = (direction, root, range) => {
|
8062 | let node;
|
8063 | const leanLeft = curry(lean, true, root);
|
8064 | const leanRight = curry(lean, false, root);
|
8065 | const container = range.startContainer;
|
8066 | const offset = range.startOffset;
|
8067 | if (isCaretContainerBlock$1(container)) {
|
8068 | const block = isText$4(container) ? container.parentNode : container;
|
8069 | const location = block.getAttribute('data-mce-caret');
|
8070 | if (location === 'before') {
|
8071 | node = block.nextSibling;
|
8072 | if (isFakeCaretTarget(node)) {
|
8073 | return before$2(node);
|
8074 | }
|
8075 | }
|
8076 | if (location === 'after') {
|
8077 | node = block.previousSibling;
|
8078 | if (isFakeCaretTarget(node)) {
|
8079 | return after$2(node);
|
8080 | }
|
8081 | }
|
8082 | }
|
8083 | if (!range.collapsed) {
|
8084 | return range;
|
8085 | }
|
8086 | if (isText$b(container)) {
|
8087 | if (isCaretContainer(container)) {
|
8088 | if (direction === 1) {
|
8089 | node = leanRight(container);
|
8090 | if (node) {
|
8091 | return before$2(node);
|
8092 | }
|
8093 | node = leanLeft(container);
|
8094 | if (node) {
|
8095 | return after$2(node);
|
8096 | }
|
8097 | }
|
8098 | if (direction === -1) {
|
8099 | node = leanLeft(container);
|
8100 | if (node) {
|
8101 | return after$2(node);
|
8102 | }
|
8103 | node = leanRight(container);
|
8104 | if (node) {
|
8105 | return before$2(node);
|
8106 | }
|
8107 | }
|
8108 | return range;
|
8109 | }
|
8110 | if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
|
8111 | if (direction === 1) {
|
8112 | node = leanRight(container);
|
8113 | if (node) {
|
8114 | return before$2(node);
|
8115 | }
|
8116 | }
|
8117 | return range;
|
8118 | }
|
8119 | if (startsWithCaretContainer$1(container) && offset <= 1) {
|
8120 | if (direction === -1) {
|
8121 | node = leanLeft(container);
|
8122 | if (node) {
|
8123 | return after$2(node);
|
8124 | }
|
8125 | }
|
8126 | return range;
|
8127 | }
|
8128 | if (offset === container.data.length) {
|
8129 | node = leanRight(container);
|
8130 | if (node) {
|
8131 | return before$2(node);
|
8132 | }
|
8133 | return range;
|
8134 | }
|
8135 | if (offset === 0) {
|
8136 | node = leanLeft(container);
|
8137 | if (node) {
|
8138 | return after$2(node);
|
8139 | }
|
8140 | return range;
|
8141 | }
|
8142 | }
|
8143 | return range;
|
8144 | };
|
8145 | const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$7);
|
8146 | const getNormalizedRangeEndPoint = (direction, root, range) => {
|
8147 | const normalizedRange = normalizeRange(direction, root, range);
|
8148 | return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange);
|
8149 | };
|
8150 | const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom);
|
8151 | const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
|
8152 | const getVisualCaretPosition = (walkFn, caretPosition) => {
|
8153 | let pos = caretPosition;
|
8154 | while (pos = walkFn(pos)) {
|
8155 | if (pos.isVisible()) {
|
8156 | return pos;
|
8157 | }
|
8158 | }
|
8159 | return pos;
|
8160 | };
|
8161 | const isMoveInsideSameBlock = (from, to) => {
|
8162 | const inSameBlock = isInSameBlock(from, to);
|
8163 | if (!inSameBlock && isBr$6(from.getNode())) {
|
8164 | return true;
|
8165 | }
|
8166 | return inSameBlock;
|
8167 | };
|
8168 |
|
8169 | var HDirection;
|
8170 | (function (HDirection) {
|
8171 | HDirection[HDirection['Backwards'] = -1] = 'Backwards';
|
8172 | HDirection[HDirection['Forwards'] = 1] = 'Forwards';
|
8173 | }(HDirection || (HDirection = {})));
|
8174 | const isContentEditableFalse$6 = isContentEditableFalse$b;
|
8175 | const isText$3 = isText$b;
|
8176 | const isElement$1 = isElement$6;
|
8177 | const isBr$2 = isBr$6;
|
8178 | const isCaretCandidate = isCaretCandidate$3;
|
8179 | const isAtomic = isAtomic$1;
|
8180 | const isEditableCaretCandidate = isEditableCaretCandidate$1;
|
8181 | const getParents$3 = (node, root) => {
|
8182 | const parents = [];
|
8183 | let tempNode = node;
|
8184 | while (tempNode && tempNode !== root) {
|
8185 | parents.push(tempNode);
|
8186 | tempNode = tempNode.parentNode;
|
8187 | }
|
8188 | return parents;
|
8189 | };
|
8190 | const nodeAtIndex = (container, offset) => {
|
8191 | if (container.hasChildNodes() && offset < container.childNodes.length) {
|
8192 | return container.childNodes[offset];
|
8193 | }
|
8194 | return null;
|
8195 | };
|
8196 | const getCaretCandidatePosition = (direction, node) => {
|
8197 | if (isForwards(direction)) {
|
8198 | if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
|
8199 | return CaretPosition.before(node);
|
8200 | }
|
8201 | if (isText$3(node)) {
|
8202 | return CaretPosition(node, 0);
|
8203 | }
|
8204 | }
|
8205 | if (isBackwards(direction)) {
|
8206 | if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
|
8207 | return CaretPosition.after(node);
|
8208 | }
|
8209 | if (isText$3(node)) {
|
8210 | return CaretPosition(node, node.data.length);
|
8211 | }
|
8212 | }
|
8213 | if (isBackwards(direction)) {
|
8214 | if (isBr$2(node)) {
|
8215 | return CaretPosition.before(node);
|
8216 | }
|
8217 | return CaretPosition.after(node);
|
8218 | }
|
8219 | return CaretPosition.before(node);
|
8220 | };
|
8221 | const moveForwardFromBr = (root, nextNode) => {
|
8222 | const nextSibling = nextNode.nextSibling;
|
8223 | if (nextSibling && isCaretCandidate(nextSibling)) {
|
8224 | if (isText$3(nextSibling)) {
|
8225 | return CaretPosition(nextSibling, 0);
|
8226 | } else {
|
8227 | return CaretPosition.before(nextSibling);
|
8228 | }
|
8229 | } else {
|
8230 | return findCaretPosition$1(HDirection.Forwards, CaretPosition.after(nextNode), root);
|
8231 | }
|
8232 | };
|
8233 | const findCaretPosition$1 = (direction, startPos, root) => {
|
8234 | let node;
|
8235 | let nextNode;
|
8236 | let innerNode;
|
8237 | let caretPosition;
|
8238 | if (!isElement$1(root) || !startPos) {
|
8239 | return null;
|
8240 | }
|
8241 | if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
|
8242 | caretPosition = CaretPosition.after(root.lastChild);
|
8243 | if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
|
8244 | return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
|
8245 | }
|
8246 | } else {
|
8247 | caretPosition = startPos;
|
8248 | }
|
8249 | const container = caretPosition.container();
|
8250 | let offset = caretPosition.offset();
|
8251 | if (isText$3(container)) {
|
8252 | if (isBackwards(direction) && offset > 0) {
|
8253 | return CaretPosition(container, --offset);
|
8254 | }
|
8255 | if (isForwards(direction) && offset < container.length) {
|
8256 | return CaretPosition(container, ++offset);
|
8257 | }
|
8258 | node = container;
|
8259 | } else {
|
8260 | if (isBackwards(direction) && offset > 0) {
|
8261 | nextNode = nodeAtIndex(container, offset - 1);
|
8262 | if (isCaretCandidate(nextNode)) {
|
8263 | if (!isAtomic(nextNode)) {
|
8264 | innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
|
8265 | if (innerNode) {
|
8266 | if (isText$3(innerNode)) {
|
8267 | return CaretPosition(innerNode, innerNode.data.length);
|
8268 | }
|
8269 | return CaretPosition.after(innerNode);
|
8270 | }
|
8271 | }
|
8272 | if (isText$3(nextNode)) {
|
8273 | return CaretPosition(nextNode, nextNode.data.length);
|
8274 | }
|
8275 | return CaretPosition.before(nextNode);
|
8276 | }
|
8277 | }
|
8278 | if (isForwards(direction) && offset < container.childNodes.length) {
|
8279 | nextNode = nodeAtIndex(container, offset);
|
8280 | if (isCaretCandidate(nextNode)) {
|
8281 | if (isBr$2(nextNode)) {
|
8282 | return moveForwardFromBr(root, nextNode);
|
8283 | }
|
8284 | if (!isAtomic(nextNode)) {
|
8285 | innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
|
8286 | if (innerNode) {
|
8287 | if (isText$3(innerNode)) {
|
8288 | return CaretPosition(innerNode, 0);
|
8289 | }
|
8290 | return CaretPosition.before(innerNode);
|
8291 | }
|
8292 | }
|
8293 | if (isText$3(nextNode)) {
|
8294 | return CaretPosition(nextNode, 0);
|
8295 | }
|
8296 | return CaretPosition.after(nextNode);
|
8297 | }
|
8298 | }
|
8299 | node = nextNode ? nextNode : caretPosition.getNode();
|
8300 | }
|
8301 | if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) {
|
8302 | node = findNode(node, direction, always, root, true);
|
8303 | if (isEditableCaretCandidate(node, root)) {
|
8304 | return getCaretCandidatePosition(direction, node);
|
8305 | }
|
8306 | }
|
8307 | nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node;
|
8308 | const rootContentEditableFalseElm = last$1(filter$5(getParents$3(container, root), isContentEditableFalse$6));
|
8309 | if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
|
8310 | if (isForwards(direction)) {
|
8311 | caretPosition = CaretPosition.after(rootContentEditableFalseElm);
|
8312 | } else {
|
8313 | caretPosition = CaretPosition.before(rootContentEditableFalseElm);
|
8314 | }
|
8315 | return caretPosition;
|
8316 | }
|
8317 | if (nextNode) {
|
8318 | return getCaretCandidatePosition(direction, nextNode);
|
8319 | }
|
8320 | return null;
|
8321 | };
|
8322 | const CaretWalker = root => ({
|
8323 | next: caretPosition => {
|
8324 | return findCaretPosition$1(HDirection.Forwards, caretPosition, root);
|
8325 | },
|
8326 | prev: caretPosition => {
|
8327 | return findCaretPosition$1(HDirection.Backwards, caretPosition, root);
|
8328 | }
|
8329 | });
|
8330 |
|
8331 | const walkToPositionIn = (forward, root, start) => {
|
8332 | const position = forward ? CaretPosition.before(start) : CaretPosition.after(start);
|
8333 | return fromPosition(forward, root, position);
|
8334 | };
|
8335 | const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
|
8336 | const isBeforeOrStart = position => {
|
8337 | if (CaretPosition.isTextPosition(position)) {
|
8338 | return position.offset() === 0;
|
8339 | } else {
|
8340 | return isCaretCandidate$3(position.getNode());
|
8341 | }
|
8342 | };
|
8343 | const isAfterOrEnd = position => {
|
8344 | if (CaretPosition.isTextPosition(position)) {
|
8345 | const container = position.container();
|
8346 | return position.offset() === container.data.length;
|
8347 | } else {
|
8348 | return isCaretCandidate$3(position.getNode(true));
|
8349 | }
|
8350 | };
|
8351 | const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
|
8352 | const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
|
8353 | const shouldSkipPosition = (forward, from, to) => {
|
8354 | if (forward) {
|
8355 | return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
|
8356 | } else {
|
8357 | return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
|
8358 | }
|
8359 | };
|
8360 | const fromPosition = (forward, root, pos) => {
|
8361 | const walker = CaretWalker(root);
|
8362 | return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
|
8363 | };
|
8364 | const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => {
|
8365 | if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
|
8366 | return fromPosition(forward, root, to);
|
8367 | } else {
|
8368 | return Optional.some(to);
|
8369 | }
|
8370 | });
|
8371 | const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
|
8372 | const positionIn = (forward, element) => {
|
8373 | const startNode = forward ? element.firstChild : element.lastChild;
|
8374 | if (isText$b(startNode)) {
|
8375 | return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
|
8376 | } else if (startNode) {
|
8377 | if (isCaretCandidate$3(startNode)) {
|
8378 | return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
|
8379 | } else {
|
8380 | return walkToPositionIn(forward, element, startNode);
|
8381 | }
|
8382 | } else {
|
8383 | return Optional.none();
|
8384 | }
|
8385 | };
|
8386 | const nextPosition = curry(fromPosition, true);
|
8387 | const prevPosition = curry(fromPosition, false);
|
8388 | const firstPositionIn = curry(positionIn, true);
|
8389 | const lastPositionIn = curry(positionIn, false);
|
8390 |
|
8391 | const CARET_ID = '_mce_caret';
|
8392 | const isCaretNode = node => isElement$6(node) && node.id === CARET_ID;
|
8393 | const getParentCaretContainer = (body, node) => {
|
8394 | let currentNode = node;
|
8395 | while (currentNode && currentNode !== body) {
|
8396 | if (isCaretNode(currentNode)) {
|
8397 | return currentNode;
|
8398 | }
|
8399 | currentNode = currentNode.parentNode;
|
8400 | }
|
8401 | return null;
|
8402 | };
|
8403 |
|
8404 | const isStringPathBookmark = bookmark => isString(bookmark.start);
|
8405 | const isRangeBookmark = bookmark => has$2(bookmark, 'rng');
|
8406 | const isIdBookmark = bookmark => has$2(bookmark, 'id');
|
8407 | const isIndexBookmark = bookmark => has$2(bookmark, 'name');
|
8408 | const isPathBookmark = bookmark => Tools.isArray(bookmark.start);
|
8409 |
|
8410 | const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
|
8411 | const addBogus = (dom, node) => {
|
8412 | if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) {
|
8413 | node.innerHTML = '<br data-mce-bogus="1" />';
|
8414 | }
|
8415 | return node;
|
8416 | };
|
8417 | const resolveCaretPositionBookmark = (dom, bookmark) => {
|
8418 | const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start));
|
8419 | const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end));
|
8420 | return lift2(startPos, endPos, (start, end) => {
|
8421 | const range = dom.createRng();
|
8422 | range.setStart(start.container(), start.offset());
|
8423 | range.setEnd(end.container(), end.offset());
|
8424 | return {
|
8425 | range,
|
8426 | forward: isForwardBookmark(bookmark)
|
8427 | };
|
8428 | });
|
8429 | };
|
8430 | const insertZwsp = (node, rng) => {
|
8431 | var _a;
|
8432 | const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
8433 | const textNode = doc.createTextNode(ZWSP$1);
|
8434 | node.appendChild(textNode);
|
8435 | rng.setStart(textNode, 0);
|
8436 | rng.setEnd(textNode, 0);
|
8437 | };
|
8438 | const isEmpty$1 = node => !node.hasChildNodes();
|
8439 | const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => {
|
8440 | rng.setStart(pos.container(), pos.offset());
|
8441 | rng.setEnd(pos.container(), pos.offset());
|
8442 | return true;
|
8443 | });
|
8444 | const padEmptyCaretContainer = (root, node, rng) => {
|
8445 | if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
|
8446 | insertZwsp(node, rng);
|
8447 | return true;
|
8448 | } else {
|
8449 | return false;
|
8450 | }
|
8451 | };
|
8452 | const setEndPoint = (dom, start, bookmark, rng) => {
|
8453 | const point = bookmark[start ? 'start' : 'end'];
|
8454 | const root = dom.getRoot();
|
8455 | if (point) {
|
8456 | let node = root;
|
8457 | let offset = point[0];
|
8458 | for (let i = point.length - 1; node && i >= 1; i--) {
|
8459 | const children = node.childNodes;
|
8460 | if (padEmptyCaretContainer(root, node, rng)) {
|
8461 | return true;
|
8462 | }
|
8463 | if (point[i] > children.length - 1) {
|
8464 | if (padEmptyCaretContainer(root, node, rng)) {
|
8465 | return true;
|
8466 | }
|
8467 | return tryFindRangePosition(node, rng);
|
8468 | }
|
8469 | node = children[point[i]];
|
8470 | }
|
8471 | if (isText$b(node)) {
|
8472 | offset = Math.min(point[0], node.data.length);
|
8473 | }
|
8474 | if (isElement$6(node)) {
|
8475 | offset = Math.min(point[0], node.childNodes.length);
|
8476 | }
|
8477 | if (start) {
|
8478 | rng.setStart(node, offset);
|
8479 | } else {
|
8480 | rng.setEnd(node, offset);
|
8481 | }
|
8482 | }
|
8483 | return true;
|
8484 | };
|
8485 | const isValidTextNode = node => isText$b(node) && node.data.length > 0;
|
8486 | const restoreEndPoint = (dom, suffix, bookmark) => {
|
8487 | const marker = dom.get(bookmark.id + '_' + suffix);
|
8488 | const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode;
|
8489 | const keep = bookmark.keep;
|
8490 | if (marker && markerParent) {
|
8491 | let container;
|
8492 | let offset;
|
8493 | if (suffix === 'start') {
|
8494 | if (!keep) {
|
8495 | container = markerParent;
|
8496 | offset = dom.nodeIndex(marker);
|
8497 | } else {
|
8498 | if (marker.hasChildNodes()) {
|
8499 | container = marker.firstChild;
|
8500 | offset = 1;
|
8501 | } else if (isValidTextNode(marker.nextSibling)) {
|
8502 | container = marker.nextSibling;
|
8503 | offset = 0;
|
8504 | } else if (isValidTextNode(marker.previousSibling)) {
|
8505 | container = marker.previousSibling;
|
8506 | offset = marker.previousSibling.data.length;
|
8507 | } else {
|
8508 | container = markerParent;
|
8509 | offset = dom.nodeIndex(marker) + 1;
|
8510 | }
|
8511 | }
|
8512 | } else {
|
8513 | if (!keep) {
|
8514 | container = markerParent;
|
8515 | offset = dom.nodeIndex(marker);
|
8516 | } else {
|
8517 | if (marker.hasChildNodes()) {
|
8518 | container = marker.firstChild;
|
8519 | offset = 1;
|
8520 | } else if (isValidTextNode(marker.previousSibling)) {
|
8521 | container = marker.previousSibling;
|
8522 | offset = marker.previousSibling.data.length;
|
8523 | } else {
|
8524 | container = markerParent;
|
8525 | offset = dom.nodeIndex(marker);
|
8526 | }
|
8527 | }
|
8528 | }
|
8529 | if (!keep) {
|
8530 | const prev = marker.previousSibling;
|
8531 | const next = marker.nextSibling;
|
8532 | Tools.each(Tools.grep(marker.childNodes), node => {
|
8533 | if (isText$b(node)) {
|
8534 | node.data = node.data.replace(/\uFEFF/g, '');
|
8535 | }
|
8536 | });
|
8537 | let otherMarker;
|
8538 | while (otherMarker = dom.get(bookmark.id + '_' + suffix)) {
|
8539 | dom.remove(otherMarker, true);
|
8540 | }
|
8541 | if (isText$b(next) && isText$b(prev) && !Env.browser.isOpera()) {
|
8542 | const idx = prev.data.length;
|
8543 | prev.appendData(next.data);
|
8544 | dom.remove(next);
|
8545 | container = prev;
|
8546 | offset = idx;
|
8547 | }
|
8548 | }
|
8549 | return Optional.some(CaretPosition(container, offset));
|
8550 | } else {
|
8551 | return Optional.none();
|
8552 | }
|
8553 | };
|
8554 | const resolvePaths = (dom, bookmark) => {
|
8555 | const range = dom.createRng();
|
8556 | if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) {
|
8557 | return Optional.some({
|
8558 | range,
|
8559 | forward: isForwardBookmark(bookmark)
|
8560 | });
|
8561 | } else {
|
8562 | return Optional.none();
|
8563 | }
|
8564 | };
|
8565 | const resolveId = (dom, bookmark) => {
|
8566 | const startPos = restoreEndPoint(dom, 'start', bookmark);
|
8567 | const endPos = restoreEndPoint(dom, 'end', bookmark);
|
8568 | return lift2(startPos, endPos.or(startPos), (spos, epos) => {
|
8569 | const range = dom.createRng();
|
8570 | range.setStart(addBogus(dom, spos.container()), spos.offset());
|
8571 | range.setEnd(addBogus(dom, epos.container()), epos.offset());
|
8572 | return {
|
8573 | range,
|
8574 | forward: isForwardBookmark(bookmark)
|
8575 | };
|
8576 | });
|
8577 | };
|
8578 | const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => {
|
8579 | const range = dom.createRng();
|
8580 | range.selectNode(elm);
|
8581 | return {
|
8582 | range,
|
8583 | forward: true
|
8584 | };
|
8585 | });
|
8586 | const resolve = (selection, bookmark) => {
|
8587 | const dom = selection.dom;
|
8588 | if (bookmark) {
|
8589 | if (isPathBookmark(bookmark)) {
|
8590 | return resolvePaths(dom, bookmark);
|
8591 | } else if (isStringPathBookmark(bookmark)) {
|
8592 | return resolveCaretPositionBookmark(dom, bookmark);
|
8593 | } else if (isIdBookmark(bookmark)) {
|
8594 | return resolveId(dom, bookmark);
|
8595 | } else if (isIndexBookmark(bookmark)) {
|
8596 | return resolveIndex(dom, bookmark);
|
8597 | } else if (isRangeBookmark(bookmark)) {
|
8598 | return Optional.some({
|
8599 | range: bookmark.rng,
|
8600 | forward: isForwardBookmark(bookmark)
|
8601 | });
|
8602 | }
|
8603 | }
|
8604 | return Optional.none();
|
8605 | };
|
8606 |
|
8607 | const getBookmark$1 = (selection, type, normalized) => {
|
8608 | return getBookmark$2(selection, type, normalized);
|
8609 | };
|
8610 | const moveToBookmark = (selection, bookmark) => {
|
8611 | resolve(selection, bookmark).each(({range, forward}) => {
|
8612 | selection.setRng(range, forward);
|
8613 | });
|
8614 | };
|
8615 | const isBookmarkNode$1 = node => {
|
8616 | return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
|
8617 | };
|
8618 |
|
8619 | const is = expected => actual => expected === actual;
|
8620 | const isNbsp = is(nbsp);
|
8621 | const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1;
|
8622 | const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$2(chr);
|
8623 |
|
8624 | const getRanges$1 = selection => {
|
8625 | const ranges = [];
|
8626 | if (selection) {
|
8627 | for (let i = 0; i < selection.rangeCount; i++) {
|
8628 | ranges.push(selection.getRangeAt(i));
|
8629 | }
|
8630 | }
|
8631 | return ranges;
|
8632 | };
|
8633 | const getSelectedNodes = ranges => {
|
8634 | return bind$3(ranges, range => {
|
8635 | const node = getSelectedNode(range);
|
8636 | return node ? [SugarElement.fromDom(node)] : [];
|
8637 | });
|
8638 | };
|
8639 | const hasMultipleRanges = selection => {
|
8640 | return getRanges$1(selection).length > 1;
|
8641 | };
|
8642 |
|
8643 | const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2);
|
8644 | const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
|
8645 | const getCellsFromElementOrRanges = (ranges, element) => {
|
8646 | const selectedCells = getCellsFromElement(element);
|
8647 | return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
|
8648 | };
|
8649 | const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
|
8650 | const getClosestTable = (cell, isRoot) => ancestor$3(cell, 'table', isRoot);
|
8651 |
|
8652 | const getStartNode = rng => {
|
8653 | const sc = rng.startContainer, so = rng.startOffset;
|
8654 | if (isText$b(sc)) {
|
8655 | return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
|
8656 | } else {
|
8657 | return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
|
8658 | }
|
8659 | };
|
8660 | const getEndNode = rng => {
|
8661 | const ec = rng.endContainer, eo = rng.endOffset;
|
8662 | if (isText$b(ec)) {
|
8663 | return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
|
8664 | } else {
|
8665 | return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
|
8666 | }
|
8667 | };
|
8668 | const getFirstChildren = node => {
|
8669 | return firstChild(node).fold(constant([node]), child => {
|
8670 | return [node].concat(getFirstChildren(child));
|
8671 | });
|
8672 | };
|
8673 | const getLastChildren = node => {
|
8674 | return lastChild(node).fold(constant([node]), child => {
|
8675 | if (name(child) === 'br') {
|
8676 | return prevSibling(child).map(sibling => {
|
8677 | return [node].concat(getLastChildren(sibling));
|
8678 | }).getOr([]);
|
8679 | } else {
|
8680 | return [node].concat(getLastChildren(child));
|
8681 | }
|
8682 | });
|
8683 | };
|
8684 | const hasAllContentsSelected = (elm, rng) => {
|
8685 | return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
|
8686 | const start = find$2(getFirstChildren(elm), curry(eq, startNode));
|
8687 | const end = find$2(getLastChildren(elm), curry(eq, endNode));
|
8688 | return start.isSome() && end.isSome();
|
8689 | }).getOr(false);
|
8690 | };
|
8691 | const moveEndPoint = (dom, rng, node, start) => {
|
8692 | const root = node;
|
8693 | const walker = new DomTreeWalker(node, root);
|
8694 | const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([
|
8695 | 'td',
|
8696 | 'th',
|
8697 | 'table'
|
8698 | ], name.toLowerCase()));
|
8699 | let currentNode = node;
|
8700 | do {
|
8701 | if (isText$b(currentNode) && Tools.trim(currentNode.data).length !== 0) {
|
8702 | if (start) {
|
8703 | rng.setStart(currentNode, 0);
|
8704 | } else {
|
8705 | rng.setEnd(currentNode, currentNode.data.length);
|
8706 | }
|
8707 | return;
|
8708 | }
|
8709 | if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) {
|
8710 | if (start) {
|
8711 | rng.setStartBefore(currentNode);
|
8712 | } else {
|
8713 | if (currentNode.nodeName === 'BR') {
|
8714 | rng.setEndBefore(currentNode);
|
8715 | } else {
|
8716 | rng.setEndAfter(currentNode);
|
8717 | }
|
8718 | }
|
8719 | return;
|
8720 | }
|
8721 | } while (currentNode = start ? walker.next() : walker.prev());
|
8722 | if (root.nodeName === 'BODY') {
|
8723 | if (start) {
|
8724 | rng.setStart(root, 0);
|
8725 | } else {
|
8726 | rng.setEnd(root, root.childNodes.length);
|
8727 | }
|
8728 | }
|
8729 | };
|
8730 | const hasAnyRanges = editor => {
|
8731 | const sel = editor.selection.getSel();
|
8732 | return isNonNullable(sel) && sel.rangeCount > 0;
|
8733 | };
|
8734 | const runOnRanges = (editor, executor) => {
|
8735 | const fakeSelectionNodes = getCellsFromEditor(editor);
|
8736 | if (fakeSelectionNodes.length > 0) {
|
8737 | each$e(fakeSelectionNodes, elem => {
|
8738 | const node = elem.dom;
|
8739 | const fakeNodeRng = editor.dom.createRng();
|
8740 | fakeNodeRng.setStartBefore(node);
|
8741 | fakeNodeRng.setEndAfter(node);
|
8742 | executor(fakeNodeRng, true);
|
8743 | });
|
8744 | } else {
|
8745 | executor(editor.selection.getRng(), false);
|
8746 | }
|
8747 | };
|
8748 | const preserve = (selection, fillBookmark, executor) => {
|
8749 | const bookmark = getPersistentBookmark(selection, fillBookmark);
|
8750 | executor(bookmark);
|
8751 | selection.moveToBookmark(bookmark);
|
8752 | };
|
8753 |
|
8754 | const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType);
|
8755 | const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
|
8756 | const isElementDirectlySelected = (dom, node) => {
|
8757 | if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) {
|
8758 | const selectedAttr = dom.getAttrib(node, 'data-mce-selected');
|
8759 | const value = parseInt(selectedAttr, 10);
|
8760 | return !isNaN(value) && value > 0;
|
8761 | } else {
|
8762 | return false;
|
8763 | }
|
8764 | };
|
8765 | const preserveSelection = (editor, action, shouldMoveStart) => {
|
8766 | const {selection, dom} = editor;
|
8767 | const selectedNodeBeforeAction = selection.getNode();
|
8768 | const isSelectedBeforeNodeNoneditable = isContentEditableFalse$b(selectedNodeBeforeAction);
|
8769 | preserve(selection, true, () => {
|
8770 | action();
|
8771 | });
|
8772 | const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$b(selectedNodeBeforeAction);
|
8773 | if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) {
|
8774 | editor.selection.select(selectedNodeBeforeAction);
|
8775 | } else if (shouldMoveStart(selection.getStart())) {
|
8776 | moveStartToNearestText(dom, selection);
|
8777 | }
|
8778 | };
|
8779 | const moveStartToNearestText = (dom, selection) => {
|
8780 | var _a, _b;
|
8781 | const rng = selection.getRng();
|
8782 | const {startContainer, startOffset} = rng;
|
8783 | const selectedNode = selection.getNode();
|
8784 | if (isElementDirectlySelected(dom, selectedNode)) {
|
8785 | return;
|
8786 | }
|
8787 | if (isElement$6(startContainer)) {
|
8788 | const nodes = startContainer.childNodes;
|
8789 | const root = dom.getRoot();
|
8790 | let walker;
|
8791 | if (startOffset < nodes.length) {
|
8792 | const startNode = nodes[startOffset];
|
8793 | walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root);
|
8794 | } else {
|
8795 | const startNode = nodes[nodes.length - 1];
|
8796 | walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root);
|
8797 | walker.next(true);
|
8798 | }
|
8799 | for (let node = walker.current(); node; node = walker.next()) {
|
8800 | if (dom.getContentEditable(node) === 'false') {
|
8801 | return;
|
8802 | } else if (isText$b(node) && !isWhiteSpaceNode$1(node)) {
|
8803 | rng.setStart(node, 0);
|
8804 | selection.setRng(rng);
|
8805 | return;
|
8806 | }
|
8807 | }
|
8808 | }
|
8809 | };
|
8810 | const getNonWhiteSpaceSibling = (node, next, inc) => {
|
8811 | if (node) {
|
8812 | const nextName = next ? 'nextSibling' : 'previousSibling';
|
8813 | for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
|
8814 | if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
|
8815 | return node;
|
8816 | }
|
8817 | }
|
8818 | }
|
8819 | return undefined;
|
8820 | };
|
8821 | const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node);
|
8822 | const isValid = (ed, parent, child) => {
|
8823 | return ed.schema.isValidChild(parent, child);
|
8824 | };
|
8825 | const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
|
8826 | if (isNonNullable(node) && isText$b(node)) {
|
8827 | const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data;
|
8828 | return isWhitespaceText(data);
|
8829 | } else {
|
8830 | return false;
|
8831 | }
|
8832 | };
|
8833 | const isEmptyTextNode$1 = node => {
|
8834 | return isNonNullable(node) && isText$b(node) && node.length === 0;
|
8835 | };
|
8836 | const isWrapNoneditableTarget = (editor, node) => {
|
8837 | const baseDataSelector = '[data-mce-cef-wrappable]';
|
8838 | const formatNoneditableSelector = getFormatNoneditableSelector(editor);
|
8839 | const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`;
|
8840 | return is$1(SugarElement.fromDom(node), selector);
|
8841 | };
|
8842 | const isWrappableNoneditable = (editor, node) => {
|
8843 | const dom = editor.dom;
|
8844 | return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0;
|
8845 | };
|
8846 | const replaceVars = (value, vars) => {
|
8847 | if (isFunction(value)) {
|
8848 | return value(vars);
|
8849 | } else if (isNonNullable(vars)) {
|
8850 | value = value.replace(/%(\w+)/g, (str, name) => {
|
8851 | return vars[name] || str;
|
8852 | });
|
8853 | }
|
8854 | return value;
|
8855 | };
|
8856 | const isEq$5 = (str1, str2) => {
|
8857 | str1 = str1 || '';
|
8858 | str2 = str2 || '';
|
8859 | str1 = '' + (str1.nodeName || str1);
|
8860 | str2 = '' + (str2.nodeName || str2);
|
8861 | return str1.toLowerCase() === str2.toLowerCase();
|
8862 | };
|
8863 | const normalizeStyleValue = (value, name) => {
|
8864 | if (isNullable(value)) {
|
8865 | return null;
|
8866 | } else {
|
8867 | let strValue = String(value);
|
8868 | if (name === 'color' || name === 'backgroundColor') {
|
8869 | strValue = rgbaToHexString(strValue);
|
8870 | }
|
8871 | if (name === 'fontWeight' && value === 700) {
|
8872 | strValue = 'bold';
|
8873 | }
|
8874 | if (name === 'fontFamily') {
|
8875 | strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
|
8876 | }
|
8877 | return strValue;
|
8878 | }
|
8879 | };
|
8880 | const getStyle = (dom, node, name) => {
|
8881 | const style = dom.getStyle(node, name);
|
8882 | return normalizeStyleValue(style, name);
|
8883 | };
|
8884 | const getTextDecoration = (dom, node) => {
|
8885 | let decoration;
|
8886 | dom.getParent(node, n => {
|
8887 | if (isElement$6(n)) {
|
8888 | decoration = dom.getStyle(n, 'text-decoration');
|
8889 | return !!decoration && decoration !== 'none';
|
8890 | } else {
|
8891 | return false;
|
8892 | }
|
8893 | });
|
8894 | return decoration;
|
8895 | };
|
8896 | const getParents$2 = (dom, node, selector) => {
|
8897 | return dom.getParents(node, selector, dom.getRoot());
|
8898 | };
|
8899 | const isFormatPredicate = (editor, formatName, predicate) => {
|
8900 | const formats = editor.formatter.get(formatName);
|
8901 | return isNonNullable(formats) && exists(formats, predicate);
|
8902 | };
|
8903 | const isVariableFormatName = (editor, formatName) => {
|
8904 | const hasVariableValues = format => {
|
8905 | const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%';
|
8906 | return exists([
|
8907 | 'styles',
|
8908 | 'attributes'
|
8909 | ], key => get$a(format, key).exists(field => {
|
8910 | const fieldValues = isArray$1(field) ? field : values(field);
|
8911 | return exists(fieldValues, isVariableValue);
|
8912 | }));
|
8913 | };
|
8914 | return isFormatPredicate(editor, formatName, hasVariableValues);
|
8915 | };
|
8916 | const areSimilarFormats = (editor, formatName, otherFormatName) => {
|
8917 | const validKeys = [
|
8918 | 'inline',
|
8919 | 'block',
|
8920 | 'selector',
|
8921 | 'attributes',
|
8922 | 'styles',
|
8923 | 'classes'
|
8924 | ];
|
8925 | const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key));
|
8926 | return isFormatPredicate(editor, formatName, fmt1 => {
|
8927 | const filteredFmt1 = filterObj(fmt1);
|
8928 | return isFormatPredicate(editor, otherFormatName, fmt2 => {
|
8929 | const filteredFmt2 = filterObj(fmt2);
|
8930 | return equal$1(filteredFmt1, filteredFmt2);
|
8931 | });
|
8932 | });
|
8933 | };
|
8934 | const isBlockFormat = format => hasNonNullableKey(format, 'block');
|
8935 | const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true;
|
8936 | const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true;
|
8937 | const isSelectorFormat = format => hasNonNullableKey(format, 'selector');
|
8938 | const isInlineFormat = format => hasNonNullableKey(format, 'inline');
|
8939 | const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true);
|
8940 | const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
|
8941 | const getEmptyCaretContainers = node => {
|
8942 | const nodes = [];
|
8943 | let tempNode = node;
|
8944 | while (tempNode) {
|
8945 | if (isText$b(tempNode) && tempNode.data !== ZWSP$1 || tempNode.childNodes.length > 1) {
|
8946 | return [];
|
8947 | }
|
8948 | if (isElement$6(tempNode)) {
|
8949 | nodes.push(tempNode);
|
8950 | }
|
8951 | tempNode = tempNode.firstChild;
|
8952 | }
|
8953 | return nodes;
|
8954 | };
|
8955 | const isCaretContainerEmpty = node => {
|
8956 | return getEmptyCaretContainers(node).length > 0;
|
8957 | };
|
8958 | const isEmptyCaretFormatElement = element => {
|
8959 | return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
|
8960 | };
|
8961 |
|
8962 | const isBookmarkNode = isBookmarkNode$1;
|
8963 | const getParents$1 = getParents$2;
|
8964 | const isWhiteSpaceNode = isWhiteSpaceNode$1;
|
8965 | const isTextBlock = isTextBlock$1;
|
8966 | const isBogusBr = node => {
|
8967 | return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling;
|
8968 | };
|
8969 | const findParentContentEditable = (dom, node) => {
|
8970 | let parent = node;
|
8971 | while (parent) {
|
8972 | if (isElement$6(parent) && dom.getContentEditable(parent)) {
|
8973 | return dom.getContentEditable(parent) === 'false' ? parent : node;
|
8974 | }
|
8975 | parent = parent.parentNode;
|
8976 | }
|
8977 | return node;
|
8978 | };
|
8979 | const walkText = (start, node, offset, predicate) => {
|
8980 | const str = node.data;
|
8981 | if (start) {
|
8982 | for (let i = offset; i > 0; i--) {
|
8983 | if (predicate(str.charAt(i - 1))) {
|
8984 | return i;
|
8985 | }
|
8986 | }
|
8987 | } else {
|
8988 | for (let i = offset; i < str.length; i++) {
|
8989 | if (predicate(str.charAt(i))) {
|
8990 | return i;
|
8991 | }
|
8992 | }
|
8993 | }
|
8994 | return -1;
|
8995 | };
|
8996 | const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c));
|
8997 | const findContent = (start, node, offset) => walkText(start, node, offset, isContent);
|
8998 | const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => {
|
8999 | let lastTextNode;
|
9000 | const rootNode = dom.getParent(container, dom.isBlock) || body;
|
9001 | const walk = (container, offset, pred) => {
|
9002 | const textSeeker = TextSeeker(dom);
|
9003 | const walker = start ? textSeeker.backwards : textSeeker.forwards;
|
9004 | return Optional.from(walker(container, offset, (text, textOffset) => {
|
9005 | if (isBookmarkNode(text.parentNode)) {
|
9006 | return -1;
|
9007 | } else {
|
9008 | lastTextNode = text;
|
9009 | return pred(start, text, textOffset);
|
9010 | }
|
9011 | }, rootNode));
|
9012 | };
|
9013 | const spaceResult = walk(container, offset, findSpace);
|
9014 | return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
|
9015 | container: lastTextNode,
|
9016 | offset: start ? 0 : lastTextNode.length
|
9017 | }) : Optional.none());
|
9018 | };
|
9019 | const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => {
|
9020 | const sibling = container[siblingName];
|
9021 | if (isText$b(container) && isEmpty$3(container.data) && sibling) {
|
9022 | container = sibling;
|
9023 | }
|
9024 | const parents = getParents$1(dom, container);
|
9025 | for (let i = 0; i < parents.length; i++) {
|
9026 | for (let y = 0; y < formatList.length; y++) {
|
9027 | const curFormat = formatList[y];
|
9028 | if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
|
9029 | continue;
|
9030 | }
|
9031 | if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) {
|
9032 | return parents[i];
|
9033 | }
|
9034 | }
|
9035 | }
|
9036 | return container;
|
9037 | };
|
9038 | const findBlockEndPoint = (dom, formatList, container, siblingName) => {
|
9039 | var _a;
|
9040 | let node = container;
|
9041 | const root = dom.getRoot();
|
9042 | const format = formatList[0];
|
9043 | if (isBlockFormat(format)) {
|
9044 | node = format.wrapper ? null : dom.getParent(container, format.block, root);
|
9045 | }
|
9046 | if (!node) {
|
9047 | const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH,SUMMARY')) !== null && _a !== void 0 ? _a : root;
|
9048 | node = dom.getParent(isText$b(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot);
|
9049 | }
|
9050 | if (node && isBlockFormat(format) && format.wrapper) {
|
9051 | node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node;
|
9052 | }
|
9053 | if (!node) {
|
9054 | node = container;
|
9055 | while (node && node[siblingName] && !dom.isBlock(node[siblingName])) {
|
9056 | node = node[siblingName];
|
9057 | if (isEq$5(node, 'br')) {
|
9058 | break;
|
9059 | }
|
9060 | }
|
9061 | }
|
9062 | return node || container;
|
9063 | };
|
9064 | const isAtBlockBoundary$1 = (dom, root, container, siblingName) => {
|
9065 | const parent = container.parentNode;
|
9066 | if (isNonNullable(container[siblingName])) {
|
9067 | return false;
|
9068 | } else if (parent === root || isNullable(parent) || dom.isBlock(parent)) {
|
9069 | return true;
|
9070 | } else {
|
9071 | return isAtBlockBoundary$1(dom, root, parent, siblingName);
|
9072 | }
|
9073 | };
|
9074 | const findParentContainer = (dom, formatList, container, offset, start) => {
|
9075 | let parent = container;
|
9076 | const siblingName = start ? 'previousSibling' : 'nextSibling';
|
9077 | const root = dom.getRoot();
|
9078 | if (isText$b(container) && !isWhiteSpaceNode(container)) {
|
9079 | if (start ? offset > 0 : offset < container.data.length) {
|
9080 | return container;
|
9081 | }
|
9082 | }
|
9083 | while (parent) {
|
9084 | if (!formatList[0].block_expand && dom.isBlock(parent)) {
|
9085 | return parent;
|
9086 | }
|
9087 | for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
|
9088 | const allowSpaces = isText$b(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName);
|
9089 | if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) {
|
9090 | return parent;
|
9091 | }
|
9092 | }
|
9093 | if (parent === root || parent.parentNode === root) {
|
9094 | container = parent;
|
9095 | break;
|
9096 | }
|
9097 | parent = parent.parentNode;
|
9098 | }
|
9099 | return container;
|
9100 | };
|
9101 | const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
|
9102 | const expandRng = (dom, rng, formatList, includeTrailingSpace = false) => {
|
9103 | let {startContainer, startOffset, endContainer, endOffset} = rng;
|
9104 | const format = formatList[0];
|
9105 | if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
|
9106 | startContainer = getNode$1(startContainer, startOffset);
|
9107 | if (isText$b(startContainer)) {
|
9108 | startOffset = 0;
|
9109 | }
|
9110 | }
|
9111 | if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
|
9112 | endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
|
9113 | if (isText$b(endContainer)) {
|
9114 | endOffset = endContainer.data.length;
|
9115 | }
|
9116 | }
|
9117 | startContainer = findParentContentEditable(dom, startContainer);
|
9118 | endContainer = findParentContentEditable(dom, endContainer);
|
9119 | if (isSelfOrParentBookmark(startContainer)) {
|
9120 | startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
|
9121 | if (rng.collapsed) {
|
9122 | startContainer = startContainer.previousSibling || startContainer;
|
9123 | } else {
|
9124 | startContainer = startContainer.nextSibling || startContainer;
|
9125 | }
|
9126 | if (isText$b(startContainer)) {
|
9127 | startOffset = rng.collapsed ? startContainer.length : 0;
|
9128 | }
|
9129 | }
|
9130 | if (isSelfOrParentBookmark(endContainer)) {
|
9131 | endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
|
9132 | if (rng.collapsed) {
|
9133 | endContainer = endContainer.nextSibling || endContainer;
|
9134 | } else {
|
9135 | endContainer = endContainer.previousSibling || endContainer;
|
9136 | }
|
9137 | if (isText$b(endContainer)) {
|
9138 | endOffset = rng.collapsed ? 0 : endContainer.length;
|
9139 | }
|
9140 | }
|
9141 | if (rng.collapsed) {
|
9142 | const startPoint = findWordEndPoint(dom, dom.getRoot(), startContainer, startOffset, true, includeTrailingSpace);
|
9143 | startPoint.each(({container, offset}) => {
|
9144 | startContainer = container;
|
9145 | startOffset = offset;
|
9146 | });
|
9147 | const endPoint = findWordEndPoint(dom, dom.getRoot(), endContainer, endOffset, false, includeTrailingSpace);
|
9148 | endPoint.each(({container, offset}) => {
|
9149 | endContainer = container;
|
9150 | endOffset = offset;
|
9151 | });
|
9152 | }
|
9153 | if (isInlineFormat(format) || format.block_expand) {
|
9154 | if (!isInlineFormat(format) || (!isText$b(startContainer) || startOffset === 0)) {
|
9155 | startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
|
9156 | }
|
9157 | if (!isInlineFormat(format) || (!isText$b(endContainer) || endOffset === endContainer.data.length)) {
|
9158 | endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
|
9159 | }
|
9160 | }
|
9161 | if (shouldExpandToSelector(format)) {
|
9162 | startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling');
|
9163 | endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling');
|
9164 | }
|
9165 | if (isBlockFormat(format) || isSelectorFormat(format)) {
|
9166 | startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling');
|
9167 | endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling');
|
9168 | if (isBlockFormat(format)) {
|
9169 | if (!dom.isBlock(startContainer)) {
|
9170 | startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
|
9171 | if (isText$b(startContainer)) {
|
9172 | startOffset = 0;
|
9173 | }
|
9174 | }
|
9175 | if (!dom.isBlock(endContainer)) {
|
9176 | endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
|
9177 | if (isText$b(endContainer)) {
|
9178 | endOffset = endContainer.data.length;
|
9179 | }
|
9180 | }
|
9181 | }
|
9182 | }
|
9183 | if (isElement$6(startContainer) && startContainer.parentNode) {
|
9184 | startOffset = dom.nodeIndex(startContainer);
|
9185 | startContainer = startContainer.parentNode;
|
9186 | }
|
9187 | if (isElement$6(endContainer) && endContainer.parentNode) {
|
9188 | endOffset = dom.nodeIndex(endContainer) + 1;
|
9189 | endContainer = endContainer.parentNode;
|
9190 | }
|
9191 | return {
|
9192 | startContainer,
|
9193 | startOffset,
|
9194 | endContainer,
|
9195 | endOffset
|
9196 | };
|
9197 | };
|
9198 |
|
9199 | const walk$3 = (dom, rng, callback) => {
|
9200 | var _a;
|
9201 | const startOffset = rng.startOffset;
|
9202 | const startContainer = getNode$1(rng.startContainer, startOffset);
|
9203 | const endOffset = rng.endOffset;
|
9204 | const endContainer = getNode$1(rng.endContainer, endOffset - 1);
|
9205 | const exclude = nodes => {
|
9206 | const firstNode = nodes[0];
|
9207 | if (isText$b(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
|
9208 | nodes.splice(0, 1);
|
9209 | }
|
9210 | const lastNode = nodes[nodes.length - 1];
|
9211 | if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$b(lastNode)) {
|
9212 | nodes.splice(nodes.length - 1, 1);
|
9213 | }
|
9214 | return nodes;
|
9215 | };
|
9216 | const collectSiblings = (node, name, endNode) => {
|
9217 | const siblings = [];
|
9218 | for (; node && node !== endNode; node = node[name]) {
|
9219 | siblings.push(node);
|
9220 | }
|
9221 | return siblings;
|
9222 | };
|
9223 | const findEndPoint = (node, root) => dom.getParent(node, node => node.parentNode === root, root);
|
9224 | const walkBoundary = (startNode, endNode, next) => {
|
9225 | const siblingName = next ? 'nextSibling' : 'previousSibling';
|
9226 | for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
|
9227 | parent = node.parentNode;
|
9228 | const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
|
9229 | if (siblings.length) {
|
9230 | if (!next) {
|
9231 | siblings.reverse();
|
9232 | }
|
9233 | callback(exclude(siblings));
|
9234 | }
|
9235 | }
|
9236 | };
|
9237 | if (startContainer === endContainer) {
|
9238 | return callback(exclude([startContainer]));
|
9239 | }
|
9240 | const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot();
|
9241 | if (dom.isChildOf(startContainer, endContainer)) {
|
9242 | return walkBoundary(startContainer, ancestor, true);
|
9243 | }
|
9244 | if (dom.isChildOf(endContainer, startContainer)) {
|
9245 | return walkBoundary(endContainer, ancestor);
|
9246 | }
|
9247 | const startPoint = findEndPoint(startContainer, ancestor) || startContainer;
|
9248 | const endPoint = findEndPoint(endContainer, ancestor) || endContainer;
|
9249 | walkBoundary(startContainer, startPoint, true);
|
9250 | const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
|
9251 | if (siblings.length) {
|
9252 | callback(exclude(siblings));
|
9253 | }
|
9254 | walkBoundary(endContainer, endPoint);
|
9255 | };
|
9256 |
|
9257 | const validBlocks = [
|
9258 | 'pre[class*=language-][contenteditable="false"]',
|
9259 | 'figure.image',
|
9260 | 'div[data-ephox-embed-iri]',
|
9261 | 'div.tiny-pageembed',
|
9262 | 'div.mce-toc',
|
9263 | 'div[data-mce-toc]'
|
9264 | ];
|
9265 | const isZeroWidth = elem => isText$c(elem) && get$3(elem) === ZWSP$1;
|
9266 | const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => {
|
9267 | if (nodeName === 'br' || isZeroWidth(elem)) {
|
9268 | return 'valid';
|
9269 | } else if (isAnnotation(elem)) {
|
9270 | return 'existing';
|
9271 | } else if (isCaretNode(elem.dom)) {
|
9272 | return 'caret';
|
9273 | } else if (exists(validBlocks, selector => is$1(elem, selector))) {
|
9274 | return 'valid-block';
|
9275 | } else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) {
|
9276 | return 'invalid-child';
|
9277 | } else {
|
9278 | return 'valid';
|
9279 | }
|
9280 | });
|
9281 |
|
9282 | const applyWordGrab = (editor, rng) => {
|
9283 | const r = expandRng(editor.dom, rng, [{ inline: 'span' }]);
|
9284 | rng.setStart(r.startContainer, r.startOffset);
|
9285 | rng.setEnd(r.endContainer, r.endOffset);
|
9286 | editor.selection.setRng(rng);
|
9287 | };
|
9288 | const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => {
|
9289 | const {uid = masterUId, ...otherData} = data;
|
9290 | add$2(elem, annotation());
|
9291 | set$3(elem, `${ dataAnnotationId() }`, uid);
|
9292 | set$3(elem, `${ dataAnnotation() }`, annotationName);
|
9293 | const {attributes = {}, classes = []} = decorate(uid, otherData);
|
9294 | setAll$1(elem, attributes);
|
9295 | add(elem, classes);
|
9296 | if (directAnnotation) {
|
9297 | if (classes.length > 0) {
|
9298 | set$3(elem, `${ dataAnnotationClasses() }`, classes.join(','));
|
9299 | }
|
9300 | const attributeNames = keys(attributes);
|
9301 | if (attributeNames.length > 0) {
|
9302 | set$3(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(','));
|
9303 | }
|
9304 | }
|
9305 | };
|
9306 | const removeDirectAnnotation = elem => {
|
9307 | remove$6(elem, annotation());
|
9308 | remove$9(elem, `${ dataAnnotationId() }`);
|
9309 | remove$9(elem, `${ dataAnnotation() }`);
|
9310 | remove$9(elem, `${ dataAnnotationActive() }`);
|
9311 | const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]);
|
9312 | const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]);
|
9313 | each$e(customAttrNames, name => remove$9(elem, name));
|
9314 | remove$3(elem, customClasses);
|
9315 | remove$9(elem, `${ dataAnnotationClasses() }`);
|
9316 | remove$9(elem, `${ dataAnnotationAttributes() }`);
|
9317 | };
|
9318 | const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => {
|
9319 | const master = SugarElement.fromTag('span', eDoc);
|
9320 | applyAnnotation(master, uid, data, annotationName, decorate, false);
|
9321 | return master;
|
9322 | };
|
9323 | const annotate = (editor, rng, uid, annotationName, decorate, data) => {
|
9324 | const newWrappers = [];
|
9325 | const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate);
|
9326 | const wrapper = value$2();
|
9327 | const finishWrapper = () => {
|
9328 | wrapper.clear();
|
9329 | };
|
9330 | const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
|
9331 | const nu = shallow$1(master);
|
9332 | newWrappers.push(nu);
|
9333 | wrapper.set(nu);
|
9334 | return nu;
|
9335 | });
|
9336 | const processElements = elems => {
|
9337 | each$e(elems, processElement);
|
9338 | };
|
9339 | const processElement = elem => {
|
9340 | const ctx = context(editor, elem, 'span', name(elem));
|
9341 | switch (ctx) {
|
9342 | case 'invalid-child': {
|
9343 | finishWrapper();
|
9344 | const children = children$1(elem);
|
9345 | processElements(children);
|
9346 | finishWrapper();
|
9347 | break;
|
9348 | }
|
9349 | case 'valid-block': {
|
9350 | finishWrapper();
|
9351 | applyAnnotation(elem, uid, data, annotationName, decorate, true);
|
9352 | break;
|
9353 | }
|
9354 | case 'valid': {
|
9355 | const w = getOrOpenWrapper();
|
9356 | wrap$2(elem, w);
|
9357 | break;
|
9358 | }
|
9359 | }
|
9360 | };
|
9361 | const processNodes = nodes => {
|
9362 | const elems = map$3(nodes, SugarElement.fromDom);
|
9363 | processElements(elems);
|
9364 | };
|
9365 | walk$3(editor.dom, rng, nodes => {
|
9366 | finishWrapper();
|
9367 | processNodes(nodes);
|
9368 | });
|
9369 | return newWrappers;
|
9370 | };
|
9371 | const annotateWithBookmark = (editor, name, settings, data) => {
|
9372 | editor.undoManager.transact(() => {
|
9373 | const selection = editor.selection;
|
9374 | const initialRng = selection.getRng();
|
9375 | const hasFakeSelection = getCellsFromEditor(editor).length > 0;
|
9376 | const masterUid = generate$1('mce-annotation');
|
9377 | if (initialRng.collapsed && !hasFakeSelection) {
|
9378 | applyWordGrab(editor, initialRng);
|
9379 | }
|
9380 | if (selection.getRng().collapsed && !hasFakeSelection) {
|
9381 | const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate);
|
9382 | set$1(wrapper, nbsp);
|
9383 | selection.getRng().insertNode(wrapper.dom);
|
9384 | selection.select(wrapper.dom);
|
9385 | } else {
|
9386 | preserve(selection, false, () => {
|
9387 | runOnRanges(editor, selectionRng => {
|
9388 | annotate(editor, selectionRng, masterUid, name, settings.decorate, data);
|
9389 | });
|
9390 | });
|
9391 | }
|
9392 | });
|
9393 | };
|
9394 |
|
9395 | const Annotator = editor => {
|
9396 | const registry = create$b();
|
9397 | setup$x(editor, registry);
|
9398 | const changes = setup$y(editor, registry);
|
9399 | const isSpan = isTag('span');
|
9400 | const removeAnnotations = elements => {
|
9401 | each$e(elements, element => {
|
9402 | if (isSpan(element)) {
|
9403 | unwrap(element);
|
9404 | } else {
|
9405 | removeDirectAnnotation(element);
|
9406 | }
|
9407 | });
|
9408 | };
|
9409 | return {
|
9410 | register: (name, settings) => {
|
9411 | registry.register(name, settings);
|
9412 | },
|
9413 | annotate: (name, data) => {
|
9414 | registry.lookup(name).each(settings => {
|
9415 | annotateWithBookmark(editor, name, settings, data);
|
9416 | });
|
9417 | },
|
9418 | annotationChanged: (name, callback) => {
|
9419 | changes.addListener(name, callback);
|
9420 | },
|
9421 | remove: name => {
|
9422 | identify(editor, Optional.some(name)).each(({elements}) => {
|
9423 | const bookmark = editor.selection.getBookmark();
|
9424 | removeAnnotations(elements);
|
9425 | editor.selection.moveToBookmark(bookmark);
|
9426 | });
|
9427 | },
|
9428 | removeAll: name => {
|
9429 | const bookmark = editor.selection.getBookmark();
|
9430 | each$d(findAll(editor, name), (elements, _) => {
|
9431 | removeAnnotations(elements);
|
9432 | });
|
9433 | editor.selection.moveToBookmark(bookmark);
|
9434 | },
|
9435 | getAll: name => {
|
9436 | const directory = findAll(editor, name);
|
9437 | return map$2(directory, elems => map$3(elems, elem => elem.dom));
|
9438 | }
|
9439 | };
|
9440 | };
|
9441 |
|
9442 | const BookmarkManager = selection => {
|
9443 | return {
|
9444 | getBookmark: curry(getBookmark$1, selection),
|
9445 | moveToBookmark: curry(moveToBookmark, selection)
|
9446 | };
|
9447 | };
|
9448 | BookmarkManager.isBookmarkNode = isBookmarkNode$1;
|
9449 |
|
9450 | const isXYWithinRange = (clientX, clientY, range) => {
|
9451 | if (range.collapsed) {
|
9452 | return false;
|
9453 | } else {
|
9454 | return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY));
|
9455 | }
|
9456 | };
|
9457 |
|
9458 | const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args);
|
9459 | const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args);
|
9460 | const fireRemove = editor => {
|
9461 | editor.dispatch('remove');
|
9462 | };
|
9463 | const fireDetach = editor => {
|
9464 | editor.dispatch('detach');
|
9465 | };
|
9466 | const fireSwitchMode = (editor, mode) => {
|
9467 | editor.dispatch('SwitchMode', { mode });
|
9468 | };
|
9469 | const fireObjectResizeStart = (editor, target, width, height, origin) => {
|
9470 | editor.dispatch('ObjectResizeStart', {
|
9471 | target,
|
9472 | width,
|
9473 | height,
|
9474 | origin
|
9475 | });
|
9476 | };
|
9477 | const fireObjectResized = (editor, target, width, height, origin) => {
|
9478 | editor.dispatch('ObjectResized', {
|
9479 | target,
|
9480 | width,
|
9481 | height,
|
9482 | origin
|
9483 | });
|
9484 | };
|
9485 | const firePreInit = editor => {
|
9486 | editor.dispatch('PreInit');
|
9487 | };
|
9488 | const firePostRender = editor => {
|
9489 | editor.dispatch('PostRender');
|
9490 | };
|
9491 | const fireInit = editor => {
|
9492 | editor.dispatch('Init');
|
9493 | };
|
9494 | const firePlaceholderToggle = (editor, state) => {
|
9495 | editor.dispatch('PlaceholderToggle', { state });
|
9496 | };
|
9497 | const fireError = (editor, errorType, error) => {
|
9498 | editor.dispatch(errorType, error);
|
9499 | };
|
9500 | const fireFormatApply = (editor, format, node, vars) => {
|
9501 | editor.dispatch('FormatApply', {
|
9502 | format,
|
9503 | node,
|
9504 | vars
|
9505 | });
|
9506 | };
|
9507 | const fireFormatRemove = (editor, format, node, vars) => {
|
9508 | editor.dispatch('FormatRemove', {
|
9509 | format,
|
9510 | node,
|
9511 | vars
|
9512 | });
|
9513 | };
|
9514 | const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args);
|
9515 | const fireSetContent = (editor, args) => editor.dispatch('SetContent', args);
|
9516 | const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args);
|
9517 | const fireGetContent = (editor, args) => editor.dispatch('GetContent', args);
|
9518 | const fireAutocompleterStart = (editor, args) => {
|
9519 | editor.dispatch('AutocompleterStart', args);
|
9520 | };
|
9521 | const fireAutocompleterUpdate = (editor, args) => {
|
9522 | editor.dispatch('AutocompleterUpdate', args);
|
9523 | };
|
9524 | const fireAutocompleterUpdateActiveRange = (editor, args) => {
|
9525 | editor.dispatch('AutocompleterUpdateActiveRange', args);
|
9526 | };
|
9527 | const fireAutocompleterEnd = editor => {
|
9528 | editor.dispatch('AutocompleterEnd');
|
9529 | };
|
9530 | const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', {
|
9531 | content: html,
|
9532 | internal
|
9533 | });
|
9534 | const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', {
|
9535 | node,
|
9536 | internal
|
9537 | });
|
9538 | const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state });
|
9539 | const fireEditableRootStateChange = (editor, state) => editor.dispatch('EditableRootStateChange', { state });
|
9540 |
|
9541 | const VK = {
|
9542 | BACKSPACE: 8,
|
9543 | DELETE: 46,
|
9544 | DOWN: 40,
|
9545 | ENTER: 13,
|
9546 | ESC: 27,
|
9547 | LEFT: 37,
|
9548 | RIGHT: 39,
|
9549 | SPACEBAR: 32,
|
9550 | TAB: 9,
|
9551 | UP: 38,
|
9552 | PAGE_UP: 33,
|
9553 | PAGE_DOWN: 34,
|
9554 | END: 35,
|
9555 | HOME: 36,
|
9556 | modifierPressed: e => {
|
9557 | return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
|
9558 | },
|
9559 | metaKeyPressed: e => {
|
9560 | return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
|
9561 | }
|
9562 | };
|
9563 |
|
9564 | const elementSelectionAttr = 'data-mce-selected';
|
9565 | const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object,details';
|
9566 | const abs = Math.abs;
|
9567 | const round$1 = Math.round;
|
9568 | const resizeHandles = {
|
9569 | nw: [
|
9570 | 0,
|
9571 | 0,
|
9572 | -1,
|
9573 | -1
|
9574 | ],
|
9575 | ne: [
|
9576 | 1,
|
9577 | 0,
|
9578 | 1,
|
9579 | -1
|
9580 | ],
|
9581 | se: [
|
9582 | 1,
|
9583 | 1,
|
9584 | 1,
|
9585 | 1
|
9586 | ],
|
9587 | sw: [
|
9588 | 0,
|
9589 | 1,
|
9590 | -1,
|
9591 | 1
|
9592 | ]
|
9593 | };
|
9594 | const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0;
|
9595 | const ControlSelection = (selection, editor) => {
|
9596 | const dom = editor.dom;
|
9597 | const editableDoc = editor.getDoc();
|
9598 | const rootDocument = document;
|
9599 | const rootElement = editor.getBody();
|
9600 | let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
|
9601 | let startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
|
9602 | let width;
|
9603 | let height;
|
9604 | let startScrollWidth;
|
9605 | let startScrollHeight;
|
9606 | const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image'));
|
9607 | const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object');
|
9608 | const isEventOnImageOutsideRange = (evt, range) => {
|
9609 | if (isTouchEvent(evt)) {
|
9610 | const touch = evt.touches[0];
|
9611 | return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range);
|
9612 | } else {
|
9613 | return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range);
|
9614 | }
|
9615 | };
|
9616 | const contextMenuSelectImage = evt => {
|
9617 | const target = evt.target;
|
9618 | if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
|
9619 | editor.selection.select(target);
|
9620 | }
|
9621 | };
|
9622 | const getResizeTargets = elm => {
|
9623 | if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
|
9624 | return [
|
9625 | elm,
|
9626 | elm.firstElementChild
|
9627 | ];
|
9628 | } else if (dom.is(elm, 'figure.image')) {
|
9629 | return [elm.querySelector('img')];
|
9630 | } else {
|
9631 | return [elm];
|
9632 | }
|
9633 | };
|
9634 | const isResizable = elm => {
|
9635 | const selector = getObjectResizing(editor);
|
9636 | if (!selector) {
|
9637 | return false;
|
9638 | }
|
9639 | if (elm.getAttribute('data-mce-resize') === 'false') {
|
9640 | return false;
|
9641 | }
|
9642 | if (elm === editor.getBody()) {
|
9643 | return false;
|
9644 | }
|
9645 | if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
|
9646 | return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
|
9647 | } else {
|
9648 | return is$1(SugarElement.fromDom(elm), selector);
|
9649 | }
|
9650 | };
|
9651 | const createGhostElement = (dom, elm) => {
|
9652 | if (isMedia(elm)) {
|
9653 | return dom.create('img', { src: Env.transparentSrc });
|
9654 | } else if (isTable$2(elm)) {
|
9655 | const isNorth = startsWith(selectedHandle.name, 'n');
|
9656 | const rowSelect = isNorth ? head : last$2;
|
9657 | const tableElm = elm.cloneNode(true);
|
9658 | rowSelect(dom.select('tr', tableElm)).each(tr => {
|
9659 | const cells = dom.select('td,th', tr);
|
9660 | dom.setStyle(tr, 'height', null);
|
9661 | each$e(cells, cell => dom.setStyle(cell, 'height', null));
|
9662 | });
|
9663 | return tableElm;
|
9664 | } else {
|
9665 | return elm.cloneNode(true);
|
9666 | }
|
9667 | };
|
9668 | const setSizeProp = (element, name, value) => {
|
9669 | if (isNonNullable(value)) {
|
9670 | const targets = getResizeTargets(element);
|
9671 | each$e(targets, target => {
|
9672 | if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
|
9673 | dom.setStyle(target, name, value);
|
9674 | } else {
|
9675 | dom.setAttrib(target, name, '' + value);
|
9676 | }
|
9677 | });
|
9678 | }
|
9679 | };
|
9680 | const setGhostElmSize = (ghostElm, width, height) => {
|
9681 | setSizeProp(ghostElm, 'width', width);
|
9682 | setSizeProp(ghostElm, 'height', height);
|
9683 | };
|
9684 | const resizeGhostElement = e => {
|
9685 | let deltaX, deltaY, proportional;
|
9686 | let resizeHelperX, resizeHelperY;
|
9687 | deltaX = e.screenX - startX;
|
9688 | deltaY = e.screenY - startY;
|
9689 | width = deltaX * selectedHandle[2] + startW;
|
9690 | height = deltaY * selectedHandle[3] + startH;
|
9691 | width = width < 5 ? 5 : width;
|
9692 | height = height < 5 ? 5 : height;
|
9693 | if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) {
|
9694 | proportional = !VK.modifierPressed(e);
|
9695 | } else {
|
9696 | proportional = VK.modifierPressed(e);
|
9697 | }
|
9698 | if (proportional) {
|
9699 | if (abs(deltaX) > abs(deltaY)) {
|
9700 | height = round$1(width * ratio);
|
9701 | width = round$1(height / ratio);
|
9702 | } else {
|
9703 | width = round$1(height / ratio);
|
9704 | height = round$1(width * ratio);
|
9705 | }
|
9706 | }
|
9707 | setGhostElmSize(selectedElmGhost, width, height);
|
9708 | resizeHelperX = selectedHandle.startPos.x + deltaX;
|
9709 | resizeHelperY = selectedHandle.startPos.y + deltaY;
|
9710 | resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
|
9711 | resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
|
9712 | dom.setStyles(resizeHelper, {
|
9713 | left: resizeHelperX,
|
9714 | top: resizeHelperY,
|
9715 | display: 'block'
|
9716 | });
|
9717 | resizeHelper.innerHTML = width + ' × ' + height;
|
9718 | if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
|
9719 | dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
|
9720 | }
|
9721 | if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
|
9722 | dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
|
9723 | }
|
9724 | deltaX = rootElement.scrollWidth - startScrollWidth;
|
9725 | deltaY = rootElement.scrollHeight - startScrollHeight;
|
9726 | if (deltaX + deltaY !== 0) {
|
9727 | dom.setStyles(resizeHelper, {
|
9728 | left: resizeHelperX - deltaX,
|
9729 | top: resizeHelperY - deltaY
|
9730 | });
|
9731 | }
|
9732 | if (!resizeStarted) {
|
9733 | fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name);
|
9734 | resizeStarted = true;
|
9735 | }
|
9736 | };
|
9737 | const endGhostResize = () => {
|
9738 | const wasResizeStarted = resizeStarted;
|
9739 | resizeStarted = false;
|
9740 | if (wasResizeStarted) {
|
9741 | setSizeProp(selectedElm, 'width', width);
|
9742 | setSizeProp(selectedElm, 'height', height);
|
9743 | }
|
9744 | dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
|
9745 | dom.unbind(editableDoc, 'mouseup', endGhostResize);
|
9746 | if (rootDocument !== editableDoc) {
|
9747 | dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
|
9748 | dom.unbind(rootDocument, 'mouseup', endGhostResize);
|
9749 | }
|
9750 | dom.remove(selectedElmGhost);
|
9751 | dom.remove(resizeHelper);
|
9752 | dom.remove(resizeBackdrop);
|
9753 | showResizeRect(selectedElm);
|
9754 | if (wasResizeStarted) {
|
9755 | fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name);
|
9756 | dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
|
9757 | }
|
9758 | editor.nodeChanged();
|
9759 | };
|
9760 | const showResizeRect = targetElm => {
|
9761 | unbindResizeHandleEvents();
|
9762 | const position = dom.getPos(targetElm, rootElement);
|
9763 | const selectedElmX = position.x;
|
9764 | const selectedElmY = position.y;
|
9765 | const rect = targetElm.getBoundingClientRect();
|
9766 | const targetWidth = rect.width || rect.right - rect.left;
|
9767 | const targetHeight = rect.height || rect.bottom - rect.top;
|
9768 | if (selectedElm !== targetElm) {
|
9769 | hideResizeRect();
|
9770 | selectedElm = targetElm;
|
9771 | width = height = 0;
|
9772 | }
|
9773 | const e = editor.dispatch('ObjectSelected', { target: targetElm });
|
9774 | if (isResizable(targetElm) && !e.isDefaultPrevented()) {
|
9775 | each$d(resizeHandles, (handle, name) => {
|
9776 | const startDrag = e => {
|
9777 | const target = getResizeTargets(selectedElm)[0];
|
9778 | startX = e.screenX;
|
9779 | startY = e.screenY;
|
9780 | startW = target.clientWidth;
|
9781 | startH = target.clientHeight;
|
9782 | ratio = startH / startW;
|
9783 | selectedHandle = handle;
|
9784 | selectedHandle.name = name;
|
9785 | selectedHandle.startPos = {
|
9786 | x: targetWidth * handle[0] + selectedElmX,
|
9787 | y: targetHeight * handle[1] + selectedElmY
|
9788 | };
|
9789 | startScrollWidth = rootElement.scrollWidth;
|
9790 | startScrollHeight = rootElement.scrollHeight;
|
9791 | resizeBackdrop = dom.add(rootElement, 'div', {
|
9792 | 'class': 'mce-resize-backdrop',
|
9793 | 'data-mce-bogus': 'all'
|
9794 | });
|
9795 | dom.setStyles(resizeBackdrop, {
|
9796 | position: 'fixed',
|
9797 | left: '0',
|
9798 | top: '0',
|
9799 | width: '100%',
|
9800 | height: '100%'
|
9801 | });
|
9802 | selectedElmGhost = createGhostElement(dom, selectedElm);
|
9803 | dom.addClass(selectedElmGhost, 'mce-clonedresizable');
|
9804 | dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
|
9805 | selectedElmGhost.contentEditable = 'false';
|
9806 | dom.setStyles(selectedElmGhost, {
|
9807 | left: selectedElmX,
|
9808 | top: selectedElmY,
|
9809 | margin: 0
|
9810 | });
|
9811 | setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
|
9812 | selectedElmGhost.removeAttribute(elementSelectionAttr);
|
9813 | rootElement.appendChild(selectedElmGhost);
|
9814 | dom.bind(editableDoc, 'mousemove', resizeGhostElement);
|
9815 | dom.bind(editableDoc, 'mouseup', endGhostResize);
|
9816 | if (rootDocument !== editableDoc) {
|
9817 | dom.bind(rootDocument, 'mousemove', resizeGhostElement);
|
9818 | dom.bind(rootDocument, 'mouseup', endGhostResize);
|
9819 | }
|
9820 | resizeHelper = dom.add(rootElement, 'div', {
|
9821 | 'class': 'mce-resize-helper',
|
9822 | 'data-mce-bogus': 'all'
|
9823 | }, startW + ' × ' + startH);
|
9824 | };
|
9825 | let handleElm = dom.get('mceResizeHandle' + name);
|
9826 | if (handleElm) {
|
9827 | dom.remove(handleElm);
|
9828 | }
|
9829 | handleElm = dom.add(rootElement, 'div', {
|
9830 | 'id': 'mceResizeHandle' + name,
|
9831 | 'data-mce-bogus': 'all',
|
9832 | 'class': 'mce-resizehandle',
|
9833 | 'unselectable': true,
|
9834 | 'style': 'cursor:' + name + '-resize; margin:0; padding:0'
|
9835 | });
|
9836 | dom.bind(handleElm, 'mousedown', e => {
|
9837 | e.stopImmediatePropagation();
|
9838 | e.preventDefault();
|
9839 | startDrag(e);
|
9840 | });
|
9841 | handle.elm = handleElm;
|
9842 | dom.setStyles(handleElm, {
|
9843 | left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
|
9844 | top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
|
9845 | });
|
9846 | });
|
9847 | } else {
|
9848 | hideResizeRect(false);
|
9849 | }
|
9850 | };
|
9851 | const throttledShowResizeRect = first$1(showResizeRect, 0);
|
9852 | const hideResizeRect = (removeSelected = true) => {
|
9853 | throttledShowResizeRect.cancel();
|
9854 | unbindResizeHandleEvents();
|
9855 | if (selectedElm && removeSelected) {
|
9856 | selectedElm.removeAttribute(elementSelectionAttr);
|
9857 | }
|
9858 | each$d(resizeHandles, (value, name) => {
|
9859 | const handleElm = dom.get('mceResizeHandle' + name);
|
9860 | if (handleElm) {
|
9861 | dom.unbind(handleElm);
|
9862 | dom.remove(handleElm);
|
9863 | }
|
9864 | });
|
9865 | };
|
9866 | const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent);
|
9867 | const updateResizeRect = e => {
|
9868 | if (resizeStarted || editor.removed || editor.composing) {
|
9869 | return;
|
9870 | }
|
9871 | const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
|
9872 | const controlElm = closest$3(SugarElement.fromDom(targetElm), controlElmSelector).map(e => e.dom).filter(e => dom.isEditable(e.parentElement) || e.nodeName === 'IMG' && dom.isEditable(e)).getOrUndefined();
|
9873 | const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1';
|
9874 | each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => {
|
9875 | img.removeAttribute(elementSelectionAttr);
|
9876 | });
|
9877 | if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement) && editor.hasFocus()) {
|
9878 | disableGeckoResize();
|
9879 | const startElm = selection.getStart(true);
|
9880 | if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
|
9881 | dom.setAttrib(controlElm, elementSelectionAttr, selectedValue);
|
9882 | throttledShowResizeRect.throttle(controlElm);
|
9883 | return;
|
9884 | }
|
9885 | }
|
9886 | hideResizeRect();
|
9887 | };
|
9888 | const unbindResizeHandleEvents = () => {
|
9889 | each$d(resizeHandles, handle => {
|
9890 | if (handle.elm) {
|
9891 | dom.unbind(handle.elm);
|
9892 | delete handle.elm;
|
9893 | }
|
9894 | });
|
9895 | };
|
9896 | const disableGeckoResize = () => {
|
9897 | try {
|
9898 | editor.getDoc().execCommand('enableObjectResizing', false, 'false');
|
9899 | } catch (ex) {
|
9900 | }
|
9901 | };
|
9902 | editor.on('init', () => {
|
9903 | disableGeckoResize();
|
9904 | editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect);
|
9905 | editor.on('keyup compositionend', e => {
|
9906 | if (selectedElm && selectedElm.nodeName === 'TABLE') {
|
9907 | updateResizeRect(e);
|
9908 | }
|
9909 | });
|
9910 | editor.on('hide blur', hideResizeRect);
|
9911 | editor.on('contextmenu longpress', contextMenuSelectImage, true);
|
9912 | });
|
9913 | editor.on('remove', unbindResizeHandleEvents);
|
9914 | const destroy = () => {
|
9915 | throttledShowResizeRect.cancel();
|
9916 | selectedElm = selectedElmGhost = resizeBackdrop = null;
|
9917 | };
|
9918 | return {
|
9919 | isResizable,
|
9920 | showResizeRect,
|
9921 | hideResizeRect,
|
9922 | updateResizeRect,
|
9923 | destroy
|
9924 | };
|
9925 | };
|
9926 |
|
9927 | const setStart = (rng, situ) => {
|
9928 | situ.fold(e => {
|
9929 | rng.setStartBefore(e.dom);
|
9930 | }, (e, o) => {
|
9931 | rng.setStart(e.dom, o);
|
9932 | }, e => {
|
9933 | rng.setStartAfter(e.dom);
|
9934 | });
|
9935 | };
|
9936 | const setFinish = (rng, situ) => {
|
9937 | situ.fold(e => {
|
9938 | rng.setEndBefore(e.dom);
|
9939 | }, (e, o) => {
|
9940 | rng.setEnd(e.dom, o);
|
9941 | }, e => {
|
9942 | rng.setEndAfter(e.dom);
|
9943 | });
|
9944 | };
|
9945 | const relativeToNative = (win, startSitu, finishSitu) => {
|
9946 | const range = win.document.createRange();
|
9947 | setStart(range, startSitu);
|
9948 | setFinish(range, finishSitu);
|
9949 | return range;
|
9950 | };
|
9951 | const exactToNative = (win, start, soffset, finish, foffset) => {
|
9952 | const rng = win.document.createRange();
|
9953 | rng.setStart(start.dom, soffset);
|
9954 | rng.setEnd(finish.dom, foffset);
|
9955 | return rng;
|
9956 | };
|
9957 |
|
9958 | const adt$3 = Adt.generate([
|
9959 | {
|
9960 | ltr: [
|
9961 | 'start',
|
9962 | 'soffset',
|
9963 | 'finish',
|
9964 | 'foffset'
|
9965 | ]
|
9966 | },
|
9967 | {
|
9968 | rtl: [
|
9969 | 'start',
|
9970 | 'soffset',
|
9971 | 'finish',
|
9972 | 'foffset'
|
9973 | ]
|
9974 | }
|
9975 | ]);
|
9976 | const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
|
9977 | const getRanges = (win, selection) => selection.match({
|
9978 | domRange: rng => {
|
9979 | return {
|
9980 | ltr: constant(rng),
|
9981 | rtl: Optional.none
|
9982 | };
|
9983 | },
|
9984 | relative: (startSitu, finishSitu) => {
|
9985 | return {
|
9986 | ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
|
9987 | rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
|
9988 | };
|
9989 | },
|
9990 | exact: (start, soffset, finish, foffset) => {
|
9991 | return {
|
9992 | ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
|
9993 | rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
|
9994 | };
|
9995 | }
|
9996 | });
|
9997 | const doDiagnose = (win, ranges) => {
|
9998 | const rng = ranges.ltr();
|
9999 | if (rng.collapsed) {
|
10000 | const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
|
10001 | return reversed.map(rev => adt$3.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$3.ltr, rng));
|
10002 | } else {
|
10003 | return fromRange(win, adt$3.ltr, rng);
|
10004 | }
|
10005 | };
|
10006 | const diagnose = (win, selection) => {
|
10007 | const ranges = getRanges(win, selection);
|
10008 | return doDiagnose(win, ranges);
|
10009 | };
|
10010 | adt$3.ltr;
|
10011 | adt$3.rtl;
|
10012 |
|
10013 | const create$9 = (start, soffset, finish, foffset) => ({
|
10014 | start,
|
10015 | soffset,
|
10016 | finish,
|
10017 | foffset
|
10018 | });
|
10019 | const SimRange = { create: create$9 };
|
10020 |
|
10021 | const caretPositionFromPoint = (doc, x, y) => {
|
10022 | var _a, _b;
|
10023 | return Optional.from((_b = (_a = doc.dom).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y)).bind(pos => {
|
10024 | if (pos.offsetNode === null) {
|
10025 | return Optional.none();
|
10026 | }
|
10027 | const r = doc.dom.createRange();
|
10028 | r.setStart(pos.offsetNode, pos.offset);
|
10029 | r.collapse();
|
10030 | return Optional.some(r);
|
10031 | });
|
10032 | };
|
10033 | const caretRangeFromPoint = (doc, x, y) => {
|
10034 | var _a, _b;
|
10035 | return Optional.from((_b = (_a = doc.dom).caretRangeFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y));
|
10036 | };
|
10037 | const availableSearch = (() => {
|
10038 | if (document.caretPositionFromPoint) {
|
10039 | return caretPositionFromPoint;
|
10040 | } else if (document.caretRangeFromPoint) {
|
10041 | return caretRangeFromPoint;
|
10042 | } else {
|
10043 | return Optional.none;
|
10044 | }
|
10045 | })();
|
10046 | const fromPoint$1 = (win, x, y) => {
|
10047 | const doc = SugarElement.fromDom(win.document);
|
10048 | return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
|
10049 | };
|
10050 |
|
10051 | const adt$2 = Adt.generate([
|
10052 | { before: ['element'] },
|
10053 | {
|
10054 | on: [
|
10055 | 'element',
|
10056 | 'offset'
|
10057 | ]
|
10058 | },
|
10059 | { after: ['element'] }
|
10060 | ]);
|
10061 | const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
|
10062 | const getStart$2 = situ => situ.fold(identity, identity, identity);
|
10063 | const before$1 = adt$2.before;
|
10064 | const on = adt$2.on;
|
10065 | const after$1 = adt$2.after;
|
10066 | const Situ = {
|
10067 | before: before$1,
|
10068 | on,
|
10069 | after: after$1,
|
10070 | cata,
|
10071 | getStart: getStart$2
|
10072 | };
|
10073 |
|
10074 | const adt$1 = Adt.generate([
|
10075 | { domRange: ['rng'] },
|
10076 | {
|
10077 | relative: [
|
10078 | 'startSitu',
|
10079 | 'finishSitu'
|
10080 | ]
|
10081 | },
|
10082 | {
|
10083 | exact: [
|
10084 | 'start',
|
10085 | 'soffset',
|
10086 | 'finish',
|
10087 | 'foffset'
|
10088 | ]
|
10089 | }
|
10090 | ]);
|
10091 | const exactFromRange = simRange => adt$1.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
|
10092 | const getStart$1 = selection => selection.match({
|
10093 | domRange: rng => SugarElement.fromDom(rng.startContainer),
|
10094 | relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
|
10095 | exact: (start, _soffset, _finish, _foffset) => start
|
10096 | });
|
10097 | const domRange = adt$1.domRange;
|
10098 | const relative = adt$1.relative;
|
10099 | const exact = adt$1.exact;
|
10100 | const getWin = selection => {
|
10101 | const start = getStart$1(selection);
|
10102 | return defaultView(start);
|
10103 | };
|
10104 | const range = SimRange.create;
|
10105 | const SimSelection = {
|
10106 | domRange,
|
10107 | relative,
|
10108 | exact,
|
10109 | exactFromRange,
|
10110 | getWin,
|
10111 | range
|
10112 | };
|
10113 |
|
10114 | const beforeSpecial = (element, offset) => {
|
10115 | const name$1 = name(element);
|
10116 | if ('input' === name$1) {
|
10117 | return Situ.after(element);
|
10118 | } else if (!contains$2([
|
10119 | 'br',
|
10120 | 'img'
|
10121 | ], name$1)) {
|
10122 | return Situ.on(element, offset);
|
10123 | } else {
|
10124 | return offset === 0 ? Situ.before(element) : Situ.after(element);
|
10125 | }
|
10126 | };
|
10127 | const preprocessRelative = (startSitu, finishSitu) => {
|
10128 | const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
|
10129 | const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
|
10130 | return SimSelection.relative(start, finish);
|
10131 | };
|
10132 | const preprocessExact = (start, soffset, finish, foffset) => {
|
10133 | const startSitu = beforeSpecial(start, soffset);
|
10134 | const finishSitu = beforeSpecial(finish, foffset);
|
10135 | return SimSelection.relative(startSitu, finishSitu);
|
10136 | };
|
10137 | const preprocess = selection => selection.match({
|
10138 | domRange: rng => {
|
10139 | const start = SugarElement.fromDom(rng.startContainer);
|
10140 | const finish = SugarElement.fromDom(rng.endContainer);
|
10141 | return preprocessExact(start, rng.startOffset, finish, rng.endOffset);
|
10142 | },
|
10143 | relative: preprocessRelative,
|
10144 | exact: preprocessExact
|
10145 | });
|
10146 |
|
10147 | const fromElements = (elements, scope) => {
|
10148 | const doc = scope || document;
|
10149 | const fragment = doc.createDocumentFragment();
|
10150 | each$e(elements, element => {
|
10151 | fragment.appendChild(element.dom);
|
10152 | });
|
10153 | return SugarElement.fromDom(fragment);
|
10154 | };
|
10155 |
|
10156 | const toNative = selection => {
|
10157 | const win = SimSelection.getWin(selection).dom;
|
10158 | const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset);
|
10159 | const filtered = preprocess(selection);
|
10160 | return diagnose(win, filtered).match({
|
10161 | ltr: getDomRange,
|
10162 | rtl: getDomRange
|
10163 | });
|
10164 | };
|
10165 | const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
|
10166 |
|
10167 | const fromPoint = (clientX, clientY, doc) => {
|
10168 | const win = defaultView(SugarElement.fromDom(doc));
|
10169 | return getAtPoint(win.dom, clientX, clientY).map(simRange => {
|
10170 | const rng = doc.createRange();
|
10171 | rng.setStart(simRange.start.dom, simRange.soffset);
|
10172 | rng.setEnd(simRange.finish.dom, simRange.foffset);
|
10173 | return rng;
|
10174 | }).getOrUndefined();
|
10175 | };
|
10176 |
|
10177 | const isEq$4 = (rng1, rng2) => {
|
10178 | return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
|
10179 | };
|
10180 |
|
10181 | const findParent = (node, rootNode, predicate) => {
|
10182 | let currentNode = node;
|
10183 | while (currentNode && currentNode !== rootNode) {
|
10184 | if (predicate(currentNode)) {
|
10185 | return currentNode;
|
10186 | }
|
10187 | currentNode = currentNode.parentNode;
|
10188 | }
|
10189 | return null;
|
10190 | };
|
10191 | const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
|
10192 | const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name);
|
10193 | const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode);
|
10194 | const hasBrBeforeAfter = (dom, node, left) => {
|
10195 | const parentNode = node.parentNode;
|
10196 | if (parentNode) {
|
10197 | const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot());
|
10198 | let currentNode;
|
10199 | while (currentNode = walker[left ? 'prev' : 'next']()) {
|
10200 | if (isBr$6(currentNode)) {
|
10201 | return true;
|
10202 | }
|
10203 | }
|
10204 | }
|
10205 | return false;
|
10206 | };
|
10207 | const isPrevNode = (node, name) => {
|
10208 | var _a;
|
10209 | return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
|
10210 | };
|
10211 | const hasContentEditableFalseParent = (root, node) => {
|
10212 | let currentNode = node;
|
10213 | while (currentNode && currentNode !== root) {
|
10214 | if (isContentEditableFalse$b(currentNode)) {
|
10215 | return true;
|
10216 | }
|
10217 | currentNode = currentNode.parentNode;
|
10218 | }
|
10219 | return false;
|
10220 | };
|
10221 | const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => {
|
10222 | const body = dom.getRoot();
|
10223 | const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
10224 | const parentNode = startNode.parentNode;
|
10225 | let lastInlineElement;
|
10226 | let node;
|
10227 | if (!parentNode) {
|
10228 | return Optional.none();
|
10229 | }
|
10230 | const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body;
|
10231 | if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
|
10232 | return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode)));
|
10233 | }
|
10234 | const walker = new DomTreeWalker(startNode, parentBlockContainer);
|
10235 | while (node = walker[left ? 'prev' : 'next']()) {
|
10236 | if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
|
10237 | return Optional.none();
|
10238 | }
|
10239 | if (isText$b(node) && node.data.length > 0) {
|
10240 | if (!hasParentWithName(node, body, 'A')) {
|
10241 | return Optional.some(CaretPosition(node, left ? node.data.length : 0));
|
10242 | }
|
10243 | return Optional.none();
|
10244 | }
|
10245 | if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
10246 | return Optional.none();
|
10247 | }
|
10248 | lastInlineElement = node;
|
10249 | }
|
10250 | if (isComment(lastInlineElement)) {
|
10251 | return Optional.none();
|
10252 | }
|
10253 | if (collapsed && lastInlineElement) {
|
10254 | return Optional.some(CaretPosition(lastInlineElement, 0));
|
10255 | }
|
10256 | return Optional.none();
|
10257 | };
|
10258 | const normalizeEndPoint = (dom, collapsed, start, rng) => {
|
10259 | const body = dom.getRoot();
|
10260 | let node;
|
10261 | let normalized = false;
|
10262 | let container = start ? rng.startContainer : rng.endContainer;
|
10263 | let offset = start ? rng.startOffset : rng.endOffset;
|
10264 | const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
|
10265 | const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
10266 | let directionLeft = start;
|
10267 | if (isCaretContainer$2(container)) {
|
10268 | return Optional.none();
|
10269 | }
|
10270 | if (isElement$6(container) && offset > container.childNodes.length - 1) {
|
10271 | directionLeft = false;
|
10272 | }
|
10273 | if (isDocument$1(container)) {
|
10274 | container = body;
|
10275 | offset = 0;
|
10276 | }
|
10277 | if (container === body) {
|
10278 | if (directionLeft) {
|
10279 | node = container.childNodes[offset > 0 ? offset - 1 : 0];
|
10280 | if (node) {
|
10281 | if (isCaretContainer$2(node)) {
|
10282 | return Optional.none();
|
10283 | }
|
10284 | if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) {
|
10285 | return Optional.none();
|
10286 | }
|
10287 | }
|
10288 | }
|
10289 | if (container.hasChildNodes()) {
|
10290 | offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
|
10291 | container = container.childNodes[offset];
|
10292 | offset = isText$b(container) && isAfterNode ? container.data.length : 0;
|
10293 | if (!collapsed && container === body.lastChild && isTable$2(container)) {
|
10294 | return Optional.none();
|
10295 | }
|
10296 | if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
|
10297 | return Optional.none();
|
10298 | }
|
10299 | if (isDetails(container)) {
|
10300 | return Optional.none();
|
10301 | }
|
10302 | if (container.hasChildNodes() && !isTable$2(container)) {
|
10303 | node = container;
|
10304 | const walker = new DomTreeWalker(container, body);
|
10305 | do {
|
10306 | if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) {
|
10307 | normalized = false;
|
10308 | break;
|
10309 | }
|
10310 | if (isText$b(node) && node.data.length > 0) {
|
10311 | offset = directionLeft ? 0 : node.data.length;
|
10312 | container = node;
|
10313 | normalized = true;
|
10314 | break;
|
10315 | }
|
10316 | if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) {
|
10317 | offset = dom.nodeIndex(node);
|
10318 | container = node.parentNode;
|
10319 | if (!directionLeft) {
|
10320 | offset++;
|
10321 | }
|
10322 | normalized = true;
|
10323 | break;
|
10324 | }
|
10325 | } while (node = directionLeft ? walker.next() : walker.prev());
|
10326 | }
|
10327 | }
|
10328 | }
|
10329 | if (collapsed) {
|
10330 | if (isText$b(container) && offset === 0) {
|
10331 | findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => {
|
10332 | container = pos.container();
|
10333 | offset = pos.offset();
|
10334 | normalized = true;
|
10335 | });
|
10336 | }
|
10337 | if (isElement$6(container)) {
|
10338 | node = container.childNodes[offset];
|
10339 | if (!node) {
|
10340 | node = container.childNodes[offset - 1];
|
10341 | }
|
10342 | if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
|
10343 | findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => {
|
10344 | container = pos.container();
|
10345 | offset = pos.offset();
|
10346 | normalized = true;
|
10347 | });
|
10348 | }
|
10349 | }
|
10350 | }
|
10351 | if (directionLeft && !collapsed && isText$b(container) && offset === container.data.length) {
|
10352 | findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => {
|
10353 | container = pos.container();
|
10354 | offset = pos.offset();
|
10355 | normalized = true;
|
10356 | });
|
10357 | }
|
10358 | return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none();
|
10359 | };
|
10360 | const normalize$2 = (dom, rng) => {
|
10361 | const collapsed = rng.collapsed, normRng = rng.cloneRange();
|
10362 | const startPos = CaretPosition.fromRangeStart(rng);
|
10363 | normalizeEndPoint(dom, collapsed, true, normRng).each(pos => {
|
10364 | if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
|
10365 | normRng.setStart(pos.container(), pos.offset());
|
10366 | }
|
10367 | });
|
10368 | if (!collapsed) {
|
10369 | normalizeEndPoint(dom, collapsed, false, normRng).each(pos => {
|
10370 | normRng.setEnd(pos.container(), pos.offset());
|
10371 | });
|
10372 | }
|
10373 | if (collapsed) {
|
10374 | normRng.collapse(true);
|
10375 | }
|
10376 | return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
|
10377 | };
|
10378 |
|
10379 | const splitText = (node, offset) => {
|
10380 | return node.splitText(offset);
|
10381 | };
|
10382 | const split = rng => {
|
10383 | let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
|
10384 | if (startContainer === endContainer && isText$b(startContainer)) {
|
10385 | if (startOffset > 0 && startOffset < startContainer.data.length) {
|
10386 | endContainer = splitText(startContainer, startOffset);
|
10387 | startContainer = endContainer.previousSibling;
|
10388 | if (endOffset > startOffset) {
|
10389 | endOffset = endOffset - startOffset;
|
10390 | const newContainer = splitText(endContainer, endOffset).previousSibling;
|
10391 | startContainer = endContainer = newContainer;
|
10392 | endOffset = newContainer.data.length;
|
10393 | startOffset = 0;
|
10394 | } else {
|
10395 | endOffset = 0;
|
10396 | }
|
10397 | }
|
10398 | } else {
|
10399 | if (isText$b(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) {
|
10400 | startContainer = splitText(startContainer, startOffset);
|
10401 | startOffset = 0;
|
10402 | }
|
10403 | if (isText$b(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) {
|
10404 | const newContainer = splitText(endContainer, endOffset).previousSibling;
|
10405 | endContainer = newContainer;
|
10406 | endOffset = newContainer.data.length;
|
10407 | }
|
10408 | }
|
10409 | return {
|
10410 | startContainer,
|
10411 | startOffset,
|
10412 | endContainer,
|
10413 | endOffset
|
10414 | };
|
10415 | };
|
10416 |
|
10417 | const RangeUtils = dom => {
|
10418 | const walk = (rng, callback) => {
|
10419 | return walk$3(dom, rng, callback);
|
10420 | };
|
10421 | const split$1 = split;
|
10422 | const normalize = rng => {
|
10423 | return normalize$2(dom, rng).fold(never, normalizedRng => {
|
10424 | rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
|
10425 | rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
|
10426 | return true;
|
10427 | });
|
10428 | };
|
10429 | const expand = (rng, options = { type: 'word' }) => {
|
10430 | if (options.type === 'word') {
|
10431 | const rangeLike = expandRng(dom, rng, [{ inline: 'span' }]);
|
10432 | const newRange = dom.createRng();
|
10433 | newRange.setStart(rangeLike.startContainer, rangeLike.startOffset);
|
10434 | newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset);
|
10435 | return newRange;
|
10436 | }
|
10437 | return rng;
|
10438 | };
|
10439 | return {
|
10440 | walk,
|
10441 | split: split$1,
|
10442 | expand,
|
10443 | normalize
|
10444 | };
|
10445 | };
|
10446 | RangeUtils.compareRanges = isEq$4;
|
10447 | RangeUtils.getCaretRangeFromPoint = fromPoint;
|
10448 | RangeUtils.getSelectedNode = getSelectedNode;
|
10449 | RangeUtils.getNode = getNode$1;
|
10450 |
|
10451 | const Dimension = (name, getOffset) => {
|
10452 | const set = (element, h) => {
|
10453 | if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
|
10454 | throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
|
10455 | }
|
10456 | const dom = element.dom;
|
10457 | if (isSupported(dom)) {
|
10458 | dom.style[name] = h + 'px';
|
10459 | }
|
10460 | };
|
10461 | const get = element => {
|
10462 | const r = getOffset(element);
|
10463 | if (r <= 0 || r === null) {
|
10464 | const css = get$7(element, name);
|
10465 | return parseFloat(css) || 0;
|
10466 | }
|
10467 | return r;
|
10468 | };
|
10469 | const getOuter = get;
|
10470 | const aggregate = (element, properties) => foldl(properties, (acc, property) => {
|
10471 | const val = get$7(element, property);
|
10472 | const value = val === undefined ? 0 : parseInt(val, 10);
|
10473 | return isNaN(value) ? acc : acc + value;
|
10474 | }, 0);
|
10475 | const max = (element, value, properties) => {
|
10476 | const cumulativeInclusions = aggregate(element, properties);
|
10477 | const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
|
10478 | return absoluteMax;
|
10479 | };
|
10480 | return {
|
10481 | set,
|
10482 | get,
|
10483 | getOuter,
|
10484 | aggregate,
|
10485 | max
|
10486 | };
|
10487 | };
|
10488 |
|
10489 | const api = Dimension('height', element => {
|
10490 | const dom = element.dom;
|
10491 | return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
|
10492 | });
|
10493 | const get$2 = element => api.get(element);
|
10494 |
|
10495 | const getDocument = () => SugarElement.fromDom(document);
|
10496 |
|
10497 | const walkUp = (navigation, doc) => {
|
10498 | const frame = navigation.view(doc);
|
10499 | return frame.fold(constant([]), f => {
|
10500 | const parent = navigation.owner(f);
|
10501 | const rest = walkUp(navigation, parent);
|
10502 | return [f].concat(rest);
|
10503 | });
|
10504 | };
|
10505 | const pathTo = (element, navigation) => {
|
10506 | const d = navigation.owner(element);
|
10507 | return walkUp(navigation, d);
|
10508 | };
|
10509 |
|
10510 | const view = doc => {
|
10511 | var _a;
|
10512 | const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
|
10513 | return element.map(SugarElement.fromDom);
|
10514 | };
|
10515 | const owner = element => documentOrOwner(element);
|
10516 |
|
10517 | var Navigation = /*#__PURE__*/Object.freeze({
|
10518 | __proto__: null,
|
10519 | view: view,
|
10520 | owner: owner
|
10521 | });
|
10522 |
|
10523 | const find = element => {
|
10524 | const doc = getDocument();
|
10525 | const scroll = get$5(doc);
|
10526 | const frames = pathTo(element, Navigation);
|
10527 | const offset = viewport(element);
|
10528 | const r = foldr(frames, (b, a) => {
|
10529 | const loc = viewport(a);
|
10530 | return {
|
10531 | left: b.left + loc.left,
|
10532 | top: b.top + loc.top
|
10533 | };
|
10534 | }, {
|
10535 | left: 0,
|
10536 | top: 0
|
10537 | });
|
10538 | return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
|
10539 | };
|
10540 |
|
10541 | const excludeFromDescend = element => name(element) === 'textarea';
|
10542 | const fireScrollIntoViewEvent = (editor, data) => {
|
10543 | const scrollEvent = editor.dispatch('ScrollIntoView', data);
|
10544 | return scrollEvent.isDefaultPrevented();
|
10545 | };
|
10546 | const fireAfterScrollIntoViewEvent = (editor, data) => {
|
10547 | editor.dispatch('AfterScrollIntoView', data);
|
10548 | };
|
10549 | const descend = (element, offset) => {
|
10550 | const children = children$1(element);
|
10551 | if (children.length === 0 || excludeFromDescend(element)) {
|
10552 | return {
|
10553 | element,
|
10554 | offset
|
10555 | };
|
10556 | } else if (offset < children.length && !excludeFromDescend(children[offset])) {
|
10557 | return {
|
10558 | element: children[offset],
|
10559 | offset: 0
|
10560 | };
|
10561 | } else {
|
10562 | const last = children[children.length - 1];
|
10563 | if (excludeFromDescend(last)) {
|
10564 | return {
|
10565 | element,
|
10566 | offset
|
10567 | };
|
10568 | } else {
|
10569 | if (name(last) === 'img') {
|
10570 | return {
|
10571 | element: last,
|
10572 | offset: 1
|
10573 | };
|
10574 | } else if (isText$c(last)) {
|
10575 | return {
|
10576 | element: last,
|
10577 | offset: get$3(last).length
|
10578 | };
|
10579 | } else {
|
10580 | return {
|
10581 | element: last,
|
10582 | offset: children$1(last).length
|
10583 | };
|
10584 | }
|
10585 | }
|
10586 | }
|
10587 | };
|
10588 | const markerInfo = (element, cleanupFun) => {
|
10589 | const pos = absolute(element);
|
10590 | const height = get$2(element);
|
10591 | return {
|
10592 | element,
|
10593 | bottom: pos.top + height,
|
10594 | height,
|
10595 | pos,
|
10596 | cleanup: cleanupFun
|
10597 | };
|
10598 | };
|
10599 | const createMarker$1 = (element, offset) => {
|
10600 | const startPoint = descend(element, offset);
|
10601 | const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + '</span>');
|
10602 | before$3(startPoint.element, span);
|
10603 | return markerInfo(span, () => remove$4(span));
|
10604 | };
|
10605 | const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop);
|
10606 | const withMarker = (editor, f, rng, alignToTop) => {
|
10607 | preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
|
10608 | };
|
10609 | const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
|
10610 | const data = {
|
10611 | elm: marker.element.dom,
|
10612 | alignToTop
|
10613 | };
|
10614 | if (fireScrollIntoViewEvent(editor, data)) {
|
10615 | return;
|
10616 | }
|
10617 | const scrollTop = get$5(doc).top;
|
10618 | f(editor, doc, scrollTop, marker, alignToTop);
|
10619 | fireAfterScrollIntoViewEvent(editor, data);
|
10620 | };
|
10621 | const applyWithMarker = (editor, f, rng, alignToTop) => {
|
10622 | const body = SugarElement.fromDom(editor.getBody());
|
10623 | const doc = SugarElement.fromDom(editor.getDoc());
|
10624 | reflow(body);
|
10625 | const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
|
10626 | withScrollEvents(editor, doc, f, marker, alignToTop);
|
10627 | marker.cleanup();
|
10628 | };
|
10629 | const withElement = (editor, element, f, alignToTop) => {
|
10630 | const doc = SugarElement.fromDom(editor.getDoc());
|
10631 | withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
|
10632 | };
|
10633 | const preserveWith = (editor, f, rng) => {
|
10634 | const startElement = rng.startContainer;
|
10635 | const startOffset = rng.startOffset;
|
10636 | const endElement = rng.endContainer;
|
10637 | const endOffset = rng.endOffset;
|
10638 | f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
|
10639 | const newRng = editor.dom.createRng();
|
10640 | newRng.setStart(startElement, startOffset);
|
10641 | newRng.setEnd(endElement, endOffset);
|
10642 | editor.selection.setRng(rng);
|
10643 | };
|
10644 | const scrollToMarker = (editor, marker, viewHeight, alignToTop, doc) => {
|
10645 | const pos = marker.pos;
|
10646 | if (alignToTop) {
|
10647 | to(pos.left, pos.top, doc);
|
10648 | } else {
|
10649 | const y = pos.top - viewHeight + marker.height;
|
10650 | to(-editor.getBody().getBoundingClientRect().left, y, doc);
|
10651 | }
|
10652 | };
|
10653 | const intoWindowIfNeeded = (editor, doc, scrollTop, viewHeight, marker, alignToTop) => {
|
10654 | const viewportBottom = viewHeight + scrollTop;
|
10655 | const markerTop = marker.pos.top;
|
10656 | const markerBottom = marker.bottom;
|
10657 | const largerThanViewport = markerBottom - markerTop >= viewHeight;
|
10658 | if (markerTop < scrollTop) {
|
10659 | scrollToMarker(editor, marker, viewHeight, alignToTop !== false, doc);
|
10660 | } else if (markerTop > viewportBottom) {
|
10661 | const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
|
10662 | scrollToMarker(editor, marker, viewHeight, align, doc);
|
10663 | } else if (markerBottom > viewportBottom && !largerThanViewport) {
|
10664 | scrollToMarker(editor, marker, viewHeight, alignToTop === true, doc);
|
10665 | }
|
10666 | };
|
10667 | const intoWindow = (editor, doc, scrollTop, marker, alignToTop) => {
|
10668 | const viewHeight = defaultView(doc).dom.innerHeight;
|
10669 | intoWindowIfNeeded(editor, doc, scrollTop, viewHeight, marker, alignToTop);
|
10670 | };
|
10671 | const intoFrame = (editor, doc, scrollTop, marker, alignToTop) => {
|
10672 | const frameViewHeight = defaultView(doc).dom.innerHeight;
|
10673 | intoWindowIfNeeded(editor, doc, scrollTop, frameViewHeight, marker, alignToTop);
|
10674 | const op = find(marker.element);
|
10675 | const viewportBounds = getBounds(window);
|
10676 | if (op.top < viewportBounds.y) {
|
10677 | intoView(marker.element, alignToTop !== false);
|
10678 | } else if (op.top > viewportBounds.bottom) {
|
10679 | intoView(marker.element, alignToTop === true);
|
10680 | }
|
10681 | };
|
10682 | const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
|
10683 | const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
|
10684 | const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
|
10685 | const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
|
10686 | const scrollElementIntoView = (editor, element, alignToTop) => {
|
10687 | const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
|
10688 | scroller(editor, element, alignToTop);
|
10689 | };
|
10690 | const scrollRangeIntoView = (editor, rng, alignToTop) => {
|
10691 | const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
|
10692 | scroller(editor, rng, alignToTop);
|
10693 | };
|
10694 |
|
10695 | const focus$1 = (element, preventScroll = false) => element.dom.focus({ preventScroll });
|
10696 | const hasFocus$1 = element => {
|
10697 | const root = getRootNode(element).dom;
|
10698 | return element.dom === root.activeElement;
|
10699 | };
|
10700 | const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
|
10701 | const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
|
10702 |
|
10703 | const clamp$1 = (offset, element) => {
|
10704 | const max = isText$c(element) ? get$3(element).length : children$1(element).length + 1;
|
10705 | if (offset > max) {
|
10706 | return max;
|
10707 | } else if (offset < 0) {
|
10708 | return 0;
|
10709 | }
|
10710 | return offset;
|
10711 | };
|
10712 | const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
|
10713 | const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
|
10714 | const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
|
10715 | const shouldStore = editor => editor.inline || Env.browser.isFirefox();
|
10716 | const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
|
10717 | const readRange = win => {
|
10718 | const selection = win.getSelection();
|
10719 | const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
|
10720 | return rng.map(nativeRangeToSelectionRange);
|
10721 | };
|
10722 | const getBookmark = root => {
|
10723 | const win = defaultView(root);
|
10724 | return readRange(win.dom).filter(isRngInRoot(root));
|
10725 | };
|
10726 | const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
|
10727 | const bookmarkToNativeRng = bookmark => {
|
10728 | const rng = document.createRange();
|
10729 | try {
|
10730 | rng.setStart(bookmark.start.dom, bookmark.soffset);
|
10731 | rng.setEnd(bookmark.finish.dom, bookmark.foffset);
|
10732 | return Optional.some(rng);
|
10733 | } catch (_) {
|
10734 | return Optional.none();
|
10735 | }
|
10736 | };
|
10737 | const store = editor => {
|
10738 | const newBookmark = shouldStore(editor) ? getBookmark(SugarElement.fromDom(editor.getBody())) : Optional.none();
|
10739 | editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
|
10740 | };
|
10741 | const getRng = editor => {
|
10742 | const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
|
10743 | return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
|
10744 | };
|
10745 | const restore = editor => {
|
10746 | getRng(editor).each(rng => editor.selection.setRng(rng));
|
10747 | };
|
10748 |
|
10749 | const isEditorUIElement$1 = elm => {
|
10750 | const className = elm.className.toString();
|
10751 | return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
|
10752 | };
|
10753 | const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
|
10754 |
|
10755 | const wrappedSetTimeout = (callback, time) => {
|
10756 | if (!isNumber(time)) {
|
10757 | time = 0;
|
10758 | }
|
10759 | return setTimeout(callback, time);
|
10760 | };
|
10761 | const wrappedSetInterval = (callback, time) => {
|
10762 | if (!isNumber(time)) {
|
10763 | time = 0;
|
10764 | }
|
10765 | return setInterval(callback, time);
|
10766 | };
|
10767 | const Delay = {
|
10768 | setEditorTimeout: (editor, callback, time) => {
|
10769 | return wrappedSetTimeout(() => {
|
10770 | if (!editor.removed) {
|
10771 | callback();
|
10772 | }
|
10773 | }, time);
|
10774 | },
|
10775 | setEditorInterval: (editor, callback, time) => {
|
10776 | const timer = wrappedSetInterval(() => {
|
10777 | if (!editor.removed) {
|
10778 | callback();
|
10779 | } else {
|
10780 | clearInterval(timer);
|
10781 | }
|
10782 | }, time);
|
10783 | return timer;
|
10784 | }
|
10785 | };
|
10786 |
|
10787 | const isManualNodeChange = e => {
|
10788 | return e.type === 'nodechange' && e.selectionChange;
|
10789 | };
|
10790 | const registerPageMouseUp = (editor, throttledStore) => {
|
10791 | const mouseUpPage = () => {
|
10792 | throttledStore.throttle();
|
10793 | };
|
10794 | DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage);
|
10795 | editor.on('remove', () => {
|
10796 | DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage);
|
10797 | });
|
10798 | };
|
10799 | const registerMouseUp = (editor, throttledStore) => {
|
10800 | editor.on('mouseup touchend', _e => {
|
10801 | throttledStore.throttle();
|
10802 | });
|
10803 | };
|
10804 | const registerEditorEvents = (editor, throttledStore) => {
|
10805 | registerMouseUp(editor, throttledStore);
|
10806 | editor.on('keyup NodeChange AfterSetSelectionRange', e => {
|
10807 | if (!isManualNodeChange(e)) {
|
10808 | store(editor);
|
10809 | }
|
10810 | });
|
10811 | };
|
10812 | const register$6 = editor => {
|
10813 | const throttledStore = first$1(() => {
|
10814 | store(editor);
|
10815 | }, 0);
|
10816 | editor.on('init', () => {
|
10817 | if (editor.inline) {
|
10818 | registerPageMouseUp(editor, throttledStore);
|
10819 | }
|
10820 | registerEditorEvents(editor, throttledStore);
|
10821 | });
|
10822 | editor.on('remove', () => {
|
10823 | throttledStore.cancel();
|
10824 | });
|
10825 | };
|
10826 |
|
10827 | let documentFocusInHandler;
|
10828 | const DOM$9 = DOMUtils.DOM;
|
10829 | const isEditorUIElement = elm => {
|
10830 | return isElement$6(elm) && FocusManager.isEditorUIElement(elm);
|
10831 | };
|
10832 | const isEditorContentAreaElement = elm => {
|
10833 | const classList = elm.classList;
|
10834 | if (classList !== undefined) {
|
10835 | return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
|
10836 | } else {
|
10837 | return false;
|
10838 | }
|
10839 | };
|
10840 | const isUIElement = (editor, elm) => {
|
10841 | const customSelector = getCustomUiSelector(editor);
|
10842 | const parent = DOM$9.getParent(elm, elm => {
|
10843 | return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
|
10844 | });
|
10845 | return parent !== null;
|
10846 | };
|
10847 | const getActiveElement = editor => {
|
10848 | try {
|
10849 | const root = getRootNode(SugarElement.fromDom(editor.getElement()));
|
10850 | return active$1(root).fold(() => document.body, x => x.dom);
|
10851 | } catch (ex) {
|
10852 | return document.body;
|
10853 | }
|
10854 | };
|
10855 | const registerEvents$1 = (editorManager, e) => {
|
10856 | const editor = e.editor;
|
10857 | register$6(editor);
|
10858 | const toggleContentAreaOnFocus = (editor, fn) => {
|
10859 | if (shouldHighlightOnFocus(editor) && editor.inline !== true) {
|
10860 | const contentArea = SugarElement.fromDom(editor.getContainer());
|
10861 | fn(contentArea, 'tox-edit-focus');
|
10862 | }
|
10863 | };
|
10864 | editor.on('focusin', () => {
|
10865 | const focusedEditor = editorManager.focusedEditor;
|
10866 | if (isEditorContentAreaElement(getActiveElement(editor))) {
|
10867 | toggleContentAreaOnFocus(editor, add$2);
|
10868 | }
|
10869 | if (focusedEditor !== editor) {
|
10870 | if (focusedEditor) {
|
10871 | focusedEditor.dispatch('blur', { focusedEditor: editor });
|
10872 | }
|
10873 | editorManager.setActive(editor);
|
10874 | editorManager.focusedEditor = editor;
|
10875 | editor.dispatch('focus', { blurredEditor: focusedEditor });
|
10876 | editor.focus(true);
|
10877 | }
|
10878 | });
|
10879 | editor.on('focusout', () => {
|
10880 | Delay.setEditorTimeout(editor, () => {
|
10881 | const focusedEditor = editorManager.focusedEditor;
|
10882 | if (!isEditorContentAreaElement(getActiveElement(editor)) || focusedEditor !== editor) {
|
10883 | toggleContentAreaOnFocus(editor, remove$6);
|
10884 | }
|
10885 | if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
|
10886 | editor.dispatch('blur', { focusedEditor: null });
|
10887 | editorManager.focusedEditor = null;
|
10888 | }
|
10889 | });
|
10890 | });
|
10891 | if (!documentFocusInHandler) {
|
10892 | documentFocusInHandler = e => {
|
10893 | const activeEditor = editorManager.activeEditor;
|
10894 | if (activeEditor) {
|
10895 | getOriginalEventTarget(e).each(target => {
|
10896 | const elem = target;
|
10897 | if (elem.ownerDocument === document) {
|
10898 | if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) {
|
10899 | activeEditor.dispatch('blur', { focusedEditor: null });
|
10900 | editorManager.focusedEditor = null;
|
10901 | }
|
10902 | }
|
10903 | });
|
10904 | }
|
10905 | };
|
10906 | DOM$9.bind(document, 'focusin', documentFocusInHandler);
|
10907 | }
|
10908 | };
|
10909 | const unregisterDocumentEvents = (editorManager, e) => {
|
10910 | if (editorManager.focusedEditor === e.editor) {
|
10911 | editorManager.focusedEditor = null;
|
10912 | }
|
10913 | if (!editorManager.activeEditor && documentFocusInHandler) {
|
10914 | DOM$9.unbind(document, 'focusin', documentFocusInHandler);
|
10915 | documentFocusInHandler = null;
|
10916 | }
|
10917 | };
|
10918 | const setup$w = editorManager => {
|
10919 | editorManager.on('AddEditor', curry(registerEvents$1, editorManager));
|
10920 | editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
|
10921 | };
|
10922 |
|
10923 | const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
|
10924 | const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
|
10925 | const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
|
10926 | if (isTableSection(node)) {
|
10927 | return Optional.some(node);
|
10928 | } else if (!contains(root, node)) {
|
10929 | return Optional.some(root);
|
10930 | } else {
|
10931 | return Optional.none();
|
10932 | }
|
10933 | });
|
10934 | const normalizeSelection = (editor, rng) => {
|
10935 | getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => {
|
10936 | return firstPositionIn(elm.dom);
|
10937 | }).fold(() => {
|
10938 | editor.selection.normalize();
|
10939 | }, caretPos => editor.selection.setRng(caretPos.toRange()));
|
10940 | };
|
10941 | const focusBody = body => {
|
10942 | if (body.setActive) {
|
10943 | try {
|
10944 | body.setActive();
|
10945 | } catch (ex) {
|
10946 | body.focus();
|
10947 | }
|
10948 | } else {
|
10949 | body.focus();
|
10950 | }
|
10951 | };
|
10952 | const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome();
|
10953 | const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
|
10954 | const hasInlineFocus = editor => {
|
10955 | const rawBody = editor.getBody();
|
10956 | return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
|
10957 | };
|
10958 | const hasUiFocus = editor => {
|
10959 | const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
|
10960 | return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
|
10961 | };
|
10962 | const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
|
10963 | const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor);
|
10964 | const focusEditor = editor => {
|
10965 | const selection = editor.selection;
|
10966 | const body = editor.getBody();
|
10967 | let rng = selection.getRng();
|
10968 | editor.quirks.refreshContentEditable();
|
10969 | if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
|
10970 | getRng(editor).each(bookmarkRng => {
|
10971 | editor.selection.setRng(bookmarkRng);
|
10972 | rng = bookmarkRng;
|
10973 | });
|
10974 | }
|
10975 | const contentEditableHost = getContentEditableHost(editor, selection.getNode());
|
10976 | if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
|
10977 | focusBody(contentEditableHost);
|
10978 | normalizeSelection(editor, rng);
|
10979 | activateEditor(editor);
|
10980 | return;
|
10981 | }
|
10982 | if (!editor.inline) {
|
10983 | if (!Env.browser.isOpera()) {
|
10984 | focusBody(body);
|
10985 | }
|
10986 | editor.getWin().focus();
|
10987 | }
|
10988 | if (Env.browser.isFirefox() || editor.inline) {
|
10989 | focusBody(body);
|
10990 | normalizeSelection(editor, rng);
|
10991 | }
|
10992 | activateEditor(editor);
|
10993 | };
|
10994 | const activateEditor = editor => editor.editorManager.setActive(editor);
|
10995 | const focus = (editor, skipFocus) => {
|
10996 | if (editor.removed) {
|
10997 | return;
|
10998 | }
|
10999 | if (skipFocus) {
|
11000 | activateEditor(editor);
|
11001 | } else {
|
11002 | focusEditor(editor);
|
11003 | }
|
11004 | };
|
11005 |
|
11006 | const isEditableRange = (dom, rng) => {
|
11007 | if (rng.collapsed) {
|
11008 | return dom.isEditable(rng.startContainer);
|
11009 | } else {
|
11010 | return dom.isEditable(rng.startContainer) && dom.isEditable(rng.endContainer);
|
11011 | }
|
11012 | };
|
11013 |
|
11014 | const getEndpointElement = (root, rng, start, real, resolve) => {
|
11015 | const container = start ? rng.startContainer : rng.endContainer;
|
11016 | const offset = start ? rng.startOffset : rng.endOffset;
|
11017 | return Optional.from(container).map(SugarElement.fromDom).map(elm => !real || !rng.collapsed ? child$1(elm, resolve(elm, offset)).getOr(elm) : elm).bind(elm => isElement$7(elm) ? Optional.some(elm) : parent(elm).filter(isElement$7)).map(elm => elm.dom).getOr(root);
|
11018 | };
|
11019 | const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
|
11020 | const getEnd = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
|
11021 | const skipEmptyTextNodes = (node, forwards) => {
|
11022 | const orig = node;
|
11023 | while (node && isText$b(node) && node.length === 0) {
|
11024 | node = forwards ? node.nextSibling : node.previousSibling;
|
11025 | }
|
11026 | return node || orig;
|
11027 | };
|
11028 | const getNode = (root, rng) => {
|
11029 | if (!rng) {
|
11030 | return root;
|
11031 | }
|
11032 | let startContainer = rng.startContainer;
|
11033 | let endContainer = rng.endContainer;
|
11034 | const startOffset = rng.startOffset;
|
11035 | const endOffset = rng.endOffset;
|
11036 | let node = rng.commonAncestorContainer;
|
11037 | if (!rng.collapsed) {
|
11038 | if (startContainer === endContainer) {
|
11039 | if (endOffset - startOffset < 2) {
|
11040 | if (startContainer.hasChildNodes()) {
|
11041 | node = startContainer.childNodes[startOffset];
|
11042 | }
|
11043 | }
|
11044 | }
|
11045 | if (isText$b(startContainer) && isText$b(endContainer)) {
|
11046 | if (startContainer.length === startOffset) {
|
11047 | startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
|
11048 | } else {
|
11049 | startContainer = startContainer.parentNode;
|
11050 | }
|
11051 | if (endOffset === 0) {
|
11052 | endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
|
11053 | } else {
|
11054 | endContainer = endContainer.parentNode;
|
11055 | }
|
11056 | if (startContainer && startContainer === endContainer) {
|
11057 | node = startContainer;
|
11058 | }
|
11059 | }
|
11060 | }
|
11061 | const elm = isText$b(node) ? node.parentNode : node;
|
11062 | return isHTMLElement(elm) ? elm : root;
|
11063 | };
|
11064 | const getSelectedBlocks = (dom, rng, startElm, endElm) => {
|
11065 | const selectedBlocks = [];
|
11066 | const root = dom.getRoot();
|
11067 | const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock);
|
11068 | const end = dom.getParent(endElm || getEnd(root, rng, rng.collapsed), dom.isBlock);
|
11069 | if (start && start !== root) {
|
11070 | selectedBlocks.push(start);
|
11071 | }
|
11072 | if (start && end && start !== end) {
|
11073 | let node;
|
11074 | const walker = new DomTreeWalker(start, root);
|
11075 | while ((node = walker.next()) && node !== end) {
|
11076 | if (dom.isBlock(node)) {
|
11077 | selectedBlocks.push(node);
|
11078 | }
|
11079 | }
|
11080 | }
|
11081 | if (end && start !== end && end !== root) {
|
11082 | selectedBlocks.push(end);
|
11083 | }
|
11084 | return selectedBlocks;
|
11085 | };
|
11086 | const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => {
|
11087 | const idx = dom.nodeIndex(node);
|
11088 | const rng = dom.createRng();
|
11089 | rng.setStart(parent, idx);
|
11090 | rng.setEnd(parent, idx + 1);
|
11091 | if (content) {
|
11092 | moveEndPoint(dom, rng, node, true);
|
11093 | moveEndPoint(dom, rng, node, false);
|
11094 | }
|
11095 | return rng;
|
11096 | }));
|
11097 |
|
11098 | const processRanges = (editor, ranges) => map$3(ranges, range => {
|
11099 | const evt = editor.dispatch('GetSelectionRange', { range });
|
11100 | return evt.range !== range ? evt.range : range;
|
11101 | });
|
11102 |
|
11103 | const typeLookup = {
|
11104 | '#text': 3,
|
11105 | '#comment': 8,
|
11106 | '#cdata': 4,
|
11107 | '#pi': 7,
|
11108 | '#doctype': 10,
|
11109 | '#document-fragment': 11
|
11110 | };
|
11111 | const walk$2 = (node, root, prev) => {
|
11112 | const startName = prev ? 'lastChild' : 'firstChild';
|
11113 | const siblingName = prev ? 'prev' : 'next';
|
11114 | if (node[startName]) {
|
11115 | return node[startName];
|
11116 | }
|
11117 | if (node !== root) {
|
11118 | let sibling = node[siblingName];
|
11119 | if (sibling) {
|
11120 | return sibling;
|
11121 | }
|
11122 | for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
|
11123 | sibling = parent[siblingName];
|
11124 | if (sibling) {
|
11125 | return sibling;
|
11126 | }
|
11127 | }
|
11128 | }
|
11129 | return undefined;
|
11130 | };
|
11131 | const isEmptyTextNode = node => {
|
11132 | var _a;
|
11133 | const text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
|
11134 | if (!isWhitespaceText(text)) {
|
11135 | return false;
|
11136 | }
|
11137 | const parentNode = node.parent;
|
11138 | if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) {
|
11139 | return false;
|
11140 | }
|
11141 | return true;
|
11142 | };
|
11143 | const isNonEmptyElement = node => {
|
11144 | const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id');
|
11145 | return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor;
|
11146 | };
|
11147 | class AstNode {
|
11148 | static create(name, attrs) {
|
11149 | const node = new AstNode(name, typeLookup[name] || 1);
|
11150 | if (attrs) {
|
11151 | each$d(attrs, (value, attrName) => {
|
11152 | node.attr(attrName, value);
|
11153 | });
|
11154 | }
|
11155 | return node;
|
11156 | }
|
11157 | constructor(name, type) {
|
11158 | this.name = name;
|
11159 | this.type = type;
|
11160 | if (type === 1) {
|
11161 | this.attributes = [];
|
11162 | this.attributes.map = {};
|
11163 | }
|
11164 | }
|
11165 | replace(node) {
|
11166 | const self = this;
|
11167 | if (node.parent) {
|
11168 | node.remove();
|
11169 | }
|
11170 | self.insert(node, self);
|
11171 | self.remove();
|
11172 | return self;
|
11173 | }
|
11174 | attr(name, value) {
|
11175 | const self = this;
|
11176 | if (!isString(name)) {
|
11177 | if (isNonNullable(name)) {
|
11178 | each$d(name, (value, key) => {
|
11179 | self.attr(key, value);
|
11180 | });
|
11181 | }
|
11182 | return self;
|
11183 | }
|
11184 | const attrs = self.attributes;
|
11185 | if (attrs) {
|
11186 | if (value !== undefined) {
|
11187 | if (value === null) {
|
11188 | if (name in attrs.map) {
|
11189 | delete attrs.map[name];
|
11190 | let i = attrs.length;
|
11191 | while (i--) {
|
11192 | if (attrs[i].name === name) {
|
11193 | attrs.splice(i, 1);
|
11194 | return self;
|
11195 | }
|
11196 | }
|
11197 | }
|
11198 | return self;
|
11199 | }
|
11200 | if (name in attrs.map) {
|
11201 | let i = attrs.length;
|
11202 | while (i--) {
|
11203 | if (attrs[i].name === name) {
|
11204 | attrs[i].value = value;
|
11205 | break;
|
11206 | }
|
11207 | }
|
11208 | } else {
|
11209 | attrs.push({
|
11210 | name,
|
11211 | value
|
11212 | });
|
11213 | }
|
11214 | attrs.map[name] = value;
|
11215 | return self;
|
11216 | }
|
11217 | return attrs.map[name];
|
11218 | }
|
11219 | return undefined;
|
11220 | }
|
11221 | clone() {
|
11222 | const self = this;
|
11223 | const clone = new AstNode(self.name, self.type);
|
11224 | const selfAttrs = self.attributes;
|
11225 | if (selfAttrs) {
|
11226 | const cloneAttrs = [];
|
11227 | cloneAttrs.map = {};
|
11228 | for (let i = 0, l = selfAttrs.length; i < l; i++) {
|
11229 | const selfAttr = selfAttrs[i];
|
11230 | if (selfAttr.name !== 'id') {
|
11231 | cloneAttrs[cloneAttrs.length] = {
|
11232 | name: selfAttr.name,
|
11233 | value: selfAttr.value
|
11234 | };
|
11235 | cloneAttrs.map[selfAttr.name] = selfAttr.value;
|
11236 | }
|
11237 | }
|
11238 | clone.attributes = cloneAttrs;
|
11239 | }
|
11240 | clone.value = self.value;
|
11241 | return clone;
|
11242 | }
|
11243 | wrap(wrapper) {
|
11244 | const self = this;
|
11245 | if (self.parent) {
|
11246 | self.parent.insert(wrapper, self);
|
11247 | wrapper.append(self);
|
11248 | }
|
11249 | return self;
|
11250 | }
|
11251 | unwrap() {
|
11252 | const self = this;
|
11253 | for (let node = self.firstChild; node;) {
|
11254 | const next = node.next;
|
11255 | self.insert(node, self, true);
|
11256 | node = next;
|
11257 | }
|
11258 | self.remove();
|
11259 | }
|
11260 | remove() {
|
11261 | const self = this, parent = self.parent, next = self.next, prev = self.prev;
|
11262 | if (parent) {
|
11263 | if (parent.firstChild === self) {
|
11264 | parent.firstChild = next;
|
11265 | if (next) {
|
11266 | next.prev = null;
|
11267 | }
|
11268 | } else if (prev) {
|
11269 | prev.next = next;
|
11270 | }
|
11271 | if (parent.lastChild === self) {
|
11272 | parent.lastChild = prev;
|
11273 | if (prev) {
|
11274 | prev.next = null;
|
11275 | }
|
11276 | } else if (next) {
|
11277 | next.prev = prev;
|
11278 | }
|
11279 | self.parent = self.next = self.prev = null;
|
11280 | }
|
11281 | return self;
|
11282 | }
|
11283 | append(node) {
|
11284 | const self = this;
|
11285 | if (node.parent) {
|
11286 | node.remove();
|
11287 | }
|
11288 | const last = self.lastChild;
|
11289 | if (last) {
|
11290 | last.next = node;
|
11291 | node.prev = last;
|
11292 | self.lastChild = node;
|
11293 | } else {
|
11294 | self.lastChild = self.firstChild = node;
|
11295 | }
|
11296 | node.parent = self;
|
11297 | return node;
|
11298 | }
|
11299 | insert(node, refNode, before) {
|
11300 | if (node.parent) {
|
11301 | node.remove();
|
11302 | }
|
11303 | const parent = refNode.parent || this;
|
11304 | if (before) {
|
11305 | if (refNode === parent.firstChild) {
|
11306 | parent.firstChild = node;
|
11307 | } else if (refNode.prev) {
|
11308 | refNode.prev.next = node;
|
11309 | }
|
11310 | node.prev = refNode.prev;
|
11311 | node.next = refNode;
|
11312 | refNode.prev = node;
|
11313 | } else {
|
11314 | if (refNode === parent.lastChild) {
|
11315 | parent.lastChild = node;
|
11316 | } else if (refNode.next) {
|
11317 | refNode.next.prev = node;
|
11318 | }
|
11319 | node.next = refNode.next;
|
11320 | node.prev = refNode;
|
11321 | refNode.next = node;
|
11322 | }
|
11323 | node.parent = parent;
|
11324 | return node;
|
11325 | }
|
11326 | getAll(name) {
|
11327 | const self = this;
|
11328 | const collection = [];
|
11329 | for (let node = self.firstChild; node; node = walk$2(node, self)) {
|
11330 | if (node.name === name) {
|
11331 | collection.push(node);
|
11332 | }
|
11333 | }
|
11334 | return collection;
|
11335 | }
|
11336 | children() {
|
11337 | const self = this;
|
11338 | const collection = [];
|
11339 | for (let node = self.firstChild; node; node = node.next) {
|
11340 | collection.push(node);
|
11341 | }
|
11342 | return collection;
|
11343 | }
|
11344 | empty() {
|
11345 | const self = this;
|
11346 | if (self.firstChild) {
|
11347 | const nodes = [];
|
11348 | for (let node = self.firstChild; node; node = walk$2(node, self)) {
|
11349 | nodes.push(node);
|
11350 | }
|
11351 | let i = nodes.length;
|
11352 | while (i--) {
|
11353 | const node = nodes[i];
|
11354 | node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
|
11355 | }
|
11356 | }
|
11357 | self.firstChild = self.lastChild = null;
|
11358 | return self;
|
11359 | }
|
11360 | isEmpty(elements, whitespace = {}, predicate) {
|
11361 | var _a;
|
11362 | const self = this;
|
11363 | let node = self.firstChild;
|
11364 | if (isNonEmptyElement(self)) {
|
11365 | return false;
|
11366 | }
|
11367 | if (node) {
|
11368 | do {
|
11369 | if (node.type === 1) {
|
11370 | if (node.attr('data-mce-bogus')) {
|
11371 | continue;
|
11372 | }
|
11373 | if (elements[node.name]) {
|
11374 | return false;
|
11375 | }
|
11376 | if (isNonEmptyElement(node)) {
|
11377 | return false;
|
11378 | }
|
11379 | }
|
11380 | if (node.type === 8) {
|
11381 | return false;
|
11382 | }
|
11383 | if (node.type === 3 && !isEmptyTextNode(node)) {
|
11384 | return false;
|
11385 | }
|
11386 | if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) {
|
11387 | return false;
|
11388 | }
|
11389 | if (predicate && predicate(node)) {
|
11390 | return false;
|
11391 | }
|
11392 | } while (node = walk$2(node, self));
|
11393 | }
|
11394 | return true;
|
11395 | }
|
11396 | walk(prev) {
|
11397 | return walk$2(this, null, prev);
|
11398 | }
|
11399 | }
|
11400 |
|
11401 | const unescapedTextParents = Tools.makeMap('NOSCRIPT STYLE SCRIPT XMP IFRAME NOEMBED NOFRAMES PLAINTEXT', ' ');
|
11402 | const containsZwsp = node => isString(node.nodeValue) && node.nodeValue.includes(ZWSP$1);
|
11403 | const getTemporaryNodeSelector = tempAttrs => `${ tempAttrs.length === 0 ? '' : `${ map$3(tempAttrs, attr => `[${ attr }]`).join(',') },` }[data-mce-bogus="all"]`;
|
11404 | const getTemporaryNodes = (tempAttrs, body) => body.querySelectorAll(getTemporaryNodeSelector(tempAttrs));
|
11405 | const createZwspCommentWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, node => containsZwsp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP);
|
11406 | const createUnescapedZwspTextWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_TEXT, node => {
|
11407 | if (containsZwsp(node)) {
|
11408 | const parent = node.parentNode;
|
11409 | return parent && has$2(unescapedTextParents, parent.nodeName) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
11410 | } else {
|
11411 | return NodeFilter.FILTER_SKIP;
|
11412 | }
|
11413 | });
|
11414 | const hasZwspComment = body => createZwspCommentWalker(body).nextNode() !== null;
|
11415 | const hasUnescapedZwspText = body => createUnescapedZwspTextWalker(body).nextNode() !== null;
|
11416 | const hasTemporaryNode = (tempAttrs, body) => body.querySelector(getTemporaryNodeSelector(tempAttrs)) !== null;
|
11417 | const trimTemporaryNodes = (tempAttrs, body) => {
|
11418 | each$e(getTemporaryNodes(tempAttrs, body), elm => {
|
11419 | const element = SugarElement.fromDom(elm);
|
11420 | if (get$9(element, 'data-mce-bogus') === 'all') {
|
11421 | remove$4(element);
|
11422 | } else {
|
11423 | each$e(tempAttrs, attr => {
|
11424 | if (has$1(element, attr)) {
|
11425 | remove$9(element, attr);
|
11426 | }
|
11427 | });
|
11428 | }
|
11429 | });
|
11430 | };
|
11431 | const emptyAllNodeValuesInWalker = walker => {
|
11432 | let curr = walker.nextNode();
|
11433 | while (curr !== null) {
|
11434 | curr.nodeValue = null;
|
11435 | curr = walker.nextNode();
|
11436 | }
|
11437 | };
|
11438 | const emptyZwspComments = compose(emptyAllNodeValuesInWalker, createZwspCommentWalker);
|
11439 | const emptyUnescapedZwspTexts = compose(emptyAllNodeValuesInWalker, createUnescapedZwspTextWalker);
|
11440 | const trim$1 = (body, tempAttrs) => {
|
11441 | const conditionalTrims = [
|
11442 | {
|
11443 | condition: curry(hasTemporaryNode, tempAttrs),
|
11444 | action: curry(trimTemporaryNodes, tempAttrs)
|
11445 | },
|
11446 | {
|
11447 | condition: hasZwspComment,
|
11448 | action: emptyZwspComments
|
11449 | },
|
11450 | {
|
11451 | condition: hasUnescapedZwspText,
|
11452 | action: emptyUnescapedZwspTexts
|
11453 | }
|
11454 | ];
|
11455 | let trimmed = body;
|
11456 | let cloned = false;
|
11457 | each$e(conditionalTrims, ({condition, action}) => {
|
11458 | if (condition(trimmed)) {
|
11459 | if (!cloned) {
|
11460 | trimmed = body.cloneNode(true);
|
11461 | cloned = true;
|
11462 | }
|
11463 | action(trimmed);
|
11464 | }
|
11465 | });
|
11466 | return trimmed;
|
11467 | };
|
11468 |
|
11469 | const cleanupBogusElements = parent => {
|
11470 | const bogusElements = descendants(parent, '[data-mce-bogus]');
|
11471 | each$e(bogusElements, elem => {
|
11472 | const bogusValue = get$9(elem, 'data-mce-bogus');
|
11473 | if (bogusValue === 'all') {
|
11474 | remove$4(elem);
|
11475 | } else if (isBr$5(elem)) {
|
11476 | before$3(elem, SugarElement.fromText(zeroWidth));
|
11477 | remove$4(elem);
|
11478 | } else {
|
11479 | unwrap(elem);
|
11480 | }
|
11481 | });
|
11482 | };
|
11483 | const cleanupInputNames = parent => {
|
11484 | const inputs = descendants(parent, 'input');
|
11485 | each$e(inputs, input => {
|
11486 | remove$9(input, 'name');
|
11487 | });
|
11488 | };
|
11489 |
|
11490 | const trimEmptyContents = (editor, html) => {
|
11491 | const blockName = getForcedRootBlock(editor);
|
11492 | const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>( | |\\s|\u00a0|<br \\/>|)<\\/${ blockName }>[\r\n]*|<br \\/>[\r\n]*)$`);
|
11493 | return html.replace(emptyRegExp, '');
|
11494 | };
|
11495 | const getPlainTextContent = (editor, body) => {
|
11496 | const doc = editor.getDoc();
|
11497 | const dos = getRootNode(SugarElement.fromDom(editor.getBody()));
|
11498 | const offscreenDiv = SugarElement.fromTag('div', doc);
|
11499 | set$3(offscreenDiv, 'data-mce-bogus', 'all');
|
11500 | setAll(offscreenDiv, {
|
11501 | position: 'fixed',
|
11502 | left: '-9999999px',
|
11503 | top: '0'
|
11504 | });
|
11505 | set$1(offscreenDiv, body.innerHTML);
|
11506 | cleanupBogusElements(offscreenDiv);
|
11507 | cleanupInputNames(offscreenDiv);
|
11508 | const root = getContentContainer(dos);
|
11509 | append$1(root, offscreenDiv);
|
11510 | const content = trim$2(offscreenDiv.dom.innerText);
|
11511 | remove$4(offscreenDiv);
|
11512 | return content;
|
11513 | };
|
11514 | const getContentFromBody = (editor, args, body) => {
|
11515 | let content;
|
11516 | if (args.format === 'raw') {
|
11517 | content = Tools.trim(trim$2(trim$1(body, editor.serializer.getTempAttrs()).innerHTML));
|
11518 | } else if (args.format === 'text') {
|
11519 | content = getPlainTextContent(editor, body);
|
11520 | } else if (args.format === 'tree') {
|
11521 | content = editor.serializer.serialize(body, args);
|
11522 | } else {
|
11523 | content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
|
11524 | }
|
11525 | const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body));
|
11526 | return shouldTrim && isString(content) ? Tools.trim(content) : content;
|
11527 | };
|
11528 | const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body));
|
11529 |
|
11530 | const makeMap$1 = Tools.makeMap;
|
11531 | const Writer = settings => {
|
11532 | const html = [];
|
11533 | settings = settings || {};
|
11534 | const indent = settings.indent;
|
11535 | const indentBefore = makeMap$1(settings.indent_before || '');
|
11536 | const indentAfter = makeMap$1(settings.indent_after || '');
|
11537 | const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
|
11538 | const htmlOutput = settings.element_format !== 'xhtml';
|
11539 | return {
|
11540 | start: (name, attrs, empty) => {
|
11541 | if (indent && indentBefore[name] && html.length > 0) {
|
11542 | const value = html[html.length - 1];
|
11543 | if (value.length > 0 && value !== '\n') {
|
11544 | html.push('\n');
|
11545 | }
|
11546 | }
|
11547 | html.push('<', name);
|
11548 | if (attrs) {
|
11549 | for (let i = 0, l = attrs.length; i < l; i++) {
|
11550 | const attr = attrs[i];
|
11551 | html.push(' ', attr.name, '="', encode(attr.value, true), '"');
|
11552 | }
|
11553 | }
|
11554 | if (!empty || htmlOutput) {
|
11555 | html[html.length] = '>';
|
11556 | } else {
|
11557 | html[html.length] = ' />';
|
11558 | }
|
11559 | if (empty && indent && indentAfter[name] && html.length > 0) {
|
11560 | const value = html[html.length - 1];
|
11561 | if (value.length > 0 && value !== '\n') {
|
11562 | html.push('\n');
|
11563 | }
|
11564 | }
|
11565 | },
|
11566 | end: name => {
|
11567 | let value;
|
11568 | html.push('</', name, '>');
|
11569 | if (indent && indentAfter[name] && html.length > 0) {
|
11570 | value = html[html.length - 1];
|
11571 | if (value.length > 0 && value !== '\n') {
|
11572 | html.push('\n');
|
11573 | }
|
11574 | }
|
11575 | },
|
11576 | text: (text, raw) => {
|
11577 | if (text.length > 0) {
|
11578 | html[html.length] = raw ? text : encode(text);
|
11579 | }
|
11580 | },
|
11581 | cdata: text => {
|
11582 | html.push('<![CDATA[', text, ']]>');
|
11583 | },
|
11584 | comment: text => {
|
11585 | html.push('<!--', text, '-->');
|
11586 | },
|
11587 | pi: (name, text) => {
|
11588 | if (text) {
|
11589 | html.push('<?', name, ' ', encode(text), '?>');
|
11590 | } else {
|
11591 | html.push('<?', name, '?>');
|
11592 | }
|
11593 | if (indent) {
|
11594 | html.push('\n');
|
11595 | }
|
11596 | },
|
11597 | doctype: text => {
|
11598 | html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
|
11599 | },
|
11600 | reset: () => {
|
11601 | html.length = 0;
|
11602 | },
|
11603 | getContent: () => {
|
11604 | return html.join('').replace(/\n$/, '');
|
11605 | }
|
11606 | };
|
11607 | };
|
11608 |
|
11609 | const HtmlSerializer = (settings = {}, schema = Schema()) => {
|
11610 | const writer = Writer(settings);
|
11611 | settings.validate = 'validate' in settings ? settings.validate : true;
|
11612 | const serialize = node => {
|
11613 | const validate = settings.validate;
|
11614 | const handlers = {
|
11615 | 3: node => {
|
11616 | var _a;
|
11617 | writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw);
|
11618 | },
|
11619 | 8: node => {
|
11620 | var _a;
|
11621 | writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : '');
|
11622 | },
|
11623 | 7: node => {
|
11624 | writer.pi(node.name, node.value);
|
11625 | },
|
11626 | 10: node => {
|
11627 | var _a;
|
11628 | writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : '');
|
11629 | },
|
11630 | 4: node => {
|
11631 | var _a;
|
11632 | writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : '');
|
11633 | },
|
11634 | 11: node => {
|
11635 | let tempNode = node;
|
11636 | if (tempNode = tempNode.firstChild) {
|
11637 | do {
|
11638 | walk(tempNode);
|
11639 | } while (tempNode = tempNode.next);
|
11640 | }
|
11641 | }
|
11642 | };
|
11643 | writer.reset();
|
11644 | const walk = node => {
|
11645 | var _a;
|
11646 | const handler = handlers[node.type];
|
11647 | if (!handler) {
|
11648 | const name = node.name;
|
11649 | const isEmpty = name in schema.getVoidElements();
|
11650 | let attrs = node.attributes;
|
11651 | if (validate && attrs && attrs.length > 1) {
|
11652 | const sortedAttrs = [];
|
11653 | sortedAttrs.map = {};
|
11654 | const elementRule = schema.getElementRule(node.name);
|
11655 | if (elementRule) {
|
11656 | for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
|
11657 | const attrName = elementRule.attributesOrder[i];
|
11658 | if (attrName in attrs.map) {
|
11659 | const attrValue = attrs.map[attrName];
|
11660 | sortedAttrs.map[attrName] = attrValue;
|
11661 | sortedAttrs.push({
|
11662 | name: attrName,
|
11663 | value: attrValue
|
11664 | });
|
11665 | }
|
11666 | }
|
11667 | for (let i = 0, l = attrs.length; i < l; i++) {
|
11668 | const attrName = attrs[i].name;
|
11669 | if (!(attrName in sortedAttrs.map)) {
|
11670 | const attrValue = attrs.map[attrName];
|
11671 | sortedAttrs.map[attrName] = attrValue;
|
11672 | sortedAttrs.push({
|
11673 | name: attrName,
|
11674 | value: attrValue
|
11675 | });
|
11676 | }
|
11677 | }
|
11678 | attrs = sortedAttrs;
|
11679 | }
|
11680 | }
|
11681 | writer.start(name, attrs, isEmpty);
|
11682 | if (isNonHtmlElementRootName(name)) {
|
11683 | if (isString(node.value)) {
|
11684 | writer.text(node.value, true);
|
11685 | }
|
11686 | writer.end(name);
|
11687 | } else {
|
11688 | if (!isEmpty) {
|
11689 | let child = node.firstChild;
|
11690 | if (child) {
|
11691 | if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') {
|
11692 | writer.text('\n', true);
|
11693 | }
|
11694 | do {
|
11695 | walk(child);
|
11696 | } while (child = child.next);
|
11697 | }
|
11698 | writer.end(name);
|
11699 | }
|
11700 | }
|
11701 | } else {
|
11702 | handler(node);
|
11703 | }
|
11704 | };
|
11705 | if (node.type === 1 && !settings.inner) {
|
11706 | walk(node);
|
11707 | } else if (node.type === 3) {
|
11708 | handlers[3](node);
|
11709 | } else {
|
11710 | handlers[11](node);
|
11711 | }
|
11712 | return writer.getContent();
|
11713 | };
|
11714 | return { serialize };
|
11715 | };
|
11716 |
|
11717 | const nonInheritableStyles = new Set();
|
11718 | (() => {
|
11719 | const nonInheritableStylesArr = [
|
11720 | 'margin',
|
11721 | 'margin-left',
|
11722 | 'margin-right',
|
11723 | 'margin-top',
|
11724 | 'margin-bottom',
|
11725 | 'padding',
|
11726 | 'padding-left',
|
11727 | 'padding-right',
|
11728 | 'padding-top',
|
11729 | 'padding-bottom',
|
11730 | 'border',
|
11731 | 'border-width',
|
11732 | 'border-style',
|
11733 | 'border-color',
|
11734 | 'background',
|
11735 | 'background-attachment',
|
11736 | 'background-clip',
|
11737 | 'background-color',
|
11738 | 'background-image',
|
11739 | 'background-origin',
|
11740 | 'background-position',
|
11741 | 'background-repeat',
|
11742 | 'background-size',
|
11743 | 'float',
|
11744 | 'position',
|
11745 | 'left',
|
11746 | 'right',
|
11747 | 'top',
|
11748 | 'bottom',
|
11749 | 'z-index',
|
11750 | 'display',
|
11751 | 'transform',
|
11752 | 'width',
|
11753 | 'max-width',
|
11754 | 'min-width',
|
11755 | 'height',
|
11756 | 'max-height',
|
11757 | 'min-height',
|
11758 | 'overflow',
|
11759 | 'overflow-x',
|
11760 | 'overflow-y',
|
11761 | 'text-overflow',
|
11762 | 'vertical-align',
|
11763 | 'transition',
|
11764 | 'transition-delay',
|
11765 | 'transition-duration',
|
11766 | 'transition-property',
|
11767 | 'transition-timing-function'
|
11768 | ];
|
11769 | each$e(nonInheritableStylesArr, style => {
|
11770 | nonInheritableStyles.add(style);
|
11771 | });
|
11772 | })();
|
11773 | const shorthandStyleProps = [
|
11774 | 'font',
|
11775 | 'text-decoration',
|
11776 | 'text-emphasis'
|
11777 | ];
|
11778 | const getStyleProps = (dom, node) => keys(dom.parseStyle(dom.getAttrib(node, 'style')));
|
11779 | const isNonInheritableStyle = style => nonInheritableStyles.has(style);
|
11780 | const hasInheritableStyles = (dom, node) => forall(getStyleProps(dom, node), style => !isNonInheritableStyle(style));
|
11781 | const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop)));
|
11782 | const hasStyleConflict = (dom, node, parentNode) => {
|
11783 | const nodeStyleProps = getStyleProps(dom, node);
|
11784 | const parentNodeStyleProps = getStyleProps(dom, parentNode);
|
11785 | const valueMismatch = prop => {
|
11786 | var _a, _b;
|
11787 | const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : '';
|
11788 | const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : '';
|
11789 | return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
|
11790 | };
|
11791 | return exists(nodeStyleProps, nodeStyleProp => {
|
11792 | const propExists = props => exists(props, prop => prop === nodeStyleProp);
|
11793 | if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
|
11794 | const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
|
11795 | return exists(longhandProps, valueMismatch);
|
11796 | } else {
|
11797 | return valueMismatch(nodeStyleProp);
|
11798 | }
|
11799 | });
|
11800 | };
|
11801 |
|
11802 | const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$b).exists(text => {
|
11803 | const delta = forward ? 0 : -1;
|
11804 | return predicate(text.data.charAt(pos.offset() + delta));
|
11805 | });
|
11806 | const isBeforeSpace = curry(isChar, true, isWhiteSpace);
|
11807 | const isAfterSpace = curry(isChar, false, isWhiteSpace);
|
11808 | const isEmptyText = pos => {
|
11809 | const container = pos.container();
|
11810 | return isText$b(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
|
11811 | };
|
11812 | const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome();
|
11813 | const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block';
|
11814 | const isCefNode = node => isContentEditableFalse$b(node) && !isBogusAll(node);
|
11815 | const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
|
11816 | const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
|
11817 | const isBeforeMedia = matchesElementPosition(true, isMedia$2);
|
11818 | const isAfterMedia = matchesElementPosition(false, isMedia$2);
|
11819 | const isBeforeTable = matchesElementPosition(true, isTable$2);
|
11820 | const isAfterTable = matchesElementPosition(false, isTable$2);
|
11821 | const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
|
11822 | const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
|
11823 |
|
11824 | const dropLast = xs => xs.slice(0, -1);
|
11825 | const parentsUntil = (start, root, predicate) => {
|
11826 | if (contains(root, start)) {
|
11827 | return dropLast(parents$1(start, elm => {
|
11828 | return predicate(elm) || eq(elm, root);
|
11829 | }));
|
11830 | } else {
|
11831 | return [];
|
11832 | }
|
11833 | };
|
11834 | const parents = (start, root) => parentsUntil(start, root, never);
|
11835 | const parentsAndSelf = (start, root) => [start].concat(parents(start, root));
|
11836 |
|
11837 | const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText);
|
11838 | const isBlock$1 = schema => el => schema.isBlock(name(el));
|
11839 | const getClosestBlock$1 = (root, pos, schema) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$1(schema));
|
11840 | const isAtBeforeAfterBlockBoundary = (forward, root, pos, schema) => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => getClosestBlock$1(root, pos, schema).fold(() => !isInSameBlock(newPos, pos, root.dom), fromBlock => !isInSameBlock(newPos, pos, root.dom) && contains(fromBlock, SugarElement.fromDom(newPos.container()))));
|
11841 | const isAtBlockBoundary = (forward, root, pos, schema) => getClosestBlock$1(root, pos, schema).fold(() => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => !isInSameBlock(newPos, pos, root.dom)), parent => navigateIgnoreEmptyTextNodes(forward, parent.dom, pos).isNone());
|
11842 | const isAtStartOfBlock = curry(isAtBlockBoundary, false);
|
11843 | const isAtEndOfBlock = curry(isAtBlockBoundary, true);
|
11844 | const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
|
11845 | const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
|
11846 |
|
11847 | const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5);
|
11848 | const findBr = (forward, root, pos, schema) => {
|
11849 | const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
|
11850 | const scope = head(parentBlocks).getOr(root);
|
11851 | return fromPosition(forward, scope.dom, pos).filter(isBr$1);
|
11852 | };
|
11853 | const isBeforeBr$1 = (root, pos, schema) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos, schema).isSome();
|
11854 | const isAfterBr = (root, pos, schema) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos, schema).isSome();
|
11855 | const findPreviousBr = curry(findBr, false);
|
11856 | const findNextBr = curry(findBr, true);
|
11857 |
|
11858 | const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
|
11859 | const getClosestBlock = (root, pos, schema) => {
|
11860 | const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
|
11861 | return head(parentBlocks).getOr(root);
|
11862 | };
|
11863 | const hasSpaceBefore = (root, pos, schema) => {
|
11864 | if (isInMiddleOfText(pos)) {
|
11865 | return isAfterSpace(pos);
|
11866 | } else {
|
11867 | return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isAfterSpace);
|
11868 | }
|
11869 | };
|
11870 | const hasSpaceAfter = (root, pos, schema) => {
|
11871 | if (isInMiddleOfText(pos)) {
|
11872 | return isBeforeSpace(pos);
|
11873 | } else {
|
11874 | return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isBeforeSpace);
|
11875 | }
|
11876 | };
|
11877 | const isPreValue = value => contains$2([
|
11878 | 'pre',
|
11879 | 'pre-wrap'
|
11880 | ], value);
|
11881 | const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space')));
|
11882 | const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
|
11883 | const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
|
11884 | const isAtLineBoundary = (root, pos, schema) => isAtBeginningOfBody(root, pos) || isAtEndOfBody(root, pos) || isAtStartOfBlock(root, pos, schema) || isAtEndOfBlock(root, pos, schema) || isAfterBr(root, pos, schema) || isBeforeBr$1(root, pos, schema);
|
11885 | const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node);
|
11886 | const isSiblingCefBlock = (root, direction) => container => {
|
11887 | return isCefBlock(new DomTreeWalker(container, root)[direction]());
|
11888 | };
|
11889 | const isBeforeCefBlock = (root, pos) => {
|
11890 | const nextPos = nextPosition(root.dom, pos).getOr(pos);
|
11891 | const isNextCefBlock = isSiblingCefBlock(root.dom, 'next');
|
11892 | return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
|
11893 | };
|
11894 | const isAfterCefBlock = (root, pos) => {
|
11895 | const prevPos = prevPosition(root.dom, pos).getOr(pos);
|
11896 | const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev');
|
11897 | return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container()));
|
11898 | };
|
11899 | const needsToHaveNbsp = (root, pos, schema) => {
|
11900 | if (isInPre(pos)) {
|
11901 | return false;
|
11902 | } else {
|
11903 | return isAtLineBoundary(root, pos, schema) || hasSpaceBefore(root, pos, schema) || hasSpaceAfter(root, pos, schema);
|
11904 | }
|
11905 | };
|
11906 | const needsToBeNbspLeft = (root, pos, schema) => {
|
11907 | if (isInPre(pos)) {
|
11908 | return false;
|
11909 | } else {
|
11910 | return isAtStartOfBlock(root, pos, schema) || isBeforeBlock(root, pos, schema) || isAfterBr(root, pos, schema) || hasSpaceBefore(root, pos, schema) || isAfterCefBlock(root, pos);
|
11911 | }
|
11912 | };
|
11913 | const leanRight = pos => {
|
11914 | const container = pos.container();
|
11915 | const offset = pos.offset();
|
11916 | if (isText$b(container) && offset < container.data.length) {
|
11917 | return CaretPosition(container, offset + 1);
|
11918 | } else {
|
11919 | return pos;
|
11920 | }
|
11921 | };
|
11922 | const needsToBeNbspRight = (root, pos, schema) => {
|
11923 | if (isInPre(pos)) {
|
11924 | return false;
|
11925 | } else {
|
11926 | return isAtEndOfBlock(root, pos, schema) || isAfterBlock(root, pos, schema) || isBeforeBr$1(root, pos, schema) || hasSpaceAfter(root, pos, schema) || isBeforeCefBlock(root, pos);
|
11927 | }
|
11928 | };
|
11929 | const needsToBeNbsp = (root, pos, schema) => needsToBeNbspLeft(root, pos, schema) || needsToBeNbspRight(root, leanRight(pos), schema);
|
11930 | const isNbspAt = (text, offset) => isNbsp(text.charAt(offset));
|
11931 | const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset));
|
11932 | const hasNbsp = pos => {
|
11933 | const container = pos.container();
|
11934 | return isText$b(container) && contains$1(container.data, nbsp);
|
11935 | };
|
11936 | const normalizeNbspMiddle = text => {
|
11937 | const chars = text.split('');
|
11938 | return map$3(chars, (chr, i) => {
|
11939 | if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
|
11940 | return ' ';
|
11941 | } else {
|
11942 | return chr;
|
11943 | }
|
11944 | }).join('');
|
11945 | };
|
11946 | const normalizeNbspAtStart = (root, node, makeNbsp, schema) => {
|
11947 | const text = node.data;
|
11948 | const firstPos = CaretPosition(node, 0);
|
11949 | if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos, schema)) {
|
11950 | node.data = ' ' + text.slice(1);
|
11951 | return true;
|
11952 | } else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos, schema)) {
|
11953 | node.data = nbsp + text.slice(1);
|
11954 | return true;
|
11955 | } else {
|
11956 | return false;
|
11957 | }
|
11958 | };
|
11959 | const normalizeNbspInMiddleOfTextNode = node => {
|
11960 | const text = node.data;
|
11961 | const newText = normalizeNbspMiddle(text);
|
11962 | if (newText !== text) {
|
11963 | node.data = newText;
|
11964 | return true;
|
11965 | } else {
|
11966 | return false;
|
11967 | }
|
11968 | };
|
11969 | const normalizeNbspAtEnd = (root, node, makeNbsp, schema) => {
|
11970 | const text = node.data;
|
11971 | const lastPos = CaretPosition(node, text.length - 1);
|
11972 | if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos, schema)) {
|
11973 | node.data = text.slice(0, -1) + ' ';
|
11974 | return true;
|
11975 | } else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos, schema)) {
|
11976 | node.data = text.slice(0, -1) + nbsp;
|
11977 | return true;
|
11978 | } else {
|
11979 | return false;
|
11980 | }
|
11981 | };
|
11982 | const normalizeNbsps = (root, pos, schema) => {
|
11983 | const container = pos.container();
|
11984 | if (!isText$b(container)) {
|
11985 | return Optional.none();
|
11986 | }
|
11987 | if (hasNbsp(pos)) {
|
11988 | const normalized = normalizeNbspAtStart(root, container, false, schema) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false, schema);
|
11989 | return someIf(normalized, pos);
|
11990 | } else if (needsToBeNbsp(root, pos, schema)) {
|
11991 | const normalized = normalizeNbspAtStart(root, container, true, schema) || normalizeNbspAtEnd(root, container, true, schema);
|
11992 | return someIf(normalized, pos);
|
11993 | } else {
|
11994 | return Optional.none();
|
11995 | }
|
11996 | };
|
11997 | const normalizeNbspsInEditor = editor => {
|
11998 | const root = SugarElement.fromDom(editor.getBody());
|
11999 | if (editor.selection.isCollapsed()) {
|
12000 | normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
|
12001 | editor.selection.setRng(pos.toRange());
|
12002 | });
|
12003 | }
|
12004 | };
|
12005 |
|
12006 | const normalize$1 = (node, offset, count, schema) => {
|
12007 | if (count === 0) {
|
12008 | return;
|
12009 | }
|
12010 | const elm = SugarElement.fromDom(node);
|
12011 | const root = ancestor$4(elm, el => schema.isBlock(name(el))).getOr(elm);
|
12012 | const whitespace = node.data.slice(offset, offset + count);
|
12013 | const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length), schema);
|
12014 | const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0), schema);
|
12015 | node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
|
12016 | };
|
12017 | const normalizeWhitespaceAfter = (node, offset, schema) => {
|
12018 | const content = node.data.slice(offset);
|
12019 | const whitespaceCount = content.length - lTrim(content).length;
|
12020 | normalize$1(node, offset, whitespaceCount, schema);
|
12021 | };
|
12022 | const normalizeWhitespaceBefore = (node, offset, schema) => {
|
12023 | const content = node.data.slice(0, offset);
|
12024 | const whitespaceCount = content.length - rTrim(content).length;
|
12025 | normalize$1(node, offset - whitespaceCount, whitespaceCount, schema);
|
12026 | };
|
12027 | const mergeTextNodes = (prevNode, nextNode, schema, normalizeWhitespace, mergeToPrev = true) => {
|
12028 | const whitespaceOffset = rTrim(prevNode.data).length;
|
12029 | const newNode = mergeToPrev ? prevNode : nextNode;
|
12030 | const removeNode = mergeToPrev ? nextNode : prevNode;
|
12031 | if (mergeToPrev) {
|
12032 | newNode.appendData(removeNode.data);
|
12033 | } else {
|
12034 | newNode.insertData(0, removeNode.data);
|
12035 | }
|
12036 | remove$4(SugarElement.fromDom(removeNode));
|
12037 | if (normalizeWhitespace) {
|
12038 | normalizeWhitespaceAfter(newNode, whitespaceOffset, schema);
|
12039 | }
|
12040 | return newNode;
|
12041 | };
|
12042 |
|
12043 | const needsReposition = (pos, elm) => {
|
12044 | const container = pos.container();
|
12045 | const offset = pos.offset();
|
12046 | return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
|
12047 | };
|
12048 | const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
|
12049 | const beforeOrStartOf = node => isText$b(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
|
12050 | const afterOrEndOf = node => isText$b(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
|
12051 | const getPreviousSiblingCaretPosition = elm => {
|
12052 | if (isCaretCandidate$3(elm.previousSibling)) {
|
12053 | return Optional.some(afterOrEndOf(elm.previousSibling));
|
12054 | } else {
|
12055 | return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
|
12056 | }
|
12057 | };
|
12058 | const getNextSiblingCaretPosition = elm => {
|
12059 | if (isCaretCandidate$3(elm.nextSibling)) {
|
12060 | return Optional.some(beforeOrStartOf(elm.nextSibling));
|
12061 | } else {
|
12062 | return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
|
12063 | }
|
12064 | };
|
12065 | const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
|
12066 | return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm)));
|
12067 | };
|
12068 | const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm)));
|
12069 | const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
|
12070 | const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
|
12071 | const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
|
12072 | const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
|
12073 | const setSelection$1 = (editor, forward, pos) => {
|
12074 | pos.fold(() => {
|
12075 | editor.focus();
|
12076 | }, pos => {
|
12077 | editor.selection.setRng(pos.toRange(), forward);
|
12078 | });
|
12079 | };
|
12080 | const eqRawNode = rawNode => elm => elm.dom === rawNode;
|
12081 | const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
|
12082 | const paddEmptyBlock = (schema, elm, preserveEmptyCaret) => {
|
12083 | if (isEmpty$2(schema, elm)) {
|
12084 | const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
|
12085 | if (preserveEmptyCaret) {
|
12086 | each$e(children$1(elm), node => {
|
12087 | if (!isEmptyCaretFormatElement(node)) {
|
12088 | remove$4(node);
|
12089 | }
|
12090 | });
|
12091 | } else {
|
12092 | empty(elm);
|
12093 | }
|
12094 | append$1(elm, br);
|
12095 | return Optional.some(CaretPosition.before(br.dom));
|
12096 | } else {
|
12097 | return Optional.none();
|
12098 | }
|
12099 | };
|
12100 | const deleteNormalized = (elm, afterDeletePosOpt, schema, normalizeWhitespace) => {
|
12101 | const prevTextOpt = prevSibling(elm).filter(isText$c);
|
12102 | const nextTextOpt = nextSibling(elm).filter(isText$c);
|
12103 | remove$4(elm);
|
12104 | return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => {
|
12105 | const prevNode = prev.dom, nextNode = next.dom;
|
12106 | const offset = prevNode.data.length;
|
12107 | mergeTextNodes(prevNode, nextNode, schema, normalizeWhitespace);
|
12108 | return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
|
12109 | }).orThunk(() => {
|
12110 | if (normalizeWhitespace) {
|
12111 | prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length, schema));
|
12112 | nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0, schema));
|
12113 | }
|
12114 | return afterDeletePosOpt;
|
12115 | });
|
12116 | };
|
12117 | const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
|
12118 | const deleteElement$2 = (editor, forward, elm, moveCaret = true, preserveEmptyCaret = false) => {
|
12119 | const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
|
12120 | const parentBlock = ancestor$4(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
|
12121 | const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, editor.schema, isInlineElement(editor, elm));
|
12122 | if (editor.dom.isEmpty(editor.getBody())) {
|
12123 | editor.setContent('');
|
12124 | editor.selection.setCursorLocation();
|
12125 | } else {
|
12126 | parentBlock.bind(elm => paddEmptyBlock(editor.schema, elm, preserveEmptyCaret)).fold(() => {
|
12127 | if (moveCaret) {
|
12128 | setSelection$1(editor, forward, normalizedAfterDeletePos);
|
12129 | }
|
12130 | }, paddPos => {
|
12131 | if (moveCaret) {
|
12132 | setSelection$1(editor, forward, Optional.some(paddPos));
|
12133 | }
|
12134 | });
|
12135 | }
|
12136 | };
|
12137 |
|
12138 | const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
|
12139 | const hasStrongRtl = text => strongRtl.test(text);
|
12140 |
|
12141 | const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm) && editor.dom.isEditable(elm);
|
12142 | const isRtl = element => {
|
12143 | var _a;
|
12144 | return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : '');
|
12145 | };
|
12146 | const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
|
12147 | const findRootInline = (isInlineTarget, rootNode, pos) => {
|
12148 | const parents = findInlineParents(isInlineTarget, rootNode, pos);
|
12149 | return Optional.from(parents[parents.length - 1]);
|
12150 | };
|
12151 | const hasSameParentBlock = (rootNode, node1, node2) => {
|
12152 | const block1 = getParentBlock$3(node1, rootNode);
|
12153 | const block2 = getParentBlock$3(node2, rootNode);
|
12154 | return isNonNullable(block1) && block1 === block2;
|
12155 | };
|
12156 | const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos);
|
12157 | const normalizePosition = (forward, pos) => {
|
12158 | const container = pos.container(), offset = pos.offset();
|
12159 | if (forward) {
|
12160 | if (isCaretContainerInline(container)) {
|
12161 | if (isText$b(container.nextSibling)) {
|
12162 | return CaretPosition(container.nextSibling, 0);
|
12163 | } else {
|
12164 | return CaretPosition.after(container);
|
12165 | }
|
12166 | } else {
|
12167 | return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
|
12168 | }
|
12169 | } else {
|
12170 | if (isCaretContainerInline(container)) {
|
12171 | if (isText$b(container.previousSibling)) {
|
12172 | return CaretPosition(container.previousSibling, container.previousSibling.data.length);
|
12173 | } else {
|
12174 | return CaretPosition.before(container);
|
12175 | }
|
12176 | } else {
|
12177 | return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
|
12178 | }
|
12179 | }
|
12180 | };
|
12181 | const normalizeForwards = curry(normalizePosition, true);
|
12182 | const normalizeBackwards = curry(normalizePosition, false);
|
12183 |
|
12184 | const execCommandIgnoreInputEvents = (editor, command) => {
|
12185 | const inputBlocker = e => e.stopImmediatePropagation();
|
12186 | editor.on('beforeinput input', inputBlocker, true);
|
12187 | editor.getDoc().execCommand(command);
|
12188 | editor.off('beforeinput input', inputBlocker);
|
12189 | };
|
12190 | const execEditorDeleteCommand = editor => {
|
12191 | editor.execCommand('delete');
|
12192 | };
|
12193 | const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete');
|
12194 | const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete');
|
12195 | const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq);
|
12196 | const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element);
|
12197 | const getParentBlock$2 = (rootNode, elm) => {
|
12198 | if (contains(rootNode, elm)) {
|
12199 | return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
|
12200 | } else {
|
12201 | return Optional.none();
|
12202 | }
|
12203 | };
|
12204 | const paddEmptyBody = (editor, moveSelection = true) => {
|
12205 | if (editor.dom.isEmpty(editor.getBody())) {
|
12206 | editor.setContent('', { no_selection: !moveSelection });
|
12207 | }
|
12208 | };
|
12209 | const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
|
12210 | const normalizedFirstPos = normalizePosition(true, firstPos);
|
12211 | const normalizedLastPos = normalizePosition(false, lastPos);
|
12212 | const normalizedFromPos = normalizePosition(false, fromPos);
|
12213 | if (forward) {
|
12214 | return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
|
12215 | } else {
|
12216 | return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
|
12217 | }
|
12218 | }).getOr(true);
|
12219 | const freefallRtl = root => {
|
12220 | const child = isComment$1(root) ? prevSibling(root) : lastChild(root);
|
12221 | return child.bind(freefallRtl).orThunk(() => Optional.some(root));
|
12222 | };
|
12223 | const deleteRangeContents = (editor, rng, root, moveSelection = true) => {
|
12224 | var _a;
|
12225 | rng.deleteContents();
|
12226 | const lastNode = freefallRtl(root).getOr(root);
|
12227 | const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom);
|
12228 | if (lastBlock.dom === editor.getBody()) {
|
12229 | paddEmptyBody(editor, moveSelection);
|
12230 | } else if (isEmpty$2(editor.schema, lastBlock, { checkRootAsContent: false })) {
|
12231 | fillWithPaddingBr(lastBlock);
|
12232 | if (moveSelection) {
|
12233 | editor.selection.setCursorLocation(lastBlock.dom, 0);
|
12234 | }
|
12235 | }
|
12236 | if (!eq(root, lastBlock)) {
|
12237 | const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
|
12238 | each$e(additionalCleanupNodes.concat(children$1(root)), node => {
|
12239 | if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(editor.schema, node)) {
|
12240 | remove$4(node);
|
12241 | }
|
12242 | });
|
12243 | }
|
12244 | };
|
12245 |
|
12246 | const isRootFromElement = root => cur => eq(root, cur);
|
12247 | const getTableCells = table => descendants(table, 'td,th');
|
12248 | const getTable$1 = (node, isRoot) => getClosestTable(SugarElement.fromDom(node), isRoot);
|
12249 | const selectionInTableWithNestedTable = details => {
|
12250 | return lift2(details.startTable, details.endTable, (startTable, endTable) => {
|
12251 | const isStartTableParentOfEndTable = descendant(startTable, t => eq(t, endTable));
|
12252 | const isEndTableParentOfStartTable = descendant(endTable, t => eq(t, startTable));
|
12253 | return !isStartTableParentOfEndTable && !isEndTableParentOfStartTable ? details : {
|
12254 | ...details,
|
12255 | startTable: isStartTableParentOfEndTable ? Optional.none() : details.startTable,
|
12256 | endTable: isEndTableParentOfStartTable ? Optional.none() : details.endTable,
|
12257 | isSameTable: false,
|
12258 | isMultiTable: false
|
12259 | };
|
12260 | }).getOr(details);
|
12261 | };
|
12262 | const adjustQuirksInDetails = details => {
|
12263 | return selectionInTableWithNestedTable(details);
|
12264 | };
|
12265 | const getTableDetailsFromRange = (rng, isRoot) => {
|
12266 | const startTable = getTable$1(rng.startContainer, isRoot);
|
12267 | const endTable = getTable$1(rng.endContainer, isRoot);
|
12268 | const isStartInTable = startTable.isSome();
|
12269 | const isEndInTable = endTable.isSome();
|
12270 | const isSameTable = lift2(startTable, endTable, eq).getOr(false);
|
12271 | const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
|
12272 | return adjustQuirksInDetails({
|
12273 | startTable,
|
12274 | endTable,
|
12275 | isStartInTable,
|
12276 | isEndInTable,
|
12277 | isSameTable,
|
12278 | isMultiTable
|
12279 | });
|
12280 | };
|
12281 |
|
12282 | const tableCellRng = (start, end) => ({
|
12283 | start,
|
12284 | end
|
12285 | });
|
12286 | const tableSelection = (rng, table, cells) => ({
|
12287 | rng,
|
12288 | table,
|
12289 | cells
|
12290 | });
|
12291 | const deleteAction = Adt.generate([
|
12292 | {
|
12293 | singleCellTable: [
|
12294 | 'rng',
|
12295 | 'cell'
|
12296 | ]
|
12297 | },
|
12298 | { fullTable: ['table'] },
|
12299 | {
|
12300 | partialTable: [
|
12301 | 'cells',
|
12302 | 'outsideDetails'
|
12303 | ]
|
12304 | },
|
12305 | {
|
12306 | multiTable: [
|
12307 | 'startTableCells',
|
12308 | 'endTableCells',
|
12309 | 'betweenRng'
|
12310 | ]
|
12311 | }
|
12312 | ]);
|
12313 | const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
|
12314 | const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end);
|
12315 | const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable)));
|
12316 | const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => {
|
12317 | const rows = table.dom.rows;
|
12318 | return rows.length === 1 && rows[0].cells.length === 1;
|
12319 | });
|
12320 | const getCellRng = (rng, isRoot) => {
|
12321 | const startCell = getClosestCell$1(rng.startContainer, isRoot);
|
12322 | const endCell = getClosestCell$1(rng.endContainer, isRoot);
|
12323 | return lift2(startCell, endCell, tableCellRng);
|
12324 | };
|
12325 | const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$2(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell)));
|
12326 | const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell)));
|
12327 | const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table)));
|
12328 | const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => {
|
12329 | if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
|
12330 | return Optional.none();
|
12331 | } else if (selectionDetails.isSameTable) {
|
12332 | const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot));
|
12333 | return Optional.some({
|
12334 | start: sameTableSelection,
|
12335 | end: sameTableSelection
|
12336 | });
|
12337 | } else {
|
12338 | const startCell = getClosestCell$1(rng.startContainer, isRoot);
|
12339 | const endCell = getClosestCell$1(rng.endContainer, isRoot);
|
12340 | const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
|
12341 | const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
|
12342 | return Optional.some({
|
12343 | start: startTableSelection,
|
12344 | end: endTableSelection
|
12345 | });
|
12346 | }
|
12347 | };
|
12348 | const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell));
|
12349 | const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1));
|
12350 | const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng));
|
12351 | const unselectCells = (rng, selectionDetails) => {
|
12352 | const {startTable, endTable} = selectionDetails;
|
12353 | const otherContentRng = rng.cloneRange();
|
12354 | startTable.each(table => otherContentRng.setStartAfter(table.dom));
|
12355 | endTable.each(table => otherContentRng.setEndBefore(table.dom));
|
12356 | return otherContentRng;
|
12357 | };
|
12358 | const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => {
|
12359 | const {isSameTable} = selectionDetails;
|
12360 | const selectedCells = getSelectedCells(tableSelection).getOr([]);
|
12361 | if (isSameTable && tableSelection.cells.length === selectedCells.length) {
|
12362 | return Optional.some(deleteAction.fullTable(tableSelection.table));
|
12363 | } else if (selectedCells.length > 0) {
|
12364 | if (isSameTable) {
|
12365 | return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
|
12366 | } else {
|
12367 | const otherContentRng = unselectCells(rng, selectionDetails);
|
12368 | return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
|
12369 | ...selectionDetails,
|
12370 | rng: otherContentRng
|
12371 | })));
|
12372 | }
|
12373 | } else {
|
12374 | return Optional.none();
|
12375 | }
|
12376 | });
|
12377 | const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => {
|
12378 | const startTableSelectedCells = start.bind(getSelectedCells).getOr([]);
|
12379 | const endTableSelectedCells = end.bind(getSelectedCells).getOr([]);
|
12380 | if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
|
12381 | const otherContentRng = unselectCells(rng, selectionDetails);
|
12382 | return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
|
12383 | } else {
|
12384 | return Optional.none();
|
12385 | }
|
12386 | });
|
12387 | const getActionFromRange = (root, rng) => {
|
12388 | const isRoot = isRootFromElement(root);
|
12389 | const optCellRng = getCellRng(rng, isRoot);
|
12390 | const selectionDetails = getTableDetailsFromRange(rng, isRoot);
|
12391 | if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) {
|
12392 | return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start));
|
12393 | } else if (selectionDetails.isMultiTable) {
|
12394 | return handleMultiTable(optCellRng, selectionDetails, rng, isRoot);
|
12395 | } else {
|
12396 | return handleSingleTable(optCellRng, selectionDetails, rng, isRoot);
|
12397 | }
|
12398 | };
|
12399 |
|
12400 | const cleanCells = cells => each$e(cells, cell => {
|
12401 | remove$9(cell, 'contenteditable');
|
12402 | fillWithPaddingBr(cell);
|
12403 | });
|
12404 | const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
|
12405 | const handleEmptyBlock = (editor, startInTable, emptyBlock) => {
|
12406 | emptyBlock.each(block => {
|
12407 | if (startInTable) {
|
12408 | remove$4(block);
|
12409 | } else {
|
12410 | fillWithPaddingBr(block);
|
12411 | editor.selection.setCursorLocation(block.dom, 0);
|
12412 | }
|
12413 | });
|
12414 | };
|
12415 | const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => {
|
12416 | const insideTableRng = rng.cloneRange();
|
12417 | if (isFirstCellInSelection) {
|
12418 | insideTableRng.setStart(rng.startContainer, rng.startOffset);
|
12419 | insideTableRng.setEndAfter(cell.dom.lastChild);
|
12420 | } else {
|
12421 | insideTableRng.setStartBefore(cell.dom.firstChild);
|
12422 | insideTableRng.setEnd(rng.endContainer, rng.endOffset);
|
12423 | }
|
12424 | deleteCellContents(editor, insideTableRng, cell, false).each(action => action());
|
12425 | };
|
12426 | const collapseAndRestoreCellSelection = editor => {
|
12427 | const selectedCells = getCellsFromEditor(editor);
|
12428 | const selectedNode = SugarElement.fromDom(editor.selection.getNode());
|
12429 | if (isTableCell$3(selectedNode.dom) && isEmpty$2(editor.schema, selectedNode)) {
|
12430 | editor.selection.setCursorLocation(selectedNode.dom, 0);
|
12431 | } else {
|
12432 | editor.selection.collapse(true);
|
12433 | }
|
12434 | if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) {
|
12435 | set$3(selectedNode, 'data-mce-selected', '1');
|
12436 | }
|
12437 | };
|
12438 | const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => {
|
12439 | const editorRng = editor.selection.getRng();
|
12440 | const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => {
|
12441 | const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
|
12442 | rng.deleteContents();
|
12443 | handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(curry(isEmpty$2, editor.schema)));
|
12444 | const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1];
|
12445 | deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
|
12446 | if (!isEmpty$2(editor.schema, endPointCell)) {
|
12447 | return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1));
|
12448 | } else {
|
12449 | return Optional.none();
|
12450 | }
|
12451 | }).getOr(cells);
|
12452 | cleanCells(cellsToClean);
|
12453 | collapseAndRestoreCellSelection(editor);
|
12454 | });
|
12455 | const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
|
12456 | const rng = editor.selection.getRng();
|
12457 | const startCell = startTableCells[0];
|
12458 | const endCell = endTableCells[endTableCells.length - 1];
|
12459 | deleteContentInsideCell(editor, startCell, rng, true);
|
12460 | deleteContentInsideCell(editor, endCell, rng, false);
|
12461 | const startTableCellsToClean = isEmpty$2(editor.schema, startCell) ? startTableCells : startTableCells.slice(1);
|
12462 | const endTableCellsToClean = isEmpty$2(editor.schema, endCell) ? endTableCells : endTableCells.slice(0, -1);
|
12463 | cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
|
12464 | betweenRng.deleteContents();
|
12465 | collapseAndRestoreCellSelection(editor);
|
12466 | });
|
12467 | const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => {
|
12468 | deleteRangeContents(editor, rng, cell, moveSelection);
|
12469 | });
|
12470 | const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table));
|
12471 | const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
|
12472 | const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
|
12473 | const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption));
|
12474 | const deleteRange$3 = (editor, startElm, selectedCells) => {
|
12475 | const rootNode = SugarElement.fromDom(editor.getBody());
|
12476 | const rng = editor.selection.getRng();
|
12477 | return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
|
12478 | };
|
12479 | const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2);
|
12480 | const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption'));
|
12481 | const deleteBetweenCells = (editor, rootElm, forward, fromCell, from) => navigate(forward, editor.getBody(), from).bind(to => getParentCell(rootElm, SugarElement.fromDom(to.getNode())).bind(toCell => eq(toCell, fromCell) ? Optional.none() : Optional.some(noop)));
|
12482 | const emptyElement = (editor, elm) => Optional.some(() => {
|
12483 | fillWithPaddingBr(elm);
|
12484 | editor.selection.setCursorLocation(elm.dom, 0);
|
12485 | });
|
12486 | const isDeleteOfLastCharPos = (fromCaption, forward, from, to) => firstPositionIn(fromCaption.dom).bind(first => lastPositionIn(fromCaption.dom).map(last => forward ? from.isEqual(first) && to.isEqual(last) : from.isEqual(last) && to.isEqual(first))).getOr(true);
|
12487 | const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
|
12488 | const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop));
|
12489 | const deleteCaretInsideCaption = (editor, rootElm, forward, fromCaption, from) => navigate(forward, editor.getBody(), from).fold(() => Optional.some(noop), to => isDeleteOfLastCharPos(fromCaption, forward, from, to) ? emptyCaretCaption(editor, fromCaption) : validateCaretCaption(rootElm, fromCaption, to));
|
12490 | const deleteCaretCells = (editor, forward, rootElm, startElm) => {
|
12491 | const from = CaretPosition.fromRangeStart(editor.selection.getRng());
|
12492 | return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(editor.schema, fromCell, { checkRootAsContent: false }) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from));
|
12493 | };
|
12494 | const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
|
12495 | const from = CaretPosition.fromRangeStart(editor.selection.getRng());
|
12496 | return isEmpty$2(editor.schema, fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
|
12497 | };
|
12498 | const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
|
12499 | const isBeforeOrAfterTable = (editor, forward) => {
|
12500 | const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
12501 | return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos));
|
12502 | };
|
12503 | const deleteCaret$3 = (editor, forward, startElm) => {
|
12504 | const rootElm = SugarElement.fromDom(editor.getBody());
|
12505 | return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption));
|
12506 | };
|
12507 | const backspaceDelete$a = (editor, forward) => {
|
12508 | const startElm = SugarElement.fromDom(editor.selection.getStart(true));
|
12509 | const cells = getCellsFromEditor(editor);
|
12510 | return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$3(editor, startElm, cells);
|
12511 | };
|
12512 |
|
12513 | const getContentEditableRoot$1 = (root, node) => {
|
12514 | let tempNode = node;
|
12515 | while (tempNode && tempNode !== root) {
|
12516 | if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$b(tempNode)) {
|
12517 | return tempNode;
|
12518 | }
|
12519 | tempNode = tempNode.parentNode;
|
12520 | }
|
12521 | return null;
|
12522 | };
|
12523 |
|
12524 | const internalAttributesPrefixes = [
|
12525 | 'data-ephox-',
|
12526 | 'data-mce-',
|
12527 | 'data-alloy-',
|
12528 | 'data-snooker-',
|
12529 | '_'
|
12530 | ];
|
12531 | const each$9 = Tools.each;
|
12532 | const ElementUtils = editor => {
|
12533 | const dom = editor.dom;
|
12534 | const internalAttributes = new Set(editor.serializer.getTempAttrs());
|
12535 | const compare = (node1, node2) => {
|
12536 | if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) {
|
12537 | return false;
|
12538 | }
|
12539 | const getAttribs = node => {
|
12540 | const attribs = {};
|
12541 | each$9(dom.getAttribs(node), attr => {
|
12542 | const name = attr.nodeName.toLowerCase();
|
12543 | if (name !== 'style' && !isAttributeInternal(name)) {
|
12544 | attribs[name] = dom.getAttrib(node, name);
|
12545 | }
|
12546 | });
|
12547 | return attribs;
|
12548 | };
|
12549 | const compareObjects = (obj1, obj2) => {
|
12550 | for (const name in obj1) {
|
12551 | if (has$2(obj1, name)) {
|
12552 | const value = obj2[name];
|
12553 | if (isUndefined(value)) {
|
12554 | return false;
|
12555 | }
|
12556 | if (obj1[name] !== value) {
|
12557 | return false;
|
12558 | }
|
12559 | delete obj2[name];
|
12560 | }
|
12561 | }
|
12562 | for (const name in obj2) {
|
12563 | if (has$2(obj2, name)) {
|
12564 | return false;
|
12565 | }
|
12566 | }
|
12567 | return true;
|
12568 | };
|
12569 | if (isElement$6(node1) && isElement$6(node2)) {
|
12570 | if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
|
12571 | return false;
|
12572 | }
|
12573 | if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
|
12574 | return false;
|
12575 | }
|
12576 | }
|
12577 | return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
|
12578 | };
|
12579 | const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName);
|
12580 | return {
|
12581 | compare,
|
12582 | isAttributeInternal
|
12583 | };
|
12584 | };
|
12585 |
|
12586 | const isHeading = node => [
|
12587 | 'h1',
|
12588 | 'h2',
|
12589 | 'h3',
|
12590 | 'h4',
|
12591 | 'h5',
|
12592 | 'h6'
|
12593 | ].includes(node.name);
|
12594 | const isSummary = node => node.name === 'summary';
|
12595 |
|
12596 | const traverse = (root, fn) => {
|
12597 | let node = root;
|
12598 | while (node = node.walk()) {
|
12599 | fn(node);
|
12600 | }
|
12601 | };
|
12602 | const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
|
12603 | const name = node.name;
|
12604 | for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
|
12605 | const filter = nodeFilters[ni];
|
12606 | if (filter.name === name) {
|
12607 | const match = matches.nodes[name];
|
12608 | if (match) {
|
12609 | match.nodes.push(node);
|
12610 | } else {
|
12611 | matches.nodes[name] = {
|
12612 | filter,
|
12613 | nodes: [node]
|
12614 | };
|
12615 | }
|
12616 | }
|
12617 | }
|
12618 | if (node.attributes) {
|
12619 | for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
|
12620 | const filter = attributeFilters[ai];
|
12621 | const attrName = filter.name;
|
12622 | if (attrName in node.attributes.map) {
|
12623 | const match = matches.attributes[attrName];
|
12624 | if (match) {
|
12625 | match.nodes.push(node);
|
12626 | } else {
|
12627 | matches.attributes[attrName] = {
|
12628 | filter,
|
12629 | nodes: [node]
|
12630 | };
|
12631 | }
|
12632 | }
|
12633 | }
|
12634 | }
|
12635 | };
|
12636 | const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
|
12637 | const matches = {
|
12638 | nodes: {},
|
12639 | attributes: {}
|
12640 | };
|
12641 | if (node.firstChild) {
|
12642 | traverse(node, childNode => {
|
12643 | matchNode$1(nodeFilters, attributeFilters, childNode, matches);
|
12644 | });
|
12645 | }
|
12646 | return matches;
|
12647 | };
|
12648 | const runFilters = (matches, args) => {
|
12649 | const run = (matchRecord, filteringAttributes) => {
|
12650 | each$d(matchRecord, match => {
|
12651 | const nodes = from(match.nodes);
|
12652 | each$e(match.filter.callbacks, callback => {
|
12653 | for (let i = nodes.length - 1; i >= 0; i--) {
|
12654 | const node = nodes[i];
|
12655 | const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name;
|
12656 | if (!valueMatches || isNullable(node.parent)) {
|
12657 | nodes.splice(i, 1);
|
12658 | }
|
12659 | }
|
12660 | if (nodes.length > 0) {
|
12661 | callback(nodes, match.filter.name, args);
|
12662 | }
|
12663 | });
|
12664 | });
|
12665 | };
|
12666 | run(matches.nodes, false);
|
12667 | run(matches.attributes, true);
|
12668 | };
|
12669 | const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => {
|
12670 | const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
|
12671 | runFilters(matches, args);
|
12672 | };
|
12673 |
|
12674 | const paddEmptyNode = (settings, args, isBlock, node) => {
|
12675 | const brPreferred = settings.pad_empty_with_br || args.insert;
|
12676 | if (brPreferred && isBlock(node)) {
|
12677 | const astNode = new AstNode('br', 1);
|
12678 | if (args.insert) {
|
12679 | astNode.attr('data-mce-bogus', '1');
|
12680 | }
|
12681 | node.empty().append(astNode);
|
12682 | } else {
|
12683 | node.empty().append(new AstNode('#text', 3)).value = nbsp;
|
12684 | }
|
12685 | };
|
12686 | const isPaddedWithNbsp = node => {
|
12687 | var _a;
|
12688 | return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp;
|
12689 | };
|
12690 | const hasOnlyChild = (node, name) => {
|
12691 | const firstChild = node === null || node === void 0 ? void 0 : node.firstChild;
|
12692 | return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name;
|
12693 | };
|
12694 | const isPadded = (schema, node) => {
|
12695 | const rule = schema.getElementRule(node.name);
|
12696 | return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true;
|
12697 | };
|
12698 | const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node));
|
12699 | const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br');
|
12700 | const findClosestEditingHost = scope => {
|
12701 | let editableNode;
|
12702 | for (let node = scope; node; node = node.parent) {
|
12703 | const contentEditable = node.attr('contenteditable');
|
12704 | if (contentEditable === 'false') {
|
12705 | break;
|
12706 | } else if (contentEditable === 'true') {
|
12707 | editableNode = node;
|
12708 | }
|
12709 | }
|
12710 | return Optional.from(editableNode);
|
12711 | };
|
12712 |
|
12713 | const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
|
12714 | if (schema.getSpecialElements()[node.name]) {
|
12715 | node.empty().remove();
|
12716 | } else {
|
12717 | const children = node.children();
|
12718 | for (const childNode of children) {
|
12719 | if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) {
|
12720 | removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
|
12721 | }
|
12722 | }
|
12723 | node.unwrap();
|
12724 | }
|
12725 | };
|
12726 | const cleanInvalidNodes = (nodes, schema, rootNode, onCreate = noop) => {
|
12727 | const textBlockElements = schema.getTextBlockElements();
|
12728 | const nonEmptyElements = schema.getNonEmptyElements();
|
12729 | const whitespaceElements = schema.getWhitespaceElements();
|
12730 | const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table,summary');
|
12731 | const fixed = new Set();
|
12732 | const isSplittableElement = node => node !== rootNode && !nonSplittableElements[node.name];
|
12733 | for (let ni = 0; ni < nodes.length; ni++) {
|
12734 | const node = nodes[ni];
|
12735 | let parent;
|
12736 | let newParent;
|
12737 | let tempNode;
|
12738 | if (!node.parent || fixed.has(node)) {
|
12739 | continue;
|
12740 | }
|
12741 | if (textBlockElements[node.name] && node.parent.name === 'li') {
|
12742 | let sibling = node.next;
|
12743 | while (sibling) {
|
12744 | if (textBlockElements[sibling.name]) {
|
12745 | sibling.name = 'li';
|
12746 | fixed.add(sibling);
|
12747 | node.parent.insert(sibling, node.parent);
|
12748 | } else {
|
12749 | break;
|
12750 | }
|
12751 | sibling = sibling.next;
|
12752 | }
|
12753 | node.unwrap();
|
12754 | continue;
|
12755 | }
|
12756 | const parents = [node];
|
12757 | for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && isSplittableElement(parent); parent = parent.parent) {
|
12758 | parents.push(parent);
|
12759 | }
|
12760 | if (parent && parents.length > 1) {
|
12761 | if (!isInvalid(schema, node, parent)) {
|
12762 | parents.reverse();
|
12763 | newParent = parents[0].clone();
|
12764 | onCreate(newParent);
|
12765 | let currentNode = newParent;
|
12766 | for (let i = 0; i < parents.length - 1; i++) {
|
12767 | if (schema.isValidChild(currentNode.name, parents[i].name) && i > 0) {
|
12768 | tempNode = parents[i].clone();
|
12769 | onCreate(tempNode);
|
12770 | currentNode.append(tempNode);
|
12771 | } else {
|
12772 | tempNode = currentNode;
|
12773 | }
|
12774 | for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
|
12775 | const nextNode = childNode.next;
|
12776 | tempNode.append(childNode);
|
12777 | childNode = nextNode;
|
12778 | }
|
12779 | currentNode = tempNode;
|
12780 | }
|
12781 | if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
|
12782 | parent.insert(newParent, parents[0], true);
|
12783 | parent.insert(node, newParent);
|
12784 | } else {
|
12785 | parent.insert(node, parents[0], true);
|
12786 | }
|
12787 | parent = parents[0];
|
12788 | if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
|
12789 | parent.empty().remove();
|
12790 | }
|
12791 | } else {
|
12792 | removeOrUnwrapInvalidNode(node, schema);
|
12793 | }
|
12794 | } else if (node.parent) {
|
12795 | if (node.name === 'li') {
|
12796 | let sibling = node.prev;
|
12797 | if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) {
|
12798 | sibling.append(node);
|
12799 | continue;
|
12800 | }
|
12801 | sibling = node.next;
|
12802 | if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) {
|
12803 | sibling.insert(node, sibling.firstChild, true);
|
12804 | continue;
|
12805 | }
|
12806 | const wrapper = new AstNode('ul', 1);
|
12807 | onCreate(wrapper);
|
12808 | node.wrap(wrapper);
|
12809 | continue;
|
12810 | }
|
12811 | if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
|
12812 | const wrapper = new AstNode('div', 1);
|
12813 | onCreate(wrapper);
|
12814 | node.wrap(wrapper);
|
12815 | } else {
|
12816 | removeOrUnwrapInvalidNode(node, schema);
|
12817 | }
|
12818 | }
|
12819 | }
|
12820 | };
|
12821 | const hasClosest = (node, parentName) => {
|
12822 | let tempNode = node;
|
12823 | while (tempNode) {
|
12824 | if (tempNode.name === parentName) {
|
12825 | return true;
|
12826 | }
|
12827 | tempNode = tempNode.parent;
|
12828 | }
|
12829 | return false;
|
12830 | };
|
12831 | const isInvalid = (schema, node, parent = node.parent) => {
|
12832 | if (!parent) {
|
12833 | return false;
|
12834 | }
|
12835 | if (schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) {
|
12836 | return true;
|
12837 | }
|
12838 | if (node.name === 'a' && hasClosest(parent, 'a')) {
|
12839 | return true;
|
12840 | }
|
12841 | if (isSummary(parent) && isHeading(node)) {
|
12842 | return !((parent === null || parent === void 0 ? void 0 : parent.firstChild) === node && (parent === null || parent === void 0 ? void 0 : parent.lastChild) === node);
|
12843 | }
|
12844 | return false;
|
12845 | };
|
12846 |
|
12847 | const createRange = (sc, so, ec, eo) => {
|
12848 | const rng = document.createRange();
|
12849 | rng.setStart(sc, so);
|
12850 | rng.setEnd(ec, eo);
|
12851 | return rng;
|
12852 | };
|
12853 | const normalizeBlockSelectionRange = rng => {
|
12854 | const startPos = CaretPosition.fromRangeStart(rng);
|
12855 | const endPos = CaretPosition.fromRangeEnd(rng);
|
12856 | const rootNode = rng.commonAncestorContainer;
|
12857 | return fromPosition(false, rootNode, endPos).map(newEndPos => {
|
12858 | if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
|
12859 | return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
|
12860 | } else {
|
12861 | return rng;
|
12862 | }
|
12863 | }).getOr(rng);
|
12864 | };
|
12865 | const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
|
12866 |
|
12867 | const hasOnlyOneChild$1 = node => {
|
12868 | return isNonNullable(node.firstChild) && node.firstChild === node.lastChild;
|
12869 | };
|
12870 | const isPaddingNode = node => {
|
12871 | return node.name === 'br' || node.value === nbsp;
|
12872 | };
|
12873 | const isPaddedEmptyBlock = (schema, node) => {
|
12874 | const blockElements = schema.getBlockElements();
|
12875 | return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
|
12876 | };
|
12877 | const isEmptyFragmentElement = (schema, node) => {
|
12878 | const nonEmptyElements = schema.getNonEmptyElements();
|
12879 | return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
|
12880 | };
|
12881 | const isListFragment = (schema, fragment) => {
|
12882 | let firstChild = fragment.firstChild;
|
12883 | let lastChild = fragment.lastChild;
|
12884 | if (firstChild && firstChild.name === 'meta') {
|
12885 | firstChild = firstChild.next;
|
12886 | }
|
12887 | if (lastChild && lastChild.attr('id') === 'mce_marker') {
|
12888 | lastChild = lastChild.prev;
|
12889 | }
|
12890 | if (isEmptyFragmentElement(schema, lastChild)) {
|
12891 | lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev;
|
12892 | }
|
12893 | if (!firstChild || firstChild !== lastChild) {
|
12894 | return false;
|
12895 | }
|
12896 | return firstChild.name === 'ul' || firstChild.name === 'ol';
|
12897 | };
|
12898 | const cleanupDomFragment = domFragment => {
|
12899 | var _a, _b;
|
12900 | const firstChild = domFragment.firstChild;
|
12901 | const lastChild = domFragment.lastChild;
|
12902 | if (firstChild && firstChild.nodeName === 'META') {
|
12903 | (_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild);
|
12904 | }
|
12905 | if (lastChild && lastChild.id === 'mce_marker') {
|
12906 | (_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild);
|
12907 | }
|
12908 | return domFragment;
|
12909 | };
|
12910 | const toDomFragment = (dom, serializer, fragment) => {
|
12911 | const html = serializer.serialize(fragment);
|
12912 | const domFragment = dom.createFragment(html);
|
12913 | return cleanupDomFragment(domFragment);
|
12914 | };
|
12915 | const listItems = elm => {
|
12916 | var _a;
|
12917 | return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => {
|
12918 | return child.nodeName === 'LI';
|
12919 | });
|
12920 | };
|
12921 | const isPadding = node => {
|
12922 | return node.data === nbsp || isBr$6(node);
|
12923 | };
|
12924 | const isListItemPadded = node => {
|
12925 | return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild);
|
12926 | };
|
12927 | const isEmptyOrPadded = elm => {
|
12928 | return !elm.firstChild || isListItemPadded(elm);
|
12929 | };
|
12930 | const trimListItems = elms => {
|
12931 | return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
|
12932 | };
|
12933 | const getParentLi = (dom, node) => {
|
12934 | const parentBlock = dom.getParent(node, dom.isBlock);
|
12935 | return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
|
12936 | };
|
12937 | const isParentBlockLi = (dom, node) => {
|
12938 | return !!getParentLi(dom, node);
|
12939 | };
|
12940 | const getSplit = (parentNode, rng) => {
|
12941 | const beforeRng = rng.cloneRange();
|
12942 | const afterRng = rng.cloneRange();
|
12943 | beforeRng.setStartBefore(parentNode);
|
12944 | afterRng.setEndAfter(parentNode);
|
12945 | return [
|
12946 | beforeRng.cloneContents(),
|
12947 | afterRng.cloneContents()
|
12948 | ];
|
12949 | };
|
12950 | const findFirstIn = (node, rootNode) => {
|
12951 | const caretPos = CaretPosition.before(node);
|
12952 | const caretWalker = CaretWalker(rootNode);
|
12953 | const newCaretPos = caretWalker.next(caretPos);
|
12954 | return newCaretPos ? newCaretPos.toRange() : null;
|
12955 | };
|
12956 | const findLastOf = (node, rootNode) => {
|
12957 | const caretPos = CaretPosition.after(node);
|
12958 | const caretWalker = CaretWalker(rootNode);
|
12959 | const newCaretPos = caretWalker.prev(caretPos);
|
12960 | return newCaretPos ? newCaretPos.toRange() : null;
|
12961 | };
|
12962 | const insertMiddle = (target, elms, rootNode, rng) => {
|
12963 | const parts = getSplit(target, rng);
|
12964 | const parentElm = target.parentNode;
|
12965 | if (parentElm) {
|
12966 | parentElm.insertBefore(parts[0], target);
|
12967 | Tools.each(elms, li => {
|
12968 | parentElm.insertBefore(li, target);
|
12969 | });
|
12970 | parentElm.insertBefore(parts[1], target);
|
12971 | parentElm.removeChild(target);
|
12972 | }
|
12973 | return findLastOf(elms[elms.length - 1], rootNode);
|
12974 | };
|
12975 | const insertBefore$2 = (target, elms, rootNode) => {
|
12976 | const parentElm = target.parentNode;
|
12977 | if (parentElm) {
|
12978 | Tools.each(elms, elm => {
|
12979 | parentElm.insertBefore(elm, target);
|
12980 | });
|
12981 | }
|
12982 | return findFirstIn(target, rootNode);
|
12983 | };
|
12984 | const insertAfter$2 = (target, elms, rootNode, dom) => {
|
12985 | dom.insertAfter(elms.reverse(), target);
|
12986 | return findLastOf(elms[0], rootNode);
|
12987 | };
|
12988 | const insertAtCaret$1 = (serializer, dom, rng, fragment) => {
|
12989 | const domFragment = toDomFragment(dom, serializer, fragment);
|
12990 | const liTarget = getParentLi(dom, rng.startContainer);
|
12991 | const liElms = trimListItems(listItems(domFragment.firstChild));
|
12992 | const BEGINNING = 1, END = 2;
|
12993 | const rootNode = dom.getRoot();
|
12994 | const isAt = location => {
|
12995 | const caretPos = CaretPosition.fromRangeStart(rng);
|
12996 | const caretWalker = CaretWalker(dom.getRoot());
|
12997 | const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
|
12998 | const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode();
|
12999 | return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true;
|
13000 | };
|
13001 | if (!liTarget) {
|
13002 | return null;
|
13003 | } else if (isAt(BEGINNING)) {
|
13004 | return insertBefore$2(liTarget, liElms, rootNode);
|
13005 | } else if (isAt(END)) {
|
13006 | return insertAfter$2(liTarget, liElms, rootNode, dom);
|
13007 | } else {
|
13008 | return insertMiddle(liTarget, liElms, rootNode, rng);
|
13009 | }
|
13010 | };
|
13011 |
|
13012 | const mergeableWrappedElements = ['pre'];
|
13013 | const shouldPasteContentOnly = (dom, fragment, parentNode, root) => {
|
13014 | var _a;
|
13015 | const firstNode = fragment.firstChild;
|
13016 | const lastNode = fragment.lastChild;
|
13017 | const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode;
|
13018 | const isPastingSingleElement = firstNode === last;
|
13019 | const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name);
|
13020 | if (isPastingSingleElement && isWrappedElement) {
|
13021 | const isContentEditable = firstNode.attr('contenteditable') !== 'false';
|
13022 | const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name;
|
13023 | const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3);
|
13024 | return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable;
|
13025 | } else {
|
13026 | return false;
|
13027 | }
|
13028 | };
|
13029 | const isTableCell = isTableCell$3;
|
13030 | const isTableCellContentSelected = (dom, rng, cell) => {
|
13031 | if (isNonNullable(cell)) {
|
13032 | const endCell = dom.getParent(rng.endContainer, isTableCell);
|
13033 | return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng);
|
13034 | } else {
|
13035 | return false;
|
13036 | }
|
13037 | };
|
13038 | const validInsertion = (editor, value, parentNode) => {
|
13039 | var _a;
|
13040 | if (parentNode.getAttribute('data-mce-bogus') === 'all') {
|
13041 | (_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode);
|
13042 | } else {
|
13043 | const node = parentNode.firstChild;
|
13044 | const node2 = parentNode.lastChild;
|
13045 | if (!node || node === node2 && node.nodeName === 'BR') {
|
13046 | editor.dom.setHTML(parentNode, value);
|
13047 | } else {
|
13048 | editor.selection.setContent(value, { no_events: true });
|
13049 | }
|
13050 | }
|
13051 | };
|
13052 | const trimBrsFromTableCell = (dom, elm, schema) => {
|
13053 | Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(el => trimBlockTrailingBr(el, schema));
|
13054 | };
|
13055 | const reduceInlineTextElements = (editor, merge) => {
|
13056 | const textInlineElements = editor.schema.getTextInlineElements();
|
13057 | const dom = editor.dom;
|
13058 | if (merge) {
|
13059 | const root = editor.getBody();
|
13060 | const elementUtils = ElementUtils(editor);
|
13061 | Tools.each(dom.select('*[data-mce-fragment]'), node => {
|
13062 | const isInline = isNonNullable(textInlineElements[node.nodeName.toLowerCase()]);
|
13063 | if (isInline && hasInheritableStyles(dom, node)) {
|
13064 | for (let parentNode = node.parentElement; isNonNullable(parentNode) && parentNode !== root; parentNode = parentNode.parentElement) {
|
13065 | const styleConflict = hasStyleConflict(dom, node, parentNode);
|
13066 | if (styleConflict) {
|
13067 | break;
|
13068 | }
|
13069 | if (elementUtils.compare(parentNode, node)) {
|
13070 | dom.remove(node, true);
|
13071 | break;
|
13072 | }
|
13073 | }
|
13074 | }
|
13075 | });
|
13076 | }
|
13077 | };
|
13078 | const markFragmentElements = fragment => {
|
13079 | let node = fragment;
|
13080 | while (node = node.walk()) {
|
13081 | if (node.type === 1) {
|
13082 | node.attr('data-mce-fragment', '1');
|
13083 | }
|
13084 | }
|
13085 | };
|
13086 | const unmarkFragmentElements = elm => {
|
13087 | Tools.each(elm.getElementsByTagName('*'), elm => {
|
13088 | elm.removeAttribute('data-mce-fragment');
|
13089 | });
|
13090 | };
|
13091 | const isPartOfFragment = node => {
|
13092 | return !!node.getAttribute('data-mce-fragment');
|
13093 | };
|
13094 | const canHaveChildren = (editor, node) => {
|
13095 | return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName];
|
13096 | };
|
13097 | const moveSelectionToMarker = (editor, marker) => {
|
13098 | var _a, _b, _c;
|
13099 | let nextRng;
|
13100 | const dom = editor.dom;
|
13101 | const selection = editor.selection;
|
13102 | if (!marker) {
|
13103 | return;
|
13104 | }
|
13105 | selection.scrollIntoView(marker);
|
13106 | const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
|
13107 | if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') {
|
13108 | dom.remove(marker);
|
13109 | selection.select(parentEditableElm);
|
13110 | return;
|
13111 | }
|
13112 | let rng = dom.createRng();
|
13113 | const node = marker.previousSibling;
|
13114 | if (isText$b(node)) {
|
13115 | rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
|
13116 | const node2 = marker.nextSibling;
|
13117 | if (isText$b(node2)) {
|
13118 | node.appendData(node2.data);
|
13119 | (_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2);
|
13120 | }
|
13121 | } else {
|
13122 | rng.setStartBefore(marker);
|
13123 | rng.setEndBefore(marker);
|
13124 | }
|
13125 | const findNextCaretRng = rng => {
|
13126 | let caretPos = CaretPosition.fromRangeStart(rng);
|
13127 | const caretWalker = CaretWalker(editor.getBody());
|
13128 | caretPos = caretWalker.next(caretPos);
|
13129 | return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange();
|
13130 | };
|
13131 | const parentBlock = dom.getParent(marker, dom.isBlock);
|
13132 | dom.remove(marker);
|
13133 | if (parentBlock && dom.isEmpty(parentBlock)) {
|
13134 | const isCell = isTableCell(parentBlock);
|
13135 | empty(SugarElement.fromDom(parentBlock));
|
13136 | rng.setStart(parentBlock, 0);
|
13137 | rng.setEnd(parentBlock, 0);
|
13138 | if (!isCell && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
|
13139 | rng = nextRng;
|
13140 | dom.remove(parentBlock);
|
13141 | } else {
|
13142 | dom.add(parentBlock, dom.create('br', isCell ? {} : { 'data-mce-bogus': '1' }));
|
13143 | }
|
13144 | }
|
13145 | selection.setRng(rng);
|
13146 | };
|
13147 | const deleteSelectedContent = editor => {
|
13148 | const dom = editor.dom;
|
13149 | const rng = normalize(editor.selection.getRng());
|
13150 | editor.selection.setRng(rng);
|
13151 | const startCell = dom.getParent(rng.startContainer, isTableCell);
|
13152 | if (isTableCellContentSelected(dom, rng, startCell)) {
|
13153 | deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
|
13154 | } else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$b(rng.startContainer.childNodes[rng.startOffset])) {
|
13155 | rng.deleteContents();
|
13156 | } else {
|
13157 | editor.getDoc().execCommand('Delete', false);
|
13158 | }
|
13159 | };
|
13160 | const findMarkerNode = scope => {
|
13161 | for (let markerNode = scope; markerNode; markerNode = markerNode.walk()) {
|
13162 | if (markerNode.attr('id') === 'mce_marker') {
|
13163 | return Optional.some(markerNode);
|
13164 | }
|
13165 | }
|
13166 | return Optional.none();
|
13167 | };
|
13168 | const notHeadingsInSummary = (dom, node, fragment) => {
|
13169 | var _a;
|
13170 | return exists(fragment.children(), isHeading) && ((_a = dom.getParent(node, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName) === 'SUMMARY';
|
13171 | };
|
13172 | const insertHtmlAtCaret = (editor, value, details) => {
|
13173 | var _a, _b;
|
13174 | const selection = editor.selection;
|
13175 | const dom = editor.dom;
|
13176 | const parser = editor.parser;
|
13177 | const merge = details.merge;
|
13178 | const serializer = HtmlSerializer({ validate: true }, editor.schema);
|
13179 | const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark"></span>';
|
13180 | if (!details.preserve_zwsp) {
|
13181 | value = trim$2(value);
|
13182 | }
|
13183 | if (value.indexOf('{$caret}') === -1) {
|
13184 | value += '{$caret}';
|
13185 | }
|
13186 | value = value.replace(/\{\$caret\}/, bookmarkHtml);
|
13187 | let rng = selection.getRng();
|
13188 | const caretElement = rng.startContainer;
|
13189 | const body = editor.getBody();
|
13190 | if (caretElement === body && selection.isCollapsed()) {
|
13191 | if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
|
13192 | rng = dom.createRng();
|
13193 | rng.setStart(body.firstChild, 0);
|
13194 | rng.setEnd(body.firstChild, 0);
|
13195 | selection.setRng(rng);
|
13196 | }
|
13197 | }
|
13198 | if (!selection.isCollapsed()) {
|
13199 | deleteSelectedContent(editor);
|
13200 | }
|
13201 | const parentNode = selection.getNode();
|
13202 | const parserArgs = {
|
13203 | context: parentNode.nodeName.toLowerCase(),
|
13204 | data: details.data,
|
13205 | insert: true
|
13206 | };
|
13207 | const fragment = parser.parse(value, parserArgs);
|
13208 | if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) {
|
13209 | rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment);
|
13210 | if (rng) {
|
13211 | selection.setRng(rng);
|
13212 | }
|
13213 | return value;
|
13214 | }
|
13215 | if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) {
|
13216 | (_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap();
|
13217 | }
|
13218 | markFragmentElements(fragment);
|
13219 | let node = fragment.lastChild;
|
13220 | if (node && node.attr('id') === 'mce_marker') {
|
13221 | const marker = node;
|
13222 | for (node = node.prev; node; node = node.walk(true)) {
|
13223 | if (node.type === 3 || !dom.isBlock(node.name)) {
|
13224 | if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
|
13225 | node.parent.insert(marker, node, node.name === 'br');
|
13226 | }
|
13227 | break;
|
13228 | }
|
13229 | }
|
13230 | }
|
13231 | editor._selectionOverrides.showBlockCaretContainer(parentNode);
|
13232 | if (!parserArgs.invalid && !notHeadingsInSummary(dom, parentNode, fragment)) {
|
13233 | value = serializer.serialize(fragment);
|
13234 | validInsertion(editor, value, parentNode);
|
13235 | } else {
|
13236 | editor.selection.setContent(bookmarkHtml);
|
13237 | let parentNode = selection.getNode();
|
13238 | let tempNode;
|
13239 | const rootNode = editor.getBody();
|
13240 | if (isDocument$1(parentNode)) {
|
13241 | parentNode = tempNode = rootNode;
|
13242 | } else {
|
13243 | tempNode = parentNode;
|
13244 | }
|
13245 | while (tempNode && tempNode !== rootNode) {
|
13246 | parentNode = tempNode;
|
13247 | tempNode = tempNode.parentNode;
|
13248 | }
|
13249 | value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
|
13250 | const root = parser.parse(value);
|
13251 | const markerNode = findMarkerNode(root);
|
13252 | const editingHost = markerNode.bind(findClosestEditingHost).getOr(root);
|
13253 | markerNode.each(marker => marker.replace(fragment));
|
13254 | const toExtract = fragment.children();
|
13255 | const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root;
|
13256 | fragment.unwrap();
|
13257 | const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent));
|
13258 | cleanInvalidNodes(invalidChildren, editor.schema, editingHost);
|
13259 | filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root);
|
13260 | value = serializer.serialize(root);
|
13261 | if (parentNode === rootNode) {
|
13262 | dom.setHTML(rootNode, value);
|
13263 | } else {
|
13264 | dom.setOuterHTML(parentNode, value);
|
13265 | }
|
13266 | }
|
13267 | reduceInlineTextElements(editor, merge);
|
13268 | moveSelectionToMarker(editor, dom.get('mce_marker'));
|
13269 | unmarkFragmentElements(editor.getBody());
|
13270 | trimBrsFromTableCell(dom, selection.getStart(), editor.schema);
|
13271 | updateCaret(editor.schema, editor.getBody(), selection.getStart());
|
13272 | return value;
|
13273 | };
|
13274 |
|
13275 | const isTreeNode = content => content instanceof AstNode;
|
13276 |
|
13277 | const moveSelection = editor => {
|
13278 | if (hasFocus(editor)) {
|
13279 | firstPositionIn(editor.getBody()).each(pos => {
|
13280 | const node = pos.getNode();
|
13281 | const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
|
13282 | editor.selection.setRng(caretPos.toRange());
|
13283 | });
|
13284 | }
|
13285 | };
|
13286 | const setEditorHtml = (editor, html, noSelection) => {
|
13287 | editor.dom.setHTML(editor.getBody(), html);
|
13288 | if (noSelection !== true) {
|
13289 | moveSelection(editor);
|
13290 | }
|
13291 | };
|
13292 | const setContentString = (editor, body, content, args) => {
|
13293 | content = trim$2(content);
|
13294 | if (content.length === 0 || /^\s+$/.test(content)) {
|
13295 | const padd = '<br data-mce-bogus="1">';
|
13296 | if (body.nodeName === 'TABLE') {
|
13297 | content = '<tr><td>' + padd + '</td></tr>';
|
13298 | } else if (/^(UL|OL)$/.test(body.nodeName)) {
|
13299 | content = '<li>' + padd + '</li>';
|
13300 | }
|
13301 | const forcedRootBlockName = getForcedRootBlock(editor);
|
13302 | if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
|
13303 | content = padd;
|
13304 | content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
|
13305 | } else if (!content) {
|
13306 | content = padd;
|
13307 | }
|
13308 | setEditorHtml(editor, content, args.no_selection);
|
13309 | return {
|
13310 | content,
|
13311 | html: content
|
13312 | };
|
13313 | } else {
|
13314 | if (args.format !== 'raw') {
|
13315 | content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
|
13316 | isRootContent: true,
|
13317 | insert: true
|
13318 | }));
|
13319 | }
|
13320 | const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
|
13321 | setEditorHtml(editor, trimmedHtml, args.no_selection);
|
13322 | return {
|
13323 | content: trimmedHtml,
|
13324 | html: trimmedHtml
|
13325 | };
|
13326 | }
|
13327 | };
|
13328 | const setContentTree = (editor, body, content, args) => {
|
13329 | filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
|
13330 | const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
|
13331 | const trimmedHtml = trim$2(isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html));
|
13332 | setEditorHtml(editor, trimmedHtml, args.no_selection);
|
13333 | return {
|
13334 | content,
|
13335 | html: trimmedHtml
|
13336 | };
|
13337 | };
|
13338 | const setContentInternal = (editor, content, args) => {
|
13339 | return Optional.from(editor.getBody()).map(body => {
|
13340 | if (isTreeNode(content)) {
|
13341 | return setContentTree(editor, body, content, args);
|
13342 | } else {
|
13343 | return setContentString(editor, body, content, args);
|
13344 | }
|
13345 | }).getOr({
|
13346 | content,
|
13347 | html: isTreeNode(args.content) ? '' : args.content
|
13348 | });
|
13349 | };
|
13350 |
|
13351 | const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
|
13352 | const ancestor = (scope, transform, isRoot) => {
|
13353 | let element = scope.dom;
|
13354 | const stop = ensureIsRoot(isRoot);
|
13355 | while (element.parentNode) {
|
13356 | element = element.parentNode;
|
13357 | const el = SugarElement.fromDom(element);
|
13358 | const transformed = transform(el);
|
13359 | if (transformed.isSome()) {
|
13360 | return transformed;
|
13361 | } else if (stop(el)) {
|
13362 | break;
|
13363 | }
|
13364 | }
|
13365 | return Optional.none();
|
13366 | };
|
13367 | const closest$1 = (scope, transform, isRoot) => {
|
13368 | const current = transform(scope);
|
13369 | const stop = ensureIsRoot(isRoot);
|
13370 | return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop));
|
13371 | };
|
13372 |
|
13373 | const isEq$3 = isEq$5;
|
13374 | const matchesUnInheritedFormatSelector = (ed, node, name) => {
|
13375 | const formatList = ed.formatter.get(name);
|
13376 | if (formatList) {
|
13377 | for (let i = 0; i < formatList.length; i++) {
|
13378 | const format = formatList[i];
|
13379 | if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
|
13380 | return true;
|
13381 | }
|
13382 | }
|
13383 | }
|
13384 | return false;
|
13385 | };
|
13386 | const matchParents = (editor, node, name, vars, similar) => {
|
13387 | const root = editor.dom.getRoot();
|
13388 | if (node === root) {
|
13389 | return false;
|
13390 | }
|
13391 | const matchedNode = editor.dom.getParent(node, elm => {
|
13392 | if (matchesUnInheritedFormatSelector(editor, elm, name)) {
|
13393 | return true;
|
13394 | }
|
13395 | return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true);
|
13396 | });
|
13397 | return !!matchNode(editor, matchedNode, name, vars, similar);
|
13398 | };
|
13399 | const matchName = (dom, node, format) => {
|
13400 | if (isInlineFormat(format) && isEq$3(node, format.inline)) {
|
13401 | return true;
|
13402 | }
|
13403 | if (isBlockFormat(format) && isEq$3(node, format.block)) {
|
13404 | return true;
|
13405 | }
|
13406 | if (isSelectorFormat(format)) {
|
13407 | return isElement$6(node) && dom.is(node, format.selector);
|
13408 | }
|
13409 | return false;
|
13410 | };
|
13411 | const matchItems = (dom, node, format, itemName, similar, vars) => {
|
13412 | const items = format[itemName];
|
13413 | const matchAttributes = itemName === 'attributes';
|
13414 | if (isFunction(format.onmatch)) {
|
13415 | return format.onmatch(node, format, itemName);
|
13416 | }
|
13417 | if (items) {
|
13418 | if (!isArrayLike(items)) {
|
13419 | for (const key in items) {
|
13420 | if (has$2(items, key)) {
|
13421 | const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key);
|
13422 | const expectedValue = replaceVars(items[key], vars);
|
13423 | const isEmptyValue = isNullable(value) || isEmpty$3(value);
|
13424 | if (isEmptyValue && isNullable(expectedValue)) {
|
13425 | continue;
|
13426 | }
|
13427 | if (similar && isEmptyValue && !format.exact) {
|
13428 | return false;
|
13429 | }
|
13430 | if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) {
|
13431 | return false;
|
13432 | }
|
13433 | }
|
13434 | }
|
13435 | } else {
|
13436 | for (let i = 0; i < items.length; i++) {
|
13437 | if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) {
|
13438 | return true;
|
13439 | }
|
13440 | }
|
13441 | }
|
13442 | }
|
13443 | return true;
|
13444 | };
|
13445 | const matchNode = (ed, node, name, vars, similar) => {
|
13446 | const formatList = ed.formatter.get(name);
|
13447 | const dom = ed.dom;
|
13448 | if (formatList && isElement$6(node)) {
|
13449 | for (let i = 0; i < formatList.length; i++) {
|
13450 | const format = formatList[i];
|
13451 | if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
|
13452 | const classes = format.classes;
|
13453 | if (classes) {
|
13454 | for (let x = 0; x < classes.length; x++) {
|
13455 | if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
|
13456 | return;
|
13457 | }
|
13458 | }
|
13459 | }
|
13460 | return format;
|
13461 | }
|
13462 | }
|
13463 | }
|
13464 | return undefined;
|
13465 | };
|
13466 | const match$2 = (editor, name, vars, node, similar) => {
|
13467 | if (node) {
|
13468 | return matchParents(editor, node, name, vars, similar);
|
13469 | }
|
13470 | node = editor.selection.getNode();
|
13471 | if (matchParents(editor, node, name, vars, similar)) {
|
13472 | return true;
|
13473 | }
|
13474 | const startNode = editor.selection.getStart();
|
13475 | if (startNode !== node) {
|
13476 | if (matchParents(editor, startNode, name, vars, similar)) {
|
13477 | return true;
|
13478 | }
|
13479 | }
|
13480 | return false;
|
13481 | };
|
13482 | const matchAll = (editor, names, vars) => {
|
13483 | const matchedFormatNames = [];
|
13484 | const checkedMap = {};
|
13485 | const startElement = editor.selection.getStart();
|
13486 | editor.dom.getParent(startElement, node => {
|
13487 | for (let i = 0; i < names.length; i++) {
|
13488 | const name = names[i];
|
13489 | if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
|
13490 | checkedMap[name] = true;
|
13491 | matchedFormatNames.push(name);
|
13492 | }
|
13493 | }
|
13494 | }, editor.dom.getRoot());
|
13495 | return matchedFormatNames;
|
13496 | };
|
13497 | const closest = (editor, names) => {
|
13498 | const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
|
13499 | const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none();
|
13500 | return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$1(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull();
|
13501 | };
|
13502 | const canApply = (editor, name) => {
|
13503 | const formatList = editor.formatter.get(name);
|
13504 | const dom = editor.dom;
|
13505 | if (formatList && editor.selection.isEditable()) {
|
13506 | const startNode = editor.selection.getStart();
|
13507 | const parents = getParents$2(dom, startNode);
|
13508 | for (let x = formatList.length - 1; x >= 0; x--) {
|
13509 | const format = formatList[x];
|
13510 | if (!isSelectorFormat(format)) {
|
13511 | return true;
|
13512 | }
|
13513 | for (let i = parents.length - 1; i >= 0; i--) {
|
13514 | if (dom.is(parents[i], format.selector)) {
|
13515 | return true;
|
13516 | }
|
13517 | }
|
13518 | }
|
13519 | }
|
13520 | return false;
|
13521 | };
|
13522 | const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => {
|
13523 | const matchSimilar = isVariableFormatName(editor, name);
|
13524 | if (editor.formatter.matchNode(node, name, {}, matchSimilar)) {
|
13525 | return acc.concat([name]);
|
13526 | } else {
|
13527 | return acc;
|
13528 | }
|
13529 | }, []);
|
13530 |
|
13531 | const ZWSP = ZWSP$1;
|
13532 | const importNode = (ownerDocument, node) => {
|
13533 | return ownerDocument.importNode(node, true);
|
13534 | };
|
13535 | const findFirstTextNode = node => {
|
13536 | if (node) {
|
13537 | const walker = new DomTreeWalker(node, node);
|
13538 | for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) {
|
13539 | if (isText$b(tempNode)) {
|
13540 | return tempNode;
|
13541 | }
|
13542 | }
|
13543 | }
|
13544 | return null;
|
13545 | };
|
13546 | const createCaretContainer = fill => {
|
13547 | const caretContainer = SugarElement.fromTag('span');
|
13548 | setAll$1(caretContainer, {
|
13549 | 'id': CARET_ID,
|
13550 | 'data-mce-bogus': '1',
|
13551 | 'data-mce-type': 'format-caret'
|
13552 | });
|
13553 | if (fill) {
|
13554 | append$1(caretContainer, SugarElement.fromText(ZWSP));
|
13555 | }
|
13556 | return caretContainer;
|
13557 | };
|
13558 | const trimZwspFromCaretContainer = caretContainerNode => {
|
13559 | const textNode = findFirstTextNode(caretContainerNode);
|
13560 | if (textNode && textNode.data.charAt(0) === ZWSP) {
|
13561 | textNode.deleteData(0, 1);
|
13562 | }
|
13563 | return textNode;
|
13564 | };
|
13565 | const removeCaretContainerNode = (editor, node, moveCaret) => {
|
13566 | const dom = editor.dom, selection = editor.selection;
|
13567 | if (isCaretContainerEmpty(node)) {
|
13568 | deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret, true);
|
13569 | } else {
|
13570 | const rng = selection.getRng();
|
13571 | const block = dom.getParent(node, dom.isBlock);
|
13572 | const startContainer = rng.startContainer;
|
13573 | const startOffset = rng.startOffset;
|
13574 | const endContainer = rng.endContainer;
|
13575 | const endOffset = rng.endOffset;
|
13576 | const textNode = trimZwspFromCaretContainer(node);
|
13577 | dom.remove(node, true);
|
13578 | if (startContainer === textNode && startOffset > 0) {
|
13579 | rng.setStart(textNode, startOffset - 1);
|
13580 | }
|
13581 | if (endContainer === textNode && endOffset > 0) {
|
13582 | rng.setEnd(textNode, endOffset - 1);
|
13583 | }
|
13584 | if (block && dom.isEmpty(block)) {
|
13585 | fillWithPaddingBr(SugarElement.fromDom(block));
|
13586 | }
|
13587 | selection.setRng(rng);
|
13588 | }
|
13589 | };
|
13590 | const removeCaretContainer = (editor, node, moveCaret) => {
|
13591 | const dom = editor.dom, selection = editor.selection;
|
13592 | if (!node) {
|
13593 | node = getParentCaretContainer(editor.getBody(), selection.getStart());
|
13594 | if (!node) {
|
13595 | while (node = dom.get(CARET_ID)) {
|
13596 | removeCaretContainerNode(editor, node, moveCaret);
|
13597 | }
|
13598 | }
|
13599 | } else {
|
13600 | removeCaretContainerNode(editor, node, moveCaret);
|
13601 | }
|
13602 | };
|
13603 | const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
|
13604 | var _a, _b;
|
13605 | const dom = editor.dom;
|
13606 | const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema));
|
13607 | if (block && dom.isEmpty(block)) {
|
13608 | (_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode);
|
13609 | } else {
|
13610 | removeTrailingBr(SugarElement.fromDom(formatNode));
|
13611 | if (dom.isEmpty(formatNode)) {
|
13612 | (_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode);
|
13613 | } else {
|
13614 | dom.insertAfter(caretContainer, formatNode);
|
13615 | }
|
13616 | }
|
13617 | };
|
13618 | const appendNode = (parentNode, node) => {
|
13619 | parentNode.appendChild(node);
|
13620 | return node;
|
13621 | };
|
13622 | const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
|
13623 | var _a;
|
13624 | const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
|
13625 | return appendNode(parentNode, formatNode.cloneNode(false));
|
13626 | }, caretContainer);
|
13627 | const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
13628 | return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP));
|
13629 | };
|
13630 | const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => {
|
13631 | const formatter = editor.formatter;
|
13632 | const dom = editor.dom;
|
13633 | const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat'));
|
13634 | const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
|
13635 | const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name));
|
13636 | if (uniqueFormats.length > 0) {
|
13637 | const clonedFormatNode = formatNode.cloneNode(false);
|
13638 | dom.add(caretContainer, clonedFormatNode);
|
13639 | formatter.remove(name, vars, clonedFormatNode, similar);
|
13640 | dom.remove(clonedFormatNode);
|
13641 | return Optional.some(clonedFormatNode);
|
13642 | } else {
|
13643 | return Optional.none();
|
13644 | }
|
13645 | };
|
13646 | const applyCaretFormat = (editor, name, vars) => {
|
13647 | let caretContainer;
|
13648 | const selection = editor.selection;
|
13649 | const formatList = editor.formatter.get(name);
|
13650 | if (!formatList) {
|
13651 | return;
|
13652 | }
|
13653 | const selectionRng = selection.getRng();
|
13654 | let offset = selectionRng.startOffset;
|
13655 | const container = selectionRng.startContainer;
|
13656 | const text = container.nodeValue;
|
13657 | caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
|
13658 | const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
|
13659 | if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
|
13660 | const bookmark = selection.getBookmark();
|
13661 | selectionRng.collapse(true);
|
13662 | let rng = expandRng(editor.dom, selectionRng, formatList);
|
13663 | rng = split(rng);
|
13664 | editor.formatter.apply(name, vars, rng);
|
13665 | selection.moveToBookmark(bookmark);
|
13666 | } else {
|
13667 | let textNode = caretContainer ? findFirstTextNode(caretContainer) : null;
|
13668 | if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) {
|
13669 | caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
|
13670 | textNode = caretContainer.firstChild;
|
13671 | selectionRng.insertNode(caretContainer);
|
13672 | offset = 1;
|
13673 | editor.formatter.apply(name, vars, caretContainer);
|
13674 | } else {
|
13675 | editor.formatter.apply(name, vars, caretContainer);
|
13676 | }
|
13677 | selection.setCursorLocation(textNode, offset);
|
13678 | }
|
13679 | };
|
13680 | const removeCaretFormat = (editor, name, vars, similar) => {
|
13681 | const dom = editor.dom;
|
13682 | const selection = editor.selection;
|
13683 | let hasContentAfter = false;
|
13684 | const formatList = editor.formatter.get(name);
|
13685 | if (!formatList) {
|
13686 | return;
|
13687 | }
|
13688 | const rng = selection.getRng();
|
13689 | const container = rng.startContainer;
|
13690 | const offset = rng.startOffset;
|
13691 | let node = container;
|
13692 | if (isText$b(container)) {
|
13693 | if (offset !== container.data.length) {
|
13694 | hasContentAfter = true;
|
13695 | }
|
13696 | node = node.parentNode;
|
13697 | }
|
13698 | const parents = [];
|
13699 | let formatNode;
|
13700 | while (node) {
|
13701 | if (matchNode(editor, node, name, vars, similar)) {
|
13702 | formatNode = node;
|
13703 | break;
|
13704 | }
|
13705 | if (node.nextSibling) {
|
13706 | hasContentAfter = true;
|
13707 | }
|
13708 | parents.push(node);
|
13709 | node = node.parentNode;
|
13710 | }
|
13711 | if (!formatNode) {
|
13712 | return;
|
13713 | }
|
13714 | if (hasContentAfter) {
|
13715 | const bookmark = selection.getBookmark();
|
13716 | rng.collapse(true);
|
13717 | let expandedRng = expandRng(dom, rng, formatList, true);
|
13718 | expandedRng = split(expandedRng);
|
13719 | editor.formatter.remove(name, vars, expandedRng, similar);
|
13720 | selection.moveToBookmark(bookmark);
|
13721 | } else {
|
13722 | const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
|
13723 | const parentsAfter = isNonNullable(caretContainer) ? dom.getParents(formatNode.parentNode, always, caretContainer) : [];
|
13724 | const newCaretContainer = createCaretContainer(false).dom;
|
13725 | insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode);
|
13726 | const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar);
|
13727 | const caretTextNode = insertFormatNodesIntoCaretContainer([
|
13728 | ...parents,
|
13729 | ...cleanedFormatNode.toArray(),
|
13730 | ...parentsAfter
|
13731 | ], newCaretContainer);
|
13732 | if (caretContainer) {
|
13733 | removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer));
|
13734 | }
|
13735 | selection.setCursorLocation(caretTextNode, 1);
|
13736 | if (dom.isEmpty(formatNode)) {
|
13737 | dom.remove(formatNode);
|
13738 | }
|
13739 | }
|
13740 | };
|
13741 | const disableCaretContainer = (editor, keyCode, moveCaret) => {
|
13742 | const selection = editor.selection, body = editor.getBody();
|
13743 | removeCaretContainer(editor, null, moveCaret);
|
13744 | if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
|
13745 | removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
|
13746 | }
|
13747 | if (keyCode === 37 || keyCode === 39) {
|
13748 | removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
|
13749 | }
|
13750 | };
|
13751 | const endsWithNbsp = element => isText$b(element) && endsWith(element.data, nbsp);
|
13752 | const setup$v = editor => {
|
13753 | editor.on('mouseup keydown', e => {
|
13754 | disableCaretContainer(editor, e.keyCode, endsWithNbsp(editor.selection.getRng().endContainer));
|
13755 | });
|
13756 | };
|
13757 | const createCaretFormat = formatNodes => {
|
13758 | const caretContainer = createCaretContainer(false);
|
13759 | const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
|
13760 | return {
|
13761 | caretContainer,
|
13762 | caretPosition: CaretPosition(innerMost, 0)
|
13763 | };
|
13764 | };
|
13765 | const replaceWithCaretFormat = (targetNode, formatNodes) => {
|
13766 | const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
|
13767 | before$3(SugarElement.fromDom(targetNode), caretContainer);
|
13768 | remove$4(SugarElement.fromDom(targetNode));
|
13769 | return caretPosition;
|
13770 | };
|
13771 | const createCaretFormatAtStart$1 = (rng, formatNodes) => {
|
13772 | const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
|
13773 | rng.insertNode(caretContainer.dom);
|
13774 | return caretPosition;
|
13775 | };
|
13776 | const isFormatElement = (editor, element) => {
|
13777 | if (isCaretNode(element.dom)) {
|
13778 | return false;
|
13779 | }
|
13780 | const inlineElements = editor.schema.getTextInlineElements();
|
13781 | return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$1(element.dom);
|
13782 | };
|
13783 |
|
13784 | const postProcessHooks = {};
|
13785 | const isPre = matchNodeNames(['pre']);
|
13786 | const addPostProcessHook = (name, hook) => {
|
13787 | const hooks = postProcessHooks[name];
|
13788 | if (!hooks) {
|
13789 | postProcessHooks[name] = [];
|
13790 | }
|
13791 | postProcessHooks[name].push(hook);
|
13792 | };
|
13793 | const postProcess$1 = (name, editor) => {
|
13794 | if (has$2(postProcessHooks, name)) {
|
13795 | each$e(postProcessHooks[name], hook => {
|
13796 | hook(editor);
|
13797 | });
|
13798 | }
|
13799 | };
|
13800 | addPostProcessHook('pre', editor => {
|
13801 | const rng = editor.selection.getRng();
|
13802 | const hasPreSibling = blocks => pre => {
|
13803 | const prev = pre.previousSibling;
|
13804 | return isPre(prev) && contains$2(blocks, prev);
|
13805 | };
|
13806 | const joinPre = (pre1, pre2) => {
|
13807 | const sPre2 = SugarElement.fromDom(pre2);
|
13808 | const doc = documentOrOwner(sPre2).dom;
|
13809 | remove$4(sPre2);
|
13810 | append(SugarElement.fromDom(pre1), [
|
13811 | SugarElement.fromTag('br', doc),
|
13812 | SugarElement.fromTag('br', doc),
|
13813 | ...children$1(sPre2)
|
13814 | ]);
|
13815 | };
|
13816 | if (!rng.collapsed) {
|
13817 | const blocks = editor.selection.getSelectedBlocks();
|
13818 | const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks));
|
13819 | each$e(preBlocks, pre => {
|
13820 | joinPre(pre.previousSibling, pre);
|
13821 | });
|
13822 | }
|
13823 | });
|
13824 |
|
13825 | const listItemStyles = [
|
13826 | 'fontWeight',
|
13827 | 'fontStyle',
|
13828 | 'color',
|
13829 | 'fontSize',
|
13830 | 'fontFamily'
|
13831 | ];
|
13832 | const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name));
|
13833 | const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt));
|
13834 | const getExpandedListItemFormat = (formatter, format) => {
|
13835 | const formatList = formatter.get(format);
|
13836 | return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none();
|
13837 | };
|
13838 | const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone();
|
13839 | const isRngEndAtEndOfElement = (rng, elm) => {
|
13840 | return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
|
13841 | };
|
13842 | const isEditableListItem = dom => elm => isListItem$2(elm) && dom.isEditable(elm);
|
13843 | const getFullySelectedBlocks = selection => {
|
13844 | const blocks = selection.getSelectedBlocks();
|
13845 | const rng = selection.getRng();
|
13846 | if (selection.isCollapsed()) {
|
13847 | return [];
|
13848 | }
|
13849 | if (blocks.length === 1) {
|
13850 | return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
|
13851 | } else {
|
13852 | const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray();
|
13853 | const last = last$2(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray();
|
13854 | const middle = blocks.slice(1, -1);
|
13855 | return first.concat(middle).concat(last);
|
13856 | }
|
13857 | };
|
13858 | const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
|
13859 | const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
|
13860 |
|
13861 | const each$8 = Tools.each;
|
13862 | const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
|
13863 | const findElementSibling = (node, siblingName) => {
|
13864 | for (let sibling = node; sibling; sibling = sibling[siblingName]) {
|
13865 | if (isText$b(sibling) && isNotEmpty(sibling.data)) {
|
13866 | return node;
|
13867 | }
|
13868 | if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) {
|
13869 | return sibling;
|
13870 | }
|
13871 | }
|
13872 | return node;
|
13873 | };
|
13874 | const mergeSiblingsNodes = (editor, prev, next) => {
|
13875 | const elementUtils = ElementUtils(editor);
|
13876 | const isPrevEditable = isHTMLElement(prev) && editor.dom.isEditable(prev);
|
13877 | const isNextEditable = isHTMLElement(next) && editor.dom.isEditable(next);
|
13878 | if (isPrevEditable && isNextEditable) {
|
13879 | const prevSibling = findElementSibling(prev, 'previousSibling');
|
13880 | const nextSibling = findElementSibling(next, 'nextSibling');
|
13881 | if (elementUtils.compare(prevSibling, nextSibling)) {
|
13882 | for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) {
|
13883 | const tmpSibling = sibling;
|
13884 | sibling = sibling.nextSibling;
|
13885 | prevSibling.appendChild(tmpSibling);
|
13886 | }
|
13887 | editor.dom.remove(nextSibling);
|
13888 | Tools.each(Tools.grep(nextSibling.childNodes), node => {
|
13889 | prevSibling.appendChild(node);
|
13890 | });
|
13891 | return prevSibling;
|
13892 | }
|
13893 | }
|
13894 | return next;
|
13895 | };
|
13896 | const mergeSiblings = (editor, format, vars, node) => {
|
13897 | var _a;
|
13898 | if (node && format.merge_siblings !== false) {
|
13899 | const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node;
|
13900 | mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true));
|
13901 | }
|
13902 | };
|
13903 | const clearChildStyles = (dom, format, node) => {
|
13904 | if (format.clear_child_styles) {
|
13905 | const selector = format.links ? '*:not(a)' : '*';
|
13906 | each$8(dom.select(selector, node), childNode => {
|
13907 | if (isElementNode(childNode) && dom.isEditable(childNode)) {
|
13908 | each$8(format.styles, (_value, name) => {
|
13909 | dom.setStyle(childNode, name, '');
|
13910 | });
|
13911 | }
|
13912 | });
|
13913 | }
|
13914 | };
|
13915 | const processChildElements = (node, filter, process) => {
|
13916 | each$8(node.childNodes, node => {
|
13917 | if (isElementNode(node)) {
|
13918 | if (filter(node)) {
|
13919 | process(node);
|
13920 | }
|
13921 | if (node.hasChildNodes()) {
|
13922 | processChildElements(node, filter, process);
|
13923 | }
|
13924 | }
|
13925 | });
|
13926 | };
|
13927 | const unwrapEmptySpan = (dom, node) => {
|
13928 | if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
|
13929 | dom.remove(node, true);
|
13930 | }
|
13931 | };
|
13932 | const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name));
|
13933 | const applyStyle = (dom, name, value) => node => {
|
13934 | dom.setStyle(node, name, value);
|
13935 | if (node.getAttribute('style') === '') {
|
13936 | node.removeAttribute('style');
|
13937 | }
|
13938 | unwrapEmptySpan(dom, node);
|
13939 | };
|
13940 |
|
13941 | const removeResult = Adt.generate([
|
13942 | { keep: [] },
|
13943 | { rename: ['name'] },
|
13944 | { removed: [] }
|
13945 | ]);
|
13946 | const MCE_ATTR_RE = /^(src|href|style)$/;
|
13947 | const each$7 = Tools.each;
|
13948 | const isEq$2 = isEq$5;
|
13949 | const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName);
|
13950 | const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
|
13951 | const getContainer = (ed, rng, start) => {
|
13952 | let container = rng[start ? 'startContainer' : 'endContainer'];
|
13953 | let offset = rng[start ? 'startOffset' : 'endOffset'];
|
13954 | if (isElement$6(container)) {
|
13955 | const lastIdx = container.childNodes.length - 1;
|
13956 | if (!start && offset) {
|
13957 | offset--;
|
13958 | }
|
13959 | container = container.childNodes[offset > lastIdx ? lastIdx : offset];
|
13960 | }
|
13961 | if (isText$b(container) && start && offset >= container.data.length) {
|
13962 | container = new DomTreeWalker(container, ed.getBody()).next() || container;
|
13963 | }
|
13964 | if (isText$b(container) && !start && offset === 0) {
|
13965 | container = new DomTreeWalker(container, ed.getBody()).prev() || container;
|
13966 | }
|
13967 | return container;
|
13968 | };
|
13969 | const normalizeTableSelection = (node, start) => {
|
13970 | const prop = start ? 'firstChild' : 'lastChild';
|
13971 | const childNode = node[prop];
|
13972 | if (isTableCellOrRow(node) && childNode) {
|
13973 | if (node.nodeName === 'TR') {
|
13974 | return childNode[prop] || childNode;
|
13975 | } else {
|
13976 | return childNode;
|
13977 | }
|
13978 | }
|
13979 | return node;
|
13980 | };
|
13981 | const wrap$1 = (dom, node, name, attrs) => {
|
13982 | var _a;
|
13983 | const wrapper = dom.create(name, attrs);
|
13984 | (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node);
|
13985 | wrapper.appendChild(node);
|
13986 | return wrapper;
|
13987 | };
|
13988 | const wrapWithSiblings = (dom, node, next, name, attrs) => {
|
13989 | const start = SugarElement.fromDom(node);
|
13990 | const wrapper = SugarElement.fromDom(dom.create(name, attrs));
|
13991 | const siblings = next ? nextSiblings(start) : prevSiblings(start);
|
13992 | append(wrapper, siblings);
|
13993 | if (next) {
|
13994 | before$3(start, wrapper);
|
13995 | prepend(wrapper, start);
|
13996 | } else {
|
13997 | after$4(start, wrapper);
|
13998 | append$1(wrapper, start);
|
13999 | }
|
14000 | return wrapper.dom;
|
14001 | };
|
14002 | const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A';
|
14003 | const removeNode = (ed, node, format) => {
|
14004 | const parentNode = node.parentNode;
|
14005 | let rootBlockElm;
|
14006 | const dom = ed.dom;
|
14007 | const forcedRootBlock = getForcedRootBlock(ed);
|
14008 | if (isBlockFormat(format)) {
|
14009 | if (parentNode === dom.getRoot()) {
|
14010 | if (!format.list_block || !isEq$2(node, format.list_block)) {
|
14011 | each$e(from(node.childNodes), node => {
|
14012 | if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
|
14013 | if (!rootBlockElm) {
|
14014 | rootBlockElm = wrap$1(dom, node, forcedRootBlock);
|
14015 | dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
|
14016 | } else {
|
14017 | rootBlockElm.appendChild(node);
|
14018 | }
|
14019 | } else {
|
14020 | rootBlockElm = null;
|
14021 | }
|
14022 | });
|
14023 | }
|
14024 | }
|
14025 | }
|
14026 | if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
|
14027 | return;
|
14028 | }
|
14029 | dom.remove(node, true);
|
14030 | };
|
14031 | const processFormatAttrOrStyle = (name, value, vars) => {
|
14032 | if (isNumber(name)) {
|
14033 | return {
|
14034 | name: value,
|
14035 | value: null
|
14036 | };
|
14037 | } else {
|
14038 | return {
|
14039 | name,
|
14040 | value: replaceVars(value, vars)
|
14041 | };
|
14042 | }
|
14043 | };
|
14044 | const removeEmptyStyleAttributeIfNeeded = (dom, elm) => {
|
14045 | if (dom.getAttrib(elm, 'style') === '') {
|
14046 | elm.removeAttribute('style');
|
14047 | elm.removeAttribute('data-mce-style');
|
14048 | }
|
14049 | };
|
14050 | const removeStyles = (dom, elm, format, vars, compareNode) => {
|
14051 | let stylesModified = false;
|
14052 | each$7(format.styles, (value, name) => {
|
14053 | const {
|
14054 | name: styleName,
|
14055 | value: styleValue
|
14056 | } = processFormatAttrOrStyle(name, value, vars);
|
14057 | const normalizedStyleValue = normalizeStyleValue(styleValue, styleName);
|
14058 | if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) {
|
14059 | dom.setStyle(elm, styleName, '');
|
14060 | }
|
14061 | stylesModified = true;
|
14062 | });
|
14063 | if (stylesModified) {
|
14064 | removeEmptyStyleAttributeIfNeeded(dom, elm);
|
14065 | }
|
14066 | };
|
14067 | const removeListStyleFormats = (editor, name, vars) => {
|
14068 | if (name === 'removeformat') {
|
14069 | each$e(getPartiallySelectedListItems(editor.selection), li => {
|
14070 | each$e(listItemStyles, name => editor.dom.setStyle(li, name, ''));
|
14071 | removeEmptyStyleAttributeIfNeeded(editor.dom, li);
|
14072 | });
|
14073 | } else {
|
14074 | getExpandedListItemFormat(editor.formatter, name).each(liFmt => {
|
14075 | each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null));
|
14076 | });
|
14077 | }
|
14078 | };
|
14079 | const removeNodeFormatInternal = (ed, format, vars, node, compareNode) => {
|
14080 | const dom = ed.dom;
|
14081 | const elementUtils = ElementUtils(ed);
|
14082 | const schema = ed.schema;
|
14083 | if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) {
|
14084 | removeNode(ed, node, format);
|
14085 | return removeResult.removed();
|
14086 | }
|
14087 | if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') {
|
14088 | return removeResult.keep();
|
14089 | }
|
14090 | if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
|
14091 | return removeResult.keep();
|
14092 | }
|
14093 | const elm = node;
|
14094 | const preserveAttributes = format.preserve_attributes;
|
14095 | if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) {
|
14096 | const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase()));
|
14097 | dom.removeAllAttribs(elm);
|
14098 | each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value));
|
14099 | if (attrsToPreserve.length > 0) {
|
14100 | return removeResult.rename('span');
|
14101 | }
|
14102 | }
|
14103 | if (format.remove !== 'all') {
|
14104 | removeStyles(dom, elm, format, vars, compareNode);
|
14105 | each$7(format.attributes, (value, name) => {
|
14106 | const {
|
14107 | name: attrName,
|
14108 | value: attrValue
|
14109 | } = processFormatAttrOrStyle(name, value, vars);
|
14110 | if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) {
|
14111 | if (attrName === 'class') {
|
14112 | const currentValue = dom.getAttrib(elm, attrName);
|
14113 | if (currentValue) {
|
14114 | let valueOut = '';
|
14115 | each$e(currentValue.split(/\s+/), cls => {
|
14116 | if (/mce\-\w+/.test(cls)) {
|
14117 | valueOut += (valueOut ? ' ' : '') + cls;
|
14118 | }
|
14119 | });
|
14120 | if (valueOut) {
|
14121 | dom.setAttrib(elm, attrName, valueOut);
|
14122 | return;
|
14123 | }
|
14124 | }
|
14125 | }
|
14126 | if (MCE_ATTR_RE.test(attrName)) {
|
14127 | elm.removeAttribute('data-mce-' + attrName);
|
14128 | }
|
14129 | if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') {
|
14130 | elm.removeAttribute(attrName);
|
14131 | dom.setStyle(elm, 'list-style-type', 'none');
|
14132 | return;
|
14133 | }
|
14134 | if (attrName === 'class') {
|
14135 | elm.removeAttribute('className');
|
14136 | }
|
14137 | elm.removeAttribute(attrName);
|
14138 | }
|
14139 | });
|
14140 | each$7(format.classes, value => {
|
14141 | value = replaceVars(value, vars);
|
14142 | if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) {
|
14143 | dom.removeClass(elm, value);
|
14144 | }
|
14145 | });
|
14146 | const attrs = dom.getAttribs(elm);
|
14147 | for (let i = 0; i < attrs.length; i++) {
|
14148 | const attrName = attrs[i].nodeName;
|
14149 | if (!elementUtils.isAttributeInternal(attrName)) {
|
14150 | return removeResult.keep();
|
14151 | }
|
14152 | }
|
14153 | }
|
14154 | if (format.remove !== 'none') {
|
14155 | removeNode(ed, elm, format);
|
14156 | return removeResult.removed();
|
14157 | }
|
14158 | return removeResult.keep();
|
14159 | };
|
14160 | const findFormatRoot = (editor, container, name, vars, similar) => {
|
14161 | let formatRoot;
|
14162 | if (container.parentNode) {
|
14163 | each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => {
|
14164 | if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') {
|
14165 | const format = matchNode(editor, parent, name, vars, similar);
|
14166 | if (format && format.split !== false) {
|
14167 | formatRoot = parent;
|
14168 | }
|
14169 | }
|
14170 | });
|
14171 | }
|
14172 | return formatRoot;
|
14173 | };
|
14174 | const removeNodeFormatFromClone = (editor, format, vars, clone) => removeNodeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => {
|
14175 | const fragment = editor.dom.createFragment();
|
14176 | fragment.appendChild(clone);
|
14177 | return editor.dom.rename(clone, newName);
|
14178 | }, constant(null));
|
14179 | const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => {
|
14180 | var _a, _b;
|
14181 | let lastClone;
|
14182 | let firstClone;
|
14183 | const dom = editor.dom;
|
14184 | if (formatRoot) {
|
14185 | const formatRootParent = formatRoot.parentNode;
|
14186 | for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
|
14187 | let clone = dom.clone(parent, false);
|
14188 | for (let i = 0; i < formatList.length; i++) {
|
14189 | clone = removeNodeFormatFromClone(editor, formatList[i], vars, clone);
|
14190 | if (clone === null) {
|
14191 | break;
|
14192 | }
|
14193 | }
|
14194 | if (clone) {
|
14195 | if (lastClone) {
|
14196 | clone.appendChild(lastClone);
|
14197 | }
|
14198 | if (!firstClone) {
|
14199 | firstClone = clone;
|
14200 | }
|
14201 | lastClone = clone;
|
14202 | }
|
14203 | }
|
14204 | if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
|
14205 | container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container;
|
14206 | }
|
14207 | if (lastClone && firstClone) {
|
14208 | (_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target);
|
14209 | firstClone.appendChild(target);
|
14210 | if (isInlineFormat(format)) {
|
14211 | mergeSiblings(editor, format, vars, lastClone);
|
14212 | }
|
14213 | }
|
14214 | }
|
14215 | return container;
|
14216 | };
|
14217 | const removeFormatInternal = (ed, name, vars, node, similar) => {
|
14218 | const formatList = ed.formatter.get(name);
|
14219 | const format = formatList[0];
|
14220 | const dom = ed.dom;
|
14221 | const selection = ed.selection;
|
14222 | const splitToFormatRoot = container => {
|
14223 | const formatRoot = findFormatRoot(ed, container, name, vars, similar);
|
14224 | return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
|
14225 | };
|
14226 | const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end');
|
14227 | const removeFormatOnNode = node => exists(formatList, fmt => removeNodeFormat(ed, fmt, vars, node, node));
|
14228 | const process = node => {
|
14229 | const children = from(node.childNodes);
|
14230 | const removed = removeFormatOnNode(node);
|
14231 | const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f));
|
14232 | const parentNode = node.parentNode;
|
14233 | if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
|
14234 | removeFormatOnNode(parentNode);
|
14235 | }
|
14236 | if (format.deep) {
|
14237 | if (children.length) {
|
14238 | for (let i = 0; i < children.length; i++) {
|
14239 | process(children[i]);
|
14240 | }
|
14241 | }
|
14242 | }
|
14243 | const textDecorations = [
|
14244 | 'underline',
|
14245 | 'line-through',
|
14246 | 'overline'
|
14247 | ];
|
14248 | each$e(textDecorations, decoration => {
|
14249 | if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) {
|
14250 | removeNodeFormat(ed, {
|
14251 | deep: false,
|
14252 | exact: true,
|
14253 | inline: 'span',
|
14254 | styles: { textDecoration: decoration }
|
14255 | }, undefined, node);
|
14256 | }
|
14257 | });
|
14258 | };
|
14259 | const unwrap = start => {
|
14260 | const node = dom.get(start ? '_start' : '_end');
|
14261 | if (node) {
|
14262 | let out = node[start ? 'firstChild' : 'lastChild'];
|
14263 | if (isRemoveBookmarkNode(out)) {
|
14264 | out = out[start ? 'firstChild' : 'lastChild'];
|
14265 | }
|
14266 | if (isText$b(out) && out.data.length === 0) {
|
14267 | out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
|
14268 | }
|
14269 | dom.remove(node, true);
|
14270 | return out;
|
14271 | } else {
|
14272 | return null;
|
14273 | }
|
14274 | };
|
14275 | const removeRngStyle = rng => {
|
14276 | let startContainer;
|
14277 | let endContainer;
|
14278 | let expandedRng = expandRng(dom, rng, formatList, rng.collapsed);
|
14279 | if (format.split) {
|
14280 | expandedRng = split(expandedRng);
|
14281 | startContainer = getContainer(ed, expandedRng, true);
|
14282 | endContainer = getContainer(ed, expandedRng);
|
14283 | if (startContainer !== endContainer) {
|
14284 | startContainer = normalizeTableSelection(startContainer, true);
|
14285 | endContainer = normalizeTableSelection(endContainer, false);
|
14286 | if (isChildOfInlineParent(dom, startContainer, endContainer)) {
|
14287 | const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
|
14288 | splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
|
14289 | 'id': '_start',
|
14290 | 'data-mce-type': 'bookmark'
|
14291 | }));
|
14292 | unwrap(true);
|
14293 | return;
|
14294 | }
|
14295 | if (isChildOfInlineParent(dom, endContainer, startContainer)) {
|
14296 | const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
|
14297 | splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
|
14298 | 'id': '_end',
|
14299 | 'data-mce-type': 'bookmark'
|
14300 | }));
|
14301 | unwrap(false);
|
14302 | return;
|
14303 | }
|
14304 | startContainer = wrap$1(dom, startContainer, 'span', {
|
14305 | 'id': '_start',
|
14306 | 'data-mce-type': 'bookmark'
|
14307 | });
|
14308 | endContainer = wrap$1(dom, endContainer, 'span', {
|
14309 | 'id': '_end',
|
14310 | 'data-mce-type': 'bookmark'
|
14311 | });
|
14312 | const newRng = dom.createRng();
|
14313 | newRng.setStartAfter(startContainer);
|
14314 | newRng.setEndBefore(endContainer);
|
14315 | walk$3(dom, newRng, nodes => {
|
14316 | each$e(nodes, n => {
|
14317 | if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
|
14318 | splitToFormatRoot(n);
|
14319 | }
|
14320 | });
|
14321 | });
|
14322 | splitToFormatRoot(startContainer);
|
14323 | splitToFormatRoot(endContainer);
|
14324 | startContainer = unwrap(true);
|
14325 | endContainer = unwrap();
|
14326 | } else {
|
14327 | startContainer = endContainer = splitToFormatRoot(startContainer);
|
14328 | }
|
14329 | expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
|
14330 | expandedRng.startOffset = dom.nodeIndex(startContainer);
|
14331 | expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
|
14332 | expandedRng.endOffset = dom.nodeIndex(endContainer) + 1;
|
14333 | }
|
14334 | walk$3(dom, expandedRng, nodes => {
|
14335 | each$e(nodes, process);
|
14336 | });
|
14337 | };
|
14338 | if (node) {
|
14339 | if (isNode(node)) {
|
14340 | const rng = dom.createRng();
|
14341 | rng.setStartBefore(node);
|
14342 | rng.setEndAfter(node);
|
14343 | removeRngStyle(rng);
|
14344 | } else {
|
14345 | removeRngStyle(node);
|
14346 | }
|
14347 | fireFormatRemove(ed, name, node, vars);
|
14348 | return;
|
14349 | }
|
14350 | if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
|
14351 | preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode));
|
14352 | ed.nodeChanged();
|
14353 | } else {
|
14354 | removeCaretFormat(ed, name, vars, similar);
|
14355 | }
|
14356 | removeListStyleFormats(ed, name, vars);
|
14357 | fireFormatRemove(ed, name, node, vars);
|
14358 | };
|
14359 | const removeFormat$1 = (ed, name, vars, node, similar) => {
|
14360 | if (node || ed.selection.isEditable()) {
|
14361 | removeFormatInternal(ed, name, vars, node, similar);
|
14362 | }
|
14363 | };
|
14364 | const removeNodeFormat = (editor, format, vars, node, compareNode) => {
|
14365 | return removeNodeFormatInternal(editor, format, vars, node, compareNode).fold(never, newName => {
|
14366 | editor.dom.rename(node, newName);
|
14367 | return true;
|
14368 | }, always);
|
14369 | };
|
14370 |
|
14371 | const each$6 = Tools.each;
|
14372 | const mergeTextDecorationsAndColor = (dom, format, vars, node) => {
|
14373 | const processTextDecorationsAndColor = n => {
|
14374 | if (isHTMLElement(n) && isElement$6(n.parentNode) && dom.isEditable(n)) {
|
14375 | const parentTextDecoration = getTextDecoration(dom, n.parentNode);
|
14376 | if (dom.getStyle(n, 'color') && parentTextDecoration) {
|
14377 | dom.setStyle(n, 'text-decoration', parentTextDecoration);
|
14378 | } else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) {
|
14379 | dom.setStyle(n, 'text-decoration', null);
|
14380 | }
|
14381 | }
|
14382 | };
|
14383 | if (format.styles && (format.styles.color || format.styles.textDecoration)) {
|
14384 | Tools.walk(node, processTextDecorationsAndColor, 'childNodes');
|
14385 | processTextDecorationsAndColor(node);
|
14386 | }
|
14387 | };
|
14388 | const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => {
|
14389 | if (format.styles && format.styles.backgroundColor) {
|
14390 | const hasFontSize = hasStyle(dom, 'fontSize');
|
14391 | processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars)));
|
14392 | }
|
14393 | };
|
14394 | const mergeSubSup = (dom, format, vars, node) => {
|
14395 | if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) {
|
14396 | const hasFontSize = hasStyle(dom, 'fontSize');
|
14397 | processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'fontSize', ''));
|
14398 | const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), dom.isEditable);
|
14399 | dom.remove(inverseTagDescendants, true);
|
14400 | }
|
14401 | };
|
14402 | const mergeWithChildren = (editor, formatList, vars, node) => {
|
14403 | each$6(formatList, format => {
|
14404 | if (isInlineFormat(format)) {
|
14405 | each$6(editor.dom.select(format.inline, node), child => {
|
14406 | if (isElementNode(child)) {
|
14407 | removeNodeFormat(editor, format, vars, child, format.exact ? child : null);
|
14408 | }
|
14409 | });
|
14410 | }
|
14411 | clearChildStyles(editor.dom, format, node);
|
14412 | });
|
14413 | };
|
14414 | const mergeWithParents = (editor, format, name, vars, node) => {
|
14415 | const parentNode = node.parentNode;
|
14416 | if (matchNode(editor, parentNode, name, vars)) {
|
14417 | if (removeNodeFormat(editor, format, vars, node)) {
|
14418 | return;
|
14419 | }
|
14420 | }
|
14421 | if (format.merge_with_parents && parentNode) {
|
14422 | editor.dom.getParent(parentNode, parent => {
|
14423 | if (matchNode(editor, parent, name, vars)) {
|
14424 | removeNodeFormat(editor, format, vars, node);
|
14425 | return true;
|
14426 | } else {
|
14427 | return false;
|
14428 | }
|
14429 | });
|
14430 | }
|
14431 | };
|
14432 |
|
14433 | const each$5 = Tools.each;
|
14434 | const canFormatBR = (editor, format, node, parentName) => {
|
14435 | if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) {
|
14436 | const validBRParentElements = getTextRootBlockElements(editor.schema);
|
14437 | const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom));
|
14438 | return hasNonNullableKey(validBRParentElements, parentName) && isEmptyNode(editor.schema, node.parentNode, {
|
14439 | skipBogus: false,
|
14440 | includeZwsp: true
|
14441 | }) && !hasCaretNodeSibling;
|
14442 | } else {
|
14443 | return false;
|
14444 | }
|
14445 | };
|
14446 | const applyStyles = (dom, elm, format, vars) => {
|
14447 | each$5(format.styles, (value, name) => {
|
14448 | dom.setStyle(elm, name, replaceVars(value, vars));
|
14449 | });
|
14450 | if (format.styles) {
|
14451 | const styleVal = dom.getAttrib(elm, 'style');
|
14452 | if (styleVal) {
|
14453 | dom.setAttrib(elm, 'data-mce-style', styleVal);
|
14454 | }
|
14455 | }
|
14456 | };
|
14457 | const applyFormatAction = (ed, name, vars, node) => {
|
14458 | const formatList = ed.formatter.get(name);
|
14459 | const format = formatList[0];
|
14460 | const isCollapsed = !node && ed.selection.isCollapsed();
|
14461 | const dom = ed.dom;
|
14462 | const selection = ed.selection;
|
14463 | const setElementFormat = (elm, fmt = format) => {
|
14464 | if (isFunction(fmt.onformat)) {
|
14465 | fmt.onformat(elm, fmt, vars, node);
|
14466 | }
|
14467 | applyStyles(dom, elm, fmt, vars);
|
14468 | each$5(fmt.attributes, (value, name) => {
|
14469 | dom.setAttrib(elm, name, replaceVars(value, vars));
|
14470 | });
|
14471 | each$5(fmt.classes, value => {
|
14472 | const newValue = replaceVars(value, vars);
|
14473 | if (!dom.hasClass(elm, newValue)) {
|
14474 | dom.addClass(elm, newValue);
|
14475 | }
|
14476 | });
|
14477 | };
|
14478 | const applyNodeStyle = (formatList, node) => {
|
14479 | let found = false;
|
14480 | each$5(formatList, format => {
|
14481 | if (!isSelectorFormat(format)) {
|
14482 | return false;
|
14483 | }
|
14484 | if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) {
|
14485 | return true;
|
14486 | }
|
14487 | if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) {
|
14488 | return true;
|
14489 | }
|
14490 | if (dom.is(node, format.selector) && !isCaretNode(node)) {
|
14491 | setElementFormat(node, format);
|
14492 | found = true;
|
14493 | return false;
|
14494 | }
|
14495 | return true;
|
14496 | });
|
14497 | return found;
|
14498 | };
|
14499 | const createWrapElement = wrapName => {
|
14500 | if (isString(wrapName)) {
|
14501 | const wrapElm = dom.create(wrapName);
|
14502 | setElementFormat(wrapElm);
|
14503 | return wrapElm;
|
14504 | } else {
|
14505 | return null;
|
14506 | }
|
14507 | };
|
14508 | const applyRngStyle = (dom, rng, nodeSpecific) => {
|
14509 | const newWrappers = [];
|
14510 | let contentEditable = true;
|
14511 | const wrapName = format.inline || format.block;
|
14512 | const wrapElm = createWrapElement(wrapName);
|
14513 | const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars);
|
14514 | const canRenameBlock = (node, parentName, isEditableDescendant) => {
|
14515 | const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName);
|
14516 | return isEditableDescendant && isValidBlockFormatForNode;
|
14517 | };
|
14518 | const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
|
14519 | const nodeName = node.nodeName.toLowerCase();
|
14520 | const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName);
|
14521 | const isZwsp$1 = !nodeSpecific && isText$b(node) && isZwsp(node.data);
|
14522 | const isCaret = isCaretNode(node);
|
14523 | const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node);
|
14524 | return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp$1 && !isCaret && isCorrectFormatForNode;
|
14525 | };
|
14526 | walk$3(dom, rng, nodes => {
|
14527 | let currentWrapElm;
|
14528 | const process = node => {
|
14529 | let hasContentEditableState = false;
|
14530 | let lastContentEditable = contentEditable;
|
14531 | let isWrappableNoneditableElm = false;
|
14532 | const parentNode = node.parentNode;
|
14533 | const parentName = parentNode.nodeName.toLowerCase();
|
14534 | const contentEditableValue = dom.getContentEditable(node);
|
14535 | if (isNonNullable(contentEditableValue)) {
|
14536 | lastContentEditable = contentEditable;
|
14537 | contentEditable = contentEditableValue === 'true';
|
14538 | hasContentEditableState = true;
|
14539 | isWrappableNoneditableElm = isWrappableNoneditable(ed, node);
|
14540 | }
|
14541 | const isEditableDescendant = contentEditable && !hasContentEditableState;
|
14542 | if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) {
|
14543 | currentWrapElm = null;
|
14544 | if (isBlockFormat(format)) {
|
14545 | dom.remove(node);
|
14546 | }
|
14547 | return;
|
14548 | }
|
14549 | if (isMatchingWrappingBlock(node)) {
|
14550 | currentWrapElm = null;
|
14551 | return;
|
14552 | }
|
14553 | if (canRenameBlock(node, parentName, isEditableDescendant)) {
|
14554 | const elm = dom.rename(node, wrapName);
|
14555 | setElementFormat(elm);
|
14556 | newWrappers.push(elm);
|
14557 | currentWrapElm = null;
|
14558 | return;
|
14559 | }
|
14560 | if (isSelectorFormat(format)) {
|
14561 | let found = applyNodeStyle(formatList, node);
|
14562 | if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
|
14563 | found = applyNodeStyle(formatList, parentNode);
|
14564 | }
|
14565 | if (!isInlineFormat(format) || found) {
|
14566 | currentWrapElm = null;
|
14567 | return;
|
14568 | }
|
14569 | }
|
14570 | if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) {
|
14571 | if (!currentWrapElm) {
|
14572 | currentWrapElm = dom.clone(wrapElm, false);
|
14573 | parentNode.insertBefore(currentWrapElm, node);
|
14574 | newWrappers.push(currentWrapElm);
|
14575 | }
|
14576 | if (isWrappableNoneditableElm && hasContentEditableState) {
|
14577 | contentEditable = lastContentEditable;
|
14578 | }
|
14579 | currentWrapElm.appendChild(node);
|
14580 | } else {
|
14581 | currentWrapElm = null;
|
14582 | each$e(from(node.childNodes), process);
|
14583 | if (hasContentEditableState) {
|
14584 | contentEditable = lastContentEditable;
|
14585 | }
|
14586 | currentWrapElm = null;
|
14587 | }
|
14588 | };
|
14589 | each$e(nodes, process);
|
14590 | });
|
14591 | if (format.links === true) {
|
14592 | each$e(newWrappers, node => {
|
14593 | const process = node => {
|
14594 | if (node.nodeName === 'A') {
|
14595 | setElementFormat(node, format);
|
14596 | }
|
14597 | each$e(from(node.childNodes), process);
|
14598 | };
|
14599 | process(node);
|
14600 | });
|
14601 | }
|
14602 | each$e(newWrappers, node => {
|
14603 | const getChildCount = node => {
|
14604 | let count = 0;
|
14605 | each$e(node.childNodes, node => {
|
14606 | if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) {
|
14607 | count++;
|
14608 | }
|
14609 | });
|
14610 | return count;
|
14611 | };
|
14612 | const mergeStyles = node => {
|
14613 | const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format));
|
14614 | return childElement.map(child => {
|
14615 | const clone = dom.clone(child, false);
|
14616 | setElementFormat(clone);
|
14617 | dom.replace(clone, node, true);
|
14618 | dom.remove(child, true);
|
14619 | return clone;
|
14620 | }).getOr(node);
|
14621 | };
|
14622 | const childCount = getChildCount(node);
|
14623 | if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
|
14624 | dom.remove(node, true);
|
14625 | return;
|
14626 | }
|
14627 | if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
|
14628 | if (!format.exact && childCount === 1) {
|
14629 | node = mergeStyles(node);
|
14630 | }
|
14631 | mergeWithChildren(ed, formatList, vars, node);
|
14632 | mergeWithParents(ed, format, name, vars, node);
|
14633 | mergeBackgroundColorAndFontSize(dom, format, vars, node);
|
14634 | mergeTextDecorationsAndColor(dom, format, vars, node);
|
14635 | mergeSubSup(dom, format, vars, node);
|
14636 | mergeSiblings(ed, format, vars, node);
|
14637 | }
|
14638 | });
|
14639 | };
|
14640 | const targetNode = isNode(node) ? node : selection.getNode();
|
14641 | if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) {
|
14642 | node = targetNode;
|
14643 | applyNodeStyle(formatList, node);
|
14644 | fireFormatApply(ed, name, node, vars);
|
14645 | return;
|
14646 | }
|
14647 | if (format) {
|
14648 | if (node) {
|
14649 | if (isNode(node)) {
|
14650 | if (!applyNodeStyle(formatList, node)) {
|
14651 | const rng = dom.createRng();
|
14652 | rng.setStartBefore(node);
|
14653 | rng.setEndAfter(node);
|
14654 | applyRngStyle(dom, expandRng(dom, rng, formatList), true);
|
14655 | }
|
14656 | } else {
|
14657 | applyRngStyle(dom, node, true);
|
14658 | }
|
14659 | } else {
|
14660 | if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
|
14661 | selection.setRng(normalize(selection.getRng()));
|
14662 | preserveSelection(ed, () => {
|
14663 | runOnRanges(ed, (selectionRng, fake) => {
|
14664 | const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList);
|
14665 | applyRngStyle(dom, expandedRng, false);
|
14666 | });
|
14667 | }, always);
|
14668 | ed.nodeChanged();
|
14669 | } else {
|
14670 | applyCaretFormat(ed, name, vars);
|
14671 | }
|
14672 | getExpandedListItemFormat(ed.formatter, name).each(liFmt => {
|
14673 | each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars));
|
14674 | });
|
14675 | }
|
14676 | postProcess$1(name, ed);
|
14677 | }
|
14678 | fireFormatApply(ed, name, node, vars);
|
14679 | };
|
14680 | const applyFormat$1 = (editor, name, vars, node) => {
|
14681 | if (node || editor.selection.isEditable()) {
|
14682 | applyFormatAction(editor, name, vars, node);
|
14683 | }
|
14684 | };
|
14685 |
|
14686 | const hasVars = value => has$2(value, 'vars');
|
14687 | const setup$u = (registeredFormatListeners, editor) => {
|
14688 | registeredFormatListeners.set({});
|
14689 | editor.on('NodeChange', e => {
|
14690 | updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
|
14691 | });
|
14692 | editor.on('FormatApply FormatRemove', e => {
|
14693 | const element = Optional.from(e.node).map(nodeOrRange => isNode(nodeOrRange) ? nodeOrRange : nodeOrRange.startContainer).bind(node => isElement$6(node) ? Optional.some(node) : Optional.from(node.parentElement)).getOrThunk(() => fallbackElement(editor));
|
14694 | updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
|
14695 | });
|
14696 | };
|
14697 | const fallbackElement = editor => editor.selection.getStart();
|
14698 | const matchingNode = (editor, parents, format, similar, vars) => {
|
14699 | const isMatchingNode = node => {
|
14700 | const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
|
14701 | return !isUndefined(matchingFormat);
|
14702 | };
|
14703 | const isUnableToMatch = node => {
|
14704 | if (matchesUnInheritedFormatSelector(editor, node, format)) {
|
14705 | return true;
|
14706 | } else {
|
14707 | if (!similar) {
|
14708 | return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
|
14709 | } else {
|
14710 | return false;
|
14711 | }
|
14712 | }
|
14713 | };
|
14714 | return findUntil$1(parents, isMatchingNode, isUnableToMatch);
|
14715 | };
|
14716 | const getParents = (editor, elm) => {
|
14717 | const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
|
14718 | return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$1(node));
|
14719 | };
|
14720 | const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
|
14721 | const parents = getParents(editor, elm);
|
14722 | each$d(registeredCallbacks, (data, format) => {
|
14723 | const runIfChanged = spec => {
|
14724 | const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined);
|
14725 | const isSet = match.isSome();
|
14726 | if (spec.state.get() !== isSet) {
|
14727 | spec.state.set(isSet);
|
14728 | const node = match.getOr(elm);
|
14729 | if (hasVars(spec)) {
|
14730 | spec.callback(isSet, {
|
14731 | node,
|
14732 | format,
|
14733 | parents
|
14734 | });
|
14735 | } else {
|
14736 | each$e(spec.callbacks, callback => callback(isSet, {
|
14737 | node,
|
14738 | format,
|
14739 | parents
|
14740 | }));
|
14741 | }
|
14742 | }
|
14743 | };
|
14744 | each$e([
|
14745 | data.withSimilar,
|
14746 | data.withoutSimilar
|
14747 | ], runIfChanged);
|
14748 | each$e(data.withVars, runIfChanged);
|
14749 | });
|
14750 | };
|
14751 | const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
|
14752 | const formatChangeItems = registeredFormatListeners.get();
|
14753 | each$e(formats.split(','), format => {
|
14754 | const group = get$a(formatChangeItems, format).getOrThunk(() => {
|
14755 | const base = {
|
14756 | withSimilar: {
|
14757 | state: Cell(false),
|
14758 | similar: true,
|
14759 | callbacks: []
|
14760 | },
|
14761 | withoutSimilar: {
|
14762 | state: Cell(false),
|
14763 | similar: false,
|
14764 | callbacks: []
|
14765 | },
|
14766 | withVars: []
|
14767 | };
|
14768 | formatChangeItems[format] = base;
|
14769 | return base;
|
14770 | });
|
14771 | const getCurrent = () => {
|
14772 | const parents = getParents(editor);
|
14773 | return matchingNode(editor, parents, format, similar, vars).isSome();
|
14774 | };
|
14775 | if (isUndefined(vars)) {
|
14776 | const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
|
14777 | toAppendTo.callbacks.push(callback);
|
14778 | if (toAppendTo.callbacks.length === 1) {
|
14779 | toAppendTo.state.set(getCurrent());
|
14780 | }
|
14781 | } else {
|
14782 | group.withVars.push({
|
14783 | state: Cell(getCurrent()),
|
14784 | similar,
|
14785 | vars,
|
14786 | callback
|
14787 | });
|
14788 | }
|
14789 | });
|
14790 | registeredFormatListeners.set(formatChangeItems);
|
14791 | };
|
14792 | const removeListeners = (registeredFormatListeners, formats, callback) => {
|
14793 | const formatChangeItems = registeredFormatListeners.get();
|
14794 | each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => {
|
14795 | formatChangeItems[format] = {
|
14796 | withSimilar: {
|
14797 | ...group.withSimilar,
|
14798 | callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback)
|
14799 | },
|
14800 | withoutSimilar: {
|
14801 | ...group.withoutSimilar,
|
14802 | callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback)
|
14803 | },
|
14804 | withVars: filter$5(group.withVars, item => item.callback !== callback)
|
14805 | };
|
14806 | }));
|
14807 | registeredFormatListeners.set(formatChangeItems);
|
14808 | };
|
14809 | const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
|
14810 | addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
|
14811 | return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
|
14812 | };
|
14813 |
|
14814 | const toggle = (editor, name, vars, node) => {
|
14815 | const fmt = editor.formatter.get(name);
|
14816 | if (fmt) {
|
14817 | if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
|
14818 | removeFormat$1(editor, name, vars, node);
|
14819 | } else {
|
14820 | applyFormat$1(editor, name, vars, node);
|
14821 | }
|
14822 | }
|
14823 | };
|
14824 |
|
14825 | const explode$1 = Tools.explode;
|
14826 | const create$8 = () => {
|
14827 | const filters = {};
|
14828 | const addFilter = (name, callback) => {
|
14829 | each$e(explode$1(name), name => {
|
14830 | if (!has$2(filters, name)) {
|
14831 | filters[name] = {
|
14832 | name,
|
14833 | callbacks: []
|
14834 | };
|
14835 | }
|
14836 | filters[name].callbacks.push(callback);
|
14837 | });
|
14838 | };
|
14839 | const getFilters = () => values(filters);
|
14840 | const removeFilter = (name, callback) => {
|
14841 | each$e(explode$1(name), name => {
|
14842 | if (has$2(filters, name)) {
|
14843 | if (isNonNullable(callback)) {
|
14844 | const filter = filters[name];
|
14845 | const newCallbacks = filter$5(filter.callbacks, c => c !== callback);
|
14846 | if (newCallbacks.length > 0) {
|
14847 | filter.callbacks = newCallbacks;
|
14848 | } else {
|
14849 | delete filters[name];
|
14850 | }
|
14851 | } else {
|
14852 | delete filters[name];
|
14853 | }
|
14854 | }
|
14855 | });
|
14856 | };
|
14857 | return {
|
14858 | addFilter,
|
14859 | getFilters,
|
14860 | removeFilter
|
14861 | };
|
14862 | };
|
14863 |
|
14864 | const removeAttrs = (node, names) => {
|
14865 | each$e(names, name => {
|
14866 | node.attr(name, null);
|
14867 | });
|
14868 | };
|
14869 | const addFontToSpansFilter = (domParser, styles, fontSizes) => {
|
14870 | domParser.addNodeFilter('font', nodes => {
|
14871 | each$e(nodes, node => {
|
14872 | const props = styles.parse(node.attr('style'));
|
14873 | const color = node.attr('color');
|
14874 | const face = node.attr('face');
|
14875 | const size = node.attr('size');
|
14876 | if (color) {
|
14877 | props.color = color;
|
14878 | }
|
14879 | if (face) {
|
14880 | props['font-family'] = face;
|
14881 | }
|
14882 | if (size) {
|
14883 | toInt(size).each(num => {
|
14884 | props['font-size'] = fontSizes[num - 1];
|
14885 | });
|
14886 | }
|
14887 | node.name = 'span';
|
14888 | node.attr('style', styles.serialize(props));
|
14889 | removeAttrs(node, [
|
14890 | 'color',
|
14891 | 'face',
|
14892 | 'size'
|
14893 | ]);
|
14894 | });
|
14895 | });
|
14896 | };
|
14897 | const addStrikeFilter = (domParser, schema, styles) => {
|
14898 | domParser.addNodeFilter('strike', nodes => {
|
14899 | const convertToSTag = schema.type !== 'html4';
|
14900 | each$e(nodes, node => {
|
14901 | if (convertToSTag) {
|
14902 | node.name = 's';
|
14903 | } else {
|
14904 | const props = styles.parse(node.attr('style'));
|
14905 | props['text-decoration'] = 'line-through';
|
14906 | node.name = 'span';
|
14907 | node.attr('style', styles.serialize(props));
|
14908 | }
|
14909 | });
|
14910 | });
|
14911 | };
|
14912 | const addFilters = (domParser, settings, schema) => {
|
14913 | var _a;
|
14914 | const styles = Styles();
|
14915 | if (settings.convert_fonts_to_spans) {
|
14916 | addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : ''));
|
14917 | }
|
14918 | addStrikeFilter(domParser, schema, styles);
|
14919 | };
|
14920 | const register$5 = (domParser, settings, schema) => {
|
14921 | if (settings.inline_styles) {
|
14922 | addFilters(domParser, settings, schema);
|
14923 | }
|
14924 | };
|
14925 |
|
14926 | const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject({
|
14927 | message: `Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`,
|
14928 | uriType: 'blob'
|
14929 | }));
|
14930 | const extractBase64Data = data => {
|
14931 | const matches = /([a-z0-9+\/=\s]+)/i.exec(data);
|
14932 | return matches ? matches[1] : '';
|
14933 | };
|
14934 | const parseDataUri = uri => {
|
14935 | const [type, ...rest] = uri.split(',');
|
14936 | const data = rest.join(',');
|
14937 | const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type);
|
14938 | if (matches) {
|
14939 | const base64Encoded = matches[2] === ';base64';
|
14940 | const extractedData = base64Encoded ? extractBase64Data(data) : decodeURIComponent(data);
|
14941 | return Optional.some({
|
14942 | type: matches[1],
|
14943 | data: extractedData,
|
14944 | base64Encoded
|
14945 | });
|
14946 | } else {
|
14947 | return Optional.none();
|
14948 | }
|
14949 | };
|
14950 | const buildBlob = (type, data, base64Encoded = true) => {
|
14951 | let str = data;
|
14952 | if (base64Encoded) {
|
14953 | try {
|
14954 | str = atob(data);
|
14955 | } catch (e) {
|
14956 | return Optional.none();
|
14957 | }
|
14958 | }
|
14959 | const arr = new Uint8Array(str.length);
|
14960 | for (let i = 0; i < arr.length; i++) {
|
14961 | arr[i] = str.charCodeAt(i);
|
14962 | }
|
14963 | return Optional.some(new Blob([arr], { type }));
|
14964 | };
|
14965 | const dataUriToBlob = uri => {
|
14966 | return new Promise((resolve, reject) => {
|
14967 | parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve);
|
14968 | });
|
14969 | };
|
14970 | const uriToBlob = url => {
|
14971 | if (startsWith(url, 'blob:')) {
|
14972 | return blobUriToBlob(url);
|
14973 | } else if (startsWith(url, 'data:')) {
|
14974 | return dataUriToBlob(url);
|
14975 | } else {
|
14976 | return Promise.reject('Unknown URI format');
|
14977 | }
|
14978 | };
|
14979 | const blobToDataUri = blob => {
|
14980 | return new Promise((resolve, reject) => {
|
14981 | const reader = new FileReader();
|
14982 | reader.onloadend = () => {
|
14983 | resolve(reader.result);
|
14984 | };
|
14985 | reader.onerror = () => {
|
14986 | var _a;
|
14987 | reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
|
14988 | };
|
14989 | reader.readAsDataURL(blob);
|
14990 | });
|
14991 | };
|
14992 |
|
14993 | let count$1 = 0;
|
14994 | const uniqueId$1 = prefix => {
|
14995 | return (prefix || 'blobid') + count$1++;
|
14996 | };
|
14997 | const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
|
14998 | return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => {
|
14999 | if (base64Only && !base64Encoded) {
|
15000 | return Optional.none();
|
15001 | } else {
|
15002 | const base64 = base64Encoded ? data : btoa(data);
|
15003 | return generateBlobInfo(base64, type);
|
15004 | }
|
15005 | });
|
15006 | };
|
15007 | const createBlobInfo$1 = (blobCache, blob, base64) => {
|
15008 | const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
|
15009 | blobCache.add(blobInfo);
|
15010 | return blobInfo;
|
15011 | };
|
15012 | const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
|
15013 | return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64))));
|
15014 | };
|
15015 | const imageToBlobInfo = (blobCache, imageSrc) => {
|
15016 | const invalidDataUri = () => Promise.reject('Invalid data URI');
|
15017 | if (startsWith(imageSrc, 'blob:')) {
|
15018 | const blobInfo = blobCache.getByUri(imageSrc);
|
15019 | if (isNonNullable(blobInfo)) {
|
15020 | return Promise.resolve(blobInfo);
|
15021 | } else {
|
15022 | return uriToBlob(imageSrc).then(blob => {
|
15023 | return blobToDataUri(blob).then(dataUri => {
|
15024 | return processDataUri(dataUri, false, base64 => {
|
15025 | return Optional.some(createBlobInfo$1(blobCache, blob, base64));
|
15026 | }).getOrThunk(invalidDataUri);
|
15027 | });
|
15028 | });
|
15029 | }
|
15030 | } else if (startsWith(imageSrc, 'data:')) {
|
15031 | return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo));
|
15032 | } else {
|
15033 | return Promise.reject('Unknown image data format');
|
15034 | }
|
15035 | };
|
15036 |
|
15037 | const hostCaptureRegex = /^(?:(?:(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)([A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*))(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?)$/;
|
15038 | const extractHost = url => Optional.from(url.match(hostCaptureRegex)).bind(ms => get$b(ms, 1)).map(h => startsWith(h, 'www.') ? h.substring(4) : h);
|
15039 |
|
15040 | const sandboxIframe = (iframeNode, exclusions) => {
|
15041 | if (Optional.from(iframeNode.attr('src')).bind(extractHost).forall(host => !contains$2(exclusions, host))) {
|
15042 | iframeNode.attr('sandbox', '');
|
15043 | }
|
15044 | };
|
15045 | const isMimeType = (mime, type) => startsWith(mime, `${ type }/`);
|
15046 | const getEmbedType = type => {
|
15047 | if (isUndefined(type)) {
|
15048 | return 'iframe';
|
15049 | } else if (isMimeType(type, 'image')) {
|
15050 | return 'img';
|
15051 | } else if (isMimeType(type, 'video')) {
|
15052 | return 'video';
|
15053 | } else if (isMimeType(type, 'audio')) {
|
15054 | return 'audio';
|
15055 | } else {
|
15056 | return 'iframe';
|
15057 | }
|
15058 | };
|
15059 | const createSafeEmbed = ({type, src, width, height} = {}, sandboxIframes, sandboxIframesExclusions) => {
|
15060 | const name = getEmbedType(type);
|
15061 | const embed = new AstNode(name, 1);
|
15062 | embed.attr(name === 'audio' ? { src } : {
|
15063 | src,
|
15064 | width,
|
15065 | height
|
15066 | });
|
15067 | if (name === 'audio' || name === 'video') {
|
15068 | embed.attr('controls', '');
|
15069 | }
|
15070 | if (name === 'iframe' && sandboxIframes) {
|
15071 | sandboxIframe(embed, sandboxIframesExclusions);
|
15072 | }
|
15073 | return embed;
|
15074 | };
|
15075 |
|
15076 | const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus'));
|
15077 | const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder'));
|
15078 | const registerBase64ImageFilter = (parser, settings) => {
|
15079 | const {blob_cache: blobCache} = settings;
|
15080 | if (blobCache) {
|
15081 | const processImage = img => {
|
15082 | const inputSrc = img.attr('src');
|
15083 | if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) {
|
15084 | return;
|
15085 | }
|
15086 | dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => {
|
15087 | img.attr('src', blobInfo.blobUri());
|
15088 | });
|
15089 | };
|
15090 | parser.addAttributeFilter('src', nodes => each$e(nodes, processImage));
|
15091 | }
|
15092 | };
|
15093 | const register$4 = (parser, settings) => {
|
15094 | var _a, _b;
|
15095 | const schema = parser.schema;
|
15096 | parser.addAttributeFilter('href', nodes => {
|
15097 | let i = nodes.length;
|
15098 | const appendRel = rel => {
|
15099 | const parts = rel.split(' ').filter(p => p.length > 0);
|
15100 | return parts.concat(['noopener']).sort().join(' ');
|
15101 | };
|
15102 | const addNoOpener = rel => {
|
15103 | const newRel = rel ? Tools.trim(rel) : '';
|
15104 | if (!/\b(noopener)\b/g.test(newRel)) {
|
15105 | return appendRel(newRel);
|
15106 | } else {
|
15107 | return newRel;
|
15108 | }
|
15109 | };
|
15110 | if (!settings.allow_unsafe_link_target) {
|
15111 | while (i--) {
|
15112 | const node = nodes[i];
|
15113 | if (node.name === 'a' && node.attr('target') === '_blank') {
|
15114 | node.attr('rel', addNoOpener(node.attr('rel')));
|
15115 | }
|
15116 | }
|
15117 | }
|
15118 | });
|
15119 | if (!settings.allow_html_in_named_anchor) {
|
15120 | parser.addAttributeFilter('id,name', nodes => {
|
15121 | let i = nodes.length, sibling, prevSibling, parent, node;
|
15122 | while (i--) {
|
15123 | node = nodes[i];
|
15124 | if (node.name === 'a' && node.firstChild && !node.attr('href')) {
|
15125 | parent = node.parent;
|
15126 | sibling = node.lastChild;
|
15127 | while (sibling && parent) {
|
15128 | prevSibling = sibling.prev;
|
15129 | parent.insert(sibling, node);
|
15130 | sibling = prevSibling;
|
15131 | }
|
15132 | }
|
15133 | }
|
15134 | });
|
15135 | }
|
15136 | if (settings.fix_list_elements) {
|
15137 | parser.addNodeFilter('ul,ol', nodes => {
|
15138 | let i = nodes.length, node, parentNode;
|
15139 | while (i--) {
|
15140 | node = nodes[i];
|
15141 | parentNode = node.parent;
|
15142 | if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) {
|
15143 | if (node.prev && node.prev.name === 'li') {
|
15144 | node.prev.append(node);
|
15145 | } else {
|
15146 | const li = new AstNode('li', 1);
|
15147 | li.attr('style', 'list-style-type: none');
|
15148 | node.wrap(li);
|
15149 | }
|
15150 | }
|
15151 | }
|
15152 | });
|
15153 | }
|
15154 | const validClasses = schema.getValidClasses();
|
15155 | if (settings.validate && validClasses) {
|
15156 | parser.addAttributeFilter('class', nodes => {
|
15157 | var _a;
|
15158 | let i = nodes.length;
|
15159 | while (i--) {
|
15160 | const node = nodes[i];
|
15161 | const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : '';
|
15162 | const classList = Tools.explode(clazz, ' ');
|
15163 | let classValue = '';
|
15164 | for (let ci = 0; ci < classList.length; ci++) {
|
15165 | const className = classList[ci];
|
15166 | let valid = false;
|
15167 | let validClassesMap = validClasses['*'];
|
15168 | if (validClassesMap && validClassesMap[className]) {
|
15169 | valid = true;
|
15170 | }
|
15171 | validClassesMap = validClasses[node.name];
|
15172 | if (!valid && validClassesMap && validClassesMap[className]) {
|
15173 | valid = true;
|
15174 | }
|
15175 | if (valid) {
|
15176 | if (classValue) {
|
15177 | classValue += ' ';
|
15178 | }
|
15179 | classValue += className;
|
15180 | }
|
15181 | }
|
15182 | if (!classValue.length) {
|
15183 | classValue = null;
|
15184 | }
|
15185 | node.attr('class', classValue);
|
15186 | }
|
15187 | });
|
15188 | }
|
15189 | registerBase64ImageFilter(parser, settings);
|
15190 | const shouldSandboxIframes = (_a = settings.sandbox_iframes) !== null && _a !== void 0 ? _a : false;
|
15191 | const sandboxIframesExclusions = unique$1((_b = settings.sandbox_iframes_exclusions) !== null && _b !== void 0 ? _b : []);
|
15192 | if (settings.convert_unsafe_embeds) {
|
15193 | parser.addNodeFilter('object,embed', nodes => each$e(nodes, node => {
|
15194 | node.replace(createSafeEmbed({
|
15195 | type: node.attr('type'),
|
15196 | src: node.name === 'object' ? node.attr('data') : node.attr('src'),
|
15197 | width: node.attr('width'),
|
15198 | height: node.attr('height')
|
15199 | }, shouldSandboxIframes, sandboxIframesExclusions));
|
15200 | }));
|
15201 | }
|
15202 | if (shouldSandboxIframes) {
|
15203 | parser.addNodeFilter('iframe', nodes => each$e(nodes, node => sandboxIframe(node, sandboxIframesExclusions)));
|
15204 | }
|
15205 | };
|
15206 |
|
15207 | const {entries, setPrototypeOf, isFrozen, getPrototypeOf, getOwnPropertyDescriptor} = Object;
|
15208 | let {freeze, seal, create: create$7} = Object;
|
15209 | let {apply, construct} = typeof Reflect !== 'undefined' && Reflect;
|
15210 | if (!apply) {
|
15211 | apply = function apply(fun, thisValue, args) {
|
15212 | return fun.apply(thisValue, args);
|
15213 | };
|
15214 | }
|
15215 | if (!freeze) {
|
15216 | freeze = function freeze(x) {
|
15217 | return x;
|
15218 | };
|
15219 | }
|
15220 | if (!seal) {
|
15221 | seal = function seal(x) {
|
15222 | return x;
|
15223 | };
|
15224 | }
|
15225 | if (!construct) {
|
15226 | construct = function construct(Func, args) {
|
15227 | return new Func(...args);
|
15228 | };
|
15229 | }
|
15230 | const arrayForEach = unapply(Array.prototype.forEach);
|
15231 | const arrayPop = unapply(Array.prototype.pop);
|
15232 | const arrayPush = unapply(Array.prototype.push);
|
15233 | const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
15234 | const stringToString = unapply(String.prototype.toString);
|
15235 | const stringMatch = unapply(String.prototype.match);
|
15236 | const stringReplace = unapply(String.prototype.replace);
|
15237 | const stringIndexOf = unapply(String.prototype.indexOf);
|
15238 | const stringTrim = unapply(String.prototype.trim);
|
15239 | const regExpTest = unapply(RegExp.prototype.test);
|
15240 | const typeErrorCreate = unconstruct(TypeError);
|
15241 | function unapply(func) {
|
15242 | return function (thisArg) {
|
15243 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
15244 | args[_key - 1] = arguments[_key];
|
15245 | }
|
15246 | return apply(func, thisArg, args);
|
15247 | };
|
15248 | }
|
15249 | function unconstruct(func) {
|
15250 | return function () {
|
15251 | for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
15252 | args[_key2] = arguments[_key2];
|
15253 | }
|
15254 | return construct(func, args);
|
15255 | };
|
15256 | }
|
15257 | function addToSet(set, array, transformCaseFunc) {
|
15258 | var _transformCaseFunc;
|
15259 | transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;
|
15260 | if (setPrototypeOf) {
|
15261 | setPrototypeOf(set, null);
|
15262 | }
|
15263 | let l = array.length;
|
15264 | while (l--) {
|
15265 | let element = array[l];
|
15266 | if (typeof element === 'string') {
|
15267 | const lcElement = transformCaseFunc(element);
|
15268 | if (lcElement !== element) {
|
15269 | if (!isFrozen(array)) {
|
15270 | array[l] = lcElement;
|
15271 | }
|
15272 | element = lcElement;
|
15273 | }
|
15274 | }
|
15275 | set[element] = true;
|
15276 | }
|
15277 | return set;
|
15278 | }
|
15279 | function clone(object) {
|
15280 | const newObject = create$7(null);
|
15281 | for (const [property, value] of entries(object)) {
|
15282 | newObject[property] = value;
|
15283 | }
|
15284 | return newObject;
|
15285 | }
|
15286 | function lookupGetter(object, prop) {
|
15287 | while (object !== null) {
|
15288 | const desc = getOwnPropertyDescriptor(object, prop);
|
15289 | if (desc) {
|
15290 | if (desc.get) {
|
15291 | return unapply(desc.get);
|
15292 | }
|
15293 | if (typeof desc.value === 'function') {
|
15294 | return unapply(desc.value);
|
15295 | }
|
15296 | }
|
15297 | object = getPrototypeOf(object);
|
15298 | }
|
15299 | function fallbackValue(element) {
|
15300 | console.warn('fallback value for', element);
|
15301 | return null;
|
15302 | }
|
15303 | return fallbackValue;
|
15304 | }
|
15305 | const html$1 = freeze([
|
15306 | 'a',
|
15307 | 'abbr',
|
15308 | 'acronym',
|
15309 | 'address',
|
15310 | 'area',
|
15311 | 'article',
|
15312 | 'aside',
|
15313 | 'audio',
|
15314 | 'b',
|
15315 | 'bdi',
|
15316 | 'bdo',
|
15317 | 'big',
|
15318 | 'blink',
|
15319 | 'blockquote',
|
15320 | 'body',
|
15321 | 'br',
|
15322 | 'button',
|
15323 | 'canvas',
|
15324 | 'caption',
|
15325 | 'center',
|
15326 | 'cite',
|
15327 | 'code',
|
15328 | 'col',
|
15329 | 'colgroup',
|
15330 | 'content',
|
15331 | 'data',
|
15332 | 'datalist',
|
15333 | 'dd',
|
15334 | 'decorator',
|
15335 | 'del',
|
15336 | 'details',
|
15337 | 'dfn',
|
15338 | 'dialog',
|
15339 | 'dir',
|
15340 | 'div',
|
15341 | 'dl',
|
15342 | 'dt',
|
15343 | 'element',
|
15344 | 'em',
|
15345 | 'fieldset',
|
15346 | 'figcaption',
|
15347 | 'figure',
|
15348 | 'font',
|
15349 | 'footer',
|
15350 | 'form',
|
15351 | 'h1',
|
15352 | 'h2',
|
15353 | 'h3',
|
15354 | 'h4',
|
15355 | 'h5',
|
15356 | 'h6',
|
15357 | 'head',
|
15358 | 'header',
|
15359 | 'hgroup',
|
15360 | 'hr',
|
15361 | 'html',
|
15362 | 'i',
|
15363 | 'img',
|
15364 | 'input',
|
15365 | 'ins',
|
15366 | 'kbd',
|
15367 | 'label',
|
15368 | 'legend',
|
15369 | 'li',
|
15370 | 'main',
|
15371 | 'map',
|
15372 | 'mark',
|
15373 | 'marquee',
|
15374 | 'menu',
|
15375 | 'menuitem',
|
15376 | 'meter',
|
15377 | 'nav',
|
15378 | 'nobr',
|
15379 | 'ol',
|
15380 | 'optgroup',
|
15381 | 'option',
|
15382 | 'output',
|
15383 | 'p',
|
15384 | 'picture',
|
15385 | 'pre',
|
15386 | 'progress',
|
15387 | 'q',
|
15388 | 'rp',
|
15389 | 'rt',
|
15390 | 'ruby',
|
15391 | 's',
|
15392 | 'samp',
|
15393 | 'section',
|
15394 | 'select',
|
15395 | 'shadow',
|
15396 | 'small',
|
15397 | 'source',
|
15398 | 'spacer',
|
15399 | 'span',
|
15400 | 'strike',
|
15401 | 'strong',
|
15402 | 'style',
|
15403 | 'sub',
|
15404 | 'summary',
|
15405 | 'sup',
|
15406 | 'table',
|
15407 | 'tbody',
|
15408 | 'td',
|
15409 | 'template',
|
15410 | 'textarea',
|
15411 | 'tfoot',
|
15412 | 'th',
|
15413 | 'thead',
|
15414 | 'time',
|
15415 | 'tr',
|
15416 | 'track',
|
15417 | 'tt',
|
15418 | 'u',
|
15419 | 'ul',
|
15420 | 'var',
|
15421 | 'video',
|
15422 | 'wbr'
|
15423 | ]);
|
15424 | const svg$1 = freeze([
|
15425 | 'svg',
|
15426 | 'a',
|
15427 | 'altglyph',
|
15428 | 'altglyphdef',
|
15429 | 'altglyphitem',
|
15430 | 'animatecolor',
|
15431 | 'animatemotion',
|
15432 | 'animatetransform',
|
15433 | 'circle',
|
15434 | 'clippath',
|
15435 | 'defs',
|
15436 | 'desc',
|
15437 | 'ellipse',
|
15438 | 'filter',
|
15439 | 'font',
|
15440 | 'g',
|
15441 | 'glyph',
|
15442 | 'glyphref',
|
15443 | 'hkern',
|
15444 | 'image',
|
15445 | 'line',
|
15446 | 'lineargradient',
|
15447 | 'marker',
|
15448 | 'mask',
|
15449 | 'metadata',
|
15450 | 'mpath',
|
15451 | 'path',
|
15452 | 'pattern',
|
15453 | 'polygon',
|
15454 | 'polyline',
|
15455 | 'radialgradient',
|
15456 | 'rect',
|
15457 | 'stop',
|
15458 | 'style',
|
15459 | 'switch',
|
15460 | 'symbol',
|
15461 | 'text',
|
15462 | 'textpath',
|
15463 | 'title',
|
15464 | 'tref',
|
15465 | 'tspan',
|
15466 | 'view',
|
15467 | 'vkern'
|
15468 | ]);
|
15469 | const svgFilters = freeze([
|
15470 | 'feBlend',
|
15471 | 'feColorMatrix',
|
15472 | 'feComponentTransfer',
|
15473 | 'feComposite',
|
15474 | 'feConvolveMatrix',
|
15475 | 'feDiffuseLighting',
|
15476 | 'feDisplacementMap',
|
15477 | 'feDistantLight',
|
15478 | 'feDropShadow',
|
15479 | 'feFlood',
|
15480 | 'feFuncA',
|
15481 | 'feFuncB',
|
15482 | 'feFuncG',
|
15483 | 'feFuncR',
|
15484 | 'feGaussianBlur',
|
15485 | 'feImage',
|
15486 | 'feMerge',
|
15487 | 'feMergeNode',
|
15488 | 'feMorphology',
|
15489 | 'feOffset',
|
15490 | 'fePointLight',
|
15491 | 'feSpecularLighting',
|
15492 | 'feSpotLight',
|
15493 | 'feTile',
|
15494 | 'feTurbulence'
|
15495 | ]);
|
15496 | const svgDisallowed = freeze([
|
15497 | 'animate',
|
15498 | 'color-profile',
|
15499 | 'cursor',
|
15500 | 'discard',
|
15501 | 'font-face',
|
15502 | 'font-face-format',
|
15503 | 'font-face-name',
|
15504 | 'font-face-src',
|
15505 | 'font-face-uri',
|
15506 | 'foreignobject',
|
15507 | 'hatch',
|
15508 | 'hatchpath',
|
15509 | 'mesh',
|
15510 | 'meshgradient',
|
15511 | 'meshpatch',
|
15512 | 'meshrow',
|
15513 | 'missing-glyph',
|
15514 | 'script',
|
15515 | 'set',
|
15516 | 'solidcolor',
|
15517 | 'unknown',
|
15518 | 'use'
|
15519 | ]);
|
15520 | const mathMl$1 = freeze([
|
15521 | 'math',
|
15522 | 'menclose',
|
15523 | 'merror',
|
15524 | 'mfenced',
|
15525 | 'mfrac',
|
15526 | 'mglyph',
|
15527 | 'mi',
|
15528 | 'mlabeledtr',
|
15529 | 'mmultiscripts',
|
15530 | 'mn',
|
15531 | 'mo',
|
15532 | 'mover',
|
15533 | 'mpadded',
|
15534 | 'mphantom',
|
15535 | 'mroot',
|
15536 | 'mrow',
|
15537 | 'ms',
|
15538 | 'mspace',
|
15539 | 'msqrt',
|
15540 | 'mstyle',
|
15541 | 'msub',
|
15542 | 'msup',
|
15543 | 'msubsup',
|
15544 | 'mtable',
|
15545 | 'mtd',
|
15546 | 'mtext',
|
15547 | 'mtr',
|
15548 | 'munder',
|
15549 | 'munderover',
|
15550 | 'mprescripts'
|
15551 | ]);
|
15552 | const mathMlDisallowed = freeze([
|
15553 | 'maction',
|
15554 | 'maligngroup',
|
15555 | 'malignmark',
|
15556 | 'mlongdiv',
|
15557 | 'mscarries',
|
15558 | 'mscarry',
|
15559 | 'msgroup',
|
15560 | 'mstack',
|
15561 | 'msline',
|
15562 | 'msrow',
|
15563 | 'semantics',
|
15564 | 'annotation',
|
15565 | 'annotation-xml',
|
15566 | 'mprescripts',
|
15567 | 'none'
|
15568 | ]);
|
15569 | const text = freeze(['#text']);
|
15570 | const html = freeze([
|
15571 | 'accept',
|
15572 | 'action',
|
15573 | 'align',
|
15574 | 'alt',
|
15575 | 'autocapitalize',
|
15576 | 'autocomplete',
|
15577 | 'autopictureinpicture',
|
15578 | 'autoplay',
|
15579 | 'background',
|
15580 | 'bgcolor',
|
15581 | 'border',
|
15582 | 'capture',
|
15583 | 'cellpadding',
|
15584 | 'cellspacing',
|
15585 | 'checked',
|
15586 | 'cite',
|
15587 | 'class',
|
15588 | 'clear',
|
15589 | 'color',
|
15590 | 'cols',
|
15591 | 'colspan',
|
15592 | 'controls',
|
15593 | 'controlslist',
|
15594 | 'coords',
|
15595 | 'crossorigin',
|
15596 | 'datetime',
|
15597 | 'decoding',
|
15598 | 'default',
|
15599 | 'dir',
|
15600 | 'disabled',
|
15601 | 'disablepictureinpicture',
|
15602 | 'disableremoteplayback',
|
15603 | 'download',
|
15604 | 'draggable',
|
15605 | 'enctype',
|
15606 | 'enterkeyhint',
|
15607 | 'face',
|
15608 | 'for',
|
15609 | 'headers',
|
15610 | 'height',
|
15611 | 'hidden',
|
15612 | 'high',
|
15613 | 'href',
|
15614 | 'hreflang',
|
15615 | 'id',
|
15616 | 'inputmode',
|
15617 | 'integrity',
|
15618 | 'ismap',
|
15619 | 'kind',
|
15620 | 'label',
|
15621 | 'lang',
|
15622 | 'list',
|
15623 | 'loading',
|
15624 | 'loop',
|
15625 | 'low',
|
15626 | 'max',
|
15627 | 'maxlength',
|
15628 | 'media',
|
15629 | 'method',
|
15630 | 'min',
|
15631 | 'minlength',
|
15632 | 'multiple',
|
15633 | 'muted',
|
15634 | 'name',
|
15635 | 'nonce',
|
15636 | 'noshade',
|
15637 | 'novalidate',
|
15638 | 'nowrap',
|
15639 | 'open',
|
15640 | 'optimum',
|
15641 | 'pattern',
|
15642 | 'placeholder',
|
15643 | 'playsinline',
|
15644 | 'poster',
|
15645 | 'preload',
|
15646 | 'pubdate',
|
15647 | 'radiogroup',
|
15648 | 'readonly',
|
15649 | 'rel',
|
15650 | 'required',
|
15651 | 'rev',
|
15652 | 'reversed',
|
15653 | 'role',
|
15654 | 'rows',
|
15655 | 'rowspan',
|
15656 | 'spellcheck',
|
15657 | 'scope',
|
15658 | 'selected',
|
15659 | 'shape',
|
15660 | 'size',
|
15661 | 'sizes',
|
15662 | 'span',
|
15663 | 'srclang',
|
15664 | 'start',
|
15665 | 'src',
|
15666 | 'srcset',
|
15667 | 'step',
|
15668 | 'style',
|
15669 | 'summary',
|
15670 | 'tabindex',
|
15671 | 'title',
|
15672 | 'translate',
|
15673 | 'type',
|
15674 | 'usemap',
|
15675 | 'valign',
|
15676 | 'value',
|
15677 | 'width',
|
15678 | 'xmlns',
|
15679 | 'slot'
|
15680 | ]);
|
15681 | const svg = freeze([
|
15682 | 'accent-height',
|
15683 | 'accumulate',
|
15684 | 'additive',
|
15685 | 'alignment-baseline',
|
15686 | 'ascent',
|
15687 | 'attributename',
|
15688 | 'attributetype',
|
15689 | 'azimuth',
|
15690 | 'basefrequency',
|
15691 | 'baseline-shift',
|
15692 | 'begin',
|
15693 | 'bias',
|
15694 | 'by',
|
15695 | 'class',
|
15696 | 'clip',
|
15697 | 'clippathunits',
|
15698 | 'clip-path',
|
15699 | 'clip-rule',
|
15700 | 'color',
|
15701 | 'color-interpolation',
|
15702 | 'color-interpolation-filters',
|
15703 | 'color-profile',
|
15704 | 'color-rendering',
|
15705 | 'cx',
|
15706 | 'cy',
|
15707 | 'd',
|
15708 | 'dx',
|
15709 | 'dy',
|
15710 | 'diffuseconstant',
|
15711 | 'direction',
|
15712 | 'display',
|
15713 | 'divisor',
|
15714 | 'dur',
|
15715 | 'edgemode',
|
15716 | 'elevation',
|
15717 | 'end',
|
15718 | 'fill',
|
15719 | 'fill-opacity',
|
15720 | 'fill-rule',
|
15721 | 'filter',
|
15722 | 'filterunits',
|
15723 | 'flood-color',
|
15724 | 'flood-opacity',
|
15725 | 'font-family',
|
15726 | 'font-size',
|
15727 | 'font-size-adjust',
|
15728 | 'font-stretch',
|
15729 | 'font-style',
|
15730 | 'font-variant',
|
15731 | 'font-weight',
|
15732 | 'fx',
|
15733 | 'fy',
|
15734 | 'g1',
|
15735 | 'g2',
|
15736 | 'glyph-name',
|
15737 | 'glyphref',
|
15738 | 'gradientunits',
|
15739 | 'gradienttransform',
|
15740 | 'height',
|
15741 | 'href',
|
15742 | 'id',
|
15743 | 'image-rendering',
|
15744 | 'in',
|
15745 | 'in2',
|
15746 | 'k',
|
15747 | 'k1',
|
15748 | 'k2',
|
15749 | 'k3',
|
15750 | 'k4',
|
15751 | 'kerning',
|
15752 | 'keypoints',
|
15753 | 'keysplines',
|
15754 | 'keytimes',
|
15755 | 'lang',
|
15756 | 'lengthadjust',
|
15757 | 'letter-spacing',
|
15758 | 'kernelmatrix',
|
15759 | 'kernelunitlength',
|
15760 | 'lighting-color',
|
15761 | 'local',
|
15762 | 'marker-end',
|
15763 | 'marker-mid',
|
15764 | 'marker-start',
|
15765 | 'markerheight',
|
15766 | 'markerunits',
|
15767 | 'markerwidth',
|
15768 | 'maskcontentunits',
|
15769 | 'maskunits',
|
15770 | 'max',
|
15771 | 'mask',
|
15772 | 'media',
|
15773 | 'method',
|
15774 | 'mode',
|
15775 | 'min',
|
15776 | 'name',
|
15777 | 'numoctaves',
|
15778 | 'offset',
|
15779 | 'operator',
|
15780 | 'opacity',
|
15781 | 'order',
|
15782 | 'orient',
|
15783 | 'orientation',
|
15784 | 'origin',
|
15785 | 'overflow',
|
15786 | 'paint-order',
|
15787 | 'path',
|
15788 | 'pathlength',
|
15789 | 'patterncontentunits',
|
15790 | 'patterntransform',
|
15791 | 'patternunits',
|
15792 | 'points',
|
15793 | 'preservealpha',
|
15794 | 'preserveaspectratio',
|
15795 | 'primitiveunits',
|
15796 | 'r',
|
15797 | 'rx',
|
15798 | 'ry',
|
15799 | 'radius',
|
15800 | 'refx',
|
15801 | 'refy',
|
15802 | 'repeatcount',
|
15803 | 'repeatdur',
|
15804 | 'restart',
|
15805 | 'result',
|
15806 | 'rotate',
|
15807 | 'scale',
|
15808 | 'seed',
|
15809 | 'shape-rendering',
|
15810 | 'specularconstant',
|
15811 | 'specularexponent',
|
15812 | 'spreadmethod',
|
15813 | 'startoffset',
|
15814 | 'stddeviation',
|
15815 | 'stitchtiles',
|
15816 | 'stop-color',
|
15817 | 'stop-opacity',
|
15818 | 'stroke-dasharray',
|
15819 | 'stroke-dashoffset',
|
15820 | 'stroke-linecap',
|
15821 | 'stroke-linejoin',
|
15822 | 'stroke-miterlimit',
|
15823 | 'stroke-opacity',
|
15824 | 'stroke',
|
15825 | 'stroke-width',
|
15826 | 'style',
|
15827 | 'surfacescale',
|
15828 | 'systemlanguage',
|
15829 | 'tabindex',
|
15830 | 'targetx',
|
15831 | 'targety',
|
15832 | 'transform',
|
15833 | 'transform-origin',
|
15834 | 'text-anchor',
|
15835 | 'text-decoration',
|
15836 | 'text-rendering',
|
15837 | 'textlength',
|
15838 | 'type',
|
15839 | 'u1',
|
15840 | 'u2',
|
15841 | 'unicode',
|
15842 | 'values',
|
15843 | 'viewbox',
|
15844 | 'visibility',
|
15845 | 'version',
|
15846 | 'vert-adv-y',
|
15847 | 'vert-origin-x',
|
15848 | 'vert-origin-y',
|
15849 | 'width',
|
15850 | 'word-spacing',
|
15851 | 'wrap',
|
15852 | 'writing-mode',
|
15853 | 'xchannelselector',
|
15854 | 'ychannelselector',
|
15855 | 'x',
|
15856 | 'x1',
|
15857 | 'x2',
|
15858 | 'xmlns',
|
15859 | 'y',
|
15860 | 'y1',
|
15861 | 'y2',
|
15862 | 'z',
|
15863 | 'zoomandpan'
|
15864 | ]);
|
15865 | const mathMl = freeze([
|
15866 | 'accent',
|
15867 | 'accentunder',
|
15868 | 'align',
|
15869 | 'bevelled',
|
15870 | 'close',
|
15871 | 'columnsalign',
|
15872 | 'columnlines',
|
15873 | 'columnspan',
|
15874 | 'denomalign',
|
15875 | 'depth',
|
15876 | 'dir',
|
15877 | 'display',
|
15878 | 'displaystyle',
|
15879 | 'encoding',
|
15880 | 'fence',
|
15881 | 'frame',
|
15882 | 'height',
|
15883 | 'href',
|
15884 | 'id',
|
15885 | 'largeop',
|
15886 | 'length',
|
15887 | 'linethickness',
|
15888 | 'lspace',
|
15889 | 'lquote',
|
15890 | 'mathbackground',
|
15891 | 'mathcolor',
|
15892 | 'mathsize',
|
15893 | 'mathvariant',
|
15894 | 'maxsize',
|
15895 | 'minsize',
|
15896 | 'movablelimits',
|
15897 | 'notation',
|
15898 | 'numalign',
|
15899 | 'open',
|
15900 | 'rowalign',
|
15901 | 'rowlines',
|
15902 | 'rowspacing',
|
15903 | 'rowspan',
|
15904 | 'rspace',
|
15905 | 'rquote',
|
15906 | 'scriptlevel',
|
15907 | 'scriptminsize',
|
15908 | 'scriptsizemultiplier',
|
15909 | 'selection',
|
15910 | 'separator',
|
15911 | 'separators',
|
15912 | 'stretchy',
|
15913 | 'subscriptshift',
|
15914 | 'supscriptshift',
|
15915 | 'symmetric',
|
15916 | 'voffset',
|
15917 | 'width',
|
15918 | 'xmlns'
|
15919 | ]);
|
15920 | const xml = freeze([
|
15921 | 'xlink:href',
|
15922 | 'xml:id',
|
15923 | 'xlink:title',
|
15924 | 'xml:space',
|
15925 | 'xmlns:xlink'
|
15926 | ]);
|
15927 | const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
|
15928 | const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
15929 | const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
|
15930 | const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
|
15931 | const ARIA_ATTR = seal(/^aria-[\-\w]+$/);
|
15932 | const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
|
15933 | const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
15934 | const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
|
15935 | const DOCTYPE_NAME = seal(/^html$/i);
|
15936 | var EXPRESSIONS = Object.freeze({
|
15937 | __proto__: null,
|
15938 | MUSTACHE_EXPR: MUSTACHE_EXPR,
|
15939 | ERB_EXPR: ERB_EXPR,
|
15940 | TMPLIT_EXPR: TMPLIT_EXPR,
|
15941 | DATA_ATTR: DATA_ATTR,
|
15942 | ARIA_ATTR: ARIA_ATTR,
|
15943 | IS_ALLOWED_URI: IS_ALLOWED_URI,
|
15944 | IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
15945 | ATTR_WHITESPACE: ATTR_WHITESPACE,
|
15946 | DOCTYPE_NAME: DOCTYPE_NAME
|
15947 | });
|
15948 | const getGlobal = () => typeof window === 'undefined' ? null : window;
|
15949 | const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
15950 | if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
15951 | return null;
|
15952 | }
|
15953 | let suffix = null;
|
15954 | const ATTR_NAME = 'data-tt-policy-suffix';
|
15955 | if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
|
15956 | suffix = purifyHostElement.getAttribute(ATTR_NAME);
|
15957 | }
|
15958 | const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
|
15959 | try {
|
15960 | return trustedTypes.createPolicy(policyName, {
|
15961 | createHTML(html) {
|
15962 | return html;
|
15963 | },
|
15964 | createScriptURL(scriptUrl) {
|
15965 | return scriptUrl;
|
15966 | }
|
15967 | });
|
15968 | } catch (_) {
|
15969 | console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
|
15970 | return null;
|
15971 | }
|
15972 | };
|
15973 | function createDOMPurify() {
|
15974 | let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
15975 | const DOMPurify = root => createDOMPurify(root);
|
15976 | DOMPurify.version = '3.0.5';
|
15977 | DOMPurify.removed = [];
|
15978 | if (!window || !window.document || window.document.nodeType !== 9) {
|
15979 | DOMPurify.isSupported = false;
|
15980 | return DOMPurify;
|
15981 | }
|
15982 | const originalDocument = window.document;
|
15983 | const currentScript = originalDocument.currentScript;
|
15984 | let {document} = window;
|
15985 | const {DocumentFragment, HTMLTemplateElement, Node, Element, NodeFilter, NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap, HTMLFormElement, DOMParser, trustedTypes} = window;
|
15986 | const ElementPrototype = Element.prototype;
|
15987 | const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
15988 | const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
15989 | const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
15990 | const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
15991 | if (typeof HTMLTemplateElement === 'function') {
|
15992 | const template = document.createElement('template');
|
15993 | if (template.content && template.content.ownerDocument) {
|
15994 | document = template.content.ownerDocument;
|
15995 | }
|
15996 | }
|
15997 | let trustedTypesPolicy;
|
15998 | let emptyHTML = '';
|
15999 | const {implementation, createNodeIterator, createDocumentFragment, getElementsByTagName} = document;
|
16000 | const {importNode} = originalDocument;
|
16001 | let hooks = {};
|
16002 | DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
16003 | const {MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR, DATA_ATTR, ARIA_ATTR, IS_SCRIPT_OR_DATA, ATTR_WHITESPACE} = EXPRESSIONS;
|
16004 | let {IS_ALLOWED_URI: IS_ALLOWED_URI$1} = EXPRESSIONS;
|
16005 | let ALLOWED_TAGS = null;
|
16006 | const DEFAULT_ALLOWED_TAGS = addToSet({}, [
|
16007 | ...html$1,
|
16008 | ...svg$1,
|
16009 | ...svgFilters,
|
16010 | ...mathMl$1,
|
16011 | ...text
|
16012 | ]);
|
16013 | let ALLOWED_ATTR = null;
|
16014 | const DEFAULT_ALLOWED_ATTR = addToSet({}, [
|
16015 | ...html,
|
16016 | ...svg,
|
16017 | ...mathMl,
|
16018 | ...xml
|
16019 | ]);
|
16020 | let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
|
16021 | tagNameCheck: {
|
16022 | writable: true,
|
16023 | configurable: false,
|
16024 | enumerable: true,
|
16025 | value: null
|
16026 | },
|
16027 | attributeNameCheck: {
|
16028 | writable: true,
|
16029 | configurable: false,
|
16030 | enumerable: true,
|
16031 | value: null
|
16032 | },
|
16033 | allowCustomizedBuiltInElements: {
|
16034 | writable: true,
|
16035 | configurable: false,
|
16036 | enumerable: true,
|
16037 | value: false
|
16038 | }
|
16039 | }));
|
16040 | let FORBID_TAGS = null;
|
16041 | let FORBID_ATTR = null;
|
16042 | let ALLOW_ARIA_ATTR = true;
|
16043 | let ALLOW_DATA_ATTR = true;
|
16044 | let ALLOW_UNKNOWN_PROTOCOLS = false;
|
16045 | let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
16046 | let SAFE_FOR_TEMPLATES = false;
|
16047 | let WHOLE_DOCUMENT = false;
|
16048 | let SET_CONFIG = false;
|
16049 | let FORCE_BODY = false;
|
16050 | let RETURN_DOM = false;
|
16051 | let RETURN_DOM_FRAGMENT = false;
|
16052 | let RETURN_TRUSTED_TYPE = false;
|
16053 | let SANITIZE_DOM = true;
|
16054 | let SANITIZE_NAMED_PROPS = false;
|
16055 | const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
16056 | let KEEP_CONTENT = true;
|
16057 | let IN_PLACE = false;
|
16058 | let USE_PROFILES = {};
|
16059 | let FORBID_CONTENTS = null;
|
16060 | const DEFAULT_FORBID_CONTENTS = addToSet({}, [
|
16061 | 'annotation-xml',
|
16062 | 'audio',
|
16063 | 'colgroup',
|
16064 | 'desc',
|
16065 | 'foreignobject',
|
16066 | 'head',
|
16067 | 'iframe',
|
16068 | 'math',
|
16069 | 'mi',
|
16070 | 'mn',
|
16071 | 'mo',
|
16072 | 'ms',
|
16073 | 'mtext',
|
16074 | 'noembed',
|
16075 | 'noframes',
|
16076 | 'noscript',
|
16077 | 'plaintext',
|
16078 | 'script',
|
16079 | 'style',
|
16080 | 'svg',
|
16081 | 'template',
|
16082 | 'thead',
|
16083 | 'title',
|
16084 | 'video',
|
16085 | 'xmp'
|
16086 | ]);
|
16087 | let DATA_URI_TAGS = null;
|
16088 | const DEFAULT_DATA_URI_TAGS = addToSet({}, [
|
16089 | 'audio',
|
16090 | 'video',
|
16091 | 'img',
|
16092 | 'source',
|
16093 | 'image',
|
16094 | 'track'
|
16095 | ]);
|
16096 | let URI_SAFE_ATTRIBUTES = null;
|
16097 | const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
|
16098 | 'alt',
|
16099 | 'class',
|
16100 | 'for',
|
16101 | 'id',
|
16102 | 'label',
|
16103 | 'name',
|
16104 | 'pattern',
|
16105 | 'placeholder',
|
16106 | 'role',
|
16107 | 'summary',
|
16108 | 'title',
|
16109 | 'value',
|
16110 | 'style',
|
16111 | 'xmlns'
|
16112 | ]);
|
16113 | const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
16114 | const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
16115 | const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
16116 | let NAMESPACE = HTML_NAMESPACE;
|
16117 | let IS_EMPTY_INPUT = false;
|
16118 | let ALLOWED_NAMESPACES = null;
|
16119 | const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [
|
16120 | MATHML_NAMESPACE,
|
16121 | SVG_NAMESPACE,
|
16122 | HTML_NAMESPACE
|
16123 | ], stringToString);
|
16124 | let PARSER_MEDIA_TYPE;
|
16125 | const SUPPORTED_PARSER_MEDIA_TYPES = [
|
16126 | 'application/xhtml+xml',
|
16127 | 'text/html'
|
16128 | ];
|
16129 | const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
16130 | let transformCaseFunc;
|
16131 | let CONFIG = null;
|
16132 | const formElement = document.createElement('form');
|
16133 | const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
16134 | return testValue instanceof RegExp || testValue instanceof Function;
|
16135 | };
|
16136 | const _parseConfig = function _parseConfig(cfg) {
|
16137 | if (CONFIG && CONFIG === cfg) {
|
16138 | return;
|
16139 | }
|
16140 | if (!cfg || typeof cfg !== 'object') {
|
16141 | cfg = {};
|
16142 | }
|
16143 | cfg = clone(cfg);
|
16144 | PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
|
16145 | transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
16146 | ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
16147 | ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
16148 | ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
16149 | URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
16150 | DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
16151 | FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
16152 | FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
16153 | FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
16154 | USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
|
16155 | ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
|
16156 | ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
|
16157 | ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
|
16158 | ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false;
|
16159 | SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
|
16160 | WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
|
16161 | RETURN_DOM = cfg.RETURN_DOM || false;
|
16162 | RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
|
16163 | RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
|
16164 | FORCE_BODY = cfg.FORCE_BODY || false;
|
16165 | SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
|
16166 | SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false;
|
16167 | KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
|
16168 | IN_PLACE = cfg.IN_PLACE || false;
|
16169 | IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
16170 | NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
16171 | CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
16172 | if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
16173 | CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
16174 | }
|
16175 | if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
|
16176 | CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
|
16177 | }
|
16178 | if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
|
16179 | CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
|
16180 | }
|
16181 | if (SAFE_FOR_TEMPLATES) {
|
16182 | ALLOW_DATA_ATTR = false;
|
16183 | }
|
16184 | if (RETURN_DOM_FRAGMENT) {
|
16185 | RETURN_DOM = true;
|
16186 | }
|
16187 | if (USE_PROFILES) {
|
16188 | ALLOWED_TAGS = addToSet({}, [...text]);
|
16189 | ALLOWED_ATTR = [];
|
16190 | if (USE_PROFILES.html === true) {
|
16191 | addToSet(ALLOWED_TAGS, html$1);
|
16192 | addToSet(ALLOWED_ATTR, html);
|
16193 | }
|
16194 | if (USE_PROFILES.svg === true) {
|
16195 | addToSet(ALLOWED_TAGS, svg$1);
|
16196 | addToSet(ALLOWED_ATTR, svg);
|
16197 | addToSet(ALLOWED_ATTR, xml);
|
16198 | }
|
16199 | if (USE_PROFILES.svgFilters === true) {
|
16200 | addToSet(ALLOWED_TAGS, svgFilters);
|
16201 | addToSet(ALLOWED_ATTR, svg);
|
16202 | addToSet(ALLOWED_ATTR, xml);
|
16203 | }
|
16204 | if (USE_PROFILES.mathMl === true) {
|
16205 | addToSet(ALLOWED_TAGS, mathMl$1);
|
16206 | addToSet(ALLOWED_ATTR, mathMl);
|
16207 | addToSet(ALLOWED_ATTR, xml);
|
16208 | }
|
16209 | }
|
16210 | if (cfg.ADD_TAGS) {
|
16211 | if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
16212 | ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
16213 | }
|
16214 | addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
16215 | }
|
16216 | if (cfg.ADD_ATTR) {
|
16217 | if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
16218 | ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
16219 | }
|
16220 | addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
16221 | }
|
16222 | if (cfg.ADD_URI_SAFE_ATTR) {
|
16223 | addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
16224 | }
|
16225 | if (cfg.FORBID_CONTENTS) {
|
16226 | if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
16227 | FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
16228 | }
|
16229 | addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
16230 | }
|
16231 | if (KEEP_CONTENT) {
|
16232 | ALLOWED_TAGS['#text'] = true;
|
16233 | }
|
16234 | if (WHOLE_DOCUMENT) {
|
16235 | addToSet(ALLOWED_TAGS, [
|
16236 | 'html',
|
16237 | 'head',
|
16238 | 'body'
|
16239 | ]);
|
16240 | }
|
16241 | if (ALLOWED_TAGS.table) {
|
16242 | addToSet(ALLOWED_TAGS, ['tbody']);
|
16243 | delete FORBID_TAGS.tbody;
|
16244 | }
|
16245 | if (cfg.TRUSTED_TYPES_POLICY) {
|
16246 | if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
|
16247 | throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
|
16248 | }
|
16249 | if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
16250 | throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
16251 | }
|
16252 | trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
|
16253 | emptyHTML = trustedTypesPolicy.createHTML('');
|
16254 | } else {
|
16255 | if (trustedTypesPolicy === undefined) {
|
16256 | trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
16257 | }
|
16258 | if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
|
16259 | emptyHTML = trustedTypesPolicy.createHTML('');
|
16260 | }
|
16261 | }
|
16262 | if (freeze) {
|
16263 | freeze(cfg);
|
16264 | }
|
16265 | CONFIG = cfg;
|
16266 | };
|
16267 | const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
|
16268 | 'mi',
|
16269 | 'mo',
|
16270 | 'mn',
|
16271 | 'ms',
|
16272 | 'mtext'
|
16273 | ]);
|
16274 | const HTML_INTEGRATION_POINTS = addToSet({}, [
|
16275 | 'foreignobject',
|
16276 | 'desc',
|
16277 | 'title',
|
16278 | 'annotation-xml'
|
16279 | ]);
|
16280 | const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
|
16281 | 'title',
|
16282 | 'style',
|
16283 | 'font',
|
16284 | 'a',
|
16285 | 'script'
|
16286 | ]);
|
16287 | const ALL_SVG_TAGS = addToSet({}, svg$1);
|
16288 | addToSet(ALL_SVG_TAGS, svgFilters);
|
16289 | addToSet(ALL_SVG_TAGS, svgDisallowed);
|
16290 | const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
|
16291 | addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
|
16292 | const _checkValidNamespace = function _checkValidNamespace(element) {
|
16293 | let parent = getParentNode(element);
|
16294 | if (!parent || !parent.tagName) {
|
16295 | parent = {
|
16296 | namespaceURI: NAMESPACE,
|
16297 | tagName: 'template'
|
16298 | };
|
16299 | }
|
16300 | const tagName = stringToLowerCase(element.tagName);
|
16301 | const parentTagName = stringToLowerCase(parent.tagName);
|
16302 | if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
|
16303 | return false;
|
16304 | }
|
16305 | if (element.namespaceURI === SVG_NAMESPACE) {
|
16306 | if (parent.namespaceURI === HTML_NAMESPACE) {
|
16307 | return tagName === 'svg';
|
16308 | }
|
16309 | if (parent.namespaceURI === MATHML_NAMESPACE) {
|
16310 | return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
16311 | }
|
16312 | return Boolean(ALL_SVG_TAGS[tagName]);
|
16313 | }
|
16314 | if (element.namespaceURI === MATHML_NAMESPACE) {
|
16315 | if (parent.namespaceURI === HTML_NAMESPACE) {
|
16316 | return tagName === 'math';
|
16317 | }
|
16318 | if (parent.namespaceURI === SVG_NAMESPACE) {
|
16319 | return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
16320 | }
|
16321 | return Boolean(ALL_MATHML_TAGS[tagName]);
|
16322 | }
|
16323 | if (element.namespaceURI === HTML_NAMESPACE) {
|
16324 | if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
|
16325 | return false;
|
16326 | }
|
16327 | if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
16328 | return false;
|
16329 | }
|
16330 | return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
16331 | }
|
16332 | if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
16333 | return true;
|
16334 | }
|
16335 | return false;
|
16336 | };
|
16337 | const _forceRemove = function _forceRemove(node) {
|
16338 | arrayPush(DOMPurify.removed, { element: node });
|
16339 | try {
|
16340 | node.parentNode.removeChild(node);
|
16341 | } catch (_) {
|
16342 | node.remove();
|
16343 | }
|
16344 | };
|
16345 | const _removeAttribute = function _removeAttribute(name, node) {
|
16346 | try {
|
16347 | arrayPush(DOMPurify.removed, {
|
16348 | attribute: node.getAttributeNode(name),
|
16349 | from: node
|
16350 | });
|
16351 | } catch (_) {
|
16352 | arrayPush(DOMPurify.removed, {
|
16353 | attribute: null,
|
16354 | from: node
|
16355 | });
|
16356 | }
|
16357 | node.removeAttribute(name);
|
16358 | if (name === 'is' && !ALLOWED_ATTR[name]) {
|
16359 | if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
16360 | try {
|
16361 | _forceRemove(node);
|
16362 | } catch (_) {
|
16363 | }
|
16364 | } else {
|
16365 | try {
|
16366 | node.setAttribute(name, '');
|
16367 | } catch (_) {
|
16368 | }
|
16369 | }
|
16370 | }
|
16371 | };
|
16372 | const _initDocument = function _initDocument(dirty) {
|
16373 | let doc;
|
16374 | let leadingWhitespace;
|
16375 | if (FORCE_BODY) {
|
16376 | dirty = '<remove></remove>' + dirty;
|
16377 | } else {
|
16378 | const matches = stringMatch(dirty, /^[\r\n\t ]+/);
|
16379 | leadingWhitespace = matches && matches[0];
|
16380 | }
|
16381 | if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
|
16382 | dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
16383 | }
|
16384 | const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
16385 | if (NAMESPACE === HTML_NAMESPACE) {
|
16386 | try {
|
16387 | doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
16388 | } catch (_) {
|
16389 | }
|
16390 | }
|
16391 | if (!doc || !doc.documentElement) {
|
16392 | doc = implementation.createDocument(NAMESPACE, 'template', null);
|
16393 | try {
|
16394 | doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
|
16395 | } catch (_) {
|
16396 | }
|
16397 | }
|
16398 | const body = doc.body || doc.documentElement;
|
16399 | if (dirty && leadingWhitespace) {
|
16400 | body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
16401 | }
|
16402 | if (NAMESPACE === HTML_NAMESPACE) {
|
16403 | return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
16404 | }
|
16405 | return WHOLE_DOCUMENT ? doc.documentElement : body;
|
16406 | };
|
16407 | const _createIterator = function _createIterator(root) {
|
16408 | return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
|
16409 | };
|
16410 | const _isClobbered = function _isClobbered(elm) {
|
16411 | return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
|
16412 | };
|
16413 | const _isNode = function _isNode(object) {
|
16414 | return typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
|
16415 | };
|
16416 | const _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
16417 | if (!hooks[entryPoint]) {
|
16418 | return;
|
16419 | }
|
16420 | arrayForEach(hooks[entryPoint], hook => {
|
16421 | hook.call(DOMPurify, currentNode, data, CONFIG);
|
16422 | });
|
16423 | };
|
16424 | const _sanitizeElements = function _sanitizeElements(currentNode) {
|
16425 | let content;
|
16426 | _executeHook('beforeSanitizeElements', currentNode, null);
|
16427 | if (_isClobbered(currentNode)) {
|
16428 | _forceRemove(currentNode);
|
16429 | return true;
|
16430 | }
|
16431 | const tagName = transformCaseFunc(currentNode.nodeName);
|
16432 | _executeHook('uponSanitizeElement', currentNode, {
|
16433 | tagName,
|
16434 | allowedTags: ALLOWED_TAGS
|
16435 | });
|
16436 | if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
|
16437 | _forceRemove(currentNode);
|
16438 | return true;
|
16439 | }
|
16440 | if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
16441 | if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
|
16442 | if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName))
|
16443 | return false;
|
16444 | if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName))
|
16445 | return false;
|
16446 | }
|
16447 | if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
16448 | const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
16449 | const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
16450 | if (childNodes && parentNode) {
|
16451 | const childCount = childNodes.length;
|
16452 | for (let i = childCount - 1; i >= 0; --i) {
|
16453 | parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
|
16454 | }
|
16455 | }
|
16456 | }
|
16457 | _forceRemove(currentNode);
|
16458 | return true;
|
16459 | }
|
16460 | if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
16461 | _forceRemove(currentNode);
|
16462 | return true;
|
16463 | }
|
16464 | if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
|
16465 | _forceRemove(currentNode);
|
16466 | return true;
|
16467 | }
|
16468 | if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
16469 | content = currentNode.textContent;
|
16470 | content = stringReplace(content, MUSTACHE_EXPR, ' ');
|
16471 | content = stringReplace(content, ERB_EXPR, ' ');
|
16472 | content = stringReplace(content, TMPLIT_EXPR, ' ');
|
16473 | if (currentNode.textContent !== content) {
|
16474 | arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
|
16475 | currentNode.textContent = content;
|
16476 | }
|
16477 | }
|
16478 | _executeHook('afterSanitizeElements', currentNode, null);
|
16479 | return false;
|
16480 | };
|
16481 | const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
16482 | if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
16483 | return false;
|
16484 | }
|
16485 | if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName));
|
16486 | else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName));
|
16487 | else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
16488 | if (_basicCustomElementTest(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) || lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)));
|
16489 | else {
|
16490 | return false;
|
16491 | }
|
16492 | } else if (URI_SAFE_ATTRIBUTES[lcName]);
|
16493 | else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, '')));
|
16494 | else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]);
|
16495 | else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, '')));
|
16496 | else if (value) {
|
16497 | return false;
|
16498 | } else ;
|
16499 | return true;
|
16500 | };
|
16501 | const _basicCustomElementTest = function _basicCustomElementTest(tagName) {
|
16502 | return tagName.indexOf('-') > 0;
|
16503 | };
|
16504 | const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
16505 | let attr;
|
16506 | let value;
|
16507 | let lcName;
|
16508 | let l;
|
16509 | _executeHook('beforeSanitizeAttributes', currentNode, null);
|
16510 | const {attributes} = currentNode;
|
16511 | if (!attributes) {
|
16512 | return;
|
16513 | }
|
16514 | const hookEvent = {
|
16515 | attrName: '',
|
16516 | attrValue: '',
|
16517 | keepAttr: true,
|
16518 | allowedAttributes: ALLOWED_ATTR
|
16519 | };
|
16520 | l = attributes.length;
|
16521 | while (l--) {
|
16522 | attr = attributes[l];
|
16523 | const {name, namespaceURI} = attr;
|
16524 | value = name === 'value' ? attr.value : stringTrim(attr.value);
|
16525 | const initValue = value;
|
16526 | lcName = transformCaseFunc(name);
|
16527 | hookEvent.attrName = lcName;
|
16528 | hookEvent.attrValue = value;
|
16529 | hookEvent.keepAttr = true;
|
16530 | hookEvent.forceKeepAttr = undefined;
|
16531 | _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
16532 | value = hookEvent.attrValue;
|
16533 | if (hookEvent.forceKeepAttr) {
|
16534 | continue;
|
16535 | }
|
16536 | if (!hookEvent.keepAttr) {
|
16537 | _removeAttribute(name, currentNode);
|
16538 | continue;
|
16539 | }
|
16540 | if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
16541 | _removeAttribute(name, currentNode);
|
16542 | continue;
|
16543 | }
|
16544 | if (SAFE_FOR_TEMPLATES) {
|
16545 | value = stringReplace(value, MUSTACHE_EXPR, ' ');
|
16546 | value = stringReplace(value, ERB_EXPR, ' ');
|
16547 | value = stringReplace(value, TMPLIT_EXPR, ' ');
|
16548 | }
|
16549 | const lcTag = transformCaseFunc(currentNode.nodeName);
|
16550 | if (!_isValidAttribute(lcTag, lcName, value)) {
|
16551 | _removeAttribute(name, currentNode);
|
16552 | continue;
|
16553 | }
|
16554 | if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
16555 | _removeAttribute(name, currentNode);
|
16556 | value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
16557 | }
|
16558 | if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
16559 | if (namespaceURI);
|
16560 | else {
|
16561 | switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
16562 | case 'TrustedHTML': {
|
16563 | value = trustedTypesPolicy.createHTML(value);
|
16564 | break;
|
16565 | }
|
16566 | case 'TrustedScriptURL': {
|
16567 | value = trustedTypesPolicy.createScriptURL(value);
|
16568 | break;
|
16569 | }
|
16570 | }
|
16571 | }
|
16572 | }
|
16573 | if (value !== initValue) {
|
16574 | try {
|
16575 | if (namespaceURI) {
|
16576 | currentNode.setAttributeNS(namespaceURI, name, value);
|
16577 | } else {
|
16578 | currentNode.setAttribute(name, value);
|
16579 | }
|
16580 | } catch (_) {
|
16581 | _removeAttribute(name, currentNode);
|
16582 | }
|
16583 | }
|
16584 | }
|
16585 | _executeHook('afterSanitizeAttributes', currentNode, null);
|
16586 | };
|
16587 | const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
16588 | let shadowNode;
|
16589 | const shadowIterator = _createIterator(fragment);
|
16590 | _executeHook('beforeSanitizeShadowDOM', fragment, null);
|
16591 | while (shadowNode = shadowIterator.nextNode()) {
|
16592 | _executeHook('uponSanitizeShadowNode', shadowNode, null);
|
16593 | if (_sanitizeElements(shadowNode)) {
|
16594 | continue;
|
16595 | }
|
16596 | if (shadowNode.content instanceof DocumentFragment) {
|
16597 | _sanitizeShadowDOM(shadowNode.content);
|
16598 | }
|
16599 | _sanitizeAttributes(shadowNode);
|
16600 | }
|
16601 | _executeHook('afterSanitizeShadowDOM', fragment, null);
|
16602 | };
|
16603 | DOMPurify.sanitize = function (dirty) {
|
16604 | let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
16605 | let body;
|
16606 | let importedNode;
|
16607 | let currentNode;
|
16608 | let returnNode;
|
16609 | IS_EMPTY_INPUT = !dirty;
|
16610 | if (IS_EMPTY_INPUT) {
|
16611 | dirty = '<!-->';
|
16612 | }
|
16613 | if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
16614 | if (typeof dirty.toString === 'function') {
|
16615 | dirty = dirty.toString();
|
16616 | if (typeof dirty !== 'string') {
|
16617 | throw typeErrorCreate('dirty is not a string, aborting');
|
16618 | }
|
16619 | } else {
|
16620 | throw typeErrorCreate('toString is not a function');
|
16621 | }
|
16622 | }
|
16623 | if (!DOMPurify.isSupported) {
|
16624 | return dirty;
|
16625 | }
|
16626 | if (!SET_CONFIG) {
|
16627 | _parseConfig(cfg);
|
16628 | }
|
16629 | DOMPurify.removed = [];
|
16630 | if (typeof dirty === 'string') {
|
16631 | IN_PLACE = false;
|
16632 | }
|
16633 | if (IN_PLACE) {
|
16634 | if (dirty.nodeName) {
|
16635 | const tagName = transformCaseFunc(dirty.nodeName);
|
16636 | if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
16637 | throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
16638 | }
|
16639 | }
|
16640 | } else if (dirty instanceof Node) {
|
16641 | body = _initDocument('<!---->');
|
16642 | importedNode = body.ownerDocument.importNode(dirty, true);
|
16643 | if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
|
16644 | body = importedNode;
|
16645 | } else if (importedNode.nodeName === 'HTML') {
|
16646 | body = importedNode;
|
16647 | } else {
|
16648 | body.appendChild(importedNode);
|
16649 | }
|
16650 | } else {
|
16651 | if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
|
16652 | return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
16653 | }
|
16654 | body = _initDocument(dirty);
|
16655 | if (!body) {
|
16656 | return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
16657 | }
|
16658 | }
|
16659 | if (body && FORCE_BODY) {
|
16660 | _forceRemove(body.firstChild);
|
16661 | }
|
16662 | const nodeIterator = _createIterator(IN_PLACE ? dirty : body);
|
16663 | while (currentNode = nodeIterator.nextNode()) {
|
16664 | if (_sanitizeElements(currentNode)) {
|
16665 | continue;
|
16666 | }
|
16667 | if (currentNode.content instanceof DocumentFragment) {
|
16668 | _sanitizeShadowDOM(currentNode.content);
|
16669 | }
|
16670 | _sanitizeAttributes(currentNode);
|
16671 | }
|
16672 | if (IN_PLACE) {
|
16673 | return dirty;
|
16674 | }
|
16675 | if (RETURN_DOM) {
|
16676 | if (RETURN_DOM_FRAGMENT) {
|
16677 | returnNode = createDocumentFragment.call(body.ownerDocument);
|
16678 | while (body.firstChild) {
|
16679 | returnNode.appendChild(body.firstChild);
|
16680 | }
|
16681 | } else {
|
16682 | returnNode = body;
|
16683 | }
|
16684 | if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
|
16685 | returnNode = importNode.call(originalDocument, returnNode, true);
|
16686 | }
|
16687 | return returnNode;
|
16688 | }
|
16689 | let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
16690 | if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
16691 | serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
16692 | }
|
16693 | if (SAFE_FOR_TEMPLATES) {
|
16694 | serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');
|
16695 | serializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');
|
16696 | serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');
|
16697 | }
|
16698 | return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
16699 | };
|
16700 | DOMPurify.setConfig = function (cfg) {
|
16701 | _parseConfig(cfg);
|
16702 | SET_CONFIG = true;
|
16703 | };
|
16704 | DOMPurify.clearConfig = function () {
|
16705 | CONFIG = null;
|
16706 | SET_CONFIG = false;
|
16707 | };
|
16708 | DOMPurify.isValidAttribute = function (tag, attr, value) {
|
16709 | if (!CONFIG) {
|
16710 | _parseConfig({});
|
16711 | }
|
16712 | const lcTag = transformCaseFunc(tag);
|
16713 | const lcName = transformCaseFunc(attr);
|
16714 | return _isValidAttribute(lcTag, lcName, value);
|
16715 | };
|
16716 | DOMPurify.addHook = function (entryPoint, hookFunction) {
|
16717 | if (typeof hookFunction !== 'function') {
|
16718 | return;
|
16719 | }
|
16720 | hooks[entryPoint] = hooks[entryPoint] || [];
|
16721 | arrayPush(hooks[entryPoint], hookFunction);
|
16722 | };
|
16723 | DOMPurify.removeHook = function (entryPoint) {
|
16724 | if (hooks[entryPoint]) {
|
16725 | return arrayPop(hooks[entryPoint]);
|
16726 | }
|
16727 | };
|
16728 | DOMPurify.removeHooks = function (entryPoint) {
|
16729 | if (hooks[entryPoint]) {
|
16730 | hooks[entryPoint] = [];
|
16731 | }
|
16732 | };
|
16733 | DOMPurify.removeAllHooks = function () {
|
16734 | hooks = {};
|
16735 | };
|
16736 | return DOMPurify;
|
16737 | }
|
16738 | var purify = createDOMPurify();
|
16739 |
|
16740 | const each$4 = Tools.each, trim = Tools.trim;
|
16741 | const queryParts = [
|
16742 | 'source',
|
16743 | 'protocol',
|
16744 | 'authority',
|
16745 | 'userInfo',
|
16746 | 'user',
|
16747 | 'password',
|
16748 | 'host',
|
16749 | 'port',
|
16750 | 'relative',
|
16751 | 'path',
|
16752 | 'directory',
|
16753 | 'file',
|
16754 | 'query',
|
16755 | 'anchor'
|
16756 | ];
|
16757 | const DEFAULT_PORTS = {
|
16758 | ftp: 21,
|
16759 | http: 80,
|
16760 | https: 443,
|
16761 | mailto: 25
|
16762 | };
|
16763 | const safeSvgDataUrlElements = [
|
16764 | 'img',
|
16765 | 'video'
|
16766 | ];
|
16767 | const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
|
16768 | if (isNonNullable(allowSvgDataUrls)) {
|
16769 | return !allowSvgDataUrls;
|
16770 | } else {
|
16771 | return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
|
16772 | }
|
16773 | };
|
16774 | const decodeUri = encodedUri => {
|
16775 | try {
|
16776 | return decodeURIComponent(encodedUri);
|
16777 | } catch (ex) {
|
16778 | return unescape(encodedUri);
|
16779 | }
|
16780 | };
|
16781 | const isInvalidUri = (settings, uri, tagName) => {
|
16782 | const decodedUri = decodeUri(uri).replace(/\s/g, '');
|
16783 | if (settings.allow_script_urls) {
|
16784 | return false;
|
16785 | } else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
|
16786 | return true;
|
16787 | } else if (settings.allow_html_data_urls) {
|
16788 | return false;
|
16789 | } else if (/^data:image\//i.test(decodedUri)) {
|
16790 | return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
|
16791 | } else {
|
16792 | return /^data:/i.test(decodedUri);
|
16793 | }
|
16794 | };
|
16795 | class URI {
|
16796 | static parseDataUri(uri) {
|
16797 | let type;
|
16798 | const uriComponents = decodeURIComponent(uri).split(',');
|
16799 | const matches = /data:([^;]+)/.exec(uriComponents[0]);
|
16800 | if (matches) {
|
16801 | type = matches[1];
|
16802 | }
|
16803 | return {
|
16804 | type,
|
16805 | data: uriComponents[1]
|
16806 | };
|
16807 | }
|
16808 | static isDomSafe(uri, context, options = {}) {
|
16809 | if (options.allow_script_urls) {
|
16810 | return true;
|
16811 | } else {
|
16812 | const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, '');
|
16813 | return !isInvalidUri(options, decodedUri, context);
|
16814 | }
|
16815 | }
|
16816 | static getDocumentBaseUrl(loc) {
|
16817 | var _a;
|
16818 | let baseUrl;
|
16819 | if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
|
16820 | baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : '';
|
16821 | } else {
|
16822 | baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
|
16823 | }
|
16824 | if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
|
16825 | baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
16826 | if (!/[\/\\]$/.test(baseUrl)) {
|
16827 | baseUrl += '/';
|
16828 | }
|
16829 | }
|
16830 | return baseUrl;
|
16831 | }
|
16832 | constructor(url, settings = {}) {
|
16833 | this.path = '';
|
16834 | this.directory = '';
|
16835 | url = trim(url);
|
16836 | this.settings = settings;
|
16837 | const baseUri = settings.base_uri;
|
16838 | const self = this;
|
16839 | if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
|
16840 | self.source = url;
|
16841 | return;
|
16842 | }
|
16843 | const isProtocolRelative = url.indexOf('//') === 0;
|
16844 | if (url.indexOf('/') === 0 && !isProtocolRelative) {
|
16845 | url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
|
16846 | }
|
16847 | if (!/^[\w\-]*:?\/\//.test(url)) {
|
16848 | const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory;
|
16849 | if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') {
|
16850 | url = '//mce_host' + self.toAbsPath(baseUrl, url);
|
16851 | } else {
|
16852 | const match = /([^#?]*)([#?]?.*)/.exec(url);
|
16853 | if (match) {
|
16854 | url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
|
16855 | }
|
16856 | }
|
16857 | }
|
16858 | url = url.replace(/@@/g, '(mce_at)');
|
16859 | const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
|
16860 | if (urlMatch) {
|
16861 | each$4(queryParts, (v, i) => {
|
16862 | let part = urlMatch[i];
|
16863 | if (part) {
|
16864 | part = part.replace(/\(mce_at\)/g, '@@');
|
16865 | }
|
16866 | self[v] = part;
|
16867 | });
|
16868 | }
|
16869 | if (baseUri) {
|
16870 | if (!self.protocol) {
|
16871 | self.protocol = baseUri.protocol;
|
16872 | }
|
16873 | if (!self.userInfo) {
|
16874 | self.userInfo = baseUri.userInfo;
|
16875 | }
|
16876 | if (!self.port && self.host === 'mce_host') {
|
16877 | self.port = baseUri.port;
|
16878 | }
|
16879 | if (!self.host || self.host === 'mce_host') {
|
16880 | self.host = baseUri.host;
|
16881 | }
|
16882 | self.source = '';
|
16883 | }
|
16884 | if (isProtocolRelative) {
|
16885 | self.protocol = '';
|
16886 | }
|
16887 | }
|
16888 | setPath(path) {
|
16889 | const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
|
16890 | if (pathMatch) {
|
16891 | this.path = pathMatch[0];
|
16892 | this.directory = pathMatch[1];
|
16893 | this.file = pathMatch[2];
|
16894 | }
|
16895 | this.source = '';
|
16896 | this.getURI();
|
16897 | }
|
16898 | toRelative(uri) {
|
16899 | if (uri === './') {
|
16900 | return uri;
|
16901 | }
|
16902 | const relativeUri = new URI(uri, { base_uri: this });
|
16903 | if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
|
16904 | return relativeUri.getURI();
|
16905 | }
|
16906 | const tu = this.getURI(), uu = relativeUri.getURI();
|
16907 | if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
|
16908 | return tu;
|
16909 | }
|
16910 | let output = this.toRelPath(this.path, relativeUri.path);
|
16911 | if (relativeUri.query) {
|
16912 | output += '?' + relativeUri.query;
|
16913 | }
|
16914 | if (relativeUri.anchor) {
|
16915 | output += '#' + relativeUri.anchor;
|
16916 | }
|
16917 | return output;
|
16918 | }
|
16919 | toAbsolute(uri, noHost) {
|
16920 | const absoluteUri = new URI(uri, { base_uri: this });
|
16921 | return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
|
16922 | }
|
16923 | isSameOrigin(uri) {
|
16924 | if (this.host == uri.host && this.protocol == uri.protocol) {
|
16925 | if (this.port == uri.port) {
|
16926 | return true;
|
16927 | }
|
16928 | const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null;
|
16929 | if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
|
16930 | return true;
|
16931 | }
|
16932 | }
|
16933 | return false;
|
16934 | }
|
16935 | toRelPath(base, path) {
|
16936 | let breakPoint = 0, out = '', i, l;
|
16937 | const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
|
16938 | const items = path.split('/');
|
16939 | if (normalizedBase.length >= items.length) {
|
16940 | for (i = 0, l = normalizedBase.length; i < l; i++) {
|
16941 | if (i >= items.length || normalizedBase[i] !== items[i]) {
|
16942 | breakPoint = i + 1;
|
16943 | break;
|
16944 | }
|
16945 | }
|
16946 | }
|
16947 | if (normalizedBase.length < items.length) {
|
16948 | for (i = 0, l = items.length; i < l; i++) {
|
16949 | if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
|
16950 | breakPoint = i + 1;
|
16951 | break;
|
16952 | }
|
16953 | }
|
16954 | }
|
16955 | if (breakPoint === 1) {
|
16956 | return path;
|
16957 | }
|
16958 | for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
|
16959 | out += '../';
|
16960 | }
|
16961 | for (i = breakPoint - 1, l = items.length; i < l; i++) {
|
16962 | if (i !== breakPoint - 1) {
|
16963 | out += '/' + items[i];
|
16964 | } else {
|
16965 | out += items[i];
|
16966 | }
|
16967 | }
|
16968 | return out;
|
16969 | }
|
16970 | toAbsPath(base, path) {
|
16971 | let nb = 0;
|
16972 | const tr = /\/$/.test(path) ? '/' : '';
|
16973 | const normalizedBase = base.split('/');
|
16974 | const normalizedPath = path.split('/');
|
16975 | const baseParts = [];
|
16976 | each$4(normalizedBase, k => {
|
16977 | if (k) {
|
16978 | baseParts.push(k);
|
16979 | }
|
16980 | });
|
16981 | const pathParts = [];
|
16982 | for (let i = normalizedPath.length - 1; i >= 0; i--) {
|
16983 | if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
|
16984 | continue;
|
16985 | }
|
16986 | if (normalizedPath[i] === '..') {
|
16987 | nb++;
|
16988 | continue;
|
16989 | }
|
16990 | if (nb > 0) {
|
16991 | nb--;
|
16992 | continue;
|
16993 | }
|
16994 | pathParts.push(normalizedPath[i]);
|
16995 | }
|
16996 | const i = baseParts.length - nb;
|
16997 | let outPath;
|
16998 | if (i <= 0) {
|
16999 | outPath = reverse(pathParts).join('/');
|
17000 | } else {
|
17001 | outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/');
|
17002 | }
|
17003 | if (outPath.indexOf('/') !== 0) {
|
17004 | outPath = '/' + outPath;
|
17005 | }
|
17006 | if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
|
17007 | outPath += tr;
|
17008 | }
|
17009 | return outPath;
|
17010 | }
|
17011 | getURI(noProtoHost = false) {
|
17012 | let s;
|
17013 | if (!this.source || noProtoHost) {
|
17014 | s = '';
|
17015 | if (!noProtoHost) {
|
17016 | if (this.protocol) {
|
17017 | s += this.protocol + '://';
|
17018 | } else {
|
17019 | s += '//';
|
17020 | }
|
17021 | if (this.userInfo) {
|
17022 | s += this.userInfo + '@';
|
17023 | }
|
17024 | if (this.host) {
|
17025 | s += this.host;
|
17026 | }
|
17027 | if (this.port) {
|
17028 | s += ':' + this.port;
|
17029 | }
|
17030 | }
|
17031 | if (this.path) {
|
17032 | s += this.path;
|
17033 | }
|
17034 | if (this.query) {
|
17035 | s += '?' + this.query;
|
17036 | }
|
17037 | if (this.anchor) {
|
17038 | s += '#' + this.anchor;
|
17039 | }
|
17040 | this.source = s;
|
17041 | }
|
17042 | return this.source;
|
17043 | }
|
17044 | }
|
17045 |
|
17046 | const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href');
|
17047 | const internalElementAttr = 'data-mce-type';
|
17048 | let uid = 0;
|
17049 | const processNode = (node, settings, schema, scope, evt) => {
|
17050 | var _a, _b, _c, _d;
|
17051 | const validate = settings.validate;
|
17052 | const specialElements = schema.getSpecialElements();
|
17053 | if (node.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '')) {
|
17054 | node.nodeValue = ' ' + node.nodeValue;
|
17055 | }
|
17056 | const lcTagName = (_b = evt === null || evt === void 0 ? void 0 : evt.tagName) !== null && _b !== void 0 ? _b : node.nodeName.toLowerCase();
|
17057 | if (scope !== 'html' && schema.isValid(scope)) {
|
17058 | if (isNonNullable(evt)) {
|
17059 | evt.allowedTags[lcTagName] = true;
|
17060 | }
|
17061 | return;
|
17062 | }
|
17063 | if (node.nodeType !== ELEMENT || lcTagName === 'body') {
|
17064 | return;
|
17065 | }
|
17066 | const element = SugarElement.fromDom(node);
|
17067 | const isInternalElement = has$1(element, internalElementAttr);
|
17068 | const bogus = get$9(element, 'data-mce-bogus');
|
17069 | if (!isInternalElement && isString(bogus)) {
|
17070 | if (bogus === 'all') {
|
17071 | remove$4(element);
|
17072 | } else {
|
17073 | unwrap(element);
|
17074 | }
|
17075 | return;
|
17076 | }
|
17077 | const rule = schema.getElementRule(lcTagName);
|
17078 | if (validate && !rule) {
|
17079 | if (has$2(specialElements, lcTagName)) {
|
17080 | remove$4(element);
|
17081 | } else {
|
17082 | unwrap(element);
|
17083 | }
|
17084 | return;
|
17085 | } else {
|
17086 | if (isNonNullable(evt)) {
|
17087 | evt.allowedTags[lcTagName] = true;
|
17088 | }
|
17089 | }
|
17090 | if (validate && rule && !isInternalElement) {
|
17091 | each$e((_c = rule.attributesForced) !== null && _c !== void 0 ? _c : [], attr => {
|
17092 | set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
|
17093 | });
|
17094 | each$e((_d = rule.attributesDefault) !== null && _d !== void 0 ? _d : [], attr => {
|
17095 | if (!has$1(element, attr.name)) {
|
17096 | set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
|
17097 | }
|
17098 | });
|
17099 | if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) {
|
17100 | unwrap(element);
|
17101 | return;
|
17102 | }
|
17103 | if (rule.removeEmptyAttrs && hasNone(element)) {
|
17104 | unwrap(element);
|
17105 | return;
|
17106 | }
|
17107 | if (rule.outputName && rule.outputName !== lcTagName) {
|
17108 | mutate(element, rule.outputName);
|
17109 | }
|
17110 | }
|
17111 | };
|
17112 | const processAttr = (ele, settings, schema, scope, evt) => {
|
17113 | const tagName = ele.tagName.toLowerCase();
|
17114 | const {attrName, attrValue} = evt;
|
17115 | evt.keepAttr = shouldKeepAttribute(settings, schema, scope, tagName, attrName, attrValue);
|
17116 | if (evt.keepAttr) {
|
17117 | evt.allowedAttributes[attrName] = true;
|
17118 | if (isBooleanAttribute(attrName, schema)) {
|
17119 | evt.attrValue = attrName;
|
17120 | }
|
17121 | if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) {
|
17122 | evt.forceKeepAttr = true;
|
17123 | }
|
17124 | } else if (isRequiredAttributeOfInternalElement(ele, attrName)) {
|
17125 | evt.forceKeepAttr = true;
|
17126 | }
|
17127 | };
|
17128 | const shouldKeepAttribute = (settings, schema, scope, tagName, attrName, attrValue) => {
|
17129 | if (scope !== 'html' && !isNonHtmlElementRootName(tagName)) {
|
17130 | return true;
|
17131 | }
|
17132 | return !(attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) && (!settings.validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-'));
|
17133 | };
|
17134 | const isRequiredAttributeOfInternalElement = (ele, attrName) => ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style');
|
17135 | const isBooleanAttribute = (attrName, schema) => attrName in schema.getBoolAttrs();
|
17136 | const filterAttributes = (ele, settings, schema, scope) => {
|
17137 | const {attributes} = ele;
|
17138 | for (let i = attributes.length - 1; i >= 0; i--) {
|
17139 | const attr = attributes[i];
|
17140 | const attrName = attr.name;
|
17141 | const attrValue = attr.value;
|
17142 | if (!shouldKeepAttribute(settings, schema, scope, ele.tagName.toLowerCase(), attrName, attrValue) && !isRequiredAttributeOfInternalElement(ele, attrName)) {
|
17143 | ele.removeAttribute(attrName);
|
17144 | } else if (isBooleanAttribute(attrName, schema)) {
|
17145 | ele.setAttribute(attrName, attrName);
|
17146 | }
|
17147 | }
|
17148 | };
|
17149 | const setupPurify = (settings, schema, namespaceTracker) => {
|
17150 | const purify$1 = purify();
|
17151 | purify$1.addHook('uponSanitizeElement', (ele, evt) => {
|
17152 | processNode(ele, settings, schema, namespaceTracker.track(ele), evt);
|
17153 | });
|
17154 | purify$1.addHook('uponSanitizeAttribute', (ele, evt) => {
|
17155 | processAttr(ele, settings, schema, namespaceTracker.current(), evt);
|
17156 | });
|
17157 | return purify$1;
|
17158 | };
|
17159 | const getPurifyConfig = (settings, mimeType) => {
|
17160 | const basePurifyConfig = {
|
17161 | IN_PLACE: true,
|
17162 | ALLOW_UNKNOWN_PROTOCOLS: true,
|
17163 | ALLOWED_TAGS: [
|
17164 | '#comment',
|
17165 | '#cdata-section',
|
17166 | 'body'
|
17167 | ],
|
17168 | ALLOWED_ATTR: []
|
17169 | };
|
17170 | const config = { ...basePurifyConfig };
|
17171 | config.PARSER_MEDIA_TYPE = mimeType;
|
17172 | if (settings.allow_script_urls) {
|
17173 | config.ALLOWED_URI_REGEXP = /.*/;
|
17174 | } else if (settings.allow_html_data_urls) {
|
17175 | config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
|
17176 | }
|
17177 | return config;
|
17178 | };
|
17179 | const sanitizeNamespaceElement = ele => {
|
17180 | const namespaceType = toScopeType(ele);
|
17181 | if (namespaceType === 'svg') {
|
17182 | const xlinkAttrs = [
|
17183 | 'type',
|
17184 | 'href',
|
17185 | 'role',
|
17186 | 'arcrole',
|
17187 | 'title',
|
17188 | 'show',
|
17189 | 'actuate',
|
17190 | 'label',
|
17191 | 'from',
|
17192 | 'to'
|
17193 | ].map(name => `xlink:${ name }`);
|
17194 | const config = {
|
17195 | IN_PLACE: true,
|
17196 | USE_PROFILES: {
|
17197 | html: true,
|
17198 | svg: true,
|
17199 | svgFilters: true
|
17200 | },
|
17201 | ALLOWED_ATTR: xlinkAttrs
|
17202 | };
|
17203 | purify().sanitize(ele, config);
|
17204 | } else if (namespaceType === 'math') {
|
17205 | const config = {
|
17206 | IN_PLACE: true,
|
17207 | USE_PROFILES: { mathMl: true }
|
17208 | };
|
17209 | purify().sanitize(ele, config);
|
17210 | } else {
|
17211 | throw new Error('Not a namespace element');
|
17212 | }
|
17213 | };
|
17214 | const getSanitizer = (settings, schema) => {
|
17215 | const namespaceTracker = createNamespaceTracker();
|
17216 | if (settings.sanitize) {
|
17217 | const purify = setupPurify(settings, schema, namespaceTracker);
|
17218 | const sanitizeHtmlElement = (body, mimeType) => {
|
17219 | purify.sanitize(body, getPurifyConfig(settings, mimeType));
|
17220 | purify.removed = [];
|
17221 | namespaceTracker.reset();
|
17222 | };
|
17223 | return {
|
17224 | sanitizeHtmlElement,
|
17225 | sanitizeNamespaceElement
|
17226 | };
|
17227 | } else {
|
17228 | const sanitizeHtmlElement = (body, _mimeType) => {
|
17229 | const nodeIterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT);
|
17230 | let node;
|
17231 | while (node = nodeIterator.nextNode()) {
|
17232 | const currentScope = namespaceTracker.track(node);
|
17233 | processNode(node, settings, schema, currentScope);
|
17234 | if (isElement$6(node)) {
|
17235 | filterAttributes(node, settings, schema, currentScope);
|
17236 | }
|
17237 | }
|
17238 | namespaceTracker.reset();
|
17239 | };
|
17240 | const sanitizeNamespaceElement = noop;
|
17241 | return {
|
17242 | sanitizeHtmlElement,
|
17243 | sanitizeNamespaceElement
|
17244 | };
|
17245 | }
|
17246 | };
|
17247 |
|
17248 | const makeMap = Tools.makeMap, extend$1 = Tools.extend;
|
17249 | const transferChildren = (parent, nativeParent, specialElements, nsSanitizer) => {
|
17250 | const parentName = parent.name;
|
17251 | const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea';
|
17252 | const childNodes = nativeParent.childNodes;
|
17253 | for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
|
17254 | const nativeChild = childNodes[ni];
|
17255 | const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
|
17256 | if (isElement$6(nativeChild)) {
|
17257 | const attributes = nativeChild.attributes;
|
17258 | for (let ai = 0, al = attributes.length; ai < al; ai++) {
|
17259 | const attr = attributes[ai];
|
17260 | child.attr(attr.name, attr.value);
|
17261 | }
|
17262 | if (isNonHtmlElementRootName(child.name)) {
|
17263 | nsSanitizer(nativeChild);
|
17264 | child.value = nativeChild.innerHTML;
|
17265 | }
|
17266 | } else if (isText$b(nativeChild)) {
|
17267 | child.value = nativeChild.data;
|
17268 | if (isSpecial) {
|
17269 | child.raw = true;
|
17270 | }
|
17271 | } else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
|
17272 | child.value = nativeChild.data;
|
17273 | }
|
17274 | if (!isNonHtmlElementRootName(child.name)) {
|
17275 | transferChildren(child, nativeChild, specialElements, nsSanitizer);
|
17276 | }
|
17277 | parent.append(child);
|
17278 | }
|
17279 | };
|
17280 | const walkTree = (root, preprocessors, postprocessors) => {
|
17281 | const traverseOrder = [];
|
17282 | for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) {
|
17283 | const tempNode = node;
|
17284 | each$e(preprocessors, preprocess => preprocess(tempNode));
|
17285 | if (isNullable(tempNode.parent) && tempNode !== root) {
|
17286 | node = lastNode;
|
17287 | } else {
|
17288 | traverseOrder.push(tempNode);
|
17289 | }
|
17290 | }
|
17291 | for (let i = traverseOrder.length - 1; i >= 0; i--) {
|
17292 | const node = traverseOrder[i];
|
17293 | each$e(postprocessors, postprocess => postprocess(node));
|
17294 | }
|
17295 | };
|
17296 | const whitespaceCleaner = (root, schema, settings, args) => {
|
17297 | const validate = settings.validate;
|
17298 | const nonEmptyElements = schema.getNonEmptyElements();
|
17299 | const whitespaceElements = schema.getWhitespaceElements();
|
17300 | const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
|
17301 | const textRootBlockElements = getTextRootBlockElements(schema);
|
17302 | const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
|
17303 | const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
|
17304 | const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
|
17305 | const hasWhitespaceParent = node => {
|
17306 | let tempNode = node.parent;
|
17307 | while (isNonNullable(tempNode)) {
|
17308 | if (tempNode.name in whitespaceElements) {
|
17309 | return true;
|
17310 | } else {
|
17311 | tempNode = tempNode.parent;
|
17312 | }
|
17313 | }
|
17314 | return false;
|
17315 | };
|
17316 | const isTextRootBlockEmpty = node => {
|
17317 | let tempNode = node;
|
17318 | while (isNonNullable(tempNode)) {
|
17319 | if (tempNode.name in textRootBlockElements) {
|
17320 | return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
|
17321 | } else {
|
17322 | tempNode = tempNode.parent;
|
17323 | }
|
17324 | }
|
17325 | return false;
|
17326 | };
|
17327 | const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node) || isNonHtmlElementRootName(node.name) && node.parent === root;
|
17328 | const isAtEdgeOfBlock = (node, start) => {
|
17329 | const neighbour = start ? node.prev : node.next;
|
17330 | if (isNonNullable(neighbour) || isNullable(node.parent)) {
|
17331 | return false;
|
17332 | }
|
17333 | return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
|
17334 | };
|
17335 | const preprocess = node => {
|
17336 | var _a;
|
17337 | if (node.type === 3) {
|
17338 | if (!hasWhitespaceParent(node)) {
|
17339 | let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
|
17340 | text = text.replace(allWhiteSpaceRegExp, ' ');
|
17341 | if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
|
17342 | text = text.replace(startWhiteSpaceRegExp, '');
|
17343 | }
|
17344 | if (text.length === 0) {
|
17345 | node.remove();
|
17346 | } else {
|
17347 | node.value = text;
|
17348 | }
|
17349 | }
|
17350 | }
|
17351 | };
|
17352 | const postprocess = node => {
|
17353 | var _a;
|
17354 | if (node.type === 1) {
|
17355 | const elementRule = schema.getElementRule(node.name);
|
17356 | if (validate && elementRule) {
|
17357 | const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
|
17358 | if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
|
17359 | paddEmptyNode(settings, args, isBlock, node);
|
17360 | } else if (elementRule.removeEmpty && isNodeEmpty) {
|
17361 | if (isBlock(node)) {
|
17362 | node.remove();
|
17363 | } else {
|
17364 | node.unwrap();
|
17365 | }
|
17366 | } else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
|
17367 | paddEmptyNode(settings, args, isBlock, node);
|
17368 | }
|
17369 | }
|
17370 | } else if (node.type === 3) {
|
17371 | if (!hasWhitespaceParent(node)) {
|
17372 | let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
|
17373 | if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) {
|
17374 | text = text.replace(endWhiteSpaceRegExp, '');
|
17375 | }
|
17376 | if (text.length === 0) {
|
17377 | node.remove();
|
17378 | } else {
|
17379 | node.value = text;
|
17380 | }
|
17381 | }
|
17382 | }
|
17383 | };
|
17384 | return [
|
17385 | preprocess,
|
17386 | postprocess
|
17387 | ];
|
17388 | };
|
17389 | const getRootBlockName = (settings, args) => {
|
17390 | var _a;
|
17391 | const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
|
17392 | if (name === false) {
|
17393 | return '';
|
17394 | } else if (name === true) {
|
17395 | return 'p';
|
17396 | } else {
|
17397 | return name;
|
17398 | }
|
17399 | };
|
17400 | const DomParser = (settings = {}, schema = Schema()) => {
|
17401 | const nodeFilterRegistry = create$8();
|
17402 | const attributeFilterRegistry = create$8();
|
17403 | const defaultedSettings = {
|
17404 | validate: true,
|
17405 | root_name: 'body',
|
17406 | sanitize: true,
|
17407 | ...settings
|
17408 | };
|
17409 | const parser = new DOMParser();
|
17410 | const sanitizer = getSanitizer(defaultedSettings, schema);
|
17411 | const parseAndSanitizeWithContext = (html, rootName, format = 'html') => {
|
17412 | const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
|
17413 | const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
|
17414 | const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html;
|
17415 | const wrappedHtml = format === 'xhtml' ? `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>` : `<body>${ content }</body>`;
|
17416 | const body = parser.parseFromString(wrappedHtml, mimeType).body;
|
17417 | sanitizer.sanitizeHtmlElement(body, mimeType);
|
17418 | return isSpecialRoot ? body.firstChild : body;
|
17419 | };
|
17420 | const addNodeFilter = nodeFilterRegistry.addFilter;
|
17421 | const getNodeFilters = nodeFilterRegistry.getFilters;
|
17422 | const removeNodeFilter = nodeFilterRegistry.removeFilter;
|
17423 | const addAttributeFilter = attributeFilterRegistry.addFilter;
|
17424 | const getAttributeFilters = attributeFilterRegistry.getFilters;
|
17425 | const removeAttributeFilter = attributeFilterRegistry.removeFilter;
|
17426 | const findInvalidChildren = (node, invalidChildren) => {
|
17427 | if (isInvalid(schema, node)) {
|
17428 | invalidChildren.push(node);
|
17429 | }
|
17430 | };
|
17431 | const isWrappableNode = (blockElements, node) => {
|
17432 | const isInternalElement = isString(node.attr(internalElementAttr));
|
17433 | const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node)) && !isNonHtmlElementRootName(node.name);
|
17434 | return node.type === 3 || isInlineElement && !isInternalElement;
|
17435 | };
|
17436 | const addRootBlocks = (rootNode, rootBlockName) => {
|
17437 | const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
|
17438 | const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
|
17439 | const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
|
17440 | let node = rootNode.firstChild, rootBlockNode = null;
|
17441 | const trim = rootBlock => {
|
17442 | var _a, _b;
|
17443 | if (rootBlock) {
|
17444 | node = rootBlock.firstChild;
|
17445 | if (node && node.type === 3) {
|
17446 | node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, '');
|
17447 | }
|
17448 | node = rootBlock.lastChild;
|
17449 | if (node && node.type === 3) {
|
17450 | node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, '');
|
17451 | }
|
17452 | }
|
17453 | };
|
17454 | if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
|
17455 | return;
|
17456 | }
|
17457 | while (node) {
|
17458 | const next = node.next;
|
17459 | if (isWrappableNode(blockElements, node)) {
|
17460 | if (!rootBlockNode) {
|
17461 | rootBlockNode = new AstNode(rootBlockName, 1);
|
17462 | rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
|
17463 | rootNode.insert(rootBlockNode, node);
|
17464 | rootBlockNode.append(node);
|
17465 | } else {
|
17466 | rootBlockNode.append(node);
|
17467 | }
|
17468 | } else {
|
17469 | trim(rootBlockNode);
|
17470 | rootBlockNode = null;
|
17471 | }
|
17472 | node = next;
|
17473 | }
|
17474 | trim(rootBlockNode);
|
17475 | };
|
17476 | const parse = (html, args = {}) => {
|
17477 | var _a;
|
17478 | const validate = defaultedSettings.validate;
|
17479 | const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
|
17480 | const element = parseAndSanitizeWithContext(html, rootName, args.format);
|
17481 | updateChildren(schema, element);
|
17482 | const rootNode = new AstNode(rootName, 11);
|
17483 | transferChildren(rootNode, element, schema.getSpecialElements(), sanitizer.sanitizeNamespaceElement);
|
17484 | element.innerHTML = '';
|
17485 | const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
|
17486 | const invalidChildren = [];
|
17487 | const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop;
|
17488 | const matches = {
|
17489 | nodes: {},
|
17490 | attributes: {}
|
17491 | };
|
17492 | const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
|
17493 | walkTree(rootNode, [
|
17494 | whitespacePre,
|
17495 | matchFinder
|
17496 | ], [
|
17497 | whitespacePost,
|
17498 | invalidFinder
|
17499 | ]);
|
17500 | invalidChildren.reverse();
|
17501 | if (validate && invalidChildren.length > 0) {
|
17502 | if (args.context) {
|
17503 | const {
|
17504 | pass: topLevelChildren,
|
17505 | fail: otherChildren
|
17506 | } = partition$2(invalidChildren, child => child.parent === rootNode);
|
17507 | cleanInvalidNodes(otherChildren, schema, rootNode, matchFinder);
|
17508 | args.invalid = topLevelChildren.length > 0;
|
17509 | } else {
|
17510 | cleanInvalidNodes(invalidChildren, schema, rootNode, matchFinder);
|
17511 | }
|
17512 | }
|
17513 | const rootBlockName = getRootBlockName(defaultedSettings, args);
|
17514 | if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
|
17515 | addRootBlocks(rootNode, rootBlockName);
|
17516 | }
|
17517 | if (!args.invalid) {
|
17518 | runFilters(matches, args);
|
17519 | }
|
17520 | return rootNode;
|
17521 | };
|
17522 | const exports = {
|
17523 | schema,
|
17524 | addAttributeFilter,
|
17525 | getAttributeFilters,
|
17526 | removeAttributeFilter,
|
17527 | addNodeFilter,
|
17528 | getNodeFilters,
|
17529 | removeNodeFilter,
|
17530 | parse
|
17531 | };
|
17532 | register$4(exports, defaultedSettings);
|
17533 | register$5(exports, defaultedSettings, schema);
|
17534 | return exports;
|
17535 | };
|
17536 |
|
17537 | const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
|
17538 | const withSerializedContent = (content, fireEvent, parserSettings) => {
|
17539 | const serializedContent = serializeContent(content);
|
17540 | const eventArgs = fireEvent(serializedContent);
|
17541 | if (eventArgs.isDefaultPrevented()) {
|
17542 | return eventArgs;
|
17543 | } else if (isTreeNode(content)) {
|
17544 | if (eventArgs.content !== serializedContent) {
|
17545 | const rootNode = DomParser({
|
17546 | validate: false,
|
17547 | forced_root_block: false,
|
17548 | ...parserSettings
|
17549 | }).parse(eventArgs.content, { context: content.name });
|
17550 | return {
|
17551 | ...eventArgs,
|
17552 | content: rootNode
|
17553 | };
|
17554 | } else {
|
17555 | return {
|
17556 | ...eventArgs,
|
17557 | content
|
17558 | };
|
17559 | }
|
17560 | } else {
|
17561 | return eventArgs;
|
17562 | }
|
17563 | };
|
17564 | const makeParserSettings = editor => ({
|
17565 | sanitize: shouldSanitizeXss(editor),
|
17566 | sandbox_iframes: shouldSandboxIframes(editor),
|
17567 | sandbox_iframes_exclusions: getSandboxIframesExclusions(editor)
|
17568 | });
|
17569 | const preProcessGetContent = (editor, args) => {
|
17570 | if (args.no_events) {
|
17571 | return Result.value(args);
|
17572 | } else {
|
17573 | const eventArgs = fireBeforeGetContent(editor, args);
|
17574 | if (eventArgs.isDefaultPrevented()) {
|
17575 | return Result.error(fireGetContent(editor, {
|
17576 | content: '',
|
17577 | ...eventArgs
|
17578 | }).content);
|
17579 | } else {
|
17580 | return Result.value(eventArgs);
|
17581 | }
|
17582 | }
|
17583 | };
|
17584 | const postProcessGetContent = (editor, content, args) => {
|
17585 | if (args.no_events) {
|
17586 | return content;
|
17587 | } else {
|
17588 | const processedEventArgs = withSerializedContent(content, content => fireGetContent(editor, {
|
17589 | ...args,
|
17590 | content
|
17591 | }), makeParserSettings(editor));
|
17592 | return processedEventArgs.content;
|
17593 | }
|
17594 | };
|
17595 | const preProcessSetContent = (editor, args) => {
|
17596 | if (args.no_events) {
|
17597 | return Result.value(args);
|
17598 | } else {
|
17599 | const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, {
|
17600 | ...args,
|
17601 | content
|
17602 | }), makeParserSettings(editor));
|
17603 | if (processedEventArgs.isDefaultPrevented()) {
|
17604 | fireSetContent(editor, processedEventArgs);
|
17605 | return Result.error(undefined);
|
17606 | } else {
|
17607 | return Result.value(processedEventArgs);
|
17608 | }
|
17609 | }
|
17610 | };
|
17611 | const postProcessSetContent = (editor, content, args) => {
|
17612 | if (!args.no_events) {
|
17613 | fireSetContent(editor, {
|
17614 | ...args,
|
17615 | content
|
17616 | });
|
17617 | }
|
17618 | };
|
17619 |
|
17620 | const tableModel = (element, width, rows) => ({
|
17621 | element,
|
17622 | width,
|
17623 | rows
|
17624 | });
|
17625 | const tableRow = (element, cells) => ({
|
17626 | element,
|
17627 | cells
|
17628 | });
|
17629 | const cellPosition = (x, y) => ({
|
17630 | x,
|
17631 | y
|
17632 | });
|
17633 | const getSpan = (td, key) => {
|
17634 | return getOpt(td, key).bind(toInt).getOr(1);
|
17635 | };
|
17636 | const fillout = (table, x, y, tr, td) => {
|
17637 | const rowspan = getSpan(td, 'rowspan');
|
17638 | const colspan = getSpan(td, 'colspan');
|
17639 | const rows = table.rows;
|
17640 | for (let y2 = y; y2 < y + rowspan; y2++) {
|
17641 | if (!rows[y2]) {
|
17642 | rows[y2] = tableRow(deep$1(tr), []);
|
17643 | }
|
17644 | for (let x2 = x; x2 < x + colspan; x2++) {
|
17645 | const cells = rows[y2].cells;
|
17646 | cells[x2] = y2 === y && x2 === x ? td : shallow$1(td);
|
17647 | }
|
17648 | }
|
17649 | };
|
17650 | const cellExists = (table, x, y) => {
|
17651 | const rows = table.rows;
|
17652 | const cells = rows[y] ? rows[y].cells : [];
|
17653 | return !!cells[x];
|
17654 | };
|
17655 | const skipCellsX = (table, x, y) => {
|
17656 | while (cellExists(table, x, y)) {
|
17657 | x++;
|
17658 | }
|
17659 | return x;
|
17660 | };
|
17661 | const getWidth = rows => {
|
17662 | return foldl(rows, (acc, row) => {
|
17663 | return row.cells.length > acc ? row.cells.length : acc;
|
17664 | }, 0);
|
17665 | };
|
17666 | const findElementPos = (table, element) => {
|
17667 | const rows = table.rows;
|
17668 | for (let y = 0; y < rows.length; y++) {
|
17669 | const cells = rows[y].cells;
|
17670 | for (let x = 0; x < cells.length; x++) {
|
17671 | if (eq(cells[x], element)) {
|
17672 | return Optional.some(cellPosition(x, y));
|
17673 | }
|
17674 | }
|
17675 | }
|
17676 | return Optional.none();
|
17677 | };
|
17678 | const extractRows = (table, sx, sy, ex, ey) => {
|
17679 | const newRows = [];
|
17680 | const rows = table.rows;
|
17681 | for (let y = sy; y <= ey; y++) {
|
17682 | const cells = rows[y].cells;
|
17683 | const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
|
17684 | newRows.push(tableRow(rows[y].element, slice));
|
17685 | }
|
17686 | return newRows;
|
17687 | };
|
17688 | const subTable = (table, startPos, endPos) => {
|
17689 | const sx = startPos.x, sy = startPos.y;
|
17690 | const ex = endPos.x, ey = endPos.y;
|
17691 | const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
|
17692 | return tableModel(table.element, getWidth(newRows), newRows);
|
17693 | };
|
17694 | const createDomTable = (table, rows) => {
|
17695 | const tableElement = shallow$1(table.element);
|
17696 | const tableBody = SugarElement.fromTag('tbody');
|
17697 | append(tableBody, rows);
|
17698 | append$1(tableElement, tableBody);
|
17699 | return tableElement;
|
17700 | };
|
17701 | const modelRowsToDomRows = table => {
|
17702 | return map$3(table.rows, row => {
|
17703 | const cells = map$3(row.cells, cell => {
|
17704 | const td = deep$1(cell);
|
17705 | remove$9(td, 'colspan');
|
17706 | remove$9(td, 'rowspan');
|
17707 | return td;
|
17708 | });
|
17709 | const tr = shallow$1(row.element);
|
17710 | append(tr, cells);
|
17711 | return tr;
|
17712 | });
|
17713 | };
|
17714 | const fromDom = tableElm => {
|
17715 | const table = tableModel(shallow$1(tableElm), 0, []);
|
17716 | each$e(descendants(tableElm, 'tr'), (tr, y) => {
|
17717 | each$e(descendants(tr, 'td,th'), (td, x) => {
|
17718 | fillout(table, skipCellsX(table, x, y), y, tr, td);
|
17719 | });
|
17720 | });
|
17721 | return tableModel(table.element, getWidth(table.rows), table.rows);
|
17722 | };
|
17723 | const toDom = table => {
|
17724 | return createDomTable(table, modelRowsToDomRows(table));
|
17725 | };
|
17726 | const subsection = (table, startElement, endElement) => {
|
17727 | return findElementPos(table, startElement).bind(startPos => {
|
17728 | return findElementPos(table, endElement).map(endPos => {
|
17729 | return subTable(table, startPos, endPos);
|
17730 | });
|
17731 | });
|
17732 | };
|
17733 |
|
17734 | const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol');
|
17735 | const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => {
|
17736 | const listElm = SugarElement.fromTag(name(listCont));
|
17737 | const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style'));
|
17738 | setAll(listElm, listStyles);
|
17739 | return [
|
17740 | SugarElement.fromTag('li'),
|
17741 | listElm
|
17742 | ];
|
17743 | }).getOr([]));
|
17744 | const wrap = (innerElm, elms) => {
|
17745 | const wrapped = foldl(elms, (acc, elm) => {
|
17746 | append$1(elm, acc);
|
17747 | return elm;
|
17748 | }, innerElm);
|
17749 | return elms.length > 0 ? fromElements([wrapped]) : wrapped;
|
17750 | };
|
17751 | const directListWrappers = commonAnchorContainer => {
|
17752 | if (isListItem$1(commonAnchorContainer)) {
|
17753 | return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [
|
17754 | commonAnchorContainer,
|
17755 | listElm
|
17756 | ]);
|
17757 | } else {
|
17758 | return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
|
17759 | }
|
17760 | };
|
17761 | const getWrapElements = (rootNode, rng, schema) => {
|
17762 | const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
|
17763 | const parents = parentsAndSelf(commonAnchorContainer, rootNode);
|
17764 | const wrapElements = filter$5(parents, el => schema.isWrapper(name(el)));
|
17765 | const listWrappers = getFullySelectedListWrappers(parents, rng);
|
17766 | const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
|
17767 | return map$3(allWrappers, shallow$1);
|
17768 | };
|
17769 | const emptyFragment = () => fromElements([]);
|
17770 | const getFragmentFromRange = (rootNode, rng, schema) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng, schema));
|
17771 | const getParentTable = (rootElm, cell) => ancestor$3(cell, 'table', curry(eq, rootElm));
|
17772 | const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => {
|
17773 | const firstCell = selectedTableCells[0];
|
17774 | const lastCell = selectedTableCells[selectedTableCells.length - 1];
|
17775 | const fullTableModel = fromDom(tableElm);
|
17776 | return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)]));
|
17777 | }).getOrThunk(emptyFragment);
|
17778 | const getSelectionFragment = (rootNode, ranges, schema) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0], schema);
|
17779 | const read$3 = (rootNode, ranges, schema) => {
|
17780 | const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
|
17781 | return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges, schema);
|
17782 | };
|
17783 |
|
17784 | const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index));
|
17785 | const getInnerText = bin => {
|
17786 | return trim$2(bin.innerText);
|
17787 | };
|
17788 | const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase();
|
17789 | const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => {
|
17790 | var _a;
|
17791 | const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
|
17792 | const body = editor.getBody();
|
17793 | const contextNodeName = getContextNodeName(parentBlockOpt);
|
17794 | const rangeContentClone = SugarElement.fromDom(rng.cloneContents());
|
17795 | cleanupBogusElements(rangeContentClone);
|
17796 | cleanupInputNames(rangeContentClone);
|
17797 | const bin = editor.dom.add(body, contextNodeName, {
|
17798 | 'data-mce-bogus': 'all',
|
17799 | 'style': 'overflow: hidden; opacity: 0;'
|
17800 | }, rangeContentClone.dom);
|
17801 | const text = getInnerText(bin);
|
17802 | const nonRenderedText = trim$2((_a = bin.textContent) !== null && _a !== void 0 ? _a : '');
|
17803 | editor.dom.remove(bin);
|
17804 | if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
|
17805 | const parentBlock = parentBlockOpt.getOr(body);
|
17806 | const parentBlockText = getInnerText(parentBlock);
|
17807 | const textIndex = parentBlockText.indexOf(text);
|
17808 | if (textIndex === -1) {
|
17809 | return text;
|
17810 | } else {
|
17811 | const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
|
17812 | const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length);
|
17813 | return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : '');
|
17814 | }
|
17815 | } else {
|
17816 | return text;
|
17817 | }
|
17818 | }).getOr('');
|
17819 | const getSerializedContent = (editor, args) => {
|
17820 | const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
|
17821 | const sel = editor.selection.getSel();
|
17822 | const ranges = processRanges(editor, getRanges$1(sel));
|
17823 | const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges, editor.schema).dom : rng.cloneContents();
|
17824 | if (fragment) {
|
17825 | tmpElm.appendChild(fragment);
|
17826 | }
|
17827 | return editor.selection.serializer.serialize(tmpElm, args);
|
17828 | };
|
17829 | const extractSelectedContent = (editor, args) => {
|
17830 | if (args.format === 'text') {
|
17831 | return getTextContent(editor);
|
17832 | } else {
|
17833 | const content = getSerializedContent(editor, args);
|
17834 | if (args.format === 'tree') {
|
17835 | return content;
|
17836 | } else {
|
17837 | return editor.selection.isCollapsed() ? '' : content;
|
17838 | }
|
17839 | }
|
17840 | };
|
17841 | const setupArgs$3 = (args, format) => ({
|
17842 | ...args,
|
17843 | format,
|
17844 | get: true,
|
17845 | selection: true,
|
17846 | getInner: true
|
17847 | });
|
17848 | const getSelectedContentInternal = (editor, format, args = {}) => {
|
17849 | const defaultedArgs = setupArgs$3(args, format);
|
17850 | return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
|
17851 | const content = extractSelectedContent(editor, updatedArgs);
|
17852 | return postProcessGetContent(editor, content, updatedArgs);
|
17853 | });
|
17854 | };
|
17855 |
|
17856 | const KEEP = 0, INSERT = 1, DELETE = 2;
|
17857 | const diff = (left, right) => {
|
17858 | const size = left.length + right.length + 2;
|
17859 | const vDown = new Array(size);
|
17860 | const vUp = new Array(size);
|
17861 | const snake = (start, end, diag) => {
|
17862 | return {
|
17863 | start,
|
17864 | end,
|
17865 | diag
|
17866 | };
|
17867 | };
|
17868 | const buildScript = (start1, end1, start2, end2, script) => {
|
17869 | const middle = getMiddleSnake(start1, end1, start2, end2);
|
17870 | if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
|
17871 | let i = start1;
|
17872 | let j = start2;
|
17873 | while (i < end1 || j < end2) {
|
17874 | if (i < end1 && j < end2 && left[i] === right[j]) {
|
17875 | script.push([
|
17876 | KEEP,
|
17877 | left[i]
|
17878 | ]);
|
17879 | ++i;
|
17880 | ++j;
|
17881 | } else {
|
17882 | if (end1 - start1 > end2 - start2) {
|
17883 | script.push([
|
17884 | DELETE,
|
17885 | left[i]
|
17886 | ]);
|
17887 | ++i;
|
17888 | } else {
|
17889 | script.push([
|
17890 | INSERT,
|
17891 | right[j]
|
17892 | ]);
|
17893 | ++j;
|
17894 | }
|
17895 | }
|
17896 | }
|
17897 | } else {
|
17898 | buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
|
17899 | for (let i2 = middle.start; i2 < middle.end; ++i2) {
|
17900 | script.push([
|
17901 | KEEP,
|
17902 | left[i2]
|
17903 | ]);
|
17904 | }
|
17905 | buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
|
17906 | }
|
17907 | };
|
17908 | const buildSnake = (start, diag, end1, end2) => {
|
17909 | let end = start;
|
17910 | while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
|
17911 | ++end;
|
17912 | }
|
17913 | return snake(start, end, diag);
|
17914 | };
|
17915 | const getMiddleSnake = (start1, end1, start2, end2) => {
|
17916 | const m = end1 - start1;
|
17917 | const n = end2 - start2;
|
17918 | if (m === 0 || n === 0) {
|
17919 | return null;
|
17920 | }
|
17921 | const delta = m - n;
|
17922 | const sum = n + m;
|
17923 | const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
|
17924 | vDown[1 + offset] = start1;
|
17925 | vUp[1 + offset] = end1 + 1;
|
17926 | let d, k, i, x, y;
|
17927 | for (d = 0; d <= offset; ++d) {
|
17928 | for (k = -d; k <= d; k += 2) {
|
17929 | i = k + offset;
|
17930 | if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
|
17931 | vDown[i] = vDown[i + 1];
|
17932 | } else {
|
17933 | vDown[i] = vDown[i - 1] + 1;
|
17934 | }
|
17935 | x = vDown[i];
|
17936 | y = x - start1 + start2 - k;
|
17937 | while (x < end1 && y < end2 && left[x] === right[y]) {
|
17938 | vDown[i] = ++x;
|
17939 | ++y;
|
17940 | }
|
17941 | if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
|
17942 | if (vUp[i - delta] <= vDown[i]) {
|
17943 | return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
|
17944 | }
|
17945 | }
|
17946 | }
|
17947 | for (k = delta - d; k <= delta + d; k += 2) {
|
17948 | i = k + offset - delta;
|
17949 | if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
|
17950 | vUp[i] = vUp[i + 1] - 1;
|
17951 | } else {
|
17952 | vUp[i] = vUp[i - 1];
|
17953 | }
|
17954 | x = vUp[i] - 1;
|
17955 | y = x - start1 + start2 - k;
|
17956 | while (x >= start1 && y >= start2 && left[x] === right[y]) {
|
17957 | vUp[i] = x--;
|
17958 | y--;
|
17959 | }
|
17960 | if (delta % 2 === 0 && -d <= k && k <= d) {
|
17961 | if (vUp[i] <= vDown[i + delta]) {
|
17962 | return buildSnake(vUp[i], k + start1 - start2, end1, end2);
|
17963 | }
|
17964 | }
|
17965 | }
|
17966 | }
|
17967 | return null;
|
17968 | };
|
17969 | const script = [];
|
17970 | buildScript(0, left.length, 0, right.length, script);
|
17971 | return script;
|
17972 | };
|
17973 |
|
17974 | const getOuterHtml = elm => {
|
17975 | if (isElement$6(elm)) {
|
17976 | return elm.outerHTML;
|
17977 | } else if (isText$b(elm)) {
|
17978 | return Entities.encodeRaw(elm.data, false);
|
17979 | } else if (isComment(elm)) {
|
17980 | return '<!--' + elm.data + '-->';
|
17981 | }
|
17982 | return '';
|
17983 | };
|
17984 | const createFragment = html => {
|
17985 | let node;
|
17986 | const container = document.createElement('div');
|
17987 | const frag = document.createDocumentFragment();
|
17988 | if (html) {
|
17989 | container.innerHTML = html;
|
17990 | }
|
17991 | while (node = container.firstChild) {
|
17992 | frag.appendChild(node);
|
17993 | }
|
17994 | return frag;
|
17995 | };
|
17996 | const insertAt = (elm, html, index) => {
|
17997 | const fragment = createFragment(html);
|
17998 | if (elm.hasChildNodes() && index < elm.childNodes.length) {
|
17999 | const target = elm.childNodes[index];
|
18000 | elm.insertBefore(fragment, target);
|
18001 | } else {
|
18002 | elm.appendChild(fragment);
|
18003 | }
|
18004 | };
|
18005 | const removeAt = (elm, index) => {
|
18006 | if (elm.hasChildNodes() && index < elm.childNodes.length) {
|
18007 | const target = elm.childNodes[index];
|
18008 | elm.removeChild(target);
|
18009 | }
|
18010 | };
|
18011 | const applyDiff = (diff, elm) => {
|
18012 | let index = 0;
|
18013 | each$e(diff, action => {
|
18014 | if (action[0] === KEEP) {
|
18015 | index++;
|
18016 | } else if (action[0] === INSERT) {
|
18017 | insertAt(elm, action[1], index);
|
18018 | index++;
|
18019 | } else if (action[0] === DELETE) {
|
18020 | removeAt(elm, index);
|
18021 | }
|
18022 | });
|
18023 | };
|
18024 | const read$2 = (elm, trimZwsp) => filter$5(map$3(from(elm.childNodes), trimZwsp ? compose(trim$2, getOuterHtml) : getOuterHtml), item => {
|
18025 | return item.length > 0;
|
18026 | });
|
18027 | const write = (fragments, elm) => {
|
18028 | const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
|
18029 | applyDiff(diff(currentFragments, fragments), elm);
|
18030 | return elm;
|
18031 | };
|
18032 |
|
18033 | const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo'));
|
18034 | const hasIframes = body => body.querySelector('iframe') !== null;
|
18035 | const createFragmentedLevel = fragments => {
|
18036 | return {
|
18037 | type: 'fragmented',
|
18038 | fragments,
|
18039 | content: '',
|
18040 | bookmark: null,
|
18041 | beforeBookmark: null
|
18042 | };
|
18043 | };
|
18044 | const createCompleteLevel = content => {
|
18045 | return {
|
18046 | type: 'complete',
|
18047 | fragments: null,
|
18048 | content,
|
18049 | bookmark: null,
|
18050 | beforeBookmark: null
|
18051 | };
|
18052 | };
|
18053 | const createFromEditor = editor => {
|
18054 | const tempAttrs = editor.serializer.getTempAttrs();
|
18055 | const body = trim$1(editor.getBody(), tempAttrs);
|
18056 | return hasIframes(body) ? createFragmentedLevel(read$2(body, true)) : createCompleteLevel(trim$2(body.innerHTML));
|
18057 | };
|
18058 | const applyToEditor = (editor, level, before) => {
|
18059 | const bookmark = before ? level.beforeBookmark : level.bookmark;
|
18060 | if (level.type === 'fragmented') {
|
18061 | write(level.fragments, editor.getBody());
|
18062 | } else {
|
18063 | editor.setContent(level.content, {
|
18064 | format: 'raw',
|
18065 | no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
|
18066 | });
|
18067 | }
|
18068 | if (bookmark) {
|
18069 | editor.selection.moveToBookmark(bookmark);
|
18070 | editor.selection.scrollIntoView();
|
18071 | }
|
18072 | };
|
18073 | const getLevelContent = level => {
|
18074 | return level.type === 'fragmented' ? level.fragments.join('') : level.content;
|
18075 | };
|
18076 | const getCleanLevelContent = level => {
|
18077 | const elm = SugarElement.fromTag('body', lazyTempDocument());
|
18078 | set$1(elm, getLevelContent(level));
|
18079 | each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
|
18080 | return get$6(elm);
|
18081 | };
|
18082 | const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
|
18083 | const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
|
18084 | const isEq$1 = (level1, level2) => {
|
18085 | if (!level1 || !level2) {
|
18086 | return false;
|
18087 | } else if (hasEqualContent(level1, level2)) {
|
18088 | return true;
|
18089 | } else {
|
18090 | return hasEqualCleanedContent(level1, level2);
|
18091 | }
|
18092 | };
|
18093 |
|
18094 | const isUnlocked = locks => locks.get() === 0;
|
18095 |
|
18096 | const setTyping = (undoManager, typing, locks) => {
|
18097 | if (isUnlocked(locks)) {
|
18098 | undoManager.typing = typing;
|
18099 | }
|
18100 | };
|
18101 | const endTyping = (undoManager, locks) => {
|
18102 | if (undoManager.typing) {
|
18103 | setTyping(undoManager, false, locks);
|
18104 | undoManager.add();
|
18105 | }
|
18106 | };
|
18107 | const endTypingLevelIgnoreLocks = undoManager => {
|
18108 | if (undoManager.typing) {
|
18109 | undoManager.typing = false;
|
18110 | undoManager.add();
|
18111 | }
|
18112 | };
|
18113 |
|
18114 | const beforeChange$1 = (editor, locks, beforeBookmark) => {
|
18115 | if (isUnlocked(locks)) {
|
18116 | beforeBookmark.set(getUndoBookmark(editor.selection));
|
18117 | }
|
18118 | };
|
18119 | const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => {
|
18120 | const currentLevel = createFromEditor(editor);
|
18121 | const newLevel = Tools.extend(level || {}, currentLevel);
|
18122 | if (!isUnlocked(locks) || editor.removed) {
|
18123 | return null;
|
18124 | }
|
18125 | const lastLevel = undoManager.data[index.get()];
|
18126 | if (editor.dispatch('BeforeAddUndo', {
|
18127 | level: newLevel,
|
18128 | lastLevel,
|
18129 | originalEvent: event
|
18130 | }).isDefaultPrevented()) {
|
18131 | return null;
|
18132 | }
|
18133 | if (lastLevel && isEq$1(lastLevel, newLevel)) {
|
18134 | return null;
|
18135 | }
|
18136 | if (undoManager.data[index.get()]) {
|
18137 | beforeBookmark.get().each(bm => {
|
18138 | undoManager.data[index.get()].beforeBookmark = bm;
|
18139 | });
|
18140 | }
|
18141 | const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
|
18142 | if (customUndoRedoLevels) {
|
18143 | if (undoManager.data.length > customUndoRedoLevels) {
|
18144 | for (let i = 0; i < undoManager.data.length - 1; i++) {
|
18145 | undoManager.data[i] = undoManager.data[i + 1];
|
18146 | }
|
18147 | undoManager.data.length--;
|
18148 | index.set(undoManager.data.length);
|
18149 | }
|
18150 | }
|
18151 | newLevel.bookmark = getUndoBookmark(editor.selection);
|
18152 | if (index.get() < undoManager.data.length - 1) {
|
18153 | undoManager.data.length = index.get() + 1;
|
18154 | }
|
18155 | undoManager.data.push(newLevel);
|
18156 | index.set(undoManager.data.length - 1);
|
18157 | const args = {
|
18158 | level: newLevel,
|
18159 | lastLevel,
|
18160 | originalEvent: event
|
18161 | };
|
18162 | if (index.get() > 0) {
|
18163 | editor.setDirty(true);
|
18164 | editor.dispatch('AddUndo', args);
|
18165 | editor.dispatch('change', args);
|
18166 | } else {
|
18167 | editor.dispatch('AddUndo', args);
|
18168 | }
|
18169 | return newLevel;
|
18170 | };
|
18171 | const clear$1 = (editor, undoManager, index) => {
|
18172 | undoManager.data = [];
|
18173 | index.set(0);
|
18174 | undoManager.typing = false;
|
18175 | editor.dispatch('ClearUndos');
|
18176 | };
|
18177 | const extra$1 = (editor, undoManager, index, callback1, callback2) => {
|
18178 | if (undoManager.transact(callback1)) {
|
18179 | const bookmark = undoManager.data[index.get()].bookmark;
|
18180 | const lastLevel = undoManager.data[index.get() - 1];
|
18181 | applyToEditor(editor, lastLevel, true);
|
18182 | if (undoManager.transact(callback2)) {
|
18183 | undoManager.data[index.get() - 1].beforeBookmark = bookmark;
|
18184 | }
|
18185 | }
|
18186 | };
|
18187 | const redo$1 = (editor, index, data) => {
|
18188 | let level;
|
18189 | if (index.get() < data.length - 1) {
|
18190 | index.set(index.get() + 1);
|
18191 | level = data[index.get()];
|
18192 | applyToEditor(editor, level, false);
|
18193 | editor.setDirty(true);
|
18194 | editor.dispatch('Redo', { level });
|
18195 | }
|
18196 | return level;
|
18197 | };
|
18198 | const undo$1 = (editor, undoManager, locks, index) => {
|
18199 | let level;
|
18200 | if (undoManager.typing) {
|
18201 | undoManager.add();
|
18202 | undoManager.typing = false;
|
18203 | setTyping(undoManager, false, locks);
|
18204 | }
|
18205 | if (index.get() > 0) {
|
18206 | index.set(index.get() - 1);
|
18207 | level = undoManager.data[index.get()];
|
18208 | applyToEditor(editor, level, true);
|
18209 | editor.setDirty(true);
|
18210 | editor.dispatch('Undo', { level });
|
18211 | }
|
18212 | return level;
|
18213 | };
|
18214 | const reset$1 = undoManager => {
|
18215 | undoManager.clear();
|
18216 | undoManager.add();
|
18217 | };
|
18218 | const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
|
18219 | const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
|
18220 | const transact$1 = (undoManager, locks, callback) => {
|
18221 | endTyping(undoManager, locks);
|
18222 | undoManager.beforeChange();
|
18223 | undoManager.ignore(callback);
|
18224 | return undoManager.add();
|
18225 | };
|
18226 | const ignore$1 = (locks, callback) => {
|
18227 | try {
|
18228 | locks.set(locks.get() + 1);
|
18229 | callback();
|
18230 | } finally {
|
18231 | locks.set(locks.get() - 1);
|
18232 | }
|
18233 | };
|
18234 |
|
18235 | const addVisualInternal = (editor, elm) => {
|
18236 | const dom = editor.dom;
|
18237 | const scope = isNonNullable(elm) ? elm : editor.getBody();
|
18238 | each$e(dom.select('table,a', scope), matchedElm => {
|
18239 | switch (matchedElm.nodeName) {
|
18240 | case 'TABLE':
|
18241 | const cls = getVisualAidsTableClass(editor);
|
18242 | const value = dom.getAttrib(matchedElm, 'border');
|
18243 | if ((!value || value === '0') && editor.hasVisual) {
|
18244 | dom.addClass(matchedElm, cls);
|
18245 | } else {
|
18246 | dom.removeClass(matchedElm, cls);
|
18247 | }
|
18248 | break;
|
18249 | case 'A':
|
18250 | if (!dom.getAttrib(matchedElm, 'href')) {
|
18251 | const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id;
|
18252 | const cls = getVisualAidsAnchorClass(editor);
|
18253 | if (value && editor.hasVisual) {
|
18254 | dom.addClass(matchedElm, cls);
|
18255 | } else {
|
18256 | dom.removeClass(matchedElm, cls);
|
18257 | }
|
18258 | }
|
18259 | break;
|
18260 | }
|
18261 | });
|
18262 | editor.dispatch('VisualAid', {
|
18263 | element: elm,
|
18264 | hasVisual: editor.hasVisual
|
18265 | });
|
18266 | };
|
18267 |
|
18268 | const makePlainAdaptor = editor => ({
|
18269 | init: { bindEvents: noop },
|
18270 | undoManager: {
|
18271 | beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
|
18272 | add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event),
|
18273 | undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index),
|
18274 | redo: (index, data) => redo$1(editor, index, data),
|
18275 | clear: (undoManager, index) => clear$1(editor, undoManager, index),
|
18276 | reset: undoManager => reset$1(undoManager),
|
18277 | hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index),
|
18278 | hasRedo: (undoManager, index) => hasRedo$1(undoManager, index),
|
18279 | transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
|
18280 | ignore: (locks, callback) => ignore$1(locks, callback),
|
18281 | extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2)
|
18282 | },
|
18283 | formatter: {
|
18284 | match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar),
|
18285 | matchAll: (names, vars) => matchAll(editor, names, vars),
|
18286 | matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar),
|
18287 | canApply: name => canApply(editor, name),
|
18288 | closest: names => closest(editor, names),
|
18289 | apply: (name, vars, node) => applyFormat$1(editor, name, vars, node),
|
18290 | remove: (name, vars, node, similar) => removeFormat$1(editor, name, vars, node, similar),
|
18291 | toggle: (name, vars, node) => toggle(editor, name, vars, node),
|
18292 | formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
|
18293 | },
|
18294 | editor: {
|
18295 | getContent: args => getContentInternal(editor, args),
|
18296 | setContent: (content, args) => setContentInternal(editor, content, args),
|
18297 | insertContent: (value, details) => insertHtmlAtCaret(editor, value, details),
|
18298 | addVisual: elm => addVisualInternal(editor, elm)
|
18299 | },
|
18300 | selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
|
18301 | autocompleter: {
|
18302 | addDecoration: noop,
|
18303 | removeDecoration: noop
|
18304 | },
|
18305 | raw: { getModel: () => Optional.none() }
|
18306 | });
|
18307 | const makeRtcAdaptor = rtcEditor => {
|
18308 | const defaultVars = vars => isObject(vars) ? vars : {};
|
18309 | const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor;
|
18310 | return {
|
18311 | init: { bindEvents: init.bindEvents },
|
18312 | undoManager: {
|
18313 | beforeChange: undoManager.beforeChange,
|
18314 | add: undoManager.add,
|
18315 | undo: undoManager.undo,
|
18316 | redo: undoManager.redo,
|
18317 | clear: undoManager.clear,
|
18318 | reset: undoManager.reset,
|
18319 | hasUndo: undoManager.hasUndo,
|
18320 | hasRedo: undoManager.hasRedo,
|
18321 | transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
|
18322 | ignore: (_locks, callback) => undoManager.ignore(callback),
|
18323 | extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
|
18324 | },
|
18325 | formatter: {
|
18326 | match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar),
|
18327 | matchAll: formatter.matchAll,
|
18328 | matchNode: formatter.matchNode,
|
18329 | canApply: name => formatter.canApply(name),
|
18330 | closest: names => formatter.closest(names),
|
18331 | apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)),
|
18332 | remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)),
|
18333 | toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)),
|
18334 | formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
|
18335 | },
|
18336 | editor: {
|
18337 | getContent: args => editor.getContent(args),
|
18338 | setContent: (content, args) => {
|
18339 | return {
|
18340 | content: editor.setContent(content, args),
|
18341 | html: ''
|
18342 | };
|
18343 | },
|
18344 | insertContent: (content, _details) => {
|
18345 | editor.insertContent(content);
|
18346 | return '';
|
18347 | },
|
18348 | addVisual: editor.addVisual
|
18349 | },
|
18350 | selection: { getContent: (_format, args) => selection.getContent(args) },
|
18351 | autocompleter: {
|
18352 | addDecoration: autocompleter.addDecoration,
|
18353 | removeDecoration: autocompleter.removeDecoration
|
18354 | },
|
18355 | raw: { getModel: () => Optional.some(raw.getRawModel()) }
|
18356 | };
|
18357 | };
|
18358 | const makeNoopAdaptor = () => {
|
18359 | const nul = constant(null);
|
18360 | const empty = constant('');
|
18361 | return {
|
18362 | init: { bindEvents: noop },
|
18363 | undoManager: {
|
18364 | beforeChange: noop,
|
18365 | add: nul,
|
18366 | undo: nul,
|
18367 | redo: nul,
|
18368 | clear: noop,
|
18369 | reset: noop,
|
18370 | hasUndo: never,
|
18371 | hasRedo: never,
|
18372 | transact: nul,
|
18373 | ignore: noop,
|
18374 | extra: noop
|
18375 | },
|
18376 | formatter: {
|
18377 | match: never,
|
18378 | matchAll: constant([]),
|
18379 | matchNode: constant(undefined),
|
18380 | canApply: never,
|
18381 | closest: empty,
|
18382 | apply: noop,
|
18383 | remove: noop,
|
18384 | toggle: noop,
|
18385 | formatChanged: constant({ unbind: noop })
|
18386 | },
|
18387 | editor: {
|
18388 | getContent: empty,
|
18389 | setContent: constant({
|
18390 | content: '',
|
18391 | html: ''
|
18392 | }),
|
18393 | insertContent: constant(''),
|
18394 | addVisual: noop
|
18395 | },
|
18396 | selection: { getContent: empty },
|
18397 | autocompleter: {
|
18398 | addDecoration: noop,
|
18399 | removeDecoration: noop
|
18400 | },
|
18401 | raw: { getModel: constant(Optional.none()) }
|
18402 | };
|
18403 | };
|
18404 | const isRtc = editor => has$2(editor.plugins, 'rtc');
|
18405 | const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup));
|
18406 | const setup$t = editor => {
|
18407 | const editorCast = editor;
|
18408 | return getRtcSetup(editor).fold(() => {
|
18409 | editorCast.rtcInstance = makePlainAdaptor(editor);
|
18410 | return Optional.none();
|
18411 | }, setup => {
|
18412 | editorCast.rtcInstance = makeNoopAdaptor();
|
18413 | return Optional.some(() => setup().then(rtcEditor => {
|
18414 | editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
|
18415 | return rtcEditor.rtc.isRemote;
|
18416 | }));
|
18417 | });
|
18418 | };
|
18419 | const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
|
18420 | const getRtcInstanceWithError = editor => {
|
18421 | const rtcInstance = editor.rtcInstance;
|
18422 | if (!rtcInstance) {
|
18423 | throw new Error('Failed to get RTC instance not yet initialized.');
|
18424 | } else {
|
18425 | return rtcInstance;
|
18426 | }
|
18427 | };
|
18428 | const beforeChange = (editor, locks, beforeBookmark) => {
|
18429 | getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
|
18430 | };
|
18431 | const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event);
|
18432 | const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index);
|
18433 | const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data);
|
18434 | const clear = (editor, undoManager, index) => {
|
18435 | getRtcInstanceWithError(editor).undoManager.clear(undoManager, index);
|
18436 | };
|
18437 | const reset = (editor, undoManager) => {
|
18438 | getRtcInstanceWithError(editor).undoManager.reset(undoManager);
|
18439 | };
|
18440 | const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index);
|
18441 | const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index);
|
18442 | const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
|
18443 | const ignore = (editor, locks, callback) => {
|
18444 | getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
|
18445 | };
|
18446 | const extra = (editor, undoManager, index, callback1, callback2) => {
|
18447 | getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2);
|
18448 | };
|
18449 | const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar);
|
18450 | const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
|
18451 | const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar);
|
18452 | const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name);
|
18453 | const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
|
18454 | const applyFormat = (editor, name, vars, node) => {
|
18455 | getRtcInstanceWithError(editor).formatter.apply(name, vars, node);
|
18456 | };
|
18457 | const removeFormat = (editor, name, vars, node, similar) => {
|
18458 | getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar);
|
18459 | };
|
18460 | const toggleFormat = (editor, name, vars, node) => {
|
18461 | getRtcInstanceWithError(editor).formatter.toggle(name, vars, node);
|
18462 | };
|
18463 | const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
|
18464 | const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
|
18465 | const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
|
18466 | const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details);
|
18467 | const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
|
18468 | const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
|
18469 | const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents();
|
18470 |
|
18471 | const getContent$1 = (editor, args = {}) => {
|
18472 | const format = args.format ? args.format : 'html';
|
18473 | return getSelectedContent(editor, format, args);
|
18474 | };
|
18475 |
|
18476 | const removeEmpty = text => {
|
18477 | if (text.dom.length === 0) {
|
18478 | remove$4(text);
|
18479 | return Optional.none();
|
18480 | } else {
|
18481 | return Optional.some(text);
|
18482 | }
|
18483 | };
|
18484 | const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling);
|
18485 | const merge$1 = (outer, inner, rng, start, schema) => {
|
18486 | const outerElm = outer.dom;
|
18487 | const innerElm = inner.dom;
|
18488 | const oldLength = start ? outerElm.length : innerElm.length;
|
18489 | if (start) {
|
18490 | mergeTextNodes(outerElm, innerElm, schema, false, !start);
|
18491 | rng.setStart(innerElm, oldLength);
|
18492 | } else {
|
18493 | mergeTextNodes(innerElm, outerElm, schema, false, !start);
|
18494 | rng.setEnd(innerElm, oldLength);
|
18495 | }
|
18496 | };
|
18497 | const normalizeTextIfRequired = (inner, start, schema) => {
|
18498 | parent(inner).each(root => {
|
18499 | const text = inner.dom;
|
18500 | if (start && needsToBeNbspLeft(root, CaretPosition(text, 0), schema)) {
|
18501 | normalizeWhitespaceAfter(text, 0, schema);
|
18502 | } else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length), schema)) {
|
18503 | normalizeWhitespaceBefore(text, text.length, schema);
|
18504 | }
|
18505 | });
|
18506 | };
|
18507 | const mergeAndNormalizeText = (outerNode, innerNode, rng, start, schema) => {
|
18508 | outerNode.bind(outer => {
|
18509 | const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
|
18510 | normalizer(outer.dom, start ? outer.dom.length : 0, schema);
|
18511 | return innerNode.filter(isText$c).map(inner => merge$1(outer, inner, rng, start, schema));
|
18512 | }).orThunk(() => {
|
18513 | const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$c);
|
18514 | return innerTextNode.map(inner => normalizeTextIfRequired(inner, start, schema));
|
18515 | });
|
18516 | };
|
18517 | const rngSetContent = (rng, fragment, schema) => {
|
18518 | const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
|
18519 | const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
|
18520 | rng.deleteContents();
|
18521 | rng.insertNode(fragment);
|
18522 | const prevText = firstChild.bind(prevSibling).filter(isText$c).bind(removeEmpty);
|
18523 | const nextText = lastChild.bind(nextSibling).filter(isText$c).bind(removeEmpty);
|
18524 | mergeAndNormalizeText(prevText, firstChild, rng, true, schema);
|
18525 | mergeAndNormalizeText(nextText, lastChild, rng, false, schema);
|
18526 | rng.collapse(false);
|
18527 | };
|
18528 | const setupArgs$2 = (args, content) => ({
|
18529 | format: 'html',
|
18530 | ...args,
|
18531 | set: true,
|
18532 | selection: true,
|
18533 | content
|
18534 | });
|
18535 | const cleanContent = (editor, args) => {
|
18536 | if (args.format !== 'raw') {
|
18537 | const rng = editor.selection.getRng();
|
18538 | const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
|
18539 | const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
|
18540 | const node = editor.parser.parse(args.content, {
|
18541 | forced_root_block: false,
|
18542 | ...contextArgs,
|
18543 | ...args
|
18544 | });
|
18545 | return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
|
18546 | } else {
|
18547 | return args.content;
|
18548 | }
|
18549 | };
|
18550 | const setContent$1 = (editor, content, args = {}) => {
|
18551 | const defaultedArgs = setupArgs$2(args, content);
|
18552 | preProcessSetContent(editor, defaultedArgs).each(updatedArgs => {
|
18553 | const cleanedContent = cleanContent(editor, updatedArgs);
|
18554 | const rng = editor.selection.getRng();
|
18555 | rngSetContent(rng, rng.createContextualFragment(cleanedContent), editor.schema);
|
18556 | editor.selection.setRng(rng);
|
18557 | scrollRangeIntoView(editor, rng);
|
18558 | postProcessSetContent(editor, cleanedContent, updatedArgs);
|
18559 | });
|
18560 | };
|
18561 |
|
18562 | const deleteFromCallbackMap = (callbackMap, selector, callback) => {
|
18563 | if (has$2(callbackMap, selector)) {
|
18564 | const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback);
|
18565 | if (newCallbacks.length === 0) {
|
18566 | delete callbackMap[selector];
|
18567 | } else {
|
18568 | callbackMap[selector] = newCallbacks;
|
18569 | }
|
18570 | }
|
18571 | };
|
18572 | var SelectorChanged = (dom, editor) => {
|
18573 | let selectorChangedData;
|
18574 | let currentSelectors;
|
18575 | const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector));
|
18576 | const getParents = elem => dom.getParents(elem, undefined, dom.getRoot());
|
18577 | const setup = () => {
|
18578 | selectorChangedData = {};
|
18579 | currentSelectors = {};
|
18580 | editor.on('NodeChange', e => {
|
18581 | const node = e.element;
|
18582 | const parents = getParents(node);
|
18583 | const matchedSelectors = {};
|
18584 | each$d(selectorChangedData, (callbacks, selector) => {
|
18585 | findMatchingNode(selector, parents).each(node => {
|
18586 | if (!currentSelectors[selector]) {
|
18587 | each$e(callbacks, callback => {
|
18588 | callback(true, {
|
18589 | node,
|
18590 | selector,
|
18591 | parents
|
18592 | });
|
18593 | });
|
18594 | currentSelectors[selector] = callbacks;
|
18595 | }
|
18596 | matchedSelectors[selector] = callbacks;
|
18597 | });
|
18598 | });
|
18599 | each$d(currentSelectors, (callbacks, selector) => {
|
18600 | if (!matchedSelectors[selector]) {
|
18601 | delete currentSelectors[selector];
|
18602 | each$e(callbacks, callback => {
|
18603 | callback(false, {
|
18604 | node,
|
18605 | selector,
|
18606 | parents
|
18607 | });
|
18608 | });
|
18609 | }
|
18610 | });
|
18611 | });
|
18612 | };
|
18613 | return {
|
18614 | selectorChangedWithUnbind: (selector, callback) => {
|
18615 | if (!selectorChangedData) {
|
18616 | setup();
|
18617 | }
|
18618 | if (!selectorChangedData[selector]) {
|
18619 | selectorChangedData[selector] = [];
|
18620 | }
|
18621 | selectorChangedData[selector].push(callback);
|
18622 | findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => {
|
18623 | currentSelectors[selector] = selectorChangedData[selector];
|
18624 | });
|
18625 | return {
|
18626 | unbind: () => {
|
18627 | deleteFromCallbackMap(selectorChangedData, selector, callback);
|
18628 | deleteFromCallbackMap(currentSelectors, selector, callback);
|
18629 | }
|
18630 | };
|
18631 | }
|
18632 | };
|
18633 | };
|
18634 |
|
18635 | const isAttachedToDom = node => {
|
18636 | return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
|
18637 | };
|
18638 | const isValidRange = rng => {
|
18639 | if (!rng) {
|
18640 | return false;
|
18641 | } else {
|
18642 | return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
|
18643 | }
|
18644 | };
|
18645 | const EditorSelection = (dom, win, serializer, editor) => {
|
18646 | let selectedRange;
|
18647 | let explicitRange;
|
18648 | const {selectorChangedWithUnbind} = SelectorChanged(dom, editor);
|
18649 | const setCursorLocation = (node, offset) => {
|
18650 | const rng = dom.createRng();
|
18651 | if (isNonNullable(node) && isNonNullable(offset)) {
|
18652 | rng.setStart(node, offset);
|
18653 | rng.setEnd(node, offset);
|
18654 | setRng(rng);
|
18655 | collapse(false);
|
18656 | } else {
|
18657 | moveEndPoint(dom, rng, editor.getBody(), true);
|
18658 | setRng(rng);
|
18659 | }
|
18660 | };
|
18661 | const getContent = args => getContent$1(editor, args);
|
18662 | const setContent = (content, args) => setContent$1(editor, content, args);
|
18663 | const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real);
|
18664 | const getEnd$1 = real => getEnd(editor.getBody(), getRng$1(), real);
|
18665 | const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized);
|
18666 | const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark);
|
18667 | const select$1 = (node, content) => {
|
18668 | select(dom, node, content).each(setRng);
|
18669 | return node;
|
18670 | };
|
18671 | const isCollapsed = () => {
|
18672 | const rng = getRng$1(), sel = getSel();
|
18673 | if (!rng || rng.item) {
|
18674 | return false;
|
18675 | }
|
18676 | if (rng.compareEndPoints) {
|
18677 | return rng.compareEndPoints('StartToEnd', rng) === 0;
|
18678 | }
|
18679 | return !sel || rng.collapsed;
|
18680 | };
|
18681 | const isEditable = () => {
|
18682 | const rng = getRng$1();
|
18683 | const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]');
|
18684 | if (fakeSelectedElements.length > 0) {
|
18685 | return forall(fakeSelectedElements, el => dom.isEditable(el.parentElement));
|
18686 | } else {
|
18687 | return isEditableRange(dom, rng);
|
18688 | }
|
18689 | };
|
18690 | const collapse = toStart => {
|
18691 | const rng = getRng$1();
|
18692 | rng.collapse(!!toStart);
|
18693 | setRng(rng);
|
18694 | };
|
18695 | const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
|
18696 | const getRng$1 = () => {
|
18697 | let rng;
|
18698 | const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
|
18699 | try {
|
18700 | return sourceRange.compareBoundaryPoints(how, destinationRange);
|
18701 | } catch (ex) {
|
18702 | return -1;
|
18703 | }
|
18704 | };
|
18705 | const doc = win.document;
|
18706 | if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
|
18707 | const bookmark = getRng(editor);
|
18708 | if (bookmark.isSome()) {
|
18709 | return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange());
|
18710 | }
|
18711 | }
|
18712 | try {
|
18713 | const selection = getSel();
|
18714 | if (selection && !isRestrictedNode(selection.anchorNode)) {
|
18715 | if (selection.rangeCount > 0) {
|
18716 | rng = selection.getRangeAt(0);
|
18717 | } else {
|
18718 | rng = doc.createRange();
|
18719 | }
|
18720 | rng = processRanges(editor, [rng])[0];
|
18721 | }
|
18722 | } catch (ex) {
|
18723 | }
|
18724 | if (!rng) {
|
18725 | rng = doc.createRange();
|
18726 | }
|
18727 | if (isDocument$1(rng.startContainer) && rng.collapsed) {
|
18728 | const elm = dom.getRoot();
|
18729 | rng.setStart(elm, 0);
|
18730 | rng.setEnd(elm, 0);
|
18731 | }
|
18732 | if (selectedRange && explicitRange) {
|
18733 | if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
|
18734 | rng = explicitRange;
|
18735 | } else {
|
18736 | selectedRange = null;
|
18737 | explicitRange = null;
|
18738 | }
|
18739 | }
|
18740 | return rng;
|
18741 | };
|
18742 | const setRng = (rng, forward) => {
|
18743 | if (!isValidRange(rng)) {
|
18744 | return;
|
18745 | }
|
18746 | const sel = getSel();
|
18747 | const evt = editor.dispatch('SetSelectionRange', {
|
18748 | range: rng,
|
18749 | forward
|
18750 | });
|
18751 | rng = evt.range;
|
18752 | if (sel) {
|
18753 | explicitRange = rng;
|
18754 | try {
|
18755 | sel.removeAllRanges();
|
18756 | sel.addRange(rng);
|
18757 | } catch (ex) {
|
18758 | }
|
18759 | if (forward === false && sel.extend) {
|
18760 | sel.collapse(rng.endContainer, rng.endOffset);
|
18761 | sel.extend(rng.startContainer, rng.startOffset);
|
18762 | }
|
18763 | selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
|
18764 | }
|
18765 | if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) {
|
18766 | if (rng.endOffset - rng.startOffset < 2) {
|
18767 | if (rng.startContainer.hasChildNodes()) {
|
18768 | const node = rng.startContainer.childNodes[rng.startOffset];
|
18769 | if (node && node.nodeName === 'IMG') {
|
18770 | sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
|
18771 | if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
|
18772 | sel.setBaseAndExtent(node, 0, node, 1);
|
18773 | }
|
18774 | }
|
18775 | }
|
18776 | }
|
18777 | }
|
18778 | editor.dispatch('AfterSetSelectionRange', {
|
18779 | range: rng,
|
18780 | forward
|
18781 | });
|
18782 | };
|
18783 | const setNode = elm => {
|
18784 | setContent(dom.getOuterHTML(elm));
|
18785 | return elm;
|
18786 | };
|
18787 | const getNode$1 = () => getNode(editor.getBody(), getRng$1());
|
18788 | const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm);
|
18789 | const isForward = () => {
|
18790 | const sel = getSel();
|
18791 | const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
|
18792 | const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
|
18793 | if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
|
18794 | return true;
|
18795 | }
|
18796 | const anchorRange = dom.createRng();
|
18797 | const focusRange = dom.createRng();
|
18798 | try {
|
18799 | anchorRange.setStart(anchorNode, sel.anchorOffset);
|
18800 | anchorRange.collapse(true);
|
18801 | focusRange.setStart(focusNode, sel.focusOffset);
|
18802 | focusRange.collapse(true);
|
18803 | } catch (e) {
|
18804 | return true;
|
18805 | }
|
18806 | return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
|
18807 | };
|
18808 | const normalize = () => {
|
18809 | const rng = getRng$1();
|
18810 | const sel = getSel();
|
18811 | if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
|
18812 | const normRng = normalize$2(dom, rng);
|
18813 | normRng.each(normRng => {
|
18814 | setRng(normRng, isForward());
|
18815 | });
|
18816 | return normRng.getOr(rng);
|
18817 | }
|
18818 | return rng;
|
18819 | };
|
18820 | const selectorChanged = (selector, callback) => {
|
18821 | selectorChangedWithUnbind(selector, callback);
|
18822 | return exports;
|
18823 | };
|
18824 | const getScrollContainer = () => {
|
18825 | let scrollContainer;
|
18826 | let node = dom.getRoot();
|
18827 | while (node && node.nodeName !== 'BODY') {
|
18828 | if (node.scrollHeight > node.clientHeight) {
|
18829 | scrollContainer = node;
|
18830 | break;
|
18831 | }
|
18832 | node = node.parentNode;
|
18833 | }
|
18834 | return scrollContainer;
|
18835 | };
|
18836 | const scrollIntoView = (elm, alignToTop) => {
|
18837 | if (isNonNullable(elm)) {
|
18838 | scrollElementIntoView(editor, elm, alignToTop);
|
18839 | } else {
|
18840 | scrollRangeIntoView(editor, getRng$1(), alignToTop);
|
18841 | }
|
18842 | };
|
18843 | const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
|
18844 | const getBoundingClientRect = () => {
|
18845 | const rng = getRng$1();
|
18846 | return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
|
18847 | };
|
18848 | const destroy = () => {
|
18849 | win = selectedRange = explicitRange = null;
|
18850 | controlSelection.destroy();
|
18851 | };
|
18852 | const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options));
|
18853 | const exports = {
|
18854 | dom,
|
18855 | win,
|
18856 | serializer,
|
18857 | editor,
|
18858 | expand,
|
18859 | collapse,
|
18860 | setCursorLocation,
|
18861 | getContent,
|
18862 | setContent,
|
18863 | getBookmark,
|
18864 | moveToBookmark,
|
18865 | select: select$1,
|
18866 | isCollapsed,
|
18867 | isEditable,
|
18868 | isForward,
|
18869 | setNode,
|
18870 | getNode: getNode$1,
|
18871 | getSel,
|
18872 | setRng,
|
18873 | getRng: getRng$1,
|
18874 | getStart: getStart$1,
|
18875 | getEnd: getEnd$1,
|
18876 | getSelectedBlocks: getSelectedBlocks$1,
|
18877 | normalize,
|
18878 | selectorChanged,
|
18879 | selectorChangedWithUnbind,
|
18880 | getScrollContainer,
|
18881 | scrollIntoView,
|
18882 | placeCaretAt,
|
18883 | getBoundingClientRect,
|
18884 | destroy
|
18885 | };
|
18886 | const bookmarkManager = BookmarkManager(exports);
|
18887 | const controlSelection = ControlSelection(exports, editor);
|
18888 | exports.bookmarkManager = bookmarkManager;
|
18889 | exports.controlSelection = controlSelection;
|
18890 | return exports;
|
18891 | };
|
18892 |
|
18893 | const addNodeFilter = (settings, htmlParser, schema) => {
|
18894 | htmlParser.addNodeFilter('br', (nodes, _, args) => {
|
18895 | const blockElements = Tools.extend({}, schema.getBlockElements());
|
18896 | const nonEmptyElements = schema.getNonEmptyElements();
|
18897 | const whitespaceElements = schema.getWhitespaceElements();
|
18898 | blockElements.body = 1;
|
18899 | const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node);
|
18900 | for (let i = 0, l = nodes.length; i < l; i++) {
|
18901 | let node = nodes[i];
|
18902 | let parent = node.parent;
|
18903 | if (parent && isBlock(parent) && node === parent.lastChild) {
|
18904 | let prev = node.prev;
|
18905 | while (prev) {
|
18906 | const prevName = prev.name;
|
18907 | if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
|
18908 | if (prevName === 'br') {
|
18909 | node = null;
|
18910 | }
|
18911 | break;
|
18912 | }
|
18913 | prev = prev.prev;
|
18914 | }
|
18915 | if (node) {
|
18916 | node.remove();
|
18917 | if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) {
|
18918 | const elementRule = schema.getElementRule(parent.name);
|
18919 | if (elementRule) {
|
18920 | if (elementRule.removeEmpty) {
|
18921 | parent.remove();
|
18922 | } else if (elementRule.paddEmpty) {
|
18923 | paddEmptyNode(settings, args, isBlock, parent);
|
18924 | }
|
18925 | }
|
18926 | }
|
18927 | }
|
18928 | } else {
|
18929 | let lastParent = node;
|
18930 | while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
|
18931 | lastParent = parent;
|
18932 | if (blockElements[parent.name]) {
|
18933 | break;
|
18934 | }
|
18935 | parent = parent.parent;
|
18936 | }
|
18937 | if (lastParent === parent) {
|
18938 | const textNode = new AstNode('#text', 3);
|
18939 | textNode.value = nbsp;
|
18940 | node.replace(textNode);
|
18941 | }
|
18942 | }
|
18943 | }
|
18944 | });
|
18945 | };
|
18946 |
|
18947 | const register$3 = (htmlParser, settings, dom) => {
|
18948 | htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => {
|
18949 | let i = nodes.length;
|
18950 | while (i--) {
|
18951 | const node = nodes[i];
|
18952 | node.attr('tabindex', node.attr('data-mce-tabindex'));
|
18953 | node.attr(name, null);
|
18954 | }
|
18955 | });
|
18956 | htmlParser.addAttributeFilter('src,href,style', (nodes, name) => {
|
18957 | const internalName = 'data-mce-' + name;
|
18958 | const urlConverter = settings.url_converter;
|
18959 | const urlConverterScope = settings.url_converter_scope;
|
18960 | let i = nodes.length;
|
18961 | while (i--) {
|
18962 | const node = nodes[i];
|
18963 | let value = node.attr(internalName);
|
18964 | if (value !== undefined) {
|
18965 | node.attr(name, value.length > 0 ? value : null);
|
18966 | node.attr(internalName, null);
|
18967 | } else {
|
18968 | value = node.attr(name);
|
18969 | if (name === 'style') {
|
18970 | value = dom.serializeStyle(dom.parseStyle(value), node.name);
|
18971 | } else if (urlConverter) {
|
18972 | value = urlConverter.call(urlConverterScope, value, name, node.name);
|
18973 | }
|
18974 | node.attr(name, value.length > 0 ? value : null);
|
18975 | }
|
18976 | }
|
18977 | });
|
18978 | htmlParser.addAttributeFilter('class', nodes => {
|
18979 | let i = nodes.length;
|
18980 | while (i--) {
|
18981 | const node = nodes[i];
|
18982 | let value = node.attr('class');
|
18983 | if (value) {
|
18984 | value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
|
18985 | node.attr('class', value.length > 0 ? value : null);
|
18986 | }
|
18987 | }
|
18988 | });
|
18989 | htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => {
|
18990 | let i = nodes.length;
|
18991 | while (i--) {
|
18992 | const node = nodes[i];
|
18993 | if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
|
18994 | const hasChildren = Optional.from(node.firstChild).exists(firstChild => {
|
18995 | var _a;
|
18996 | return !isZwsp((_a = firstChild.value) !== null && _a !== void 0 ? _a : '');
|
18997 | });
|
18998 | if (hasChildren) {
|
18999 | node.unwrap();
|
19000 | } else {
|
19001 | node.remove();
|
19002 | }
|
19003 | }
|
19004 | }
|
19005 | });
|
19006 | htmlParser.addNodeFilter('noscript', nodes => {
|
19007 | var _a;
|
19008 | let i = nodes.length;
|
19009 | while (i--) {
|
19010 | const node = nodes[i].firstChild;
|
19011 | if (node) {
|
19012 | node.value = Entities.decode((_a = node.value) !== null && _a !== void 0 ? _a : '');
|
19013 | }
|
19014 | }
|
19015 | });
|
19016 | htmlParser.addNodeFilter('script,style', (nodes, name) => {
|
19017 | var _a;
|
19018 | const trim = value => {
|
19019 | return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n').replace(/^[\r\n]*|[\r\n]*$/g, '').replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '').replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
|
19020 | };
|
19021 | let i = nodes.length;
|
19022 | while (i--) {
|
19023 | const node = nodes[i];
|
19024 | const firstChild = node.firstChild;
|
19025 | const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : '';
|
19026 | if (name === 'script') {
|
19027 | const type = node.attr('type');
|
19028 | if (type) {
|
19029 | node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
|
19030 | }
|
19031 | if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
|
19032 | firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
|
19033 | }
|
19034 | } else {
|
19035 | if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
|
19036 | firstChild.value = '<!--\n' + trim(value) + '\n-->';
|
19037 | }
|
19038 | }
|
19039 | }
|
19040 | });
|
19041 | htmlParser.addNodeFilter('#comment', nodes => {
|
19042 | let i = nodes.length;
|
19043 | while (i--) {
|
19044 | const node = nodes[i];
|
19045 | const value = node.value;
|
19046 | if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) {
|
19047 | node.name = '#cdata';
|
19048 | node.type = 4;
|
19049 | node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, ''));
|
19050 | } else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) {
|
19051 | node.name = '#text';
|
19052 | node.type = 3;
|
19053 | node.raw = true;
|
19054 | node.value = unescape(value).substr(14);
|
19055 | }
|
19056 | }
|
19057 | });
|
19058 | htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => {
|
19059 | let i = nodes.length;
|
19060 | while (i--) {
|
19061 | const node = nodes[i];
|
19062 | if (node.type === 7) {
|
19063 | node.remove();
|
19064 | } else if (node.type === 1) {
|
19065 | if (name === 'input' && !node.attr('type')) {
|
19066 | node.attr('type', 'text');
|
19067 | }
|
19068 | }
|
19069 | }
|
19070 | });
|
19071 | htmlParser.addAttributeFilter('data-mce-type', nodes => {
|
19072 | each$e(nodes, node => {
|
19073 | if (node.attr('data-mce-type') === 'format-caret') {
|
19074 | if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
|
19075 | node.remove();
|
19076 | } else {
|
19077 | node.unwrap();
|
19078 | }
|
19079 | }
|
19080 | });
|
19081 | });
|
19082 | htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style,' + 'data-mce-selected,data-mce-expando,data-mce-block,' + 'data-mce-type,data-mce-resize,data-mce-placeholder', (nodes, name) => {
|
19083 | let i = nodes.length;
|
19084 | while (i--) {
|
19085 | nodes[i].attr(name, null);
|
19086 | }
|
19087 | });
|
19088 | if (settings.remove_trailing_brs) {
|
19089 | addNodeFilter(settings, htmlParser, htmlParser.schema);
|
19090 | }
|
19091 | };
|
19092 | const trimTrailingBr = rootNode => {
|
19093 | const isBr = node => {
|
19094 | return (node === null || node === void 0 ? void 0 : node.name) === 'br';
|
19095 | };
|
19096 | const brNode1 = rootNode.lastChild;
|
19097 | if (isBr(brNode1)) {
|
19098 | const brNode2 = brNode1.prev;
|
19099 | if (isBr(brNode2)) {
|
19100 | brNode1.remove();
|
19101 | brNode2.remove();
|
19102 | }
|
19103 | }
|
19104 | };
|
19105 |
|
19106 | const preProcess$1 = (editor, node, args) => {
|
19107 | let oldDoc;
|
19108 | const dom = editor.dom;
|
19109 | let clonedNode = node.cloneNode(true);
|
19110 | const impl = document.implementation;
|
19111 | if (impl.createHTMLDocument) {
|
19112 | const doc = impl.createHTMLDocument('');
|
19113 | Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => {
|
19114 | doc.body.appendChild(doc.importNode(node, true));
|
19115 | });
|
19116 | if (clonedNode.nodeName !== 'BODY') {
|
19117 | clonedNode = doc.body.firstChild;
|
19118 | } else {
|
19119 | clonedNode = doc.body;
|
19120 | }
|
19121 | oldDoc = dom.doc;
|
19122 | dom.doc = doc;
|
19123 | }
|
19124 | firePreProcess(editor, {
|
19125 | ...args,
|
19126 | node: clonedNode
|
19127 | });
|
19128 | if (oldDoc) {
|
19129 | dom.doc = oldDoc;
|
19130 | }
|
19131 | return clonedNode;
|
19132 | };
|
19133 | const shouldFireEvent = (editor, args) => {
|
19134 | return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events;
|
19135 | };
|
19136 | const process$1 = (editor, node, args) => {
|
19137 | return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
|
19138 | };
|
19139 |
|
19140 | const addTempAttr = (htmlParser, tempAttrs, name) => {
|
19141 | if (Tools.inArray(tempAttrs, name) === -1) {
|
19142 | htmlParser.addAttributeFilter(name, (nodes, name) => {
|
19143 | let i = nodes.length;
|
19144 | while (i--) {
|
19145 | nodes[i].attr(name, null);
|
19146 | }
|
19147 | });
|
19148 | tempAttrs.push(name);
|
19149 | }
|
19150 | };
|
19151 | const postProcess = (editor, args, content) => {
|
19152 | if (!args.no_events && editor) {
|
19153 | const outArgs = firePostProcess(editor, {
|
19154 | ...args,
|
19155 | content
|
19156 | });
|
19157 | return outArgs.content;
|
19158 | } else {
|
19159 | return content;
|
19160 | }
|
19161 | };
|
19162 | const getHtmlFromNode = (dom, node, args) => {
|
19163 | const html = trim$2(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
|
19164 | return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html);
|
19165 | };
|
19166 | const parseHtml = (htmlParser, html, args) => {
|
19167 | const parserArgs = args.selection ? {
|
19168 | forced_root_block: false,
|
19169 | ...args
|
19170 | } : args;
|
19171 | const rootNode = htmlParser.parse(html, parserArgs);
|
19172 | trimTrailingBr(rootNode);
|
19173 | return rootNode;
|
19174 | };
|
19175 | const serializeNode = (settings, schema, node) => {
|
19176 | const htmlSerializer = HtmlSerializer(settings, schema);
|
19177 | return htmlSerializer.serialize(node);
|
19178 | };
|
19179 | const toHtml = (editor, settings, schema, rootNode, args) => {
|
19180 | const content = serializeNode(settings, schema, rootNode);
|
19181 | return postProcess(editor, args, content);
|
19182 | };
|
19183 | const DomSerializerImpl = (settings, editor) => {
|
19184 | const tempAttrs = ['data-mce-selected'];
|
19185 | const defaultedSettings = {
|
19186 | entity_encoding: 'named',
|
19187 | remove_trailing_brs: true,
|
19188 | pad_empty_with_br: false,
|
19189 | ...settings
|
19190 | };
|
19191 | const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM;
|
19192 | const schema = editor && editor.schema ? editor.schema : Schema(defaultedSettings);
|
19193 | const htmlParser = DomParser(defaultedSettings, schema);
|
19194 | register$3(htmlParser, defaultedSettings, dom);
|
19195 | const serialize = (node, parserArgs = {}) => {
|
19196 | const args = {
|
19197 | format: 'html',
|
19198 | ...parserArgs
|
19199 | };
|
19200 | const targetNode = process$1(editor, node, args);
|
19201 | const html = getHtmlFromNode(dom, targetNode, args);
|
19202 | const rootNode = parseHtml(htmlParser, html, args);
|
19203 | return args.format === 'tree' ? rootNode : toHtml(editor, defaultedSettings, schema, rootNode, args);
|
19204 | };
|
19205 | return {
|
19206 | schema,
|
19207 | addNodeFilter: htmlParser.addNodeFilter,
|
19208 | addAttributeFilter: htmlParser.addAttributeFilter,
|
19209 | serialize: serialize,
|
19210 | addRules: schema.addValidElements,
|
19211 | setRules: schema.setValidElements,
|
19212 | addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
|
19213 | getTempAttrs: constant(tempAttrs),
|
19214 | getNodeFilters: htmlParser.getNodeFilters,
|
19215 | getAttributeFilters: htmlParser.getAttributeFilters,
|
19216 | removeNodeFilter: htmlParser.removeNodeFilter,
|
19217 | removeAttributeFilter: htmlParser.removeAttributeFilter
|
19218 | };
|
19219 | };
|
19220 |
|
19221 | const DomSerializer = (settings, editor) => {
|
19222 | const domSerializer = DomSerializerImpl(settings, editor);
|
19223 | return {
|
19224 | schema: domSerializer.schema,
|
19225 | addNodeFilter: domSerializer.addNodeFilter,
|
19226 | addAttributeFilter: domSerializer.addAttributeFilter,
|
19227 | serialize: domSerializer.serialize,
|
19228 | addRules: domSerializer.addRules,
|
19229 | setRules: domSerializer.setRules,
|
19230 | addTempAttr: domSerializer.addTempAttr,
|
19231 | getTempAttrs: domSerializer.getTempAttrs,
|
19232 | getNodeFilters: domSerializer.getNodeFilters,
|
19233 | getAttributeFilters: domSerializer.getAttributeFilters,
|
19234 | removeNodeFilter: domSerializer.removeNodeFilter,
|
19235 | removeAttributeFilter: domSerializer.removeAttributeFilter
|
19236 | };
|
19237 | };
|
19238 |
|
19239 | const defaultFormat$1 = 'html';
|
19240 | const setupArgs$1 = (args, format) => ({
|
19241 | ...args,
|
19242 | format,
|
19243 | get: true,
|
19244 | getInner: true
|
19245 | });
|
19246 | const getContent = (editor, args = {}) => {
|
19247 | const format = args.format ? args.format : defaultFormat$1;
|
19248 | const defaultedArgs = setupArgs$1(args, format);
|
19249 | return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
|
19250 | const content = getContent$2(editor, updatedArgs);
|
19251 | return postProcessGetContent(editor, content, updatedArgs);
|
19252 | });
|
19253 | };
|
19254 |
|
19255 | const defaultFormat = 'html';
|
19256 | const setupArgs = (args, content) => ({
|
19257 | format: defaultFormat,
|
19258 | ...args,
|
19259 | set: true,
|
19260 | content
|
19261 | });
|
19262 | const setContent = (editor, content, args = {}) => {
|
19263 | const defaultedArgs = setupArgs(args, content);
|
19264 | return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => {
|
19265 | const result = setContent$2(editor, updatedArgs.content, updatedArgs);
|
19266 | postProcessSetContent(editor, result.html, updatedArgs);
|
19267 | return result.content;
|
19268 | }).getOr(content);
|
19269 | };
|
19270 |
|
19271 | const removedOptions = ('autoresize_on_init,content_editable_state,padd_empty_with_br,block_elements,' + 'boolean_attributes,editor_deselector,editor_selector,elements,file_browser_callback_types,filepicker_validator_handler,' + 'force_hex_style_colors,force_p_newlines,gecko_spellcheck,images_dataimg_filter,media_scripts,mode,move_caret_before_on_enter_elements,' + 'non_empty_elements,self_closing_elements,short_ended_elements,special,spellchecker_select_languages,spellchecker_whitelist,' + 'tab_focus,tabfocus_elements,table_responsive_width,text_block_elements,text_inline_elements,toolbar_drawer,types,validate,whitespace_elements,' + 'paste_enable_default_filters,paste_filter_drop,paste_word_valid_elements,paste_retain_style_properties,paste_convert_word_fake_lists,' + 'template_cdate_classes,template_mdate_classes,template_selected_content_classes,template_preview_replace_values,template_replace_values,templates,template_cdate_format,template_mdate_format').split(',');
|
19272 | const deprecatedOptions = [];
|
19273 | const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,template,textcolor,rtc'.split(',');
|
19274 | const deprecatedPlugins = [];
|
19275 | const getMatchingOptions = (options, searchingFor) => {
|
19276 | const settingNames = filter$5(searchingFor, setting => has$2(options, setting));
|
19277 | return sort(settingNames);
|
19278 | };
|
19279 | const getRemovedOptions = options => {
|
19280 | const settingNames = getMatchingOptions(options, removedOptions);
|
19281 | const forcedRootBlock = options.forced_root_block;
|
19282 | if (forcedRootBlock === false || forcedRootBlock === '') {
|
19283 | settingNames.push('forced_root_block (false only)');
|
19284 | }
|
19285 | return sort(settingNames);
|
19286 | };
|
19287 | const getDeprecatedOptions = options => getMatchingOptions(options, deprecatedOptions);
|
19288 | const getMatchingPlugins = (options, searchingFor) => {
|
19289 | const plugins = Tools.makeMap(options.plugins, ' ');
|
19290 | const hasPlugin = plugin => has$2(plugins, plugin);
|
19291 | const pluginNames = filter$5(searchingFor, hasPlugin);
|
19292 | return sort(pluginNames);
|
19293 | };
|
19294 | const getRemovedPlugins = options => getMatchingPlugins(options, removedPlugins);
|
19295 | const getDeprecatedPlugins = options => getMatchingPlugins(options, deprecatedPlugins.map(entry => entry.name));
|
19296 | const logRemovedWarnings = (rawOptions, normalizedOptions) => {
|
19297 | const removedOptions = getRemovedOptions(rawOptions);
|
19298 | const removedPlugins = getRemovedPlugins(normalizedOptions);
|
19299 | const hasRemovedPlugins = removedPlugins.length > 0;
|
19300 | const hasRemovedOptions = removedOptions.length > 0;
|
19301 | const isLegacyMobileTheme = normalizedOptions.theme === 'mobile';
|
19302 | if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
|
19303 | const listJoiner = '\n- ';
|
19304 | const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : '';
|
19305 | const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : '';
|
19306 | const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : '';
|
19307 | console.warn('The following deprecated features are currently enabled and have been removed in TinyMCE 7.0. These features will no longer work and should be removed from the TinyMCE configuration. ' + 'See https://www.tiny.cloud/docs/tinymce/7/migration-from-6x/ for more information.' + themesMessage + pluginsMessage + optionsMessage);
|
19308 | }
|
19309 | };
|
19310 | const getPluginDescription = name => find$2(deprecatedPlugins, entry => entry.name === name).fold(() => name, entry => {
|
19311 | if (entry.replacedWith) {
|
19312 | return `${ name }, replaced by ${ entry.replacedWith }`;
|
19313 | } else {
|
19314 | return name;
|
19315 | }
|
19316 | });
|
19317 | const logDeprecatedWarnings = (rawOptions, normalizedOptions) => {
|
19318 | const deprecatedOptions = getDeprecatedOptions(rawOptions);
|
19319 | const deprecatedPlugins = getDeprecatedPlugins(normalizedOptions);
|
19320 | const hasDeprecatedPlugins = deprecatedPlugins.length > 0;
|
19321 | const hasDeprecatedOptions = deprecatedOptions.length > 0;
|
19322 | if (hasDeprecatedPlugins || hasDeprecatedOptions) {
|
19323 | const listJoiner = '\n- ';
|
19324 | const pluginsMessage = hasDeprecatedPlugins ? `\n\nPlugins:${ listJoiner }${ deprecatedPlugins.map(getPluginDescription).join(listJoiner) }` : '';
|
19325 | const optionsMessage = hasDeprecatedOptions ? `\n\nOptions:${ listJoiner }${ deprecatedOptions.join(listJoiner) }` : '';
|
19326 | console.warn('The following deprecated features are currently enabled but will be removed soon.' + pluginsMessage + optionsMessage);
|
19327 | }
|
19328 | };
|
19329 | const logWarnings = (rawOptions, normalizedOptions) => {
|
19330 | logRemovedWarnings(rawOptions, normalizedOptions);
|
19331 | logDeprecatedWarnings(rawOptions, normalizedOptions);
|
19332 | };
|
19333 |
|
19334 | const DOM$8 = DOMUtils.DOM;
|
19335 | const restoreOriginalStyles = editor => {
|
19336 | DOM$8.setStyle(editor.id, 'display', editor.orgDisplay);
|
19337 | };
|
19338 | const safeDestroy = x => Optional.from(x).each(x => x.destroy());
|
19339 | const clearDomReferences = editor => {
|
19340 | const ed = editor;
|
19341 | ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null;
|
19342 | ed.bodyElement = ed.contentDocument = ed.contentWindow = null;
|
19343 | ed.iframeElement = ed.targetElm = null;
|
19344 | const selection = editor.selection;
|
19345 | if (selection) {
|
19346 | const dom = selection.dom;
|
19347 | ed.selection = selection.win = selection.dom = dom.doc = null;
|
19348 | }
|
19349 | };
|
19350 | const restoreForm = editor => {
|
19351 | const form = editor.formElement;
|
19352 | if (form) {
|
19353 | if (form._mceOldSubmit) {
|
19354 | form.submit = form._mceOldSubmit;
|
19355 | delete form._mceOldSubmit;
|
19356 | }
|
19357 | DOM$8.unbind(form, 'submit reset', editor.formEventDelegate);
|
19358 | }
|
19359 | };
|
19360 | const remove$1 = editor => {
|
19361 | if (!editor.removed) {
|
19362 | const {_selectionOverrides, editorUpload} = editor;
|
19363 | const body = editor.getBody();
|
19364 | const element = editor.getElement();
|
19365 | if (body) {
|
19366 | editor.save({ is_removing: true });
|
19367 | }
|
19368 | editor.removed = true;
|
19369 | editor.unbindAllNativeEvents();
|
19370 | if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) {
|
19371 | DOM$8.remove(element.nextSibling);
|
19372 | }
|
19373 | fireRemove(editor);
|
19374 | editor.editorManager.remove(editor);
|
19375 | if (!editor.inline && body) {
|
19376 | restoreOriginalStyles(editor);
|
19377 | }
|
19378 | fireDetach(editor);
|
19379 | DOM$8.remove(editor.getContainer());
|
19380 | safeDestroy(_selectionOverrides);
|
19381 | safeDestroy(editorUpload);
|
19382 | editor.destroy();
|
19383 | }
|
19384 | };
|
19385 | const destroy = (editor, automatic) => {
|
19386 | const {selection, dom} = editor;
|
19387 | if (editor.destroyed) {
|
19388 | return;
|
19389 | }
|
19390 | if (!automatic && !editor.removed) {
|
19391 | editor.remove();
|
19392 | return;
|
19393 | }
|
19394 | if (!automatic) {
|
19395 | editor.editorManager.off('beforeunload', editor._beforeUnload);
|
19396 | if (editor.theme && editor.theme.destroy) {
|
19397 | editor.theme.destroy();
|
19398 | }
|
19399 | safeDestroy(selection);
|
19400 | safeDestroy(dom);
|
19401 | }
|
19402 | restoreForm(editor);
|
19403 | clearDomReferences(editor);
|
19404 | editor.destroyed = true;
|
19405 | };
|
19406 |
|
19407 | const CreateIconManager = () => {
|
19408 | const lookup = {};
|
19409 | const add = (id, iconPack) => {
|
19410 | lookup[id] = iconPack;
|
19411 | };
|
19412 | const get = id => {
|
19413 | if (lookup[id]) {
|
19414 | return lookup[id];
|
19415 | } else {
|
19416 | return { icons: {} };
|
19417 | }
|
19418 | };
|
19419 | const has = id => has$2(lookup, id);
|
19420 | return {
|
19421 | add,
|
19422 | get,
|
19423 | has
|
19424 | };
|
19425 | };
|
19426 | const IconManager = CreateIconManager();
|
19427 |
|
19428 | const ModelManager = AddOnManager.ModelManager;
|
19429 |
|
19430 | const getProp = (propName, elm) => {
|
19431 | const rawElm = elm.dom;
|
19432 | return rawElm[propName];
|
19433 | };
|
19434 | const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
|
19435 | const getClientWidth = curry(getProp, 'clientWidth');
|
19436 | const getClientHeight = curry(getProp, 'clientHeight');
|
19437 | const getMarginTop = curry(getComputedSizeProp, 'margin-top');
|
19438 | const getMarginLeft = curry(getComputedSizeProp, 'margin-left');
|
19439 | const getBoundingClientRect = elm => elm.dom.getBoundingClientRect();
|
19440 | const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
|
19441 | const clientWidth = getClientWidth(bodyElm);
|
19442 | const clientHeight = getClientHeight(bodyElm);
|
19443 | return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
|
19444 | };
|
19445 | const transpose = (inline, elm, clientX, clientY) => {
|
19446 | const clientRect = getBoundingClientRect(elm);
|
19447 | const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
|
19448 | const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
|
19449 | const x = clientX - deltaX;
|
19450 | const y = clientY - deltaY;
|
19451 | return {
|
19452 | x,
|
19453 | y
|
19454 | };
|
19455 | };
|
19456 | const isXYInContentArea = (editor, clientX, clientY) => {
|
19457 | const bodyElm = SugarElement.fromDom(editor.getBody());
|
19458 | const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
|
19459 | const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
|
19460 | return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
|
19461 | };
|
19462 | const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom);
|
19463 | const isEditorAttachedToDom = editor => {
|
19464 | const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
|
19465 | return fromDomSafe(rawContainer).map(inBody).getOr(false);
|
19466 | };
|
19467 |
|
19468 | var NotificationManagerImpl = () => {
|
19469 | const unimplemented = () => {
|
19470 | throw new Error('Theme did not provide a NotificationManager implementation.');
|
19471 | };
|
19472 | return {
|
19473 | open: unimplemented,
|
19474 | close: unimplemented,
|
19475 | getArgs: unimplemented
|
19476 | };
|
19477 | };
|
19478 |
|
19479 | const NotificationManager = editor => {
|
19480 | const notifications = [];
|
19481 | const getImplementation = () => {
|
19482 | const theme = editor.theme;
|
19483 | return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
|
19484 | };
|
19485 | const getTopNotification = () => {
|
19486 | return Optional.from(notifications[0]);
|
19487 | };
|
19488 | const isEqual = (a, b) => {
|
19489 | return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
|
19490 | };
|
19491 | const reposition = () => {
|
19492 | getTopNotification().each(notification => {
|
19493 | notification.reposition();
|
19494 | });
|
19495 | };
|
19496 | const addNotification = notification => {
|
19497 | notifications.push(notification);
|
19498 | };
|
19499 | const closeNotification = notification => {
|
19500 | findIndex$2(notifications, otherNotification => {
|
19501 | return otherNotification === notification;
|
19502 | }).each(index => {
|
19503 | notifications.splice(index, 1);
|
19504 | });
|
19505 | };
|
19506 | const open = (spec, fireEvent = true) => {
|
19507 | if (editor.removed || !isEditorAttachedToDom(editor)) {
|
19508 | return {};
|
19509 | }
|
19510 | if (fireEvent) {
|
19511 | editor.dispatch('BeforeOpenNotification', { notification: spec });
|
19512 | }
|
19513 | return find$2(notifications, notification => {
|
19514 | return isEqual(getImplementation().getArgs(notification), spec);
|
19515 | }).getOrThunk(() => {
|
19516 | editor.editorManager.setActive(editor);
|
19517 | const notification = getImplementation().open(spec, () => {
|
19518 | closeNotification(notification);
|
19519 | }, () => hasEditorOrUiFocus(editor));
|
19520 | addNotification(notification);
|
19521 | reposition();
|
19522 | editor.dispatch('OpenNotification', { notification: { ...notification } });
|
19523 | return notification;
|
19524 | });
|
19525 | };
|
19526 | const close = () => {
|
19527 | getTopNotification().each(notification => {
|
19528 | getImplementation().close(notification);
|
19529 | closeNotification(notification);
|
19530 | reposition();
|
19531 | });
|
19532 | };
|
19533 | const getNotifications = constant(notifications);
|
19534 | const registerEvents = editor => {
|
19535 | editor.on('SkinLoaded', () => {
|
19536 | const serviceMessage = getServiceMessage(editor);
|
19537 | if (serviceMessage) {
|
19538 | open({
|
19539 | text: serviceMessage,
|
19540 | type: 'warning',
|
19541 | timeout: 0
|
19542 | }, false);
|
19543 | }
|
19544 | reposition();
|
19545 | });
|
19546 | editor.on('show ResizeEditor NodeChange', () => {
|
19547 | requestAnimationFrame(reposition);
|
19548 | });
|
19549 | editor.on('remove', () => {
|
19550 | each$e(notifications.slice(), notification => {
|
19551 | getImplementation().close(notification);
|
19552 | });
|
19553 | });
|
19554 | editor.addShortcut('alt+F12', 'Focus to notification', () => getTopNotification().map(notificationApi => SugarElement.fromDom(notificationApi.getEl())).each(elm => focus$1(elm)));
|
19555 | };
|
19556 | registerEvents(editor);
|
19557 | return {
|
19558 | open,
|
19559 | close,
|
19560 | getNotifications
|
19561 | };
|
19562 | };
|
19563 |
|
19564 | const PluginManager = AddOnManager.PluginManager;
|
19565 |
|
19566 | const ThemeManager = AddOnManager.ThemeManager;
|
19567 |
|
19568 | var WindowManagerImpl = () => {
|
19569 | const unimplemented = () => {
|
19570 | throw new Error('Theme did not provide a WindowManager implementation.');
|
19571 | };
|
19572 | return {
|
19573 | open: unimplemented,
|
19574 | openUrl: unimplemented,
|
19575 | alert: unimplemented,
|
19576 | confirm: unimplemented,
|
19577 | close: unimplemented
|
19578 | };
|
19579 | };
|
19580 |
|
19581 | const WindowManager = editor => {
|
19582 | let dialogs = [];
|
19583 | const getImplementation = () => {
|
19584 | const theme = editor.theme;
|
19585 | return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
|
19586 | };
|
19587 | const funcBind = (scope, f) => {
|
19588 | return (...args) => {
|
19589 | return f ? f.apply(scope, args) : undefined;
|
19590 | };
|
19591 | };
|
19592 | const fireOpenEvent = dialog => {
|
19593 | editor.dispatch('OpenWindow', { dialog });
|
19594 | };
|
19595 | const fireCloseEvent = dialog => {
|
19596 | editor.dispatch('CloseWindow', { dialog });
|
19597 | };
|
19598 | const addDialog = dialog => {
|
19599 | dialogs.push(dialog);
|
19600 | fireOpenEvent(dialog);
|
19601 | };
|
19602 | const closeDialog = dialog => {
|
19603 | fireCloseEvent(dialog);
|
19604 | dialogs = filter$5(dialogs, otherDialog => {
|
19605 | return otherDialog !== dialog;
|
19606 | });
|
19607 | if (dialogs.length === 0) {
|
19608 | editor.focus();
|
19609 | }
|
19610 | };
|
19611 | const getTopDialog = () => {
|
19612 | return Optional.from(dialogs[dialogs.length - 1]);
|
19613 | };
|
19614 | const storeSelectionAndOpenDialog = openDialog => {
|
19615 | editor.editorManager.setActive(editor);
|
19616 | store(editor);
|
19617 | editor.ui.show();
|
19618 | const dialog = openDialog();
|
19619 | addDialog(dialog);
|
19620 | return dialog;
|
19621 | };
|
19622 | const open = (args, params) => {
|
19623 | return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
|
19624 | };
|
19625 | const openUrl = args => {
|
19626 | return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
|
19627 | };
|
19628 | const alert = (message, callback, scope) => {
|
19629 | const windowManagerImpl = getImplementation();
|
19630 | windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
|
19631 | };
|
19632 | const confirm = (message, callback, scope) => {
|
19633 | const windowManagerImpl = getImplementation();
|
19634 | windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
|
19635 | };
|
19636 | const close = () => {
|
19637 | getTopDialog().each(dialog => {
|
19638 | getImplementation().close(dialog);
|
19639 | closeDialog(dialog);
|
19640 | });
|
19641 | };
|
19642 | editor.on('remove', () => {
|
19643 | each$e(dialogs, dialog => {
|
19644 | getImplementation().close(dialog);
|
19645 | });
|
19646 | });
|
19647 | return {
|
19648 | open,
|
19649 | openUrl,
|
19650 | alert,
|
19651 | confirm,
|
19652 | close
|
19653 | };
|
19654 | };
|
19655 |
|
19656 | const displayNotification = (editor, message) => {
|
19657 | editor.notificationManager.open({
|
19658 | type: 'error',
|
19659 | text: message
|
19660 | });
|
19661 | };
|
19662 | const displayError = (editor, message) => {
|
19663 | if (editor._skinLoaded) {
|
19664 | displayNotification(editor, message);
|
19665 | } else {
|
19666 | editor.on('SkinLoaded', () => {
|
19667 | displayNotification(editor, message);
|
19668 | });
|
19669 | }
|
19670 | };
|
19671 | const uploadError = (editor, message) => {
|
19672 | displayError(editor, I18n.translate([
|
19673 | 'Failed to upload image: {0}',
|
19674 | message
|
19675 | ]));
|
19676 | };
|
19677 | const logError = (editor, errorType, msg) => {
|
19678 | fireError(editor, errorType, { message: msg });
|
19679 | console.error(msg);
|
19680 | };
|
19681 | const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`;
|
19682 | const pluginLoadError = (editor, url, name) => {
|
19683 | logError(editor, 'PluginLoadError', createLoadError('plugin', url, name));
|
19684 | };
|
19685 | const iconsLoadError = (editor, url, name) => {
|
19686 | logError(editor, 'IconsLoadError', createLoadError('icons', url, name));
|
19687 | };
|
19688 | const languageLoadError = (editor, url, name) => {
|
19689 | logError(editor, 'LanguageLoadError', createLoadError('language', url, name));
|
19690 | };
|
19691 | const themeLoadError = (editor, url, name) => {
|
19692 | logError(editor, 'ThemeLoadError', createLoadError('theme', url, name));
|
19693 | };
|
19694 | const modelLoadError = (editor, url, name) => {
|
19695 | logError(editor, 'ModelLoadError', createLoadError('model', url, name));
|
19696 | };
|
19697 | const pluginInitError = (editor, name, err) => {
|
19698 | const message = I18n.translate([
|
19699 | 'Failed to initialize plugin: {0}',
|
19700 | name
|
19701 | ]);
|
19702 | fireError(editor, 'PluginLoadError', { message });
|
19703 | initError(message, err);
|
19704 | displayError(editor, message);
|
19705 | };
|
19706 | const initError = (message, ...x) => {
|
19707 | const console = window.console;
|
19708 | if (console) {
|
19709 | if (console.error) {
|
19710 | console.error(message, ...x);
|
19711 | } else {
|
19712 | console.log(message, ...x);
|
19713 | }
|
19714 | }
|
19715 | };
|
19716 |
|
19717 | const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url);
|
19718 | const toContentSkinResourceName = url => 'content/' + url + '/content.css';
|
19719 | const isBundledCssSkinName = url => tinymce.Resource.has(toContentSkinResourceName(url));
|
19720 | const getContentCssUrls = editor => {
|
19721 | return transformToUrls(editor, getContentCss(editor));
|
19722 | };
|
19723 | const getFontCssUrls = editor => {
|
19724 | return transformToUrls(editor, getFontCss(editor));
|
19725 | };
|
19726 | const transformToUrls = (editor, cssLinks) => {
|
19727 | const skinUrl = editor.editorManager.baseURL + '/skins/content';
|
19728 | const suffix = editor.editorManager.suffix;
|
19729 | const contentCssFile = `content${ suffix }.css`;
|
19730 | return map$3(cssLinks, url => {
|
19731 | if (isBundledCssSkinName(url)) {
|
19732 | return url;
|
19733 | } else if (isContentCssSkinName(url) && !editor.inline) {
|
19734 | return `${ skinUrl }/${ url }/${ contentCssFile }`;
|
19735 | } else {
|
19736 | return editor.documentBaseURI.toAbsolute(url);
|
19737 | }
|
19738 | });
|
19739 | };
|
19740 | const appendContentCssFromSettings = editor => {
|
19741 | editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
|
19742 | };
|
19743 |
|
19744 | const getAllImages = elm => {
|
19745 | return elm ? from(elm.getElementsByTagName('img')) : [];
|
19746 | };
|
19747 | const ImageScanner = (uploadStatus, blobCache) => {
|
19748 | const cachedPromises = {};
|
19749 | const findAll = (elm, predicate = always) => {
|
19750 | const images = filter$5(getAllImages(elm), img => {
|
19751 | const src = img.src;
|
19752 | if (img.hasAttribute('data-mce-bogus')) {
|
19753 | return false;
|
19754 | }
|
19755 | if (img.hasAttribute('data-mce-placeholder')) {
|
19756 | return false;
|
19757 | }
|
19758 | if (!src || src === Env.transparentSrc) {
|
19759 | return false;
|
19760 | }
|
19761 | if (startsWith(src, 'blob:')) {
|
19762 | return !uploadStatus.isUploaded(src) && predicate(img);
|
19763 | }
|
19764 | if (startsWith(src, 'data:')) {
|
19765 | return predicate(img);
|
19766 | }
|
19767 | return false;
|
19768 | });
|
19769 | const promises = map$3(images, img => {
|
19770 | const imageSrc = img.src;
|
19771 | if (has$2(cachedPromises, imageSrc)) {
|
19772 | return cachedPromises[imageSrc].then(imageInfo => {
|
19773 | if (isString(imageInfo)) {
|
19774 | return imageInfo;
|
19775 | } else {
|
19776 | return {
|
19777 | image: img,
|
19778 | blobInfo: imageInfo.blobInfo
|
19779 | };
|
19780 | }
|
19781 | });
|
19782 | } else {
|
19783 | const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => {
|
19784 | delete cachedPromises[imageSrc];
|
19785 | return {
|
19786 | image: img,
|
19787 | blobInfo
|
19788 | };
|
19789 | }).catch(error => {
|
19790 | delete cachedPromises[imageSrc];
|
19791 | return error;
|
19792 | });
|
19793 | cachedPromises[imageSrc] = newPromise;
|
19794 | return newPromise;
|
19795 | }
|
19796 | });
|
19797 | return Promise.all(promises);
|
19798 | };
|
19799 | return { findAll };
|
19800 | };
|
19801 |
|
19802 | const UploadStatus = () => {
|
19803 | const PENDING = 1, UPLOADED = 2;
|
19804 | let blobUriStatuses = {};
|
19805 | const createStatus = (status, resultUri) => {
|
19806 | return {
|
19807 | status,
|
19808 | resultUri
|
19809 | };
|
19810 | };
|
19811 | const hasBlobUri = blobUri => {
|
19812 | return blobUri in blobUriStatuses;
|
19813 | };
|
19814 | const getResultUri = blobUri => {
|
19815 | const result = blobUriStatuses[blobUri];
|
19816 | return result ? result.resultUri : null;
|
19817 | };
|
19818 | const isPending = blobUri => {
|
19819 | return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
|
19820 | };
|
19821 | const isUploaded = blobUri => {
|
19822 | return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
|
19823 | };
|
19824 | const markPending = blobUri => {
|
19825 | blobUriStatuses[blobUri] = createStatus(PENDING, null);
|
19826 | };
|
19827 | const markUploaded = (blobUri, resultUri) => {
|
19828 | blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
|
19829 | };
|
19830 | const removeFailed = blobUri => {
|
19831 | delete blobUriStatuses[blobUri];
|
19832 | };
|
19833 | const destroy = () => {
|
19834 | blobUriStatuses = {};
|
19835 | };
|
19836 | return {
|
19837 | hasBlobUri,
|
19838 | getResultUri,
|
19839 | isPending,
|
19840 | isUploaded,
|
19841 | markPending,
|
19842 | markUploaded,
|
19843 | removeFailed,
|
19844 | destroy
|
19845 | };
|
19846 | };
|
19847 |
|
19848 | let count = 0;
|
19849 | const seed = () => {
|
19850 | const rnd = () => {
|
19851 | return Math.round(Math.random() * 4294967295).toString(36);
|
19852 | };
|
19853 | const now = new Date().getTime();
|
19854 | return 's' + now.toString(36) + rnd() + rnd() + rnd();
|
19855 | };
|
19856 | const uuid = prefix => {
|
19857 | return prefix + count++ + seed();
|
19858 | };
|
19859 |
|
19860 | const BlobCache = () => {
|
19861 | let cache = [];
|
19862 | const mimeToExt = mime => {
|
19863 | const mimes = {
|
19864 | 'image/jpeg': 'jpg',
|
19865 | 'image/jpg': 'jpg',
|
19866 | 'image/gif': 'gif',
|
19867 | 'image/png': 'png',
|
19868 | 'image/apng': 'apng',
|
19869 | 'image/avif': 'avif',
|
19870 | 'image/svg+xml': 'svg',
|
19871 | 'image/webp': 'webp',
|
19872 | 'image/bmp': 'bmp',
|
19873 | 'image/tiff': 'tiff'
|
19874 | };
|
19875 | return mimes[mime.toLowerCase()] || 'dat';
|
19876 | };
|
19877 | const create = (o, blob, base64, name, filename) => {
|
19878 | if (isString(o)) {
|
19879 | const id = o;
|
19880 | return toBlobInfo({
|
19881 | id,
|
19882 | name,
|
19883 | filename,
|
19884 | blob: blob,
|
19885 | base64: base64
|
19886 | });
|
19887 | } else if (isObject(o)) {
|
19888 | return toBlobInfo(o);
|
19889 | } else {
|
19890 | throw new Error('Unknown input type');
|
19891 | }
|
19892 | };
|
19893 | const toBlobInfo = o => {
|
19894 | if (!o.blob || !o.base64) {
|
19895 | throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
|
19896 | }
|
19897 | const id = o.id || uuid('blobid');
|
19898 | const name = o.name || id;
|
19899 | const blob = o.blob;
|
19900 | return {
|
19901 | id: constant(id),
|
19902 | name: constant(name),
|
19903 | filename: constant(o.filename || name + '.' + mimeToExt(blob.type)),
|
19904 | blob: constant(blob),
|
19905 | base64: constant(o.base64),
|
19906 | blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
|
19907 | uri: constant(o.uri)
|
19908 | };
|
19909 | };
|
19910 | const add = blobInfo => {
|
19911 | if (!get(blobInfo.id())) {
|
19912 | cache.push(blobInfo);
|
19913 | }
|
19914 | };
|
19915 | const findFirst = predicate => find$2(cache, predicate).getOrUndefined();
|
19916 | const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id);
|
19917 | const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri);
|
19918 | const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type);
|
19919 | const removeByUri = blobUri => {
|
19920 | cache = filter$5(cache, blobInfo => {
|
19921 | if (blobInfo.blobUri() === blobUri) {
|
19922 | URL.revokeObjectURL(blobInfo.blobUri());
|
19923 | return false;
|
19924 | }
|
19925 | return true;
|
19926 | });
|
19927 | };
|
19928 | const destroy = () => {
|
19929 | each$e(cache, cachedBlobInfo => {
|
19930 | URL.revokeObjectURL(cachedBlobInfo.blobUri());
|
19931 | });
|
19932 | cache = [];
|
19933 | };
|
19934 | return {
|
19935 | create,
|
19936 | add,
|
19937 | get,
|
19938 | getByUri,
|
19939 | getByData,
|
19940 | findFirst,
|
19941 | removeByUri,
|
19942 | destroy
|
19943 | };
|
19944 | };
|
19945 |
|
19946 | const Uploader = (uploadStatus, settings) => {
|
19947 | const pendingPromises = {};
|
19948 | const pathJoin = (path1, path2) => {
|
19949 | if (path1) {
|
19950 | return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
|
19951 | }
|
19952 | return path2;
|
19953 | };
|
19954 | const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
|
19955 | const xhr = new XMLHttpRequest();
|
19956 | xhr.open('POST', settings.url);
|
19957 | xhr.withCredentials = settings.credentials;
|
19958 | xhr.upload.onprogress = e => {
|
19959 | progress(e.loaded / e.total * 100);
|
19960 | };
|
19961 | xhr.onerror = () => {
|
19962 | failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
|
19963 | };
|
19964 | xhr.onload = () => {
|
19965 | if (xhr.status < 200 || xhr.status >= 300) {
|
19966 | failure('HTTP Error: ' + xhr.status);
|
19967 | return;
|
19968 | }
|
19969 | const json = JSON.parse(xhr.responseText);
|
19970 | if (!json || !isString(json.location)) {
|
19971 | failure('Invalid JSON: ' + xhr.responseText);
|
19972 | return;
|
19973 | }
|
19974 | success(pathJoin(settings.basePath, json.location));
|
19975 | };
|
19976 | const formData = new FormData();
|
19977 | formData.append('file', blobInfo.blob(), blobInfo.filename());
|
19978 | xhr.send(formData);
|
19979 | });
|
19980 | const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler;
|
19981 | const noUpload = () => new Promise(resolve => {
|
19982 | resolve([]);
|
19983 | });
|
19984 | const handlerSuccess = (blobInfo, url) => ({
|
19985 | url,
|
19986 | blobInfo,
|
19987 | status: true
|
19988 | });
|
19989 | const handlerFailure = (blobInfo, error) => ({
|
19990 | url: '',
|
19991 | blobInfo,
|
19992 | status: false,
|
19993 | error
|
19994 | });
|
19995 | const resolvePending = (blobUri, result) => {
|
19996 | Tools.each(pendingPromises[blobUri], resolve => {
|
19997 | resolve(result);
|
19998 | });
|
19999 | delete pendingPromises[blobUri];
|
20000 | };
|
20001 | const uploadBlobInfo = (blobInfo, handler, openNotification) => {
|
20002 | uploadStatus.markPending(blobInfo.blobUri());
|
20003 | return new Promise(resolve => {
|
20004 | let notification;
|
20005 | let progress;
|
20006 | try {
|
20007 | const closeNotification = () => {
|
20008 | if (notification) {
|
20009 | notification.close();
|
20010 | progress = noop;
|
20011 | }
|
20012 | };
|
20013 | const success = url => {
|
20014 | closeNotification();
|
20015 | uploadStatus.markUploaded(blobInfo.blobUri(), url);
|
20016 | resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
|
20017 | resolve(handlerSuccess(blobInfo, url));
|
20018 | };
|
20019 | const failure = error => {
|
20020 | closeNotification();
|
20021 | uploadStatus.removeFailed(blobInfo.blobUri());
|
20022 | resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
|
20023 | resolve(handlerFailure(blobInfo, error));
|
20024 | };
|
20025 | progress = percent => {
|
20026 | if (percent < 0 || percent > 100) {
|
20027 | return;
|
20028 | }
|
20029 | Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => {
|
20030 | notification = n;
|
20031 | n.progressBar.value(percent);
|
20032 | });
|
20033 | };
|
20034 | handler(blobInfo, progress).then(success, err => {
|
20035 | failure(isString(err) ? { message: err } : err);
|
20036 | });
|
20037 | } catch (ex) {
|
20038 | resolve(handlerFailure(blobInfo, ex));
|
20039 | }
|
20040 | });
|
20041 | };
|
20042 | const isDefaultHandler = handler => handler === defaultHandler;
|
20043 | const pendingUploadBlobInfo = blobInfo => {
|
20044 | const blobUri = blobInfo.blobUri();
|
20045 | return new Promise(resolve => {
|
20046 | pendingPromises[blobUri] = pendingPromises[blobUri] || [];
|
20047 | pendingPromises[blobUri].push(resolve);
|
20048 | });
|
20049 | };
|
20050 | const uploadBlobs = (blobInfos, openNotification) => {
|
20051 | blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri()));
|
20052 | return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification)));
|
20053 | };
|
20054 | const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
|
20055 | return { upload };
|
20056 | };
|
20057 |
|
20058 | const openNotification = editor => () => editor.notificationManager.open({
|
20059 | text: editor.translate('Image uploading...'),
|
20060 | type: 'info',
|
20061 | timeout: -1,
|
20062 | progressBar: true
|
20063 | });
|
20064 | const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
|
20065 | url: getImageUploadUrl(editor),
|
20066 | basePath: getImageUploadBasePath(editor),
|
20067 | credentials: getImagesUploadCredentials(editor),
|
20068 | handler: getImagesUploadHandler(editor)
|
20069 | });
|
20070 | const ImageUploader = editor => {
|
20071 | const uploadStatus = UploadStatus();
|
20072 | const uploader = createUploader(editor, uploadStatus);
|
20073 | return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) };
|
20074 | };
|
20075 |
|
20076 | const isEmptyForPadding = (editor, element) => editor.dom.isEmpty(element.dom) && isNonNullable(editor.schema.getTextBlockElements()[name(element)]);
|
20077 | const addPaddingToEmpty = editor => element => {
|
20078 | if (isEmptyForPadding(editor, element)) {
|
20079 | append$1(element, SugarElement.fromHtml('<br data-mce-bogus="1" />'));
|
20080 | }
|
20081 | };
|
20082 | const EditorUpload = editor => {
|
20083 | const blobCache = BlobCache();
|
20084 | let uploader, imageScanner;
|
20085 | const uploadStatus = UploadStatus();
|
20086 | const urlFilters = [];
|
20087 | const aliveGuard = callback => {
|
20088 | return result => {
|
20089 | if (editor.selection) {
|
20090 | return callback(result);
|
20091 | }
|
20092 | return [];
|
20093 | };
|
20094 | };
|
20095 | const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime();
|
20096 | const replaceString = (content, search, replace) => {
|
20097 | let index = 0;
|
20098 | do {
|
20099 | index = content.indexOf(search, index);
|
20100 | if (index !== -1) {
|
20101 | content = content.substring(0, index) + replace + content.substr(index + search.length);
|
20102 | index += replace.length - search.length + 1;
|
20103 | }
|
20104 | } while (index !== -1);
|
20105 | return content;
|
20106 | };
|
20107 | const replaceImageUrl = (content, targetUrl, replacementUrl) => {
|
20108 | const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`;
|
20109 | content = replaceString(content, `src="${ targetUrl }"`, replacementString);
|
20110 | content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
|
20111 | return content;
|
20112 | };
|
20113 | const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
|
20114 | each$e(editor.undoManager.data, level => {
|
20115 | if (level.type === 'fragmented') {
|
20116 | level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl));
|
20117 | } else {
|
20118 | level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
|
20119 | }
|
20120 | });
|
20121 | };
|
20122 | const replaceImageUriInView = (image, resultUri) => {
|
20123 | const src = editor.convertURL(resultUri, 'src');
|
20124 | replaceUrlInUndoStack(image.src, resultUri);
|
20125 | setAll$1(SugarElement.fromDom(image), {
|
20126 | 'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
|
20127 | 'data-mce-src': src
|
20128 | });
|
20129 | };
|
20130 | const uploadImages = () => {
|
20131 | if (!uploader) {
|
20132 | uploader = createUploader(editor, uploadStatus);
|
20133 | }
|
20134 | return scanForImages().then(aliveGuard(imageInfos => {
|
20135 | const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo);
|
20136 | return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => {
|
20137 | const imagesToRemove = [];
|
20138 | let shouldDispatchChange = false;
|
20139 | const filteredResult = map$3(result, (uploadInfo, index) => {
|
20140 | const {blobInfo, image} = imageInfos[index];
|
20141 | let removed = false;
|
20142 | if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
|
20143 | if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
|
20144 | shouldDispatchChange = true;
|
20145 | }
|
20146 | blobCache.removeByUri(image.src);
|
20147 | if (isRtc(editor)) ; else {
|
20148 | replaceImageUriInView(image, uploadInfo.url);
|
20149 | }
|
20150 | } else if (uploadInfo.error) {
|
20151 | if (uploadInfo.error.remove) {
|
20152 | replaceUrlInUndoStack(image.src, Env.transparentSrc);
|
20153 | imagesToRemove.push(image);
|
20154 | removed = true;
|
20155 | }
|
20156 | uploadError(editor, uploadInfo.error.message);
|
20157 | }
|
20158 | return {
|
20159 | element: image,
|
20160 | status: uploadInfo.status,
|
20161 | uploadUri: uploadInfo.url,
|
20162 | blobInfo,
|
20163 | removed
|
20164 | };
|
20165 | });
|
20166 | if (imagesToRemove.length > 0 && !isRtc(editor)) {
|
20167 | editor.undoManager.transact(() => {
|
20168 | each$e(fromDom$1(imagesToRemove), sugarElement => {
|
20169 | const parentOpt = parent(sugarElement);
|
20170 | remove$4(sugarElement);
|
20171 | parentOpt.each(addPaddingToEmpty(editor));
|
20172 | blobCache.removeByUri(sugarElement.dom.src);
|
20173 | });
|
20174 | });
|
20175 | } else if (shouldDispatchChange) {
|
20176 | editor.undoManager.dispatchChange();
|
20177 | }
|
20178 | return filteredResult;
|
20179 | }));
|
20180 | }));
|
20181 | };
|
20182 | const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
|
20183 | const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm));
|
20184 | const addFilter = filter => {
|
20185 | urlFilters.push(filter);
|
20186 | };
|
20187 | const scanForImages = () => {
|
20188 | if (!imageScanner) {
|
20189 | imageScanner = ImageScanner(uploadStatus, blobCache);
|
20190 | }
|
20191 | return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => {
|
20192 | const filteredResult = filter$5(result, resultItem => {
|
20193 | if (isString(resultItem)) {
|
20194 | displayError(editor, resultItem);
|
20195 | return false;
|
20196 | } else if (resultItem.uriType === 'blob') {
|
20197 | return false;
|
20198 | } else {
|
20199 | return true;
|
20200 | }
|
20201 | });
|
20202 | if (isRtc(editor)) ; else {
|
20203 | each$e(filteredResult, resultItem => {
|
20204 | replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
|
20205 | resultItem.image.src = resultItem.blobInfo.blobUri();
|
20206 | resultItem.image.removeAttribute('data-mce-src');
|
20207 | });
|
20208 | }
|
20209 | return filteredResult;
|
20210 | }));
|
20211 | };
|
20212 | const destroy = () => {
|
20213 | blobCache.destroy();
|
20214 | uploadStatus.destroy();
|
20215 | imageScanner = uploader = null;
|
20216 | };
|
20217 | const replaceBlobUris = content => {
|
20218 | return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => {
|
20219 | const resultUri = uploadStatus.getResultUri(blobUri);
|
20220 | if (resultUri) {
|
20221 | return 'src="' + resultUri + '"';
|
20222 | }
|
20223 | let blobInfo = blobCache.getByUri(blobUri);
|
20224 | if (!blobInfo) {
|
20225 | blobInfo = foldl(editor.editorManager.get(), (result, editor) => {
|
20226 | return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
|
20227 | }, undefined);
|
20228 | }
|
20229 | if (blobInfo) {
|
20230 | const blob = blobInfo.blob();
|
20231 | return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
|
20232 | }
|
20233 | return match;
|
20234 | });
|
20235 | };
|
20236 | editor.on('SetContent', () => {
|
20237 | if (isAutomaticUploadsEnabled(editor)) {
|
20238 | uploadImagesAuto();
|
20239 | } else {
|
20240 | scanForImages();
|
20241 | }
|
20242 | });
|
20243 | editor.on('RawSaveContent', e => {
|
20244 | e.content = replaceBlobUris(e.content);
|
20245 | });
|
20246 | editor.on('GetContent', e => {
|
20247 | if (e.source_view || e.format === 'raw' || e.format === 'tree') {
|
20248 | return;
|
20249 | }
|
20250 | e.content = replaceBlobUris(e.content);
|
20251 | });
|
20252 | editor.on('PostRender', () => {
|
20253 | editor.parser.addNodeFilter('img', images => {
|
20254 | each$e(images, img => {
|
20255 | const src = img.attr('src');
|
20256 | if (!src || blobCache.getByUri(src)) {
|
20257 | return;
|
20258 | }
|
20259 | const resultUri = uploadStatus.getResultUri(src);
|
20260 | if (resultUri) {
|
20261 | img.attr('src', resultUri);
|
20262 | }
|
20263 | });
|
20264 | });
|
20265 | });
|
20266 | return {
|
20267 | blobCache,
|
20268 | addFilter,
|
20269 | uploadImages,
|
20270 | uploadImagesAuto,
|
20271 | scanForImages,
|
20272 | destroy
|
20273 | };
|
20274 | };
|
20275 |
|
20276 | const get$1 = editor => {
|
20277 | const dom = editor.dom;
|
20278 | const schemaType = editor.schema.type;
|
20279 | const formats = {
|
20280 | valigntop: [{
|
20281 | selector: 'td,th',
|
20282 | styles: { verticalAlign: 'top' }
|
20283 | }],
|
20284 | valignmiddle: [{
|
20285 | selector: 'td,th',
|
20286 | styles: { verticalAlign: 'middle' }
|
20287 | }],
|
20288 | valignbottom: [{
|
20289 | selector: 'td,th',
|
20290 | styles: { verticalAlign: 'bottom' }
|
20291 | }],
|
20292 | alignleft: [
|
20293 | {
|
20294 | selector: 'figure.image',
|
20295 | collapsed: false,
|
20296 | classes: 'align-left',
|
20297 | ceFalseOverride: true,
|
20298 | preview: 'font-family font-size'
|
20299 | },
|
20300 | {
|
20301 | selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
20302 | styles: { textAlign: 'left' },
|
20303 | inherit: false,
|
20304 | preview: false
|
20305 | },
|
20306 | {
|
20307 | selector: 'img,audio,video',
|
20308 | collapsed: false,
|
20309 | styles: { float: 'left' },
|
20310 | preview: 'font-family font-size'
|
20311 | },
|
20312 | {
|
20313 | selector: 'table',
|
20314 | collapsed: false,
|
20315 | styles: {
|
20316 | marginLeft: '0px',
|
20317 | marginRight: 'auto'
|
20318 | },
|
20319 | onformat: table => {
|
20320 | dom.setStyle(table, 'float', null);
|
20321 | },
|
20322 | preview: 'font-family font-size'
|
20323 | },
|
20324 | {
|
20325 | selector: '.mce-preview-object,[data-ephox-embed-iri]',
|
20326 | ceFalseOverride: true,
|
20327 | styles: { float: 'left' }
|
20328 | }
|
20329 | ],
|
20330 | aligncenter: [
|
20331 | {
|
20332 | selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
20333 | styles: { textAlign: 'center' },
|
20334 | inherit: false,
|
20335 | preview: 'font-family font-size'
|
20336 | },
|
20337 | {
|
20338 | selector: 'figure.image',
|
20339 | collapsed: false,
|
20340 | classes: 'align-center',
|
20341 | ceFalseOverride: true,
|
20342 | preview: 'font-family font-size'
|
20343 | },
|
20344 | {
|
20345 | selector: 'img,audio,video',
|
20346 | collapsed: false,
|
20347 | styles: {
|
20348 | display: 'block',
|
20349 | marginLeft: 'auto',
|
20350 | marginRight: 'auto'
|
20351 | },
|
20352 | preview: false
|
20353 | },
|
20354 | {
|
20355 | selector: 'table',
|
20356 | collapsed: false,
|
20357 | styles: {
|
20358 | marginLeft: 'auto',
|
20359 | marginRight: 'auto'
|
20360 | },
|
20361 | preview: 'font-family font-size'
|
20362 | },
|
20363 | {
|
20364 | selector: '.mce-preview-object',
|
20365 | ceFalseOverride: true,
|
20366 | styles: {
|
20367 | display: 'table',
|
20368 | marginLeft: 'auto',
|
20369 | marginRight: 'auto'
|
20370 | },
|
20371 | preview: false
|
20372 | },
|
20373 | {
|
20374 | selector: '[data-ephox-embed-iri]',
|
20375 | ceFalseOverride: true,
|
20376 | styles: {
|
20377 | marginLeft: 'auto',
|
20378 | marginRight: 'auto'
|
20379 | },
|
20380 | preview: false
|
20381 | }
|
20382 | ],
|
20383 | alignright: [
|
20384 | {
|
20385 | selector: 'figure.image',
|
20386 | collapsed: false,
|
20387 | classes: 'align-right',
|
20388 | ceFalseOverride: true,
|
20389 | preview: 'font-family font-size'
|
20390 | },
|
20391 | {
|
20392 | selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
20393 | styles: { textAlign: 'right' },
|
20394 | inherit: false,
|
20395 | preview: 'font-family font-size'
|
20396 | },
|
20397 | {
|
20398 | selector: 'img,audio,video',
|
20399 | collapsed: false,
|
20400 | styles: { float: 'right' },
|
20401 | preview: 'font-family font-size'
|
20402 | },
|
20403 | {
|
20404 | selector: 'table',
|
20405 | collapsed: false,
|
20406 | styles: {
|
20407 | marginRight: '0px',
|
20408 | marginLeft: 'auto'
|
20409 | },
|
20410 | onformat: table => {
|
20411 | dom.setStyle(table, 'float', null);
|
20412 | },
|
20413 | preview: 'font-family font-size'
|
20414 | },
|
20415 | {
|
20416 | selector: '.mce-preview-object,[data-ephox-embed-iri]',
|
20417 | ceFalseOverride: true,
|
20418 | styles: { float: 'right' },
|
20419 | preview: false
|
20420 | }
|
20421 | ],
|
20422 | alignjustify: [{
|
20423 | selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
20424 | styles: { textAlign: 'justify' },
|
20425 | inherit: false,
|
20426 | preview: 'font-family font-size'
|
20427 | }],
|
20428 | bold: [
|
20429 | {
|
20430 | inline: 'strong',
|
20431 | remove: 'all',
|
20432 | preserve_attributes: [
|
20433 | 'class',
|
20434 | 'style'
|
20435 | ]
|
20436 | },
|
20437 | {
|
20438 | inline: 'span',
|
20439 | styles: { fontWeight: 'bold' }
|
20440 | },
|
20441 | {
|
20442 | inline: 'b',
|
20443 | remove: 'all',
|
20444 | preserve_attributes: [
|
20445 | 'class',
|
20446 | 'style'
|
20447 | ]
|
20448 | }
|
20449 | ],
|
20450 | italic: [
|
20451 | {
|
20452 | inline: 'em',
|
20453 | remove: 'all',
|
20454 | preserve_attributes: [
|
20455 | 'class',
|
20456 | 'style'
|
20457 | ]
|
20458 | },
|
20459 | {
|
20460 | inline: 'span',
|
20461 | styles: { fontStyle: 'italic' }
|
20462 | },
|
20463 | {
|
20464 | inline: 'i',
|
20465 | remove: 'all',
|
20466 | preserve_attributes: [
|
20467 | 'class',
|
20468 | 'style'
|
20469 | ]
|
20470 | }
|
20471 | ],
|
20472 | underline: [
|
20473 | {
|
20474 | inline: 'span',
|
20475 | styles: { textDecoration: 'underline' },
|
20476 | exact: true
|
20477 | },
|
20478 | {
|
20479 | inline: 'u',
|
20480 | remove: 'all',
|
20481 | preserve_attributes: [
|
20482 | 'class',
|
20483 | 'style'
|
20484 | ]
|
20485 | }
|
20486 | ],
|
20487 | strikethrough: (() => {
|
20488 | const span = {
|
20489 | inline: 'span',
|
20490 | styles: { textDecoration: 'line-through' },
|
20491 | exact: true
|
20492 | };
|
20493 | const strike = {
|
20494 | inline: 'strike',
|
20495 | remove: 'all',
|
20496 | preserve_attributes: [
|
20497 | 'class',
|
20498 | 'style'
|
20499 | ]
|
20500 | };
|
20501 | const s = {
|
20502 | inline: 's',
|
20503 | remove: 'all',
|
20504 | preserve_attributes: [
|
20505 | 'class',
|
20506 | 'style'
|
20507 | ]
|
20508 | };
|
20509 | return schemaType !== 'html4' ? [
|
20510 | s,
|
20511 | span,
|
20512 | strike
|
20513 | ] : [
|
20514 | span,
|
20515 | s,
|
20516 | strike
|
20517 | ];
|
20518 | })(),
|
20519 | forecolor: {
|
20520 | inline: 'span',
|
20521 | styles: { color: '%value' },
|
20522 | links: true,
|
20523 | remove_similar: true,
|
20524 | clear_child_styles: true
|
20525 | },
|
20526 | hilitecolor: {
|
20527 | inline: 'span',
|
20528 | styles: { backgroundColor: '%value' },
|
20529 | links: true,
|
20530 | remove_similar: true,
|
20531 | clear_child_styles: true
|
20532 | },
|
20533 | fontname: {
|
20534 | inline: 'span',
|
20535 | toggle: false,
|
20536 | styles: { fontFamily: '%value' },
|
20537 | clear_child_styles: true
|
20538 | },
|
20539 | fontsize: {
|
20540 | inline: 'span',
|
20541 | toggle: false,
|
20542 | styles: { fontSize: '%value' },
|
20543 | clear_child_styles: true
|
20544 | },
|
20545 | lineheight: {
|
20546 | selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div',
|
20547 | styles: { lineHeight: '%value' }
|
20548 | },
|
20549 | fontsize_class: {
|
20550 | inline: 'span',
|
20551 | attributes: { class: '%value' }
|
20552 | },
|
20553 | blockquote: {
|
20554 | block: 'blockquote',
|
20555 | wrapper: true,
|
20556 | remove: 'all'
|
20557 | },
|
20558 | subscript: { inline: 'sub' },
|
20559 | superscript: { inline: 'sup' },
|
20560 | code: { inline: 'code' },
|
20561 | link: {
|
20562 | inline: 'a',
|
20563 | selector: 'a',
|
20564 | remove: 'all',
|
20565 | split: true,
|
20566 | deep: true,
|
20567 | onmatch: (node, _fmt, _itemName) => {
|
20568 | return isElement$6(node) && node.hasAttribute('href');
|
20569 | },
|
20570 | onformat: (elm, _fmt, vars) => {
|
20571 | Tools.each(vars, (value, key) => {
|
20572 | dom.setAttrib(elm, key, value);
|
20573 | });
|
20574 | }
|
20575 | },
|
20576 | lang: {
|
20577 | inline: 'span',
|
20578 | clear_child_styles: true,
|
20579 | remove_similar: true,
|
20580 | attributes: {
|
20581 | 'lang': '%value',
|
20582 | 'data-mce-lang': vars => {
|
20583 | var _a;
|
20584 | return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
|
20585 | }
|
20586 | }
|
20587 | },
|
20588 | removeformat: [
|
20589 | {
|
20590 | selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small',
|
20591 | remove: 'all',
|
20592 | split: true,
|
20593 | expand: false,
|
20594 | block_expand: true,
|
20595 | deep: true
|
20596 | },
|
20597 | {
|
20598 | selector: 'span',
|
20599 | attributes: [
|
20600 | 'style',
|
20601 | 'class'
|
20602 | ],
|
20603 | remove: 'empty',
|
20604 | split: true,
|
20605 | expand: false,
|
20606 | deep: true
|
20607 | },
|
20608 | {
|
20609 | selector: '*',
|
20610 | attributes: [
|
20611 | 'style',
|
20612 | 'class'
|
20613 | ],
|
20614 | split: false,
|
20615 | expand: false,
|
20616 | deep: true
|
20617 | }
|
20618 | ]
|
20619 | };
|
20620 | Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd samp'.split(/\s/), name => {
|
20621 | formats[name] = {
|
20622 | block: name,
|
20623 | remove: 'all'
|
20624 | };
|
20625 | });
|
20626 | return formats;
|
20627 | };
|
20628 |
|
20629 | const genericBase = {
|
20630 | remove_similar: true,
|
20631 | inherit: false
|
20632 | };
|
20633 | const cellBase = {
|
20634 | selector: 'td,th',
|
20635 | ...genericBase
|
20636 | };
|
20637 | const cellFormats = {
|
20638 | tablecellbackgroundcolor: {
|
20639 | styles: { backgroundColor: '%value' },
|
20640 | ...cellBase
|
20641 | },
|
20642 | tablecellverticalalign: {
|
20643 | styles: { 'vertical-align': '%value' },
|
20644 | ...cellBase
|
20645 | },
|
20646 | tablecellbordercolor: {
|
20647 | styles: { borderColor: '%value' },
|
20648 | ...cellBase
|
20649 | },
|
20650 | tablecellclass: {
|
20651 | classes: ['%value'],
|
20652 | ...cellBase
|
20653 | },
|
20654 | tableclass: {
|
20655 | selector: 'table',
|
20656 | classes: ['%value'],
|
20657 | ...genericBase
|
20658 | },
|
20659 | tablecellborderstyle: {
|
20660 | styles: { borderStyle: '%value' },
|
20661 | ...cellBase
|
20662 | },
|
20663 | tablecellborderwidth: {
|
20664 | styles: { borderWidth: '%value' },
|
20665 | ...cellBase
|
20666 | }
|
20667 | };
|
20668 | const get = constant(cellFormats);
|
20669 |
|
20670 | const FormatRegistry = editor => {
|
20671 | const formats = {};
|
20672 | const get$2 = name => isNonNullable(name) ? formats[name] : formats;
|
20673 | const has = name => has$2(formats, name);
|
20674 | const register = (name, format) => {
|
20675 | if (name) {
|
20676 | if (!isString(name)) {
|
20677 | each$d(name, (format, name) => {
|
20678 | register(name, format);
|
20679 | });
|
20680 | } else {
|
20681 | if (!isArray$1(format)) {
|
20682 | format = [format];
|
20683 | }
|
20684 | each$e(format, format => {
|
20685 | if (isUndefined(format.deep)) {
|
20686 | format.deep = !isSelectorFormat(format);
|
20687 | }
|
20688 | if (isUndefined(format.split)) {
|
20689 | format.split = !isSelectorFormat(format) || isInlineFormat(format);
|
20690 | }
|
20691 | if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) {
|
20692 | format.remove = 'none';
|
20693 | }
|
20694 | if (isSelectorFormat(format) && isInlineFormat(format)) {
|
20695 | format.mixed = true;
|
20696 | format.block_expand = true;
|
20697 | }
|
20698 | if (isString(format.classes)) {
|
20699 | format.classes = format.classes.split(/\s+/);
|
20700 | }
|
20701 | });
|
20702 | formats[name] = format;
|
20703 | }
|
20704 | }
|
20705 | };
|
20706 | const unregister = name => {
|
20707 | if (name && formats[name]) {
|
20708 | delete formats[name];
|
20709 | }
|
20710 | return formats;
|
20711 | };
|
20712 | register(get$1(editor));
|
20713 | register(get());
|
20714 | register(getFormats(editor));
|
20715 | return {
|
20716 | get: get$2,
|
20717 | has,
|
20718 | register,
|
20719 | unregister
|
20720 | };
|
20721 | };
|
20722 |
|
20723 | const each$3 = Tools.each;
|
20724 | const dom = DOMUtils.DOM;
|
20725 | const isPreviewItem = item => isNonNullable(item) && isObject(item);
|
20726 | const parsedSelectorToHtml = (ancestry, editor) => {
|
20727 | const schema = editor && editor.schema || Schema({});
|
20728 | const decorate = (elm, item) => {
|
20729 | if (item.classes.length > 0) {
|
20730 | dom.addClass(elm, item.classes.join(' '));
|
20731 | }
|
20732 | dom.setAttribs(elm, item.attrs);
|
20733 | };
|
20734 | const createElement = sItem => {
|
20735 | const item = isString(sItem) ? {
|
20736 | name: sItem,
|
20737 | classes: [],
|
20738 | attrs: {}
|
20739 | } : sItem;
|
20740 | const elm = dom.create(item.name);
|
20741 | decorate(elm, item);
|
20742 | return elm;
|
20743 | };
|
20744 | const getRequiredParent = (elm, candidate) => {
|
20745 | const elmRule = schema.getElementRule(elm.nodeName.toLowerCase());
|
20746 | const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired;
|
20747 | if (parentsRequired && parentsRequired.length) {
|
20748 | return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0];
|
20749 | } else {
|
20750 | return false;
|
20751 | }
|
20752 | };
|
20753 | const wrapInHtml = (elm, ancestors, siblings) => {
|
20754 | let parentCandidate;
|
20755 | const ancestor = ancestors[0];
|
20756 | const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined;
|
20757 | const parentRequired = getRequiredParent(elm, ancestorName);
|
20758 | if (parentRequired) {
|
20759 | if (ancestorName === parentRequired) {
|
20760 | parentCandidate = ancestor;
|
20761 | ancestors = ancestors.slice(1);
|
20762 | } else {
|
20763 | parentCandidate = parentRequired;
|
20764 | }
|
20765 | } else if (ancestor) {
|
20766 | parentCandidate = ancestor;
|
20767 | ancestors = ancestors.slice(1);
|
20768 | } else if (!siblings) {
|
20769 | return elm;
|
20770 | }
|
20771 | const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div');
|
20772 | parent.appendChild(elm);
|
20773 | if (siblings) {
|
20774 | Tools.each(siblings, sibling => {
|
20775 | const siblingElm = createElement(sibling);
|
20776 | parent.insertBefore(siblingElm, elm);
|
20777 | });
|
20778 | }
|
20779 | const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined;
|
20780 | return wrapInHtml(parent, ancestors, parentSiblings);
|
20781 | };
|
20782 | const fragment = dom.create('div');
|
20783 | if (ancestry.length > 0) {
|
20784 | const item = ancestry[0];
|
20785 | const elm = createElement(item);
|
20786 | const siblings = isPreviewItem(item) ? item.siblings : undefined;
|
20787 | fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings));
|
20788 | }
|
20789 | return fragment;
|
20790 | };
|
20791 | const parseSelectorItem = item => {
|
20792 | item = Tools.trim(item);
|
20793 | let tagName = 'div';
|
20794 | const obj = {
|
20795 | name: tagName,
|
20796 | classes: [],
|
20797 | attrs: {},
|
20798 | selector: item
|
20799 | };
|
20800 | if (item !== '*') {
|
20801 | tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
|
20802 | switch ($1) {
|
20803 | case '#':
|
20804 | obj.attrs.id = $2;
|
20805 | break;
|
20806 | case '.':
|
20807 | obj.classes.push($2);
|
20808 | break;
|
20809 | case ':':
|
20810 | if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
|
20811 | obj.attrs[$2] = $2;
|
20812 | }
|
20813 | break;
|
20814 | }
|
20815 | if ($3 === '[') {
|
20816 | const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
|
20817 | if (m) {
|
20818 | obj.attrs[m[1]] = m[2];
|
20819 | }
|
20820 | }
|
20821 | return '';
|
20822 | });
|
20823 | }
|
20824 | obj.name = tagName || 'div';
|
20825 | return obj;
|
20826 | };
|
20827 | const parseSelector = selector => {
|
20828 | if (!isString(selector)) {
|
20829 | return [];
|
20830 | }
|
20831 | selector = selector.split(/\s*,\s*/)[0];
|
20832 | selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
|
20833 | return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => {
|
20834 | const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
|
20835 | const obj = siblings.pop();
|
20836 | if (siblings.length) {
|
20837 | obj.siblings = siblings;
|
20838 | }
|
20839 | return obj;
|
20840 | }).reverse();
|
20841 | };
|
20842 | const getCssText = (editor, format) => {
|
20843 | let previewCss = '';
|
20844 | let previewStyles = getPreviewStyles(editor);
|
20845 | if (previewStyles === '') {
|
20846 | return '';
|
20847 | }
|
20848 | const removeVars = val => {
|
20849 | return isString(val) ? val.replace(/%(\w+)/g, '') : '';
|
20850 | };
|
20851 | const getComputedStyle = (name, elm) => {
|
20852 | return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true);
|
20853 | };
|
20854 | if (isString(format)) {
|
20855 | const formats = editor.formatter.get(format);
|
20856 | if (!formats) {
|
20857 | return '';
|
20858 | }
|
20859 | format = formats[0];
|
20860 | }
|
20861 | if ('preview' in format) {
|
20862 | const preview = format.preview;
|
20863 | if (preview === false) {
|
20864 | return '';
|
20865 | } else {
|
20866 | previewStyles = preview || previewStyles;
|
20867 | }
|
20868 | }
|
20869 | let name = format.block || format.inline || 'span';
|
20870 | let previewFrag;
|
20871 | const items = parseSelector(format.selector);
|
20872 | if (items.length > 0) {
|
20873 | if (!items[0].name) {
|
20874 | items[0].name = name;
|
20875 | }
|
20876 | name = format.selector;
|
20877 | previewFrag = parsedSelectorToHtml(items, editor);
|
20878 | } else {
|
20879 | previewFrag = parsedSelectorToHtml([name], editor);
|
20880 | }
|
20881 | const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
|
20882 | each$3(format.styles, (value, name) => {
|
20883 | const newValue = removeVars(value);
|
20884 | if (newValue) {
|
20885 | dom.setStyle(previewElm, name, newValue);
|
20886 | }
|
20887 | });
|
20888 | each$3(format.attributes, (value, name) => {
|
20889 | const newValue = removeVars(value);
|
20890 | if (newValue) {
|
20891 | dom.setAttrib(previewElm, name, newValue);
|
20892 | }
|
20893 | });
|
20894 | each$3(format.classes, value => {
|
20895 | const newValue = removeVars(value);
|
20896 | if (!dom.hasClass(previewElm, newValue)) {
|
20897 | dom.addClass(previewElm, newValue);
|
20898 | }
|
20899 | });
|
20900 | editor.dispatch('PreviewFormats');
|
20901 | dom.setStyles(previewFrag, {
|
20902 | position: 'absolute',
|
20903 | left: -65535
|
20904 | });
|
20905 | editor.getBody().appendChild(previewFrag);
|
20906 | const rawParentFontSize = getComputedStyle('fontSize');
|
20907 | const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0;
|
20908 | each$3(previewStyles.split(' '), name => {
|
20909 | let value = getComputedStyle(name, previewElm);
|
20910 | if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
|
20911 | value = getComputedStyle(name);
|
20912 | if (rgbaToHexString(value).toLowerCase() === '#ffffff') {
|
20913 | return;
|
20914 | }
|
20915 | }
|
20916 | if (name === 'color') {
|
20917 | if (rgbaToHexString(value).toLowerCase() === '#000000') {
|
20918 | return;
|
20919 | }
|
20920 | }
|
20921 | if (name === 'font-size') {
|
20922 | if (/em|%$/.test(value)) {
|
20923 | if (parentFontSize === 0) {
|
20924 | return;
|
20925 | }
|
20926 | const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
|
20927 | value = numValue * parentFontSize + 'px';
|
20928 | }
|
20929 | }
|
20930 | if (name === 'border' && value) {
|
20931 | previewCss += 'padding:0 2px;';
|
20932 | }
|
20933 | previewCss += name + ':' + value + ';';
|
20934 | });
|
20935 | editor.dispatch('AfterPreviewFormats');
|
20936 | dom.remove(previewFrag);
|
20937 | return previewCss;
|
20938 | };
|
20939 |
|
20940 | const setup$s = editor => {
|
20941 | editor.addShortcut('meta+b', '', 'Bold');
|
20942 | editor.addShortcut('meta+i', '', 'Italic');
|
20943 | editor.addShortcut('meta+u', '', 'Underline');
|
20944 | for (let i = 1; i <= 6; i++) {
|
20945 | editor.addShortcut('access+' + i, '', [
|
20946 | 'FormatBlock',
|
20947 | false,
|
20948 | 'h' + i
|
20949 | ]);
|
20950 | }
|
20951 | editor.addShortcut('access+7', '', [
|
20952 | 'FormatBlock',
|
20953 | false,
|
20954 | 'p'
|
20955 | ]);
|
20956 | editor.addShortcut('access+8', '', [
|
20957 | 'FormatBlock',
|
20958 | false,
|
20959 | 'div'
|
20960 | ]);
|
20961 | editor.addShortcut('access+9', '', [
|
20962 | 'FormatBlock',
|
20963 | false,
|
20964 | 'address'
|
20965 | ]);
|
20966 | };
|
20967 |
|
20968 | const Formatter = editor => {
|
20969 | const formats = FormatRegistry(editor);
|
20970 | const formatChangeState = Cell({});
|
20971 | setup$s(editor);
|
20972 | setup$v(editor);
|
20973 | if (!isRtc(editor)) {
|
20974 | setup$u(formatChangeState, editor);
|
20975 | }
|
20976 | return {
|
20977 | get: formats.get,
|
20978 | has: formats.has,
|
20979 | register: formats.register,
|
20980 | unregister: formats.unregister,
|
20981 | apply: (name, vars, node) => {
|
20982 | applyFormat(editor, name, vars, node);
|
20983 | },
|
20984 | remove: (name, vars, node, similar) => {
|
20985 | removeFormat(editor, name, vars, node, similar);
|
20986 | },
|
20987 | toggle: (name, vars, node) => {
|
20988 | toggleFormat(editor, name, vars, node);
|
20989 | },
|
20990 | match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar),
|
20991 | closest: names => closestFormat(editor, names),
|
20992 | matchAll: (names, vars) => matchAllFormats(editor, names, vars),
|
20993 | matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar),
|
20994 | canApply: name => canApplyFormat(editor, name),
|
20995 | formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars),
|
20996 | getCssText: curry(getCssText, editor)
|
20997 | };
|
20998 | };
|
20999 |
|
21000 | const shouldIgnoreCommand = cmd => {
|
21001 | switch (cmd.toLowerCase()) {
|
21002 | case 'undo':
|
21003 | case 'redo':
|
21004 | case 'mcefocus':
|
21005 | return true;
|
21006 | default:
|
21007 | return false;
|
21008 | }
|
21009 | };
|
21010 | const registerEvents = (editor, undoManager, locks) => {
|
21011 | const isFirstTypedCharacter = Cell(false);
|
21012 | const addNonTypingUndoLevel = e => {
|
21013 | setTyping(undoManager, false, locks);
|
21014 | undoManager.add({}, e);
|
21015 | };
|
21016 | editor.on('init', () => {
|
21017 | undoManager.add();
|
21018 | });
|
21019 | editor.on('BeforeExecCommand', e => {
|
21020 | const cmd = e.command;
|
21021 | if (!shouldIgnoreCommand(cmd)) {
|
21022 | endTyping(undoManager, locks);
|
21023 | undoManager.beforeChange();
|
21024 | }
|
21025 | });
|
21026 | editor.on('ExecCommand', e => {
|
21027 | const cmd = e.command;
|
21028 | if (!shouldIgnoreCommand(cmd)) {
|
21029 | addNonTypingUndoLevel(e);
|
21030 | }
|
21031 | });
|
21032 | editor.on('ObjectResizeStart cut', () => {
|
21033 | undoManager.beforeChange();
|
21034 | });
|
21035 | editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
|
21036 | editor.on('dragend', addNonTypingUndoLevel);
|
21037 | editor.on('keyup', e => {
|
21038 | const keyCode = e.keyCode;
|
21039 | if (e.isDefaultPrevented()) {
|
21040 | return;
|
21041 | }
|
21042 | const isMeta = Env.os.isMacOS() && e.key === 'Meta';
|
21043 | if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey || isMeta) {
|
21044 | addNonTypingUndoLevel();
|
21045 | editor.nodeChanged();
|
21046 | }
|
21047 | if (keyCode === 46 || keyCode === 8) {
|
21048 | editor.nodeChanged();
|
21049 | }
|
21050 | if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
|
21051 | if (!editor.isDirty()) {
|
21052 | editor.setDirty(true);
|
21053 | }
|
21054 | editor.dispatch('TypingUndo');
|
21055 | isFirstTypedCharacter.set(false);
|
21056 | editor.nodeChanged();
|
21057 | }
|
21058 | });
|
21059 | editor.on('keydown', e => {
|
21060 | const keyCode = e.keyCode;
|
21061 | if (e.isDefaultPrevented()) {
|
21062 | return;
|
21063 | }
|
21064 | if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
|
21065 | if (undoManager.typing) {
|
21066 | addNonTypingUndoLevel(e);
|
21067 | }
|
21068 | return;
|
21069 | }
|
21070 | const modKey = e.ctrlKey && !e.altKey || e.metaKey;
|
21071 | if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
|
21072 | undoManager.beforeChange();
|
21073 | setTyping(undoManager, true, locks);
|
21074 | undoManager.add({}, e);
|
21075 | isFirstTypedCharacter.set(true);
|
21076 | return;
|
21077 | }
|
21078 | const hasOnlyMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey;
|
21079 | if (hasOnlyMetaOrCtrlModifier) {
|
21080 | undoManager.beforeChange();
|
21081 | }
|
21082 | });
|
21083 | editor.on('mousedown', e => {
|
21084 | if (undoManager.typing) {
|
21085 | addNonTypingUndoLevel(e);
|
21086 | }
|
21087 | });
|
21088 | const isInsertReplacementText = event => event.inputType === 'insertReplacementText';
|
21089 | const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null;
|
21090 | const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop';
|
21091 | editor.on('input', e => {
|
21092 | if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
|
21093 | addNonTypingUndoLevel(e);
|
21094 | }
|
21095 | });
|
21096 | editor.on('AddUndo Undo Redo ClearUndos', e => {
|
21097 | if (!e.isDefaultPrevented()) {
|
21098 | editor.nodeChanged();
|
21099 | }
|
21100 | });
|
21101 | };
|
21102 | const addKeyboardShortcuts = editor => {
|
21103 | editor.addShortcut('meta+z', '', 'Undo');
|
21104 | editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
|
21105 | };
|
21106 |
|
21107 | const UndoManager = editor => {
|
21108 | const beforeBookmark = value$2();
|
21109 | const locks = Cell(0);
|
21110 | const index = Cell(0);
|
21111 | const undoManager = {
|
21112 | data: [],
|
21113 | typing: false,
|
21114 | beforeChange: () => {
|
21115 | beforeChange(editor, locks, beforeBookmark);
|
21116 | },
|
21117 | add: (level, event) => {
|
21118 | return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
|
21119 | },
|
21120 | dispatchChange: () => {
|
21121 | editor.setDirty(true);
|
21122 | const level = createFromEditor(editor);
|
21123 | level.bookmark = getUndoBookmark(editor.selection);
|
21124 | editor.dispatch('change', {
|
21125 | level,
|
21126 | lastLevel: get$b(undoManager.data, index.get()).getOrUndefined()
|
21127 | });
|
21128 | },
|
21129 | undo: () => {
|
21130 | return undo(editor, undoManager, locks, index);
|
21131 | },
|
21132 | redo: () => {
|
21133 | return redo(editor, index, undoManager.data);
|
21134 | },
|
21135 | clear: () => {
|
21136 | clear(editor, undoManager, index);
|
21137 | },
|
21138 | reset: () => {
|
21139 | reset(editor, undoManager);
|
21140 | },
|
21141 | hasUndo: () => {
|
21142 | return hasUndo(editor, undoManager, index);
|
21143 | },
|
21144 | hasRedo: () => {
|
21145 | return hasRedo(editor, undoManager, index);
|
21146 | },
|
21147 | transact: callback => {
|
21148 | return transact(editor, undoManager, locks, callback);
|
21149 | },
|
21150 | ignore: callback => {
|
21151 | ignore(editor, locks, callback);
|
21152 | },
|
21153 | extra: (callback1, callback2) => {
|
21154 | extra(editor, undoManager, index, callback1, callback2);
|
21155 | }
|
21156 | };
|
21157 | if (!isRtc(editor)) {
|
21158 | registerEvents(editor, undoManager, locks);
|
21159 | }
|
21160 | addKeyboardShortcuts(editor);
|
21161 | return undoManager;
|
21162 | };
|
21163 |
|
21164 | const nonTypingKeycodes = [
|
21165 | 9,
|
21166 | 27,
|
21167 | VK.HOME,
|
21168 | VK.END,
|
21169 | 19,
|
21170 | 20,
|
21171 | 44,
|
21172 | 144,
|
21173 | 145,
|
21174 | 33,
|
21175 | 34,
|
21176 | 45,
|
21177 | 16,
|
21178 | 17,
|
21179 | 18,
|
21180 | 91,
|
21181 | 92,
|
21182 | 93,
|
21183 | VK.DOWN,
|
21184 | VK.UP,
|
21185 | VK.LEFT,
|
21186 | VK.RIGHT
|
21187 | ].concat(Env.browser.isFirefox() ? [224] : []);
|
21188 | const placeholderAttr = 'data-mce-placeholder';
|
21189 | const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup';
|
21190 | const isDeleteEvent = e => {
|
21191 | const keyCode = e.keyCode;
|
21192 | return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
|
21193 | };
|
21194 | const isNonTypingKeyboardEvent = e => {
|
21195 | if (isKeyboardEvent(e)) {
|
21196 | const keyCode = e.keyCode;
|
21197 | return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
|
21198 | } else {
|
21199 | return false;
|
21200 | }
|
21201 | };
|
21202 | const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229);
|
21203 | const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => {
|
21204 | if (dom.isEmpty(rootElm, undefined, {
|
21205 | skipBogus: false,
|
21206 | includeZwsp: true
|
21207 | })) {
|
21208 | const firstElement = rootElm.firstElementChild;
|
21209 | if (!firstElement) {
|
21210 | return true;
|
21211 | } else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) {
|
21212 | return false;
|
21213 | } else {
|
21214 | return forcedRootBlock === firstElement.nodeName.toLowerCase();
|
21215 | }
|
21216 | } else {
|
21217 | return false;
|
21218 | }
|
21219 | };
|
21220 | const setup$r = editor => {
|
21221 | var _a;
|
21222 | const dom = editor.dom;
|
21223 | const rootBlock = getForcedRootBlock(editor);
|
21224 | const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : '';
|
21225 | const updatePlaceholder = (e, initial) => {
|
21226 | if (isNonTypingKeyboardEvent(e)) {
|
21227 | return;
|
21228 | }
|
21229 | const body = editor.getBody();
|
21230 | const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock);
|
21231 | const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== '';
|
21232 | if (isPlaceholderShown !== showPlaceholder || initial) {
|
21233 | dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
|
21234 | firePlaceholderToggle(editor, showPlaceholder);
|
21235 | editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder);
|
21236 | editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder);
|
21237 | }
|
21238 | };
|
21239 | if (isNotEmpty(placeholder)) {
|
21240 | editor.on('init', e => {
|
21241 | updatePlaceholder(e, true);
|
21242 | editor.on('change SetContent ExecCommand', updatePlaceholder);
|
21243 | editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e)));
|
21244 | });
|
21245 | }
|
21246 | };
|
21247 |
|
21248 | const blockPosition = (block, position) => ({
|
21249 | block,
|
21250 | position
|
21251 | });
|
21252 | const blockBoundary = (from, to) => ({
|
21253 | from,
|
21254 | to
|
21255 | });
|
21256 | const getBlockPosition = (rootNode, pos) => {
|
21257 | const rootElm = SugarElement.fromDom(rootNode);
|
21258 | const containerElm = SugarElement.fromDom(pos.container());
|
21259 | return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos));
|
21260 | };
|
21261 | const isNotAncestorial = blockBoundary => !(contains(blockBoundary.to.block, blockBoundary.from.block) || contains(blockBoundary.from.block, blockBoundary.to.block));
|
21262 | const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block);
|
21263 | const getClosestHost = (root, scope) => {
|
21264 | const isRoot = node => eq(node, root);
|
21265 | const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
|
21266 | return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root);
|
21267 | };
|
21268 | const hasSameHost = (rootNode, blockBoundary) => {
|
21269 | const root = SugarElement.fromDom(rootNode);
|
21270 | return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block));
|
21271 | };
|
21272 | const isEditable$1 = blockBoundary => isContentEditableFalse$b(blockBoundary.from.block.dom) === false && isContentEditableFalse$b(blockBoundary.to.block.dom) === false;
|
21273 | const hasValidBlocks = blockBoundary => {
|
21274 | const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom) || isListItem$1(block);
|
21275 | return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block);
|
21276 | };
|
21277 | const skipLastBr = (schema, rootNode, forward, blockPosition) => {
|
21278 | if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(schema, blockPosition.block)) {
|
21279 | return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => {
|
21280 | if (lastPositionInBlock.isEqual(blockPosition.position)) {
|
21281 | return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to));
|
21282 | } else {
|
21283 | return Optional.some(blockPosition);
|
21284 | }
|
21285 | }).getOr(blockPosition);
|
21286 | } else {
|
21287 | return blockPosition;
|
21288 | }
|
21289 | };
|
21290 | const readFromRange = (schema, rootNode, forward, rng) => {
|
21291 | const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
|
21292 | const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(schema, rootNode, forward, blockPos))));
|
21293 | return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$1(blockBoundary) && hasValidBlocks(blockBoundary) && isNotAncestorial(blockBoundary));
|
21294 | };
|
21295 | const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
|
21296 |
|
21297 | const getChildrenUntilBlockBoundary = (block, schema) => {
|
21298 | const children = children$1(block);
|
21299 | return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
|
21300 | };
|
21301 | const extractChildren = (block, schema) => {
|
21302 | const children = getChildrenUntilBlockBoundary(block, schema);
|
21303 | each$e(children, remove$4);
|
21304 | return children;
|
21305 | };
|
21306 | const removeEmptyRoot = (schema, rootNode, block) => {
|
21307 | const parents = parentsAndSelf(block, rootNode);
|
21308 | return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4);
|
21309 | };
|
21310 | const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0;
|
21311 | const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => {
|
21312 | if (isEmpty$2(schema, toBlock)) {
|
21313 | fillWithPaddingBr(toBlock);
|
21314 | return firstPositionIn(toBlock.dom);
|
21315 | }
|
21316 | if (isEmptyBefore(schema, insertionPoint) && isEmpty$2(schema, fromBlock)) {
|
21317 | before$3(insertionPoint, SugarElement.fromTag('br'));
|
21318 | }
|
21319 | const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
|
21320 | each$e(extractChildren(fromBlock, schema), child => {
|
21321 | before$3(insertionPoint, child);
|
21322 | });
|
21323 | removeEmptyRoot(schema, rootNode, fromBlock);
|
21324 | return position;
|
21325 | };
|
21326 | const isInline = (schema, node) => schema.isInline(name(node));
|
21327 | const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => {
|
21328 | if (isEmpty$2(schema, toBlock)) {
|
21329 | if (isEmpty$2(schema, fromBlock)) {
|
21330 | const getInlineToBlockDescendants = el => {
|
21331 | const helper = (node, elements) => firstChild(node).fold(() => elements, child => isInline(schema, child) ? helper(child, elements.concat(shallow$1(child))) : elements);
|
21332 | return helper(el, []);
|
21333 | };
|
21334 | const newFromBlockDescendants = foldr(getInlineToBlockDescendants(toBlock), (element, descendant) => {
|
21335 | wrap$2(element, descendant);
|
21336 | return descendant;
|
21337 | }, createPaddingBr());
|
21338 | empty(fromBlock);
|
21339 | append$1(fromBlock, newFromBlockDescendants);
|
21340 | }
|
21341 | remove$4(toBlock);
|
21342 | return firstPositionIn(fromBlock.dom);
|
21343 | }
|
21344 | const position = lastPositionIn(toBlock.dom);
|
21345 | each$e(extractChildren(fromBlock, schema), child => {
|
21346 | append$1(toBlock, child);
|
21347 | });
|
21348 | removeEmptyRoot(schema, rootNode, fromBlock);
|
21349 | return position;
|
21350 | };
|
21351 | const findInsertionPoint = (toBlock, block) => {
|
21352 | const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
|
21353 | return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
|
21354 | };
|
21355 | const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
|
21356 | const trimBr = (first, block) => {
|
21357 | positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4);
|
21358 | };
|
21359 | const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => {
|
21360 | trimBr(true, fromBlock);
|
21361 | trimBr(false, toBlock);
|
21362 | return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema));
|
21363 | };
|
21364 | const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema);
|
21365 |
|
21366 | const backspaceDelete$9 = (editor, forward) => {
|
21367 | const rootNode = SugarElement.fromDom(editor.getBody());
|
21368 | const position = read$1(editor.schema, rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
|
21369 | mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => {
|
21370 | editor.selection.setRng(pos.toRange());
|
21371 | });
|
21372 | });
|
21373 | return position;
|
21374 | };
|
21375 |
|
21376 | const deleteRangeMergeBlocks = (rootNode, selection, schema) => {
|
21377 | const rng = selection.getRng();
|
21378 | return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
|
21379 | if (!eq(block1, block2)) {
|
21380 | return Optional.some(() => {
|
21381 | rng.deleteContents();
|
21382 | mergeBlocks(rootNode, true, block1, block2, schema).each(pos => {
|
21383 | selection.setRng(pos.toRange());
|
21384 | });
|
21385 | });
|
21386 | } else {
|
21387 | return Optional.none();
|
21388 | }
|
21389 | }).getOr(Optional.none());
|
21390 | };
|
21391 | const isRawNodeInTable = (root, rawNode) => {
|
21392 | const node = SugarElement.fromDom(rawNode);
|
21393 | const isRoot = curry(eq, root);
|
21394 | return ancestor$4(node, isTableCell$2, isRoot).isSome();
|
21395 | };
|
21396 | const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
|
21397 | const isEverythingSelected = (root, rng) => {
|
21398 | const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
|
21399 | const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
|
21400 | return !isSelectionInTable(root, rng) && noPrevious && noNext;
|
21401 | };
|
21402 | const emptyEditor = editor => {
|
21403 | return Optional.some(() => {
|
21404 | editor.setContent('');
|
21405 | editor.selection.setCursorLocation();
|
21406 | });
|
21407 | };
|
21408 | const deleteRange$2 = editor => {
|
21409 | const rootNode = SugarElement.fromDom(editor.getBody());
|
21410 | const rng = editor.selection.getRng();
|
21411 | return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection, editor.schema);
|
21412 | };
|
21413 | const backspaceDelete$8 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$2(editor);
|
21414 |
|
21415 | const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView));
|
21416 | const getNodeRange = node => {
|
21417 | const rng = node.ownerDocument.createRange();
|
21418 | rng.selectNode(node);
|
21419 | return rng;
|
21420 | };
|
21421 | const selectNode = (editor, node) => {
|
21422 | const e = editor.dispatch('BeforeObjectSelected', { target: node });
|
21423 | if (e.isDefaultPrevented()) {
|
21424 | return Optional.none();
|
21425 | }
|
21426 | return Optional.some(getNodeRange(node));
|
21427 | };
|
21428 | const renderCaretAtRange = (editor, range, scrollIntoView) => {
|
21429 | const normalizedRange = normalizeRange(1, editor.getBody(), range);
|
21430 | const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
|
21431 | const caretPositionNode = caretPosition.getNode();
|
21432 | if (isInlineFakeCaretTarget(caretPositionNode)) {
|
21433 | return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
|
21434 | }
|
21435 | const caretPositionBeforeNode = caretPosition.getNode(true);
|
21436 | if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
|
21437 | return showCaret(1, editor, caretPositionBeforeNode, false, false);
|
21438 | }
|
21439 | const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode());
|
21440 | if (isInlineFakeCaretTarget(ceRoot)) {
|
21441 | return showCaret(1, editor, ceRoot, false, scrollIntoView);
|
21442 | }
|
21443 | return Optional.none();
|
21444 | };
|
21445 | const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range;
|
21446 |
|
21447 | const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
|
21448 | const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
|
21449 | const trimEmptyTextNode = (dom, node) => {
|
21450 | if (isText$b(node) && node.data.length === 0) {
|
21451 | dom.remove(node);
|
21452 | }
|
21453 | };
|
21454 | const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => {
|
21455 | showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => {
|
21456 | if (range.collapsed) {
|
21457 | const deleteRange = range.cloneRange();
|
21458 | if (forward) {
|
21459 | deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
|
21460 | } else {
|
21461 | deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
|
21462 | }
|
21463 | deleteRange.deleteContents();
|
21464 | } else {
|
21465 | range.deleteContents();
|
21466 | }
|
21467 | editor.selection.setRng(caretRange);
|
21468 | });
|
21469 | trimEmptyTextNode(editor.dom, node);
|
21470 | };
|
21471 | const deleteBoundaryText = (editor, forward) => {
|
21472 | const range = editor.selection.getRng();
|
21473 | if (!isText$b(range.commonAncestorContainer)) {
|
21474 | return Optional.none();
|
21475 | }
|
21476 | const direction = forward ? HDirection.Forwards : HDirection.Backwards;
|
21477 | const caretWalker = CaretWalker(editor.getBody());
|
21478 | const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
|
21479 | const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
|
21480 | const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
21481 | const nextCaretPosition = getNextPosFn(caretPosition);
|
21482 | const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition;
|
21483 | if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) {
|
21484 | return Optional.none();
|
21485 | } else if (isBeforeFn(normalizedNextCaretPosition)) {
|
21486 | return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition));
|
21487 | }
|
21488 | const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition);
|
21489 | if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
|
21490 | if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) {
|
21491 | return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition));
|
21492 | }
|
21493 | }
|
21494 | return Optional.none();
|
21495 | };
|
21496 | const backspaceDelete$7 = (editor, forward) => deleteBoundaryText(editor, forward);
|
21497 |
|
21498 | const getEdgeCefPosition = (editor, atStart) => {
|
21499 | const root = editor.getBody();
|
21500 | return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
|
21501 | };
|
21502 | const isCefAtEdgeSelected = editor => {
|
21503 | const rng = editor.selection.getRng();
|
21504 | return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
|
21505 | };
|
21506 |
|
21507 | const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node)));
|
21508 | const DeleteAction = Adt.generate([
|
21509 | { remove: ['element'] },
|
21510 | { moveToElement: ['element'] },
|
21511 | { moveToPosition: ['position'] }
|
21512 | ]);
|
21513 | const isAtContentEditableBlockCaret = (forward, from) => {
|
21514 | const elm = from.getNode(!forward);
|
21515 | const caretLocation = forward ? 'after' : 'before';
|
21516 | return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
|
21517 | };
|
21518 | const isDeleteFromCefDifferentBlocks = (root, forward, from, to, schema) => {
|
21519 | const inSameBlock = elm => schema.isInline(elm.nodeName.toLowerCase()) && !isInSameBlock(from, to, root);
|
21520 | return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock);
|
21521 | };
|
21522 | const deleteEmptyBlockOrMoveToCef = (schema, root, forward, from, to) => {
|
21523 | const toCefElm = to.getNode(!forward);
|
21524 | return getParentBlock$2(SugarElement.fromDom(root), SugarElement.fromDom(from.getNode())).map(blockElm => isEmpty$2(schema, blockElm) ? DeleteAction.remove(blockElm.dom) : DeleteAction.moveToElement(toCefElm)).orThunk(() => Optional.some(DeleteAction.moveToElement(toCefElm)));
|
21525 | };
|
21526 | const findCefPosition = (root, forward, from, schema) => fromPosition(forward, root, from).bind(to => {
|
21527 | if (isCompoundElement(to.getNode())) {
|
21528 | return Optional.none();
|
21529 | } else if (isDeleteFromCefDifferentBlocks(root, forward, from, to, schema)) {
|
21530 | return Optional.none();
|
21531 | } else if (forward && isContentEditableFalse$b(to.getNode())) {
|
21532 | return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
|
21533 | } else if (!forward && isContentEditableFalse$b(to.getNode(true))) {
|
21534 | return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
|
21535 | } else if (forward && isAfterContentEditableFalse(from)) {
|
21536 | return Optional.some(DeleteAction.moveToPosition(to));
|
21537 | } else if (!forward && isBeforeContentEditableFalse(from)) {
|
21538 | return Optional.some(DeleteAction.moveToPosition(to));
|
21539 | } else {
|
21540 | return Optional.none();
|
21541 | }
|
21542 | });
|
21543 | const getContentEditableBlockAction = (forward, elm) => {
|
21544 | if (isNullable(elm)) {
|
21545 | return Optional.none();
|
21546 | } else if (forward && isContentEditableFalse$b(elm.nextSibling)) {
|
21547 | return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
|
21548 | } else if (!forward && isContentEditableFalse$b(elm.previousSibling)) {
|
21549 | return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
|
21550 | } else {
|
21551 | return Optional.none();
|
21552 | }
|
21553 | };
|
21554 | const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => {
|
21555 | if (isInSameBlock(from, to, root)) {
|
21556 | return Optional.none();
|
21557 | } else {
|
21558 | return Optional.some(DeleteAction.moveToPosition(to));
|
21559 | }
|
21560 | });
|
21561 | const getContentEditableAction = (root, forward, from, schema) => {
|
21562 | if (isAtContentEditableBlockCaret(forward, from)) {
|
21563 | return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from, schema));
|
21564 | } else {
|
21565 | return findCefPosition(root, forward, from, schema).bind(deleteAction => skipMoveToActionFromInlineCefToContent(root, from, deleteAction));
|
21566 | }
|
21567 | };
|
21568 | const read = (root, forward, rng, schema) => {
|
21569 | const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
|
21570 | const from = CaretPosition.fromRangeStart(normalizedRange);
|
21571 | const rootElement = SugarElement.fromDom(root);
|
21572 | if (!forward && isAfterContentEditableFalse(from)) {
|
21573 | return Optional.some(DeleteAction.remove(from.getNode(true)));
|
21574 | } else if (forward && isBeforeContentEditableFalse(from)) {
|
21575 | return Optional.some(DeleteAction.remove(from.getNode()));
|
21576 | } else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from, schema)) {
|
21577 | return findPreviousBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
|
21578 | } else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from, schema)) {
|
21579 | return findNextBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
|
21580 | } else {
|
21581 | return getContentEditableAction(root, forward, from, schema);
|
21582 | }
|
21583 | };
|
21584 |
|
21585 | const deleteElement$1 = (editor, forward) => element => {
|
21586 | editor._selectionOverrides.hideFakeCaret();
|
21587 | deleteElement$2(editor, forward, SugarElement.fromDom(element));
|
21588 | return true;
|
21589 | };
|
21590 | const moveToElement = (editor, forward) => element => {
|
21591 | const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
|
21592 | editor.selection.setRng(pos.toRange());
|
21593 | return true;
|
21594 | };
|
21595 | const moveToPosition = editor => pos => {
|
21596 | editor.selection.setRng(pos.toRange());
|
21597 | return true;
|
21598 | };
|
21599 | const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
|
21600 | const backspaceDeleteCaret = (editor, forward) => {
|
21601 | const selectedNode = editor.selection.getNode();
|
21602 | return getAncestorCe(editor, selectedNode).filter(isContentEditableFalse$b).fold(() => read(editor.getBody(), forward, editor.selection.getRng(), editor.schema).map(deleteAction => () => deleteAction.fold(deleteElement$1(editor, forward), moveToElement(editor, forward), moveToPosition(editor))), () => Optional.some(noop));
|
21603 | };
|
21604 | const deleteOffscreenSelection = rootElement => {
|
21605 | each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$4);
|
21606 | };
|
21607 | const backspaceDeleteRange = (editor, forward) => {
|
21608 | const selectedNode = editor.selection.getNode();
|
21609 | if (isContentEditableFalse$b(selectedNode) && !isTableCell$3(selectedNode)) {
|
21610 | const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b);
|
21611 | return hasCefAncestor.fold(() => Optional.some(() => {
|
21612 | deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
|
21613 | deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
|
21614 | paddEmptyBody(editor);
|
21615 | }), () => Optional.some(noop));
|
21616 | }
|
21617 | if (isCefAtEdgeSelected(editor)) {
|
21618 | return Optional.some(() => {
|
21619 | deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
|
21620 | });
|
21621 | }
|
21622 | return Optional.none();
|
21623 | };
|
21624 | const paddEmptyElement = editor => {
|
21625 | const dom = editor.dom, selection = editor.selection;
|
21626 | const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
|
21627 | if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) {
|
21628 | const br = dom.create('br', { 'data-mce-bogus': '1' });
|
21629 | dom.setHTML(ceRoot, '');
|
21630 | ceRoot.appendChild(br);
|
21631 | selection.setRng(CaretPosition.before(br).toRange());
|
21632 | }
|
21633 | return true;
|
21634 | };
|
21635 | const backspaceDelete$6 = (editor, forward) => {
|
21636 | if (editor.selection.isCollapsed()) {
|
21637 | return backspaceDeleteCaret(editor, forward);
|
21638 | } else {
|
21639 | return backspaceDeleteRange(editor, forward);
|
21640 | }
|
21641 | };
|
21642 |
|
21643 | const deleteCaret$2 = (editor, forward) => {
|
21644 | const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
21645 | return fromPosition(forward, editor.getBody(), fromPos).filter(pos => forward ? isBeforeImageBlock(pos) : isAfterImageBlock(pos)).bind(pos => getChildNodeAtRelativeOffset(forward ? 0 : -1, pos)).map(elm => () => editor.selection.select(elm));
|
21646 | };
|
21647 | const backspaceDelete$5 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
|
21648 |
|
21649 | const isText$2 = isText$b;
|
21650 | const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1;
|
21651 | const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
|
21652 | const createZwsp = node => {
|
21653 | var _a;
|
21654 | const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
21655 | return doc.createTextNode(ZWSP$1);
|
21656 | };
|
21657 | const insertBefore$1 = node => {
|
21658 | var _a;
|
21659 | if (isText$2(node.previousSibling)) {
|
21660 | if (endsWithCaretContainer(node.previousSibling)) {
|
21661 | return node.previousSibling;
|
21662 | } else {
|
21663 | node.previousSibling.appendData(ZWSP$1);
|
21664 | return node.previousSibling;
|
21665 | }
|
21666 | } else if (isText$2(node)) {
|
21667 | if (startsWithCaretContainer(node)) {
|
21668 | return node;
|
21669 | } else {
|
21670 | node.insertData(0, ZWSP$1);
|
21671 | return node;
|
21672 | }
|
21673 | } else {
|
21674 | const newNode = createZwsp(node);
|
21675 | (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node);
|
21676 | return newNode;
|
21677 | }
|
21678 | };
|
21679 | const insertAfter$1 = node => {
|
21680 | var _a, _b;
|
21681 | if (isText$2(node.nextSibling)) {
|
21682 | if (startsWithCaretContainer(node.nextSibling)) {
|
21683 | return node.nextSibling;
|
21684 | } else {
|
21685 | node.nextSibling.insertData(0, ZWSP$1);
|
21686 | return node.nextSibling;
|
21687 | }
|
21688 | } else if (isText$2(node)) {
|
21689 | if (endsWithCaretContainer(node)) {
|
21690 | return node;
|
21691 | } else {
|
21692 | node.appendData(ZWSP$1);
|
21693 | return node;
|
21694 | }
|
21695 | } else {
|
21696 | const newNode = createZwsp(node);
|
21697 | if (node.nextSibling) {
|
21698 | (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling);
|
21699 | } else {
|
21700 | (_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode);
|
21701 | }
|
21702 | return newNode;
|
21703 | }
|
21704 | };
|
21705 | const insertInline = (before, node) => before ? insertBefore$1(node) : insertAfter$1(node);
|
21706 | const insertInlineBefore = curry(insertInline, true);
|
21707 | const insertInlineAfter = curry(insertInline, false);
|
21708 |
|
21709 | const insertInlinePos = (pos, before) => {
|
21710 | if (isText$b(pos.container())) {
|
21711 | return insertInline(before, pos.container());
|
21712 | } else {
|
21713 | return insertInline(before, pos.getNode());
|
21714 | }
|
21715 | };
|
21716 | const isPosCaretContainer = (pos, caret) => {
|
21717 | const caretNode = caret.get();
|
21718 | return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
|
21719 | };
|
21720 | const renderCaret = (caret, location) => location.fold(element => {
|
21721 | remove$2(caret.get());
|
21722 | const text = insertInlineBefore(element);
|
21723 | caret.set(text);
|
21724 | return Optional.some(CaretPosition(text, text.length - 1));
|
21725 | }, element => firstPositionIn(element).map(pos => {
|
21726 | if (!isPosCaretContainer(pos, caret)) {
|
21727 | remove$2(caret.get());
|
21728 | const text = insertInlinePos(pos, true);
|
21729 | caret.set(text);
|
21730 | return CaretPosition(text, 1);
|
21731 | } else {
|
21732 | const node = caret.get();
|
21733 | return CaretPosition(node, 1);
|
21734 | }
|
21735 | }), element => lastPositionIn(element).map(pos => {
|
21736 | if (!isPosCaretContainer(pos, caret)) {
|
21737 | remove$2(caret.get());
|
21738 | const text = insertInlinePos(pos, false);
|
21739 | caret.set(text);
|
21740 | return CaretPosition(text, text.length - 1);
|
21741 | } else {
|
21742 | const node = caret.get();
|
21743 | return CaretPosition(node, node.length - 1);
|
21744 | }
|
21745 | }), element => {
|
21746 | remove$2(caret.get());
|
21747 | const text = insertInlineAfter(element);
|
21748 | caret.set(text);
|
21749 | return Optional.some(CaretPosition(text, 1));
|
21750 | });
|
21751 |
|
21752 | const evaluateUntil = (fns, args) => {
|
21753 | for (let i = 0; i < fns.length; i++) {
|
21754 | const result = fns[i].apply(null, args);
|
21755 | if (result.isSome()) {
|
21756 | return result;
|
21757 | }
|
21758 | }
|
21759 | return Optional.none();
|
21760 | };
|
21761 |
|
21762 | const Location = Adt.generate([
|
21763 | { before: ['element'] },
|
21764 | { start: ['element'] },
|
21765 | { end: ['element'] },
|
21766 | { after: ['element'] }
|
21767 | ]);
|
21768 | const rescope$1 = (rootNode, node) => {
|
21769 | const parentBlock = getParentBlock$3(node, rootNode);
|
21770 | return parentBlock ? parentBlock : rootNode;
|
21771 | };
|
21772 | const before = (isInlineTarget, rootNode, pos) => {
|
21773 | const nPos = normalizeForwards(pos);
|
21774 | const scope = rescope$1(rootNode, nPos.container());
|
21775 | return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none);
|
21776 | };
|
21777 | const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
|
21778 | const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
|
21779 | const start$1 = (isInlineTarget, rootNode, pos) => {
|
21780 | const nPos = normalizeBackwards(pos);
|
21781 | return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
|
21782 | const prevPos = prevPosition(inline, nPos);
|
21783 | return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
|
21784 | });
|
21785 | };
|
21786 | const end = (isInlineTarget, rootNode, pos) => {
|
21787 | const nPos = normalizeForwards(pos);
|
21788 | return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
|
21789 | const nextPos = nextPosition(inline, nPos);
|
21790 | return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
|
21791 | });
|
21792 | };
|
21793 | const after = (isInlineTarget, rootNode, pos) => {
|
21794 | const nPos = normalizeBackwards(pos);
|
21795 | const scope = rescope$1(rootNode, nPos.container());
|
21796 | return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none);
|
21797 | };
|
21798 | const isValidLocation = location => !isRtl(getElement(location));
|
21799 | const readLocation = (isInlineTarget, rootNode, pos) => {
|
21800 | const location = evaluateUntil([
|
21801 | before,
|
21802 | start$1,
|
21803 | end,
|
21804 | after
|
21805 | ], [
|
21806 | isInlineTarget,
|
21807 | rootNode,
|
21808 | pos
|
21809 | ]);
|
21810 | return location.filter(isValidLocation);
|
21811 | };
|
21812 | const getElement = location => location.fold(identity, identity, identity, identity);
|
21813 | const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
|
21814 | const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after);
|
21815 | const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end);
|
21816 | const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
|
21817 | const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => {
|
21818 | if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
|
21819 | return Location.after(forward ? fromInline : toInline);
|
21820 | } else {
|
21821 | return location;
|
21822 | }
|
21823 | }).getOr(location);
|
21824 | const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation));
|
21825 | const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => {
|
21826 | const from = normalizePosition(forward, pos);
|
21827 | const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward));
|
21828 | const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation)));
|
21829 | return location.filter(isValidLocation);
|
21830 | };
|
21831 | const findLocationSimple = (forward, location) => {
|
21832 | if (forward) {
|
21833 | return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
|
21834 | } else {
|
21835 | return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
|
21836 | }
|
21837 | };
|
21838 | const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => {
|
21839 | const from = normalizePosition(forward, pos);
|
21840 | const fromLocation = readLocation(isInlineTarget, rootNode, from);
|
21841 | return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos));
|
21842 | };
|
21843 |
|
21844 | const hasSelectionModifyApi = editor => {
|
21845 | return isFunction(editor.selection.getSel().modify);
|
21846 | };
|
21847 | const moveRel = (forward, selection, pos) => {
|
21848 | const delta = forward ? 1 : -1;
|
21849 | selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
|
21850 | selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
|
21851 | return true;
|
21852 | };
|
21853 | const moveByWord = (forward, editor) => {
|
21854 | const rng = editor.selection.getRng();
|
21855 | const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
|
21856 | if (!hasSelectionModifyApi(editor)) {
|
21857 | return false;
|
21858 | } else if (forward && isBeforeInline(pos)) {
|
21859 | return moveRel(true, editor.selection, pos);
|
21860 | } else if (!forward && isAfterInline(pos)) {
|
21861 | return moveRel(false, editor.selection, pos);
|
21862 | } else {
|
21863 | return false;
|
21864 | }
|
21865 | };
|
21866 |
|
21867 | var BreakType;
|
21868 | (function (BreakType) {
|
21869 | BreakType[BreakType['Br'] = 0] = 'Br';
|
21870 | BreakType[BreakType['Block'] = 1] = 'Block';
|
21871 | BreakType[BreakType['Wrap'] = 2] = 'Wrap';
|
21872 | BreakType[BreakType['Eol'] = 3] = 'Eol';
|
21873 | }(BreakType || (BreakType = {})));
|
21874 | const flip = (direction, positions) => direction === HDirection.Backwards ? reverse(positions) : positions;
|
21875 | const walk$1 = (direction, caretWalker, pos) => direction === HDirection.Forwards ? caretWalker.next(pos) : caretWalker.prev(pos);
|
21876 | const getBreakType = (scope, direction, currentPos, nextPos) => {
|
21877 | if (isBr$6(nextPos.getNode(direction === HDirection.Forwards))) {
|
21878 | return BreakType.Br;
|
21879 | } else if (isInSameBlock(currentPos, nextPos) === false) {
|
21880 | return BreakType.Block;
|
21881 | } else {
|
21882 | return BreakType.Wrap;
|
21883 | }
|
21884 | };
|
21885 | const getPositionsUntil = (predicate, direction, scope, start) => {
|
21886 | const caretWalker = CaretWalker(scope);
|
21887 | let currentPos = start;
|
21888 | const positions = [];
|
21889 | while (currentPos) {
|
21890 | const nextPos = walk$1(direction, caretWalker, currentPos);
|
21891 | if (!nextPos) {
|
21892 | break;
|
21893 | }
|
21894 | if (isBr$6(nextPos.getNode(false))) {
|
21895 | if (direction === HDirection.Forwards) {
|
21896 | return {
|
21897 | positions: flip(direction, positions).concat([nextPos]),
|
21898 | breakType: BreakType.Br,
|
21899 | breakAt: Optional.some(nextPos)
|
21900 | };
|
21901 | } else {
|
21902 | return {
|
21903 | positions: flip(direction, positions),
|
21904 | breakType: BreakType.Br,
|
21905 | breakAt: Optional.some(nextPos)
|
21906 | };
|
21907 | }
|
21908 | }
|
21909 | if (!nextPos.isVisible()) {
|
21910 | currentPos = nextPos;
|
21911 | continue;
|
21912 | }
|
21913 | if (predicate(currentPos, nextPos)) {
|
21914 | const breakType = getBreakType(scope, direction, currentPos, nextPos);
|
21915 | return {
|
21916 | positions: flip(direction, positions),
|
21917 | breakType,
|
21918 | breakAt: Optional.some(nextPos)
|
21919 | };
|
21920 | }
|
21921 | positions.push(nextPos);
|
21922 | currentPos = nextPos;
|
21923 | }
|
21924 | return {
|
21925 | positions: flip(direction, positions),
|
21926 | breakType: BreakType.Eol,
|
21927 | breakAt: Optional.none()
|
21928 | };
|
21929 | };
|
21930 | const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => {
|
21931 | const positions = getPositionsUntilBreak(scope, pos).positions;
|
21932 | return direction === HDirection.Backwards ? positions.concat(pos) : [pos].concat(positions);
|
21933 | }).getOr([]);
|
21934 | const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
|
21935 | const lastDist = Math.abs(x - lastRect.left);
|
21936 | const newDist = Math.abs(x - newRect.left);
|
21937 | return newDist <= lastDist ? newPos : lastPos;
|
21938 | }).or(acc)), Optional.none());
|
21939 | const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
|
21940 | const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
|
21941 | const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
|
21942 | const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
|
21943 | const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
|
21944 | const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
|
21945 | const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
|
21946 | const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
|
21947 | const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
|
21948 | const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
|
21949 | const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
|
21950 |
|
21951 | const isContentEditableFalse$5 = isContentEditableFalse$b;
|
21952 | const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
|
21953 | const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
|
21954 | const isNodeClientRect = rect => hasNonNullableKey(rect, 'node');
|
21955 | const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
|
21956 | const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
|
21957 | const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
|
21958 | if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$5(clientRect.node)) {
|
21959 | return clientRect;
|
21960 | }
|
21961 | if (newDistance < oldDistance) {
|
21962 | return clientRect;
|
21963 | }
|
21964 | return oldClientRect;
|
21965 | });
|
21966 |
|
21967 | const getNodeClientRects = node => {
|
21968 | const toArrayWithNode = clientRects => {
|
21969 | return map$3(clientRects, rect => {
|
21970 | const clientRect = clone$1(rect);
|
21971 | clientRect.node = node;
|
21972 | return clientRect;
|
21973 | });
|
21974 | };
|
21975 | if (isElement$6(node)) {
|
21976 | return toArrayWithNode(node.getClientRects());
|
21977 | } else if (isText$b(node)) {
|
21978 | const rng = node.ownerDocument.createRange();
|
21979 | rng.setStart(node, 0);
|
21980 | rng.setEnd(node, node.data.length);
|
21981 | return toArrayWithNode(rng.getClientRects());
|
21982 | } else {
|
21983 | return [];
|
21984 | }
|
21985 | };
|
21986 | const getClientRects = nodes => bind$3(nodes, getNodeClientRects);
|
21987 |
|
21988 | var VDirection;
|
21989 | (function (VDirection) {
|
21990 | VDirection[VDirection['Up'] = -1] = 'Up';
|
21991 | VDirection[VDirection['Down'] = 1] = 'Down';
|
21992 | }(VDirection || (VDirection = {})));
|
21993 | const findUntil = (direction, root, predicateFn, node) => {
|
21994 | let currentNode = node;
|
21995 | while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) {
|
21996 | if (predicateFn(currentNode)) {
|
21997 | return;
|
21998 | }
|
21999 | }
|
22000 | };
|
22001 | const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
|
22002 | let line = 0;
|
22003 | const result = [];
|
22004 | const add = node => {
|
22005 | let clientRects = getClientRects([node]);
|
22006 | if (direction === -1) {
|
22007 | clientRects = clientRects.reverse();
|
22008 | }
|
22009 | for (let i = 0; i < clientRects.length; i++) {
|
22010 | const clientRect = clientRects[i];
|
22011 | if (isBeflowFn(clientRect, targetClientRect)) {
|
22012 | continue;
|
22013 | }
|
22014 | if (result.length > 0 && isAboveFn(clientRect, last$1(result))) {
|
22015 | line++;
|
22016 | }
|
22017 | clientRect.line = line;
|
22018 | if (predicateFn(clientRect)) {
|
22019 | return true;
|
22020 | }
|
22021 | result.push(clientRect);
|
22022 | }
|
22023 | return false;
|
22024 | };
|
22025 | const targetClientRect = last$1(caretPosition.getClientRects());
|
22026 | if (!targetClientRect) {
|
22027 | return result;
|
22028 | }
|
22029 | const node = caretPosition.getNode();
|
22030 | if (node) {
|
22031 | add(node);
|
22032 | findUntil(direction, root, add, node);
|
22033 | }
|
22034 | return result;
|
22035 | };
|
22036 | const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
|
22037 | const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
|
22038 | const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
|
22039 | const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
|
22040 | const getLastClientRect = caretPosition => {
|
22041 | return last$1(caretPosition.getClientRects());
|
22042 | };
|
22043 | const positionsUntil = (direction, root, predicateFn, node) => {
|
22044 | const caretWalker = CaretWalker(root);
|
22045 | let walkFn;
|
22046 | let isBelowFn;
|
22047 | let isAboveFn;
|
22048 | let caretPosition;
|
22049 | const result = [];
|
22050 | let line = 0;
|
22051 | if (direction === 1) {
|
22052 | walkFn = caretWalker.next;
|
22053 | isBelowFn = isBelow$1;
|
22054 | isAboveFn = isAbove$1;
|
22055 | caretPosition = CaretPosition.after(node);
|
22056 | } else {
|
22057 | walkFn = caretWalker.prev;
|
22058 | isBelowFn = isAbove$1;
|
22059 | isAboveFn = isBelow$1;
|
22060 | caretPosition = CaretPosition.before(node);
|
22061 | }
|
22062 | const targetClientRect = getLastClientRect(caretPosition);
|
22063 | do {
|
22064 | if (!caretPosition.isVisible()) {
|
22065 | continue;
|
22066 | }
|
22067 | const rect = getLastClientRect(caretPosition);
|
22068 | if (isAboveFn(rect, targetClientRect)) {
|
22069 | continue;
|
22070 | }
|
22071 | if (result.length > 0 && isBelowFn(rect, last$1(result))) {
|
22072 | line++;
|
22073 | }
|
22074 | const clientRect = clone$1(rect);
|
22075 | clientRect.position = caretPosition;
|
22076 | clientRect.line = line;
|
22077 | if (predicateFn(clientRect)) {
|
22078 | return result;
|
22079 | }
|
22080 | result.push(clientRect);
|
22081 | } while (caretPosition = walkFn(caretPosition));
|
22082 | return result;
|
22083 | };
|
22084 | const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect);
|
22085 | const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect);
|
22086 |
|
22087 | const moveToRange = (editor, rng) => {
|
22088 | editor.selection.setRng(rng);
|
22089 | scrollRangeIntoView(editor, editor.selection.getRng());
|
22090 | };
|
22091 | const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView));
|
22092 | const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => {
|
22093 | const forwards = direction === HDirection.Forwards;
|
22094 | const caretWalker = CaretWalker(editor.getBody());
|
22095 | const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
|
22096 | const isBeforeFn = forwards ? isBefore : isAfter;
|
22097 | if (!range.collapsed) {
|
22098 | const node = getSelectedNode(range);
|
22099 | if (isElement(node)) {
|
22100 | return showCaret(direction, editor, node, direction === HDirection.Backwards, false);
|
22101 | } else if (isCefAtEdgeSelected(editor)) {
|
22102 | const newRange = range.cloneRange();
|
22103 | newRange.collapse(direction === HDirection.Backwards);
|
22104 | return Optional.from(newRange);
|
22105 | }
|
22106 | }
|
22107 | const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
22108 | if (isBeforeFn(caretPosition)) {
|
22109 | return selectNode(editor, caretPosition.getNode(!forwards));
|
22110 | }
|
22111 | let nextCaretPosition = getNextPosFn(caretPosition);
|
22112 | const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
|
22113 | if (!nextCaretPosition) {
|
22114 | return rangeIsInContainerBlock ? Optional.some(range) : Optional.none();
|
22115 | } else {
|
22116 | nextCaretPosition = normalizePosition(forwards, nextCaretPosition);
|
22117 | }
|
22118 | if (isBeforeFn(nextCaretPosition)) {
|
22119 | return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
|
22120 | }
|
22121 | const peekCaretPosition = getNextPosFn(nextCaretPosition);
|
22122 | if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
|
22123 | if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
|
22124 | return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
|
22125 | }
|
22126 | }
|
22127 | if (rangeIsInContainerBlock) {
|
22128 | return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
|
22129 | }
|
22130 | return Optional.none();
|
22131 | };
|
22132 | const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => {
|
22133 | const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
22134 | const caretClientRect = last$1(caretPosition.getClientRects());
|
22135 | const forwards = direction === VDirection.Down;
|
22136 | const root = editor.getBody();
|
22137 | if (!caretClientRect) {
|
22138 | return Optional.none();
|
22139 | }
|
22140 | if (isCefAtEdgeSelected(editor)) {
|
22141 | const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range);
|
22142 | const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
|
22143 | return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange());
|
22144 | }
|
22145 | const walkerFn = forwards ? downUntil : upUntil;
|
22146 | const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
|
22147 | const nextLinePositions = filter$5(linePositions, isLine(1));
|
22148 | const clientX = caretClientRect.left;
|
22149 | const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
|
22150 | if (nextLineRect && isElement(nextLineRect.node)) {
|
22151 | const dist1 = Math.abs(clientX - nextLineRect.left);
|
22152 | const dist2 = Math.abs(clientX - nextLineRect.right);
|
22153 | return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
|
22154 | }
|
22155 | let currentNode;
|
22156 | if (isBefore(caretPosition)) {
|
22157 | currentNode = caretPosition.getNode();
|
22158 | } else if (isAfter(caretPosition)) {
|
22159 | currentNode = caretPosition.getNode(true);
|
22160 | } else {
|
22161 | currentNode = getSelectedNode(range);
|
22162 | }
|
22163 | if (currentNode) {
|
22164 | const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
|
22165 | let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX);
|
22166 | if (closestNextLineRect) {
|
22167 | return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
|
22168 | }
|
22169 | closestNextLineRect = last$1(filter$5(caretPositions, isLine(0)));
|
22170 | if (closestNextLineRect) {
|
22171 | return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
|
22172 | }
|
22173 | }
|
22174 | if (nextLinePositions.length === 0) {
|
22175 | return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false));
|
22176 | }
|
22177 | return Optional.none();
|
22178 | };
|
22179 | const getLineEndPoint = (editor, forward) => {
|
22180 | const rng = editor.selection.getRng();
|
22181 | const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
|
22182 | const host = getEditingHost(from.container(), editor.getBody());
|
22183 | if (forward) {
|
22184 | const lineInfo = getPositionsUntilNextLine(host, from);
|
22185 | return last$2(lineInfo.positions);
|
22186 | } else {
|
22187 | const lineInfo = getPositionsUntilPreviousLine(host, from);
|
22188 | return head(lineInfo.positions);
|
22189 | }
|
22190 | };
|
22191 | const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => {
|
22192 | editor.selection.setRng(pos.toRange());
|
22193 | return true;
|
22194 | });
|
22195 |
|
22196 | const setCaretPosition = (editor, pos) => {
|
22197 | const rng = editor.dom.createRng();
|
22198 | rng.setStart(pos.container(), pos.offset());
|
22199 | rng.setEnd(pos.container(), pos.offset());
|
22200 | editor.selection.setRng(rng);
|
22201 | };
|
22202 | const setSelected = (state, elm) => {
|
22203 | if (state) {
|
22204 | elm.setAttribute('data-mce-selected', 'inline-boundary');
|
22205 | } else {
|
22206 | elm.removeAttribute('data-mce-selected');
|
22207 | }
|
22208 | };
|
22209 | const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => {
|
22210 | setCaretPosition(editor, pos);
|
22211 | return location;
|
22212 | });
|
22213 | const getPositionFromRange = (range, root, forward) => {
|
22214 | const start = CaretPosition.fromRangeStart(range);
|
22215 | if (range.collapsed) {
|
22216 | return start;
|
22217 | } else {
|
22218 | const end = CaretPosition.fromRangeEnd(range);
|
22219 | return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start);
|
22220 | }
|
22221 | };
|
22222 | const findLocation = (editor, caret, forward) => {
|
22223 | const rootNode = editor.getBody();
|
22224 | const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
|
22225 | const isInlineTarget$1 = curry(isInlineTarget, editor);
|
22226 | const location = findLocation$1(forward, isInlineTarget$1, rootNode, from);
|
22227 | return location.bind(location => renderCaretLocation(editor, caret, location));
|
22228 | };
|
22229 | const toggleInlines = (isInlineTarget, dom, elms) => {
|
22230 | const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom);
|
22231 | const selectedInlines = filter$5(inlineBoundaries, isInlineTarget);
|
22232 | const targetInlines = filter$5(elms, isInlineTarget);
|
22233 | each$e(difference(selectedInlines, targetInlines), curry(setSelected, false));
|
22234 | each$e(difference(targetInlines, selectedInlines), curry(setSelected, true));
|
22235 | };
|
22236 | const safeRemoveCaretContainer = (editor, caret) => {
|
22237 | const caretValue = caret.get();
|
22238 | if (editor.selection.isCollapsed() && !editor.composing && caretValue) {
|
22239 | const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
22240 | if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) {
|
22241 | setCaretPosition(editor, removeAndReposition(caretValue, pos));
|
22242 | caret.set(null);
|
22243 | }
|
22244 | }
|
22245 | };
|
22246 | const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => {
|
22247 | if (editor.selection.isCollapsed()) {
|
22248 | const inlines = filter$5(elms, isInlineTarget);
|
22249 | each$e(inlines, _inline => {
|
22250 | const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
22251 | readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location));
|
22252 | });
|
22253 | }
|
22254 | };
|
22255 | const move$3 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
|
22256 | const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
|
22257 | const setupSelectedState = editor => {
|
22258 | const caret = Cell(null);
|
22259 | const isInlineTarget$1 = curry(isInlineTarget, editor);
|
22260 | editor.on('NodeChange', e => {
|
22261 | if (isInlineBoundariesEnabled(editor)) {
|
22262 | toggleInlines(isInlineTarget$1, editor.dom, e.parents);
|
22263 | safeRemoveCaretContainer(editor, caret);
|
22264 | renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
|
22265 | }
|
22266 | });
|
22267 | return caret;
|
22268 | };
|
22269 | const moveNextWord = curry(moveWord, true);
|
22270 | const movePrevWord = curry(moveWord, false);
|
22271 | const moveToLineEndPoint$2 = (editor, forward, caret) => {
|
22272 | if (isInlineBoundariesEnabled(editor)) {
|
22273 | const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
|
22274 | const rng = editor.selection.getRng();
|
22275 | return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
|
22276 | });
|
22277 | return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => {
|
22278 | const outsideLoc = outside(loc);
|
22279 | return renderCaret(caret, outsideLoc).exists(pos => {
|
22280 | setCaretPosition(editor, pos);
|
22281 | return true;
|
22282 | });
|
22283 | });
|
22284 | } else {
|
22285 | return false;
|
22286 | }
|
22287 | };
|
22288 |
|
22289 | const rangeFromPositions = (from, to) => {
|
22290 | const range = document.createRange();
|
22291 | range.setStart(from.container(), from.offset());
|
22292 | range.setEnd(to.container(), to.offset());
|
22293 | return range;
|
22294 | };
|
22295 | const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
|
22296 | const normalizedFirstPos = normalizePosition(true, firstPos);
|
22297 | const normalizedLastPos = normalizePosition(false, lastPos);
|
22298 | return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos));
|
22299 | }).getOr(true);
|
22300 | const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos));
|
22301 | const deleteFromTo = (editor, caret, from, to) => {
|
22302 | const rootNode = editor.getBody();
|
22303 | const isInlineTarget$1 = curry(isInlineTarget, editor);
|
22304 | editor.undoManager.ignore(() => {
|
22305 | editor.selection.setRng(rangeFromPositions(from, to));
|
22306 | execNativeDeleteCommand(editor);
|
22307 | readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
|
22308 | });
|
22309 | editor.nodeChanged();
|
22310 | };
|
22311 | const rescope = (rootNode, node) => {
|
22312 | const parentBlock = getParentBlock$3(node, rootNode);
|
22313 | return parentBlock ? parentBlock : rootNode;
|
22314 | };
|
22315 | const backspaceDeleteCollapsed = (editor, caret, forward, from) => {
|
22316 | const rootNode = rescope(editor.getBody(), from.container());
|
22317 | const isInlineTarget$1 = curry(isInlineTarget, editor);
|
22318 | const fromLocation = readLocation(isInlineTarget$1, rootNode, from);
|
22319 | const location = fromLocation.bind(location => {
|
22320 | if (forward) {
|
22321 | return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none);
|
22322 | } else {
|
22323 | return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location))));
|
22324 | }
|
22325 | });
|
22326 | return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
|
22327 | const toPosition = navigate(forward, rootNode, from);
|
22328 | const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos));
|
22329 | return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => {
|
22330 | if (hasOnlyTwoOrLessPositionsLeft(elm)) {
|
22331 | return Optional.some(() => {
|
22332 | deleteElement$2(editor, forward, SugarElement.fromDom(elm));
|
22333 | });
|
22334 | } else {
|
22335 | return Optional.none();
|
22336 | }
|
22337 | })).getOrThunk(() => toLocation.bind(() => toPosition.map(to => {
|
22338 | return () => {
|
22339 | if (forward) {
|
22340 | deleteFromTo(editor, caret, from, to);
|
22341 | } else {
|
22342 | deleteFromTo(editor, caret, to, from);
|
22343 | }
|
22344 | };
|
22345 | })));
|
22346 | });
|
22347 | };
|
22348 | const backspaceDelete$4 = (editor, caret, forward) => {
|
22349 | if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
|
22350 | const from = CaretPosition.fromRangeStart(editor.selection.getRng());
|
22351 | return backspaceDeleteCollapsed(editor, caret, forward, from);
|
22352 | }
|
22353 | return Optional.none();
|
22354 | };
|
22355 |
|
22356 | const hasMultipleChildren = elm => childNodesCount(elm) > 1;
|
22357 | const getParentsUntil = (editor, pred) => {
|
22358 | const rootElm = SugarElement.fromDom(editor.getBody());
|
22359 | const startElm = SugarElement.fromDom(editor.selection.getStart());
|
22360 | const parents = parentsAndSelf(startElm, rootElm);
|
22361 | return findIndex$2(parents, pred).fold(constant(parents), index => parents.slice(0, index));
|
22362 | };
|
22363 | const hasOnlyOneChild = elm => childNodesCount(elm) === 1;
|
22364 | const getParentInlinesUntilMultichildInline = editor => getParentsUntil(editor, elm => editor.schema.isBlock(name(elm)) || hasMultipleChildren(elm));
|
22365 | const getParentInlines = editor => getParentsUntil(editor, el => editor.schema.isBlock(name(el)));
|
22366 | const getFormatNodes = (editor, parentInlines) => {
|
22367 | const isFormatElement$1 = curry(isFormatElement, editor);
|
22368 | return bind$3(parentInlines, elm => isFormatElement$1(elm) ? [elm.dom] : []);
|
22369 | };
|
22370 | const getFormatNodesAtStart = editor => {
|
22371 | const parentInlines = getParentInlines(editor);
|
22372 | return getFormatNodes(editor, parentInlines);
|
22373 | };
|
22374 | const deleteLastPosition = (forward, editor, target, parentInlines) => {
|
22375 | const formatNodes = getFormatNodes(editor, parentInlines);
|
22376 | if (formatNodes.length === 0) {
|
22377 | deleteElement$2(editor, forward, target);
|
22378 | } else {
|
22379 | const pos = replaceWithCaretFormat(target.dom, formatNodes);
|
22380 | editor.selection.setRng(pos.toRange());
|
22381 | }
|
22382 | };
|
22383 | const deleteCaret$1 = (editor, forward) => {
|
22384 | const parentInlines = filter$5(getParentInlinesUntilMultichildInline(editor), hasOnlyOneChild);
|
22385 | return last$2(parentInlines).bind(target => {
|
22386 | const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
22387 | if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
|
22388 | return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
|
22389 | } else {
|
22390 | return Optional.none();
|
22391 | }
|
22392 | });
|
22393 | };
|
22394 | const isBrInEmptyElement = (editor, elm) => {
|
22395 | const parentElm = elm.parentElement;
|
22396 | return isBr$6(elm) && !isNull(parentElm) && editor.dom.isEmpty(parentElm);
|
22397 | };
|
22398 | const isEmptyCaret = elm => isEmptyCaretFormatElement(SugarElement.fromDom(elm));
|
22399 | const createCaretFormatAtStart = (editor, formatNodes) => {
|
22400 | const startElm = editor.selection.getStart();
|
22401 | const pos = isBrInEmptyElement(editor, startElm) || isEmptyCaret(startElm) ? replaceWithCaretFormat(startElm, formatNodes) : createCaretFormatAtStart$1(editor.selection.getRng(), formatNodes);
|
22402 | editor.selection.setRng(pos.toRange());
|
22403 | };
|
22404 | const updateCaretFormat = (editor, updateFormats) => {
|
22405 | const missingFormats = difference(updateFormats, getFormatNodesAtStart(editor));
|
22406 | if (missingFormats.length > 0) {
|
22407 | createCaretFormatAtStart(editor, missingFormats);
|
22408 | }
|
22409 | };
|
22410 | const rangeStartsAtTextContainer = rng => isText$b(rng.startContainer);
|
22411 | const rangeStartsAtStartOfTextContainer = rng => rng.startOffset === 0 && rangeStartsAtTextContainer(rng);
|
22412 | const rangeStartParentIsFormatElement = (editor, rng) => {
|
22413 | const startParent = rng.startContainer.parentElement;
|
22414 | return !isNull(startParent) && isFormatElement(editor, SugarElement.fromDom(startParent));
|
22415 | };
|
22416 | const rangeStartAndEndHaveSameParent = rng => {
|
22417 | const startParent = rng.startContainer.parentNode;
|
22418 | const endParent = rng.endContainer.parentNode;
|
22419 | return !isNull(startParent) && !isNull(endParent) && startParent.isEqualNode(endParent);
|
22420 | };
|
22421 | const rangeEndsAtEndOfEndContainer = rng => {
|
22422 | const endContainer = rng.endContainer;
|
22423 | return rng.endOffset === (isText$b(endContainer) ? endContainer.length : endContainer.childNodes.length);
|
22424 | };
|
22425 | const rangeEndsAtEndOfStartContainer = rng => rangeStartAndEndHaveSameParent(rng) && rangeEndsAtEndOfEndContainer(rng);
|
22426 | const rangeEndsAfterEndOfStartContainer = rng => !rng.endContainer.isEqualNode(rng.commonAncestorContainer);
|
22427 | const rangeEndsAtOrAfterEndOfStartContainer = rng => rangeEndsAtEndOfStartContainer(rng) || rangeEndsAfterEndOfStartContainer(rng);
|
22428 | const requiresDeleteRangeOverride = editor => {
|
22429 | const rng = editor.selection.getRng();
|
22430 | return rangeStartsAtStartOfTextContainer(rng) && rangeStartParentIsFormatElement(editor, rng) && rangeEndsAtOrAfterEndOfStartContainer(rng);
|
22431 | };
|
22432 | const deleteRange$1 = editor => {
|
22433 | if (requiresDeleteRangeOverride(editor)) {
|
22434 | const formatNodes = getFormatNodesAtStart(editor);
|
22435 | return Optional.some(() => {
|
22436 | execNativeDeleteCommand(editor);
|
22437 | updateCaretFormat(editor, formatNodes);
|
22438 | });
|
22439 | } else {
|
22440 | return Optional.none();
|
22441 | }
|
22442 | };
|
22443 | const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : deleteRange$1(editor);
|
22444 | const hasAncestorInlineCaret = (elm, schema) => ancestor$2(elm, node => isCaretNode(node.dom), el => schema.isBlock(name(el)));
|
22445 | const hasAncestorInlineCaretAtStart = editor => hasAncestorInlineCaret(SugarElement.fromDom(editor.selection.getStart()), editor.schema);
|
22446 | const requiresRefreshCaretOverride = editor => {
|
22447 | const rng = editor.selection.getRng();
|
22448 | return rng.collapsed && (rangeStartsAtTextContainer(rng) || editor.dom.isEmpty(rng.startContainer)) && !hasAncestorInlineCaretAtStart(editor);
|
22449 | };
|
22450 | const refreshCaret = editor => {
|
22451 | if (requiresRefreshCaretOverride(editor)) {
|
22452 | createCaretFormatAtStart(editor, []);
|
22453 | }
|
22454 | return true;
|
22455 | };
|
22456 |
|
22457 | const deleteElement = (editor, forward, element) => {
|
22458 | if (isNonNullable(element)) {
|
22459 | return Optional.some(() => {
|
22460 | editor._selectionOverrides.hideFakeCaret();
|
22461 | deleteElement$2(editor, forward, SugarElement.fromDom(element));
|
22462 | });
|
22463 | } else {
|
22464 | return Optional.none();
|
22465 | }
|
22466 | };
|
22467 | const deleteCaret = (editor, forward) => {
|
22468 | const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
|
22469 | const direction = forward ? HDirection.Forwards : HDirection.Backwards;
|
22470 | const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
|
22471 | if (isNearMedia(fromPos)) {
|
22472 | return deleteElement(editor, forward, fromPos.getNode(!forward));
|
22473 | } else {
|
22474 | return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward)));
|
22475 | }
|
22476 | };
|
22477 | const deleteRange = (editor, forward) => {
|
22478 | const selectedNode = editor.selection.getNode();
|
22479 | return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
|
22480 | };
|
22481 | const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
|
22482 |
|
22483 | const isEditable = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$b(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom));
|
22484 | const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0);
|
22485 | const getIndentStyleName = (useMargin, element) => {
|
22486 | const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
|
22487 | const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left';
|
22488 | return indentStyleName + suffix;
|
22489 | };
|
22490 | const indentElement = (dom, command, useMargin, value, unit, element) => {
|
22491 | const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
|
22492 | const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName));
|
22493 | if (command === 'outdent') {
|
22494 | const styleValue = Math.max(0, parsedValue - value);
|
22495 | dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
|
22496 | } else {
|
22497 | const styleValue = parsedValue + value + unit;
|
22498 | dom.setStyle(element, indentStyleName, styleValue);
|
22499 | }
|
22500 | };
|
22501 | const validateBlocks = (editor, blocks) => forall(blocks, block => {
|
22502 | const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
|
22503 | const intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0);
|
22504 | const contentEditable = editor.dom.getContentEditable(block.dom);
|
22505 | return contentEditable !== 'false' && intentValue > 0;
|
22506 | });
|
22507 | const canOutdent = editor => {
|
22508 | const blocks = getBlocksToIndent(editor);
|
22509 | return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks));
|
22510 | };
|
22511 | const isListComponent = el => isList(el) || isListItem$1(el);
|
22512 | const parentIsListComponent = el => parent(el).exists(isListComponent);
|
22513 | const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el));
|
22514 | const handle = (editor, command) => {
|
22515 | var _a, _b;
|
22516 | const {dom} = editor;
|
22517 | const indentation = getIndentation(editor);
|
22518 | const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
|
22519 | const indentValue = parseIndentValue(indentation);
|
22520 | const useMargin = shouldIndentUseMargin(editor);
|
22521 | each$e(getBlocksToIndent(editor), block => {
|
22522 | indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom);
|
22523 | });
|
22524 | };
|
22525 | const indent = editor => handle(editor, 'indent');
|
22526 | const outdent = editor => handle(editor, 'outdent');
|
22527 |
|
22528 | const backspaceDelete$1 = editor => {
|
22529 | if (editor.selection.isCollapsed() && canOutdent(editor)) {
|
22530 | const dom = editor.dom;
|
22531 | const rng = editor.selection.getRng();
|
22532 | const pos = CaretPosition.fromRangeStart(rng);
|
22533 | const block = dom.getParent(rng.startContainer, dom.isBlock);
|
22534 | if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos, editor.schema)) {
|
22535 | return Optional.some(() => outdent(editor));
|
22536 | }
|
22537 | }
|
22538 | return Optional.none();
|
22539 | };
|
22540 |
|
22541 | const findAction = (editor, caret, forward) => findMap([
|
22542 | backspaceDelete$1,
|
22543 | backspaceDelete$6,
|
22544 | backspaceDelete$7,
|
22545 | (editor, forward) => backspaceDelete$4(editor, caret, forward),
|
22546 | backspaceDelete$9,
|
22547 | backspaceDelete$a,
|
22548 | backspaceDelete$5,
|
22549 | backspaceDelete$2,
|
22550 | backspaceDelete$8,
|
22551 | backspaceDelete$3
|
22552 | ], item => item(editor, forward)).filter(_ => editor.selection.isEditable());
|
22553 | const deleteCommand = (editor, caret) => {
|
22554 | const result = findAction(editor, caret, false);
|
22555 | result.fold(() => {
|
22556 | if (editor.selection.isEditable()) {
|
22557 | execNativeDeleteCommand(editor);
|
22558 | paddEmptyBody(editor);
|
22559 | }
|
22560 | }, call);
|
22561 | };
|
22562 | const forwardDeleteCommand = (editor, caret) => {
|
22563 | const result = findAction(editor, caret, true);
|
22564 | result.fold(() => {
|
22565 | if (editor.selection.isEditable()) {
|
22566 | execNativeForwardDeleteCommand(editor);
|
22567 | }
|
22568 | }, call);
|
22569 | };
|
22570 | const setup$q = (editor, caret) => {
|
22571 | editor.addCommand('delete', () => {
|
22572 | deleteCommand(editor, caret);
|
22573 | });
|
22574 | editor.addCommand('forwardDelete', () => {
|
22575 | forwardDeleteCommand(editor, caret);
|
22576 | });
|
22577 | };
|
22578 |
|
22579 | const SIGNIFICANT_MOVE = 5;
|
22580 | const LONGPRESS_DELAY = 400;
|
22581 | const getTouch = event => {
|
22582 | if (event.touches === undefined || event.touches.length !== 1) {
|
22583 | return Optional.none();
|
22584 | }
|
22585 | return Optional.some(event.touches[0]);
|
22586 | };
|
22587 | const isFarEnough = (touch, data) => {
|
22588 | const distX = Math.abs(touch.clientX - data.x);
|
22589 | const distY = Math.abs(touch.clientY - data.y);
|
22590 | return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
|
22591 | };
|
22592 | const setup$p = editor => {
|
22593 | const startData = value$2();
|
22594 | const longpressFired = Cell(false);
|
22595 | const debounceLongpress = last(e => {
|
22596 | editor.dispatch('longpress', {
|
22597 | ...e,
|
22598 | type: 'longpress'
|
22599 | });
|
22600 | longpressFired.set(true);
|
22601 | }, LONGPRESS_DELAY);
|
22602 | editor.on('touchstart', e => {
|
22603 | getTouch(e).each(touch => {
|
22604 | debounceLongpress.cancel();
|
22605 | const data = {
|
22606 | x: touch.clientX,
|
22607 | y: touch.clientY,
|
22608 | target: e.target
|
22609 | };
|
22610 | debounceLongpress.throttle(e);
|
22611 | longpressFired.set(false);
|
22612 | startData.set(data);
|
22613 | });
|
22614 | }, true);
|
22615 | editor.on('touchmove', e => {
|
22616 | debounceLongpress.cancel();
|
22617 | getTouch(e).each(touch => {
|
22618 | startData.on(data => {
|
22619 | if (isFarEnough(touch, data)) {
|
22620 | startData.clear();
|
22621 | longpressFired.set(false);
|
22622 | editor.dispatch('longpresscancel');
|
22623 | }
|
22624 | });
|
22625 | });
|
22626 | }, true);
|
22627 | editor.on('touchend touchcancel', e => {
|
22628 | debounceLongpress.cancel();
|
22629 | if (e.type === 'touchcancel') {
|
22630 | return;
|
22631 | }
|
22632 | startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => {
|
22633 | if (longpressFired.get()) {
|
22634 | e.preventDefault();
|
22635 | } else {
|
22636 | editor.dispatch('tap', {
|
22637 | ...e,
|
22638 | type: 'tap'
|
22639 | });
|
22640 | }
|
22641 | });
|
22642 | }, true);
|
22643 | };
|
22644 |
|
22645 | const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
|
22646 | const isValidTarget = (schema, node) => {
|
22647 | if (isText$b(node)) {
|
22648 | return true;
|
22649 | } else if (isElement$6(node)) {
|
22650 | return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node) && !isNonHtmlElementRoot(node);
|
22651 | } else {
|
22652 | return false;
|
22653 | }
|
22654 | };
|
22655 | const hasBlockParent = (blockElements, root, node) => {
|
22656 | return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => {
|
22657 | return isBlockElement(blockElements, elm.dom);
|
22658 | });
|
22659 | };
|
22660 | const shouldRemoveTextNode = (blockElements, node) => {
|
22661 | if (isText$b(node)) {
|
22662 | if (node.data.length === 0) {
|
22663 | return true;
|
22664 | } else if (/^\s+$/.test(node.data)) {
|
22665 | return !node.nextSibling || isBlockElement(blockElements, node.nextSibling) || isNonHtmlElementRoot(node.nextSibling);
|
22666 | }
|
22667 | }
|
22668 | return false;
|
22669 | };
|
22670 | const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
|
22671 | const addRootBlocks = editor => {
|
22672 | const dom = editor.dom, selection = editor.selection;
|
22673 | const schema = editor.schema;
|
22674 | const blockElements = schema.getBlockElements();
|
22675 | const startNode = selection.getStart();
|
22676 | const rootNode = editor.getBody();
|
22677 | let rootBlockNode;
|
22678 | let tempNode;
|
22679 | let wrapped = false;
|
22680 | const forcedRootBlock = getForcedRootBlock(editor);
|
22681 | if (!startNode || !isElement$6(startNode)) {
|
22682 | return;
|
22683 | }
|
22684 | const rootNodeName = rootNode.nodeName.toLowerCase();
|
22685 | if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) {
|
22686 | return;
|
22687 | }
|
22688 | const rng = selection.getRng();
|
22689 | const {startContainer, startOffset, endContainer, endOffset} = rng;
|
22690 | const restoreSelection = hasFocus(editor);
|
22691 | let node = rootNode.firstChild;
|
22692 | while (node) {
|
22693 | if (isElement$6(node)) {
|
22694 | updateElement(schema, node);
|
22695 | }
|
22696 | if (isValidTarget(schema, node)) {
|
22697 | if (shouldRemoveTextNode(blockElements, node)) {
|
22698 | tempNode = node;
|
22699 | node = node.nextSibling;
|
22700 | dom.remove(tempNode);
|
22701 | continue;
|
22702 | }
|
22703 | if (!rootBlockNode) {
|
22704 | rootBlockNode = createRootBlock(editor);
|
22705 | rootNode.insertBefore(rootBlockNode, node);
|
22706 | wrapped = true;
|
22707 | }
|
22708 | tempNode = node;
|
22709 | node = node.nextSibling;
|
22710 | rootBlockNode.appendChild(tempNode);
|
22711 | } else {
|
22712 | rootBlockNode = null;
|
22713 | node = node.nextSibling;
|
22714 | }
|
22715 | }
|
22716 | if (wrapped && restoreSelection) {
|
22717 | rng.setStart(startContainer, startOffset);
|
22718 | rng.setEnd(endContainer, endOffset);
|
22719 | selection.setRng(rng);
|
22720 | editor.nodeChanged();
|
22721 | }
|
22722 | };
|
22723 | const insertEmptyLine = (editor, root, insertBlock) => {
|
22724 | const block = SugarElement.fromDom(createRootBlock(editor));
|
22725 | const br = createPaddingBr();
|
22726 | append$1(block, br);
|
22727 | insertBlock(root, block);
|
22728 | const rng = document.createRange();
|
22729 | rng.setStartBefore(br.dom);
|
22730 | rng.setEndBefore(br.dom);
|
22731 | return rng;
|
22732 | };
|
22733 | const setup$o = editor => {
|
22734 | editor.on('NodeChange', curry(addRootBlocks, editor));
|
22735 | };
|
22736 |
|
22737 | const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1;
|
22738 | const replaceMatchWithSpan = (editor, content, cls) => {
|
22739 | return function (match) {
|
22740 | const args = arguments, index = args[args.length - 2];
|
22741 | const prevChar = index > 0 ? content.charAt(index - 1) : '';
|
22742 | if (prevChar === '"') {
|
22743 | return match;
|
22744 | }
|
22745 | if (prevChar === '>') {
|
22746 | const findStartTagIndex = content.lastIndexOf('<', index);
|
22747 | if (findStartTagIndex !== -1) {
|
22748 | const tagHtml = content.substring(findStartTagIndex, index);
|
22749 | if (tagHtml.indexOf('contenteditable="false"') !== -1) {
|
22750 | return match;
|
22751 | }
|
22752 | }
|
22753 | }
|
22754 | return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '</span>';
|
22755 | };
|
22756 | };
|
22757 | const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
|
22758 | let i = nonEditableRegExps.length, content = e.content;
|
22759 | if (e.format === 'raw') {
|
22760 | return;
|
22761 | }
|
22762 | while (i--) {
|
22763 | content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
|
22764 | }
|
22765 | e.content = content;
|
22766 | };
|
22767 | const setup$n = editor => {
|
22768 | const contentEditableAttrName = 'contenteditable';
|
22769 | const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' ';
|
22770 | const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' ';
|
22771 | const hasEditClass = hasClass(editClass);
|
22772 | const hasNonEditClass = hasClass(nonEditClass);
|
22773 | const nonEditableRegExps = getNonEditableRegExps(editor);
|
22774 | if (nonEditableRegExps.length > 0) {
|
22775 | editor.on('BeforeSetContent', e => {
|
22776 | convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
|
22777 | });
|
22778 | }
|
22779 | editor.parser.addAttributeFilter('class', nodes => {
|
22780 | let i = nodes.length;
|
22781 | while (i--) {
|
22782 | const node = nodes[i];
|
22783 | if (hasEditClass(node)) {
|
22784 | node.attr(contentEditableAttrName, 'true');
|
22785 | } else if (hasNonEditClass(node)) {
|
22786 | node.attr(contentEditableAttrName, 'false');
|
22787 | }
|
22788 | }
|
22789 | });
|
22790 | editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => {
|
22791 | let i = nodes.length;
|
22792 | while (i--) {
|
22793 | const node = nodes[i];
|
22794 | if (!hasEditClass(node) && !hasNonEditClass(node)) {
|
22795 | continue;
|
22796 | }
|
22797 | if (nonEditableRegExps.length > 0 && node.attr('data-mce-content')) {
|
22798 | node.name = '#text';
|
22799 | node.type = 3;
|
22800 | node.raw = true;
|
22801 | node.value = node.attr('data-mce-content');
|
22802 | } else {
|
22803 | node.attr(contentEditableAttrName, null);
|
22804 | }
|
22805 | }
|
22806 | });
|
22807 | };
|
22808 |
|
22809 | const findBlockCaretContainer = editor => descendant$1(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull();
|
22810 | const showBlockCaretContainer = (editor, blockCaretContainer) => {
|
22811 | if (blockCaretContainer.hasAttribute('data-mce-caret')) {
|
22812 | showCaretContainerBlock(blockCaretContainer);
|
22813 | editor.selection.setRng(editor.selection.getRng());
|
22814 | editor.selection.scrollIntoView(blockCaretContainer);
|
22815 | }
|
22816 | };
|
22817 | const handleBlockContainer = (editor, e) => {
|
22818 | const blockCaretContainer = findBlockCaretContainer(editor);
|
22819 | if (!blockCaretContainer) {
|
22820 | return;
|
22821 | }
|
22822 | if (e.type === 'compositionstart') {
|
22823 | e.preventDefault();
|
22824 | e.stopPropagation();
|
22825 | showBlockCaretContainer(editor, blockCaretContainer);
|
22826 | return;
|
22827 | }
|
22828 | if (hasContent(blockCaretContainer)) {
|
22829 | showBlockCaretContainer(editor, blockCaretContainer);
|
22830 | editor.undoManager.add();
|
22831 | }
|
22832 | };
|
22833 | const setup$m = editor => {
|
22834 | editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
|
22835 | };
|
22836 |
|
22837 | const isContentEditableFalse$4 = isContentEditableFalse$b;
|
22838 | const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$4);
|
22839 | const moveToCeFalseVertically = (direction, editor, range) => {
|
22840 | const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
|
22841 | const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
|
22842 | return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$4);
|
22843 | };
|
22844 | const createTextBlock = editor => {
|
22845 | const textBlock = editor.dom.create(getForcedRootBlock(editor));
|
22846 | textBlock.innerHTML = '<br data-mce-bogus="1">';
|
22847 | return textBlock;
|
22848 | };
|
22849 | const exitPreBlock = (editor, direction, range) => {
|
22850 | const caretWalker = CaretWalker(editor.getBody());
|
22851 | const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
|
22852 | if (range.collapsed) {
|
22853 | const pre = editor.dom.getParent(range.startContainer, 'PRE');
|
22854 | if (!pre) {
|
22855 | return;
|
22856 | }
|
22857 | const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range));
|
22858 | if (!caretPos) {
|
22859 | const newBlock = SugarElement.fromDom(createTextBlock(editor));
|
22860 | if (direction === 1) {
|
22861 | after$4(SugarElement.fromDom(pre), newBlock);
|
22862 | } else {
|
22863 | before$3(SugarElement.fromDom(pre), newBlock);
|
22864 | }
|
22865 | editor.selection.select(newBlock.dom, true);
|
22866 | editor.selection.collapse();
|
22867 | }
|
22868 | }
|
22869 | };
|
22870 | const getHorizontalRange = (editor, forward) => {
|
22871 | const direction = forward ? HDirection.Forwards : HDirection.Backwards;
|
22872 | const range = editor.selection.getRng();
|
22873 | return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => {
|
22874 | exitPreBlock(editor, direction, range);
|
22875 | return Optional.none();
|
22876 | });
|
22877 | };
|
22878 | const getVerticalRange = (editor, down) => {
|
22879 | const direction = down ? 1 : -1;
|
22880 | const range = editor.selection.getRng();
|
22881 | return moveToCeFalseVertically(direction, editor, range).orThunk(() => {
|
22882 | exitPreBlock(editor, direction, range);
|
22883 | return Optional.none();
|
22884 | });
|
22885 | };
|
22886 | const flipDirection = (selection, forward) => {
|
22887 | const elm = forward ? selection.getEnd(true) : selection.getStart(true);
|
22888 | return isRtl(elm) ? !forward : forward;
|
22889 | };
|
22890 | const moveH$2 = (editor, forward) => getHorizontalRange(editor, flipDirection(editor.selection, forward)).exists(newRange => {
|
22891 | moveToRange(editor, newRange);
|
22892 | return true;
|
22893 | });
|
22894 | const moveV$4 = (editor, down) => getVerticalRange(editor, down).exists(newRange => {
|
22895 | moveToRange(editor, newRange);
|
22896 | return true;
|
22897 | });
|
22898 | const moveToLineEndPoint$1 = (editor, forward) => {
|
22899 | const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
|
22900 | return moveToLineEndPoint$3(editor, forward, isCefPosition);
|
22901 | };
|
22902 | const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => {
|
22903 | const rng = pos.toRange();
|
22904 | const curRng = editor.selection.getRng();
|
22905 | if (forward) {
|
22906 | rng.setStart(curRng.startContainer, curRng.startOffset);
|
22907 | } else {
|
22908 | rng.setEnd(curRng.endContainer, curRng.endOffset);
|
22909 | }
|
22910 | return rng;
|
22911 | }).exists(rng => {
|
22912 | moveToRange(editor, rng);
|
22913 | return true;
|
22914 | });
|
22915 |
|
22916 | const isTarget = node => contains$2(['figcaption'], name(node));
|
22917 | const getClosestTargetBlock = (pos, root, schema) => {
|
22918 | const isRoot = curry(eq, root);
|
22919 | return closest$4(SugarElement.fromDom(pos.container()), el => schema.isBlock(name(el)), isRoot).filter(isTarget);
|
22920 | };
|
22921 | const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
|
22922 | const moveCaretToNewEmptyLine = (editor, forward) => {
|
22923 | const root = SugarElement.fromDom(editor.getBody());
|
22924 | const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
22925 | return getClosestTargetBlock(pos, root, editor.schema).exists(() => {
|
22926 | if (isAtFirstOrLastLine(root, forward, pos)) {
|
22927 | const insertFn = forward ? append$1 : prepend;
|
22928 | const rng = insertEmptyLine(editor, root, insertFn);
|
22929 | editor.selection.setRng(rng);
|
22930 | return true;
|
22931 | } else {
|
22932 | return false;
|
22933 | }
|
22934 | });
|
22935 | };
|
22936 | const moveV$3 = (editor, forward) => {
|
22937 | if (editor.selection.isCollapsed()) {
|
22938 | return moveCaretToNewEmptyLine(editor, forward);
|
22939 | } else {
|
22940 | return false;
|
22941 | }
|
22942 | };
|
22943 |
|
22944 | const moveUp = (editor, details, summary) => {
|
22945 | const rng = editor.selection.getRng();
|
22946 | const pos = CaretPosition.fromRangeStart(rng);
|
22947 | const root = editor.getBody();
|
22948 | if (root.firstChild === details && isAtFirstLine(summary, pos)) {
|
22949 | editor.execCommand('InsertNewBlockBefore');
|
22950 | return true;
|
22951 | } else {
|
22952 | return false;
|
22953 | }
|
22954 | };
|
22955 | const moveDown = (editor, details) => {
|
22956 | const rng = editor.selection.getRng();
|
22957 | const pos = CaretPosition.fromRangeStart(rng);
|
22958 | const root = editor.getBody();
|
22959 | if (root.lastChild === details && isAtLastLine(details, pos)) {
|
22960 | editor.execCommand('InsertNewBlockAfter');
|
22961 | return true;
|
22962 | } else {
|
22963 | return false;
|
22964 | }
|
22965 | };
|
22966 | const move$2 = (editor, forward) => {
|
22967 | if (forward) {
|
22968 | return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'details')).map(details => moveDown(editor, details)).getOr(false);
|
22969 | } else {
|
22970 | return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'summary')).bind(summary => Optional.from(editor.dom.getParent(summary, 'details')).map(details => moveUp(editor, details, summary))).getOr(false);
|
22971 | }
|
22972 | };
|
22973 | const moveV$2 = (editor, forward) => move$2(editor, forward);
|
22974 |
|
22975 | const baseKeyPattern = {
|
22976 | shiftKey: false,
|
22977 | altKey: false,
|
22978 | ctrlKey: false,
|
22979 | metaKey: false,
|
22980 | keyCode: 0
|
22981 | };
|
22982 | const defaultPatterns = patterns => map$3(patterns, pattern => ({
|
22983 | ...baseKeyPattern,
|
22984 | ...pattern
|
22985 | }));
|
22986 | const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({
|
22987 | ...baseKeyPattern,
|
22988 | ...pattern
|
22989 | }));
|
22990 | const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
|
22991 | const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
|
22992 | const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
|
22993 | const action = (f, ...x) => () => f.apply(null, x);
|
22994 | const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action());
|
22995 | const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action());
|
22996 |
|
22997 | const moveH$1 = (editor, forward) => {
|
22998 | const direction = forward ? HDirection.Forwards : HDirection.Backwards;
|
22999 | const range = editor.selection.getRng();
|
23000 | return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
|
23001 | moveToRange(editor, newRange);
|
23002 | return true;
|
23003 | });
|
23004 | };
|
23005 | const moveV$1 = (editor, down) => {
|
23006 | const direction = down ? 1 : -1;
|
23007 | const range = editor.selection.getRng();
|
23008 | return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
|
23009 | moveToRange(editor, newRange);
|
23010 | return true;
|
23011 | });
|
23012 | };
|
23013 | const moveToLineEndPoint = (editor, forward) => {
|
23014 | const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
|
23015 | return moveToLineEndPoint$3(editor, forward, isNearMedia);
|
23016 | };
|
23017 |
|
23018 | const adt = Adt.generate([
|
23019 | { none: ['current'] },
|
23020 | { first: ['current'] },
|
23021 | {
|
23022 | middle: [
|
23023 | 'current',
|
23024 | 'target'
|
23025 | ]
|
23026 | },
|
23027 | { last: ['current'] }
|
23028 | ]);
|
23029 | const none = current => adt.none(current);
|
23030 | const CellLocation = {
|
23031 | ...adt,
|
23032 | none
|
23033 | };
|
23034 |
|
23035 | const firstLayer = (scope, selector) => {
|
23036 | return filterFirstLayer(scope, selector, always);
|
23037 | };
|
23038 | const filterFirstLayer = (scope, selector, predicate) => {
|
23039 | return bind$3(children$1(scope), x => {
|
23040 | if (is$1(x, selector)) {
|
23041 | return predicate(x) ? [x] : [];
|
23042 | } else {
|
23043 | return filterFirstLayer(x, selector, predicate);
|
23044 | }
|
23045 | });
|
23046 | };
|
23047 |
|
23048 | const lookup$1 = (tags, element, isRoot = never) => {
|
23049 | if (isRoot(element)) {
|
23050 | return Optional.none();
|
23051 | }
|
23052 | if (contains$2(tags, name(element))) {
|
23053 | return Optional.some(element);
|
23054 | }
|
23055 | const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm);
|
23056 | return ancestor$3(element, tags.join(','), isRootOrUpperTable);
|
23057 | };
|
23058 | const cell = (element, isRoot) => lookup$1([
|
23059 | 'td',
|
23060 | 'th'
|
23061 | ], element, isRoot);
|
23062 | const cells = ancestor => firstLayer(ancestor, 'th,td');
|
23063 | const table = (element, isRoot) => closest$3(element, 'table', isRoot);
|
23064 |
|
23065 | const walk = (all, current, index, direction, isEligible = always) => {
|
23066 | const forwards = direction === 1;
|
23067 | if (!forwards && index <= 0) {
|
23068 | return CellLocation.first(all[0]);
|
23069 | } else if (forwards && index >= all.length - 1) {
|
23070 | return CellLocation.last(all[all.length - 1]);
|
23071 | } else {
|
23072 | const newIndex = index + direction;
|
23073 | const elem = all[newIndex];
|
23074 | return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible);
|
23075 | }
|
23076 | };
|
23077 | const detect = (current, isRoot) => {
|
23078 | return table(current, isRoot).bind(table => {
|
23079 | const all = cells(table);
|
23080 | const index = findIndex$2(all, x => eq(current, x));
|
23081 | return index.map(index => ({
|
23082 | index,
|
23083 | all
|
23084 | }));
|
23085 | });
|
23086 | };
|
23087 | const next = (current, isEligible, isRoot) => {
|
23088 | const detection = detect(current, isRoot);
|
23089 | return detection.fold(() => {
|
23090 | return CellLocation.none(current);
|
23091 | }, info => {
|
23092 | return walk(info.all, current, info.index, 1, isEligible);
|
23093 | });
|
23094 | };
|
23095 | const prev = (current, isEligible, isRoot) => {
|
23096 | const detection = detect(current, isRoot);
|
23097 | return detection.fold(() => {
|
23098 | return CellLocation.none();
|
23099 | }, info => {
|
23100 | return walk(info.all, current, info.index, -1, isEligible);
|
23101 | });
|
23102 | };
|
23103 |
|
23104 | const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
|
23105 | const isContentEditableFalse$3 = elem => isHTMLElement$1(elem) && get$9(elem, 'contenteditable') === 'false';
|
23106 | const elementsWithCursorPosition = [
|
23107 | 'img',
|
23108 | 'br'
|
23109 | ];
|
23110 | const isCursorPosition = elem => {
|
23111 | const hasCursorPosition = isTextNodeWithCursorPosition(elem);
|
23112 | return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse$3(elem);
|
23113 | };
|
23114 |
|
23115 | const first = element => descendant$2(element, isCursorPosition);
|
23116 |
|
23117 | const deflate = (rect, delta) => ({
|
23118 | left: rect.left - delta,
|
23119 | top: rect.top - delta,
|
23120 | right: rect.right + delta * 2,
|
23121 | bottom: rect.bottom + delta * 2,
|
23122 | width: rect.width + delta,
|
23123 | height: rect.height + delta
|
23124 | });
|
23125 | const getCorners = (getYAxisValue, tds) => bind$3(tds, td => {
|
23126 | const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
|
23127 | return [
|
23128 | {
|
23129 | x: rect.left,
|
23130 | y: getYAxisValue(rect),
|
23131 | cell: td
|
23132 | },
|
23133 | {
|
23134 | x: rect.right,
|
23135 | y: getYAxisValue(rect),
|
23136 | cell: td
|
23137 | }
|
23138 | ];
|
23139 | });
|
23140 | const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => {
|
23141 | const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
|
23142 | const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
|
23143 | return Optional.some(newDist < oldDist ? newCorner : oldCorner);
|
23144 | }), Optional.none());
|
23145 | const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => {
|
23146 | const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom);
|
23147 | const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y));
|
23148 | return findClosestCorner(corners, x, y).map(corner => corner.cell);
|
23149 | };
|
23150 | const getBottomValue = rect => rect.bottom;
|
23151 | const getTopValue = rect => rect.top;
|
23152 | const isAbove = (corner, y) => corner.y < y;
|
23153 | const isBelow = (corner, y) => corner.y > y;
|
23154 | const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
|
23155 | const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
|
23156 | const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos));
|
23157 | const findClosestPositionInBelowCell = (table, pos) => last$2(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos));
|
23158 |
|
23159 | const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome());
|
23160 | const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
|
23161 | const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
|
23162 | const isAtTableCellLine = (getPositionsUntil, scope, pos) => {
|
23163 | const lineInfo = getPositionsUntil(scope, pos);
|
23164 | if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
|
23165 | return !hasNextBreak(getPositionsUntil, scope, lineInfo);
|
23166 | } else {
|
23167 | return lineInfo.breakAt.isNone();
|
23168 | }
|
23169 | };
|
23170 | const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
|
23171 | const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
|
23172 | const isCaretAtStartOrEndOfTable = (forward, rng, table) => {
|
23173 | const caretPos = CaretPosition.fromRangeStart(rng);
|
23174 | return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos));
|
23175 | };
|
23176 | const navigateHorizontally = (editor, forward, table, _td) => {
|
23177 | const rng = editor.selection.getRng();
|
23178 | const direction = forward ? 1 : -1;
|
23179 | if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
|
23180 | showCaret(direction, editor, table, !forward, false).each(newRng => {
|
23181 | moveToRange(editor, newRng);
|
23182 | });
|
23183 | return true;
|
23184 | }
|
23185 | return false;
|
23186 | };
|
23187 | const getClosestAbovePosition = (root, table, start) => findClosestPositionInAboveCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsAbove(root, CaretPosition.before(table)), rect.left))).getOr(CaretPosition.before(table));
|
23188 | const getClosestBelowPosition = (root, table, start) => findClosestPositionInBelowCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsBelow(root, CaretPosition.after(table)), rect.left))).getOr(CaretPosition.after(table));
|
23189 | const getTable = (previous, pos) => {
|
23190 | const node = pos.getNode(previous);
|
23191 | return isTable$2(node) ? Optional.some(node) : Optional.none();
|
23192 | };
|
23193 | const renderBlock = (down, editor, table) => {
|
23194 | editor.undoManager.transact(() => {
|
23195 | const insertFn = down ? after$4 : before$3;
|
23196 | const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn);
|
23197 | moveToRange(editor, rng);
|
23198 | });
|
23199 | };
|
23200 | const moveCaret = (editor, down, pos) => {
|
23201 | const table = down ? getTable(true, pos) : getTable(false, pos);
|
23202 | const last = down === false;
|
23203 | table.fold(() => moveToRange(editor, pos.toRange()), table => positionIn(last, editor.getBody()).filter(lastPos => lastPos.isEqual(pos)).fold(() => moveToRange(editor, pos.toRange()), _ => renderBlock(down, editor, table)));
|
23204 | };
|
23205 | const navigateVertically = (editor, down, table, td) => {
|
23206 | const rng = editor.selection.getRng();
|
23207 | const pos = CaretPosition.fromRangeStart(rng);
|
23208 | const root = editor.getBody();
|
23209 | if (!down && isAtFirstTableCellLine(td, pos)) {
|
23210 | const newPos = getClosestAbovePosition(root, table, pos);
|
23211 | moveCaret(editor, down, newPos);
|
23212 | return true;
|
23213 | } else if (down && isAtLastTableCellLine(td, pos)) {
|
23214 | const newPos = getClosestBelowPosition(root, table, pos);
|
23215 | moveCaret(editor, down, newPos);
|
23216 | return true;
|
23217 | } else {
|
23218 | return false;
|
23219 | }
|
23220 | };
|
23221 | const move$1 = (editor, forward, mover) => Optional.from(editor.dom.getParent(editor.selection.getNode(), 'td,th')).bind(td => Optional.from(editor.dom.getParent(td, 'table')).map(table => mover(editor, forward, table, td))).getOr(false);
|
23222 | const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
|
23223 | const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
|
23224 | const getCellFirstCursorPosition = cell => {
|
23225 | const selection = SimSelection.exact(cell, 0, cell, 0);
|
23226 | return toNative(selection);
|
23227 | };
|
23228 | const tabGo = (editor, isRoot, cell) => {
|
23229 | return cell.fold(Optional.none, Optional.none, (_current, next) => {
|
23230 | return first(next).map(cell => {
|
23231 | return getCellFirstCursorPosition(cell);
|
23232 | });
|
23233 | }, current => {
|
23234 | editor.execCommand('mceTableInsertRowAfter');
|
23235 | return tabForward(editor, isRoot, current);
|
23236 | });
|
23237 | };
|
23238 | const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable$2));
|
23239 | const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable$2));
|
23240 | const handleTab = (editor, forward) => {
|
23241 | const rootElements = [
|
23242 | 'table',
|
23243 | 'li',
|
23244 | 'dl'
|
23245 | ];
|
23246 | const body = SugarElement.fromDom(editor.getBody());
|
23247 | const isRoot = element => {
|
23248 | const name$1 = name(element);
|
23249 | return eq(element, body) || contains$2(rootElements, name$1);
|
23250 | };
|
23251 | const rng = editor.selection.getRng();
|
23252 | const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
|
23253 | return cell(container, isRoot).map(cell => {
|
23254 | table(cell, isRoot).each(table => {
|
23255 | editor.model.table.clearSelectedCells(table.dom);
|
23256 | });
|
23257 | editor.selection.collapse(!forward);
|
23258 | const navigation = !forward ? tabBackward : tabForward;
|
23259 | const rng = navigation(editor, isRoot, cell);
|
23260 | rng.each(range => {
|
23261 | editor.selection.setRng(range);
|
23262 | });
|
23263 | return true;
|
23264 | }).getOr(false);
|
23265 | };
|
23266 |
|
23267 | const executeKeydownOverride$4 = (editor, caret, evt) => {
|
23268 | const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
23269 | execute([
|
23270 | {
|
23271 | keyCode: VK.RIGHT,
|
23272 | action: action(moveH$2, editor, true)
|
23273 | },
|
23274 | {
|
23275 | keyCode: VK.LEFT,
|
23276 | action: action(moveH$2, editor, false)
|
23277 | },
|
23278 | {
|
23279 | keyCode: VK.UP,
|
23280 | action: action(moveV$4, editor, false)
|
23281 | },
|
23282 | {
|
23283 | keyCode: VK.DOWN,
|
23284 | action: action(moveV$4, editor, true)
|
23285 | },
|
23286 | ...isMac ? [
|
23287 | {
|
23288 | keyCode: VK.UP,
|
23289 | action: action(selectToEndPoint, editor, false),
|
23290 | metaKey: true,
|
23291 | shiftKey: true
|
23292 | },
|
23293 | {
|
23294 | keyCode: VK.DOWN,
|
23295 | action: action(selectToEndPoint, editor, true),
|
23296 | metaKey: true,
|
23297 | shiftKey: true
|
23298 | }
|
23299 | ] : [],
|
23300 | {
|
23301 | keyCode: VK.RIGHT,
|
23302 | action: action(moveH, editor, true)
|
23303 | },
|
23304 | {
|
23305 | keyCode: VK.LEFT,
|
23306 | action: action(moveH, editor, false)
|
23307 | },
|
23308 | {
|
23309 | keyCode: VK.UP,
|
23310 | action: action(moveV, editor, false)
|
23311 | },
|
23312 | {
|
23313 | keyCode: VK.DOWN,
|
23314 | action: action(moveV, editor, true)
|
23315 | },
|
23316 | {
|
23317 | keyCode: VK.UP,
|
23318 | action: action(moveV, editor, false)
|
23319 | },
|
23320 | {
|
23321 | keyCode: VK.UP,
|
23322 | action: action(moveV$2, editor, false)
|
23323 | },
|
23324 | {
|
23325 | keyCode: VK.DOWN,
|
23326 | action: action(moveV$2, editor, true)
|
23327 | },
|
23328 | {
|
23329 | keyCode: VK.RIGHT,
|
23330 | action: action(moveH$1, editor, true)
|
23331 | },
|
23332 | {
|
23333 | keyCode: VK.LEFT,
|
23334 | action: action(moveH$1, editor, false)
|
23335 | },
|
23336 | {
|
23337 | keyCode: VK.UP,
|
23338 | action: action(moveV$1, editor, false)
|
23339 | },
|
23340 | {
|
23341 | keyCode: VK.DOWN,
|
23342 | action: action(moveV$1, editor, true)
|
23343 | },
|
23344 | {
|
23345 | keyCode: VK.RIGHT,
|
23346 | action: action(move$3, editor, caret, true)
|
23347 | },
|
23348 | {
|
23349 | keyCode: VK.LEFT,
|
23350 | action: action(move$3, editor, caret, false)
|
23351 | },
|
23352 | {
|
23353 | keyCode: VK.RIGHT,
|
23354 | ctrlKey: !isMac,
|
23355 | altKey: isMac,
|
23356 | action: action(moveNextWord, editor, caret)
|
23357 | },
|
23358 | {
|
23359 | keyCode: VK.LEFT,
|
23360 | ctrlKey: !isMac,
|
23361 | altKey: isMac,
|
23362 | action: action(movePrevWord, editor, caret)
|
23363 | },
|
23364 | {
|
23365 | keyCode: VK.UP,
|
23366 | action: action(moveV$3, editor, false)
|
23367 | },
|
23368 | {
|
23369 | keyCode: VK.DOWN,
|
23370 | action: action(moveV$3, editor, true)
|
23371 | }
|
23372 | ], evt).each(_ => {
|
23373 | evt.preventDefault();
|
23374 | });
|
23375 | };
|
23376 | const setup$l = (editor, caret) => {
|
23377 | editor.on('keydown', evt => {
|
23378 | if (!evt.isDefaultPrevented()) {
|
23379 | executeKeydownOverride$4(editor, caret, evt);
|
23380 | }
|
23381 | });
|
23382 | };
|
23383 |
|
23384 | const point = (container, offset) => ({
|
23385 | container,
|
23386 | offset
|
23387 | });
|
23388 |
|
23389 | const DOM$7 = DOMUtils.DOM;
|
23390 | const alwaysNext = startNode => node => startNode === node ? -1 : 0;
|
23391 | const isBoundary = dom => node => dom.isBlock(node) || contains$2([
|
23392 | 'BR',
|
23393 | 'IMG',
|
23394 | 'HR',
|
23395 | 'INPUT'
|
23396 | ], node.nodeName) || dom.getContentEditable(node) === 'false';
|
23397 | const textBefore = (node, offset, rootNode) => {
|
23398 | if (isText$b(node) && offset >= 0) {
|
23399 | return Optional.some(point(node, offset));
|
23400 | } else {
|
23401 | const textSeeker = TextSeeker(DOM$7);
|
23402 | return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length));
|
23403 | }
|
23404 | };
|
23405 | const textAfter = (node, offset, rootNode) => {
|
23406 | if (isText$b(node) && offset >= node.length) {
|
23407 | return Optional.some(point(node, offset));
|
23408 | } else {
|
23409 | const textSeeker = TextSeeker(DOM$7);
|
23410 | return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0));
|
23411 | }
|
23412 | };
|
23413 | const scanLeft = (node, offset, rootNode) => {
|
23414 | if (!isText$b(node)) {
|
23415 | return Optional.none();
|
23416 | }
|
23417 | const text = node.data;
|
23418 | if (offset >= 0 && offset <= text.length) {
|
23419 | return Optional.some(point(node, offset));
|
23420 | } else {
|
23421 | const textSeeker = TextSeeker(DOM$7);
|
23422 | return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => {
|
23423 | const prevText = prev.container.data;
|
23424 | return scanLeft(prev.container, offset + prevText.length, rootNode);
|
23425 | });
|
23426 | }
|
23427 | };
|
23428 | const scanRight = (node, offset, rootNode) => {
|
23429 | if (!isText$b(node)) {
|
23430 | return Optional.none();
|
23431 | }
|
23432 | const text = node.data;
|
23433 | if (offset <= text.length) {
|
23434 | return Optional.some(point(node, offset));
|
23435 | } else {
|
23436 | const textSeeker = TextSeeker(DOM$7);
|
23437 | return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode));
|
23438 | }
|
23439 | };
|
23440 | const repeatLeft = (dom, node, offset, process, rootNode) => {
|
23441 | const search = TextSeeker(dom, isBoundary(dom));
|
23442 | return Optional.from(search.backwards(node, offset, process, rootNode));
|
23443 | };
|
23444 |
|
23445 | const isValidTextRange = rng => rng.collapsed && isText$b(rng.startContainer);
|
23446 | const getText = rng => trim$2(rng.toString().replace(/\u00A0/g, ' '));
|
23447 | const isWhitespace = chr => chr !== '' && ' \xA0\f\n\r\t\x0B'.indexOf(chr) !== -1;
|
23448 |
|
23449 | const stripTrigger = (text, trigger) => text.substring(trigger.length);
|
23450 | const findTrigger = (text, index, trigger, includeWhitespace = false) => {
|
23451 | let i;
|
23452 | const firstChar = trigger.charAt(0);
|
23453 | for (i = index - 1; i >= 0; i--) {
|
23454 | const char = text.charAt(i);
|
23455 | if (!includeWhitespace && isWhitespace(char)) {
|
23456 | return Optional.none();
|
23457 | }
|
23458 | if (firstChar === char && contains$1(text, trigger, i, index)) {
|
23459 | break;
|
23460 | }
|
23461 | }
|
23462 | return Optional.some(i);
|
23463 | };
|
23464 | const getContext = (dom, initRange, trigger, includeWhitespace = false) => {
|
23465 | if (!isValidTextRange(initRange)) {
|
23466 | return Optional.none();
|
23467 | }
|
23468 | const buffer = {
|
23469 | text: '',
|
23470 | offset: 0
|
23471 | };
|
23472 | const findTriggerIndex = (element, offset, text) => {
|
23473 | buffer.text = text + buffer.text;
|
23474 | buffer.offset += offset;
|
23475 | return findTrigger(buffer.text, buffer.offset, trigger, includeWhitespace).getOr(offset);
|
23476 | };
|
23477 | const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot();
|
23478 | return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => {
|
23479 | const range = initRange.cloneRange();
|
23480 | range.setStart(spot.container, spot.offset);
|
23481 | range.setEnd(initRange.endContainer, initRange.endOffset);
|
23482 | if (range.collapsed) {
|
23483 | return Optional.none();
|
23484 | }
|
23485 | const text = getText(range);
|
23486 | const triggerIndex = text.lastIndexOf(trigger);
|
23487 | if (triggerIndex !== 0) {
|
23488 | return Optional.none();
|
23489 | } else {
|
23490 | return Optional.some({
|
23491 | text: stripTrigger(text, trigger),
|
23492 | range,
|
23493 | trigger
|
23494 | });
|
23495 | }
|
23496 | });
|
23497 | };
|
23498 |
|
23499 | const isText$1 = node => node.nodeType === TEXT;
|
23500 | const isElement = node => node.nodeType === ELEMENT;
|
23501 | const toLast = node => {
|
23502 | if (isText$1(node)) {
|
23503 | return point(node, node.data.length);
|
23504 | } else {
|
23505 | const children = node.childNodes;
|
23506 | return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length);
|
23507 | }
|
23508 | };
|
23509 | const toLeaf = (node, offset) => {
|
23510 | const children = node.childNodes;
|
23511 | if (children.length > 0 && offset < children.length) {
|
23512 | return toLeaf(children[offset], 0);
|
23513 | } else if (children.length > 0 && isElement(node) && children.length === offset) {
|
23514 | return toLast(children[children.length - 1]);
|
23515 | } else {
|
23516 | return point(node, offset);
|
23517 | }
|
23518 | };
|
23519 |
|
23520 | const isPreviousCharContent = (dom, leaf) => {
|
23521 | var _a;
|
23522 | const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
|
23523 | return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => {
|
23524 | const char = spot.container.data.charAt(spot.offset - 1);
|
23525 | return !isWhitespace(char);
|
23526 | }).isSome();
|
23527 | };
|
23528 | const isStartOfWord = dom => rng => {
|
23529 | const leaf = toLeaf(rng.startContainer, rng.startOffset);
|
23530 | return !isPreviousCharContent(dom, leaf);
|
23531 | };
|
23532 | const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger));
|
23533 | const lookup = (editor, getDatabase) => {
|
23534 | const database = getDatabase();
|
23535 | const rng = editor.selection.getRng();
|
23536 | return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context));
|
23537 | };
|
23538 | const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => {
|
23539 | var _a;
|
23540 | const database = getDatabase();
|
23541 | const rng = editor.selection.getRng();
|
23542 | const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : '';
|
23543 | const autocompleters = filter$5(database.lookupByTrigger(context.trigger), autocompleter => context.text.length >= autocompleter.minChars && autocompleter.matches.getOrThunk(() => isStartOfWord(editor.dom))(context.range, startText, context.text));
|
23544 | if (autocompleters.length === 0) {
|
23545 | return Optional.none();
|
23546 | }
|
23547 | const lookupData = Promise.all(map$3(autocompleters, ac => {
|
23548 | const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions);
|
23549 | return fetchResult.then(results => ({
|
23550 | matchText: context.text,
|
23551 | items: results,
|
23552 | columns: ac.columns,
|
23553 | onAction: ac.onAction,
|
23554 | highlightOn: ac.highlightOn
|
23555 | }));
|
23556 | }));
|
23557 | return Optional.some({
|
23558 | lookupData,
|
23559 | context
|
23560 | });
|
23561 | };
|
23562 |
|
23563 | var SimpleResultType;
|
23564 | (function (SimpleResultType) {
|
23565 | SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
|
23566 | SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
|
23567 | }(SimpleResultType || (SimpleResultType = {})));
|
23568 | const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
|
23569 | const partition = results => {
|
23570 | const values = [];
|
23571 | const errors = [];
|
23572 | each$e(results, obj => {
|
23573 | fold$1(obj, err => errors.push(err), val => values.push(val));
|
23574 | });
|
23575 | return {
|
23576 | values,
|
23577 | errors
|
23578 | };
|
23579 | };
|
23580 | const mapError = (res, f) => {
|
23581 | if (res.stype === SimpleResultType.Error) {
|
23582 | return {
|
23583 | stype: SimpleResultType.Error,
|
23584 | serror: f(res.serror)
|
23585 | };
|
23586 | } else {
|
23587 | return res;
|
23588 | }
|
23589 | };
|
23590 | const map = (res, f) => {
|
23591 | if (res.stype === SimpleResultType.Value) {
|
23592 | return {
|
23593 | stype: SimpleResultType.Value,
|
23594 | svalue: f(res.svalue)
|
23595 | };
|
23596 | } else {
|
23597 | return res;
|
23598 | }
|
23599 | };
|
23600 | const bind$1 = (res, f) => {
|
23601 | if (res.stype === SimpleResultType.Value) {
|
23602 | return f(res.svalue);
|
23603 | } else {
|
23604 | return res;
|
23605 | }
|
23606 | };
|
23607 | const bindError = (res, f) => {
|
23608 | if (res.stype === SimpleResultType.Error) {
|
23609 | return f(res.serror);
|
23610 | } else {
|
23611 | return res;
|
23612 | }
|
23613 | };
|
23614 | const svalue = v => ({
|
23615 | stype: SimpleResultType.Value,
|
23616 | svalue: v
|
23617 | });
|
23618 | const serror = e => ({
|
23619 | stype: SimpleResultType.Error,
|
23620 | serror: e
|
23621 | });
|
23622 | const toResult = res => fold$1(res, Result.error, Result.value);
|
23623 | const fromResult = res => res.fold(serror, svalue);
|
23624 | const SimpleResult = {
|
23625 | fromResult,
|
23626 | toResult,
|
23627 | svalue,
|
23628 | partition,
|
23629 | serror,
|
23630 | bind: bind$1,
|
23631 | bindError,
|
23632 | map,
|
23633 | mapError,
|
23634 | fold: fold$1
|
23635 | };
|
23636 |
|
23637 | const formatObj = input => {
|
23638 | return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
|
23639 | };
|
23640 | const formatErrors = errors => {
|
23641 | const es = errors.length > 10 ? errors.slice(0, 10).concat([{
|
23642 | path: [],
|
23643 | getErrorInfo: constant('... (only showing first ten failures)')
|
23644 | }]) : errors;
|
23645 | return map$3(es, e => {
|
23646 | return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
|
23647 | });
|
23648 | };
|
23649 |
|
23650 | const nu = (path, getErrorInfo) => {
|
23651 | return SimpleResult.serror([{
|
23652 | path,
|
23653 | getErrorInfo
|
23654 | }]);
|
23655 | };
|
23656 | const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
|
23657 | const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
|
23658 | const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
|
23659 | const custom = (path, err) => nu(path, constant(err));
|
23660 |
|
23661 | const chooseFrom = (path, input, branches, ch) => {
|
23662 | const fields = get$a(branches, ch);
|
23663 | return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
|
23664 | };
|
23665 | const choose$1 = (key, branches) => {
|
23666 | const extract = (path, input) => {
|
23667 | const choice = get$a(input, key);
|
23668 | return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
|
23669 | };
|
23670 | const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
|
23671 | return {
|
23672 | extract,
|
23673 | toString
|
23674 | };
|
23675 | };
|
23676 |
|
23677 | const shallow = (old, nu) => {
|
23678 | return nu;
|
23679 | };
|
23680 | const deep = (old, nu) => {
|
23681 | const bothObjects = isPlainObject(old) && isPlainObject(nu);
|
23682 | return bothObjects ? deepMerge(old, nu) : nu;
|
23683 | };
|
23684 | const baseMerge = merger => {
|
23685 | return (...objects) => {
|
23686 | if (objects.length === 0) {
|
23687 | throw new Error(`Can't merge zero objects`);
|
23688 | }
|
23689 | const ret = {};
|
23690 | for (let j = 0; j < objects.length; j++) {
|
23691 | const curObject = objects[j];
|
23692 | for (const key in curObject) {
|
23693 | if (has$2(curObject, key)) {
|
23694 | ret[key] = merger(ret[key], curObject[key]);
|
23695 | }
|
23696 | }
|
23697 | }
|
23698 | return ret;
|
23699 | };
|
23700 | };
|
23701 | const deepMerge = baseMerge(deep);
|
23702 | const merge = baseMerge(shallow);
|
23703 |
|
23704 | const required = () => ({
|
23705 | tag: 'required',
|
23706 | process: {}
|
23707 | });
|
23708 | const defaultedThunk = fallbackThunk => ({
|
23709 | tag: 'defaultedThunk',
|
23710 | process: fallbackThunk
|
23711 | });
|
23712 | const defaulted$1 = fallback => defaultedThunk(constant(fallback));
|
23713 | const asOption = () => ({
|
23714 | tag: 'option',
|
23715 | process: {}
|
23716 | });
|
23717 |
|
23718 | const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base);
|
23719 | const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors);
|
23720 | const consolidateObj = (objects, base) => {
|
23721 | const partition = SimpleResult.partition(objects);
|
23722 | return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
|
23723 | };
|
23724 | const consolidateArr = objects => {
|
23725 | const partitions = SimpleResult.partition(objects);
|
23726 | return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
|
23727 | };
|
23728 | const ResultCombine = {
|
23729 | consolidateObj,
|
23730 | consolidateArr
|
23731 | };
|
23732 |
|
23733 | const field$1 = (key, newKey, presence, prop) => ({
|
23734 | tag: 'field',
|
23735 | key,
|
23736 | newKey,
|
23737 | presence,
|
23738 | prop
|
23739 | });
|
23740 | const customField$1 = (newKey, instantiator) => ({
|
23741 | tag: 'custom',
|
23742 | newKey,
|
23743 | instantiator
|
23744 | });
|
23745 | const fold = (value, ifField, ifCustom) => {
|
23746 | switch (value.tag) {
|
23747 | case 'field':
|
23748 | return ifField(value.key, value.newKey, value.presence, value.prop);
|
23749 | case 'custom':
|
23750 | return ifCustom(value.newKey, value.instantiator);
|
23751 | }
|
23752 | };
|
23753 |
|
23754 | const value = validator => {
|
23755 | const extract = (path, val) => {
|
23756 | return SimpleResult.bindError(validator(val), err => custom(path, err));
|
23757 | };
|
23758 | const toString = constant('val');
|
23759 | return {
|
23760 | extract,
|
23761 | toString
|
23762 | };
|
23763 | };
|
23764 | const anyValue$1 = value(SimpleResult.svalue);
|
23765 |
|
23766 | const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
|
23767 | const fallbackAccess = (obj, key, fallback, bundle) => {
|
23768 | const v = get$a(obj, key).getOrThunk(() => fallback(obj));
|
23769 | return bundle(v);
|
23770 | };
|
23771 | const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
|
23772 | const optionDefaultedAccess = (obj, key, fallback, bundle) => {
|
23773 | const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val);
|
23774 | return bundle(opt);
|
23775 | };
|
23776 | const extractField = (field, path, obj, key, prop) => {
|
23777 | const bundle = av => prop.extract(path.concat([key]), av);
|
23778 | const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
|
23779 | const result = prop.extract(path.concat([key]), ov);
|
23780 | return SimpleResult.map(result, Optional.some);
|
23781 | });
|
23782 | switch (field.tag) {
|
23783 | case 'required':
|
23784 | return requiredAccess(path, obj, key, bundle);
|
23785 | case 'defaultedThunk':
|
23786 | return fallbackAccess(obj, key, field.process, bundle);
|
23787 | case 'option':
|
23788 | return optionAccess(obj, key, bundleAsOption);
|
23789 | case 'defaultedOptionThunk':
|
23790 | return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
|
23791 | case 'mergeWithThunk': {
|
23792 | return fallbackAccess(obj, key, constant({}), v => {
|
23793 | const result = deepMerge(field.process(obj), v);
|
23794 | return bundle(result);
|
23795 | });
|
23796 | }
|
23797 | }
|
23798 | };
|
23799 | const extractFields = (path, obj, fields) => {
|
23800 | const success = {};
|
23801 | const errors = [];
|
23802 | for (const field of fields) {
|
23803 | fold(field, (key, newKey, presence, prop) => {
|
23804 | const result = extractField(presence, path, obj, key, prop);
|
23805 | SimpleResult.fold(result, err => {
|
23806 | errors.push(...err);
|
23807 | }, res => {
|
23808 | success[newKey] = res;
|
23809 | });
|
23810 | }, (newKey, instantiator) => {
|
23811 | success[newKey] = instantiator(obj);
|
23812 | });
|
23813 | }
|
23814 | return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
|
23815 | };
|
23816 | const objOf = values => {
|
23817 | const extract = (path, o) => extractFields(path, o, values);
|
23818 | const toString = () => {
|
23819 | const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
|
23820 | return 'obj{\n' + fieldStrings.join('\n') + '}';
|
23821 | };
|
23822 | return {
|
23823 | extract,
|
23824 | toString
|
23825 | };
|
23826 | };
|
23827 | const arrOf = prop => {
|
23828 | const extract = (path, array) => {
|
23829 | const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
|
23830 | return ResultCombine.consolidateArr(results);
|
23831 | };
|
23832 | const toString = () => 'array(' + prop.toString() + ')';
|
23833 | return {
|
23834 | extract,
|
23835 | toString
|
23836 | };
|
23837 | };
|
23838 |
|
23839 | const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
|
23840 | const extractValue = (label, prop, obj) => {
|
23841 | const res = prop.extract([label], obj);
|
23842 | return SimpleResult.mapError(res, errs => ({
|
23843 | input: obj,
|
23844 | errors: errs
|
23845 | }));
|
23846 | };
|
23847 | const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
|
23848 | const formatError = errInfo => {
|
23849 | return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
|
23850 | };
|
23851 | const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
|
23852 |
|
23853 | const anyValue = constant(anyValue$1);
|
23854 | const typedValue = (validator, expectedType) => value(a => {
|
23855 | const actualType = typeof a;
|
23856 | return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
|
23857 | });
|
23858 | const number = typedValue(isNumber, 'number');
|
23859 | const string = typedValue(isString, 'string');
|
23860 | const boolean = typedValue(isBoolean, 'boolean');
|
23861 | const functionProcessor = typedValue(isFunction, 'function');
|
23862 |
|
23863 | const field = field$1;
|
23864 | const customField = customField$1;
|
23865 | const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
|
23866 | const requiredOf = (key, schema) => field(key, key, required(), schema);
|
23867 | const requiredString = key => requiredOf(key, string);
|
23868 | const requiredFunction = key => requiredOf(key, functionProcessor);
|
23869 | const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
|
23870 | const optionOf = (key, schema) => field(key, key, asOption(), schema);
|
23871 | const optionString = key => optionOf(key, string);
|
23872 | const optionFunction = key => optionOf(key, functionProcessor);
|
23873 | const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
|
23874 | const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
|
23875 | const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
|
23876 | const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
|
23877 | const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
|
23878 | const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
|
23879 | const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
|
23880 | const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
|
23881 |
|
23882 | const type = requiredString('type');
|
23883 | const fetch$1 = requiredFunction('fetch');
|
23884 | const onAction = requiredFunction('onAction');
|
23885 | const onSetup = defaultedFunction('onSetup', () => noop);
|
23886 | const optionalText = optionString('text');
|
23887 | const optionalIcon = optionString('icon');
|
23888 | const optionalTooltip = optionString('tooltip');
|
23889 | const optionalLabel = optionString('label');
|
23890 | const active = defaultedBoolean('active', false);
|
23891 | const enabled = defaultedBoolean('enabled', true);
|
23892 | const primary = defaultedBoolean('primary', false);
|
23893 | const defaultedColumns = num => defaulted('columns', num);
|
23894 | const defaultedType = type => defaultedString('type', type);
|
23895 |
|
23896 | const autocompleterSchema = objOf([
|
23897 | type,
|
23898 | requiredString('trigger'),
|
23899 | defaultedNumber('minChars', 1),
|
23900 | defaultedColumns(1),
|
23901 | defaultedNumber('maxResults', 10),
|
23902 | optionFunction('matches'),
|
23903 | fetch$1,
|
23904 | onAction,
|
23905 | defaultedArrayOf('highlightOn', [], string)
|
23906 | ]);
|
23907 | const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, spec);
|
23908 |
|
23909 | const baseToolbarButtonFields = [
|
23910 | enabled,
|
23911 | optionalTooltip,
|
23912 | optionalIcon,
|
23913 | optionalText,
|
23914 | onSetup
|
23915 | ];
|
23916 |
|
23917 | const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
|
23918 |
|
23919 | const contextBarFields = [
|
23920 | defaultedFunction('predicate', never),
|
23921 | defaultedStringEnum('scope', 'node', [
|
23922 | 'node',
|
23923 | 'editor'
|
23924 | ]),
|
23925 | defaultedStringEnum('position', 'selection', [
|
23926 | 'node',
|
23927 | 'selection',
|
23928 | 'line'
|
23929 | ])
|
23930 | ];
|
23931 |
|
23932 | const contextButtonFields = baseToolbarButtonFields.concat([
|
23933 | defaultedType('contextformbutton'),
|
23934 | primary,
|
23935 | onAction,
|
23936 | customField('original', identity)
|
23937 | ]);
|
23938 | const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
|
23939 | defaultedType('contextformbutton'),
|
23940 | primary,
|
23941 | onAction,
|
23942 | customField('original', identity)
|
23943 | ]);
|
23944 | const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
|
23945 | const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
|
23946 | const toggleOrNormal = choose('type', {
|
23947 | contextformbutton: contextButtonFields,
|
23948 | contextformtogglebutton: contextToggleButtonFields
|
23949 | });
|
23950 | objOf([
|
23951 | defaultedType('contextform'),
|
23952 | defaultedFunction('initValue', constant('')),
|
23953 | optionalLabel,
|
23954 | requiredArrayOf('commands', toggleOrNormal),
|
23955 | optionOf('launch', choose('type', {
|
23956 | contextformbutton: launchButtonFields,
|
23957 | contextformtogglebutton: launchToggleButtonFields
|
23958 | }))
|
23959 | ].concat(contextBarFields));
|
23960 |
|
23961 | const register$2 = editor => {
|
23962 | const popups = editor.ui.registry.getAll().popups;
|
23963 | const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => {
|
23964 | throw new Error(formatError(err));
|
23965 | }, identity));
|
23966 | const triggers = stringArray(mapToArray(dataset, v => v.trigger));
|
23967 | const datasetValues = values(dataset);
|
23968 | const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger);
|
23969 | return {
|
23970 | dataset,
|
23971 | triggers,
|
23972 | lookupByTrigger
|
23973 | };
|
23974 | };
|
23975 |
|
23976 | const setupEditorInput = (editor, api) => {
|
23977 | const update = last(api.load, 50);
|
23978 | editor.on('input', e => {
|
23979 | if (e.inputType === 'insertCompositionText' && !editor.composing) {
|
23980 | return;
|
23981 | }
|
23982 | update.throttle();
|
23983 | });
|
23984 | editor.on('keydown', e => {
|
23985 | const keyCode = e.which;
|
23986 | if (keyCode === 8) {
|
23987 | update.throttle();
|
23988 | } else if (keyCode === 27) {
|
23989 | update.cancel();
|
23990 | api.cancelIfNecessary();
|
23991 | } else if (keyCode === 38 || keyCode === 40) {
|
23992 | update.cancel();
|
23993 | }
|
23994 | }, true);
|
23995 | editor.on('remove', update.cancel);
|
23996 | };
|
23997 | const setup$k = editor => {
|
23998 | const activeAutocompleter = value$2();
|
23999 | const uiActive = Cell(false);
|
24000 | const isActive = activeAutocompleter.isSet;
|
24001 | const cancelIfNecessary = () => {
|
24002 | if (isActive()) {
|
24003 | fireAutocompleterEnd(editor);
|
24004 | uiActive.set(false);
|
24005 | activeAutocompleter.clear();
|
24006 | }
|
24007 | };
|
24008 | const commenceIfNecessary = context => {
|
24009 | if (!isActive()) {
|
24010 | activeAutocompleter.set({
|
24011 | trigger: context.trigger,
|
24012 | matchLength: context.text.length
|
24013 | });
|
24014 | }
|
24015 | };
|
24016 | const getAutocompleters = cached(() => register$2(editor));
|
24017 | const doLookup = fetchOptions => activeAutocompleter.get().map(ac => getContext(editor.dom, editor.selection.getRng(), ac.trigger, true).bind(newContext => lookupWithContext(editor, getAutocompleters, newContext, fetchOptions))).getOrThunk(() => lookup(editor, getAutocompleters));
|
24018 | const load = fetchOptions => {
|
24019 | doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => {
|
24020 | commenceIfNecessary(lookupInfo.context);
|
24021 | lookupInfo.lookupData.then(lookupData => {
|
24022 | activeAutocompleter.get().map(ac => {
|
24023 | const context = lookupInfo.context;
|
24024 | if (ac.trigger !== context.trigger) {
|
24025 | return;
|
24026 | }
|
24027 | activeAutocompleter.set({
|
24028 | ...ac,
|
24029 | matchLength: context.text.length
|
24030 | });
|
24031 | if (uiActive.get()) {
|
24032 | fireAutocompleterUpdateActiveRange(editor, { range: context.range });
|
24033 | fireAutocompleterUpdate(editor, { lookupData });
|
24034 | } else {
|
24035 | uiActive.set(true);
|
24036 | fireAutocompleterUpdateActiveRange(editor, { range: context.range });
|
24037 | fireAutocompleterStart(editor, { lookupData });
|
24038 | }
|
24039 | });
|
24040 | });
|
24041 | });
|
24042 | };
|
24043 | const isRangeInsideOrEqual = (innerRange, outerRange) => {
|
24044 | const startComparison = innerRange.compareBoundaryPoints(window.Range.START_TO_START, outerRange);
|
24045 | const endComparison = innerRange.compareBoundaryPoints(window.Range.END_TO_END, outerRange);
|
24046 | return startComparison >= 0 && endComparison <= 0;
|
24047 | };
|
24048 | const readActiveRange = () => {
|
24049 | return activeAutocompleter.get().bind(({trigger}) => {
|
24050 | const selRange = editor.selection.getRng();
|
24051 | return getContext(editor.dom, selRange, trigger, uiActive.get()).filter(({range}) => isRangeInsideOrEqual(selRange, range)).map(({range}) => range);
|
24052 | });
|
24053 | };
|
24054 | editor.addCommand('mceAutocompleterReload', (_ui, value) => {
|
24055 | const fetchOptions = isObject(value) ? value.fetchOptions : {};
|
24056 | load(fetchOptions);
|
24057 | });
|
24058 | editor.addCommand('mceAutocompleterClose', cancelIfNecessary);
|
24059 | editor.addCommand('mceAutocompleterRefreshActiveRange', () => {
|
24060 | readActiveRange().each(range => {
|
24061 | fireAutocompleterUpdateActiveRange(editor, { range });
|
24062 | });
|
24063 | });
|
24064 | editor.editorCommands.addQueryStateHandler('mceAutoCompleterInRange', () => readActiveRange().isSome());
|
24065 | setupEditorInput(editor, {
|
24066 | cancelIfNecessary,
|
24067 | load
|
24068 | });
|
24069 | };
|
24070 |
|
24071 | const browser$1 = detect$1().browser;
|
24072 | const isSafari = browser$1.isSafari();
|
24073 | const emptyNodeContents = node => fillWithPaddingBr(SugarElement.fromDom(node));
|
24074 | const isEntireNodeSelected = (rng, node) => {
|
24075 | var _a;
|
24076 | return rng.startOffset === 0 && rng.endOffset === ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length);
|
24077 | };
|
24078 | const getParentDetailsElementAtPos = (dom, pos) => Optional.from(dom.getParent(pos.container(), 'details'));
|
24079 | const isInDetailsElement = (dom, pos) => getParentDetailsElementAtPos(dom, pos).isSome();
|
24080 | const getDetailsElements = (dom, rng) => {
|
24081 | const startDetails = Optional.from(dom.getParent(rng.startContainer, 'details'));
|
24082 | const endDetails = Optional.from(dom.getParent(rng.endContainer, 'details'));
|
24083 | if (startDetails.isSome() || endDetails.isSome()) {
|
24084 | const startSummary = startDetails.bind(details => Optional.from(dom.select('summary', details)[0]));
|
24085 | return Optional.some({
|
24086 | startSummary,
|
24087 | startDetails,
|
24088 | endDetails
|
24089 | });
|
24090 | } else {
|
24091 | return Optional.none();
|
24092 | }
|
24093 | };
|
24094 | const isCaretInTheBeginningOf = (caretPos, element) => firstPositionIn(element).exists(pos => pos.isEqual(caretPos));
|
24095 | const isCaretInTheEndOf = (caretPos, element) => {
|
24096 | return lastPositionIn(element).exists(pos => {
|
24097 | if (isBr$6(pos.getNode())) {
|
24098 | return prevPosition(element, pos).exists(pos2 => pos2.isEqual(caretPos)) || pos.isEqual(caretPos);
|
24099 | } else {
|
24100 | return pos.isEqual(caretPos);
|
24101 | }
|
24102 | });
|
24103 | };
|
24104 | const isCaretAtStartOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheBeginningOf(caretPos, summary));
|
24105 | const isCaretAtEndOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheEndOf(caretPos, summary));
|
24106 | const isCaretInFirstPositionInBody = (caretPos, detailsElements) => detailsElements.startDetails.exists(details => prevPosition(details, caretPos).forall(pos => detailsElements.startSummary.exists(summary => !summary.contains(caretPos.container()) && summary.contains(pos.container()))));
|
24107 | const isCaretInLastPositionInBody = (root, caretPos, detailsElements) => detailsElements.startDetails.exists(details => nextPosition(root, caretPos).forall(pos => !details.contains(pos.container())));
|
24108 | const setCaretToPosition = (editor, position) => {
|
24109 | const node = position.getNode();
|
24110 | if (!isUndefined(node)) {
|
24111 | editor.selection.setCursorLocation(node, position.offset());
|
24112 | }
|
24113 | };
|
24114 | const moveCaretToDetailsPos = (editor, pos, forward) => {
|
24115 | const details = editor.dom.getParent(pos.container(), 'details');
|
24116 | if (details && !details.open) {
|
24117 | const summary = editor.dom.select('summary', details)[0];
|
24118 | if (summary) {
|
24119 | const newPos = forward ? firstPositionIn(summary) : lastPositionIn(summary);
|
24120 | newPos.each(pos => setCaretToPosition(editor, pos));
|
24121 | }
|
24122 | } else {
|
24123 | setCaretToPosition(editor, pos);
|
24124 | }
|
24125 | };
|
24126 | const isPartialDelete = (rng, detailsElements) => {
|
24127 | const containsStart = element => element.contains(rng.startContainer);
|
24128 | const containsEnd = element => element.contains(rng.endContainer);
|
24129 | const startInSummary = detailsElements.startSummary.exists(containsStart);
|
24130 | const endInSummary = detailsElements.startSummary.exists(containsEnd);
|
24131 | const isPartiallySelectedDetailsElements = detailsElements.startDetails.forall(startDetails => detailsElements.endDetails.forall(endDetails => startDetails !== endDetails));
|
24132 | const isInPartiallySelectedSummary = (startInSummary || endInSummary) && !(startInSummary && endInSummary);
|
24133 | return isInPartiallySelectedSummary || isPartiallySelectedDetailsElements;
|
24134 | };
|
24135 | const shouldPreventDeleteIntoDetails = (editor, forward, granularity) => {
|
24136 | const {dom, selection} = editor;
|
24137 | const root = editor.getBody();
|
24138 | if (granularity === 'character') {
|
24139 | const caretPos = CaretPosition.fromRangeStart(selection.getRng());
|
24140 | const parentBlock = dom.getParent(caretPos.container(), dom.isBlock);
|
24141 | const parentDetailsAtCaret = getParentDetailsElementAtPos(dom, caretPos);
|
24142 | const inEmptyParentBlock = parentBlock && dom.isEmpty(parentBlock);
|
24143 | const isFirstBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.previousSibling);
|
24144 | const isLastBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.nextSibling);
|
24145 | if (inEmptyParentBlock) {
|
24146 | const firstOrLast = forward ? isLastBlock : isFirstBlock;
|
24147 | if (firstOrLast) {
|
24148 | const isBeforeAfterDetails = navigate(!forward, root, caretPos).exists(pos => {
|
24149 | return isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, getParentDetailsElementAtPos(dom, pos));
|
24150 | });
|
24151 | if (isBeforeAfterDetails) {
|
24152 | return true;
|
24153 | }
|
24154 | }
|
24155 | }
|
24156 | return navigate(forward, root, caretPos).fold(never, pos => {
|
24157 | const parentDetailsAtNewPos = getParentDetailsElementAtPos(dom, pos);
|
24158 | if (isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, parentDetailsAtNewPos)) {
|
24159 | if (!forward) {
|
24160 | moveCaretToDetailsPos(editor, pos, false);
|
24161 | }
|
24162 | if (parentBlock && inEmptyParentBlock) {
|
24163 | if (forward && isFirstBlock) {
|
24164 | return true;
|
24165 | } else if (!forward && isLastBlock) {
|
24166 | return true;
|
24167 | }
|
24168 | moveCaretToDetailsPos(editor, pos, forward);
|
24169 | editor.dom.remove(parentBlock);
|
24170 | }
|
24171 | return true;
|
24172 | } else {
|
24173 | return false;
|
24174 | }
|
24175 | });
|
24176 | } else {
|
24177 | return false;
|
24178 | }
|
24179 | };
|
24180 | const shouldPreventDeleteSummaryAction = (editor, detailElements, forward, granularity) => {
|
24181 | const selection = editor.selection;
|
24182 | const rng = selection.getRng();
|
24183 | const caretPos = CaretPosition.fromRangeStart(rng);
|
24184 | const root = editor.getBody();
|
24185 | if (granularity === 'selection') {
|
24186 | return isPartialDelete(rng, detailElements);
|
24187 | } else if (forward) {
|
24188 | return isCaretAtEndOfSummary(caretPos, detailElements) || isCaretInLastPositionInBody(root, caretPos, detailElements);
|
24189 | } else {
|
24190 | return isCaretAtStartOfSummary(caretPos, detailElements) || isCaretInFirstPositionInBody(caretPos, detailElements);
|
24191 | }
|
24192 | };
|
24193 | const shouldPreventDeleteAction = (editor, forward, granularity) => getDetailsElements(editor.dom, editor.selection.getRng()).fold(() => shouldPreventDeleteIntoDetails(editor, forward, granularity), detailsElements => shouldPreventDeleteSummaryAction(editor, detailsElements, forward, granularity) || shouldPreventDeleteIntoDetails(editor, forward, granularity));
|
24194 | const handleDeleteActionSafari = (editor, forward, granularity) => {
|
24195 | const selection = editor.selection;
|
24196 | const node = selection.getNode();
|
24197 | const rng = selection.getRng();
|
24198 | const caretPos = CaretPosition.fromRangeStart(rng);
|
24199 | if (isSummary$1(node)) {
|
24200 | if (granularity === 'selection' && isEntireNodeSelected(rng, node) || willDeleteLastPositionInElement(forward, caretPos, node)) {
|
24201 | emptyNodeContents(node);
|
24202 | } else {
|
24203 | editor.undoManager.transact(() => {
|
24204 | const sel = selection.getSel();
|
24205 | let {anchorNode, anchorOffset, focusNode, focusOffset} = sel !== null && sel !== void 0 ? sel : {};
|
24206 | const applySelection = () => {
|
24207 | if (isNonNullable(anchorNode) && isNonNullable(anchorOffset) && isNonNullable(focusNode) && isNonNullable(focusOffset)) {
|
24208 | sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
|
24209 | }
|
24210 | };
|
24211 | const updateSelection = () => {
|
24212 | anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
|
24213 | anchorOffset = sel === null || sel === void 0 ? void 0 : sel.anchorOffset;
|
24214 | focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
|
24215 | focusOffset = sel === null || sel === void 0 ? void 0 : sel.focusOffset;
|
24216 | };
|
24217 | const appendAllChildNodes = (from, to) => {
|
24218 | each$e(from.childNodes, child => {
|
24219 | if (isNode(child)) {
|
24220 | to.appendChild(child);
|
24221 | }
|
24222 | });
|
24223 | };
|
24224 | const container = editor.dom.create('span', { 'data-mce-bogus': '1' });
|
24225 | appendAllChildNodes(node, container);
|
24226 | node.appendChild(container);
|
24227 | applySelection();
|
24228 | if (granularity === 'word' || granularity === 'line') {
|
24229 | sel === null || sel === void 0 ? void 0 : sel.modify('extend', forward ? 'right' : 'left', granularity);
|
24230 | }
|
24231 | if (!selection.isCollapsed() && isEntireNodeSelected(selection.getRng(), container)) {
|
24232 | emptyNodeContents(node);
|
24233 | } else {
|
24234 | editor.execCommand(forward ? 'ForwardDelete' : 'Delete');
|
24235 | updateSelection();
|
24236 | appendAllChildNodes(container, node);
|
24237 | applySelection();
|
24238 | }
|
24239 | editor.dom.remove(container);
|
24240 | });
|
24241 | }
|
24242 | return true;
|
24243 | } else {
|
24244 | return false;
|
24245 | }
|
24246 | };
|
24247 | const backspaceDelete = (editor, forward, granularity) => shouldPreventDeleteAction(editor, forward, granularity) || isSafari && handleDeleteActionSafari(editor, forward, granularity) ? Optional.some(noop) : Optional.none();
|
24248 |
|
24249 | const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => {
|
24250 | const target = editor.getBody();
|
24251 | const overrides = {
|
24252 | bubbles: true,
|
24253 | composed: true,
|
24254 | data: null,
|
24255 | isComposing: false,
|
24256 | detail: 0,
|
24257 | view: null,
|
24258 | target,
|
24259 | currentTarget: target,
|
24260 | eventPhase: Event.AT_TARGET,
|
24261 | originalTarget: target,
|
24262 | explicitOriginalTarget: target,
|
24263 | isTrusted: false,
|
24264 | srcElement: target,
|
24265 | cancelable: false,
|
24266 | preventDefault: noop,
|
24267 | inputType
|
24268 | };
|
24269 | const input = clone$3(new InputEvent(eventType));
|
24270 | return editor.dispatch(eventType, {
|
24271 | ...input,
|
24272 | ...overrides,
|
24273 | ...specifics
|
24274 | });
|
24275 | };
|
24276 | const fireInputEvent = createAndFireInputEvent('input');
|
24277 | const fireBeforeInputEvent = createAndFireInputEvent('beforeinput');
|
24278 |
|
24279 | const platform$2 = detect$1();
|
24280 | const os = platform$2.os;
|
24281 | const isMacOSOriOS = os.isMacOS() || os.isiOS();
|
24282 | const browser = platform$2.browser;
|
24283 | const isFirefox = browser.isFirefox();
|
24284 | const executeKeydownOverride$3 = (editor, caret, evt) => {
|
24285 | const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward';
|
24286 | const isCollapsed = editor.selection.isCollapsed();
|
24287 | const unmodifiedGranularity = isCollapsed ? 'character' : 'selection';
|
24288 | const getModifiedGranularity = isWord => {
|
24289 | if (isCollapsed) {
|
24290 | return isWord ? 'word' : 'line';
|
24291 | } else {
|
24292 | return 'selection';
|
24293 | }
|
24294 | };
|
24295 | executeWithDelayedAction([
|
24296 | {
|
24297 | keyCode: VK.BACKSPACE,
|
24298 | action: action(backspaceDelete$1, editor)
|
24299 | },
|
24300 | {
|
24301 | keyCode: VK.BACKSPACE,
|
24302 | action: action(backspaceDelete$6, editor, false)
|
24303 | },
|
24304 | {
|
24305 | keyCode: VK.DELETE,
|
24306 | action: action(backspaceDelete$6, editor, true)
|
24307 | },
|
24308 | {
|
24309 | keyCode: VK.BACKSPACE,
|
24310 | action: action(backspaceDelete$7, editor, false)
|
24311 | },
|
24312 | {
|
24313 | keyCode: VK.DELETE,
|
24314 | action: action(backspaceDelete$7, editor, true)
|
24315 | },
|
24316 | {
|
24317 | keyCode: VK.BACKSPACE,
|
24318 | action: action(backspaceDelete$4, editor, caret, false)
|
24319 | },
|
24320 | {
|
24321 | keyCode: VK.DELETE,
|
24322 | action: action(backspaceDelete$4, editor, caret, true)
|
24323 | },
|
24324 | {
|
24325 | keyCode: VK.BACKSPACE,
|
24326 | action: action(backspaceDelete$a, editor, false)
|
24327 | },
|
24328 | {
|
24329 | keyCode: VK.DELETE,
|
24330 | action: action(backspaceDelete$a, editor, true)
|
24331 | },
|
24332 | {
|
24333 | keyCode: VK.BACKSPACE,
|
24334 | action: action(backspaceDelete, editor, false, unmodifiedGranularity)
|
24335 | },
|
24336 | {
|
24337 | keyCode: VK.DELETE,
|
24338 | action: action(backspaceDelete, editor, true, unmodifiedGranularity)
|
24339 | },
|
24340 | ...isMacOSOriOS ? [
|
24341 | {
|
24342 | keyCode: VK.BACKSPACE,
|
24343 | altKey: true,
|
24344 | action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
|
24345 | },
|
24346 | {
|
24347 | keyCode: VK.DELETE,
|
24348 | altKey: true,
|
24349 | action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
|
24350 | },
|
24351 | {
|
24352 | keyCode: VK.BACKSPACE,
|
24353 | metaKey: true,
|
24354 | action: action(backspaceDelete, editor, false, getModifiedGranularity(false))
|
24355 | }
|
24356 | ] : [
|
24357 | {
|
24358 | keyCode: VK.BACKSPACE,
|
24359 | ctrlKey: true,
|
24360 | action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
|
24361 | },
|
24362 | {
|
24363 | keyCode: VK.DELETE,
|
24364 | ctrlKey: true,
|
24365 | action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
|
24366 | }
|
24367 | ],
|
24368 | {
|
24369 | keyCode: VK.BACKSPACE,
|
24370 | action: action(backspaceDelete$5, editor, false)
|
24371 | },
|
24372 | {
|
24373 | keyCode: VK.DELETE,
|
24374 | action: action(backspaceDelete$5, editor, true)
|
24375 | },
|
24376 | {
|
24377 | keyCode: VK.BACKSPACE,
|
24378 | action: action(backspaceDelete$2, editor, false)
|
24379 | },
|
24380 | {
|
24381 | keyCode: VK.DELETE,
|
24382 | action: action(backspaceDelete$2, editor, true)
|
24383 | },
|
24384 | {
|
24385 | keyCode: VK.BACKSPACE,
|
24386 | action: action(backspaceDelete$8, editor, false)
|
24387 | },
|
24388 | {
|
24389 | keyCode: VK.DELETE,
|
24390 | action: action(backspaceDelete$8, editor, true)
|
24391 | },
|
24392 | {
|
24393 | keyCode: VK.BACKSPACE,
|
24394 | action: action(backspaceDelete$9, editor, false)
|
24395 | },
|
24396 | {
|
24397 | keyCode: VK.DELETE,
|
24398 | action: action(backspaceDelete$9, editor, true)
|
24399 | },
|
24400 | {
|
24401 | keyCode: VK.BACKSPACE,
|
24402 | action: action(backspaceDelete$3, editor, false)
|
24403 | },
|
24404 | {
|
24405 | keyCode: VK.DELETE,
|
24406 | action: action(backspaceDelete$3, editor, true)
|
24407 | }
|
24408 | ], evt).filter(_ => editor.selection.isEditable()).each(applyAction => {
|
24409 | evt.preventDefault();
|
24410 | const beforeInput = fireBeforeInputEvent(editor, inputType);
|
24411 | if (!beforeInput.isDefaultPrevented()) {
|
24412 | applyAction();
|
24413 | fireInputEvent(editor, inputType);
|
24414 | }
|
24415 | });
|
24416 | };
|
24417 | const executeKeyupOverride = (editor, evt, isBackspaceKeydown) => execute([
|
24418 | {
|
24419 | keyCode: VK.BACKSPACE,
|
24420 | action: action(paddEmptyElement, editor)
|
24421 | },
|
24422 | {
|
24423 | keyCode: VK.DELETE,
|
24424 | action: action(paddEmptyElement, editor)
|
24425 | },
|
24426 | ...isMacOSOriOS ? [
|
24427 | {
|
24428 | keyCode: VK.BACKSPACE,
|
24429 | altKey: true,
|
24430 | action: action(refreshCaret, editor)
|
24431 | },
|
24432 | {
|
24433 | keyCode: VK.DELETE,
|
24434 | altKey: true,
|
24435 | action: action(refreshCaret, editor)
|
24436 | },
|
24437 | ...isBackspaceKeydown ? [{
|
24438 | keyCode: isFirefox ? 224 : 91,
|
24439 | action: action(refreshCaret, editor)
|
24440 | }] : []
|
24441 | ] : [
|
24442 | {
|
24443 | keyCode: VK.BACKSPACE,
|
24444 | ctrlKey: true,
|
24445 | action: action(refreshCaret, editor)
|
24446 | },
|
24447 | {
|
24448 | keyCode: VK.DELETE,
|
24449 | ctrlKey: true,
|
24450 | action: action(refreshCaret, editor)
|
24451 | }
|
24452 | ]
|
24453 | ], evt);
|
24454 | const setup$j = (editor, caret) => {
|
24455 | let isBackspaceKeydown = false;
|
24456 | editor.on('keydown', evt => {
|
24457 | isBackspaceKeydown = evt.keyCode === VK.BACKSPACE;
|
24458 | if (!evt.isDefaultPrevented()) {
|
24459 | executeKeydownOverride$3(editor, caret, evt);
|
24460 | }
|
24461 | });
|
24462 | editor.on('keyup', evt => {
|
24463 | if (!evt.isDefaultPrevented()) {
|
24464 | executeKeyupOverride(editor, evt, isBackspaceKeydown);
|
24465 | }
|
24466 | isBackspaceKeydown = false;
|
24467 | });
|
24468 | };
|
24469 |
|
24470 | const firstNonWhiteSpaceNodeSibling = node => {
|
24471 | while (node) {
|
24472 | if (isElement$6(node) || isText$b(node) && node.data && /[\r\n\s]/.test(node.data)) {
|
24473 | return node;
|
24474 | }
|
24475 | node = node.nextSibling;
|
24476 | }
|
24477 | return null;
|
24478 | };
|
24479 | const moveToCaretPosition = (editor, root) => {
|
24480 | const dom = editor.dom;
|
24481 | const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
|
24482 | if (!root) {
|
24483 | return;
|
24484 | }
|
24485 | if (/^(LI|DT|DD)$/.test(root.nodeName)) {
|
24486 | const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
|
24487 | if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
|
24488 | root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild);
|
24489 | }
|
24490 | }
|
24491 | const rng = dom.createRng();
|
24492 | root.normalize();
|
24493 | if (root.hasChildNodes()) {
|
24494 | const walker = new DomTreeWalker(root, root);
|
24495 | let lastNode = root;
|
24496 | let node;
|
24497 | while (node = walker.current()) {
|
24498 | if (isText$b(node)) {
|
24499 | rng.setStart(node, 0);
|
24500 | rng.setEnd(node, 0);
|
24501 | break;
|
24502 | }
|
24503 | if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
|
24504 | rng.setStartBefore(node);
|
24505 | rng.setEndBefore(node);
|
24506 | break;
|
24507 | }
|
24508 | lastNode = node;
|
24509 | node = walker.next();
|
24510 | }
|
24511 | if (!node) {
|
24512 | rng.setStart(lastNode, 0);
|
24513 | rng.setEnd(lastNode, 0);
|
24514 | }
|
24515 | } else {
|
24516 | if (isBr$6(root)) {
|
24517 | if (root.nextSibling && dom.isBlock(root.nextSibling)) {
|
24518 | rng.setStartBefore(root);
|
24519 | rng.setEndBefore(root);
|
24520 | } else {
|
24521 | rng.setStartAfter(root);
|
24522 | rng.setEndAfter(root);
|
24523 | }
|
24524 | } else {
|
24525 | rng.setStart(root, 0);
|
24526 | rng.setEnd(root, 0);
|
24527 | }
|
24528 | }
|
24529 | editor.selection.setRng(rng);
|
24530 | scrollRangeIntoView(editor, rng);
|
24531 | };
|
24532 | const getEditableRoot = (dom, node) => {
|
24533 | const root = dom.getRoot();
|
24534 | let editableRoot;
|
24535 | let parent = node;
|
24536 | while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') {
|
24537 | if (dom.getContentEditable(parent) === 'true') {
|
24538 | editableRoot = parent;
|
24539 | break;
|
24540 | }
|
24541 | parent = parent.parentNode;
|
24542 | }
|
24543 | return parent !== root ? editableRoot : root;
|
24544 | };
|
24545 | const getParentBlock$1 = editor => {
|
24546 | return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
|
24547 | };
|
24548 | const getParentBlockName = editor => {
|
24549 | return getParentBlock$1(editor).fold(constant(''), parentBlock => {
|
24550 | return parentBlock.nodeName.toUpperCase();
|
24551 | });
|
24552 | };
|
24553 | const isListItemParentBlock = editor => {
|
24554 | return getParentBlock$1(editor).filter(elm => {
|
24555 | return isListItem$1(SugarElement.fromDom(elm));
|
24556 | }).isSome();
|
24557 | };
|
24558 | const emptyBlock = elm => {
|
24559 | elm.innerHTML = '<br data-mce-bogus="1">';
|
24560 | };
|
24561 | const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
|
24562 | const dom = editor.dom;
|
24563 | Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => {
|
24564 | const currentStyles = getAllRaw(SugarElement.fromDom(node));
|
24565 | const newStyles = {
|
24566 | ...currentStyles,
|
24567 | ...attrStyles
|
24568 | };
|
24569 | dom.setStyles(node, newStyles);
|
24570 | });
|
24571 | const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/));
|
24572 | const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== ''));
|
24573 | lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
|
24574 | const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz));
|
24575 | const newClasses = [
|
24576 | ...attrClasses,
|
24577 | ...filteredClasses
|
24578 | ];
|
24579 | dom.setAttrib(node, 'class', newClasses.join(' '));
|
24580 | });
|
24581 | const appliedAttrs = [
|
24582 | 'style',
|
24583 | 'class'
|
24584 | ];
|
24585 | const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
|
24586 | dom.setAttribs(node, remainingAttrs);
|
24587 | };
|
24588 | const setForcedBlockAttrs = (editor, node) => {
|
24589 | const forcedRootBlockName = getForcedRootBlock(editor);
|
24590 | if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
|
24591 | const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
|
24592 | applyAttributes(editor, node, forcedRootBlockAttrs);
|
24593 | }
|
24594 | };
|
24595 | const createNewBlock = (editor, container, parentBlock, editableRoot, keepStyles = true, name, styles) => {
|
24596 | const dom = editor.dom;
|
24597 | const schema = editor.schema;
|
24598 | const newBlockName = getForcedRootBlock(editor);
|
24599 | const parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
|
24600 | let node = container;
|
24601 | const textInlineElements = schema.getTextInlineElements();
|
24602 | let block;
|
24603 | if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
|
24604 | block = dom.create(name || newBlockName, styles || {});
|
24605 | } else {
|
24606 | block = parentBlock.cloneNode(false);
|
24607 | }
|
24608 | let caretNode = block;
|
24609 | if (!keepStyles) {
|
24610 | dom.setAttrib(block, 'style', null);
|
24611 | dom.setAttrib(block, 'class', null);
|
24612 | } else {
|
24613 | do {
|
24614 | if (textInlineElements[node.nodeName]) {
|
24615 | if (isCaretNode(node) || isBookmarkNode$1(node)) {
|
24616 | continue;
|
24617 | }
|
24618 | const clonedNode = node.cloneNode(false);
|
24619 | dom.setAttrib(clonedNode, 'id', '');
|
24620 | if (block.hasChildNodes()) {
|
24621 | clonedNode.appendChild(block.firstChild);
|
24622 | block.appendChild(clonedNode);
|
24623 | } else {
|
24624 | caretNode = clonedNode;
|
24625 | block.appendChild(clonedNode);
|
24626 | }
|
24627 | }
|
24628 | } while ((node = node.parentNode) && node !== editableRoot);
|
24629 | }
|
24630 | setForcedBlockAttrs(editor, block);
|
24631 | emptyBlock(caretNode);
|
24632 | return block;
|
24633 | };
|
24634 |
|
24635 | const getDetailsRoot = (editor, element) => editor.dom.getParent(element, isDetails);
|
24636 | const isAtDetailsEdge = (root, element, isTextBlock) => {
|
24637 | let node = element;
|
24638 | while (node && node !== root && isNull(node.nextSibling)) {
|
24639 | const parent = node.parentElement;
|
24640 | if (!parent || !isTextBlock(parent)) {
|
24641 | return isDetails(parent);
|
24642 | }
|
24643 | node = parent;
|
24644 | }
|
24645 | return false;
|
24646 | };
|
24647 | const isLastEmptyBlockInDetails = (editor, shiftKey, element) => !shiftKey && element.nodeName.toLowerCase() === getForcedRootBlock(editor) && editor.dom.isEmpty(element) && isAtDetailsEdge(editor.getBody(), element, el => has$2(editor.schema.getTextBlockElements(), el.nodeName.toLowerCase()));
|
24648 | const insertNewLine = (editor, createNewBlock, parentBlock) => {
|
24649 | var _a, _b, _c;
|
24650 | const newBlock = createNewBlock(getForcedRootBlock(editor));
|
24651 | const root = getDetailsRoot(editor, parentBlock);
|
24652 | if (!root) {
|
24653 | return;
|
24654 | }
|
24655 | editor.dom.insertAfter(newBlock, root);
|
24656 | moveToCaretPosition(editor, newBlock);
|
24657 | if (((_c = (_b = (_a = parentBlock.parentElement) === null || _a === void 0 ? void 0 : _a.childNodes) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 1) {
|
24658 | editor.dom.remove(parentBlock);
|
24659 | }
|
24660 | };
|
24661 |
|
24662 | const hasFirstChild = (elm, name) => {
|
24663 | return elm.firstChild && elm.firstChild.nodeName === name;
|
24664 | };
|
24665 | const isFirstChild = elm => {
|
24666 | var _a;
|
24667 | return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
|
24668 | };
|
24669 | const hasParent = (elm, parentName) => {
|
24670 | const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode;
|
24671 | return isNonNullable(parentNode) && parentNode.nodeName === parentName;
|
24672 | };
|
24673 | const isListBlock = elm => {
|
24674 | return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName);
|
24675 | };
|
24676 | const isListItem = elm => {
|
24677 | return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName);
|
24678 | };
|
24679 | const isNestedList = elm => {
|
24680 | return isListBlock(elm) && isListBlock(elm.parentNode);
|
24681 | };
|
24682 | const getContainerBlock = containerBlock => {
|
24683 | const containerBlockParent = containerBlock.parentNode;
|
24684 | return isListItem(containerBlockParent) ? containerBlockParent : containerBlock;
|
24685 | };
|
24686 | const isFirstOrLastLi = (containerBlock, parentBlock, first) => {
|
24687 | let node = containerBlock[first ? 'firstChild' : 'lastChild'];
|
24688 | while (node) {
|
24689 | if (isElement$6(node)) {
|
24690 | break;
|
24691 | }
|
24692 | node = node[first ? 'nextSibling' : 'previousSibling'];
|
24693 | }
|
24694 | return node === parentBlock;
|
24695 | };
|
24696 | const getStyles = elm => foldl(mapToArray(getAllRaw(SugarElement.fromDom(elm)), (style, styleName) => `${ styleName }: ${ style };`), (acc, s) => acc + s, '');
|
24697 | const insert$4 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
|
24698 | const dom = editor.dom;
|
24699 | const rng = editor.selection.getRng();
|
24700 | const containerParent = containerBlock.parentNode;
|
24701 | if (containerBlock === editor.getBody() || !containerParent) {
|
24702 | return;
|
24703 | }
|
24704 | if (isNestedList(containerBlock)) {
|
24705 | newBlockName = 'LI';
|
24706 | }
|
24707 | const parentBlockStyles = isListItem(parentBlock) ? getStyles(parentBlock) : undefined;
|
24708 | let newBlock = isListItem(parentBlock) && parentBlockStyles ? createNewBlock(newBlockName, { style: getStyles(parentBlock) }) : createNewBlock(newBlockName);
|
24709 | if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
|
24710 | if (hasParent(containerBlock, 'LI')) {
|
24711 | const containerBlockParent = getContainerBlock(containerBlock);
|
24712 | dom.insertAfter(newBlock, containerBlockParent);
|
24713 | if (isFirstChild(containerBlock)) {
|
24714 | dom.remove(containerBlockParent);
|
24715 | } else {
|
24716 | dom.remove(containerBlock);
|
24717 | }
|
24718 | } else {
|
24719 | dom.replace(newBlock, containerBlock);
|
24720 | }
|
24721 | } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
|
24722 | if (hasParent(containerBlock, 'LI')) {
|
24723 | dom.insertAfter(newBlock, getContainerBlock(containerBlock));
|
24724 | newBlock.appendChild(dom.doc.createTextNode(' '));
|
24725 | newBlock.appendChild(containerBlock);
|
24726 | } else {
|
24727 | containerParent.insertBefore(newBlock, containerBlock);
|
24728 | }
|
24729 | dom.remove(parentBlock);
|
24730 | } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
|
24731 | dom.insertAfter(newBlock, getContainerBlock(containerBlock));
|
24732 | dom.remove(parentBlock);
|
24733 | } else {
|
24734 | containerBlock = getContainerBlock(containerBlock);
|
24735 | const tmpRng = rng.cloneRange();
|
24736 | tmpRng.setStartAfter(parentBlock);
|
24737 | tmpRng.setEndAfter(containerBlock);
|
24738 | const fragment = tmpRng.extractContents();
|
24739 | if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
|
24740 | const previousChildren = filter$5(map$3(newBlock.children, SugarElement.fromDom), not(isTag('br')));
|
24741 | newBlock = fragment.firstChild;
|
24742 | dom.insertAfter(fragment, containerBlock);
|
24743 | each$e(previousChildren, child => prepend(SugarElement.fromDom(newBlock), child));
|
24744 | if (parentBlockStyles) {
|
24745 | newBlock.setAttribute('style', parentBlockStyles);
|
24746 | }
|
24747 | } else {
|
24748 | dom.insertAfter(fragment, containerBlock);
|
24749 | dom.insertAfter(newBlock, containerBlock);
|
24750 | }
|
24751 | dom.remove(parentBlock);
|
24752 | }
|
24753 | moveToCaretPosition(editor, newBlock);
|
24754 | };
|
24755 |
|
24756 | const trimZwsp = fragment => {
|
24757 | each$e(descendants$1(SugarElement.fromDom(fragment), isText$c), text => {
|
24758 | const rawNode = text.dom;
|
24759 | rawNode.nodeValue = trim$2(rawNode.data);
|
24760 | });
|
24761 | };
|
24762 | const isWithinNonEditableList = (editor, node) => {
|
24763 | const parentList = editor.dom.getParent(node, 'ol,ul,dl');
|
24764 | return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false';
|
24765 | };
|
24766 | const isEmptyAnchor = (dom, elm) => {
|
24767 | return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
|
24768 | };
|
24769 | const containerAndSiblingName = (container, nodeName) => {
|
24770 | return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
|
24771 | };
|
24772 | const canSplitBlock = (dom, node) => {
|
24773 | return isNonNullable(node) && dom.isBlock(node) && !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) && !/^(fixed|absolute)/i.test(node.style.position) && dom.isEditable(node.parentNode) && dom.getContentEditable(node) !== 'false';
|
24774 | };
|
24775 | const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => {
|
24776 | var _a;
|
24777 | const firstChilds = [];
|
24778 | if (!block) {
|
24779 | return;
|
24780 | }
|
24781 | let currentNode = block;
|
24782 | while (currentNode = currentNode.firstChild) {
|
24783 | if (dom.isBlock(currentNode)) {
|
24784 | return;
|
24785 | }
|
24786 | if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) {
|
24787 | firstChilds.push(currentNode);
|
24788 | }
|
24789 | }
|
24790 | let i = firstChilds.length;
|
24791 | while (i--) {
|
24792 | currentNode = firstChilds[i];
|
24793 | if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') {
|
24794 | dom.remove(currentNode);
|
24795 | } else {
|
24796 | if (isEmptyAnchor(dom, currentNode)) {
|
24797 | dom.remove(currentNode);
|
24798 | }
|
24799 | }
|
24800 | }
|
24801 | };
|
24802 | const normalizeZwspOffset = (start, container, offset) => {
|
24803 | if (!isText$b(container)) {
|
24804 | return offset;
|
24805 | } else if (start) {
|
24806 | return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
|
24807 | } else {
|
24808 | return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
|
24809 | }
|
24810 | };
|
24811 | const includeZwspInRange = rng => {
|
24812 | const newRng = rng.cloneRange();
|
24813 | newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
|
24814 | newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
|
24815 | return newRng;
|
24816 | };
|
24817 | const trimLeadingLineBreaks = node => {
|
24818 | let currentNode = node;
|
24819 | do {
|
24820 | if (isText$b(currentNode)) {
|
24821 | currentNode.data = currentNode.data.replace(/^[\r\n]+/, '');
|
24822 | }
|
24823 | currentNode = currentNode.firstChild;
|
24824 | } while (currentNode);
|
24825 | };
|
24826 | const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
|
24827 | var _a, _b;
|
24828 | const dom = editor.dom;
|
24829 | const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot();
|
24830 | let parentBlock = dom.getParent(container, dom.isBlock);
|
24831 | if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
|
24832 | parentBlock = parentBlock || editableRoot;
|
24833 | if (!parentBlock.hasChildNodes()) {
|
24834 | const newBlock = dom.create(newBlockName);
|
24835 | setForcedBlockAttrs(editor, newBlock);
|
24836 | parentBlock.appendChild(newBlock);
|
24837 | rng.setStart(newBlock, 0);
|
24838 | rng.setEnd(newBlock, 0);
|
24839 | return newBlock;
|
24840 | }
|
24841 | let node = container;
|
24842 | while (node && node.parentNode !== parentBlock) {
|
24843 | node = node.parentNode;
|
24844 | }
|
24845 | let startNode;
|
24846 | while (node && !dom.isBlock(node)) {
|
24847 | startNode = node;
|
24848 | node = node.previousSibling;
|
24849 | }
|
24850 | const startNodeName = (_b = startNode === null || startNode === void 0 ? void 0 : startNode.parentElement) === null || _b === void 0 ? void 0 : _b.nodeName;
|
24851 | if (startNode && startNodeName && editor.schema.isValidChild(startNodeName, newBlockName.toLowerCase())) {
|
24852 | const startNodeParent = startNode.parentNode;
|
24853 | const newBlock = dom.create(newBlockName);
|
24854 | setForcedBlockAttrs(editor, newBlock);
|
24855 | startNodeParent.insertBefore(newBlock, startNode);
|
24856 | node = startNode;
|
24857 | while (node && !dom.isBlock(node)) {
|
24858 | const next = node.nextSibling;
|
24859 | newBlock.appendChild(node);
|
24860 | node = next;
|
24861 | }
|
24862 | rng.setStart(container, offset);
|
24863 | rng.setEnd(container, offset);
|
24864 | }
|
24865 | }
|
24866 | return container;
|
24867 | };
|
24868 | const addBrToBlockIfNeeded = (dom, block) => {
|
24869 | block.normalize();
|
24870 | const lastChild = block.lastChild;
|
24871 | if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
|
24872 | dom.add(block, 'br');
|
24873 | }
|
24874 | };
|
24875 | const shouldEndContainer = (editor, container) => {
|
24876 | const optionValue = shouldEndContainerOnEmptyBlock(editor);
|
24877 | if (isNullable(container)) {
|
24878 | return false;
|
24879 | } else if (isString(optionValue)) {
|
24880 | return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
|
24881 | } else {
|
24882 | return optionValue;
|
24883 | }
|
24884 | };
|
24885 | const insert$3 = (editor, evt) => {
|
24886 | let container;
|
24887 | let offset;
|
24888 | let parentBlockName;
|
24889 | let containerBlock;
|
24890 | let isAfterLastNodeInContainer = false;
|
24891 | const dom = editor.dom;
|
24892 | const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
|
24893 | const rng = editor.selection.getRng();
|
24894 | const newBlockName = getForcedRootBlock(editor);
|
24895 | const start = SugarElement.fromDom(rng.startContainer);
|
24896 | const child = child$1(start, rng.startOffset);
|
24897 | const isCef = child.exists(element => isHTMLElement$1(element) && !isEditable$2(element));
|
24898 | const collapsedAndCef = rng.collapsed && isCef;
|
24899 | const createNewBlock$1 = (name, styles) => {
|
24900 | return createNewBlock(editor, container, parentBlock, editableRoot, shouldKeepStyles(editor), name, styles);
|
24901 | };
|
24902 | const isCaretAtStartOrEndOfBlock = start => {
|
24903 | const normalizedOffset = normalizeZwspOffset(start, container, offset);
|
24904 | if (isText$b(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) {
|
24905 | return false;
|
24906 | }
|
24907 | if ((container.parentNode === parentBlock || container === parentBlock) && isAfterLastNodeInContainer && !start) {
|
24908 | return true;
|
24909 | }
|
24910 | if (start && isElement$6(container) && container === parentBlock.firstChild) {
|
24911 | return true;
|
24912 | }
|
24913 | if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
|
24914 | return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
|
24915 | }
|
24916 | const walker = new DomTreeWalker(container, parentBlock);
|
24917 | if (isText$b(container)) {
|
24918 | if (start && normalizedOffset === 0) {
|
24919 | walker.prev();
|
24920 | } else if (!start && normalizedOffset === container.data.length) {
|
24921 | walker.next();
|
24922 | }
|
24923 | }
|
24924 | let node;
|
24925 | while (node = walker.current()) {
|
24926 | if (isElement$6(node)) {
|
24927 | if (!node.getAttribute('data-mce-bogus')) {
|
24928 | const name = node.nodeName.toLowerCase();
|
24929 | if (nonEmptyElementsMap[name] && name !== 'br') {
|
24930 | return false;
|
24931 | }
|
24932 | }
|
24933 | } else if (isText$b(node) && !isWhitespaceText(node.data)) {
|
24934 | return false;
|
24935 | }
|
24936 | if (start) {
|
24937 | walker.prev();
|
24938 | } else {
|
24939 | walker.next();
|
24940 | }
|
24941 | }
|
24942 | return true;
|
24943 | };
|
24944 | const insertNewBlockAfter = () => {
|
24945 | let block;
|
24946 | if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
|
24947 | block = createNewBlock$1(newBlockName);
|
24948 | } else {
|
24949 | block = createNewBlock$1();
|
24950 | }
|
24951 | if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock, undefined, { includeZwsp: true })) {
|
24952 | block = dom.split(containerBlock, parentBlock);
|
24953 | } else {
|
24954 | dom.insertAfter(block, parentBlock);
|
24955 | }
|
24956 | moveToCaretPosition(editor, block);
|
24957 | return block;
|
24958 | };
|
24959 | normalize$2(dom, rng).each(normRng => {
|
24960 | rng.setStart(normRng.startContainer, normRng.startOffset);
|
24961 | rng.setEnd(normRng.endContainer, normRng.endOffset);
|
24962 | });
|
24963 | container = rng.startContainer;
|
24964 | offset = rng.startOffset;
|
24965 | const shiftKey = !!(evt && evt.shiftKey);
|
24966 | const ctrlKey = !!(evt && evt.ctrlKey);
|
24967 | if (isElement$6(container) && container.hasChildNodes() && !collapsedAndCef) {
|
24968 | isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
24969 | container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
24970 | if (isAfterLastNodeInContainer && isText$b(container)) {
|
24971 | offset = container.data.length;
|
24972 | } else {
|
24973 | offset = 0;
|
24974 | }
|
24975 | }
|
24976 | const editableRoot = getEditableRoot(dom, container);
|
24977 | if (!editableRoot || isWithinNonEditableList(editor, container)) {
|
24978 | return;
|
24979 | }
|
24980 | if (!shiftKey) {
|
24981 | container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
|
24982 | }
|
24983 | let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot();
|
24984 | containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
|
24985 | parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
|
24986 | const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
|
24987 | if (containerBlockName === 'LI' && !ctrlKey) {
|
24988 | const liBlock = containerBlock;
|
24989 | parentBlock = liBlock;
|
24990 | containerBlock = liBlock.parentNode;
|
24991 | parentBlockName = containerBlockName;
|
24992 | }
|
24993 | if (isElement$6(containerBlock) && isLastEmptyBlockInDetails(editor, shiftKey, parentBlock)) {
|
24994 | return insertNewLine(editor, createNewBlock$1, parentBlock);
|
24995 | }
|
24996 | if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) {
|
24997 | if (dom.isEmpty(parentBlock)) {
|
24998 | insert$4(editor, createNewBlock$1, containerBlock, parentBlock, newBlockName);
|
24999 | return;
|
25000 | }
|
25001 | }
|
25002 | if (!collapsedAndCef && (parentBlock === editor.getBody() || !canSplitBlock(dom, parentBlock))) {
|
25003 | return;
|
25004 | }
|
25005 | const parentBlockParent = parentBlock.parentNode;
|
25006 | let newBlock;
|
25007 | if (collapsedAndCef) {
|
25008 | newBlock = createNewBlock$1(newBlockName);
|
25009 | child.fold(() => {
|
25010 | append$1(start, SugarElement.fromDom(newBlock));
|
25011 | }, child => {
|
25012 | before$3(child, SugarElement.fromDom(newBlock));
|
25013 | });
|
25014 | editor.selection.setCursorLocation(newBlock, 0);
|
25015 | } else if (isCaretContainerBlock$1(parentBlock)) {
|
25016 | newBlock = showCaretContainerBlock(parentBlock);
|
25017 | if (dom.isEmpty(parentBlock)) {
|
25018 | emptyBlock(parentBlock);
|
25019 | }
|
25020 | setForcedBlockAttrs(editor, newBlock);
|
25021 | moveToCaretPosition(editor, newBlock);
|
25022 | } else if (isCaretAtStartOrEndOfBlock(false)) {
|
25023 | newBlock = insertNewBlockAfter();
|
25024 | } else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) {
|
25025 | newBlock = parentBlockParent.insertBefore(createNewBlock$1(), parentBlock);
|
25026 | const isNearChildren = hasChildNodes(SugarElement.fromDom(rng.startContainer)) && rng.collapsed;
|
25027 | moveToCaretPosition(editor, containerAndSiblingName(parentBlock, 'HR') || isNearChildren ? newBlock : parentBlock);
|
25028 | } else {
|
25029 | const tmpRng = includeZwspInRange(rng).cloneRange();
|
25030 | tmpRng.setEndAfter(parentBlock);
|
25031 | const fragment = tmpRng.extractContents();
|
25032 | trimZwsp(fragment);
|
25033 | trimLeadingLineBreaks(fragment);
|
25034 | newBlock = fragment.firstChild;
|
25035 | dom.insertAfter(fragment, parentBlock);
|
25036 | trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
|
25037 | addBrToBlockIfNeeded(dom, parentBlock);
|
25038 | if (dom.isEmpty(parentBlock)) {
|
25039 | emptyBlock(parentBlock);
|
25040 | }
|
25041 | newBlock.normalize();
|
25042 | if (dom.isEmpty(newBlock)) {
|
25043 | dom.remove(newBlock);
|
25044 | insertNewBlockAfter();
|
25045 | } else {
|
25046 | setForcedBlockAttrs(editor, newBlock);
|
25047 | moveToCaretPosition(editor, newBlock);
|
25048 | }
|
25049 | }
|
25050 | dom.setAttrib(newBlock, 'id', '');
|
25051 | editor.dispatch('NewBlock', { newBlock });
|
25052 | };
|
25053 | const fakeEventName$1 = 'insertParagraph';
|
25054 | const blockbreak = {
|
25055 | insert: insert$3,
|
25056 | fakeEventName: fakeEventName$1
|
25057 | };
|
25058 |
|
25059 | const hasRightSideContent = (schema, container, parentBlock) => {
|
25060 | const walker = new DomTreeWalker(container, parentBlock);
|
25061 | let node;
|
25062 | const nonEmptyElementsMap = schema.getNonEmptyElements();
|
25063 | while (node = walker.next()) {
|
25064 | if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$b(node) && node.length > 0) {
|
25065 | return true;
|
25066 | }
|
25067 | }
|
25068 | return false;
|
25069 | };
|
25070 | const moveSelectionToBr = (editor, brElm, extraBr) => {
|
25071 | const rng = editor.dom.createRng();
|
25072 | if (!extraBr) {
|
25073 | rng.setStartAfter(brElm);
|
25074 | rng.setEndAfter(brElm);
|
25075 | } else {
|
25076 | rng.setStartBefore(brElm);
|
25077 | rng.setEndBefore(brElm);
|
25078 | }
|
25079 | editor.selection.setRng(rng);
|
25080 | scrollRangeIntoView(editor, rng);
|
25081 | };
|
25082 | const insertBrAtCaret = (editor, evt) => {
|
25083 | const selection = editor.selection;
|
25084 | const dom = editor.dom;
|
25085 | const rng = selection.getRng();
|
25086 | let brElm;
|
25087 | let extraBr = false;
|
25088 | normalize$2(dom, rng).each(normRng => {
|
25089 | rng.setStart(normRng.startContainer, normRng.startOffset);
|
25090 | rng.setEnd(normRng.endContainer, normRng.endOffset);
|
25091 | });
|
25092 | let offset = rng.startOffset;
|
25093 | let container = rng.startContainer;
|
25094 | if (isElement$6(container) && container.hasChildNodes()) {
|
25095 | const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
25096 | container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
25097 | if (isAfterLastNodeInContainer && isText$b(container)) {
|
25098 | offset = container.data.length;
|
25099 | } else {
|
25100 | offset = 0;
|
25101 | }
|
25102 | }
|
25103 | let parentBlock = dom.getParent(container, dom.isBlock);
|
25104 | const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
|
25105 | const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
|
25106 | const isControlKey = !!(evt && evt.ctrlKey);
|
25107 | if (containerBlockName === 'LI' && !isControlKey) {
|
25108 | parentBlock = containerBlock;
|
25109 | }
|
25110 | if (isText$b(container) && offset >= container.data.length) {
|
25111 | if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) {
|
25112 | brElm = dom.create('br');
|
25113 | rng.insertNode(brElm);
|
25114 | rng.setStartAfter(brElm);
|
25115 | rng.setEndAfter(brElm);
|
25116 | extraBr = true;
|
25117 | }
|
25118 | }
|
25119 | brElm = dom.create('br');
|
25120 | rangeInsertNode(dom, rng, brElm);
|
25121 | moveSelectionToBr(editor, brElm, extraBr);
|
25122 | editor.undoManager.add();
|
25123 | };
|
25124 | const insertBrBefore = (editor, inline) => {
|
25125 | const br = SugarElement.fromTag('br');
|
25126 | before$3(SugarElement.fromDom(inline), br);
|
25127 | editor.undoManager.add();
|
25128 | };
|
25129 | const insertBrAfter = (editor, inline) => {
|
25130 | if (!hasBrAfter(editor.getBody(), inline)) {
|
25131 | after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br'));
|
25132 | }
|
25133 | const br = SugarElement.fromTag('br');
|
25134 | after$4(SugarElement.fromDom(inline), br);
|
25135 | moveSelectionToBr(editor, br.dom, false);
|
25136 | editor.undoManager.add();
|
25137 | };
|
25138 | const isBeforeBr = pos => {
|
25139 | return isBr$6(pos.getNode());
|
25140 | };
|
25141 | const hasBrAfter = (rootNode, startNode) => {
|
25142 | if (isBeforeBr(CaretPosition.after(startNode))) {
|
25143 | return true;
|
25144 | } else {
|
25145 | return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => {
|
25146 | return isBr$6(pos.getNode());
|
25147 | }).getOr(false);
|
25148 | }
|
25149 | };
|
25150 | const isAnchorLink = elm => {
|
25151 | return elm && elm.nodeName === 'A' && 'href' in elm;
|
25152 | };
|
25153 | const isInsideAnchor = location => {
|
25154 | return location.fold(never, isAnchorLink, isAnchorLink, never);
|
25155 | };
|
25156 | const readInlineAnchorLocation = editor => {
|
25157 | const isInlineTarget$1 = curry(isInlineTarget, editor);
|
25158 | const position = CaretPosition.fromRangeStart(editor.selection.getRng());
|
25159 | return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
|
25160 | };
|
25161 | const insertBrOutsideAnchor = (editor, location) => {
|
25162 | location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
|
25163 | };
|
25164 | const insert$2 = (editor, evt) => {
|
25165 | const anchorLocation = readInlineAnchorLocation(editor);
|
25166 | if (anchorLocation.isSome()) {
|
25167 | anchorLocation.each(curry(insertBrOutsideAnchor, editor));
|
25168 | } else {
|
25169 | insertBrAtCaret(editor, evt);
|
25170 | }
|
25171 | };
|
25172 | const fakeEventName = 'insertLineBreak';
|
25173 | const linebreak = {
|
25174 | insert: insert$2,
|
25175 | fakeEventName
|
25176 | };
|
25177 |
|
25178 | const matchesSelector = (editor, selector) => {
|
25179 | return getParentBlock$1(editor).filter(parentBlock => {
|
25180 | return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
|
25181 | }).isSome();
|
25182 | };
|
25183 | const shouldInsertBr = editor => {
|
25184 | return matchesSelector(editor, getBrNewLineSelector(editor));
|
25185 | };
|
25186 | const shouldBlockNewLine$1 = editor => {
|
25187 | return matchesSelector(editor, getNoNewLineSelector(editor));
|
25188 | };
|
25189 |
|
25190 | const newLineAction = Adt.generate([
|
25191 | { br: [] },
|
25192 | { block: [] },
|
25193 | { none: [] }
|
25194 | ]);
|
25195 | const shouldBlockNewLine = (editor, _shiftKey) => {
|
25196 | return shouldBlockNewLine$1(editor);
|
25197 | };
|
25198 | const inListBlock = requiredState => {
|
25199 | return (editor, _shiftKey) => {
|
25200 | return isListItemParentBlock(editor) === requiredState;
|
25201 | };
|
25202 | };
|
25203 | const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
|
25204 | const state = getParentBlockName(editor) === blockName.toUpperCase();
|
25205 | return state === requiredState;
|
25206 | };
|
25207 | const inCefBlock = editor => {
|
25208 | const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart());
|
25209 | return isNullable(editableRoot);
|
25210 | };
|
25211 | const inPreBlock = requiredState => inBlock('pre', requiredState);
|
25212 | const inSummaryBlock = () => inBlock('summary', true);
|
25213 | const shouldPutBrInPre = requiredState => {
|
25214 | return (editor, _shiftKey) => {
|
25215 | return shouldPutBrInPre$1(editor) === requiredState;
|
25216 | };
|
25217 | };
|
25218 | const inBrContext = (editor, _shiftKey) => {
|
25219 | return shouldInsertBr(editor);
|
25220 | };
|
25221 | const hasShiftKey = (_editor, shiftKey) => {
|
25222 | return shiftKey;
|
25223 | };
|
25224 | const canInsertIntoEditableRoot = editor => {
|
25225 | const forcedRootBlock = getForcedRootBlock(editor);
|
25226 | const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart());
|
25227 | return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
|
25228 | };
|
25229 | const isInRootWithEmptyOrCEF = editor => {
|
25230 | const rng = editor.selection.getRng();
|
25231 | const start = SugarElement.fromDom(rng.startContainer);
|
25232 | const child = child$1(start, rng.startOffset);
|
25233 | const isCefOpt = child.map(element => isHTMLElement$1(element) && !isEditable$2(element));
|
25234 | return rng.collapsed && isCefOpt.getOr(true);
|
25235 | };
|
25236 | const match = (predicates, action) => {
|
25237 | return (editor, shiftKey) => {
|
25238 | const isMatch = foldl(predicates, (res, p) => {
|
25239 | return res && p(editor, shiftKey);
|
25240 | }, true);
|
25241 | return isMatch ? Optional.some(action) : Optional.none();
|
25242 | };
|
25243 | };
|
25244 | const getAction = (editor, evt) => {
|
25245 | return evaluateUntil([
|
25246 | match([shouldBlockNewLine], newLineAction.none()),
|
25247 | match([
|
25248 | inPreBlock(true),
|
25249 | inCefBlock
|
25250 | ], newLineAction.none()),
|
25251 | match([inSummaryBlock()], newLineAction.br()),
|
25252 | match([
|
25253 | inPreBlock(true),
|
25254 | shouldPutBrInPre(false),
|
25255 | hasShiftKey
|
25256 | ], newLineAction.br()),
|
25257 | match([
|
25258 | inPreBlock(true),
|
25259 | shouldPutBrInPre(false)
|
25260 | ], newLineAction.block()),
|
25261 | match([
|
25262 | inPreBlock(true),
|
25263 | shouldPutBrInPre(true),
|
25264 | hasShiftKey
|
25265 | ], newLineAction.block()),
|
25266 | match([
|
25267 | inPreBlock(true),
|
25268 | shouldPutBrInPre(true)
|
25269 | ], newLineAction.br()),
|
25270 | match([
|
25271 | inListBlock(true),
|
25272 | hasShiftKey
|
25273 | ], newLineAction.br()),
|
25274 | match([inListBlock(true)], newLineAction.block()),
|
25275 | match([inBrContext], newLineAction.br()),
|
25276 | match([hasShiftKey], newLineAction.br()),
|
25277 | match([canInsertIntoEditableRoot], newLineAction.block()),
|
25278 | match([isInRootWithEmptyOrCEF], newLineAction.block())
|
25279 | ], [
|
25280 | editor,
|
25281 | !!(evt && evt.shiftKey)
|
25282 | ]).getOr(newLineAction.none());
|
25283 | };
|
25284 |
|
25285 | const insertBreak = (breakType, editor, evt) => {
|
25286 | if (!editor.selection.isCollapsed()) {
|
25287 | execEditorDeleteCommand(editor);
|
25288 | }
|
25289 | if (isNonNullable(evt)) {
|
25290 | const event = fireBeforeInputEvent(editor, breakType.fakeEventName);
|
25291 | if (event.isDefaultPrevented()) {
|
25292 | return;
|
25293 | }
|
25294 | }
|
25295 | breakType.insert(editor, evt);
|
25296 | if (isNonNullable(evt)) {
|
25297 | fireInputEvent(editor, breakType.fakeEventName);
|
25298 | }
|
25299 | };
|
25300 | const insert$1 = (editor, evt) => {
|
25301 | const br = () => insertBreak(linebreak, editor, evt);
|
25302 | const block = () => insertBreak(blockbreak, editor, evt);
|
25303 | const logicalAction = getAction(editor, evt);
|
25304 | switch (getNewlineBehavior(editor)) {
|
25305 | case 'linebreak':
|
25306 | logicalAction.fold(br, br, noop);
|
25307 | break;
|
25308 | case 'block':
|
25309 | logicalAction.fold(block, block, noop);
|
25310 | break;
|
25311 | case 'invert':
|
25312 | logicalAction.fold(block, br, noop);
|
25313 | break;
|
25314 | default:
|
25315 | logicalAction.fold(br, block, noop);
|
25316 | break;
|
25317 | }
|
25318 | };
|
25319 |
|
25320 | const platform$1 = detect$1();
|
25321 | const isIOSSafari = platform$1.os.isiOS() && platform$1.browser.isSafari();
|
25322 | const handleEnterKeyEvent = (editor, event) => {
|
25323 | if (event.isDefaultPrevented()) {
|
25324 | return;
|
25325 | }
|
25326 | event.preventDefault();
|
25327 | endTypingLevelIgnoreLocks(editor.undoManager);
|
25328 | editor.undoManager.transact(() => {
|
25329 | insert$1(editor, event);
|
25330 | });
|
25331 | };
|
25332 | const isCaretAfterKoreanCharacter = rng => {
|
25333 | if (!rng.collapsed) {
|
25334 | return false;
|
25335 | }
|
25336 | const startContainer = rng.startContainer;
|
25337 | if (isText$b(startContainer)) {
|
25338 | const koreanCharRegex = /^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/;
|
25339 | const char = startContainer.data.charAt(rng.startOffset - 1);
|
25340 | return koreanCharRegex.test(char);
|
25341 | } else {
|
25342 | return false;
|
25343 | }
|
25344 | };
|
25345 | const setup$i = editor => {
|
25346 | let iOSSafariKeydownBookmark = Optional.none();
|
25347 | const iOSSafariKeydownOverride = editor => {
|
25348 | iOSSafariKeydownBookmark = Optional.some(editor.selection.getBookmark());
|
25349 | editor.undoManager.add();
|
25350 | };
|
25351 | const iOSSafariKeyupOverride = (editor, event) => {
|
25352 | editor.undoManager.undo();
|
25353 | iOSSafariKeydownBookmark.fold(noop, b => editor.selection.moveToBookmark(b));
|
25354 | handleEnterKeyEvent(editor, event);
|
25355 | iOSSafariKeydownBookmark = Optional.none();
|
25356 | };
|
25357 | editor.on('keydown', event => {
|
25358 | if (event.keyCode === VK.ENTER) {
|
25359 | if (isIOSSafari && isCaretAfterKoreanCharacter(editor.selection.getRng())) {
|
25360 | iOSSafariKeydownOverride(editor);
|
25361 | } else {
|
25362 | handleEnterKeyEvent(editor, event);
|
25363 | }
|
25364 | }
|
25365 | });
|
25366 | editor.on('keyup', event => {
|
25367 | if (event.keyCode === VK.ENTER) {
|
25368 | iOSSafariKeydownBookmark.each(() => iOSSafariKeyupOverride(editor, event));
|
25369 | }
|
25370 | });
|
25371 | };
|
25372 |
|
25373 | const executeKeydownOverride$2 = (editor, caret, evt) => {
|
25374 | const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
25375 | execute([
|
25376 | {
|
25377 | keyCode: VK.END,
|
25378 | action: action(moveToLineEndPoint$1, editor, true)
|
25379 | },
|
25380 | {
|
25381 | keyCode: VK.HOME,
|
25382 | action: action(moveToLineEndPoint$1, editor, false)
|
25383 | },
|
25384 | ...!isMac ? [
|
25385 | {
|
25386 | keyCode: VK.HOME,
|
25387 | action: action(selectToEndPoint, editor, false),
|
25388 | ctrlKey: true,
|
25389 | shiftKey: true
|
25390 | },
|
25391 | {
|
25392 | keyCode: VK.END,
|
25393 | action: action(selectToEndPoint, editor, true),
|
25394 | ctrlKey: true,
|
25395 | shiftKey: true
|
25396 | }
|
25397 | ] : [],
|
25398 | {
|
25399 | keyCode: VK.END,
|
25400 | action: action(moveToLineEndPoint, editor, true)
|
25401 | },
|
25402 | {
|
25403 | keyCode: VK.HOME,
|
25404 | action: action(moveToLineEndPoint, editor, false)
|
25405 | },
|
25406 | {
|
25407 | keyCode: VK.END,
|
25408 | action: action(moveToLineEndPoint$2, editor, true, caret)
|
25409 | },
|
25410 | {
|
25411 | keyCode: VK.HOME,
|
25412 | action: action(moveToLineEndPoint$2, editor, false, caret)
|
25413 | }
|
25414 | ], evt).each(_ => {
|
25415 | evt.preventDefault();
|
25416 | });
|
25417 | };
|
25418 | const setup$h = (editor, caret) => {
|
25419 | editor.on('keydown', evt => {
|
25420 | if (!evt.isDefaultPrevented()) {
|
25421 | executeKeydownOverride$2(editor, caret, evt);
|
25422 | }
|
25423 | });
|
25424 | };
|
25425 |
|
25426 | const setup$g = editor => {
|
25427 | editor.on('input', e => {
|
25428 | if (!e.isComposing) {
|
25429 | normalizeNbspsInEditor(editor);
|
25430 | }
|
25431 | });
|
25432 | };
|
25433 |
|
25434 | const platform = detect$1();
|
25435 | const executeKeyupAction = (editor, caret, evt) => {
|
25436 | execute([
|
25437 | {
|
25438 | keyCode: VK.PAGE_UP,
|
25439 | action: action(moveToLineEndPoint$2, editor, false, caret)
|
25440 | },
|
25441 | {
|
25442 | keyCode: VK.PAGE_DOWN,
|
25443 | action: action(moveToLineEndPoint$2, editor, true, caret)
|
25444 | }
|
25445 | ], evt);
|
25446 | };
|
25447 | const stopImmediatePropagation = e => e.stopImmediatePropagation();
|
25448 | const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
|
25449 | const setNodeChangeBlocker = (blocked, editor, block) => {
|
25450 | if (block && !blocked.get()) {
|
25451 | editor.on('NodeChange', stopImmediatePropagation, true);
|
25452 | } else if (!block && blocked.get()) {
|
25453 | editor.off('NodeChange', stopImmediatePropagation);
|
25454 | }
|
25455 | blocked.set(block);
|
25456 | };
|
25457 | const setup$f = (editor, caret) => {
|
25458 | if (platform.os.isMacOS()) {
|
25459 | return;
|
25460 | }
|
25461 | const blocked = Cell(false);
|
25462 | editor.on('keydown', evt => {
|
25463 | if (isPageUpDown(evt)) {
|
25464 | setNodeChangeBlocker(blocked, editor, true);
|
25465 | }
|
25466 | });
|
25467 | editor.on('keyup', evt => {
|
25468 | if (!evt.isDefaultPrevented()) {
|
25469 | executeKeyupAction(editor, caret, evt);
|
25470 | }
|
25471 | if (isPageUpDown(evt) && blocked.get()) {
|
25472 | setNodeChangeBlocker(blocked, editor, false);
|
25473 | editor.nodeChanged();
|
25474 | }
|
25475 | });
|
25476 | };
|
25477 |
|
25478 | const setup$e = editor => {
|
25479 | editor.on('beforeinput', e => {
|
25480 | if (!editor.selection.isEditable() || exists(e.getTargetRanges(), rng => !isEditableRange(editor.dom, rng))) {
|
25481 | e.preventDefault();
|
25482 | }
|
25483 | });
|
25484 | };
|
25485 |
|
25486 | const insertTextAtPosition = (text, pos) => {
|
25487 | const container = pos.container();
|
25488 | const offset = pos.offset();
|
25489 | if (isText$b(container)) {
|
25490 | container.insertData(offset, text);
|
25491 | return Optional.some(CaretPosition(container, offset + text.length));
|
25492 | } else {
|
25493 | return getElementFromPosition(pos).map(elm => {
|
25494 | const textNode = SugarElement.fromText(text);
|
25495 | if (pos.isAtEnd()) {
|
25496 | after$4(elm, textNode);
|
25497 | } else {
|
25498 | before$3(elm, textNode);
|
25499 | }
|
25500 | return CaretPosition(textNode.dom, text.length);
|
25501 | });
|
25502 | }
|
25503 | };
|
25504 | const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
|
25505 | const insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
|
25506 |
|
25507 | const insertSpaceOrNbspAtPosition = (root, pos, schema) => needsToHaveNbsp(root, pos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
|
25508 | const locationToCaretPosition = root => location => location.fold(element => prevPosition(root.dom, CaretPosition.before(element)), element => firstPositionIn(element), element => lastPositionIn(element), element => nextPosition(root.dom, CaretPosition.after(element)));
|
25509 | const insertInlineBoundarySpaceOrNbsp = (root, pos, schema) => checkPos => needsToHaveNbsp(root, checkPos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
|
25510 | const setSelection = editor => pos => {
|
25511 | editor.selection.setRng(pos.toRange());
|
25512 | editor.nodeChanged();
|
25513 | };
|
25514 | const isInsideSummary = (domUtils, node) => domUtils.isEditable(domUtils.getParent(node, 'summary'));
|
25515 | const insertSpaceOrNbspAtSelection = editor => {
|
25516 | const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
25517 | const root = SugarElement.fromDom(editor.getBody());
|
25518 | if (editor.selection.isCollapsed()) {
|
25519 | const isInlineTarget$1 = curry(isInlineTarget, editor);
|
25520 | const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
|
25521 | return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos, editor.schema)(checkPos).each(setSelection(editor)));
|
25522 | } else {
|
25523 | return Optional.none();
|
25524 | }
|
25525 | };
|
25526 | const insertSpaceInSummaryAtSelectionOnFirefox = editor => {
|
25527 | const insertSpaceThunk = () => {
|
25528 | const root = SugarElement.fromDom(editor.getBody());
|
25529 | if (!editor.selection.isCollapsed()) {
|
25530 | editor.getDoc().execCommand('Delete');
|
25531 | }
|
25532 | const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
25533 | insertSpaceOrNbspAtPosition(root, pos, editor.schema).each(setSelection(editor));
|
25534 | };
|
25535 | return someIf(Env.browser.isFirefox() && editor.selection.isEditable() && isInsideSummary(editor.dom, editor.selection.getRng().startContainer), insertSpaceThunk);
|
25536 | };
|
25537 |
|
25538 | const executeKeydownOverride$1 = (editor, evt) => {
|
25539 | executeWithDelayedAction([
|
25540 | {
|
25541 | keyCode: VK.SPACEBAR,
|
25542 | action: action(insertSpaceOrNbspAtSelection, editor)
|
25543 | },
|
25544 | {
|
25545 | keyCode: VK.SPACEBAR,
|
25546 | action: action(insertSpaceInSummaryAtSelectionOnFirefox, editor)
|
25547 | }
|
25548 | ], evt).each(applyAction => {
|
25549 | evt.preventDefault();
|
25550 | const event = fireBeforeInputEvent(editor, 'insertText', { data: ' ' });
|
25551 | if (!event.isDefaultPrevented()) {
|
25552 | applyAction();
|
25553 | fireInputEvent(editor, 'insertText', { data: ' ' });
|
25554 | }
|
25555 | });
|
25556 | };
|
25557 | const setup$d = editor => {
|
25558 | editor.on('keydown', evt => {
|
25559 | if (!evt.isDefaultPrevented()) {
|
25560 | executeKeydownOverride$1(editor, evt);
|
25561 | }
|
25562 | });
|
25563 | };
|
25564 |
|
25565 | const tableTabNavigation = editor => {
|
25566 | if (hasTableTabNavigation(editor)) {
|
25567 | return [
|
25568 | {
|
25569 | keyCode: VK.TAB,
|
25570 | action: action(handleTab, editor, true)
|
25571 | },
|
25572 | {
|
25573 | keyCode: VK.TAB,
|
25574 | shiftKey: true,
|
25575 | action: action(handleTab, editor, false)
|
25576 | }
|
25577 | ];
|
25578 | } else {
|
25579 | return [];
|
25580 | }
|
25581 | };
|
25582 | const executeKeydownOverride = (editor, evt) => {
|
25583 | execute([...tableTabNavigation(editor)], evt).each(_ => {
|
25584 | evt.preventDefault();
|
25585 | });
|
25586 | };
|
25587 | const setup$c = editor => {
|
25588 | editor.on('keydown', evt => {
|
25589 | if (!evt.isDefaultPrevented()) {
|
25590 | executeKeydownOverride(editor, evt);
|
25591 | }
|
25592 | });
|
25593 | };
|
25594 |
|
25595 | const setup$b = editor => {
|
25596 | editor.addShortcut('Meta+P', '', 'mcePrint');
|
25597 | setup$k(editor);
|
25598 | if (isRtc(editor)) {
|
25599 | return Cell(null);
|
25600 | } else {
|
25601 | const caret = setupSelectedState(editor);
|
25602 | setup$e(editor);
|
25603 | setup$m(editor);
|
25604 | setup$l(editor, caret);
|
25605 | setup$j(editor, caret);
|
25606 | setup$i(editor);
|
25607 | setup$d(editor);
|
25608 | setup$g(editor);
|
25609 | setup$c(editor);
|
25610 | setup$h(editor, caret);
|
25611 | setup$f(editor, caret);
|
25612 | return caret;
|
25613 | }
|
25614 | };
|
25615 |
|
25616 | class NodeChange {
|
25617 | constructor(editor) {
|
25618 | this.lastPath = [];
|
25619 | this.editor = editor;
|
25620 | let lastRng;
|
25621 | const self = this;
|
25622 | if (!('onselectionchange' in editor.getDoc())) {
|
25623 | editor.on('NodeChange click mouseup keyup focus', e => {
|
25624 | const nativeRng = editor.selection.getRng();
|
25625 | const fakeRng = {
|
25626 | startContainer: nativeRng.startContainer,
|
25627 | startOffset: nativeRng.startOffset,
|
25628 | endContainer: nativeRng.endContainer,
|
25629 | endOffset: nativeRng.endOffset
|
25630 | };
|
25631 | if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) {
|
25632 | editor.dispatch('SelectionChange');
|
25633 | }
|
25634 | lastRng = fakeRng;
|
25635 | });
|
25636 | }
|
25637 | editor.on('contextmenu', () => {
|
25638 | store(editor);
|
25639 | editor.dispatch('SelectionChange');
|
25640 | });
|
25641 | editor.on('SelectionChange', () => {
|
25642 | const startElm = editor.selection.getStart(true);
|
25643 | if (!startElm) {
|
25644 | return;
|
25645 | }
|
25646 | if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
|
25647 | editor.nodeChanged({ selectionChange: true });
|
25648 | }
|
25649 | });
|
25650 | editor.on('mouseup', e => {
|
25651 | if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
|
25652 | if (editor.selection.getNode().nodeName === 'IMG') {
|
25653 | Delay.setEditorTimeout(editor, () => {
|
25654 | editor.nodeChanged();
|
25655 | });
|
25656 | } else {
|
25657 | editor.nodeChanged();
|
25658 | }
|
25659 | }
|
25660 | });
|
25661 | }
|
25662 | nodeChanged(args = {}) {
|
25663 | const selection = this.editor.selection;
|
25664 | let node;
|
25665 | if (this.editor.initialized && selection && !shouldDisableNodeChange(this.editor) && !this.editor.mode.isReadOnly()) {
|
25666 | const root = this.editor.getBody();
|
25667 | node = selection.getStart(true) || root;
|
25668 | if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
|
25669 | node = root;
|
25670 | }
|
25671 | const parents = [];
|
25672 | this.editor.dom.getParent(node, node => {
|
25673 | if (node === root) {
|
25674 | return true;
|
25675 | } else {
|
25676 | parents.push(node);
|
25677 | return false;
|
25678 | }
|
25679 | });
|
25680 | this.editor.dispatch('NodeChange', {
|
25681 | ...args,
|
25682 | element: node,
|
25683 | parents
|
25684 | });
|
25685 | }
|
25686 | }
|
25687 | isSameElementPath(startElm) {
|
25688 | let i;
|
25689 | const editor = this.editor;
|
25690 | const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
|
25691 | if (currentPath.length === this.lastPath.length) {
|
25692 | for (i = currentPath.length; i >= 0; i--) {
|
25693 | if (currentPath[i] !== this.lastPath[i]) {
|
25694 | break;
|
25695 | }
|
25696 | }
|
25697 | if (i === -1) {
|
25698 | this.lastPath = currentPath;
|
25699 | return true;
|
25700 | }
|
25701 | }
|
25702 | this.lastPath = currentPath;
|
25703 | return false;
|
25704 | }
|
25705 | }
|
25706 |
|
25707 | const imageId = generate$1('image');
|
25708 | const getDragImage = transfer => {
|
25709 | const dt = transfer;
|
25710 | return Optional.from(dt[imageId]);
|
25711 | };
|
25712 | const setDragImage = (transfer, imageData) => {
|
25713 | const dt = transfer;
|
25714 | dt[imageId] = imageData;
|
25715 | };
|
25716 |
|
25717 | const eventId = generate$1('event');
|
25718 | const getEvent = transfer => {
|
25719 | const dt = transfer;
|
25720 | return Optional.from(dt[eventId]);
|
25721 | };
|
25722 | const mkSetEventFn = type => transfer => {
|
25723 | const dt = transfer;
|
25724 | dt[eventId] = type;
|
25725 | };
|
25726 | const setEvent = (transfer, type) => mkSetEventFn(type)(transfer);
|
25727 | const setDragstartEvent = mkSetEventFn(0);
|
25728 | const setDropEvent = mkSetEventFn(2);
|
25729 | const setDragendEvent = mkSetEventFn(1);
|
25730 | const checkEvent = expectedType => transfer => {
|
25731 | const dt = transfer;
|
25732 | return Optional.from(dt[eventId]).exists(type => type === expectedType);
|
25733 | };
|
25734 | const isInDragStartEvent = checkEvent(0);
|
25735 |
|
25736 | const createEmptyFileList = () => Object.freeze({
|
25737 | length: 0,
|
25738 | item: _ => null
|
25739 | });
|
25740 |
|
25741 | const modeId = generate$1('mode');
|
25742 | const getMode = transfer => {
|
25743 | const dt = transfer;
|
25744 | return Optional.from(dt[modeId]);
|
25745 | };
|
25746 | const mkSetModeFn = mode => transfer => {
|
25747 | const dt = transfer;
|
25748 | dt[modeId] = mode;
|
25749 | };
|
25750 | const setMode$1 = (transfer, mode) => mkSetModeFn(mode)(transfer);
|
25751 | const setReadWriteMode = mkSetModeFn(0);
|
25752 | const setReadOnlyMode = mkSetModeFn(2);
|
25753 | const setProtectedMode = mkSetModeFn(1);
|
25754 | const checkMode = expectedMode => transfer => {
|
25755 | const dt = transfer;
|
25756 | return Optional.from(dt[modeId]).exists(mode => mode === expectedMode);
|
25757 | };
|
25758 | const isInReadWriteMode = checkMode(0);
|
25759 | const isInProtectedMode = checkMode(1);
|
25760 |
|
25761 | const normalizeItems = (dataTransfer, itemsImpl) => ({
|
25762 | ...itemsImpl,
|
25763 | get length() {
|
25764 | return itemsImpl.length;
|
25765 | },
|
25766 | add: (data, type) => {
|
25767 | if (isInReadWriteMode(dataTransfer)) {
|
25768 | if (isString(data)) {
|
25769 | if (!isUndefined(type)) {
|
25770 | return itemsImpl.add(data, type);
|
25771 | }
|
25772 | } else {
|
25773 | return itemsImpl.add(data);
|
25774 | }
|
25775 | }
|
25776 | return null;
|
25777 | },
|
25778 | remove: idx => {
|
25779 | if (isInReadWriteMode(dataTransfer)) {
|
25780 | itemsImpl.remove(idx);
|
25781 | }
|
25782 | },
|
25783 | clear: () => {
|
25784 | if (isInReadWriteMode(dataTransfer)) {
|
25785 | itemsImpl.clear();
|
25786 | }
|
25787 | }
|
25788 | });
|
25789 |
|
25790 | const validDropEffects = [
|
25791 | 'none',
|
25792 | 'copy',
|
25793 | 'link',
|
25794 | 'move'
|
25795 | ];
|
25796 | const validEffectAlloweds = [
|
25797 | 'none',
|
25798 | 'copy',
|
25799 | 'copyLink',
|
25800 | 'copyMove',
|
25801 | 'link',
|
25802 | 'linkMove',
|
25803 | 'move',
|
25804 | 'all',
|
25805 | 'uninitialized'
|
25806 | ];
|
25807 | const createDataTransfer = () => {
|
25808 | const dataTransferImpl = new window.DataTransfer();
|
25809 | let dropEffect = 'move';
|
25810 | let effectAllowed = 'all';
|
25811 | const dataTransfer = {
|
25812 | get dropEffect() {
|
25813 | return dropEffect;
|
25814 | },
|
25815 | set dropEffect(effect) {
|
25816 | if (contains$2(validDropEffects, effect)) {
|
25817 | dropEffect = effect;
|
25818 | }
|
25819 | },
|
25820 | get effectAllowed() {
|
25821 | return effectAllowed;
|
25822 | },
|
25823 | set effectAllowed(allowed) {
|
25824 | if (isInDragStartEvent(dataTransfer) && contains$2(validEffectAlloweds, allowed)) {
|
25825 | effectAllowed = allowed;
|
25826 | }
|
25827 | },
|
25828 | get items() {
|
25829 | return normalizeItems(dataTransfer, dataTransferImpl.items);
|
25830 | },
|
25831 | get files() {
|
25832 | if (isInProtectedMode(dataTransfer)) {
|
25833 | return createEmptyFileList();
|
25834 | } else {
|
25835 | return dataTransferImpl.files;
|
25836 | }
|
25837 | },
|
25838 | get types() {
|
25839 | return dataTransferImpl.types;
|
25840 | },
|
25841 | setDragImage: (image, x, y) => {
|
25842 | if (isInReadWriteMode(dataTransfer)) {
|
25843 | setDragImage(dataTransfer, {
|
25844 | image,
|
25845 | x,
|
25846 | y
|
25847 | });
|
25848 | dataTransferImpl.setDragImage(image, x, y);
|
25849 | }
|
25850 | },
|
25851 | getData: format => {
|
25852 | if (isInProtectedMode(dataTransfer)) {
|
25853 | return '';
|
25854 | } else {
|
25855 | return dataTransferImpl.getData(format);
|
25856 | }
|
25857 | },
|
25858 | setData: (format, data) => {
|
25859 | if (isInReadWriteMode(dataTransfer)) {
|
25860 | dataTransferImpl.setData(format, data);
|
25861 | }
|
25862 | },
|
25863 | clearData: format => {
|
25864 | if (isInReadWriteMode(dataTransfer)) {
|
25865 | dataTransferImpl.clearData(format);
|
25866 | }
|
25867 | }
|
25868 | };
|
25869 | setReadWriteMode(dataTransfer);
|
25870 | return dataTransfer;
|
25871 | };
|
25872 | const cloneDataTransfer = original => {
|
25873 | const clone = createDataTransfer();
|
25874 | const originalMode = getMode(original);
|
25875 | setReadOnlyMode(original);
|
25876 | setDragstartEvent(clone);
|
25877 | clone.dropEffect = original.dropEffect;
|
25878 | clone.effectAllowed = original.effectAllowed;
|
25879 | getDragImage(original).each(imageData => clone.setDragImage(imageData.image, imageData.x, imageData.y));
|
25880 | each$e(original.types, type => {
|
25881 | if (type !== 'Files') {
|
25882 | clone.setData(type, original.getData(type));
|
25883 | }
|
25884 | });
|
25885 | each$e(original.files, file => clone.items.add(file));
|
25886 | getEvent(original).each(type => {
|
25887 | setEvent(clone, type);
|
25888 | });
|
25889 | originalMode.each(mode => {
|
25890 | setMode$1(original, mode);
|
25891 | setMode$1(clone, mode);
|
25892 | });
|
25893 | return clone;
|
25894 | };
|
25895 |
|
25896 | const getHtmlData = dataTransfer => {
|
25897 | const html = dataTransfer.getData('text/html');
|
25898 | return html === '' ? Optional.none() : Optional.some(html);
|
25899 | };
|
25900 | const setHtmlData = (dataTransfer, html) => dataTransfer.setData('text/html', html);
|
25901 |
|
25902 | const internalMimeType = 'x-tinymce/html';
|
25903 | const internalHtmlMime = constant(internalMimeType);
|
25904 | const internalMark = '<!-- ' + internalMimeType + ' -->';
|
25905 | const mark = html => internalMark + html;
|
25906 | const unmark = html => html.replace(internalMark, '');
|
25907 | const isMarked = html => html.indexOf(internalMark) !== -1;
|
25908 |
|
25909 | const isPlainText = text => {
|
25910 | return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
|
25911 | };
|
25912 | const openContainer = (rootTag, rootAttrs) => {
|
25913 | let tag = '<' + rootTag;
|
25914 | const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"');
|
25915 | if (attrs.length) {
|
25916 | tag += ' ' + attrs.join(' ');
|
25917 | }
|
25918 | return tag + '>';
|
25919 | };
|
25920 | const toBlockElements = (text, rootTag, rootAttrs) => {
|
25921 | const blocks = text.split(/\n\n/);
|
25922 | const tagOpen = openContainer(rootTag, rootAttrs);
|
25923 | const tagClose = '</' + rootTag + '>';
|
25924 | const paragraphs = map$3(blocks, p => {
|
25925 | return p.split(/\n/).join('<br />');
|
25926 | });
|
25927 | const stitch = p => {
|
25928 | return tagOpen + p + tagClose;
|
25929 | };
|
25930 | return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join('');
|
25931 | };
|
25932 |
|
25933 | const pasteBinDefaultContent = '%MCEPASTEBIN%';
|
25934 | const create$6 = (editor, lastRngCell) => {
|
25935 | const {dom, selection} = editor;
|
25936 | const body = editor.getBody();
|
25937 | lastRngCell.set(selection.getRng());
|
25938 | const pasteBinElm = dom.add(editor.getBody(), 'div', {
|
25939 | 'id': 'mcepastebin',
|
25940 | 'class': 'mce-pastebin',
|
25941 | 'contentEditable': true,
|
25942 | 'data-mce-bogus': 'all',
|
25943 | 'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0'
|
25944 | }, pasteBinDefaultContent);
|
25945 | if (Env.browser.isFirefox()) {
|
25946 | dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535);
|
25947 | }
|
25948 | dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => {
|
25949 | e.stopPropagation();
|
25950 | });
|
25951 | pasteBinElm.focus();
|
25952 | selection.select(pasteBinElm, true);
|
25953 | };
|
25954 | const remove = (editor, lastRngCell) => {
|
25955 | const dom = editor.dom;
|
25956 | if (getEl(editor)) {
|
25957 | let pasteBinClone;
|
25958 | const lastRng = lastRngCell.get();
|
25959 | while (pasteBinClone = getEl(editor)) {
|
25960 | dom.remove(pasteBinClone);
|
25961 | dom.unbind(pasteBinClone);
|
25962 | }
|
25963 | if (lastRng) {
|
25964 | editor.selection.setRng(lastRng);
|
25965 | }
|
25966 | }
|
25967 | lastRngCell.set(null);
|
25968 | };
|
25969 | const getEl = editor => editor.dom.get('mcepastebin');
|
25970 | const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin';
|
25971 | const getHtml = editor => {
|
25972 | const dom = editor.dom;
|
25973 | const copyAndRemove = (toElm, fromElm) => {
|
25974 | toElm.appendChild(fromElm);
|
25975 | dom.remove(fromElm, true);
|
25976 | };
|
25977 | const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin);
|
25978 | each$e(pasteBinClones, pasteBinClone => {
|
25979 | copyAndRemove(pasteBinElm, pasteBinClone);
|
25980 | });
|
25981 | const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm);
|
25982 | for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
|
25983 | const cleanWrapper = dom.create('div');
|
25984 | pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
|
25985 | copyAndRemove(cleanWrapper, dirtyWrappers[i]);
|
25986 | }
|
25987 | return pasteBinElm ? pasteBinElm.innerHTML : '';
|
25988 | };
|
25989 | const isDefaultPasteBinContent = content => content === pasteBinDefaultContent;
|
25990 | const PasteBin = editor => {
|
25991 | const lastRng = Cell(null);
|
25992 | return {
|
25993 | create: () => create$6(editor, lastRng),
|
25994 | remove: () => remove(editor, lastRng),
|
25995 | getEl: () => getEl(editor),
|
25996 | getHtml: () => getHtml(editor),
|
25997 | getLastRng: lastRng.get
|
25998 | };
|
25999 | };
|
26000 |
|
26001 | const filter$1 = (content, items) => {
|
26002 | Tools.each(items, v => {
|
26003 | if (is$4(v, RegExp)) {
|
26004 | content = content.replace(v, '');
|
26005 | } else {
|
26006 | content = content.replace(v[0], v[1]);
|
26007 | }
|
26008 | });
|
26009 | return content;
|
26010 | };
|
26011 | const innerText = html => {
|
26012 | const schema = Schema();
|
26013 | const domParser = DomParser({}, schema);
|
26014 | let text = '';
|
26015 | const voidElements = schema.getVoidElements();
|
26016 | const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
|
26017 | const blockElements = schema.getBlockElements();
|
26018 | const walk = node => {
|
26019 | const name = node.name, currentNode = node;
|
26020 | if (name === 'br') {
|
26021 | text += '\n';
|
26022 | return;
|
26023 | }
|
26024 | if (name === 'wbr') {
|
26025 | return;
|
26026 | }
|
26027 | if (voidElements[name]) {
|
26028 | text += ' ';
|
26029 | }
|
26030 | if (ignoreElements[name]) {
|
26031 | text += ' ';
|
26032 | return;
|
26033 | }
|
26034 | if (node.type === 3) {
|
26035 | text += node.value;
|
26036 | }
|
26037 | if (!(node.name in schema.getVoidElements())) {
|
26038 | let currentNode = node.firstChild;
|
26039 | if (currentNode) {
|
26040 | do {
|
26041 | walk(currentNode);
|
26042 | } while (currentNode = currentNode.next);
|
26043 | }
|
26044 | }
|
26045 | if (blockElements[name] && currentNode.next) {
|
26046 | text += '\n';
|
26047 | if (name === 'p') {
|
26048 | text += '\n';
|
26049 | }
|
26050 | }
|
26051 | };
|
26052 | html = filter$1(html, [/<!\[[^\]]+\]>/g]);
|
26053 | walk(domParser.parse(html));
|
26054 | return text;
|
26055 | };
|
26056 | const trimHtml = html => {
|
26057 | const trimSpaces = (all, s1, s2) => {
|
26058 | if (!s1 && !s2) {
|
26059 | return ' ';
|
26060 | }
|
26061 | return nbsp;
|
26062 | };
|
26063 | html = filter$1(html, [
|
26064 | /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
|
26065 | /<!--StartFragment-->|<!--EndFragment-->/g,
|
26066 | [
|
26067 | /( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,
|
26068 | trimSpaces
|
26069 | ],
|
26070 | /<br class="Apple-interchange-newline">/g,
|
26071 | /<br>$/i
|
26072 | ]);
|
26073 | return html;
|
26074 | };
|
26075 | const createIdGenerator = prefix => {
|
26076 | let count = 0;
|
26077 | return () => {
|
26078 | return prefix + count++;
|
26079 | };
|
26080 | };
|
26081 | const getImageMimeType = ext => {
|
26082 | const lowerExt = ext.toLowerCase();
|
26083 | const mimeOverrides = {
|
26084 | jpg: 'jpeg',
|
26085 | jpe: 'jpeg',
|
26086 | jfi: 'jpeg',
|
26087 | jif: 'jpeg',
|
26088 | jfif: 'jpeg',
|
26089 | pjpeg: 'jpeg',
|
26090 | pjp: 'jpeg',
|
26091 | svg: 'svg+xml'
|
26092 | };
|
26093 | return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt;
|
26094 | };
|
26095 |
|
26096 | const preProcess = (editor, html) => {
|
26097 | const parser = DomParser({
|
26098 | sanitize: shouldSanitizeXss(editor),
|
26099 | sandbox_iframes: shouldSandboxIframes(editor),
|
26100 | sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
|
26101 | convert_unsafe_embeds: shouldConvertUnsafeEmbeds(editor)
|
26102 | }, editor.schema);
|
26103 | parser.addNodeFilter('meta', nodes => {
|
26104 | Tools.each(nodes, node => {
|
26105 | node.remove();
|
26106 | });
|
26107 | });
|
26108 | const fragment = parser.parse(html, {
|
26109 | forced_root_block: false,
|
26110 | isRootContent: true
|
26111 | });
|
26112 | return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
|
26113 | };
|
26114 | const processResult = (content, cancelled) => ({
|
26115 | content,
|
26116 | cancelled
|
26117 | });
|
26118 | const postProcessFilter = (editor, html, internal) => {
|
26119 | const tempBody = editor.dom.create('div', { style: 'display:none' }, html);
|
26120 | const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
|
26121 | return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
|
26122 | };
|
26123 | const filterContent = (editor, content, internal) => {
|
26124 | const preProcessArgs = firePastePreProcess(editor, content, internal);
|
26125 | const filteredContent = preProcess(editor, preProcessArgs.content);
|
26126 | if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
|
26127 | return postProcessFilter(editor, filteredContent, internal);
|
26128 | } else {
|
26129 | return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
|
26130 | }
|
26131 | };
|
26132 | const process = (editor, html, internal) => {
|
26133 | return filterContent(editor, html, internal);
|
26134 | };
|
26135 |
|
26136 | const pasteHtml$1 = (editor, html) => {
|
26137 | editor.insertContent(html, {
|
26138 | merge: shouldPasteMergeFormats(editor),
|
26139 | paste: true
|
26140 | });
|
26141 | return true;
|
26142 | };
|
26143 | const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
|
26144 | const isImageUrl = (editor, url) => {
|
26145 | return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`));
|
26146 | };
|
26147 | const createImage = (editor, url, pasteHtmlFn) => {
|
26148 | editor.undoManager.extra(() => {
|
26149 | pasteHtmlFn(editor, url);
|
26150 | }, () => {
|
26151 | editor.insertContent('<img src="' + url + '">');
|
26152 | });
|
26153 | return true;
|
26154 | };
|
26155 | const createLink = (editor, url, pasteHtmlFn) => {
|
26156 | editor.undoManager.extra(() => {
|
26157 | pasteHtmlFn(editor, url);
|
26158 | }, () => {
|
26159 | editor.execCommand('mceInsertLink', false, url);
|
26160 | });
|
26161 | return true;
|
26162 | };
|
26163 | const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false;
|
26164 | const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false;
|
26165 | const smartInsertContent = (editor, html) => {
|
26166 | Tools.each([
|
26167 | linkSelection,
|
26168 | insertImage,
|
26169 | pasteHtml$1
|
26170 | ], action => {
|
26171 | return !action(editor, html, pasteHtml$1);
|
26172 | });
|
26173 | };
|
26174 | const insertContent = (editor, html, pasteAsText) => {
|
26175 | if (pasteAsText || !isSmartPasteEnabled(editor)) {
|
26176 | pasteHtml$1(editor, html);
|
26177 | } else {
|
26178 | smartInsertContent(editor, html);
|
26179 | }
|
26180 | };
|
26181 |
|
26182 | const uniqueId = createIdGenerator('mceclip');
|
26183 | const createPasteDataTransfer = html => {
|
26184 | const dataTransfer = createDataTransfer();
|
26185 | setHtmlData(dataTransfer, html);
|
26186 | setReadOnlyMode(dataTransfer);
|
26187 | return dataTransfer;
|
26188 | };
|
26189 | const doPaste = (editor, content, internal, pasteAsText, shouldSimulateInputEvent) => {
|
26190 | const res = process(editor, content, internal);
|
26191 | if (!res.cancelled) {
|
26192 | const content = res.content;
|
26193 | const doPasteAction = () => insertContent(editor, content, pasteAsText);
|
26194 | if (shouldSimulateInputEvent) {
|
26195 | const args = fireBeforeInputEvent(editor, 'insertFromPaste', { dataTransfer: createPasteDataTransfer(content) });
|
26196 | if (!args.isDefaultPrevented()) {
|
26197 | doPasteAction();
|
26198 | fireInputEvent(editor, 'insertFromPaste');
|
26199 | }
|
26200 | } else {
|
26201 | doPasteAction();
|
26202 | }
|
26203 | }
|
26204 | };
|
26205 | const pasteHtml = (editor, html, internalFlag, shouldSimulateInputEvent) => {
|
26206 | const internal = internalFlag ? internalFlag : isMarked(html);
|
26207 | doPaste(editor, unmark(html), internal, false, shouldSimulateInputEvent);
|
26208 | };
|
26209 | const pasteText = (editor, text, shouldSimulateInputEvent) => {
|
26210 | const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n');
|
26211 | const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
|
26212 | const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
|
26213 | doPaste(editor, html, false, true, shouldSimulateInputEvent);
|
26214 | };
|
26215 | const getDataTransferItems = dataTransfer => {
|
26216 | const items = {};
|
26217 | if (dataTransfer && dataTransfer.types) {
|
26218 | for (let i = 0; i < dataTransfer.types.length; i++) {
|
26219 | const contentType = dataTransfer.types[i];
|
26220 | try {
|
26221 | items[contentType] = dataTransfer.getData(contentType);
|
26222 | } catch (ex) {
|
26223 | items[contentType] = '';
|
26224 | }
|
26225 | }
|
26226 | }
|
26227 | return items;
|
26228 | };
|
26229 | const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
|
26230 | const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
|
26231 | const extractFilename = (editor, str) => {
|
26232 | const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
|
26233 | return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined;
|
26234 | };
|
26235 | const createBlobInfo = (editor, blobCache, file, base64) => {
|
26236 | const id = uniqueId();
|
26237 | const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
|
26238 | const name = useFileName ? extractFilename(editor, file.name) : id;
|
26239 | const filename = useFileName ? file.name : undefined;
|
26240 | const blobInfo = blobCache.create(id, file, base64, name, filename);
|
26241 | blobCache.add(blobInfo);
|
26242 | return blobInfo;
|
26243 | };
|
26244 | const pasteImage = (editor, imageItem) => {
|
26245 | parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => {
|
26246 | const base64 = base64Encoded ? data : btoa(data);
|
26247 | const file = imageItem.file;
|
26248 | const blobCache = editor.editorUpload.blobCache;
|
26249 | const existingBlobInfo = blobCache.getByData(base64, type);
|
26250 | const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
|
26251 | pasteHtml(editor, `<img src="${ blobInfo.blobUri() }">`, false, true);
|
26252 | });
|
26253 | };
|
26254 | const isClipboardEvent = event => event.type === 'paste';
|
26255 | const readFilesAsDataUris = items => Promise.all(map$3(items, file => {
|
26256 | return blobToDataUri(file).then(uri => ({
|
26257 | file,
|
26258 | uri
|
26259 | }));
|
26260 | }));
|
26261 | const isImage = editor => {
|
26262 | const allowedExtensions = getAllowedImageFileTypes(editor);
|
26263 | return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => {
|
26264 | return getImageMimeType(extension) === file.type;
|
26265 | });
|
26266 | };
|
26267 | const getImagesFromDataTransfer = (editor, dataTransfer) => {
|
26268 | const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => {
|
26269 | return item.kind === 'file' ? [item.getAsFile()] : [];
|
26270 | }) : [];
|
26271 | const files = dataTransfer.files ? from(dataTransfer.files) : [];
|
26272 | return filter$5(items.length > 0 ? items : files, isImage(editor));
|
26273 | };
|
26274 | const pasteImageData = (editor, e, rng) => {
|
26275 | const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
|
26276 | if (shouldPasteDataImages(editor) && dataTransfer) {
|
26277 | const images = getImagesFromDataTransfer(editor, dataTransfer);
|
26278 | if (images.length > 0) {
|
26279 | e.preventDefault();
|
26280 | readFilesAsDataUris(images).then(fileResults => {
|
26281 | if (rng) {
|
26282 | editor.selection.setRng(rng);
|
26283 | }
|
26284 | each$e(fileResults, result => {
|
26285 | pasteImage(editor, result);
|
26286 | });
|
26287 | });
|
26288 | return true;
|
26289 | }
|
26290 | }
|
26291 | return false;
|
26292 | };
|
26293 | const isBrokenAndroidClipboardEvent = e => {
|
26294 | var _a, _b;
|
26295 | return Env.os.isAndroid() && ((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.items) === null || _b === void 0 ? void 0 : _b.length) === 0;
|
26296 | };
|
26297 | const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
|
26298 | const insertClipboardContent = (editor, clipboardContent, html, plainTextMode, shouldSimulateInputEvent) => {
|
26299 | let content = trimHtml(html);
|
26300 | const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html);
|
26301 | const isPlainTextHtml = !isInternal && isPlainText(content);
|
26302 | const isAbsoluteUrl$1 = isAbsoluteUrl(content);
|
26303 | if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
|
26304 | plainTextMode = true;
|
26305 | }
|
26306 | if (plainTextMode || isAbsoluteUrl$1) {
|
26307 | if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) {
|
26308 | content = clipboardContent['text/plain'];
|
26309 | } else {
|
26310 | content = innerText(content);
|
26311 | }
|
26312 | }
|
26313 | if (isDefaultPasteBinContent(content)) {
|
26314 | return;
|
26315 | }
|
26316 | if (plainTextMode) {
|
26317 | pasteText(editor, content, shouldSimulateInputEvent);
|
26318 | } else {
|
26319 | pasteHtml(editor, content, isInternal, shouldSimulateInputEvent);
|
26320 | }
|
26321 | };
|
26322 | const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
|
26323 | let keyboardPastePlainTextState;
|
26324 | const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
|
26325 | editor.on('keydown', e => {
|
26326 | if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
|
26327 | keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
|
26328 | }
|
26329 | });
|
26330 | editor.on('paste', e => {
|
26331 | if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
|
26332 | return;
|
26333 | }
|
26334 | const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState;
|
26335 | keyboardPastePlainTextState = false;
|
26336 | const clipboardContent = getDataTransferItems(e.clipboardData);
|
26337 | if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
|
26338 | return;
|
26339 | }
|
26340 | if (hasContentType(clipboardContent, 'text/html')) {
|
26341 | e.preventDefault();
|
26342 | insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode, true);
|
26343 | } else if (hasContentType(clipboardContent, 'text/plain') && hasContentType(clipboardContent, 'text/uri-list')) {
|
26344 | e.preventDefault();
|
26345 | insertClipboardContent(editor, clipboardContent, clipboardContent['text/plain'], plainTextMode, true);
|
26346 | } else {
|
26347 | pasteBin.create();
|
26348 | Delay.setEditorTimeout(editor, () => {
|
26349 | const html = pasteBin.getHtml();
|
26350 | pasteBin.remove();
|
26351 | insertClipboardContent(editor, clipboardContent, html, plainTextMode, false);
|
26352 | }, 0);
|
26353 | }
|
26354 | });
|
26355 | };
|
26356 | const registerDataImageFilter = editor => {
|
26357 | const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url');
|
26358 | const isDataUri = src => startsWith(src, 'data:');
|
26359 | const isPasteInsert = args => {
|
26360 | var _a;
|
26361 | return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
|
26362 | };
|
26363 | editor.parser.addNodeFilter('img', (nodes, name, args) => {
|
26364 | if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
|
26365 | for (const node of nodes) {
|
26366 | const src = node.attr('src');
|
26367 | if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) {
|
26368 | if (isWebKitFakeUrl(src)) {
|
26369 | node.remove();
|
26370 | } else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
|
26371 | node.remove();
|
26372 | }
|
26373 | }
|
26374 | }
|
26375 | }
|
26376 | });
|
26377 | };
|
26378 | const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
|
26379 | registerEventHandlers(editor, pasteBin, pasteFormat);
|
26380 | registerDataImageFilter(editor);
|
26381 | };
|
26382 |
|
26383 | const togglePlainTextPaste = (editor, pasteFormat) => {
|
26384 | if (pasteFormat.get() === 'text') {
|
26385 | pasteFormat.set('html');
|
26386 | firePastePlainTextToggle(editor, false);
|
26387 | } else {
|
26388 | pasteFormat.set('text');
|
26389 | firePastePlainTextToggle(editor, true);
|
26390 | }
|
26391 | editor.focus();
|
26392 | };
|
26393 | const register$1 = (editor, pasteFormat) => {
|
26394 | editor.addCommand('mceTogglePlainTextPaste', () => {
|
26395 | togglePlainTextPaste(editor, pasteFormat);
|
26396 | });
|
26397 | editor.addCommand('mceInsertClipboardContent', (ui, value) => {
|
26398 | if (value.html) {
|
26399 | pasteHtml(editor, value.html, value.internal, false);
|
26400 | }
|
26401 | if (value.text) {
|
26402 | pasteText(editor, value.text, false);
|
26403 | }
|
26404 | });
|
26405 | };
|
26406 |
|
26407 | const setHtml5Clipboard = (clipboardData, html, text) => {
|
26408 | if (clipboardData) {
|
26409 | try {
|
26410 | clipboardData.clearData();
|
26411 | clipboardData.setData('text/html', html);
|
26412 | clipboardData.setData('text/plain', text);
|
26413 | clipboardData.setData(internalHtmlMime(), html);
|
26414 | return true;
|
26415 | } catch (e) {
|
26416 | return false;
|
26417 | }
|
26418 | } else {
|
26419 | return false;
|
26420 | }
|
26421 | };
|
26422 | const setClipboardData = (evt, data, fallback, done) => {
|
26423 | if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
|
26424 | evt.preventDefault();
|
26425 | done();
|
26426 | } else {
|
26427 | fallback(data.html, done);
|
26428 | }
|
26429 | };
|
26430 | const fallback = editor => (html, done) => {
|
26431 | const {dom, selection} = editor;
|
26432 | const outer = dom.create('div', {
|
26433 | 'contenteditable': 'false',
|
26434 | 'data-mce-bogus': 'all'
|
26435 | });
|
26436 | const inner = dom.create('div', { contenteditable: 'true' }, html);
|
26437 | dom.setStyles(outer, {
|
26438 | position: 'fixed',
|
26439 | top: '0',
|
26440 | left: '-3000px',
|
26441 | width: '1000px',
|
26442 | overflow: 'hidden'
|
26443 | });
|
26444 | outer.appendChild(inner);
|
26445 | dom.add(editor.getBody(), outer);
|
26446 | const range = selection.getRng();
|
26447 | inner.focus();
|
26448 | const offscreenRange = dom.createRng();
|
26449 | offscreenRange.selectNodeContents(inner);
|
26450 | selection.setRng(offscreenRange);
|
26451 | Delay.setEditorTimeout(editor, () => {
|
26452 | selection.setRng(range);
|
26453 | dom.remove(outer);
|
26454 | done();
|
26455 | }, 0);
|
26456 | };
|
26457 | const getData = editor => ({
|
26458 | html: mark(editor.selection.getContent({ contextual: true })),
|
26459 | text: editor.selection.getContent({ format: 'text' })
|
26460 | });
|
26461 | const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody());
|
26462 | const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor);
|
26463 | const cut = editor => evt => {
|
26464 | if (!evt.isDefaultPrevented() && hasSelectedContent(editor) && editor.selection.isEditable()) {
|
26465 | setClipboardData(evt, getData(editor), fallback(editor), () => {
|
26466 | if (Env.browser.isChromium() || Env.browser.isFirefox()) {
|
26467 | const rng = editor.selection.getRng();
|
26468 | Delay.setEditorTimeout(editor, () => {
|
26469 | editor.selection.setRng(rng);
|
26470 | editor.execCommand('Delete');
|
26471 | }, 0);
|
26472 | } else {
|
26473 | editor.execCommand('Delete');
|
26474 | }
|
26475 | });
|
26476 | }
|
26477 | };
|
26478 | const copy = editor => evt => {
|
26479 | if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
|
26480 | setClipboardData(evt, getData(editor), fallback(editor), noop);
|
26481 | }
|
26482 | };
|
26483 | const register = editor => {
|
26484 | editor.on('cut', cut(editor));
|
26485 | editor.on('copy', copy(editor));
|
26486 | };
|
26487 |
|
26488 | const getCaretRangeFromEvent = (editor, e) => {
|
26489 | var _a, _b;
|
26490 | return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
|
26491 | };
|
26492 | const isPlainTextFileUrl = content => {
|
26493 | const plainTextContent = content['text/plain'];
|
26494 | return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false;
|
26495 | };
|
26496 | const setFocusedRange = (editor, rng) => {
|
26497 | editor.focus();
|
26498 | if (rng) {
|
26499 | editor.selection.setRng(rng);
|
26500 | }
|
26501 | };
|
26502 | const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type));
|
26503 | const needsCustomInternalDrop = (dom, schema, target, dropContent) => {
|
26504 | const parentTransparent = dom.getParent(target, node => isTransparentBlock(schema, node));
|
26505 | const inSummary = !isNull(dom.getParent(target, 'summary'));
|
26506 | if (inSummary) {
|
26507 | return true;
|
26508 | } else if (parentTransparent && has$2(dropContent, 'text/html')) {
|
26509 | const fragment = new DOMParser().parseFromString(dropContent['text/html'], 'text/html').body;
|
26510 | return !isNull(fragment.querySelector(parentTransparent.nodeName.toLowerCase()));
|
26511 | } else {
|
26512 | return false;
|
26513 | }
|
26514 | };
|
26515 | const setupSummaryDeleteByDragFix = editor => {
|
26516 | editor.on('input', e => {
|
26517 | const hasNoSummary = el => isNull(el.querySelector('summary'));
|
26518 | if (e.inputType === 'deleteByDrag') {
|
26519 | const brokenDetailElements = filter$5(editor.dom.select('details'), hasNoSummary);
|
26520 | each$e(brokenDetailElements, details => {
|
26521 | if (isBr$6(details.firstChild)) {
|
26522 | details.firstChild.remove();
|
26523 | }
|
26524 | const summary = editor.dom.create('summary');
|
26525 | summary.appendChild(createPaddingBr().dom);
|
26526 | details.prepend(summary);
|
26527 | });
|
26528 | }
|
26529 | });
|
26530 | };
|
26531 | const setup$a = (editor, draggingInternallyState) => {
|
26532 | if (shouldPasteBlockDrop(editor)) {
|
26533 | editor.on('dragend dragover draggesture dragdrop drop drag', e => {
|
26534 | e.preventDefault();
|
26535 | e.stopPropagation();
|
26536 | });
|
26537 | }
|
26538 | if (!shouldPasteDataImages(editor)) {
|
26539 | editor.on('drop', e => {
|
26540 | const dataTransfer = e.dataTransfer;
|
26541 | if (dataTransfer && hasImage(dataTransfer)) {
|
26542 | e.preventDefault();
|
26543 | }
|
26544 | });
|
26545 | }
|
26546 | editor.on('drop', e => {
|
26547 | if (e.isDefaultPrevented()) {
|
26548 | return;
|
26549 | }
|
26550 | const rng = getCaretRangeFromEvent(editor, e);
|
26551 | if (isNullable(rng)) {
|
26552 | return;
|
26553 | }
|
26554 | const dropContent = getDataTransferItems(e.dataTransfer);
|
26555 | const internal = hasContentType(dropContent, internalHtmlMime());
|
26556 | if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
|
26557 | return;
|
26558 | }
|
26559 | const internalContent = dropContent[internalHtmlMime()];
|
26560 | const content = internalContent || dropContent['text/html'] || dropContent['text/plain'];
|
26561 | const needsInternalDrop = needsCustomInternalDrop(editor.dom, editor.schema, rng.startContainer, dropContent);
|
26562 | const isInternalDrop = draggingInternallyState.get();
|
26563 | if (isInternalDrop && !needsInternalDrop) {
|
26564 | return;
|
26565 | }
|
26566 | if (content) {
|
26567 | e.preventDefault();
|
26568 | Delay.setEditorTimeout(editor, () => {
|
26569 | editor.undoManager.transact(() => {
|
26570 | if (internalContent || isInternalDrop && needsInternalDrop) {
|
26571 | editor.execCommand('Delete');
|
26572 | }
|
26573 | setFocusedRange(editor, rng);
|
26574 | const trimmedContent = trimHtml(content);
|
26575 | if (dropContent['text/html']) {
|
26576 | pasteHtml(editor, trimmedContent, internal, true);
|
26577 | } else {
|
26578 | pasteText(editor, trimmedContent, true);
|
26579 | }
|
26580 | });
|
26581 | });
|
26582 | }
|
26583 | });
|
26584 | editor.on('dragstart', _e => {
|
26585 | draggingInternallyState.set(true);
|
26586 | });
|
26587 | editor.on('dragover dragend', e => {
|
26588 | if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) {
|
26589 | e.preventDefault();
|
26590 | setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
|
26591 | }
|
26592 | if (e.type === 'dragend') {
|
26593 | draggingInternallyState.set(false);
|
26594 | }
|
26595 | });
|
26596 | setupSummaryDeleteByDragFix(editor);
|
26597 | };
|
26598 |
|
26599 | const setup$9 = editor => {
|
26600 | const processEvent = f => e => {
|
26601 | f(editor, e);
|
26602 | };
|
26603 | const preProcess = getPastePreProcess(editor);
|
26604 | if (isFunction(preProcess)) {
|
26605 | editor.on('PastePreProcess', processEvent(preProcess));
|
26606 | }
|
26607 | const postProcess = getPastePostProcess(editor);
|
26608 | if (isFunction(postProcess)) {
|
26609 | editor.on('PastePostProcess', processEvent(postProcess));
|
26610 | }
|
26611 | };
|
26612 |
|
26613 | const addPreProcessFilter = (editor, filterFunc) => {
|
26614 | editor.on('PastePreProcess', e => {
|
26615 | e.content = filterFunc(editor, e.content, e.internal);
|
26616 | });
|
26617 | };
|
26618 | const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
|
26619 | const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase();
|
26620 | const removeWebKitStyles = (editor, content, internal) => {
|
26621 | const webKitStylesOption = getPasteWebkitStyles(editor);
|
26622 | if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) {
|
26623 | return content;
|
26624 | }
|
26625 | const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
|
26626 | if (webKitStyles && webKitStylesOption !== 'none') {
|
26627 | const dom = editor.dom, node = editor.selection.getNode();
|
26628 | content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => {
|
26629 | const inputStyles = dom.parseStyle(dom.decode(value));
|
26630 | const outputStyles = {};
|
26631 | for (let i = 0; i < webKitStyles.length; i++) {
|
26632 | const inputValue = inputStyles[webKitStyles[i]];
|
26633 | let compareInput = inputValue;
|
26634 | let currentValue = dom.getStyle(node, webKitStyles[i], true);
|
26635 | if (/color/.test(webKitStyles[i])) {
|
26636 | compareInput = rgbToHex(compareInput);
|
26637 | currentValue = rgbToHex(currentValue);
|
26638 | }
|
26639 | if (currentValue !== compareInput) {
|
26640 | outputStyles[webKitStyles[i]] = inputValue;
|
26641 | }
|
26642 | }
|
26643 | const outputStyle = dom.serializeStyle(outputStyles, 'span');
|
26644 | if (outputStyle) {
|
26645 | return before + ' style="' + outputStyle + '"' + after;
|
26646 | }
|
26647 | return before + after;
|
26648 | });
|
26649 | } else {
|
26650 | content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
|
26651 | }
|
26652 | content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => {
|
26653 | return before + ' style="' + value + '"' + after;
|
26654 | });
|
26655 | return content;
|
26656 | };
|
26657 | const setup$8 = editor => {
|
26658 | if (Env.browser.isChromium() || Env.browser.isSafari()) {
|
26659 | addPreProcessFilter(editor, removeWebKitStyles);
|
26660 | }
|
26661 | };
|
26662 |
|
26663 | const setup$7 = editor => {
|
26664 | const draggingInternallyState = Cell(false);
|
26665 | const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html');
|
26666 | const pasteBin = PasteBin(editor);
|
26667 | setup$8(editor);
|
26668 | register$1(editor, pasteFormat);
|
26669 | setup$9(editor);
|
26670 | editor.on('PreInit', () => {
|
26671 | register(editor);
|
26672 | setup$a(editor, draggingInternallyState);
|
26673 | registerEventsAndFilters(editor, pasteBin, pasteFormat);
|
26674 | });
|
26675 | };
|
26676 |
|
26677 | const preventSummaryToggle = editor => {
|
26678 | editor.on('click', e => {
|
26679 | if (editor.dom.getParent(e.target, 'details')) {
|
26680 | e.preventDefault();
|
26681 | }
|
26682 | });
|
26683 | };
|
26684 | const filterDetails = editor => {
|
26685 | editor.parser.addNodeFilter('details', elms => {
|
26686 | const initialStateOption = getDetailsInitialState(editor);
|
26687 | each$e(elms, details => {
|
26688 | if (initialStateOption === 'expanded') {
|
26689 | details.attr('open', 'open');
|
26690 | } else if (initialStateOption === 'collapsed') {
|
26691 | details.attr('open', null);
|
26692 | }
|
26693 | });
|
26694 | });
|
26695 | editor.serializer.addNodeFilter('details', elms => {
|
26696 | const serializedStateOption = getDetailsSerializedState(editor);
|
26697 | each$e(elms, details => {
|
26698 | if (serializedStateOption === 'expanded') {
|
26699 | details.attr('open', 'open');
|
26700 | } else if (serializedStateOption === 'collapsed') {
|
26701 | details.attr('open', null);
|
26702 | }
|
26703 | });
|
26704 | });
|
26705 | };
|
26706 | const setup$6 = editor => {
|
26707 | preventSummaryToggle(editor);
|
26708 | filterDetails(editor);
|
26709 | };
|
26710 |
|
26711 | const isBr = isBr$6;
|
26712 | const isText = isText$b;
|
26713 | const isContentEditableFalse$2 = elm => isContentEditableFalse$b(elm.dom);
|
26714 | const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom);
|
26715 | const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm);
|
26716 | const getClosestScope = (node, rootNode, schema) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
|
26717 | const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
|
26718 | const findEdgeCaretCandidate = (startNode, scope, forward) => {
|
26719 | const walker = new DomTreeWalker(startNode, scope);
|
26720 | const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
|
26721 | let result = startNode;
|
26722 | for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) {
|
26723 | if (isCaretCandidate$3(current)) {
|
26724 | result = current;
|
26725 | }
|
26726 | }
|
26727 | return result;
|
26728 | };
|
26729 | const findClosestBlockRange = (startRng, rootNode, schema) => {
|
26730 | const startPos = CaretPosition.fromRangeStart(startRng);
|
26731 | const clickNode = startPos.getNode();
|
26732 | const scope = getClosestScope(clickNode, rootNode, schema);
|
26733 | const startNode = findEdgeCaretCandidate(clickNode, scope, false);
|
26734 | const endNode = findEdgeCaretCandidate(clickNode, scope, true);
|
26735 | const rng = document.createRange();
|
26736 | getClosestCef(startNode, scope).fold(() => {
|
26737 | if (isText(startNode)) {
|
26738 | rng.setStart(startNode, 0);
|
26739 | } else {
|
26740 | rng.setStartBefore(startNode);
|
26741 | }
|
26742 | }, cef => rng.setStartBefore(cef.dom));
|
26743 | getClosestCef(endNode, scope).fold(() => {
|
26744 | if (isText(endNode)) {
|
26745 | rng.setEnd(endNode, endNode.data.length);
|
26746 | } else {
|
26747 | rng.setEndAfter(endNode);
|
26748 | }
|
26749 | }, cef => rng.setEndAfter(cef.dom));
|
26750 | return rng;
|
26751 | };
|
26752 | const onTripleClickSelect = editor => {
|
26753 | const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody(), editor.schema);
|
26754 | editor.selection.setRng(normalize(rng));
|
26755 | };
|
26756 | const setup$5 = editor => {
|
26757 | editor.on('mousedown', e => {
|
26758 | if (e.detail >= 3) {
|
26759 | e.preventDefault();
|
26760 | onTripleClickSelect(editor);
|
26761 | }
|
26762 | });
|
26763 | };
|
26764 |
|
26765 | var FakeCaretPosition;
|
26766 | (function (FakeCaretPosition) {
|
26767 | FakeCaretPosition['Before'] = 'before';
|
26768 | FakeCaretPosition['After'] = 'after';
|
26769 | }(FakeCaretPosition || (FakeCaretPosition = {})));
|
26770 | const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
|
26771 | const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
|
26772 | const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
|
26773 | const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
|
26774 | const isOverlapping = (r1, r2) => {
|
26775 | const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
|
26776 | return collidesY(r1, r2) && overlap > 0.5;
|
26777 | };
|
26778 | const splitRectsPerAxis = (rects, y) => {
|
26779 | const intersectingRects = filter$5(rects, rect => isInsideY(y, rect));
|
26780 | return boundingClientRectFromRects(intersectingRects).fold(() => [
|
26781 | [],
|
26782 | rects
|
26783 | ], boundingRect => {
|
26784 | const {
|
26785 | pass: horizontal,
|
26786 | fail: vertical
|
26787 | } = partition$2(rects, rect => isOverlapping(rect, boundingRect));
|
26788 | return [
|
26789 | horizontal,
|
26790 | vertical
|
26791 | ];
|
26792 | });
|
26793 | };
|
26794 | const clientInfo = (rect, clientX) => {
|
26795 | return {
|
26796 | node: rect.node,
|
26797 | position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
|
26798 | };
|
26799 | };
|
26800 | const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
|
26801 | const closestChildCaretCandidateNodeRect = (children, clientX, clientY, findCloserTextNode) => {
|
26802 | const caretCandidateRect = rect => {
|
26803 | if (isCaretCandidate$3(rect.node)) {
|
26804 | return Optional.some(rect);
|
26805 | } else if (isElement$6(rect.node)) {
|
26806 | return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY, false);
|
26807 | } else {
|
26808 | return Optional.none();
|
26809 | }
|
26810 | };
|
26811 | const tryFindSecondBestTextNode = (closest, sndClosest, distance) => {
|
26812 | return caretCandidateRect(sndClosest).filter(rect => {
|
26813 | const deltaDistance = Math.abs(distance(closest, clientX, clientY) - distance(rect, clientX, clientY));
|
26814 | return deltaDistance < 2 && isText$b(rect.node);
|
26815 | });
|
26816 | };
|
26817 | const findClosestCaretCandidateNodeRect = (rects, distance) => {
|
26818 | const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
|
26819 | return findMap(sortedRects, caretCandidateRect).map(closest => {
|
26820 | if (findCloserTextNode && !isText$b(closest.node) && sortedRects.length > 1) {
|
26821 | return tryFindSecondBestTextNode(closest, sortedRects[1], distance).getOr(closest);
|
26822 | } else {
|
26823 | return closest;
|
26824 | }
|
26825 | });
|
26826 | };
|
26827 | const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY);
|
26828 | const {
|
26829 | pass: above,
|
26830 | fail: below
|
26831 | } = partition$2(verticalRects, rect => rect.top < clientY);
|
26832 | return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
|
26833 | };
|
26834 | const traverseUp = (rootElm, scope, clientX, clientY) => {
|
26835 | const helper = (scope, prevScope) => {
|
26836 | const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container');
|
26837 | const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer));
|
26838 | return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY, true), prevScope => {
|
26839 | const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom);
|
26840 | return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY, true);
|
26841 | }).orThunk(() => {
|
26842 | const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope);
|
26843 | return parent.bind(newScope => helper(newScope, Optional.some(scope)));
|
26844 | });
|
26845 | };
|
26846 | return helper(scope, Optional.none());
|
26847 | };
|
26848 | const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
|
26849 | const rootElm = SugarElement.fromDom(root);
|
26850 | const ownerDoc = documentOrOwner(rootElm);
|
26851 | const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm));
|
26852 | const element = elementAtPoint.getOr(rootElm);
|
26853 | return traverseUp(rootElm, element, clientX, clientY);
|
26854 | };
|
26855 | const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX));
|
26856 |
|
26857 | const getAbsolutePosition = elm => {
|
26858 | var _a, _b;
|
26859 | const clientRect = elm.getBoundingClientRect();
|
26860 | const doc = elm.ownerDocument;
|
26861 | const docElem = doc.documentElement;
|
26862 | const win = doc.defaultView;
|
26863 | return {
|
26864 | top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop,
|
26865 | left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft
|
26866 | };
|
26867 | };
|
26868 | const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : {
|
26869 | left: 0,
|
26870 | top: 0
|
26871 | };
|
26872 | const getScrollPosition = editor => {
|
26873 | const body = editor.getBody();
|
26874 | return editor.inline ? {
|
26875 | left: body.scrollLeft,
|
26876 | top: body.scrollTop
|
26877 | } : {
|
26878 | left: 0,
|
26879 | top: 0
|
26880 | };
|
26881 | };
|
26882 | const getBodyScroll = editor => {
|
26883 | const body = editor.getBody(), docElm = editor.getDoc().documentElement;
|
26884 | const inlineScroll = {
|
26885 | left: body.scrollLeft,
|
26886 | top: body.scrollTop
|
26887 | };
|
26888 | const iframeScroll = {
|
26889 | left: body.scrollLeft || docElm.scrollLeft,
|
26890 | top: body.scrollTop || docElm.scrollTop
|
26891 | };
|
26892 | return editor.inline ? inlineScroll : iframeScroll;
|
26893 | };
|
26894 | const getMousePosition = (editor, event) => {
|
26895 | if (event.target.ownerDocument !== editor.getDoc()) {
|
26896 | const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
|
26897 | const scrollPosition = getBodyScroll(editor);
|
26898 | return {
|
26899 | left: event.pageX - iframePosition.left + scrollPosition.left,
|
26900 | top: event.pageY - iframePosition.top + scrollPosition.top
|
26901 | };
|
26902 | }
|
26903 | return {
|
26904 | left: event.pageX,
|
26905 | top: event.pageY
|
26906 | };
|
26907 | };
|
26908 | const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
|
26909 | pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
|
26910 | pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
|
26911 | });
|
26912 | const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
|
26913 |
|
26914 | const getTargetProps = target => ({
|
26915 | target,
|
26916 | srcElement: target
|
26917 | });
|
26918 | const makeDndEventFromMouseEvent = (type, mouseEvent, target, dataTransfer) => ({
|
26919 | ...mouseEvent,
|
26920 | dataTransfer,
|
26921 | type,
|
26922 | ...getTargetProps(target)
|
26923 | });
|
26924 | const makeDndEvent = (type, target, dataTransfer) => {
|
26925 | const fail = die('Function not supported on simulated event.');
|
26926 | const event = {
|
26927 | bubbles: true,
|
26928 | cancelBubble: false,
|
26929 | cancelable: true,
|
26930 | composed: false,
|
26931 | currentTarget: null,
|
26932 | defaultPrevented: false,
|
26933 | eventPhase: 0,
|
26934 | isTrusted: true,
|
26935 | returnValue: false,
|
26936 | timeStamp: 0,
|
26937 | type,
|
26938 | composedPath: fail,
|
26939 | initEvent: fail,
|
26940 | preventDefault: noop,
|
26941 | stopImmediatePropagation: noop,
|
26942 | stopPropagation: noop,
|
26943 | AT_TARGET: window.Event.AT_TARGET,
|
26944 | BUBBLING_PHASE: window.Event.BUBBLING_PHASE,
|
26945 | CAPTURING_PHASE: window.Event.CAPTURING_PHASE,
|
26946 | NONE: window.Event.NONE,
|
26947 | altKey: false,
|
26948 | button: 0,
|
26949 | buttons: 0,
|
26950 | clientX: 0,
|
26951 | clientY: 0,
|
26952 | ctrlKey: false,
|
26953 | metaKey: false,
|
26954 | movementX: 0,
|
26955 | movementY: 0,
|
26956 | offsetX: 0,
|
26957 | offsetY: 0,
|
26958 | pageX: 0,
|
26959 | pageY: 0,
|
26960 | relatedTarget: null,
|
26961 | screenX: 0,
|
26962 | screenY: 0,
|
26963 | shiftKey: false,
|
26964 | x: 0,
|
26965 | y: 0,
|
26966 | detail: 0,
|
26967 | view: null,
|
26968 | which: 0,
|
26969 | initUIEvent: fail,
|
26970 | initMouseEvent: fail,
|
26971 | getModifierState: fail,
|
26972 | dataTransfer,
|
26973 | ...getTargetProps(target)
|
26974 | };
|
26975 | return event;
|
26976 | };
|
26977 | const makeDataTransferCopyForDragEvent = (dataTransfer, eventType) => {
|
26978 | const copy = cloneDataTransfer(dataTransfer);
|
26979 | if (eventType === 'dragstart') {
|
26980 | setDragstartEvent(copy);
|
26981 | setReadWriteMode(copy);
|
26982 | } else if (eventType === 'drop') {
|
26983 | setDropEvent(copy);
|
26984 | setReadOnlyMode(copy);
|
26985 | } else {
|
26986 | setDragendEvent(copy);
|
26987 | setProtectedMode(copy);
|
26988 | }
|
26989 | return copy;
|
26990 | };
|
26991 | const makeDragEvent = (type, target, dataTransfer, mouseEvent) => {
|
26992 | const dataTransferForDispatch = makeDataTransferCopyForDragEvent(dataTransfer, type);
|
26993 | return isUndefined(mouseEvent) ? makeDndEvent(type, target, dataTransferForDispatch) : makeDndEventFromMouseEvent(type, mouseEvent, target, dataTransferForDispatch);
|
26994 | };
|
26995 |
|
26996 | const scrollPixelsPerInterval = 32;
|
26997 | const scrollIntervalValue = 100;
|
26998 | const mouseRangeToTriggerScrollInsideEditor = 8;
|
26999 | const mouseRangeToTriggerScrollOutsideEditor = 16;
|
27000 | const isContentEditableFalse$1 = isContentEditableFalse$b;
|
27001 | const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3);
|
27002 | const isDraggable = (dom, rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm && dom.isEditable(elm.parentElement);
|
27003 | const isValidDropTarget = (editor, targetElement, dragElement) => {
|
27004 | if (isNullable(targetElement)) {
|
27005 | return false;
|
27006 | } else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
|
27007 | return false;
|
27008 | } else {
|
27009 | return editor.dom.isEditable(targetElement);
|
27010 | }
|
27011 | };
|
27012 | const createGhost = (editor, elm, width, height) => {
|
27013 | const dom = editor.dom;
|
27014 | const clonedElm = elm.cloneNode(true);
|
27015 | dom.setStyles(clonedElm, {
|
27016 | width,
|
27017 | height
|
27018 | });
|
27019 | dom.setAttrib(clonedElm, 'data-mce-selected', null);
|
27020 | const ghostElm = dom.create('div', {
|
27021 | 'class': 'mce-drag-container',
|
27022 | 'data-mce-bogus': 'all',
|
27023 | 'unselectable': 'on',
|
27024 | 'contenteditable': 'false'
|
27025 | });
|
27026 | dom.setStyles(ghostElm, {
|
27027 | position: 'absolute',
|
27028 | opacity: 0.5,
|
27029 | overflow: 'hidden',
|
27030 | border: 0,
|
27031 | padding: 0,
|
27032 | margin: 0,
|
27033 | width,
|
27034 | height
|
27035 | });
|
27036 | dom.setStyles(clonedElm, {
|
27037 | margin: 0,
|
27038 | boxSizing: 'border-box'
|
27039 | });
|
27040 | ghostElm.appendChild(clonedElm);
|
27041 | return ghostElm;
|
27042 | };
|
27043 | const appendGhostToBody = (ghostElm, bodyElm) => {
|
27044 | if (ghostElm.parentNode !== bodyElm) {
|
27045 | bodyElm.appendChild(ghostElm);
|
27046 | }
|
27047 | };
|
27048 | const scrollEditor = (direction, amount) => win => () => {
|
27049 | const current = direction === 'left' ? win.scrollX : win.scrollY;
|
27050 | win.scroll({
|
27051 | [direction]: current + amount,
|
27052 | behavior: 'smooth'
|
27053 | });
|
27054 | };
|
27055 | const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval);
|
27056 | const scrollRight = scrollEditor('left', scrollPixelsPerInterval);
|
27057 | const scrollUp = scrollEditor('top', -scrollPixelsPerInterval);
|
27058 | const scrollDown = scrollEditor('top', scrollPixelsPerInterval);
|
27059 | const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => {
|
27060 | let overflowX = 0, overflowY = 0;
|
27061 | ghostElm.style.left = position.pageX + 'px';
|
27062 | ghostElm.style.top = position.pageY + 'px';
|
27063 | if (position.pageX + width > maxX) {
|
27064 | overflowX = position.pageX + width - maxX;
|
27065 | }
|
27066 | if (position.pageY + height > maxY) {
|
27067 | overflowY = position.pageY + height - maxY;
|
27068 | }
|
27069 | ghostElm.style.width = width - overflowX + 'px';
|
27070 | ghostElm.style.height = height - overflowY + 'px';
|
27071 | const clientHeight = contentAreaContainer.clientHeight;
|
27072 | const clientWidth = contentAreaContainer.clientWidth;
|
27073 | const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top;
|
27074 | const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left;
|
27075 | state.on(state => {
|
27076 | state.intervalId.clear();
|
27077 | if (state.dragging && mouseEventOriginatedFromWithinTheEditor) {
|
27078 | if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) {
|
27079 | state.intervalId.set(scrollDown(win));
|
27080 | } else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) {
|
27081 | state.intervalId.set(scrollUp(win));
|
27082 | } else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) {
|
27083 | state.intervalId.set(scrollRight(win));
|
27084 | } else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) {
|
27085 | state.intervalId.set(scrollLeft(win));
|
27086 | } else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) {
|
27087 | state.intervalId.set(scrollDown(window));
|
27088 | } else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) {
|
27089 | state.intervalId.set(scrollUp(window));
|
27090 | } else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) {
|
27091 | state.intervalId.set(scrollRight(window));
|
27092 | } else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) {
|
27093 | state.intervalId.set(scrollLeft(window));
|
27094 | }
|
27095 | }
|
27096 | });
|
27097 | };
|
27098 | const removeElement = elm => {
|
27099 | if (elm && elm.parentNode) {
|
27100 | elm.parentNode.removeChild(elm);
|
27101 | }
|
27102 | };
|
27103 | const removeElementWithPadding = (dom, elm) => {
|
27104 | const parentBlock = dom.getParent(elm.parentNode, dom.isBlock);
|
27105 | removeElement(elm);
|
27106 | if (parentBlock && parentBlock !== dom.getRoot() && dom.isEmpty(parentBlock)) {
|
27107 | fillWithPaddingBr(SugarElement.fromDom(parentBlock));
|
27108 | }
|
27109 | };
|
27110 | const isLeftMouseButtonPressed = e => e.button === 0;
|
27111 | const applyRelPos = (state, position) => ({
|
27112 | pageX: position.pageX - state.relX,
|
27113 | pageY: position.pageY + 5
|
27114 | });
|
27115 | const start = (state, editor) => e => {
|
27116 | if (isLeftMouseButtonPressed(e)) {
|
27117 | const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null);
|
27118 | if (isNonNullable(ceElm) && isDraggable(editor.dom, editor.getBody(), ceElm)) {
|
27119 | const elmPos = editor.dom.getPos(ceElm);
|
27120 | const bodyElm = editor.getBody();
|
27121 | const docElm = editor.getDoc().documentElement;
|
27122 | state.set({
|
27123 | element: ceElm,
|
27124 | dataTransfer: createDataTransfer(),
|
27125 | dragging: false,
|
27126 | screenX: e.screenX,
|
27127 | screenY: e.screenY,
|
27128 | maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
|
27129 | maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
|
27130 | relX: e.pageX - elmPos.x,
|
27131 | relY: e.pageY - elmPos.y,
|
27132 | width: ceElm.offsetWidth,
|
27133 | height: ceElm.offsetHeight,
|
27134 | ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight),
|
27135 | intervalId: repeatable(scrollIntervalValue)
|
27136 | });
|
27137 | }
|
27138 | }
|
27139 | };
|
27140 | const placeCaretAt = (editor, clientX, clientY) => {
|
27141 | editor._selectionOverrides.hideFakeCaret();
|
27142 | closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => {
|
27143 | const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
|
27144 | if (range) {
|
27145 | editor.selection.setRng(range);
|
27146 | } else {
|
27147 | editor.selection.placeCaretAt(clientX, clientY);
|
27148 | }
|
27149 | });
|
27150 | };
|
27151 | const dispatchDragEvent = (editor, type, target, dataTransfer, mouseEvent) => {
|
27152 | if (type === 'dragstart') {
|
27153 | setHtmlData(dataTransfer, editor.dom.getOuterHTML(target));
|
27154 | }
|
27155 | const event = makeDragEvent(type, target, dataTransfer, mouseEvent);
|
27156 | const args = editor.dispatch(type, event);
|
27157 | return args;
|
27158 | };
|
27159 | const move = (state, editor) => {
|
27160 | const throttledPlaceCaretAt = first$1((clientX, clientY) => placeCaretAt(editor, clientX, clientY), 0);
|
27161 | editor.on('remove', throttledPlaceCaretAt.cancel);
|
27162 | const state_ = state;
|
27163 | return e => state.on(state => {
|
27164 | const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
|
27165 | if (!state.dragging && movement > 10) {
|
27166 | const args = dispatchDragEvent(editor, 'dragstart', state.element, state.dataTransfer, e);
|
27167 | if (isNonNullable(args.dataTransfer)) {
|
27168 | state.dataTransfer = args.dataTransfer;
|
27169 | }
|
27170 | if (args.isDefaultPrevented()) {
|
27171 | return;
|
27172 | }
|
27173 | state.dragging = true;
|
27174 | editor.focus();
|
27175 | }
|
27176 | if (state.dragging) {
|
27177 | const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement;
|
27178 | const targetPos = applyRelPos(state, calc(editor, e));
|
27179 | appendGhostToBody(state.ghost, editor.getBody());
|
27180 | moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor);
|
27181 | throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
|
27182 | }
|
27183 | });
|
27184 | };
|
27185 | const getRawTarget = selection => {
|
27186 | const sel = selection.getSel();
|
27187 | if (isNonNullable(sel)) {
|
27188 | const rng = sel.getRangeAt(0);
|
27189 | const startContainer = rng.startContainer;
|
27190 | return isText$b(startContainer) ? startContainer.parentNode : startContainer;
|
27191 | } else {
|
27192 | return null;
|
27193 | }
|
27194 | };
|
27195 | const drop = (state, editor) => e => {
|
27196 | state.on(state => {
|
27197 | var _a;
|
27198 | state.intervalId.clear();
|
27199 | if (state.dragging) {
|
27200 | if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
|
27201 | const dropTarget = (_a = editor.getDoc().elementFromPoint(e.clientX, e.clientY)) !== null && _a !== void 0 ? _a : editor.getBody();
|
27202 | const args = dispatchDragEvent(editor, 'drop', dropTarget, state.dataTransfer, e);
|
27203 | if (!args.isDefaultPrevented()) {
|
27204 | editor.undoManager.transact(() => {
|
27205 | removeElementWithPadding(editor.dom, state.element);
|
27206 | getHtmlData(state.dataTransfer).each(content => editor.insertContent(content));
|
27207 | editor._selectionOverrides.hideFakeCaret();
|
27208 | });
|
27209 | }
|
27210 | }
|
27211 | dispatchDragEvent(editor, 'dragend', editor.getBody(), state.dataTransfer, e);
|
27212 | }
|
27213 | });
|
27214 | removeDragState(state);
|
27215 | };
|
27216 | const stopDragging = (state, editor, e) => {
|
27217 | state.on(state => {
|
27218 | state.intervalId.clear();
|
27219 | if (state.dragging) {
|
27220 | e.fold(() => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer), mouseEvent => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer, mouseEvent));
|
27221 | }
|
27222 | });
|
27223 | removeDragState(state);
|
27224 | };
|
27225 | const stop = (state, editor) => e => stopDragging(state, editor, Optional.some(e));
|
27226 | const removeDragState = state => {
|
27227 | state.on(state => {
|
27228 | state.intervalId.clear();
|
27229 | removeElement(state.ghost);
|
27230 | });
|
27231 | state.clear();
|
27232 | };
|
27233 | const bindFakeDragEvents = editor => {
|
27234 | const state = value$2();
|
27235 | const pageDom = DOMUtils.DOM;
|
27236 | const rootDocument = document;
|
27237 | const dragStartHandler = start(state, editor);
|
27238 | const dragHandler = move(state, editor);
|
27239 | const dropHandler = drop(state, editor);
|
27240 | const dragEndHandler = stop(state, editor);
|
27241 | editor.on('mousedown', dragStartHandler);
|
27242 | editor.on('mousemove', dragHandler);
|
27243 | editor.on('mouseup', dropHandler);
|
27244 | pageDom.bind(rootDocument, 'mousemove', dragHandler);
|
27245 | pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
|
27246 | editor.on('remove', () => {
|
27247 | pageDom.unbind(rootDocument, 'mousemove', dragHandler);
|
27248 | pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
|
27249 | });
|
27250 | editor.on('keydown', e => {
|
27251 | if (e.keyCode === VK.ESC) {
|
27252 | stopDragging(state, editor, Optional.none());
|
27253 | }
|
27254 | });
|
27255 | };
|
27256 | const blockUnsupportedFileDrop = editor => {
|
27257 | const preventFileDrop = e => {
|
27258 | if (!e.isDefaultPrevented()) {
|
27259 | const dataTransfer = e.dataTransfer;
|
27260 | if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) {
|
27261 | e.preventDefault();
|
27262 | if (e.type === 'drop') {
|
27263 | displayError(editor, 'Dropped file type is not supported');
|
27264 | }
|
27265 | }
|
27266 | }
|
27267 | };
|
27268 | const preventFileDropIfUIElement = e => {
|
27269 | if (isUIElement(editor, e.target)) {
|
27270 | preventFileDrop(e);
|
27271 | }
|
27272 | };
|
27273 | const setup = () => {
|
27274 | const pageDom = DOMUtils.DOM;
|
27275 | const dom = editor.dom;
|
27276 | const doc = document;
|
27277 | const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
|
27278 | const eventNames = [
|
27279 | 'drop',
|
27280 | 'dragover'
|
27281 | ];
|
27282 | each$e(eventNames, name => {
|
27283 | pageDom.bind(doc, name, preventFileDropIfUIElement);
|
27284 | dom.bind(editorRoot, name, preventFileDrop);
|
27285 | });
|
27286 | editor.on('remove', () => {
|
27287 | each$e(eventNames, name => {
|
27288 | pageDom.unbind(doc, name, preventFileDropIfUIElement);
|
27289 | dom.unbind(editorRoot, name, preventFileDrop);
|
27290 | });
|
27291 | });
|
27292 | };
|
27293 | editor.on('init', () => {
|
27294 | Delay.setEditorTimeout(editor, setup, 0);
|
27295 | });
|
27296 | };
|
27297 | const init$2 = editor => {
|
27298 | bindFakeDragEvents(editor);
|
27299 | if (shouldBlockUnsupportedDrop(editor)) {
|
27300 | blockUnsupportedFileDrop(editor);
|
27301 | }
|
27302 | };
|
27303 |
|
27304 | const setup$4 = editor => {
|
27305 | const renderFocusCaret = first$1(() => {
|
27306 | if (!editor.removed && editor.getBody().contains(document.activeElement)) {
|
27307 | const rng = editor.selection.getRng();
|
27308 | if (rng.collapsed) {
|
27309 | const caretRange = renderRangeCaret(editor, rng, false);
|
27310 | editor.selection.setRng(caretRange);
|
27311 | }
|
27312 | }
|
27313 | }, 0);
|
27314 | editor.on('focus', () => {
|
27315 | renderFocusCaret.throttle();
|
27316 | });
|
27317 | editor.on('blur', () => {
|
27318 | renderFocusCaret.cancel();
|
27319 | });
|
27320 | };
|
27321 |
|
27322 | const setup$3 = editor => {
|
27323 | editor.on('init', () => {
|
27324 | editor.on('focusin', e => {
|
27325 | const target = e.target;
|
27326 | if (isMedia$2(target)) {
|
27327 | const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
|
27328 | const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target;
|
27329 | if (editor.selection.getNode() !== node) {
|
27330 | selectNode(editor, node).each(rng => editor.selection.setRng(rng));
|
27331 | }
|
27332 | }
|
27333 | });
|
27334 | });
|
27335 | };
|
27336 |
|
27337 | const isContentEditableFalse = isContentEditableFalse$b;
|
27338 | const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
|
27339 | const SelectionOverrides = editor => {
|
27340 | const selection = editor.selection, dom = editor.dom;
|
27341 | const rootNode = editor.getBody();
|
27342 | const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor));
|
27343 | const realSelectionId = 'sel-' + dom.uniqueId();
|
27344 | const elementSelectionAttr = 'data-mce-selected';
|
27345 | let selectedElement;
|
27346 | const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection');
|
27347 | const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode) && dom.isEditable(node.parentNode);
|
27348 | const setRange = range => {
|
27349 | if (range) {
|
27350 | selection.setRng(range);
|
27351 | }
|
27352 | };
|
27353 | const showCaret = (direction, node, before, scrollIntoView = true) => {
|
27354 | const e = editor.dispatch('ShowCaret', {
|
27355 | target: node,
|
27356 | direction,
|
27357 | before
|
27358 | });
|
27359 | if (e.isDefaultPrevented()) {
|
27360 | return null;
|
27361 | }
|
27362 | if (scrollIntoView) {
|
27363 | selection.scrollIntoView(node, direction === -1);
|
27364 | }
|
27365 | return fakeCaret.show(before, node);
|
27366 | };
|
27367 | const showBlockCaretContainer = blockCaretContainer => {
|
27368 | if (blockCaretContainer.hasAttribute('data-mce-caret')) {
|
27369 | showCaretContainerBlock(blockCaretContainer);
|
27370 | selection.scrollIntoView(blockCaretContainer);
|
27371 | }
|
27372 | };
|
27373 | const registerEvents = () => {
|
27374 | editor.on('click', e => {
|
27375 | if (!dom.isEditable(e.target)) {
|
27376 | e.preventDefault();
|
27377 | editor.focus();
|
27378 | }
|
27379 | });
|
27380 | editor.on('blur NewBlock', removeElementSelection);
|
27381 | editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition);
|
27382 | editor.on('tap', e => {
|
27383 | const targetElm = e.target;
|
27384 | const contentEditableRoot = getContentEditableRoot(editor, targetElm);
|
27385 | if (isContentEditableFalse(contentEditableRoot)) {
|
27386 | e.preventDefault();
|
27387 | selectNode(editor, contentEditableRoot).each(setElementSelection);
|
27388 | } else if (isFakeSelectionTargetElement(targetElm)) {
|
27389 | selectNode(editor, targetElm).each(setElementSelection);
|
27390 | }
|
27391 | }, true);
|
27392 | editor.on('mousedown', e => {
|
27393 | const targetElm = e.target;
|
27394 | if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) {
|
27395 | return;
|
27396 | }
|
27397 | if (!isXYInContentArea(editor, e.clientX, e.clientY)) {
|
27398 | return;
|
27399 | }
|
27400 | removeElementSelection();
|
27401 | hideFakeCaret();
|
27402 | const closestContentEditable = getContentEditableRoot(editor, targetElm);
|
27403 | if (isContentEditableFalse(closestContentEditable)) {
|
27404 | e.preventDefault();
|
27405 | selectNode(editor, closestContentEditable).each(setElementSelection);
|
27406 | } else {
|
27407 | closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => {
|
27408 | e.preventDefault();
|
27409 | const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
|
27410 | setRange(range);
|
27411 | if (isHTMLElement(closestContentEditable)) {
|
27412 | closestContentEditable.focus();
|
27413 | } else {
|
27414 | editor.getBody().focus();
|
27415 | }
|
27416 | });
|
27417 | }
|
27418 | });
|
27419 | editor.on('keypress', e => {
|
27420 | if (VK.modifierPressed(e)) {
|
27421 | return;
|
27422 | }
|
27423 | if (isContentEditableFalse(selection.getNode())) {
|
27424 | e.preventDefault();
|
27425 | }
|
27426 | });
|
27427 | editor.on('GetSelectionRange', e => {
|
27428 | let rng = e.range;
|
27429 | if (selectedElement) {
|
27430 | if (!selectedElement.parentNode) {
|
27431 | selectedElement = null;
|
27432 | return;
|
27433 | }
|
27434 | rng = rng.cloneRange();
|
27435 | rng.selectNode(selectedElement);
|
27436 | e.range = rng;
|
27437 | }
|
27438 | });
|
27439 | editor.on('SetSelectionRange', e => {
|
27440 | e.range = normalizeVoidElementSelection(e.range);
|
27441 | const rng = setElementSelection(e.range, e.forward);
|
27442 | if (rng) {
|
27443 | e.range = rng;
|
27444 | }
|
27445 | });
|
27446 | const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin';
|
27447 | editor.on('AfterSetSelectionRange', e => {
|
27448 | const rng = e.range;
|
27449 | const parent = rng.startContainer.parentElement;
|
27450 | if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) {
|
27451 | hideFakeCaret();
|
27452 | }
|
27453 | if (!isFakeSelectionElement(parent)) {
|
27454 | removeElementSelection();
|
27455 | }
|
27456 | });
|
27457 | init$2(editor);
|
27458 | setup$4(editor);
|
27459 | setup$3(editor);
|
27460 | };
|
27461 | const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
|
27462 | const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
|
27463 | const normalizeVoidElementSelection = rng => {
|
27464 | const voidElements = editor.schema.getVoidElements();
|
27465 | const newRng = dom.createRng();
|
27466 | const startContainer = rng.startContainer;
|
27467 | const startOffset = rng.startOffset;
|
27468 | const endContainer = rng.endContainer;
|
27469 | const endOffset = rng.endOffset;
|
27470 | if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
|
27471 | if (startOffset === 0) {
|
27472 | newRng.setStartBefore(startContainer);
|
27473 | } else {
|
27474 | newRng.setStartAfter(startContainer);
|
27475 | }
|
27476 | } else {
|
27477 | newRng.setStart(startContainer, startOffset);
|
27478 | }
|
27479 | if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
|
27480 | if (endOffset === 0) {
|
27481 | newRng.setEndBefore(endContainer);
|
27482 | } else {
|
27483 | newRng.setEndAfter(endContainer);
|
27484 | }
|
27485 | } else {
|
27486 | newRng.setEnd(endContainer, endOffset);
|
27487 | }
|
27488 | return newRng;
|
27489 | };
|
27490 | const setupOffscreenSelection = (node, targetClone) => {
|
27491 | const body = SugarElement.fromDom(editor.getBody());
|
27492 | const doc = editor.getDoc();
|
27493 | const realSelectionContainer = descendant$1(body, '#' + realSelectionId).getOrThunk(() => {
|
27494 | const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc);
|
27495 | set$3(newContainer, 'id', realSelectionId);
|
27496 | append$1(body, newContainer);
|
27497 | return newContainer;
|
27498 | });
|
27499 | const newRange = dom.createRng();
|
27500 | empty(realSelectionContainer);
|
27501 | append(realSelectionContainer, [
|
27502 | SugarElement.fromText(nbsp, doc),
|
27503 | SugarElement.fromDom(targetClone),
|
27504 | SugarElement.fromText(nbsp, doc)
|
27505 | ]);
|
27506 | newRange.setStart(realSelectionContainer.dom.firstChild, 1);
|
27507 | newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
|
27508 | setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' });
|
27509 | focus$1(realSelectionContainer);
|
27510 | const sel = selection.getSel();
|
27511 | if (sel) {
|
27512 | sel.removeAllRanges();
|
27513 | sel.addRange(newRange);
|
27514 | }
|
27515 | return newRange;
|
27516 | };
|
27517 | const selectElement = elm => {
|
27518 | const targetClone = elm.cloneNode(true);
|
27519 | const e = editor.dispatch('ObjectSelected', {
|
27520 | target: elm,
|
27521 | targetClone
|
27522 | });
|
27523 | if (e.isDefaultPrevented()) {
|
27524 | return null;
|
27525 | }
|
27526 | const range = setupOffscreenSelection(elm, e.targetClone);
|
27527 | const nodeElm = SugarElement.fromDom(elm);
|
27528 | each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => {
|
27529 | if (!eq(nodeElm, elm)) {
|
27530 | remove$9(elm, elementSelectionAttr);
|
27531 | }
|
27532 | });
|
27533 | if (!dom.getAttrib(elm, elementSelectionAttr)) {
|
27534 | elm.setAttribute(elementSelectionAttr, '1');
|
27535 | }
|
27536 | selectedElement = elm;
|
27537 | hideFakeCaret();
|
27538 | return range;
|
27539 | };
|
27540 | const setElementSelection = (range, forward) => {
|
27541 | if (!range) {
|
27542 | return null;
|
27543 | }
|
27544 | if (range.collapsed) {
|
27545 | if (!isRangeInCaretContainer(range)) {
|
27546 | const dir = forward ? 1 : -1;
|
27547 | const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range);
|
27548 | const beforeNode = caretPosition.getNode(!forward);
|
27549 | if (isNonNullable(beforeNode)) {
|
27550 | if (isFakeCaretTarget(beforeNode)) {
|
27551 | return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
|
27552 | }
|
27553 | if (isCaretContainerInline(beforeNode) && isContentEditableFalse$b(beforeNode.nextSibling)) {
|
27554 | const rng = dom.createRng();
|
27555 | rng.setStart(beforeNode, 0);
|
27556 | rng.setEnd(beforeNode, 0);
|
27557 | return rng;
|
27558 | }
|
27559 | }
|
27560 | const afterNode = caretPosition.getNode(forward);
|
27561 | if (isNonNullable(afterNode)) {
|
27562 | if (isFakeCaretTarget(afterNode)) {
|
27563 | return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
|
27564 | }
|
27565 | if (isCaretContainerInline(afterNode) && isContentEditableFalse$b(afterNode.previousSibling)) {
|
27566 | const rng = dom.createRng();
|
27567 | rng.setStart(afterNode, 1);
|
27568 | rng.setEnd(afterNode, 1);
|
27569 | return rng;
|
27570 | }
|
27571 | }
|
27572 | }
|
27573 | return null;
|
27574 | }
|
27575 | let startContainer = range.startContainer;
|
27576 | let startOffset = range.startOffset;
|
27577 | const endOffset = range.endOffset;
|
27578 | if (isText$b(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
|
27579 | startContainer = startContainer.parentNode;
|
27580 | startOffset = dom.nodeIndex(startContainer);
|
27581 | startContainer = startContainer.parentNode;
|
27582 | }
|
27583 | if (!isElement$6(startContainer)) {
|
27584 | return null;
|
27585 | }
|
27586 | if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
|
27587 | const node = startContainer.childNodes[startOffset];
|
27588 | if (isFakeSelectionTargetElement(node)) {
|
27589 | return selectElement(node);
|
27590 | }
|
27591 | }
|
27592 | return null;
|
27593 | };
|
27594 | const removeElementSelection = () => {
|
27595 | if (selectedElement) {
|
27596 | selectedElement.removeAttribute(elementSelectionAttr);
|
27597 | }
|
27598 | descendant$1(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$4);
|
27599 | selectedElement = null;
|
27600 | };
|
27601 | const destroy = () => {
|
27602 | fakeCaret.destroy();
|
27603 | selectedElement = null;
|
27604 | };
|
27605 | const hideFakeCaret = () => {
|
27606 | fakeCaret.hide();
|
27607 | };
|
27608 | if (!isRtc(editor)) {
|
27609 | registerEvents();
|
27610 | }
|
27611 | return {
|
27612 | showCaret,
|
27613 | showBlockCaretContainer,
|
27614 | hideFakeCaret,
|
27615 | destroy
|
27616 | };
|
27617 | };
|
27618 |
|
27619 | const getNormalizedTextOffset = (container, offset) => {
|
27620 | let normalizedOffset = offset;
|
27621 | for (let node = container.previousSibling; isText$b(node); node = node.previousSibling) {
|
27622 | normalizedOffset += node.data.length;
|
27623 | }
|
27624 | return normalizedOffset;
|
27625 | };
|
27626 | const generatePath = (dom, root, node, offset, normalized) => {
|
27627 | if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
|
27628 | return [];
|
27629 | }
|
27630 | const p = normalized && isText$b(node) ? [getNormalizedTextOffset(node, offset)] : [offset];
|
27631 | let current = node;
|
27632 | while (current !== root && current.parentNode) {
|
27633 | p.push(dom.nodeIndex(current, normalized));
|
27634 | current = current.parentNode;
|
27635 | }
|
27636 | return current === root ? p.reverse() : [];
|
27637 | };
|
27638 | const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => {
|
27639 | const start = generatePath(dom, root, startNode, startOffset, normalized);
|
27640 | const end = generatePath(dom, root, endNode, endOffset, normalized);
|
27641 | return {
|
27642 | start,
|
27643 | end
|
27644 | };
|
27645 | };
|
27646 | const resolvePath = (root, path) => {
|
27647 | const nodePath = path.slice();
|
27648 | const offset = nodePath.pop();
|
27649 | if (!isNumber(offset)) {
|
27650 | return Optional.none();
|
27651 | } else {
|
27652 | const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root));
|
27653 | return resolvedNode.bind(node => {
|
27654 | if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
|
27655 | return Optional.none();
|
27656 | } else {
|
27657 | return Optional.some({
|
27658 | node,
|
27659 | offset
|
27660 | });
|
27661 | }
|
27662 | });
|
27663 | }
|
27664 | };
|
27665 | const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({
|
27666 | node: startNode,
|
27667 | offset: startOffset
|
27668 | }) => resolvePath(root, range.end).map(({
|
27669 | node: endNode,
|
27670 | offset: endOffset
|
27671 | }) => {
|
27672 | const rng = document.createRange();
|
27673 | rng.setStart(startNode, startOffset);
|
27674 | rng.setEnd(endNode, endOffset);
|
27675 | return rng;
|
27676 | }));
|
27677 | const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized);
|
27678 |
|
27679 | const cleanEmptyNodes = (dom, node, isRoot) => {
|
27680 | if (node && dom.isEmpty(node) && !isRoot(node)) {
|
27681 | const parent = node.parentNode;
|
27682 | dom.remove(node, isText$b(node.firstChild) && isWhitespaceText(node.firstChild.data));
|
27683 | cleanEmptyNodes(dom, parent, isRoot);
|
27684 | }
|
27685 | };
|
27686 | const deleteRng = (dom, rng, isRoot, clean = true) => {
|
27687 | const startParent = rng.startContainer.parentNode;
|
27688 | const endParent = rng.endContainer.parentNode;
|
27689 | rng.deleteContents();
|
27690 | if (clean && !isRoot(rng.startContainer)) {
|
27691 | if (isText$b(rng.startContainer) && rng.startContainer.data.length === 0) {
|
27692 | dom.remove(rng.startContainer);
|
27693 | }
|
27694 | if (isText$b(rng.endContainer) && rng.endContainer.data.length === 0) {
|
27695 | dom.remove(rng.endContainer);
|
27696 | }
|
27697 | cleanEmptyNodes(dom, startParent, isRoot);
|
27698 | if (startParent !== endParent) {
|
27699 | cleanEmptyNodes(dom, endParent, isRoot);
|
27700 | }
|
27701 | }
|
27702 | };
|
27703 | const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
|
27704 | const resolveFromDynamicPatterns = (patternSet, block, beforeText) => {
|
27705 | const dynamicPatterns = patternSet.dynamicPatternsLookup({
|
27706 | text: beforeText,
|
27707 | block
|
27708 | });
|
27709 | return {
|
27710 | ...patternSet,
|
27711 | blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns),
|
27712 | inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns)
|
27713 | };
|
27714 | };
|
27715 | const getBeforeText = (dom, block, node, offset) => {
|
27716 | const rng = dom.createRng();
|
27717 | rng.setStart(block, 0);
|
27718 | rng.setEnd(node, offset);
|
27719 | return rng.toString();
|
27720 | };
|
27721 |
|
27722 | const newMarker = (dom, id) => dom.create('span', {
|
27723 | 'data-mce-type': 'bookmark',
|
27724 | id
|
27725 | });
|
27726 | const rangeFromMarker = (dom, marker) => {
|
27727 | const rng = dom.createRng();
|
27728 | rng.setStartAfter(marker.start);
|
27729 | rng.setEndBefore(marker.end);
|
27730 | return rng;
|
27731 | };
|
27732 | const createMarker = (dom, markerPrefix, pathRange) => {
|
27733 | const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range');
|
27734 | const startNode = rng.startContainer;
|
27735 | const endNode = rng.endContainer;
|
27736 | const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
|
27737 | const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
|
27738 | const startParentNode = textStart.parentNode;
|
27739 | const endParentNode = textEnd.parentNode;
|
27740 | return {
|
27741 | prefix: markerPrefix,
|
27742 | end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd),
|
27743 | start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart)
|
27744 | };
|
27745 | };
|
27746 | const removeMarker = (dom, marker, isRoot) => {
|
27747 | cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot);
|
27748 | cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot);
|
27749 | };
|
27750 |
|
27751 | const isReplacementPattern = pattern => pattern.start.length === 0;
|
27752 | const matchesPattern = patternContent => (element, offset) => {
|
27753 | const text = element.data;
|
27754 | const searchText = text.substring(0, offset);
|
27755 | const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
|
27756 | const startIndex = searchText.lastIndexOf(patternContent);
|
27757 | if (startIndex !== -1) {
|
27758 | return startIndex + patternContent.length;
|
27759 | } else if (startEndIndex !== -1) {
|
27760 | return startEndIndex + 1;
|
27761 | } else {
|
27762 | return -1;
|
27763 | }
|
27764 | };
|
27765 | const findPatternStartFromSpot = (dom, pattern, block, spot) => {
|
27766 | const startPattern = pattern.start;
|
27767 | const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block);
|
27768 | return startSpot.bind(spot => {
|
27769 | var _a, _b;
|
27770 | const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1;
|
27771 | const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length;
|
27772 | if (isCompleteMatch) {
|
27773 | const rng = dom.createRng();
|
27774 | rng.setStart(spot.container, spot.offset - startPattern.length);
|
27775 | rng.setEnd(spot.container, spot.offset);
|
27776 | return Optional.some(rng);
|
27777 | } else {
|
27778 | const offset = spot.offset - startPattern.length;
|
27779 | return scanLeft(spot.container, offset, block).map(nextSpot => {
|
27780 | const rng = dom.createRng();
|
27781 | rng.setStart(nextSpot.container, nextSpot.offset);
|
27782 | rng.setEnd(spot.container, spot.offset);
|
27783 | return rng;
|
27784 | }).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0)));
|
27785 | }
|
27786 | });
|
27787 | };
|
27788 | const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => {
|
27789 | if (pattern.start.length === 0 && !requireGap) {
|
27790 | const rng = dom.createRng();
|
27791 | rng.setStart(node, offset);
|
27792 | rng.setEnd(node, offset);
|
27793 | return Optional.some(rng);
|
27794 | }
|
27795 | return textBefore(node, offset, block).bind(spot => {
|
27796 | const start = findPatternStartFromSpot(dom, pattern, block, spot);
|
27797 | return start.bind(startRange => {
|
27798 | var _a;
|
27799 | if (requireGap) {
|
27800 | if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
|
27801 | return Optional.none();
|
27802 | } else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) {
|
27803 | return Optional.none();
|
27804 | }
|
27805 | }
|
27806 | return Optional.some(startRange);
|
27807 | });
|
27808 | });
|
27809 | };
|
27810 | const findPattern$3 = (editor, block, details, normalizedMatches) => {
|
27811 | const dom = editor.dom;
|
27812 | const root = dom.getRoot();
|
27813 | const pattern = details.pattern;
|
27814 | const endNode = details.position.container;
|
27815 | const endOffset = details.position.offset;
|
27816 | return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => {
|
27817 | const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches);
|
27818 | if (isReplacementPattern(pattern)) {
|
27819 | return Optional.some({
|
27820 | matches: [{
|
27821 | pattern,
|
27822 | startRng: endPathRng,
|
27823 | endRng: endPathRng
|
27824 | }],
|
27825 | position: spot
|
27826 | });
|
27827 | } else {
|
27828 | const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches);
|
27829 | const results = resultsOpt.getOr({
|
27830 | matches: [],
|
27831 | position: spot
|
27832 | });
|
27833 | const pos = results.position;
|
27834 | const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
|
27835 | return start.map(startRng => {
|
27836 | const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches);
|
27837 | return {
|
27838 | matches: results.matches.concat([{
|
27839 | pattern,
|
27840 | startRng: startPathRng,
|
27841 | endRng: endPathRng
|
27842 | }]),
|
27843 | position: point(startRng.startContainer, startRng.startOffset)
|
27844 | };
|
27845 | });
|
27846 | }
|
27847 | });
|
27848 | };
|
27849 | const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => {
|
27850 | const dom = editor.dom;
|
27851 | return textBefore(node, offset, dom.getRoot()).bind(endSpot => {
|
27852 | const text = getBeforeText(dom, block, node, offset);
|
27853 | for (let i = 0; i < patterns.length; i++) {
|
27854 | const pattern = patterns[i];
|
27855 | if (!endsWith(text, pattern.end)) {
|
27856 | continue;
|
27857 | }
|
27858 | const patternsWithoutCurrent = patterns.slice();
|
27859 | patternsWithoutCurrent.splice(i, 1);
|
27860 | const result = findPattern$3(editor, block, {
|
27861 | pattern,
|
27862 | remainingPatterns: patternsWithoutCurrent,
|
27863 | position: endSpot
|
27864 | }, normalizedMatches);
|
27865 | if (result.isNone() && offset > 0) {
|
27866 | return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches);
|
27867 | }
|
27868 | if (result.isSome()) {
|
27869 | return result;
|
27870 | }
|
27871 | }
|
27872 | return Optional.none();
|
27873 | });
|
27874 | };
|
27875 | const applyPattern$2 = (editor, pattern, patternRange) => {
|
27876 | editor.selection.setRng(patternRange);
|
27877 | if (pattern.type === 'inline-format') {
|
27878 | each$e(pattern.format, format => {
|
27879 | editor.formatter.apply(format);
|
27880 | });
|
27881 | } else {
|
27882 | editor.execCommand(pattern.cmd, false, pattern.value);
|
27883 | }
|
27884 | };
|
27885 | const applyReplacementPattern = (editor, pattern, marker, isRoot) => {
|
27886 | const markerRange = rangeFromMarker(editor.dom, marker);
|
27887 | deleteRng(editor.dom, markerRange, isRoot);
|
27888 | applyPattern$2(editor, pattern, markerRange);
|
27889 | };
|
27890 | const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => {
|
27891 | const dom = editor.dom;
|
27892 | const markerEndRange = rangeFromMarker(dom, endMarker);
|
27893 | const markerStartRange = rangeFromMarker(dom, startMarker);
|
27894 | deleteRng(dom, markerStartRange, isRoot);
|
27895 | deleteRng(dom, markerEndRange, isRoot);
|
27896 | const patternMarker = {
|
27897 | prefix: startMarker.prefix,
|
27898 | start: startMarker.end,
|
27899 | end: endMarker.start
|
27900 | };
|
27901 | const patternRange = rangeFromMarker(dom, patternMarker);
|
27902 | applyPattern$2(editor, pattern, patternRange);
|
27903 | };
|
27904 | const addMarkers = (dom, matches) => {
|
27905 | const markerPrefix = generate$1('mce_textpattern');
|
27906 | const matchesWithEnds = foldr(matches, (acc, match) => {
|
27907 | const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng);
|
27908 | return acc.concat([{
|
27909 | ...match,
|
27910 | endMarker
|
27911 | }]);
|
27912 | }, []);
|
27913 | return foldr(matchesWithEnds, (acc, match) => {
|
27914 | const idx = matchesWithEnds.length - acc.length - 1;
|
27915 | const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng);
|
27916 | return acc.concat([{
|
27917 | ...match,
|
27918 | startMarker
|
27919 | }]);
|
27920 | }, []);
|
27921 | };
|
27922 | const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.end.length - a.end.length);
|
27923 | const getBestMatches = (matches, matchesWithSortedPatterns) => {
|
27924 | const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end));
|
27925 | if (matches.length === matchesWithSortedPatterns.length) {
|
27926 | if (hasSameMatches) {
|
27927 | return matches;
|
27928 | } else {
|
27929 | return matchesWithSortedPatterns;
|
27930 | }
|
27931 | }
|
27932 | return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns;
|
27933 | };
|
27934 | const findPatterns$2 = (editor, block, node, offset, patternSet, normalizedMatches) => {
|
27935 | const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
|
27936 | const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns$1(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
|
27937 | return getBestMatches(matches, matchesWithSortedPatterns);
|
27938 | };
|
27939 | const applyMatches$2 = (editor, matches) => {
|
27940 | if (matches.length === 0) {
|
27941 | return;
|
27942 | }
|
27943 | const dom = editor.dom;
|
27944 | const bookmark = editor.selection.getBookmark();
|
27945 | const matchesWithMarkers = addMarkers(dom, matches);
|
27946 | each$e(matchesWithMarkers, match => {
|
27947 | const block = dom.getParent(match.startMarker.start, dom.isBlock);
|
27948 | const isRoot = node => node === block;
|
27949 | if (isReplacementPattern(match.pattern)) {
|
27950 | applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot);
|
27951 | } else {
|
27952 | applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot);
|
27953 | }
|
27954 | removeMarker(dom, match.endMarker, isRoot);
|
27955 | removeMarker(dom, match.startMarker, isRoot);
|
27956 | });
|
27957 | editor.selection.moveToBookmark(bookmark);
|
27958 | };
|
27959 |
|
27960 | const stripPattern$1 = (dom, block, pattern) => {
|
27961 | return textAfter(block, 0, block).map(spot => {
|
27962 | const node = spot.container;
|
27963 | scanRight(node, pattern.start.length, block).each(end => {
|
27964 | const rng = dom.createRng();
|
27965 | rng.setStart(node, 0);
|
27966 | rng.setEnd(end.container, end.offset);
|
27967 | deleteRng(dom, rng, e => e === block);
|
27968 | });
|
27969 | return node;
|
27970 | });
|
27971 | };
|
27972 | const createApplyPattern = stripPattern => (editor, match) => {
|
27973 | const dom = editor.dom;
|
27974 | const pattern = match.pattern;
|
27975 | const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range');
|
27976 | const isBlockFormatName = (name, formatter) => {
|
27977 | const formatSet = formatter.get(name);
|
27978 | return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block'));
|
27979 | };
|
27980 | getParentBlock(editor, rng).each(block => {
|
27981 | if (pattern.type === 'block-format') {
|
27982 | if (isBlockFormatName(pattern.format, editor.formatter)) {
|
27983 | editor.undoManager.transact(() => {
|
27984 | stripPattern(editor.dom, block, pattern);
|
27985 | editor.formatter.apply(pattern.format);
|
27986 | });
|
27987 | }
|
27988 | } else if (pattern.type === 'block-command') {
|
27989 | editor.undoManager.transact(() => {
|
27990 | stripPattern(editor.dom, block, pattern);
|
27991 | editor.execCommand(pattern.cmd, false, pattern.value);
|
27992 | });
|
27993 | }
|
27994 | });
|
27995 | return true;
|
27996 | };
|
27997 | const sortPatterns = patterns => sort(patterns, (a, b) => b.start.length - a.start.length);
|
27998 | const findPattern$2 = predicate => (patterns, text) => {
|
27999 | const sortedPatterns = sortPatterns(patterns);
|
28000 | const nuText = text.replace(nbsp, ' ');
|
28001 | return find$2(sortedPatterns, pattern => predicate(pattern, text, nuText));
|
28002 | };
|
28003 | const createFindPatterns = (findPattern, skipFullMatch) => (editor, block, patternSet, normalizedMatches, text) => {
|
28004 | var _a;
|
28005 | if (text === void 0) {
|
28006 | text = (_a = block.textContent) !== null && _a !== void 0 ? _a : '';
|
28007 | }
|
28008 | const dom = editor.dom;
|
28009 | const forcedRootBlock = getForcedRootBlock(editor);
|
28010 | if (!dom.is(block, forcedRootBlock)) {
|
28011 | return [];
|
28012 | }
|
28013 | return findPattern(patternSet.blockPatterns, text).map(pattern => {
|
28014 | if (skipFullMatch && Tools.trim(text).length === pattern.start.length) {
|
28015 | return [];
|
28016 | }
|
28017 | return [{
|
28018 | pattern,
|
28019 | range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches)
|
28020 | }];
|
28021 | }).getOr([]);
|
28022 | };
|
28023 |
|
28024 | const startsWithSingleSpace = s => /^\s[^\s]/.test(s);
|
28025 | const stripPattern = (dom, block, pattern) => {
|
28026 | stripPattern$1(dom, block, pattern).each(node => {
|
28027 | const text = SugarElement.fromDom(node);
|
28028 | const textContent = get$3(text);
|
28029 | if (startsWithSingleSpace(textContent)) {
|
28030 | set(text, textContent.slice(1));
|
28031 | }
|
28032 | });
|
28033 | };
|
28034 | const applyPattern$1 = createApplyPattern(stripPattern);
|
28035 | const findPattern$1 = findPattern$2((pattern, text, nuText) => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
|
28036 | const findPatterns$1 = createFindPatterns(findPattern$1, true);
|
28037 | const getMatches$1 = (editor, patternSet) => {
|
28038 | const rng = editor.selection.getRng();
|
28039 | return getParentBlock(editor, rng).map(block => {
|
28040 | var _a;
|
28041 | const offset = Math.max(0, rng.startOffset);
|
28042 | const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : '');
|
28043 | const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, true);
|
28044 | const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true);
|
28045 | return {
|
28046 | inlineMatches,
|
28047 | blockMatches
|
28048 | };
|
28049 | }).filter(({inlineMatches, blockMatches}) => blockMatches.length > 0 || inlineMatches.length > 0);
|
28050 | };
|
28051 | const applyMatches$1 = (editor, matches) => {
|
28052 | if (matches.length === 0) {
|
28053 | return;
|
28054 | }
|
28055 | const bookmark = editor.selection.getBookmark();
|
28056 | each$e(matches, match => applyPattern$1(editor, match));
|
28057 | editor.selection.moveToBookmark(bookmark);
|
28058 | };
|
28059 |
|
28060 | const applyPattern = createApplyPattern(stripPattern$1);
|
28061 | const findPattern = findPattern$2((pattern, text, nuText) => text === pattern.start || nuText === pattern.start);
|
28062 | const findPatterns = createFindPatterns(findPattern, false);
|
28063 | const getMatches = (editor, patternSet) => {
|
28064 | const rng = editor.selection.getRng();
|
28065 | return getParentBlock(editor, rng).map(block => {
|
28066 | const offset = Math.max(0, rng.startOffset);
|
28067 | const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
|
28068 | const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
|
28069 | return findPatterns(editor, block, dynamicPatternSet, false, beforeText);
|
28070 | }).filter(matches => matches.length > 0);
|
28071 | };
|
28072 | const applyMatches = (editor, matches) => {
|
28073 | each$e(matches, match => applyPattern(editor, match));
|
28074 | };
|
28075 |
|
28076 | const handleEnter = (editor, patternSet) => getMatches$1(editor, patternSet).fold(never, ({inlineMatches, blockMatches}) => {
|
28077 | editor.undoManager.add();
|
28078 | editor.undoManager.extra(() => {
|
28079 | editor.execCommand('mceInsertNewLine');
|
28080 | }, () => {
|
28081 | insert$5(editor);
|
28082 | applyMatches$2(editor, inlineMatches);
|
28083 | applyMatches$1(editor, blockMatches);
|
28084 | const range = editor.selection.getRng();
|
28085 | const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot());
|
28086 | editor.execCommand('mceInsertNewLine');
|
28087 | spot.each(s => {
|
28088 | const node = s.container;
|
28089 | if (node.data.charAt(s.offset - 1) === zeroWidth) {
|
28090 | node.deleteData(s.offset - 1, 1);
|
28091 | cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot());
|
28092 | }
|
28093 | });
|
28094 | });
|
28095 | return true;
|
28096 | });
|
28097 | const handleInlineKey = (editor, patternSet) => {
|
28098 | const rng = editor.selection.getRng();
|
28099 | getParentBlock(editor, rng).map(block => {
|
28100 | const offset = Math.max(0, rng.startOffset - 1);
|
28101 | const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
|
28102 | const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
|
28103 | const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, false);
|
28104 | if (inlineMatches.length > 0) {
|
28105 | editor.undoManager.transact(() => {
|
28106 | applyMatches$2(editor, inlineMatches);
|
28107 | });
|
28108 | }
|
28109 | });
|
28110 | };
|
28111 | const handleBlockPatternOnSpace = (editor, patternSet) => getMatches(editor, patternSet).fold(never, matches => {
|
28112 | editor.undoManager.transact(() => {
|
28113 | applyMatches(editor, matches);
|
28114 | });
|
28115 | return true;
|
28116 | });
|
28117 | const checkKeyEvent = (codes, event, predicate) => {
|
28118 | for (let i = 0; i < codes.length; i++) {
|
28119 | if (predicate(codes[i], event)) {
|
28120 | return true;
|
28121 | }
|
28122 | }
|
28123 | return false;
|
28124 | };
|
28125 | const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => {
|
28126 | return code === event.keyCode && !VK.modifierPressed(event);
|
28127 | });
|
28128 | const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => {
|
28129 | return chr.charCodeAt(0) === event.charCode;
|
28130 | });
|
28131 |
|
28132 | const setup$2 = editor => {
|
28133 | const charCodes = [
|
28134 | ',',
|
28135 | '.',
|
28136 | ';',
|
28137 | ':',
|
28138 | '!',
|
28139 | '?'
|
28140 | ];
|
28141 | const keyCodes = [32];
|
28142 | const getPatternSet = () => createPatternSet(getTextPatterns(editor), getTextPatternsLookup(editor));
|
28143 | const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
|
28144 | editor.on('keydown', e => {
|
28145 | if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
|
28146 | const patternSet = filterByTrigger(getPatternSet(), 'enter');
|
28147 | const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
|
28148 | if (hasPatterns && handleEnter(editor, patternSet)) {
|
28149 | e.preventDefault();
|
28150 | }
|
28151 | }
|
28152 | }, true);
|
28153 | editor.on('keydown', e => {
|
28154 | if (e.keyCode === 32 && editor.selection.isCollapsed()) {
|
28155 | const patternSet = filterByTrigger(getPatternSet(), 'space');
|
28156 | const hasPatterns = patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
|
28157 | if (hasPatterns && handleBlockPatternOnSpace(editor, patternSet)) {
|
28158 | e.preventDefault();
|
28159 | }
|
28160 | }
|
28161 | }, true);
|
28162 | const handleInlineTrigger = () => {
|
28163 | if (editor.selection.isCollapsed()) {
|
28164 | const patternSet = filterByTrigger(getPatternSet(), 'space');
|
28165 | const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
|
28166 | if (hasPatterns) {
|
28167 | handleInlineKey(editor, patternSet);
|
28168 | }
|
28169 | }
|
28170 | };
|
28171 | editor.on('keyup', e => {
|
28172 | if (checkKeyCode(keyCodes, e)) {
|
28173 | handleInlineTrigger();
|
28174 | }
|
28175 | });
|
28176 | editor.on('keypress', e => {
|
28177 | if (checkCharCode(charCodes, e)) {
|
28178 | Delay.setEditorTimeout(editor, handleInlineTrigger);
|
28179 | }
|
28180 | });
|
28181 | };
|
28182 |
|
28183 | const setup$1 = editor => {
|
28184 | setup$2(editor);
|
28185 | };
|
28186 |
|
28187 | const Quirks = editor => {
|
28188 | const each = Tools.each;
|
28189 | const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser;
|
28190 | const browser = Env.browser;
|
28191 | const isGecko = browser.isFirefox();
|
28192 | const isWebKit = browser.isChromium() || browser.isSafari();
|
28193 | const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
|
28194 | const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
28195 | const setEditorCommandState = (cmd, state) => {
|
28196 | try {
|
28197 | editor.getDoc().execCommand(cmd, false, String(state));
|
28198 | } catch (ex) {
|
28199 | }
|
28200 | };
|
28201 | const isDefaultPrevented = e => {
|
28202 | return e.isDefaultPrevented();
|
28203 | };
|
28204 | const emptyEditorWhenDeleting = () => {
|
28205 | const serializeRng = rng => {
|
28206 | const body = dom.create('body');
|
28207 | const contents = rng.cloneContents();
|
28208 | body.appendChild(contents);
|
28209 | return selection.serializer.serialize(body, { format: 'html' });
|
28210 | };
|
28211 | const allContentsSelected = rng => {
|
28212 | const selection = serializeRng(rng);
|
28213 | const allRng = dom.createRng();
|
28214 | allRng.selectNode(editor.getBody());
|
28215 | const allSelection = serializeRng(allRng);
|
28216 | return selection === allSelection;
|
28217 | };
|
28218 | editor.on('keydown', e => {
|
28219 | const keyCode = e.keyCode;
|
28220 | if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE) && editor.selection.isEditable()) {
|
28221 | const isCollapsed = editor.selection.isCollapsed();
|
28222 | const body = editor.getBody();
|
28223 | if (isCollapsed && !isEmptyNode(editor.schema, body)) {
|
28224 | return;
|
28225 | }
|
28226 | if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
|
28227 | return;
|
28228 | }
|
28229 | e.preventDefault();
|
28230 | editor.setContent('');
|
28231 | if (body.firstChild && dom.isBlock(body.firstChild)) {
|
28232 | editor.selection.setCursorLocation(body.firstChild, 0);
|
28233 | } else {
|
28234 | editor.selection.setCursorLocation(body, 0);
|
28235 | }
|
28236 | editor.nodeChanged();
|
28237 | }
|
28238 | });
|
28239 | };
|
28240 | const selectAll = () => {
|
28241 | editor.shortcuts.add('meta+a', null, 'SelectAll');
|
28242 | };
|
28243 | const documentElementEditingFocus = () => {
|
28244 | if (!editor.inline) {
|
28245 | dom.bind(editor.getDoc(), 'mousedown mouseup', e => {
|
28246 | let rng;
|
28247 | if (e.target === editor.getDoc().documentElement) {
|
28248 | rng = selection.getRng();
|
28249 | editor.getBody().focus();
|
28250 | if (e.type === 'mousedown') {
|
28251 | if (isCaretContainer$2(rng.startContainer)) {
|
28252 | return;
|
28253 | }
|
28254 | selection.placeCaretAt(e.clientX, e.clientY);
|
28255 | } else {
|
28256 | selection.setRng(rng);
|
28257 | }
|
28258 | }
|
28259 | });
|
28260 | }
|
28261 | };
|
28262 | const removeHrOnBackspace = () => {
|
28263 | editor.on('keydown', e => {
|
28264 | if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
|
28265 | if (!editor.getBody().getElementsByTagName('hr').length) {
|
28266 | return;
|
28267 | }
|
28268 | if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
|
28269 | const node = selection.getNode();
|
28270 | const previousSibling = node.previousSibling;
|
28271 | if (node.nodeName === 'HR') {
|
28272 | dom.remove(node);
|
28273 | e.preventDefault();
|
28274 | return;
|
28275 | }
|
28276 | if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
|
28277 | dom.remove(previousSibling);
|
28278 | e.preventDefault();
|
28279 | }
|
28280 | }
|
28281 | }
|
28282 | });
|
28283 | };
|
28284 | const focusBody = () => {
|
28285 | if (!Range.prototype.getClientRects) {
|
28286 | editor.on('mousedown', e => {
|
28287 | if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
|
28288 | const body = editor.getBody();
|
28289 | body.blur();
|
28290 | Delay.setEditorTimeout(editor, () => {
|
28291 | body.focus();
|
28292 | });
|
28293 | }
|
28294 | });
|
28295 | }
|
28296 | };
|
28297 | const selectControlElements = () => {
|
28298 | const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
|
28299 | editor.on('click', e => {
|
28300 | const target = e.target;
|
28301 | if (/^(IMG|HR)$/.test(target.nodeName) && dom.isEditable(target)) {
|
28302 | e.preventDefault();
|
28303 | editor.selection.select(target);
|
28304 | editor.nodeChanged();
|
28305 | }
|
28306 | if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0 && dom.isEditable(target.parentNode)) {
|
28307 | e.preventDefault();
|
28308 | selection.select(target);
|
28309 | }
|
28310 | });
|
28311 | };
|
28312 | const removeStylesWhenDeletingAcrossBlockElements = () => {
|
28313 | const getAttributeApplyFunction = () => {
|
28314 | const template = dom.getAttribs(selection.getStart().cloneNode(false));
|
28315 | return () => {
|
28316 | const target = selection.getStart();
|
28317 | if (target !== editor.getBody()) {
|
28318 | dom.setAttrib(target, 'style', null);
|
28319 | each(template, attr => {
|
28320 | target.setAttributeNode(attr.cloneNode(true));
|
28321 | });
|
28322 | }
|
28323 | };
|
28324 | };
|
28325 | const isSelectionAcrossElements = () => {
|
28326 | return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
|
28327 | };
|
28328 | editor.on('keypress', e => {
|
28329 | let applyAttributes;
|
28330 | if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
|
28331 | applyAttributes = getAttributeApplyFunction();
|
28332 | editor.getDoc().execCommand('delete', false);
|
28333 | applyAttributes();
|
28334 | e.preventDefault();
|
28335 | return false;
|
28336 | } else {
|
28337 | return true;
|
28338 | }
|
28339 | });
|
28340 | dom.bind(editor.getDoc(), 'cut', e => {
|
28341 | if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
|
28342 | const applyAttributes = getAttributeApplyFunction();
|
28343 | Delay.setEditorTimeout(editor, () => {
|
28344 | applyAttributes();
|
28345 | });
|
28346 | }
|
28347 | });
|
28348 | };
|
28349 | const disableBackspaceIntoATable = () => {
|
28350 | editor.on('keydown', e => {
|
28351 | if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
|
28352 | if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
|
28353 | const previousSibling = selection.getNode().previousSibling;
|
28354 | if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
|
28355 | e.preventDefault();
|
28356 | return false;
|
28357 | }
|
28358 | }
|
28359 | }
|
28360 | return true;
|
28361 | });
|
28362 | };
|
28363 | const removeBlockQuoteOnBackSpace = () => {
|
28364 | editor.on('keydown', e => {
|
28365 | if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
|
28366 | return;
|
28367 | }
|
28368 | let rng = selection.getRng();
|
28369 | const container = rng.startContainer;
|
28370 | const offset = rng.startOffset;
|
28371 | const root = dom.getRoot();
|
28372 | let parent = container;
|
28373 | if (!rng.collapsed || offset !== 0) {
|
28374 | return;
|
28375 | }
|
28376 | while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
|
28377 | parent = parent.parentNode;
|
28378 | }
|
28379 | if (parent.nodeName === 'BLOCKQUOTE') {
|
28380 | editor.formatter.toggle('blockquote', undefined, parent);
|
28381 | rng = dom.createRng();
|
28382 | rng.setStart(container, 0);
|
28383 | rng.setEnd(container, 0);
|
28384 | selection.setRng(rng);
|
28385 | }
|
28386 | });
|
28387 | };
|
28388 | const setGeckoEditingOptions = () => {
|
28389 | const setOpts = () => {
|
28390 | setEditorCommandState('StyleWithCSS', false);
|
28391 | setEditorCommandState('enableInlineTableEditing', false);
|
28392 | if (!getObjectResizing(editor)) {
|
28393 | setEditorCommandState('enableObjectResizing', false);
|
28394 | }
|
28395 | };
|
28396 | if (!isReadOnly$1(editor)) {
|
28397 | editor.on('BeforeExecCommand mousedown', setOpts);
|
28398 | }
|
28399 | };
|
28400 | const addBrAfterLastLinks = () => {
|
28401 | const fixLinks = () => {
|
28402 | each(dom.select('a:not([data-mce-block])'), node => {
|
28403 | var _a;
|
28404 | let parentNode = node.parentNode;
|
28405 | const root = dom.getRoot();
|
28406 | if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) {
|
28407 | while (parentNode && !dom.isBlock(parentNode)) {
|
28408 | if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) {
|
28409 | return;
|
28410 | }
|
28411 | parentNode = parentNode.parentNode;
|
28412 | }
|
28413 | dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
|
28414 | }
|
28415 | });
|
28416 | };
|
28417 | editor.on('SetContent ExecCommand', e => {
|
28418 | if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
|
28419 | fixLinks();
|
28420 | }
|
28421 | });
|
28422 | };
|
28423 | const setDefaultBlockType = () => {
|
28424 | editor.on('init', () => {
|
28425 | setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor));
|
28426 | });
|
28427 | };
|
28428 | const isAllContentSelected = editor => {
|
28429 | const body = editor.getBody();
|
28430 | const rng = editor.selection.getRng();
|
28431 | return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
|
28432 | };
|
28433 | const normalizeSelection = () => {
|
28434 | editor.on('keyup focusin mouseup', e => {
|
28435 | if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
|
28436 | selection.normalize();
|
28437 | }
|
28438 | }, true);
|
28439 | };
|
28440 | const showBrokenImageIcon = () => {
|
28441 | editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
|
28442 | };
|
28443 | const restoreFocusOnKeyDown = () => {
|
28444 | if (!editor.inline) {
|
28445 | editor.on('keydown', () => {
|
28446 | if (document.activeElement === document.body) {
|
28447 | editor.getWin().focus();
|
28448 | }
|
28449 | });
|
28450 | }
|
28451 | };
|
28452 | const bodyHeight = () => {
|
28453 | if (!editor.inline) {
|
28454 | editor.contentStyles.push('body {min-height: 150px}');
|
28455 | editor.on('click', e => {
|
28456 | let rng;
|
28457 | if (e.target.nodeName === 'HTML') {
|
28458 | rng = editor.selection.getRng();
|
28459 | editor.getBody().focus();
|
28460 | editor.selection.setRng(rng);
|
28461 | editor.selection.normalize();
|
28462 | editor.nodeChanged();
|
28463 | }
|
28464 | });
|
28465 | }
|
28466 | };
|
28467 | const blockCmdArrowNavigation = () => {
|
28468 | if (isMac) {
|
28469 | editor.on('keydown', e => {
|
28470 | if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
|
28471 | e.preventDefault();
|
28472 | const selection = editor.selection.getSel();
|
28473 | selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
|
28474 | }
|
28475 | });
|
28476 | }
|
28477 | };
|
28478 | const tapLinksAndImages = () => {
|
28479 | editor.on('click', e => {
|
28480 | let elm = e.target;
|
28481 | do {
|
28482 | if (elm.tagName === 'A') {
|
28483 | e.preventDefault();
|
28484 | return;
|
28485 | }
|
28486 | } while (elm = elm.parentNode);
|
28487 | });
|
28488 | editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
|
28489 | };
|
28490 | const blockFormSubmitInsideEditor = () => {
|
28491 | editor.on('init', () => {
|
28492 | editor.dom.bind(editor.getBody(), 'submit', e => {
|
28493 | e.preventDefault();
|
28494 | });
|
28495 | });
|
28496 | };
|
28497 | const removeAppleInterchangeBrs = () => {
|
28498 | parser.addNodeFilter('br', nodes => {
|
28499 | let i = nodes.length;
|
28500 | while (i--) {
|
28501 | if (nodes[i].attr('class') === 'Apple-interchange-newline') {
|
28502 | nodes[i].remove();
|
28503 | }
|
28504 | }
|
28505 | });
|
28506 | };
|
28507 | const refreshContentEditable = noop;
|
28508 | const isHidden = () => {
|
28509 | if (!isGecko || editor.removed) {
|
28510 | return false;
|
28511 | }
|
28512 | const sel = editor.selection.getSel();
|
28513 | return !sel || !sel.rangeCount || sel.rangeCount === 0;
|
28514 | };
|
28515 | const setupRtc = () => {
|
28516 | if (isWebKit) {
|
28517 | documentElementEditingFocus();
|
28518 | selectControlElements();
|
28519 | blockFormSubmitInsideEditor();
|
28520 | selectAll();
|
28521 | if (isiOS) {
|
28522 | restoreFocusOnKeyDown();
|
28523 | bodyHeight();
|
28524 | tapLinksAndImages();
|
28525 | }
|
28526 | }
|
28527 | if (isGecko) {
|
28528 | focusBody();
|
28529 | setGeckoEditingOptions();
|
28530 | showBrokenImageIcon();
|
28531 | blockCmdArrowNavigation();
|
28532 | }
|
28533 | };
|
28534 | const setup = () => {
|
28535 | removeBlockQuoteOnBackSpace();
|
28536 | emptyEditorWhenDeleting();
|
28537 | if (!Env.windowsPhone) {
|
28538 | normalizeSelection();
|
28539 | }
|
28540 | if (isWebKit) {
|
28541 | documentElementEditingFocus();
|
28542 | selectControlElements();
|
28543 | setDefaultBlockType();
|
28544 | blockFormSubmitInsideEditor();
|
28545 | disableBackspaceIntoATable();
|
28546 | removeAppleInterchangeBrs();
|
28547 | if (isiOS) {
|
28548 | restoreFocusOnKeyDown();
|
28549 | bodyHeight();
|
28550 | tapLinksAndImages();
|
28551 | } else {
|
28552 | selectAll();
|
28553 | }
|
28554 | }
|
28555 | if (isGecko) {
|
28556 | removeHrOnBackspace();
|
28557 | focusBody();
|
28558 | removeStylesWhenDeletingAcrossBlockElements();
|
28559 | setGeckoEditingOptions();
|
28560 | addBrAfterLastLinks();
|
28561 | showBrokenImageIcon();
|
28562 | blockCmdArrowNavigation();
|
28563 | disableBackspaceIntoATable();
|
28564 | }
|
28565 | };
|
28566 | if (isRtc(editor)) {
|
28567 | setupRtc();
|
28568 | } else {
|
28569 | setup();
|
28570 | }
|
28571 | return {
|
28572 | refreshContentEditable,
|
28573 | isHidden
|
28574 | };
|
28575 | };
|
28576 |
|
28577 | const isGplKey = key => key.toLowerCase() === 'gpl';
|
28578 | const isValidGeneratedKey = key => key.length >= 64 && key.length <= 255;
|
28579 | const validateLicenseKey = key => isGplKey(key) || isValidGeneratedKey(key) ? 'VALID' : 'INVALID';
|
28580 | const validateEditorLicenseKey = editor => {
|
28581 | const licenseKey = getLicenseKey(editor);
|
28582 | const hasApiKey = isString(getApiKey(editor));
|
28583 | if (!hasApiKey && (isUndefined(licenseKey) || validateLicenseKey(licenseKey) === 'INVALID')) {
|
28584 | console.warn(`TinyMCE is running in evaluation mode. Provide a valid license key or add license_key: 'gpl' to the init config to agree to the open source license terms. Read more at https://www.tiny.cloud/license-key/`);
|
28585 | }
|
28586 | };
|
28587 |
|
28588 | const DOM$6 = DOMUtils.DOM;
|
28589 | const appendStyle = (editor, text) => {
|
28590 | const body = SugarElement.fromDom(editor.getBody());
|
28591 | const container = getStyleContainer(getRootNode(body));
|
28592 | const style = SugarElement.fromTag('style');
|
28593 | set$3(style, 'type', 'text/css');
|
28594 | append$1(style, SugarElement.fromText(text));
|
28595 | append$1(container, style);
|
28596 | editor.on('remove', () => {
|
28597 | remove$4(style);
|
28598 | });
|
28599 | };
|
28600 | const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined;
|
28601 | const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false);
|
28602 | const mkParserSettings = editor => {
|
28603 | const getOption = editor.options.get;
|
28604 | const blobCache = editor.editorUpload.blobCache;
|
28605 | return removeUndefined({
|
28606 | allow_conditional_comments: getOption('allow_conditional_comments'),
|
28607 | allow_html_data_urls: getOption('allow_html_data_urls'),
|
28608 | allow_svg_data_urls: getOption('allow_svg_data_urls'),
|
28609 | allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
|
28610 | allow_script_urls: getOption('allow_script_urls'),
|
28611 | allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
|
28612 | convert_unsafe_embeds: getOption('convert_unsafe_embeds'),
|
28613 | convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
|
28614 | fix_list_elements: getOption('fix_list_elements'),
|
28615 | font_size_legacy_values: getOption('font_size_legacy_values'),
|
28616 | forced_root_block: getOption('forced_root_block'),
|
28617 | forced_root_block_attrs: getOption('forced_root_block_attrs'),
|
28618 | preserve_cdata: getOption('preserve_cdata'),
|
28619 | inline_styles: getOption('inline_styles'),
|
28620 | root_name: getRootName(editor),
|
28621 | sandbox_iframes: getOption('sandbox_iframes'),
|
28622 | sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
|
28623 | sanitize: getOption('xss_sanitization'),
|
28624 | validate: true,
|
28625 | blob_cache: blobCache,
|
28626 | document: editor.getDoc()
|
28627 | });
|
28628 | };
|
28629 | const mkSchemaSettings = editor => {
|
28630 | const getOption = editor.options.get;
|
28631 | return removeUndefined({
|
28632 | custom_elements: getOption('custom_elements'),
|
28633 | extended_valid_elements: getOption('extended_valid_elements'),
|
28634 | invalid_elements: getOption('invalid_elements'),
|
28635 | invalid_styles: getOption('invalid_styles'),
|
28636 | schema: getOption('schema'),
|
28637 | valid_children: getOption('valid_children'),
|
28638 | valid_classes: getOption('valid_classes'),
|
28639 | valid_elements: getOption('valid_elements'),
|
28640 | valid_styles: getOption('valid_styles'),
|
28641 | verify_html: getOption('verify_html'),
|
28642 | padd_empty_block_inline_children: getOption('format_empty_lines')
|
28643 | });
|
28644 | };
|
28645 | const mkSerializerSettings = editor => {
|
28646 | const getOption = editor.options.get;
|
28647 | return {
|
28648 | ...mkParserSettings(editor),
|
28649 | ...mkSchemaSettings(editor),
|
28650 | ...removeUndefined({
|
28651 | remove_trailing_brs: getOption('remove_trailing_brs'),
|
28652 | pad_empty_with_br: getOption('pad_empty_with_br'),
|
28653 | url_converter: getOption('url_converter'),
|
28654 | url_converter_scope: getOption('url_converter_scope'),
|
28655 | element_format: getOption('element_format'),
|
28656 | entities: getOption('entities'),
|
28657 | entity_encoding: getOption('entity_encoding'),
|
28658 | indent: getOption('indent'),
|
28659 | indent_after: getOption('indent_after'),
|
28660 | indent_before: getOption('indent_before')
|
28661 | })
|
28662 | };
|
28663 | };
|
28664 | const createParser = editor => {
|
28665 | const parser = DomParser(mkParserSettings(editor), editor.schema);
|
28666 | parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => {
|
28667 | const dom = editor.dom;
|
28668 | const internalName = 'data-mce-' + name;
|
28669 | let i = nodes.length;
|
28670 | while (i--) {
|
28671 | const node = nodes[i];
|
28672 | let value = node.attr(name);
|
28673 | if (value && !node.attr(internalName)) {
|
28674 | if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
|
28675 | continue;
|
28676 | }
|
28677 | if (name === 'style') {
|
28678 | value = dom.serializeStyle(dom.parseStyle(value), node.name);
|
28679 | if (!value.length) {
|
28680 | value = null;
|
28681 | }
|
28682 | node.attr(internalName, value);
|
28683 | node.attr(name, value);
|
28684 | } else if (name === 'tabindex') {
|
28685 | node.attr(internalName, value);
|
28686 | node.attr(name, null);
|
28687 | } else {
|
28688 | node.attr(internalName, editor.convertURL(value, name, node.name));
|
28689 | }
|
28690 | }
|
28691 | }
|
28692 | });
|
28693 | parser.addNodeFilter('script', nodes => {
|
28694 | let i = nodes.length;
|
28695 | while (i--) {
|
28696 | const node = nodes[i];
|
28697 | const type = node.attr('type') || 'no/type';
|
28698 | if (type.indexOf('mce-') !== 0) {
|
28699 | node.attr('type', 'mce-' + type);
|
28700 | }
|
28701 | }
|
28702 | });
|
28703 | if (shouldPreserveCData(editor)) {
|
28704 | parser.addNodeFilter('#cdata', nodes => {
|
28705 | var _a;
|
28706 | let i = nodes.length;
|
28707 | while (i--) {
|
28708 | const node = nodes[i];
|
28709 | node.type = 8;
|
28710 | node.name = '#comment';
|
28711 | node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]';
|
28712 | }
|
28713 | });
|
28714 | }
|
28715 | parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => {
|
28716 | let i = nodes.length;
|
28717 | const nonEmptyElements = editor.schema.getNonEmptyElements();
|
28718 | while (i--) {
|
28719 | const node = nodes[i];
|
28720 | if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
|
28721 | node.append(new AstNode('br', 1));
|
28722 | }
|
28723 | }
|
28724 | });
|
28725 | return parser;
|
28726 | };
|
28727 | const autoFocus = editor => {
|
28728 | const autoFocus = getAutoFocus(editor);
|
28729 | if (autoFocus) {
|
28730 | Delay.setEditorTimeout(editor, () => {
|
28731 | let focusEditor;
|
28732 | if (autoFocus === true) {
|
28733 | focusEditor = editor;
|
28734 | } else {
|
28735 | focusEditor = editor.editorManager.get(autoFocus);
|
28736 | }
|
28737 | if (focusEditor && !focusEditor.destroyed) {
|
28738 | focusEditor.focus();
|
28739 | focusEditor.selection.scrollIntoView();
|
28740 | }
|
28741 | }, 100);
|
28742 | }
|
28743 | };
|
28744 | const moveSelectionToFirstCaretPosition = editor => {
|
28745 | const root = editor.dom.getRoot();
|
28746 | if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
|
28747 | firstPositionIn(root).each(pos => {
|
28748 | const node = pos.getNode();
|
28749 | const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
|
28750 | editor.selection.setRng(caretPos.toRange());
|
28751 | });
|
28752 | }
|
28753 | };
|
28754 | const initEditor = editor => {
|
28755 | editor.bindPendingEventDelegates();
|
28756 | editor.initialized = true;
|
28757 | fireInit(editor);
|
28758 | editor.focus(true);
|
28759 | moveSelectionToFirstCaretPosition(editor);
|
28760 | editor.nodeChanged({ initial: true });
|
28761 | const initInstanceCallback = getInitInstanceCallback(editor);
|
28762 | if (isFunction(initInstanceCallback)) {
|
28763 | initInstanceCallback.call(editor, editor);
|
28764 | }
|
28765 | autoFocus(editor);
|
28766 | };
|
28767 | const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
|
28768 | const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
|
28769 | const {
|
28770 | pass: bundledCss,
|
28771 | fail: normalCss
|
28772 | } = partition$2(css, name => tinymce.Resource.has(toContentSkinResourceName(name)));
|
28773 | const bundledPromises = bundledCss.map(url => {
|
28774 | const css = tinymce.Resource.get(toContentSkinResourceName(url));
|
28775 | if (isString(css)) {
|
28776 | return Promise.resolve(getStyleSheetLoader$1(editor).loadRawCss(url, css));
|
28777 | }
|
28778 | return Promise.resolve();
|
28779 | });
|
28780 | const promises = [
|
28781 | ...bundledPromises,
|
28782 | getStyleSheetLoader$1(editor).loadAll(normalCss)
|
28783 | ];
|
28784 | if (editor.inline) {
|
28785 | return promises;
|
28786 | } else {
|
28787 | return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
|
28788 | }
|
28789 | };
|
28790 | const loadContentCss = editor => {
|
28791 | const styleSheetLoader = getStyleSheetLoader$1(editor);
|
28792 | const fontCss = getFontCss(editor);
|
28793 | const css = editor.contentCSS;
|
28794 | const removeCss = () => {
|
28795 | styleSheetLoader.unloadAll(css);
|
28796 | if (!editor.inline) {
|
28797 | editor.ui.styleSheetLoader.unloadAll(fontCss);
|
28798 | }
|
28799 | };
|
28800 | const loaded = () => {
|
28801 | if (editor.removed) {
|
28802 | removeCss();
|
28803 | } else {
|
28804 | editor.on('remove', removeCss);
|
28805 | }
|
28806 | };
|
28807 | if (editor.contentStyles.length > 0) {
|
28808 | let contentCssText = '';
|
28809 | Tools.each(editor.contentStyles, style => {
|
28810 | contentCssText += style + '\r\n';
|
28811 | });
|
28812 | editor.dom.addStyle(contentCssText);
|
28813 | }
|
28814 | const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
|
28815 | const contentStyle = getContentStyle(editor);
|
28816 | if (contentStyle) {
|
28817 | appendStyle(editor, contentStyle);
|
28818 | }
|
28819 | return allStylesheets;
|
28820 | };
|
28821 | const preInit = editor => {
|
28822 | const doc = editor.getDoc(), body = editor.getBody();
|
28823 | firePreInit(editor);
|
28824 | if (!shouldBrowserSpellcheck(editor)) {
|
28825 | doc.body.spellcheck = false;
|
28826 | DOM$6.setAttrib(body, 'spellcheck', 'false');
|
28827 | }
|
28828 | editor.quirks = Quirks(editor);
|
28829 | firePostRender(editor);
|
28830 | const directionality = getDirectionality(editor);
|
28831 | if (directionality !== undefined) {
|
28832 | body.dir = directionality;
|
28833 | }
|
28834 | const protect = getProtect(editor);
|
28835 | if (protect) {
|
28836 | editor.on('BeforeSetContent', e => {
|
28837 | Tools.each(protect, pattern => {
|
28838 | e.content = e.content.replace(pattern, str => {
|
28839 | return '<!--mce:protected ' + escape(str) + '-->';
|
28840 | });
|
28841 | });
|
28842 | });
|
28843 | }
|
28844 | editor.on('SetContent', () => {
|
28845 | editor.addVisual(editor.getBody());
|
28846 | });
|
28847 | editor.on('compositionstart compositionend', e => {
|
28848 | editor.composing = e.type === 'compositionstart';
|
28849 | });
|
28850 | };
|
28851 | const loadInitialContent = editor => {
|
28852 | if (!isRtc(editor)) {
|
28853 | editor.load({
|
28854 | initial: true,
|
28855 | format: 'html'
|
28856 | });
|
28857 | }
|
28858 | editor.startContent = editor.getContent({ format: 'raw' });
|
28859 | };
|
28860 | const initEditorWithInitialContent = editor => {
|
28861 | if (editor.removed !== true) {
|
28862 | loadInitialContent(editor);
|
28863 | initEditor(editor);
|
28864 | }
|
28865 | };
|
28866 | const startProgress = editor => {
|
28867 | let canceled = false;
|
28868 | const progressTimeout = setTimeout(() => {
|
28869 | if (!canceled) {
|
28870 | editor.setProgressState(true);
|
28871 | }
|
28872 | }, 500);
|
28873 | return () => {
|
28874 | clearTimeout(progressTimeout);
|
28875 | canceled = true;
|
28876 | editor.setProgressState(false);
|
28877 | };
|
28878 | };
|
28879 | const contentBodyLoaded = editor => {
|
28880 | const targetElm = editor.getElement();
|
28881 | let doc = editor.getDoc();
|
28882 | if (editor.inline) {
|
28883 | DOM$6.addClass(targetElm, 'mce-content-body');
|
28884 | editor.contentDocument = doc = document;
|
28885 | editor.contentWindow = window;
|
28886 | editor.bodyElement = targetElm;
|
28887 | editor.contentAreaContainer = targetElm;
|
28888 | }
|
28889 | const body = editor.getBody();
|
28890 | body.disabled = true;
|
28891 | editor.readonly = isReadOnly$1(editor);
|
28892 | editor._editableRoot = hasEditableRoot$1(editor);
|
28893 | if (!editor.readonly && editor.hasEditableRoot()) {
|
28894 | if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
|
28895 | body.style.position = 'relative';
|
28896 | }
|
28897 | body.contentEditable = 'true';
|
28898 | }
|
28899 | body.disabled = false;
|
28900 | editor.editorUpload = EditorUpload(editor);
|
28901 | editor.schema = Schema(mkSchemaSettings(editor));
|
28902 | editor.dom = DOMUtils(doc, {
|
28903 | keep_values: true,
|
28904 | url_converter: editor.convertURL,
|
28905 | url_converter_scope: editor,
|
28906 | update_styles: true,
|
28907 | root_element: editor.inline ? editor.getBody() : null,
|
28908 | collect: editor.inline,
|
28909 | schema: editor.schema,
|
28910 | contentCssCors: shouldUseContentCssCors(editor),
|
28911 | referrerPolicy: getReferrerPolicy(editor),
|
28912 | onSetAttrib: e => {
|
28913 | editor.dispatch('SetAttrib', e);
|
28914 | }
|
28915 | });
|
28916 | editor.parser = createParser(editor);
|
28917 | editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
|
28918 | editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
|
28919 | editor.annotator = Annotator(editor);
|
28920 | editor.formatter = Formatter(editor);
|
28921 | editor.undoManager = UndoManager(editor);
|
28922 | editor._nodeChangeDispatcher = new NodeChange(editor);
|
28923 | editor._selectionOverrides = SelectionOverrides(editor);
|
28924 | setup$p(editor);
|
28925 | setup$6(editor);
|
28926 | setup$n(editor);
|
28927 | if (!isRtc(editor)) {
|
28928 | setup$5(editor);
|
28929 | setup$1(editor);
|
28930 | }
|
28931 | const caret = setup$b(editor);
|
28932 | setup$q(editor, caret);
|
28933 | setup$o(editor);
|
28934 | setup$r(editor);
|
28935 | setup$7(editor);
|
28936 | const setupRtcThunk = setup$t(editor);
|
28937 | preInit(editor);
|
28938 | validateEditorLicenseKey(editor);
|
28939 | setupRtcThunk.fold(() => {
|
28940 | const cancelProgress = startProgress(editor);
|
28941 | loadContentCss(editor).then(() => {
|
28942 | initEditorWithInitialContent(editor);
|
28943 | cancelProgress();
|
28944 | });
|
28945 | }, setupRtc => {
|
28946 | editor.setProgressState(true);
|
28947 | loadContentCss(editor).then(() => {
|
28948 | setupRtc().then(_rtcMode => {
|
28949 | editor.setProgressState(false);
|
28950 | initEditorWithInitialContent(editor);
|
28951 | bindEvents(editor);
|
28952 | }, err => {
|
28953 | editor.notificationManager.open({
|
28954 | type: 'error',
|
28955 | text: String(err)
|
28956 | });
|
28957 | initEditorWithInitialContent(editor);
|
28958 | bindEvents(editor);
|
28959 | });
|
28960 | });
|
28961 | });
|
28962 | };
|
28963 |
|
28964 | const filter = always;
|
28965 | const bind = (element, event, handler) => bind$2(element, event, filter, handler);
|
28966 |
|
28967 | const DOM$5 = DOMUtils.DOM;
|
28968 | const createIframeElement = (id, title, customAttrs, tabindex) => {
|
28969 | const iframe = SugarElement.fromTag('iframe');
|
28970 | tabindex.each(t => set$3(iframe, 'tabindex', t));
|
28971 | setAll$1(iframe, customAttrs);
|
28972 | setAll$1(iframe, {
|
28973 | id: id + '_ifr',
|
28974 | frameBorder: '0',
|
28975 | allowTransparency: 'true',
|
28976 | title
|
28977 | });
|
28978 | add$2(iframe, 'tox-edit-area__iframe');
|
28979 | return iframe;
|
28980 | };
|
28981 | const getIframeHtml = editor => {
|
28982 | let iframeHTML = getDocType(editor) + '<html><head>';
|
28983 | if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
|
28984 | iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
|
28985 | }
|
28986 | iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
|
28987 | const bodyId = getBodyId(editor);
|
28988 | const bodyClass = getBodyClass(editor);
|
28989 | const translatedAriaText = editor.translate(getIframeAriaText(editor));
|
28990 | if (getContentSecurityPolicy(editor)) {
|
28991 | iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />';
|
28992 | }
|
28993 | iframeHTML += '</head>' + `<body id="${ bodyId }" class="mce-content-body ${ bodyClass }" data-id="${ editor.id }" aria-label="${ translatedAriaText }">` + '<br>' + '</body></html>';
|
28994 | return iframeHTML;
|
28995 | };
|
28996 | const createIframe = (editor, boxInfo) => {
|
28997 | const iframeTitle = Env.browser.isFirefox() ? getIframeAriaText(editor) : 'Rich Text Area';
|
28998 | const translatedTitle = editor.translate(iframeTitle);
|
28999 | const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt);
|
29000 | const ifr = createIframeElement(editor.id, translatedTitle, getIframeAttrs(editor), tabindex).dom;
|
29001 | ifr.onload = () => {
|
29002 | ifr.onload = null;
|
29003 | editor.dispatch('load');
|
29004 | };
|
29005 | editor.contentAreaContainer = boxInfo.iframeContainer;
|
29006 | editor.iframeElement = ifr;
|
29007 | editor.iframeHTML = getIframeHtml(editor);
|
29008 | DOM$5.add(boxInfo.iframeContainer, ifr);
|
29009 | };
|
29010 | const setupIframeBody = editor => {
|
29011 | const iframe = editor.iframeElement;
|
29012 | const ready = () => {
|
29013 | editor.contentDocument = iframe.contentDocument;
|
29014 | contentBodyLoaded(editor);
|
29015 | };
|
29016 | if (shouldUseDocumentWrite(editor) || Env.browser.isFirefox()) {
|
29017 | const doc = editor.getDoc();
|
29018 | doc.open();
|
29019 | doc.write(editor.iframeHTML);
|
29020 | doc.close();
|
29021 | ready();
|
29022 | } else {
|
29023 | const binder = bind(SugarElement.fromDom(iframe), 'load', () => {
|
29024 | binder.unbind();
|
29025 | ready();
|
29026 | });
|
29027 | iframe.srcdoc = editor.iframeHTML;
|
29028 | }
|
29029 | };
|
29030 | const init$1 = (editor, boxInfo) => {
|
29031 | createIframe(editor, boxInfo);
|
29032 | if (boxInfo.editorContainer) {
|
29033 | boxInfo.editorContainer.style.display = editor.orgDisplay;
|
29034 | editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
|
29035 | }
|
29036 | editor.getElement().style.display = 'none';
|
29037 | DOM$5.setAttrib(editor.id, 'aria-hidden', 'true');
|
29038 | editor.getElement().style.visibility = editor.orgVisibility;
|
29039 | setupIframeBody(editor);
|
29040 | };
|
29041 |
|
29042 | const DOM$4 = DOMUtils.DOM;
|
29043 | const initPlugin = (editor, initializedPlugins, plugin) => {
|
29044 | const Plugin = PluginManager.get(plugin);
|
29045 | const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
|
29046 | plugin = Tools.trim(plugin);
|
29047 | if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
|
29048 | if (editor.plugins[plugin]) {
|
29049 | return;
|
29050 | }
|
29051 | try {
|
29052 | const pluginInstance = Plugin(editor, pluginUrl) || {};
|
29053 | editor.plugins[plugin] = pluginInstance;
|
29054 | if (isFunction(pluginInstance.init)) {
|
29055 | pluginInstance.init(editor, pluginUrl);
|
29056 | initializedPlugins.push(plugin);
|
29057 | }
|
29058 | } catch (e) {
|
29059 | pluginInitError(editor, plugin, e);
|
29060 | }
|
29061 | }
|
29062 | };
|
29063 | const trimLegacyPrefix = name => {
|
29064 | return name.replace(/^\-/, '');
|
29065 | };
|
29066 | const initPlugins = editor => {
|
29067 | const initializedPlugins = [];
|
29068 | each$e(getPlugins(editor), name => {
|
29069 | initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
|
29070 | });
|
29071 | };
|
29072 | const initIcons = editor => {
|
29073 | const iconPackName = Tools.trim(getIconPackName(editor));
|
29074 | const currentIcons = editor.ui.registry.getAll().icons;
|
29075 | const loadIcons = {
|
29076 | ...IconManager.get('default').icons,
|
29077 | ...IconManager.get(iconPackName).icons
|
29078 | };
|
29079 | each$d(loadIcons, (svgData, icon) => {
|
29080 | if (!has$2(currentIcons, icon)) {
|
29081 | editor.ui.registry.addIcon(icon, svgData);
|
29082 | }
|
29083 | });
|
29084 | };
|
29085 | const initTheme = editor => {
|
29086 | const theme = getTheme(editor);
|
29087 | if (isString(theme)) {
|
29088 | const Theme = ThemeManager.get(theme);
|
29089 | editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
|
29090 | if (isFunction(editor.theme.init)) {
|
29091 | editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''));
|
29092 | }
|
29093 | } else {
|
29094 | editor.theme = {};
|
29095 | }
|
29096 | };
|
29097 | const initModel = editor => {
|
29098 | const model = getModel(editor);
|
29099 | const Model = ModelManager.get(model);
|
29100 | editor.model = Model(editor, ModelManager.urls[model]);
|
29101 | };
|
29102 | const renderFromLoadedTheme = editor => {
|
29103 | const render = editor.theme.renderUI;
|
29104 | return render ? render() : renderThemeFalse(editor);
|
29105 | };
|
29106 | const renderFromThemeFunc = editor => {
|
29107 | const elm = editor.getElement();
|
29108 | const theme = getTheme(editor);
|
29109 | const info = theme(editor, elm);
|
29110 | if (info.editorContainer.nodeType) {
|
29111 | info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
|
29112 | }
|
29113 | if (info.iframeContainer && info.iframeContainer.nodeType) {
|
29114 | info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
|
29115 | }
|
29116 | info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
|
29117 | return info;
|
29118 | };
|
29119 | const createThemeFalseResult = (element, iframe) => {
|
29120 | return {
|
29121 | editorContainer: element,
|
29122 | iframeContainer: iframe,
|
29123 | api: {}
|
29124 | };
|
29125 | };
|
29126 | const renderThemeFalseIframe = targetElement => {
|
29127 | const iframeContainer = DOM$4.create('div');
|
29128 | DOM$4.insertAfter(iframeContainer, targetElement);
|
29129 | return createThemeFalseResult(iframeContainer, iframeContainer);
|
29130 | };
|
29131 | const renderThemeFalse = editor => {
|
29132 | const targetElement = editor.getElement();
|
29133 | return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
|
29134 | };
|
29135 | const renderThemeUi = editor => {
|
29136 | const elm = editor.getElement();
|
29137 | editor.orgDisplay = elm.style.display;
|
29138 | if (isString(getTheme(editor))) {
|
29139 | return renderFromLoadedTheme(editor);
|
29140 | } else if (isFunction(getTheme(editor))) {
|
29141 | return renderFromThemeFunc(editor);
|
29142 | } else {
|
29143 | return renderThemeFalse(editor);
|
29144 | }
|
29145 | };
|
29146 | const augmentEditorUiApi = (editor, api) => {
|
29147 | const uiApiFacade = {
|
29148 | show: Optional.from(api.show).getOr(noop),
|
29149 | hide: Optional.from(api.hide).getOr(noop),
|
29150 | isEnabled: Optional.from(api.isEnabled).getOr(always),
|
29151 | setEnabled: state => {
|
29152 | if (!editor.mode.isReadOnly()) {
|
29153 | Optional.from(api.setEnabled).each(f => f(state));
|
29154 | }
|
29155 | }
|
29156 | };
|
29157 | editor.ui = {
|
29158 | ...editor.ui,
|
29159 | ...uiApiFacade
|
29160 | };
|
29161 | };
|
29162 | const init = async editor => {
|
29163 | editor.dispatch('ScriptsLoaded');
|
29164 | initIcons(editor);
|
29165 | initTheme(editor);
|
29166 | initModel(editor);
|
29167 | initPlugins(editor);
|
29168 | const renderInfo = await renderThemeUi(editor);
|
29169 | augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
|
29170 | editor.editorContainer = renderInfo.editorContainer;
|
29171 | appendContentCssFromSettings(editor);
|
29172 | if (editor.inline) {
|
29173 | contentBodyLoaded(editor);
|
29174 | } else {
|
29175 | init$1(editor, {
|
29176 | editorContainer: renderInfo.editorContainer,
|
29177 | iframeContainer: renderInfo.iframeContainer
|
29178 | });
|
29179 | }
|
29180 | };
|
29181 |
|
29182 | const DOM$3 = DOMUtils.DOM;
|
29183 | const hasSkipLoadPrefix = name => name.charAt(0) === '-';
|
29184 | const loadLanguage = (scriptLoader, editor) => {
|
29185 | const languageCode = getLanguageCode(editor);
|
29186 | const languageUrl = getLanguageUrl(editor);
|
29187 | if (!I18n.hasCode(languageCode) && languageCode !== 'en') {
|
29188 | const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`;
|
29189 | scriptLoader.add(url).catch(() => {
|
29190 | languageLoadError(editor, url, languageCode);
|
29191 | });
|
29192 | }
|
29193 | };
|
29194 | const loadTheme = (editor, suffix) => {
|
29195 | const theme = getTheme(editor);
|
29196 | if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
|
29197 | const themeUrl = getThemeUrl(editor);
|
29198 | const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`;
|
29199 | ThemeManager.load(theme, url).catch(() => {
|
29200 | themeLoadError(editor, url, theme);
|
29201 | });
|
29202 | }
|
29203 | };
|
29204 | const loadModel = (editor, suffix) => {
|
29205 | const model = getModel(editor);
|
29206 | if (model !== 'plugin' && !has$2(ModelManager.urls, model)) {
|
29207 | const modelUrl = getModelUrl(editor);
|
29208 | const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`;
|
29209 | ModelManager.load(model, url).catch(() => {
|
29210 | modelLoadError(editor, url, model);
|
29211 | });
|
29212 | }
|
29213 | };
|
29214 | const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({
|
29215 | url,
|
29216 | name: Optional.none()
|
29217 | }));
|
29218 | const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({
|
29219 | url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`,
|
29220 | name: Optional.some(name)
|
29221 | }));
|
29222 | const loadIcons = (scriptLoader, editor, suffix) => {
|
29223 | const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix);
|
29224 | const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ''));
|
29225 | each$e(cat([
|
29226 | defaultIconsUrl,
|
29227 | customIconsUrl
|
29228 | ]), urlMeta => {
|
29229 | scriptLoader.add(urlMeta.url).catch(() => {
|
29230 | iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
|
29231 | });
|
29232 | });
|
29233 | };
|
29234 | const loadPlugins = (editor, suffix) => {
|
29235 | const loadPlugin = (name, url) => {
|
29236 | PluginManager.load(name, url).catch(() => {
|
29237 | pluginLoadError(editor, url, name);
|
29238 | });
|
29239 | };
|
29240 | each$d(getExternalPlugins$1(editor), (url, name) => {
|
29241 | loadPlugin(name, url);
|
29242 | editor.options.set('plugins', getPlugins(editor).concat(name));
|
29243 | });
|
29244 | each$e(getPlugins(editor), plugin => {
|
29245 | plugin = Tools.trim(plugin);
|
29246 | if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
|
29247 | loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`);
|
29248 | }
|
29249 | });
|
29250 | };
|
29251 | const isThemeLoaded = editor => {
|
29252 | const theme = getTheme(editor);
|
29253 | return !isString(theme) || isNonNullable(ThemeManager.get(theme));
|
29254 | };
|
29255 | const isModelLoaded = editor => {
|
29256 | const model = getModel(editor);
|
29257 | return isNonNullable(ModelManager.get(model));
|
29258 | };
|
29259 | const loadScripts = (editor, suffix) => {
|
29260 | const scriptLoader = ScriptLoader.ScriptLoader;
|
29261 | const initEditor = () => {
|
29262 | if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
|
29263 | init(editor);
|
29264 | }
|
29265 | };
|
29266 | loadTheme(editor, suffix);
|
29267 | loadModel(editor, suffix);
|
29268 | loadLanguage(scriptLoader, editor);
|
29269 | loadIcons(scriptLoader, editor, suffix);
|
29270 | loadPlugins(editor, suffix);
|
29271 | scriptLoader.loadQueue().then(initEditor, initEditor);
|
29272 | };
|
29273 | const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
|
29274 | contentCssCors: hasContentCssCors(editor),
|
29275 | referrerPolicy: getReferrerPolicy(editor)
|
29276 | });
|
29277 | const render = editor => {
|
29278 | const id = editor.id;
|
29279 | I18n.setCode(getLanguageCode(editor));
|
29280 | const readyHandler = () => {
|
29281 | DOM$3.unbind(window, 'ready', readyHandler);
|
29282 | editor.render();
|
29283 | };
|
29284 | if (!EventUtils.Event.domLoaded) {
|
29285 | DOM$3.bind(window, 'ready', readyHandler);
|
29286 | return;
|
29287 | }
|
29288 | if (!editor.getElement()) {
|
29289 | return;
|
29290 | }
|
29291 | const element = SugarElement.fromDom(editor.getElement());
|
29292 | const snapshot = clone$4(element);
|
29293 | editor.on('remove', () => {
|
29294 | eachr(element.dom.attributes, attr => remove$9(element, attr.name));
|
29295 | setAll$1(element, snapshot);
|
29296 | });
|
29297 | editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
|
29298 | if (!isInline$1(editor)) {
|
29299 | editor.orgVisibility = editor.getElement().style.visibility;
|
29300 | editor.getElement().style.visibility = 'hidden';
|
29301 | } else {
|
29302 | editor.inline = true;
|
29303 | }
|
29304 | const form = editor.getElement().form || DOM$3.getParent(id, 'form');
|
29305 | if (form) {
|
29306 | editor.formElement = form;
|
29307 | if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
|
29308 | DOM$3.insertAfter(DOM$3.create('input', {
|
29309 | type: 'hidden',
|
29310 | name: id
|
29311 | }), id);
|
29312 | editor.hasHiddenInput = true;
|
29313 | }
|
29314 | editor.formEventDelegate = e => {
|
29315 | editor.dispatch(e.type, e);
|
29316 | };
|
29317 | DOM$3.bind(form, 'submit reset', editor.formEventDelegate);
|
29318 | editor.on('reset', () => {
|
29319 | editor.resetContent();
|
29320 | });
|
29321 | if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
|
29322 | form._mceOldSubmit = form.submit;
|
29323 | form.submit = () => {
|
29324 | editor.editorManager.triggerSave();
|
29325 | editor.setDirty(false);
|
29326 | return form._mceOldSubmit(form);
|
29327 | };
|
29328 | }
|
29329 | }
|
29330 | editor.windowManager = WindowManager(editor);
|
29331 | editor.notificationManager = NotificationManager(editor);
|
29332 | if (isEncodingXml(editor)) {
|
29333 | editor.on('GetContent', e => {
|
29334 | if (e.save) {
|
29335 | e.content = DOM$3.encode(e.content);
|
29336 | }
|
29337 | });
|
29338 | }
|
29339 | if (shouldAddFormSubmitTrigger(editor)) {
|
29340 | editor.on('submit', () => {
|
29341 | if (editor.initialized) {
|
29342 | editor.save();
|
29343 | }
|
29344 | });
|
29345 | }
|
29346 | if (shouldAddUnloadTrigger(editor)) {
|
29347 | editor._beforeUnload = () => {
|
29348 | if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
|
29349 | editor.save({
|
29350 | format: 'raw',
|
29351 | no_events: true,
|
29352 | set_dirty: false
|
29353 | });
|
29354 | }
|
29355 | };
|
29356 | editor.editorManager.on('BeforeUnload', editor._beforeUnload);
|
29357 | }
|
29358 | editor.editorManager.add(editor);
|
29359 | loadScripts(editor, editor.suffix);
|
29360 | };
|
29361 |
|
29362 | const setEditableRoot = (editor, state) => {
|
29363 | if (editor._editableRoot !== state) {
|
29364 | editor._editableRoot = state;
|
29365 | if (!editor.readonly) {
|
29366 | editor.getBody().contentEditable = String(editor.hasEditableRoot());
|
29367 | editor.nodeChanged();
|
29368 | }
|
29369 | fireEditableRootStateChange(editor, state);
|
29370 | }
|
29371 | };
|
29372 | const hasEditableRoot = editor => editor._editableRoot;
|
29373 |
|
29374 | const sectionResult = (sections, settings) => ({
|
29375 | sections: constant(sections),
|
29376 | options: constant(settings)
|
29377 | });
|
29378 | const deviceDetection = detect$1().deviceType;
|
29379 | const isPhone = deviceDetection.isPhone();
|
29380 | const isTablet = deviceDetection.isTablet();
|
29381 | const normalizePlugins = plugins => {
|
29382 | if (isNullable(plugins)) {
|
29383 | return [];
|
29384 | } else {
|
29385 | const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
|
29386 | const trimmedPlugins = map$3(pluginNames, trim$4);
|
29387 | return filter$5(trimmedPlugins, isNotEmpty);
|
29388 | }
|
29389 | };
|
29390 | const extractSections = (keys, options) => {
|
29391 | const result = bifilter(options, (value, key) => {
|
29392 | return contains$2(keys, key);
|
29393 | });
|
29394 | return sectionResult(result.t, result.f);
|
29395 | };
|
29396 | const getSection = (sectionResult, name, defaults = {}) => {
|
29397 | const sections = sectionResult.sections();
|
29398 | const sectionOptions = get$a(sections, name).getOr({});
|
29399 | return Tools.extend({}, defaults, sectionOptions);
|
29400 | };
|
29401 | const hasSection = (sectionResult, name) => {
|
29402 | return has$2(sectionResult.sections(), name);
|
29403 | };
|
29404 | const getSectionConfig = (sectionResult, name) => {
|
29405 | return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
|
29406 | };
|
29407 | const getMobileOverrideOptions = (mobileOptions, isPhone) => {
|
29408 | const defaultMobileOptions = {
|
29409 | table_grid: false,
|
29410 | object_resizing: false,
|
29411 | resize: false,
|
29412 | toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'),
|
29413 | toolbar_sticky: false
|
29414 | };
|
29415 | const defaultPhoneOptions = { menubar: false };
|
29416 | return {
|
29417 | ...defaultMobileOptions,
|
29418 | ...isPhone ? defaultPhoneOptions : {}
|
29419 | };
|
29420 | };
|
29421 | const getExternalPlugins = (overrideOptions, options) => {
|
29422 | var _a;
|
29423 | const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
|
29424 | if (overrideOptions && overrideOptions.external_plugins) {
|
29425 | return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
|
29426 | } else {
|
29427 | return userDefinedExternalPlugins;
|
29428 | }
|
29429 | };
|
29430 | const combinePlugins = (forcedPlugins, plugins) => [
|
29431 | ...normalizePlugins(forcedPlugins),
|
29432 | ...normalizePlugins(plugins)
|
29433 | ];
|
29434 | const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => {
|
29435 | if (isMobileDevice && hasSection(sectionResult, 'mobile')) {
|
29436 | return mobilePlugins;
|
29437 | } else {
|
29438 | return desktopPlugins;
|
29439 | }
|
29440 | };
|
29441 | const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => {
|
29442 | const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
|
29443 | const desktopPlugins = normalizePlugins(options.plugins);
|
29444 | const mobileConfig = getSectionConfig(sectionResult, 'mobile');
|
29445 | const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
|
29446 | const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins);
|
29447 | const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
|
29448 | return Tools.extend(options, {
|
29449 | forced_plugins: forcedPlugins,
|
29450 | plugins: combinedPlugins
|
29451 | });
|
29452 | };
|
29453 | const isOnMobile = (isMobileDevice, sectionResult) => {
|
29454 | return isMobileDevice && hasSection(sectionResult, 'mobile');
|
29455 | };
|
29456 | const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => {
|
29457 | var _a;
|
29458 | const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {};
|
29459 | const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options));
|
29460 | const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) });
|
29461 | return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions);
|
29462 | };
|
29463 | const normalizeOptions = (defaultOverrideOptions, options) => combineOptions(isPhone || isTablet, isPhone, options, defaultOverrideOptions, options);
|
29464 |
|
29465 | const addVisual = (editor, elm) => addVisual$1(editor, elm);
|
29466 |
|
29467 | const registerExecCommands$2 = editor => {
|
29468 | const toggleFormat = (name, value) => {
|
29469 | editor.formatter.toggle(name, value);
|
29470 | editor.nodeChanged();
|
29471 | };
|
29472 | const toggleAlign = align => () => {
|
29473 | each$e('left,center,right,justify'.split(','), name => {
|
29474 | if (align !== name) {
|
29475 | editor.formatter.remove('align' + name);
|
29476 | }
|
29477 | });
|
29478 | if (align !== 'none') {
|
29479 | toggleFormat('align' + align);
|
29480 | }
|
29481 | };
|
29482 | editor.editorCommands.addCommands({
|
29483 | JustifyLeft: toggleAlign('left'),
|
29484 | JustifyCenter: toggleAlign('center'),
|
29485 | JustifyRight: toggleAlign('right'),
|
29486 | JustifyFull: toggleAlign('justify'),
|
29487 | JustifyNone: toggleAlign('none')
|
29488 | });
|
29489 | };
|
29490 | const registerQueryStateCommands = editor => {
|
29491 | const alignStates = name => () => {
|
29492 | const selection = editor.selection;
|
29493 | const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
|
29494 | return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name)));
|
29495 | };
|
29496 | editor.editorCommands.addCommands({
|
29497 | JustifyLeft: alignStates('alignleft'),
|
29498 | JustifyCenter: alignStates('aligncenter'),
|
29499 | JustifyRight: alignStates('alignright'),
|
29500 | JustifyFull: alignStates('alignjustify')
|
29501 | }, 'state');
|
29502 | };
|
29503 | const registerCommands$a = editor => {
|
29504 | registerExecCommands$2(editor);
|
29505 | registerQueryStateCommands(editor);
|
29506 | };
|
29507 |
|
29508 | const registerCommands$9 = editor => {
|
29509 | editor.editorCommands.addCommands({
|
29510 | 'Cut,Copy,Paste': command => {
|
29511 | const doc = editor.getDoc();
|
29512 | let failed;
|
29513 | try {
|
29514 | doc.execCommand(command);
|
29515 | } catch (ex) {
|
29516 | failed = true;
|
29517 | }
|
29518 | if (command === 'paste' && !doc.queryCommandEnabled(command)) {
|
29519 | failed = true;
|
29520 | }
|
29521 | if (failed || !doc.queryCommandSupported(command)) {
|
29522 | let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
|
29523 | if (Env.os.isMacOS() || Env.os.isiOS()) {
|
29524 | msg = msg.replace(/Ctrl\+/g, '\u2318+');
|
29525 | }
|
29526 | editor.notificationManager.open({
|
29527 | text: msg,
|
29528 | type: 'error'
|
29529 | });
|
29530 | }
|
29531 | }
|
29532 | });
|
29533 | };
|
29534 |
|
29535 | const trimOrPadLeftRight = (dom, rng, html, schema) => {
|
29536 | const root = SugarElement.fromDom(dom.getRoot());
|
29537 | if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng), schema)) {
|
29538 | html = html.replace(/^ /, ' ');
|
29539 | } else {
|
29540 | html = html.replace(/^ /, ' ');
|
29541 | }
|
29542 | if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng), schema)) {
|
29543 | html = html.replace(/( | )(<br( \/)>)?$/, ' ');
|
29544 | } else {
|
29545 | html = html.replace(/ (<br( \/)?>)?$/, ' ');
|
29546 | }
|
29547 | return html;
|
29548 | };
|
29549 |
|
29550 | const processValue$1 = value => {
|
29551 | if (typeof value !== 'string') {
|
29552 | const details = Tools.extend({
|
29553 | paste: value.paste,
|
29554 | data: { paste: value.paste }
|
29555 | }, value);
|
29556 | return {
|
29557 | content: value.content,
|
29558 | details
|
29559 | };
|
29560 | }
|
29561 | return {
|
29562 | content: value,
|
29563 | details: {}
|
29564 | };
|
29565 | };
|
29566 | const trimOrPad = (editor, value) => {
|
29567 | const selection = editor.selection;
|
29568 | const dom = editor.dom;
|
29569 | if (/^ | $/.test(value)) {
|
29570 | return trimOrPadLeftRight(dom, selection.getRng(), value, editor.schema);
|
29571 | } else {
|
29572 | return value;
|
29573 | }
|
29574 | };
|
29575 | const insertAtCaret = (editor, value) => {
|
29576 | if (editor.selection.isEditable()) {
|
29577 | const {content, details} = processValue$1(value);
|
29578 | preProcessSetContent(editor, {
|
29579 | ...details,
|
29580 | content: trimOrPad(editor, content),
|
29581 | format: 'html',
|
29582 | set: false,
|
29583 | selection: true
|
29584 | }).each(args => {
|
29585 | const insertedContent = insertContent$1(editor, args.content, details);
|
29586 | postProcessSetContent(editor, insertedContent, args);
|
29587 | editor.addVisual();
|
29588 | });
|
29589 | }
|
29590 | };
|
29591 |
|
29592 | const registerCommands$8 = editor => {
|
29593 | editor.editorCommands.addCommands({
|
29594 | mceCleanup: () => {
|
29595 | const bm = editor.selection.getBookmark();
|
29596 | editor.setContent(editor.getContent());
|
29597 | editor.selection.moveToBookmark(bm);
|
29598 | },
|
29599 | insertImage: (_command, _ui, value) => {
|
29600 | insertAtCaret(editor, editor.dom.createHTML('img', { src: value }));
|
29601 | },
|
29602 | insertHorizontalRule: () => {
|
29603 | editor.execCommand('mceInsertContent', false, '<hr>');
|
29604 | },
|
29605 | insertText: (_command, _ui, value) => {
|
29606 | insertAtCaret(editor, editor.dom.encode(value));
|
29607 | },
|
29608 | insertHTML: (_command, _ui, value) => {
|
29609 | insertAtCaret(editor, value);
|
29610 | },
|
29611 | mceInsertContent: (_command, _ui, value) => {
|
29612 | insertAtCaret(editor, value);
|
29613 | },
|
29614 | mceSetContent: (_command, _ui, value) => {
|
29615 | editor.setContent(value);
|
29616 | },
|
29617 | mceReplaceContent: (_command, _ui, value) => {
|
29618 | editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
|
29619 | },
|
29620 | mceNewDocument: () => {
|
29621 | editor.setContent(getNewDocumentContent(editor));
|
29622 | }
|
29623 | });
|
29624 | };
|
29625 |
|
29626 | const legacyPropNames = {
|
29627 | 'font-size': 'size',
|
29628 | 'font-family': 'face'
|
29629 | };
|
29630 | const isFont = isTag('font');
|
29631 | const getSpecifiedFontProp = (propName, rootElm, elm) => {
|
29632 | const getProperty = elm => getRaw(elm, propName).orThunk(() => {
|
29633 | if (isFont(elm)) {
|
29634 | return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName));
|
29635 | } else {
|
29636 | return Optional.none();
|
29637 | }
|
29638 | });
|
29639 | const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm);
|
29640 | return closest$1(SugarElement.fromDom(elm), elm => getProperty(elm), isRoot);
|
29641 | };
|
29642 | const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
|
29643 | const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
|
29644 | const getFontProp = propName => (rootElm, elm) => Optional.from(elm).map(SugarElement.fromDom).filter(isElement$7).bind(element => getSpecifiedFontProp(propName, rootElm, element.dom).or(getComputedFontProp(propName, element.dom))).getOr('');
|
29645 | const getFontSize = getFontProp('font-size');
|
29646 | const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family'));
|
29647 |
|
29648 | const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => {
|
29649 | const container = caret.container();
|
29650 | return Optional.from(isText$b(container) ? container.parentNode : container);
|
29651 | });
|
29652 | const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => {
|
29653 | const root = editor.getBody();
|
29654 | const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
|
29655 | return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
|
29656 | });
|
29657 | const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder);
|
29658 | const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
|
29659 |
|
29660 | const fromFontSizeNumber = (editor, value) => {
|
29661 | if (/^[0-9.]+$/.test(value)) {
|
29662 | const fontSizeNumber = parseInt(value, 10);
|
29663 | if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
|
29664 | const fontSizes = getFontStyleValues(editor);
|
29665 | const fontClasses = getFontSizeClasses(editor);
|
29666 | if (fontClasses.length > 0) {
|
29667 | return fontClasses[fontSizeNumber - 1] || value;
|
29668 | } else {
|
29669 | return fontSizes[fontSizeNumber - 1] || value;
|
29670 | }
|
29671 | } else {
|
29672 | return value;
|
29673 | }
|
29674 | } else {
|
29675 | return value;
|
29676 | }
|
29677 | };
|
29678 | const normalizeFontNames = font => {
|
29679 | const fonts = font.split(/\s*,\s*/);
|
29680 | return map$3(fonts, font => {
|
29681 | if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) {
|
29682 | return `'${ font }'`;
|
29683 | } else {
|
29684 | return font;
|
29685 | }
|
29686 | }).join(',');
|
29687 | };
|
29688 | const fontNameAction = (editor, value) => {
|
29689 | const font = fromFontSizeNumber(editor, value);
|
29690 | editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
|
29691 | editor.nodeChanged();
|
29692 | };
|
29693 | const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr('');
|
29694 | const fontSizeAction = (editor, value) => {
|
29695 | editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
|
29696 | editor.nodeChanged();
|
29697 | };
|
29698 | const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr('');
|
29699 |
|
29700 | const lineHeightQuery = editor => mapRange(editor, elm => {
|
29701 | const root = SugarElement.fromDom(editor.getBody());
|
29702 | const specifiedStyle = closest$1(elm, elm => getRaw(elm, 'line-height'), curry(eq, root));
|
29703 | const computedStyle = () => {
|
29704 | const lineHeight = parseFloat(get$7(elm, 'line-height'));
|
29705 | const fontSize = parseFloat(get$7(elm, 'font-size'));
|
29706 | return String(lineHeight / fontSize);
|
29707 | };
|
29708 | return specifiedStyle.getOrThunk(computedStyle);
|
29709 | }).getOr('');
|
29710 | const lineHeightAction = (editor, lineHeight) => {
|
29711 | editor.formatter.toggle('lineheight', { value: String(lineHeight) });
|
29712 | editor.nodeChanged();
|
29713 | };
|
29714 |
|
29715 | const registerExecCommands$1 = editor => {
|
29716 | const toggleFormat = (name, value) => {
|
29717 | editor.formatter.toggle(name, value);
|
29718 | editor.nodeChanged();
|
29719 | };
|
29720 | editor.editorCommands.addCommands({
|
29721 | 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => {
|
29722 | toggleFormat(command);
|
29723 | },
|
29724 | 'ForeColor,HiliteColor': (command, _ui, value) => {
|
29725 | toggleFormat(command, { value });
|
29726 | },
|
29727 | 'BackColor': (_command, _ui, value) => {
|
29728 | toggleFormat('hilitecolor', { value });
|
29729 | },
|
29730 | 'FontName': (_command, _ui, value) => {
|
29731 | fontNameAction(editor, value);
|
29732 | },
|
29733 | 'FontSize': (_command, _ui, value) => {
|
29734 | fontSizeAction(editor, value);
|
29735 | },
|
29736 | 'LineHeight': (_command, _ui, value) => {
|
29737 | lineHeightAction(editor, value);
|
29738 | },
|
29739 | 'Lang': (command, _ui, lang) => {
|
29740 | var _a;
|
29741 | toggleFormat(command, {
|
29742 | value: lang.code,
|
29743 | customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null
|
29744 | });
|
29745 | },
|
29746 | 'RemoveFormat': command => {
|
29747 | editor.formatter.remove(command);
|
29748 | },
|
29749 | 'mceBlockQuote': () => {
|
29750 | toggleFormat('blockquote');
|
29751 | },
|
29752 | 'FormatBlock': (_command, _ui, value) => {
|
29753 | toggleFormat(isString(value) ? value : 'p');
|
29754 | },
|
29755 | 'mceToggleFormat': (_command, _ui, value) => {
|
29756 | toggleFormat(value);
|
29757 | }
|
29758 | });
|
29759 | };
|
29760 | const registerQueryValueCommands = editor => {
|
29761 | const isFormatMatch = name => editor.formatter.match(name);
|
29762 | editor.editorCommands.addCommands({
|
29763 | 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command),
|
29764 | 'mceBlockQuote': () => isFormatMatch('blockquote')
|
29765 | }, 'state');
|
29766 | editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor));
|
29767 | editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor));
|
29768 | editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor));
|
29769 | };
|
29770 | const registerCommands$7 = editor => {
|
29771 | registerExecCommands$1(editor);
|
29772 | registerQueryValueCommands(editor);
|
29773 | };
|
29774 |
|
29775 | const registerCommands$6 = editor => {
|
29776 | editor.editorCommands.addCommands({
|
29777 | mceAddUndoLevel: () => {
|
29778 | editor.undoManager.add();
|
29779 | },
|
29780 | mceEndUndoLevel: () => {
|
29781 | editor.undoManager.add();
|
29782 | },
|
29783 | Undo: () => {
|
29784 | editor.undoManager.undo();
|
29785 | },
|
29786 | Redo: () => {
|
29787 | editor.undoManager.redo();
|
29788 | }
|
29789 | });
|
29790 | };
|
29791 |
|
29792 | const registerCommands$5 = editor => {
|
29793 | editor.editorCommands.addCommands({
|
29794 | Indent: () => {
|
29795 | indent(editor);
|
29796 | },
|
29797 | Outdent: () => {
|
29798 | outdent(editor);
|
29799 | }
|
29800 | });
|
29801 | editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state');
|
29802 | };
|
29803 |
|
29804 | const registerCommands$4 = editor => {
|
29805 | const applyLinkToSelection = (_command, _ui, value) => {
|
29806 | const linkDetails = isString(value) ? { href: value } : value;
|
29807 | const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
|
29808 | if (isObject(linkDetails) && isString(linkDetails.href)) {
|
29809 | linkDetails.href = linkDetails.href.replace(/ /g, '%20');
|
29810 | if (!anchor || !linkDetails.href) {
|
29811 | editor.formatter.remove('link');
|
29812 | }
|
29813 | if (linkDetails.href) {
|
29814 | editor.formatter.apply('link', linkDetails, anchor);
|
29815 | }
|
29816 | }
|
29817 | };
|
29818 | editor.editorCommands.addCommands({
|
29819 | unlink: () => {
|
29820 | if (editor.selection.isEditable()) {
|
29821 | if (editor.selection.isCollapsed()) {
|
29822 | const elm = editor.dom.getParent(editor.selection.getStart(), 'a');
|
29823 | if (elm) {
|
29824 | editor.dom.remove(elm, true);
|
29825 | }
|
29826 | return;
|
29827 | }
|
29828 | editor.formatter.remove('link');
|
29829 | }
|
29830 | },
|
29831 | mceInsertLink: applyLinkToSelection,
|
29832 | createLink: applyLinkToSelection
|
29833 | });
|
29834 | };
|
29835 |
|
29836 | const getTopParentBlock = (editor, node, root, container) => {
|
29837 | const dom = editor.dom;
|
29838 | const selector = node => dom.isBlock(node) && node.parentElement === root;
|
29839 | const topParentBlock = selector(node) ? node : dom.getParent(container, selector, root);
|
29840 | return Optional.from(topParentBlock).map(SugarElement.fromDom);
|
29841 | };
|
29842 | const insert = (editor, before) => {
|
29843 | const dom = editor.dom;
|
29844 | const rng = editor.selection.getRng();
|
29845 | const node = before ? editor.selection.getStart() : editor.selection.getEnd();
|
29846 | const container = before ? rng.startContainer : rng.endContainer;
|
29847 | const root = getEditableRoot(dom, container);
|
29848 | if (!root || !root.isContentEditable) {
|
29849 | return;
|
29850 | }
|
29851 | const insertFn = before ? before$3 : after$4;
|
29852 | const newBlockName = getForcedRootBlock(editor);
|
29853 | getTopParentBlock(editor, node, root, container).each(parentBlock => {
|
29854 | const newBlock = createNewBlock(editor, container, parentBlock.dom, root, false, newBlockName);
|
29855 | insertFn(parentBlock, SugarElement.fromDom(newBlock));
|
29856 | editor.selection.setCursorLocation(newBlock, 0);
|
29857 | editor.dispatch('NewBlock', { newBlock });
|
29858 | fireInputEvent(editor, 'insertParagraph');
|
29859 | });
|
29860 | };
|
29861 | const insertBefore = editor => insert(editor, true);
|
29862 | const insertAfter = editor => insert(editor, false);
|
29863 |
|
29864 | const registerCommands$3 = editor => {
|
29865 | editor.editorCommands.addCommands({
|
29866 | InsertNewBlockBefore: () => {
|
29867 | insertBefore(editor);
|
29868 | },
|
29869 | InsertNewBlockAfter: () => {
|
29870 | insertAfter(editor);
|
29871 | }
|
29872 | });
|
29873 | };
|
29874 |
|
29875 | const registerCommands$2 = editor => {
|
29876 | editor.editorCommands.addCommands({
|
29877 | insertParagraph: () => {
|
29878 | insertBreak(blockbreak, editor);
|
29879 | },
|
29880 | mceInsertNewLine: (_command, _ui, value) => {
|
29881 | insert$1(editor, value);
|
29882 | },
|
29883 | InsertLineBreak: (_command, _ui, _value) => {
|
29884 | insertBreak(linebreak, editor);
|
29885 | }
|
29886 | });
|
29887 | };
|
29888 |
|
29889 | const registerCommands$1 = editor => {
|
29890 | editor.editorCommands.addCommands({
|
29891 | mceSelectNodeDepth: (_command, _ui, value) => {
|
29892 | let counter = 0;
|
29893 | editor.dom.getParent(editor.selection.getNode(), node => {
|
29894 | if (isElement$6(node) && counter++ === value) {
|
29895 | editor.selection.select(node);
|
29896 | return false;
|
29897 | } else {
|
29898 | return true;
|
29899 | }
|
29900 | }, editor.getBody());
|
29901 | },
|
29902 | mceSelectNode: (_command, _ui, value) => {
|
29903 | editor.selection.select(value);
|
29904 | },
|
29905 | selectAll: () => {
|
29906 | const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3);
|
29907 | if (editingHost) {
|
29908 | const rng = editor.dom.createRng();
|
29909 | rng.selectNodeContents(editingHost);
|
29910 | editor.selection.setRng(rng);
|
29911 | }
|
29912 | }
|
29913 | });
|
29914 | };
|
29915 |
|
29916 | const registerExecCommands = editor => {
|
29917 | editor.editorCommands.addCommands({
|
29918 | mceRemoveNode: (_command, _ui, value) => {
|
29919 | const node = value !== null && value !== void 0 ? value : editor.selection.getNode();
|
29920 | if (node !== editor.getBody()) {
|
29921 | const bm = editor.selection.getBookmark();
|
29922 | editor.dom.remove(node, true);
|
29923 | editor.selection.moveToBookmark(bm);
|
29924 | }
|
29925 | },
|
29926 | mcePrint: () => {
|
29927 | editor.getWin().print();
|
29928 | },
|
29929 | mceFocus: (_command, _ui, value) => {
|
29930 | focus(editor, value === true);
|
29931 | },
|
29932 | mceToggleVisualAid: () => {
|
29933 | editor.hasVisual = !editor.hasVisual;
|
29934 | editor.addVisual();
|
29935 | }
|
29936 | });
|
29937 | };
|
29938 | const registerCommands = editor => {
|
29939 | registerCommands$a(editor);
|
29940 | registerCommands$9(editor);
|
29941 | registerCommands$6(editor);
|
29942 | registerCommands$1(editor);
|
29943 | registerCommands$8(editor);
|
29944 | registerCommands$4(editor);
|
29945 | registerCommands$5(editor);
|
29946 | registerCommands$3(editor);
|
29947 | registerCommands$2(editor);
|
29948 | registerCommands$7(editor);
|
29949 | registerExecCommands(editor);
|
29950 | };
|
29951 |
|
29952 | const selectionSafeCommands = ['toggleview'];
|
29953 | const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase());
|
29954 | class EditorCommands {
|
29955 | constructor(editor) {
|
29956 | this.commands = {
|
29957 | state: {},
|
29958 | exec: {},
|
29959 | value: {}
|
29960 | };
|
29961 | this.editor = editor;
|
29962 | }
|
29963 | execCommand(command, ui = false, value, args) {
|
29964 | const editor = this.editor;
|
29965 | const lowerCaseCommand = command.toLowerCase();
|
29966 | const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
|
29967 | if (editor.removed) {
|
29968 | return false;
|
29969 | }
|
29970 | if (lowerCaseCommand !== 'mcefocus') {
|
29971 | if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
|
29972 | editor.focus();
|
29973 | } else {
|
29974 | restore(editor);
|
29975 | }
|
29976 | }
|
29977 | const eventArgs = editor.dispatch('BeforeExecCommand', {
|
29978 | command,
|
29979 | ui,
|
29980 | value
|
29981 | });
|
29982 | if (eventArgs.isDefaultPrevented()) {
|
29983 | return false;
|
29984 | }
|
29985 | const func = this.commands.exec[lowerCaseCommand];
|
29986 | if (isFunction(func)) {
|
29987 | func(lowerCaseCommand, ui, value);
|
29988 | editor.dispatch('ExecCommand', {
|
29989 | command,
|
29990 | ui,
|
29991 | value
|
29992 | });
|
29993 | return true;
|
29994 | }
|
29995 | return false;
|
29996 | }
|
29997 | queryCommandState(command) {
|
29998 | if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
|
29999 | return false;
|
30000 | }
|
30001 | const lowerCaseCommand = command.toLowerCase();
|
30002 | const func = this.commands.state[lowerCaseCommand];
|
30003 | if (isFunction(func)) {
|
30004 | return func(lowerCaseCommand);
|
30005 | }
|
30006 | return false;
|
30007 | }
|
30008 | queryCommandValue(command) {
|
30009 | if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
|
30010 | return '';
|
30011 | }
|
30012 | const lowerCaseCommand = command.toLowerCase();
|
30013 | const func = this.commands.value[lowerCaseCommand];
|
30014 | if (isFunction(func)) {
|
30015 | return func(lowerCaseCommand);
|
30016 | }
|
30017 | return '';
|
30018 | }
|
30019 | addCommands(commandList, type = 'exec') {
|
30020 | const commands = this.commands;
|
30021 | each$d(commandList, (callback, command) => {
|
30022 | each$e(command.toLowerCase().split(','), command => {
|
30023 | commands[type][command] = callback;
|
30024 | });
|
30025 | });
|
30026 | }
|
30027 | addCommand(command, callback, scope) {
|
30028 | const lowerCaseCommand = command.toLowerCase();
|
30029 | this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value);
|
30030 | }
|
30031 | queryCommandSupported(command) {
|
30032 | const lowerCaseCommand = command.toLowerCase();
|
30033 | if (this.commands.exec[lowerCaseCommand]) {
|
30034 | return true;
|
30035 | } else {
|
30036 | return false;
|
30037 | }
|
30038 | }
|
30039 | addQueryStateHandler(command, callback, scope) {
|
30040 | this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
|
30041 | }
|
30042 | addQueryValueHandler(command, callback, scope) {
|
30043 | this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
|
30044 | }
|
30045 | }
|
30046 |
|
30047 | const internalContentEditableAttr = 'data-mce-contenteditable';
|
30048 | const toggleClass = (elm, cls, state) => {
|
30049 | if (has(elm, cls) && !state) {
|
30050 | remove$6(elm, cls);
|
30051 | } else if (state) {
|
30052 | add$2(elm, cls);
|
30053 | }
|
30054 | };
|
30055 | const setEditorCommandState = (editor, cmd, state) => {
|
30056 | try {
|
30057 | editor.getDoc().execCommand(cmd, false, String(state));
|
30058 | } catch (ex) {
|
30059 | }
|
30060 | };
|
30061 | const setContentEditable = (elm, state) => {
|
30062 | elm.dom.contentEditable = state ? 'true' : 'false';
|
30063 | };
|
30064 | const switchOffContentEditableTrue = elm => {
|
30065 | each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
|
30066 | set$3(elm, internalContentEditableAttr, 'true');
|
30067 | setContentEditable(elm, false);
|
30068 | });
|
30069 | };
|
30070 | const switchOnContentEditableTrue = elm => {
|
30071 | each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
|
30072 | remove$9(elm, internalContentEditableAttr);
|
30073 | setContentEditable(elm, true);
|
30074 | });
|
30075 | };
|
30076 | const removeFakeSelection = editor => {
|
30077 | Optional.from(editor.selection.getNode()).each(elm => {
|
30078 | elm.removeAttribute('data-mce-selected');
|
30079 | });
|
30080 | };
|
30081 | const restoreFakeSelection = editor => {
|
30082 | editor.selection.setRng(editor.selection.getRng());
|
30083 | };
|
30084 | const toggleReadOnly = (editor, state) => {
|
30085 | const body = SugarElement.fromDom(editor.getBody());
|
30086 | toggleClass(body, 'mce-content-readonly', state);
|
30087 | if (state) {
|
30088 | editor.selection.controlSelection.hideResizeRect();
|
30089 | editor._selectionOverrides.hideFakeCaret();
|
30090 | removeFakeSelection(editor);
|
30091 | editor.readonly = true;
|
30092 | setContentEditable(body, false);
|
30093 | switchOffContentEditableTrue(body);
|
30094 | } else {
|
30095 | editor.readonly = false;
|
30096 | if (editor.hasEditableRoot()) {
|
30097 | setContentEditable(body, true);
|
30098 | }
|
30099 | switchOnContentEditableTrue(body);
|
30100 | setEditorCommandState(editor, 'StyleWithCSS', false);
|
30101 | setEditorCommandState(editor, 'enableInlineTableEditing', false);
|
30102 | setEditorCommandState(editor, 'enableObjectResizing', false);
|
30103 | if (hasEditorOrUiFocus(editor)) {
|
30104 | editor.focus();
|
30105 | }
|
30106 | restoreFakeSelection(editor);
|
30107 | editor.nodeChanged();
|
30108 | }
|
30109 | };
|
30110 | const isReadOnly = editor => editor.readonly;
|
30111 | const registerFilters = editor => {
|
30112 | editor.parser.addAttributeFilter('contenteditable', nodes => {
|
30113 | if (isReadOnly(editor)) {
|
30114 | each$e(nodes, node => {
|
30115 | node.attr(internalContentEditableAttr, node.attr('contenteditable'));
|
30116 | node.attr('contenteditable', 'false');
|
30117 | });
|
30118 | }
|
30119 | });
|
30120 | editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
|
30121 | if (isReadOnly(editor)) {
|
30122 | each$e(nodes, node => {
|
30123 | node.attr('contenteditable', node.attr(internalContentEditableAttr));
|
30124 | });
|
30125 | }
|
30126 | });
|
30127 | editor.serializer.addTempAttr(internalContentEditableAttr);
|
30128 | };
|
30129 | const registerReadOnlyContentFilters = editor => {
|
30130 | if (editor.serializer) {
|
30131 | registerFilters(editor);
|
30132 | } else {
|
30133 | editor.on('PreInit', () => {
|
30134 | registerFilters(editor);
|
30135 | });
|
30136 | }
|
30137 | };
|
30138 | const isClickEvent = e => e.type === 'click';
|
30139 | const allowedEvents = ['copy'];
|
30140 | const isReadOnlyAllowedEvent = e => contains$2(allowedEvents, e.type);
|
30141 | const getAnchorHrefOpt = (editor, elm) => {
|
30142 | const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
|
30143 | return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href'));
|
30144 | };
|
30145 | const processReadonlyEvents = (editor, e) => {
|
30146 | if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
|
30147 | const elm = SugarElement.fromDom(e.target);
|
30148 | getAnchorHrefOpt(editor, elm).each(href => {
|
30149 | e.preventDefault();
|
30150 | if (/^#/.test(href)) {
|
30151 | const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`);
|
30152 | if (targetEl.length) {
|
30153 | editor.selection.scrollIntoView(targetEl[0], true);
|
30154 | }
|
30155 | } else {
|
30156 | window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes');
|
30157 | }
|
30158 | });
|
30159 | } else if (isReadOnlyAllowedEvent(e)) {
|
30160 | editor.dispatch(e.type, e);
|
30161 | }
|
30162 | };
|
30163 | const registerReadOnlySelectionBlockers = editor => {
|
30164 | editor.on('ShowCaret', e => {
|
30165 | if (isReadOnly(editor)) {
|
30166 | e.preventDefault();
|
30167 | }
|
30168 | });
|
30169 | editor.on('ObjectSelected', e => {
|
30170 | if (isReadOnly(editor)) {
|
30171 | e.preventDefault();
|
30172 | }
|
30173 | });
|
30174 | };
|
30175 |
|
30176 | const nativeEvents = Tools.makeMap('focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange ' + 'mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover ' + 'draggesture dragdrop drop drag submit ' + 'compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel', ' ');
|
30177 | class EventDispatcher {
|
30178 | static isNative(name) {
|
30179 | return !!nativeEvents[name.toLowerCase()];
|
30180 | }
|
30181 | constructor(settings) {
|
30182 | this.bindings = {};
|
30183 | this.settings = settings || {};
|
30184 | this.scope = this.settings.scope || this;
|
30185 | this.toggleEvent = this.settings.toggleEvent || never;
|
30186 | }
|
30187 | fire(name, args) {
|
30188 | return this.dispatch(name, args);
|
30189 | }
|
30190 | dispatch(name, args) {
|
30191 | const lcName = name.toLowerCase();
|
30192 | const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
|
30193 | if (this.settings.beforeFire) {
|
30194 | this.settings.beforeFire(event);
|
30195 | }
|
30196 | const handlers = this.bindings[lcName];
|
30197 | if (handlers) {
|
30198 | for (let i = 0, l = handlers.length; i < l; i++) {
|
30199 | const callback = handlers[i];
|
30200 | if (callback.removed) {
|
30201 | continue;
|
30202 | }
|
30203 | if (callback.once) {
|
30204 | this.off(lcName, callback.func);
|
30205 | }
|
30206 | if (event.isImmediatePropagationStopped()) {
|
30207 | return event;
|
30208 | }
|
30209 | if (callback.func.call(this.scope, event) === false) {
|
30210 | event.preventDefault();
|
30211 | return event;
|
30212 | }
|
30213 | }
|
30214 | }
|
30215 | return event;
|
30216 | }
|
30217 | on(name, callback, prepend, extra) {
|
30218 | if (callback === false) {
|
30219 | callback = never;
|
30220 | }
|
30221 | if (callback) {
|
30222 | const wrappedCallback = {
|
30223 | func: callback,
|
30224 | removed: false
|
30225 | };
|
30226 | if (extra) {
|
30227 | Tools.extend(wrappedCallback, extra);
|
30228 | }
|
30229 | const names = name.toLowerCase().split(' ');
|
30230 | let i = names.length;
|
30231 | while (i--) {
|
30232 | const currentName = names[i];
|
30233 | let handlers = this.bindings[currentName];
|
30234 | if (!handlers) {
|
30235 | handlers = [];
|
30236 | this.toggleEvent(currentName, true);
|
30237 | }
|
30238 | if (prepend) {
|
30239 | handlers = [
|
30240 | wrappedCallback,
|
30241 | ...handlers
|
30242 | ];
|
30243 | } else {
|
30244 | handlers = [
|
30245 | ...handlers,
|
30246 | wrappedCallback
|
30247 | ];
|
30248 | }
|
30249 | this.bindings[currentName] = handlers;
|
30250 | }
|
30251 | }
|
30252 | return this;
|
30253 | }
|
30254 | off(name, callback) {
|
30255 | if (name) {
|
30256 | const names = name.toLowerCase().split(' ');
|
30257 | let i = names.length;
|
30258 | while (i--) {
|
30259 | const currentName = names[i];
|
30260 | let handlers = this.bindings[currentName];
|
30261 | if (!currentName) {
|
30262 | each$d(this.bindings, (_value, bindingName) => {
|
30263 | this.toggleEvent(bindingName, false);
|
30264 | delete this.bindings[bindingName];
|
30265 | });
|
30266 | return this;
|
30267 | }
|
30268 | if (handlers) {
|
30269 | if (!callback) {
|
30270 | handlers.length = 0;
|
30271 | } else {
|
30272 | const filteredHandlers = partition$2(handlers, handler => handler.func === callback);
|
30273 | handlers = filteredHandlers.fail;
|
30274 | this.bindings[currentName] = handlers;
|
30275 | each$e(filteredHandlers.pass, handler => {
|
30276 | handler.removed = true;
|
30277 | });
|
30278 | }
|
30279 | if (!handlers.length) {
|
30280 | this.toggleEvent(name, false);
|
30281 | delete this.bindings[currentName];
|
30282 | }
|
30283 | }
|
30284 | }
|
30285 | } else {
|
30286 | each$d(this.bindings, (_value, name) => {
|
30287 | this.toggleEvent(name, false);
|
30288 | });
|
30289 | this.bindings = {};
|
30290 | }
|
30291 | return this;
|
30292 | }
|
30293 | once(name, callback, prepend) {
|
30294 | return this.on(name, callback, prepend, { once: true });
|
30295 | }
|
30296 | has(name) {
|
30297 | name = name.toLowerCase();
|
30298 | const binding = this.bindings[name];
|
30299 | return !(!binding || binding.length === 0);
|
30300 | }
|
30301 | }
|
30302 |
|
30303 | const getEventDispatcher = obj => {
|
30304 | if (!obj._eventDispatcher) {
|
30305 | obj._eventDispatcher = new EventDispatcher({
|
30306 | scope: obj,
|
30307 | toggleEvent: (name, state) => {
|
30308 | if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
|
30309 | obj.toggleNativeEvent(name, state);
|
30310 | }
|
30311 | }
|
30312 | });
|
30313 | }
|
30314 | return obj._eventDispatcher;
|
30315 | };
|
30316 | const Observable = {
|
30317 | fire(name, args, bubble) {
|
30318 | return this.dispatch(name, args, bubble);
|
30319 | },
|
30320 | dispatch(name, args, bubble) {
|
30321 | const self = this;
|
30322 | if (self.removed && name !== 'remove' && name !== 'detach') {
|
30323 | return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
|
30324 | }
|
30325 | const dispatcherArgs = getEventDispatcher(self).dispatch(name, args);
|
30326 | if (bubble !== false && self.parent) {
|
30327 | let parent = self.parent();
|
30328 | while (parent && !dispatcherArgs.isPropagationStopped()) {
|
30329 | parent.dispatch(name, dispatcherArgs, false);
|
30330 | parent = parent.parent ? parent.parent() : undefined;
|
30331 | }
|
30332 | }
|
30333 | return dispatcherArgs;
|
30334 | },
|
30335 | on(name, callback, prepend) {
|
30336 | return getEventDispatcher(this).on(name, callback, prepend);
|
30337 | },
|
30338 | off(name, callback) {
|
30339 | return getEventDispatcher(this).off(name, callback);
|
30340 | },
|
30341 | once(name, callback) {
|
30342 | return getEventDispatcher(this).once(name, callback);
|
30343 | },
|
30344 | hasEventListeners(name) {
|
30345 | return getEventDispatcher(this).has(name);
|
30346 | }
|
30347 | };
|
30348 |
|
30349 | const DOM$2 = DOMUtils.DOM;
|
30350 | let customEventRootDelegates;
|
30351 | const getEventTarget = (editor, eventName) => {
|
30352 | if (eventName === 'selectionchange') {
|
30353 | return editor.getDoc();
|
30354 | }
|
30355 | if (!editor.inline && /^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(eventName)) {
|
30356 | return editor.getDoc().documentElement;
|
30357 | }
|
30358 | const eventRoot = getEventRoot(editor);
|
30359 | if (eventRoot) {
|
30360 | if (!editor.eventRoot) {
|
30361 | editor.eventRoot = DOM$2.select(eventRoot)[0];
|
30362 | }
|
30363 | return editor.eventRoot;
|
30364 | }
|
30365 | return editor.getBody();
|
30366 | };
|
30367 | const isListening = editor => !editor.hidden && !isReadOnly(editor);
|
30368 | const fireEvent = (editor, eventName, e) => {
|
30369 | if (isListening(editor)) {
|
30370 | editor.dispatch(eventName, e);
|
30371 | } else if (isReadOnly(editor)) {
|
30372 | processReadonlyEvents(editor, e);
|
30373 | }
|
30374 | };
|
30375 | const bindEventDelegate = (editor, eventName) => {
|
30376 | if (!editor.delegates) {
|
30377 | editor.delegates = {};
|
30378 | }
|
30379 | if (editor.delegates[eventName] || editor.removed) {
|
30380 | return;
|
30381 | }
|
30382 | const eventRootElm = getEventTarget(editor, eventName);
|
30383 | if (getEventRoot(editor)) {
|
30384 | if (!customEventRootDelegates) {
|
30385 | customEventRootDelegates = {};
|
30386 | editor.editorManager.on('removeEditor', () => {
|
30387 | if (!editor.editorManager.activeEditor) {
|
30388 | if (customEventRootDelegates) {
|
30389 | each$d(customEventRootDelegates, (_value, name) => {
|
30390 | editor.dom.unbind(getEventTarget(editor, name));
|
30391 | });
|
30392 | customEventRootDelegates = null;
|
30393 | }
|
30394 | }
|
30395 | });
|
30396 | }
|
30397 | if (customEventRootDelegates[eventName]) {
|
30398 | return;
|
30399 | }
|
30400 | const delegate = e => {
|
30401 | const target = e.target;
|
30402 | const editors = editor.editorManager.get();
|
30403 | let i = editors.length;
|
30404 | while (i--) {
|
30405 | const body = editors[i].getBody();
|
30406 | if (body === target || DOM$2.isChildOf(target, body)) {
|
30407 | fireEvent(editors[i], eventName, e);
|
30408 | }
|
30409 | }
|
30410 | };
|
30411 | customEventRootDelegates[eventName] = delegate;
|
30412 | DOM$2.bind(eventRootElm, eventName, delegate);
|
30413 | } else {
|
30414 | const delegate = e => {
|
30415 | fireEvent(editor, eventName, e);
|
30416 | };
|
30417 | DOM$2.bind(eventRootElm, eventName, delegate);
|
30418 | editor.delegates[eventName] = delegate;
|
30419 | }
|
30420 | };
|
30421 | const EditorObservable = {
|
30422 | ...Observable,
|
30423 | bindPendingEventDelegates() {
|
30424 | const self = this;
|
30425 | Tools.each(self._pendingNativeEvents, name => {
|
30426 | bindEventDelegate(self, name);
|
30427 | });
|
30428 | },
|
30429 | toggleNativeEvent(name, state) {
|
30430 | const self = this;
|
30431 | if (name === 'focus' || name === 'blur') {
|
30432 | return;
|
30433 | }
|
30434 | if (self.removed) {
|
30435 | return;
|
30436 | }
|
30437 | if (state) {
|
30438 | if (self.initialized) {
|
30439 | bindEventDelegate(self, name);
|
30440 | } else {
|
30441 | if (!self._pendingNativeEvents) {
|
30442 | self._pendingNativeEvents = [name];
|
30443 | } else {
|
30444 | self._pendingNativeEvents.push(name);
|
30445 | }
|
30446 | }
|
30447 | } else if (self.initialized && self.delegates) {
|
30448 | self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
|
30449 | delete self.delegates[name];
|
30450 | }
|
30451 | },
|
30452 | unbindAllNativeEvents() {
|
30453 | const self = this;
|
30454 | const body = self.getBody();
|
30455 | const dom = self.dom;
|
30456 | if (self.delegates) {
|
30457 | each$d(self.delegates, (value, name) => {
|
30458 | self.dom.unbind(getEventTarget(self, name), name, value);
|
30459 | });
|
30460 | delete self.delegates;
|
30461 | }
|
30462 | if (!self.inline && body && dom) {
|
30463 | body.onload = null;
|
30464 | dom.unbind(self.getWin());
|
30465 | dom.unbind(self.getDoc());
|
30466 | }
|
30467 | if (dom) {
|
30468 | dom.unbind(body);
|
30469 | dom.unbind(self.getContainer());
|
30470 | }
|
30471 | }
|
30472 | };
|
30473 |
|
30474 | const stringListProcessor = value => {
|
30475 | if (isString(value)) {
|
30476 | return {
|
30477 | value: value.split(/[ ,]/),
|
30478 | valid: true
|
30479 | };
|
30480 | } else if (isArrayOf(value, isString)) {
|
30481 | return {
|
30482 | value,
|
30483 | valid: true
|
30484 | };
|
30485 | } else {
|
30486 | return {
|
30487 | valid: false,
|
30488 | message: `The value must be a string[] or a comma/space separated string.`
|
30489 | };
|
30490 | }
|
30491 | };
|
30492 | const getBuiltInProcessor = type => {
|
30493 | const validator = (() => {
|
30494 | switch (type) {
|
30495 | case 'array':
|
30496 | return isArray$1;
|
30497 | case 'boolean':
|
30498 | return isBoolean;
|
30499 | case 'function':
|
30500 | return isFunction;
|
30501 | case 'number':
|
30502 | return isNumber;
|
30503 | case 'object':
|
30504 | return isObject;
|
30505 | case 'string':
|
30506 | return isString;
|
30507 | case 'string[]':
|
30508 | return stringListProcessor;
|
30509 | case 'object[]':
|
30510 | return val => isArrayOf(val, isObject);
|
30511 | case 'regexp':
|
30512 | return val => is$4(val, RegExp);
|
30513 | default:
|
30514 | return always;
|
30515 | }
|
30516 | })();
|
30517 | return value => processValue(value, validator, `The value must be a ${ type }.`);
|
30518 | };
|
30519 | const isBuiltInSpec = spec => isString(spec.processor);
|
30520 | const getErrorMessage = (message, result) => {
|
30521 | const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`;
|
30522 | return message + additionalText;
|
30523 | };
|
30524 | const isValidResult = result => result.valid;
|
30525 | const processValue = (value, processor, message = '') => {
|
30526 | const result = processor(value);
|
30527 | if (isBoolean(result)) {
|
30528 | return result ? {
|
30529 | value: value,
|
30530 | valid: true
|
30531 | } : {
|
30532 | valid: false,
|
30533 | message
|
30534 | };
|
30535 | } else {
|
30536 | return result;
|
30537 | }
|
30538 | };
|
30539 | const processDefaultValue = (name, defaultValue, processor) => {
|
30540 | if (!isUndefined(defaultValue)) {
|
30541 | const result = processValue(defaultValue, processor);
|
30542 | if (isValidResult(result)) {
|
30543 | return result.value;
|
30544 | } else {
|
30545 | console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result));
|
30546 | }
|
30547 | }
|
30548 | return undefined;
|
30549 | };
|
30550 | const create$5 = (editor, initialOptions) => {
|
30551 | const registry = {};
|
30552 | const values = {};
|
30553 | const setValue = (name, value, processor) => {
|
30554 | const result = processValue(value, processor);
|
30555 | if (isValidResult(result)) {
|
30556 | values[name] = result.value;
|
30557 | return true;
|
30558 | } else {
|
30559 | console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result));
|
30560 | return false;
|
30561 | }
|
30562 | };
|
30563 | const register = (name, spec) => {
|
30564 | const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
|
30565 | const defaultValue = processDefaultValue(name, spec.default, processor);
|
30566 | registry[name] = {
|
30567 | ...spec,
|
30568 | default: defaultValue,
|
30569 | processor
|
30570 | };
|
30571 | const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name));
|
30572 | initValue.each(value => setValue(name, value, processor));
|
30573 | };
|
30574 | const isRegistered = name => has$2(registry, name);
|
30575 | const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined();
|
30576 | const set = (name, value) => {
|
30577 | if (!isRegistered(name)) {
|
30578 | console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`);
|
30579 | return false;
|
30580 | } else {
|
30581 | const spec = registry[name];
|
30582 | if (spec.immutable) {
|
30583 | console.error(`"${ name }" is an immutable option and cannot be updated`);
|
30584 | return false;
|
30585 | } else {
|
30586 | return setValue(name, value, spec.processor);
|
30587 | }
|
30588 | }
|
30589 | };
|
30590 | const unset = name => {
|
30591 | const registered = isRegistered(name);
|
30592 | if (registered) {
|
30593 | delete values[name];
|
30594 | }
|
30595 | return registered;
|
30596 | };
|
30597 | const isSet = name => has$2(values, name);
|
30598 | return {
|
30599 | register,
|
30600 | isRegistered,
|
30601 | get,
|
30602 | set,
|
30603 | unset,
|
30604 | isSet
|
30605 | };
|
30606 | };
|
30607 |
|
30608 | const defaultModes = [
|
30609 | 'design',
|
30610 | 'readonly'
|
30611 | ];
|
30612 | const switchToMode = (editor, activeMode, availableModes, mode) => {
|
30613 | const oldMode = availableModes[activeMode.get()];
|
30614 | const newMode = availableModes[mode];
|
30615 | try {
|
30616 | newMode.activate();
|
30617 | } catch (e) {
|
30618 | console.error(`problem while activating editor mode ${ mode }:`, e);
|
30619 | return;
|
30620 | }
|
30621 | oldMode.deactivate();
|
30622 | if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
|
30623 | toggleReadOnly(editor, newMode.editorReadOnly);
|
30624 | }
|
30625 | activeMode.set(mode);
|
30626 | fireSwitchMode(editor, mode);
|
30627 | };
|
30628 | const setMode = (editor, availableModes, activeMode, mode) => {
|
30629 | if (mode === activeMode.get()) {
|
30630 | return;
|
30631 | } else if (!has$2(availableModes, mode)) {
|
30632 | throw new Error(`Editor mode '${ mode }' is invalid`);
|
30633 | }
|
30634 | if (editor.initialized) {
|
30635 | switchToMode(editor, activeMode, availableModes, mode);
|
30636 | } else {
|
30637 | editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode));
|
30638 | }
|
30639 | };
|
30640 | const registerMode = (availableModes, mode, api) => {
|
30641 | if (contains$2(defaultModes, mode)) {
|
30642 | throw new Error(`Cannot override default mode ${ mode }`);
|
30643 | }
|
30644 | return {
|
30645 | ...availableModes,
|
30646 | [mode]: {
|
30647 | ...api,
|
30648 | deactivate: () => {
|
30649 | try {
|
30650 | api.deactivate();
|
30651 | } catch (e) {
|
30652 | console.error(`problem while deactivating editor mode ${ mode }:`, e);
|
30653 | }
|
30654 | }
|
30655 | }
|
30656 | };
|
30657 | };
|
30658 |
|
30659 | const create$4 = editor => {
|
30660 | const activeMode = Cell('design');
|
30661 | const availableModes = Cell({
|
30662 | design: {
|
30663 | activate: noop,
|
30664 | deactivate: noop,
|
30665 | editorReadOnly: false
|
30666 | },
|
30667 | readonly: {
|
30668 | activate: noop,
|
30669 | deactivate: noop,
|
30670 | editorReadOnly: true
|
30671 | }
|
30672 | });
|
30673 | registerReadOnlyContentFilters(editor);
|
30674 | registerReadOnlySelectionBlockers(editor);
|
30675 | return {
|
30676 | isReadOnly: () => isReadOnly(editor),
|
30677 | set: mode => setMode(editor, availableModes.get(), activeMode, mode),
|
30678 | get: () => activeMode.get(),
|
30679 | register: (mode, api) => {
|
30680 | availableModes.set(registerMode(availableModes.get(), mode, api));
|
30681 | }
|
30682 | };
|
30683 | };
|
30684 |
|
30685 | const each$2 = Tools.each, explode = Tools.explode;
|
30686 | const keyCodeLookup = {
|
30687 | f1: 112,
|
30688 | f2: 113,
|
30689 | f3: 114,
|
30690 | f4: 115,
|
30691 | f5: 116,
|
30692 | f6: 117,
|
30693 | f7: 118,
|
30694 | f8: 119,
|
30695 | f9: 120,
|
30696 | f10: 121,
|
30697 | f11: 122,
|
30698 | f12: 123
|
30699 | };
|
30700 | const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
|
30701 | const isModifier = key => key in modifierNames;
|
30702 | const parseShortcut = pattern => {
|
30703 | const shortcut = {};
|
30704 | const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
30705 | each$2(explode(pattern.toLowerCase(), '+'), value => {
|
30706 | if (isModifier(value)) {
|
30707 | shortcut[value] = true;
|
30708 | } else {
|
30709 | if (/^[0-9]{2,}$/.test(value)) {
|
30710 | shortcut.keyCode = parseInt(value, 10);
|
30711 | } else {
|
30712 | shortcut.charCode = value.charCodeAt(0);
|
30713 | shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
|
30714 | }
|
30715 | }
|
30716 | });
|
30717 | const id = [shortcut.keyCode];
|
30718 | let key;
|
30719 | for (key in modifierNames) {
|
30720 | if (shortcut[key]) {
|
30721 | id.push(key);
|
30722 | } else {
|
30723 | shortcut[key] = false;
|
30724 | }
|
30725 | }
|
30726 | shortcut.id = id.join(',');
|
30727 | if (shortcut.access) {
|
30728 | shortcut.alt = true;
|
30729 | if (isMac) {
|
30730 | shortcut.ctrl = true;
|
30731 | } else {
|
30732 | shortcut.shift = true;
|
30733 | }
|
30734 | }
|
30735 | if (shortcut.meta) {
|
30736 | if (isMac) {
|
30737 | shortcut.meta = true;
|
30738 | } else {
|
30739 | shortcut.ctrl = true;
|
30740 | shortcut.meta = false;
|
30741 | }
|
30742 | }
|
30743 | return shortcut;
|
30744 | };
|
30745 | class Shortcuts {
|
30746 | constructor(editor) {
|
30747 | this.shortcuts = {};
|
30748 | this.pendingPatterns = [];
|
30749 | this.editor = editor;
|
30750 | const self = this;
|
30751 | editor.on('keyup keypress keydown', e => {
|
30752 | if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
|
30753 | each$2(self.shortcuts, shortcut => {
|
30754 | if (self.matchShortcut(e, shortcut)) {
|
30755 | self.pendingPatterns = shortcut.subpatterns.slice(0);
|
30756 | if (e.type === 'keydown') {
|
30757 | self.executeShortcutAction(shortcut);
|
30758 | }
|
30759 | }
|
30760 | });
|
30761 | if (self.matchShortcut(e, self.pendingPatterns[0])) {
|
30762 | if (self.pendingPatterns.length === 1) {
|
30763 | if (e.type === 'keydown') {
|
30764 | self.executeShortcutAction(self.pendingPatterns[0]);
|
30765 | }
|
30766 | }
|
30767 | self.pendingPatterns.shift();
|
30768 | }
|
30769 | }
|
30770 | });
|
30771 | }
|
30772 | add(pattern, desc, cmdFunc, scope) {
|
30773 | const self = this;
|
30774 | const func = self.normalizeCommandFunc(cmdFunc);
|
30775 | each$2(explode(Tools.trim(pattern)), pattern => {
|
30776 | const shortcut = self.createShortcut(pattern, desc, func, scope);
|
30777 | self.shortcuts[shortcut.id] = shortcut;
|
30778 | });
|
30779 | return true;
|
30780 | }
|
30781 | remove(pattern) {
|
30782 | const shortcut = this.createShortcut(pattern);
|
30783 | if (this.shortcuts[shortcut.id]) {
|
30784 | delete this.shortcuts[shortcut.id];
|
30785 | return true;
|
30786 | }
|
30787 | return false;
|
30788 | }
|
30789 | normalizeCommandFunc(cmdFunc) {
|
30790 | const self = this;
|
30791 | const cmd = cmdFunc;
|
30792 | if (typeof cmd === 'string') {
|
30793 | return () => {
|
30794 | self.editor.execCommand(cmd, false, null);
|
30795 | };
|
30796 | } else if (Tools.isArray(cmd)) {
|
30797 | return () => {
|
30798 | self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
|
30799 | };
|
30800 | } else {
|
30801 | return cmd;
|
30802 | }
|
30803 | }
|
30804 | createShortcut(pattern, desc, cmdFunc, scope) {
|
30805 | const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
|
30806 | shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
|
30807 | func: cmdFunc,
|
30808 | scope: scope || this.editor
|
30809 | });
|
30810 | return Tools.extend(shortcuts[0], {
|
30811 | desc: this.editor.translate(desc),
|
30812 | subpatterns: shortcuts.slice(1)
|
30813 | });
|
30814 | }
|
30815 | hasModifier(e) {
|
30816 | return e.altKey || e.ctrlKey || e.metaKey;
|
30817 | }
|
30818 | isFunctionKey(e) {
|
30819 | return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
|
30820 | }
|
30821 | matchShortcut(e, shortcut) {
|
30822 | if (!shortcut) {
|
30823 | return false;
|
30824 | }
|
30825 | if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
|
30826 | return false;
|
30827 | }
|
30828 | if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
|
30829 | return false;
|
30830 | }
|
30831 | if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
|
30832 | e.preventDefault();
|
30833 | return true;
|
30834 | }
|
30835 | return false;
|
30836 | }
|
30837 | executeShortcutAction(shortcut) {
|
30838 | return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
|
30839 | }
|
30840 | }
|
30841 |
|
30842 | const create$3 = () => {
|
30843 | const buttons = {};
|
30844 | const menuItems = {};
|
30845 | const popups = {};
|
30846 | const icons = {};
|
30847 | const contextMenus = {};
|
30848 | const contextToolbars = {};
|
30849 | const sidebars = {};
|
30850 | const views = {};
|
30851 | const add = (collection, type) => (name, spec) => {
|
30852 | collection[name.toLowerCase()] = {
|
30853 | ...spec,
|
30854 | type
|
30855 | };
|
30856 | };
|
30857 | const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
|
30858 | return {
|
30859 | addButton: add(buttons, 'button'),
|
30860 | addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
|
30861 | addToggleButton: add(buttons, 'togglebutton'),
|
30862 | addMenuButton: add(buttons, 'menubutton'),
|
30863 | addSplitButton: add(buttons, 'splitbutton'),
|
30864 | addMenuItem: add(menuItems, 'menuitem'),
|
30865 | addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
|
30866 | addToggleMenuItem: add(menuItems, 'togglemenuitem'),
|
30867 | addAutocompleter: add(popups, 'autocompleter'),
|
30868 | addContextMenu: add(contextMenus, 'contextmenu'),
|
30869 | addContextToolbar: add(contextToolbars, 'contexttoolbar'),
|
30870 | addContextForm: add(contextToolbars, 'contextform'),
|
30871 | addSidebar: add(sidebars, 'sidebar'),
|
30872 | addView: add(views, 'views'),
|
30873 | addIcon,
|
30874 | getAll: () => ({
|
30875 | buttons,
|
30876 | menuItems,
|
30877 | icons,
|
30878 | popups,
|
30879 | contextMenus,
|
30880 | contextToolbars,
|
30881 | sidebars,
|
30882 | views
|
30883 | })
|
30884 | };
|
30885 | };
|
30886 |
|
30887 | const registry = () => {
|
30888 | const bridge = create$3();
|
30889 | return {
|
30890 | addAutocompleter: bridge.addAutocompleter,
|
30891 | addButton: bridge.addButton,
|
30892 | addContextForm: bridge.addContextForm,
|
30893 | addContextMenu: bridge.addContextMenu,
|
30894 | addContextToolbar: bridge.addContextToolbar,
|
30895 | addIcon: bridge.addIcon,
|
30896 | addMenuButton: bridge.addMenuButton,
|
30897 | addMenuItem: bridge.addMenuItem,
|
30898 | addNestedMenuItem: bridge.addNestedMenuItem,
|
30899 | addSidebar: bridge.addSidebar,
|
30900 | addSplitButton: bridge.addSplitButton,
|
30901 | addToggleButton: bridge.addToggleButton,
|
30902 | addGroupToolbarButton: bridge.addGroupToolbarButton,
|
30903 | addToggleMenuItem: bridge.addToggleMenuItem,
|
30904 | addView: bridge.addView,
|
30905 | getAll: bridge.getAll
|
30906 | };
|
30907 | };
|
30908 |
|
30909 | const DOM$1 = DOMUtils.DOM;
|
30910 | const extend = Tools.extend, each$1 = Tools.each;
|
30911 | class Editor {
|
30912 | constructor(id, options, editorManager) {
|
30913 | this.plugins = {};
|
30914 | this.contentCSS = [];
|
30915 | this.contentStyles = [];
|
30916 | this.loadedCSS = {};
|
30917 | this.isNotDirty = false;
|
30918 | this.composing = false;
|
30919 | this.destroyed = false;
|
30920 | this.hasHiddenInput = false;
|
30921 | this.iframeElement = null;
|
30922 | this.initialized = false;
|
30923 | this.readonly = false;
|
30924 | this.removed = false;
|
30925 | this.startContent = '';
|
30926 | this._pendingNativeEvents = [];
|
30927 | this._skinLoaded = false;
|
30928 | this._editableRoot = true;
|
30929 | this.editorManager = editorManager;
|
30930 | this.documentBaseUrl = editorManager.documentBaseURL;
|
30931 | extend(this, EditorObservable);
|
30932 | const self = this;
|
30933 | this.id = id;
|
30934 | this.hidden = false;
|
30935 | const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
|
30936 | this.options = create$5(self, normalizedOptions);
|
30937 | register$7(self);
|
30938 | const getOption = this.options.get;
|
30939 | if (getOption('deprecation_warnings')) {
|
30940 | logWarnings(options, normalizedOptions);
|
30941 | }
|
30942 | const suffix = getOption('suffix');
|
30943 | if (suffix) {
|
30944 | editorManager.suffix = suffix;
|
30945 | }
|
30946 | this.suffix = editorManager.suffix;
|
30947 | const baseUrl = getOption('base_url');
|
30948 | if (baseUrl) {
|
30949 | editorManager._setBaseUrl(baseUrl);
|
30950 | }
|
30951 | this.baseUri = editorManager.baseURI;
|
30952 | const referrerPolicy = getReferrerPolicy(self);
|
30953 | if (referrerPolicy) {
|
30954 | ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy);
|
30955 | DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
|
30956 | }
|
30957 | const contentCssCors = hasContentCssCors(self);
|
30958 | if (isNonNullable(contentCssCors)) {
|
30959 | DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors);
|
30960 | }
|
30961 | AddOnManager.languageLoad = getOption('language_load');
|
30962 | AddOnManager.baseURL = editorManager.baseURL;
|
30963 | this.setDirty(false);
|
30964 | this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
|
30965 | this.baseURI = this.baseUri;
|
30966 | this.inline = isInline$1(self);
|
30967 | this.hasVisual = isVisualAidsEnabled(self);
|
30968 | this.shortcuts = new Shortcuts(this);
|
30969 | this.editorCommands = new EditorCommands(this);
|
30970 | registerCommands(this);
|
30971 | const cacheSuffix = getOption('cache_suffix');
|
30972 | if (cacheSuffix) {
|
30973 | Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, '');
|
30974 | }
|
30975 | this.ui = {
|
30976 | registry: registry(),
|
30977 | styleSheetLoader: undefined,
|
30978 | show: noop,
|
30979 | hide: noop,
|
30980 | setEnabled: noop,
|
30981 | isEnabled: always
|
30982 | };
|
30983 | this.mode = create$4(self);
|
30984 | editorManager.dispatch('SetupEditor', { editor: this });
|
30985 | const setupCallback = getSetupCallback(self);
|
30986 | if (isFunction(setupCallback)) {
|
30987 | setupCallback.call(self, self);
|
30988 | }
|
30989 | }
|
30990 | render() {
|
30991 | render(this);
|
30992 | }
|
30993 | focus(skipFocus) {
|
30994 | this.execCommand('mceFocus', false, skipFocus);
|
30995 | }
|
30996 | hasFocus() {
|
30997 | return hasFocus(this);
|
30998 | }
|
30999 | translate(text) {
|
31000 | return I18n.translate(text);
|
31001 | }
|
31002 | getParam(name, defaultVal, type) {
|
31003 | const options = this.options;
|
31004 | if (!options.isRegistered(name)) {
|
31005 | if (isNonNullable(type)) {
|
31006 | options.register(name, {
|
31007 | processor: type,
|
31008 | default: defaultVal
|
31009 | });
|
31010 | } else {
|
31011 | options.register(name, {
|
31012 | processor: always,
|
31013 | default: defaultVal
|
31014 | });
|
31015 | }
|
31016 | }
|
31017 | return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name);
|
31018 | }
|
31019 | hasPlugin(name, loaded) {
|
31020 | const hasPlugin = contains$2(getPlugins(this), name);
|
31021 | if (hasPlugin) {
|
31022 | return loaded ? PluginManager.get(name) !== undefined : true;
|
31023 | } else {
|
31024 | return false;
|
31025 | }
|
31026 | }
|
31027 | nodeChanged(args) {
|
31028 | this._nodeChangeDispatcher.nodeChanged(args);
|
31029 | }
|
31030 | addCommand(name, callback, scope) {
|
31031 | this.editorCommands.addCommand(name, callback, scope);
|
31032 | }
|
31033 | addQueryStateHandler(name, callback, scope) {
|
31034 | this.editorCommands.addQueryStateHandler(name, callback, scope);
|
31035 | }
|
31036 | addQueryValueHandler(name, callback, scope) {
|
31037 | this.editorCommands.addQueryValueHandler(name, callback, scope);
|
31038 | }
|
31039 | addShortcut(pattern, desc, cmdFunc, scope) {
|
31040 | this.shortcuts.add(pattern, desc, cmdFunc, scope);
|
31041 | }
|
31042 | execCommand(cmd, ui, value, args) {
|
31043 | return this.editorCommands.execCommand(cmd, ui, value, args);
|
31044 | }
|
31045 | queryCommandState(cmd) {
|
31046 | return this.editorCommands.queryCommandState(cmd);
|
31047 | }
|
31048 | queryCommandValue(cmd) {
|
31049 | return this.editorCommands.queryCommandValue(cmd);
|
31050 | }
|
31051 | queryCommandSupported(cmd) {
|
31052 | return this.editorCommands.queryCommandSupported(cmd);
|
31053 | }
|
31054 | show() {
|
31055 | const self = this;
|
31056 | if (self.hidden) {
|
31057 | self.hidden = false;
|
31058 | if (self.inline) {
|
31059 | self.getBody().contentEditable = 'true';
|
31060 | } else {
|
31061 | DOM$1.show(self.getContainer());
|
31062 | DOM$1.hide(self.id);
|
31063 | }
|
31064 | self.load();
|
31065 | self.dispatch('show');
|
31066 | }
|
31067 | }
|
31068 | hide() {
|
31069 | const self = this;
|
31070 | if (!self.hidden) {
|
31071 | self.save();
|
31072 | if (self.inline) {
|
31073 | self.getBody().contentEditable = 'false';
|
31074 | if (self === self.editorManager.focusedEditor) {
|
31075 | self.editorManager.focusedEditor = null;
|
31076 | }
|
31077 | } else {
|
31078 | DOM$1.hide(self.getContainer());
|
31079 | DOM$1.setStyle(self.id, 'display', self.orgDisplay);
|
31080 | }
|
31081 | self.hidden = true;
|
31082 | self.dispatch('hide');
|
31083 | }
|
31084 | }
|
31085 | isHidden() {
|
31086 | return this.hidden;
|
31087 | }
|
31088 | setProgressState(state, time) {
|
31089 | this.dispatch('ProgressState', {
|
31090 | state,
|
31091 | time
|
31092 | });
|
31093 | }
|
31094 | load(args = {}) {
|
31095 | const self = this;
|
31096 | const elm = self.getElement();
|
31097 | if (self.removed) {
|
31098 | return '';
|
31099 | }
|
31100 | if (elm) {
|
31101 | const loadArgs = {
|
31102 | ...args,
|
31103 | load: true
|
31104 | };
|
31105 | const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
|
31106 | const html = self.setContent(value, loadArgs);
|
31107 | if (!loadArgs.no_events) {
|
31108 | self.dispatch('LoadContent', {
|
31109 | ...loadArgs,
|
31110 | element: elm
|
31111 | });
|
31112 | }
|
31113 | return html;
|
31114 | } else {
|
31115 | return '';
|
31116 | }
|
31117 | }
|
31118 | save(args = {}) {
|
31119 | const self = this;
|
31120 | let elm = self.getElement();
|
31121 | if (!elm || !self.initialized || self.removed) {
|
31122 | return '';
|
31123 | }
|
31124 | const getArgs = {
|
31125 | ...args,
|
31126 | save: true,
|
31127 | element: elm
|
31128 | };
|
31129 | let html = self.getContent(getArgs);
|
31130 | const saveArgs = {
|
31131 | ...getArgs,
|
31132 | content: html
|
31133 | };
|
31134 | if (!saveArgs.no_events) {
|
31135 | self.dispatch('SaveContent', saveArgs);
|
31136 | }
|
31137 | if (saveArgs.format === 'raw') {
|
31138 | self.dispatch('RawSaveContent', saveArgs);
|
31139 | }
|
31140 | html = saveArgs.content;
|
31141 | if (!isTextareaOrInput(elm)) {
|
31142 | if (args.is_removing || !self.inline) {
|
31143 | elm.innerHTML = html;
|
31144 | }
|
31145 | const form = DOM$1.getParent(self.id, 'form');
|
31146 | if (form) {
|
31147 | each$1(form.elements, elm => {
|
31148 | if (elm.name === self.id) {
|
31149 | elm.value = html;
|
31150 | return false;
|
31151 | } else {
|
31152 | return true;
|
31153 | }
|
31154 | });
|
31155 | }
|
31156 | } else {
|
31157 | elm.value = html;
|
31158 | }
|
31159 | saveArgs.element = getArgs.element = elm = null;
|
31160 | if (saveArgs.set_dirty !== false) {
|
31161 | self.setDirty(false);
|
31162 | }
|
31163 | return html;
|
31164 | }
|
31165 | setContent(content, args) {
|
31166 | return setContent(this, content, args);
|
31167 | }
|
31168 | getContent(args) {
|
31169 | return getContent(this, args);
|
31170 | }
|
31171 | insertContent(content, args) {
|
31172 | if (args) {
|
31173 | content = extend({ content }, args);
|
31174 | }
|
31175 | this.execCommand('mceInsertContent', false, content);
|
31176 | }
|
31177 | resetContent(initialContent) {
|
31178 | if (initialContent === undefined) {
|
31179 | setContent(this, this.startContent, { format: 'raw' });
|
31180 | } else {
|
31181 | setContent(this, initialContent);
|
31182 | }
|
31183 | this.undoManager.reset();
|
31184 | this.setDirty(false);
|
31185 | this.nodeChanged();
|
31186 | }
|
31187 | isDirty() {
|
31188 | return !this.isNotDirty;
|
31189 | }
|
31190 | setDirty(state) {
|
31191 | const oldState = !this.isNotDirty;
|
31192 | this.isNotDirty = !state;
|
31193 | if (state && state !== oldState) {
|
31194 | this.dispatch('dirty');
|
31195 | }
|
31196 | }
|
31197 | getContainer() {
|
31198 | const self = this;
|
31199 | if (!self.container) {
|
31200 | self.container = self.editorContainer || DOM$1.get(self.id + '_parent');
|
31201 | }
|
31202 | return self.container;
|
31203 | }
|
31204 | getContentAreaContainer() {
|
31205 | return this.contentAreaContainer;
|
31206 | }
|
31207 | getElement() {
|
31208 | if (!this.targetElm) {
|
31209 | this.targetElm = DOM$1.get(this.id);
|
31210 | }
|
31211 | return this.targetElm;
|
31212 | }
|
31213 | getWin() {
|
31214 | const self = this;
|
31215 | if (!self.contentWindow) {
|
31216 | const elm = self.iframeElement;
|
31217 | if (elm) {
|
31218 | self.contentWindow = elm.contentWindow;
|
31219 | }
|
31220 | }
|
31221 | return self.contentWindow;
|
31222 | }
|
31223 | getDoc() {
|
31224 | const self = this;
|
31225 | if (!self.contentDocument) {
|
31226 | const win = self.getWin();
|
31227 | if (win) {
|
31228 | self.contentDocument = win.document;
|
31229 | }
|
31230 | }
|
31231 | return self.contentDocument;
|
31232 | }
|
31233 | getBody() {
|
31234 | var _a, _b;
|
31235 | const doc = this.getDoc();
|
31236 | return (_b = (_a = this.bodyElement) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.body) !== null && _b !== void 0 ? _b : null;
|
31237 | }
|
31238 | convertURL(url, name, elm) {
|
31239 | const self = this, getOption = self.options.get;
|
31240 | const urlConverterCallback = getUrlConverterCallback(self);
|
31241 | if (isFunction(urlConverterCallback)) {
|
31242 | return urlConverterCallback.call(self, url, elm, true, name);
|
31243 | }
|
31244 | if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
|
31245 | return url;
|
31246 | }
|
31247 | const urlObject = new URI(url);
|
31248 | if (urlObject.protocol !== 'http' && urlObject.protocol !== 'https' && urlObject.protocol !== '') {
|
31249 | return url;
|
31250 | }
|
31251 | if (getOption('relative_urls')) {
|
31252 | return self.documentBaseURI.toRelative(url);
|
31253 | }
|
31254 | url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host'));
|
31255 | return url;
|
31256 | }
|
31257 | addVisual(elm) {
|
31258 | addVisual(this, elm);
|
31259 | }
|
31260 | setEditableRoot(state) {
|
31261 | setEditableRoot(this, state);
|
31262 | }
|
31263 | hasEditableRoot() {
|
31264 | return hasEditableRoot(this);
|
31265 | }
|
31266 | remove() {
|
31267 | remove$1(this);
|
31268 | }
|
31269 | destroy(automatic) {
|
31270 | destroy(this, automatic);
|
31271 | }
|
31272 | uploadImages() {
|
31273 | return this.editorUpload.uploadImages();
|
31274 | }
|
31275 | _scanForImages() {
|
31276 | return this.editorUpload.scanForImages();
|
31277 | }
|
31278 | }
|
31279 |
|
31280 | const DOM = DOMUtils.DOM;
|
31281 | const each = Tools.each;
|
31282 | let boundGlobalEvents = false;
|
31283 | let beforeUnloadDelegate;
|
31284 | let editors = [];
|
31285 | const globalEventDelegate = e => {
|
31286 | const type = e.type;
|
31287 | each(EditorManager.get(), editor => {
|
31288 | switch (type) {
|
31289 | case 'scroll':
|
31290 | editor.dispatch('ScrollWindow', e);
|
31291 | break;
|
31292 | case 'resize':
|
31293 | editor.dispatch('ResizeWindow', e);
|
31294 | break;
|
31295 | }
|
31296 | });
|
31297 | };
|
31298 | const toggleGlobalEvents = state => {
|
31299 | if (state !== boundGlobalEvents) {
|
31300 | const DOM = DOMUtils.DOM;
|
31301 | if (state) {
|
31302 | DOM.bind(window, 'resize', globalEventDelegate);
|
31303 | DOM.bind(window, 'scroll', globalEventDelegate);
|
31304 | } else {
|
31305 | DOM.unbind(window, 'resize', globalEventDelegate);
|
31306 | DOM.unbind(window, 'scroll', globalEventDelegate);
|
31307 | }
|
31308 | boundGlobalEvents = state;
|
31309 | }
|
31310 | };
|
31311 | const removeEditorFromList = targetEditor => {
|
31312 | const oldEditors = editors;
|
31313 | editors = filter$5(editors, editor => {
|
31314 | return targetEditor !== editor;
|
31315 | });
|
31316 | if (EditorManager.activeEditor === targetEditor) {
|
31317 | EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
|
31318 | }
|
31319 | if (EditorManager.focusedEditor === targetEditor) {
|
31320 | EditorManager.focusedEditor = null;
|
31321 | }
|
31322 | return oldEditors.length !== editors.length;
|
31323 | };
|
31324 | const purgeDestroyedEditor = editor => {
|
31325 | if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
|
31326 | removeEditorFromList(editor);
|
31327 | editor.unbindAllNativeEvents();
|
31328 | editor.destroy(true);
|
31329 | editor.removed = true;
|
31330 | }
|
31331 | };
|
31332 | const isQuirksMode = document.compatMode !== 'CSS1Compat';
|
31333 | const EditorManager = {
|
31334 | ...Observable,
|
31335 | baseURI: null,
|
31336 | baseURL: null,
|
31337 | defaultOptions: {},
|
31338 | documentBaseURL: null,
|
31339 | suffix: null,
|
31340 | majorVersion: '7',
|
31341 | minorVersion: '1.1',
|
31342 | releaseDate: '2024-05-22',
|
31343 | i18n: I18n,
|
31344 | activeEditor: null,
|
31345 | focusedEditor: null,
|
31346 | setup() {
|
31347 | const self = this;
|
31348 | let baseURL = '';
|
31349 | let suffix = '';
|
31350 | let documentBaseURL = URI.getDocumentBaseUrl(document.location);
|
31351 | if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
|
31352 | documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
31353 | if (!/[\/\\]$/.test(documentBaseURL)) {
|
31354 | documentBaseURL += '/';
|
31355 | }
|
31356 | }
|
31357 | const preInit = window.tinymce || window.tinyMCEPreInit;
|
31358 | if (preInit) {
|
31359 | baseURL = preInit.base || preInit.baseURL;
|
31360 | suffix = preInit.suffix;
|
31361 | } else {
|
31362 | const scripts = document.getElementsByTagName('script');
|
31363 | for (let i = 0; i < scripts.length; i++) {
|
31364 | const src = scripts[i].src || '';
|
31365 | if (src === '') {
|
31366 | continue;
|
31367 | }
|
31368 | const srcScript = src.substring(src.lastIndexOf('/'));
|
31369 | if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
|
31370 | if (srcScript.indexOf('.min') !== -1) {
|
31371 | suffix = '.min';
|
31372 | }
|
31373 | baseURL = src.substring(0, src.lastIndexOf('/'));
|
31374 | break;
|
31375 | }
|
31376 | }
|
31377 | if (!baseURL && document.currentScript) {
|
31378 | const src = document.currentScript.src;
|
31379 | if (src.indexOf('.min') !== -1) {
|
31380 | suffix = '.min';
|
31381 | }
|
31382 | baseURL = src.substring(0, src.lastIndexOf('/'));
|
31383 | }
|
31384 | }
|
31385 | self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
|
31386 | self.documentBaseURL = documentBaseURL;
|
31387 | self.baseURI = new URI(self.baseURL);
|
31388 | self.suffix = suffix;
|
31389 | setup$w(self);
|
31390 | },
|
31391 | overrideDefaults(defaultOptions) {
|
31392 | const baseUrl = defaultOptions.base_url;
|
31393 | if (baseUrl) {
|
31394 | this._setBaseUrl(baseUrl);
|
31395 | }
|
31396 | const suffix = defaultOptions.suffix;
|
31397 | if (suffix) {
|
31398 | this.suffix = suffix;
|
31399 | }
|
31400 | this.defaultOptions = defaultOptions;
|
31401 | const pluginBaseUrls = defaultOptions.plugin_base_urls;
|
31402 | if (pluginBaseUrls !== undefined) {
|
31403 | each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
|
31404 | AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
|
31405 | });
|
31406 | }
|
31407 | },
|
31408 | init(options) {
|
31409 | const self = this;
|
31410 | let result;
|
31411 | const invalidInlineTargets = Tools.makeMap('area base basefont br col frame hr img input isindex link meta param embed source wbr track ' + 'colgroup option table tbody tfoot thead tr th td script noscript style textarea video audio iframe object menu', ' ');
|
31412 | const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
|
31413 | const createId = elm => {
|
31414 | let id = elm.id;
|
31415 | if (!id) {
|
31416 | id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId);
|
31417 | elm.setAttribute('id', id);
|
31418 | }
|
31419 | return id;
|
31420 | };
|
31421 | const execCallback = name => {
|
31422 | const callback = options[name];
|
31423 | if (!callback) {
|
31424 | return;
|
31425 | }
|
31426 | return callback.apply(self, []);
|
31427 | };
|
31428 | const findTargets = options => {
|
31429 | if (Env.browser.isIE() || Env.browser.isEdge()) {
|
31430 | initError('TinyMCE does not support the browser you are using. For a list of supported' + ' browsers please see: https://www.tiny.cloud/docs/tinymce/7/support/#supportedwebbrowsers');
|
31431 | return [];
|
31432 | } else if (isQuirksMode) {
|
31433 | initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
|
31434 | return [];
|
31435 | } else if (isString(options.selector)) {
|
31436 | return DOM.select(options.selector);
|
31437 | } else if (isNonNullable(options.target)) {
|
31438 | return [options.target];
|
31439 | } else {
|
31440 | return [];
|
31441 | }
|
31442 | };
|
31443 | let provideResults = editors => {
|
31444 | result = editors;
|
31445 | };
|
31446 | const initEditors = () => {
|
31447 | let initCount = 0;
|
31448 | const editors = [];
|
31449 | let targets;
|
31450 | const createEditor = (id, options, targetElm) => {
|
31451 | const editor = new Editor(id, options, self);
|
31452 | editors.push(editor);
|
31453 | editor.on('init', () => {
|
31454 | if (++initCount === targets.length) {
|
31455 | provideResults(editors);
|
31456 | }
|
31457 | });
|
31458 | editor.targetElm = editor.targetElm || targetElm;
|
31459 | editor.render();
|
31460 | };
|
31461 | DOM.unbind(window, 'ready', initEditors);
|
31462 | execCallback('onpageload');
|
31463 | targets = unique$1(findTargets(options));
|
31464 | Tools.each(targets, elm => {
|
31465 | purgeDestroyedEditor(self.get(elm.id));
|
31466 | });
|
31467 | targets = Tools.grep(targets, elm => {
|
31468 | return !self.get(elm.id);
|
31469 | });
|
31470 | if (targets.length === 0) {
|
31471 | provideResults([]);
|
31472 | } else {
|
31473 | each(targets, elm => {
|
31474 | if (isInvalidInlineTarget(options, elm)) {
|
31475 | initError('Could not initialize inline editor on invalid inline target element', elm);
|
31476 | } else {
|
31477 | createEditor(createId(elm), options, elm);
|
31478 | }
|
31479 | });
|
31480 | }
|
31481 | };
|
31482 | DOM.bind(window, 'ready', initEditors);
|
31483 | return new Promise(resolve => {
|
31484 | if (result) {
|
31485 | resolve(result);
|
31486 | } else {
|
31487 | provideResults = editors => {
|
31488 | resolve(editors);
|
31489 | };
|
31490 | }
|
31491 | });
|
31492 | },
|
31493 | get(id) {
|
31494 | if (arguments.length === 0) {
|
31495 | return editors.slice(0);
|
31496 | } else if (isString(id)) {
|
31497 | return find$2(editors, editor => {
|
31498 | return editor.id === id;
|
31499 | }).getOr(null);
|
31500 | } else if (isNumber(id)) {
|
31501 | return editors[id] ? editors[id] : null;
|
31502 | } else {
|
31503 | return null;
|
31504 | }
|
31505 | },
|
31506 | add(editor) {
|
31507 | const self = this;
|
31508 | const existingEditor = self.get(editor.id);
|
31509 | if (existingEditor === editor) {
|
31510 | return editor;
|
31511 | }
|
31512 | if (existingEditor === null) {
|
31513 | editors.push(editor);
|
31514 | }
|
31515 | toggleGlobalEvents(true);
|
31516 | self.activeEditor = editor;
|
31517 | self.dispatch('AddEditor', { editor });
|
31518 | if (!beforeUnloadDelegate) {
|
31519 | beforeUnloadDelegate = e => {
|
31520 | const event = self.dispatch('BeforeUnload');
|
31521 | if (event.returnValue) {
|
31522 | e.preventDefault();
|
31523 | e.returnValue = event.returnValue;
|
31524 | return event.returnValue;
|
31525 | }
|
31526 | };
|
31527 | window.addEventListener('beforeunload', beforeUnloadDelegate);
|
31528 | }
|
31529 | return editor;
|
31530 | },
|
31531 | createEditor(id, options) {
|
31532 | return this.add(new Editor(id, options, this));
|
31533 | },
|
31534 | remove(selector) {
|
31535 | const self = this;
|
31536 | let editor;
|
31537 | if (!selector) {
|
31538 | for (let i = editors.length - 1; i >= 0; i--) {
|
31539 | self.remove(editors[i]);
|
31540 | }
|
31541 | return;
|
31542 | }
|
31543 | if (isString(selector)) {
|
31544 | each(DOM.select(selector), elm => {
|
31545 | editor = self.get(elm.id);
|
31546 | if (editor) {
|
31547 | self.remove(editor);
|
31548 | }
|
31549 | });
|
31550 | return;
|
31551 | }
|
31552 | editor = selector;
|
31553 | if (isNull(self.get(editor.id))) {
|
31554 | return null;
|
31555 | }
|
31556 | if (removeEditorFromList(editor)) {
|
31557 | self.dispatch('RemoveEditor', { editor });
|
31558 | }
|
31559 | if (editors.length === 0) {
|
31560 | window.removeEventListener('beforeunload', beforeUnloadDelegate);
|
31561 | }
|
31562 | editor.remove();
|
31563 | toggleGlobalEvents(editors.length > 0);
|
31564 | return editor;
|
31565 | },
|
31566 | execCommand(cmd, ui, value) {
|
31567 | var _a;
|
31568 | const self = this;
|
31569 | const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value;
|
31570 | switch (cmd) {
|
31571 | case 'mceAddEditor': {
|
31572 | if (!self.get(editorId)) {
|
31573 | const editorOptions = value.options;
|
31574 | new Editor(editorId, editorOptions, self).render();
|
31575 | }
|
31576 | return true;
|
31577 | }
|
31578 | case 'mceRemoveEditor': {
|
31579 | const editor = self.get(editorId);
|
31580 | if (editor) {
|
31581 | editor.remove();
|
31582 | }
|
31583 | return true;
|
31584 | }
|
31585 | case 'mceToggleEditor': {
|
31586 | const editor = self.get(editorId);
|
31587 | if (!editor) {
|
31588 | self.execCommand('mceAddEditor', false, value);
|
31589 | return true;
|
31590 | }
|
31591 | if (editor.isHidden()) {
|
31592 | editor.show();
|
31593 | } else {
|
31594 | editor.hide();
|
31595 | }
|
31596 | return true;
|
31597 | }
|
31598 | }
|
31599 | if (self.activeEditor) {
|
31600 | return self.activeEditor.execCommand(cmd, ui, value);
|
31601 | }
|
31602 | return false;
|
31603 | },
|
31604 | triggerSave: () => {
|
31605 | each(editors, editor => {
|
31606 | editor.save();
|
31607 | });
|
31608 | },
|
31609 | addI18n: (code, items) => {
|
31610 | I18n.add(code, items);
|
31611 | },
|
31612 | translate: text => {
|
31613 | return I18n.translate(text);
|
31614 | },
|
31615 | setActive(editor) {
|
31616 | const activeEditor = this.activeEditor;
|
31617 | if (this.activeEditor !== editor) {
|
31618 | if (activeEditor) {
|
31619 | activeEditor.dispatch('deactivate', { relatedTarget: editor });
|
31620 | }
|
31621 | editor.dispatch('activate', { relatedTarget: activeEditor });
|
31622 | }
|
31623 | this.activeEditor = editor;
|
31624 | },
|
31625 | _setBaseUrl(baseUrl) {
|
31626 | this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
|
31627 | this.baseURI = new URI(this.baseURL);
|
31628 | }
|
31629 | };
|
31630 | EditorManager.setup();
|
31631 |
|
31632 | const setup = () => {
|
31633 | const dataValue = value$2();
|
31634 | const FakeClipboardItem = items => ({
|
31635 | items,
|
31636 | types: keys(items),
|
31637 | getType: type => get$a(items, type).getOrUndefined()
|
31638 | });
|
31639 | const write = data => {
|
31640 | dataValue.set(data);
|
31641 | };
|
31642 | const read = () => dataValue.get().getOrUndefined();
|
31643 | const clear = dataValue.clear;
|
31644 | return {
|
31645 | FakeClipboardItem,
|
31646 | write,
|
31647 | read,
|
31648 | clear
|
31649 | };
|
31650 | };
|
31651 | const FakeClipboard = setup();
|
31652 |
|
31653 | const min = Math.min, max = Math.max, round = Math.round;
|
31654 | const relativePosition = (rect, targetRect, rel) => {
|
31655 | let x = targetRect.x;
|
31656 | let y = targetRect.y;
|
31657 | const w = rect.w;
|
31658 | const h = rect.h;
|
31659 | const targetW = targetRect.w;
|
31660 | const targetH = targetRect.h;
|
31661 | const relChars = (rel || '').split('');
|
31662 | if (relChars[0] === 'b') {
|
31663 | y += targetH;
|
31664 | }
|
31665 | if (relChars[1] === 'r') {
|
31666 | x += targetW;
|
31667 | }
|
31668 | if (relChars[0] === 'c') {
|
31669 | y += round(targetH / 2);
|
31670 | }
|
31671 | if (relChars[1] === 'c') {
|
31672 | x += round(targetW / 2);
|
31673 | }
|
31674 | if (relChars[3] === 'b') {
|
31675 | y -= h;
|
31676 | }
|
31677 | if (relChars[4] === 'r') {
|
31678 | x -= w;
|
31679 | }
|
31680 | if (relChars[3] === 'c') {
|
31681 | y -= round(h / 2);
|
31682 | }
|
31683 | if (relChars[4] === 'c') {
|
31684 | x -= round(w / 2);
|
31685 | }
|
31686 | return create$2(x, y, w, h);
|
31687 | };
|
31688 | const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
|
31689 | for (let i = 0; i < rels.length; i++) {
|
31690 | const pos = relativePosition(rect, targetRect, rels[i]);
|
31691 | if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x && pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) {
|
31692 | return rels[i];
|
31693 | }
|
31694 | }
|
31695 | return null;
|
31696 | };
|
31697 | const inflate = (rect, w, h) => {
|
31698 | return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
|
31699 | };
|
31700 | const intersect = (rect, cropRect) => {
|
31701 | const x1 = max(rect.x, cropRect.x);
|
31702 | const y1 = max(rect.y, cropRect.y);
|
31703 | const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
|
31704 | const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
|
31705 | if (x2 - x1 < 0 || y2 - y1 < 0) {
|
31706 | return null;
|
31707 | }
|
31708 | return create$2(x1, y1, x2 - x1, y2 - y1);
|
31709 | };
|
31710 | const clamp = (rect, clampRect, fixedSize) => {
|
31711 | let x1 = rect.x;
|
31712 | let y1 = rect.y;
|
31713 | let x2 = rect.x + rect.w;
|
31714 | let y2 = rect.y + rect.h;
|
31715 | const cx2 = clampRect.x + clampRect.w;
|
31716 | const cy2 = clampRect.y + clampRect.h;
|
31717 | const underflowX1 = max(0, clampRect.x - x1);
|
31718 | const underflowY1 = max(0, clampRect.y - y1);
|
31719 | const overflowX2 = max(0, x2 - cx2);
|
31720 | const overflowY2 = max(0, y2 - cy2);
|
31721 | x1 += underflowX1;
|
31722 | y1 += underflowY1;
|
31723 | if (fixedSize) {
|
31724 | x2 += underflowX1;
|
31725 | y2 += underflowY1;
|
31726 | x1 -= overflowX2;
|
31727 | y1 -= overflowY2;
|
31728 | }
|
31729 | x2 -= overflowX2;
|
31730 | y2 -= overflowY2;
|
31731 | return create$2(x1, y1, x2 - x1, y2 - y1);
|
31732 | };
|
31733 | const create$2 = (x, y, w, h) => {
|
31734 | return {
|
31735 | x,
|
31736 | y,
|
31737 | w,
|
31738 | h
|
31739 | };
|
31740 | };
|
31741 | const fromClientRect = clientRect => {
|
31742 | return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
|
31743 | };
|
31744 | const Rect = {
|
31745 | inflate,
|
31746 | relativePosition,
|
31747 | findBestRelativePosition,
|
31748 | intersect,
|
31749 | clamp,
|
31750 | create: create$2,
|
31751 | fromClientRect
|
31752 | };
|
31753 |
|
31754 | const awaiter = (resolveCb, rejectCb, timeout = 1000) => {
|
31755 | let done = false;
|
31756 | let timer = null;
|
31757 | const complete = completer => (...args) => {
|
31758 | if (!done) {
|
31759 | done = true;
|
31760 | if (timer !== null) {
|
31761 | clearTimeout(timer);
|
31762 | timer = null;
|
31763 | }
|
31764 | completer.apply(null, args);
|
31765 | }
|
31766 | };
|
31767 | const resolve = complete(resolveCb);
|
31768 | const reject = complete(rejectCb);
|
31769 | const start = (...args) => {
|
31770 | if (!done && timer === null) {
|
31771 | timer = setTimeout(() => reject.apply(null, args), timeout);
|
31772 | }
|
31773 | };
|
31774 | return {
|
31775 | start,
|
31776 | resolve,
|
31777 | reject
|
31778 | };
|
31779 | };
|
31780 | const create$1 = () => {
|
31781 | const tasks = {};
|
31782 | const resultFns = {};
|
31783 | const resources = {};
|
31784 | const load = (id, url) => {
|
31785 | const loadErrMsg = `Script at URL "${ url }" failed to load`;
|
31786 | const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`;
|
31787 | if (tasks[id] !== undefined) {
|
31788 | return tasks[id];
|
31789 | } else {
|
31790 | const task = new Promise((resolve, reject) => {
|
31791 | const waiter = awaiter(resolve, reject);
|
31792 | resultFns[id] = waiter.resolve;
|
31793 | ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
|
31794 | });
|
31795 | tasks[id] = task;
|
31796 | return task;
|
31797 | }
|
31798 | };
|
31799 | const add = (id, data) => {
|
31800 | if (resultFns[id] !== undefined) {
|
31801 | resultFns[id](data);
|
31802 | delete resultFns[id];
|
31803 | }
|
31804 | tasks[id] = Promise.resolve(data);
|
31805 | resources[id] = data;
|
31806 | };
|
31807 | const has = id => {
|
31808 | return id in resources;
|
31809 | };
|
31810 | const unload = id => {
|
31811 | delete tasks[id];
|
31812 | delete resources[id];
|
31813 | };
|
31814 | const get = id => resources[id];
|
31815 | return {
|
31816 | load,
|
31817 | add,
|
31818 | has,
|
31819 | get,
|
31820 | unload
|
31821 | };
|
31822 | };
|
31823 | const Resource = create$1();
|
31824 |
|
31825 | const create = () => (() => {
|
31826 | let data = {};
|
31827 | let keys = [];
|
31828 | const storage = {
|
31829 | getItem: key => {
|
31830 | const item = data[key];
|
31831 | return item ? item : null;
|
31832 | },
|
31833 | setItem: (key, value) => {
|
31834 | keys.push(key);
|
31835 | data[key] = String(value);
|
31836 | },
|
31837 | key: index => {
|
31838 | return keys[index];
|
31839 | },
|
31840 | removeItem: key => {
|
31841 | keys = keys.filter(k => k === key);
|
31842 | delete data[key];
|
31843 | },
|
31844 | clear: () => {
|
31845 | keys = [];
|
31846 | data = {};
|
31847 | },
|
31848 | length: 0
|
31849 | };
|
31850 | Object.defineProperty(storage, 'length', {
|
31851 | get: () => keys.length,
|
31852 | configurable: false,
|
31853 | enumerable: false
|
31854 | });
|
31855 | return storage;
|
31856 | })();
|
31857 |
|
31858 | let localStorage;
|
31859 | try {
|
31860 | const test = '__storage_test__';
|
31861 | localStorage = window.localStorage;
|
31862 | localStorage.setItem(test, test);
|
31863 | localStorage.removeItem(test);
|
31864 | } catch (e) {
|
31865 | localStorage = create();
|
31866 | }
|
31867 | var LocalStorage = localStorage;
|
31868 |
|
31869 | const publicApi = {
|
31870 | geom: { Rect },
|
31871 | util: {
|
31872 | Delay,
|
31873 | Tools,
|
31874 | VK,
|
31875 | URI,
|
31876 | EventDispatcher,
|
31877 | Observable,
|
31878 | I18n,
|
31879 | LocalStorage,
|
31880 | ImageUploader
|
31881 | },
|
31882 | dom: {
|
31883 | EventUtils,
|
31884 | TreeWalker: DomTreeWalker,
|
31885 | TextSeeker,
|
31886 | DOMUtils,
|
31887 | ScriptLoader,
|
31888 | RangeUtils,
|
31889 | Serializer: DomSerializer,
|
31890 | StyleSheetLoader,
|
31891 | ControlSelection,
|
31892 | BookmarkManager,
|
31893 | Selection: EditorSelection,
|
31894 | Event: EventUtils.Event
|
31895 | },
|
31896 | html: {
|
31897 | Styles,
|
31898 | Entities,
|
31899 | Node: AstNode,
|
31900 | Schema,
|
31901 | DomParser,
|
31902 | Writer,
|
31903 | Serializer: HtmlSerializer
|
31904 | },
|
31905 | Env,
|
31906 | AddOnManager,
|
31907 | Annotator,
|
31908 | Formatter,
|
31909 | UndoManager,
|
31910 | EditorCommands,
|
31911 | WindowManager,
|
31912 | NotificationManager,
|
31913 | EditorObservable,
|
31914 | Shortcuts,
|
31915 | Editor,
|
31916 | FocusManager,
|
31917 | EditorManager,
|
31918 | DOM: DOMUtils.DOM,
|
31919 | ScriptLoader: ScriptLoader.ScriptLoader,
|
31920 | PluginManager,
|
31921 | ThemeManager,
|
31922 | ModelManager,
|
31923 | IconManager,
|
31924 | Resource,
|
31925 | FakeClipboard,
|
31926 | trim: Tools.trim,
|
31927 | isArray: Tools.isArray,
|
31928 | is: Tools.is,
|
31929 | toArray: Tools.toArray,
|
31930 | makeMap: Tools.makeMap,
|
31931 | each: Tools.each,
|
31932 | map: Tools.map,
|
31933 | grep: Tools.grep,
|
31934 | inArray: Tools.inArray,
|
31935 | extend: Tools.extend,
|
31936 | walk: Tools.walk,
|
31937 | resolve: Tools.resolve,
|
31938 | explode: Tools.explode,
|
31939 | _addCacheSuffix: Tools._addCacheSuffix
|
31940 | };
|
31941 | const tinymce$1 = Tools.extend(EditorManager, publicApi);
|
31942 |
|
31943 | const exportToModuleLoaders = tinymce => {
|
31944 | if (typeof module === 'object') {
|
31945 | try {
|
31946 | module.exports = tinymce;
|
31947 | } catch (_) {
|
31948 | }
|
31949 | }
|
31950 | };
|
31951 | const exportToWindowGlobal = tinymce => {
|
31952 | window.tinymce = tinymce;
|
31953 | window.tinyMCE = tinymce;
|
31954 | };
|
31955 | exportToWindowGlobal(tinymce$1);
|
31956 | exportToModuleLoaders(tinymce$1);
|
31957 |
|
31958 | })();
|