| 1 |
efrain |
1 |
/**
|
| 1441 |
ariadna |
2 |
* TinyMCE version 7.7.1 (2025-03-05)
|
| 1 |
efrain |
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);
|
| 1441 |
ariadna |
427 |
const last$2 = xs => get$b(xs, xs.length - 1);
|
| 1 |
efrain |
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 |
};
|
| 1441 |
ariadna |
597 |
const last$1 = collection => collection[collection.length - 1];
|
| 1 |
efrain |
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 |
};
|
| 1441 |
ariadna |
655 |
const detect$4 = (versionRegexes, agent) => {
|
| 1 |
efrain |
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,
|
| 1441 |
ariadna |
673 |
detect: detect$4,
|
| 1 |
efrain |
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 |
|
| 1441 |
ariadna |
690 |
const detect$3 = (candidates, userAgent) => {
|
| 1 |
efrain |
691 |
const agent = String(userAgent).toLowerCase();
|
|
|
692 |
return find$2(candidates, candidate => {
|
|
|
693 |
return candidate.search(agent);
|
|
|
694 |
});
|
|
|
695 |
};
|
|
|
696 |
const detectBrowser = (browsers, userAgent) => {
|
| 1441 |
ariadna |
697 |
return detect$3(browsers, userAgent).map(browser => {
|
| 1 |
efrain |
698 |
const version = Version.detect(browser.versionRegexes, userAgent);
|
|
|
699 |
return {
|
|
|
700 |
current: browser.name,
|
|
|
701 |
version
|
|
|
702 |
};
|
|
|
703 |
});
|
|
|
704 |
};
|
|
|
705 |
const detectOs = (oses, userAgent) => {
|
| 1441 |
ariadna |
706 |
return detect$3(oses, userAgent).map(os => {
|
| 1 |
efrain |
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 |
|
| 1441 |
ariadna |
943 |
const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => {
|
| 1 |
efrain |
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 |
};
|
| 1441 |
ariadna |
955 |
const PlatformDetection = { detect: detect$2 };
|
| 1 |
efrain |
956 |
|
|
|
957 |
const mediaMatch = query => window.matchMedia(query).matches;
|
| 1441 |
ariadna |
958 |
let platform$4 = cached(() => PlatformDetection.detect(window.navigator.userAgent, Optional.from(window.navigator.userAgentData), mediaMatch));
|
|
|
959 |
const detect$1 = () => platform$4();
|
| 1 |
efrain |
960 |
|
| 1441 |
ariadna |
961 |
const userAgent = window.navigator.userAgent;
|
|
|
962 |
const platform$3 = detect$1();
|
| 1 |
efrain |
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);
|
| 1441 |
ariadna |
1168 |
const isText$c = isType(TEXT);
|
| 1 |
efrain |
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 |
};
|
| 1441 |
ariadna |
1181 |
const set$4 = (element, key, value) => {
|
| 1 |
efrain |
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 |
};
|
| 1441 |
ariadna |
1199 |
const remove$9 = (element, key) => {
|
| 1 |
efrain |
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]);
|
| 1441 |
ariadna |
1218 |
set$4(element, attr, nu.join(' '));
|
| 1 |
efrain |
1219 |
return true;
|
|
|
1220 |
};
|
| 1441 |
ariadna |
1221 |
const remove$8 = (element, attr, id) => {
|
| 1 |
efrain |
1222 |
const nu = filter$5(read$4(element, attr), v => v !== id);
|
|
|
1223 |
if (nu.length > 0) {
|
| 1441 |
ariadna |
1224 |
set$4(element, attr, nu.join(' '));
|
| 1 |
efrain |
1225 |
} else {
|
| 1441 |
ariadna |
1226 |
remove$9(element, attr);
|
| 1 |
efrain |
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);
|
| 1441 |
ariadna |
1234 |
const remove$7 = (element, clazz) => remove$8(element, 'class', clazz);
|
| 1 |
efrain |
1235 |
const toggle$2 = (element, clazz) => {
|
|
|
1236 |
if (contains$2(get$8(element), clazz)) {
|
| 1441 |
ariadna |
1237 |
return remove$7(element, clazz);
|
| 1 |
efrain |
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) {
|
| 1441 |
ariadna |
1253 |
remove$9(element, 'class');
|
| 1 |
efrain |
1254 |
}
|
|
|
1255 |
};
|
| 1441 |
ariadna |
1256 |
const remove$6 = (element, clazz) => {
|
| 1 |
efrain |
1257 |
if (supports(element)) {
|
|
|
1258 |
const classList = element.dom.classList;
|
|
|
1259 |
classList.remove(clazz);
|
|
|
1260 |
} else {
|
| 1441 |
ariadna |
1261 |
remove$7(element, clazz);
|
| 1 |
efrain |
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 |
|
|
|
1396 |
const getHead = doc => {
|
|
|
1397 |
const b = doc.dom.head;
|
|
|
1398 |
if (b === null || b === undefined) {
|
|
|
1399 |
throw new Error('Head is not available yet');
|
|
|
1400 |
}
|
|
|
1401 |
return SugarElement.fromDom(b);
|
|
|
1402 |
};
|
|
|
1403 |
|
|
|
1404 |
const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
|
| 1441 |
ariadna |
1405 |
const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode());
|
| 1 |
efrain |
1406 |
const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
|
|
|
1407 |
const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
|
|
|
1408 |
const getShadowRoot = e => {
|
|
|
1409 |
const r = getRootNode(e);
|
|
|
1410 |
return isShadowRoot(r) ? Optional.some(r) : Optional.none();
|
|
|
1411 |
};
|
|
|
1412 |
const getShadowHost = e => SugarElement.fromDom(e.dom.host);
|
|
|
1413 |
const getOriginalEventTarget = event => {
|
| 1441 |
ariadna |
1414 |
if (isNonNullable(event.target)) {
|
| 1 |
efrain |
1415 |
const el = SugarElement.fromDom(event.target);
|
|
|
1416 |
if (isElement$7(el) && isOpenShadowHost(el)) {
|
|
|
1417 |
if (event.composed && event.composedPath) {
|
|
|
1418 |
const composedPath = event.composedPath();
|
|
|
1419 |
if (composedPath) {
|
|
|
1420 |
return head(composedPath);
|
|
|
1421 |
}
|
|
|
1422 |
}
|
|
|
1423 |
}
|
|
|
1424 |
}
|
|
|
1425 |
return Optional.from(event.target);
|
|
|
1426 |
};
|
|
|
1427 |
const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
|
|
|
1428 |
|
|
|
1429 |
const inBody = element => {
|
| 1441 |
ariadna |
1430 |
const dom = isText$c(element) ? element.dom.parentNode : element.dom;
|
| 1 |
efrain |
1431 |
if (dom === undefined || dom === null || dom.ownerDocument === null) {
|
|
|
1432 |
return false;
|
|
|
1433 |
}
|
|
|
1434 |
const doc = dom.ownerDocument;
|
|
|
1435 |
return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
|
|
|
1436 |
};
|
|
|
1437 |
|
|
|
1438 |
var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
|
|
|
1439 |
if (is(scope, a)) {
|
|
|
1440 |
return Optional.some(scope);
|
|
|
1441 |
} else if (isFunction(isRoot) && isRoot(scope)) {
|
|
|
1442 |
return Optional.none();
|
|
|
1443 |
} else {
|
|
|
1444 |
return ancestor(scope, a, isRoot);
|
|
|
1445 |
}
|
|
|
1446 |
};
|
|
|
1447 |
|
|
|
1448 |
const ancestor$4 = (scope, predicate, isRoot) => {
|
|
|
1449 |
let element = scope.dom;
|
|
|
1450 |
const stop = isFunction(isRoot) ? isRoot : never;
|
|
|
1451 |
while (element.parentNode) {
|
|
|
1452 |
element = element.parentNode;
|
|
|
1453 |
const el = SugarElement.fromDom(element);
|
|
|
1454 |
if (predicate(el)) {
|
|
|
1455 |
return Optional.some(el);
|
|
|
1456 |
} else if (stop(el)) {
|
|
|
1457 |
break;
|
|
|
1458 |
}
|
|
|
1459 |
}
|
|
|
1460 |
return Optional.none();
|
|
|
1461 |
};
|
|
|
1462 |
const closest$4 = (scope, predicate, isRoot) => {
|
|
|
1463 |
const is = (s, test) => test(s);
|
|
|
1464 |
return ClosestOrAncestor(is, ancestor$4, scope, predicate, isRoot);
|
|
|
1465 |
};
|
|
|
1466 |
const sibling$1 = (scope, predicate) => {
|
|
|
1467 |
const element = scope.dom;
|
|
|
1468 |
if (!element.parentNode) {
|
|
|
1469 |
return Optional.none();
|
|
|
1470 |
}
|
|
|
1471 |
return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
|
|
|
1472 |
};
|
|
|
1473 |
const child = (scope, predicate) => {
|
|
|
1474 |
const pred = node => predicate(SugarElement.fromDom(node));
|
|
|
1475 |
const result = find$2(scope.dom.childNodes, pred);
|
|
|
1476 |
return result.map(SugarElement.fromDom);
|
|
|
1477 |
};
|
|
|
1478 |
const descendant$2 = (scope, predicate) => {
|
|
|
1479 |
const descend = node => {
|
|
|
1480 |
for (let i = 0; i < node.childNodes.length; i++) {
|
|
|
1481 |
const child = SugarElement.fromDom(node.childNodes[i]);
|
|
|
1482 |
if (predicate(child)) {
|
|
|
1483 |
return Optional.some(child);
|
|
|
1484 |
}
|
|
|
1485 |
const res = descend(node.childNodes[i]);
|
|
|
1486 |
if (res.isSome()) {
|
|
|
1487 |
return res;
|
|
|
1488 |
}
|
|
|
1489 |
}
|
|
|
1490 |
return Optional.none();
|
|
|
1491 |
};
|
|
|
1492 |
return descend(scope.dom);
|
|
|
1493 |
};
|
|
|
1494 |
|
|
|
1495 |
const ancestor$3 = (scope, selector, isRoot) => ancestor$4(scope, e => is$1(e, selector), isRoot);
|
|
|
1496 |
const descendant$1 = (scope, selector) => one(selector, scope);
|
|
|
1497 |
const closest$3 = (scope, selector, isRoot) => {
|
|
|
1498 |
const is = (element, selector) => is$1(element, selector);
|
|
|
1499 |
return ClosestOrAncestor(is, ancestor$3, scope, selector, isRoot);
|
|
|
1500 |
};
|
|
|
1501 |
|
|
|
1502 |
const closest$2 = target => closest$3(target, '[contenteditable]');
|
|
|
1503 |
const isEditable$2 = (element, assumeEditable = false) => {
|
|
|
1504 |
if (inBody(element)) {
|
|
|
1505 |
return element.dom.isContentEditable;
|
|
|
1506 |
} else {
|
|
|
1507 |
return closest$2(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
|
|
|
1508 |
}
|
|
|
1509 |
};
|
|
|
1510 |
const getRaw$1 = element => element.dom.contentEditable;
|
| 1441 |
ariadna |
1511 |
const set$3 = (element, editable) => {
|
|
|
1512 |
element.dom.contentEditable = editable ? 'true' : 'false';
|
|
|
1513 |
};
|
| 1 |
efrain |
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 |
};
|
| 1441 |
ariadna |
1564 |
const remove$5 = (element, property) => {
|
| 1 |
efrain |
1565 |
const dom = element.dom;
|
|
|
1566 |
internalRemove(dom, property);
|
|
|
1567 |
if (is$2(getOpt(element, 'style').map(trim$4), '')) {
|
| 1441 |
ariadna |
1568 |
remove$9(element, 'style');
|
| 1 |
efrain |
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 => {
|
| 1441 |
ariadna |
1621 |
remove$4(rogue);
|
| 1 |
efrain |
1622 |
});
|
|
|
1623 |
};
|
| 1441 |
ariadna |
1624 |
const remove$4 = element => {
|
| 1 |
efrain |
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 |
}
|
| 1441 |
ariadna |
1635 |
remove$4(wrapper);
|
| 1 |
efrain |
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) => {
|
| 1441 |
ariadna |
1756 |
const isSafari = detect$1().browser.isSafari();
|
| 1 |
efrain |
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;
|
| 1441 |
ariadna |
1766 |
if (detect$1().browser.isFirefox()) {
|
| 1 |
efrain |
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 |
|
| 1441 |
ariadna |
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();
|
| 1 |
efrain |
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 |
|
| 1441 |
ariadna |
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 |
|
| 1 |
efrain |
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 |
};
|
| 1441 |
ariadna |
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';
|
| 1 |
efrain |
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 |
]);
|
| 1441 |
ariadna |
1992 |
const isText$b = isNodeType(3);
|
| 1 |
efrain |
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');
|
| 1441 |
ariadna |
2002 |
const isEditingHost = node => isHTMLElement(node) && node.isContentEditable && isNonNullable(node.parentElement) && !node.parentElement.isContentEditable;
|
| 1 |
efrain |
2003 |
const isTableCell$3 = matchNodeNames([
|
|
|
2004 |
'td',
|
|
|
2005 |
'th'
|
|
|
2006 |
]);
|
|
|
2007 |
const isTableCellOrCaption = matchNodeNames([
|
|
|
2008 |
'td',
|
|
|
2009 |
'th',
|
|
|
2010 |
'caption'
|
|
|
2011 |
]);
|
|
|
2012 |
const isMedia$2 = matchNodeNames([
|
|
|
2013 |
'video',
|
|
|
2014 |
'audio',
|
|
|
2015 |
'object',
|
|
|
2016 |
'embed'
|
|
|
2017 |
]);
|
|
|
2018 |
const isListItem$2 = matchNodeName('li');
|
|
|
2019 |
const isDetails = matchNodeName('details');
|
|
|
2020 |
const isSummary$1 = matchNodeName('summary');
|
|
|
2021 |
|
| 1441 |
ariadna |
2022 |
const defaultOptionValues = {
|
|
|
2023 |
skipBogus: true,
|
|
|
2024 |
includeZwsp: false,
|
|
|
2025 |
checkRootAsContent: false
|
| 1 |
efrain |
2026 |
};
|
| 1441 |
ariadna |
2027 |
const hasWhitespacePreserveParent = (node, rootNode, schema) => {
|
|
|
2028 |
const rootElement = SugarElement.fromDom(rootNode);
|
|
|
2029 |
const startNode = SugarElement.fromDom(node);
|
|
|
2030 |
const whitespaceElements = schema.getWhitespaceElements();
|
|
|
2031 |
const predicate = node => has$2(whitespaceElements, name(node));
|
|
|
2032 |
return ancestor$2(startNode, predicate, curry(eq, rootElement));
|
| 1 |
efrain |
2033 |
};
|
| 1441 |
ariadna |
2034 |
const isNamedAnchor = node => {
|
|
|
2035 |
return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id'));
|
| 1 |
efrain |
2036 |
};
|
| 1441 |
ariadna |
2037 |
const isNonEmptyElement$1 = (node, schema) => {
|
|
|
2038 |
return isElement$6(node) && has$2(schema.getNonEmptyElements(), node.nodeName);
|
| 1 |
efrain |
2039 |
};
|
| 1441 |
ariadna |
2040 |
const isBookmark = hasAttribute('data-mce-bookmark');
|
|
|
2041 |
const hasNonEditableParent = node => parentElement(SugarElement.fromDom(node)).exists(parent => !isEditable$2(parent));
|
|
|
2042 |
const isWhitespace$1 = (node, rootNode, schema) => isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode, schema);
|
|
|
2043 |
const isText$a = (node, rootNode, schema, options) => isText$b(node) && !isWhitespace$1(node, rootNode, schema) && (!options.includeZwsp || !isZwsp$1(node.data));
|
|
|
2044 |
const isContentNode = (schema, node, rootNode, options) => {
|
|
|
2045 |
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);
|
| 1 |
efrain |
2046 |
};
|
| 1441 |
ariadna |
2047 |
const isEmptyNode = (schema, targetNode, opts) => {
|
|
|
2048 |
const options = {
|
|
|
2049 |
...defaultOptionValues,
|
|
|
2050 |
...opts
|
|
|
2051 |
};
|
|
|
2052 |
if (options.checkRootAsContent) {
|
|
|
2053 |
if (isContentNode(schema, targetNode, targetNode, options)) {
|
|
|
2054 |
return false;
|
| 1 |
efrain |
2055 |
}
|
|
|
2056 |
}
|
| 1441 |
ariadna |
2057 |
let node = targetNode.firstChild;
|
|
|
2058 |
let brCount = 0;
|
|
|
2059 |
if (!node) {
|
|
|
2060 |
return true;
|
| 1 |
efrain |
2061 |
}
|
| 1441 |
ariadna |
2062 |
const walker = new DomTreeWalker(node, targetNode);
|
|
|
2063 |
do {
|
|
|
2064 |
if (options.skipBogus && isElement$6(node)) {
|
|
|
2065 |
const bogusValue = node.getAttribute('data-mce-bogus');
|
|
|
2066 |
if (bogusValue) {
|
|
|
2067 |
node = walker.next(bogusValue === 'all');
|
|
|
2068 |
continue;
|
|
|
2069 |
}
|
| 1 |
efrain |
2070 |
}
|
| 1441 |
ariadna |
2071 |
if (isComment(node)) {
|
|
|
2072 |
node = walker.next(true);
|
|
|
2073 |
continue;
|
| 1 |
efrain |
2074 |
}
|
| 1441 |
ariadna |
2075 |
if (isBr$6(node)) {
|
|
|
2076 |
brCount++;
|
|
|
2077 |
node = walker.next();
|
|
|
2078 |
continue;
|
| 1 |
efrain |
2079 |
}
|
| 1441 |
ariadna |
2080 |
if (isContentNode(schema, node, targetNode, options)) {
|
| 1 |
efrain |
2081 |
return false;
|
|
|
2082 |
}
|
| 1441 |
ariadna |
2083 |
node = walker.next();
|
|
|
2084 |
} while (node);
|
|
|
2085 |
return brCount <= 1;
|
| 1 |
efrain |
2086 |
};
|
| 1441 |
ariadna |
2087 |
const isEmpty$2 = (schema, elm, options) => {
|
|
|
2088 |
return isEmptyNode(schema, elm.dom, {
|
|
|
2089 |
checkRootAsContent: true,
|
|
|
2090 |
...options
|
| 1 |
efrain |
2091 |
});
|
|
|
2092 |
};
|
| 1441 |
ariadna |
2093 |
const isContent$1 = (schema, node, options) => {
|
|
|
2094 |
return isContentNode(schema, node, node, {
|
|
|
2095 |
includeZwsp: defaultOptionValues.includeZwsp,
|
|
|
2096 |
...options
|
|
|
2097 |
});
|
|
|
2098 |
};
|
| 1 |
efrain |
2099 |
|
| 1441 |
ariadna |
2100 |
const Cell = initial => {
|
|
|
2101 |
let value = initial;
|
|
|
2102 |
const get = () => {
|
|
|
2103 |
return value;
|
|
|
2104 |
};
|
|
|
2105 |
const set = v => {
|
|
|
2106 |
value = v;
|
|
|
2107 |
};
|
|
|
2108 |
return {
|
|
|
2109 |
get,
|
|
|
2110 |
set
|
|
|
2111 |
};
|
| 1 |
efrain |
2112 |
};
|
| 1441 |
ariadna |
2113 |
|
|
|
2114 |
const singleton = doRevoke => {
|
|
|
2115 |
const subject = Cell(Optional.none());
|
|
|
2116 |
const revoke = () => subject.get().each(doRevoke);
|
|
|
2117 |
const clear = () => {
|
|
|
2118 |
revoke();
|
|
|
2119 |
subject.set(Optional.none());
|
|
|
2120 |
};
|
|
|
2121 |
const isSet = () => subject.get().isSome();
|
|
|
2122 |
const get = () => subject.get();
|
|
|
2123 |
const set = s => {
|
|
|
2124 |
revoke();
|
|
|
2125 |
subject.set(Optional.some(s));
|
|
|
2126 |
};
|
|
|
2127 |
return {
|
|
|
2128 |
clear,
|
|
|
2129 |
isSet,
|
|
|
2130 |
get,
|
|
|
2131 |
set
|
|
|
2132 |
};
|
| 1 |
efrain |
2133 |
};
|
| 1441 |
ariadna |
2134 |
const repeatable = delay => {
|
|
|
2135 |
const intervalId = Cell(Optional.none());
|
|
|
2136 |
const revoke = () => intervalId.get().each(id => clearInterval(id));
|
|
|
2137 |
const clear = () => {
|
|
|
2138 |
revoke();
|
|
|
2139 |
intervalId.set(Optional.none());
|
|
|
2140 |
};
|
|
|
2141 |
const isSet = () => intervalId.get().isSome();
|
|
|
2142 |
const get = () => intervalId.get();
|
|
|
2143 |
const set = functionToRepeat => {
|
|
|
2144 |
revoke();
|
|
|
2145 |
intervalId.set(Optional.some(setInterval(functionToRepeat, delay)));
|
|
|
2146 |
};
|
|
|
2147 |
return {
|
|
|
2148 |
clear,
|
|
|
2149 |
isSet,
|
|
|
2150 |
get,
|
|
|
2151 |
set
|
|
|
2152 |
};
|
| 1 |
efrain |
2153 |
};
|
| 1441 |
ariadna |
2154 |
const value$2 = () => {
|
|
|
2155 |
const subject = singleton(noop);
|
|
|
2156 |
const on = f => subject.get().each(f);
|
|
|
2157 |
return {
|
|
|
2158 |
...subject,
|
|
|
2159 |
on
|
|
|
2160 |
};
|
| 1 |
efrain |
2161 |
};
|
| 1441 |
ariadna |
2162 |
|
|
|
2163 |
const nodeNameToNamespaceType = name => {
|
|
|
2164 |
const lowerCaseName = name.toLowerCase();
|
|
|
2165 |
if (lowerCaseName === 'svg') {
|
|
|
2166 |
return 'svg';
|
|
|
2167 |
} else if (lowerCaseName === 'math') {
|
|
|
2168 |
return 'math';
|
| 1 |
efrain |
2169 |
} else {
|
| 1441 |
ariadna |
2170 |
return 'html';
|
| 1 |
efrain |
2171 |
}
|
|
|
2172 |
};
|
| 1441 |
ariadna |
2173 |
const isNonHtmlElementRootName = name => nodeNameToNamespaceType(name) !== 'html';
|
| 1 |
efrain |
2174 |
const isNonHtmlElementRoot = node => isNonHtmlElementRootName(node.nodeName);
|
| 1441 |
ariadna |
2175 |
const toScopeType = node => nodeNameToNamespaceType(node.nodeName);
|
|
|
2176 |
const namespaceElements = [
|
|
|
2177 |
'svg',
|
|
|
2178 |
'math'
|
|
|
2179 |
];
|
| 1 |
efrain |
2180 |
const createNamespaceTracker = () => {
|
| 1441 |
ariadna |
2181 |
const currentScope = value$2();
|
|
|
2182 |
const current = () => currentScope.get().map(toScopeType).getOr('html');
|
| 1 |
efrain |
2183 |
const track = node => {
|
|
|
2184 |
if (isNonHtmlElementRoot(node)) {
|
| 1441 |
ariadna |
2185 |
currentScope.set(node);
|
|
|
2186 |
} else if (currentScope.get().exists(scopeNode => !scopeNode.contains(node))) {
|
|
|
2187 |
currentScope.clear();
|
| 1 |
efrain |
2188 |
}
|
| 1441 |
ariadna |
2189 |
return current();
|
| 1 |
efrain |
2190 |
};
|
|
|
2191 |
const reset = () => {
|
| 1441 |
ariadna |
2192 |
currentScope.clear();
|
| 1 |
efrain |
2193 |
};
|
|
|
2194 |
return {
|
|
|
2195 |
track,
|
|
|
2196 |
current,
|
|
|
2197 |
reset
|
|
|
2198 |
};
|
|
|
2199 |
};
|
|
|
2200 |
|
|
|
2201 |
const transparentBlockAttr = 'data-mce-block';
|
|
|
2202 |
const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key));
|
|
|
2203 |
const makeSelectorFromSchemaMap = map => map$3(elementNames(map), name => {
|
| 1441 |
ariadna |
2204 |
const escapedName = CSS.escape(name);
|
|
|
2205 |
return `${ escapedName }:` + map$3(namespaceElements, ns => `not(${ ns } ${ escapedName })`).join(':');
|
| 1 |
efrain |
2206 |
}).join(',');
|
|
|
2207 |
const updateTransparent = (blocksSelector, transparent) => {
|
|
|
2208 |
if (isNonNullable(transparent.querySelector(blocksSelector))) {
|
|
|
2209 |
transparent.setAttribute(transparentBlockAttr, 'true');
|
|
|
2210 |
if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') {
|
|
|
2211 |
transparent.removeAttribute('data-mce-selected');
|
|
|
2212 |
}
|
|
|
2213 |
return true;
|
|
|
2214 |
} else {
|
|
|
2215 |
transparent.removeAttribute(transparentBlockAttr);
|
|
|
2216 |
return false;
|
|
|
2217 |
}
|
|
|
2218 |
};
|
|
|
2219 |
const updateBlockStateOnChildren = (schema, scope) => {
|
|
|
2220 |
const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements());
|
|
|
2221 |
const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
|
|
|
2222 |
return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent));
|
|
|
2223 |
};
|
| 1441 |
ariadna |
2224 |
const trimEdge = (schema, el, leftSide) => {
|
| 1 |
efrain |
2225 |
var _a;
|
|
|
2226 |
const childPropertyName = leftSide ? 'lastChild' : 'firstChild';
|
|
|
2227 |
for (let child = el[childPropertyName]; child; child = child[childPropertyName]) {
|
| 1441 |
ariadna |
2228 |
if (isEmptyNode(schema, child, { checkRootAsContent: true })) {
|
| 1 |
efrain |
2229 |
(_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
|
|
|
2230 |
return;
|
|
|
2231 |
}
|
|
|
2232 |
}
|
|
|
2233 |
};
|
| 1441 |
ariadna |
2234 |
const split$2 = (schema, parentElm, splitElm) => {
|
| 1 |
efrain |
2235 |
const range = document.createRange();
|
|
|
2236 |
const parentNode = parentElm.parentNode;
|
|
|
2237 |
if (parentNode) {
|
|
|
2238 |
range.setStartBefore(parentElm);
|
|
|
2239 |
range.setEndBefore(splitElm);
|
|
|
2240 |
const beforeFragment = range.extractContents();
|
| 1441 |
ariadna |
2241 |
trimEdge(schema, beforeFragment, true);
|
| 1 |
efrain |
2242 |
range.setStartAfter(splitElm);
|
|
|
2243 |
range.setEndAfter(parentElm);
|
|
|
2244 |
const afterFragment = range.extractContents();
|
| 1441 |
ariadna |
2245 |
trimEdge(schema, afterFragment, false);
|
|
|
2246 |
if (!isEmptyNode(schema, beforeFragment, { checkRootAsContent: true })) {
|
| 1 |
efrain |
2247 |
parentNode.insertBefore(beforeFragment, parentElm);
|
|
|
2248 |
}
|
| 1441 |
ariadna |
2249 |
if (!isEmptyNode(schema, splitElm, { checkRootAsContent: true })) {
|
| 1 |
efrain |
2250 |
parentNode.insertBefore(splitElm, parentElm);
|
|
|
2251 |
}
|
| 1441 |
ariadna |
2252 |
if (!isEmptyNode(schema, afterFragment, { checkRootAsContent: true })) {
|
| 1 |
efrain |
2253 |
parentNode.insertBefore(afterFragment, parentElm);
|
|
|
2254 |
}
|
|
|
2255 |
parentNode.removeChild(parentElm);
|
|
|
2256 |
}
|
|
|
2257 |
};
|
|
|
2258 |
const splitInvalidChildren = (schema, scope, transparentBlocks) => {
|
|
|
2259 |
const blocksElements = schema.getBlockElements();
|
|
|
2260 |
const rootNode = SugarElement.fromDom(scope);
|
|
|
2261 |
const isBlock = el => name(el) in blocksElements;
|
|
|
2262 |
const isRoot = el => eq(el, rootNode);
|
|
|
2263 |
each$e(fromDom$1(transparentBlocks), transparentBlock => {
|
|
|
2264 |
ancestor$4(transparentBlock, isBlock, isRoot).each(parentBlock => {
|
|
|
2265 |
const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
|
|
|
2266 |
if (invalidChildren.length > 0) {
|
|
|
2267 |
const stateScope = parentElement(parentBlock);
|
|
|
2268 |
each$e(invalidChildren, child => {
|
|
|
2269 |
ancestor$4(child, isBlock, isRoot).each(parentBlock => {
|
| 1441 |
ariadna |
2270 |
split$2(schema, parentBlock.dom, child.dom);
|
| 1 |
efrain |
2271 |
});
|
|
|
2272 |
});
|
|
|
2273 |
stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom));
|
|
|
2274 |
}
|
|
|
2275 |
});
|
|
|
2276 |
});
|
|
|
2277 |
};
|
|
|
2278 |
const unwrapInvalidChildren = (schema, scope, transparentBlocks) => {
|
|
|
2279 |
each$e([
|
|
|
2280 |
...transparentBlocks,
|
|
|
2281 |
...isTransparentBlock(schema, scope) ? [scope] : []
|
|
|
2282 |
], block => each$e(descendants(SugarElement.fromDom(block), block.nodeName.toLowerCase()), elm => {
|
|
|
2283 |
if (isTransparentInline(schema, elm.dom)) {
|
|
|
2284 |
unwrap(elm);
|
|
|
2285 |
}
|
|
|
2286 |
}));
|
|
|
2287 |
};
|
|
|
2288 |
const updateChildren = (schema, scope) => {
|
|
|
2289 |
const transparentBlocks = updateBlockStateOnChildren(schema, scope);
|
|
|
2290 |
splitInvalidChildren(schema, scope, transparentBlocks);
|
|
|
2291 |
unwrapInvalidChildren(schema, scope, transparentBlocks);
|
|
|
2292 |
};
|
|
|
2293 |
const updateElement = (schema, target) => {
|
|
|
2294 |
if (isTransparentElement(schema, target)) {
|
|
|
2295 |
const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
|
|
|
2296 |
updateTransparent(blocksSelector, target);
|
|
|
2297 |
}
|
|
|
2298 |
};
|
|
|
2299 |
const updateCaret = (schema, root, caretParent) => {
|
|
|
2300 |
const isRoot = el => eq(el, SugarElement.fromDom(root));
|
|
|
2301 |
const parents = parents$1(SugarElement.fromDom(caretParent), isRoot);
|
|
|
2302 |
get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom));
|
|
|
2303 |
};
|
|
|
2304 |
const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr);
|
|
|
2305 |
const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name);
|
|
|
2306 |
const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName);
|
|
|
2307 |
const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node);
|
|
|
2308 |
const isTransparentInline = (schema, node) => isTransparentElement(schema, node) && !hasBlockAttr(node);
|
|
|
2309 |
const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr));
|
|
|
2310 |
|
| 1441 |
ariadna |
2311 |
const browser$2 = detect$1().browser;
|
| 1 |
efrain |
2312 |
const firstElement = nodes => find$2(nodes, isElement$7);
|
|
|
2313 |
const getTableCaptionDeltaY = elm => {
|
|
|
2314 |
if (browser$2.isFirefox() && name(elm) === 'table') {
|
|
|
2315 |
return firstElement(children$1(elm)).filter(elm => {
|
|
|
2316 |
return name(elm) === 'caption';
|
|
|
2317 |
}).bind(caption => {
|
|
|
2318 |
return firstElement(nextSiblings(caption)).map(body => {
|
|
|
2319 |
const bodyTop = body.dom.offsetTop;
|
|
|
2320 |
const captionTop = caption.dom.offsetTop;
|
|
|
2321 |
const captionHeight = caption.dom.offsetHeight;
|
|
|
2322 |
return bodyTop <= captionTop ? -captionHeight : 0;
|
|
|
2323 |
});
|
|
|
2324 |
}).getOr(0);
|
|
|
2325 |
} else {
|
|
|
2326 |
return 0;
|
|
|
2327 |
}
|
|
|
2328 |
};
|
|
|
2329 |
const hasChild = (elm, child) => elm.children && contains$2(elm.children, child);
|
|
|
2330 |
const getPos = (body, elm, rootElm) => {
|
|
|
2331 |
let x = 0, y = 0;
|
|
|
2332 |
const doc = body.ownerDocument;
|
|
|
2333 |
rootElm = rootElm ? rootElm : body;
|
|
|
2334 |
if (elm) {
|
|
|
2335 |
if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') {
|
|
|
2336 |
const pos = elm.getBoundingClientRect();
|
|
|
2337 |
x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
|
|
|
2338 |
y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
|
|
|
2339 |
return {
|
|
|
2340 |
x,
|
|
|
2341 |
y
|
|
|
2342 |
};
|
|
|
2343 |
}
|
|
|
2344 |
let offsetParent = elm;
|
|
|
2345 |
while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
|
|
|
2346 |
const castOffsetParent = offsetParent;
|
|
|
2347 |
x += castOffsetParent.offsetLeft || 0;
|
|
|
2348 |
y += castOffsetParent.offsetTop || 0;
|
|
|
2349 |
offsetParent = castOffsetParent.offsetParent;
|
|
|
2350 |
}
|
|
|
2351 |
offsetParent = elm.parentNode;
|
|
|
2352 |
while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
|
|
|
2353 |
x -= offsetParent.scrollLeft || 0;
|
|
|
2354 |
y -= offsetParent.scrollTop || 0;
|
|
|
2355 |
offsetParent = offsetParent.parentNode;
|
|
|
2356 |
}
|
|
|
2357 |
y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
|
|
|
2358 |
}
|
|
|
2359 |
return {
|
|
|
2360 |
x,
|
|
|
2361 |
y
|
|
|
2362 |
};
|
|
|
2363 |
};
|
|
|
2364 |
|
|
|
2365 |
const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
|
|
|
2366 |
let idCount = 0;
|
|
|
2367 |
const loadedStates = {};
|
|
|
2368 |
const edos = SugarElement.fromDom(documentOrShadowRoot);
|
|
|
2369 |
const doc = documentOrOwner(edos);
|
|
|
2370 |
const _setReferrerPolicy = referrerPolicy => {
|
|
|
2371 |
settings.referrerPolicy = referrerPolicy;
|
|
|
2372 |
};
|
|
|
2373 |
const _setContentCssCors = contentCssCors => {
|
|
|
2374 |
settings.contentCssCors = contentCssCors;
|
|
|
2375 |
};
|
|
|
2376 |
const addStyle = element => {
|
|
|
2377 |
append$1(getStyleContainer(edos), element);
|
|
|
2378 |
};
|
|
|
2379 |
const removeStyle = id => {
|
|
|
2380 |
const styleContainer = getStyleContainer(edos);
|
| 1441 |
ariadna |
2381 |
descendant$1(styleContainer, '#' + id).each(remove$4);
|
| 1 |
efrain |
2382 |
};
|
|
|
2383 |
const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({
|
|
|
2384 |
id: 'mce-u' + idCount++,
|
|
|
2385 |
passed: [],
|
|
|
2386 |
failed: [],
|
|
|
2387 |
count: 0
|
|
|
2388 |
}));
|
|
|
2389 |
const load = url => new Promise((success, failure) => {
|
|
|
2390 |
let link;
|
|
|
2391 |
const urlWithSuffix = Tools._addCacheSuffix(url);
|
|
|
2392 |
const state = getOrCreateState(urlWithSuffix);
|
|
|
2393 |
loadedStates[urlWithSuffix] = state;
|
|
|
2394 |
state.count++;
|
|
|
2395 |
const resolve = (callbacks, status) => {
|
|
|
2396 |
each$e(callbacks, call);
|
|
|
2397 |
state.status = status;
|
|
|
2398 |
state.passed = [];
|
|
|
2399 |
state.failed = [];
|
|
|
2400 |
if (link) {
|
|
|
2401 |
link.onload = null;
|
|
|
2402 |
link.onerror = null;
|
|
|
2403 |
link = null;
|
|
|
2404 |
}
|
|
|
2405 |
};
|
|
|
2406 |
const passed = () => resolve(state.passed, 2);
|
|
|
2407 |
const failed = () => resolve(state.failed, 3);
|
|
|
2408 |
if (success) {
|
|
|
2409 |
state.passed.push(success);
|
|
|
2410 |
}
|
|
|
2411 |
if (failure) {
|
|
|
2412 |
state.failed.push(failure);
|
|
|
2413 |
}
|
|
|
2414 |
if (state.status === 1) {
|
|
|
2415 |
return;
|
|
|
2416 |
}
|
|
|
2417 |
if (state.status === 2) {
|
|
|
2418 |
passed();
|
|
|
2419 |
return;
|
|
|
2420 |
}
|
|
|
2421 |
if (state.status === 3) {
|
|
|
2422 |
failed();
|
|
|
2423 |
return;
|
|
|
2424 |
}
|
|
|
2425 |
state.status = 1;
|
|
|
2426 |
const linkElem = SugarElement.fromTag('link', doc.dom);
|
|
|
2427 |
setAll$1(linkElem, {
|
|
|
2428 |
rel: 'stylesheet',
|
|
|
2429 |
type: 'text/css',
|
|
|
2430 |
id: state.id
|
|
|
2431 |
});
|
|
|
2432 |
if (settings.contentCssCors) {
|
| 1441 |
ariadna |
2433 |
set$4(linkElem, 'crossOrigin', 'anonymous');
|
| 1 |
efrain |
2434 |
}
|
|
|
2435 |
if (settings.referrerPolicy) {
|
| 1441 |
ariadna |
2436 |
set$4(linkElem, 'referrerpolicy', settings.referrerPolicy);
|
| 1 |
efrain |
2437 |
}
|
|
|
2438 |
link = linkElem.dom;
|
|
|
2439 |
link.onload = passed;
|
|
|
2440 |
link.onerror = failed;
|
|
|
2441 |
addStyle(linkElem);
|
| 1441 |
ariadna |
2442 |
set$4(linkElem, 'href', urlWithSuffix);
|
| 1 |
efrain |
2443 |
});
|
|
|
2444 |
const loadRawCss = (key, css) => {
|
|
|
2445 |
const state = getOrCreateState(key);
|
|
|
2446 |
loadedStates[key] = state;
|
|
|
2447 |
state.count++;
|
|
|
2448 |
const styleElem = SugarElement.fromTag('style', doc.dom);
|
|
|
2449 |
setAll$1(styleElem, {
|
| 1441 |
ariadna |
2450 |
'rel': 'stylesheet',
|
|
|
2451 |
'type': 'text/css',
|
|
|
2452 |
'id': state.id,
|
|
|
2453 |
'data-mce-key': key
|
| 1 |
efrain |
2454 |
});
|
|
|
2455 |
styleElem.dom.innerHTML = css;
|
|
|
2456 |
addStyle(styleElem);
|
|
|
2457 |
};
|
|
|
2458 |
const loadAll = urls => {
|
|
|
2459 |
const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url))));
|
|
|
2460 |
return loadedUrls.then(results => {
|
|
|
2461 |
const parts = partition$2(results, r => r.status === 'fulfilled');
|
|
|
2462 |
if (parts.fail.length > 0) {
|
|
|
2463 |
return Promise.reject(map$3(parts.fail, result => result.reason));
|
|
|
2464 |
} else {
|
|
|
2465 |
return map$3(parts.pass, result => result.value);
|
|
|
2466 |
}
|
|
|
2467 |
});
|
|
|
2468 |
};
|
|
|
2469 |
const unload = url => {
|
|
|
2470 |
const urlWithSuffix = Tools._addCacheSuffix(url);
|
|
|
2471 |
get$a(loadedStates, urlWithSuffix).each(state => {
|
|
|
2472 |
const count = --state.count;
|
|
|
2473 |
if (count === 0) {
|
|
|
2474 |
delete loadedStates[urlWithSuffix];
|
|
|
2475 |
removeStyle(state.id);
|
|
|
2476 |
}
|
|
|
2477 |
});
|
|
|
2478 |
};
|
|
|
2479 |
const unloadRawCss = key => {
|
|
|
2480 |
get$a(loadedStates, key).each(state => {
|
|
|
2481 |
const count = --state.count;
|
|
|
2482 |
if (count === 0) {
|
|
|
2483 |
delete loadedStates[key];
|
|
|
2484 |
removeStyle(state.id);
|
|
|
2485 |
}
|
|
|
2486 |
});
|
|
|
2487 |
};
|
|
|
2488 |
const unloadAll = urls => {
|
|
|
2489 |
each$e(urls, url => {
|
|
|
2490 |
unload(url);
|
|
|
2491 |
});
|
|
|
2492 |
};
|
|
|
2493 |
return {
|
|
|
2494 |
load,
|
|
|
2495 |
loadRawCss,
|
|
|
2496 |
loadAll,
|
|
|
2497 |
unload,
|
|
|
2498 |
unloadRawCss,
|
|
|
2499 |
unloadAll,
|
|
|
2500 |
_setReferrerPolicy,
|
|
|
2501 |
_setContentCssCors
|
|
|
2502 |
};
|
|
|
2503 |
};
|
|
|
2504 |
|
| 1441 |
ariadna |
2505 |
const create$c = () => {
|
| 1 |
efrain |
2506 |
const map = new WeakMap();
|
|
|
2507 |
const forElement = (referenceElement, settings) => {
|
|
|
2508 |
const root = getRootNode(referenceElement);
|
|
|
2509 |
const rootDom = root.dom;
|
|
|
2510 |
return Optional.from(map.get(rootDom)).getOrThunk(() => {
|
|
|
2511 |
const sl = StyleSheetLoader(rootDom, settings);
|
|
|
2512 |
map.set(rootDom, sl);
|
|
|
2513 |
return sl;
|
|
|
2514 |
});
|
|
|
2515 |
};
|
|
|
2516 |
return { forElement };
|
|
|
2517 |
};
|
| 1441 |
ariadna |
2518 |
const instance = create$c();
|
| 1 |
efrain |
2519 |
|
|
|
2520 |
const isSpan = node => node.nodeName.toLowerCase() === 'span';
|
| 1441 |
ariadna |
2521 |
const isInlineContent = (node, schema) => isNonNullable(node) && (isContent$1(schema, node) || schema.isInline(node.nodeName.toLowerCase()));
|
| 1 |
efrain |
2522 |
const surroundedByInlineContent = (node, root, schema) => {
|
|
|
2523 |
const prev = new DomTreeWalker(node, root).prev(false);
|
|
|
2524 |
const next = new DomTreeWalker(node, root).next(false);
|
| 1441 |
ariadna |
2525 |
const prevIsInline = isUndefined(prev) || isInlineContent(prev, schema);
|
|
|
2526 |
const nextIsInline = isUndefined(next) || isInlineContent(next, schema);
|
| 1 |
efrain |
2527 |
return prevIsInline && nextIsInline;
|
|
|
2528 |
};
|
|
|
2529 |
const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark';
|
| 1441 |
ariadna |
2530 |
const isKeepTextNode = (node, root, schema) => isText$b(node) && node.data.length > 0 && surroundedByInlineContent(node, root, schema);
|
| 1 |
efrain |
2531 |
const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false;
|
|
|
2532 |
const isDocument = node => isDocumentFragment(node) || isDocument$1(node);
|
|
|
2533 |
const trimNode = (dom, node, schema, root) => {
|
|
|
2534 |
var _a;
|
|
|
2535 |
const rootNode = root || node;
|
|
|
2536 |
if (isElement$6(node) && isBookmarkNode$2(node)) {
|
|
|
2537 |
return node;
|
|
|
2538 |
}
|
|
|
2539 |
const children = node.childNodes;
|
|
|
2540 |
for (let i = children.length - 1; i >= 0; i--) {
|
|
|
2541 |
trimNode(dom, children[i], schema, rootNode);
|
|
|
2542 |
}
|
|
|
2543 |
if (isElement$6(node)) {
|
|
|
2544 |
const currentChildren = node.childNodes;
|
|
|
2545 |
if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
|
|
|
2546 |
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node);
|
|
|
2547 |
}
|
|
|
2548 |
}
|
| 1441 |
ariadna |
2549 |
if (!isDocument(node) && !isContent$1(schema, node) && !isKeepElement(node) && !isKeepTextNode(node, rootNode, schema)) {
|
| 1 |
efrain |
2550 |
dom.remove(node);
|
|
|
2551 |
}
|
|
|
2552 |
return node;
|
|
|
2553 |
};
|
|
|
2554 |
|
|
|
2555 |
const makeMap$3 = Tools.makeMap;
|
|
|
2556 |
const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
|
2557 |
const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
|
2558 |
const rawCharsRegExp = /[<>&\"\']/g;
|
|
|
2559 |
const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
|
|
|
2560 |
const asciiMap = {
|
|
|
2561 |
128: '\u20AC',
|
|
|
2562 |
130: '\u201A',
|
|
|
2563 |
131: '\u0192',
|
|
|
2564 |
132: '\u201E',
|
|
|
2565 |
133: '\u2026',
|
|
|
2566 |
134: '\u2020',
|
|
|
2567 |
135: '\u2021',
|
|
|
2568 |
136: '\u02c6',
|
|
|
2569 |
137: '\u2030',
|
|
|
2570 |
138: '\u0160',
|
|
|
2571 |
139: '\u2039',
|
|
|
2572 |
140: '\u0152',
|
|
|
2573 |
142: '\u017d',
|
|
|
2574 |
145: '\u2018',
|
|
|
2575 |
146: '\u2019',
|
|
|
2576 |
147: '\u201C',
|
|
|
2577 |
148: '\u201D',
|
|
|
2578 |
149: '\u2022',
|
|
|
2579 |
150: '\u2013',
|
|
|
2580 |
151: '\u2014',
|
|
|
2581 |
152: '\u02DC',
|
|
|
2582 |
153: '\u2122',
|
|
|
2583 |
154: '\u0161',
|
|
|
2584 |
155: '\u203A',
|
|
|
2585 |
156: '\u0153',
|
|
|
2586 |
158: '\u017e',
|
|
|
2587 |
159: '\u0178'
|
|
|
2588 |
};
|
|
|
2589 |
const baseEntities = {
|
|
|
2590 |
'"': '"',
|
|
|
2591 |
'\'': ''',
|
|
|
2592 |
'<': '<',
|
|
|
2593 |
'>': '>',
|
|
|
2594 |
'&': '&',
|
|
|
2595 |
'`': '`'
|
|
|
2596 |
};
|
|
|
2597 |
const reverseEntities = {
|
|
|
2598 |
'<': '<',
|
|
|
2599 |
'>': '>',
|
|
|
2600 |
'&': '&',
|
|
|
2601 |
'"': '"',
|
|
|
2602 |
''': `'`
|
|
|
2603 |
};
|
|
|
2604 |
const nativeDecode = text => {
|
|
|
2605 |
const elm = SugarElement.fromTag('div').dom;
|
|
|
2606 |
elm.innerHTML = text;
|
|
|
2607 |
return elm.textContent || elm.innerText || text;
|
|
|
2608 |
};
|
|
|
2609 |
const buildEntitiesLookup = (items, radix) => {
|
|
|
2610 |
const lookup = {};
|
|
|
2611 |
if (items) {
|
|
|
2612 |
const itemList = items.split(',');
|
|
|
2613 |
radix = radix || 10;
|
|
|
2614 |
for (let i = 0; i < itemList.length; i += 2) {
|
|
|
2615 |
const chr = String.fromCharCode(parseInt(itemList[i], radix));
|
|
|
2616 |
if (!baseEntities[chr]) {
|
|
|
2617 |
const entity = '&' + itemList[i + 1] + ';';
|
|
|
2618 |
lookup[chr] = entity;
|
|
|
2619 |
lookup[entity] = chr;
|
|
|
2620 |
}
|
|
|
2621 |
}
|
|
|
2622 |
return lookup;
|
|
|
2623 |
} else {
|
|
|
2624 |
return undefined;
|
|
|
2625 |
}
|
|
|
2626 |
};
|
|
|
2627 |
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);
|
|
|
2628 |
const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
|
|
2629 |
return baseEntities[chr] || chr;
|
|
|
2630 |
});
|
|
|
2631 |
const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => {
|
|
|
2632 |
return baseEntities[chr] || chr;
|
|
|
2633 |
});
|
|
|
2634 |
const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
|
|
2635 |
if (chr.length > 1) {
|
|
|
2636 |
return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
|
|
|
2637 |
}
|
|
|
2638 |
return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
|
|
|
2639 |
});
|
|
|
2640 |
const encodeNamed = (text, attr, entities) => {
|
|
|
2641 |
const resolveEntities = entities || namedEntities;
|
|
|
2642 |
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
|
|
2643 |
return baseEntities[chr] || resolveEntities[chr] || chr;
|
|
|
2644 |
});
|
|
|
2645 |
};
|
|
|
2646 |
const getEncodeFunc = (name, entities) => {
|
|
|
2647 |
const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
|
|
|
2648 |
const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
|
|
|
2649 |
if (baseEntities[chr] !== undefined) {
|
|
|
2650 |
return baseEntities[chr];
|
|
|
2651 |
}
|
|
|
2652 |
if (entitiesMap[chr] !== undefined) {
|
|
|
2653 |
return entitiesMap[chr];
|
|
|
2654 |
}
|
|
|
2655 |
if (chr.length > 1) {
|
|
|
2656 |
return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
|
|
|
2657 |
}
|
|
|
2658 |
return '&#' + chr.charCodeAt(0) + ';';
|
|
|
2659 |
});
|
|
|
2660 |
const encodeCustomNamed = (text, attr) => {
|
|
|
2661 |
return encodeNamed(text, attr, entitiesMap);
|
|
|
2662 |
};
|
|
|
2663 |
const nameMap = makeMap$3(name.replace(/\+/g, ','));
|
|
|
2664 |
if (nameMap.named && nameMap.numeric) {
|
|
|
2665 |
return encodeNamedAndNumeric;
|
|
|
2666 |
}
|
|
|
2667 |
if (nameMap.named) {
|
|
|
2668 |
if (entities) {
|
|
|
2669 |
return encodeCustomNamed;
|
|
|
2670 |
}
|
|
|
2671 |
return encodeNamed;
|
|
|
2672 |
}
|
|
|
2673 |
if (nameMap.numeric) {
|
|
|
2674 |
return encodeNumeric;
|
|
|
2675 |
}
|
|
|
2676 |
return encodeRaw;
|
|
|
2677 |
};
|
|
|
2678 |
const decode = text => text.replace(entityRegExp, (all, numeric) => {
|
|
|
2679 |
if (numeric) {
|
|
|
2680 |
if (numeric.charAt(0).toLowerCase() === 'x') {
|
|
|
2681 |
numeric = parseInt(numeric.substr(1), 16);
|
|
|
2682 |
} else {
|
|
|
2683 |
numeric = parseInt(numeric, 10);
|
|
|
2684 |
}
|
|
|
2685 |
if (numeric > 65535) {
|
|
|
2686 |
numeric -= 65536;
|
|
|
2687 |
return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
|
|
|
2688 |
}
|
|
|
2689 |
return asciiMap[numeric] || String.fromCharCode(numeric);
|
|
|
2690 |
}
|
|
|
2691 |
return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
|
|
|
2692 |
});
|
|
|
2693 |
const Entities = {
|
|
|
2694 |
encodeRaw,
|
|
|
2695 |
encodeAllRaw,
|
|
|
2696 |
encodeNumeric,
|
|
|
2697 |
encodeNamed,
|
|
|
2698 |
getEncodeFunc,
|
|
|
2699 |
decode
|
|
|
2700 |
};
|
|
|
2701 |
|
|
|
2702 |
const split$1 = (items, delim) => {
|
|
|
2703 |
items = Tools.trim(items);
|
|
|
2704 |
return items ? items.split(delim || ' ') : [];
|
|
|
2705 |
};
|
|
|
2706 |
const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
|
| 1441 |
ariadna |
2707 |
const isRegExp$1 = obj => isObject(obj) && obj.source && Object.prototype.toString.call(obj) === '[object RegExp]';
|
|
|
2708 |
const deepCloneElementRule = obj => {
|
|
|
2709 |
const helper = value => {
|
|
|
2710 |
if (isArray$1(value)) {
|
|
|
2711 |
return map$3(value, helper);
|
|
|
2712 |
} else if (isRegExp$1(value)) {
|
|
|
2713 |
return new RegExp(value.source, value.flags);
|
|
|
2714 |
} else if (isObject(value)) {
|
|
|
2715 |
return map$2(value, helper);
|
|
|
2716 |
} else {
|
|
|
2717 |
return value;
|
|
|
2718 |
}
|
|
|
2719 |
};
|
|
|
2720 |
return helper(obj);
|
|
|
2721 |
};
|
| 1 |
efrain |
2722 |
|
|
|
2723 |
const parseCustomElementsRules = value => {
|
|
|
2724 |
const customElementRegExp = /^(~)?(.+)$/;
|
|
|
2725 |
return bind$3(split$1(value, ','), rule => {
|
|
|
2726 |
const matches = customElementRegExp.exec(rule);
|
|
|
2727 |
if (matches) {
|
|
|
2728 |
const inline = matches[1] === '~';
|
|
|
2729 |
const cloneName = inline ? 'span' : 'div';
|
|
|
2730 |
const name = matches[2];
|
|
|
2731 |
return [{
|
|
|
2732 |
cloneName,
|
|
|
2733 |
name
|
|
|
2734 |
}];
|
|
|
2735 |
} else {
|
|
|
2736 |
return [];
|
|
|
2737 |
}
|
|
|
2738 |
});
|
|
|
2739 |
};
|
|
|
2740 |
|
| 1441 |
ariadna |
2741 |
const getGlobalAttributeSet = type => {
|
|
|
2742 |
return Object.freeze([
|
|
|
2743 |
'id',
|
|
|
2744 |
'accesskey',
|
|
|
2745 |
'class',
|
|
|
2746 |
'dir',
|
|
|
2747 |
'lang',
|
|
|
2748 |
'style',
|
|
|
2749 |
'tabindex',
|
|
|
2750 |
'title',
|
|
|
2751 |
'role',
|
|
|
2752 |
...type !== 'html4' ? [
|
|
|
2753 |
'contenteditable',
|
|
|
2754 |
'contextmenu',
|
|
|
2755 |
'draggable',
|
|
|
2756 |
'dropzone',
|
|
|
2757 |
'hidden',
|
|
|
2758 |
'spellcheck',
|
|
|
2759 |
'translate',
|
|
|
2760 |
'itemprop',
|
|
|
2761 |
'itemscope',
|
|
|
2762 |
'itemtype'
|
|
|
2763 |
] : [],
|
|
|
2764 |
...type !== 'html5-strict' ? ['xml:lang'] : []
|
|
|
2765 |
]);
|
|
|
2766 |
};
|
|
|
2767 |
|
| 1 |
efrain |
2768 |
const getElementSetsAsStrings = type => {
|
| 1441 |
ariadna |
2769 |
let blockContent;
|
| 1 |
efrain |
2770 |
let phrasingContent;
|
|
|
2771 |
blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
|
|
|
2772 |
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';
|
|
|
2773 |
if (type !== 'html4') {
|
|
|
2774 |
const transparentContent = 'a ins del canvas map';
|
|
|
2775 |
blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent;
|
| 1441 |
ariadna |
2776 |
phrasingContent += ' audio canvas command data datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen svg';
|
| 1 |
efrain |
2777 |
}
|
|
|
2778 |
if (type !== 'html5-strict') {
|
|
|
2779 |
const html4PhrasingContent = 'acronym applet basefont big font strike tt';
|
|
|
2780 |
phrasingContent = [
|
|
|
2781 |
phrasingContent,
|
|
|
2782 |
html4PhrasingContent
|
|
|
2783 |
].join(' ');
|
|
|
2784 |
const html4BlockContent = 'center dir isindex noframes';
|
|
|
2785 |
blockContent = [
|
|
|
2786 |
blockContent,
|
|
|
2787 |
html4BlockContent
|
|
|
2788 |
].join(' ');
|
|
|
2789 |
}
|
|
|
2790 |
const flowContent = [
|
|
|
2791 |
blockContent,
|
|
|
2792 |
phrasingContent
|
|
|
2793 |
].join(' ');
|
|
|
2794 |
return {
|
|
|
2795 |
blockContent,
|
|
|
2796 |
phrasingContent,
|
|
|
2797 |
flowContent
|
|
|
2798 |
};
|
|
|
2799 |
};
|
| 1441 |
ariadna |
2800 |
const getElementSets = type => {
|
|
|
2801 |
const {blockContent, phrasingContent, flowContent} = getElementSetsAsStrings(type);
|
|
|
2802 |
const toArr = value => {
|
|
|
2803 |
return Object.freeze(value.split(' '));
|
|
|
2804 |
};
|
|
|
2805 |
return Object.freeze({
|
|
|
2806 |
blockContent: toArr(blockContent),
|
|
|
2807 |
phrasingContent: toArr(phrasingContent),
|
|
|
2808 |
flowContent: toArr(flowContent)
|
|
|
2809 |
});
|
|
|
2810 |
};
|
| 1 |
efrain |
2811 |
|
| 1441 |
ariadna |
2812 |
const cachedSets = {
|
|
|
2813 |
'html4': cached(() => getElementSets('html4')),
|
|
|
2814 |
'html5': cached(() => getElementSets('html5')),
|
|
|
2815 |
'html5-strict': cached(() => getElementSets('html5-strict'))
|
|
|
2816 |
};
|
|
|
2817 |
const getElementsPreset = (type, name) => {
|
|
|
2818 |
const {blockContent, phrasingContent, flowContent} = cachedSets[type]();
|
|
|
2819 |
if (name === 'blocks') {
|
|
|
2820 |
return Optional.some(blockContent);
|
|
|
2821 |
} else if (name === 'phrasing') {
|
|
|
2822 |
return Optional.some(phrasingContent);
|
|
|
2823 |
} else if (name === 'flow') {
|
|
|
2824 |
return Optional.some(flowContent);
|
|
|
2825 |
} else {
|
|
|
2826 |
return Optional.none();
|
|
|
2827 |
}
|
|
|
2828 |
};
|
|
|
2829 |
|
| 1 |
efrain |
2830 |
const makeSchema = type => {
|
| 1441 |
ariadna |
2831 |
const globalAttributes = getGlobalAttributeSet(type);
|
|
|
2832 |
const {phrasingContent, flowContent} = getElementSetsAsStrings(type);
|
| 1 |
efrain |
2833 |
const schema = {};
|
|
|
2834 |
const addElement = (name, attributes, children) => {
|
|
|
2835 |
schema[name] = {
|
|
|
2836 |
attributes: mapToObject(attributes, constant({})),
|
|
|
2837 |
attributesOrder: attributes,
|
|
|
2838 |
children: mapToObject(children, constant({}))
|
|
|
2839 |
};
|
|
|
2840 |
};
|
|
|
2841 |
const add = (name, attributes = '', children = '') => {
|
|
|
2842 |
const childNames = split$1(children);
|
|
|
2843 |
const names = split$1(name);
|
|
|
2844 |
let ni = names.length;
|
| 1441 |
ariadna |
2845 |
const allAttributes = [
|
|
|
2846 |
...globalAttributes,
|
|
|
2847 |
...split$1(attributes)
|
|
|
2848 |
];
|
| 1 |
efrain |
2849 |
while (ni--) {
|
|
|
2850 |
addElement(names[ni], allAttributes.slice(), childNames);
|
|
|
2851 |
}
|
|
|
2852 |
};
|
|
|
2853 |
const addAttrs = (name, attributes) => {
|
|
|
2854 |
const names = split$1(name);
|
|
|
2855 |
const attrs = split$1(attributes);
|
|
|
2856 |
let ni = names.length;
|
|
|
2857 |
while (ni--) {
|
|
|
2858 |
const schemaItem = schema[names[ni]];
|
|
|
2859 |
for (let i = 0, l = attrs.length; i < l; i++) {
|
|
|
2860 |
schemaItem.attributes[attrs[i]] = {};
|
|
|
2861 |
schemaItem.attributesOrder.push(attrs[i]);
|
|
|
2862 |
}
|
|
|
2863 |
}
|
|
|
2864 |
};
|
|
|
2865 |
if (type !== 'html5-strict') {
|
|
|
2866 |
const html4PhrasingContent = 'acronym applet basefont big font strike tt';
|
|
|
2867 |
each$e(split$1(html4PhrasingContent), name => {
|
|
|
2868 |
add(name, '', phrasingContent);
|
|
|
2869 |
});
|
|
|
2870 |
const html4BlockContent = 'center dir isindex noframes';
|
|
|
2871 |
each$e(split$1(html4BlockContent), name => {
|
|
|
2872 |
add(name, '', flowContent);
|
|
|
2873 |
});
|
|
|
2874 |
}
|
|
|
2875 |
add('html', 'manifest', 'head body');
|
|
|
2876 |
add('head', '', 'base command link meta noscript script style title');
|
|
|
2877 |
add('title hr noscript br');
|
|
|
2878 |
add('base', 'href target');
|
|
|
2879 |
add('link', 'href rel media hreflang type sizes hreflang');
|
|
|
2880 |
add('meta', 'name http-equiv content charset');
|
|
|
2881 |
add('style', 'media type scoped');
|
|
|
2882 |
add('script', 'src async defer type charset');
|
|
|
2883 |
add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
|
|
|
2884 |
add('dd div', '', flowContent);
|
|
|
2885 |
add('address dt caption', '', type === 'html4' ? phrasingContent : flowContent);
|
|
|
2886 |
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);
|
|
|
2887 |
add('blockquote', 'cite', flowContent);
|
|
|
2888 |
add('ol', 'reversed start type', 'li');
|
|
|
2889 |
add('ul', '', 'li');
|
|
|
2890 |
add('li', 'value', flowContent);
|
|
|
2891 |
add('dl', '', 'dt dd');
|
|
|
2892 |
add('a', 'href target rel media hreflang type', type === 'html4' ? phrasingContent : flowContent);
|
|
|
2893 |
add('q', 'cite', phrasingContent);
|
|
|
2894 |
add('ins del', 'cite datetime', flowContent);
|
|
|
2895 |
add('img', 'src sizes srcset alt usemap ismap width height');
|
|
|
2896 |
add('iframe', 'src name width height', flowContent);
|
|
|
2897 |
add('embed', 'src type width height');
|
|
|
2898 |
add('object', 'data type typemustmatch name usemap form width height', [
|
|
|
2899 |
flowContent,
|
|
|
2900 |
'param'
|
|
|
2901 |
].join(' '));
|
|
|
2902 |
add('param', 'name value');
|
|
|
2903 |
add('map', 'name', [
|
|
|
2904 |
flowContent,
|
|
|
2905 |
'area'
|
|
|
2906 |
].join(' '));
|
|
|
2907 |
add('area', 'alt coords shape href target rel media hreflang type');
|
|
|
2908 |
add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
|
|
|
2909 |
add('colgroup', 'span', 'col');
|
|
|
2910 |
add('col', 'span');
|
|
|
2911 |
add('tbody thead tfoot', '', 'tr');
|
|
|
2912 |
add('tr', '', 'td th');
|
|
|
2913 |
add('td', 'colspan rowspan headers', flowContent);
|
|
|
2914 |
add('th', 'colspan rowspan headers scope abbr', flowContent);
|
|
|
2915 |
add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
|
|
|
2916 |
add('fieldset', 'disabled form name', [
|
|
|
2917 |
flowContent,
|
|
|
2918 |
'legend'
|
|
|
2919 |
].join(' '));
|
|
|
2920 |
add('label', 'form for', phrasingContent);
|
|
|
2921 |
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');
|
|
|
2922 |
add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
|
|
|
2923 |
add('select', 'disabled form multiple name required size', 'option optgroup');
|
|
|
2924 |
add('optgroup', 'disabled label', 'option');
|
|
|
2925 |
add('option', 'disabled label selected value');
|
|
|
2926 |
add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
|
|
|
2927 |
add('menu', 'type label', [
|
|
|
2928 |
flowContent,
|
|
|
2929 |
'li'
|
|
|
2930 |
].join(' '));
|
|
|
2931 |
add('noscript', '', flowContent);
|
|
|
2932 |
if (type !== 'html4') {
|
|
|
2933 |
add('wbr');
|
|
|
2934 |
add('ruby', '', [
|
|
|
2935 |
phrasingContent,
|
|
|
2936 |
'rt rp'
|
|
|
2937 |
].join(' '));
|
|
|
2938 |
add('figcaption', '', flowContent);
|
|
|
2939 |
add('mark rt rp bdi', '', phrasingContent);
|
|
|
2940 |
add('summary', '', [
|
|
|
2941 |
phrasingContent,
|
|
|
2942 |
'h1 h2 h3 h4 h5 h6'
|
|
|
2943 |
].join(' '));
|
|
|
2944 |
add('canvas', 'width height', flowContent);
|
| 1441 |
ariadna |
2945 |
add('data', 'value', phrasingContent);
|
| 1 |
efrain |
2946 |
add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
|
|
|
2947 |
flowContent,
|
|
|
2948 |
'track source'
|
|
|
2949 |
].join(' '));
|
|
|
2950 |
add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
|
|
|
2951 |
flowContent,
|
|
|
2952 |
'track source'
|
|
|
2953 |
].join(' '));
|
|
|
2954 |
add('picture', '', 'img source');
|
|
|
2955 |
add('source', 'src srcset type media sizes');
|
|
|
2956 |
add('track', 'kind src srclang label default');
|
|
|
2957 |
add('datalist', '', [
|
|
|
2958 |
phrasingContent,
|
|
|
2959 |
'option'
|
|
|
2960 |
].join(' '));
|
|
|
2961 |
add('article section nav aside main header footer', '', flowContent);
|
|
|
2962 |
add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
|
|
|
2963 |
add('figure', '', [
|
|
|
2964 |
flowContent,
|
|
|
2965 |
'figcaption'
|
|
|
2966 |
].join(' '));
|
|
|
2967 |
add('time', 'datetime', phrasingContent);
|
|
|
2968 |
add('dialog', 'open', flowContent);
|
|
|
2969 |
add('command', 'type label icon disabled checked radiogroup command');
|
|
|
2970 |
add('output', 'for form name', phrasingContent);
|
|
|
2971 |
add('progress', 'value max', phrasingContent);
|
|
|
2972 |
add('meter', 'value min max low high optimum', phrasingContent);
|
|
|
2973 |
add('details', 'open', [
|
|
|
2974 |
flowContent,
|
|
|
2975 |
'summary'
|
|
|
2976 |
].join(' '));
|
|
|
2977 |
add('keygen', 'autofocus challenge disabled form keytype name');
|
|
|
2978 |
addElement('svg', 'id tabindex lang xml:space class style x y width height viewBox preserveAspectRatio zoomAndPan transform'.split(' '), []);
|
|
|
2979 |
}
|
|
|
2980 |
if (type !== 'html5-strict') {
|
|
|
2981 |
addAttrs('script', 'language xml:space');
|
|
|
2982 |
addAttrs('style', 'xml:space');
|
|
|
2983 |
addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
|
|
|
2984 |
addAttrs('embed', 'align name hspace vspace');
|
|
|
2985 |
addAttrs('param', 'valuetype type');
|
|
|
2986 |
addAttrs('a', 'charset name rev shape coords');
|
|
|
2987 |
addAttrs('br', 'clear');
|
|
|
2988 |
addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
|
|
|
2989 |
addAttrs('img', 'name longdesc align border hspace vspace');
|
|
|
2990 |
addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
|
|
|
2991 |
addAttrs('font basefont', 'size color face');
|
|
|
2992 |
addAttrs('input', 'usemap align');
|
|
|
2993 |
addAttrs('select');
|
|
|
2994 |
addAttrs('textarea');
|
|
|
2995 |
addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
|
|
|
2996 |
addAttrs('ul', 'type compact');
|
|
|
2997 |
addAttrs('li', 'type');
|
|
|
2998 |
addAttrs('ol dl menu dir', 'compact');
|
|
|
2999 |
addAttrs('pre', 'width xml:space');
|
|
|
3000 |
addAttrs('hr', 'align noshade size width');
|
|
|
3001 |
addAttrs('isindex', 'prompt');
|
|
|
3002 |
addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
|
|
|
3003 |
addAttrs('col', 'width align char charoff valign');
|
|
|
3004 |
addAttrs('colgroup', 'width align char charoff valign');
|
|
|
3005 |
addAttrs('thead', 'align char charoff valign');
|
|
|
3006 |
addAttrs('tr', 'align char charoff valign bgcolor');
|
|
|
3007 |
addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
|
|
|
3008 |
addAttrs('form', 'accept');
|
|
|
3009 |
addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
|
|
|
3010 |
addAttrs('tfoot', 'align char charoff valign');
|
|
|
3011 |
addAttrs('tbody', 'align char charoff valign');
|
|
|
3012 |
addAttrs('area', 'nohref');
|
|
|
3013 |
addAttrs('body', 'background bgcolor text link vlink alink');
|
|
|
3014 |
}
|
|
|
3015 |
if (type !== 'html4') {
|
|
|
3016 |
addAttrs('input button select textarea', 'autofocus');
|
|
|
3017 |
addAttrs('input textarea', 'placeholder');
|
|
|
3018 |
addAttrs('a', 'download');
|
|
|
3019 |
addAttrs('link script img', 'crossorigin');
|
|
|
3020 |
addAttrs('img', 'loading');
|
| 1441 |
ariadna |
3021 |
addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading referrerpolicy');
|
| 1 |
efrain |
3022 |
}
|
|
|
3023 |
if (type !== 'html4') {
|
|
|
3024 |
each$e([
|
|
|
3025 |
schema.video,
|
|
|
3026 |
schema.audio
|
|
|
3027 |
], item => {
|
|
|
3028 |
delete item.children.audio;
|
|
|
3029 |
delete item.children.video;
|
|
|
3030 |
});
|
|
|
3031 |
}
|
|
|
3032 |
each$e(split$1('a form meter progress dfn'), name => {
|
|
|
3033 |
if (schema[name]) {
|
|
|
3034 |
delete schema[name].children[name];
|
|
|
3035 |
}
|
|
|
3036 |
});
|
|
|
3037 |
delete schema.caption.children.table;
|
|
|
3038 |
delete schema.script;
|
|
|
3039 |
return schema;
|
|
|
3040 |
};
|
|
|
3041 |
|
|
|
3042 |
const prefixToOperation = prefix => prefix === '-' ? 'remove' : 'add';
|
| 1441 |
ariadna |
3043 |
const parseValidChild = name => {
|
|
|
3044 |
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]+)$/;
|
|
|
3045 |
return Optional.from(validChildRegExp.exec(name)).map(matches => ({
|
|
|
3046 |
preset: matches[1] === '@',
|
|
|
3047 |
name: matches[2]
|
|
|
3048 |
}));
|
|
|
3049 |
};
|
| 1 |
efrain |
3050 |
const parseValidChildrenRules = value => {
|
|
|
3051 |
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]+)\[([^\]]+)]$/;
|
|
|
3052 |
return bind$3(split$1(value, ','), rule => {
|
|
|
3053 |
const matches = childRuleRegExp.exec(rule);
|
|
|
3054 |
if (matches) {
|
|
|
3055 |
const prefix = matches[1];
|
|
|
3056 |
const operation = prefix ? prefixToOperation(prefix) : 'replace';
|
|
|
3057 |
const name = matches[2];
|
| 1441 |
ariadna |
3058 |
const validChildren = bind$3(split$1(matches[3], '|'), validChild => parseValidChild(validChild).toArray());
|
| 1 |
efrain |
3059 |
return [{
|
|
|
3060 |
operation,
|
|
|
3061 |
name,
|
|
|
3062 |
validChildren
|
|
|
3063 |
}];
|
|
|
3064 |
} else {
|
|
|
3065 |
return [];
|
|
|
3066 |
}
|
|
|
3067 |
});
|
|
|
3068 |
};
|
|
|
3069 |
|
|
|
3070 |
const parseValidElementsAttrDataIntoElement = (attrData, targetElement) => {
|
|
|
3071 |
const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/;
|
|
|
3072 |
const hasPatternsRegExp = /[*?+]/;
|
|
|
3073 |
const {attributes, attributesOrder} = targetElement;
|
|
|
3074 |
return each$e(split$1(attrData, '|'), rule => {
|
|
|
3075 |
const matches = attrRuleRegExp.exec(rule);
|
|
|
3076 |
if (matches) {
|
|
|
3077 |
const attr = {};
|
|
|
3078 |
const attrType = matches[1];
|
|
|
3079 |
const attrName = matches[2].replace(/[\\:]:/g, ':');
|
|
|
3080 |
const attrPrefix = matches[3];
|
|
|
3081 |
const value = matches[4];
|
|
|
3082 |
if (attrType === '!') {
|
|
|
3083 |
targetElement.attributesRequired = targetElement.attributesRequired || [];
|
|
|
3084 |
targetElement.attributesRequired.push(attrName);
|
|
|
3085 |
attr.required = true;
|
|
|
3086 |
}
|
|
|
3087 |
if (attrType === '-') {
|
|
|
3088 |
delete attributes[attrName];
|
|
|
3089 |
attributesOrder.splice(Tools.inArray(attributesOrder, attrName), 1);
|
|
|
3090 |
return;
|
|
|
3091 |
}
|
|
|
3092 |
if (attrPrefix) {
|
|
|
3093 |
if (attrPrefix === '=') {
|
|
|
3094 |
targetElement.attributesDefault = targetElement.attributesDefault || [];
|
|
|
3095 |
targetElement.attributesDefault.push({
|
|
|
3096 |
name: attrName,
|
|
|
3097 |
value
|
|
|
3098 |
});
|
|
|
3099 |
attr.defaultValue = value;
|
|
|
3100 |
} else if (attrPrefix === '~') {
|
|
|
3101 |
targetElement.attributesForced = targetElement.attributesForced || [];
|
|
|
3102 |
targetElement.attributesForced.push({
|
|
|
3103 |
name: attrName,
|
|
|
3104 |
value
|
|
|
3105 |
});
|
|
|
3106 |
attr.forcedValue = value;
|
|
|
3107 |
} else if (attrPrefix === '<') {
|
|
|
3108 |
attr.validValues = Tools.makeMap(value, '?');
|
|
|
3109 |
}
|
|
|
3110 |
}
|
|
|
3111 |
if (hasPatternsRegExp.test(attrName)) {
|
|
|
3112 |
const attrPattern = attr;
|
|
|
3113 |
targetElement.attributePatterns = targetElement.attributePatterns || [];
|
|
|
3114 |
attrPattern.pattern = patternToRegExp(attrName);
|
|
|
3115 |
targetElement.attributePatterns.push(attrPattern);
|
|
|
3116 |
} else {
|
|
|
3117 |
if (!attributes[attrName]) {
|
|
|
3118 |
attributesOrder.push(attrName);
|
|
|
3119 |
}
|
|
|
3120 |
attributes[attrName] = attr;
|
|
|
3121 |
}
|
|
|
3122 |
}
|
|
|
3123 |
});
|
|
|
3124 |
};
|
|
|
3125 |
const cloneAttributesInto = (from, to) => {
|
|
|
3126 |
each$d(from.attributes, (value, key) => {
|
|
|
3127 |
to.attributes[key] = value;
|
|
|
3128 |
});
|
|
|
3129 |
to.attributesOrder.push(...from.attributesOrder);
|
|
|
3130 |
};
|
|
|
3131 |
const parseValidElementsRules = (globalElement, validElements) => {
|
|
|
3132 |
const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;
|
|
|
3133 |
return bind$3(split$1(validElements, ','), rule => {
|
|
|
3134 |
const matches = elementRuleRegExp.exec(rule);
|
|
|
3135 |
if (matches) {
|
|
|
3136 |
const prefix = matches[1];
|
|
|
3137 |
const elementName = matches[2];
|
|
|
3138 |
const outputName = matches[3];
|
|
|
3139 |
const attrsPrefix = matches[4];
|
|
|
3140 |
const attrData = matches[5];
|
|
|
3141 |
const element = {
|
|
|
3142 |
attributes: {},
|
|
|
3143 |
attributesOrder: []
|
|
|
3144 |
};
|
|
|
3145 |
globalElement.each(el => cloneAttributesInto(el, element));
|
|
|
3146 |
if (prefix === '#') {
|
|
|
3147 |
element.paddEmpty = true;
|
|
|
3148 |
} else if (prefix === '-') {
|
|
|
3149 |
element.removeEmpty = true;
|
|
|
3150 |
}
|
|
|
3151 |
if (attrsPrefix === '!') {
|
|
|
3152 |
element.removeEmptyAttrs = true;
|
|
|
3153 |
}
|
|
|
3154 |
if (attrData) {
|
|
|
3155 |
parseValidElementsAttrDataIntoElement(attrData, element);
|
|
|
3156 |
}
|
|
|
3157 |
if (outputName) {
|
|
|
3158 |
element.outputName = elementName;
|
|
|
3159 |
}
|
|
|
3160 |
if (elementName === '@') {
|
|
|
3161 |
if (globalElement.isNone()) {
|
|
|
3162 |
globalElement = Optional.some(element);
|
|
|
3163 |
} else {
|
|
|
3164 |
return [];
|
|
|
3165 |
}
|
|
|
3166 |
}
|
|
|
3167 |
return [outputName ? {
|
|
|
3168 |
name: elementName,
|
|
|
3169 |
element,
|
|
|
3170 |
aliasName: outputName
|
|
|
3171 |
} : {
|
|
|
3172 |
name: elementName,
|
|
|
3173 |
element
|
|
|
3174 |
}];
|
|
|
3175 |
} else {
|
|
|
3176 |
return [];
|
|
|
3177 |
}
|
|
|
3178 |
});
|
|
|
3179 |
};
|
|
|
3180 |
|
|
|
3181 |
const mapCache = {};
|
|
|
3182 |
const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode;
|
|
|
3183 |
const createMap = (defaultValue, extendWith = {}) => {
|
|
|
3184 |
const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
|
|
|
3185 |
return extend$2(value, extendWith);
|
|
|
3186 |
};
|
|
|
3187 |
const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements());
|
|
|
3188 |
const compileElementMap = (value, mode) => {
|
|
|
3189 |
if (value) {
|
|
|
3190 |
const styles = {};
|
|
|
3191 |
if (isString(value)) {
|
|
|
3192 |
value = { '*': value };
|
|
|
3193 |
}
|
|
|
3194 |
each$b(value, (value, key) => {
|
|
|
3195 |
styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/);
|
|
|
3196 |
});
|
|
|
3197 |
return styles;
|
|
|
3198 |
} else {
|
|
|
3199 |
return undefined;
|
|
|
3200 |
}
|
|
|
3201 |
};
|
|
|
3202 |
const Schema = (settings = {}) => {
|
|
|
3203 |
var _a;
|
|
|
3204 |
const elements = {};
|
|
|
3205 |
const children = {};
|
|
|
3206 |
let patternElements = [];
|
|
|
3207 |
const customElementsMap = {};
|
|
|
3208 |
const specialElements = {};
|
|
|
3209 |
const createLookupTable = (option, defaultValue, extendWith) => {
|
|
|
3210 |
const value = settings[option];
|
|
|
3211 |
if (!value) {
|
|
|
3212 |
let newValue = mapCache[option];
|
|
|
3213 |
if (!newValue) {
|
|
|
3214 |
newValue = createMap(defaultValue, extendWith);
|
|
|
3215 |
mapCache[option] = newValue;
|
|
|
3216 |
}
|
|
|
3217 |
return newValue;
|
|
|
3218 |
} else {
|
|
|
3219 |
return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
|
|
|
3220 |
}
|
|
|
3221 |
};
|
|
|
3222 |
const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5';
|
|
|
3223 |
const schemaItems = makeSchema(schemaType);
|
|
|
3224 |
if (settings.verify_html === false) {
|
|
|
3225 |
settings.valid_elements = '*[*]';
|
|
|
3226 |
}
|
|
|
3227 |
const validStyles = compileElementMap(settings.valid_styles);
|
|
|
3228 |
const invalidStyles = compileElementMap(settings.invalid_styles, 'map');
|
|
|
3229 |
const validClasses = compileElementMap(settings.valid_classes, 'map');
|
|
|
3230 |
const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
|
|
|
3231 |
const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
|
|
|
3232 |
const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
|
|
|
3233 |
const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen');
|
|
|
3234 |
const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code';
|
| 1441 |
ariadna |
3235 |
const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre svg textarea summary', voidElementsMap);
|
| 1 |
efrain |
3236 |
const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap);
|
|
|
3237 |
const headings = 'h1 h2 h3 h4 h5 h6';
|
|
|
3238 |
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');
|
|
|
3239 |
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);
|
|
|
3240 |
const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp');
|
|
|
3241 |
const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map');
|
|
|
3242 |
const wrapBlockElementsMap = createLookupTable('wrap_block_elements', 'pre ' + headings);
|
|
|
3243 |
each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => {
|
|
|
3244 |
specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
|
|
|
3245 |
});
|
|
|
3246 |
const addValidElements = validElements => {
|
|
|
3247 |
const globalElement = Optional.from(elements['@']);
|
|
|
3248 |
const hasPatternsRegExp = /[*?+]/;
|
|
|
3249 |
each$e(parseValidElementsRules(globalElement, validElements !== null && validElements !== void 0 ? validElements : ''), ({name, element, aliasName}) => {
|
|
|
3250 |
if (aliasName) {
|
|
|
3251 |
elements[aliasName] = element;
|
|
|
3252 |
}
|
|
|
3253 |
if (hasPatternsRegExp.test(name)) {
|
|
|
3254 |
const patternElement = element;
|
|
|
3255 |
patternElement.pattern = patternToRegExp(name);
|
|
|
3256 |
patternElements.push(patternElement);
|
|
|
3257 |
} else {
|
|
|
3258 |
elements[name] = element;
|
|
|
3259 |
}
|
|
|
3260 |
});
|
|
|
3261 |
};
|
|
|
3262 |
const setValidElements = validElements => {
|
|
|
3263 |
patternElements = [];
|
|
|
3264 |
each$e(keys(elements), name => {
|
|
|
3265 |
delete elements[name];
|
|
|
3266 |
});
|
|
|
3267 |
addValidElements(validElements);
|
|
|
3268 |
};
|
| 1441 |
ariadna |
3269 |
const addCustomElement = (name, spec) => {
|
|
|
3270 |
var _a, _b;
|
| 1 |
efrain |
3271 |
delete mapCache.text_block_elements;
|
|
|
3272 |
delete mapCache.block_elements;
|
| 1441 |
ariadna |
3273 |
const inline = spec.extends ? !isBlock(spec.extends) : false;
|
|
|
3274 |
const cloneName = spec.extends;
|
|
|
3275 |
children[name] = cloneName ? children[cloneName] : {};
|
|
|
3276 |
customElementsMap[name] = cloneName !== null && cloneName !== void 0 ? cloneName : name;
|
|
|
3277 |
nonEmptyElementsMap[name.toUpperCase()] = {};
|
|
|
3278 |
nonEmptyElementsMap[name] = {};
|
|
|
3279 |
if (!inline) {
|
|
|
3280 |
blockElementsMap[name.toUpperCase()] = {};
|
|
|
3281 |
blockElementsMap[name] = {};
|
|
|
3282 |
}
|
|
|
3283 |
if (cloneName && !elements[name] && elements[cloneName]) {
|
|
|
3284 |
const customRule = deepCloneElementRule(elements[cloneName]);
|
|
|
3285 |
delete customRule.removeEmptyAttrs;
|
|
|
3286 |
delete customRule.removeEmpty;
|
|
|
3287 |
elements[name] = customRule;
|
|
|
3288 |
} else {
|
|
|
3289 |
elements[name] = {
|
|
|
3290 |
attributesOrder: [],
|
|
|
3291 |
attributes: {}
|
|
|
3292 |
};
|
|
|
3293 |
}
|
|
|
3294 |
if (isArray$1(spec.attributes)) {
|
|
|
3295 |
const processAttrName = name => {
|
|
|
3296 |
customRule.attributesOrder.push(name);
|
|
|
3297 |
customRule.attributes[name] = {};
|
|
|
3298 |
};
|
|
|
3299 |
const customRule = (_a = elements[name]) !== null && _a !== void 0 ? _a : {};
|
|
|
3300 |
delete customRule.attributesDefault;
|
|
|
3301 |
delete customRule.attributesForced;
|
|
|
3302 |
delete customRule.attributePatterns;
|
|
|
3303 |
delete customRule.attributesRequired;
|
|
|
3304 |
customRule.attributesOrder = [];
|
|
|
3305 |
customRule.attributes = {};
|
|
|
3306 |
each$e(spec.attributes, attrName => {
|
|
|
3307 |
const globalAttrs = getGlobalAttributeSet(schemaType);
|
|
|
3308 |
parseValidChild(attrName).each(({preset, name}) => {
|
|
|
3309 |
if (preset) {
|
|
|
3310 |
if (name === 'global') {
|
|
|
3311 |
each$e(globalAttrs, processAttrName);
|
|
|
3312 |
}
|
|
|
3313 |
} else {
|
|
|
3314 |
processAttrName(name);
|
|
|
3315 |
}
|
|
|
3316 |
});
|
|
|
3317 |
});
|
|
|
3318 |
elements[name] = customRule;
|
|
|
3319 |
}
|
|
|
3320 |
if (isBoolean(spec.padEmpty)) {
|
|
|
3321 |
const customRule = (_b = elements[name]) !== null && _b !== void 0 ? _b : {};
|
|
|
3322 |
customRule.paddEmpty = spec.padEmpty;
|
|
|
3323 |
elements[name] = customRule;
|
|
|
3324 |
}
|
|
|
3325 |
if (isArray$1(spec.children)) {
|
|
|
3326 |
const customElementChildren = {};
|
|
|
3327 |
const processNodeName = name => {
|
|
|
3328 |
customElementChildren[name] = {};
|
|
|
3329 |
};
|
|
|
3330 |
const processPreset = name => {
|
|
|
3331 |
getElementsPreset(schemaType, name).each(names => {
|
|
|
3332 |
each$e(names, processNodeName);
|
|
|
3333 |
});
|
|
|
3334 |
};
|
|
|
3335 |
each$e(spec.children, child => {
|
|
|
3336 |
parseValidChild(child).each(({preset, name}) => {
|
|
|
3337 |
if (preset) {
|
|
|
3338 |
processPreset(name);
|
|
|
3339 |
} else {
|
|
|
3340 |
processNodeName(name);
|
|
|
3341 |
}
|
|
|
3342 |
});
|
|
|
3343 |
});
|
|
|
3344 |
children[name] = customElementChildren;
|
|
|
3345 |
}
|
|
|
3346 |
if (cloneName) {
|
| 1 |
efrain |
3347 |
each$d(children, (element, elmName) => {
|
|
|
3348 |
if (element[cloneName]) {
|
|
|
3349 |
children[elmName] = element = extend$2({}, children[elmName]);
|
|
|
3350 |
element[name] = element[cloneName];
|
|
|
3351 |
}
|
|
|
3352 |
});
|
| 1441 |
ariadna |
3353 |
}
|
|
|
3354 |
};
|
|
|
3355 |
const addCustomElementsFromString = customElements => {
|
|
|
3356 |
each$e(parseCustomElementsRules(customElements !== null && customElements !== void 0 ? customElements : ''), ({name, cloneName}) => {
|
|
|
3357 |
addCustomElement(name, { extends: cloneName });
|
| 1 |
efrain |
3358 |
});
|
|
|
3359 |
};
|
| 1441 |
ariadna |
3360 |
const addCustomElements = customElements => {
|
|
|
3361 |
if (isObject(customElements)) {
|
|
|
3362 |
each$d(customElements, (spec, name) => addCustomElement(name, spec));
|
|
|
3363 |
} else if (isString(customElements)) {
|
|
|
3364 |
addCustomElementsFromString(customElements);
|
|
|
3365 |
}
|
|
|
3366 |
};
|
| 1 |
efrain |
3367 |
const addValidChildren = validChildren => {
|
|
|
3368 |
each$e(parseValidChildrenRules(validChildren !== null && validChildren !== void 0 ? validChildren : ''), ({operation, name, validChildren}) => {
|
|
|
3369 |
const parent = operation === 'replace' ? { '#comment': {} } : children[name];
|
| 1441 |
ariadna |
3370 |
const processNodeName = name => {
|
| 1 |
efrain |
3371 |
if (operation === 'remove') {
|
| 1441 |
ariadna |
3372 |
delete parent[name];
|
| 1 |
efrain |
3373 |
} else {
|
| 1441 |
ariadna |
3374 |
parent[name] = {};
|
| 1 |
efrain |
3375 |
}
|
| 1441 |
ariadna |
3376 |
};
|
|
|
3377 |
const processPreset = name => {
|
|
|
3378 |
getElementsPreset(schemaType, name).each(names => {
|
|
|
3379 |
each$e(names, processNodeName);
|
|
|
3380 |
});
|
|
|
3381 |
};
|
|
|
3382 |
each$e(validChildren, ({preset, name}) => {
|
|
|
3383 |
if (preset) {
|
|
|
3384 |
processPreset(name);
|
|
|
3385 |
} else {
|
|
|
3386 |
processNodeName(name);
|
|
|
3387 |
}
|
| 1 |
efrain |
3388 |
});
|
|
|
3389 |
children[name] = parent;
|
|
|
3390 |
});
|
|
|
3391 |
};
|
|
|
3392 |
const getElementRule = name => {
|
|
|
3393 |
const element = elements[name];
|
|
|
3394 |
if (element) {
|
|
|
3395 |
return element;
|
|
|
3396 |
}
|
|
|
3397 |
let i = patternElements.length;
|
|
|
3398 |
while (i--) {
|
|
|
3399 |
const patternElement = patternElements[i];
|
|
|
3400 |
if (patternElement.pattern.test(name)) {
|
|
|
3401 |
return patternElement;
|
|
|
3402 |
}
|
|
|
3403 |
}
|
|
|
3404 |
return undefined;
|
|
|
3405 |
};
|
| 1441 |
ariadna |
3406 |
const setup = () => {
|
|
|
3407 |
if (!settings.valid_elements) {
|
|
|
3408 |
each$b(schemaItems, (element, name) => {
|
|
|
3409 |
elements[name] = {
|
|
|
3410 |
attributes: element.attributes,
|
|
|
3411 |
attributesOrder: element.attributesOrder
|
|
|
3412 |
};
|
|
|
3413 |
children[name] = element.children;
|
|
|
3414 |
});
|
|
|
3415 |
each$b(split$1('strong/b em/i'), item => {
|
|
|
3416 |
const items = split$1(item, '/');
|
|
|
3417 |
elements[items[1]].outputName = items[0];
|
|
|
3418 |
});
|
|
|
3419 |
each$b(textInlineElementsMap, (_val, name) => {
|
|
|
3420 |
if (elements[name]) {
|
|
|
3421 |
if (settings.padd_empty_block_inline_children) {
|
|
|
3422 |
elements[name].paddInEmptyBlock = true;
|
|
|
3423 |
}
|
|
|
3424 |
elements[name].removeEmpty = true;
|
| 1 |
efrain |
3425 |
}
|
| 1441 |
ariadna |
3426 |
});
|
|
|
3427 |
each$b(split$1('ol ul blockquote a table tbody'), name => {
|
|
|
3428 |
if (elements[name]) {
|
|
|
3429 |
elements[name].removeEmpty = true;
|
|
|
3430 |
}
|
|
|
3431 |
});
|
|
|
3432 |
each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary'), name => {
|
|
|
3433 |
if (elements[name]) {
|
|
|
3434 |
elements[name].paddEmpty = true;
|
|
|
3435 |
}
|
|
|
3436 |
});
|
|
|
3437 |
each$b(split$1('span'), name => {
|
|
|
3438 |
elements[name].removeEmptyAttrs = true;
|
|
|
3439 |
});
|
|
|
3440 |
} else {
|
|
|
3441 |
setValidElements(settings.valid_elements);
|
|
|
3442 |
each$b(schemaItems, (element, name) => {
|
|
|
3443 |
children[name] = element.children;
|
|
|
3444 |
});
|
| 1 |
efrain |
3445 |
}
|
| 1441 |
ariadna |
3446 |
delete elements.svg;
|
|
|
3447 |
addCustomElements(settings.custom_elements);
|
|
|
3448 |
addValidChildren(settings.valid_children);
|
|
|
3449 |
addValidElements(settings.extended_valid_elements);
|
|
|
3450 |
addValidChildren('+ol[ul|ol],+ul[ul|ol]');
|
|
|
3451 |
each$b({
|
|
|
3452 |
dd: 'dl',
|
|
|
3453 |
dt: 'dl',
|
|
|
3454 |
li: 'ul ol',
|
|
|
3455 |
td: 'tr',
|
|
|
3456 |
th: 'tr',
|
|
|
3457 |
tr: 'tbody thead tfoot',
|
|
|
3458 |
tbody: 'table',
|
|
|
3459 |
thead: 'table',
|
|
|
3460 |
tfoot: 'table',
|
|
|
3461 |
legend: 'fieldset',
|
|
|
3462 |
area: 'map',
|
|
|
3463 |
param: 'video audio object'
|
|
|
3464 |
}, (parents, item) => {
|
| 1 |
efrain |
3465 |
if (elements[item]) {
|
| 1441 |
ariadna |
3466 |
elements[item].parentsRequired = split$1(parents);
|
| 1 |
efrain |
3467 |
}
|
|
|
3468 |
});
|
| 1441 |
ariadna |
3469 |
if (settings.invalid_elements) {
|
|
|
3470 |
each$b(explode$2(settings.invalid_elements), item => {
|
|
|
3471 |
if (elements[item]) {
|
|
|
3472 |
delete elements[item];
|
|
|
3473 |
}
|
|
|
3474 |
});
|
|
|
3475 |
}
|
|
|
3476 |
if (!getElementRule('span')) {
|
|
|
3477 |
addValidElements('span[!data-mce-type|*]');
|
|
|
3478 |
}
|
|
|
3479 |
};
|
| 1 |
efrain |
3480 |
const getValidStyles = constant(validStyles);
|
|
|
3481 |
const getInvalidStyles = constant(invalidStyles);
|
|
|
3482 |
const getValidClasses = constant(validClasses);
|
|
|
3483 |
const getBoolAttrs = constant(boolAttrMap);
|
|
|
3484 |
const getBlockElements = constant(blockElementsMap);
|
|
|
3485 |
const getTextBlockElements = constant(textBlockElementsMap);
|
|
|
3486 |
const getTextInlineElements = constant(textInlineElementsMap);
|
|
|
3487 |
const getVoidElements = constant(Object.seal(voidElementsMap));
|
|
|
3488 |
const getSelfClosingElements = constant(selfClosingElementsMap);
|
|
|
3489 |
const getNonEmptyElements = constant(nonEmptyElementsMap);
|
|
|
3490 |
const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
|
|
|
3491 |
const getWhitespaceElements = constant(whitespaceElementsMap);
|
|
|
3492 |
const getTransparentElements = constant(transparentElementsMap);
|
|
|
3493 |
const getWrapBlockElements = constant(wrapBlockElementsMap);
|
|
|
3494 |
const getSpecialElements = constant(Object.seal(specialElements));
|
|
|
3495 |
const isValidChild = (name, child) => {
|
|
|
3496 |
const parent = children[name.toLowerCase()];
|
|
|
3497 |
return !!(parent && parent[child.toLowerCase()]);
|
|
|
3498 |
};
|
|
|
3499 |
const isValid = (name, attr) => {
|
|
|
3500 |
const rule = getElementRule(name);
|
|
|
3501 |
if (rule) {
|
|
|
3502 |
if (attr) {
|
|
|
3503 |
if (rule.attributes[attr]) {
|
|
|
3504 |
return true;
|
|
|
3505 |
}
|
|
|
3506 |
const attrPatterns = rule.attributePatterns;
|
|
|
3507 |
if (attrPatterns) {
|
|
|
3508 |
let i = attrPatterns.length;
|
|
|
3509 |
while (i--) {
|
|
|
3510 |
if (attrPatterns[i].pattern.test(attr)) {
|
|
|
3511 |
return true;
|
|
|
3512 |
}
|
|
|
3513 |
}
|
|
|
3514 |
}
|
|
|
3515 |
} else {
|
|
|
3516 |
return true;
|
|
|
3517 |
}
|
|
|
3518 |
}
|
|
|
3519 |
return false;
|
|
|
3520 |
};
|
|
|
3521 |
const isBlock = name => has$2(getBlockElements(), name);
|
|
|
3522 |
const isInline = name => !startsWith(name, '#') && isValid(name) && !isBlock(name);
|
|
|
3523 |
const isWrapper = name => has$2(getWrapBlockElements(), name) || isInline(name);
|
|
|
3524 |
const getCustomElements = constant(customElementsMap);
|
| 1441 |
ariadna |
3525 |
setup();
|
| 1 |
efrain |
3526 |
return {
|
|
|
3527 |
type: schemaType,
|
|
|
3528 |
children,
|
|
|
3529 |
elements,
|
|
|
3530 |
getValidStyles,
|
|
|
3531 |
getValidClasses,
|
|
|
3532 |
getBlockElements,
|
|
|
3533 |
getInvalidStyles,
|
|
|
3534 |
getVoidElements,
|
|
|
3535 |
getTextBlockElements,
|
|
|
3536 |
getTextInlineElements,
|
|
|
3537 |
getBoolAttrs,
|
|
|
3538 |
getElementRule,
|
|
|
3539 |
getSelfClosingElements,
|
|
|
3540 |
getNonEmptyElements,
|
|
|
3541 |
getMoveCaretBeforeOnEnterElements,
|
|
|
3542 |
getWhitespaceElements,
|
|
|
3543 |
getTransparentElements,
|
|
|
3544 |
getSpecialElements,
|
|
|
3545 |
isValidChild,
|
|
|
3546 |
isValid,
|
|
|
3547 |
isBlock,
|
|
|
3548 |
isInline,
|
|
|
3549 |
isWrapper,
|
|
|
3550 |
getCustomElements,
|
|
|
3551 |
addValidElements,
|
|
|
3552 |
setValidElements,
|
|
|
3553 |
addCustomElements,
|
|
|
3554 |
addValidChildren
|
|
|
3555 |
};
|
|
|
3556 |
};
|
|
|
3557 |
|
|
|
3558 |
const hexColour = value => ({ value: normalizeHex(value) });
|
|
|
3559 |
const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
|
|
|
3560 |
const toHex = component => {
|
|
|
3561 |
const hex = component.toString(16);
|
|
|
3562 |
return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
|
|
|
3563 |
};
|
|
|
3564 |
const fromRgba = rgbaColour => {
|
|
|
3565 |
const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
|
|
|
3566 |
return hexColour(value);
|
|
|
3567 |
};
|
|
|
3568 |
|
| 1441 |
ariadna |
3569 |
const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i;
|
|
|
3570 |
const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*((?:\d?\.\d+|\d+)%?)\s*\)\s*$/i;
|
| 1 |
efrain |
3571 |
const rgbaColour = (red, green, blue, alpha) => ({
|
|
|
3572 |
red,
|
|
|
3573 |
green,
|
|
|
3574 |
blue,
|
|
|
3575 |
alpha
|
|
|
3576 |
});
|
|
|
3577 |
const fromStringValues = (red, green, blue, alpha) => {
|
|
|
3578 |
const r = parseInt(red, 10);
|
|
|
3579 |
const g = parseInt(green, 10);
|
|
|
3580 |
const b = parseInt(blue, 10);
|
|
|
3581 |
const a = parseFloat(alpha);
|
|
|
3582 |
return rgbaColour(r, g, b, a);
|
|
|
3583 |
};
|
| 1441 |
ariadna |
3584 |
const getColorFormat = colorString => {
|
|
|
3585 |
if (rgbRegex.test(colorString)) {
|
|
|
3586 |
return 'rgb';
|
|
|
3587 |
} else if (rgbaRegex.test(colorString)) {
|
|
|
3588 |
return 'rgba';
|
|
|
3589 |
}
|
|
|
3590 |
return 'other';
|
|
|
3591 |
};
|
| 1 |
efrain |
3592 |
const fromString = rgbaString => {
|
|
|
3593 |
const rgbMatch = rgbRegex.exec(rgbaString);
|
|
|
3594 |
if (rgbMatch !== null) {
|
|
|
3595 |
return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
|
|
|
3596 |
}
|
|
|
3597 |
const rgbaMatch = rgbaRegex.exec(rgbaString);
|
|
|
3598 |
if (rgbaMatch !== null) {
|
|
|
3599 |
return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
|
|
|
3600 |
}
|
|
|
3601 |
return Optional.none();
|
|
|
3602 |
};
|
|
|
3603 |
const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
|
|
|
3604 |
|
|
|
3605 |
const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
|
|
|
3606 |
|
|
|
3607 |
const Styles = (settings = {}, schema) => {
|
|
|
3608 |
const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
|
|
|
3609 |
const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
|
|
|
3610 |
const trimRightRegExp = /\s+$/;
|
|
|
3611 |
const encodingLookup = {};
|
|
|
3612 |
let validStyles;
|
|
|
3613 |
let invalidStyles;
|
|
|
3614 |
const invisibleChar = zeroWidth;
|
|
|
3615 |
if (schema) {
|
|
|
3616 |
validStyles = schema.getValidStyles();
|
|
|
3617 |
invalidStyles = schema.getInvalidStyles();
|
|
|
3618 |
}
|
|
|
3619 |
const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' ');
|
|
|
3620 |
for (let i = 0; i < encodingItems.length; i++) {
|
|
|
3621 |
encodingLookup[encodingItems[i]] = invisibleChar + i;
|
|
|
3622 |
encodingLookup[invisibleChar + i] = encodingItems[i];
|
|
|
3623 |
}
|
|
|
3624 |
const self = {
|
|
|
3625 |
parse: css => {
|
|
|
3626 |
const styles = {};
|
|
|
3627 |
let isEncoded = false;
|
|
|
3628 |
const urlConverter = settings.url_converter;
|
|
|
3629 |
const urlConverterScope = settings.url_converter_scope || self;
|
|
|
3630 |
const compress = (prefix, suffix, noJoin) => {
|
|
|
3631 |
const top = styles[prefix + '-top' + suffix];
|
|
|
3632 |
if (!top) {
|
|
|
3633 |
return;
|
|
|
3634 |
}
|
|
|
3635 |
const right = styles[prefix + '-right' + suffix];
|
|
|
3636 |
if (!right) {
|
|
|
3637 |
return;
|
|
|
3638 |
}
|
|
|
3639 |
const bottom = styles[prefix + '-bottom' + suffix];
|
|
|
3640 |
if (!bottom) {
|
|
|
3641 |
return;
|
|
|
3642 |
}
|
|
|
3643 |
const left = styles[prefix + '-left' + suffix];
|
|
|
3644 |
if (!left) {
|
|
|
3645 |
return;
|
|
|
3646 |
}
|
|
|
3647 |
const box = [
|
|
|
3648 |
top,
|
|
|
3649 |
right,
|
|
|
3650 |
bottom,
|
|
|
3651 |
left
|
|
|
3652 |
];
|
|
|
3653 |
let i = box.length - 1;
|
|
|
3654 |
while (i--) {
|
|
|
3655 |
if (box[i] !== box[i + 1]) {
|
|
|
3656 |
break;
|
|
|
3657 |
}
|
|
|
3658 |
}
|
|
|
3659 |
if (i > -1 && noJoin) {
|
|
|
3660 |
return;
|
|
|
3661 |
}
|
|
|
3662 |
styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
|
|
|
3663 |
delete styles[prefix + '-top' + suffix];
|
|
|
3664 |
delete styles[prefix + '-right' + suffix];
|
|
|
3665 |
delete styles[prefix + '-bottom' + suffix];
|
|
|
3666 |
delete styles[prefix + '-left' + suffix];
|
|
|
3667 |
};
|
|
|
3668 |
const canCompress = key => {
|
|
|
3669 |
const value = styles[key];
|
|
|
3670 |
if (!value) {
|
|
|
3671 |
return;
|
|
|
3672 |
}
|
|
|
3673 |
const values = value.indexOf(',') > -1 ? [value] : value.split(' ');
|
|
|
3674 |
let i = values.length;
|
|
|
3675 |
while (i--) {
|
|
|
3676 |
if (values[i] !== values[0]) {
|
|
|
3677 |
return false;
|
|
|
3678 |
}
|
|
|
3679 |
}
|
|
|
3680 |
styles[key] = values[0];
|
|
|
3681 |
return true;
|
|
|
3682 |
};
|
|
|
3683 |
const compress2 = (target, a, b, c) => {
|
|
|
3684 |
if (!canCompress(a)) {
|
|
|
3685 |
return;
|
|
|
3686 |
}
|
|
|
3687 |
if (!canCompress(b)) {
|
|
|
3688 |
return;
|
|
|
3689 |
}
|
|
|
3690 |
if (!canCompress(c)) {
|
|
|
3691 |
return;
|
|
|
3692 |
}
|
|
|
3693 |
styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
|
|
|
3694 |
delete styles[a];
|
|
|
3695 |
delete styles[b];
|
|
|
3696 |
delete styles[c];
|
|
|
3697 |
};
|
|
|
3698 |
const encode = str => {
|
|
|
3699 |
isEncoded = true;
|
|
|
3700 |
return encodingLookup[str];
|
|
|
3701 |
};
|
|
|
3702 |
const decode = (str, keepSlashes) => {
|
|
|
3703 |
if (isEncoded) {
|
|
|
3704 |
str = str.replace(/\uFEFF[0-9]/g, str => {
|
|
|
3705 |
return encodingLookup[str];
|
|
|
3706 |
});
|
|
|
3707 |
}
|
|
|
3708 |
if (!keepSlashes) {
|
|
|
3709 |
str = str.replace(/\\([\'\";:])/g, '$1');
|
|
|
3710 |
}
|
|
|
3711 |
return str;
|
|
|
3712 |
};
|
|
|
3713 |
const decodeSingleHexSequence = escSeq => {
|
|
|
3714 |
return String.fromCharCode(parseInt(escSeq.slice(1), 16));
|
|
|
3715 |
};
|
|
|
3716 |
const decodeHexSequences = value => {
|
|
|
3717 |
return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
|
|
|
3718 |
};
|
|
|
3719 |
const processUrl = (match, url, url2, url3, str, str2) => {
|
|
|
3720 |
str = str || str2;
|
|
|
3721 |
if (str) {
|
|
|
3722 |
str = decode(str);
|
|
|
3723 |
return `'` + str.replace(/\'/g, `\\'`) + `'`;
|
|
|
3724 |
}
|
|
|
3725 |
url = decode(url || url2 || url3 || '');
|
|
|
3726 |
if (!settings.allow_script_urls) {
|
|
|
3727 |
const scriptUrl = url.replace(/[\s\r\n]+/g, '');
|
|
|
3728 |
if (/(java|vb)script:/i.test(scriptUrl)) {
|
|
|
3729 |
return '';
|
|
|
3730 |
}
|
|
|
3731 |
if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
|
|
|
3732 |
return '';
|
|
|
3733 |
}
|
|
|
3734 |
}
|
|
|
3735 |
if (urlConverter) {
|
|
|
3736 |
url = urlConverter.call(urlConverterScope, url, 'style');
|
|
|
3737 |
}
|
|
|
3738 |
return `url('` + url.replace(/\'/g, `\\'`) + `')`;
|
|
|
3739 |
};
|
|
|
3740 |
if (css) {
|
|
|
3741 |
css = css.replace(/[\u0000-\u001F]/g, '');
|
|
|
3742 |
css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => {
|
|
|
3743 |
return str.replace(/[;:]/g, encode);
|
|
|
3744 |
});
|
|
|
3745 |
let matches;
|
|
|
3746 |
while (matches = styleRegExp.exec(css)) {
|
|
|
3747 |
styleRegExp.lastIndex = matches.index + matches[0].length;
|
|
|
3748 |
let name = matches[1].replace(trimRightRegExp, '').toLowerCase();
|
|
|
3749 |
let value = matches[2].replace(trimRightRegExp, '');
|
|
|
3750 |
if (name && value) {
|
|
|
3751 |
name = decodeHexSequences(name);
|
|
|
3752 |
value = decodeHexSequences(value);
|
|
|
3753 |
if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
|
|
|
3754 |
continue;
|
|
|
3755 |
}
|
|
|
3756 |
if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
|
|
|
3757 |
continue;
|
|
|
3758 |
}
|
|
|
3759 |
if (name === 'font-weight' && value === '700') {
|
|
|
3760 |
value = 'bold';
|
|
|
3761 |
} else if (name === 'color' || name === 'background-color') {
|
|
|
3762 |
value = value.toLowerCase();
|
|
|
3763 |
}
|
| 1441 |
ariadna |
3764 |
if (getColorFormat(value) === 'rgb') {
|
| 1 |
efrain |
3765 |
fromString(value).each(rgba => {
|
| 1441 |
ariadna |
3766 |
value = rgbaToHexString(toString(rgba)).toLowerCase();
|
| 1 |
efrain |
3767 |
});
|
|
|
3768 |
}
|
|
|
3769 |
value = value.replace(urlOrStrRegExp, processUrl);
|
|
|
3770 |
styles[name] = isEncoded ? decode(value, true) : value;
|
|
|
3771 |
}
|
|
|
3772 |
}
|
|
|
3773 |
compress('border', '', true);
|
|
|
3774 |
compress('border', '-width');
|
|
|
3775 |
compress('border', '-color');
|
|
|
3776 |
compress('border', '-style');
|
|
|
3777 |
compress('padding', '');
|
|
|
3778 |
compress('margin', '');
|
|
|
3779 |
compress2('border', 'border-width', 'border-style', 'border-color');
|
|
|
3780 |
if (styles.border === 'medium none') {
|
|
|
3781 |
delete styles.border;
|
|
|
3782 |
}
|
|
|
3783 |
if (styles['border-image'] === 'none') {
|
|
|
3784 |
delete styles['border-image'];
|
|
|
3785 |
}
|
|
|
3786 |
}
|
|
|
3787 |
return styles;
|
|
|
3788 |
},
|
|
|
3789 |
serialize: (styles, elementName) => {
|
|
|
3790 |
let css = '';
|
|
|
3791 |
const serializeStyles = (elemName, validStyleList) => {
|
|
|
3792 |
const styleList = validStyleList[elemName];
|
|
|
3793 |
if (styleList) {
|
|
|
3794 |
for (let i = 0, l = styleList.length; i < l; i++) {
|
|
|
3795 |
const name = styleList[i];
|
|
|
3796 |
const value = styles[name];
|
|
|
3797 |
if (value) {
|
|
|
3798 |
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
|
|
3799 |
}
|
|
|
3800 |
}
|
|
|
3801 |
}
|
|
|
3802 |
};
|
|
|
3803 |
const isValid = (name, elemName) => {
|
|
|
3804 |
if (!invalidStyles || !elemName) {
|
|
|
3805 |
return true;
|
|
|
3806 |
}
|
|
|
3807 |
let styleMap = invalidStyles['*'];
|
|
|
3808 |
if (styleMap && styleMap[name]) {
|
|
|
3809 |
return false;
|
|
|
3810 |
}
|
|
|
3811 |
styleMap = invalidStyles[elemName];
|
|
|
3812 |
return !(styleMap && styleMap[name]);
|
|
|
3813 |
};
|
|
|
3814 |
if (elementName && validStyles) {
|
|
|
3815 |
serializeStyles('*', validStyles);
|
|
|
3816 |
serializeStyles(elementName, validStyles);
|
|
|
3817 |
} else {
|
|
|
3818 |
each$d(styles, (value, name) => {
|
|
|
3819 |
if (value && isValid(name, elementName)) {
|
|
|
3820 |
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
|
|
|
3821 |
}
|
|
|
3822 |
});
|
|
|
3823 |
}
|
|
|
3824 |
return css;
|
|
|
3825 |
}
|
|
|
3826 |
};
|
|
|
3827 |
return self;
|
|
|
3828 |
};
|
|
|
3829 |
|
|
|
3830 |
const deprecated = {
|
|
|
3831 |
keyLocation: true,
|
|
|
3832 |
layerX: true,
|
|
|
3833 |
layerY: true,
|
|
|
3834 |
returnValue: true,
|
|
|
3835 |
webkitMovementX: true,
|
|
|
3836 |
webkitMovementY: true,
|
|
|
3837 |
keyIdentifier: true,
|
|
|
3838 |
mozPressure: true
|
|
|
3839 |
};
|
|
|
3840 |
const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent);
|
|
|
3841 |
const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
|
|
|
3842 |
const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event);
|
|
|
3843 |
const clone$3 = (originalEvent, data) => {
|
|
|
3844 |
const event = data !== null && data !== void 0 ? data : {};
|
|
|
3845 |
for (const name in originalEvent) {
|
|
|
3846 |
if (!has$2(deprecated, name)) {
|
|
|
3847 |
event[name] = originalEvent[name];
|
|
|
3848 |
}
|
|
|
3849 |
}
|
|
|
3850 |
if (isNonNullable(originalEvent.composedPath)) {
|
|
|
3851 |
event.composedPath = () => originalEvent.composedPath();
|
|
|
3852 |
}
|
|
|
3853 |
if (isNonNullable(originalEvent.getModifierState)) {
|
|
|
3854 |
event.getModifierState = keyArg => originalEvent.getModifierState(keyArg);
|
|
|
3855 |
}
|
|
|
3856 |
if (isNonNullable(originalEvent.getTargetRanges)) {
|
|
|
3857 |
event.getTargetRanges = () => originalEvent.getTargetRanges();
|
|
|
3858 |
}
|
|
|
3859 |
return event;
|
|
|
3860 |
};
|
|
|
3861 |
const normalize$3 = (type, originalEvent, fallbackTarget, data) => {
|
|
|
3862 |
var _a;
|
|
|
3863 |
const event = clone$3(originalEvent, data);
|
|
|
3864 |
event.type = type;
|
|
|
3865 |
if (isNullable(event.target)) {
|
|
|
3866 |
event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
|
|
|
3867 |
}
|
|
|
3868 |
if (needsNormalizing(originalEvent)) {
|
|
|
3869 |
event.preventDefault = () => {
|
|
|
3870 |
event.defaultPrevented = true;
|
|
|
3871 |
event.isDefaultPrevented = always;
|
|
|
3872 |
if (isFunction(originalEvent.preventDefault)) {
|
|
|
3873 |
originalEvent.preventDefault();
|
|
|
3874 |
}
|
|
|
3875 |
};
|
|
|
3876 |
event.stopPropagation = () => {
|
|
|
3877 |
event.cancelBubble = true;
|
|
|
3878 |
event.isPropagationStopped = always;
|
|
|
3879 |
if (isFunction(originalEvent.stopPropagation)) {
|
|
|
3880 |
originalEvent.stopPropagation();
|
|
|
3881 |
}
|
|
|
3882 |
};
|
|
|
3883 |
event.stopImmediatePropagation = () => {
|
|
|
3884 |
event.isImmediatePropagationStopped = always;
|
|
|
3885 |
event.stopPropagation();
|
|
|
3886 |
};
|
|
|
3887 |
if (!hasIsDefaultPrevented(event)) {
|
|
|
3888 |
event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
|
|
|
3889 |
event.isPropagationStopped = event.cancelBubble === true ? always : never;
|
|
|
3890 |
event.isImmediatePropagationStopped = never;
|
|
|
3891 |
}
|
|
|
3892 |
}
|
|
|
3893 |
return event;
|
|
|
3894 |
};
|
|
|
3895 |
|
|
|
3896 |
const eventExpandoPrefix = 'mce-data-';
|
|
|
3897 |
const mouseEventRe = /^(?:mouse|contextmenu)|click/;
|
|
|
3898 |
const addEvent = (target, name, callback, capture) => {
|
|
|
3899 |
target.addEventListener(name, callback, capture || false);
|
|
|
3900 |
};
|
|
|
3901 |
const removeEvent = (target, name, callback, capture) => {
|
|
|
3902 |
target.removeEventListener(name, callback, capture || false);
|
|
|
3903 |
};
|
|
|
3904 |
const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type);
|
|
|
3905 |
const fix = (originalEvent, data) => {
|
|
|
3906 |
const event = normalize$3(originalEvent.type, originalEvent, document, data);
|
|
|
3907 |
if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
|
|
|
3908 |
const eventDoc = event.target.ownerDocument || document;
|
|
|
3909 |
const doc = eventDoc.documentElement;
|
|
|
3910 |
const body = eventDoc.body;
|
|
|
3911 |
const mouseEvent = event;
|
|
|
3912 |
mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
|
|
|
3913 |
mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
|
|
|
3914 |
}
|
|
|
3915 |
return event;
|
|
|
3916 |
};
|
|
|
3917 |
const bindOnReady = (win, callback, eventUtils) => {
|
|
|
3918 |
const doc = win.document, event = { type: 'ready' };
|
|
|
3919 |
if (eventUtils.domLoaded) {
|
|
|
3920 |
callback(event);
|
|
|
3921 |
return;
|
|
|
3922 |
}
|
|
|
3923 |
const isDocReady = () => {
|
|
|
3924 |
return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
|
|
|
3925 |
};
|
|
|
3926 |
const readyHandler = () => {
|
|
|
3927 |
removeEvent(win, 'DOMContentLoaded', readyHandler);
|
|
|
3928 |
removeEvent(win, 'load', readyHandler);
|
|
|
3929 |
if (!eventUtils.domLoaded) {
|
|
|
3930 |
eventUtils.domLoaded = true;
|
|
|
3931 |
callback(event);
|
|
|
3932 |
}
|
|
|
3933 |
win = null;
|
|
|
3934 |
};
|
|
|
3935 |
if (isDocReady()) {
|
|
|
3936 |
readyHandler();
|
|
|
3937 |
} else {
|
|
|
3938 |
addEvent(win, 'DOMContentLoaded', readyHandler);
|
|
|
3939 |
}
|
|
|
3940 |
if (!eventUtils.domLoaded) {
|
|
|
3941 |
addEvent(win, 'load', readyHandler);
|
|
|
3942 |
}
|
|
|
3943 |
};
|
|
|
3944 |
class EventUtils {
|
|
|
3945 |
constructor() {
|
|
|
3946 |
this.domLoaded = false;
|
|
|
3947 |
this.events = {};
|
|
|
3948 |
this.count = 1;
|
|
|
3949 |
this.expando = eventExpandoPrefix + (+new Date()).toString(32);
|
|
|
3950 |
this.hasFocusIn = 'onfocusin' in document.documentElement;
|
|
|
3951 |
this.count = 1;
|
|
|
3952 |
}
|
|
|
3953 |
bind(target, names, callback, scope) {
|
|
|
3954 |
const self = this;
|
|
|
3955 |
let callbackList;
|
|
|
3956 |
const win = window;
|
|
|
3957 |
const defaultNativeHandler = evt => {
|
|
|
3958 |
self.executeHandlers(fix(evt || win.event), id);
|
|
|
3959 |
};
|
| 1441 |
ariadna |
3960 |
if (!target || isText$b(target) || isComment(target)) {
|
| 1 |
efrain |
3961 |
return callback;
|
|
|
3962 |
}
|
|
|
3963 |
let id;
|
|
|
3964 |
if (!target[self.expando]) {
|
|
|
3965 |
id = self.count++;
|
|
|
3966 |
target[self.expando] = id;
|
|
|
3967 |
self.events[id] = {};
|
|
|
3968 |
} else {
|
|
|
3969 |
id = target[self.expando];
|
|
|
3970 |
}
|
|
|
3971 |
scope = scope || target;
|
|
|
3972 |
const namesList = names.split(' ');
|
|
|
3973 |
let i = namesList.length;
|
|
|
3974 |
while (i--) {
|
|
|
3975 |
let name = namesList[i];
|
|
|
3976 |
let nativeHandler = defaultNativeHandler;
|
|
|
3977 |
let capture = false;
|
|
|
3978 |
let fakeName = false;
|
|
|
3979 |
if (name === 'DOMContentLoaded') {
|
|
|
3980 |
name = 'ready';
|
|
|
3981 |
}
|
|
|
3982 |
if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
|
|
|
3983 |
callback.call(scope, fix({ type: name }));
|
|
|
3984 |
continue;
|
|
|
3985 |
}
|
|
|
3986 |
if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
|
|
|
3987 |
capture = true;
|
|
|
3988 |
fakeName = name === 'focusin' ? 'focus' : 'blur';
|
|
|
3989 |
nativeHandler = evt => {
|
|
|
3990 |
const event = fix(evt || win.event);
|
|
|
3991 |
event.type = event.type === 'focus' ? 'focusin' : 'focusout';
|
|
|
3992 |
self.executeHandlers(event, id);
|
|
|
3993 |
};
|
|
|
3994 |
}
|
|
|
3995 |
callbackList = self.events[id][name];
|
|
|
3996 |
if (!callbackList) {
|
|
|
3997 |
self.events[id][name] = callbackList = [{
|
|
|
3998 |
func: callback,
|
|
|
3999 |
scope
|
|
|
4000 |
}];
|
|
|
4001 |
callbackList.fakeName = fakeName;
|
|
|
4002 |
callbackList.capture = capture;
|
|
|
4003 |
callbackList.nativeHandler = nativeHandler;
|
|
|
4004 |
if (name === 'ready') {
|
|
|
4005 |
bindOnReady(target, nativeHandler, self);
|
|
|
4006 |
} else {
|
|
|
4007 |
addEvent(target, fakeName || name, nativeHandler, capture);
|
|
|
4008 |
}
|
|
|
4009 |
} else {
|
|
|
4010 |
if (name === 'ready' && self.domLoaded) {
|
|
|
4011 |
callback(fix({ type: name }));
|
|
|
4012 |
} else {
|
|
|
4013 |
callbackList.push({
|
|
|
4014 |
func: callback,
|
|
|
4015 |
scope
|
|
|
4016 |
});
|
|
|
4017 |
}
|
|
|
4018 |
}
|
|
|
4019 |
}
|
|
|
4020 |
target = callbackList = null;
|
|
|
4021 |
return callback;
|
|
|
4022 |
}
|
|
|
4023 |
unbind(target, names, callback) {
|
| 1441 |
ariadna |
4024 |
if (!target || isText$b(target) || isComment(target)) {
|
| 1 |
efrain |
4025 |
return this;
|
|
|
4026 |
}
|
|
|
4027 |
const id = target[this.expando];
|
|
|
4028 |
if (id) {
|
|
|
4029 |
let eventMap = this.events[id];
|
|
|
4030 |
if (names) {
|
|
|
4031 |
const namesList = names.split(' ');
|
|
|
4032 |
let i = namesList.length;
|
|
|
4033 |
while (i--) {
|
|
|
4034 |
const name = namesList[i];
|
|
|
4035 |
const callbackList = eventMap[name];
|
|
|
4036 |
if (callbackList) {
|
|
|
4037 |
if (callback) {
|
|
|
4038 |
let ci = callbackList.length;
|
|
|
4039 |
while (ci--) {
|
|
|
4040 |
if (callbackList[ci].func === callback) {
|
|
|
4041 |
const nativeHandler = callbackList.nativeHandler;
|
|
|
4042 |
const fakeName = callbackList.fakeName, capture = callbackList.capture;
|
|
|
4043 |
const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
|
|
|
4044 |
newCallbackList.nativeHandler = nativeHandler;
|
|
|
4045 |
newCallbackList.fakeName = fakeName;
|
|
|
4046 |
newCallbackList.capture = capture;
|
|
|
4047 |
eventMap[name] = newCallbackList;
|
|
|
4048 |
}
|
|
|
4049 |
}
|
|
|
4050 |
}
|
|
|
4051 |
if (!callback || callbackList.length === 0) {
|
|
|
4052 |
delete eventMap[name];
|
|
|
4053 |
removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
|
|
|
4054 |
}
|
|
|
4055 |
}
|
|
|
4056 |
}
|
|
|
4057 |
} else {
|
|
|
4058 |
each$d(eventMap, (callbackList, name) => {
|
|
|
4059 |
removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
|
|
|
4060 |
});
|
|
|
4061 |
eventMap = {};
|
|
|
4062 |
}
|
|
|
4063 |
for (const name in eventMap) {
|
|
|
4064 |
if (has$2(eventMap, name)) {
|
|
|
4065 |
return this;
|
|
|
4066 |
}
|
|
|
4067 |
}
|
|
|
4068 |
delete this.events[id];
|
|
|
4069 |
try {
|
|
|
4070 |
delete target[this.expando];
|
| 1441 |
ariadna |
4071 |
} catch (_a) {
|
| 1 |
efrain |
4072 |
target[this.expando] = null;
|
|
|
4073 |
}
|
|
|
4074 |
}
|
|
|
4075 |
return this;
|
|
|
4076 |
}
|
|
|
4077 |
fire(target, name, args) {
|
|
|
4078 |
return this.dispatch(target, name, args);
|
|
|
4079 |
}
|
|
|
4080 |
dispatch(target, name, args) {
|
| 1441 |
ariadna |
4081 |
if (!target || isText$b(target) || isComment(target)) {
|
| 1 |
efrain |
4082 |
return this;
|
|
|
4083 |
}
|
|
|
4084 |
const event = fix({
|
|
|
4085 |
type: name,
|
|
|
4086 |
target
|
|
|
4087 |
}, args);
|
|
|
4088 |
do {
|
|
|
4089 |
const id = target[this.expando];
|
|
|
4090 |
if (id) {
|
|
|
4091 |
this.executeHandlers(event, id);
|
|
|
4092 |
}
|
|
|
4093 |
target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
|
|
|
4094 |
} while (target && !event.isPropagationStopped());
|
|
|
4095 |
return this;
|
|
|
4096 |
}
|
|
|
4097 |
clean(target) {
|
| 1441 |
ariadna |
4098 |
if (!target || isText$b(target) || isComment(target)) {
|
| 1 |
efrain |
4099 |
return this;
|
|
|
4100 |
}
|
|
|
4101 |
if (target[this.expando]) {
|
|
|
4102 |
this.unbind(target);
|
|
|
4103 |
}
|
|
|
4104 |
if (!target.getElementsByTagName) {
|
|
|
4105 |
target = target.document;
|
|
|
4106 |
}
|
|
|
4107 |
if (target && target.getElementsByTagName) {
|
|
|
4108 |
this.unbind(target);
|
|
|
4109 |
const children = target.getElementsByTagName('*');
|
|
|
4110 |
let i = children.length;
|
|
|
4111 |
while (i--) {
|
|
|
4112 |
target = children[i];
|
|
|
4113 |
if (target[this.expando]) {
|
|
|
4114 |
this.unbind(target);
|
|
|
4115 |
}
|
|
|
4116 |
}
|
|
|
4117 |
}
|
|
|
4118 |
return this;
|
|
|
4119 |
}
|
|
|
4120 |
destroy() {
|
|
|
4121 |
this.events = {};
|
|
|
4122 |
}
|
|
|
4123 |
cancel(e) {
|
|
|
4124 |
if (e) {
|
|
|
4125 |
e.preventDefault();
|
|
|
4126 |
e.stopImmediatePropagation();
|
|
|
4127 |
}
|
|
|
4128 |
return false;
|
|
|
4129 |
}
|
|
|
4130 |
executeHandlers(evt, id) {
|
|
|
4131 |
const container = this.events[id];
|
|
|
4132 |
const callbackList = container && container[evt.type];
|
|
|
4133 |
if (callbackList) {
|
|
|
4134 |
for (let i = 0, l = callbackList.length; i < l; i++) {
|
|
|
4135 |
const callback = callbackList[i];
|
|
|
4136 |
if (callback && callback.func.call(callback.scope, evt) === false) {
|
|
|
4137 |
evt.preventDefault();
|
|
|
4138 |
}
|
|
|
4139 |
if (evt.isImmediatePropagationStopped()) {
|
|
|
4140 |
return;
|
|
|
4141 |
}
|
|
|
4142 |
}
|
|
|
4143 |
}
|
|
|
4144 |
}
|
|
|
4145 |
}
|
|
|
4146 |
EventUtils.Event = new EventUtils();
|
|
|
4147 |
|
|
|
4148 |
const each$a = Tools.each;
|
|
|
4149 |
const grep = Tools.grep;
|
|
|
4150 |
const internalStyleName = 'data-mce-style';
|
|
|
4151 |
const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' ');
|
|
|
4152 |
const legacySetAttribute = (elm, name, value) => {
|
|
|
4153 |
if (isNullable(value) || value === '') {
|
| 1441 |
ariadna |
4154 |
remove$9(elm, name);
|
| 1 |
efrain |
4155 |
} else {
|
| 1441 |
ariadna |
4156 |
set$4(elm, name, value);
|
| 1 |
efrain |
4157 |
}
|
|
|
4158 |
};
|
|
|
4159 |
const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase());
|
|
|
4160 |
const findNodeIndex = (node, normalized) => {
|
|
|
4161 |
let idx = 0;
|
|
|
4162 |
if (node) {
|
|
|
4163 |
for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) {
|
|
|
4164 |
const nodeType = tempNode.nodeType;
|
| 1441 |
ariadna |
4165 |
if (normalized && isText$b(tempNode)) {
|
| 1 |
efrain |
4166 |
if (nodeType === lastNodeType || !tempNode.data.length) {
|
|
|
4167 |
continue;
|
|
|
4168 |
}
|
|
|
4169 |
}
|
|
|
4170 |
idx++;
|
|
|
4171 |
lastNodeType = nodeType;
|
|
|
4172 |
}
|
|
|
4173 |
}
|
|
|
4174 |
return idx;
|
|
|
4175 |
};
|
|
|
4176 |
const updateInternalStyleAttr = (styles, elm) => {
|
|
|
4177 |
const rawValue = get$9(elm, 'style');
|
|
|
4178 |
const value = styles.serialize(styles.parse(rawValue), name(elm));
|
|
|
4179 |
legacySetAttribute(elm, internalStyleName, value);
|
|
|
4180 |
};
|
|
|
4181 |
const convertStyleToString = (cssValue, cssName) => {
|
|
|
4182 |
if (isNumber(cssValue)) {
|
|
|
4183 |
return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px';
|
|
|
4184 |
} else {
|
|
|
4185 |
return cssValue;
|
|
|
4186 |
}
|
|
|
4187 |
};
|
|
|
4188 |
const applyStyle$1 = ($elm, cssName, cssValue) => {
|
|
|
4189 |
const normalizedName = camelCaseToHyphens(cssName);
|
|
|
4190 |
if (isNullable(cssValue) || cssValue === '') {
|
| 1441 |
ariadna |
4191 |
remove$5($elm, normalizedName);
|
| 1 |
efrain |
4192 |
} else {
|
|
|
4193 |
set$2($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
|
|
|
4194 |
}
|
|
|
4195 |
};
|
|
|
4196 |
const setupAttrHooks = (styles, settings, getContext) => {
|
|
|
4197 |
const keepValues = settings.keep_values;
|
|
|
4198 |
const keepUrlHook = {
|
|
|
4199 |
set: (elm, value, name) => {
|
|
|
4200 |
const sugarElm = SugarElement.fromDom(elm);
|
|
|
4201 |
if (isFunction(settings.url_converter) && isNonNullable(value)) {
|
|
|
4202 |
value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm);
|
|
|
4203 |
}
|
|
|
4204 |
const internalName = 'data-mce-' + name;
|
|
|
4205 |
legacySetAttribute(sugarElm, internalName, value);
|
|
|
4206 |
legacySetAttribute(sugarElm, name, value);
|
|
|
4207 |
},
|
|
|
4208 |
get: (elm, name) => {
|
|
|
4209 |
const sugarElm = SugarElement.fromDom(elm);
|
|
|
4210 |
return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name);
|
|
|
4211 |
}
|
|
|
4212 |
};
|
|
|
4213 |
const attrHooks = {
|
|
|
4214 |
style: {
|
|
|
4215 |
set: (elm, value) => {
|
|
|
4216 |
const sugarElm = SugarElement.fromDom(elm);
|
|
|
4217 |
if (keepValues) {
|
|
|
4218 |
legacySetAttribute(sugarElm, internalStyleName, value);
|
|
|
4219 |
}
|
| 1441 |
ariadna |
4220 |
remove$9(sugarElm, 'style');
|
| 1 |
efrain |
4221 |
if (isString(value)) {
|
|
|
4222 |
setAll(sugarElm, styles.parse(value));
|
|
|
4223 |
}
|
|
|
4224 |
},
|
|
|
4225 |
get: elm => {
|
|
|
4226 |
const sugarElm = SugarElement.fromDom(elm);
|
|
|
4227 |
const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style');
|
|
|
4228 |
return styles.serialize(styles.parse(value), name(sugarElm));
|
|
|
4229 |
}
|
|
|
4230 |
}
|
|
|
4231 |
};
|
|
|
4232 |
if (keepValues) {
|
|
|
4233 |
attrHooks.href = attrHooks.src = keepUrlHook;
|
|
|
4234 |
}
|
|
|
4235 |
return attrHooks;
|
|
|
4236 |
};
|
|
|
4237 |
const DOMUtils = (doc, settings = {}) => {
|
|
|
4238 |
const addedStyles = {};
|
|
|
4239 |
const win = window;
|
|
|
4240 |
const files = {};
|
|
|
4241 |
let counter = 0;
|
|
|
4242 |
const stdMode = true;
|
|
|
4243 |
const boxModel = true;
|
|
|
4244 |
const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
|
|
|
4245 |
contentCssCors: settings.contentCssCors,
|
|
|
4246 |
referrerPolicy: settings.referrerPolicy
|
|
|
4247 |
});
|
|
|
4248 |
const boundEvents = [];
|
|
|
4249 |
const schema = settings.schema ? settings.schema : Schema({});
|
|
|
4250 |
const styles = Styles({
|
|
|
4251 |
url_converter: settings.url_converter,
|
| 1441 |
ariadna |
4252 |
url_converter_scope: settings.url_converter_scope
|
| 1 |
efrain |
4253 |
}, settings.schema);
|
|
|
4254 |
const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
|
|
|
4255 |
const blockElementsMap = schema.getBlockElements();
|
|
|
4256 |
const isBlock = node => {
|
|
|
4257 |
if (isString(node)) {
|
|
|
4258 |
return has$2(blockElementsMap, node);
|
|
|
4259 |
} else {
|
|
|
4260 |
return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node));
|
|
|
4261 |
}
|
|
|
4262 |
};
|
|
|
4263 |
const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
|
|
|
4264 |
const _get = elm => {
|
|
|
4265 |
const value = get(elm);
|
|
|
4266 |
return isNonNullable(value) ? SugarElement.fromDom(value) : null;
|
|
|
4267 |
};
|
|
|
4268 |
const getAttrib = (elm, name, defaultVal = '') => {
|
|
|
4269 |
let value;
|
|
|
4270 |
const $elm = _get(elm);
|
|
|
4271 |
if (isNonNullable($elm) && isElement$7($elm)) {
|
|
|
4272 |
const hook = attrHooks[name];
|
|
|
4273 |
if (hook && hook.get) {
|
|
|
4274 |
value = hook.get($elm.dom, name);
|
|
|
4275 |
} else {
|
|
|
4276 |
value = get$9($elm, name);
|
|
|
4277 |
}
|
|
|
4278 |
}
|
|
|
4279 |
return isNonNullable(value) ? value : defaultVal;
|
|
|
4280 |
};
|
|
|
4281 |
const getAttribs = elm => {
|
|
|
4282 |
const node = get(elm);
|
|
|
4283 |
return isNullable(node) ? [] : node.attributes;
|
|
|
4284 |
};
|
|
|
4285 |
const setAttrib = (elm, name, value) => {
|
|
|
4286 |
run(elm, e => {
|
|
|
4287 |
if (isElement$6(e)) {
|
|
|
4288 |
const $elm = SugarElement.fromDom(e);
|
|
|
4289 |
const val = value === '' ? null : value;
|
|
|
4290 |
const originalValue = get$9($elm, name);
|
|
|
4291 |
const hook = attrHooks[name];
|
|
|
4292 |
if (hook && hook.set) {
|
|
|
4293 |
hook.set($elm.dom, val, name);
|
|
|
4294 |
} else {
|
|
|
4295 |
legacySetAttribute($elm, name, val);
|
|
|
4296 |
}
|
|
|
4297 |
if (originalValue !== val && settings.onSetAttrib) {
|
|
|
4298 |
settings.onSetAttrib({
|
|
|
4299 |
attrElm: $elm.dom,
|
|
|
4300 |
attrName: name,
|
|
|
4301 |
attrValue: val
|
|
|
4302 |
});
|
|
|
4303 |
}
|
|
|
4304 |
}
|
|
|
4305 |
});
|
|
|
4306 |
};
|
|
|
4307 |
const clone = (node, deep) => {
|
|
|
4308 |
return node.cloneNode(deep);
|
|
|
4309 |
};
|
|
|
4310 |
const getRoot = () => settings.root_element || doc.body;
|
|
|
4311 |
const getViewPort = argWin => {
|
|
|
4312 |
const vp = getBounds(argWin);
|
|
|
4313 |
return {
|
|
|
4314 |
x: vp.x,
|
|
|
4315 |
y: vp.y,
|
|
|
4316 |
w: vp.width,
|
|
|
4317 |
h: vp.height
|
|
|
4318 |
};
|
|
|
4319 |
};
|
|
|
4320 |
const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm);
|
|
|
4321 |
const setStyle = (elm, name, value) => {
|
|
|
4322 |
run(elm, e => {
|
|
|
4323 |
const $elm = SugarElement.fromDom(e);
|
|
|
4324 |
applyStyle$1($elm, name, value);
|
|
|
4325 |
if (settings.update_styles) {
|
|
|
4326 |
updateInternalStyleAttr(styles, $elm);
|
|
|
4327 |
}
|
|
|
4328 |
});
|
|
|
4329 |
};
|
|
|
4330 |
const setStyles = (elm, stylesArg) => {
|
|
|
4331 |
run(elm, e => {
|
|
|
4332 |
const $elm = SugarElement.fromDom(e);
|
|
|
4333 |
each$d(stylesArg, (v, n) => {
|
|
|
4334 |
applyStyle$1($elm, n, v);
|
|
|
4335 |
});
|
|
|
4336 |
if (settings.update_styles) {
|
|
|
4337 |
updateInternalStyleAttr(styles, $elm);
|
|
|
4338 |
}
|
|
|
4339 |
});
|
|
|
4340 |
};
|
|
|
4341 |
const getStyle = (elm, name, computed) => {
|
|
|
4342 |
const $elm = get(elm);
|
|
|
4343 |
if (isNullable($elm) || !isHTMLElement($elm) && !isSVGElement($elm)) {
|
|
|
4344 |
return undefined;
|
|
|
4345 |
}
|
|
|
4346 |
if (computed) {
|
|
|
4347 |
return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name));
|
|
|
4348 |
} else {
|
|
|
4349 |
name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase());
|
|
|
4350 |
if (name === 'float') {
|
|
|
4351 |
name = 'cssFloat';
|
|
|
4352 |
}
|
|
|
4353 |
return $elm.style ? $elm.style[name] : undefined;
|
|
|
4354 |
}
|
|
|
4355 |
};
|
|
|
4356 |
const getSize = elm => {
|
|
|
4357 |
const $elm = get(elm);
|
|
|
4358 |
if (!$elm) {
|
|
|
4359 |
return {
|
|
|
4360 |
w: 0,
|
|
|
4361 |
h: 0
|
|
|
4362 |
};
|
|
|
4363 |
}
|
|
|
4364 |
let w = getStyle($elm, 'width');
|
|
|
4365 |
let h = getStyle($elm, 'height');
|
|
|
4366 |
if (!w || w.indexOf('px') === -1) {
|
|
|
4367 |
w = '0';
|
|
|
4368 |
}
|
|
|
4369 |
if (!h || h.indexOf('px') === -1) {
|
|
|
4370 |
h = '0';
|
|
|
4371 |
}
|
|
|
4372 |
return {
|
|
|
4373 |
w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
|
|
|
4374 |
h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight
|
|
|
4375 |
};
|
|
|
4376 |
};
|
|
|
4377 |
const getRect = elm => {
|
|
|
4378 |
const $elm = get(elm);
|
|
|
4379 |
const pos = getPos$1($elm);
|
|
|
4380 |
const size = getSize($elm);
|
|
|
4381 |
return {
|
|
|
4382 |
x: pos.x,
|
|
|
4383 |
y: pos.y,
|
|
|
4384 |
w: size.w,
|
|
|
4385 |
h: size.h
|
|
|
4386 |
};
|
|
|
4387 |
};
|
|
|
4388 |
const is = (elm, selector) => {
|
|
|
4389 |
if (!elm) {
|
|
|
4390 |
return false;
|
|
|
4391 |
}
|
|
|
4392 |
const elms = isArray$1(elm) ? elm : [elm];
|
|
|
4393 |
return exists(elms, e => {
|
|
|
4394 |
return is$1(SugarElement.fromDom(e), selector);
|
|
|
4395 |
});
|
|
|
4396 |
};
|
|
|
4397 |
const getParents = (elm, selector, root, collect) => {
|
|
|
4398 |
const result = [];
|
|
|
4399 |
let node = get(elm);
|
|
|
4400 |
collect = collect === undefined;
|
|
|
4401 |
const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
|
|
|
4402 |
if (isString(selector)) {
|
|
|
4403 |
if (selector === '*') {
|
|
|
4404 |
selector = isElement$6;
|
|
|
4405 |
} else {
|
|
|
4406 |
const selectorVal = selector;
|
|
|
4407 |
selector = node => is(node, selectorVal);
|
|
|
4408 |
}
|
|
|
4409 |
}
|
|
|
4410 |
while (node) {
|
|
|
4411 |
if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
|
|
|
4412 |
break;
|
|
|
4413 |
}
|
|
|
4414 |
if (!selector || selector(node)) {
|
|
|
4415 |
if (collect) {
|
|
|
4416 |
result.push(node);
|
|
|
4417 |
} else {
|
|
|
4418 |
return [node];
|
|
|
4419 |
}
|
|
|
4420 |
}
|
|
|
4421 |
node = node.parentNode;
|
|
|
4422 |
}
|
|
|
4423 |
return collect ? result : null;
|
|
|
4424 |
};
|
|
|
4425 |
const getParent = (node, selector, root) => {
|
|
|
4426 |
const parents = getParents(node, selector, root, false);
|
|
|
4427 |
return parents && parents.length > 0 ? parents[0] : null;
|
|
|
4428 |
};
|
|
|
4429 |
const _findSib = (node, selector, name) => {
|
|
|
4430 |
let func = selector;
|
|
|
4431 |
if (node) {
|
|
|
4432 |
if (isString(selector)) {
|
|
|
4433 |
func = node => {
|
|
|
4434 |
return is(node, selector);
|
|
|
4435 |
};
|
|
|
4436 |
}
|
|
|
4437 |
for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) {
|
|
|
4438 |
if (isFunction(func) && func(tempNode)) {
|
|
|
4439 |
return tempNode;
|
|
|
4440 |
}
|
|
|
4441 |
}
|
|
|
4442 |
}
|
|
|
4443 |
return null;
|
|
|
4444 |
};
|
|
|
4445 |
const getNext = (node, selector) => _findSib(node, selector, 'nextSibling');
|
|
|
4446 |
const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling');
|
|
|
4447 |
const isParentNode = node => isFunction(node.querySelectorAll);
|
|
|
4448 |
const select = (selector, scope) => {
|
|
|
4449 |
var _a, _b;
|
|
|
4450 |
const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
|
|
|
4451 |
return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : [];
|
|
|
4452 |
};
|
|
|
4453 |
const run = function (elm, func, scope) {
|
|
|
4454 |
const context = scope !== null && scope !== void 0 ? scope : this;
|
|
|
4455 |
if (isArray$1(elm)) {
|
|
|
4456 |
const result = [];
|
|
|
4457 |
each$a(elm, (e, i) => {
|
|
|
4458 |
const node = get(e);
|
|
|
4459 |
if (node) {
|
|
|
4460 |
result.push(func.call(context, node, i));
|
|
|
4461 |
}
|
|
|
4462 |
});
|
|
|
4463 |
return result;
|
|
|
4464 |
} else {
|
|
|
4465 |
const node = get(elm);
|
|
|
4466 |
return !node ? false : func.call(context, node);
|
|
|
4467 |
}
|
|
|
4468 |
};
|
|
|
4469 |
const setAttribs = (elm, attrs) => {
|
|
|
4470 |
run(elm, $elm => {
|
|
|
4471 |
each$d(attrs, (value, name) => {
|
|
|
4472 |
setAttrib($elm, name, value);
|
|
|
4473 |
});
|
|
|
4474 |
});
|
|
|
4475 |
};
|
|
|
4476 |
const setHTML = (elm, html) => {
|
|
|
4477 |
run(elm, e => {
|
|
|
4478 |
const $elm = SugarElement.fromDom(e);
|
|
|
4479 |
set$1($elm, html);
|
|
|
4480 |
});
|
|
|
4481 |
};
|
|
|
4482 |
const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => {
|
|
|
4483 |
const newElm = isString(name) ? doc.createElement(name) : name;
|
|
|
4484 |
if (isNonNullable(attrs)) {
|
|
|
4485 |
setAttribs(newElm, attrs);
|
|
|
4486 |
}
|
|
|
4487 |
if (html) {
|
|
|
4488 |
if (!isString(html) && html.nodeType) {
|
|
|
4489 |
newElm.appendChild(html);
|
|
|
4490 |
} else if (isString(html)) {
|
|
|
4491 |
setHTML(newElm, html);
|
|
|
4492 |
}
|
|
|
4493 |
}
|
|
|
4494 |
return !create ? parentElm.appendChild(newElm) : newElm;
|
|
|
4495 |
});
|
|
|
4496 |
const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true);
|
|
|
4497 |
const decode = Entities.decode;
|
|
|
4498 |
const encode = Entities.encodeAllRaw;
|
|
|
4499 |
const createHTML = (name, attrs, html = '') => {
|
|
|
4500 |
let outHtml = '<' + name;
|
|
|
4501 |
for (const key in attrs) {
|
|
|
4502 |
if (hasNonNullableKey(attrs, key)) {
|
|
|
4503 |
outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
|
|
|
4504 |
}
|
|
|
4505 |
}
|
|
|
4506 |
if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) {
|
|
|
4507 |
return outHtml + ' />';
|
|
|
4508 |
} else {
|
|
|
4509 |
return outHtml + '>' + html + '</' + name + '>';
|
|
|
4510 |
}
|
|
|
4511 |
};
|
|
|
4512 |
const createFragment = html => {
|
|
|
4513 |
const container = doc.createElement('div');
|
|
|
4514 |
const frag = doc.createDocumentFragment();
|
|
|
4515 |
frag.appendChild(container);
|
|
|
4516 |
if (html) {
|
|
|
4517 |
container.innerHTML = html;
|
|
|
4518 |
}
|
|
|
4519 |
let node;
|
|
|
4520 |
while (node = container.firstChild) {
|
|
|
4521 |
frag.appendChild(node);
|
|
|
4522 |
}
|
|
|
4523 |
frag.removeChild(container);
|
|
|
4524 |
return frag;
|
|
|
4525 |
};
|
|
|
4526 |
const remove = (node, keepChildren) => {
|
|
|
4527 |
return run(node, n => {
|
|
|
4528 |
const $node = SugarElement.fromDom(n);
|
|
|
4529 |
if (keepChildren) {
|
|
|
4530 |
each$e(children$1($node), child => {
|
| 1441 |
ariadna |
4531 |
if (isText$c(child) && child.dom.length === 0) {
|
|
|
4532 |
remove$4(child);
|
| 1 |
efrain |
4533 |
} else {
|
|
|
4534 |
before$3($node, child);
|
|
|
4535 |
}
|
|
|
4536 |
});
|
|
|
4537 |
}
|
| 1441 |
ariadna |
4538 |
remove$4($node);
|
| 1 |
efrain |
4539 |
return $node.dom;
|
|
|
4540 |
});
|
|
|
4541 |
};
|
|
|
4542 |
const removeAllAttribs = e => run(e, e => {
|
|
|
4543 |
const attrs = e.attributes;
|
|
|
4544 |
for (let i = attrs.length - 1; i >= 0; i--) {
|
|
|
4545 |
e.removeAttributeNode(attrs.item(i));
|
|
|
4546 |
}
|
|
|
4547 |
});
|
|
|
4548 |
const parseStyle = cssText => styles.parse(cssText);
|
|
|
4549 |
const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name);
|
|
|
4550 |
const addStyle = cssText => {
|
|
|
4551 |
if (self !== DOMUtils.DOM && doc === document) {
|
|
|
4552 |
if (addedStyles[cssText]) {
|
|
|
4553 |
return;
|
|
|
4554 |
}
|
|
|
4555 |
addedStyles[cssText] = true;
|
|
|
4556 |
}
|
|
|
4557 |
let styleElm = doc.getElementById('mceDefaultStyles');
|
|
|
4558 |
if (!styleElm) {
|
|
|
4559 |
styleElm = doc.createElement('style');
|
|
|
4560 |
styleElm.id = 'mceDefaultStyles';
|
|
|
4561 |
styleElm.type = 'text/css';
|
|
|
4562 |
const head = doc.head;
|
|
|
4563 |
if (head.firstChild) {
|
|
|
4564 |
head.insertBefore(styleElm, head.firstChild);
|
|
|
4565 |
} else {
|
|
|
4566 |
head.appendChild(styleElm);
|
|
|
4567 |
}
|
|
|
4568 |
}
|
|
|
4569 |
if (styleElm.styleSheet) {
|
|
|
4570 |
styleElm.styleSheet.cssText += cssText;
|
|
|
4571 |
} else {
|
|
|
4572 |
styleElm.appendChild(doc.createTextNode(cssText));
|
|
|
4573 |
}
|
|
|
4574 |
};
|
|
|
4575 |
const loadCSS = urls => {
|
|
|
4576 |
if (!urls) {
|
|
|
4577 |
urls = '';
|
|
|
4578 |
}
|
|
|
4579 |
each$e(urls.split(','), url => {
|
|
|
4580 |
files[url] = true;
|
|
|
4581 |
styleSheetLoader.load(url).catch(noop);
|
|
|
4582 |
});
|
|
|
4583 |
};
|
|
|
4584 |
const toggleClass = (elm, cls, state) => {
|
|
|
4585 |
run(elm, e => {
|
|
|
4586 |
if (isElement$6(e)) {
|
|
|
4587 |
const $elm = SugarElement.fromDom(e);
|
|
|
4588 |
const classes = cls.split(' ');
|
|
|
4589 |
each$e(classes, c => {
|
|
|
4590 |
if (isNonNullable(state)) {
|
| 1441 |
ariadna |
4591 |
const fn = state ? add$2 : remove$6;
|
| 1 |
efrain |
4592 |
fn($elm, c);
|
|
|
4593 |
} else {
|
|
|
4594 |
toggle$1($elm, c);
|
|
|
4595 |
}
|
|
|
4596 |
});
|
|
|
4597 |
}
|
|
|
4598 |
});
|
|
|
4599 |
};
|
|
|
4600 |
const addClass = (elm, cls) => {
|
|
|
4601 |
toggleClass(elm, cls, true);
|
|
|
4602 |
};
|
|
|
4603 |
const removeClass = (elm, cls) => {
|
|
|
4604 |
toggleClass(elm, cls, false);
|
|
|
4605 |
};
|
|
|
4606 |
const hasClass = (elm, cls) => {
|
|
|
4607 |
const $elm = _get(elm);
|
|
|
4608 |
const classes = cls.split(' ');
|
|
|
4609 |
return isNonNullable($elm) && forall(classes, c => has($elm, c));
|
|
|
4610 |
};
|
|
|
4611 |
const show = elm => {
|
| 1441 |
ariadna |
4612 |
run(elm, e => remove$5(SugarElement.fromDom(e), 'display'));
|
| 1 |
efrain |
4613 |
};
|
|
|
4614 |
const hide = elm => {
|
|
|
4615 |
run(elm, e => set$2(SugarElement.fromDom(e), 'display', 'none'));
|
|
|
4616 |
};
|
|
|
4617 |
const isHidden = elm => {
|
|
|
4618 |
const $elm = _get(elm);
|
|
|
4619 |
return isNonNullable($elm) && is$2(getRaw($elm, 'display'), 'none');
|
|
|
4620 |
};
|
|
|
4621 |
const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++;
|
|
|
4622 |
const getOuterHTML = elm => {
|
|
|
4623 |
const $elm = _get(elm);
|
|
|
4624 |
if (isNonNullable($elm)) {
|
|
|
4625 |
return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
|
|
|
4626 |
} else {
|
|
|
4627 |
return '';
|
|
|
4628 |
}
|
|
|
4629 |
};
|
|
|
4630 |
const setOuterHTML = (elm, html) => {
|
|
|
4631 |
run(elm, $elm => {
|
|
|
4632 |
if (isElement$6($elm)) {
|
|
|
4633 |
$elm.outerHTML = html;
|
|
|
4634 |
}
|
|
|
4635 |
});
|
|
|
4636 |
};
|
|
|
4637 |
const insertAfter = (node, reference) => {
|
|
|
4638 |
const referenceNode = get(reference);
|
|
|
4639 |
return run(node, node => {
|
|
|
4640 |
const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode;
|
|
|
4641 |
const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling;
|
|
|
4642 |
if (parent) {
|
|
|
4643 |
if (nextSibling) {
|
|
|
4644 |
parent.insertBefore(node, nextSibling);
|
|
|
4645 |
} else {
|
|
|
4646 |
parent.appendChild(node);
|
|
|
4647 |
}
|
|
|
4648 |
}
|
|
|
4649 |
return node;
|
|
|
4650 |
});
|
|
|
4651 |
};
|
|
|
4652 |
const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => {
|
|
|
4653 |
var _a;
|
|
|
4654 |
const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm;
|
|
|
4655 |
if (keepChildren) {
|
|
|
4656 |
each$a(grep(elm.childNodes), node => {
|
|
|
4657 |
replacee.appendChild(node);
|
|
|
4658 |
});
|
|
|
4659 |
}
|
|
|
4660 |
(_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm);
|
|
|
4661 |
return elm;
|
|
|
4662 |
});
|
|
|
4663 |
const rename = (elm, name) => {
|
|
|
4664 |
if (elm.nodeName !== name.toUpperCase()) {
|
|
|
4665 |
const newElm = create(name);
|
|
|
4666 |
each$a(getAttribs(elm), attrNode => {
|
|
|
4667 |
setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
|
|
|
4668 |
});
|
|
|
4669 |
replace(newElm, elm, true);
|
|
|
4670 |
return newElm;
|
|
|
4671 |
} else {
|
|
|
4672 |
return elm;
|
|
|
4673 |
}
|
|
|
4674 |
};
|
|
|
4675 |
const findCommonAncestor = (a, b) => {
|
|
|
4676 |
let ps = a;
|
|
|
4677 |
while (ps) {
|
|
|
4678 |
let pe = b;
|
|
|
4679 |
while (pe && ps !== pe) {
|
|
|
4680 |
pe = pe.parentNode;
|
|
|
4681 |
}
|
|
|
4682 |
if (ps === pe) {
|
|
|
4683 |
break;
|
|
|
4684 |
}
|
|
|
4685 |
ps = ps.parentNode;
|
|
|
4686 |
}
|
|
|
4687 |
if (!ps && a.ownerDocument) {
|
|
|
4688 |
return a.ownerDocument.documentElement;
|
|
|
4689 |
} else {
|
|
|
4690 |
return ps;
|
|
|
4691 |
}
|
|
|
4692 |
};
|
|
|
4693 |
const isEmpty = (node, elements, options) => {
|
| 1441 |
ariadna |
4694 |
if (isPlainObject(elements)) {
|
|
|
4695 |
const isContent = node => {
|
|
|
4696 |
const name = node.nodeName.toLowerCase();
|
|
|
4697 |
return Boolean(elements[name]);
|
|
|
4698 |
};
|
|
|
4699 |
return isEmptyNode(schema, node, {
|
|
|
4700 |
...options,
|
|
|
4701 |
isContent
|
|
|
4702 |
});
|
|
|
4703 |
} else {
|
|
|
4704 |
return isEmptyNode(schema, node, options);
|
| 1 |
efrain |
4705 |
}
|
|
|
4706 |
};
|
|
|
4707 |
const createRng = () => doc.createRange();
|
|
|
4708 |
const split = (parentElm, splitElm, replacementElm) => {
|
|
|
4709 |
let range = createRng();
|
|
|
4710 |
let beforeFragment;
|
|
|
4711 |
let afterFragment;
|
|
|
4712 |
if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) {
|
|
|
4713 |
const parentNode = parentElm.parentNode;
|
|
|
4714 |
range.setStart(parentNode, findNodeIndex(parentElm));
|
|
|
4715 |
range.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
|
|
|
4716 |
beforeFragment = range.extractContents();
|
|
|
4717 |
range = createRng();
|
|
|
4718 |
range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
|
|
|
4719 |
range.setEnd(parentNode, findNodeIndex(parentElm) + 1);
|
|
|
4720 |
afterFragment = range.extractContents();
|
|
|
4721 |
parentNode.insertBefore(trimNode(self, beforeFragment, schema), parentElm);
|
|
|
4722 |
if (replacementElm) {
|
|
|
4723 |
parentNode.insertBefore(replacementElm, parentElm);
|
|
|
4724 |
} else {
|
|
|
4725 |
parentNode.insertBefore(splitElm, parentElm);
|
|
|
4726 |
}
|
|
|
4727 |
parentNode.insertBefore(trimNode(self, afterFragment, schema), parentElm);
|
|
|
4728 |
remove(parentElm);
|
|
|
4729 |
return replacementElm || splitElm;
|
|
|
4730 |
} else {
|
|
|
4731 |
return undefined;
|
|
|
4732 |
}
|
|
|
4733 |
};
|
|
|
4734 |
const bind = (target, name, func, scope) => {
|
|
|
4735 |
if (isArray$1(target)) {
|
|
|
4736 |
let i = target.length;
|
|
|
4737 |
const rv = [];
|
|
|
4738 |
while (i--) {
|
|
|
4739 |
rv[i] = bind(target[i], name, func, scope);
|
|
|
4740 |
}
|
|
|
4741 |
return rv;
|
|
|
4742 |
} else {
|
|
|
4743 |
if (settings.collect && (target === doc || target === win)) {
|
|
|
4744 |
boundEvents.push([
|
|
|
4745 |
target,
|
|
|
4746 |
name,
|
|
|
4747 |
func,
|
|
|
4748 |
scope
|
|
|
4749 |
]);
|
|
|
4750 |
}
|
|
|
4751 |
return events.bind(target, name, func, scope || self);
|
|
|
4752 |
}
|
|
|
4753 |
};
|
|
|
4754 |
const unbind = (target, name, func) => {
|
|
|
4755 |
if (isArray$1(target)) {
|
|
|
4756 |
let i = target.length;
|
|
|
4757 |
const rv = [];
|
|
|
4758 |
while (i--) {
|
|
|
4759 |
rv[i] = unbind(target[i], name, func);
|
|
|
4760 |
}
|
|
|
4761 |
return rv;
|
|
|
4762 |
} else {
|
|
|
4763 |
if (boundEvents.length > 0 && (target === doc || target === win)) {
|
|
|
4764 |
let i = boundEvents.length;
|
|
|
4765 |
while (i--) {
|
|
|
4766 |
const [boundTarget, boundName, boundFunc] = boundEvents[i];
|
|
|
4767 |
if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) {
|
|
|
4768 |
events.unbind(boundTarget, boundName, boundFunc);
|
|
|
4769 |
}
|
|
|
4770 |
}
|
|
|
4771 |
}
|
|
|
4772 |
return events.unbind(target, name, func);
|
|
|
4773 |
}
|
|
|
4774 |
};
|
|
|
4775 |
const dispatch = (target, name, evt) => events.dispatch(target, name, evt);
|
|
|
4776 |
const fire = (target, name, evt) => events.dispatch(target, name, evt);
|
|
|
4777 |
const getContentEditable = node => {
|
|
|
4778 |
if (node && isHTMLElement(node)) {
|
|
|
4779 |
const contentEditable = node.getAttribute('data-mce-contenteditable');
|
|
|
4780 |
if (contentEditable && contentEditable !== 'inherit') {
|
|
|
4781 |
return contentEditable;
|
|
|
4782 |
}
|
|
|
4783 |
return node.contentEditable !== 'inherit' ? node.contentEditable : null;
|
|
|
4784 |
} else {
|
|
|
4785 |
return null;
|
|
|
4786 |
}
|
|
|
4787 |
};
|
|
|
4788 |
const getContentEditableParent = node => {
|
|
|
4789 |
const root = getRoot();
|
|
|
4790 |
let state = null;
|
|
|
4791 |
for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
|
|
|
4792 |
state = getContentEditable(tempNode);
|
|
|
4793 |
if (state !== null) {
|
|
|
4794 |
break;
|
|
|
4795 |
}
|
|
|
4796 |
}
|
|
|
4797 |
return state;
|
|
|
4798 |
};
|
|
|
4799 |
const isEditable = node => {
|
|
|
4800 |
if (isNonNullable(node)) {
|
|
|
4801 |
const scope = isElement$6(node) ? node : node.parentElement;
|
|
|
4802 |
return isNonNullable(scope) && isHTMLElement(scope) && isEditable$2(SugarElement.fromDom(scope));
|
|
|
4803 |
} else {
|
|
|
4804 |
return false;
|
|
|
4805 |
}
|
|
|
4806 |
};
|
|
|
4807 |
const destroy = () => {
|
|
|
4808 |
if (boundEvents.length > 0) {
|
|
|
4809 |
let i = boundEvents.length;
|
|
|
4810 |
while (i--) {
|
|
|
4811 |
const [boundTarget, boundName, boundFunc] = boundEvents[i];
|
|
|
4812 |
events.unbind(boundTarget, boundName, boundFunc);
|
|
|
4813 |
}
|
|
|
4814 |
}
|
|
|
4815 |
each$d(files, (_, url) => {
|
|
|
4816 |
styleSheetLoader.unload(url);
|
|
|
4817 |
delete files[url];
|
|
|
4818 |
});
|
|
|
4819 |
};
|
|
|
4820 |
const isChildOf = (node, parent) => {
|
|
|
4821 |
return node === parent || parent.contains(node);
|
|
|
4822 |
};
|
|
|
4823 |
const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
|
|
|
4824 |
const self = {
|
|
|
4825 |
doc,
|
|
|
4826 |
settings,
|
|
|
4827 |
win,
|
|
|
4828 |
files,
|
|
|
4829 |
stdMode,
|
|
|
4830 |
boxModel,
|
|
|
4831 |
styleSheetLoader,
|
|
|
4832 |
boundEvents,
|
|
|
4833 |
styles,
|
|
|
4834 |
schema,
|
|
|
4835 |
events,
|
|
|
4836 |
isBlock: isBlock,
|
|
|
4837 |
root: null,
|
|
|
4838 |
clone,
|
|
|
4839 |
getRoot,
|
|
|
4840 |
getViewPort,
|
|
|
4841 |
getRect,
|
|
|
4842 |
getSize,
|
|
|
4843 |
getParent,
|
|
|
4844 |
getParents: getParents,
|
|
|
4845 |
get,
|
|
|
4846 |
getNext,
|
|
|
4847 |
getPrev,
|
|
|
4848 |
select,
|
|
|
4849 |
is,
|
|
|
4850 |
add,
|
|
|
4851 |
create,
|
|
|
4852 |
createHTML,
|
|
|
4853 |
createFragment,
|
|
|
4854 |
remove,
|
|
|
4855 |
setStyle,
|
|
|
4856 |
getStyle: getStyle,
|
|
|
4857 |
setStyles,
|
|
|
4858 |
removeAllAttribs,
|
|
|
4859 |
setAttrib,
|
|
|
4860 |
setAttribs,
|
|
|
4861 |
getAttrib,
|
|
|
4862 |
getPos: getPos$1,
|
|
|
4863 |
parseStyle,
|
|
|
4864 |
serializeStyle,
|
|
|
4865 |
addStyle,
|
|
|
4866 |
loadCSS,
|
|
|
4867 |
addClass,
|
|
|
4868 |
removeClass,
|
|
|
4869 |
hasClass,
|
|
|
4870 |
toggleClass,
|
|
|
4871 |
show,
|
|
|
4872 |
hide,
|
|
|
4873 |
isHidden,
|
|
|
4874 |
uniqueId,
|
|
|
4875 |
setHTML,
|
|
|
4876 |
getOuterHTML,
|
|
|
4877 |
setOuterHTML,
|
|
|
4878 |
decode,
|
|
|
4879 |
encode,
|
|
|
4880 |
insertAfter,
|
|
|
4881 |
replace,
|
|
|
4882 |
rename,
|
|
|
4883 |
findCommonAncestor,
|
|
|
4884 |
run,
|
|
|
4885 |
getAttribs,
|
|
|
4886 |
isEmpty,
|
|
|
4887 |
createRng,
|
|
|
4888 |
nodeIndex: findNodeIndex,
|
|
|
4889 |
split,
|
|
|
4890 |
bind: bind,
|
|
|
4891 |
unbind: unbind,
|
|
|
4892 |
fire,
|
|
|
4893 |
dispatch,
|
|
|
4894 |
getContentEditable,
|
|
|
4895 |
getContentEditableParent,
|
|
|
4896 |
isEditable,
|
|
|
4897 |
destroy,
|
|
|
4898 |
isChildOf,
|
|
|
4899 |
dumpRng
|
|
|
4900 |
};
|
|
|
4901 |
const attrHooks = setupAttrHooks(styles, settings, constant(self));
|
|
|
4902 |
return self;
|
|
|
4903 |
};
|
|
|
4904 |
DOMUtils.DOM = DOMUtils(document);
|
|
|
4905 |
DOMUtils.nodeIndex = findNodeIndex;
|
|
|
4906 |
|
|
|
4907 |
const DOM$b = DOMUtils.DOM;
|
|
|
4908 |
const QUEUED = 0;
|
|
|
4909 |
const LOADING = 1;
|
|
|
4910 |
const LOADED = 2;
|
|
|
4911 |
const FAILED = 3;
|
|
|
4912 |
class ScriptLoader {
|
|
|
4913 |
constructor(settings = {}) {
|
|
|
4914 |
this.states = {};
|
|
|
4915 |
this.queue = [];
|
|
|
4916 |
this.scriptLoadedCallbacks = {};
|
|
|
4917 |
this.queueLoadedCallbacks = [];
|
|
|
4918 |
this.loading = false;
|
|
|
4919 |
this.settings = settings;
|
|
|
4920 |
}
|
|
|
4921 |
_setReferrerPolicy(referrerPolicy) {
|
|
|
4922 |
this.settings.referrerPolicy = referrerPolicy;
|
|
|
4923 |
}
|
|
|
4924 |
loadScript(url) {
|
|
|
4925 |
return new Promise((resolve, reject) => {
|
|
|
4926 |
const dom = DOM$b;
|
|
|
4927 |
let elm;
|
|
|
4928 |
const cleanup = () => {
|
|
|
4929 |
dom.remove(id);
|
|
|
4930 |
if (elm) {
|
|
|
4931 |
elm.onerror = elm.onload = elm = null;
|
|
|
4932 |
}
|
|
|
4933 |
};
|
|
|
4934 |
const done = () => {
|
|
|
4935 |
cleanup();
|
|
|
4936 |
resolve();
|
|
|
4937 |
};
|
|
|
4938 |
const error = () => {
|
|
|
4939 |
cleanup();
|
|
|
4940 |
reject('Failed to load script: ' + url);
|
|
|
4941 |
};
|
|
|
4942 |
const id = dom.uniqueId();
|
|
|
4943 |
elm = document.createElement('script');
|
|
|
4944 |
elm.id = id;
|
|
|
4945 |
elm.type = 'text/javascript';
|
|
|
4946 |
elm.src = Tools._addCacheSuffix(url);
|
|
|
4947 |
if (this.settings.referrerPolicy) {
|
|
|
4948 |
dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
|
|
|
4949 |
}
|
|
|
4950 |
elm.onload = done;
|
|
|
4951 |
elm.onerror = error;
|
|
|
4952 |
(document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
|
|
|
4953 |
});
|
|
|
4954 |
}
|
|
|
4955 |
isDone(url) {
|
|
|
4956 |
return this.states[url] === LOADED;
|
|
|
4957 |
}
|
|
|
4958 |
markDone(url) {
|
|
|
4959 |
this.states[url] = LOADED;
|
|
|
4960 |
}
|
|
|
4961 |
add(url) {
|
|
|
4962 |
const self = this;
|
|
|
4963 |
self.queue.push(url);
|
|
|
4964 |
const state = self.states[url];
|
|
|
4965 |
if (state === undefined) {
|
|
|
4966 |
self.states[url] = QUEUED;
|
|
|
4967 |
}
|
|
|
4968 |
return new Promise((resolve, reject) => {
|
|
|
4969 |
if (!self.scriptLoadedCallbacks[url]) {
|
|
|
4970 |
self.scriptLoadedCallbacks[url] = [];
|
|
|
4971 |
}
|
|
|
4972 |
self.scriptLoadedCallbacks[url].push({
|
|
|
4973 |
resolve,
|
|
|
4974 |
reject
|
|
|
4975 |
});
|
|
|
4976 |
});
|
|
|
4977 |
}
|
|
|
4978 |
load(url) {
|
|
|
4979 |
return this.add(url);
|
|
|
4980 |
}
|
|
|
4981 |
remove(url) {
|
|
|
4982 |
delete this.states[url];
|
|
|
4983 |
delete this.scriptLoadedCallbacks[url];
|
|
|
4984 |
}
|
|
|
4985 |
loadQueue() {
|
|
|
4986 |
const queue = this.queue;
|
|
|
4987 |
this.queue = [];
|
|
|
4988 |
return this.loadScripts(queue);
|
|
|
4989 |
}
|
|
|
4990 |
loadScripts(scripts) {
|
|
|
4991 |
const self = this;
|
|
|
4992 |
const execCallbacks = (name, url) => {
|
|
|
4993 |
get$a(self.scriptLoadedCallbacks, url).each(callbacks => {
|
|
|
4994 |
each$e(callbacks, callback => callback[name](url));
|
|
|
4995 |
});
|
|
|
4996 |
delete self.scriptLoadedCallbacks[url];
|
|
|
4997 |
};
|
|
|
4998 |
const processResults = results => {
|
|
|
4999 |
const failures = filter$5(results, result => result.status === 'rejected');
|
|
|
5000 |
if (failures.length > 0) {
|
|
|
5001 |
return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason]));
|
|
|
5002 |
} else {
|
|
|
5003 |
return Promise.resolve();
|
|
|
5004 |
}
|
|
|
5005 |
};
|
|
|
5006 |
const load = urls => Promise.allSettled(map$3(urls, url => {
|
|
|
5007 |
if (self.states[url] === LOADED) {
|
|
|
5008 |
execCallbacks('resolve', url);
|
|
|
5009 |
return Promise.resolve();
|
|
|
5010 |
} else if (self.states[url] === FAILED) {
|
|
|
5011 |
execCallbacks('reject', url);
|
|
|
5012 |
return Promise.reject(url);
|
|
|
5013 |
} else {
|
|
|
5014 |
self.states[url] = LOADING;
|
|
|
5015 |
return self.loadScript(url).then(() => {
|
|
|
5016 |
self.states[url] = LOADED;
|
|
|
5017 |
execCallbacks('resolve', url);
|
|
|
5018 |
const queue = self.queue;
|
|
|
5019 |
if (queue.length > 0) {
|
|
|
5020 |
self.queue = [];
|
|
|
5021 |
return load(queue).then(processResults);
|
|
|
5022 |
} else {
|
|
|
5023 |
return Promise.resolve();
|
|
|
5024 |
}
|
|
|
5025 |
}, () => {
|
|
|
5026 |
self.states[url] = FAILED;
|
|
|
5027 |
execCallbacks('reject', url);
|
|
|
5028 |
return Promise.reject(url);
|
|
|
5029 |
});
|
|
|
5030 |
}
|
|
|
5031 |
}));
|
|
|
5032 |
const processQueue = urls => {
|
|
|
5033 |
self.loading = true;
|
|
|
5034 |
return load(urls).then(results => {
|
|
|
5035 |
self.loading = false;
|
|
|
5036 |
const nextQueuedItem = self.queueLoadedCallbacks.shift();
|
|
|
5037 |
Optional.from(nextQueuedItem).each(call);
|
|
|
5038 |
return processResults(results);
|
|
|
5039 |
});
|
|
|
5040 |
};
|
|
|
5041 |
const uniqueScripts = stringArray(scripts);
|
|
|
5042 |
if (self.loading) {
|
|
|
5043 |
return new Promise((resolve, reject) => {
|
|
|
5044 |
self.queueLoadedCallbacks.push(() => {
|
|
|
5045 |
processQueue(uniqueScripts).then(resolve, reject);
|
|
|
5046 |
});
|
|
|
5047 |
});
|
|
|
5048 |
} else {
|
|
|
5049 |
return processQueue(uniqueScripts);
|
|
|
5050 |
}
|
|
|
5051 |
}
|
|
|
5052 |
}
|
|
|
5053 |
ScriptLoader.ScriptLoader = new ScriptLoader();
|
|
|
5054 |
|
|
|
5055 |
const isDuplicated = (items, item) => {
|
|
|
5056 |
const firstIndex = items.indexOf(item);
|
|
|
5057 |
return firstIndex !== -1 && items.indexOf(item, firstIndex + 1) > firstIndex;
|
|
|
5058 |
};
|
|
|
5059 |
const isRaw = str => isObject(str) && has$2(str, 'raw');
|
|
|
5060 |
const isTokenised = str => isArray$1(str) && str.length > 1;
|
|
|
5061 |
const data = {};
|
|
|
5062 |
const currentCode = Cell('en');
|
|
|
5063 |
const getLanguageData = () => get$a(data, currentCode.get());
|
|
|
5064 |
const getData$1 = () => map$2(data, value => ({ ...value }));
|
|
|
5065 |
const setCode = newCode => {
|
|
|
5066 |
if (newCode) {
|
|
|
5067 |
currentCode.set(newCode);
|
|
|
5068 |
}
|
|
|
5069 |
};
|
|
|
5070 |
const getCode = () => currentCode.get();
|
|
|
5071 |
const add$1 = (code, items) => {
|
|
|
5072 |
let langData = data[code];
|
|
|
5073 |
if (!langData) {
|
|
|
5074 |
data[code] = langData = {};
|
|
|
5075 |
}
|
|
|
5076 |
const lcNames = map$3(keys(items), name => name.toLowerCase());
|
|
|
5077 |
each$d(items, (translation, name) => {
|
|
|
5078 |
const lcName = name.toLowerCase();
|
|
|
5079 |
if (lcName !== name && isDuplicated(lcNames, lcName)) {
|
|
|
5080 |
if (!has$2(items, lcName)) {
|
|
|
5081 |
langData[lcName] = translation;
|
|
|
5082 |
}
|
|
|
5083 |
langData[name] = translation;
|
|
|
5084 |
} else {
|
|
|
5085 |
langData[lcName] = translation;
|
|
|
5086 |
}
|
|
|
5087 |
});
|
|
|
5088 |
};
|
|
|
5089 |
const translate = text => {
|
|
|
5090 |
const langData = getLanguageData().getOr({});
|
|
|
5091 |
const toString = obj => {
|
|
|
5092 |
if (isFunction(obj)) {
|
|
|
5093 |
return Object.prototype.toString.call(obj);
|
|
|
5094 |
}
|
|
|
5095 |
return !isEmpty(obj) ? '' + obj : '';
|
|
|
5096 |
};
|
|
|
5097 |
const isEmpty = text => text === '' || text === null || text === undefined;
|
|
|
5098 |
const getLangData = text => {
|
|
|
5099 |
const textStr = toString(text);
|
|
|
5100 |
return has$2(langData, textStr) ? toString(langData[textStr]) : get$a(langData, textStr.toLowerCase()).map(toString).getOr(textStr);
|
|
|
5101 |
};
|
|
|
5102 |
const removeContext = str => str.replace(/{context:\w+}$/, '');
|
|
|
5103 |
if (isEmpty(text)) {
|
|
|
5104 |
return '';
|
|
|
5105 |
}
|
|
|
5106 |
if (isRaw(text)) {
|
|
|
5107 |
return toString(text.raw);
|
|
|
5108 |
}
|
|
|
5109 |
if (isTokenised(text)) {
|
|
|
5110 |
const values = text.slice(1);
|
|
|
5111 |
const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1);
|
|
|
5112 |
return removeContext(substitued);
|
|
|
5113 |
}
|
|
|
5114 |
return removeContext(getLangData(text));
|
|
|
5115 |
};
|
|
|
5116 |
const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl');
|
|
|
5117 |
const hasCode = code => has$2(data, code);
|
|
|
5118 |
const I18n = {
|
|
|
5119 |
getData: getData$1,
|
|
|
5120 |
setCode,
|
|
|
5121 |
getCode,
|
|
|
5122 |
add: add$1,
|
|
|
5123 |
translate,
|
|
|
5124 |
isRtl: isRtl$1,
|
|
|
5125 |
hasCode
|
|
|
5126 |
};
|
|
|
5127 |
|
|
|
5128 |
const AddOnManager = () => {
|
|
|
5129 |
const items = [];
|
|
|
5130 |
const urls = {};
|
|
|
5131 |
const lookup = {};
|
|
|
5132 |
const _listeners = [];
|
|
|
5133 |
const runListeners = (name, state) => {
|
|
|
5134 |
const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state);
|
|
|
5135 |
each$e(matchedListeners, listener => listener.resolve());
|
|
|
5136 |
};
|
|
|
5137 |
const isLoaded = name => has$2(urls, name);
|
|
|
5138 |
const isAdded = name => has$2(lookup, name);
|
|
|
5139 |
const get = name => {
|
|
|
5140 |
if (lookup[name]) {
|
|
|
5141 |
return lookup[name].instance;
|
|
|
5142 |
}
|
|
|
5143 |
return undefined;
|
|
|
5144 |
};
|
|
|
5145 |
const loadLanguagePack = (name, languages) => {
|
|
|
5146 |
const language = I18n.getCode();
|
|
|
5147 |
const wrappedLanguages = ',' + (languages || '') + ',';
|
|
|
5148 |
if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) {
|
|
|
5149 |
return;
|
|
|
5150 |
}
|
|
|
5151 |
ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
|
|
|
5152 |
};
|
|
|
5153 |
const requireLangPack = (name, languages) => {
|
|
|
5154 |
if (AddOnManager.languageLoad !== false) {
|
|
|
5155 |
if (isLoaded(name)) {
|
|
|
5156 |
loadLanguagePack(name, languages);
|
|
|
5157 |
} else {
|
|
|
5158 |
waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages));
|
|
|
5159 |
}
|
|
|
5160 |
}
|
|
|
5161 |
};
|
|
|
5162 |
const add = (id, addOn) => {
|
|
|
5163 |
items.push(addOn);
|
|
|
5164 |
lookup[id] = { instance: addOn };
|
|
|
5165 |
runListeners(id, 'added');
|
|
|
5166 |
return addOn;
|
|
|
5167 |
};
|
|
|
5168 |
const remove = name => {
|
|
|
5169 |
delete urls[name];
|
|
|
5170 |
delete lookup[name];
|
|
|
5171 |
};
|
|
|
5172 |
const createUrl = (baseUrl, dep) => {
|
|
|
5173 |
if (isString(dep)) {
|
|
|
5174 |
return isString(baseUrl) ? {
|
|
|
5175 |
prefix: '',
|
|
|
5176 |
resource: dep,
|
|
|
5177 |
suffix: ''
|
|
|
5178 |
} : {
|
|
|
5179 |
prefix: baseUrl.prefix,
|
|
|
5180 |
resource: dep,
|
|
|
5181 |
suffix: baseUrl.suffix
|
|
|
5182 |
};
|
|
|
5183 |
} else {
|
|
|
5184 |
return dep;
|
|
|
5185 |
}
|
|
|
5186 |
};
|
|
|
5187 |
const load = (name, addOnUrl) => {
|
|
|
5188 |
if (urls[name]) {
|
|
|
5189 |
return Promise.resolve();
|
|
|
5190 |
}
|
|
|
5191 |
let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
|
|
|
5192 |
if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
|
|
|
5193 |
urlString = AddOnManager.baseURL + '/' + urlString;
|
|
|
5194 |
}
|
|
|
5195 |
urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
|
|
|
5196 |
const done = () => {
|
|
|
5197 |
runListeners(name, 'loaded');
|
|
|
5198 |
return Promise.resolve();
|
|
|
5199 |
};
|
|
|
5200 |
if (lookup[name]) {
|
|
|
5201 |
return done();
|
|
|
5202 |
} else {
|
|
|
5203 |
return ScriptLoader.ScriptLoader.add(urlString).then(done);
|
|
|
5204 |
}
|
|
|
5205 |
};
|
|
|
5206 |
const waitFor = (name, state = 'added') => {
|
|
|
5207 |
if (state === 'added' && isAdded(name)) {
|
|
|
5208 |
return Promise.resolve();
|
|
|
5209 |
} else if (state === 'loaded' && isLoaded(name)) {
|
|
|
5210 |
return Promise.resolve();
|
|
|
5211 |
} else {
|
|
|
5212 |
return new Promise(resolve => {
|
|
|
5213 |
_listeners.push({
|
|
|
5214 |
name,
|
|
|
5215 |
state,
|
|
|
5216 |
resolve
|
|
|
5217 |
});
|
|
|
5218 |
});
|
|
|
5219 |
}
|
|
|
5220 |
};
|
|
|
5221 |
return {
|
|
|
5222 |
items,
|
|
|
5223 |
urls,
|
|
|
5224 |
lookup,
|
|
|
5225 |
get,
|
|
|
5226 |
requireLangPack,
|
|
|
5227 |
add,
|
|
|
5228 |
remove,
|
|
|
5229 |
createUrl,
|
|
|
5230 |
load,
|
|
|
5231 |
waitFor
|
|
|
5232 |
};
|
|
|
5233 |
};
|
|
|
5234 |
AddOnManager.languageLoad = true;
|
|
|
5235 |
AddOnManager.baseURL = '';
|
|
|
5236 |
AddOnManager.PluginManager = AddOnManager();
|
|
|
5237 |
AddOnManager.ThemeManager = AddOnManager();
|
|
|
5238 |
AddOnManager.ModelManager = AddOnManager();
|
|
|
5239 |
|
|
|
5240 |
const first$1 = (fn, rate) => {
|
|
|
5241 |
let timer = null;
|
|
|
5242 |
const cancel = () => {
|
|
|
5243 |
if (!isNull(timer)) {
|
|
|
5244 |
clearTimeout(timer);
|
|
|
5245 |
timer = null;
|
|
|
5246 |
}
|
|
|
5247 |
};
|
|
|
5248 |
const throttle = (...args) => {
|
|
|
5249 |
if (isNull(timer)) {
|
|
|
5250 |
timer = setTimeout(() => {
|
|
|
5251 |
timer = null;
|
|
|
5252 |
fn.apply(null, args);
|
|
|
5253 |
}, rate);
|
|
|
5254 |
}
|
|
|
5255 |
};
|
|
|
5256 |
return {
|
|
|
5257 |
cancel,
|
|
|
5258 |
throttle
|
|
|
5259 |
};
|
|
|
5260 |
};
|
| 1441 |
ariadna |
5261 |
const last = (fn, rate) => {
|
| 1 |
efrain |
5262 |
let timer = null;
|
|
|
5263 |
const cancel = () => {
|
|
|
5264 |
if (!isNull(timer)) {
|
|
|
5265 |
clearTimeout(timer);
|
|
|
5266 |
timer = null;
|
|
|
5267 |
}
|
|
|
5268 |
};
|
|
|
5269 |
const throttle = (...args) => {
|
|
|
5270 |
cancel();
|
|
|
5271 |
timer = setTimeout(() => {
|
|
|
5272 |
timer = null;
|
|
|
5273 |
fn.apply(null, args);
|
|
|
5274 |
}, rate);
|
|
|
5275 |
};
|
|
|
5276 |
return {
|
|
|
5277 |
cancel,
|
|
|
5278 |
throttle
|
|
|
5279 |
};
|
|
|
5280 |
};
|
|
|
5281 |
|
| 1441 |
ariadna |
5282 |
const ancestor$1 = (scope, selector, isRoot) => ancestor$3(scope, selector, isRoot).isSome();
|
|
|
5283 |
|
| 1 |
efrain |
5284 |
const annotation = constant('mce-annotation');
|
|
|
5285 |
const dataAnnotation = constant('data-mce-annotation');
|
|
|
5286 |
const dataAnnotationId = constant('data-mce-annotation-uid');
|
|
|
5287 |
const dataAnnotationActive = constant('data-mce-annotation-active');
|
|
|
5288 |
const dataAnnotationClasses = constant('data-mce-annotation-classes');
|
|
|
5289 |
const dataAnnotationAttributes = constant('data-mce-annotation-attrs');
|
|
|
5290 |
|
|
|
5291 |
const isRoot$1 = root => node => eq(node, root);
|
|
|
5292 |
const identify = (editor, annotationName) => {
|
|
|
5293 |
const rng = editor.selection.getRng();
|
|
|
5294 |
const start = SugarElement.fromDom(rng.startContainer);
|
|
|
5295 |
const root = SugarElement.fromDom(editor.getBody());
|
|
|
5296 |
const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`);
|
|
|
5297 |
const newStart = child$1(start, rng.startOffset).getOr(start);
|
|
|
5298 |
const closest = closest$3(newStart, selector, isRoot$1(root));
|
|
|
5299 |
return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => {
|
|
|
5300 |
const elements = findMarkers(editor, uid);
|
|
|
5301 |
return {
|
|
|
5302 |
uid,
|
|
|
5303 |
name,
|
|
|
5304 |
elements
|
|
|
5305 |
};
|
|
|
5306 |
})));
|
|
|
5307 |
};
|
|
|
5308 |
const isAnnotation = elem => isElement$7(elem) && has(elem, annotation());
|
| 1441 |
ariadna |
5309 |
const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root));
|
| 1 |
efrain |
5310 |
const findMarkers = (editor, uid) => {
|
|
|
5311 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
5312 |
const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`);
|
|
|
5313 |
return filter$5(descendants$1, descendant => !isBogusElement(descendant, body));
|
|
|
5314 |
};
|
|
|
5315 |
const findAll = (editor, name) => {
|
|
|
5316 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
5317 |
const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`);
|
|
|
5318 |
const directory = {};
|
|
|
5319 |
each$e(markers, m => {
|
|
|
5320 |
if (!isBogusElement(m, body)) {
|
|
|
5321 |
const uid = get$9(m, dataAnnotationId());
|
|
|
5322 |
const nodesAlready = get$a(directory, uid).getOr([]);
|
|
|
5323 |
directory[uid] = nodesAlready.concat([m]);
|
|
|
5324 |
}
|
|
|
5325 |
});
|
|
|
5326 |
return directory;
|
|
|
5327 |
};
|
|
|
5328 |
|
|
|
5329 |
const setup$y = (editor, registry) => {
|
|
|
5330 |
const changeCallbacks = Cell({});
|
|
|
5331 |
const initData = () => ({
|
|
|
5332 |
listeners: [],
|
|
|
5333 |
previous: value$2()
|
|
|
5334 |
});
|
|
|
5335 |
const withCallbacks = (name, f) => {
|
|
|
5336 |
updateCallbacks(name, data => {
|
|
|
5337 |
f(data);
|
|
|
5338 |
return data;
|
|
|
5339 |
});
|
|
|
5340 |
};
|
|
|
5341 |
const updateCallbacks = (name, f) => {
|
|
|
5342 |
const callbackMap = changeCallbacks.get();
|
|
|
5343 |
const data = get$a(callbackMap, name).getOrThunk(initData);
|
|
|
5344 |
const outputData = f(data);
|
|
|
5345 |
callbackMap[name] = outputData;
|
|
|
5346 |
changeCallbacks.set(callbackMap);
|
|
|
5347 |
};
|
|
|
5348 |
const fireCallbacks = (name, uid, elements) => {
|
|
|
5349 |
withCallbacks(name, data => {
|
|
|
5350 |
each$e(data.listeners, f => f(true, name, {
|
|
|
5351 |
uid,
|
|
|
5352 |
nodes: map$3(elements, elem => elem.dom)
|
|
|
5353 |
}));
|
|
|
5354 |
});
|
|
|
5355 |
};
|
|
|
5356 |
const fireNoAnnotation = name => {
|
|
|
5357 |
withCallbacks(name, data => {
|
|
|
5358 |
each$e(data.listeners, f => f(false, name));
|
|
|
5359 |
});
|
|
|
5360 |
};
|
|
|
5361 |
const toggleActiveAttr = (uid, state) => {
|
|
|
5362 |
each$e(findMarkers(editor, uid), elem => {
|
|
|
5363 |
if (state) {
|
| 1441 |
ariadna |
5364 |
set$4(elem, dataAnnotationActive(), 'true');
|
| 1 |
efrain |
5365 |
} else {
|
| 1441 |
ariadna |
5366 |
remove$9(elem, dataAnnotationActive());
|
| 1 |
efrain |
5367 |
}
|
|
|
5368 |
});
|
|
|
5369 |
};
|
| 1441 |
ariadna |
5370 |
const onNodeChange = last(() => {
|
| 1 |
efrain |
5371 |
const annotations = sort(registry.getNames());
|
|
|
5372 |
each$e(annotations, name => {
|
|
|
5373 |
updateCallbacks(name, data => {
|
|
|
5374 |
const prev = data.previous.get();
|
|
|
5375 |
identify(editor, Optional.some(name)).fold(() => {
|
|
|
5376 |
prev.each(uid => {
|
|
|
5377 |
fireNoAnnotation(name);
|
|
|
5378 |
data.previous.clear();
|
|
|
5379 |
toggleActiveAttr(uid, false);
|
|
|
5380 |
});
|
|
|
5381 |
}, ({uid, name, elements}) => {
|
|
|
5382 |
if (!is$2(prev, uid)) {
|
|
|
5383 |
prev.each(uid => toggleActiveAttr(uid, false));
|
|
|
5384 |
fireCallbacks(name, uid, elements);
|
|
|
5385 |
data.previous.set(uid);
|
|
|
5386 |
toggleActiveAttr(uid, true);
|
|
|
5387 |
}
|
|
|
5388 |
});
|
|
|
5389 |
return {
|
|
|
5390 |
previous: data.previous,
|
|
|
5391 |
listeners: data.listeners
|
|
|
5392 |
};
|
|
|
5393 |
});
|
|
|
5394 |
});
|
|
|
5395 |
}, 30);
|
|
|
5396 |
editor.on('remove', () => {
|
|
|
5397 |
onNodeChange.cancel();
|
|
|
5398 |
});
|
|
|
5399 |
editor.on('NodeChange', () => {
|
|
|
5400 |
onNodeChange.throttle();
|
|
|
5401 |
});
|
|
|
5402 |
const addListener = (name, f) => {
|
|
|
5403 |
updateCallbacks(name, data => ({
|
|
|
5404 |
previous: data.previous,
|
|
|
5405 |
listeners: data.listeners.concat([f])
|
|
|
5406 |
}));
|
|
|
5407 |
};
|
|
|
5408 |
return { addListener };
|
|
|
5409 |
};
|
|
|
5410 |
|
|
|
5411 |
const setup$x = (editor, registry) => {
|
|
|
5412 |
const dataAnnotation$1 = dataAnnotation();
|
|
|
5413 |
const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup);
|
|
|
5414 |
const removeDirectAnnotation = node => {
|
|
|
5415 |
var _a, _b;
|
|
|
5416 |
node.attr(dataAnnotationId(), null);
|
|
|
5417 |
node.attr(dataAnnotation(), null);
|
|
|
5418 |
node.attr(dataAnnotationActive(), null);
|
|
|
5419 |
const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]);
|
|
|
5420 |
const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]);
|
|
|
5421 |
each$e(customAttrNames, name => node.attr(name, null));
|
|
|
5422 |
const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
|
|
|
5423 |
const newClassList = difference(classList, [annotation()].concat(customClasses));
|
|
|
5424 |
node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null);
|
|
|
5425 |
node.attr(dataAnnotationClasses(), null);
|
|
|
5426 |
node.attr(dataAnnotationAttributes(), null);
|
|
|
5427 |
};
|
|
|
5428 |
editor.serializer.addTempAttr(dataAnnotationActive());
|
|
|
5429 |
editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => {
|
|
|
5430 |
for (const node of nodes) {
|
|
|
5431 |
identifyParserNode(node).each(settings => {
|
|
|
5432 |
if (settings.persistent === false) {
|
|
|
5433 |
if (node.name === 'span') {
|
|
|
5434 |
node.unwrap();
|
|
|
5435 |
} else {
|
|
|
5436 |
removeDirectAnnotation(node);
|
|
|
5437 |
}
|
|
|
5438 |
}
|
|
|
5439 |
});
|
|
|
5440 |
}
|
|
|
5441 |
});
|
|
|
5442 |
};
|
|
|
5443 |
|
| 1441 |
ariadna |
5444 |
const create$b = () => {
|
| 1 |
efrain |
5445 |
const annotations = {};
|
|
|
5446 |
const register = (name, settings) => {
|
|
|
5447 |
annotations[name] = {
|
|
|
5448 |
name,
|
|
|
5449 |
settings
|
|
|
5450 |
};
|
|
|
5451 |
};
|
|
|
5452 |
const lookup = name => get$a(annotations, name).map(a => a.settings);
|
|
|
5453 |
const getNames = () => keys(annotations);
|
|
|
5454 |
return {
|
|
|
5455 |
register,
|
|
|
5456 |
lookup,
|
|
|
5457 |
getNames
|
|
|
5458 |
};
|
|
|
5459 |
};
|
|
|
5460 |
|
| 1441 |
ariadna |
5461 |
const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
|
5462 |
const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295;
|
|
|
5463 |
|
| 1 |
efrain |
5464 |
let unique = 0;
|
|
|
5465 |
const generate$1 = prefix => {
|
|
|
5466 |
const date = new Date();
|
|
|
5467 |
const time = date.getTime();
|
| 1441 |
ariadna |
5468 |
const random$1 = Math.floor(random() * 1000000000);
|
| 1 |
efrain |
5469 |
unique++;
|
| 1441 |
ariadna |
5470 |
return prefix + '_' + random$1 + unique + String(time);
|
| 1 |
efrain |
5471 |
};
|
|
|
5472 |
|
|
|
5473 |
const add = (element, classes) => {
|
|
|
5474 |
each$e(classes, x => {
|
|
|
5475 |
add$2(element, x);
|
|
|
5476 |
});
|
|
|
5477 |
};
|
| 1441 |
ariadna |
5478 |
const remove$3 = (element, classes) => {
|
| 1 |
efrain |
5479 |
each$e(classes, x => {
|
| 1441 |
ariadna |
5480 |
remove$6(element, x);
|
| 1 |
efrain |
5481 |
});
|
|
|
5482 |
};
|
|
|
5483 |
|
|
|
5484 |
const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
|
|
|
5485 |
const shallow$1 = original => clone$2(original, false);
|
|
|
5486 |
const deep$1 = original => clone$2(original, true);
|
|
|
5487 |
const shallowAs = (original, tag) => {
|
|
|
5488 |
const nu = SugarElement.fromTag(tag);
|
|
|
5489 |
const attributes = clone$4(original);
|
|
|
5490 |
setAll$1(nu, attributes);
|
|
|
5491 |
return nu;
|
|
|
5492 |
};
|
|
|
5493 |
const mutate = (original, tag) => {
|
|
|
5494 |
const nu = shallowAs(original, tag);
|
|
|
5495 |
after$4(original, nu);
|
|
|
5496 |
const children = children$1(original);
|
|
|
5497 |
append(nu, children);
|
| 1441 |
ariadna |
5498 |
remove$4(original);
|
| 1 |
efrain |
5499 |
return nu;
|
|
|
5500 |
};
|
|
|
5501 |
|
|
|
5502 |
const TextWalker = (startNode, rootNode, isBoundary = never) => {
|
|
|
5503 |
const walker = new DomTreeWalker(startNode, rootNode);
|
|
|
5504 |
const walk = direction => {
|
|
|
5505 |
let next;
|
|
|
5506 |
do {
|
|
|
5507 |
next = walker[direction]();
|
| 1441 |
ariadna |
5508 |
} while (next && !isText$b(next) && !isBoundary(next));
|
|
|
5509 |
return Optional.from(next).filter(isText$b);
|
| 1 |
efrain |
5510 |
};
|
|
|
5511 |
return {
|
| 1441 |
ariadna |
5512 |
current: () => Optional.from(walker.current()).filter(isText$b),
|
| 1 |
efrain |
5513 |
next: () => walk('next'),
|
|
|
5514 |
prev: () => walk('prev'),
|
|
|
5515 |
prev2: () => walk('prev2')
|
|
|
5516 |
};
|
|
|
5517 |
};
|
|
|
5518 |
|
|
|
5519 |
const TextSeeker = (dom, isBoundary) => {
|
|
|
5520 |
const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node);
|
|
|
5521 |
const walk = (node, offset, walker, process) => {
|
| 1441 |
ariadna |
5522 |
if (isText$b(node)) {
|
| 1 |
efrain |
5523 |
const newOffset = process(node, offset, node.data);
|
|
|
5524 |
if (newOffset !== -1) {
|
|
|
5525 |
return Optional.some({
|
|
|
5526 |
container: node,
|
|
|
5527 |
offset: newOffset
|
|
|
5528 |
});
|
|
|
5529 |
}
|
|
|
5530 |
}
|
|
|
5531 |
return walker().bind(next => walk(next.container, next.offset, walker, process));
|
|
|
5532 |
};
|
|
|
5533 |
const backwards = (node, offset, process, root) => {
|
|
|
5534 |
const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
|
|
|
5535 |
return walk(node, offset, () => walker.prev().map(prev => ({
|
|
|
5536 |
container: prev,
|
|
|
5537 |
offset: prev.length
|
|
|
5538 |
})), process).getOrNull();
|
|
|
5539 |
};
|
|
|
5540 |
const forwards = (node, offset, process, root) => {
|
|
|
5541 |
const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
|
|
|
5542 |
return walk(node, offset, () => walker.next().map(next => ({
|
|
|
5543 |
container: next,
|
|
|
5544 |
offset: 0
|
|
|
5545 |
})), process).getOrNull();
|
|
|
5546 |
};
|
|
|
5547 |
return {
|
|
|
5548 |
backwards,
|
|
|
5549 |
forwards
|
|
|
5550 |
};
|
|
|
5551 |
};
|
|
|
5552 |
|
| 1441 |
ariadna |
5553 |
const NodeValue = (is, name) => {
|
|
|
5554 |
const get = element => {
|
|
|
5555 |
if (!is(element)) {
|
|
|
5556 |
throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
|
|
|
5557 |
}
|
|
|
5558 |
return getOption(element).getOr('');
|
|
|
5559 |
};
|
|
|
5560 |
const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
|
|
|
5561 |
const set = (element, value) => {
|
|
|
5562 |
if (!is(element)) {
|
|
|
5563 |
throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
|
|
|
5564 |
}
|
|
|
5565 |
element.dom.nodeValue = value;
|
|
|
5566 |
};
|
|
|
5567 |
return {
|
|
|
5568 |
get,
|
|
|
5569 |
getOption,
|
|
|
5570 |
set
|
|
|
5571 |
};
|
|
|
5572 |
};
|
|
|
5573 |
|
|
|
5574 |
const api$1 = NodeValue(isText$c, 'text');
|
|
|
5575 |
const get$3 = element => api$1.get(element);
|
|
|
5576 |
const getOption = element => api$1.getOption(element);
|
|
|
5577 |
const set = (element, value) => api$1.set(element, value);
|
|
|
5578 |
|
|
|
5579 |
const tableCells = [
|
|
|
5580 |
'td',
|
|
|
5581 |
'th'
|
|
|
5582 |
];
|
|
|
5583 |
const tableSections = [
|
|
|
5584 |
'thead',
|
|
|
5585 |
'tbody',
|
|
|
5586 |
'tfoot'
|
|
|
5587 |
];
|
|
|
5588 |
const textBlocks = [
|
|
|
5589 |
'h1',
|
|
|
5590 |
'h2',
|
|
|
5591 |
'h3',
|
|
|
5592 |
'h4',
|
|
|
5593 |
'h5',
|
|
|
5594 |
'h6',
|
|
|
5595 |
'p',
|
|
|
5596 |
'div',
|
|
|
5597 |
'address',
|
|
|
5598 |
'pre',
|
|
|
5599 |
'form',
|
|
|
5600 |
'blockquote',
|
|
|
5601 |
'center',
|
|
|
5602 |
'dir',
|
|
|
5603 |
'fieldset',
|
|
|
5604 |
'header',
|
|
|
5605 |
'footer',
|
|
|
5606 |
'article',
|
|
|
5607 |
'section',
|
|
|
5608 |
'hgroup',
|
|
|
5609 |
'aside',
|
|
|
5610 |
'nav',
|
|
|
5611 |
'figure'
|
|
|
5612 |
];
|
|
|
5613 |
const listItems$1 = [
|
|
|
5614 |
'li',
|
|
|
5615 |
'dd',
|
|
|
5616 |
'dt'
|
|
|
5617 |
];
|
|
|
5618 |
const lists = [
|
|
|
5619 |
'ul',
|
|
|
5620 |
'ol',
|
|
|
5621 |
'dl'
|
|
|
5622 |
];
|
|
|
5623 |
const wsElements = [
|
|
|
5624 |
'pre',
|
|
|
5625 |
'script',
|
|
|
5626 |
'textarea',
|
|
|
5627 |
'style'
|
|
|
5628 |
];
|
|
|
5629 |
const lazyLookup = items => {
|
|
|
5630 |
let lookup;
|
|
|
5631 |
return node => {
|
|
|
5632 |
lookup = lookup ? lookup : mapToObject(items, always);
|
|
|
5633 |
return has$2(lookup, name(node));
|
|
|
5634 |
};
|
|
|
5635 |
};
|
|
|
5636 |
const isTable$1 = node => name(node) === 'table';
|
|
|
5637 |
const isBr$5 = node => isElement$7(node) && name(node) === 'br';
|
|
|
5638 |
const isTextBlock$2 = lazyLookup(textBlocks);
|
|
|
5639 |
const isList = lazyLookup(lists);
|
|
|
5640 |
const isListItem$1 = lazyLookup(listItems$1);
|
|
|
5641 |
const isTableSection = lazyLookup(tableSections);
|
|
|
5642 |
const isTableCell$2 = lazyLookup(tableCells);
|
|
|
5643 |
const isWsPreserveElement = lazyLookup(wsElements);
|
|
|
5644 |
|
|
|
5645 |
const getLastChildren$1 = elm => {
|
|
|
5646 |
const children = [];
|
|
|
5647 |
let rawNode = elm.dom;
|
|
|
5648 |
while (rawNode) {
|
|
|
5649 |
children.push(SugarElement.fromDom(rawNode));
|
|
|
5650 |
rawNode = rawNode.lastChild;
|
|
|
5651 |
}
|
|
|
5652 |
return children;
|
|
|
5653 |
};
|
|
|
5654 |
const removeTrailingBr = elm => {
|
|
|
5655 |
const allBrs = descendants(elm, 'br');
|
|
|
5656 |
const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5);
|
|
|
5657 |
if (allBrs.length === brs.length) {
|
|
|
5658 |
each$e(brs, remove$4);
|
|
|
5659 |
}
|
|
|
5660 |
};
|
|
|
5661 |
const createPaddingBr = () => {
|
|
|
5662 |
const br = SugarElement.fromTag('br');
|
|
|
5663 |
set$4(br, 'data-mce-bogus', '1');
|
|
|
5664 |
return br;
|
|
|
5665 |
};
|
|
|
5666 |
const fillWithPaddingBr = elm => {
|
|
|
5667 |
empty(elm);
|
|
|
5668 |
append$1(elm, createPaddingBr());
|
|
|
5669 |
};
|
|
|
5670 |
const trimBlockTrailingBr = (elm, schema) => {
|
|
|
5671 |
lastChild(elm).each(lastChild => {
|
|
|
5672 |
prevSibling(lastChild).each(lastChildPrevSibling => {
|
|
|
5673 |
if (schema.isBlock(name(elm)) && isBr$5(lastChild) && schema.isBlock(name(lastChildPrevSibling))) {
|
|
|
5674 |
remove$4(lastChild);
|
|
|
5675 |
}
|
|
|
5676 |
});
|
|
|
5677 |
});
|
|
|
5678 |
};
|
|
|
5679 |
|
|
|
5680 |
const ZWSP$1 = zeroWidth;
|
|
|
5681 |
const isZwsp = isZwsp$2;
|
|
|
5682 |
const trim$2 = removeZwsp;
|
|
|
5683 |
const insert$5 = editor => editor.insertContent(ZWSP$1, { preserve_zwsp: true });
|
|
|
5684 |
|
|
|
5685 |
const isElement$5 = isElement$6;
|
|
|
5686 |
const isText$9 = isText$b;
|
|
|
5687 |
const isCaretContainerBlock$1 = node => {
|
|
|
5688 |
if (isText$9(node)) {
|
|
|
5689 |
node = node.parentNode;
|
|
|
5690 |
}
|
|
|
5691 |
return isElement$5(node) && node.hasAttribute('data-mce-caret');
|
|
|
5692 |
};
|
|
|
5693 |
const isCaretContainerInline = node => isText$9(node) && isZwsp(node.data);
|
|
|
5694 |
const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
|
|
|
5695 |
const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
|
|
|
5696 |
const insertInline$1 = (node, before) => {
|
|
|
5697 |
var _a;
|
|
|
5698 |
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
|
5699 |
const textNode = doc.createTextNode(ZWSP$1);
|
|
|
5700 |
const parentNode = node.parentNode;
|
|
|
5701 |
if (!before) {
|
|
|
5702 |
const sibling = node.nextSibling;
|
|
|
5703 |
if (isText$9(sibling)) {
|
|
|
5704 |
if (isCaretContainer$2(sibling)) {
|
|
|
5705 |
return sibling;
|
|
|
5706 |
}
|
|
|
5707 |
if (startsWithCaretContainer$1(sibling)) {
|
|
|
5708 |
sibling.splitText(1);
|
|
|
5709 |
return sibling;
|
|
|
5710 |
}
|
|
|
5711 |
}
|
|
|
5712 |
if (node.nextSibling) {
|
|
|
5713 |
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling);
|
|
|
5714 |
} else {
|
|
|
5715 |
parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode);
|
|
|
5716 |
}
|
|
|
5717 |
} else {
|
|
|
5718 |
const sibling = node.previousSibling;
|
|
|
5719 |
if (isText$9(sibling)) {
|
|
|
5720 |
if (isCaretContainer$2(sibling)) {
|
|
|
5721 |
return sibling;
|
|
|
5722 |
}
|
|
|
5723 |
if (endsWithCaretContainer$1(sibling)) {
|
|
|
5724 |
return sibling.splitText(sibling.data.length - 1);
|
|
|
5725 |
}
|
|
|
5726 |
}
|
|
|
5727 |
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node);
|
|
|
5728 |
}
|
|
|
5729 |
return textNode;
|
|
|
5730 |
};
|
|
|
5731 |
const isBeforeInline = pos => {
|
|
|
5732 |
const container = pos.container();
|
|
|
5733 |
if (!isText$b(container)) {
|
|
|
5734 |
return false;
|
|
|
5735 |
}
|
|
|
5736 |
return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
|
|
|
5737 |
};
|
|
|
5738 |
const isAfterInline = pos => {
|
|
|
5739 |
const container = pos.container();
|
|
|
5740 |
if (!isText$b(container)) {
|
|
|
5741 |
return false;
|
|
|
5742 |
}
|
|
|
5743 |
return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
|
|
|
5744 |
};
|
|
|
5745 |
const insertBlock = (blockName, node, before) => {
|
|
|
5746 |
var _a;
|
|
|
5747 |
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
|
5748 |
const blockNode = doc.createElement(blockName);
|
|
|
5749 |
blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
|
|
|
5750 |
blockNode.setAttribute('data-mce-bogus', 'all');
|
|
|
5751 |
blockNode.appendChild(createPaddingBr().dom);
|
|
|
5752 |
const parentNode = node.parentNode;
|
|
|
5753 |
if (!before) {
|
|
|
5754 |
if (node.nextSibling) {
|
|
|
5755 |
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling);
|
|
|
5756 |
} else {
|
|
|
5757 |
parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode);
|
|
|
5758 |
}
|
|
|
5759 |
} else {
|
|
|
5760 |
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node);
|
|
|
5761 |
}
|
|
|
5762 |
return blockNode;
|
|
|
5763 |
};
|
|
|
5764 |
const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1;
|
|
|
5765 |
const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1;
|
|
|
5766 |
const trimBogusBr = elm => {
|
|
|
5767 |
var _a;
|
|
|
5768 |
const brs = elm.getElementsByTagName('br');
|
|
|
5769 |
const lastBr = brs[brs.length - 1];
|
|
|
5770 |
if (isBogus$1(lastBr)) {
|
|
|
5771 |
(_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr);
|
|
|
5772 |
}
|
|
|
5773 |
};
|
|
|
5774 |
const showCaretContainerBlock = caretContainer => {
|
|
|
5775 |
if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
|
|
|
5776 |
trimBogusBr(caretContainer);
|
|
|
5777 |
caretContainer.removeAttribute('data-mce-caret');
|
|
|
5778 |
caretContainer.removeAttribute('data-mce-bogus');
|
|
|
5779 |
caretContainer.removeAttribute('style');
|
|
|
5780 |
caretContainer.removeAttribute('data-mce-style');
|
|
|
5781 |
caretContainer.removeAttribute('_moz_abspos');
|
|
|
5782 |
return caretContainer;
|
|
|
5783 |
}
|
|
|
5784 |
return null;
|
|
|
5785 |
};
|
|
|
5786 |
const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer);
|
|
|
5787 |
|
| 1 |
efrain |
5788 |
const round$2 = Math.round;
|
|
|
5789 |
const clone$1 = rect => {
|
|
|
5790 |
if (!rect) {
|
|
|
5791 |
return {
|
|
|
5792 |
left: 0,
|
|
|
5793 |
top: 0,
|
|
|
5794 |
bottom: 0,
|
|
|
5795 |
right: 0,
|
|
|
5796 |
width: 0,
|
|
|
5797 |
height: 0
|
|
|
5798 |
};
|
|
|
5799 |
}
|
|
|
5800 |
return {
|
|
|
5801 |
left: round$2(rect.left),
|
|
|
5802 |
top: round$2(rect.top),
|
|
|
5803 |
bottom: round$2(rect.bottom),
|
|
|
5804 |
right: round$2(rect.right),
|
|
|
5805 |
width: round$2(rect.width),
|
|
|
5806 |
height: round$2(rect.height)
|
|
|
5807 |
};
|
|
|
5808 |
};
|
|
|
5809 |
const collapse = (rect, toStart) => {
|
|
|
5810 |
rect = clone$1(rect);
|
|
|
5811 |
if (toStart) {
|
|
|
5812 |
rect.right = rect.left;
|
|
|
5813 |
} else {
|
|
|
5814 |
rect.left = rect.left + rect.width;
|
|
|
5815 |
rect.right = rect.left;
|
|
|
5816 |
}
|
|
|
5817 |
rect.width = 0;
|
|
|
5818 |
return rect;
|
|
|
5819 |
};
|
|
|
5820 |
const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
|
|
|
5821 |
const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
|
|
|
5822 |
const isAbove$1 = (rect1, rect2) => {
|
|
|
5823 |
const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
|
|
|
5824 |
if (rect1.bottom - halfHeight < rect2.top) {
|
|
|
5825 |
return true;
|
|
|
5826 |
}
|
|
|
5827 |
if (rect1.top > rect2.bottom) {
|
|
|
5828 |
return false;
|
|
|
5829 |
}
|
|
|
5830 |
return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
|
|
|
5831 |
};
|
|
|
5832 |
const isBelow$1 = (rect1, rect2) => {
|
|
|
5833 |
if (rect1.top > rect2.bottom) {
|
|
|
5834 |
return true;
|
|
|
5835 |
}
|
|
|
5836 |
if (rect1.bottom < rect2.top) {
|
|
|
5837 |
return false;
|
|
|
5838 |
}
|
|
|
5839 |
return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
|
|
|
5840 |
};
|
|
|
5841 |
const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
|
|
|
5842 |
const boundingClientRectFromRects = rects => {
|
|
|
5843 |
return foldl(rects, (acc, rect) => {
|
|
|
5844 |
return acc.fold(() => Optional.some(rect), prevRect => {
|
|
|
5845 |
const left = Math.min(rect.left, prevRect.left);
|
|
|
5846 |
const top = Math.min(rect.top, prevRect.top);
|
|
|
5847 |
const right = Math.max(rect.right, prevRect.right);
|
|
|
5848 |
const bottom = Math.max(rect.bottom, prevRect.bottom);
|
|
|
5849 |
return Optional.some({
|
|
|
5850 |
top,
|
|
|
5851 |
right,
|
|
|
5852 |
bottom,
|
|
|
5853 |
left,
|
|
|
5854 |
width: right - left,
|
|
|
5855 |
height: bottom - top
|
|
|
5856 |
});
|
|
|
5857 |
});
|
|
|
5858 |
}, Optional.none());
|
|
|
5859 |
};
|
|
|
5860 |
const distanceToRectEdgeFromXY = (rect, x, y) => {
|
|
|
5861 |
const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
|
|
|
5862 |
const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
|
|
|
5863 |
return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
|
|
|
5864 |
};
|
|
|
5865 |
const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
|
|
|
5866 |
|
|
|
5867 |
const getSelectedNode = range => {
|
|
|
5868 |
const startContainer = range.startContainer, startOffset = range.startOffset;
|
|
|
5869 |
if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
|
|
|
5870 |
return startContainer.childNodes[startOffset];
|
|
|
5871 |
}
|
|
|
5872 |
return null;
|
|
|
5873 |
};
|
|
|
5874 |
const getNode$1 = (container, offset) => {
|
|
|
5875 |
if (isElement$6(container) && container.hasChildNodes()) {
|
|
|
5876 |
const childNodes = container.childNodes;
|
|
|
5877 |
const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
|
|
|
5878 |
return childNodes[safeOffset];
|
|
|
5879 |
} else {
|
|
|
5880 |
return container;
|
|
|
5881 |
}
|
|
|
5882 |
};
|
|
|
5883 |
const getNodeUnsafe = (container, offset) => {
|
|
|
5884 |
if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
|
|
|
5885 |
return undefined;
|
|
|
5886 |
} else {
|
|
|
5887 |
return getNode$1(container, offset);
|
|
|
5888 |
}
|
|
|
5889 |
};
|
|
|
5890 |
|
|
|
5891 |
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]');
|
|
|
5892 |
const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
|
|
|
5893 |
|
|
|
5894 |
const or = (...args) => {
|
|
|
5895 |
return x => {
|
|
|
5896 |
for (let i = 0; i < args.length; i++) {
|
|
|
5897 |
if (args[i](x)) {
|
|
|
5898 |
return true;
|
|
|
5899 |
}
|
|
|
5900 |
}
|
|
|
5901 |
return false;
|
|
|
5902 |
};
|
|
|
5903 |
};
|
|
|
5904 |
const and = (...args) => {
|
|
|
5905 |
return x => {
|
|
|
5906 |
for (let i = 0; i < args.length; i++) {
|
|
|
5907 |
if (!args[i](x)) {
|
|
|
5908 |
return false;
|
|
|
5909 |
}
|
|
|
5910 |
}
|
|
|
5911 |
return true;
|
|
|
5912 |
};
|
|
|
5913 |
};
|
|
|
5914 |
|
| 1441 |
ariadna |
5915 |
const isContentEditableTrue$2 = isContentEditableTrue$3;
|
|
|
5916 |
const isContentEditableFalse$a = isContentEditableFalse$b;
|
|
|
5917 |
const isBr$4 = isBr$6;
|
|
|
5918 |
const isText$8 = isText$b;
|
|
|
5919 |
const isInvalidTextElement = matchNodeNames([
|
|
|
5920 |
'script',
|
|
|
5921 |
'style',
|
|
|
5922 |
'textarea'
|
|
|
5923 |
]);
|
|
|
5924 |
const isAtomicInline = matchNodeNames([
|
|
|
5925 |
'img',
|
|
|
5926 |
'input',
|
|
|
5927 |
'textarea',
|
|
|
5928 |
'hr',
|
|
|
5929 |
'iframe',
|
|
|
5930 |
'video',
|
|
|
5931 |
'audio',
|
|
|
5932 |
'object',
|
|
|
5933 |
'embed'
|
|
|
5934 |
]);
|
|
|
5935 |
const isTable = matchNodeNames(['table']);
|
|
|
5936 |
const isCaretContainer$1 = isCaretContainer$2;
|
|
|
5937 |
const isCaretCandidate$3 = node => {
|
|
|
5938 |
if (isCaretContainer$1(node)) {
|
|
|
5939 |
return false;
|
|
|
5940 |
}
|
|
|
5941 |
if (isText$8(node)) {
|
|
|
5942 |
return !isInvalidTextElement(node.parentNode);
|
|
|
5943 |
}
|
|
|
5944 |
return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node);
|
|
|
5945 |
};
|
|
|
5946 |
const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true';
|
|
|
5947 |
const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$a(node);
|
|
|
5948 |
const isInEditable = (node, root) => {
|
|
|
5949 |
for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
|
|
|
5950 |
if (isNonUiContentEditableFalse(tempNode)) {
|
|
|
5951 |
return false;
|
|
|
5952 |
}
|
|
|
5953 |
if (isContentEditableTrue$2(tempNode)) {
|
|
|
5954 |
return true;
|
|
|
5955 |
}
|
|
|
5956 |
}
|
|
|
5957 |
return true;
|
|
|
5958 |
};
|
|
|
5959 |
const isAtomicContentEditableFalse = node => {
|
|
|
5960 |
if (!isNonUiContentEditableFalse(node)) {
|
|
|
5961 |
return false;
|
|
|
5962 |
}
|
|
|
5963 |
return !foldl(from(node.getElementsByTagName('*')), (result, elm) => {
|
|
|
5964 |
return result || isContentEditableTrue$2(elm);
|
|
|
5965 |
}, false);
|
|
|
5966 |
};
|
|
|
5967 |
const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node);
|
|
|
5968 |
const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
|
|
|
5969 |
|
| 1 |
efrain |
5970 |
const isElement$4 = isElement$6;
|
|
|
5971 |
const isCaretCandidate$2 = isCaretCandidate$3;
|
|
|
5972 |
const isBlock$2 = matchStyleValues('display', 'block table');
|
|
|
5973 |
const isFloated = matchStyleValues('float', 'left right');
|
|
|
5974 |
const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
|
|
|
5975 |
const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap'));
|
| 1441 |
ariadna |
5976 |
const isText$7 = isText$b;
|
| 1 |
efrain |
5977 |
const isBr$3 = isBr$6;
|
|
|
5978 |
const nodeIndex$1 = DOMUtils.nodeIndex;
|
|
|
5979 |
const resolveIndex$1 = getNodeUnsafe;
|
|
|
5980 |
const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng();
|
|
|
5981 |
const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr);
|
|
|
5982 |
const isRange = rng => !!rng.setStart && !!rng.setEnd;
|
|
|
5983 |
const isHiddenWhiteSpaceRange = range => {
|
|
|
5984 |
const container = range.startContainer;
|
|
|
5985 |
const offset = range.startOffset;
|
| 1441 |
ariadna |
5986 |
if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$b(container)) {
|
| 1 |
efrain |
5987 |
const text = container.data;
|
|
|
5988 |
if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) {
|
|
|
5989 |
return true;
|
|
|
5990 |
}
|
|
|
5991 |
}
|
|
|
5992 |
return false;
|
|
|
5993 |
};
|
|
|
5994 |
const getBrClientRect = brNode => {
|
|
|
5995 |
const doc = brNode.ownerDocument;
|
|
|
5996 |
const rng = createRange$1(doc);
|
|
|
5997 |
const nbsp$1 = doc.createTextNode(nbsp);
|
|
|
5998 |
const parentNode = brNode.parentNode;
|
|
|
5999 |
parentNode.insertBefore(nbsp$1, brNode);
|
|
|
6000 |
rng.setStart(nbsp$1, 0);
|
|
|
6001 |
rng.setEnd(nbsp$1, 1);
|
|
|
6002 |
const clientRect = clone$1(rng.getBoundingClientRect());
|
|
|
6003 |
parentNode.removeChild(nbsp$1);
|
|
|
6004 |
return clientRect;
|
|
|
6005 |
};
|
|
|
6006 |
const getBoundingClientRectWebKitText = rng => {
|
|
|
6007 |
const sc = rng.startContainer;
|
|
|
6008 |
const ec = rng.endContainer;
|
|
|
6009 |
const so = rng.startOffset;
|
|
|
6010 |
const eo = rng.endOffset;
|
| 1441 |
ariadna |
6011 |
if (sc === ec && isText$b(ec) && so === 0 && eo === 1) {
|
| 1 |
efrain |
6012 |
const newRng = rng.cloneRange();
|
|
|
6013 |
newRng.setEndAfter(ec);
|
|
|
6014 |
return getBoundingClientRect$1(newRng);
|
|
|
6015 |
} else {
|
|
|
6016 |
return null;
|
|
|
6017 |
}
|
|
|
6018 |
};
|
|
|
6019 |
const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
|
|
|
6020 |
const getBoundingClientRect$1 = item => {
|
|
|
6021 |
var _a;
|
|
|
6022 |
let clientRect;
|
|
|
6023 |
const clientRects = item.getClientRects();
|
|
|
6024 |
if (clientRects.length > 0) {
|
|
|
6025 |
clientRect = clone$1(clientRects[0]);
|
|
|
6026 |
} else {
|
|
|
6027 |
clientRect = clone$1(item.getBoundingClientRect());
|
|
|
6028 |
}
|
|
|
6029 |
if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
|
|
|
6030 |
return getBrClientRect(item);
|
|
|
6031 |
}
|
|
|
6032 |
if (isZeroRect(clientRect) && isRange(item)) {
|
|
|
6033 |
return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect;
|
|
|
6034 |
}
|
|
|
6035 |
return clientRect;
|
|
|
6036 |
};
|
|
|
6037 |
const collapseAndInflateWidth = (clientRect, toStart) => {
|
|
|
6038 |
const newClientRect = collapse(clientRect, toStart);
|
|
|
6039 |
newClientRect.width = 1;
|
|
|
6040 |
newClientRect.right = newClientRect.left + 1;
|
|
|
6041 |
return newClientRect;
|
|
|
6042 |
};
|
|
|
6043 |
const getCaretPositionClientRects = caretPosition => {
|
|
|
6044 |
const clientRects = [];
|
|
|
6045 |
const addUniqueAndValidRect = clientRect => {
|
|
|
6046 |
if (clientRect.height === 0) {
|
|
|
6047 |
return;
|
|
|
6048 |
}
|
|
|
6049 |
if (clientRects.length > 0) {
|
|
|
6050 |
if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
|
|
|
6051 |
return;
|
|
|
6052 |
}
|
|
|
6053 |
}
|
|
|
6054 |
clientRects.push(clientRect);
|
|
|
6055 |
};
|
|
|
6056 |
const addCharacterOffset = (container, offset) => {
|
|
|
6057 |
const range = createRange$1(container.ownerDocument);
|
|
|
6058 |
if (offset < container.data.length) {
|
|
|
6059 |
if (isExtendingChar(container.data[offset])) {
|
|
|
6060 |
return;
|
|
|
6061 |
}
|
|
|
6062 |
if (isExtendingChar(container.data[offset - 1])) {
|
|
|
6063 |
range.setStart(container, offset);
|
|
|
6064 |
range.setEnd(container, offset + 1);
|
|
|
6065 |
if (!isHiddenWhiteSpaceRange(range)) {
|
|
|
6066 |
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
|
|
|
6067 |
return;
|
|
|
6068 |
}
|
|
|
6069 |
}
|
|
|
6070 |
}
|
|
|
6071 |
if (offset > 0) {
|
|
|
6072 |
range.setStart(container, offset - 1);
|
|
|
6073 |
range.setEnd(container, offset);
|
|
|
6074 |
if (!isHiddenWhiteSpaceRange(range)) {
|
|
|
6075 |
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
|
|
|
6076 |
}
|
|
|
6077 |
}
|
|
|
6078 |
if (offset < container.data.length) {
|
|
|
6079 |
range.setStart(container, offset);
|
|
|
6080 |
range.setEnd(container, offset + 1);
|
|
|
6081 |
if (!isHiddenWhiteSpaceRange(range)) {
|
|
|
6082 |
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true));
|
|
|
6083 |
}
|
|
|
6084 |
}
|
|
|
6085 |
};
|
|
|
6086 |
const container = caretPosition.container();
|
|
|
6087 |
const offset = caretPosition.offset();
|
|
|
6088 |
if (isText$7(container)) {
|
|
|
6089 |
addCharacterOffset(container, offset);
|
|
|
6090 |
return clientRects;
|
|
|
6091 |
}
|
|
|
6092 |
if (isElement$4(container)) {
|
|
|
6093 |
if (caretPosition.isAtEnd()) {
|
|
|
6094 |
const node = resolveIndex$1(container, offset);
|
|
|
6095 |
if (isText$7(node)) {
|
|
|
6096 |
addCharacterOffset(node, node.data.length);
|
|
|
6097 |
}
|
|
|
6098 |
if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
|
|
|
6099 |
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
|
|
|
6100 |
}
|
|
|
6101 |
} else {
|
|
|
6102 |
const node = resolveIndex$1(container, offset);
|
|
|
6103 |
if (isText$7(node)) {
|
|
|
6104 |
addCharacterOffset(node, 0);
|
|
|
6105 |
}
|
|
|
6106 |
if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
|
|
|
6107 |
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
|
|
|
6108 |
return clientRects;
|
|
|
6109 |
}
|
|
|
6110 |
const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
|
|
|
6111 |
if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
|
|
|
6112 |
if (isBlock$2(beforeNode) || isBlock$2(node) || !isValidElementCaretCandidate(node)) {
|
|
|
6113 |
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
|
|
|
6114 |
}
|
|
|
6115 |
}
|
|
|
6116 |
if (isValidElementCaretCandidate(node)) {
|
|
|
6117 |
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
|
|
|
6118 |
}
|
|
|
6119 |
}
|
|
|
6120 |
}
|
|
|
6121 |
return clientRects;
|
|
|
6122 |
};
|
|
|
6123 |
const CaretPosition = (container, offset, clientRects) => {
|
|
|
6124 |
const isAtStart = () => {
|
|
|
6125 |
if (isText$7(container)) {
|
|
|
6126 |
return offset === 0;
|
|
|
6127 |
}
|
|
|
6128 |
return offset === 0;
|
|
|
6129 |
};
|
|
|
6130 |
const isAtEnd = () => {
|
|
|
6131 |
if (isText$7(container)) {
|
|
|
6132 |
return offset >= container.data.length;
|
|
|
6133 |
}
|
|
|
6134 |
return offset >= container.childNodes.length;
|
|
|
6135 |
};
|
|
|
6136 |
const toRange = () => {
|
|
|
6137 |
const range = createRange$1(container.ownerDocument);
|
|
|
6138 |
range.setStart(container, offset);
|
|
|
6139 |
range.setEnd(container, offset);
|
|
|
6140 |
return range;
|
|
|
6141 |
};
|
|
|
6142 |
const getClientRects = () => {
|
|
|
6143 |
if (!clientRects) {
|
|
|
6144 |
clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
|
|
|
6145 |
}
|
|
|
6146 |
return clientRects;
|
|
|
6147 |
};
|
|
|
6148 |
const isVisible = () => getClientRects().length > 0;
|
|
|
6149 |
const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
|
|
|
6150 |
const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset);
|
|
|
6151 |
return {
|
|
|
6152 |
container: constant(container),
|
|
|
6153 |
offset: constant(offset),
|
|
|
6154 |
toRange,
|
|
|
6155 |
getClientRects,
|
|
|
6156 |
isVisible,
|
|
|
6157 |
isAtStart,
|
|
|
6158 |
isAtEnd,
|
|
|
6159 |
isEqual,
|
|
|
6160 |
getNode
|
|
|
6161 |
};
|
|
|
6162 |
};
|
|
|
6163 |
CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset);
|
|
|
6164 |
CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset);
|
|
|
6165 |
CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
|
|
|
6166 |
CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node));
|
| 1441 |
ariadna |
6167 |
CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$2(pos1.getClientRects()), isAbove$1).getOr(false);
|
|
|
6168 |
CaretPosition.isBelow = (pos1, pos2) => lift2(last$2(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
|
| 1 |
efrain |
6169 |
CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false;
|
|
|
6170 |
CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false;
|
| 1441 |
ariadna |
6171 |
CaretPosition.isTextPosition = pos => pos ? isText$b(pos.container()) : false;
|
| 1 |
efrain |
6172 |
CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos);
|
|
|
6173 |
|
|
|
6174 |
const trimEmptyTextNode$1 = (dom, node) => {
|
| 1441 |
ariadna |
6175 |
if (isText$b(node) && node.data.length === 0) {
|
| 1 |
efrain |
6176 |
dom.remove(node);
|
|
|
6177 |
}
|
|
|
6178 |
};
|
|
|
6179 |
const insertNode = (dom, rng, node) => {
|
|
|
6180 |
rng.insertNode(node);
|
|
|
6181 |
trimEmptyTextNode$1(dom, node.previousSibling);
|
|
|
6182 |
trimEmptyTextNode$1(dom, node.nextSibling);
|
|
|
6183 |
};
|
|
|
6184 |
const insertFragment = (dom, rng, frag) => {
|
|
|
6185 |
const firstChild = Optional.from(frag.firstChild);
|
|
|
6186 |
const lastChild = Optional.from(frag.lastChild);
|
|
|
6187 |
rng.insertNode(frag);
|
|
|
6188 |
firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling));
|
|
|
6189 |
lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling));
|
|
|
6190 |
};
|
|
|
6191 |
const rangeInsertNode = (dom, rng, node) => {
|
|
|
6192 |
if (isDocumentFragment(node)) {
|
|
|
6193 |
insertFragment(dom, rng, node);
|
|
|
6194 |
} else {
|
|
|
6195 |
insertNode(dom, rng, node);
|
|
|
6196 |
}
|
|
|
6197 |
};
|
|
|
6198 |
|
| 1441 |
ariadna |
6199 |
const isText$6 = isText$b;
|
|
|
6200 |
const isBogus = isBogus$1;
|
| 1 |
efrain |
6201 |
const nodeIndex = DOMUtils.nodeIndex;
|
|
|
6202 |
const normalizedParent = node => {
|
|
|
6203 |
const parentNode = node.parentNode;
|
|
|
6204 |
if (isBogus(parentNode)) {
|
|
|
6205 |
return normalizedParent(parentNode);
|
|
|
6206 |
}
|
|
|
6207 |
return parentNode;
|
|
|
6208 |
};
|
|
|
6209 |
const getChildNodes = node => {
|
|
|
6210 |
if (!node) {
|
|
|
6211 |
return [];
|
|
|
6212 |
}
|
|
|
6213 |
return reduce(node.childNodes, (result, node) => {
|
|
|
6214 |
if (isBogus(node) && node.nodeName !== 'BR') {
|
|
|
6215 |
result = result.concat(getChildNodes(node));
|
|
|
6216 |
} else {
|
|
|
6217 |
result.push(node);
|
|
|
6218 |
}
|
|
|
6219 |
return result;
|
|
|
6220 |
}, []);
|
|
|
6221 |
};
|
|
|
6222 |
const normalizedTextOffset = (node, offset) => {
|
|
|
6223 |
let tempNode = node;
|
|
|
6224 |
while (tempNode = tempNode.previousSibling) {
|
|
|
6225 |
if (!isText$6(tempNode)) {
|
|
|
6226 |
break;
|
|
|
6227 |
}
|
|
|
6228 |
offset += tempNode.data.length;
|
|
|
6229 |
}
|
|
|
6230 |
return offset;
|
|
|
6231 |
};
|
|
|
6232 |
const equal = a => b => a === b;
|
|
|
6233 |
const normalizedNodeIndex = node => {
|
|
|
6234 |
let nodes, index;
|
|
|
6235 |
nodes = getChildNodes(normalizedParent(node));
|
|
|
6236 |
index = findIndex$1(nodes, equal(node), node);
|
|
|
6237 |
nodes = nodes.slice(0, index + 1);
|
|
|
6238 |
const numTextFragments = reduce(nodes, (result, node, i) => {
|
|
|
6239 |
if (isText$6(node) && isText$6(nodes[i - 1])) {
|
|
|
6240 |
result++;
|
|
|
6241 |
}
|
|
|
6242 |
return result;
|
|
|
6243 |
}, 0);
|
|
|
6244 |
nodes = filter$3(nodes, matchNodeNames([node.nodeName]));
|
|
|
6245 |
index = findIndex$1(nodes, equal(node), node);
|
|
|
6246 |
return index - numTextFragments;
|
|
|
6247 |
};
|
|
|
6248 |
const createPathItem = node => {
|
|
|
6249 |
const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase();
|
|
|
6250 |
return name + '[' + normalizedNodeIndex(node) + ']';
|
|
|
6251 |
};
|
|
|
6252 |
const parentsUntil$1 = (root, node, predicate) => {
|
|
|
6253 |
const parents = [];
|
|
|
6254 |
for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
|
|
|
6255 |
if (predicate && predicate(tempNode)) {
|
|
|
6256 |
break;
|
|
|
6257 |
}
|
|
|
6258 |
parents.push(tempNode);
|
|
|
6259 |
}
|
|
|
6260 |
return parents;
|
|
|
6261 |
};
|
| 1441 |
ariadna |
6262 |
const create$a = (root, caretPosition) => {
|
| 1 |
efrain |
6263 |
let path = [];
|
|
|
6264 |
let container = caretPosition.container();
|
|
|
6265 |
let offset = caretPosition.offset();
|
|
|
6266 |
let outputOffset;
|
|
|
6267 |
if (isText$6(container)) {
|
|
|
6268 |
outputOffset = normalizedTextOffset(container, offset);
|
|
|
6269 |
} else {
|
|
|
6270 |
const childNodes = container.childNodes;
|
|
|
6271 |
if (offset >= childNodes.length) {
|
|
|
6272 |
outputOffset = 'after';
|
|
|
6273 |
offset = childNodes.length - 1;
|
|
|
6274 |
} else {
|
|
|
6275 |
outputOffset = 'before';
|
|
|
6276 |
}
|
|
|
6277 |
container = childNodes[offset];
|
|
|
6278 |
}
|
|
|
6279 |
path.push(createPathItem(container));
|
|
|
6280 |
let parents = parentsUntil$1(root, container);
|
| 1441 |
ariadna |
6281 |
parents = filter$3(parents, not(isBogus$1));
|
| 1 |
efrain |
6282 |
path = path.concat(map$1(parents, node => {
|
|
|
6283 |
return createPathItem(node);
|
|
|
6284 |
}));
|
|
|
6285 |
return path.reverse().join('/') + ',' + outputOffset;
|
|
|
6286 |
};
|
|
|
6287 |
const resolvePathItem = (node, name, index) => {
|
|
|
6288 |
let nodes = getChildNodes(node);
|
|
|
6289 |
nodes = filter$3(nodes, (node, index) => {
|
|
|
6290 |
return !isText$6(node) || !isText$6(nodes[index - 1]);
|
|
|
6291 |
});
|
|
|
6292 |
nodes = filter$3(nodes, matchNodeNames([name]));
|
|
|
6293 |
return nodes[index];
|
|
|
6294 |
};
|
|
|
6295 |
const findTextPosition = (container, offset) => {
|
|
|
6296 |
let node = container;
|
|
|
6297 |
let targetOffset = 0;
|
|
|
6298 |
while (isText$6(node)) {
|
|
|
6299 |
const dataLen = node.data.length;
|
|
|
6300 |
if (offset >= targetOffset && offset <= targetOffset + dataLen) {
|
|
|
6301 |
container = node;
|
|
|
6302 |
offset = offset - targetOffset;
|
|
|
6303 |
break;
|
|
|
6304 |
}
|
|
|
6305 |
if (!isText$6(node.nextSibling)) {
|
|
|
6306 |
container = node;
|
|
|
6307 |
offset = dataLen;
|
|
|
6308 |
break;
|
|
|
6309 |
}
|
|
|
6310 |
targetOffset += dataLen;
|
|
|
6311 |
node = node.nextSibling;
|
|
|
6312 |
}
|
|
|
6313 |
if (isText$6(container) && offset > container.data.length) {
|
|
|
6314 |
offset = container.data.length;
|
|
|
6315 |
}
|
|
|
6316 |
return CaretPosition(container, offset);
|
|
|
6317 |
};
|
|
|
6318 |
const resolve$1 = (root, path) => {
|
|
|
6319 |
if (!path) {
|
|
|
6320 |
return null;
|
|
|
6321 |
}
|
|
|
6322 |
const parts = path.split(',');
|
|
|
6323 |
const paths = parts[0].split('/');
|
|
|
6324 |
const offset = parts.length > 1 ? parts[1] : 'before';
|
|
|
6325 |
const container = reduce(paths, (result, value) => {
|
|
|
6326 |
const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
|
|
|
6327 |
if (!match) {
|
|
|
6328 |
return null;
|
|
|
6329 |
}
|
|
|
6330 |
if (match[1] === 'text()') {
|
|
|
6331 |
match[1] = '#text';
|
|
|
6332 |
}
|
|
|
6333 |
return resolvePathItem(result, match[1], parseInt(match[2], 10));
|
|
|
6334 |
}, root);
|
|
|
6335 |
if (!container) {
|
|
|
6336 |
return null;
|
|
|
6337 |
}
|
|
|
6338 |
if (!isText$6(container) && container.parentNode) {
|
|
|
6339 |
let nodeOffset;
|
|
|
6340 |
if (offset === 'after') {
|
|
|
6341 |
nodeOffset = nodeIndex(container) + 1;
|
|
|
6342 |
} else {
|
|
|
6343 |
nodeOffset = nodeIndex(container);
|
|
|
6344 |
}
|
|
|
6345 |
return CaretPosition(container.parentNode, nodeOffset);
|
|
|
6346 |
}
|
|
|
6347 |
return findTextPosition(container, parseInt(offset, 10));
|
|
|
6348 |
};
|
|
|
6349 |
|
|
|
6350 |
const isContentEditableFalse$9 = isContentEditableFalse$b;
|
|
|
6351 |
const getNormalizedTextOffset$1 = (trim, container, offset) => {
|
|
|
6352 |
let trimmedOffset = trim(container.data.slice(0, offset)).length;
|
| 1441 |
ariadna |
6353 |
for (let node = container.previousSibling; node && isText$b(node); node = node.previousSibling) {
|
| 1 |
efrain |
6354 |
trimmedOffset += trim(node.data).length;
|
|
|
6355 |
}
|
|
|
6356 |
return trimmedOffset;
|
|
|
6357 |
};
|
|
|
6358 |
const getPoint = (dom, trim, normalized, rng, start) => {
|
|
|
6359 |
const container = start ? rng.startContainer : rng.endContainer;
|
|
|
6360 |
let offset = start ? rng.startOffset : rng.endOffset;
|
|
|
6361 |
const point = [];
|
|
|
6362 |
const root = dom.getRoot();
|
| 1441 |
ariadna |
6363 |
if (isText$b(container)) {
|
| 1 |
efrain |
6364 |
point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset);
|
|
|
6365 |
} else {
|
|
|
6366 |
let after = 0;
|
|
|
6367 |
const childNodes = container.childNodes;
|
|
|
6368 |
if (offset >= childNodes.length && childNodes.length) {
|
|
|
6369 |
after = 1;
|
|
|
6370 |
offset = Math.max(0, childNodes.length - 1);
|
|
|
6371 |
}
|
|
|
6372 |
point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
|
|
|
6373 |
}
|
|
|
6374 |
for (let node = container; node && node !== root; node = node.parentNode) {
|
|
|
6375 |
point.push(dom.nodeIndex(node, normalized));
|
|
|
6376 |
}
|
|
|
6377 |
return point;
|
|
|
6378 |
};
|
|
|
6379 |
const getLocation = (trim, selection, normalized, rng) => {
|
|
|
6380 |
const dom = selection.dom;
|
|
|
6381 |
const start = getPoint(dom, trim, normalized, rng, true);
|
|
|
6382 |
const forward = selection.isForward();
|
|
|
6383 |
const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
|
|
|
6384 |
if (!selection.isCollapsed()) {
|
|
|
6385 |
const end = getPoint(dom, trim, normalized, rng, false);
|
|
|
6386 |
return {
|
|
|
6387 |
start,
|
|
|
6388 |
end,
|
|
|
6389 |
forward,
|
|
|
6390 |
...fakeCaret
|
|
|
6391 |
};
|
|
|
6392 |
} else {
|
|
|
6393 |
return {
|
|
|
6394 |
start,
|
|
|
6395 |
forward,
|
|
|
6396 |
...fakeCaret
|
|
|
6397 |
};
|
|
|
6398 |
}
|
|
|
6399 |
};
|
|
|
6400 |
const findIndex = (dom, name, element) => {
|
|
|
6401 |
let count = 0;
|
|
|
6402 |
Tools.each(dom.select(name), node => {
|
|
|
6403 |
if (node.getAttribute('data-mce-bogus') === 'all') {
|
|
|
6404 |
return;
|
|
|
6405 |
} else if (node === element) {
|
|
|
6406 |
return false;
|
|
|
6407 |
} else {
|
|
|
6408 |
count++;
|
|
|
6409 |
return;
|
|
|
6410 |
}
|
|
|
6411 |
});
|
|
|
6412 |
return count;
|
|
|
6413 |
};
|
|
|
6414 |
const moveEndPoint$1 = (rng, start) => {
|
|
|
6415 |
let container = start ? rng.startContainer : rng.endContainer;
|
|
|
6416 |
let offset = start ? rng.startOffset : rng.endOffset;
|
|
|
6417 |
if (isElement$6(container) && container.nodeName === 'TR') {
|
|
|
6418 |
const childNodes = container.childNodes;
|
|
|
6419 |
container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
|
|
|
6420 |
if (container) {
|
|
|
6421 |
offset = start ? 0 : container.childNodes.length;
|
|
|
6422 |
if (start) {
|
|
|
6423 |
rng.setStart(container, offset);
|
|
|
6424 |
} else {
|
|
|
6425 |
rng.setEnd(container, offset);
|
|
|
6426 |
}
|
|
|
6427 |
}
|
|
|
6428 |
}
|
|
|
6429 |
};
|
|
|
6430 |
const normalizeTableCellSelection = rng => {
|
|
|
6431 |
moveEndPoint$1(rng, true);
|
|
|
6432 |
moveEndPoint$1(rng, false);
|
|
|
6433 |
return rng;
|
|
|
6434 |
};
|
|
|
6435 |
const findSibling = (node, offset) => {
|
|
|
6436 |
if (isElement$6(node)) {
|
|
|
6437 |
node = getNode$1(node, offset);
|
|
|
6438 |
if (isContentEditableFalse$9(node)) {
|
|
|
6439 |
return node;
|
|
|
6440 |
}
|
|
|
6441 |
}
|
|
|
6442 |
if (isCaretContainer$2(node)) {
|
| 1441 |
ariadna |
6443 |
if (isText$b(node) && isCaretContainerBlock$1(node)) {
|
| 1 |
efrain |
6444 |
node = node.parentNode;
|
|
|
6445 |
}
|
|
|
6446 |
let sibling = node.previousSibling;
|
|
|
6447 |
if (isContentEditableFalse$9(sibling)) {
|
|
|
6448 |
return sibling;
|
|
|
6449 |
}
|
|
|
6450 |
sibling = node.nextSibling;
|
|
|
6451 |
if (isContentEditableFalse$9(sibling)) {
|
|
|
6452 |
return sibling;
|
|
|
6453 |
}
|
|
|
6454 |
}
|
|
|
6455 |
return undefined;
|
|
|
6456 |
};
|
|
|
6457 |
const findAdjacentContentEditableFalseElm = rng => {
|
|
|
6458 |
return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
|
|
|
6459 |
};
|
|
|
6460 |
const getOffsetBookmark = (trim, normalized, selection) => {
|
|
|
6461 |
const element = selection.getNode();
|
|
|
6462 |
const rng = selection.getRng();
|
|
|
6463 |
if (element.nodeName === 'IMG' || isContentEditableFalse$9(element)) {
|
|
|
6464 |
const name = element.nodeName;
|
|
|
6465 |
return {
|
|
|
6466 |
name,
|
|
|
6467 |
index: findIndex(selection.dom, name, element)
|
|
|
6468 |
};
|
|
|
6469 |
}
|
|
|
6470 |
const sibling = findAdjacentContentEditableFalseElm(rng);
|
|
|
6471 |
if (sibling) {
|
|
|
6472 |
const name = sibling.tagName;
|
|
|
6473 |
return {
|
|
|
6474 |
name,
|
|
|
6475 |
index: findIndex(selection.dom, name, sibling)
|
|
|
6476 |
};
|
|
|
6477 |
}
|
|
|
6478 |
return getLocation(trim, selection, normalized, rng);
|
|
|
6479 |
};
|
|
|
6480 |
const getCaretBookmark = selection => {
|
|
|
6481 |
const rng = selection.getRng();
|
|
|
6482 |
return {
|
| 1441 |
ariadna |
6483 |
start: create$a(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
|
|
|
6484 |
end: create$a(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
|
| 1 |
efrain |
6485 |
forward: selection.isForward()
|
|
|
6486 |
};
|
|
|
6487 |
};
|
|
|
6488 |
const getRangeBookmark = selection => {
|
|
|
6489 |
return {
|
|
|
6490 |
rng: selection.getRng(),
|
|
|
6491 |
forward: selection.isForward()
|
|
|
6492 |
};
|
|
|
6493 |
};
|
|
|
6494 |
const createBookmarkSpan = (dom, id, filled) => {
|
|
|
6495 |
const args = {
|
|
|
6496 |
'data-mce-type': 'bookmark',
|
|
|
6497 |
id,
|
|
|
6498 |
'style': 'overflow:hidden;line-height:0px'
|
|
|
6499 |
};
|
|
|
6500 |
return filled ? dom.create('span', args, '') : dom.create('span', args);
|
|
|
6501 |
};
|
|
|
6502 |
const getPersistentBookmark = (selection, filled) => {
|
|
|
6503 |
const dom = selection.dom;
|
|
|
6504 |
let rng = selection.getRng();
|
|
|
6505 |
const id = dom.uniqueId();
|
|
|
6506 |
const collapsed = selection.isCollapsed();
|
|
|
6507 |
const element = selection.getNode();
|
|
|
6508 |
const name = element.nodeName;
|
|
|
6509 |
const forward = selection.isForward();
|
|
|
6510 |
if (name === 'IMG') {
|
|
|
6511 |
return {
|
|
|
6512 |
name,
|
|
|
6513 |
index: findIndex(dom, name, element)
|
|
|
6514 |
};
|
|
|
6515 |
}
|
|
|
6516 |
const rng2 = normalizeTableCellSelection(rng.cloneRange());
|
|
|
6517 |
if (!collapsed) {
|
|
|
6518 |
rng2.collapse(false);
|
|
|
6519 |
const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
|
|
|
6520 |
rangeInsertNode(dom, rng2, endBookmarkNode);
|
|
|
6521 |
}
|
|
|
6522 |
rng = normalizeTableCellSelection(rng);
|
|
|
6523 |
rng.collapse(true);
|
|
|
6524 |
const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
|
|
|
6525 |
rangeInsertNode(dom, rng, startBookmarkNode);
|
|
|
6526 |
selection.moveToBookmark({
|
|
|
6527 |
id,
|
|
|
6528 |
keep: true,
|
|
|
6529 |
forward
|
|
|
6530 |
});
|
|
|
6531 |
return {
|
|
|
6532 |
id,
|
|
|
6533 |
forward
|
|
|
6534 |
};
|
|
|
6535 |
};
|
| 1441 |
ariadna |
6536 |
const getBookmark$3 = (selection, type, normalized = false) => {
|
| 1 |
efrain |
6537 |
if (type === 2) {
|
|
|
6538 |
return getOffsetBookmark(trim$2, normalized, selection);
|
|
|
6539 |
} else if (type === 3) {
|
|
|
6540 |
return getCaretBookmark(selection);
|
|
|
6541 |
} else if (type) {
|
|
|
6542 |
return getRangeBookmark(selection);
|
|
|
6543 |
} else {
|
|
|
6544 |
return getPersistentBookmark(selection, false);
|
|
|
6545 |
}
|
|
|
6546 |
};
|
|
|
6547 |
const getUndoBookmark = curry(getOffsetBookmark, identity, true);
|
|
|
6548 |
|
|
|
6549 |
const value$1 = value => {
|
|
|
6550 |
const applyHelper = fn => fn(value);
|
|
|
6551 |
const constHelper = constant(value);
|
|
|
6552 |
const outputHelper = () => output;
|
|
|
6553 |
const output = {
|
|
|
6554 |
tag: true,
|
|
|
6555 |
inner: value,
|
|
|
6556 |
fold: (_onError, onValue) => onValue(value),
|
|
|
6557 |
isValue: always,
|
|
|
6558 |
isError: never,
|
|
|
6559 |
map: mapper => Result.value(mapper(value)),
|
|
|
6560 |
mapError: outputHelper,
|
|
|
6561 |
bind: applyHelper,
|
|
|
6562 |
exists: applyHelper,
|
|
|
6563 |
forall: applyHelper,
|
|
|
6564 |
getOr: constHelper,
|
|
|
6565 |
or: outputHelper,
|
|
|
6566 |
getOrThunk: constHelper,
|
|
|
6567 |
orThunk: outputHelper,
|
|
|
6568 |
getOrDie: constHelper,
|
|
|
6569 |
each: fn => {
|
|
|
6570 |
fn(value);
|
|
|
6571 |
},
|
|
|
6572 |
toOptional: () => Optional.some(value)
|
|
|
6573 |
};
|
|
|
6574 |
return output;
|
|
|
6575 |
};
|
|
|
6576 |
const error = error => {
|
|
|
6577 |
const outputHelper = () => output;
|
|
|
6578 |
const output = {
|
|
|
6579 |
tag: false,
|
|
|
6580 |
inner: error,
|
|
|
6581 |
fold: (onError, _onValue) => onError(error),
|
|
|
6582 |
isValue: never,
|
|
|
6583 |
isError: always,
|
|
|
6584 |
map: outputHelper,
|
|
|
6585 |
mapError: mapper => Result.error(mapper(error)),
|
|
|
6586 |
bind: outputHelper,
|
|
|
6587 |
exists: never,
|
|
|
6588 |
forall: always,
|
|
|
6589 |
getOr: identity,
|
|
|
6590 |
or: identity,
|
|
|
6591 |
getOrThunk: apply$1,
|
|
|
6592 |
orThunk: apply$1,
|
|
|
6593 |
getOrDie: die(String(error)),
|
|
|
6594 |
each: noop,
|
|
|
6595 |
toOptional: Optional.none
|
|
|
6596 |
};
|
|
|
6597 |
return output;
|
|
|
6598 |
};
|
|
|
6599 |
const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
|
|
|
6600 |
const Result = {
|
|
|
6601 |
value: value$1,
|
|
|
6602 |
error,
|
|
|
6603 |
fromOption
|
|
|
6604 |
};
|
|
|
6605 |
|
|
|
6606 |
const generate = cases => {
|
|
|
6607 |
if (!isArray$1(cases)) {
|
|
|
6608 |
throw new Error('cases must be an array');
|
|
|
6609 |
}
|
|
|
6610 |
if (cases.length === 0) {
|
|
|
6611 |
throw new Error('there must be at least one case');
|
|
|
6612 |
}
|
|
|
6613 |
const constructors = [];
|
|
|
6614 |
const adt = {};
|
|
|
6615 |
each$e(cases, (acase, count) => {
|
|
|
6616 |
const keys$1 = keys(acase);
|
|
|
6617 |
if (keys$1.length !== 1) {
|
|
|
6618 |
throw new Error('one and only one name per case');
|
|
|
6619 |
}
|
|
|
6620 |
const key = keys$1[0];
|
|
|
6621 |
const value = acase[key];
|
|
|
6622 |
if (adt[key] !== undefined) {
|
|
|
6623 |
throw new Error('duplicate key detected:' + key);
|
|
|
6624 |
} else if (key === 'cata') {
|
|
|
6625 |
throw new Error('cannot have a case named cata (sorry)');
|
|
|
6626 |
} else if (!isArray$1(value)) {
|
|
|
6627 |
throw new Error('case arguments must be an array');
|
|
|
6628 |
}
|
|
|
6629 |
constructors.push(key);
|
|
|
6630 |
adt[key] = (...args) => {
|
|
|
6631 |
const argLength = args.length;
|
|
|
6632 |
if (argLength !== value.length) {
|
|
|
6633 |
throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
|
|
|
6634 |
}
|
|
|
6635 |
const match = branches => {
|
|
|
6636 |
const branchKeys = keys(branches);
|
|
|
6637 |
if (constructors.length !== branchKeys.length) {
|
|
|
6638 |
throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
|
|
|
6639 |
}
|
|
|
6640 |
const allReqd = forall(constructors, reqKey => {
|
|
|
6641 |
return contains$2(branchKeys, reqKey);
|
|
|
6642 |
});
|
|
|
6643 |
if (!allReqd) {
|
|
|
6644 |
throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
|
|
|
6645 |
}
|
|
|
6646 |
return branches[key].apply(null, args);
|
|
|
6647 |
};
|
|
|
6648 |
return {
|
|
|
6649 |
fold: (...foldArgs) => {
|
|
|
6650 |
if (foldArgs.length !== cases.length) {
|
|
|
6651 |
throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
|
|
|
6652 |
}
|
|
|
6653 |
const target = foldArgs[count];
|
|
|
6654 |
return target.apply(null, args);
|
|
|
6655 |
},
|
|
|
6656 |
match,
|
|
|
6657 |
log: label => {
|
|
|
6658 |
console.log(label, {
|
|
|
6659 |
constructors,
|
|
|
6660 |
constructor: key,
|
|
|
6661 |
params: args
|
|
|
6662 |
});
|
|
|
6663 |
}
|
|
|
6664 |
};
|
|
|
6665 |
};
|
|
|
6666 |
});
|
|
|
6667 |
return adt;
|
|
|
6668 |
};
|
|
|
6669 |
const Adt = { generate };
|
|
|
6670 |
|
|
|
6671 |
Adt.generate([
|
|
|
6672 |
{
|
|
|
6673 |
bothErrors: [
|
|
|
6674 |
'error1',
|
|
|
6675 |
'error2'
|
|
|
6676 |
]
|
|
|
6677 |
},
|
|
|
6678 |
{
|
|
|
6679 |
firstError: [
|
|
|
6680 |
'error1',
|
|
|
6681 |
'value2'
|
|
|
6682 |
]
|
|
|
6683 |
},
|
|
|
6684 |
{
|
|
|
6685 |
secondError: [
|
|
|
6686 |
'value1',
|
|
|
6687 |
'error2'
|
|
|
6688 |
]
|
|
|
6689 |
},
|
|
|
6690 |
{
|
|
|
6691 |
bothValues: [
|
|
|
6692 |
'value1',
|
|
|
6693 |
'value2'
|
|
|
6694 |
]
|
|
|
6695 |
}
|
|
|
6696 |
]);
|
|
|
6697 |
const partition$1 = results => {
|
|
|
6698 |
const errors = [];
|
|
|
6699 |
const values = [];
|
|
|
6700 |
each$e(results, result => {
|
|
|
6701 |
result.fold(err => {
|
|
|
6702 |
errors.push(err);
|
|
|
6703 |
}, value => {
|
|
|
6704 |
values.push(value);
|
|
|
6705 |
});
|
|
|
6706 |
});
|
|
|
6707 |
return {
|
|
|
6708 |
errors,
|
|
|
6709 |
values
|
|
|
6710 |
};
|
|
|
6711 |
};
|
|
|
6712 |
|
|
|
6713 |
const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format';
|
|
|
6714 |
const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format';
|
| 1441 |
ariadna |
6715 |
const hasBlockTrigger = (pattern, trigger) => (pattern.type === 'block-command' || pattern.type === 'block-format') && pattern.trigger === trigger;
|
| 1 |
efrain |
6716 |
const normalizePattern = pattern => {
|
| 1441 |
ariadna |
6717 |
var _a;
|
| 1 |
efrain |
6718 |
const err = message => Result.error({
|
|
|
6719 |
message,
|
|
|
6720 |
pattern
|
|
|
6721 |
});
|
|
|
6722 |
const formatOrCmd = (name, onFormat, onCommand) => {
|
|
|
6723 |
if (pattern.format !== undefined) {
|
|
|
6724 |
let formats;
|
|
|
6725 |
if (isArray$1(pattern.format)) {
|
|
|
6726 |
if (!forall(pattern.format, isString)) {
|
|
|
6727 |
return err(name + ' pattern has non-string items in the `format` array');
|
|
|
6728 |
}
|
|
|
6729 |
formats = pattern.format;
|
|
|
6730 |
} else if (isString(pattern.format)) {
|
|
|
6731 |
formats = [pattern.format];
|
|
|
6732 |
} else {
|
|
|
6733 |
return err(name + ' pattern has non-string `format` parameter');
|
|
|
6734 |
}
|
|
|
6735 |
return Result.value(onFormat(formats));
|
|
|
6736 |
} else if (pattern.cmd !== undefined) {
|
|
|
6737 |
if (!isString(pattern.cmd)) {
|
|
|
6738 |
return err(name + ' pattern has non-string `cmd` parameter');
|
|
|
6739 |
}
|
|
|
6740 |
return Result.value(onCommand(pattern.cmd, pattern.value));
|
|
|
6741 |
} else {
|
|
|
6742 |
return err(name + ' pattern is missing both `format` and `cmd` parameters');
|
|
|
6743 |
}
|
|
|
6744 |
};
|
|
|
6745 |
if (!isObject(pattern)) {
|
|
|
6746 |
return err('Raw pattern is not an object');
|
|
|
6747 |
}
|
|
|
6748 |
if (!isString(pattern.start)) {
|
|
|
6749 |
return err('Raw pattern is missing `start` parameter');
|
|
|
6750 |
}
|
|
|
6751 |
if (pattern.end !== undefined) {
|
|
|
6752 |
if (!isString(pattern.end)) {
|
|
|
6753 |
return err('Inline pattern has non-string `end` parameter');
|
|
|
6754 |
}
|
|
|
6755 |
if (pattern.start.length === 0 && pattern.end.length === 0) {
|
|
|
6756 |
return err('Inline pattern has empty `start` and `end` parameters');
|
|
|
6757 |
}
|
|
|
6758 |
let start = pattern.start;
|
|
|
6759 |
let end = pattern.end;
|
|
|
6760 |
if (end.length === 0) {
|
|
|
6761 |
end = start;
|
|
|
6762 |
start = '';
|
|
|
6763 |
}
|
|
|
6764 |
return formatOrCmd('Inline', format => ({
|
|
|
6765 |
type: 'inline-format',
|
|
|
6766 |
start,
|
|
|
6767 |
end,
|
|
|
6768 |
format
|
|
|
6769 |
}), (cmd, value) => ({
|
|
|
6770 |
type: 'inline-command',
|
|
|
6771 |
start,
|
|
|
6772 |
end,
|
|
|
6773 |
cmd,
|
|
|
6774 |
value
|
|
|
6775 |
}));
|
|
|
6776 |
} else if (pattern.replacement !== undefined) {
|
|
|
6777 |
if (!isString(pattern.replacement)) {
|
|
|
6778 |
return err('Replacement pattern has non-string `replacement` parameter');
|
|
|
6779 |
}
|
|
|
6780 |
if (pattern.start.length === 0) {
|
|
|
6781 |
return err('Replacement pattern has empty `start` parameter');
|
|
|
6782 |
}
|
|
|
6783 |
return Result.value({
|
|
|
6784 |
type: 'inline-command',
|
|
|
6785 |
start: '',
|
|
|
6786 |
end: pattern.start,
|
|
|
6787 |
cmd: 'mceInsertContent',
|
|
|
6788 |
value: pattern.replacement
|
|
|
6789 |
});
|
|
|
6790 |
} else {
|
| 1441 |
ariadna |
6791 |
const trigger = (_a = pattern.trigger) !== null && _a !== void 0 ? _a : 'space';
|
| 1 |
efrain |
6792 |
if (pattern.start.length === 0) {
|
|
|
6793 |
return err('Block pattern has empty `start` parameter');
|
|
|
6794 |
}
|
|
|
6795 |
return formatOrCmd('Block', formats => ({
|
|
|
6796 |
type: 'block-format',
|
|
|
6797 |
start: pattern.start,
|
| 1441 |
ariadna |
6798 |
format: formats[0],
|
|
|
6799 |
trigger
|
| 1 |
efrain |
6800 |
}), (command, commandValue) => ({
|
|
|
6801 |
type: 'block-command',
|
|
|
6802 |
start: pattern.start,
|
|
|
6803 |
cmd: command,
|
| 1441 |
ariadna |
6804 |
value: commandValue,
|
|
|
6805 |
trigger
|
| 1 |
efrain |
6806 |
}));
|
|
|
6807 |
}
|
|
|
6808 |
};
|
|
|
6809 |
const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern);
|
|
|
6810 |
const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern);
|
|
|
6811 |
const createPatternSet = (patterns, dynamicPatternsLookup) => ({
|
|
|
6812 |
inlinePatterns: getInlinePatterns(patterns),
|
|
|
6813 |
blockPatterns: getBlockPatterns(patterns),
|
|
|
6814 |
dynamicPatternsLookup
|
|
|
6815 |
});
|
| 1441 |
ariadna |
6816 |
const filterByTrigger = (patterns, trigger) => {
|
|
|
6817 |
return {
|
|
|
6818 |
...patterns,
|
|
|
6819 |
blockPatterns: filter$5(patterns.blockPatterns, pattern => hasBlockTrigger(pattern, trigger))
|
|
|
6820 |
};
|
|
|
6821 |
};
|
| 1 |
efrain |
6822 |
const fromRawPatterns = patterns => {
|
|
|
6823 |
const normalized = partition$1(map$3(patterns, normalizePattern));
|
|
|
6824 |
each$e(normalized.errors, err => console.error(err.message, err.pattern));
|
|
|
6825 |
return normalized.values;
|
|
|
6826 |
};
|
|
|
6827 |
const fromRawPatternsLookup = lookupFn => {
|
|
|
6828 |
return ctx => {
|
|
|
6829 |
const rawPatterns = lookupFn(ctx);
|
|
|
6830 |
return fromRawPatterns(rawPatterns);
|
|
|
6831 |
};
|
|
|
6832 |
};
|
|
|
6833 |
|
| 1441 |
ariadna |
6834 |
const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args);
|
|
|
6835 |
const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args);
|
|
|
6836 |
const fireRemove = editor => {
|
|
|
6837 |
editor.dispatch('remove');
|
|
|
6838 |
};
|
|
|
6839 |
const fireDetach = editor => {
|
|
|
6840 |
editor.dispatch('detach');
|
|
|
6841 |
};
|
|
|
6842 |
const fireSwitchMode = (editor, mode) => {
|
|
|
6843 |
editor.dispatch('SwitchMode', { mode });
|
|
|
6844 |
};
|
|
|
6845 |
const fireObjectResizeStart = (editor, target, width, height, origin) => {
|
|
|
6846 |
editor.dispatch('ObjectResizeStart', {
|
|
|
6847 |
target,
|
|
|
6848 |
width,
|
|
|
6849 |
height,
|
|
|
6850 |
origin
|
|
|
6851 |
});
|
|
|
6852 |
};
|
|
|
6853 |
const fireObjectResized = (editor, target, width, height, origin) => {
|
|
|
6854 |
editor.dispatch('ObjectResized', {
|
|
|
6855 |
target,
|
|
|
6856 |
width,
|
|
|
6857 |
height,
|
|
|
6858 |
origin
|
|
|
6859 |
});
|
|
|
6860 |
};
|
|
|
6861 |
const firePreInit = editor => {
|
|
|
6862 |
editor.dispatch('PreInit');
|
|
|
6863 |
};
|
|
|
6864 |
const firePostRender = editor => {
|
|
|
6865 |
editor.dispatch('PostRender');
|
|
|
6866 |
};
|
|
|
6867 |
const fireInit = editor => {
|
|
|
6868 |
editor.dispatch('Init');
|
|
|
6869 |
};
|
|
|
6870 |
const firePlaceholderToggle = (editor, state) => {
|
|
|
6871 |
editor.dispatch('PlaceholderToggle', { state });
|
|
|
6872 |
};
|
|
|
6873 |
const fireError = (editor, errorType, error) => {
|
|
|
6874 |
editor.dispatch(errorType, error);
|
|
|
6875 |
};
|
|
|
6876 |
const fireFormatApply = (editor, format, node, vars) => {
|
|
|
6877 |
editor.dispatch('FormatApply', {
|
|
|
6878 |
format,
|
|
|
6879 |
node,
|
|
|
6880 |
vars
|
|
|
6881 |
});
|
|
|
6882 |
};
|
|
|
6883 |
const fireFormatRemove = (editor, format, node, vars) => {
|
|
|
6884 |
editor.dispatch('FormatRemove', {
|
|
|
6885 |
format,
|
|
|
6886 |
node,
|
|
|
6887 |
vars
|
|
|
6888 |
});
|
|
|
6889 |
};
|
|
|
6890 |
const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args);
|
|
|
6891 |
const fireSetContent = (editor, args) => editor.dispatch('SetContent', args);
|
|
|
6892 |
const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args);
|
|
|
6893 |
const fireGetContent = (editor, args) => editor.dispatch('GetContent', args);
|
|
|
6894 |
const fireAutocompleterStart = (editor, args) => {
|
|
|
6895 |
editor.dispatch('AutocompleterStart', args);
|
|
|
6896 |
};
|
|
|
6897 |
const fireAutocompleterUpdate = (editor, args) => {
|
|
|
6898 |
editor.dispatch('AutocompleterUpdate', args);
|
|
|
6899 |
};
|
|
|
6900 |
const fireAutocompleterUpdateActiveRange = (editor, args) => {
|
|
|
6901 |
editor.dispatch('AutocompleterUpdateActiveRange', args);
|
|
|
6902 |
};
|
|
|
6903 |
const fireAutocompleterEnd = editor => {
|
|
|
6904 |
editor.dispatch('AutocompleterEnd');
|
|
|
6905 |
};
|
|
|
6906 |
const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', {
|
|
|
6907 |
content: html,
|
|
|
6908 |
internal
|
|
|
6909 |
});
|
|
|
6910 |
const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', {
|
|
|
6911 |
node,
|
|
|
6912 |
internal
|
|
|
6913 |
});
|
|
|
6914 |
const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state });
|
|
|
6915 |
const fireEditableRootStateChange = (editor, state) => editor.dispatch('EditableRootStateChange', { state });
|
|
|
6916 |
const fireDisabledStateChange = (editor, state) => editor.dispatch('DisabledStateChange', { state });
|
|
|
6917 |
|
|
|
6918 |
const deviceDetection$1 = detect$1().deviceType;
|
| 1 |
efrain |
6919 |
const isTouch = deviceDetection$1.isTouch();
|
|
|
6920 |
const DOM$a = DOMUtils.DOM;
|
|
|
6921 |
const getHash = value => {
|
|
|
6922 |
const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(',');
|
|
|
6923 |
return foldl(items, (output, item) => {
|
|
|
6924 |
const arr = item.split('=');
|
|
|
6925 |
const key = arr[0];
|
|
|
6926 |
const val = arr.length > 1 ? arr[1] : key;
|
|
|
6927 |
output[trim$4(key)] = trim$4(val);
|
|
|
6928 |
return output;
|
|
|
6929 |
}, {});
|
|
|
6930 |
};
|
|
|
6931 |
const isRegExp = x => is$4(x, RegExp);
|
|
|
6932 |
const option = name => editor => editor.options.get(name);
|
|
|
6933 |
const stringOrObjectProcessor = value => isString(value) || isObject(value);
|
|
|
6934 |
const bodyOptionProcessor = (editor, defaultValue = '') => value => {
|
|
|
6935 |
const valid = isString(value);
|
|
|
6936 |
if (valid) {
|
|
|
6937 |
if (value.indexOf('=') !== -1) {
|
|
|
6938 |
const bodyObj = getHash(value);
|
|
|
6939 |
return {
|
|
|
6940 |
value: get$a(bodyObj, editor.id).getOr(defaultValue),
|
|
|
6941 |
valid
|
|
|
6942 |
};
|
|
|
6943 |
} else {
|
|
|
6944 |
return {
|
|
|
6945 |
value,
|
|
|
6946 |
valid
|
|
|
6947 |
};
|
|
|
6948 |
}
|
|
|
6949 |
} else {
|
|
|
6950 |
return {
|
|
|
6951 |
valid: false,
|
|
|
6952 |
message: 'Must be a string.'
|
|
|
6953 |
};
|
|
|
6954 |
}
|
|
|
6955 |
};
|
|
|
6956 |
const register$7 = editor => {
|
|
|
6957 |
const registerOption = editor.options.register;
|
|
|
6958 |
registerOption('id', {
|
|
|
6959 |
processor: 'string',
|
|
|
6960 |
default: editor.id
|
|
|
6961 |
});
|
|
|
6962 |
registerOption('selector', { processor: 'string' });
|
|
|
6963 |
registerOption('target', { processor: 'object' });
|
|
|
6964 |
registerOption('suffix', { processor: 'string' });
|
|
|
6965 |
registerOption('cache_suffix', { processor: 'string' });
|
|
|
6966 |
registerOption('base_url', { processor: 'string' });
|
|
|
6967 |
registerOption('referrer_policy', {
|
|
|
6968 |
processor: 'string',
|
|
|
6969 |
default: ''
|
|
|
6970 |
});
|
|
|
6971 |
registerOption('language_load', {
|
|
|
6972 |
processor: 'boolean',
|
|
|
6973 |
default: true
|
|
|
6974 |
});
|
|
|
6975 |
registerOption('inline', {
|
|
|
6976 |
processor: 'boolean',
|
|
|
6977 |
default: false
|
|
|
6978 |
});
|
|
|
6979 |
registerOption('iframe_attrs', {
|
|
|
6980 |
processor: 'object',
|
|
|
6981 |
default: {}
|
|
|
6982 |
});
|
|
|
6983 |
registerOption('doctype', {
|
|
|
6984 |
processor: 'string',
|
|
|
6985 |
default: '<!DOCTYPE html>'
|
|
|
6986 |
});
|
|
|
6987 |
registerOption('document_base_url', {
|
|
|
6988 |
processor: 'string',
|
|
|
6989 |
default: editor.documentBaseUrl
|
|
|
6990 |
});
|
|
|
6991 |
registerOption('body_id', {
|
|
|
6992 |
processor: bodyOptionProcessor(editor, 'tinymce'),
|
|
|
6993 |
default: 'tinymce'
|
|
|
6994 |
});
|
|
|
6995 |
registerOption('body_class', {
|
|
|
6996 |
processor: bodyOptionProcessor(editor),
|
|
|
6997 |
default: ''
|
|
|
6998 |
});
|
|
|
6999 |
registerOption('content_security_policy', {
|
|
|
7000 |
processor: 'string',
|
|
|
7001 |
default: ''
|
|
|
7002 |
});
|
|
|
7003 |
registerOption('br_in_pre', {
|
|
|
7004 |
processor: 'boolean',
|
|
|
7005 |
default: true
|
|
|
7006 |
});
|
|
|
7007 |
registerOption('forced_root_block', {
|
|
|
7008 |
processor: value => {
|
|
|
7009 |
const valid = isString(value) && isNotEmpty(value);
|
|
|
7010 |
if (valid) {
|
|
|
7011 |
return {
|
|
|
7012 |
value,
|
|
|
7013 |
valid
|
|
|
7014 |
};
|
|
|
7015 |
} else {
|
|
|
7016 |
return {
|
|
|
7017 |
valid: false,
|
|
|
7018 |
message: 'Must be a non-empty string.'
|
|
|
7019 |
};
|
|
|
7020 |
}
|
|
|
7021 |
},
|
|
|
7022 |
default: 'p'
|
|
|
7023 |
});
|
|
|
7024 |
registerOption('forced_root_block_attrs', {
|
|
|
7025 |
processor: 'object',
|
|
|
7026 |
default: {}
|
|
|
7027 |
});
|
|
|
7028 |
registerOption('newline_behavior', {
|
|
|
7029 |
processor: value => {
|
|
|
7030 |
const valid = contains$2([
|
|
|
7031 |
'block',
|
|
|
7032 |
'linebreak',
|
|
|
7033 |
'invert',
|
|
|
7034 |
'default'
|
|
|
7035 |
], value);
|
|
|
7036 |
return valid ? {
|
|
|
7037 |
value,
|
|
|
7038 |
valid
|
|
|
7039 |
} : {
|
|
|
7040 |
valid: false,
|
|
|
7041 |
message: 'Must be one of: block, linebreak, invert or default.'
|
|
|
7042 |
};
|
|
|
7043 |
},
|
|
|
7044 |
default: 'default'
|
|
|
7045 |
});
|
|
|
7046 |
registerOption('br_newline_selector', {
|
|
|
7047 |
processor: 'string',
|
|
|
7048 |
default: '.mce-toc h2,figcaption,caption'
|
|
|
7049 |
});
|
|
|
7050 |
registerOption('no_newline_selector', {
|
|
|
7051 |
processor: 'string',
|
|
|
7052 |
default: ''
|
|
|
7053 |
});
|
|
|
7054 |
registerOption('keep_styles', {
|
|
|
7055 |
processor: 'boolean',
|
|
|
7056 |
default: true
|
|
|
7057 |
});
|
|
|
7058 |
registerOption('end_container_on_empty_block', {
|
|
|
7059 |
processor: value => {
|
|
|
7060 |
if (isBoolean(value)) {
|
|
|
7061 |
return {
|
|
|
7062 |
valid: true,
|
|
|
7063 |
value
|
|
|
7064 |
};
|
|
|
7065 |
} else if (isString(value)) {
|
|
|
7066 |
return {
|
|
|
7067 |
valid: true,
|
|
|
7068 |
value
|
|
|
7069 |
};
|
|
|
7070 |
} else {
|
|
|
7071 |
return {
|
|
|
7072 |
valid: false,
|
|
|
7073 |
message: 'Must be boolean or a string'
|
|
|
7074 |
};
|
|
|
7075 |
}
|
|
|
7076 |
},
|
|
|
7077 |
default: 'blockquote'
|
|
|
7078 |
});
|
|
|
7079 |
registerOption('font_size_style_values', {
|
|
|
7080 |
processor: 'string',
|
|
|
7081 |
default: 'xx-small,x-small,small,medium,large,x-large,xx-large'
|
|
|
7082 |
});
|
|
|
7083 |
registerOption('font_size_legacy_values', {
|
|
|
7084 |
processor: 'string',
|
|
|
7085 |
default: 'xx-small,small,medium,large,x-large,xx-large,300%'
|
|
|
7086 |
});
|
|
|
7087 |
registerOption('font_size_classes', {
|
|
|
7088 |
processor: 'string',
|
|
|
7089 |
default: ''
|
|
|
7090 |
});
|
|
|
7091 |
registerOption('automatic_uploads', {
|
|
|
7092 |
processor: 'boolean',
|
|
|
7093 |
default: true
|
|
|
7094 |
});
|
|
|
7095 |
registerOption('images_reuse_filename', {
|
|
|
7096 |
processor: 'boolean',
|
|
|
7097 |
default: false
|
|
|
7098 |
});
|
|
|
7099 |
registerOption('images_replace_blob_uris', {
|
|
|
7100 |
processor: 'boolean',
|
|
|
7101 |
default: true
|
|
|
7102 |
});
|
|
|
7103 |
registerOption('icons', {
|
|
|
7104 |
processor: 'string',
|
|
|
7105 |
default: ''
|
|
|
7106 |
});
|
|
|
7107 |
registerOption('icons_url', {
|
|
|
7108 |
processor: 'string',
|
|
|
7109 |
default: ''
|
|
|
7110 |
});
|
|
|
7111 |
registerOption('images_upload_url', {
|
|
|
7112 |
processor: 'string',
|
|
|
7113 |
default: ''
|
|
|
7114 |
});
|
|
|
7115 |
registerOption('images_upload_base_path', {
|
|
|
7116 |
processor: 'string',
|
|
|
7117 |
default: ''
|
|
|
7118 |
});
|
|
|
7119 |
registerOption('images_upload_credentials', {
|
|
|
7120 |
processor: 'boolean',
|
|
|
7121 |
default: false
|
|
|
7122 |
});
|
|
|
7123 |
registerOption('images_upload_handler', { processor: 'function' });
|
|
|
7124 |
registerOption('language', {
|
|
|
7125 |
processor: 'string',
|
|
|
7126 |
default: 'en'
|
|
|
7127 |
});
|
|
|
7128 |
registerOption('language_url', {
|
|
|
7129 |
processor: 'string',
|
|
|
7130 |
default: ''
|
|
|
7131 |
});
|
|
|
7132 |
registerOption('entity_encoding', {
|
|
|
7133 |
processor: 'string',
|
|
|
7134 |
default: 'named'
|
|
|
7135 |
});
|
|
|
7136 |
registerOption('indent', {
|
|
|
7137 |
processor: 'boolean',
|
|
|
7138 |
default: true
|
|
|
7139 |
});
|
|
|
7140 |
registerOption('indent_before', {
|
|
|
7141 |
processor: 'string',
|
|
|
7142 |
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'
|
|
|
7143 |
});
|
|
|
7144 |
registerOption('indent_after', {
|
|
|
7145 |
processor: 'string',
|
|
|
7146 |
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'
|
|
|
7147 |
});
|
|
|
7148 |
registerOption('indent_use_margin', {
|
|
|
7149 |
processor: 'boolean',
|
|
|
7150 |
default: false
|
|
|
7151 |
});
|
|
|
7152 |
registerOption('indentation', {
|
|
|
7153 |
processor: 'string',
|
|
|
7154 |
default: '40px'
|
|
|
7155 |
});
|
|
|
7156 |
registerOption('content_css', {
|
|
|
7157 |
processor: value => {
|
|
|
7158 |
const valid = value === false || isString(value) || isArrayOf(value, isString);
|
|
|
7159 |
if (valid) {
|
|
|
7160 |
if (isString(value)) {
|
|
|
7161 |
return {
|
|
|
7162 |
value: map$3(value.split(','), trim$4),
|
|
|
7163 |
valid
|
|
|
7164 |
};
|
|
|
7165 |
} else if (isArray$1(value)) {
|
|
|
7166 |
return {
|
|
|
7167 |
value,
|
|
|
7168 |
valid
|
|
|
7169 |
};
|
|
|
7170 |
} else if (value === false) {
|
|
|
7171 |
return {
|
|
|
7172 |
value: [],
|
|
|
7173 |
valid
|
|
|
7174 |
};
|
|
|
7175 |
} else {
|
|
|
7176 |
return {
|
|
|
7177 |
value,
|
|
|
7178 |
valid
|
|
|
7179 |
};
|
|
|
7180 |
}
|
|
|
7181 |
} else {
|
|
|
7182 |
return {
|
|
|
7183 |
valid: false,
|
|
|
7184 |
message: 'Must be false, a string or an array of strings.'
|
|
|
7185 |
};
|
|
|
7186 |
}
|
|
|
7187 |
},
|
|
|
7188 |
default: isInline$1(editor) ? [] : ['default']
|
|
|
7189 |
});
|
|
|
7190 |
registerOption('content_style', { processor: 'string' });
|
|
|
7191 |
registerOption('content_css_cors', {
|
|
|
7192 |
processor: 'boolean',
|
|
|
7193 |
default: false
|
|
|
7194 |
});
|
|
|
7195 |
registerOption('font_css', {
|
|
|
7196 |
processor: value => {
|
|
|
7197 |
const valid = isString(value) || isArrayOf(value, isString);
|
|
|
7198 |
if (valid) {
|
|
|
7199 |
const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$4);
|
|
|
7200 |
return {
|
|
|
7201 |
value: newValue,
|
|
|
7202 |
valid
|
|
|
7203 |
};
|
|
|
7204 |
} else {
|
|
|
7205 |
return {
|
|
|
7206 |
valid: false,
|
|
|
7207 |
message: 'Must be a string or an array of strings.'
|
|
|
7208 |
};
|
|
|
7209 |
}
|
|
|
7210 |
},
|
|
|
7211 |
default: []
|
|
|
7212 |
});
|
|
|
7213 |
registerOption('inline_boundaries', {
|
|
|
7214 |
processor: 'boolean',
|
|
|
7215 |
default: true
|
|
|
7216 |
});
|
|
|
7217 |
registerOption('inline_boundaries_selector', {
|
|
|
7218 |
processor: 'string',
|
|
|
7219 |
default: 'a[href],code,span.mce-annotation'
|
|
|
7220 |
});
|
|
|
7221 |
registerOption('object_resizing', {
|
|
|
7222 |
processor: value => {
|
|
|
7223 |
const valid = isBoolean(value) || isString(value);
|
|
|
7224 |
if (valid) {
|
|
|
7225 |
if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
|
|
|
7226 |
return {
|
|
|
7227 |
value: '',
|
|
|
7228 |
valid
|
|
|
7229 |
};
|
|
|
7230 |
} else {
|
|
|
7231 |
return {
|
|
|
7232 |
value: value === true ? 'table,img,figure.image,div,video,iframe' : value,
|
|
|
7233 |
valid
|
|
|
7234 |
};
|
|
|
7235 |
}
|
|
|
7236 |
} else {
|
|
|
7237 |
return {
|
|
|
7238 |
valid: false,
|
|
|
7239 |
message: 'Must be boolean or a string'
|
|
|
7240 |
};
|
|
|
7241 |
}
|
|
|
7242 |
},
|
|
|
7243 |
default: !isTouch
|
|
|
7244 |
});
|
|
|
7245 |
registerOption('resize_img_proportional', {
|
|
|
7246 |
processor: 'boolean',
|
|
|
7247 |
default: true
|
|
|
7248 |
});
|
| 1441 |
ariadna |
7249 |
registerOption('event_root', { processor: 'string' });
|
| 1 |
efrain |
7250 |
registerOption('service_message', { processor: 'string' });
|
|
|
7251 |
registerOption('theme', {
|
|
|
7252 |
processor: value => value === false || isString(value) || isFunction(value),
|
|
|
7253 |
default: 'silver'
|
|
|
7254 |
});
|
|
|
7255 |
registerOption('theme_url', { processor: 'string' });
|
|
|
7256 |
registerOption('formats', { processor: 'object' });
|
|
|
7257 |
registerOption('format_empty_lines', {
|
|
|
7258 |
processor: 'boolean',
|
|
|
7259 |
default: false
|
|
|
7260 |
});
|
|
|
7261 |
registerOption('format_noneditable_selector', {
|
|
|
7262 |
processor: 'string',
|
|
|
7263 |
default: ''
|
|
|
7264 |
});
|
|
|
7265 |
registerOption('preview_styles', {
|
|
|
7266 |
processor: value => {
|
|
|
7267 |
const valid = value === false || isString(value);
|
|
|
7268 |
if (valid) {
|
|
|
7269 |
return {
|
|
|
7270 |
value: value === false ? '' : value,
|
|
|
7271 |
valid
|
|
|
7272 |
};
|
|
|
7273 |
} else {
|
|
|
7274 |
return {
|
|
|
7275 |
valid: false,
|
|
|
7276 |
message: 'Must be false or a string'
|
|
|
7277 |
};
|
|
|
7278 |
}
|
|
|
7279 |
},
|
|
|
7280 |
default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow'
|
|
|
7281 |
});
|
|
|
7282 |
registerOption('custom_ui_selector', {
|
|
|
7283 |
processor: 'string',
|
|
|
7284 |
default: ''
|
|
|
7285 |
});
|
|
|
7286 |
registerOption('hidden_input', {
|
|
|
7287 |
processor: 'boolean',
|
|
|
7288 |
default: true
|
|
|
7289 |
});
|
|
|
7290 |
registerOption('submit_patch', {
|
|
|
7291 |
processor: 'boolean',
|
|
|
7292 |
default: true
|
|
|
7293 |
});
|
|
|
7294 |
registerOption('encoding', { processor: 'string' });
|
|
|
7295 |
registerOption('add_form_submit_trigger', {
|
|
|
7296 |
processor: 'boolean',
|
|
|
7297 |
default: true
|
|
|
7298 |
});
|
|
|
7299 |
registerOption('add_unload_trigger', {
|
|
|
7300 |
processor: 'boolean',
|
|
|
7301 |
default: true
|
|
|
7302 |
});
|
|
|
7303 |
registerOption('custom_undo_redo_levels', {
|
|
|
7304 |
processor: 'number',
|
|
|
7305 |
default: 0
|
|
|
7306 |
});
|
|
|
7307 |
registerOption('disable_nodechange', {
|
|
|
7308 |
processor: 'boolean',
|
|
|
7309 |
default: false
|
|
|
7310 |
});
|
| 1441 |
ariadna |
7311 |
registerOption('disabled', {
|
|
|
7312 |
processor: value => {
|
|
|
7313 |
if (isBoolean(value)) {
|
|
|
7314 |
if (editor.initialized && isDisabled$1(editor) !== value) {
|
|
|
7315 |
Promise.resolve().then(() => {
|
|
|
7316 |
fireDisabledStateChange(editor, value);
|
|
|
7317 |
});
|
|
|
7318 |
}
|
|
|
7319 |
return {
|
|
|
7320 |
valid: true,
|
|
|
7321 |
value
|
|
|
7322 |
};
|
|
|
7323 |
}
|
|
|
7324 |
return {
|
|
|
7325 |
valid: false,
|
|
|
7326 |
message: 'The value must be a boolean.'
|
|
|
7327 |
};
|
|
|
7328 |
},
|
|
|
7329 |
default: false
|
|
|
7330 |
});
|
| 1 |
efrain |
7331 |
registerOption('readonly', {
|
|
|
7332 |
processor: 'boolean',
|
|
|
7333 |
default: false
|
|
|
7334 |
});
|
|
|
7335 |
registerOption('editable_root', {
|
|
|
7336 |
processor: 'boolean',
|
|
|
7337 |
default: true
|
|
|
7338 |
});
|
|
|
7339 |
registerOption('plugins', {
|
|
|
7340 |
processor: 'string[]',
|
|
|
7341 |
default: []
|
|
|
7342 |
});
|
|
|
7343 |
registerOption('external_plugins', { processor: 'object' });
|
|
|
7344 |
registerOption('forced_plugins', { processor: 'string[]' });
|
|
|
7345 |
registerOption('model', {
|
|
|
7346 |
processor: 'string',
|
|
|
7347 |
default: editor.hasPlugin('rtc') ? 'plugin' : 'dom'
|
|
|
7348 |
});
|
|
|
7349 |
registerOption('model_url', { processor: 'string' });
|
|
|
7350 |
registerOption('block_unsupported_drop', {
|
|
|
7351 |
processor: 'boolean',
|
|
|
7352 |
default: true
|
|
|
7353 |
});
|
|
|
7354 |
registerOption('visual', {
|
|
|
7355 |
processor: 'boolean',
|
|
|
7356 |
default: true
|
|
|
7357 |
});
|
|
|
7358 |
registerOption('visual_table_class', {
|
|
|
7359 |
processor: 'string',
|
|
|
7360 |
default: 'mce-item-table'
|
|
|
7361 |
});
|
|
|
7362 |
registerOption('visual_anchor_class', {
|
|
|
7363 |
processor: 'string',
|
|
|
7364 |
default: 'mce-item-anchor'
|
|
|
7365 |
});
|
|
|
7366 |
registerOption('iframe_aria_text', {
|
|
|
7367 |
processor: 'string',
|
| 1441 |
ariadna |
7368 |
default: 'Rich Text Area'.concat(editor.hasPlugin('help') ? '. Press ALT-0 for help.' : '')
|
| 1 |
efrain |
7369 |
});
|
|
|
7370 |
registerOption('setup', { processor: 'function' });
|
|
|
7371 |
registerOption('init_instance_callback', { processor: 'function' });
|
|
|
7372 |
registerOption('url_converter', {
|
|
|
7373 |
processor: 'function',
|
|
|
7374 |
default: editor.convertURL
|
|
|
7375 |
});
|
|
|
7376 |
registerOption('url_converter_scope', {
|
|
|
7377 |
processor: 'object',
|
|
|
7378 |
default: editor
|
|
|
7379 |
});
|
|
|
7380 |
registerOption('urlconverter_callback', { processor: 'function' });
|
|
|
7381 |
registerOption('allow_conditional_comments', {
|
|
|
7382 |
processor: 'boolean',
|
|
|
7383 |
default: false
|
|
|
7384 |
});
|
|
|
7385 |
registerOption('allow_html_data_urls', {
|
|
|
7386 |
processor: 'boolean',
|
|
|
7387 |
default: false
|
|
|
7388 |
});
|
|
|
7389 |
registerOption('allow_svg_data_urls', { processor: 'boolean' });
|
|
|
7390 |
registerOption('allow_html_in_named_anchor', {
|
|
|
7391 |
processor: 'boolean',
|
|
|
7392 |
default: false
|
|
|
7393 |
});
|
|
|
7394 |
registerOption('allow_script_urls', {
|
|
|
7395 |
processor: 'boolean',
|
|
|
7396 |
default: false
|
|
|
7397 |
});
|
|
|
7398 |
registerOption('allow_unsafe_link_target', {
|
|
|
7399 |
processor: 'boolean',
|
|
|
7400 |
default: false
|
|
|
7401 |
});
|
| 1441 |
ariadna |
7402 |
registerOption('allow_mathml_annotation_encodings', {
|
|
|
7403 |
processor: value => {
|
|
|
7404 |
const valid = isArrayOf(value, isString);
|
|
|
7405 |
return valid ? {
|
|
|
7406 |
value,
|
|
|
7407 |
valid
|
|
|
7408 |
} : {
|
|
|
7409 |
valid: false,
|
|
|
7410 |
message: 'Must be an array of strings.'
|
|
|
7411 |
};
|
|
|
7412 |
},
|
|
|
7413 |
default: []
|
|
|
7414 |
});
|
| 1 |
efrain |
7415 |
registerOption('convert_fonts_to_spans', {
|
|
|
7416 |
processor: 'boolean',
|
|
|
7417 |
default: true,
|
|
|
7418 |
deprecated: true
|
|
|
7419 |
});
|
|
|
7420 |
registerOption('fix_list_elements', {
|
|
|
7421 |
processor: 'boolean',
|
|
|
7422 |
default: false
|
|
|
7423 |
});
|
|
|
7424 |
registerOption('preserve_cdata', {
|
|
|
7425 |
processor: 'boolean',
|
|
|
7426 |
default: false
|
|
|
7427 |
});
|
|
|
7428 |
registerOption('remove_trailing_brs', {
|
|
|
7429 |
processor: 'boolean',
|
|
|
7430 |
default: true
|
|
|
7431 |
});
|
|
|
7432 |
registerOption('pad_empty_with_br', {
|
|
|
7433 |
processor: 'boolean',
|
|
|
7434 |
default: false
|
|
|
7435 |
});
|
|
|
7436 |
registerOption('inline_styles', {
|
|
|
7437 |
processor: 'boolean',
|
|
|
7438 |
default: true,
|
|
|
7439 |
deprecated: true
|
|
|
7440 |
});
|
|
|
7441 |
registerOption('element_format', {
|
|
|
7442 |
processor: 'string',
|
|
|
7443 |
default: 'html'
|
|
|
7444 |
});
|
|
|
7445 |
registerOption('entities', { processor: 'string' });
|
|
|
7446 |
registerOption('schema', {
|
|
|
7447 |
processor: 'string',
|
|
|
7448 |
default: 'html5'
|
|
|
7449 |
});
|
|
|
7450 |
registerOption('convert_urls', {
|
|
|
7451 |
processor: 'boolean',
|
|
|
7452 |
default: true
|
|
|
7453 |
});
|
|
|
7454 |
registerOption('relative_urls', {
|
|
|
7455 |
processor: 'boolean',
|
|
|
7456 |
default: true
|
|
|
7457 |
});
|
|
|
7458 |
registerOption('remove_script_host', {
|
|
|
7459 |
processor: 'boolean',
|
|
|
7460 |
default: true
|
|
|
7461 |
});
|
| 1441 |
ariadna |
7462 |
registerOption('custom_elements', { processor: stringOrObjectProcessor });
|
| 1 |
efrain |
7463 |
registerOption('extended_valid_elements', { processor: 'string' });
|
|
|
7464 |
registerOption('invalid_elements', { processor: 'string' });
|
|
|
7465 |
registerOption('invalid_styles', { processor: stringOrObjectProcessor });
|
|
|
7466 |
registerOption('valid_children', { processor: 'string' });
|
|
|
7467 |
registerOption('valid_classes', { processor: stringOrObjectProcessor });
|
|
|
7468 |
registerOption('valid_elements', { processor: 'string' });
|
|
|
7469 |
registerOption('valid_styles', { processor: stringOrObjectProcessor });
|
|
|
7470 |
registerOption('verify_html', {
|
|
|
7471 |
processor: 'boolean',
|
|
|
7472 |
default: true
|
|
|
7473 |
});
|
|
|
7474 |
registerOption('auto_focus', { processor: value => isString(value) || value === true });
|
|
|
7475 |
registerOption('browser_spellcheck', {
|
|
|
7476 |
processor: 'boolean',
|
|
|
7477 |
default: false
|
|
|
7478 |
});
|
|
|
7479 |
registerOption('protect', { processor: 'array' });
|
|
|
7480 |
registerOption('images_file_types', {
|
|
|
7481 |
processor: 'string',
|
|
|
7482 |
default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'
|
|
|
7483 |
});
|
|
|
7484 |
registerOption('deprecation_warnings', {
|
|
|
7485 |
processor: 'boolean',
|
|
|
7486 |
default: true
|
|
|
7487 |
});
|
|
|
7488 |
registerOption('a11y_advanced_options', {
|
|
|
7489 |
processor: 'boolean',
|
|
|
7490 |
default: false
|
|
|
7491 |
});
|
|
|
7492 |
registerOption('api_key', { processor: 'string' });
|
| 1441 |
ariadna |
7493 |
registerOption('license_key', { processor: 'string' });
|
| 1 |
efrain |
7494 |
registerOption('paste_block_drop', {
|
|
|
7495 |
processor: 'boolean',
|
|
|
7496 |
default: false
|
|
|
7497 |
});
|
|
|
7498 |
registerOption('paste_data_images', {
|
|
|
7499 |
processor: 'boolean',
|
|
|
7500 |
default: true
|
|
|
7501 |
});
|
|
|
7502 |
registerOption('paste_preprocess', { processor: 'function' });
|
|
|
7503 |
registerOption('paste_postprocess', { processor: 'function' });
|
|
|
7504 |
registerOption('paste_webkit_styles', {
|
|
|
7505 |
processor: 'string',
|
|
|
7506 |
default: 'none'
|
|
|
7507 |
});
|
|
|
7508 |
registerOption('paste_remove_styles_if_webkit', {
|
|
|
7509 |
processor: 'boolean',
|
|
|
7510 |
default: true
|
|
|
7511 |
});
|
|
|
7512 |
registerOption('paste_merge_formats', {
|
|
|
7513 |
processor: 'boolean',
|
|
|
7514 |
default: true
|
|
|
7515 |
});
|
|
|
7516 |
registerOption('smart_paste', {
|
|
|
7517 |
processor: 'boolean',
|
|
|
7518 |
default: true
|
|
|
7519 |
});
|
|
|
7520 |
registerOption('paste_as_text', {
|
|
|
7521 |
processor: 'boolean',
|
|
|
7522 |
default: false
|
|
|
7523 |
});
|
|
|
7524 |
registerOption('paste_tab_spaces', {
|
|
|
7525 |
processor: 'number',
|
|
|
7526 |
default: 4
|
|
|
7527 |
});
|
|
|
7528 |
registerOption('text_patterns', {
|
|
|
7529 |
processor: value => {
|
|
|
7530 |
if (isArrayOf(value, isObject) || value === false) {
|
|
|
7531 |
const patterns = value === false ? [] : value;
|
|
|
7532 |
return {
|
|
|
7533 |
value: fromRawPatterns(patterns),
|
|
|
7534 |
valid: true
|
|
|
7535 |
};
|
|
|
7536 |
} else {
|
|
|
7537 |
return {
|
|
|
7538 |
valid: false,
|
|
|
7539 |
message: 'Must be an array of objects or false.'
|
|
|
7540 |
};
|
|
|
7541 |
}
|
|
|
7542 |
},
|
|
|
7543 |
default: [
|
|
|
7544 |
{
|
|
|
7545 |
start: '*',
|
|
|
7546 |
end: '*',
|
|
|
7547 |
format: 'italic'
|
|
|
7548 |
},
|
|
|
7549 |
{
|
|
|
7550 |
start: '**',
|
|
|
7551 |
end: '**',
|
|
|
7552 |
format: 'bold'
|
|
|
7553 |
},
|
|
|
7554 |
{
|
|
|
7555 |
start: '#',
|
| 1441 |
ariadna |
7556 |
format: 'h1',
|
|
|
7557 |
trigger: 'space'
|
| 1 |
efrain |
7558 |
},
|
|
|
7559 |
{
|
|
|
7560 |
start: '##',
|
| 1441 |
ariadna |
7561 |
format: 'h2',
|
|
|
7562 |
trigger: 'space'
|
| 1 |
efrain |
7563 |
},
|
|
|
7564 |
{
|
|
|
7565 |
start: '###',
|
| 1441 |
ariadna |
7566 |
format: 'h3',
|
|
|
7567 |
trigger: 'space'
|
| 1 |
efrain |
7568 |
},
|
|
|
7569 |
{
|
|
|
7570 |
start: '####',
|
| 1441 |
ariadna |
7571 |
format: 'h4',
|
|
|
7572 |
trigger: 'space'
|
| 1 |
efrain |
7573 |
},
|
|
|
7574 |
{
|
|
|
7575 |
start: '#####',
|
| 1441 |
ariadna |
7576 |
format: 'h5',
|
|
|
7577 |
trigger: 'space'
|
| 1 |
efrain |
7578 |
},
|
|
|
7579 |
{
|
|
|
7580 |
start: '######',
|
| 1441 |
ariadna |
7581 |
format: 'h6',
|
|
|
7582 |
trigger: 'space'
|
| 1 |
efrain |
7583 |
},
|
|
|
7584 |
{
|
| 1441 |
ariadna |
7585 |
start: '1.',
|
|
|
7586 |
cmd: 'InsertOrderedList',
|
|
|
7587 |
trigger: 'space'
|
| 1 |
efrain |
7588 |
},
|
|
|
7589 |
{
|
| 1441 |
ariadna |
7590 |
start: '*',
|
|
|
7591 |
cmd: 'InsertUnorderedList',
|
|
|
7592 |
trigger: 'space'
|
| 1 |
efrain |
7593 |
},
|
|
|
7594 |
{
|
| 1441 |
ariadna |
7595 |
start: '-',
|
|
|
7596 |
cmd: 'InsertUnorderedList',
|
|
|
7597 |
trigger: 'space'
|
|
|
7598 |
},
|
|
|
7599 |
{
|
|
|
7600 |
start: '>',
|
|
|
7601 |
cmd: 'mceBlockQuote',
|
|
|
7602 |
trigger: 'space'
|
|
|
7603 |
},
|
|
|
7604 |
{
|
|
|
7605 |
start: '---',
|
|
|
7606 |
cmd: 'InsertHorizontalRule',
|
|
|
7607 |
trigger: 'space'
|
| 1 |
efrain |
7608 |
}
|
|
|
7609 |
]
|
|
|
7610 |
});
|
|
|
7611 |
registerOption('text_patterns_lookup', {
|
|
|
7612 |
processor: value => {
|
|
|
7613 |
if (isFunction(value)) {
|
|
|
7614 |
return {
|
|
|
7615 |
value: fromRawPatternsLookup(value),
|
|
|
7616 |
valid: true
|
|
|
7617 |
};
|
|
|
7618 |
} else {
|
|
|
7619 |
return {
|
|
|
7620 |
valid: false,
|
|
|
7621 |
message: 'Must be a single function'
|
|
|
7622 |
};
|
|
|
7623 |
}
|
|
|
7624 |
},
|
|
|
7625 |
default: _ctx => []
|
|
|
7626 |
});
|
|
|
7627 |
registerOption('noneditable_class', {
|
|
|
7628 |
processor: 'string',
|
|
|
7629 |
default: 'mceNonEditable'
|
|
|
7630 |
});
|
|
|
7631 |
registerOption('editable_class', {
|
|
|
7632 |
processor: 'string',
|
|
|
7633 |
default: 'mceEditable'
|
|
|
7634 |
});
|
|
|
7635 |
registerOption('noneditable_regexp', {
|
|
|
7636 |
processor: value => {
|
|
|
7637 |
if (isArrayOf(value, isRegExp)) {
|
|
|
7638 |
return {
|
|
|
7639 |
value,
|
|
|
7640 |
valid: true
|
|
|
7641 |
};
|
|
|
7642 |
} else if (isRegExp(value)) {
|
|
|
7643 |
return {
|
|
|
7644 |
value: [value],
|
|
|
7645 |
valid: true
|
|
|
7646 |
};
|
|
|
7647 |
} else {
|
|
|
7648 |
return {
|
|
|
7649 |
valid: false,
|
|
|
7650 |
message: 'Must be a RegExp or an array of RegExp.'
|
|
|
7651 |
};
|
|
|
7652 |
}
|
|
|
7653 |
},
|
|
|
7654 |
default: []
|
|
|
7655 |
});
|
|
|
7656 |
registerOption('table_tab_navigation', {
|
|
|
7657 |
processor: 'boolean',
|
|
|
7658 |
default: true
|
|
|
7659 |
});
|
|
|
7660 |
registerOption('highlight_on_focus', {
|
|
|
7661 |
processor: 'boolean',
|
| 1441 |
ariadna |
7662 |
default: true
|
| 1 |
efrain |
7663 |
});
|
|
|
7664 |
registerOption('xss_sanitization', {
|
|
|
7665 |
processor: 'boolean',
|
|
|
7666 |
default: true
|
|
|
7667 |
});
|
|
|
7668 |
registerOption('details_initial_state', {
|
|
|
7669 |
processor: value => {
|
|
|
7670 |
const valid = contains$2([
|
|
|
7671 |
'inherited',
|
|
|
7672 |
'collapsed',
|
|
|
7673 |
'expanded'
|
|
|
7674 |
], value);
|
|
|
7675 |
return valid ? {
|
|
|
7676 |
value,
|
|
|
7677 |
valid
|
|
|
7678 |
} : {
|
|
|
7679 |
valid: false,
|
|
|
7680 |
message: 'Must be one of: inherited, collapsed, or expanded.'
|
|
|
7681 |
};
|
|
|
7682 |
},
|
|
|
7683 |
default: 'inherited'
|
|
|
7684 |
});
|
|
|
7685 |
registerOption('details_serialized_state', {
|
|
|
7686 |
processor: value => {
|
|
|
7687 |
const valid = contains$2([
|
|
|
7688 |
'inherited',
|
|
|
7689 |
'collapsed',
|
|
|
7690 |
'expanded'
|
|
|
7691 |
], value);
|
|
|
7692 |
return valid ? {
|
|
|
7693 |
value,
|
|
|
7694 |
valid
|
|
|
7695 |
} : {
|
|
|
7696 |
valid: false,
|
|
|
7697 |
message: 'Must be one of: inherited, collapsed, or expanded.'
|
|
|
7698 |
};
|
|
|
7699 |
},
|
|
|
7700 |
default: 'inherited'
|
|
|
7701 |
});
|
|
|
7702 |
registerOption('init_content_sync', {
|
|
|
7703 |
processor: 'boolean',
|
|
|
7704 |
default: false
|
|
|
7705 |
});
|
|
|
7706 |
registerOption('newdocument_content', {
|
|
|
7707 |
processor: 'string',
|
|
|
7708 |
default: ''
|
|
|
7709 |
});
|
|
|
7710 |
registerOption('sandbox_iframes', {
|
|
|
7711 |
processor: 'boolean',
|
| 1441 |
ariadna |
7712 |
default: true
|
| 1 |
efrain |
7713 |
});
|
| 1441 |
ariadna |
7714 |
registerOption('sandbox_iframes_exclusions', {
|
|
|
7715 |
processor: 'string[]',
|
|
|
7716 |
default: [
|
|
|
7717 |
'youtube.com',
|
|
|
7718 |
'youtu.be',
|
|
|
7719 |
'vimeo.com',
|
|
|
7720 |
'player.vimeo.com',
|
|
|
7721 |
'dailymotion.com',
|
|
|
7722 |
'embed.music.apple.com',
|
|
|
7723 |
'open.spotify.com',
|
|
|
7724 |
'giphy.com',
|
|
|
7725 |
'dai.ly',
|
|
|
7726 |
'codepen.io'
|
|
|
7727 |
]
|
|
|
7728 |
});
|
| 1 |
efrain |
7729 |
registerOption('convert_unsafe_embeds', {
|
|
|
7730 |
processor: 'boolean',
|
| 1441 |
ariadna |
7731 |
default: true
|
| 1 |
efrain |
7732 |
});
|
|
|
7733 |
editor.on('ScriptsLoaded', () => {
|
|
|
7734 |
registerOption('directionality', {
|
|
|
7735 |
processor: 'string',
|
|
|
7736 |
default: I18n.isRtl() ? 'rtl' : undefined
|
|
|
7737 |
});
|
|
|
7738 |
registerOption('placeholder', {
|
|
|
7739 |
processor: 'string',
|
|
|
7740 |
default: DOM$a.getAttrib(editor.getElement(), 'placeholder')
|
|
|
7741 |
});
|
|
|
7742 |
});
|
|
|
7743 |
};
|
|
|
7744 |
const getIframeAttrs = option('iframe_attrs');
|
|
|
7745 |
const getDocType = option('doctype');
|
|
|
7746 |
const getDocumentBaseUrl = option('document_base_url');
|
|
|
7747 |
const getBodyId = option('body_id');
|
|
|
7748 |
const getBodyClass = option('body_class');
|
|
|
7749 |
const getContentSecurityPolicy = option('content_security_policy');
|
|
|
7750 |
const shouldPutBrInPre$1 = option('br_in_pre');
|
|
|
7751 |
const getForcedRootBlock = option('forced_root_block');
|
|
|
7752 |
const getForcedRootBlockAttrs = option('forced_root_block_attrs');
|
|
|
7753 |
const getNewlineBehavior = option('newline_behavior');
|
|
|
7754 |
const getBrNewLineSelector = option('br_newline_selector');
|
|
|
7755 |
const getNoNewLineSelector = option('no_newline_selector');
|
|
|
7756 |
const shouldKeepStyles = option('keep_styles');
|
|
|
7757 |
const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
|
|
|
7758 |
const isAutomaticUploadsEnabled = option('automatic_uploads');
|
|
|
7759 |
const shouldReuseFileName = option('images_reuse_filename');
|
|
|
7760 |
const shouldReplaceBlobUris = option('images_replace_blob_uris');
|
|
|
7761 |
const getIconPackName = option('icons');
|
|
|
7762 |
const getIconsUrl = option('icons_url');
|
|
|
7763 |
const getImageUploadUrl = option('images_upload_url');
|
|
|
7764 |
const getImageUploadBasePath = option('images_upload_base_path');
|
|
|
7765 |
const getImagesUploadCredentials = option('images_upload_credentials');
|
|
|
7766 |
const getImagesUploadHandler = option('images_upload_handler');
|
|
|
7767 |
const shouldUseContentCssCors = option('content_css_cors');
|
|
|
7768 |
const getReferrerPolicy = option('referrer_policy');
|
|
|
7769 |
const getLanguageCode = option('language');
|
|
|
7770 |
const getLanguageUrl = option('language_url');
|
|
|
7771 |
const shouldIndentUseMargin = option('indent_use_margin');
|
|
|
7772 |
const getIndentation = option('indentation');
|
|
|
7773 |
const getContentCss = option('content_css');
|
|
|
7774 |
const getContentStyle = option('content_style');
|
|
|
7775 |
const getFontCss = option('font_css');
|
|
|
7776 |
const getDirectionality = option('directionality');
|
|
|
7777 |
const getInlineBoundarySelector = option('inline_boundaries_selector');
|
|
|
7778 |
const getObjectResizing = option('object_resizing');
|
|
|
7779 |
const getResizeImgProportional = option('resize_img_proportional');
|
|
|
7780 |
const getPlaceholder = option('placeholder');
|
|
|
7781 |
const getEventRoot = option('event_root');
|
|
|
7782 |
const getServiceMessage = option('service_message');
|
|
|
7783 |
const getTheme = option('theme');
|
|
|
7784 |
const getThemeUrl = option('theme_url');
|
|
|
7785 |
const getModel = option('model');
|
|
|
7786 |
const getModelUrl = option('model_url');
|
|
|
7787 |
const isInlineBoundariesEnabled = option('inline_boundaries');
|
|
|
7788 |
const getFormats = option('formats');
|
|
|
7789 |
const getPreviewStyles = option('preview_styles');
|
|
|
7790 |
const canFormatEmptyLines = option('format_empty_lines');
|
|
|
7791 |
const getFormatNoneditableSelector = option('format_noneditable_selector');
|
|
|
7792 |
const getCustomUiSelector = option('custom_ui_selector');
|
|
|
7793 |
const isInline$1 = option('inline');
|
|
|
7794 |
const hasHiddenInput = option('hidden_input');
|
|
|
7795 |
const shouldPatchSubmit = option('submit_patch');
|
|
|
7796 |
const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
|
|
|
7797 |
const shouldAddUnloadTrigger = option('add_unload_trigger');
|
|
|
7798 |
const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
|
|
|
7799 |
const shouldDisableNodeChange = option('disable_nodechange');
|
|
|
7800 |
const isReadOnly$1 = option('readonly');
|
|
|
7801 |
const hasEditableRoot$1 = option('editable_root');
|
|
|
7802 |
const hasContentCssCors = option('content_css_cors');
|
|
|
7803 |
const getPlugins = option('plugins');
|
|
|
7804 |
const getExternalPlugins$1 = option('external_plugins');
|
|
|
7805 |
const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
|
|
|
7806 |
const isVisualAidsEnabled = option('visual');
|
|
|
7807 |
const getVisualAidsTableClass = option('visual_table_class');
|
|
|
7808 |
const getVisualAidsAnchorClass = option('visual_anchor_class');
|
|
|
7809 |
const getIframeAriaText = option('iframe_aria_text');
|
|
|
7810 |
const getSetupCallback = option('setup');
|
|
|
7811 |
const getInitInstanceCallback = option('init_instance_callback');
|
|
|
7812 |
const getUrlConverterCallback = option('urlconverter_callback');
|
|
|
7813 |
const getAutoFocus = option('auto_focus');
|
|
|
7814 |
const shouldBrowserSpellcheck = option('browser_spellcheck');
|
|
|
7815 |
const getProtect = option('protect');
|
|
|
7816 |
const shouldPasteBlockDrop = option('paste_block_drop');
|
|
|
7817 |
const shouldPasteDataImages = option('paste_data_images');
|
|
|
7818 |
const getPastePreProcess = option('paste_preprocess');
|
|
|
7819 |
const getPastePostProcess = option('paste_postprocess');
|
|
|
7820 |
const getNewDocumentContent = option('newdocument_content');
|
|
|
7821 |
const getPasteWebkitStyles = option('paste_webkit_styles');
|
|
|
7822 |
const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
|
|
|
7823 |
const shouldPasteMergeFormats = option('paste_merge_formats');
|
|
|
7824 |
const isSmartPasteEnabled = option('smart_paste');
|
|
|
7825 |
const isPasteAsTextEnabled = option('paste_as_text');
|
|
|
7826 |
const getPasteTabSpaces = option('paste_tab_spaces');
|
|
|
7827 |
const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
|
|
|
7828 |
const getTextPatterns = option('text_patterns');
|
|
|
7829 |
const getTextPatternsLookup = option('text_patterns_lookup');
|
|
|
7830 |
const getNonEditableClass = option('noneditable_class');
|
|
|
7831 |
const getEditableClass = option('editable_class');
|
|
|
7832 |
const getNonEditableRegExps = option('noneditable_regexp');
|
|
|
7833 |
const shouldPreserveCData = option('preserve_cdata');
|
|
|
7834 |
const shouldHighlightOnFocus = option('highlight_on_focus');
|
|
|
7835 |
const shouldSanitizeXss = option('xss_sanitization');
|
|
|
7836 |
const shouldUseDocumentWrite = option('init_content_sync');
|
|
|
7837 |
const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup');
|
|
|
7838 |
const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values'));
|
|
|
7839 |
const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes'));
|
|
|
7840 |
const isEncodingXml = editor => editor.options.get('encoding') === 'xml';
|
|
|
7841 |
const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types'));
|
|
|
7842 |
const hasTableTabNavigation = option('table_tab_navigation');
|
|
|
7843 |
const getDetailsInitialState = option('details_initial_state');
|
|
|
7844 |
const getDetailsSerializedState = option('details_serialized_state');
|
|
|
7845 |
const shouldSandboxIframes = option('sandbox_iframes');
|
| 1441 |
ariadna |
7846 |
const getSandboxIframesExclusions = editor => editor.options.get('sandbox_iframes_exclusions');
|
|
|
7847 |
const shouldConvertUnsafeEmbeds = option('convert_unsafe_embeds');
|
|
|
7848 |
const getLicenseKey = option('license_key');
|
|
|
7849 |
const getApiKey = option('api_key');
|
|
|
7850 |
const isDisabled$1 = option('disabled');
|
| 1 |
efrain |
7851 |
|
|
|
7852 |
const isElement$3 = isElement$6;
|
| 1441 |
ariadna |
7853 |
const isText$5 = isText$b;
|
| 1 |
efrain |
7854 |
const removeNode$1 = node => {
|
|
|
7855 |
const parentNode = node.parentNode;
|
|
|
7856 |
if (parentNode) {
|
|
|
7857 |
parentNode.removeChild(node);
|
|
|
7858 |
}
|
|
|
7859 |
};
|
|
|
7860 |
const trimCount = text => {
|
|
|
7861 |
const trimmedText = trim$2(text);
|
|
|
7862 |
return {
|
|
|
7863 |
count: text.length - trimmedText.length,
|
|
|
7864 |
text: trimmedText
|
|
|
7865 |
};
|
|
|
7866 |
};
|
|
|
7867 |
const deleteZwspChars = caretContainer => {
|
|
|
7868 |
let idx;
|
|
|
7869 |
while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
|
|
|
7870 |
caretContainer.deleteData(idx, 1);
|
|
|
7871 |
}
|
|
|
7872 |
};
|
|
|
7873 |
const removeUnchanged = (caretContainer, pos) => {
|
| 1441 |
ariadna |
7874 |
remove$2(caretContainer);
|
| 1 |
efrain |
7875 |
return pos;
|
|
|
7876 |
};
|
|
|
7877 |
const removeTextAndReposition = (caretContainer, pos) => {
|
|
|
7878 |
const before = trimCount(caretContainer.data.substr(0, pos.offset()));
|
|
|
7879 |
const after = trimCount(caretContainer.data.substr(pos.offset()));
|
|
|
7880 |
const text = before.text + after.text;
|
|
|
7881 |
if (text.length > 0) {
|
|
|
7882 |
deleteZwspChars(caretContainer);
|
|
|
7883 |
return CaretPosition(caretContainer, pos.offset() - before.count);
|
|
|
7884 |
} else {
|
|
|
7885 |
return pos;
|
|
|
7886 |
}
|
|
|
7887 |
};
|
|
|
7888 |
const removeElementAndReposition = (caretContainer, pos) => {
|
|
|
7889 |
const parentNode = pos.container();
|
|
|
7890 |
const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => {
|
|
|
7891 |
return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
|
|
|
7892 |
}).getOr(pos);
|
| 1441 |
ariadna |
7893 |
remove$2(caretContainer);
|
| 1 |
efrain |
7894 |
return newPosition;
|
|
|
7895 |
};
|
|
|
7896 |
const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
|
|
|
7897 |
const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
|
|
|
7898 |
const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
|
| 1441 |
ariadna |
7899 |
const remove$2 = caretContainerNode => {
|
| 1 |
efrain |
7900 |
if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
|
|
|
7901 |
if (hasContent(caretContainerNode)) {
|
|
|
7902 |
caretContainerNode.removeAttribute('data-mce-caret');
|
|
|
7903 |
} else {
|
|
|
7904 |
removeNode$1(caretContainerNode);
|
|
|
7905 |
}
|
|
|
7906 |
}
|
|
|
7907 |
if (isText$5(caretContainerNode)) {
|
|
|
7908 |
deleteZwspChars(caretContainerNode);
|
|
|
7909 |
if (caretContainerNode.data.length === 0) {
|
|
|
7910 |
removeNode$1(caretContainerNode);
|
|
|
7911 |
}
|
|
|
7912 |
}
|
|
|
7913 |
};
|
|
|
7914 |
|
|
|
7915 |
const isContentEditableFalse$8 = isContentEditableFalse$b;
|
|
|
7916 |
const isMedia$1 = isMedia$2;
|
|
|
7917 |
const isTableCell$1 = isTableCell$3;
|
|
|
7918 |
const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object';
|
|
|
7919 |
const getAbsoluteClientRect = (root, element, before) => {
|
|
|
7920 |
const clientRect = collapse(element.getBoundingClientRect(), before);
|
|
|
7921 |
let scrollX;
|
|
|
7922 |
let scrollY;
|
|
|
7923 |
if (root.tagName === 'BODY') {
|
|
|
7924 |
const docElm = root.ownerDocument.documentElement;
|
|
|
7925 |
scrollX = root.scrollLeft || docElm.scrollLeft;
|
|
|
7926 |
scrollY = root.scrollTop || docElm.scrollTop;
|
|
|
7927 |
} else {
|
|
|
7928 |
const rootRect = root.getBoundingClientRect();
|
|
|
7929 |
scrollX = root.scrollLeft - rootRect.left;
|
|
|
7930 |
scrollY = root.scrollTop - rootRect.top;
|
|
|
7931 |
}
|
|
|
7932 |
clientRect.left += scrollX;
|
|
|
7933 |
clientRect.right += scrollX;
|
|
|
7934 |
clientRect.top += scrollY;
|
|
|
7935 |
clientRect.bottom += scrollY;
|
|
|
7936 |
clientRect.width = 1;
|
|
|
7937 |
let margin = element.offsetWidth - element.clientWidth;
|
|
|
7938 |
if (margin > 0) {
|
|
|
7939 |
if (before) {
|
|
|
7940 |
margin *= -1;
|
|
|
7941 |
}
|
|
|
7942 |
clientRect.left += margin;
|
|
|
7943 |
clientRect.right += margin;
|
|
|
7944 |
}
|
|
|
7945 |
return clientRect;
|
|
|
7946 |
};
|
|
|
7947 |
const trimInlineCaretContainers = root => {
|
|
|
7948 |
var _a, _b;
|
|
|
7949 |
const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
|
|
|
7950 |
for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
|
|
|
7951 |
const node = fakeCaretTargetNodes[i].dom;
|
|
|
7952 |
let sibling = node.previousSibling;
|
|
|
7953 |
if (endsWithCaretContainer$1(sibling)) {
|
|
|
7954 |
const data = sibling.data;
|
|
|
7955 |
if (data.length === 1) {
|
|
|
7956 |
(_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling);
|
|
|
7957 |
} else {
|
|
|
7958 |
sibling.deleteData(data.length - 1, 1);
|
|
|
7959 |
}
|
|
|
7960 |
}
|
|
|
7961 |
sibling = node.nextSibling;
|
|
|
7962 |
if (startsWithCaretContainer$1(sibling)) {
|
|
|
7963 |
const data = sibling.data;
|
|
|
7964 |
if (data.length === 1) {
|
|
|
7965 |
(_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling);
|
|
|
7966 |
} else {
|
|
|
7967 |
sibling.deleteData(0, 1);
|
|
|
7968 |
}
|
|
|
7969 |
}
|
|
|
7970 |
}
|
|
|
7971 |
};
|
|
|
7972 |
const FakeCaret = (editor, root, isBlock, hasFocus) => {
|
|
|
7973 |
const lastVisualCaret = value$2();
|
|
|
7974 |
let cursorInterval;
|
|
|
7975 |
let caretContainerNode;
|
|
|
7976 |
const caretBlock = getForcedRootBlock(editor);
|
|
|
7977 |
const dom = editor.dom;
|
|
|
7978 |
const show = (before, element) => {
|
|
|
7979 |
let rng;
|
|
|
7980 |
hide();
|
|
|
7981 |
if (isTableCell$1(element)) {
|
|
|
7982 |
return null;
|
|
|
7983 |
}
|
|
|
7984 |
if (isBlock(element)) {
|
|
|
7985 |
const caretContainer = insertBlock(caretBlock, element, before);
|
|
|
7986 |
const clientRect = getAbsoluteClientRect(root, element, before);
|
|
|
7987 |
dom.setStyle(caretContainer, 'top', clientRect.top);
|
| 1441 |
ariadna |
7988 |
dom.setStyle(caretContainer, 'caret-color', 'transparent');
|
| 1 |
efrain |
7989 |
caretContainerNode = caretContainer;
|
|
|
7990 |
const caret = dom.create('div', {
|
|
|
7991 |
'class': 'mce-visual-caret',
|
|
|
7992 |
'data-mce-bogus': 'all'
|
|
|
7993 |
});
|
|
|
7994 |
dom.setStyles(caret, { ...clientRect });
|
|
|
7995 |
dom.add(root, caret);
|
|
|
7996 |
lastVisualCaret.set({
|
|
|
7997 |
caret,
|
|
|
7998 |
element,
|
|
|
7999 |
before
|
|
|
8000 |
});
|
|
|
8001 |
if (before) {
|
|
|
8002 |
dom.addClass(caret, 'mce-visual-caret-before');
|
|
|
8003 |
}
|
|
|
8004 |
startBlink();
|
|
|
8005 |
rng = element.ownerDocument.createRange();
|
|
|
8006 |
rng.setStart(caretContainer, 0);
|
|
|
8007 |
rng.setEnd(caretContainer, 0);
|
|
|
8008 |
} else {
|
|
|
8009 |
caretContainerNode = insertInline$1(element, before);
|
|
|
8010 |
rng = element.ownerDocument.createRange();
|
|
|
8011 |
if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
|
|
|
8012 |
rng.setStart(caretContainerNode, 0);
|
|
|
8013 |
rng.setEnd(caretContainerNode, 0);
|
|
|
8014 |
} else {
|
|
|
8015 |
rng.setStart(caretContainerNode, 1);
|
|
|
8016 |
rng.setEnd(caretContainerNode, 1);
|
|
|
8017 |
}
|
|
|
8018 |
return rng;
|
|
|
8019 |
}
|
|
|
8020 |
return rng;
|
|
|
8021 |
};
|
|
|
8022 |
const hide = () => {
|
|
|
8023 |
trimInlineCaretContainers(root);
|
|
|
8024 |
if (caretContainerNode) {
|
| 1441 |
ariadna |
8025 |
remove$2(caretContainerNode);
|
| 1 |
efrain |
8026 |
caretContainerNode = null;
|
|
|
8027 |
}
|
|
|
8028 |
lastVisualCaret.on(caretState => {
|
|
|
8029 |
dom.remove(caretState.caret);
|
|
|
8030 |
lastVisualCaret.clear();
|
|
|
8031 |
});
|
|
|
8032 |
if (cursorInterval) {
|
|
|
8033 |
clearInterval(cursorInterval);
|
|
|
8034 |
cursorInterval = undefined;
|
|
|
8035 |
}
|
|
|
8036 |
};
|
|
|
8037 |
const startBlink = () => {
|
|
|
8038 |
cursorInterval = setInterval(() => {
|
|
|
8039 |
lastVisualCaret.on(caretState => {
|
|
|
8040 |
if (hasFocus()) {
|
|
|
8041 |
dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden');
|
|
|
8042 |
} else {
|
|
|
8043 |
dom.addClass(caretState.caret, 'mce-visual-caret-hidden');
|
|
|
8044 |
}
|
|
|
8045 |
});
|
|
|
8046 |
}, 500);
|
|
|
8047 |
};
|
|
|
8048 |
const reposition = () => {
|
|
|
8049 |
lastVisualCaret.on(caretState => {
|
|
|
8050 |
const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
|
|
|
8051 |
dom.setStyles(caretState.caret, { ...clientRect });
|
|
|
8052 |
});
|
|
|
8053 |
};
|
|
|
8054 |
const destroy = () => clearInterval(cursorInterval);
|
|
|
8055 |
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;' + '}';
|
|
|
8056 |
return {
|
|
|
8057 |
show,
|
|
|
8058 |
hide,
|
|
|
8059 |
getCss,
|
|
|
8060 |
reposition,
|
|
|
8061 |
destroy
|
|
|
8062 |
};
|
|
|
8063 |
};
|
|
|
8064 |
const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
|
|
|
8065 |
const isInlineFakeCaretTarget = node => isContentEditableFalse$8(node) || isMedia$1(node);
|
|
|
8066 |
const isFakeCaretTarget = node => {
|
|
|
8067 |
const isTarget = isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser();
|
|
|
8068 |
return isTarget && parentElement(SugarElement.fromDom(node)).exists(isEditable$2);
|
|
|
8069 |
};
|
|
|
8070 |
|
|
|
8071 |
const isContentEditableTrue$1 = isContentEditableTrue$3;
|
|
|
8072 |
const isContentEditableFalse$7 = isContentEditableFalse$b;
|
|
|
8073 |
const isMedia = isMedia$2;
|
| 1441 |
ariadna |
8074 |
const isBlockLike = matchStyleValues('display', 'block table table-cell table-row table-caption list-item');
|
| 1 |
efrain |
8075 |
const isCaretContainer = isCaretContainer$2;
|
|
|
8076 |
const isCaretContainerBlock = isCaretContainerBlock$1;
|
|
|
8077 |
const isElement$2 = isElement$6;
|
| 1441 |
ariadna |
8078 |
const isText$4 = isText$b;
|
| 1 |
efrain |
8079 |
const isCaretCandidate$1 = isCaretCandidate$3;
|
| 1441 |
ariadna |
8080 |
const isForwards = direction => direction === 1;
|
|
|
8081 |
const isBackwards = direction => direction === -1;
|
| 1 |
efrain |
8082 |
const skipCaretContainers = (walk, shallow) => {
|
|
|
8083 |
let node;
|
|
|
8084 |
while (node = walk(shallow)) {
|
|
|
8085 |
if (!isCaretContainerBlock(node)) {
|
|
|
8086 |
return node;
|
|
|
8087 |
}
|
|
|
8088 |
}
|
|
|
8089 |
return null;
|
|
|
8090 |
};
|
|
|
8091 |
const findNode = (node, direction, predicateFn, rootNode, shallow) => {
|
|
|
8092 |
const walker = new DomTreeWalker(node, rootNode);
|
|
|
8093 |
const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node);
|
|
|
8094 |
let tempNode;
|
|
|
8095 |
if (isBackwards(direction)) {
|
|
|
8096 |
if (isCefOrCaretContainer) {
|
|
|
8097 |
tempNode = skipCaretContainers(walker.prev.bind(walker), true);
|
|
|
8098 |
if (predicateFn(tempNode)) {
|
|
|
8099 |
return tempNode;
|
|
|
8100 |
}
|
|
|
8101 |
}
|
|
|
8102 |
while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) {
|
|
|
8103 |
if (predicateFn(tempNode)) {
|
|
|
8104 |
return tempNode;
|
|
|
8105 |
}
|
|
|
8106 |
}
|
|
|
8107 |
}
|
|
|
8108 |
if (isForwards(direction)) {
|
|
|
8109 |
if (isCefOrCaretContainer) {
|
|
|
8110 |
tempNode = skipCaretContainers(walker.next.bind(walker), true);
|
|
|
8111 |
if (predicateFn(tempNode)) {
|
|
|
8112 |
return tempNode;
|
|
|
8113 |
}
|
|
|
8114 |
}
|
|
|
8115 |
while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) {
|
|
|
8116 |
if (predicateFn(tempNode)) {
|
|
|
8117 |
return tempNode;
|
|
|
8118 |
}
|
|
|
8119 |
}
|
|
|
8120 |
}
|
|
|
8121 |
return null;
|
|
|
8122 |
};
|
|
|
8123 |
const getEditingHost = (node, rootNode) => {
|
|
|
8124 |
const isCETrue = node => isContentEditableTrue$1(node.dom);
|
|
|
8125 |
const isRoot = node => node.dom === rootNode;
|
|
|
8126 |
return ancestor$4(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode);
|
|
|
8127 |
};
|
|
|
8128 |
const getParentBlock$3 = (node, rootNode) => {
|
|
|
8129 |
while (node && node !== rootNode) {
|
|
|
8130 |
if (isBlockLike(node)) {
|
|
|
8131 |
return node;
|
|
|
8132 |
}
|
|
|
8133 |
node = node.parentNode;
|
|
|
8134 |
}
|
|
|
8135 |
return null;
|
|
|
8136 |
};
|
|
|
8137 |
const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
|
|
|
8138 |
const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
|
|
|
8139 |
if (!caretPosition) {
|
|
|
8140 |
return Optional.none();
|
|
|
8141 |
}
|
|
|
8142 |
const container = caretPosition.container();
|
|
|
8143 |
const offset = caretPosition.offset();
|
|
|
8144 |
if (!isElement$2(container)) {
|
|
|
8145 |
return Optional.none();
|
|
|
8146 |
}
|
|
|
8147 |
return Optional.from(container.childNodes[offset + relativeOffset]);
|
|
|
8148 |
};
|
|
|
8149 |
const beforeAfter = (before, node) => {
|
|
|
8150 |
var _a;
|
|
|
8151 |
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
|
8152 |
const range = doc.createRange();
|
|
|
8153 |
if (before) {
|
|
|
8154 |
range.setStartBefore(node);
|
|
|
8155 |
range.setEndBefore(node);
|
|
|
8156 |
} else {
|
|
|
8157 |
range.setStartAfter(node);
|
|
|
8158 |
range.setEndAfter(node);
|
|
|
8159 |
}
|
|
|
8160 |
return range;
|
|
|
8161 |
};
|
|
|
8162 |
const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
|
|
|
8163 |
const lean = (left, root, node) => {
|
|
|
8164 |
const siblingName = left ? 'previousSibling' : 'nextSibling';
|
|
|
8165 |
let tempNode = node;
|
|
|
8166 |
while (tempNode && tempNode !== root) {
|
|
|
8167 |
let sibling = tempNode[siblingName];
|
|
|
8168 |
if (sibling && isCaretContainer(sibling)) {
|
|
|
8169 |
sibling = sibling[siblingName];
|
|
|
8170 |
}
|
|
|
8171 |
if (isContentEditableFalse$7(sibling) || isMedia(sibling)) {
|
|
|
8172 |
if (isNodesInSameBlock(root, sibling, tempNode)) {
|
|
|
8173 |
return sibling;
|
|
|
8174 |
}
|
|
|
8175 |
break;
|
|
|
8176 |
}
|
|
|
8177 |
if (isCaretCandidate$1(sibling)) {
|
|
|
8178 |
break;
|
|
|
8179 |
}
|
|
|
8180 |
tempNode = tempNode.parentNode;
|
|
|
8181 |
}
|
|
|
8182 |
return null;
|
|
|
8183 |
};
|
|
|
8184 |
const before$2 = curry(beforeAfter, true);
|
|
|
8185 |
const after$2 = curry(beforeAfter, false);
|
|
|
8186 |
const normalizeRange = (direction, root, range) => {
|
|
|
8187 |
let node;
|
|
|
8188 |
const leanLeft = curry(lean, true, root);
|
|
|
8189 |
const leanRight = curry(lean, false, root);
|
|
|
8190 |
const container = range.startContainer;
|
|
|
8191 |
const offset = range.startOffset;
|
|
|
8192 |
if (isCaretContainerBlock$1(container)) {
|
|
|
8193 |
const block = isText$4(container) ? container.parentNode : container;
|
|
|
8194 |
const location = block.getAttribute('data-mce-caret');
|
|
|
8195 |
if (location === 'before') {
|
|
|
8196 |
node = block.nextSibling;
|
|
|
8197 |
if (isFakeCaretTarget(node)) {
|
|
|
8198 |
return before$2(node);
|
|
|
8199 |
}
|
|
|
8200 |
}
|
|
|
8201 |
if (location === 'after') {
|
|
|
8202 |
node = block.previousSibling;
|
|
|
8203 |
if (isFakeCaretTarget(node)) {
|
|
|
8204 |
return after$2(node);
|
|
|
8205 |
}
|
|
|
8206 |
}
|
|
|
8207 |
}
|
|
|
8208 |
if (!range.collapsed) {
|
|
|
8209 |
return range;
|
|
|
8210 |
}
|
| 1441 |
ariadna |
8211 |
if (isText$b(container)) {
|
| 1 |
efrain |
8212 |
if (isCaretContainer(container)) {
|
|
|
8213 |
if (direction === 1) {
|
|
|
8214 |
node = leanRight(container);
|
|
|
8215 |
if (node) {
|
|
|
8216 |
return before$2(node);
|
|
|
8217 |
}
|
|
|
8218 |
node = leanLeft(container);
|
|
|
8219 |
if (node) {
|
|
|
8220 |
return after$2(node);
|
|
|
8221 |
}
|
|
|
8222 |
}
|
|
|
8223 |
if (direction === -1) {
|
|
|
8224 |
node = leanLeft(container);
|
|
|
8225 |
if (node) {
|
|
|
8226 |
return after$2(node);
|
|
|
8227 |
}
|
|
|
8228 |
node = leanRight(container);
|
|
|
8229 |
if (node) {
|
|
|
8230 |
return before$2(node);
|
|
|
8231 |
}
|
|
|
8232 |
}
|
|
|
8233 |
return range;
|
|
|
8234 |
}
|
|
|
8235 |
if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
|
|
|
8236 |
if (direction === 1) {
|
|
|
8237 |
node = leanRight(container);
|
|
|
8238 |
if (node) {
|
|
|
8239 |
return before$2(node);
|
|
|
8240 |
}
|
|
|
8241 |
}
|
|
|
8242 |
return range;
|
|
|
8243 |
}
|
|
|
8244 |
if (startsWithCaretContainer$1(container) && offset <= 1) {
|
|
|
8245 |
if (direction === -1) {
|
|
|
8246 |
node = leanLeft(container);
|
|
|
8247 |
if (node) {
|
|
|
8248 |
return after$2(node);
|
|
|
8249 |
}
|
|
|
8250 |
}
|
|
|
8251 |
return range;
|
|
|
8252 |
}
|
|
|
8253 |
if (offset === container.data.length) {
|
|
|
8254 |
node = leanRight(container);
|
|
|
8255 |
if (node) {
|
|
|
8256 |
return before$2(node);
|
|
|
8257 |
}
|
|
|
8258 |
return range;
|
|
|
8259 |
}
|
|
|
8260 |
if (offset === 0) {
|
|
|
8261 |
node = leanLeft(container);
|
|
|
8262 |
if (node) {
|
|
|
8263 |
return after$2(node);
|
|
|
8264 |
}
|
|
|
8265 |
return range;
|
|
|
8266 |
}
|
|
|
8267 |
}
|
|
|
8268 |
return range;
|
|
|
8269 |
};
|
|
|
8270 |
const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$7);
|
|
|
8271 |
const getNormalizedRangeEndPoint = (direction, root, range) => {
|
|
|
8272 |
const normalizedRange = normalizeRange(direction, root, range);
|
|
|
8273 |
return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange);
|
|
|
8274 |
};
|
|
|
8275 |
const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom);
|
|
|
8276 |
const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
|
|
|
8277 |
const getVisualCaretPosition = (walkFn, caretPosition) => {
|
|
|
8278 |
let pos = caretPosition;
|
|
|
8279 |
while (pos = walkFn(pos)) {
|
|
|
8280 |
if (pos.isVisible()) {
|
|
|
8281 |
return pos;
|
|
|
8282 |
}
|
|
|
8283 |
}
|
|
|
8284 |
return pos;
|
|
|
8285 |
};
|
|
|
8286 |
const isMoveInsideSameBlock = (from, to) => {
|
|
|
8287 |
const inSameBlock = isInSameBlock(from, to);
|
|
|
8288 |
if (!inSameBlock && isBr$6(from.getNode())) {
|
|
|
8289 |
return true;
|
|
|
8290 |
}
|
|
|
8291 |
return inSameBlock;
|
|
|
8292 |
};
|
|
|
8293 |
|
|
|
8294 |
const isContentEditableFalse$6 = isContentEditableFalse$b;
|
| 1441 |
ariadna |
8295 |
const isText$3 = isText$b;
|
| 1 |
efrain |
8296 |
const isElement$1 = isElement$6;
|
|
|
8297 |
const isBr$2 = isBr$6;
|
|
|
8298 |
const isCaretCandidate = isCaretCandidate$3;
|
|
|
8299 |
const isAtomic = isAtomic$1;
|
|
|
8300 |
const isEditableCaretCandidate = isEditableCaretCandidate$1;
|
|
|
8301 |
const getParents$3 = (node, root) => {
|
|
|
8302 |
const parents = [];
|
|
|
8303 |
let tempNode = node;
|
|
|
8304 |
while (tempNode && tempNode !== root) {
|
|
|
8305 |
parents.push(tempNode);
|
|
|
8306 |
tempNode = tempNode.parentNode;
|
|
|
8307 |
}
|
|
|
8308 |
return parents;
|
|
|
8309 |
};
|
|
|
8310 |
const nodeAtIndex = (container, offset) => {
|
|
|
8311 |
if (container.hasChildNodes() && offset < container.childNodes.length) {
|
|
|
8312 |
return container.childNodes[offset];
|
|
|
8313 |
}
|
|
|
8314 |
return null;
|
|
|
8315 |
};
|
|
|
8316 |
const getCaretCandidatePosition = (direction, node) => {
|
|
|
8317 |
if (isForwards(direction)) {
|
|
|
8318 |
if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
|
|
|
8319 |
return CaretPosition.before(node);
|
|
|
8320 |
}
|
|
|
8321 |
if (isText$3(node)) {
|
|
|
8322 |
return CaretPosition(node, 0);
|
|
|
8323 |
}
|
|
|
8324 |
}
|
|
|
8325 |
if (isBackwards(direction)) {
|
|
|
8326 |
if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
|
|
|
8327 |
return CaretPosition.after(node);
|
|
|
8328 |
}
|
|
|
8329 |
if (isText$3(node)) {
|
|
|
8330 |
return CaretPosition(node, node.data.length);
|
|
|
8331 |
}
|
|
|
8332 |
}
|
|
|
8333 |
if (isBackwards(direction)) {
|
|
|
8334 |
if (isBr$2(node)) {
|
|
|
8335 |
return CaretPosition.before(node);
|
|
|
8336 |
}
|
|
|
8337 |
return CaretPosition.after(node);
|
|
|
8338 |
}
|
|
|
8339 |
return CaretPosition.before(node);
|
|
|
8340 |
};
|
|
|
8341 |
const moveForwardFromBr = (root, nextNode) => {
|
|
|
8342 |
const nextSibling = nextNode.nextSibling;
|
|
|
8343 |
if (nextSibling && isCaretCandidate(nextSibling)) {
|
|
|
8344 |
if (isText$3(nextSibling)) {
|
|
|
8345 |
return CaretPosition(nextSibling, 0);
|
|
|
8346 |
} else {
|
|
|
8347 |
return CaretPosition.before(nextSibling);
|
|
|
8348 |
}
|
|
|
8349 |
} else {
|
| 1441 |
ariadna |
8350 |
return findCaretPosition$1(1, CaretPosition.after(nextNode), root);
|
| 1 |
efrain |
8351 |
}
|
|
|
8352 |
};
|
|
|
8353 |
const findCaretPosition$1 = (direction, startPos, root) => {
|
|
|
8354 |
let node;
|
|
|
8355 |
let nextNode;
|
|
|
8356 |
let innerNode;
|
|
|
8357 |
let caretPosition;
|
|
|
8358 |
if (!isElement$1(root) || !startPos) {
|
|
|
8359 |
return null;
|
|
|
8360 |
}
|
|
|
8361 |
if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
|
|
|
8362 |
caretPosition = CaretPosition.after(root.lastChild);
|
|
|
8363 |
if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
|
|
|
8364 |
return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
|
|
|
8365 |
}
|
|
|
8366 |
} else {
|
|
|
8367 |
caretPosition = startPos;
|
|
|
8368 |
}
|
|
|
8369 |
const container = caretPosition.container();
|
|
|
8370 |
let offset = caretPosition.offset();
|
|
|
8371 |
if (isText$3(container)) {
|
|
|
8372 |
if (isBackwards(direction) && offset > 0) {
|
|
|
8373 |
return CaretPosition(container, --offset);
|
|
|
8374 |
}
|
|
|
8375 |
if (isForwards(direction) && offset < container.length) {
|
|
|
8376 |
return CaretPosition(container, ++offset);
|
|
|
8377 |
}
|
|
|
8378 |
node = container;
|
|
|
8379 |
} else {
|
|
|
8380 |
if (isBackwards(direction) && offset > 0) {
|
|
|
8381 |
nextNode = nodeAtIndex(container, offset - 1);
|
|
|
8382 |
if (isCaretCandidate(nextNode)) {
|
|
|
8383 |
if (!isAtomic(nextNode)) {
|
|
|
8384 |
innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
|
|
|
8385 |
if (innerNode) {
|
|
|
8386 |
if (isText$3(innerNode)) {
|
|
|
8387 |
return CaretPosition(innerNode, innerNode.data.length);
|
|
|
8388 |
}
|
|
|
8389 |
return CaretPosition.after(innerNode);
|
|
|
8390 |
}
|
|
|
8391 |
}
|
|
|
8392 |
if (isText$3(nextNode)) {
|
|
|
8393 |
return CaretPosition(nextNode, nextNode.data.length);
|
|
|
8394 |
}
|
|
|
8395 |
return CaretPosition.before(nextNode);
|
|
|
8396 |
}
|
|
|
8397 |
}
|
|
|
8398 |
if (isForwards(direction) && offset < container.childNodes.length) {
|
|
|
8399 |
nextNode = nodeAtIndex(container, offset);
|
|
|
8400 |
if (isCaretCandidate(nextNode)) {
|
|
|
8401 |
if (isBr$2(nextNode)) {
|
|
|
8402 |
return moveForwardFromBr(root, nextNode);
|
|
|
8403 |
}
|
|
|
8404 |
if (!isAtomic(nextNode)) {
|
|
|
8405 |
innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
|
|
|
8406 |
if (innerNode) {
|
|
|
8407 |
if (isText$3(innerNode)) {
|
|
|
8408 |
return CaretPosition(innerNode, 0);
|
|
|
8409 |
}
|
|
|
8410 |
return CaretPosition.before(innerNode);
|
|
|
8411 |
}
|
|
|
8412 |
}
|
|
|
8413 |
if (isText$3(nextNode)) {
|
|
|
8414 |
return CaretPosition(nextNode, 0);
|
|
|
8415 |
}
|
|
|
8416 |
return CaretPosition.after(nextNode);
|
|
|
8417 |
}
|
|
|
8418 |
}
|
|
|
8419 |
node = nextNode ? nextNode : caretPosition.getNode();
|
|
|
8420 |
}
|
|
|
8421 |
if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) {
|
|
|
8422 |
node = findNode(node, direction, always, root, true);
|
|
|
8423 |
if (isEditableCaretCandidate(node, root)) {
|
|
|
8424 |
return getCaretCandidatePosition(direction, node);
|
|
|
8425 |
}
|
|
|
8426 |
}
|
|
|
8427 |
nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node;
|
| 1441 |
ariadna |
8428 |
const rootContentEditableFalseElm = last$1(filter$5(getParents$3(container, root), isContentEditableFalse$6));
|
| 1 |
efrain |
8429 |
if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
|
|
|
8430 |
if (isForwards(direction)) {
|
|
|
8431 |
caretPosition = CaretPosition.after(rootContentEditableFalseElm);
|
|
|
8432 |
} else {
|
|
|
8433 |
caretPosition = CaretPosition.before(rootContentEditableFalseElm);
|
|
|
8434 |
}
|
|
|
8435 |
return caretPosition;
|
|
|
8436 |
}
|
|
|
8437 |
if (nextNode) {
|
|
|
8438 |
return getCaretCandidatePosition(direction, nextNode);
|
|
|
8439 |
}
|
|
|
8440 |
return null;
|
|
|
8441 |
};
|
|
|
8442 |
const CaretWalker = root => ({
|
|
|
8443 |
next: caretPosition => {
|
| 1441 |
ariadna |
8444 |
return findCaretPosition$1(1, caretPosition, root);
|
| 1 |
efrain |
8445 |
},
|
|
|
8446 |
prev: caretPosition => {
|
| 1441 |
ariadna |
8447 |
return findCaretPosition$1(-1, caretPosition, root);
|
| 1 |
efrain |
8448 |
}
|
|
|
8449 |
});
|
|
|
8450 |
|
|
|
8451 |
const walkToPositionIn = (forward, root, start) => {
|
|
|
8452 |
const position = forward ? CaretPosition.before(start) : CaretPosition.after(start);
|
|
|
8453 |
return fromPosition(forward, root, position);
|
|
|
8454 |
};
|
|
|
8455 |
const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
|
|
|
8456 |
const isBeforeOrStart = position => {
|
|
|
8457 |
if (CaretPosition.isTextPosition(position)) {
|
|
|
8458 |
return position.offset() === 0;
|
|
|
8459 |
} else {
|
|
|
8460 |
return isCaretCandidate$3(position.getNode());
|
|
|
8461 |
}
|
|
|
8462 |
};
|
|
|
8463 |
const isAfterOrEnd = position => {
|
|
|
8464 |
if (CaretPosition.isTextPosition(position)) {
|
|
|
8465 |
const container = position.container();
|
|
|
8466 |
return position.offset() === container.data.length;
|
|
|
8467 |
} else {
|
|
|
8468 |
return isCaretCandidate$3(position.getNode(true));
|
|
|
8469 |
}
|
|
|
8470 |
};
|
|
|
8471 |
const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
|
|
|
8472 |
const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
|
|
|
8473 |
const shouldSkipPosition = (forward, from, to) => {
|
|
|
8474 |
if (forward) {
|
|
|
8475 |
return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
|
|
|
8476 |
} else {
|
|
|
8477 |
return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
|
|
|
8478 |
}
|
|
|
8479 |
};
|
|
|
8480 |
const fromPosition = (forward, root, pos) => {
|
|
|
8481 |
const walker = CaretWalker(root);
|
|
|
8482 |
return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
|
|
|
8483 |
};
|
|
|
8484 |
const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => {
|
|
|
8485 |
if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
|
|
|
8486 |
return fromPosition(forward, root, to);
|
|
|
8487 |
} else {
|
|
|
8488 |
return Optional.some(to);
|
|
|
8489 |
}
|
|
|
8490 |
});
|
|
|
8491 |
const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
|
|
|
8492 |
const positionIn = (forward, element) => {
|
|
|
8493 |
const startNode = forward ? element.firstChild : element.lastChild;
|
| 1441 |
ariadna |
8494 |
if (isText$b(startNode)) {
|
| 1 |
efrain |
8495 |
return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
|
|
|
8496 |
} else if (startNode) {
|
|
|
8497 |
if (isCaretCandidate$3(startNode)) {
|
|
|
8498 |
return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
|
|
|
8499 |
} else {
|
|
|
8500 |
return walkToPositionIn(forward, element, startNode);
|
|
|
8501 |
}
|
|
|
8502 |
} else {
|
|
|
8503 |
return Optional.none();
|
|
|
8504 |
}
|
|
|
8505 |
};
|
|
|
8506 |
const nextPosition = curry(fromPosition, true);
|
|
|
8507 |
const prevPosition = curry(fromPosition, false);
|
|
|
8508 |
const firstPositionIn = curry(positionIn, true);
|
|
|
8509 |
const lastPositionIn = curry(positionIn, false);
|
|
|
8510 |
|
|
|
8511 |
const CARET_ID = '_mce_caret';
|
|
|
8512 |
const isCaretNode = node => isElement$6(node) && node.id === CARET_ID;
|
|
|
8513 |
const getParentCaretContainer = (body, node) => {
|
|
|
8514 |
let currentNode = node;
|
|
|
8515 |
while (currentNode && currentNode !== body) {
|
|
|
8516 |
if (isCaretNode(currentNode)) {
|
|
|
8517 |
return currentNode;
|
|
|
8518 |
}
|
|
|
8519 |
currentNode = currentNode.parentNode;
|
|
|
8520 |
}
|
|
|
8521 |
return null;
|
|
|
8522 |
};
|
|
|
8523 |
|
|
|
8524 |
const isStringPathBookmark = bookmark => isString(bookmark.start);
|
|
|
8525 |
const isRangeBookmark = bookmark => has$2(bookmark, 'rng');
|
|
|
8526 |
const isIdBookmark = bookmark => has$2(bookmark, 'id');
|
|
|
8527 |
const isIndexBookmark = bookmark => has$2(bookmark, 'name');
|
|
|
8528 |
const isPathBookmark = bookmark => Tools.isArray(bookmark.start);
|
|
|
8529 |
|
|
|
8530 |
const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
|
|
|
8531 |
const addBogus = (dom, node) => {
|
|
|
8532 |
if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) {
|
|
|
8533 |
node.innerHTML = '<br data-mce-bogus="1" />';
|
|
|
8534 |
}
|
|
|
8535 |
return node;
|
|
|
8536 |
};
|
|
|
8537 |
const resolveCaretPositionBookmark = (dom, bookmark) => {
|
|
|
8538 |
const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start));
|
|
|
8539 |
const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end));
|
|
|
8540 |
return lift2(startPos, endPos, (start, end) => {
|
|
|
8541 |
const range = dom.createRng();
|
|
|
8542 |
range.setStart(start.container(), start.offset());
|
|
|
8543 |
range.setEnd(end.container(), end.offset());
|
|
|
8544 |
return {
|
|
|
8545 |
range,
|
|
|
8546 |
forward: isForwardBookmark(bookmark)
|
|
|
8547 |
};
|
|
|
8548 |
});
|
|
|
8549 |
};
|
|
|
8550 |
const insertZwsp = (node, rng) => {
|
|
|
8551 |
var _a;
|
|
|
8552 |
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
|
8553 |
const textNode = doc.createTextNode(ZWSP$1);
|
|
|
8554 |
node.appendChild(textNode);
|
|
|
8555 |
rng.setStart(textNode, 0);
|
|
|
8556 |
rng.setEnd(textNode, 0);
|
|
|
8557 |
};
|
|
|
8558 |
const isEmpty$1 = node => !node.hasChildNodes();
|
|
|
8559 |
const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => {
|
|
|
8560 |
rng.setStart(pos.container(), pos.offset());
|
|
|
8561 |
rng.setEnd(pos.container(), pos.offset());
|
|
|
8562 |
return true;
|
|
|
8563 |
});
|
|
|
8564 |
const padEmptyCaretContainer = (root, node, rng) => {
|
|
|
8565 |
if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
|
|
|
8566 |
insertZwsp(node, rng);
|
|
|
8567 |
return true;
|
|
|
8568 |
} else {
|
|
|
8569 |
return false;
|
|
|
8570 |
}
|
|
|
8571 |
};
|
|
|
8572 |
const setEndPoint = (dom, start, bookmark, rng) => {
|
|
|
8573 |
const point = bookmark[start ? 'start' : 'end'];
|
|
|
8574 |
const root = dom.getRoot();
|
|
|
8575 |
if (point) {
|
|
|
8576 |
let node = root;
|
|
|
8577 |
let offset = point[0];
|
|
|
8578 |
for (let i = point.length - 1; node && i >= 1; i--) {
|
|
|
8579 |
const children = node.childNodes;
|
|
|
8580 |
if (padEmptyCaretContainer(root, node, rng)) {
|
|
|
8581 |
return true;
|
|
|
8582 |
}
|
|
|
8583 |
if (point[i] > children.length - 1) {
|
|
|
8584 |
if (padEmptyCaretContainer(root, node, rng)) {
|
|
|
8585 |
return true;
|
|
|
8586 |
}
|
|
|
8587 |
return tryFindRangePosition(node, rng);
|
|
|
8588 |
}
|
|
|
8589 |
node = children[point[i]];
|
|
|
8590 |
}
|
| 1441 |
ariadna |
8591 |
if (isText$b(node)) {
|
| 1 |
efrain |
8592 |
offset = Math.min(point[0], node.data.length);
|
|
|
8593 |
}
|
|
|
8594 |
if (isElement$6(node)) {
|
|
|
8595 |
offset = Math.min(point[0], node.childNodes.length);
|
|
|
8596 |
}
|
|
|
8597 |
if (start) {
|
|
|
8598 |
rng.setStart(node, offset);
|
|
|
8599 |
} else {
|
|
|
8600 |
rng.setEnd(node, offset);
|
|
|
8601 |
}
|
|
|
8602 |
}
|
|
|
8603 |
return true;
|
|
|
8604 |
};
|
| 1441 |
ariadna |
8605 |
const isValidTextNode = node => isText$b(node) && node.data.length > 0;
|
| 1 |
efrain |
8606 |
const restoreEndPoint = (dom, suffix, bookmark) => {
|
|
|
8607 |
const marker = dom.get(bookmark.id + '_' + suffix);
|
|
|
8608 |
const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode;
|
|
|
8609 |
const keep = bookmark.keep;
|
|
|
8610 |
if (marker && markerParent) {
|
|
|
8611 |
let container;
|
|
|
8612 |
let offset;
|
|
|
8613 |
if (suffix === 'start') {
|
|
|
8614 |
if (!keep) {
|
|
|
8615 |
container = markerParent;
|
|
|
8616 |
offset = dom.nodeIndex(marker);
|
|
|
8617 |
} else {
|
|
|
8618 |
if (marker.hasChildNodes()) {
|
|
|
8619 |
container = marker.firstChild;
|
|
|
8620 |
offset = 1;
|
|
|
8621 |
} else if (isValidTextNode(marker.nextSibling)) {
|
|
|
8622 |
container = marker.nextSibling;
|
|
|
8623 |
offset = 0;
|
|
|
8624 |
} else if (isValidTextNode(marker.previousSibling)) {
|
|
|
8625 |
container = marker.previousSibling;
|
|
|
8626 |
offset = marker.previousSibling.data.length;
|
|
|
8627 |
} else {
|
|
|
8628 |
container = markerParent;
|
|
|
8629 |
offset = dom.nodeIndex(marker) + 1;
|
|
|
8630 |
}
|
|
|
8631 |
}
|
|
|
8632 |
} else {
|
|
|
8633 |
if (!keep) {
|
|
|
8634 |
container = markerParent;
|
|
|
8635 |
offset = dom.nodeIndex(marker);
|
|
|
8636 |
} else {
|
|
|
8637 |
if (marker.hasChildNodes()) {
|
|
|
8638 |
container = marker.firstChild;
|
|
|
8639 |
offset = 1;
|
|
|
8640 |
} else if (isValidTextNode(marker.previousSibling)) {
|
|
|
8641 |
container = marker.previousSibling;
|
|
|
8642 |
offset = marker.previousSibling.data.length;
|
|
|
8643 |
} else {
|
|
|
8644 |
container = markerParent;
|
|
|
8645 |
offset = dom.nodeIndex(marker);
|
|
|
8646 |
}
|
|
|
8647 |
}
|
|
|
8648 |
}
|
|
|
8649 |
if (!keep) {
|
|
|
8650 |
const prev = marker.previousSibling;
|
|
|
8651 |
const next = marker.nextSibling;
|
|
|
8652 |
Tools.each(Tools.grep(marker.childNodes), node => {
|
| 1441 |
ariadna |
8653 |
if (isText$b(node)) {
|
| 1 |
efrain |
8654 |
node.data = node.data.replace(/\uFEFF/g, '');
|
|
|
8655 |
}
|
|
|
8656 |
});
|
|
|
8657 |
let otherMarker;
|
|
|
8658 |
while (otherMarker = dom.get(bookmark.id + '_' + suffix)) {
|
|
|
8659 |
dom.remove(otherMarker, true);
|
|
|
8660 |
}
|
| 1441 |
ariadna |
8661 |
if (isText$b(next) && isText$b(prev) && !Env.browser.isOpera()) {
|
| 1 |
efrain |
8662 |
const idx = prev.data.length;
|
|
|
8663 |
prev.appendData(next.data);
|
|
|
8664 |
dom.remove(next);
|
|
|
8665 |
container = prev;
|
|
|
8666 |
offset = idx;
|
|
|
8667 |
}
|
|
|
8668 |
}
|
|
|
8669 |
return Optional.some(CaretPosition(container, offset));
|
|
|
8670 |
} else {
|
|
|
8671 |
return Optional.none();
|
|
|
8672 |
}
|
|
|
8673 |
};
|
|
|
8674 |
const resolvePaths = (dom, bookmark) => {
|
|
|
8675 |
const range = dom.createRng();
|
|
|
8676 |
if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) {
|
|
|
8677 |
return Optional.some({
|
|
|
8678 |
range,
|
|
|
8679 |
forward: isForwardBookmark(bookmark)
|
|
|
8680 |
});
|
|
|
8681 |
} else {
|
|
|
8682 |
return Optional.none();
|
|
|
8683 |
}
|
|
|
8684 |
};
|
|
|
8685 |
const resolveId = (dom, bookmark) => {
|
|
|
8686 |
const startPos = restoreEndPoint(dom, 'start', bookmark);
|
|
|
8687 |
const endPos = restoreEndPoint(dom, 'end', bookmark);
|
|
|
8688 |
return lift2(startPos, endPos.or(startPos), (spos, epos) => {
|
|
|
8689 |
const range = dom.createRng();
|
|
|
8690 |
range.setStart(addBogus(dom, spos.container()), spos.offset());
|
|
|
8691 |
range.setEnd(addBogus(dom, epos.container()), epos.offset());
|
|
|
8692 |
return {
|
|
|
8693 |
range,
|
|
|
8694 |
forward: isForwardBookmark(bookmark)
|
|
|
8695 |
};
|
|
|
8696 |
});
|
|
|
8697 |
};
|
|
|
8698 |
const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => {
|
|
|
8699 |
const range = dom.createRng();
|
|
|
8700 |
range.selectNode(elm);
|
|
|
8701 |
return {
|
|
|
8702 |
range,
|
|
|
8703 |
forward: true
|
|
|
8704 |
};
|
|
|
8705 |
});
|
|
|
8706 |
const resolve = (selection, bookmark) => {
|
|
|
8707 |
const dom = selection.dom;
|
|
|
8708 |
if (bookmark) {
|
|
|
8709 |
if (isPathBookmark(bookmark)) {
|
|
|
8710 |
return resolvePaths(dom, bookmark);
|
|
|
8711 |
} else if (isStringPathBookmark(bookmark)) {
|
|
|
8712 |
return resolveCaretPositionBookmark(dom, bookmark);
|
|
|
8713 |
} else if (isIdBookmark(bookmark)) {
|
|
|
8714 |
return resolveId(dom, bookmark);
|
|
|
8715 |
} else if (isIndexBookmark(bookmark)) {
|
|
|
8716 |
return resolveIndex(dom, bookmark);
|
|
|
8717 |
} else if (isRangeBookmark(bookmark)) {
|
|
|
8718 |
return Optional.some({
|
|
|
8719 |
range: bookmark.rng,
|
|
|
8720 |
forward: isForwardBookmark(bookmark)
|
|
|
8721 |
});
|
|
|
8722 |
}
|
|
|
8723 |
}
|
|
|
8724 |
return Optional.none();
|
|
|
8725 |
};
|
|
|
8726 |
|
| 1441 |
ariadna |
8727 |
const getBookmark$2 = (selection, type, normalized) => {
|
|
|
8728 |
return getBookmark$3(selection, type, normalized);
|
| 1 |
efrain |
8729 |
};
|
|
|
8730 |
const moveToBookmark = (selection, bookmark) => {
|
|
|
8731 |
resolve(selection, bookmark).each(({range, forward}) => {
|
|
|
8732 |
selection.setRng(range, forward);
|
|
|
8733 |
});
|
|
|
8734 |
};
|
|
|
8735 |
const isBookmarkNode$1 = node => {
|
|
|
8736 |
return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
|
|
|
8737 |
};
|
|
|
8738 |
|
|
|
8739 |
const is = expected => actual => expected === actual;
|
|
|
8740 |
const isNbsp = is(nbsp);
|
|
|
8741 |
const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1;
|
|
|
8742 |
const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$2(chr);
|
|
|
8743 |
|
|
|
8744 |
const getRanges$1 = selection => {
|
|
|
8745 |
const ranges = [];
|
|
|
8746 |
if (selection) {
|
|
|
8747 |
for (let i = 0; i < selection.rangeCount; i++) {
|
|
|
8748 |
ranges.push(selection.getRangeAt(i));
|
|
|
8749 |
}
|
|
|
8750 |
}
|
|
|
8751 |
return ranges;
|
|
|
8752 |
};
|
|
|
8753 |
const getSelectedNodes = ranges => {
|
|
|
8754 |
return bind$3(ranges, range => {
|
|
|
8755 |
const node = getSelectedNode(range);
|
|
|
8756 |
return node ? [SugarElement.fromDom(node)] : [];
|
|
|
8757 |
});
|
|
|
8758 |
};
|
|
|
8759 |
const hasMultipleRanges = selection => {
|
|
|
8760 |
return getRanges$1(selection).length > 1;
|
|
|
8761 |
};
|
|
|
8762 |
|
|
|
8763 |
const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2);
|
|
|
8764 |
const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
|
|
|
8765 |
const getCellsFromElementOrRanges = (ranges, element) => {
|
|
|
8766 |
const selectedCells = getCellsFromElement(element);
|
|
|
8767 |
return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
|
|
|
8768 |
};
|
|
|
8769 |
const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
|
|
|
8770 |
const getClosestTable = (cell, isRoot) => ancestor$3(cell, 'table', isRoot);
|
|
|
8771 |
|
|
|
8772 |
const getStartNode = rng => {
|
|
|
8773 |
const sc = rng.startContainer, so = rng.startOffset;
|
| 1441 |
ariadna |
8774 |
if (isText$b(sc)) {
|
| 1 |
efrain |
8775 |
return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
|
|
|
8776 |
} else {
|
|
|
8777 |
return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
|
|
|
8778 |
}
|
|
|
8779 |
};
|
|
|
8780 |
const getEndNode = rng => {
|
|
|
8781 |
const ec = rng.endContainer, eo = rng.endOffset;
|
| 1441 |
ariadna |
8782 |
if (isText$b(ec)) {
|
| 1 |
efrain |
8783 |
return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
|
|
|
8784 |
} else {
|
|
|
8785 |
return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
|
|
|
8786 |
}
|
|
|
8787 |
};
|
|
|
8788 |
const getFirstChildren = node => {
|
|
|
8789 |
return firstChild(node).fold(constant([node]), child => {
|
|
|
8790 |
return [node].concat(getFirstChildren(child));
|
|
|
8791 |
});
|
|
|
8792 |
};
|
|
|
8793 |
const getLastChildren = node => {
|
|
|
8794 |
return lastChild(node).fold(constant([node]), child => {
|
|
|
8795 |
if (name(child) === 'br') {
|
|
|
8796 |
return prevSibling(child).map(sibling => {
|
|
|
8797 |
return [node].concat(getLastChildren(sibling));
|
|
|
8798 |
}).getOr([]);
|
|
|
8799 |
} else {
|
|
|
8800 |
return [node].concat(getLastChildren(child));
|
|
|
8801 |
}
|
|
|
8802 |
});
|
|
|
8803 |
};
|
|
|
8804 |
const hasAllContentsSelected = (elm, rng) => {
|
|
|
8805 |
return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
|
|
|
8806 |
const start = find$2(getFirstChildren(elm), curry(eq, startNode));
|
|
|
8807 |
const end = find$2(getLastChildren(elm), curry(eq, endNode));
|
|
|
8808 |
return start.isSome() && end.isSome();
|
|
|
8809 |
}).getOr(false);
|
|
|
8810 |
};
|
|
|
8811 |
const moveEndPoint = (dom, rng, node, start) => {
|
|
|
8812 |
const root = node;
|
|
|
8813 |
const walker = new DomTreeWalker(node, root);
|
|
|
8814 |
const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([
|
|
|
8815 |
'td',
|
|
|
8816 |
'th',
|
|
|
8817 |
'table'
|
|
|
8818 |
], name.toLowerCase()));
|
|
|
8819 |
let currentNode = node;
|
|
|
8820 |
do {
|
| 1441 |
ariadna |
8821 |
if (isText$b(currentNode) && Tools.trim(currentNode.data).length !== 0) {
|
| 1 |
efrain |
8822 |
if (start) {
|
|
|
8823 |
rng.setStart(currentNode, 0);
|
|
|
8824 |
} else {
|
|
|
8825 |
rng.setEnd(currentNode, currentNode.data.length);
|
|
|
8826 |
}
|
|
|
8827 |
return;
|
|
|
8828 |
}
|
|
|
8829 |
if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) {
|
|
|
8830 |
if (start) {
|
|
|
8831 |
rng.setStartBefore(currentNode);
|
|
|
8832 |
} else {
|
|
|
8833 |
if (currentNode.nodeName === 'BR') {
|
|
|
8834 |
rng.setEndBefore(currentNode);
|
|
|
8835 |
} else {
|
|
|
8836 |
rng.setEndAfter(currentNode);
|
|
|
8837 |
}
|
|
|
8838 |
}
|
|
|
8839 |
return;
|
|
|
8840 |
}
|
|
|
8841 |
} while (currentNode = start ? walker.next() : walker.prev());
|
|
|
8842 |
if (root.nodeName === 'BODY') {
|
|
|
8843 |
if (start) {
|
|
|
8844 |
rng.setStart(root, 0);
|
|
|
8845 |
} else {
|
|
|
8846 |
rng.setEnd(root, root.childNodes.length);
|
|
|
8847 |
}
|
|
|
8848 |
}
|
|
|
8849 |
};
|
|
|
8850 |
const hasAnyRanges = editor => {
|
|
|
8851 |
const sel = editor.selection.getSel();
|
|
|
8852 |
return isNonNullable(sel) && sel.rangeCount > 0;
|
|
|
8853 |
};
|
|
|
8854 |
const runOnRanges = (editor, executor) => {
|
|
|
8855 |
const fakeSelectionNodes = getCellsFromEditor(editor);
|
|
|
8856 |
if (fakeSelectionNodes.length > 0) {
|
|
|
8857 |
each$e(fakeSelectionNodes, elem => {
|
|
|
8858 |
const node = elem.dom;
|
|
|
8859 |
const fakeNodeRng = editor.dom.createRng();
|
|
|
8860 |
fakeNodeRng.setStartBefore(node);
|
|
|
8861 |
fakeNodeRng.setEndAfter(node);
|
|
|
8862 |
executor(fakeNodeRng, true);
|
|
|
8863 |
});
|
|
|
8864 |
} else {
|
|
|
8865 |
executor(editor.selection.getRng(), false);
|
|
|
8866 |
}
|
|
|
8867 |
};
|
|
|
8868 |
const preserve = (selection, fillBookmark, executor) => {
|
|
|
8869 |
const bookmark = getPersistentBookmark(selection, fillBookmark);
|
|
|
8870 |
executor(bookmark);
|
|
|
8871 |
selection.moveToBookmark(bookmark);
|
|
|
8872 |
};
|
|
|
8873 |
|
|
|
8874 |
const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType);
|
| 1441 |
ariadna |
8875 |
const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
|
| 1 |
efrain |
8876 |
const isElementDirectlySelected = (dom, node) => {
|
|
|
8877 |
if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) {
|
|
|
8878 |
const selectedAttr = dom.getAttrib(node, 'data-mce-selected');
|
|
|
8879 |
const value = parseInt(selectedAttr, 10);
|
|
|
8880 |
return !isNaN(value) && value > 0;
|
|
|
8881 |
} else {
|
|
|
8882 |
return false;
|
|
|
8883 |
}
|
|
|
8884 |
};
|
|
|
8885 |
const preserveSelection = (editor, action, shouldMoveStart) => {
|
|
|
8886 |
const {selection, dom} = editor;
|
|
|
8887 |
const selectedNodeBeforeAction = selection.getNode();
|
|
|
8888 |
const isSelectedBeforeNodeNoneditable = isContentEditableFalse$b(selectedNodeBeforeAction);
|
|
|
8889 |
preserve(selection, true, () => {
|
|
|
8890 |
action();
|
|
|
8891 |
});
|
|
|
8892 |
const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$b(selectedNodeBeforeAction);
|
|
|
8893 |
if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) {
|
|
|
8894 |
editor.selection.select(selectedNodeBeforeAction);
|
|
|
8895 |
} else if (shouldMoveStart(selection.getStart())) {
|
|
|
8896 |
moveStartToNearestText(dom, selection);
|
|
|
8897 |
}
|
|
|
8898 |
};
|
|
|
8899 |
const moveStartToNearestText = (dom, selection) => {
|
|
|
8900 |
var _a, _b;
|
|
|
8901 |
const rng = selection.getRng();
|
|
|
8902 |
const {startContainer, startOffset} = rng;
|
|
|
8903 |
const selectedNode = selection.getNode();
|
|
|
8904 |
if (isElementDirectlySelected(dom, selectedNode)) {
|
|
|
8905 |
return;
|
|
|
8906 |
}
|
|
|
8907 |
if (isElement$6(startContainer)) {
|
|
|
8908 |
const nodes = startContainer.childNodes;
|
|
|
8909 |
const root = dom.getRoot();
|
|
|
8910 |
let walker;
|
|
|
8911 |
if (startOffset < nodes.length) {
|
|
|
8912 |
const startNode = nodes[startOffset];
|
|
|
8913 |
walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root);
|
|
|
8914 |
} else {
|
|
|
8915 |
const startNode = nodes[nodes.length - 1];
|
|
|
8916 |
walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root);
|
|
|
8917 |
walker.next(true);
|
|
|
8918 |
}
|
|
|
8919 |
for (let node = walker.current(); node; node = walker.next()) {
|
|
|
8920 |
if (dom.getContentEditable(node) === 'false') {
|
|
|
8921 |
return;
|
| 1441 |
ariadna |
8922 |
} else if (isText$b(node) && !isWhiteSpaceNode$1(node)) {
|
| 1 |
efrain |
8923 |
rng.setStart(node, 0);
|
|
|
8924 |
selection.setRng(rng);
|
|
|
8925 |
return;
|
|
|
8926 |
}
|
|
|
8927 |
}
|
|
|
8928 |
}
|
|
|
8929 |
};
|
|
|
8930 |
const getNonWhiteSpaceSibling = (node, next, inc) => {
|
|
|
8931 |
if (node) {
|
|
|
8932 |
const nextName = next ? 'nextSibling' : 'previousSibling';
|
|
|
8933 |
for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
|
|
|
8934 |
if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
|
|
|
8935 |
return node;
|
|
|
8936 |
}
|
|
|
8937 |
}
|
|
|
8938 |
}
|
|
|
8939 |
return undefined;
|
|
|
8940 |
};
|
|
|
8941 |
const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node);
|
|
|
8942 |
const isValid = (ed, parent, child) => {
|
|
|
8943 |
return ed.schema.isValidChild(parent, child);
|
|
|
8944 |
};
|
|
|
8945 |
const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
|
| 1441 |
ariadna |
8946 |
if (isNonNullable(node) && isText$b(node)) {
|
| 1 |
efrain |
8947 |
const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data;
|
|
|
8948 |
return isWhitespaceText(data);
|
|
|
8949 |
} else {
|
|
|
8950 |
return false;
|
|
|
8951 |
}
|
|
|
8952 |
};
|
|
|
8953 |
const isEmptyTextNode$1 = node => {
|
| 1441 |
ariadna |
8954 |
return isNonNullable(node) && isText$b(node) && node.length === 0;
|
| 1 |
efrain |
8955 |
};
|
|
|
8956 |
const isWrapNoneditableTarget = (editor, node) => {
|
|
|
8957 |
const baseDataSelector = '[data-mce-cef-wrappable]';
|
|
|
8958 |
const formatNoneditableSelector = getFormatNoneditableSelector(editor);
|
|
|
8959 |
const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`;
|
|
|
8960 |
return is$1(SugarElement.fromDom(node), selector);
|
|
|
8961 |
};
|
|
|
8962 |
const isWrappableNoneditable = (editor, node) => {
|
|
|
8963 |
const dom = editor.dom;
|
|
|
8964 |
return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0;
|
|
|
8965 |
};
|
|
|
8966 |
const replaceVars = (value, vars) => {
|
|
|
8967 |
if (isFunction(value)) {
|
|
|
8968 |
return value(vars);
|
|
|
8969 |
} else if (isNonNullable(vars)) {
|
|
|
8970 |
value = value.replace(/%(\w+)/g, (str, name) => {
|
|
|
8971 |
return vars[name] || str;
|
|
|
8972 |
});
|
|
|
8973 |
}
|
|
|
8974 |
return value;
|
|
|
8975 |
};
|
|
|
8976 |
const isEq$5 = (str1, str2) => {
|
|
|
8977 |
str1 = str1 || '';
|
|
|
8978 |
str2 = str2 || '';
|
|
|
8979 |
str1 = '' + (str1.nodeName || str1);
|
|
|
8980 |
str2 = '' + (str2.nodeName || str2);
|
|
|
8981 |
return str1.toLowerCase() === str2.toLowerCase();
|
|
|
8982 |
};
|
|
|
8983 |
const normalizeStyleValue = (value, name) => {
|
|
|
8984 |
if (isNullable(value)) {
|
|
|
8985 |
return null;
|
|
|
8986 |
} else {
|
|
|
8987 |
let strValue = String(value);
|
|
|
8988 |
if (name === 'color' || name === 'backgroundColor') {
|
|
|
8989 |
strValue = rgbaToHexString(strValue);
|
|
|
8990 |
}
|
|
|
8991 |
if (name === 'fontWeight' && value === 700) {
|
|
|
8992 |
strValue = 'bold';
|
|
|
8993 |
}
|
|
|
8994 |
if (name === 'fontFamily') {
|
|
|
8995 |
strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
|
|
|
8996 |
}
|
|
|
8997 |
return strValue;
|
|
|
8998 |
}
|
|
|
8999 |
};
|
|
|
9000 |
const getStyle = (dom, node, name) => {
|
|
|
9001 |
const style = dom.getStyle(node, name);
|
|
|
9002 |
return normalizeStyleValue(style, name);
|
|
|
9003 |
};
|
|
|
9004 |
const getTextDecoration = (dom, node) => {
|
|
|
9005 |
let decoration;
|
|
|
9006 |
dom.getParent(node, n => {
|
|
|
9007 |
if (isElement$6(n)) {
|
|
|
9008 |
decoration = dom.getStyle(n, 'text-decoration');
|
|
|
9009 |
return !!decoration && decoration !== 'none';
|
|
|
9010 |
} else {
|
|
|
9011 |
return false;
|
|
|
9012 |
}
|
|
|
9013 |
});
|
|
|
9014 |
return decoration;
|
|
|
9015 |
};
|
|
|
9016 |
const getParents$2 = (dom, node, selector) => {
|
|
|
9017 |
return dom.getParents(node, selector, dom.getRoot());
|
|
|
9018 |
};
|
|
|
9019 |
const isFormatPredicate = (editor, formatName, predicate) => {
|
|
|
9020 |
const formats = editor.formatter.get(formatName);
|
|
|
9021 |
return isNonNullable(formats) && exists(formats, predicate);
|
|
|
9022 |
};
|
|
|
9023 |
const isVariableFormatName = (editor, formatName) => {
|
|
|
9024 |
const hasVariableValues = format => {
|
|
|
9025 |
const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%';
|
|
|
9026 |
return exists([
|
|
|
9027 |
'styles',
|
|
|
9028 |
'attributes'
|
|
|
9029 |
], key => get$a(format, key).exists(field => {
|
|
|
9030 |
const fieldValues = isArray$1(field) ? field : values(field);
|
|
|
9031 |
return exists(fieldValues, isVariableValue);
|
|
|
9032 |
}));
|
|
|
9033 |
};
|
|
|
9034 |
return isFormatPredicate(editor, formatName, hasVariableValues);
|
|
|
9035 |
};
|
|
|
9036 |
const areSimilarFormats = (editor, formatName, otherFormatName) => {
|
|
|
9037 |
const validKeys = [
|
|
|
9038 |
'inline',
|
|
|
9039 |
'block',
|
|
|
9040 |
'selector',
|
|
|
9041 |
'attributes',
|
|
|
9042 |
'styles',
|
|
|
9043 |
'classes'
|
|
|
9044 |
];
|
|
|
9045 |
const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key));
|
|
|
9046 |
return isFormatPredicate(editor, formatName, fmt1 => {
|
|
|
9047 |
const filteredFmt1 = filterObj(fmt1);
|
|
|
9048 |
return isFormatPredicate(editor, otherFormatName, fmt2 => {
|
|
|
9049 |
const filteredFmt2 = filterObj(fmt2);
|
|
|
9050 |
return equal$1(filteredFmt1, filteredFmt2);
|
|
|
9051 |
});
|
|
|
9052 |
});
|
|
|
9053 |
};
|
|
|
9054 |
const isBlockFormat = format => hasNonNullableKey(format, 'block');
|
|
|
9055 |
const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true;
|
|
|
9056 |
const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true;
|
|
|
9057 |
const isSelectorFormat = format => hasNonNullableKey(format, 'selector');
|
|
|
9058 |
const isInlineFormat = format => hasNonNullableKey(format, 'inline');
|
|
|
9059 |
const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true);
|
|
|
9060 |
const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
|
|
|
9061 |
const getEmptyCaretContainers = node => {
|
|
|
9062 |
const nodes = [];
|
|
|
9063 |
let tempNode = node;
|
|
|
9064 |
while (tempNode) {
|
| 1441 |
ariadna |
9065 |
if (isText$b(tempNode) && tempNode.data !== ZWSP$1 || tempNode.childNodes.length > 1) {
|
| 1 |
efrain |
9066 |
return [];
|
|
|
9067 |
}
|
|
|
9068 |
if (isElement$6(tempNode)) {
|
|
|
9069 |
nodes.push(tempNode);
|
|
|
9070 |
}
|
|
|
9071 |
tempNode = tempNode.firstChild;
|
|
|
9072 |
}
|
|
|
9073 |
return nodes;
|
|
|
9074 |
};
|
|
|
9075 |
const isCaretContainerEmpty = node => {
|
|
|
9076 |
return getEmptyCaretContainers(node).length > 0;
|
|
|
9077 |
};
|
|
|
9078 |
const isEmptyCaretFormatElement = element => {
|
|
|
9079 |
return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
|
|
|
9080 |
};
|
|
|
9081 |
|
|
|
9082 |
const isBookmarkNode = isBookmarkNode$1;
|
|
|
9083 |
const getParents$1 = getParents$2;
|
|
|
9084 |
const isWhiteSpaceNode = isWhiteSpaceNode$1;
|
|
|
9085 |
const isTextBlock = isTextBlock$1;
|
|
|
9086 |
const isBogusBr = node => {
|
|
|
9087 |
return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling;
|
|
|
9088 |
};
|
|
|
9089 |
const findParentContentEditable = (dom, node) => {
|
|
|
9090 |
let parent = node;
|
|
|
9091 |
while (parent) {
|
|
|
9092 |
if (isElement$6(parent) && dom.getContentEditable(parent)) {
|
|
|
9093 |
return dom.getContentEditable(parent) === 'false' ? parent : node;
|
|
|
9094 |
}
|
|
|
9095 |
parent = parent.parentNode;
|
|
|
9096 |
}
|
|
|
9097 |
return node;
|
|
|
9098 |
};
|
|
|
9099 |
const walkText = (start, node, offset, predicate) => {
|
|
|
9100 |
const str = node.data;
|
|
|
9101 |
if (start) {
|
|
|
9102 |
for (let i = offset; i > 0; i--) {
|
|
|
9103 |
if (predicate(str.charAt(i - 1))) {
|
|
|
9104 |
return i;
|
|
|
9105 |
}
|
|
|
9106 |
}
|
|
|
9107 |
} else {
|
|
|
9108 |
for (let i = offset; i < str.length; i++) {
|
|
|
9109 |
if (predicate(str.charAt(i))) {
|
|
|
9110 |
return i;
|
|
|
9111 |
}
|
|
|
9112 |
}
|
|
|
9113 |
}
|
|
|
9114 |
return -1;
|
|
|
9115 |
};
|
|
|
9116 |
const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c));
|
|
|
9117 |
const findContent = (start, node, offset) => walkText(start, node, offset, isContent);
|
|
|
9118 |
const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => {
|
|
|
9119 |
let lastTextNode;
|
| 1441 |
ariadna |
9120 |
const closestRoot = dom.getParent(container, node => isEditingHost(node) || dom.isBlock(node));
|
|
|
9121 |
const rootNode = isNonNullable(closestRoot) ? closestRoot : body;
|
| 1 |
efrain |
9122 |
const walk = (container, offset, pred) => {
|
|
|
9123 |
const textSeeker = TextSeeker(dom);
|
|
|
9124 |
const walker = start ? textSeeker.backwards : textSeeker.forwards;
|
|
|
9125 |
return Optional.from(walker(container, offset, (text, textOffset) => {
|
|
|
9126 |
if (isBookmarkNode(text.parentNode)) {
|
|
|
9127 |
return -1;
|
|
|
9128 |
} else {
|
|
|
9129 |
lastTextNode = text;
|
|
|
9130 |
return pred(start, text, textOffset);
|
|
|
9131 |
}
|
|
|
9132 |
}, rootNode));
|
|
|
9133 |
};
|
|
|
9134 |
const spaceResult = walk(container, offset, findSpace);
|
|
|
9135 |
return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
|
|
|
9136 |
container: lastTextNode,
|
|
|
9137 |
offset: start ? 0 : lastTextNode.length
|
|
|
9138 |
}) : Optional.none());
|
|
|
9139 |
};
|
|
|
9140 |
const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => {
|
|
|
9141 |
const sibling = container[siblingName];
|
| 1441 |
ariadna |
9142 |
if (isText$b(container) && isEmpty$3(container.data) && sibling) {
|
| 1 |
efrain |
9143 |
container = sibling;
|
|
|
9144 |
}
|
|
|
9145 |
const parents = getParents$1(dom, container);
|
|
|
9146 |
for (let i = 0; i < parents.length; i++) {
|
|
|
9147 |
for (let y = 0; y < formatList.length; y++) {
|
|
|
9148 |
const curFormat = formatList[y];
|
|
|
9149 |
if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
|
|
|
9150 |
continue;
|
|
|
9151 |
}
|
|
|
9152 |
if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) {
|
|
|
9153 |
return parents[i];
|
|
|
9154 |
}
|
|
|
9155 |
}
|
|
|
9156 |
}
|
|
|
9157 |
return container;
|
|
|
9158 |
};
|
|
|
9159 |
const findBlockEndPoint = (dom, formatList, container, siblingName) => {
|
|
|
9160 |
var _a;
|
|
|
9161 |
let node = container;
|
|
|
9162 |
const root = dom.getRoot();
|
|
|
9163 |
const format = formatList[0];
|
|
|
9164 |
if (isBlockFormat(format)) {
|
|
|
9165 |
node = format.wrapper ? null : dom.getParent(container, format.block, root);
|
|
|
9166 |
}
|
|
|
9167 |
if (!node) {
|
|
|
9168 |
const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH,SUMMARY')) !== null && _a !== void 0 ? _a : root;
|
| 1441 |
ariadna |
9169 |
node = dom.getParent(isText$b(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot);
|
| 1 |
efrain |
9170 |
}
|
|
|
9171 |
if (node && isBlockFormat(format) && format.wrapper) {
|
|
|
9172 |
node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node;
|
|
|
9173 |
}
|
|
|
9174 |
if (!node) {
|
|
|
9175 |
node = container;
|
|
|
9176 |
while (node && node[siblingName] && !dom.isBlock(node[siblingName])) {
|
|
|
9177 |
node = node[siblingName];
|
|
|
9178 |
if (isEq$5(node, 'br')) {
|
|
|
9179 |
break;
|
|
|
9180 |
}
|
|
|
9181 |
}
|
|
|
9182 |
}
|
|
|
9183 |
return node || container;
|
|
|
9184 |
};
|
|
|
9185 |
const isAtBlockBoundary$1 = (dom, root, container, siblingName) => {
|
|
|
9186 |
const parent = container.parentNode;
|
|
|
9187 |
if (isNonNullable(container[siblingName])) {
|
|
|
9188 |
return false;
|
|
|
9189 |
} else if (parent === root || isNullable(parent) || dom.isBlock(parent)) {
|
|
|
9190 |
return true;
|
|
|
9191 |
} else {
|
|
|
9192 |
return isAtBlockBoundary$1(dom, root, parent, siblingName);
|
|
|
9193 |
}
|
|
|
9194 |
};
|
| 1441 |
ariadna |
9195 |
const findParentContainer = (dom, formatList, container, offset, start, expandToBlock) => {
|
| 1 |
efrain |
9196 |
let parent = container;
|
|
|
9197 |
const siblingName = start ? 'previousSibling' : 'nextSibling';
|
|
|
9198 |
const root = dom.getRoot();
|
| 1441 |
ariadna |
9199 |
if (isText$b(container) && !isWhiteSpaceNode(container)) {
|
| 1 |
efrain |
9200 |
if (start ? offset > 0 : offset < container.data.length) {
|
|
|
9201 |
return container;
|
|
|
9202 |
}
|
|
|
9203 |
}
|
|
|
9204 |
while (parent) {
|
| 1441 |
ariadna |
9205 |
if (isEditingHost(parent)) {
|
|
|
9206 |
return container;
|
|
|
9207 |
}
|
| 1 |
efrain |
9208 |
if (!formatList[0].block_expand && dom.isBlock(parent)) {
|
| 1441 |
ariadna |
9209 |
return expandToBlock ? parent : container;
|
| 1 |
efrain |
9210 |
}
|
|
|
9211 |
for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
|
| 1441 |
ariadna |
9212 |
const allowSpaces = isText$b(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName);
|
| 1 |
efrain |
9213 |
if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) {
|
|
|
9214 |
return parent;
|
|
|
9215 |
}
|
|
|
9216 |
}
|
|
|
9217 |
if (parent === root || parent.parentNode === root) {
|
|
|
9218 |
container = parent;
|
|
|
9219 |
break;
|
|
|
9220 |
}
|
|
|
9221 |
parent = parent.parentNode;
|
|
|
9222 |
}
|
|
|
9223 |
return container;
|
|
|
9224 |
};
|
|
|
9225 |
const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
|
| 1441 |
ariadna |
9226 |
const expandRng = (dom, rng, formatList, expandOptions = {}) => {
|
|
|
9227 |
const {includeTrailingSpace = false, expandToBlock = true} = expandOptions;
|
|
|
9228 |
const editableHost = dom.getParent(rng.commonAncestorContainer, node => isEditingHost(node));
|
|
|
9229 |
const root = isNonNullable(editableHost) ? editableHost : dom.getRoot();
|
| 1 |
efrain |
9230 |
let {startContainer, startOffset, endContainer, endOffset} = rng;
|
|
|
9231 |
const format = formatList[0];
|
|
|
9232 |
if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
|
|
|
9233 |
startContainer = getNode$1(startContainer, startOffset);
|
| 1441 |
ariadna |
9234 |
if (isText$b(startContainer)) {
|
| 1 |
efrain |
9235 |
startOffset = 0;
|
|
|
9236 |
}
|
|
|
9237 |
}
|
|
|
9238 |
if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
|
|
|
9239 |
endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
|
| 1441 |
ariadna |
9240 |
if (isText$b(endContainer)) {
|
| 1 |
efrain |
9241 |
endOffset = endContainer.data.length;
|
|
|
9242 |
}
|
|
|
9243 |
}
|
|
|
9244 |
startContainer = findParentContentEditable(dom, startContainer);
|
|
|
9245 |
endContainer = findParentContentEditable(dom, endContainer);
|
|
|
9246 |
if (isSelfOrParentBookmark(startContainer)) {
|
|
|
9247 |
startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
|
|
|
9248 |
if (rng.collapsed) {
|
|
|
9249 |
startContainer = startContainer.previousSibling || startContainer;
|
|
|
9250 |
} else {
|
|
|
9251 |
startContainer = startContainer.nextSibling || startContainer;
|
|
|
9252 |
}
|
| 1441 |
ariadna |
9253 |
if (isText$b(startContainer)) {
|
| 1 |
efrain |
9254 |
startOffset = rng.collapsed ? startContainer.length : 0;
|
|
|
9255 |
}
|
|
|
9256 |
}
|
|
|
9257 |
if (isSelfOrParentBookmark(endContainer)) {
|
|
|
9258 |
endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
|
|
|
9259 |
if (rng.collapsed) {
|
|
|
9260 |
endContainer = endContainer.nextSibling || endContainer;
|
|
|
9261 |
} else {
|
|
|
9262 |
endContainer = endContainer.previousSibling || endContainer;
|
|
|
9263 |
}
|
| 1441 |
ariadna |
9264 |
if (isText$b(endContainer)) {
|
| 1 |
efrain |
9265 |
endOffset = rng.collapsed ? 0 : endContainer.length;
|
|
|
9266 |
}
|
|
|
9267 |
}
|
|
|
9268 |
if (rng.collapsed) {
|
| 1441 |
ariadna |
9269 |
const startPoint = findWordEndPoint(dom, root, startContainer, startOffset, true, includeTrailingSpace);
|
| 1 |
efrain |
9270 |
startPoint.each(({container, offset}) => {
|
|
|
9271 |
startContainer = container;
|
|
|
9272 |
startOffset = offset;
|
|
|
9273 |
});
|
| 1441 |
ariadna |
9274 |
const endPoint = findWordEndPoint(dom, root, endContainer, endOffset, false, includeTrailingSpace);
|
| 1 |
efrain |
9275 |
endPoint.each(({container, offset}) => {
|
|
|
9276 |
endContainer = container;
|
|
|
9277 |
endOffset = offset;
|
|
|
9278 |
});
|
|
|
9279 |
}
|
|
|
9280 |
if (isInlineFormat(format) || format.block_expand) {
|
| 1441 |
ariadna |
9281 |
if (!isInlineFormat(format) || (!isText$b(startContainer) || startOffset === 0)) {
|
|
|
9282 |
startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true, expandToBlock);
|
| 1 |
efrain |
9283 |
}
|
| 1441 |
ariadna |
9284 |
if (!isInlineFormat(format) || (!isText$b(endContainer) || endOffset === endContainer.data.length)) {
|
|
|
9285 |
endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false, expandToBlock);
|
| 1 |
efrain |
9286 |
}
|
|
|
9287 |
}
|
|
|
9288 |
if (shouldExpandToSelector(format)) {
|
|
|
9289 |
startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling');
|
|
|
9290 |
endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling');
|
|
|
9291 |
}
|
|
|
9292 |
if (isBlockFormat(format) || isSelectorFormat(format)) {
|
|
|
9293 |
startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling');
|
|
|
9294 |
endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling');
|
|
|
9295 |
if (isBlockFormat(format)) {
|
|
|
9296 |
if (!dom.isBlock(startContainer)) {
|
| 1441 |
ariadna |
9297 |
startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true, expandToBlock);
|
|
|
9298 |
if (isText$b(startContainer)) {
|
|
|
9299 |
startOffset = 0;
|
|
|
9300 |
}
|
| 1 |
efrain |
9301 |
}
|
|
|
9302 |
if (!dom.isBlock(endContainer)) {
|
| 1441 |
ariadna |
9303 |
endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false, expandToBlock);
|
|
|
9304 |
if (isText$b(endContainer)) {
|
|
|
9305 |
endOffset = endContainer.data.length;
|
|
|
9306 |
}
|
| 1 |
efrain |
9307 |
}
|
|
|
9308 |
}
|
|
|
9309 |
}
|
|
|
9310 |
if (isElement$6(startContainer) && startContainer.parentNode) {
|
|
|
9311 |
startOffset = dom.nodeIndex(startContainer);
|
|
|
9312 |
startContainer = startContainer.parentNode;
|
|
|
9313 |
}
|
|
|
9314 |
if (isElement$6(endContainer) && endContainer.parentNode) {
|
|
|
9315 |
endOffset = dom.nodeIndex(endContainer) + 1;
|
|
|
9316 |
endContainer = endContainer.parentNode;
|
|
|
9317 |
}
|
|
|
9318 |
return {
|
|
|
9319 |
startContainer,
|
|
|
9320 |
startOffset,
|
|
|
9321 |
endContainer,
|
|
|
9322 |
endOffset
|
|
|
9323 |
};
|
|
|
9324 |
};
|
|
|
9325 |
|
|
|
9326 |
const walk$3 = (dom, rng, callback) => {
|
|
|
9327 |
var _a;
|
|
|
9328 |
const startOffset = rng.startOffset;
|
|
|
9329 |
const startContainer = getNode$1(rng.startContainer, startOffset);
|
|
|
9330 |
const endOffset = rng.endOffset;
|
|
|
9331 |
const endContainer = getNode$1(rng.endContainer, endOffset - 1);
|
|
|
9332 |
const exclude = nodes => {
|
|
|
9333 |
const firstNode = nodes[0];
|
| 1441 |
ariadna |
9334 |
if (isText$b(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
|
| 1 |
efrain |
9335 |
nodes.splice(0, 1);
|
|
|
9336 |
}
|
|
|
9337 |
const lastNode = nodes[nodes.length - 1];
|
| 1441 |
ariadna |
9338 |
if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$b(lastNode)) {
|
| 1 |
efrain |
9339 |
nodes.splice(nodes.length - 1, 1);
|
|
|
9340 |
}
|
|
|
9341 |
return nodes;
|
|
|
9342 |
};
|
|
|
9343 |
const collectSiblings = (node, name, endNode) => {
|
|
|
9344 |
const siblings = [];
|
|
|
9345 |
for (; node && node !== endNode; node = node[name]) {
|
|
|
9346 |
siblings.push(node);
|
|
|
9347 |
}
|
|
|
9348 |
return siblings;
|
|
|
9349 |
};
|
|
|
9350 |
const findEndPoint = (node, root) => dom.getParent(node, node => node.parentNode === root, root);
|
|
|
9351 |
const walkBoundary = (startNode, endNode, next) => {
|
|
|
9352 |
const siblingName = next ? 'nextSibling' : 'previousSibling';
|
|
|
9353 |
for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
|
|
|
9354 |
parent = node.parentNode;
|
|
|
9355 |
const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
|
|
|
9356 |
if (siblings.length) {
|
|
|
9357 |
if (!next) {
|
|
|
9358 |
siblings.reverse();
|
|
|
9359 |
}
|
|
|
9360 |
callback(exclude(siblings));
|
|
|
9361 |
}
|
|
|
9362 |
}
|
|
|
9363 |
};
|
|
|
9364 |
if (startContainer === endContainer) {
|
|
|
9365 |
return callback(exclude([startContainer]));
|
|
|
9366 |
}
|
|
|
9367 |
const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot();
|
|
|
9368 |
if (dom.isChildOf(startContainer, endContainer)) {
|
|
|
9369 |
return walkBoundary(startContainer, ancestor, true);
|
|
|
9370 |
}
|
|
|
9371 |
if (dom.isChildOf(endContainer, startContainer)) {
|
|
|
9372 |
return walkBoundary(endContainer, ancestor);
|
|
|
9373 |
}
|
|
|
9374 |
const startPoint = findEndPoint(startContainer, ancestor) || startContainer;
|
|
|
9375 |
const endPoint = findEndPoint(endContainer, ancestor) || endContainer;
|
|
|
9376 |
walkBoundary(startContainer, startPoint, true);
|
|
|
9377 |
const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
|
|
|
9378 |
if (siblings.length) {
|
|
|
9379 |
callback(exclude(siblings));
|
|
|
9380 |
}
|
|
|
9381 |
walkBoundary(endContainer, endPoint);
|
|
|
9382 |
};
|
|
|
9383 |
|
|
|
9384 |
const validBlocks = [
|
|
|
9385 |
'pre[class*=language-][contenteditable="false"]',
|
|
|
9386 |
'figure.image',
|
|
|
9387 |
'div[data-ephox-embed-iri]',
|
|
|
9388 |
'div.tiny-pageembed',
|
|
|
9389 |
'div.mce-toc',
|
|
|
9390 |
'div[data-mce-toc]'
|
|
|
9391 |
];
|
| 1441 |
ariadna |
9392 |
const isZeroWidth = elem => isText$c(elem) && get$3(elem) === ZWSP$1;
|
| 1 |
efrain |
9393 |
const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => {
|
|
|
9394 |
if (nodeName === 'br' || isZeroWidth(elem)) {
|
|
|
9395 |
return 'valid';
|
|
|
9396 |
} else if (isAnnotation(elem)) {
|
|
|
9397 |
return 'existing';
|
|
|
9398 |
} else if (isCaretNode(elem.dom)) {
|
|
|
9399 |
return 'caret';
|
|
|
9400 |
} else if (exists(validBlocks, selector => is$1(elem, selector))) {
|
|
|
9401 |
return 'valid-block';
|
|
|
9402 |
} else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) {
|
|
|
9403 |
return 'invalid-child';
|
|
|
9404 |
} else {
|
|
|
9405 |
return 'valid';
|
|
|
9406 |
}
|
|
|
9407 |
});
|
|
|
9408 |
|
|
|
9409 |
const applyWordGrab = (editor, rng) => {
|
|
|
9410 |
const r = expandRng(editor.dom, rng, [{ inline: 'span' }]);
|
|
|
9411 |
rng.setStart(r.startContainer, r.startOffset);
|
|
|
9412 |
rng.setEnd(r.endContainer, r.endOffset);
|
|
|
9413 |
editor.selection.setRng(rng);
|
|
|
9414 |
};
|
|
|
9415 |
const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => {
|
|
|
9416 |
const {uid = masterUId, ...otherData} = data;
|
|
|
9417 |
add$2(elem, annotation());
|
| 1441 |
ariadna |
9418 |
set$4(elem, `${ dataAnnotationId() }`, uid);
|
|
|
9419 |
set$4(elem, `${ dataAnnotation() }`, annotationName);
|
| 1 |
efrain |
9420 |
const {attributes = {}, classes = []} = decorate(uid, otherData);
|
|
|
9421 |
setAll$1(elem, attributes);
|
|
|
9422 |
add(elem, classes);
|
|
|
9423 |
if (directAnnotation) {
|
|
|
9424 |
if (classes.length > 0) {
|
| 1441 |
ariadna |
9425 |
set$4(elem, `${ dataAnnotationClasses() }`, classes.join(','));
|
| 1 |
efrain |
9426 |
}
|
|
|
9427 |
const attributeNames = keys(attributes);
|
|
|
9428 |
if (attributeNames.length > 0) {
|
| 1441 |
ariadna |
9429 |
set$4(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(','));
|
| 1 |
efrain |
9430 |
}
|
|
|
9431 |
}
|
|
|
9432 |
};
|
|
|
9433 |
const removeDirectAnnotation = elem => {
|
| 1441 |
ariadna |
9434 |
remove$6(elem, annotation());
|
|
|
9435 |
remove$9(elem, `${ dataAnnotationId() }`);
|
|
|
9436 |
remove$9(elem, `${ dataAnnotation() }`);
|
|
|
9437 |
remove$9(elem, `${ dataAnnotationActive() }`);
|
| 1 |
efrain |
9438 |
const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]);
|
|
|
9439 |
const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]);
|
| 1441 |
ariadna |
9440 |
each$e(customAttrNames, name => remove$9(elem, name));
|
|
|
9441 |
remove$3(elem, customClasses);
|
|
|
9442 |
remove$9(elem, `${ dataAnnotationClasses() }`);
|
|
|
9443 |
remove$9(elem, `${ dataAnnotationAttributes() }`);
|
| 1 |
efrain |
9444 |
};
|
|
|
9445 |
const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => {
|
|
|
9446 |
const master = SugarElement.fromTag('span', eDoc);
|
|
|
9447 |
applyAnnotation(master, uid, data, annotationName, decorate, false);
|
|
|
9448 |
return master;
|
|
|
9449 |
};
|
|
|
9450 |
const annotate = (editor, rng, uid, annotationName, decorate, data) => {
|
|
|
9451 |
const newWrappers = [];
|
|
|
9452 |
const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate);
|
|
|
9453 |
const wrapper = value$2();
|
|
|
9454 |
const finishWrapper = () => {
|
|
|
9455 |
wrapper.clear();
|
|
|
9456 |
};
|
|
|
9457 |
const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
|
|
|
9458 |
const nu = shallow$1(master);
|
|
|
9459 |
newWrappers.push(nu);
|
|
|
9460 |
wrapper.set(nu);
|
|
|
9461 |
return nu;
|
|
|
9462 |
});
|
|
|
9463 |
const processElements = elems => {
|
|
|
9464 |
each$e(elems, processElement);
|
|
|
9465 |
};
|
|
|
9466 |
const processElement = elem => {
|
|
|
9467 |
const ctx = context(editor, elem, 'span', name(elem));
|
|
|
9468 |
switch (ctx) {
|
|
|
9469 |
case 'invalid-child': {
|
|
|
9470 |
finishWrapper();
|
|
|
9471 |
const children = children$1(elem);
|
|
|
9472 |
processElements(children);
|
|
|
9473 |
finishWrapper();
|
|
|
9474 |
break;
|
|
|
9475 |
}
|
|
|
9476 |
case 'valid-block': {
|
|
|
9477 |
finishWrapper();
|
|
|
9478 |
applyAnnotation(elem, uid, data, annotationName, decorate, true);
|
|
|
9479 |
break;
|
|
|
9480 |
}
|
|
|
9481 |
case 'valid': {
|
|
|
9482 |
const w = getOrOpenWrapper();
|
|
|
9483 |
wrap$2(elem, w);
|
|
|
9484 |
break;
|
|
|
9485 |
}
|
|
|
9486 |
}
|
|
|
9487 |
};
|
|
|
9488 |
const processNodes = nodes => {
|
|
|
9489 |
const elems = map$3(nodes, SugarElement.fromDom);
|
|
|
9490 |
processElements(elems);
|
|
|
9491 |
};
|
|
|
9492 |
walk$3(editor.dom, rng, nodes => {
|
|
|
9493 |
finishWrapper();
|
|
|
9494 |
processNodes(nodes);
|
|
|
9495 |
});
|
|
|
9496 |
return newWrappers;
|
|
|
9497 |
};
|
|
|
9498 |
const annotateWithBookmark = (editor, name, settings, data) => {
|
|
|
9499 |
editor.undoManager.transact(() => {
|
|
|
9500 |
const selection = editor.selection;
|
|
|
9501 |
const initialRng = selection.getRng();
|
|
|
9502 |
const hasFakeSelection = getCellsFromEditor(editor).length > 0;
|
|
|
9503 |
const masterUid = generate$1('mce-annotation');
|
|
|
9504 |
if (initialRng.collapsed && !hasFakeSelection) {
|
|
|
9505 |
applyWordGrab(editor, initialRng);
|
|
|
9506 |
}
|
|
|
9507 |
if (selection.getRng().collapsed && !hasFakeSelection) {
|
|
|
9508 |
const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate);
|
|
|
9509 |
set$1(wrapper, nbsp);
|
|
|
9510 |
selection.getRng().insertNode(wrapper.dom);
|
|
|
9511 |
selection.select(wrapper.dom);
|
|
|
9512 |
} else {
|
|
|
9513 |
preserve(selection, false, () => {
|
|
|
9514 |
runOnRanges(editor, selectionRng => {
|
|
|
9515 |
annotate(editor, selectionRng, masterUid, name, settings.decorate, data);
|
|
|
9516 |
});
|
|
|
9517 |
});
|
|
|
9518 |
}
|
|
|
9519 |
});
|
|
|
9520 |
};
|
|
|
9521 |
|
|
|
9522 |
const Annotator = editor => {
|
| 1441 |
ariadna |
9523 |
const registry = create$b();
|
| 1 |
efrain |
9524 |
setup$x(editor, registry);
|
|
|
9525 |
const changes = setup$y(editor, registry);
|
|
|
9526 |
const isSpan = isTag('span');
|
|
|
9527 |
const removeAnnotations = elements => {
|
|
|
9528 |
each$e(elements, element => {
|
|
|
9529 |
if (isSpan(element)) {
|
|
|
9530 |
unwrap(element);
|
|
|
9531 |
} else {
|
|
|
9532 |
removeDirectAnnotation(element);
|
|
|
9533 |
}
|
|
|
9534 |
});
|
|
|
9535 |
};
|
|
|
9536 |
return {
|
|
|
9537 |
register: (name, settings) => {
|
|
|
9538 |
registry.register(name, settings);
|
|
|
9539 |
},
|
|
|
9540 |
annotate: (name, data) => {
|
|
|
9541 |
registry.lookup(name).each(settings => {
|
|
|
9542 |
annotateWithBookmark(editor, name, settings, data);
|
|
|
9543 |
});
|
|
|
9544 |
},
|
|
|
9545 |
annotationChanged: (name, callback) => {
|
|
|
9546 |
changes.addListener(name, callback);
|
|
|
9547 |
},
|
|
|
9548 |
remove: name => {
|
|
|
9549 |
identify(editor, Optional.some(name)).each(({elements}) => {
|
|
|
9550 |
const bookmark = editor.selection.getBookmark();
|
|
|
9551 |
removeAnnotations(elements);
|
|
|
9552 |
editor.selection.moveToBookmark(bookmark);
|
|
|
9553 |
});
|
|
|
9554 |
},
|
|
|
9555 |
removeAll: name => {
|
|
|
9556 |
const bookmark = editor.selection.getBookmark();
|
|
|
9557 |
each$d(findAll(editor, name), (elements, _) => {
|
|
|
9558 |
removeAnnotations(elements);
|
|
|
9559 |
});
|
|
|
9560 |
editor.selection.moveToBookmark(bookmark);
|
|
|
9561 |
},
|
|
|
9562 |
getAll: name => {
|
|
|
9563 |
const directory = findAll(editor, name);
|
|
|
9564 |
return map$2(directory, elems => map$3(elems, elem => elem.dom));
|
|
|
9565 |
}
|
|
|
9566 |
};
|
|
|
9567 |
};
|
|
|
9568 |
|
|
|
9569 |
const BookmarkManager = selection => {
|
|
|
9570 |
return {
|
| 1441 |
ariadna |
9571 |
getBookmark: curry(getBookmark$2, selection),
|
| 1 |
efrain |
9572 |
moveToBookmark: curry(moveToBookmark, selection)
|
|
|
9573 |
};
|
|
|
9574 |
};
|
|
|
9575 |
BookmarkManager.isBookmarkNode = isBookmarkNode$1;
|
|
|
9576 |
|
|
|
9577 |
const isXYWithinRange = (clientX, clientY, range) => {
|
|
|
9578 |
if (range.collapsed) {
|
|
|
9579 |
return false;
|
|
|
9580 |
} else {
|
|
|
9581 |
return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY));
|
|
|
9582 |
}
|
|
|
9583 |
};
|
|
|
9584 |
|
| 1441 |
ariadna |
9585 |
const getDocument = () => SugarElement.fromDom(document);
|
|
|
9586 |
|
|
|
9587 |
const focus$1 = (element, preventScroll = false) => element.dom.focus({ preventScroll });
|
|
|
9588 |
const hasFocus$1 = element => {
|
|
|
9589 |
const root = getRootNode(element).dom;
|
|
|
9590 |
return element.dom === root.activeElement;
|
| 1 |
efrain |
9591 |
};
|
| 1441 |
ariadna |
9592 |
const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
|
|
|
9593 |
const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
|
|
|
9594 |
|
|
|
9595 |
const create$9 = (start, soffset, finish, foffset) => ({
|
|
|
9596 |
start,
|
|
|
9597 |
soffset,
|
|
|
9598 |
finish,
|
|
|
9599 |
foffset
|
|
|
9600 |
});
|
|
|
9601 |
const SimRange = { create: create$9 };
|
|
|
9602 |
|
|
|
9603 |
const adt$3 = Adt.generate([
|
|
|
9604 |
{ before: ['element'] },
|
|
|
9605 |
{
|
|
|
9606 |
on: [
|
|
|
9607 |
'element',
|
|
|
9608 |
'offset'
|
|
|
9609 |
]
|
|
|
9610 |
},
|
|
|
9611 |
{ after: ['element'] }
|
|
|
9612 |
]);
|
|
|
9613 |
const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
|
|
|
9614 |
const getStart$2 = situ => situ.fold(identity, identity, identity);
|
|
|
9615 |
const before$1 = adt$3.before;
|
|
|
9616 |
const on = adt$3.on;
|
|
|
9617 |
const after$1 = adt$3.after;
|
|
|
9618 |
const Situ = {
|
|
|
9619 |
before: before$1,
|
|
|
9620 |
on,
|
|
|
9621 |
after: after$1,
|
|
|
9622 |
cata,
|
|
|
9623 |
getStart: getStart$2
|
| 1 |
efrain |
9624 |
};
|
| 1441 |
ariadna |
9625 |
|
|
|
9626 |
const adt$2 = Adt.generate([
|
|
|
9627 |
{ domRange: ['rng'] },
|
|
|
9628 |
{
|
|
|
9629 |
relative: [
|
|
|
9630 |
'startSitu',
|
|
|
9631 |
'finishSitu'
|
|
|
9632 |
]
|
|
|
9633 |
},
|
|
|
9634 |
{
|
|
|
9635 |
exact: [
|
|
|
9636 |
'start',
|
|
|
9637 |
'soffset',
|
|
|
9638 |
'finish',
|
|
|
9639 |
'foffset'
|
|
|
9640 |
]
|
|
|
9641 |
}
|
|
|
9642 |
]);
|
|
|
9643 |
const exactFromRange = simRange => adt$2.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
|
|
|
9644 |
const getStart$1 = selection => selection.match({
|
|
|
9645 |
domRange: rng => SugarElement.fromDom(rng.startContainer),
|
|
|
9646 |
relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
|
|
|
9647 |
exact: (start, _soffset, _finish, _foffset) => start
|
|
|
9648 |
});
|
|
|
9649 |
const domRange = adt$2.domRange;
|
|
|
9650 |
const relative = adt$2.relative;
|
|
|
9651 |
const exact = adt$2.exact;
|
|
|
9652 |
const getWin = selection => {
|
|
|
9653 |
const start = getStart$1(selection);
|
|
|
9654 |
return defaultView(start);
|
| 1 |
efrain |
9655 |
};
|
| 1441 |
ariadna |
9656 |
const range = SimRange.create;
|
|
|
9657 |
const SimSelection = {
|
|
|
9658 |
domRange,
|
|
|
9659 |
relative,
|
|
|
9660 |
exact,
|
|
|
9661 |
exactFromRange,
|
|
|
9662 |
getWin,
|
|
|
9663 |
range
|
|
|
9664 |
};
|
|
|
9665 |
|
|
|
9666 |
const clamp$1 = (offset, element) => {
|
|
|
9667 |
const max = isText$c(element) ? get$3(element).length : children$1(element).length + 1;
|
|
|
9668 |
if (offset > max) {
|
|
|
9669 |
return max;
|
|
|
9670 |
} else if (offset < 0) {
|
|
|
9671 |
return 0;
|
|
|
9672 |
}
|
|
|
9673 |
return offset;
|
|
|
9674 |
};
|
|
|
9675 |
const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
|
|
|
9676 |
const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
|
|
|
9677 |
const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
|
|
|
9678 |
const shouldStore = editor => editor.inline || Env.browser.isFirefox();
|
|
|
9679 |
const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
|
|
|
9680 |
const readRange = win => {
|
|
|
9681 |
const selection = win.getSelection();
|
|
|
9682 |
const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
|
|
|
9683 |
return rng.map(nativeRangeToSelectionRange);
|
|
|
9684 |
};
|
|
|
9685 |
const getBookmark$1 = root => {
|
|
|
9686 |
const win = defaultView(root);
|
|
|
9687 |
return readRange(win.dom).filter(isRngInRoot(root));
|
|
|
9688 |
};
|
|
|
9689 |
const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
|
|
|
9690 |
const bookmarkToNativeRng = bookmark => {
|
|
|
9691 |
const rng = document.createRange();
|
|
|
9692 |
try {
|
|
|
9693 |
rng.setStart(bookmark.start.dom, bookmark.soffset);
|
|
|
9694 |
rng.setEnd(bookmark.finish.dom, bookmark.foffset);
|
|
|
9695 |
return Optional.some(rng);
|
|
|
9696 |
} catch (_a) {
|
|
|
9697 |
return Optional.none();
|
|
|
9698 |
}
|
|
|
9699 |
};
|
|
|
9700 |
const store = editor => {
|
|
|
9701 |
const newBookmark = shouldStore(editor) ? getBookmark$1(SugarElement.fromDom(editor.getBody())) : Optional.none();
|
|
|
9702 |
editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
|
|
|
9703 |
};
|
|
|
9704 |
const getRng = editor => {
|
|
|
9705 |
const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
|
|
|
9706 |
return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
|
|
|
9707 |
};
|
|
|
9708 |
const restore = editor => {
|
|
|
9709 |
getRng(editor).each(rng => editor.selection.setRng(rng));
|
|
|
9710 |
};
|
|
|
9711 |
|
|
|
9712 |
const isEditorUIElement$1 = elm => {
|
|
|
9713 |
const className = elm.className.toString();
|
|
|
9714 |
return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
|
|
|
9715 |
};
|
|
|
9716 |
const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
|
|
|
9717 |
|
|
|
9718 |
const wrappedSetTimeout = (callback, time) => {
|
|
|
9719 |
if (!isNumber(time)) {
|
|
|
9720 |
time = 0;
|
|
|
9721 |
}
|
|
|
9722 |
return setTimeout(callback, time);
|
|
|
9723 |
};
|
|
|
9724 |
const wrappedSetInterval = (callback, time) => {
|
|
|
9725 |
if (!isNumber(time)) {
|
|
|
9726 |
time = 0;
|
|
|
9727 |
}
|
|
|
9728 |
return setInterval(callback, time);
|
|
|
9729 |
};
|
|
|
9730 |
const Delay = {
|
|
|
9731 |
setEditorTimeout: (editor, callback, time) => {
|
|
|
9732 |
return wrappedSetTimeout(() => {
|
|
|
9733 |
if (!editor.removed) {
|
|
|
9734 |
callback();
|
|
|
9735 |
}
|
|
|
9736 |
}, time);
|
|
|
9737 |
},
|
|
|
9738 |
setEditorInterval: (editor, callback, time) => {
|
|
|
9739 |
const timer = wrappedSetInterval(() => {
|
|
|
9740 |
if (!editor.removed) {
|
|
|
9741 |
callback();
|
|
|
9742 |
} else {
|
|
|
9743 |
clearInterval(timer);
|
|
|
9744 |
}
|
|
|
9745 |
}, time);
|
|
|
9746 |
return timer;
|
|
|
9747 |
}
|
|
|
9748 |
};
|
|
|
9749 |
|
|
|
9750 |
const isManualNodeChange = e => {
|
|
|
9751 |
return e.type === 'nodechange' && e.selectionChange;
|
|
|
9752 |
};
|
|
|
9753 |
const registerPageMouseUp = (editor, throttledStore) => {
|
|
|
9754 |
const mouseUpPage = () => {
|
|
|
9755 |
throttledStore.throttle();
|
|
|
9756 |
};
|
|
|
9757 |
DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage);
|
|
|
9758 |
editor.on('remove', () => {
|
|
|
9759 |
DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage);
|
| 1 |
efrain |
9760 |
});
|
|
|
9761 |
};
|
| 1441 |
ariadna |
9762 |
const registerMouseUp = (editor, throttledStore) => {
|
|
|
9763 |
editor.on('mouseup touchend', _e => {
|
|
|
9764 |
throttledStore.throttle();
|
| 1 |
efrain |
9765 |
});
|
|
|
9766 |
};
|
| 1441 |
ariadna |
9767 |
const registerEditorEvents = (editor, throttledStore) => {
|
|
|
9768 |
registerMouseUp(editor, throttledStore);
|
|
|
9769 |
editor.on('keyup NodeChange AfterSetSelectionRange', e => {
|
|
|
9770 |
if (!isManualNodeChange(e)) {
|
|
|
9771 |
store(editor);
|
|
|
9772 |
}
|
|
|
9773 |
});
|
| 1 |
efrain |
9774 |
};
|
| 1441 |
ariadna |
9775 |
const register$6 = editor => {
|
|
|
9776 |
const throttledStore = first$1(() => {
|
|
|
9777 |
store(editor);
|
|
|
9778 |
}, 0);
|
|
|
9779 |
editor.on('init', () => {
|
|
|
9780 |
if (editor.inline) {
|
|
|
9781 |
registerPageMouseUp(editor, throttledStore);
|
|
|
9782 |
}
|
|
|
9783 |
registerEditorEvents(editor, throttledStore);
|
|
|
9784 |
});
|
|
|
9785 |
editor.on('remove', () => {
|
|
|
9786 |
throttledStore.cancel();
|
|
|
9787 |
});
|
| 1 |
efrain |
9788 |
};
|
| 1441 |
ariadna |
9789 |
|
|
|
9790 |
let documentFocusInHandler;
|
|
|
9791 |
const DOM$9 = DOMUtils.DOM;
|
|
|
9792 |
const isEditorUIElement = elm => {
|
|
|
9793 |
return isElement$6(elm) && FocusManager.isEditorUIElement(elm);
|
| 1 |
efrain |
9794 |
};
|
| 1441 |
ariadna |
9795 |
const isEditorContentAreaElement = elm => {
|
|
|
9796 |
const classList = elm.classList;
|
|
|
9797 |
if (classList !== undefined) {
|
|
|
9798 |
return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
|
|
|
9799 |
} else {
|
|
|
9800 |
return false;
|
|
|
9801 |
}
|
| 1 |
efrain |
9802 |
};
|
| 1441 |
ariadna |
9803 |
const isUIElement = (editor, elm) => {
|
|
|
9804 |
const customSelector = getCustomUiSelector(editor);
|
|
|
9805 |
const parent = DOM$9.getParent(elm, elm => {
|
|
|
9806 |
return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
|
| 1 |
efrain |
9807 |
});
|
| 1441 |
ariadna |
9808 |
return parent !== null;
|
| 1 |
efrain |
9809 |
};
|
| 1441 |
ariadna |
9810 |
const getActiveElement = editor => {
|
|
|
9811 |
try {
|
|
|
9812 |
const root = getRootNode(SugarElement.fromDom(editor.getElement()));
|
|
|
9813 |
return active$1(root).fold(() => document.body, x => x.dom);
|
|
|
9814 |
} catch (_a) {
|
|
|
9815 |
return document.body;
|
|
|
9816 |
}
|
|
|
9817 |
};
|
|
|
9818 |
const registerEvents$1 = (editorManager, e) => {
|
|
|
9819 |
const editor = e.editor;
|
|
|
9820 |
register$6(editor);
|
|
|
9821 |
const toggleContentAreaOnFocus = (editor, fn) => {
|
|
|
9822 |
if (shouldHighlightOnFocus(editor) && editor.inline !== true) {
|
|
|
9823 |
const contentArea = SugarElement.fromDom(editor.getContainer());
|
|
|
9824 |
fn(contentArea, 'tox-edit-focus');
|
|
|
9825 |
}
|
|
|
9826 |
};
|
|
|
9827 |
editor.on('focusin', () => {
|
|
|
9828 |
const focusedEditor = editorManager.focusedEditor;
|
|
|
9829 |
if (isEditorContentAreaElement(getActiveElement(editor))) {
|
|
|
9830 |
toggleContentAreaOnFocus(editor, add$2);
|
|
|
9831 |
}
|
|
|
9832 |
if (focusedEditor !== editor) {
|
|
|
9833 |
if (focusedEditor) {
|
|
|
9834 |
focusedEditor.dispatch('blur', { focusedEditor: editor });
|
|
|
9835 |
}
|
|
|
9836 |
editorManager.setActive(editor);
|
|
|
9837 |
editorManager.focusedEditor = editor;
|
|
|
9838 |
editor.dispatch('focus', { blurredEditor: focusedEditor });
|
|
|
9839 |
editor.focus(true);
|
|
|
9840 |
}
|
| 1 |
efrain |
9841 |
});
|
| 1441 |
ariadna |
9842 |
editor.on('focusout', () => {
|
|
|
9843 |
Delay.setEditorTimeout(editor, () => {
|
|
|
9844 |
const focusedEditor = editorManager.focusedEditor;
|
|
|
9845 |
if (!isEditorContentAreaElement(getActiveElement(editor)) || focusedEditor !== editor) {
|
|
|
9846 |
toggleContentAreaOnFocus(editor, remove$6);
|
|
|
9847 |
}
|
|
|
9848 |
if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
|
|
|
9849 |
editor.dispatch('blur', { focusedEditor: null });
|
|
|
9850 |
editorManager.focusedEditor = null;
|
|
|
9851 |
}
|
|
|
9852 |
});
|
|
|
9853 |
});
|
|
|
9854 |
if (!documentFocusInHandler) {
|
|
|
9855 |
documentFocusInHandler = e => {
|
|
|
9856 |
const activeEditor = editorManager.activeEditor;
|
|
|
9857 |
if (activeEditor) {
|
|
|
9858 |
getOriginalEventTarget(e).each(target => {
|
|
|
9859 |
const elem = target;
|
|
|
9860 |
if (elem.ownerDocument === document) {
|
|
|
9861 |
if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) {
|
|
|
9862 |
activeEditor.dispatch('blur', { focusedEditor: null });
|
|
|
9863 |
editorManager.focusedEditor = null;
|
|
|
9864 |
}
|
|
|
9865 |
}
|
|
|
9866 |
});
|
|
|
9867 |
}
|
|
|
9868 |
};
|
|
|
9869 |
DOM$9.bind(document, 'focusin', documentFocusInHandler);
|
|
|
9870 |
}
|
| 1 |
efrain |
9871 |
};
|
| 1441 |
ariadna |
9872 |
const unregisterDocumentEvents = (editorManager, e) => {
|
|
|
9873 |
if (editorManager.focusedEditor === e.editor) {
|
|
|
9874 |
editorManager.focusedEditor = null;
|
|
|
9875 |
}
|
|
|
9876 |
if (!editorManager.activeEditor && documentFocusInHandler) {
|
|
|
9877 |
DOM$9.unbind(document, 'focusin', documentFocusInHandler);
|
|
|
9878 |
documentFocusInHandler = null;
|
|
|
9879 |
}
|
| 1 |
efrain |
9880 |
};
|
| 1441 |
ariadna |
9881 |
const setup$w = editorManager => {
|
|
|
9882 |
editorManager.on('AddEditor', curry(registerEvents$1, editorManager));
|
|
|
9883 |
editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
|
| 1 |
efrain |
9884 |
};
|
| 1441 |
ariadna |
9885 |
|
|
|
9886 |
const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
|
|
|
9887 |
const hasContentEditableFalseParent$1 = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'false') !== null;
|
|
|
9888 |
const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
|
|
|
9889 |
const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
|
|
|
9890 |
if (isTableSection(node)) {
|
|
|
9891 |
return Optional.some(node);
|
|
|
9892 |
} else if (!contains(root, node)) {
|
|
|
9893 |
return Optional.some(root);
|
|
|
9894 |
} else {
|
|
|
9895 |
return Optional.none();
|
|
|
9896 |
}
|
|
|
9897 |
});
|
|
|
9898 |
const normalizeSelection = (editor, rng) => {
|
|
|
9899 |
getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => {
|
|
|
9900 |
return firstPositionIn(elm.dom);
|
|
|
9901 |
}).fold(() => {
|
|
|
9902 |
editor.selection.normalize();
|
|
|
9903 |
}, caretPos => editor.selection.setRng(caretPos.toRange()));
|
| 1 |
efrain |
9904 |
};
|
| 1441 |
ariadna |
9905 |
const focusBody = body => {
|
|
|
9906 |
if (body.setActive) {
|
|
|
9907 |
try {
|
|
|
9908 |
body.setActive();
|
|
|
9909 |
} catch (_a) {
|
|
|
9910 |
body.focus();
|
|
|
9911 |
}
|
|
|
9912 |
} else {
|
|
|
9913 |
body.focus();
|
|
|
9914 |
}
|
|
|
9915 |
};
|
|
|
9916 |
const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome();
|
|
|
9917 |
const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
|
|
|
9918 |
const hasInlineFocus = editor => {
|
|
|
9919 |
const rawBody = editor.getBody();
|
|
|
9920 |
return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
|
|
|
9921 |
};
|
|
|
9922 |
const hasUiFocus = editor => {
|
|
|
9923 |
const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
|
|
|
9924 |
return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
|
|
|
9925 |
};
|
|
|
9926 |
const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
|
|
|
9927 |
const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor);
|
|
|
9928 |
const focusEditor = editor => {
|
|
|
9929 |
const selection = editor.selection;
|
|
|
9930 |
const body = editor.getBody();
|
|
|
9931 |
let rng = selection.getRng();
|
|
|
9932 |
editor.quirks.refreshContentEditable();
|
|
|
9933 |
const restoreBookmark = editor => {
|
|
|
9934 |
getRng(editor).each(bookmarkRng => {
|
|
|
9935 |
editor.selection.setRng(bookmarkRng);
|
|
|
9936 |
rng = bookmarkRng;
|
|
|
9937 |
});
|
|
|
9938 |
};
|
|
|
9939 |
if (!hasFocus(editor) && editor.hasEditableRoot()) {
|
|
|
9940 |
restoreBookmark(editor);
|
|
|
9941 |
}
|
|
|
9942 |
const contentEditableHost = getContentEditableHost(editor, selection.getNode());
|
|
|
9943 |
if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
|
|
|
9944 |
if (!hasContentEditableFalseParent$1(editor, contentEditableHost)) {
|
|
|
9945 |
focusBody(body);
|
|
|
9946 |
}
|
|
|
9947 |
focusBody(contentEditableHost);
|
|
|
9948 |
if (!editor.hasEditableRoot()) {
|
|
|
9949 |
restoreBookmark(editor);
|
|
|
9950 |
}
|
|
|
9951 |
normalizeSelection(editor, rng);
|
|
|
9952 |
activateEditor(editor);
|
|
|
9953 |
return;
|
|
|
9954 |
}
|
|
|
9955 |
if (!editor.inline) {
|
|
|
9956 |
if (!Env.browser.isOpera()) {
|
|
|
9957 |
focusBody(body);
|
|
|
9958 |
}
|
|
|
9959 |
editor.getWin().focus();
|
|
|
9960 |
}
|
|
|
9961 |
if (Env.browser.isFirefox() || editor.inline) {
|
|
|
9962 |
focusBody(body);
|
|
|
9963 |
normalizeSelection(editor, rng);
|
|
|
9964 |
}
|
|
|
9965 |
activateEditor(editor);
|
|
|
9966 |
};
|
|
|
9967 |
const activateEditor = editor => editor.editorManager.setActive(editor);
|
|
|
9968 |
const focus = (editor, skipFocus) => {
|
|
|
9969 |
if (editor.removed) {
|
|
|
9970 |
return;
|
|
|
9971 |
}
|
|
|
9972 |
if (skipFocus) {
|
|
|
9973 |
activateEditor(editor);
|
|
|
9974 |
} else {
|
|
|
9975 |
focusEditor(editor);
|
|
|
9976 |
}
|
|
|
9977 |
};
|
| 1 |
efrain |
9978 |
|
|
|
9979 |
const VK = {
|
|
|
9980 |
BACKSPACE: 8,
|
|
|
9981 |
DELETE: 46,
|
|
|
9982 |
DOWN: 40,
|
|
|
9983 |
ENTER: 13,
|
|
|
9984 |
ESC: 27,
|
|
|
9985 |
LEFT: 37,
|
|
|
9986 |
RIGHT: 39,
|
|
|
9987 |
SPACEBAR: 32,
|
|
|
9988 |
TAB: 9,
|
|
|
9989 |
UP: 38,
|
|
|
9990 |
PAGE_UP: 33,
|
|
|
9991 |
PAGE_DOWN: 34,
|
|
|
9992 |
END: 35,
|
|
|
9993 |
HOME: 36,
|
|
|
9994 |
modifierPressed: e => {
|
|
|
9995 |
return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
|
|
|
9996 |
},
|
|
|
9997 |
metaKeyPressed: e => {
|
|
|
9998 |
return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
|
|
|
9999 |
}
|
|
|
10000 |
};
|
|
|
10001 |
|
|
|
10002 |
const elementSelectionAttr = 'data-mce-selected';
|
|
|
10003 |
const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object,details';
|
|
|
10004 |
const abs = Math.abs;
|
|
|
10005 |
const round$1 = Math.round;
|
|
|
10006 |
const resizeHandles = {
|
|
|
10007 |
nw: [
|
|
|
10008 |
0,
|
|
|
10009 |
0,
|
|
|
10010 |
-1,
|
|
|
10011 |
-1
|
|
|
10012 |
],
|
|
|
10013 |
ne: [
|
|
|
10014 |
1,
|
|
|
10015 |
0,
|
|
|
10016 |
1,
|
|
|
10017 |
-1
|
|
|
10018 |
],
|
|
|
10019 |
se: [
|
|
|
10020 |
1,
|
|
|
10021 |
1,
|
|
|
10022 |
1,
|
|
|
10023 |
1
|
|
|
10024 |
],
|
|
|
10025 |
sw: [
|
|
|
10026 |
0,
|
|
|
10027 |
1,
|
|
|
10028 |
-1,
|
|
|
10029 |
1
|
|
|
10030 |
]
|
|
|
10031 |
};
|
|
|
10032 |
const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0;
|
|
|
10033 |
const ControlSelection = (selection, editor) => {
|
|
|
10034 |
const dom = editor.dom;
|
|
|
10035 |
const editableDoc = editor.getDoc();
|
|
|
10036 |
const rootDocument = document;
|
|
|
10037 |
const rootElement = editor.getBody();
|
|
|
10038 |
let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
|
| 1441 |
ariadna |
10039 |
let startX, startY, startW, startH, ratio, resizeStarted;
|
| 1 |
efrain |
10040 |
let width;
|
|
|
10041 |
let height;
|
|
|
10042 |
let startScrollWidth;
|
|
|
10043 |
let startScrollHeight;
|
|
|
10044 |
const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image'));
|
|
|
10045 |
const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object');
|
|
|
10046 |
const isEventOnImageOutsideRange = (evt, range) => {
|
|
|
10047 |
if (isTouchEvent(evt)) {
|
|
|
10048 |
const touch = evt.touches[0];
|
|
|
10049 |
return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range);
|
|
|
10050 |
} else {
|
|
|
10051 |
return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range);
|
|
|
10052 |
}
|
|
|
10053 |
};
|
|
|
10054 |
const contextMenuSelectImage = evt => {
|
|
|
10055 |
const target = evt.target;
|
|
|
10056 |
if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
|
|
|
10057 |
editor.selection.select(target);
|
|
|
10058 |
}
|
|
|
10059 |
};
|
|
|
10060 |
const getResizeTargets = elm => {
|
|
|
10061 |
if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
|
|
|
10062 |
return [
|
|
|
10063 |
elm,
|
|
|
10064 |
elm.firstElementChild
|
|
|
10065 |
];
|
|
|
10066 |
} else if (dom.is(elm, 'figure.image')) {
|
|
|
10067 |
return [elm.querySelector('img')];
|
|
|
10068 |
} else {
|
|
|
10069 |
return [elm];
|
|
|
10070 |
}
|
|
|
10071 |
};
|
|
|
10072 |
const isResizable = elm => {
|
|
|
10073 |
const selector = getObjectResizing(editor);
|
| 1441 |
ariadna |
10074 |
if (!selector || editor.mode.isReadOnly()) {
|
| 1 |
efrain |
10075 |
return false;
|
|
|
10076 |
}
|
|
|
10077 |
if (elm.getAttribute('data-mce-resize') === 'false') {
|
|
|
10078 |
return false;
|
|
|
10079 |
}
|
|
|
10080 |
if (elm === editor.getBody()) {
|
|
|
10081 |
return false;
|
|
|
10082 |
}
|
|
|
10083 |
if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
|
|
|
10084 |
return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
|
|
|
10085 |
} else {
|
|
|
10086 |
return is$1(SugarElement.fromDom(elm), selector);
|
|
|
10087 |
}
|
|
|
10088 |
};
|
| 1441 |
ariadna |
10089 |
const createGhostElement = (dom, elm) => {
|
| 1 |
efrain |
10090 |
if (isMedia(elm)) {
|
|
|
10091 |
return dom.create('img', { src: Env.transparentSrc });
|
| 1441 |
ariadna |
10092 |
} else if (isTable$2(elm)) {
|
|
|
10093 |
const isNorth = startsWith(selectedHandle.name, 'n');
|
|
|
10094 |
const rowSelect = isNorth ? head : last$2;
|
|
|
10095 |
const tableElm = elm.cloneNode(true);
|
|
|
10096 |
rowSelect(dom.select('tr', tableElm)).each(tr => {
|
|
|
10097 |
const cells = dom.select('td,th', tr);
|
|
|
10098 |
dom.setStyle(tr, 'height', null);
|
|
|
10099 |
each$e(cells, cell => dom.setStyle(cell, 'height', null));
|
|
|
10100 |
});
|
|
|
10101 |
return tableElm;
|
| 1 |
efrain |
10102 |
} else {
|
|
|
10103 |
return elm.cloneNode(true);
|
|
|
10104 |
}
|
|
|
10105 |
};
|
|
|
10106 |
const setSizeProp = (element, name, value) => {
|
|
|
10107 |
if (isNonNullable(value)) {
|
|
|
10108 |
const targets = getResizeTargets(element);
|
|
|
10109 |
each$e(targets, target => {
|
|
|
10110 |
if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
|
|
|
10111 |
dom.setStyle(target, name, value);
|
|
|
10112 |
} else {
|
|
|
10113 |
dom.setAttrib(target, name, '' + value);
|
|
|
10114 |
}
|
|
|
10115 |
});
|
|
|
10116 |
}
|
|
|
10117 |
};
|
|
|
10118 |
const setGhostElmSize = (ghostElm, width, height) => {
|
|
|
10119 |
setSizeProp(ghostElm, 'width', width);
|
|
|
10120 |
setSizeProp(ghostElm, 'height', height);
|
|
|
10121 |
};
|
|
|
10122 |
const resizeGhostElement = e => {
|
|
|
10123 |
let deltaX, deltaY, proportional;
|
|
|
10124 |
let resizeHelperX, resizeHelperY;
|
|
|
10125 |
deltaX = e.screenX - startX;
|
|
|
10126 |
deltaY = e.screenY - startY;
|
|
|
10127 |
width = deltaX * selectedHandle[2] + startW;
|
|
|
10128 |
height = deltaY * selectedHandle[3] + startH;
|
|
|
10129 |
width = width < 5 ? 5 : width;
|
|
|
10130 |
height = height < 5 ? 5 : height;
|
|
|
10131 |
if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) {
|
|
|
10132 |
proportional = !VK.modifierPressed(e);
|
|
|
10133 |
} else {
|
|
|
10134 |
proportional = VK.modifierPressed(e);
|
|
|
10135 |
}
|
|
|
10136 |
if (proportional) {
|
|
|
10137 |
if (abs(deltaX) > abs(deltaY)) {
|
|
|
10138 |
height = round$1(width * ratio);
|
|
|
10139 |
width = round$1(height / ratio);
|
|
|
10140 |
} else {
|
|
|
10141 |
width = round$1(height / ratio);
|
|
|
10142 |
height = round$1(width * ratio);
|
|
|
10143 |
}
|
|
|
10144 |
}
|
|
|
10145 |
setGhostElmSize(selectedElmGhost, width, height);
|
|
|
10146 |
resizeHelperX = selectedHandle.startPos.x + deltaX;
|
|
|
10147 |
resizeHelperY = selectedHandle.startPos.y + deltaY;
|
|
|
10148 |
resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
|
|
|
10149 |
resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
|
|
|
10150 |
dom.setStyles(resizeHelper, {
|
|
|
10151 |
left: resizeHelperX,
|
|
|
10152 |
top: resizeHelperY,
|
|
|
10153 |
display: 'block'
|
|
|
10154 |
});
|
|
|
10155 |
resizeHelper.innerHTML = width + ' × ' + height;
|
|
|
10156 |
deltaX = rootElement.scrollWidth - startScrollWidth;
|
|
|
10157 |
deltaY = rootElement.scrollHeight - startScrollHeight;
|
|
|
10158 |
if (deltaX + deltaY !== 0) {
|
|
|
10159 |
dom.setStyles(resizeHelper, {
|
|
|
10160 |
left: resizeHelperX - deltaX,
|
|
|
10161 |
top: resizeHelperY - deltaY
|
|
|
10162 |
});
|
|
|
10163 |
}
|
|
|
10164 |
if (!resizeStarted) {
|
|
|
10165 |
fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name);
|
|
|
10166 |
resizeStarted = true;
|
|
|
10167 |
}
|
|
|
10168 |
};
|
|
|
10169 |
const endGhostResize = () => {
|
|
|
10170 |
const wasResizeStarted = resizeStarted;
|
|
|
10171 |
resizeStarted = false;
|
|
|
10172 |
if (wasResizeStarted) {
|
|
|
10173 |
setSizeProp(selectedElm, 'width', width);
|
|
|
10174 |
setSizeProp(selectedElm, 'height', height);
|
|
|
10175 |
}
|
|
|
10176 |
dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
|
|
|
10177 |
dom.unbind(editableDoc, 'mouseup', endGhostResize);
|
|
|
10178 |
if (rootDocument !== editableDoc) {
|
|
|
10179 |
dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
|
|
|
10180 |
dom.unbind(rootDocument, 'mouseup', endGhostResize);
|
|
|
10181 |
}
|
|
|
10182 |
dom.remove(selectedElmGhost);
|
|
|
10183 |
dom.remove(resizeHelper);
|
|
|
10184 |
dom.remove(resizeBackdrop);
|
|
|
10185 |
showResizeRect(selectedElm);
|
|
|
10186 |
if (wasResizeStarted) {
|
|
|
10187 |
fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name);
|
|
|
10188 |
dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
|
|
|
10189 |
}
|
|
|
10190 |
editor.nodeChanged();
|
|
|
10191 |
};
|
|
|
10192 |
const showResizeRect = targetElm => {
|
|
|
10193 |
unbindResizeHandleEvents();
|
|
|
10194 |
const position = dom.getPos(targetElm, rootElement);
|
|
|
10195 |
const selectedElmX = position.x;
|
|
|
10196 |
const selectedElmY = position.y;
|
|
|
10197 |
const rect = targetElm.getBoundingClientRect();
|
|
|
10198 |
const targetWidth = rect.width || rect.right - rect.left;
|
|
|
10199 |
const targetHeight = rect.height || rect.bottom - rect.top;
|
|
|
10200 |
if (selectedElm !== targetElm) {
|
|
|
10201 |
hideResizeRect();
|
|
|
10202 |
selectedElm = targetElm;
|
|
|
10203 |
width = height = 0;
|
|
|
10204 |
}
|
|
|
10205 |
const e = editor.dispatch('ObjectSelected', { target: targetElm });
|
|
|
10206 |
if (isResizable(targetElm) && !e.isDefaultPrevented()) {
|
|
|
10207 |
each$d(resizeHandles, (handle, name) => {
|
|
|
10208 |
const startDrag = e => {
|
|
|
10209 |
const target = getResizeTargets(selectedElm)[0];
|
|
|
10210 |
startX = e.screenX;
|
|
|
10211 |
startY = e.screenY;
|
|
|
10212 |
startW = target.clientWidth;
|
|
|
10213 |
startH = target.clientHeight;
|
|
|
10214 |
ratio = startH / startW;
|
|
|
10215 |
selectedHandle = handle;
|
|
|
10216 |
selectedHandle.name = name;
|
|
|
10217 |
selectedHandle.startPos = {
|
|
|
10218 |
x: targetWidth * handle[0] + selectedElmX,
|
|
|
10219 |
y: targetHeight * handle[1] + selectedElmY
|
|
|
10220 |
};
|
|
|
10221 |
startScrollWidth = rootElement.scrollWidth;
|
|
|
10222 |
startScrollHeight = rootElement.scrollHeight;
|
|
|
10223 |
resizeBackdrop = dom.add(rootElement, 'div', {
|
|
|
10224 |
'class': 'mce-resize-backdrop',
|
|
|
10225 |
'data-mce-bogus': 'all'
|
|
|
10226 |
});
|
|
|
10227 |
dom.setStyles(resizeBackdrop, {
|
|
|
10228 |
position: 'fixed',
|
|
|
10229 |
left: '0',
|
|
|
10230 |
top: '0',
|
|
|
10231 |
width: '100%',
|
|
|
10232 |
height: '100%'
|
|
|
10233 |
});
|
| 1441 |
ariadna |
10234 |
selectedElmGhost = createGhostElement(dom, selectedElm);
|
| 1 |
efrain |
10235 |
dom.addClass(selectedElmGhost, 'mce-clonedresizable');
|
|
|
10236 |
dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
|
|
|
10237 |
selectedElmGhost.contentEditable = 'false';
|
|
|
10238 |
dom.setStyles(selectedElmGhost, {
|
|
|
10239 |
left: selectedElmX,
|
|
|
10240 |
top: selectedElmY,
|
|
|
10241 |
margin: 0
|
|
|
10242 |
});
|
|
|
10243 |
setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
|
|
|
10244 |
selectedElmGhost.removeAttribute(elementSelectionAttr);
|
|
|
10245 |
rootElement.appendChild(selectedElmGhost);
|
|
|
10246 |
dom.bind(editableDoc, 'mousemove', resizeGhostElement);
|
|
|
10247 |
dom.bind(editableDoc, 'mouseup', endGhostResize);
|
|
|
10248 |
if (rootDocument !== editableDoc) {
|
|
|
10249 |
dom.bind(rootDocument, 'mousemove', resizeGhostElement);
|
|
|
10250 |
dom.bind(rootDocument, 'mouseup', endGhostResize);
|
|
|
10251 |
}
|
|
|
10252 |
resizeHelper = dom.add(rootElement, 'div', {
|
|
|
10253 |
'class': 'mce-resize-helper',
|
|
|
10254 |
'data-mce-bogus': 'all'
|
|
|
10255 |
}, startW + ' × ' + startH);
|
|
|
10256 |
};
|
|
|
10257 |
let handleElm = dom.get('mceResizeHandle' + name);
|
|
|
10258 |
if (handleElm) {
|
|
|
10259 |
dom.remove(handleElm);
|
|
|
10260 |
}
|
|
|
10261 |
handleElm = dom.add(rootElement, 'div', {
|
|
|
10262 |
'id': 'mceResizeHandle' + name,
|
|
|
10263 |
'data-mce-bogus': 'all',
|
|
|
10264 |
'class': 'mce-resizehandle',
|
|
|
10265 |
'unselectable': true,
|
|
|
10266 |
'style': 'cursor:' + name + '-resize; margin:0; padding:0'
|
|
|
10267 |
});
|
|
|
10268 |
dom.bind(handleElm, 'mousedown', e => {
|
|
|
10269 |
e.stopImmediatePropagation();
|
|
|
10270 |
e.preventDefault();
|
|
|
10271 |
startDrag(e);
|
|
|
10272 |
});
|
|
|
10273 |
handle.elm = handleElm;
|
|
|
10274 |
dom.setStyles(handleElm, {
|
|
|
10275 |
left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
|
|
|
10276 |
top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
|
|
|
10277 |
});
|
|
|
10278 |
});
|
|
|
10279 |
} else {
|
|
|
10280 |
hideResizeRect(false);
|
|
|
10281 |
}
|
|
|
10282 |
};
|
|
|
10283 |
const throttledShowResizeRect = first$1(showResizeRect, 0);
|
|
|
10284 |
const hideResizeRect = (removeSelected = true) => {
|
|
|
10285 |
throttledShowResizeRect.cancel();
|
|
|
10286 |
unbindResizeHandleEvents();
|
|
|
10287 |
if (selectedElm && removeSelected) {
|
|
|
10288 |
selectedElm.removeAttribute(elementSelectionAttr);
|
|
|
10289 |
}
|
|
|
10290 |
each$d(resizeHandles, (value, name) => {
|
|
|
10291 |
const handleElm = dom.get('mceResizeHandle' + name);
|
|
|
10292 |
if (handleElm) {
|
|
|
10293 |
dom.unbind(handleElm);
|
|
|
10294 |
dom.remove(handleElm);
|
|
|
10295 |
}
|
|
|
10296 |
});
|
|
|
10297 |
};
|
|
|
10298 |
const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent);
|
|
|
10299 |
const updateResizeRect = e => {
|
|
|
10300 |
if (resizeStarted || editor.removed || editor.composing) {
|
|
|
10301 |
return;
|
|
|
10302 |
}
|
|
|
10303 |
const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
|
|
|
10304 |
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();
|
|
|
10305 |
const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1';
|
|
|
10306 |
each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => {
|
|
|
10307 |
img.removeAttribute(elementSelectionAttr);
|
|
|
10308 |
});
|
| 1441 |
ariadna |
10309 |
if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement) && hasEditorOrUiFocus(editor)) {
|
| 1 |
efrain |
10310 |
disableGeckoResize();
|
|
|
10311 |
const startElm = selection.getStart(true);
|
|
|
10312 |
if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
|
|
|
10313 |
dom.setAttrib(controlElm, elementSelectionAttr, selectedValue);
|
|
|
10314 |
throttledShowResizeRect.throttle(controlElm);
|
|
|
10315 |
return;
|
|
|
10316 |
}
|
|
|
10317 |
}
|
|
|
10318 |
hideResizeRect();
|
|
|
10319 |
};
|
|
|
10320 |
const unbindResizeHandleEvents = () => {
|
|
|
10321 |
each$d(resizeHandles, handle => {
|
|
|
10322 |
if (handle.elm) {
|
|
|
10323 |
dom.unbind(handle.elm);
|
|
|
10324 |
delete handle.elm;
|
|
|
10325 |
}
|
|
|
10326 |
});
|
|
|
10327 |
};
|
|
|
10328 |
const disableGeckoResize = () => {
|
|
|
10329 |
try {
|
|
|
10330 |
editor.getDoc().execCommand('enableObjectResizing', false, 'false');
|
| 1441 |
ariadna |
10331 |
} catch (_a) {
|
| 1 |
efrain |
10332 |
}
|
|
|
10333 |
};
|
|
|
10334 |
editor.on('init', () => {
|
|
|
10335 |
disableGeckoResize();
|
|
|
10336 |
editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect);
|
|
|
10337 |
editor.on('keyup compositionend', e => {
|
|
|
10338 |
if (selectedElm && selectedElm.nodeName === 'TABLE') {
|
|
|
10339 |
updateResizeRect(e);
|
|
|
10340 |
}
|
|
|
10341 |
});
|
|
|
10342 |
editor.on('hide blur', hideResizeRect);
|
|
|
10343 |
editor.on('contextmenu longpress', contextMenuSelectImage, true);
|
|
|
10344 |
});
|
|
|
10345 |
editor.on('remove', unbindResizeHandleEvents);
|
|
|
10346 |
const destroy = () => {
|
|
|
10347 |
throttledShowResizeRect.cancel();
|
|
|
10348 |
selectedElm = selectedElmGhost = resizeBackdrop = null;
|
|
|
10349 |
};
|
|
|
10350 |
return {
|
|
|
10351 |
isResizable,
|
|
|
10352 |
showResizeRect,
|
|
|
10353 |
hideResizeRect,
|
|
|
10354 |
updateResizeRect,
|
|
|
10355 |
destroy
|
|
|
10356 |
};
|
|
|
10357 |
};
|
|
|
10358 |
|
|
|
10359 |
const setStart = (rng, situ) => {
|
|
|
10360 |
situ.fold(e => {
|
|
|
10361 |
rng.setStartBefore(e.dom);
|
|
|
10362 |
}, (e, o) => {
|
|
|
10363 |
rng.setStart(e.dom, o);
|
|
|
10364 |
}, e => {
|
|
|
10365 |
rng.setStartAfter(e.dom);
|
|
|
10366 |
});
|
|
|
10367 |
};
|
|
|
10368 |
const setFinish = (rng, situ) => {
|
|
|
10369 |
situ.fold(e => {
|
|
|
10370 |
rng.setEndBefore(e.dom);
|
|
|
10371 |
}, (e, o) => {
|
|
|
10372 |
rng.setEnd(e.dom, o);
|
|
|
10373 |
}, e => {
|
|
|
10374 |
rng.setEndAfter(e.dom);
|
|
|
10375 |
});
|
|
|
10376 |
};
|
|
|
10377 |
const relativeToNative = (win, startSitu, finishSitu) => {
|
|
|
10378 |
const range = win.document.createRange();
|
|
|
10379 |
setStart(range, startSitu);
|
|
|
10380 |
setFinish(range, finishSitu);
|
|
|
10381 |
return range;
|
|
|
10382 |
};
|
|
|
10383 |
const exactToNative = (win, start, soffset, finish, foffset) => {
|
|
|
10384 |
const rng = win.document.createRange();
|
|
|
10385 |
rng.setStart(start.dom, soffset);
|
|
|
10386 |
rng.setEnd(finish.dom, foffset);
|
|
|
10387 |
return rng;
|
|
|
10388 |
};
|
|
|
10389 |
|
| 1441 |
ariadna |
10390 |
const adt$1 = Adt.generate([
|
| 1 |
efrain |
10391 |
{
|
|
|
10392 |
ltr: [
|
|
|
10393 |
'start',
|
|
|
10394 |
'soffset',
|
|
|
10395 |
'finish',
|
|
|
10396 |
'foffset'
|
|
|
10397 |
]
|
|
|
10398 |
},
|
|
|
10399 |
{
|
|
|
10400 |
rtl: [
|
|
|
10401 |
'start',
|
|
|
10402 |
'soffset',
|
|
|
10403 |
'finish',
|
|
|
10404 |
'foffset'
|
|
|
10405 |
]
|
|
|
10406 |
}
|
|
|
10407 |
]);
|
|
|
10408 |
const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
|
|
|
10409 |
const getRanges = (win, selection) => selection.match({
|
|
|
10410 |
domRange: rng => {
|
|
|
10411 |
return {
|
|
|
10412 |
ltr: constant(rng),
|
|
|
10413 |
rtl: Optional.none
|
|
|
10414 |
};
|
|
|
10415 |
},
|
|
|
10416 |
relative: (startSitu, finishSitu) => {
|
|
|
10417 |
return {
|
|
|
10418 |
ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
|
|
|
10419 |
rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
|
|
|
10420 |
};
|
|
|
10421 |
},
|
|
|
10422 |
exact: (start, soffset, finish, foffset) => {
|
|
|
10423 |
return {
|
|
|
10424 |
ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
|
|
|
10425 |
rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
|
|
|
10426 |
};
|
|
|
10427 |
}
|
|
|
10428 |
});
|
|
|
10429 |
const doDiagnose = (win, ranges) => {
|
|
|
10430 |
const rng = ranges.ltr();
|
|
|
10431 |
if (rng.collapsed) {
|
|
|
10432 |
const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
|
| 1441 |
ariadna |
10433 |
return reversed.map(rev => adt$1.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$1.ltr, rng));
|
| 1 |
efrain |
10434 |
} else {
|
| 1441 |
ariadna |
10435 |
return fromRange(win, adt$1.ltr, rng);
|
| 1 |
efrain |
10436 |
}
|
|
|
10437 |
};
|
|
|
10438 |
const diagnose = (win, selection) => {
|
|
|
10439 |
const ranges = getRanges(win, selection);
|
|
|
10440 |
return doDiagnose(win, ranges);
|
|
|
10441 |
};
|
| 1441 |
ariadna |
10442 |
adt$1.ltr;
|
|
|
10443 |
adt$1.rtl;
|
| 1 |
efrain |
10444 |
|
|
|
10445 |
const caretPositionFromPoint = (doc, x, y) => {
|
| 1441 |
ariadna |
10446 |
var _a;
|
|
|
10447 |
return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)).bind(pos => {
|
| 1 |
efrain |
10448 |
if (pos.offsetNode === null) {
|
|
|
10449 |
return Optional.none();
|
|
|
10450 |
}
|
| 1441 |
ariadna |
10451 |
const r = doc.createRange();
|
| 1 |
efrain |
10452 |
r.setStart(pos.offsetNode, pos.offset);
|
|
|
10453 |
r.collapse();
|
|
|
10454 |
return Optional.some(r);
|
|
|
10455 |
});
|
|
|
10456 |
};
|
|
|
10457 |
const caretRangeFromPoint = (doc, x, y) => {
|
| 1441 |
ariadna |
10458 |
var _a;
|
|
|
10459 |
return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y));
|
| 1 |
efrain |
10460 |
};
|
| 1441 |
ariadna |
10461 |
const availableSearch = (doc, x, y) => {
|
|
|
10462 |
if (doc.caretPositionFromPoint) {
|
|
|
10463 |
return caretPositionFromPoint(doc, x, y);
|
|
|
10464 |
} else if (doc.caretRangeFromPoint) {
|
|
|
10465 |
return caretRangeFromPoint(doc, x, y);
|
| 1 |
efrain |
10466 |
} else {
|
| 1441 |
ariadna |
10467 |
return Optional.none();
|
| 1 |
efrain |
10468 |
}
|
| 1441 |
ariadna |
10469 |
};
|
| 1 |
efrain |
10470 |
const fromPoint$1 = (win, x, y) => {
|
| 1441 |
ariadna |
10471 |
const doc = win.document;
|
| 1 |
efrain |
10472 |
return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
|
|
|
10473 |
};
|
|
|
10474 |
|
|
|
10475 |
const beforeSpecial = (element, offset) => {
|
|
|
10476 |
const name$1 = name(element);
|
|
|
10477 |
if ('input' === name$1) {
|
|
|
10478 |
return Situ.after(element);
|
|
|
10479 |
} else if (!contains$2([
|
|
|
10480 |
'br',
|
|
|
10481 |
'img'
|
|
|
10482 |
], name$1)) {
|
|
|
10483 |
return Situ.on(element, offset);
|
|
|
10484 |
} else {
|
|
|
10485 |
return offset === 0 ? Situ.before(element) : Situ.after(element);
|
|
|
10486 |
}
|
|
|
10487 |
};
|
|
|
10488 |
const preprocessRelative = (startSitu, finishSitu) => {
|
|
|
10489 |
const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
|
|
|
10490 |
const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
|
|
|
10491 |
return SimSelection.relative(start, finish);
|
|
|
10492 |
};
|
|
|
10493 |
const preprocessExact = (start, soffset, finish, foffset) => {
|
|
|
10494 |
const startSitu = beforeSpecial(start, soffset);
|
|
|
10495 |
const finishSitu = beforeSpecial(finish, foffset);
|
|
|
10496 |
return SimSelection.relative(startSitu, finishSitu);
|
|
|
10497 |
};
|
|
|
10498 |
const preprocess = selection => selection.match({
|
|
|
10499 |
domRange: rng => {
|
|
|
10500 |
const start = SugarElement.fromDom(rng.startContainer);
|
|
|
10501 |
const finish = SugarElement.fromDom(rng.endContainer);
|
|
|
10502 |
return preprocessExact(start, rng.startOffset, finish, rng.endOffset);
|
|
|
10503 |
},
|
|
|
10504 |
relative: preprocessRelative,
|
|
|
10505 |
exact: preprocessExact
|
|
|
10506 |
});
|
|
|
10507 |
|
|
|
10508 |
const fromElements = (elements, scope) => {
|
|
|
10509 |
const doc = scope || document;
|
|
|
10510 |
const fragment = doc.createDocumentFragment();
|
|
|
10511 |
each$e(elements, element => {
|
|
|
10512 |
fragment.appendChild(element.dom);
|
|
|
10513 |
});
|
|
|
10514 |
return SugarElement.fromDom(fragment);
|
|
|
10515 |
};
|
|
|
10516 |
|
|
|
10517 |
const toNative = selection => {
|
|
|
10518 |
const win = SimSelection.getWin(selection).dom;
|
|
|
10519 |
const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset);
|
|
|
10520 |
const filtered = preprocess(selection);
|
|
|
10521 |
return diagnose(win, filtered).match({
|
|
|
10522 |
ltr: getDomRange,
|
|
|
10523 |
rtl: getDomRange
|
|
|
10524 |
});
|
|
|
10525 |
};
|
|
|
10526 |
const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
|
|
|
10527 |
|
|
|
10528 |
const fromPoint = (clientX, clientY, doc) => {
|
|
|
10529 |
const win = defaultView(SugarElement.fromDom(doc));
|
|
|
10530 |
return getAtPoint(win.dom, clientX, clientY).map(simRange => {
|
|
|
10531 |
const rng = doc.createRange();
|
|
|
10532 |
rng.setStart(simRange.start.dom, simRange.soffset);
|
|
|
10533 |
rng.setEnd(simRange.finish.dom, simRange.foffset);
|
|
|
10534 |
return rng;
|
|
|
10535 |
}).getOrUndefined();
|
|
|
10536 |
};
|
|
|
10537 |
|
|
|
10538 |
const isEq$4 = (rng1, rng2) => {
|
|
|
10539 |
return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
|
|
|
10540 |
};
|
|
|
10541 |
|
|
|
10542 |
const findParent = (node, rootNode, predicate) => {
|
|
|
10543 |
let currentNode = node;
|
|
|
10544 |
while (currentNode && currentNode !== rootNode) {
|
|
|
10545 |
if (predicate(currentNode)) {
|
|
|
10546 |
return currentNode;
|
|
|
10547 |
}
|
|
|
10548 |
currentNode = currentNode.parentNode;
|
|
|
10549 |
}
|
|
|
10550 |
return null;
|
|
|
10551 |
};
|
|
|
10552 |
const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
|
|
|
10553 |
const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name);
|
|
|
10554 |
const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode);
|
|
|
10555 |
const hasBrBeforeAfter = (dom, node, left) => {
|
|
|
10556 |
const parentNode = node.parentNode;
|
|
|
10557 |
if (parentNode) {
|
|
|
10558 |
const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot());
|
|
|
10559 |
let currentNode;
|
|
|
10560 |
while (currentNode = walker[left ? 'prev' : 'next']()) {
|
|
|
10561 |
if (isBr$6(currentNode)) {
|
|
|
10562 |
return true;
|
|
|
10563 |
}
|
|
|
10564 |
}
|
|
|
10565 |
}
|
|
|
10566 |
return false;
|
|
|
10567 |
};
|
|
|
10568 |
const isPrevNode = (node, name) => {
|
|
|
10569 |
var _a;
|
|
|
10570 |
return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
|
|
|
10571 |
};
|
|
|
10572 |
const hasContentEditableFalseParent = (root, node) => {
|
|
|
10573 |
let currentNode = node;
|
|
|
10574 |
while (currentNode && currentNode !== root) {
|
|
|
10575 |
if (isContentEditableFalse$b(currentNode)) {
|
|
|
10576 |
return true;
|
|
|
10577 |
}
|
|
|
10578 |
currentNode = currentNode.parentNode;
|
|
|
10579 |
}
|
|
|
10580 |
return false;
|
|
|
10581 |
};
|
|
|
10582 |
const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => {
|
|
|
10583 |
const body = dom.getRoot();
|
|
|
10584 |
const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
|
|
10585 |
const parentNode = startNode.parentNode;
|
|
|
10586 |
let lastInlineElement;
|
|
|
10587 |
let node;
|
|
|
10588 |
if (!parentNode) {
|
|
|
10589 |
return Optional.none();
|
|
|
10590 |
}
|
|
|
10591 |
const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body;
|
|
|
10592 |
if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
|
|
|
10593 |
return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode)));
|
|
|
10594 |
}
|
|
|
10595 |
const walker = new DomTreeWalker(startNode, parentBlockContainer);
|
|
|
10596 |
while (node = walker[left ? 'prev' : 'next']()) {
|
|
|
10597 |
if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
|
|
|
10598 |
return Optional.none();
|
|
|
10599 |
}
|
| 1441 |
ariadna |
10600 |
if (isText$b(node) && node.data.length > 0) {
|
| 1 |
efrain |
10601 |
if (!hasParentWithName(node, body, 'A')) {
|
|
|
10602 |
return Optional.some(CaretPosition(node, left ? node.data.length : 0));
|
|
|
10603 |
}
|
|
|
10604 |
return Optional.none();
|
|
|
10605 |
}
|
|
|
10606 |
if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
|
|
10607 |
return Optional.none();
|
|
|
10608 |
}
|
|
|
10609 |
lastInlineElement = node;
|
|
|
10610 |
}
|
|
|
10611 |
if (isComment(lastInlineElement)) {
|
|
|
10612 |
return Optional.none();
|
|
|
10613 |
}
|
|
|
10614 |
if (collapsed && lastInlineElement) {
|
|
|
10615 |
return Optional.some(CaretPosition(lastInlineElement, 0));
|
|
|
10616 |
}
|
|
|
10617 |
return Optional.none();
|
|
|
10618 |
};
|
|
|
10619 |
const normalizeEndPoint = (dom, collapsed, start, rng) => {
|
|
|
10620 |
const body = dom.getRoot();
|
|
|
10621 |
let node;
|
|
|
10622 |
let normalized = false;
|
|
|
10623 |
let container = start ? rng.startContainer : rng.endContainer;
|
|
|
10624 |
let offset = start ? rng.startOffset : rng.endOffset;
|
|
|
10625 |
const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
|
|
|
10626 |
const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
|
|
10627 |
let directionLeft = start;
|
|
|
10628 |
if (isCaretContainer$2(container)) {
|
|
|
10629 |
return Optional.none();
|
|
|
10630 |
}
|
|
|
10631 |
if (isElement$6(container) && offset > container.childNodes.length - 1) {
|
|
|
10632 |
directionLeft = false;
|
|
|
10633 |
}
|
|
|
10634 |
if (isDocument$1(container)) {
|
|
|
10635 |
container = body;
|
|
|
10636 |
offset = 0;
|
|
|
10637 |
}
|
|
|
10638 |
if (container === body) {
|
|
|
10639 |
if (directionLeft) {
|
|
|
10640 |
node = container.childNodes[offset > 0 ? offset - 1 : 0];
|
|
|
10641 |
if (node) {
|
|
|
10642 |
if (isCaretContainer$2(node)) {
|
|
|
10643 |
return Optional.none();
|
|
|
10644 |
}
|
|
|
10645 |
if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) {
|
|
|
10646 |
return Optional.none();
|
|
|
10647 |
}
|
|
|
10648 |
}
|
|
|
10649 |
}
|
|
|
10650 |
if (container.hasChildNodes()) {
|
|
|
10651 |
offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
|
|
|
10652 |
container = container.childNodes[offset];
|
| 1441 |
ariadna |
10653 |
offset = isText$b(container) && isAfterNode ? container.data.length : 0;
|
| 1 |
efrain |
10654 |
if (!collapsed && container === body.lastChild && isTable$2(container)) {
|
|
|
10655 |
return Optional.none();
|
|
|
10656 |
}
|
|
|
10657 |
if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
|
|
|
10658 |
return Optional.none();
|
|
|
10659 |
}
|
|
|
10660 |
if (isDetails(container)) {
|
|
|
10661 |
return Optional.none();
|
|
|
10662 |
}
|
|
|
10663 |
if (container.hasChildNodes() && !isTable$2(container)) {
|
|
|
10664 |
node = container;
|
|
|
10665 |
const walker = new DomTreeWalker(container, body);
|
|
|
10666 |
do {
|
|
|
10667 |
if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) {
|
|
|
10668 |
normalized = false;
|
|
|
10669 |
break;
|
|
|
10670 |
}
|
| 1441 |
ariadna |
10671 |
if (isText$b(node) && node.data.length > 0) {
|
| 1 |
efrain |
10672 |
offset = directionLeft ? 0 : node.data.length;
|
|
|
10673 |
container = node;
|
|
|
10674 |
normalized = true;
|
|
|
10675 |
break;
|
|
|
10676 |
}
|
|
|
10677 |
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) {
|
|
|
10678 |
offset = dom.nodeIndex(node);
|
|
|
10679 |
container = node.parentNode;
|
|
|
10680 |
if (!directionLeft) {
|
|
|
10681 |
offset++;
|
|
|
10682 |
}
|
|
|
10683 |
normalized = true;
|
|
|
10684 |
break;
|
|
|
10685 |
}
|
|
|
10686 |
} while (node = directionLeft ? walker.next() : walker.prev());
|
|
|
10687 |
}
|
|
|
10688 |
}
|
|
|
10689 |
}
|
|
|
10690 |
if (collapsed) {
|
| 1441 |
ariadna |
10691 |
if (isText$b(container) && offset === 0) {
|
| 1 |
efrain |
10692 |
findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => {
|
|
|
10693 |
container = pos.container();
|
|
|
10694 |
offset = pos.offset();
|
|
|
10695 |
normalized = true;
|
|
|
10696 |
});
|
|
|
10697 |
}
|
|
|
10698 |
if (isElement$6(container)) {
|
|
|
10699 |
node = container.childNodes[offset];
|
|
|
10700 |
if (!node) {
|
|
|
10701 |
node = container.childNodes[offset - 1];
|
|
|
10702 |
}
|
|
|
10703 |
if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
|
|
|
10704 |
findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => {
|
|
|
10705 |
container = pos.container();
|
|
|
10706 |
offset = pos.offset();
|
|
|
10707 |
normalized = true;
|
|
|
10708 |
});
|
|
|
10709 |
}
|
|
|
10710 |
}
|
|
|
10711 |
}
|
| 1441 |
ariadna |
10712 |
if (directionLeft && !collapsed && isText$b(container) && offset === container.data.length) {
|
| 1 |
efrain |
10713 |
findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => {
|
|
|
10714 |
container = pos.container();
|
|
|
10715 |
offset = pos.offset();
|
|
|
10716 |
normalized = true;
|
|
|
10717 |
});
|
|
|
10718 |
}
|
|
|
10719 |
return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none();
|
|
|
10720 |
};
|
|
|
10721 |
const normalize$2 = (dom, rng) => {
|
|
|
10722 |
const collapsed = rng.collapsed, normRng = rng.cloneRange();
|
|
|
10723 |
const startPos = CaretPosition.fromRangeStart(rng);
|
|
|
10724 |
normalizeEndPoint(dom, collapsed, true, normRng).each(pos => {
|
|
|
10725 |
if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
|
|
|
10726 |
normRng.setStart(pos.container(), pos.offset());
|
|
|
10727 |
}
|
|
|
10728 |
});
|
|
|
10729 |
if (!collapsed) {
|
|
|
10730 |
normalizeEndPoint(dom, collapsed, false, normRng).each(pos => {
|
|
|
10731 |
normRng.setEnd(pos.container(), pos.offset());
|
|
|
10732 |
});
|
|
|
10733 |
}
|
|
|
10734 |
if (collapsed) {
|
|
|
10735 |
normRng.collapse(true);
|
|
|
10736 |
}
|
|
|
10737 |
return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
|
|
|
10738 |
};
|
|
|
10739 |
|
|
|
10740 |
const splitText = (node, offset) => {
|
|
|
10741 |
return node.splitText(offset);
|
|
|
10742 |
};
|
|
|
10743 |
const split = rng => {
|
|
|
10744 |
let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
|
| 1441 |
ariadna |
10745 |
if (startContainer === endContainer && isText$b(startContainer)) {
|
| 1 |
efrain |
10746 |
if (startOffset > 0 && startOffset < startContainer.data.length) {
|
|
|
10747 |
endContainer = splitText(startContainer, startOffset);
|
|
|
10748 |
startContainer = endContainer.previousSibling;
|
|
|
10749 |
if (endOffset > startOffset) {
|
|
|
10750 |
endOffset = endOffset - startOffset;
|
|
|
10751 |
const newContainer = splitText(endContainer, endOffset).previousSibling;
|
|
|
10752 |
startContainer = endContainer = newContainer;
|
|
|
10753 |
endOffset = newContainer.data.length;
|
|
|
10754 |
startOffset = 0;
|
|
|
10755 |
} else {
|
|
|
10756 |
endOffset = 0;
|
|
|
10757 |
}
|
|
|
10758 |
}
|
|
|
10759 |
} else {
|
| 1441 |
ariadna |
10760 |
if (isText$b(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) {
|
| 1 |
efrain |
10761 |
startContainer = splitText(startContainer, startOffset);
|
|
|
10762 |
startOffset = 0;
|
|
|
10763 |
}
|
| 1441 |
ariadna |
10764 |
if (isText$b(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) {
|
| 1 |
efrain |
10765 |
const newContainer = splitText(endContainer, endOffset).previousSibling;
|
|
|
10766 |
endContainer = newContainer;
|
|
|
10767 |
endOffset = newContainer.data.length;
|
|
|
10768 |
}
|
|
|
10769 |
}
|
|
|
10770 |
return {
|
|
|
10771 |
startContainer,
|
|
|
10772 |
startOffset,
|
|
|
10773 |
endContainer,
|
|
|
10774 |
endOffset
|
|
|
10775 |
};
|
|
|
10776 |
};
|
|
|
10777 |
|
|
|
10778 |
const RangeUtils = dom => {
|
|
|
10779 |
const walk = (rng, callback) => {
|
|
|
10780 |
return walk$3(dom, rng, callback);
|
|
|
10781 |
};
|
|
|
10782 |
const split$1 = split;
|
|
|
10783 |
const normalize = rng => {
|
|
|
10784 |
return normalize$2(dom, rng).fold(never, normalizedRng => {
|
|
|
10785 |
rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
|
|
|
10786 |
rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
|
|
|
10787 |
return true;
|
|
|
10788 |
});
|
|
|
10789 |
};
|
|
|
10790 |
const expand = (rng, options = { type: 'word' }) => {
|
|
|
10791 |
if (options.type === 'word') {
|
| 1441 |
ariadna |
10792 |
const rangeLike = expandRng(dom, rng, [{ inline: 'span' }], {
|
|
|
10793 |
includeTrailingSpace: false,
|
|
|
10794 |
expandToBlock: false
|
|
|
10795 |
});
|
| 1 |
efrain |
10796 |
const newRange = dom.createRng();
|
|
|
10797 |
newRange.setStart(rangeLike.startContainer, rangeLike.startOffset);
|
|
|
10798 |
newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset);
|
|
|
10799 |
return newRange;
|
|
|
10800 |
}
|
|
|
10801 |
return rng;
|
|
|
10802 |
};
|
|
|
10803 |
return {
|
|
|
10804 |
walk,
|
|
|
10805 |
split: split$1,
|
|
|
10806 |
expand,
|
|
|
10807 |
normalize
|
|
|
10808 |
};
|
|
|
10809 |
};
|
|
|
10810 |
RangeUtils.compareRanges = isEq$4;
|
|
|
10811 |
RangeUtils.getCaretRangeFromPoint = fromPoint;
|
|
|
10812 |
RangeUtils.getSelectedNode = getSelectedNode;
|
|
|
10813 |
RangeUtils.getNode = getNode$1;
|
|
|
10814 |
|
|
|
10815 |
const Dimension = (name, getOffset) => {
|
|
|
10816 |
const set = (element, h) => {
|
|
|
10817 |
if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
|
|
|
10818 |
throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
|
|
|
10819 |
}
|
|
|
10820 |
const dom = element.dom;
|
|
|
10821 |
if (isSupported(dom)) {
|
|
|
10822 |
dom.style[name] = h + 'px';
|
|
|
10823 |
}
|
|
|
10824 |
};
|
|
|
10825 |
const get = element => {
|
|
|
10826 |
const r = getOffset(element);
|
|
|
10827 |
if (r <= 0 || r === null) {
|
|
|
10828 |
const css = get$7(element, name);
|
|
|
10829 |
return parseFloat(css) || 0;
|
|
|
10830 |
}
|
|
|
10831 |
return r;
|
|
|
10832 |
};
|
|
|
10833 |
const getOuter = get;
|
|
|
10834 |
const aggregate = (element, properties) => foldl(properties, (acc, property) => {
|
|
|
10835 |
const val = get$7(element, property);
|
|
|
10836 |
const value = val === undefined ? 0 : parseInt(val, 10);
|
|
|
10837 |
return isNaN(value) ? acc : acc + value;
|
|
|
10838 |
}, 0);
|
|
|
10839 |
const max = (element, value, properties) => {
|
|
|
10840 |
const cumulativeInclusions = aggregate(element, properties);
|
|
|
10841 |
const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
|
|
|
10842 |
return absoluteMax;
|
|
|
10843 |
};
|
|
|
10844 |
return {
|
|
|
10845 |
set,
|
|
|
10846 |
get,
|
|
|
10847 |
getOuter,
|
|
|
10848 |
aggregate,
|
|
|
10849 |
max
|
|
|
10850 |
};
|
|
|
10851 |
};
|
|
|
10852 |
|
|
|
10853 |
const api = Dimension('height', element => {
|
|
|
10854 |
const dom = element.dom;
|
|
|
10855 |
return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
|
|
|
10856 |
});
|
|
|
10857 |
const get$2 = element => api.get(element);
|
|
|
10858 |
|
|
|
10859 |
const walkUp = (navigation, doc) => {
|
|
|
10860 |
const frame = navigation.view(doc);
|
|
|
10861 |
return frame.fold(constant([]), f => {
|
|
|
10862 |
const parent = navigation.owner(f);
|
|
|
10863 |
const rest = walkUp(navigation, parent);
|
|
|
10864 |
return [f].concat(rest);
|
|
|
10865 |
});
|
|
|
10866 |
};
|
|
|
10867 |
const pathTo = (element, navigation) => {
|
|
|
10868 |
const d = navigation.owner(element);
|
|
|
10869 |
return walkUp(navigation, d);
|
|
|
10870 |
};
|
|
|
10871 |
|
|
|
10872 |
const view = doc => {
|
|
|
10873 |
var _a;
|
|
|
10874 |
const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
|
|
|
10875 |
return element.map(SugarElement.fromDom);
|
|
|
10876 |
};
|
|
|
10877 |
const owner = element => documentOrOwner(element);
|
|
|
10878 |
|
|
|
10879 |
var Navigation = /*#__PURE__*/Object.freeze({
|
|
|
10880 |
__proto__: null,
|
|
|
10881 |
view: view,
|
|
|
10882 |
owner: owner
|
|
|
10883 |
});
|
|
|
10884 |
|
|
|
10885 |
const find = element => {
|
|
|
10886 |
const doc = getDocument();
|
|
|
10887 |
const scroll = get$5(doc);
|
|
|
10888 |
const frames = pathTo(element, Navigation);
|
|
|
10889 |
const offset = viewport(element);
|
|
|
10890 |
const r = foldr(frames, (b, a) => {
|
|
|
10891 |
const loc = viewport(a);
|
|
|
10892 |
return {
|
|
|
10893 |
left: b.left + loc.left,
|
|
|
10894 |
top: b.top + loc.top
|
|
|
10895 |
};
|
|
|
10896 |
}, {
|
|
|
10897 |
left: 0,
|
|
|
10898 |
top: 0
|
|
|
10899 |
});
|
|
|
10900 |
return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
|
|
|
10901 |
};
|
|
|
10902 |
|
|
|
10903 |
const excludeFromDescend = element => name(element) === 'textarea';
|
|
|
10904 |
const fireScrollIntoViewEvent = (editor, data) => {
|
|
|
10905 |
const scrollEvent = editor.dispatch('ScrollIntoView', data);
|
|
|
10906 |
return scrollEvent.isDefaultPrevented();
|
|
|
10907 |
};
|
|
|
10908 |
const fireAfterScrollIntoViewEvent = (editor, data) => {
|
|
|
10909 |
editor.dispatch('AfterScrollIntoView', data);
|
|
|
10910 |
};
|
|
|
10911 |
const descend = (element, offset) => {
|
|
|
10912 |
const children = children$1(element);
|
|
|
10913 |
if (children.length === 0 || excludeFromDescend(element)) {
|
|
|
10914 |
return {
|
|
|
10915 |
element,
|
|
|
10916 |
offset
|
|
|
10917 |
};
|
|
|
10918 |
} else if (offset < children.length && !excludeFromDescend(children[offset])) {
|
|
|
10919 |
return {
|
|
|
10920 |
element: children[offset],
|
|
|
10921 |
offset: 0
|
|
|
10922 |
};
|
|
|
10923 |
} else {
|
|
|
10924 |
const last = children[children.length - 1];
|
|
|
10925 |
if (excludeFromDescend(last)) {
|
|
|
10926 |
return {
|
|
|
10927 |
element,
|
|
|
10928 |
offset
|
|
|
10929 |
};
|
|
|
10930 |
} else {
|
|
|
10931 |
if (name(last) === 'img') {
|
|
|
10932 |
return {
|
|
|
10933 |
element: last,
|
|
|
10934 |
offset: 1
|
|
|
10935 |
};
|
| 1441 |
ariadna |
10936 |
} else if (isText$c(last)) {
|
| 1 |
efrain |
10937 |
return {
|
|
|
10938 |
element: last,
|
|
|
10939 |
offset: get$3(last).length
|
|
|
10940 |
};
|
|
|
10941 |
} else {
|
|
|
10942 |
return {
|
|
|
10943 |
element: last,
|
|
|
10944 |
offset: children$1(last).length
|
|
|
10945 |
};
|
|
|
10946 |
}
|
|
|
10947 |
}
|
|
|
10948 |
}
|
|
|
10949 |
};
|
|
|
10950 |
const markerInfo = (element, cleanupFun) => {
|
|
|
10951 |
const pos = absolute(element);
|
|
|
10952 |
const height = get$2(element);
|
|
|
10953 |
return {
|
|
|
10954 |
element,
|
|
|
10955 |
bottom: pos.top + height,
|
|
|
10956 |
height,
|
|
|
10957 |
pos,
|
|
|
10958 |
cleanup: cleanupFun
|
|
|
10959 |
};
|
|
|
10960 |
};
|
|
|
10961 |
const createMarker$1 = (element, offset) => {
|
|
|
10962 |
const startPoint = descend(element, offset);
|
|
|
10963 |
const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + '</span>');
|
|
|
10964 |
before$3(startPoint.element, span);
|
| 1441 |
ariadna |
10965 |
return markerInfo(span, () => remove$4(span));
|
| 1 |
efrain |
10966 |
};
|
|
|
10967 |
const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop);
|
|
|
10968 |
const withMarker = (editor, f, rng, alignToTop) => {
|
|
|
10969 |
preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
|
|
|
10970 |
};
|
|
|
10971 |
const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
|
|
|
10972 |
const data = {
|
|
|
10973 |
elm: marker.element.dom,
|
|
|
10974 |
alignToTop
|
|
|
10975 |
};
|
|
|
10976 |
if (fireScrollIntoViewEvent(editor, data)) {
|
|
|
10977 |
return;
|
|
|
10978 |
}
|
|
|
10979 |
const scrollTop = get$5(doc).top;
|
|
|
10980 |
f(editor, doc, scrollTop, marker, alignToTop);
|
|
|
10981 |
fireAfterScrollIntoViewEvent(editor, data);
|
|
|
10982 |
};
|
|
|
10983 |
const applyWithMarker = (editor, f, rng, alignToTop) => {
|
|
|
10984 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
10985 |
const doc = SugarElement.fromDom(editor.getDoc());
|
|
|
10986 |
reflow(body);
|
|
|
10987 |
const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
|
|
|
10988 |
withScrollEvents(editor, doc, f, marker, alignToTop);
|
|
|
10989 |
marker.cleanup();
|
|
|
10990 |
};
|
|
|
10991 |
const withElement = (editor, element, f, alignToTop) => {
|
|
|
10992 |
const doc = SugarElement.fromDom(editor.getDoc());
|
|
|
10993 |
withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
|
|
|
10994 |
};
|
|
|
10995 |
const preserveWith = (editor, f, rng) => {
|
|
|
10996 |
const startElement = rng.startContainer;
|
|
|
10997 |
const startOffset = rng.startOffset;
|
|
|
10998 |
const endElement = rng.endContainer;
|
|
|
10999 |
const endOffset = rng.endOffset;
|
|
|
11000 |
f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
|
|
|
11001 |
const newRng = editor.dom.createRng();
|
|
|
11002 |
newRng.setStart(startElement, startOffset);
|
|
|
11003 |
newRng.setEnd(endElement, endOffset);
|
|
|
11004 |
editor.selection.setRng(rng);
|
|
|
11005 |
};
|
|
|
11006 |
const scrollToMarker = (editor, marker, viewHeight, alignToTop, doc) => {
|
|
|
11007 |
const pos = marker.pos;
|
|
|
11008 |
if (alignToTop) {
|
|
|
11009 |
to(pos.left, pos.top, doc);
|
|
|
11010 |
} else {
|
|
|
11011 |
const y = pos.top - viewHeight + marker.height;
|
|
|
11012 |
to(-editor.getBody().getBoundingClientRect().left, y, doc);
|
|
|
11013 |
}
|
|
|
11014 |
};
|
|
|
11015 |
const intoWindowIfNeeded = (editor, doc, scrollTop, viewHeight, marker, alignToTop) => {
|
|
|
11016 |
const viewportBottom = viewHeight + scrollTop;
|
|
|
11017 |
const markerTop = marker.pos.top;
|
|
|
11018 |
const markerBottom = marker.bottom;
|
|
|
11019 |
const largerThanViewport = markerBottom - markerTop >= viewHeight;
|
|
|
11020 |
if (markerTop < scrollTop) {
|
|
|
11021 |
scrollToMarker(editor, marker, viewHeight, alignToTop !== false, doc);
|
|
|
11022 |
} else if (markerTop > viewportBottom) {
|
|
|
11023 |
const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
|
|
|
11024 |
scrollToMarker(editor, marker, viewHeight, align, doc);
|
|
|
11025 |
} else if (markerBottom > viewportBottom && !largerThanViewport) {
|
|
|
11026 |
scrollToMarker(editor, marker, viewHeight, alignToTop === true, doc);
|
|
|
11027 |
}
|
|
|
11028 |
};
|
|
|
11029 |
const intoWindow = (editor, doc, scrollTop, marker, alignToTop) => {
|
|
|
11030 |
const viewHeight = defaultView(doc).dom.innerHeight;
|
|
|
11031 |
intoWindowIfNeeded(editor, doc, scrollTop, viewHeight, marker, alignToTop);
|
|
|
11032 |
};
|
|
|
11033 |
const intoFrame = (editor, doc, scrollTop, marker, alignToTop) => {
|
|
|
11034 |
const frameViewHeight = defaultView(doc).dom.innerHeight;
|
|
|
11035 |
intoWindowIfNeeded(editor, doc, scrollTop, frameViewHeight, marker, alignToTop);
|
|
|
11036 |
const op = find(marker.element);
|
|
|
11037 |
const viewportBounds = getBounds(window);
|
|
|
11038 |
if (op.top < viewportBounds.y) {
|
|
|
11039 |
intoView(marker.element, alignToTop !== false);
|
|
|
11040 |
} else if (op.top > viewportBounds.bottom) {
|
|
|
11041 |
intoView(marker.element, alignToTop === true);
|
|
|
11042 |
}
|
|
|
11043 |
};
|
|
|
11044 |
const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
|
|
|
11045 |
const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
|
|
|
11046 |
const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
|
|
|
11047 |
const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
|
|
|
11048 |
const scrollElementIntoView = (editor, element, alignToTop) => {
|
|
|
11049 |
const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
|
|
|
11050 |
scroller(editor, element, alignToTop);
|
|
|
11051 |
};
|
|
|
11052 |
const scrollRangeIntoView = (editor, rng, alignToTop) => {
|
|
|
11053 |
const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
|
|
|
11054 |
scroller(editor, rng, alignToTop);
|
|
|
11055 |
};
|
|
|
11056 |
|
|
|
11057 |
const isEditableRange = (dom, rng) => {
|
|
|
11058 |
if (rng.collapsed) {
|
|
|
11059 |
return dom.isEditable(rng.startContainer);
|
|
|
11060 |
} else {
|
|
|
11061 |
return dom.isEditable(rng.startContainer) && dom.isEditable(rng.endContainer);
|
|
|
11062 |
}
|
|
|
11063 |
};
|
|
|
11064 |
|
|
|
11065 |
const getEndpointElement = (root, rng, start, real, resolve) => {
|
|
|
11066 |
const container = start ? rng.startContainer : rng.endContainer;
|
|
|
11067 |
const offset = start ? rng.startOffset : rng.endOffset;
|
|
|
11068 |
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);
|
|
|
11069 |
};
|
|
|
11070 |
const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
|
| 1441 |
ariadna |
11071 |
const getEnd = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
|
| 1 |
efrain |
11072 |
const skipEmptyTextNodes = (node, forwards) => {
|
|
|
11073 |
const orig = node;
|
| 1441 |
ariadna |
11074 |
while (node && isText$b(node) && node.length === 0) {
|
| 1 |
efrain |
11075 |
node = forwards ? node.nextSibling : node.previousSibling;
|
|
|
11076 |
}
|
|
|
11077 |
return node || orig;
|
|
|
11078 |
};
|
|
|
11079 |
const getNode = (root, rng) => {
|
|
|
11080 |
if (!rng) {
|
|
|
11081 |
return root;
|
|
|
11082 |
}
|
|
|
11083 |
let startContainer = rng.startContainer;
|
|
|
11084 |
let endContainer = rng.endContainer;
|
|
|
11085 |
const startOffset = rng.startOffset;
|
|
|
11086 |
const endOffset = rng.endOffset;
|
|
|
11087 |
let node = rng.commonAncestorContainer;
|
|
|
11088 |
if (!rng.collapsed) {
|
|
|
11089 |
if (startContainer === endContainer) {
|
|
|
11090 |
if (endOffset - startOffset < 2) {
|
|
|
11091 |
if (startContainer.hasChildNodes()) {
|
|
|
11092 |
node = startContainer.childNodes[startOffset];
|
|
|
11093 |
}
|
|
|
11094 |
}
|
|
|
11095 |
}
|
| 1441 |
ariadna |
11096 |
if (isText$b(startContainer) && isText$b(endContainer)) {
|
| 1 |
efrain |
11097 |
if (startContainer.length === startOffset) {
|
|
|
11098 |
startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
|
|
|
11099 |
} else {
|
|
|
11100 |
startContainer = startContainer.parentNode;
|
|
|
11101 |
}
|
|
|
11102 |
if (endOffset === 0) {
|
|
|
11103 |
endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
|
|
|
11104 |
} else {
|
|
|
11105 |
endContainer = endContainer.parentNode;
|
|
|
11106 |
}
|
|
|
11107 |
if (startContainer && startContainer === endContainer) {
|
|
|
11108 |
node = startContainer;
|
|
|
11109 |
}
|
|
|
11110 |
}
|
|
|
11111 |
}
|
| 1441 |
ariadna |
11112 |
const elm = isText$b(node) ? node.parentNode : node;
|
| 1 |
efrain |
11113 |
return isHTMLElement(elm) ? elm : root;
|
|
|
11114 |
};
|
|
|
11115 |
const getSelectedBlocks = (dom, rng, startElm, endElm) => {
|
|
|
11116 |
const selectedBlocks = [];
|
|
|
11117 |
const root = dom.getRoot();
|
|
|
11118 |
const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock);
|
| 1441 |
ariadna |
11119 |
const end = dom.getParent(endElm || getEnd(root, rng, rng.collapsed), dom.isBlock);
|
| 1 |
efrain |
11120 |
if (start && start !== root) {
|
|
|
11121 |
selectedBlocks.push(start);
|
|
|
11122 |
}
|
|
|
11123 |
if (start && end && start !== end) {
|
|
|
11124 |
let node;
|
|
|
11125 |
const walker = new DomTreeWalker(start, root);
|
|
|
11126 |
while ((node = walker.next()) && node !== end) {
|
|
|
11127 |
if (dom.isBlock(node)) {
|
|
|
11128 |
selectedBlocks.push(node);
|
|
|
11129 |
}
|
|
|
11130 |
}
|
|
|
11131 |
}
|
|
|
11132 |
if (end && start !== end && end !== root) {
|
|
|
11133 |
selectedBlocks.push(end);
|
|
|
11134 |
}
|
|
|
11135 |
return selectedBlocks;
|
|
|
11136 |
};
|
|
|
11137 |
const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => {
|
|
|
11138 |
const idx = dom.nodeIndex(node);
|
|
|
11139 |
const rng = dom.createRng();
|
|
|
11140 |
rng.setStart(parent, idx);
|
|
|
11141 |
rng.setEnd(parent, idx + 1);
|
|
|
11142 |
if (content) {
|
|
|
11143 |
moveEndPoint(dom, rng, node, true);
|
|
|
11144 |
moveEndPoint(dom, rng, node, false);
|
|
|
11145 |
}
|
|
|
11146 |
return rng;
|
|
|
11147 |
}));
|
|
|
11148 |
|
|
|
11149 |
const processRanges = (editor, ranges) => map$3(ranges, range => {
|
|
|
11150 |
const evt = editor.dispatch('GetSelectionRange', { range });
|
|
|
11151 |
return evt.range !== range ? evt.range : range;
|
|
|
11152 |
});
|
|
|
11153 |
|
|
|
11154 |
const typeLookup = {
|
|
|
11155 |
'#text': 3,
|
|
|
11156 |
'#comment': 8,
|
|
|
11157 |
'#cdata': 4,
|
|
|
11158 |
'#pi': 7,
|
|
|
11159 |
'#doctype': 10,
|
|
|
11160 |
'#document-fragment': 11
|
|
|
11161 |
};
|
|
|
11162 |
const walk$2 = (node, root, prev) => {
|
|
|
11163 |
const startName = prev ? 'lastChild' : 'firstChild';
|
|
|
11164 |
const siblingName = prev ? 'prev' : 'next';
|
|
|
11165 |
if (node[startName]) {
|
|
|
11166 |
return node[startName];
|
|
|
11167 |
}
|
|
|
11168 |
if (node !== root) {
|
|
|
11169 |
let sibling = node[siblingName];
|
|
|
11170 |
if (sibling) {
|
|
|
11171 |
return sibling;
|
|
|
11172 |
}
|
|
|
11173 |
for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
|
|
|
11174 |
sibling = parent[siblingName];
|
|
|
11175 |
if (sibling) {
|
|
|
11176 |
return sibling;
|
|
|
11177 |
}
|
|
|
11178 |
}
|
|
|
11179 |
}
|
|
|
11180 |
return undefined;
|
|
|
11181 |
};
|
|
|
11182 |
const isEmptyTextNode = node => {
|
|
|
11183 |
var _a;
|
|
|
11184 |
const text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
|
|
|
11185 |
if (!isWhitespaceText(text)) {
|
|
|
11186 |
return false;
|
|
|
11187 |
}
|
|
|
11188 |
const parentNode = node.parent;
|
|
|
11189 |
if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) {
|
|
|
11190 |
return false;
|
|
|
11191 |
}
|
|
|
11192 |
return true;
|
|
|
11193 |
};
|
|
|
11194 |
const isNonEmptyElement = node => {
|
|
|
11195 |
const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id');
|
|
|
11196 |
return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor;
|
|
|
11197 |
};
|
|
|
11198 |
class AstNode {
|
|
|
11199 |
static create(name, attrs) {
|
|
|
11200 |
const node = new AstNode(name, typeLookup[name] || 1);
|
|
|
11201 |
if (attrs) {
|
|
|
11202 |
each$d(attrs, (value, attrName) => {
|
|
|
11203 |
node.attr(attrName, value);
|
|
|
11204 |
});
|
|
|
11205 |
}
|
|
|
11206 |
return node;
|
|
|
11207 |
}
|
|
|
11208 |
constructor(name, type) {
|
|
|
11209 |
this.name = name;
|
|
|
11210 |
this.type = type;
|
|
|
11211 |
if (type === 1) {
|
|
|
11212 |
this.attributes = [];
|
|
|
11213 |
this.attributes.map = {};
|
|
|
11214 |
}
|
|
|
11215 |
}
|
|
|
11216 |
replace(node) {
|
|
|
11217 |
const self = this;
|
|
|
11218 |
if (node.parent) {
|
|
|
11219 |
node.remove();
|
|
|
11220 |
}
|
|
|
11221 |
self.insert(node, self);
|
|
|
11222 |
self.remove();
|
|
|
11223 |
return self;
|
|
|
11224 |
}
|
|
|
11225 |
attr(name, value) {
|
|
|
11226 |
const self = this;
|
|
|
11227 |
if (!isString(name)) {
|
|
|
11228 |
if (isNonNullable(name)) {
|
|
|
11229 |
each$d(name, (value, key) => {
|
|
|
11230 |
self.attr(key, value);
|
|
|
11231 |
});
|
|
|
11232 |
}
|
|
|
11233 |
return self;
|
|
|
11234 |
}
|
|
|
11235 |
const attrs = self.attributes;
|
|
|
11236 |
if (attrs) {
|
|
|
11237 |
if (value !== undefined) {
|
|
|
11238 |
if (value === null) {
|
|
|
11239 |
if (name in attrs.map) {
|
|
|
11240 |
delete attrs.map[name];
|
|
|
11241 |
let i = attrs.length;
|
|
|
11242 |
while (i--) {
|
|
|
11243 |
if (attrs[i].name === name) {
|
|
|
11244 |
attrs.splice(i, 1);
|
|
|
11245 |
return self;
|
|
|
11246 |
}
|
|
|
11247 |
}
|
|
|
11248 |
}
|
|
|
11249 |
return self;
|
|
|
11250 |
}
|
|
|
11251 |
if (name in attrs.map) {
|
|
|
11252 |
let i = attrs.length;
|
|
|
11253 |
while (i--) {
|
|
|
11254 |
if (attrs[i].name === name) {
|
|
|
11255 |
attrs[i].value = value;
|
|
|
11256 |
break;
|
|
|
11257 |
}
|
|
|
11258 |
}
|
|
|
11259 |
} else {
|
|
|
11260 |
attrs.push({
|
|
|
11261 |
name,
|
|
|
11262 |
value
|
|
|
11263 |
});
|
|
|
11264 |
}
|
|
|
11265 |
attrs.map[name] = value;
|
|
|
11266 |
return self;
|
|
|
11267 |
}
|
|
|
11268 |
return attrs.map[name];
|
|
|
11269 |
}
|
|
|
11270 |
return undefined;
|
|
|
11271 |
}
|
|
|
11272 |
clone() {
|
|
|
11273 |
const self = this;
|
|
|
11274 |
const clone = new AstNode(self.name, self.type);
|
|
|
11275 |
const selfAttrs = self.attributes;
|
|
|
11276 |
if (selfAttrs) {
|
|
|
11277 |
const cloneAttrs = [];
|
|
|
11278 |
cloneAttrs.map = {};
|
|
|
11279 |
for (let i = 0, l = selfAttrs.length; i < l; i++) {
|
|
|
11280 |
const selfAttr = selfAttrs[i];
|
|
|
11281 |
if (selfAttr.name !== 'id') {
|
|
|
11282 |
cloneAttrs[cloneAttrs.length] = {
|
|
|
11283 |
name: selfAttr.name,
|
|
|
11284 |
value: selfAttr.value
|
|
|
11285 |
};
|
|
|
11286 |
cloneAttrs.map[selfAttr.name] = selfAttr.value;
|
|
|
11287 |
}
|
|
|
11288 |
}
|
|
|
11289 |
clone.attributes = cloneAttrs;
|
|
|
11290 |
}
|
|
|
11291 |
clone.value = self.value;
|
|
|
11292 |
return clone;
|
|
|
11293 |
}
|
|
|
11294 |
wrap(wrapper) {
|
|
|
11295 |
const self = this;
|
|
|
11296 |
if (self.parent) {
|
|
|
11297 |
self.parent.insert(wrapper, self);
|
|
|
11298 |
wrapper.append(self);
|
|
|
11299 |
}
|
|
|
11300 |
return self;
|
|
|
11301 |
}
|
|
|
11302 |
unwrap() {
|
|
|
11303 |
const self = this;
|
|
|
11304 |
for (let node = self.firstChild; node;) {
|
|
|
11305 |
const next = node.next;
|
|
|
11306 |
self.insert(node, self, true);
|
|
|
11307 |
node = next;
|
|
|
11308 |
}
|
|
|
11309 |
self.remove();
|
|
|
11310 |
}
|
|
|
11311 |
remove() {
|
|
|
11312 |
const self = this, parent = self.parent, next = self.next, prev = self.prev;
|
|
|
11313 |
if (parent) {
|
|
|
11314 |
if (parent.firstChild === self) {
|
|
|
11315 |
parent.firstChild = next;
|
|
|
11316 |
if (next) {
|
|
|
11317 |
next.prev = null;
|
|
|
11318 |
}
|
|
|
11319 |
} else if (prev) {
|
|
|
11320 |
prev.next = next;
|
|
|
11321 |
}
|
|
|
11322 |
if (parent.lastChild === self) {
|
|
|
11323 |
parent.lastChild = prev;
|
|
|
11324 |
if (prev) {
|
|
|
11325 |
prev.next = null;
|
|
|
11326 |
}
|
|
|
11327 |
} else if (next) {
|
|
|
11328 |
next.prev = prev;
|
|
|
11329 |
}
|
|
|
11330 |
self.parent = self.next = self.prev = null;
|
|
|
11331 |
}
|
|
|
11332 |
return self;
|
|
|
11333 |
}
|
|
|
11334 |
append(node) {
|
|
|
11335 |
const self = this;
|
|
|
11336 |
if (node.parent) {
|
|
|
11337 |
node.remove();
|
|
|
11338 |
}
|
|
|
11339 |
const last = self.lastChild;
|
|
|
11340 |
if (last) {
|
|
|
11341 |
last.next = node;
|
|
|
11342 |
node.prev = last;
|
|
|
11343 |
self.lastChild = node;
|
|
|
11344 |
} else {
|
|
|
11345 |
self.lastChild = self.firstChild = node;
|
|
|
11346 |
}
|
|
|
11347 |
node.parent = self;
|
|
|
11348 |
return node;
|
|
|
11349 |
}
|
|
|
11350 |
insert(node, refNode, before) {
|
|
|
11351 |
if (node.parent) {
|
|
|
11352 |
node.remove();
|
|
|
11353 |
}
|
|
|
11354 |
const parent = refNode.parent || this;
|
|
|
11355 |
if (before) {
|
|
|
11356 |
if (refNode === parent.firstChild) {
|
|
|
11357 |
parent.firstChild = node;
|
|
|
11358 |
} else if (refNode.prev) {
|
|
|
11359 |
refNode.prev.next = node;
|
|
|
11360 |
}
|
|
|
11361 |
node.prev = refNode.prev;
|
|
|
11362 |
node.next = refNode;
|
|
|
11363 |
refNode.prev = node;
|
|
|
11364 |
} else {
|
|
|
11365 |
if (refNode === parent.lastChild) {
|
|
|
11366 |
parent.lastChild = node;
|
|
|
11367 |
} else if (refNode.next) {
|
|
|
11368 |
refNode.next.prev = node;
|
|
|
11369 |
}
|
|
|
11370 |
node.next = refNode.next;
|
|
|
11371 |
node.prev = refNode;
|
|
|
11372 |
refNode.next = node;
|
|
|
11373 |
}
|
|
|
11374 |
node.parent = parent;
|
|
|
11375 |
return node;
|
|
|
11376 |
}
|
|
|
11377 |
getAll(name) {
|
|
|
11378 |
const self = this;
|
|
|
11379 |
const collection = [];
|
|
|
11380 |
for (let node = self.firstChild; node; node = walk$2(node, self)) {
|
|
|
11381 |
if (node.name === name) {
|
|
|
11382 |
collection.push(node);
|
|
|
11383 |
}
|
|
|
11384 |
}
|
|
|
11385 |
return collection;
|
|
|
11386 |
}
|
|
|
11387 |
children() {
|
|
|
11388 |
const self = this;
|
|
|
11389 |
const collection = [];
|
|
|
11390 |
for (let node = self.firstChild; node; node = node.next) {
|
|
|
11391 |
collection.push(node);
|
|
|
11392 |
}
|
|
|
11393 |
return collection;
|
|
|
11394 |
}
|
|
|
11395 |
empty() {
|
|
|
11396 |
const self = this;
|
|
|
11397 |
if (self.firstChild) {
|
|
|
11398 |
const nodes = [];
|
|
|
11399 |
for (let node = self.firstChild; node; node = walk$2(node, self)) {
|
|
|
11400 |
nodes.push(node);
|
|
|
11401 |
}
|
|
|
11402 |
let i = nodes.length;
|
|
|
11403 |
while (i--) {
|
|
|
11404 |
const node = nodes[i];
|
|
|
11405 |
node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
|
|
|
11406 |
}
|
|
|
11407 |
}
|
|
|
11408 |
self.firstChild = self.lastChild = null;
|
|
|
11409 |
return self;
|
|
|
11410 |
}
|
|
|
11411 |
isEmpty(elements, whitespace = {}, predicate) {
|
|
|
11412 |
var _a;
|
|
|
11413 |
const self = this;
|
|
|
11414 |
let node = self.firstChild;
|
|
|
11415 |
if (isNonEmptyElement(self)) {
|
|
|
11416 |
return false;
|
|
|
11417 |
}
|
|
|
11418 |
if (node) {
|
|
|
11419 |
do {
|
|
|
11420 |
if (node.type === 1) {
|
|
|
11421 |
if (node.attr('data-mce-bogus')) {
|
|
|
11422 |
continue;
|
|
|
11423 |
}
|
|
|
11424 |
if (elements[node.name]) {
|
|
|
11425 |
return false;
|
|
|
11426 |
}
|
|
|
11427 |
if (isNonEmptyElement(node)) {
|
|
|
11428 |
return false;
|
|
|
11429 |
}
|
|
|
11430 |
}
|
|
|
11431 |
if (node.type === 8) {
|
|
|
11432 |
return false;
|
|
|
11433 |
}
|
|
|
11434 |
if (node.type === 3 && !isEmptyTextNode(node)) {
|
|
|
11435 |
return false;
|
|
|
11436 |
}
|
|
|
11437 |
if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) {
|
|
|
11438 |
return false;
|
|
|
11439 |
}
|
|
|
11440 |
if (predicate && predicate(node)) {
|
|
|
11441 |
return false;
|
|
|
11442 |
}
|
|
|
11443 |
} while (node = walk$2(node, self));
|
|
|
11444 |
}
|
|
|
11445 |
return true;
|
|
|
11446 |
}
|
|
|
11447 |
walk(prev) {
|
|
|
11448 |
return walk$2(this, null, prev);
|
|
|
11449 |
}
|
|
|
11450 |
}
|
|
|
11451 |
|
|
|
11452 |
const unescapedTextParents = Tools.makeMap('NOSCRIPT STYLE SCRIPT XMP IFRAME NOEMBED NOFRAMES PLAINTEXT', ' ');
|
|
|
11453 |
const containsZwsp = node => isString(node.nodeValue) && node.nodeValue.includes(ZWSP$1);
|
|
|
11454 |
const getTemporaryNodeSelector = tempAttrs => `${ tempAttrs.length === 0 ? '' : `${ map$3(tempAttrs, attr => `[${ attr }]`).join(',') },` }[data-mce-bogus="all"]`;
|
|
|
11455 |
const getTemporaryNodes = (tempAttrs, body) => body.querySelectorAll(getTemporaryNodeSelector(tempAttrs));
|
|
|
11456 |
const createZwspCommentWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, node => containsZwsp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP);
|
|
|
11457 |
const createUnescapedZwspTextWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_TEXT, node => {
|
|
|
11458 |
if (containsZwsp(node)) {
|
|
|
11459 |
const parent = node.parentNode;
|
|
|
11460 |
return parent && has$2(unescapedTextParents, parent.nodeName) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
|
|
|
11461 |
} else {
|
|
|
11462 |
return NodeFilter.FILTER_SKIP;
|
|
|
11463 |
}
|
|
|
11464 |
});
|
|
|
11465 |
const hasZwspComment = body => createZwspCommentWalker(body).nextNode() !== null;
|
|
|
11466 |
const hasUnescapedZwspText = body => createUnescapedZwspTextWalker(body).nextNode() !== null;
|
|
|
11467 |
const hasTemporaryNode = (tempAttrs, body) => body.querySelector(getTemporaryNodeSelector(tempAttrs)) !== null;
|
|
|
11468 |
const trimTemporaryNodes = (tempAttrs, body) => {
|
|
|
11469 |
each$e(getTemporaryNodes(tempAttrs, body), elm => {
|
|
|
11470 |
const element = SugarElement.fromDom(elm);
|
|
|
11471 |
if (get$9(element, 'data-mce-bogus') === 'all') {
|
| 1441 |
ariadna |
11472 |
remove$4(element);
|
| 1 |
efrain |
11473 |
} else {
|
|
|
11474 |
each$e(tempAttrs, attr => {
|
|
|
11475 |
if (has$1(element, attr)) {
|
| 1441 |
ariadna |
11476 |
remove$9(element, attr);
|
| 1 |
efrain |
11477 |
}
|
|
|
11478 |
});
|
|
|
11479 |
}
|
|
|
11480 |
});
|
|
|
11481 |
};
|
|
|
11482 |
const emptyAllNodeValuesInWalker = walker => {
|
|
|
11483 |
let curr = walker.nextNode();
|
|
|
11484 |
while (curr !== null) {
|
|
|
11485 |
curr.nodeValue = null;
|
|
|
11486 |
curr = walker.nextNode();
|
|
|
11487 |
}
|
|
|
11488 |
};
|
|
|
11489 |
const emptyZwspComments = compose(emptyAllNodeValuesInWalker, createZwspCommentWalker);
|
|
|
11490 |
const emptyUnescapedZwspTexts = compose(emptyAllNodeValuesInWalker, createUnescapedZwspTextWalker);
|
|
|
11491 |
const trim$1 = (body, tempAttrs) => {
|
|
|
11492 |
const conditionalTrims = [
|
|
|
11493 |
{
|
|
|
11494 |
condition: curry(hasTemporaryNode, tempAttrs),
|
|
|
11495 |
action: curry(trimTemporaryNodes, tempAttrs)
|
|
|
11496 |
},
|
|
|
11497 |
{
|
|
|
11498 |
condition: hasZwspComment,
|
|
|
11499 |
action: emptyZwspComments
|
|
|
11500 |
},
|
|
|
11501 |
{
|
|
|
11502 |
condition: hasUnescapedZwspText,
|
|
|
11503 |
action: emptyUnescapedZwspTexts
|
|
|
11504 |
}
|
|
|
11505 |
];
|
|
|
11506 |
let trimmed = body;
|
|
|
11507 |
let cloned = false;
|
|
|
11508 |
each$e(conditionalTrims, ({condition, action}) => {
|
|
|
11509 |
if (condition(trimmed)) {
|
|
|
11510 |
if (!cloned) {
|
|
|
11511 |
trimmed = body.cloneNode(true);
|
|
|
11512 |
cloned = true;
|
|
|
11513 |
}
|
|
|
11514 |
action(trimmed);
|
|
|
11515 |
}
|
|
|
11516 |
});
|
|
|
11517 |
return trimmed;
|
|
|
11518 |
};
|
|
|
11519 |
|
|
|
11520 |
const cleanupBogusElements = parent => {
|
|
|
11521 |
const bogusElements = descendants(parent, '[data-mce-bogus]');
|
|
|
11522 |
each$e(bogusElements, elem => {
|
|
|
11523 |
const bogusValue = get$9(elem, 'data-mce-bogus');
|
|
|
11524 |
if (bogusValue === 'all') {
|
| 1441 |
ariadna |
11525 |
remove$4(elem);
|
| 1 |
efrain |
11526 |
} else if (isBr$5(elem)) {
|
|
|
11527 |
before$3(elem, SugarElement.fromText(zeroWidth));
|
| 1441 |
ariadna |
11528 |
remove$4(elem);
|
| 1 |
efrain |
11529 |
} else {
|
|
|
11530 |
unwrap(elem);
|
|
|
11531 |
}
|
|
|
11532 |
});
|
|
|
11533 |
};
|
|
|
11534 |
const cleanupInputNames = parent => {
|
|
|
11535 |
const inputs = descendants(parent, 'input');
|
|
|
11536 |
each$e(inputs, input => {
|
| 1441 |
ariadna |
11537 |
remove$9(input, 'name');
|
| 1 |
efrain |
11538 |
});
|
|
|
11539 |
};
|
|
|
11540 |
|
|
|
11541 |
const trimEmptyContents = (editor, html) => {
|
|
|
11542 |
const blockName = getForcedRootBlock(editor);
|
|
|
11543 |
const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>( | |\\s|\u00a0|<br \\/>|)<\\/${ blockName }>[\r\n]*|<br \\/>[\r\n]*)$`);
|
|
|
11544 |
return html.replace(emptyRegExp, '');
|
|
|
11545 |
};
|
|
|
11546 |
const getPlainTextContent = (editor, body) => {
|
|
|
11547 |
const doc = editor.getDoc();
|
|
|
11548 |
const dos = getRootNode(SugarElement.fromDom(editor.getBody()));
|
|
|
11549 |
const offscreenDiv = SugarElement.fromTag('div', doc);
|
| 1441 |
ariadna |
11550 |
set$4(offscreenDiv, 'data-mce-bogus', 'all');
|
| 1 |
efrain |
11551 |
setAll(offscreenDiv, {
|
|
|
11552 |
position: 'fixed',
|
|
|
11553 |
left: '-9999999px',
|
|
|
11554 |
top: '0'
|
|
|
11555 |
});
|
|
|
11556 |
set$1(offscreenDiv, body.innerHTML);
|
|
|
11557 |
cleanupBogusElements(offscreenDiv);
|
|
|
11558 |
cleanupInputNames(offscreenDiv);
|
|
|
11559 |
const root = getContentContainer(dos);
|
|
|
11560 |
append$1(root, offscreenDiv);
|
|
|
11561 |
const content = trim$2(offscreenDiv.dom.innerText);
|
| 1441 |
ariadna |
11562 |
remove$4(offscreenDiv);
|
| 1 |
efrain |
11563 |
return content;
|
|
|
11564 |
};
|
|
|
11565 |
const getContentFromBody = (editor, args, body) => {
|
|
|
11566 |
let content;
|
|
|
11567 |
if (args.format === 'raw') {
|
|
|
11568 |
content = Tools.trim(trim$2(trim$1(body, editor.serializer.getTempAttrs()).innerHTML));
|
|
|
11569 |
} else if (args.format === 'text') {
|
|
|
11570 |
content = getPlainTextContent(editor, body);
|
|
|
11571 |
} else if (args.format === 'tree') {
|
|
|
11572 |
content = editor.serializer.serialize(body, args);
|
|
|
11573 |
} else {
|
|
|
11574 |
content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
|
|
|
11575 |
}
|
|
|
11576 |
const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body));
|
|
|
11577 |
return shouldTrim && isString(content) ? Tools.trim(content) : content;
|
|
|
11578 |
};
|
|
|
11579 |
const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body));
|
|
|
11580 |
|
|
|
11581 |
const makeMap$1 = Tools.makeMap;
|
|
|
11582 |
const Writer = settings => {
|
|
|
11583 |
const html = [];
|
|
|
11584 |
settings = settings || {};
|
|
|
11585 |
const indent = settings.indent;
|
|
|
11586 |
const indentBefore = makeMap$1(settings.indent_before || '');
|
|
|
11587 |
const indentAfter = makeMap$1(settings.indent_after || '');
|
|
|
11588 |
const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
|
|
|
11589 |
const htmlOutput = settings.element_format !== 'xhtml';
|
|
|
11590 |
return {
|
|
|
11591 |
start: (name, attrs, empty) => {
|
|
|
11592 |
if (indent && indentBefore[name] && html.length > 0) {
|
|
|
11593 |
const value = html[html.length - 1];
|
|
|
11594 |
if (value.length > 0 && value !== '\n') {
|
|
|
11595 |
html.push('\n');
|
|
|
11596 |
}
|
|
|
11597 |
}
|
|
|
11598 |
html.push('<', name);
|
|
|
11599 |
if (attrs) {
|
|
|
11600 |
for (let i = 0, l = attrs.length; i < l; i++) {
|
|
|
11601 |
const attr = attrs[i];
|
|
|
11602 |
html.push(' ', attr.name, '="', encode(attr.value, true), '"');
|
|
|
11603 |
}
|
|
|
11604 |
}
|
|
|
11605 |
if (!empty || htmlOutput) {
|
|
|
11606 |
html[html.length] = '>';
|
|
|
11607 |
} else {
|
|
|
11608 |
html[html.length] = ' />';
|
|
|
11609 |
}
|
|
|
11610 |
if (empty && indent && indentAfter[name] && html.length > 0) {
|
|
|
11611 |
const value = html[html.length - 1];
|
|
|
11612 |
if (value.length > 0 && value !== '\n') {
|
|
|
11613 |
html.push('\n');
|
|
|
11614 |
}
|
|
|
11615 |
}
|
|
|
11616 |
},
|
|
|
11617 |
end: name => {
|
|
|
11618 |
let value;
|
|
|
11619 |
html.push('</', name, '>');
|
|
|
11620 |
if (indent && indentAfter[name] && html.length > 0) {
|
|
|
11621 |
value = html[html.length - 1];
|
|
|
11622 |
if (value.length > 0 && value !== '\n') {
|
|
|
11623 |
html.push('\n');
|
|
|
11624 |
}
|
|
|
11625 |
}
|
|
|
11626 |
},
|
|
|
11627 |
text: (text, raw) => {
|
|
|
11628 |
if (text.length > 0) {
|
|
|
11629 |
html[html.length] = raw ? text : encode(text);
|
|
|
11630 |
}
|
|
|
11631 |
},
|
|
|
11632 |
cdata: text => {
|
|
|
11633 |
html.push('<![CDATA[', text, ']]>');
|
|
|
11634 |
},
|
|
|
11635 |
comment: text => {
|
|
|
11636 |
html.push('<!--', text, '-->');
|
|
|
11637 |
},
|
|
|
11638 |
pi: (name, text) => {
|
|
|
11639 |
if (text) {
|
|
|
11640 |
html.push('<?', name, ' ', encode(text), '?>');
|
|
|
11641 |
} else {
|
|
|
11642 |
html.push('<?', name, '?>');
|
|
|
11643 |
}
|
|
|
11644 |
if (indent) {
|
|
|
11645 |
html.push('\n');
|
|
|
11646 |
}
|
|
|
11647 |
},
|
|
|
11648 |
doctype: text => {
|
|
|
11649 |
html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
|
|
|
11650 |
},
|
|
|
11651 |
reset: () => {
|
|
|
11652 |
html.length = 0;
|
|
|
11653 |
},
|
|
|
11654 |
getContent: () => {
|
|
|
11655 |
return html.join('').replace(/\n$/, '');
|
|
|
11656 |
}
|
|
|
11657 |
};
|
|
|
11658 |
};
|
|
|
11659 |
|
|
|
11660 |
const HtmlSerializer = (settings = {}, schema = Schema()) => {
|
|
|
11661 |
const writer = Writer(settings);
|
|
|
11662 |
settings.validate = 'validate' in settings ? settings.validate : true;
|
|
|
11663 |
const serialize = node => {
|
|
|
11664 |
const validate = settings.validate;
|
|
|
11665 |
const handlers = {
|
|
|
11666 |
3: node => {
|
|
|
11667 |
var _a;
|
|
|
11668 |
writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw);
|
|
|
11669 |
},
|
|
|
11670 |
8: node => {
|
|
|
11671 |
var _a;
|
|
|
11672 |
writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : '');
|
|
|
11673 |
},
|
|
|
11674 |
7: node => {
|
|
|
11675 |
writer.pi(node.name, node.value);
|
|
|
11676 |
},
|
|
|
11677 |
10: node => {
|
|
|
11678 |
var _a;
|
|
|
11679 |
writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : '');
|
|
|
11680 |
},
|
|
|
11681 |
4: node => {
|
|
|
11682 |
var _a;
|
|
|
11683 |
writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : '');
|
|
|
11684 |
},
|
|
|
11685 |
11: node => {
|
|
|
11686 |
let tempNode = node;
|
|
|
11687 |
if (tempNode = tempNode.firstChild) {
|
|
|
11688 |
do {
|
|
|
11689 |
walk(tempNode);
|
|
|
11690 |
} while (tempNode = tempNode.next);
|
|
|
11691 |
}
|
|
|
11692 |
}
|
|
|
11693 |
};
|
|
|
11694 |
writer.reset();
|
|
|
11695 |
const walk = node => {
|
|
|
11696 |
var _a;
|
|
|
11697 |
const handler = handlers[node.type];
|
|
|
11698 |
if (!handler) {
|
|
|
11699 |
const name = node.name;
|
|
|
11700 |
const isEmpty = name in schema.getVoidElements();
|
|
|
11701 |
let attrs = node.attributes;
|
|
|
11702 |
if (validate && attrs && attrs.length > 1) {
|
|
|
11703 |
const sortedAttrs = [];
|
|
|
11704 |
sortedAttrs.map = {};
|
|
|
11705 |
const elementRule = schema.getElementRule(node.name);
|
|
|
11706 |
if (elementRule) {
|
|
|
11707 |
for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
|
|
|
11708 |
const attrName = elementRule.attributesOrder[i];
|
|
|
11709 |
if (attrName in attrs.map) {
|
|
|
11710 |
const attrValue = attrs.map[attrName];
|
|
|
11711 |
sortedAttrs.map[attrName] = attrValue;
|
|
|
11712 |
sortedAttrs.push({
|
|
|
11713 |
name: attrName,
|
|
|
11714 |
value: attrValue
|
|
|
11715 |
});
|
|
|
11716 |
}
|
|
|
11717 |
}
|
|
|
11718 |
for (let i = 0, l = attrs.length; i < l; i++) {
|
|
|
11719 |
const attrName = attrs[i].name;
|
|
|
11720 |
if (!(attrName in sortedAttrs.map)) {
|
|
|
11721 |
const attrValue = attrs.map[attrName];
|
|
|
11722 |
sortedAttrs.map[attrName] = attrValue;
|
|
|
11723 |
sortedAttrs.push({
|
|
|
11724 |
name: attrName,
|
|
|
11725 |
value: attrValue
|
|
|
11726 |
});
|
|
|
11727 |
}
|
|
|
11728 |
}
|
|
|
11729 |
attrs = sortedAttrs;
|
|
|
11730 |
}
|
|
|
11731 |
}
|
|
|
11732 |
writer.start(name, attrs, isEmpty);
|
|
|
11733 |
if (isNonHtmlElementRootName(name)) {
|
|
|
11734 |
if (isString(node.value)) {
|
|
|
11735 |
writer.text(node.value, true);
|
|
|
11736 |
}
|
|
|
11737 |
writer.end(name);
|
|
|
11738 |
} else {
|
|
|
11739 |
if (!isEmpty) {
|
|
|
11740 |
let child = node.firstChild;
|
|
|
11741 |
if (child) {
|
|
|
11742 |
if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') {
|
|
|
11743 |
writer.text('\n', true);
|
|
|
11744 |
}
|
|
|
11745 |
do {
|
|
|
11746 |
walk(child);
|
|
|
11747 |
} while (child = child.next);
|
|
|
11748 |
}
|
|
|
11749 |
writer.end(name);
|
|
|
11750 |
}
|
|
|
11751 |
}
|
|
|
11752 |
} else {
|
|
|
11753 |
handler(node);
|
|
|
11754 |
}
|
|
|
11755 |
};
|
|
|
11756 |
if (node.type === 1 && !settings.inner) {
|
|
|
11757 |
walk(node);
|
|
|
11758 |
} else if (node.type === 3) {
|
|
|
11759 |
handlers[3](node);
|
|
|
11760 |
} else {
|
|
|
11761 |
handlers[11](node);
|
|
|
11762 |
}
|
|
|
11763 |
return writer.getContent();
|
|
|
11764 |
};
|
|
|
11765 |
return { serialize };
|
|
|
11766 |
};
|
|
|
11767 |
|
|
|
11768 |
const nonInheritableStyles = new Set();
|
|
|
11769 |
(() => {
|
|
|
11770 |
const nonInheritableStylesArr = [
|
|
|
11771 |
'margin',
|
|
|
11772 |
'margin-left',
|
|
|
11773 |
'margin-right',
|
|
|
11774 |
'margin-top',
|
|
|
11775 |
'margin-bottom',
|
|
|
11776 |
'padding',
|
|
|
11777 |
'padding-left',
|
|
|
11778 |
'padding-right',
|
|
|
11779 |
'padding-top',
|
|
|
11780 |
'padding-bottom',
|
|
|
11781 |
'border',
|
|
|
11782 |
'border-width',
|
|
|
11783 |
'border-style',
|
|
|
11784 |
'border-color',
|
|
|
11785 |
'background',
|
|
|
11786 |
'background-attachment',
|
|
|
11787 |
'background-clip',
|
|
|
11788 |
'background-image',
|
|
|
11789 |
'background-origin',
|
|
|
11790 |
'background-position',
|
|
|
11791 |
'background-repeat',
|
|
|
11792 |
'background-size',
|
|
|
11793 |
'float',
|
|
|
11794 |
'position',
|
|
|
11795 |
'left',
|
|
|
11796 |
'right',
|
|
|
11797 |
'top',
|
|
|
11798 |
'bottom',
|
|
|
11799 |
'z-index',
|
|
|
11800 |
'display',
|
|
|
11801 |
'transform',
|
|
|
11802 |
'width',
|
|
|
11803 |
'max-width',
|
|
|
11804 |
'min-width',
|
|
|
11805 |
'height',
|
|
|
11806 |
'max-height',
|
|
|
11807 |
'min-height',
|
|
|
11808 |
'overflow',
|
|
|
11809 |
'overflow-x',
|
|
|
11810 |
'overflow-y',
|
|
|
11811 |
'text-overflow',
|
|
|
11812 |
'vertical-align',
|
|
|
11813 |
'transition',
|
|
|
11814 |
'transition-delay',
|
|
|
11815 |
'transition-duration',
|
|
|
11816 |
'transition-property',
|
|
|
11817 |
'transition-timing-function'
|
|
|
11818 |
];
|
|
|
11819 |
each$e(nonInheritableStylesArr, style => {
|
|
|
11820 |
nonInheritableStyles.add(style);
|
|
|
11821 |
});
|
|
|
11822 |
})();
|
| 1441 |
ariadna |
11823 |
const conditionalNonInheritableStyles = new Set();
|
|
|
11824 |
(() => {
|
|
|
11825 |
const conditionalNonInheritableStylesArr = ['background-color'];
|
|
|
11826 |
each$e(conditionalNonInheritableStylesArr, style => {
|
|
|
11827 |
conditionalNonInheritableStyles.add(style);
|
|
|
11828 |
});
|
|
|
11829 |
})();
|
| 1 |
efrain |
11830 |
const shorthandStyleProps = [
|
|
|
11831 |
'font',
|
|
|
11832 |
'text-decoration',
|
|
|
11833 |
'text-emphasis'
|
|
|
11834 |
];
|
| 1441 |
ariadna |
11835 |
const getStyles$1 = (dom, node) => dom.parseStyle(dom.getAttrib(node, 'style'));
|
|
|
11836 |
const getStyleProps = (dom, node) => keys(getStyles$1(dom, node));
|
| 1 |
efrain |
11837 |
const isNonInheritableStyle = style => nonInheritableStyles.has(style);
|
| 1441 |
ariadna |
11838 |
const isConditionalNonInheritableStyle = style => conditionalNonInheritableStyles.has(style);
|
|
|
11839 |
const hasNonInheritableStyles = (dom, node) => exists(getStyleProps(dom, node), style => isNonInheritableStyle(style));
|
|
|
11840 |
const hasConditionalNonInheritableStyles = (dom, node) => hasNonInheritableStyles(dom, node) && exists(getStyleProps(dom, node), style => isConditionalNonInheritableStyle(style));
|
| 1 |
efrain |
11841 |
const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop)));
|
|
|
11842 |
const hasStyleConflict = (dom, node, parentNode) => {
|
|
|
11843 |
const nodeStyleProps = getStyleProps(dom, node);
|
|
|
11844 |
const parentNodeStyleProps = getStyleProps(dom, parentNode);
|
|
|
11845 |
const valueMismatch = prop => {
|
|
|
11846 |
var _a, _b;
|
|
|
11847 |
const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : '';
|
|
|
11848 |
const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : '';
|
|
|
11849 |
return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
|
|
|
11850 |
};
|
|
|
11851 |
return exists(nodeStyleProps, nodeStyleProp => {
|
|
|
11852 |
const propExists = props => exists(props, prop => prop === nodeStyleProp);
|
|
|
11853 |
if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
|
|
|
11854 |
const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
|
|
|
11855 |
return exists(longhandProps, valueMismatch);
|
|
|
11856 |
} else {
|
|
|
11857 |
return valueMismatch(nodeStyleProp);
|
|
|
11858 |
}
|
|
|
11859 |
});
|
|
|
11860 |
};
|
|
|
11861 |
|
| 1441 |
ariadna |
11862 |
const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$b).exists(text => {
|
| 1 |
efrain |
11863 |
const delta = forward ? 0 : -1;
|
|
|
11864 |
return predicate(text.data.charAt(pos.offset() + delta));
|
|
|
11865 |
});
|
|
|
11866 |
const isBeforeSpace = curry(isChar, true, isWhiteSpace);
|
|
|
11867 |
const isAfterSpace = curry(isChar, false, isWhiteSpace);
|
|
|
11868 |
const isEmptyText = pos => {
|
|
|
11869 |
const container = pos.container();
|
| 1441 |
ariadna |
11870 |
return isText$b(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
|
| 1 |
efrain |
11871 |
};
|
|
|
11872 |
const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome();
|
|
|
11873 |
const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block';
|
| 1441 |
ariadna |
11874 |
const isCefNode = node => isContentEditableFalse$b(node) && !isBogusAll(node);
|
| 1 |
efrain |
11875 |
const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
|
|
|
11876 |
const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
|
|
|
11877 |
const isBeforeMedia = matchesElementPosition(true, isMedia$2);
|
|
|
11878 |
const isAfterMedia = matchesElementPosition(false, isMedia$2);
|
|
|
11879 |
const isBeforeTable = matchesElementPosition(true, isTable$2);
|
|
|
11880 |
const isAfterTable = matchesElementPosition(false, isTable$2);
|
|
|
11881 |
const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
|
|
|
11882 |
const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
|
|
|
11883 |
|
|
|
11884 |
const dropLast = xs => xs.slice(0, -1);
|
|
|
11885 |
const parentsUntil = (start, root, predicate) => {
|
|
|
11886 |
if (contains(root, start)) {
|
|
|
11887 |
return dropLast(parents$1(start, elm => {
|
|
|
11888 |
return predicate(elm) || eq(elm, root);
|
|
|
11889 |
}));
|
|
|
11890 |
} else {
|
|
|
11891 |
return [];
|
|
|
11892 |
}
|
|
|
11893 |
};
|
|
|
11894 |
const parents = (start, root) => parentsUntil(start, root, never);
|
|
|
11895 |
const parentsAndSelf = (start, root) => [start].concat(parents(start, root));
|
|
|
11896 |
|
|
|
11897 |
const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText);
|
|
|
11898 |
const isBlock$1 = schema => el => schema.isBlock(name(el));
|
|
|
11899 |
const getClosestBlock$1 = (root, pos, schema) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$1(schema));
|
|
|
11900 |
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()))));
|
|
|
11901 |
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());
|
|
|
11902 |
const isAtStartOfBlock = curry(isAtBlockBoundary, false);
|
|
|
11903 |
const isAtEndOfBlock = curry(isAtBlockBoundary, true);
|
|
|
11904 |
const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
|
|
|
11905 |
const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
|
|
|
11906 |
|
|
|
11907 |
const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5);
|
|
|
11908 |
const findBr = (forward, root, pos, schema) => {
|
|
|
11909 |
const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
|
|
|
11910 |
const scope = head(parentBlocks).getOr(root);
|
|
|
11911 |
return fromPosition(forward, scope.dom, pos).filter(isBr$1);
|
|
|
11912 |
};
|
|
|
11913 |
const isBeforeBr$1 = (root, pos, schema) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos, schema).isSome();
|
|
|
11914 |
const isAfterBr = (root, pos, schema) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos, schema).isSome();
|
|
|
11915 |
const findPreviousBr = curry(findBr, false);
|
|
|
11916 |
const findNextBr = curry(findBr, true);
|
|
|
11917 |
|
|
|
11918 |
const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
|
|
|
11919 |
const getClosestBlock = (root, pos, schema) => {
|
|
|
11920 |
const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
|
|
|
11921 |
return head(parentBlocks).getOr(root);
|
|
|
11922 |
};
|
|
|
11923 |
const hasSpaceBefore = (root, pos, schema) => {
|
|
|
11924 |
if (isInMiddleOfText(pos)) {
|
|
|
11925 |
return isAfterSpace(pos);
|
|
|
11926 |
} else {
|
|
|
11927 |
return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isAfterSpace);
|
|
|
11928 |
}
|
|
|
11929 |
};
|
|
|
11930 |
const hasSpaceAfter = (root, pos, schema) => {
|
|
|
11931 |
if (isInMiddleOfText(pos)) {
|
|
|
11932 |
return isBeforeSpace(pos);
|
|
|
11933 |
} else {
|
|
|
11934 |
return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isBeforeSpace);
|
|
|
11935 |
}
|
|
|
11936 |
};
|
|
|
11937 |
const isPreValue = value => contains$2([
|
|
|
11938 |
'pre',
|
|
|
11939 |
'pre-wrap'
|
|
|
11940 |
], value);
|
|
|
11941 |
const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space')));
|
|
|
11942 |
const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
|
|
|
11943 |
const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
|
|
|
11944 |
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);
|
|
|
11945 |
const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node);
|
|
|
11946 |
const isSiblingCefBlock = (root, direction) => container => {
|
|
|
11947 |
return isCefBlock(new DomTreeWalker(container, root)[direction]());
|
|
|
11948 |
};
|
|
|
11949 |
const isBeforeCefBlock = (root, pos) => {
|
|
|
11950 |
const nextPos = nextPosition(root.dom, pos).getOr(pos);
|
|
|
11951 |
const isNextCefBlock = isSiblingCefBlock(root.dom, 'next');
|
|
|
11952 |
return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
|
|
|
11953 |
};
|
|
|
11954 |
const isAfterCefBlock = (root, pos) => {
|
|
|
11955 |
const prevPos = prevPosition(root.dom, pos).getOr(pos);
|
|
|
11956 |
const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev');
|
|
|
11957 |
return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container()));
|
|
|
11958 |
};
|
|
|
11959 |
const needsToHaveNbsp = (root, pos, schema) => {
|
|
|
11960 |
if (isInPre(pos)) {
|
|
|
11961 |
return false;
|
|
|
11962 |
} else {
|
|
|
11963 |
return isAtLineBoundary(root, pos, schema) || hasSpaceBefore(root, pos, schema) || hasSpaceAfter(root, pos, schema);
|
|
|
11964 |
}
|
|
|
11965 |
};
|
|
|
11966 |
const needsToBeNbspLeft = (root, pos, schema) => {
|
|
|
11967 |
if (isInPre(pos)) {
|
|
|
11968 |
return false;
|
|
|
11969 |
} else {
|
|
|
11970 |
return isAtStartOfBlock(root, pos, schema) || isBeforeBlock(root, pos, schema) || isAfterBr(root, pos, schema) || hasSpaceBefore(root, pos, schema) || isAfterCefBlock(root, pos);
|
|
|
11971 |
}
|
|
|
11972 |
};
|
|
|
11973 |
const leanRight = pos => {
|
|
|
11974 |
const container = pos.container();
|
|
|
11975 |
const offset = pos.offset();
|
| 1441 |
ariadna |
11976 |
if (isText$b(container) && offset < container.data.length) {
|
| 1 |
efrain |
11977 |
return CaretPosition(container, offset + 1);
|
|
|
11978 |
} else {
|
|
|
11979 |
return pos;
|
|
|
11980 |
}
|
|
|
11981 |
};
|
|
|
11982 |
const needsToBeNbspRight = (root, pos, schema) => {
|
|
|
11983 |
if (isInPre(pos)) {
|
|
|
11984 |
return false;
|
|
|
11985 |
} else {
|
|
|
11986 |
return isAtEndOfBlock(root, pos, schema) || isAfterBlock(root, pos, schema) || isBeforeBr$1(root, pos, schema) || hasSpaceAfter(root, pos, schema) || isBeforeCefBlock(root, pos);
|
|
|
11987 |
}
|
|
|
11988 |
};
|
|
|
11989 |
const needsToBeNbsp = (root, pos, schema) => needsToBeNbspLeft(root, pos, schema) || needsToBeNbspRight(root, leanRight(pos), schema);
|
|
|
11990 |
const isNbspAt = (text, offset) => isNbsp(text.charAt(offset));
|
|
|
11991 |
const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset));
|
|
|
11992 |
const hasNbsp = pos => {
|
|
|
11993 |
const container = pos.container();
|
| 1441 |
ariadna |
11994 |
return isText$b(container) && contains$1(container.data, nbsp);
|
| 1 |
efrain |
11995 |
};
|
|
|
11996 |
const normalizeNbspMiddle = text => {
|
|
|
11997 |
const chars = text.split('');
|
|
|
11998 |
return map$3(chars, (chr, i) => {
|
|
|
11999 |
if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
|
|
|
12000 |
return ' ';
|
|
|
12001 |
} else {
|
|
|
12002 |
return chr;
|
|
|
12003 |
}
|
|
|
12004 |
}).join('');
|
|
|
12005 |
};
|
|
|
12006 |
const normalizeNbspAtStart = (root, node, makeNbsp, schema) => {
|
|
|
12007 |
const text = node.data;
|
|
|
12008 |
const firstPos = CaretPosition(node, 0);
|
|
|
12009 |
if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos, schema)) {
|
|
|
12010 |
node.data = ' ' + text.slice(1);
|
|
|
12011 |
return true;
|
|
|
12012 |
} else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos, schema)) {
|
|
|
12013 |
node.data = nbsp + text.slice(1);
|
|
|
12014 |
return true;
|
|
|
12015 |
} else {
|
|
|
12016 |
return false;
|
|
|
12017 |
}
|
|
|
12018 |
};
|
|
|
12019 |
const normalizeNbspInMiddleOfTextNode = node => {
|
|
|
12020 |
const text = node.data;
|
|
|
12021 |
const newText = normalizeNbspMiddle(text);
|
|
|
12022 |
if (newText !== text) {
|
|
|
12023 |
node.data = newText;
|
|
|
12024 |
return true;
|
|
|
12025 |
} else {
|
|
|
12026 |
return false;
|
|
|
12027 |
}
|
|
|
12028 |
};
|
|
|
12029 |
const normalizeNbspAtEnd = (root, node, makeNbsp, schema) => {
|
|
|
12030 |
const text = node.data;
|
|
|
12031 |
const lastPos = CaretPosition(node, text.length - 1);
|
|
|
12032 |
if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos, schema)) {
|
|
|
12033 |
node.data = text.slice(0, -1) + ' ';
|
|
|
12034 |
return true;
|
|
|
12035 |
} else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos, schema)) {
|
|
|
12036 |
node.data = text.slice(0, -1) + nbsp;
|
|
|
12037 |
return true;
|
|
|
12038 |
} else {
|
|
|
12039 |
return false;
|
|
|
12040 |
}
|
|
|
12041 |
};
|
| 1441 |
ariadna |
12042 |
const normalizeNbsps$1 = (root, pos, schema) => {
|
| 1 |
efrain |
12043 |
const container = pos.container();
|
| 1441 |
ariadna |
12044 |
if (!isText$b(container)) {
|
| 1 |
efrain |
12045 |
return Optional.none();
|
|
|
12046 |
}
|
|
|
12047 |
if (hasNbsp(pos)) {
|
|
|
12048 |
const normalized = normalizeNbspAtStart(root, container, false, schema) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false, schema);
|
|
|
12049 |
return someIf(normalized, pos);
|
|
|
12050 |
} else if (needsToBeNbsp(root, pos, schema)) {
|
|
|
12051 |
const normalized = normalizeNbspAtStart(root, container, true, schema) || normalizeNbspAtEnd(root, container, true, schema);
|
|
|
12052 |
return someIf(normalized, pos);
|
|
|
12053 |
} else {
|
|
|
12054 |
return Optional.none();
|
|
|
12055 |
}
|
|
|
12056 |
};
|
|
|
12057 |
const normalizeNbspsInEditor = editor => {
|
|
|
12058 |
const root = SugarElement.fromDom(editor.getBody());
|
|
|
12059 |
if (editor.selection.isCollapsed()) {
|
| 1441 |
ariadna |
12060 |
normalizeNbsps$1(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
|
| 1 |
efrain |
12061 |
editor.selection.setRng(pos.toRange());
|
|
|
12062 |
});
|
|
|
12063 |
}
|
|
|
12064 |
};
|
|
|
12065 |
|
|
|
12066 |
const normalize$1 = (node, offset, count, schema) => {
|
|
|
12067 |
if (count === 0) {
|
|
|
12068 |
return;
|
|
|
12069 |
}
|
|
|
12070 |
const elm = SugarElement.fromDom(node);
|
|
|
12071 |
const root = ancestor$4(elm, el => schema.isBlock(name(el))).getOr(elm);
|
|
|
12072 |
const whitespace = node.data.slice(offset, offset + count);
|
|
|
12073 |
const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length), schema);
|
|
|
12074 |
const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0), schema);
|
|
|
12075 |
node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
|
|
|
12076 |
};
|
|
|
12077 |
const normalizeWhitespaceAfter = (node, offset, schema) => {
|
|
|
12078 |
const content = node.data.slice(offset);
|
|
|
12079 |
const whitespaceCount = content.length - lTrim(content).length;
|
|
|
12080 |
normalize$1(node, offset, whitespaceCount, schema);
|
|
|
12081 |
};
|
|
|
12082 |
const normalizeWhitespaceBefore = (node, offset, schema) => {
|
|
|
12083 |
const content = node.data.slice(0, offset);
|
|
|
12084 |
const whitespaceCount = content.length - rTrim(content).length;
|
|
|
12085 |
normalize$1(node, offset - whitespaceCount, whitespaceCount, schema);
|
|
|
12086 |
};
|
|
|
12087 |
const mergeTextNodes = (prevNode, nextNode, schema, normalizeWhitespace, mergeToPrev = true) => {
|
|
|
12088 |
const whitespaceOffset = rTrim(prevNode.data).length;
|
|
|
12089 |
const newNode = mergeToPrev ? prevNode : nextNode;
|
|
|
12090 |
const removeNode = mergeToPrev ? nextNode : prevNode;
|
|
|
12091 |
if (mergeToPrev) {
|
|
|
12092 |
newNode.appendData(removeNode.data);
|
|
|
12093 |
} else {
|
|
|
12094 |
newNode.insertData(0, removeNode.data);
|
|
|
12095 |
}
|
| 1441 |
ariadna |
12096 |
remove$4(SugarElement.fromDom(removeNode));
|
| 1 |
efrain |
12097 |
if (normalizeWhitespace) {
|
|
|
12098 |
normalizeWhitespaceAfter(newNode, whitespaceOffset, schema);
|
|
|
12099 |
}
|
|
|
12100 |
return newNode;
|
|
|
12101 |
};
|
|
|
12102 |
|
|
|
12103 |
const needsReposition = (pos, elm) => {
|
|
|
12104 |
const container = pos.container();
|
|
|
12105 |
const offset = pos.offset();
|
|
|
12106 |
return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
|
|
|
12107 |
};
|
|
|
12108 |
const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
|
| 1441 |
ariadna |
12109 |
const beforeOrStartOf = node => isText$b(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
|
|
|
12110 |
const afterOrEndOf = node => isText$b(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
|
| 1 |
efrain |
12111 |
const getPreviousSiblingCaretPosition = elm => {
|
|
|
12112 |
if (isCaretCandidate$3(elm.previousSibling)) {
|
|
|
12113 |
return Optional.some(afterOrEndOf(elm.previousSibling));
|
|
|
12114 |
} else {
|
|
|
12115 |
return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
|
|
|
12116 |
}
|
|
|
12117 |
};
|
|
|
12118 |
const getNextSiblingCaretPosition = elm => {
|
|
|
12119 |
if (isCaretCandidate$3(elm.nextSibling)) {
|
|
|
12120 |
return Optional.some(beforeOrStartOf(elm.nextSibling));
|
|
|
12121 |
} else {
|
|
|
12122 |
return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
|
|
|
12123 |
}
|
|
|
12124 |
};
|
|
|
12125 |
const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
|
|
|
12126 |
return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm)));
|
|
|
12127 |
};
|
|
|
12128 |
const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm)));
|
|
|
12129 |
const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
|
|
|
12130 |
const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
|
|
|
12131 |
const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
|
|
|
12132 |
const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
|
|
|
12133 |
const setSelection$1 = (editor, forward, pos) => {
|
|
|
12134 |
pos.fold(() => {
|
|
|
12135 |
editor.focus();
|
|
|
12136 |
}, pos => {
|
|
|
12137 |
editor.selection.setRng(pos.toRange(), forward);
|
|
|
12138 |
});
|
|
|
12139 |
};
|
|
|
12140 |
const eqRawNode = rawNode => elm => elm.dom === rawNode;
|
|
|
12141 |
const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
|
| 1441 |
ariadna |
12142 |
const paddEmptyBlock = (schema, elm, preserveEmptyCaret) => {
|
|
|
12143 |
if (isEmpty$2(schema, elm)) {
|
| 1 |
efrain |
12144 |
const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
|
|
|
12145 |
if (preserveEmptyCaret) {
|
|
|
12146 |
each$e(children$1(elm), node => {
|
|
|
12147 |
if (!isEmptyCaretFormatElement(node)) {
|
| 1441 |
ariadna |
12148 |
remove$4(node);
|
| 1 |
efrain |
12149 |
}
|
|
|
12150 |
});
|
|
|
12151 |
} else {
|
|
|
12152 |
empty(elm);
|
|
|
12153 |
}
|
|
|
12154 |
append$1(elm, br);
|
|
|
12155 |
return Optional.some(CaretPosition.before(br.dom));
|
|
|
12156 |
} else {
|
|
|
12157 |
return Optional.none();
|
|
|
12158 |
}
|
|
|
12159 |
};
|
|
|
12160 |
const deleteNormalized = (elm, afterDeletePosOpt, schema, normalizeWhitespace) => {
|
| 1441 |
ariadna |
12161 |
const prevTextOpt = prevSibling(elm).filter(isText$c);
|
|
|
12162 |
const nextTextOpt = nextSibling(elm).filter(isText$c);
|
|
|
12163 |
remove$4(elm);
|
| 1 |
efrain |
12164 |
return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => {
|
|
|
12165 |
const prevNode = prev.dom, nextNode = next.dom;
|
|
|
12166 |
const offset = prevNode.data.length;
|
|
|
12167 |
mergeTextNodes(prevNode, nextNode, schema, normalizeWhitespace);
|
|
|
12168 |
return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
|
|
|
12169 |
}).orThunk(() => {
|
|
|
12170 |
if (normalizeWhitespace) {
|
|
|
12171 |
prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length, schema));
|
|
|
12172 |
nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0, schema));
|
|
|
12173 |
}
|
|
|
12174 |
return afterDeletePosOpt;
|
|
|
12175 |
});
|
|
|
12176 |
};
|
|
|
12177 |
const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
|
|
|
12178 |
const deleteElement$2 = (editor, forward, elm, moveCaret = true, preserveEmptyCaret = false) => {
|
|
|
12179 |
const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
|
|
|
12180 |
const parentBlock = ancestor$4(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
|
|
|
12181 |
const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, editor.schema, isInlineElement(editor, elm));
|
|
|
12182 |
if (editor.dom.isEmpty(editor.getBody())) {
|
|
|
12183 |
editor.setContent('');
|
|
|
12184 |
editor.selection.setCursorLocation();
|
|
|
12185 |
} else {
|
| 1441 |
ariadna |
12186 |
parentBlock.bind(elm => paddEmptyBlock(editor.schema, elm, preserveEmptyCaret)).fold(() => {
|
| 1 |
efrain |
12187 |
if (moveCaret) {
|
|
|
12188 |
setSelection$1(editor, forward, normalizedAfterDeletePos);
|
|
|
12189 |
}
|
|
|
12190 |
}, paddPos => {
|
|
|
12191 |
if (moveCaret) {
|
|
|
12192 |
setSelection$1(editor, forward, Optional.some(paddPos));
|
|
|
12193 |
}
|
|
|
12194 |
});
|
|
|
12195 |
}
|
|
|
12196 |
};
|
|
|
12197 |
|
|
|
12198 |
const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
|
|
|
12199 |
const hasStrongRtl = text => strongRtl.test(text);
|
|
|
12200 |
|
|
|
12201 |
const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm) && editor.dom.isEditable(elm);
|
|
|
12202 |
const isRtl = element => {
|
|
|
12203 |
var _a;
|
|
|
12204 |
return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : '');
|
|
|
12205 |
};
|
|
|
12206 |
const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
|
|
|
12207 |
const findRootInline = (isInlineTarget, rootNode, pos) => {
|
|
|
12208 |
const parents = findInlineParents(isInlineTarget, rootNode, pos);
|
|
|
12209 |
return Optional.from(parents[parents.length - 1]);
|
|
|
12210 |
};
|
|
|
12211 |
const hasSameParentBlock = (rootNode, node1, node2) => {
|
|
|
12212 |
const block1 = getParentBlock$3(node1, rootNode);
|
|
|
12213 |
const block2 = getParentBlock$3(node2, rootNode);
|
|
|
12214 |
return isNonNullable(block1) && block1 === block2;
|
|
|
12215 |
};
|
|
|
12216 |
const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos);
|
|
|
12217 |
const normalizePosition = (forward, pos) => {
|
|
|
12218 |
const container = pos.container(), offset = pos.offset();
|
|
|
12219 |
if (forward) {
|
|
|
12220 |
if (isCaretContainerInline(container)) {
|
| 1441 |
ariadna |
12221 |
if (isText$b(container.nextSibling)) {
|
| 1 |
efrain |
12222 |
return CaretPosition(container.nextSibling, 0);
|
|
|
12223 |
} else {
|
|
|
12224 |
return CaretPosition.after(container);
|
|
|
12225 |
}
|
|
|
12226 |
} else {
|
|
|
12227 |
return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
|
|
|
12228 |
}
|
|
|
12229 |
} else {
|
|
|
12230 |
if (isCaretContainerInline(container)) {
|
| 1441 |
ariadna |
12231 |
if (isText$b(container.previousSibling)) {
|
| 1 |
efrain |
12232 |
return CaretPosition(container.previousSibling, container.previousSibling.data.length);
|
|
|
12233 |
} else {
|
|
|
12234 |
return CaretPosition.before(container);
|
|
|
12235 |
}
|
|
|
12236 |
} else {
|
|
|
12237 |
return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
|
|
|
12238 |
}
|
|
|
12239 |
}
|
|
|
12240 |
};
|
|
|
12241 |
const normalizeForwards = curry(normalizePosition, true);
|
|
|
12242 |
const normalizeBackwards = curry(normalizePosition, false);
|
|
|
12243 |
|
|
|
12244 |
const execCommandIgnoreInputEvents = (editor, command) => {
|
|
|
12245 |
const inputBlocker = e => e.stopImmediatePropagation();
|
|
|
12246 |
editor.on('beforeinput input', inputBlocker, true);
|
|
|
12247 |
editor.getDoc().execCommand(command);
|
|
|
12248 |
editor.off('beforeinput input', inputBlocker);
|
|
|
12249 |
};
|
|
|
12250 |
const execEditorDeleteCommand = editor => {
|
|
|
12251 |
editor.execCommand('delete');
|
|
|
12252 |
};
|
|
|
12253 |
const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete');
|
|
|
12254 |
const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete');
|
|
|
12255 |
const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq);
|
|
|
12256 |
const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element);
|
|
|
12257 |
const getParentBlock$2 = (rootNode, elm) => {
|
|
|
12258 |
if (contains(rootNode, elm)) {
|
|
|
12259 |
return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
|
|
|
12260 |
} else {
|
|
|
12261 |
return Optional.none();
|
|
|
12262 |
}
|
|
|
12263 |
};
|
|
|
12264 |
const paddEmptyBody = (editor, moveSelection = true) => {
|
|
|
12265 |
if (editor.dom.isEmpty(editor.getBody())) {
|
|
|
12266 |
editor.setContent('', { no_selection: !moveSelection });
|
|
|
12267 |
}
|
|
|
12268 |
};
|
|
|
12269 |
const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
|
|
|
12270 |
const normalizedFirstPos = normalizePosition(true, firstPos);
|
|
|
12271 |
const normalizedLastPos = normalizePosition(false, lastPos);
|
|
|
12272 |
const normalizedFromPos = normalizePosition(false, fromPos);
|
|
|
12273 |
if (forward) {
|
|
|
12274 |
return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
|
|
|
12275 |
} else {
|
|
|
12276 |
return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
|
|
|
12277 |
}
|
|
|
12278 |
}).getOr(true);
|
|
|
12279 |
const freefallRtl = root => {
|
|
|
12280 |
const child = isComment$1(root) ? prevSibling(root) : lastChild(root);
|
|
|
12281 |
return child.bind(freefallRtl).orThunk(() => Optional.some(root));
|
|
|
12282 |
};
|
|
|
12283 |
const deleteRangeContents = (editor, rng, root, moveSelection = true) => {
|
|
|
12284 |
var _a;
|
|
|
12285 |
rng.deleteContents();
|
|
|
12286 |
const lastNode = freefallRtl(root).getOr(root);
|
|
|
12287 |
const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom);
|
|
|
12288 |
if (lastBlock.dom === editor.getBody()) {
|
|
|
12289 |
paddEmptyBody(editor, moveSelection);
|
| 1441 |
ariadna |
12290 |
} else if (isEmpty$2(editor.schema, lastBlock, { checkRootAsContent: false })) {
|
| 1 |
efrain |
12291 |
fillWithPaddingBr(lastBlock);
|
|
|
12292 |
if (moveSelection) {
|
|
|
12293 |
editor.selection.setCursorLocation(lastBlock.dom, 0);
|
|
|
12294 |
}
|
|
|
12295 |
}
|
|
|
12296 |
if (!eq(root, lastBlock)) {
|
|
|
12297 |
const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
|
|
|
12298 |
each$e(additionalCleanupNodes.concat(children$1(root)), node => {
|
| 1441 |
ariadna |
12299 |
if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(editor.schema, node)) {
|
|
|
12300 |
remove$4(node);
|
| 1 |
efrain |
12301 |
}
|
|
|
12302 |
});
|
|
|
12303 |
}
|
|
|
12304 |
};
|
|
|
12305 |
|
|
|
12306 |
const isRootFromElement = root => cur => eq(root, cur);
|
|
|
12307 |
const getTableCells = table => descendants(table, 'td,th');
|
|
|
12308 |
const getTable$1 = (node, isRoot) => getClosestTable(SugarElement.fromDom(node), isRoot);
|
|
|
12309 |
const selectionInTableWithNestedTable = details => {
|
|
|
12310 |
return lift2(details.startTable, details.endTable, (startTable, endTable) => {
|
|
|
12311 |
const isStartTableParentOfEndTable = descendant(startTable, t => eq(t, endTable));
|
|
|
12312 |
const isEndTableParentOfStartTable = descendant(endTable, t => eq(t, startTable));
|
|
|
12313 |
return !isStartTableParentOfEndTable && !isEndTableParentOfStartTable ? details : {
|
|
|
12314 |
...details,
|
|
|
12315 |
startTable: isStartTableParentOfEndTable ? Optional.none() : details.startTable,
|
|
|
12316 |
endTable: isEndTableParentOfStartTable ? Optional.none() : details.endTable,
|
|
|
12317 |
isSameTable: false,
|
|
|
12318 |
isMultiTable: false
|
|
|
12319 |
};
|
|
|
12320 |
}).getOr(details);
|
|
|
12321 |
};
|
|
|
12322 |
const adjustQuirksInDetails = details => {
|
|
|
12323 |
return selectionInTableWithNestedTable(details);
|
|
|
12324 |
};
|
|
|
12325 |
const getTableDetailsFromRange = (rng, isRoot) => {
|
|
|
12326 |
const startTable = getTable$1(rng.startContainer, isRoot);
|
|
|
12327 |
const endTable = getTable$1(rng.endContainer, isRoot);
|
|
|
12328 |
const isStartInTable = startTable.isSome();
|
|
|
12329 |
const isEndInTable = endTable.isSome();
|
|
|
12330 |
const isSameTable = lift2(startTable, endTable, eq).getOr(false);
|
|
|
12331 |
const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
|
|
|
12332 |
return adjustQuirksInDetails({
|
|
|
12333 |
startTable,
|
|
|
12334 |
endTable,
|
|
|
12335 |
isStartInTable,
|
|
|
12336 |
isEndInTable,
|
|
|
12337 |
isSameTable,
|
|
|
12338 |
isMultiTable
|
|
|
12339 |
});
|
|
|
12340 |
};
|
|
|
12341 |
|
|
|
12342 |
const tableCellRng = (start, end) => ({
|
|
|
12343 |
start,
|
|
|
12344 |
end
|
|
|
12345 |
});
|
|
|
12346 |
const tableSelection = (rng, table, cells) => ({
|
|
|
12347 |
rng,
|
|
|
12348 |
table,
|
|
|
12349 |
cells
|
|
|
12350 |
});
|
|
|
12351 |
const deleteAction = Adt.generate([
|
|
|
12352 |
{
|
|
|
12353 |
singleCellTable: [
|
|
|
12354 |
'rng',
|
|
|
12355 |
'cell'
|
|
|
12356 |
]
|
|
|
12357 |
},
|
|
|
12358 |
{ fullTable: ['table'] },
|
|
|
12359 |
{
|
|
|
12360 |
partialTable: [
|
|
|
12361 |
'cells',
|
|
|
12362 |
'outsideDetails'
|
|
|
12363 |
]
|
|
|
12364 |
},
|
|
|
12365 |
{
|
|
|
12366 |
multiTable: [
|
|
|
12367 |
'startTableCells',
|
|
|
12368 |
'endTableCells',
|
|
|
12369 |
'betweenRng'
|
|
|
12370 |
]
|
|
|
12371 |
}
|
|
|
12372 |
]);
|
|
|
12373 |
const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
|
|
|
12374 |
const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end);
|
|
|
12375 |
const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable)));
|
|
|
12376 |
const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => {
|
|
|
12377 |
const rows = table.dom.rows;
|
|
|
12378 |
return rows.length === 1 && rows[0].cells.length === 1;
|
|
|
12379 |
});
|
|
|
12380 |
const getCellRng = (rng, isRoot) => {
|
|
|
12381 |
const startCell = getClosestCell$1(rng.startContainer, isRoot);
|
|
|
12382 |
const endCell = getClosestCell$1(rng.endContainer, isRoot);
|
|
|
12383 |
return lift2(startCell, endCell, tableCellRng);
|
|
|
12384 |
};
|
| 1441 |
ariadna |
12385 |
const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$2(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell)));
|
| 1 |
efrain |
12386 |
const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell)));
|
|
|
12387 |
const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table)));
|
|
|
12388 |
const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => {
|
|
|
12389 |
if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
|
|
|
12390 |
return Optional.none();
|
|
|
12391 |
} else if (selectionDetails.isSameTable) {
|
|
|
12392 |
const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot));
|
|
|
12393 |
return Optional.some({
|
|
|
12394 |
start: sameTableSelection,
|
|
|
12395 |
end: sameTableSelection
|
|
|
12396 |
});
|
|
|
12397 |
} else {
|
|
|
12398 |
const startCell = getClosestCell$1(rng.startContainer, isRoot);
|
|
|
12399 |
const endCell = getClosestCell$1(rng.endContainer, isRoot);
|
|
|
12400 |
const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
|
|
|
12401 |
const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
|
|
|
12402 |
return Optional.some({
|
|
|
12403 |
start: startTableSelection,
|
|
|
12404 |
end: endTableSelection
|
|
|
12405 |
});
|
|
|
12406 |
}
|
|
|
12407 |
};
|
|
|
12408 |
const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell));
|
|
|
12409 |
const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1));
|
|
|
12410 |
const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng));
|
|
|
12411 |
const unselectCells = (rng, selectionDetails) => {
|
|
|
12412 |
const {startTable, endTable} = selectionDetails;
|
|
|
12413 |
const otherContentRng = rng.cloneRange();
|
|
|
12414 |
startTable.each(table => otherContentRng.setStartAfter(table.dom));
|
|
|
12415 |
endTable.each(table => otherContentRng.setEndBefore(table.dom));
|
|
|
12416 |
return otherContentRng;
|
|
|
12417 |
};
|
|
|
12418 |
const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => {
|
|
|
12419 |
const {isSameTable} = selectionDetails;
|
|
|
12420 |
const selectedCells = getSelectedCells(tableSelection).getOr([]);
|
|
|
12421 |
if (isSameTable && tableSelection.cells.length === selectedCells.length) {
|
|
|
12422 |
return Optional.some(deleteAction.fullTable(tableSelection.table));
|
|
|
12423 |
} else if (selectedCells.length > 0) {
|
|
|
12424 |
if (isSameTable) {
|
|
|
12425 |
return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
|
|
|
12426 |
} else {
|
|
|
12427 |
const otherContentRng = unselectCells(rng, selectionDetails);
|
|
|
12428 |
return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
|
|
|
12429 |
...selectionDetails,
|
|
|
12430 |
rng: otherContentRng
|
|
|
12431 |
})));
|
|
|
12432 |
}
|
|
|
12433 |
} else {
|
|
|
12434 |
return Optional.none();
|
|
|
12435 |
}
|
|
|
12436 |
});
|
|
|
12437 |
const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => {
|
|
|
12438 |
const startTableSelectedCells = start.bind(getSelectedCells).getOr([]);
|
|
|
12439 |
const endTableSelectedCells = end.bind(getSelectedCells).getOr([]);
|
|
|
12440 |
if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
|
|
|
12441 |
const otherContentRng = unselectCells(rng, selectionDetails);
|
|
|
12442 |
return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
|
|
|
12443 |
} else {
|
|
|
12444 |
return Optional.none();
|
|
|
12445 |
}
|
|
|
12446 |
});
|
|
|
12447 |
const getActionFromRange = (root, rng) => {
|
|
|
12448 |
const isRoot = isRootFromElement(root);
|
|
|
12449 |
const optCellRng = getCellRng(rng, isRoot);
|
|
|
12450 |
const selectionDetails = getTableDetailsFromRange(rng, isRoot);
|
|
|
12451 |
if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) {
|
|
|
12452 |
return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start));
|
|
|
12453 |
} else if (selectionDetails.isMultiTable) {
|
|
|
12454 |
return handleMultiTable(optCellRng, selectionDetails, rng, isRoot);
|
|
|
12455 |
} else {
|
|
|
12456 |
return handleSingleTable(optCellRng, selectionDetails, rng, isRoot);
|
|
|
12457 |
}
|
|
|
12458 |
};
|
|
|
12459 |
|
|
|
12460 |
const cleanCells = cells => each$e(cells, cell => {
|
| 1441 |
ariadna |
12461 |
remove$9(cell, 'contenteditable');
|
| 1 |
efrain |
12462 |
fillWithPaddingBr(cell);
|
|
|
12463 |
});
|
|
|
12464 |
const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
|
|
|
12465 |
const handleEmptyBlock = (editor, startInTable, emptyBlock) => {
|
|
|
12466 |
emptyBlock.each(block => {
|
|
|
12467 |
if (startInTable) {
|
| 1441 |
ariadna |
12468 |
remove$4(block);
|
| 1 |
efrain |
12469 |
} else {
|
|
|
12470 |
fillWithPaddingBr(block);
|
|
|
12471 |
editor.selection.setCursorLocation(block.dom, 0);
|
|
|
12472 |
}
|
|
|
12473 |
});
|
|
|
12474 |
};
|
|
|
12475 |
const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => {
|
|
|
12476 |
const insideTableRng = rng.cloneRange();
|
|
|
12477 |
if (isFirstCellInSelection) {
|
|
|
12478 |
insideTableRng.setStart(rng.startContainer, rng.startOffset);
|
|
|
12479 |
insideTableRng.setEndAfter(cell.dom.lastChild);
|
|
|
12480 |
} else {
|
|
|
12481 |
insideTableRng.setStartBefore(cell.dom.firstChild);
|
|
|
12482 |
insideTableRng.setEnd(rng.endContainer, rng.endOffset);
|
|
|
12483 |
}
|
|
|
12484 |
deleteCellContents(editor, insideTableRng, cell, false).each(action => action());
|
|
|
12485 |
};
|
|
|
12486 |
const collapseAndRestoreCellSelection = editor => {
|
|
|
12487 |
const selectedCells = getCellsFromEditor(editor);
|
|
|
12488 |
const selectedNode = SugarElement.fromDom(editor.selection.getNode());
|
| 1441 |
ariadna |
12489 |
if (isTableCell$3(selectedNode.dom) && isEmpty$2(editor.schema, selectedNode)) {
|
| 1 |
efrain |
12490 |
editor.selection.setCursorLocation(selectedNode.dom, 0);
|
|
|
12491 |
} else {
|
|
|
12492 |
editor.selection.collapse(true);
|
|
|
12493 |
}
|
|
|
12494 |
if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) {
|
| 1441 |
ariadna |
12495 |
set$4(selectedNode, 'data-mce-selected', '1');
|
| 1 |
efrain |
12496 |
}
|
|
|
12497 |
};
|
|
|
12498 |
const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => {
|
|
|
12499 |
const editorRng = editor.selection.getRng();
|
|
|
12500 |
const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => {
|
|
|
12501 |
const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
|
|
|
12502 |
rng.deleteContents();
|
| 1441 |
ariadna |
12503 |
handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(curry(isEmpty$2, editor.schema)));
|
| 1 |
efrain |
12504 |
const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1];
|
|
|
12505 |
deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
|
| 1441 |
ariadna |
12506 |
if (!isEmpty$2(editor.schema, endPointCell)) {
|
| 1 |
efrain |
12507 |
return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1));
|
|
|
12508 |
} else {
|
|
|
12509 |
return Optional.none();
|
|
|
12510 |
}
|
|
|
12511 |
}).getOr(cells);
|
|
|
12512 |
cleanCells(cellsToClean);
|
|
|
12513 |
collapseAndRestoreCellSelection(editor);
|
|
|
12514 |
});
|
|
|
12515 |
const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
|
|
|
12516 |
const rng = editor.selection.getRng();
|
|
|
12517 |
const startCell = startTableCells[0];
|
|
|
12518 |
const endCell = endTableCells[endTableCells.length - 1];
|
|
|
12519 |
deleteContentInsideCell(editor, startCell, rng, true);
|
|
|
12520 |
deleteContentInsideCell(editor, endCell, rng, false);
|
| 1441 |
ariadna |
12521 |
const startTableCellsToClean = isEmpty$2(editor.schema, startCell) ? startTableCells : startTableCells.slice(1);
|
|
|
12522 |
const endTableCellsToClean = isEmpty$2(editor.schema, endCell) ? endTableCells : endTableCells.slice(0, -1);
|
| 1 |
efrain |
12523 |
cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
|
|
|
12524 |
betweenRng.deleteContents();
|
|
|
12525 |
collapseAndRestoreCellSelection(editor);
|
|
|
12526 |
});
|
|
|
12527 |
const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => {
|
|
|
12528 |
deleteRangeContents(editor, rng, cell, moveSelection);
|
|
|
12529 |
});
|
|
|
12530 |
const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table));
|
|
|
12531 |
const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
|
|
|
12532 |
const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
|
|
|
12533 |
const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption));
|
|
|
12534 |
const deleteRange$3 = (editor, startElm, selectedCells) => {
|
|
|
12535 |
const rootNode = SugarElement.fromDom(editor.getBody());
|
|
|
12536 |
const rng = editor.selection.getRng();
|
|
|
12537 |
return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
|
|
|
12538 |
};
|
|
|
12539 |
const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2);
|
|
|
12540 |
const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption'));
|
|
|
12541 |
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)));
|
|
|
12542 |
const emptyElement = (editor, elm) => Optional.some(() => {
|
|
|
12543 |
fillWithPaddingBr(elm);
|
|
|
12544 |
editor.selection.setCursorLocation(elm.dom, 0);
|
|
|
12545 |
});
|
|
|
12546 |
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);
|
|
|
12547 |
const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
|
|
|
12548 |
const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop));
|
|
|
12549 |
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));
|
|
|
12550 |
const deleteCaretCells = (editor, forward, rootElm, startElm) => {
|
|
|
12551 |
const from = CaretPosition.fromRangeStart(editor.selection.getRng());
|
| 1441 |
ariadna |
12552 |
return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(editor.schema, fromCell, { checkRootAsContent: false }) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from));
|
| 1 |
efrain |
12553 |
};
|
|
|
12554 |
const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
|
|
|
12555 |
const from = CaretPosition.fromRangeStart(editor.selection.getRng());
|
| 1441 |
ariadna |
12556 |
return isEmpty$2(editor.schema, fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
|
| 1 |
efrain |
12557 |
};
|
|
|
12558 |
const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
|
|
|
12559 |
const isBeforeOrAfterTable = (editor, forward) => {
|
|
|
12560 |
const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
12561 |
return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos));
|
|
|
12562 |
};
|
|
|
12563 |
const deleteCaret$3 = (editor, forward, startElm) => {
|
|
|
12564 |
const rootElm = SugarElement.fromDom(editor.getBody());
|
|
|
12565 |
return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption));
|
|
|
12566 |
};
|
| 1441 |
ariadna |
12567 |
const backspaceDelete$b = (editor, forward) => {
|
| 1 |
efrain |
12568 |
const startElm = SugarElement.fromDom(editor.selection.getStart(true));
|
|
|
12569 |
const cells = getCellsFromEditor(editor);
|
|
|
12570 |
return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$3(editor, startElm, cells);
|
|
|
12571 |
};
|
|
|
12572 |
|
|
|
12573 |
const getContentEditableRoot$1 = (root, node) => {
|
|
|
12574 |
let tempNode = node;
|
|
|
12575 |
while (tempNode && tempNode !== root) {
|
|
|
12576 |
if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$b(tempNode)) {
|
|
|
12577 |
return tempNode;
|
|
|
12578 |
}
|
|
|
12579 |
tempNode = tempNode.parentNode;
|
|
|
12580 |
}
|
|
|
12581 |
return null;
|
|
|
12582 |
};
|
|
|
12583 |
|
|
|
12584 |
const internalAttributesPrefixes = [
|
|
|
12585 |
'data-ephox-',
|
|
|
12586 |
'data-mce-',
|
|
|
12587 |
'data-alloy-',
|
|
|
12588 |
'data-snooker-',
|
|
|
12589 |
'_'
|
|
|
12590 |
];
|
|
|
12591 |
const each$9 = Tools.each;
|
|
|
12592 |
const ElementUtils = editor => {
|
|
|
12593 |
const dom = editor.dom;
|
|
|
12594 |
const internalAttributes = new Set(editor.serializer.getTempAttrs());
|
|
|
12595 |
const compare = (node1, node2) => {
|
|
|
12596 |
if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) {
|
|
|
12597 |
return false;
|
|
|
12598 |
}
|
|
|
12599 |
const getAttribs = node => {
|
|
|
12600 |
const attribs = {};
|
|
|
12601 |
each$9(dom.getAttribs(node), attr => {
|
|
|
12602 |
const name = attr.nodeName.toLowerCase();
|
|
|
12603 |
if (name !== 'style' && !isAttributeInternal(name)) {
|
|
|
12604 |
attribs[name] = dom.getAttrib(node, name);
|
|
|
12605 |
}
|
|
|
12606 |
});
|
|
|
12607 |
return attribs;
|
|
|
12608 |
};
|
|
|
12609 |
const compareObjects = (obj1, obj2) => {
|
|
|
12610 |
for (const name in obj1) {
|
|
|
12611 |
if (has$2(obj1, name)) {
|
|
|
12612 |
const value = obj2[name];
|
|
|
12613 |
if (isUndefined(value)) {
|
|
|
12614 |
return false;
|
|
|
12615 |
}
|
|
|
12616 |
if (obj1[name] !== value) {
|
|
|
12617 |
return false;
|
|
|
12618 |
}
|
|
|
12619 |
delete obj2[name];
|
|
|
12620 |
}
|
|
|
12621 |
}
|
|
|
12622 |
for (const name in obj2) {
|
|
|
12623 |
if (has$2(obj2, name)) {
|
|
|
12624 |
return false;
|
|
|
12625 |
}
|
|
|
12626 |
}
|
|
|
12627 |
return true;
|
|
|
12628 |
};
|
|
|
12629 |
if (isElement$6(node1) && isElement$6(node2)) {
|
|
|
12630 |
if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
|
|
|
12631 |
return false;
|
|
|
12632 |
}
|
|
|
12633 |
if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
|
|
|
12634 |
return false;
|
|
|
12635 |
}
|
|
|
12636 |
}
|
|
|
12637 |
return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
|
|
|
12638 |
};
|
|
|
12639 |
const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName);
|
|
|
12640 |
return {
|
|
|
12641 |
compare,
|
|
|
12642 |
isAttributeInternal
|
|
|
12643 |
};
|
|
|
12644 |
};
|
|
|
12645 |
|
|
|
12646 |
const isHeading = node => [
|
|
|
12647 |
'h1',
|
|
|
12648 |
'h2',
|
|
|
12649 |
'h3',
|
|
|
12650 |
'h4',
|
|
|
12651 |
'h5',
|
|
|
12652 |
'h6'
|
|
|
12653 |
].includes(node.name);
|
|
|
12654 |
const isSummary = node => node.name === 'summary';
|
|
|
12655 |
|
|
|
12656 |
const traverse = (root, fn) => {
|
|
|
12657 |
let node = root;
|
|
|
12658 |
while (node = node.walk()) {
|
|
|
12659 |
fn(node);
|
|
|
12660 |
}
|
|
|
12661 |
};
|
|
|
12662 |
const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
|
|
|
12663 |
const name = node.name;
|
|
|
12664 |
for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
|
|
|
12665 |
const filter = nodeFilters[ni];
|
|
|
12666 |
if (filter.name === name) {
|
|
|
12667 |
const match = matches.nodes[name];
|
|
|
12668 |
if (match) {
|
|
|
12669 |
match.nodes.push(node);
|
|
|
12670 |
} else {
|
|
|
12671 |
matches.nodes[name] = {
|
|
|
12672 |
filter,
|
|
|
12673 |
nodes: [node]
|
|
|
12674 |
};
|
|
|
12675 |
}
|
|
|
12676 |
}
|
|
|
12677 |
}
|
|
|
12678 |
if (node.attributes) {
|
|
|
12679 |
for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
|
|
|
12680 |
const filter = attributeFilters[ai];
|
|
|
12681 |
const attrName = filter.name;
|
|
|
12682 |
if (attrName in node.attributes.map) {
|
|
|
12683 |
const match = matches.attributes[attrName];
|
|
|
12684 |
if (match) {
|
|
|
12685 |
match.nodes.push(node);
|
|
|
12686 |
} else {
|
|
|
12687 |
matches.attributes[attrName] = {
|
|
|
12688 |
filter,
|
|
|
12689 |
nodes: [node]
|
|
|
12690 |
};
|
|
|
12691 |
}
|
|
|
12692 |
}
|
|
|
12693 |
}
|
|
|
12694 |
}
|
|
|
12695 |
};
|
|
|
12696 |
const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
|
|
|
12697 |
const matches = {
|
|
|
12698 |
nodes: {},
|
|
|
12699 |
attributes: {}
|
|
|
12700 |
};
|
|
|
12701 |
if (node.firstChild) {
|
|
|
12702 |
traverse(node, childNode => {
|
|
|
12703 |
matchNode$1(nodeFilters, attributeFilters, childNode, matches);
|
|
|
12704 |
});
|
|
|
12705 |
}
|
|
|
12706 |
return matches;
|
|
|
12707 |
};
|
|
|
12708 |
const runFilters = (matches, args) => {
|
|
|
12709 |
const run = (matchRecord, filteringAttributes) => {
|
|
|
12710 |
each$d(matchRecord, match => {
|
|
|
12711 |
const nodes = from(match.nodes);
|
|
|
12712 |
each$e(match.filter.callbacks, callback => {
|
|
|
12713 |
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
|
12714 |
const node = nodes[i];
|
|
|
12715 |
const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name;
|
|
|
12716 |
if (!valueMatches || isNullable(node.parent)) {
|
|
|
12717 |
nodes.splice(i, 1);
|
|
|
12718 |
}
|
|
|
12719 |
}
|
|
|
12720 |
if (nodes.length > 0) {
|
|
|
12721 |
callback(nodes, match.filter.name, args);
|
|
|
12722 |
}
|
|
|
12723 |
});
|
|
|
12724 |
});
|
|
|
12725 |
};
|
|
|
12726 |
run(matches.nodes, false);
|
|
|
12727 |
run(matches.attributes, true);
|
|
|
12728 |
};
|
|
|
12729 |
const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => {
|
|
|
12730 |
const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
|
|
|
12731 |
runFilters(matches, args);
|
|
|
12732 |
};
|
|
|
12733 |
|
|
|
12734 |
const paddEmptyNode = (settings, args, isBlock, node) => {
|
|
|
12735 |
const brPreferred = settings.pad_empty_with_br || args.insert;
|
|
|
12736 |
if (brPreferred && isBlock(node)) {
|
|
|
12737 |
const astNode = new AstNode('br', 1);
|
|
|
12738 |
if (args.insert) {
|
|
|
12739 |
astNode.attr('data-mce-bogus', '1');
|
|
|
12740 |
}
|
|
|
12741 |
node.empty().append(astNode);
|
|
|
12742 |
} else {
|
|
|
12743 |
node.empty().append(new AstNode('#text', 3)).value = nbsp;
|
|
|
12744 |
}
|
|
|
12745 |
};
|
|
|
12746 |
const isPaddedWithNbsp = node => {
|
|
|
12747 |
var _a;
|
|
|
12748 |
return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp;
|
|
|
12749 |
};
|
|
|
12750 |
const hasOnlyChild = (node, name) => {
|
|
|
12751 |
const firstChild = node === null || node === void 0 ? void 0 : node.firstChild;
|
|
|
12752 |
return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name;
|
|
|
12753 |
};
|
|
|
12754 |
const isPadded = (schema, node) => {
|
|
|
12755 |
const rule = schema.getElementRule(node.name);
|
|
|
12756 |
return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true;
|
|
|
12757 |
};
|
|
|
12758 |
const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node));
|
|
|
12759 |
const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br');
|
|
|
12760 |
const findClosestEditingHost = scope => {
|
|
|
12761 |
let editableNode;
|
|
|
12762 |
for (let node = scope; node; node = node.parent) {
|
|
|
12763 |
const contentEditable = node.attr('contenteditable');
|
|
|
12764 |
if (contentEditable === 'false') {
|
|
|
12765 |
break;
|
|
|
12766 |
} else if (contentEditable === 'true') {
|
|
|
12767 |
editableNode = node;
|
|
|
12768 |
}
|
|
|
12769 |
}
|
|
|
12770 |
return Optional.from(editableNode);
|
|
|
12771 |
};
|
|
|
12772 |
|
|
|
12773 |
const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
|
|
|
12774 |
if (schema.getSpecialElements()[node.name]) {
|
|
|
12775 |
node.empty().remove();
|
|
|
12776 |
} else {
|
|
|
12777 |
const children = node.children();
|
|
|
12778 |
for (const childNode of children) {
|
|
|
12779 |
if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) {
|
|
|
12780 |
removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
|
|
|
12781 |
}
|
|
|
12782 |
}
|
|
|
12783 |
node.unwrap();
|
|
|
12784 |
}
|
|
|
12785 |
};
|
|
|
12786 |
const cleanInvalidNodes = (nodes, schema, rootNode, onCreate = noop) => {
|
|
|
12787 |
const textBlockElements = schema.getTextBlockElements();
|
|
|
12788 |
const nonEmptyElements = schema.getNonEmptyElements();
|
|
|
12789 |
const whitespaceElements = schema.getWhitespaceElements();
|
|
|
12790 |
const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table,summary');
|
|
|
12791 |
const fixed = new Set();
|
|
|
12792 |
const isSplittableElement = node => node !== rootNode && !nonSplittableElements[node.name];
|
|
|
12793 |
for (let ni = 0; ni < nodes.length; ni++) {
|
|
|
12794 |
const node = nodes[ni];
|
|
|
12795 |
let parent;
|
|
|
12796 |
let newParent;
|
|
|
12797 |
let tempNode;
|
|
|
12798 |
if (!node.parent || fixed.has(node)) {
|
|
|
12799 |
continue;
|
|
|
12800 |
}
|
|
|
12801 |
if (textBlockElements[node.name] && node.parent.name === 'li') {
|
|
|
12802 |
let sibling = node.next;
|
|
|
12803 |
while (sibling) {
|
|
|
12804 |
if (textBlockElements[sibling.name]) {
|
|
|
12805 |
sibling.name = 'li';
|
|
|
12806 |
fixed.add(sibling);
|
|
|
12807 |
node.parent.insert(sibling, node.parent);
|
|
|
12808 |
} else {
|
|
|
12809 |
break;
|
|
|
12810 |
}
|
|
|
12811 |
sibling = sibling.next;
|
|
|
12812 |
}
|
|
|
12813 |
node.unwrap();
|
|
|
12814 |
continue;
|
|
|
12815 |
}
|
|
|
12816 |
const parents = [node];
|
|
|
12817 |
for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && isSplittableElement(parent); parent = parent.parent) {
|
|
|
12818 |
parents.push(parent);
|
|
|
12819 |
}
|
|
|
12820 |
if (parent && parents.length > 1) {
|
|
|
12821 |
if (!isInvalid(schema, node, parent)) {
|
|
|
12822 |
parents.reverse();
|
|
|
12823 |
newParent = parents[0].clone();
|
|
|
12824 |
onCreate(newParent);
|
|
|
12825 |
let currentNode = newParent;
|
|
|
12826 |
for (let i = 0; i < parents.length - 1; i++) {
|
|
|
12827 |
if (schema.isValidChild(currentNode.name, parents[i].name) && i > 0) {
|
|
|
12828 |
tempNode = parents[i].clone();
|
|
|
12829 |
onCreate(tempNode);
|
|
|
12830 |
currentNode.append(tempNode);
|
|
|
12831 |
} else {
|
|
|
12832 |
tempNode = currentNode;
|
|
|
12833 |
}
|
|
|
12834 |
for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
|
|
|
12835 |
const nextNode = childNode.next;
|
|
|
12836 |
tempNode.append(childNode);
|
|
|
12837 |
childNode = nextNode;
|
|
|
12838 |
}
|
|
|
12839 |
currentNode = tempNode;
|
|
|
12840 |
}
|
|
|
12841 |
if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
|
|
|
12842 |
parent.insert(newParent, parents[0], true);
|
|
|
12843 |
parent.insert(node, newParent);
|
|
|
12844 |
} else {
|
|
|
12845 |
parent.insert(node, parents[0], true);
|
|
|
12846 |
}
|
|
|
12847 |
parent = parents[0];
|
|
|
12848 |
if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
|
|
|
12849 |
parent.empty().remove();
|
|
|
12850 |
}
|
|
|
12851 |
} else {
|
|
|
12852 |
removeOrUnwrapInvalidNode(node, schema);
|
|
|
12853 |
}
|
|
|
12854 |
} else if (node.parent) {
|
|
|
12855 |
if (node.name === 'li') {
|
|
|
12856 |
let sibling = node.prev;
|
|
|
12857 |
if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) {
|
|
|
12858 |
sibling.append(node);
|
|
|
12859 |
continue;
|
|
|
12860 |
}
|
|
|
12861 |
sibling = node.next;
|
|
|
12862 |
if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) {
|
|
|
12863 |
sibling.insert(node, sibling.firstChild, true);
|
|
|
12864 |
continue;
|
|
|
12865 |
}
|
|
|
12866 |
const wrapper = new AstNode('ul', 1);
|
|
|
12867 |
onCreate(wrapper);
|
|
|
12868 |
node.wrap(wrapper);
|
|
|
12869 |
continue;
|
|
|
12870 |
}
|
|
|
12871 |
if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
|
|
|
12872 |
const wrapper = new AstNode('div', 1);
|
|
|
12873 |
onCreate(wrapper);
|
|
|
12874 |
node.wrap(wrapper);
|
|
|
12875 |
} else {
|
|
|
12876 |
removeOrUnwrapInvalidNode(node, schema);
|
|
|
12877 |
}
|
|
|
12878 |
}
|
|
|
12879 |
}
|
|
|
12880 |
};
|
|
|
12881 |
const hasClosest = (node, parentName) => {
|
|
|
12882 |
let tempNode = node;
|
|
|
12883 |
while (tempNode) {
|
|
|
12884 |
if (tempNode.name === parentName) {
|
|
|
12885 |
return true;
|
|
|
12886 |
}
|
|
|
12887 |
tempNode = tempNode.parent;
|
|
|
12888 |
}
|
|
|
12889 |
return false;
|
|
|
12890 |
};
|
|
|
12891 |
const isInvalid = (schema, node, parent = node.parent) => {
|
|
|
12892 |
if (!parent) {
|
|
|
12893 |
return false;
|
|
|
12894 |
}
|
|
|
12895 |
if (schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) {
|
|
|
12896 |
return true;
|
|
|
12897 |
}
|
|
|
12898 |
if (node.name === 'a' && hasClosest(parent, 'a')) {
|
|
|
12899 |
return true;
|
|
|
12900 |
}
|
|
|
12901 |
if (isSummary(parent) && isHeading(node)) {
|
|
|
12902 |
return !((parent === null || parent === void 0 ? void 0 : parent.firstChild) === node && (parent === null || parent === void 0 ? void 0 : parent.lastChild) === node);
|
|
|
12903 |
}
|
|
|
12904 |
return false;
|
|
|
12905 |
};
|
|
|
12906 |
|
|
|
12907 |
const createRange = (sc, so, ec, eo) => {
|
|
|
12908 |
const rng = document.createRange();
|
|
|
12909 |
rng.setStart(sc, so);
|
|
|
12910 |
rng.setEnd(ec, eo);
|
|
|
12911 |
return rng;
|
|
|
12912 |
};
|
|
|
12913 |
const normalizeBlockSelectionRange = rng => {
|
|
|
12914 |
const startPos = CaretPosition.fromRangeStart(rng);
|
|
|
12915 |
const endPos = CaretPosition.fromRangeEnd(rng);
|
|
|
12916 |
const rootNode = rng.commonAncestorContainer;
|
|
|
12917 |
return fromPosition(false, rootNode, endPos).map(newEndPos => {
|
|
|
12918 |
if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
|
|
|
12919 |
return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
|
|
|
12920 |
} else {
|
|
|
12921 |
return rng;
|
|
|
12922 |
}
|
|
|
12923 |
}).getOr(rng);
|
|
|
12924 |
};
|
|
|
12925 |
const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
|
|
|
12926 |
|
|
|
12927 |
const hasOnlyOneChild$1 = node => {
|
|
|
12928 |
return isNonNullable(node.firstChild) && node.firstChild === node.lastChild;
|
|
|
12929 |
};
|
|
|
12930 |
const isPaddingNode = node => {
|
|
|
12931 |
return node.name === 'br' || node.value === nbsp;
|
|
|
12932 |
};
|
|
|
12933 |
const isPaddedEmptyBlock = (schema, node) => {
|
|
|
12934 |
const blockElements = schema.getBlockElements();
|
|
|
12935 |
return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
|
|
|
12936 |
};
|
|
|
12937 |
const isEmptyFragmentElement = (schema, node) => {
|
|
|
12938 |
const nonEmptyElements = schema.getNonEmptyElements();
|
|
|
12939 |
return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
|
|
|
12940 |
};
|
|
|
12941 |
const isListFragment = (schema, fragment) => {
|
|
|
12942 |
let firstChild = fragment.firstChild;
|
|
|
12943 |
let lastChild = fragment.lastChild;
|
|
|
12944 |
if (firstChild && firstChild.name === 'meta') {
|
|
|
12945 |
firstChild = firstChild.next;
|
|
|
12946 |
}
|
|
|
12947 |
if (lastChild && lastChild.attr('id') === 'mce_marker') {
|
|
|
12948 |
lastChild = lastChild.prev;
|
|
|
12949 |
}
|
|
|
12950 |
if (isEmptyFragmentElement(schema, lastChild)) {
|
|
|
12951 |
lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev;
|
|
|
12952 |
}
|
|
|
12953 |
if (!firstChild || firstChild !== lastChild) {
|
|
|
12954 |
return false;
|
|
|
12955 |
}
|
|
|
12956 |
return firstChild.name === 'ul' || firstChild.name === 'ol';
|
|
|
12957 |
};
|
|
|
12958 |
const cleanupDomFragment = domFragment => {
|
|
|
12959 |
var _a, _b;
|
|
|
12960 |
const firstChild = domFragment.firstChild;
|
|
|
12961 |
const lastChild = domFragment.lastChild;
|
|
|
12962 |
if (firstChild && firstChild.nodeName === 'META') {
|
|
|
12963 |
(_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild);
|
|
|
12964 |
}
|
|
|
12965 |
if (lastChild && lastChild.id === 'mce_marker') {
|
|
|
12966 |
(_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild);
|
|
|
12967 |
}
|
|
|
12968 |
return domFragment;
|
|
|
12969 |
};
|
|
|
12970 |
const toDomFragment = (dom, serializer, fragment) => {
|
|
|
12971 |
const html = serializer.serialize(fragment);
|
|
|
12972 |
const domFragment = dom.createFragment(html);
|
|
|
12973 |
return cleanupDomFragment(domFragment);
|
|
|
12974 |
};
|
|
|
12975 |
const listItems = elm => {
|
|
|
12976 |
var _a;
|
|
|
12977 |
return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => {
|
|
|
12978 |
return child.nodeName === 'LI';
|
|
|
12979 |
});
|
|
|
12980 |
};
|
|
|
12981 |
const isPadding = node => {
|
|
|
12982 |
return node.data === nbsp || isBr$6(node);
|
|
|
12983 |
};
|
|
|
12984 |
const isListItemPadded = node => {
|
|
|
12985 |
return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild);
|
|
|
12986 |
};
|
|
|
12987 |
const isEmptyOrPadded = elm => {
|
|
|
12988 |
return !elm.firstChild || isListItemPadded(elm);
|
|
|
12989 |
};
|
|
|
12990 |
const trimListItems = elms => {
|
|
|
12991 |
return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
|
|
|
12992 |
};
|
|
|
12993 |
const getParentLi = (dom, node) => {
|
|
|
12994 |
const parentBlock = dom.getParent(node, dom.isBlock);
|
|
|
12995 |
return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
|
|
|
12996 |
};
|
|
|
12997 |
const isParentBlockLi = (dom, node) => {
|
|
|
12998 |
return !!getParentLi(dom, node);
|
|
|
12999 |
};
|
|
|
13000 |
const getSplit = (parentNode, rng) => {
|
|
|
13001 |
const beforeRng = rng.cloneRange();
|
|
|
13002 |
const afterRng = rng.cloneRange();
|
|
|
13003 |
beforeRng.setStartBefore(parentNode);
|
|
|
13004 |
afterRng.setEndAfter(parentNode);
|
|
|
13005 |
return [
|
|
|
13006 |
beforeRng.cloneContents(),
|
|
|
13007 |
afterRng.cloneContents()
|
|
|
13008 |
];
|
|
|
13009 |
};
|
|
|
13010 |
const findFirstIn = (node, rootNode) => {
|
|
|
13011 |
const caretPos = CaretPosition.before(node);
|
|
|
13012 |
const caretWalker = CaretWalker(rootNode);
|
|
|
13013 |
const newCaretPos = caretWalker.next(caretPos);
|
|
|
13014 |
return newCaretPos ? newCaretPos.toRange() : null;
|
|
|
13015 |
};
|
|
|
13016 |
const findLastOf = (node, rootNode) => {
|
|
|
13017 |
const caretPos = CaretPosition.after(node);
|
|
|
13018 |
const caretWalker = CaretWalker(rootNode);
|
|
|
13019 |
const newCaretPos = caretWalker.prev(caretPos);
|
|
|
13020 |
return newCaretPos ? newCaretPos.toRange() : null;
|
|
|
13021 |
};
|
|
|
13022 |
const insertMiddle = (target, elms, rootNode, rng) => {
|
|
|
13023 |
const parts = getSplit(target, rng);
|
|
|
13024 |
const parentElm = target.parentNode;
|
|
|
13025 |
if (parentElm) {
|
|
|
13026 |
parentElm.insertBefore(parts[0], target);
|
|
|
13027 |
Tools.each(elms, li => {
|
|
|
13028 |
parentElm.insertBefore(li, target);
|
|
|
13029 |
});
|
|
|
13030 |
parentElm.insertBefore(parts[1], target);
|
|
|
13031 |
parentElm.removeChild(target);
|
|
|
13032 |
}
|
|
|
13033 |
return findLastOf(elms[elms.length - 1], rootNode);
|
|
|
13034 |
};
|
|
|
13035 |
const insertBefore$2 = (target, elms, rootNode) => {
|
|
|
13036 |
const parentElm = target.parentNode;
|
|
|
13037 |
if (parentElm) {
|
|
|
13038 |
Tools.each(elms, elm => {
|
|
|
13039 |
parentElm.insertBefore(elm, target);
|
|
|
13040 |
});
|
|
|
13041 |
}
|
|
|
13042 |
return findFirstIn(target, rootNode);
|
|
|
13043 |
};
|
|
|
13044 |
const insertAfter$2 = (target, elms, rootNode, dom) => {
|
|
|
13045 |
dom.insertAfter(elms.reverse(), target);
|
|
|
13046 |
return findLastOf(elms[0], rootNode);
|
|
|
13047 |
};
|
|
|
13048 |
const insertAtCaret$1 = (serializer, dom, rng, fragment) => {
|
|
|
13049 |
const domFragment = toDomFragment(dom, serializer, fragment);
|
|
|
13050 |
const liTarget = getParentLi(dom, rng.startContainer);
|
|
|
13051 |
const liElms = trimListItems(listItems(domFragment.firstChild));
|
|
|
13052 |
const BEGINNING = 1, END = 2;
|
|
|
13053 |
const rootNode = dom.getRoot();
|
|
|
13054 |
const isAt = location => {
|
|
|
13055 |
const caretPos = CaretPosition.fromRangeStart(rng);
|
|
|
13056 |
const caretWalker = CaretWalker(dom.getRoot());
|
|
|
13057 |
const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
|
|
|
13058 |
const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode();
|
|
|
13059 |
return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true;
|
|
|
13060 |
};
|
|
|
13061 |
if (!liTarget) {
|
|
|
13062 |
return null;
|
|
|
13063 |
} else if (isAt(BEGINNING)) {
|
|
|
13064 |
return insertBefore$2(liTarget, liElms, rootNode);
|
|
|
13065 |
} else if (isAt(END)) {
|
|
|
13066 |
return insertAfter$2(liTarget, liElms, rootNode, dom);
|
|
|
13067 |
} else {
|
|
|
13068 |
return insertMiddle(liTarget, liElms, rootNode, rng);
|
|
|
13069 |
}
|
|
|
13070 |
};
|
|
|
13071 |
|
|
|
13072 |
const mergeableWrappedElements = ['pre'];
|
|
|
13073 |
const shouldPasteContentOnly = (dom, fragment, parentNode, root) => {
|
|
|
13074 |
var _a;
|
|
|
13075 |
const firstNode = fragment.firstChild;
|
|
|
13076 |
const lastNode = fragment.lastChild;
|
|
|
13077 |
const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode;
|
|
|
13078 |
const isPastingSingleElement = firstNode === last;
|
|
|
13079 |
const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name);
|
|
|
13080 |
if (isPastingSingleElement && isWrappedElement) {
|
|
|
13081 |
const isContentEditable = firstNode.attr('contenteditable') !== 'false';
|
|
|
13082 |
const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name;
|
|
|
13083 |
const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3);
|
|
|
13084 |
return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable;
|
|
|
13085 |
} else {
|
|
|
13086 |
return false;
|
|
|
13087 |
}
|
|
|
13088 |
};
|
|
|
13089 |
const isTableCell = isTableCell$3;
|
|
|
13090 |
const isTableCellContentSelected = (dom, rng, cell) => {
|
|
|
13091 |
if (isNonNullable(cell)) {
|
|
|
13092 |
const endCell = dom.getParent(rng.endContainer, isTableCell);
|
|
|
13093 |
return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng);
|
|
|
13094 |
} else {
|
|
|
13095 |
return false;
|
|
|
13096 |
}
|
|
|
13097 |
};
|
| 1441 |
ariadna |
13098 |
const isEditableEmptyBlock = (dom, node) => {
|
|
|
13099 |
if (dom.isBlock(node) && dom.isEditable(node)) {
|
|
|
13100 |
const childNodes = node.childNodes;
|
|
|
13101 |
return childNodes.length === 1 && isBr$6(childNodes[0]) || childNodes.length === 0;
|
|
|
13102 |
} else {
|
|
|
13103 |
return false;
|
|
|
13104 |
}
|
|
|
13105 |
};
|
| 1 |
efrain |
13106 |
const validInsertion = (editor, value, parentNode) => {
|
|
|
13107 |
var _a;
|
|
|
13108 |
if (parentNode.getAttribute('data-mce-bogus') === 'all') {
|
|
|
13109 |
(_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode);
|
|
|
13110 |
} else {
|
| 1441 |
ariadna |
13111 |
if (isEditableEmptyBlock(editor.dom, parentNode)) {
|
| 1 |
efrain |
13112 |
editor.dom.setHTML(parentNode, value);
|
|
|
13113 |
} else {
|
|
|
13114 |
editor.selection.setContent(value, { no_events: true });
|
|
|
13115 |
}
|
|
|
13116 |
}
|
|
|
13117 |
};
|
|
|
13118 |
const trimBrsFromTableCell = (dom, elm, schema) => {
|
|
|
13119 |
Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(el => trimBlockTrailingBr(el, schema));
|
|
|
13120 |
};
|
|
|
13121 |
const reduceInlineTextElements = (editor, merge) => {
|
|
|
13122 |
const textInlineElements = editor.schema.getTextInlineElements();
|
|
|
13123 |
const dom = editor.dom;
|
|
|
13124 |
if (merge) {
|
|
|
13125 |
const root = editor.getBody();
|
|
|
13126 |
const elementUtils = ElementUtils(editor);
|
| 1441 |
ariadna |
13127 |
const fragmentSelector = '*[data-mce-fragment]';
|
|
|
13128 |
const fragments = dom.select(fragmentSelector);
|
|
|
13129 |
Tools.each(fragments, node => {
|
|
|
13130 |
const isInline = currentNode => isNonNullable(textInlineElements[currentNode.nodeName.toLowerCase()]);
|
|
|
13131 |
const hasOneChild = currentNode => currentNode.childNodes.length === 1;
|
|
|
13132 |
const hasNoNonInheritableStyles = currentNode => !(hasNonInheritableStyles(dom, currentNode) || hasConditionalNonInheritableStyles(dom, currentNode));
|
|
|
13133 |
if (hasNoNonInheritableStyles(node) && isInline(node) && hasOneChild(node)) {
|
|
|
13134 |
const styles = getStyleProps(dom, node);
|
|
|
13135 |
const isOverridden = (oldStyles, newStyles) => forall(oldStyles, style => contains$2(newStyles, style));
|
|
|
13136 |
const overriddenByAllChildren = childNode => hasOneChild(node) && dom.is(childNode, fragmentSelector) && isInline(childNode) && (childNode.nodeName === node.nodeName && isOverridden(styles, getStyleProps(dom, childNode)) || overriddenByAllChildren(childNode.children[0]));
|
|
|
13137 |
const identicalToParent = parentNode => isNonNullable(parentNode) && parentNode !== root && (elementUtils.compare(node, parentNode) || identicalToParent(parentNode.parentElement));
|
|
|
13138 |
const conflictWithInsertedParent = parentNode => isNonNullable(parentNode) && parentNode !== root && dom.is(parentNode, fragmentSelector) && (hasStyleConflict(dom, node, parentNode) || conflictWithInsertedParent(parentNode.parentElement));
|
|
|
13139 |
if (overriddenByAllChildren(node.children[0]) || identicalToParent(node.parentElement) && !conflictWithInsertedParent(node.parentElement)) {
|
|
|
13140 |
dom.remove(node, true);
|
| 1 |
efrain |
13141 |
}
|
|
|
13142 |
}
|
|
|
13143 |
});
|
|
|
13144 |
}
|
|
|
13145 |
};
|
|
|
13146 |
const markFragmentElements = fragment => {
|
|
|
13147 |
let node = fragment;
|
|
|
13148 |
while (node = node.walk()) {
|
|
|
13149 |
if (node.type === 1) {
|
|
|
13150 |
node.attr('data-mce-fragment', '1');
|
|
|
13151 |
}
|
|
|
13152 |
}
|
|
|
13153 |
};
|
|
|
13154 |
const unmarkFragmentElements = elm => {
|
|
|
13155 |
Tools.each(elm.getElementsByTagName('*'), elm => {
|
|
|
13156 |
elm.removeAttribute('data-mce-fragment');
|
|
|
13157 |
});
|
|
|
13158 |
};
|
|
|
13159 |
const isPartOfFragment = node => {
|
|
|
13160 |
return !!node.getAttribute('data-mce-fragment');
|
|
|
13161 |
};
|
|
|
13162 |
const canHaveChildren = (editor, node) => {
|
|
|
13163 |
return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName];
|
|
|
13164 |
};
|
|
|
13165 |
const moveSelectionToMarker = (editor, marker) => {
|
|
|
13166 |
var _a, _b, _c;
|
|
|
13167 |
let nextRng;
|
|
|
13168 |
const dom = editor.dom;
|
|
|
13169 |
const selection = editor.selection;
|
|
|
13170 |
if (!marker) {
|
|
|
13171 |
return;
|
|
|
13172 |
}
|
|
|
13173 |
selection.scrollIntoView(marker);
|
|
|
13174 |
const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
|
|
|
13175 |
if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') {
|
|
|
13176 |
dom.remove(marker);
|
|
|
13177 |
selection.select(parentEditableElm);
|
|
|
13178 |
return;
|
|
|
13179 |
}
|
|
|
13180 |
let rng = dom.createRng();
|
|
|
13181 |
const node = marker.previousSibling;
|
| 1441 |
ariadna |
13182 |
if (isText$b(node)) {
|
| 1 |
efrain |
13183 |
rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
|
|
|
13184 |
const node2 = marker.nextSibling;
|
| 1441 |
ariadna |
13185 |
if (isText$b(node2)) {
|
| 1 |
efrain |
13186 |
node.appendData(node2.data);
|
|
|
13187 |
(_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2);
|
|
|
13188 |
}
|
|
|
13189 |
} else {
|
|
|
13190 |
rng.setStartBefore(marker);
|
|
|
13191 |
rng.setEndBefore(marker);
|
|
|
13192 |
}
|
|
|
13193 |
const findNextCaretRng = rng => {
|
|
|
13194 |
let caretPos = CaretPosition.fromRangeStart(rng);
|
|
|
13195 |
const caretWalker = CaretWalker(editor.getBody());
|
|
|
13196 |
caretPos = caretWalker.next(caretPos);
|
|
|
13197 |
return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange();
|
|
|
13198 |
};
|
|
|
13199 |
const parentBlock = dom.getParent(marker, dom.isBlock);
|
|
|
13200 |
dom.remove(marker);
|
|
|
13201 |
if (parentBlock && dom.isEmpty(parentBlock)) {
|
|
|
13202 |
const isCell = isTableCell(parentBlock);
|
|
|
13203 |
empty(SugarElement.fromDom(parentBlock));
|
|
|
13204 |
rng.setStart(parentBlock, 0);
|
|
|
13205 |
rng.setEnd(parentBlock, 0);
|
|
|
13206 |
if (!isCell && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
|
|
|
13207 |
rng = nextRng;
|
|
|
13208 |
dom.remove(parentBlock);
|
|
|
13209 |
} else {
|
|
|
13210 |
dom.add(parentBlock, dom.create('br', isCell ? {} : { 'data-mce-bogus': '1' }));
|
|
|
13211 |
}
|
|
|
13212 |
}
|
|
|
13213 |
selection.setRng(rng);
|
|
|
13214 |
};
|
|
|
13215 |
const deleteSelectedContent = editor => {
|
|
|
13216 |
const dom = editor.dom;
|
|
|
13217 |
const rng = normalize(editor.selection.getRng());
|
|
|
13218 |
editor.selection.setRng(rng);
|
|
|
13219 |
const startCell = dom.getParent(rng.startContainer, isTableCell);
|
|
|
13220 |
if (isTableCellContentSelected(dom, rng, startCell)) {
|
|
|
13221 |
deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
|
| 1441 |
ariadna |
13222 |
} else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$b(rng.startContainer.childNodes[rng.startOffset])) {
|
| 1 |
efrain |
13223 |
rng.deleteContents();
|
|
|
13224 |
} else {
|
|
|
13225 |
editor.getDoc().execCommand('Delete', false);
|
|
|
13226 |
}
|
|
|
13227 |
};
|
|
|
13228 |
const findMarkerNode = scope => {
|
|
|
13229 |
for (let markerNode = scope; markerNode; markerNode = markerNode.walk()) {
|
|
|
13230 |
if (markerNode.attr('id') === 'mce_marker') {
|
|
|
13231 |
return Optional.some(markerNode);
|
|
|
13232 |
}
|
|
|
13233 |
}
|
|
|
13234 |
return Optional.none();
|
|
|
13235 |
};
|
|
|
13236 |
const notHeadingsInSummary = (dom, node, fragment) => {
|
|
|
13237 |
var _a;
|
|
|
13238 |
return exists(fragment.children(), isHeading) && ((_a = dom.getParent(node, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName) === 'SUMMARY';
|
|
|
13239 |
};
|
|
|
13240 |
const insertHtmlAtCaret = (editor, value, details) => {
|
|
|
13241 |
var _a, _b;
|
|
|
13242 |
const selection = editor.selection;
|
|
|
13243 |
const dom = editor.dom;
|
|
|
13244 |
const parser = editor.parser;
|
|
|
13245 |
const merge = details.merge;
|
|
|
13246 |
const serializer = HtmlSerializer({ validate: true }, editor.schema);
|
|
|
13247 |
const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark"></span>';
|
|
|
13248 |
if (!details.preserve_zwsp) {
|
|
|
13249 |
value = trim$2(value);
|
|
|
13250 |
}
|
|
|
13251 |
if (value.indexOf('{$caret}') === -1) {
|
|
|
13252 |
value += '{$caret}';
|
|
|
13253 |
}
|
|
|
13254 |
value = value.replace(/\{\$caret\}/, bookmarkHtml);
|
|
|
13255 |
let rng = selection.getRng();
|
|
|
13256 |
const caretElement = rng.startContainer;
|
|
|
13257 |
const body = editor.getBody();
|
|
|
13258 |
if (caretElement === body && selection.isCollapsed()) {
|
|
|
13259 |
if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
|
|
|
13260 |
rng = dom.createRng();
|
|
|
13261 |
rng.setStart(body.firstChild, 0);
|
|
|
13262 |
rng.setEnd(body.firstChild, 0);
|
|
|
13263 |
selection.setRng(rng);
|
|
|
13264 |
}
|
|
|
13265 |
}
|
|
|
13266 |
if (!selection.isCollapsed()) {
|
|
|
13267 |
deleteSelectedContent(editor);
|
|
|
13268 |
}
|
|
|
13269 |
const parentNode = selection.getNode();
|
|
|
13270 |
const parserArgs = {
|
|
|
13271 |
context: parentNode.nodeName.toLowerCase(),
|
|
|
13272 |
data: details.data,
|
|
|
13273 |
insert: true
|
|
|
13274 |
};
|
|
|
13275 |
const fragment = parser.parse(value, parserArgs);
|
|
|
13276 |
if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) {
|
|
|
13277 |
rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment);
|
|
|
13278 |
if (rng) {
|
|
|
13279 |
selection.setRng(rng);
|
|
|
13280 |
}
|
|
|
13281 |
return value;
|
|
|
13282 |
}
|
|
|
13283 |
if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) {
|
|
|
13284 |
(_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap();
|
|
|
13285 |
}
|
|
|
13286 |
markFragmentElements(fragment);
|
|
|
13287 |
let node = fragment.lastChild;
|
|
|
13288 |
if (node && node.attr('id') === 'mce_marker') {
|
|
|
13289 |
const marker = node;
|
|
|
13290 |
for (node = node.prev; node; node = node.walk(true)) {
|
| 1441 |
ariadna |
13291 |
if (node.name === 'table') {
|
|
|
13292 |
break;
|
|
|
13293 |
}
|
| 1 |
efrain |
13294 |
if (node.type === 3 || !dom.isBlock(node.name)) {
|
|
|
13295 |
if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
|
|
|
13296 |
node.parent.insert(marker, node, node.name === 'br');
|
|
|
13297 |
}
|
|
|
13298 |
break;
|
|
|
13299 |
}
|
|
|
13300 |
}
|
|
|
13301 |
}
|
|
|
13302 |
editor._selectionOverrides.showBlockCaretContainer(parentNode);
|
|
|
13303 |
if (!parserArgs.invalid && !notHeadingsInSummary(dom, parentNode, fragment)) {
|
|
|
13304 |
value = serializer.serialize(fragment);
|
|
|
13305 |
validInsertion(editor, value, parentNode);
|
|
|
13306 |
} else {
|
|
|
13307 |
editor.selection.setContent(bookmarkHtml);
|
|
|
13308 |
let parentNode = selection.getNode();
|
|
|
13309 |
let tempNode;
|
|
|
13310 |
const rootNode = editor.getBody();
|
|
|
13311 |
if (isDocument$1(parentNode)) {
|
|
|
13312 |
parentNode = tempNode = rootNode;
|
|
|
13313 |
} else {
|
|
|
13314 |
tempNode = parentNode;
|
|
|
13315 |
}
|
|
|
13316 |
while (tempNode && tempNode !== rootNode) {
|
|
|
13317 |
parentNode = tempNode;
|
|
|
13318 |
tempNode = tempNode.parentNode;
|
|
|
13319 |
}
|
|
|
13320 |
value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
|
|
|
13321 |
const root = parser.parse(value);
|
|
|
13322 |
const markerNode = findMarkerNode(root);
|
|
|
13323 |
const editingHost = markerNode.bind(findClosestEditingHost).getOr(root);
|
|
|
13324 |
markerNode.each(marker => marker.replace(fragment));
|
|
|
13325 |
const toExtract = fragment.children();
|
|
|
13326 |
const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root;
|
|
|
13327 |
fragment.unwrap();
|
|
|
13328 |
const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent));
|
|
|
13329 |
cleanInvalidNodes(invalidChildren, editor.schema, editingHost);
|
|
|
13330 |
filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root);
|
|
|
13331 |
value = serializer.serialize(root);
|
|
|
13332 |
if (parentNode === rootNode) {
|
|
|
13333 |
dom.setHTML(rootNode, value);
|
|
|
13334 |
} else {
|
|
|
13335 |
dom.setOuterHTML(parentNode, value);
|
|
|
13336 |
}
|
|
|
13337 |
}
|
|
|
13338 |
reduceInlineTextElements(editor, merge);
|
|
|
13339 |
moveSelectionToMarker(editor, dom.get('mce_marker'));
|
|
|
13340 |
unmarkFragmentElements(editor.getBody());
|
|
|
13341 |
trimBrsFromTableCell(dom, selection.getStart(), editor.schema);
|
|
|
13342 |
updateCaret(editor.schema, editor.getBody(), selection.getStart());
|
|
|
13343 |
return value;
|
|
|
13344 |
};
|
|
|
13345 |
|
|
|
13346 |
const isTreeNode = content => content instanceof AstNode;
|
|
|
13347 |
|
|
|
13348 |
const moveSelection = editor => {
|
|
|
13349 |
if (hasFocus(editor)) {
|
|
|
13350 |
firstPositionIn(editor.getBody()).each(pos => {
|
|
|
13351 |
const node = pos.getNode();
|
|
|
13352 |
const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
|
|
|
13353 |
editor.selection.setRng(caretPos.toRange());
|
|
|
13354 |
});
|
|
|
13355 |
}
|
|
|
13356 |
};
|
|
|
13357 |
const setEditorHtml = (editor, html, noSelection) => {
|
|
|
13358 |
editor.dom.setHTML(editor.getBody(), html);
|
|
|
13359 |
if (noSelection !== true) {
|
|
|
13360 |
moveSelection(editor);
|
|
|
13361 |
}
|
|
|
13362 |
};
|
|
|
13363 |
const setContentString = (editor, body, content, args) => {
|
|
|
13364 |
content = trim$2(content);
|
|
|
13365 |
if (content.length === 0 || /^\s+$/.test(content)) {
|
|
|
13366 |
const padd = '<br data-mce-bogus="1">';
|
|
|
13367 |
if (body.nodeName === 'TABLE') {
|
|
|
13368 |
content = '<tr><td>' + padd + '</td></tr>';
|
|
|
13369 |
} else if (/^(UL|OL)$/.test(body.nodeName)) {
|
|
|
13370 |
content = '<li>' + padd + '</li>';
|
|
|
13371 |
}
|
|
|
13372 |
const forcedRootBlockName = getForcedRootBlock(editor);
|
|
|
13373 |
if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
|
|
|
13374 |
content = padd;
|
|
|
13375 |
content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
|
|
|
13376 |
} else if (!content) {
|
|
|
13377 |
content = padd;
|
|
|
13378 |
}
|
|
|
13379 |
setEditorHtml(editor, content, args.no_selection);
|
|
|
13380 |
return {
|
|
|
13381 |
content,
|
|
|
13382 |
html: content
|
|
|
13383 |
};
|
|
|
13384 |
} else {
|
|
|
13385 |
if (args.format !== 'raw') {
|
|
|
13386 |
content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
|
|
|
13387 |
isRootContent: true,
|
|
|
13388 |
insert: true
|
|
|
13389 |
}));
|
|
|
13390 |
}
|
|
|
13391 |
const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
|
|
|
13392 |
setEditorHtml(editor, trimmedHtml, args.no_selection);
|
|
|
13393 |
return {
|
|
|
13394 |
content: trimmedHtml,
|
|
|
13395 |
html: trimmedHtml
|
|
|
13396 |
};
|
|
|
13397 |
}
|
|
|
13398 |
};
|
|
|
13399 |
const setContentTree = (editor, body, content, args) => {
|
|
|
13400 |
filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
|
|
|
13401 |
const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
|
|
|
13402 |
const trimmedHtml = trim$2(isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html));
|
|
|
13403 |
setEditorHtml(editor, trimmedHtml, args.no_selection);
|
|
|
13404 |
return {
|
|
|
13405 |
content,
|
|
|
13406 |
html: trimmedHtml
|
|
|
13407 |
};
|
|
|
13408 |
};
|
|
|
13409 |
const setContentInternal = (editor, content, args) => {
|
|
|
13410 |
return Optional.from(editor.getBody()).map(body => {
|
|
|
13411 |
if (isTreeNode(content)) {
|
|
|
13412 |
return setContentTree(editor, body, content, args);
|
|
|
13413 |
} else {
|
|
|
13414 |
return setContentString(editor, body, content, args);
|
|
|
13415 |
}
|
|
|
13416 |
}).getOr({
|
|
|
13417 |
content,
|
|
|
13418 |
html: isTreeNode(args.content) ? '' : args.content
|
|
|
13419 |
});
|
|
|
13420 |
};
|
|
|
13421 |
|
|
|
13422 |
const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
|
|
|
13423 |
const ancestor = (scope, transform, isRoot) => {
|
|
|
13424 |
let element = scope.dom;
|
|
|
13425 |
const stop = ensureIsRoot(isRoot);
|
|
|
13426 |
while (element.parentNode) {
|
|
|
13427 |
element = element.parentNode;
|
|
|
13428 |
const el = SugarElement.fromDom(element);
|
|
|
13429 |
const transformed = transform(el);
|
|
|
13430 |
if (transformed.isSome()) {
|
|
|
13431 |
return transformed;
|
|
|
13432 |
} else if (stop(el)) {
|
|
|
13433 |
break;
|
|
|
13434 |
}
|
|
|
13435 |
}
|
|
|
13436 |
return Optional.none();
|
|
|
13437 |
};
|
|
|
13438 |
const closest$1 = (scope, transform, isRoot) => {
|
|
|
13439 |
const current = transform(scope);
|
|
|
13440 |
const stop = ensureIsRoot(isRoot);
|
|
|
13441 |
return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop));
|
|
|
13442 |
};
|
|
|
13443 |
|
|
|
13444 |
const isEq$3 = isEq$5;
|
|
|
13445 |
const matchesUnInheritedFormatSelector = (ed, node, name) => {
|
|
|
13446 |
const formatList = ed.formatter.get(name);
|
|
|
13447 |
if (formatList) {
|
|
|
13448 |
for (let i = 0; i < formatList.length; i++) {
|
|
|
13449 |
const format = formatList[i];
|
|
|
13450 |
if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
|
|
|
13451 |
return true;
|
|
|
13452 |
}
|
|
|
13453 |
}
|
|
|
13454 |
}
|
|
|
13455 |
return false;
|
|
|
13456 |
};
|
|
|
13457 |
const matchParents = (editor, node, name, vars, similar) => {
|
|
|
13458 |
const root = editor.dom.getRoot();
|
|
|
13459 |
if (node === root) {
|
|
|
13460 |
return false;
|
|
|
13461 |
}
|
|
|
13462 |
const matchedNode = editor.dom.getParent(node, elm => {
|
|
|
13463 |
if (matchesUnInheritedFormatSelector(editor, elm, name)) {
|
|
|
13464 |
return true;
|
|
|
13465 |
}
|
|
|
13466 |
return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true);
|
|
|
13467 |
});
|
|
|
13468 |
return !!matchNode(editor, matchedNode, name, vars, similar);
|
|
|
13469 |
};
|
|
|
13470 |
const matchName = (dom, node, format) => {
|
|
|
13471 |
if (isInlineFormat(format) && isEq$3(node, format.inline)) {
|
|
|
13472 |
return true;
|
|
|
13473 |
}
|
|
|
13474 |
if (isBlockFormat(format) && isEq$3(node, format.block)) {
|
|
|
13475 |
return true;
|
|
|
13476 |
}
|
|
|
13477 |
if (isSelectorFormat(format)) {
|
|
|
13478 |
return isElement$6(node) && dom.is(node, format.selector);
|
|
|
13479 |
}
|
|
|
13480 |
return false;
|
|
|
13481 |
};
|
|
|
13482 |
const matchItems = (dom, node, format, itemName, similar, vars) => {
|
|
|
13483 |
const items = format[itemName];
|
|
|
13484 |
const matchAttributes = itemName === 'attributes';
|
|
|
13485 |
if (isFunction(format.onmatch)) {
|
|
|
13486 |
return format.onmatch(node, format, itemName);
|
|
|
13487 |
}
|
|
|
13488 |
if (items) {
|
|
|
13489 |
if (!isArrayLike(items)) {
|
|
|
13490 |
for (const key in items) {
|
|
|
13491 |
if (has$2(items, key)) {
|
|
|
13492 |
const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key);
|
|
|
13493 |
const expectedValue = replaceVars(items[key], vars);
|
|
|
13494 |
const isEmptyValue = isNullable(value) || isEmpty$3(value);
|
|
|
13495 |
if (isEmptyValue && isNullable(expectedValue)) {
|
|
|
13496 |
continue;
|
|
|
13497 |
}
|
|
|
13498 |
if (similar && isEmptyValue && !format.exact) {
|
|
|
13499 |
return false;
|
|
|
13500 |
}
|
|
|
13501 |
if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) {
|
|
|
13502 |
return false;
|
|
|
13503 |
}
|
|
|
13504 |
}
|
|
|
13505 |
}
|
|
|
13506 |
} else {
|
|
|
13507 |
for (let i = 0; i < items.length; i++) {
|
|
|
13508 |
if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) {
|
|
|
13509 |
return true;
|
|
|
13510 |
}
|
|
|
13511 |
}
|
|
|
13512 |
}
|
|
|
13513 |
}
|
|
|
13514 |
return true;
|
|
|
13515 |
};
|
|
|
13516 |
const matchNode = (ed, node, name, vars, similar) => {
|
|
|
13517 |
const formatList = ed.formatter.get(name);
|
|
|
13518 |
const dom = ed.dom;
|
|
|
13519 |
if (formatList && isElement$6(node)) {
|
|
|
13520 |
for (let i = 0; i < formatList.length; i++) {
|
|
|
13521 |
const format = formatList[i];
|
|
|
13522 |
if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
|
|
|
13523 |
const classes = format.classes;
|
|
|
13524 |
if (classes) {
|
|
|
13525 |
for (let x = 0; x < classes.length; x++) {
|
|
|
13526 |
if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
|
|
|
13527 |
return;
|
|
|
13528 |
}
|
|
|
13529 |
}
|
|
|
13530 |
}
|
|
|
13531 |
return format;
|
|
|
13532 |
}
|
|
|
13533 |
}
|
|
|
13534 |
}
|
|
|
13535 |
return undefined;
|
|
|
13536 |
};
|
|
|
13537 |
const match$2 = (editor, name, vars, node, similar) => {
|
|
|
13538 |
if (node) {
|
|
|
13539 |
return matchParents(editor, node, name, vars, similar);
|
|
|
13540 |
}
|
|
|
13541 |
node = editor.selection.getNode();
|
|
|
13542 |
if (matchParents(editor, node, name, vars, similar)) {
|
|
|
13543 |
return true;
|
|
|
13544 |
}
|
|
|
13545 |
const startNode = editor.selection.getStart();
|
|
|
13546 |
if (startNode !== node) {
|
|
|
13547 |
if (matchParents(editor, startNode, name, vars, similar)) {
|
|
|
13548 |
return true;
|
|
|
13549 |
}
|
|
|
13550 |
}
|
|
|
13551 |
return false;
|
|
|
13552 |
};
|
|
|
13553 |
const matchAll = (editor, names, vars) => {
|
|
|
13554 |
const matchedFormatNames = [];
|
|
|
13555 |
const checkedMap = {};
|
|
|
13556 |
const startElement = editor.selection.getStart();
|
|
|
13557 |
editor.dom.getParent(startElement, node => {
|
|
|
13558 |
for (let i = 0; i < names.length; i++) {
|
|
|
13559 |
const name = names[i];
|
|
|
13560 |
if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
|
|
|
13561 |
checkedMap[name] = true;
|
|
|
13562 |
matchedFormatNames.push(name);
|
|
|
13563 |
}
|
|
|
13564 |
}
|
|
|
13565 |
}, editor.dom.getRoot());
|
|
|
13566 |
return matchedFormatNames;
|
|
|
13567 |
};
|
|
|
13568 |
const closest = (editor, names) => {
|
|
|
13569 |
const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
|
|
|
13570 |
const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none();
|
|
|
13571 |
return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$1(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull();
|
|
|
13572 |
};
|
|
|
13573 |
const canApply = (editor, name) => {
|
|
|
13574 |
const formatList = editor.formatter.get(name);
|
|
|
13575 |
const dom = editor.dom;
|
|
|
13576 |
if (formatList && editor.selection.isEditable()) {
|
|
|
13577 |
const startNode = editor.selection.getStart();
|
|
|
13578 |
const parents = getParents$2(dom, startNode);
|
|
|
13579 |
for (let x = formatList.length - 1; x >= 0; x--) {
|
|
|
13580 |
const format = formatList[x];
|
|
|
13581 |
if (!isSelectorFormat(format)) {
|
|
|
13582 |
return true;
|
|
|
13583 |
}
|
|
|
13584 |
for (let i = parents.length - 1; i >= 0; i--) {
|
|
|
13585 |
if (dom.is(parents[i], format.selector)) {
|
|
|
13586 |
return true;
|
|
|
13587 |
}
|
|
|
13588 |
}
|
|
|
13589 |
}
|
|
|
13590 |
}
|
|
|
13591 |
return false;
|
|
|
13592 |
};
|
|
|
13593 |
const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => {
|
|
|
13594 |
const matchSimilar = isVariableFormatName(editor, name);
|
|
|
13595 |
if (editor.formatter.matchNode(node, name, {}, matchSimilar)) {
|
|
|
13596 |
return acc.concat([name]);
|
|
|
13597 |
} else {
|
|
|
13598 |
return acc;
|
|
|
13599 |
}
|
|
|
13600 |
}, []);
|
|
|
13601 |
|
|
|
13602 |
const ZWSP = ZWSP$1;
|
|
|
13603 |
const importNode = (ownerDocument, node) => {
|
|
|
13604 |
return ownerDocument.importNode(node, true);
|
|
|
13605 |
};
|
|
|
13606 |
const findFirstTextNode = node => {
|
|
|
13607 |
if (node) {
|
|
|
13608 |
const walker = new DomTreeWalker(node, node);
|
|
|
13609 |
for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) {
|
| 1441 |
ariadna |
13610 |
if (isText$b(tempNode)) {
|
| 1 |
efrain |
13611 |
return tempNode;
|
|
|
13612 |
}
|
|
|
13613 |
}
|
|
|
13614 |
}
|
|
|
13615 |
return null;
|
|
|
13616 |
};
|
|
|
13617 |
const createCaretContainer = fill => {
|
|
|
13618 |
const caretContainer = SugarElement.fromTag('span');
|
|
|
13619 |
setAll$1(caretContainer, {
|
|
|
13620 |
'id': CARET_ID,
|
|
|
13621 |
'data-mce-bogus': '1',
|
|
|
13622 |
'data-mce-type': 'format-caret'
|
|
|
13623 |
});
|
|
|
13624 |
if (fill) {
|
|
|
13625 |
append$1(caretContainer, SugarElement.fromText(ZWSP));
|
|
|
13626 |
}
|
|
|
13627 |
return caretContainer;
|
|
|
13628 |
};
|
|
|
13629 |
const trimZwspFromCaretContainer = caretContainerNode => {
|
|
|
13630 |
const textNode = findFirstTextNode(caretContainerNode);
|
|
|
13631 |
if (textNode && textNode.data.charAt(0) === ZWSP) {
|
|
|
13632 |
textNode.deleteData(0, 1);
|
|
|
13633 |
}
|
|
|
13634 |
return textNode;
|
|
|
13635 |
};
|
|
|
13636 |
const removeCaretContainerNode = (editor, node, moveCaret) => {
|
|
|
13637 |
const dom = editor.dom, selection = editor.selection;
|
|
|
13638 |
if (isCaretContainerEmpty(node)) {
|
|
|
13639 |
deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret, true);
|
|
|
13640 |
} else {
|
|
|
13641 |
const rng = selection.getRng();
|
|
|
13642 |
const block = dom.getParent(node, dom.isBlock);
|
|
|
13643 |
const startContainer = rng.startContainer;
|
|
|
13644 |
const startOffset = rng.startOffset;
|
|
|
13645 |
const endContainer = rng.endContainer;
|
|
|
13646 |
const endOffset = rng.endOffset;
|
|
|
13647 |
const textNode = trimZwspFromCaretContainer(node);
|
|
|
13648 |
dom.remove(node, true);
|
|
|
13649 |
if (startContainer === textNode && startOffset > 0) {
|
|
|
13650 |
rng.setStart(textNode, startOffset - 1);
|
|
|
13651 |
}
|
|
|
13652 |
if (endContainer === textNode && endOffset > 0) {
|
|
|
13653 |
rng.setEnd(textNode, endOffset - 1);
|
|
|
13654 |
}
|
|
|
13655 |
if (block && dom.isEmpty(block)) {
|
|
|
13656 |
fillWithPaddingBr(SugarElement.fromDom(block));
|
|
|
13657 |
}
|
|
|
13658 |
selection.setRng(rng);
|
|
|
13659 |
}
|
|
|
13660 |
};
|
|
|
13661 |
const removeCaretContainer = (editor, node, moveCaret) => {
|
|
|
13662 |
const dom = editor.dom, selection = editor.selection;
|
|
|
13663 |
if (!node) {
|
|
|
13664 |
node = getParentCaretContainer(editor.getBody(), selection.getStart());
|
|
|
13665 |
if (!node) {
|
|
|
13666 |
while (node = dom.get(CARET_ID)) {
|
|
|
13667 |
removeCaretContainerNode(editor, node, moveCaret);
|
|
|
13668 |
}
|
|
|
13669 |
}
|
|
|
13670 |
} else {
|
|
|
13671 |
removeCaretContainerNode(editor, node, moveCaret);
|
|
|
13672 |
}
|
|
|
13673 |
};
|
|
|
13674 |
const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
|
|
|
13675 |
var _a, _b;
|
|
|
13676 |
const dom = editor.dom;
|
|
|
13677 |
const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema));
|
|
|
13678 |
if (block && dom.isEmpty(block)) {
|
|
|
13679 |
(_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode);
|
|
|
13680 |
} else {
|
|
|
13681 |
removeTrailingBr(SugarElement.fromDom(formatNode));
|
|
|
13682 |
if (dom.isEmpty(formatNode)) {
|
|
|
13683 |
(_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode);
|
|
|
13684 |
} else {
|
|
|
13685 |
dom.insertAfter(caretContainer, formatNode);
|
|
|
13686 |
}
|
|
|
13687 |
}
|
|
|
13688 |
};
|
|
|
13689 |
const appendNode = (parentNode, node) => {
|
|
|
13690 |
parentNode.appendChild(node);
|
|
|
13691 |
return node;
|
|
|
13692 |
};
|
|
|
13693 |
const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
|
|
|
13694 |
var _a;
|
|
|
13695 |
const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
|
|
|
13696 |
return appendNode(parentNode, formatNode.cloneNode(false));
|
|
|
13697 |
}, caretContainer);
|
|
|
13698 |
const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
|
13699 |
return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP));
|
|
|
13700 |
};
|
|
|
13701 |
const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => {
|
|
|
13702 |
const formatter = editor.formatter;
|
|
|
13703 |
const dom = editor.dom;
|
|
|
13704 |
const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat'));
|
|
|
13705 |
const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
|
|
|
13706 |
const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name));
|
|
|
13707 |
if (uniqueFormats.length > 0) {
|
|
|
13708 |
const clonedFormatNode = formatNode.cloneNode(false);
|
|
|
13709 |
dom.add(caretContainer, clonedFormatNode);
|
|
|
13710 |
formatter.remove(name, vars, clonedFormatNode, similar);
|
|
|
13711 |
dom.remove(clonedFormatNode);
|
|
|
13712 |
return Optional.some(clonedFormatNode);
|
|
|
13713 |
} else {
|
|
|
13714 |
return Optional.none();
|
|
|
13715 |
}
|
|
|
13716 |
};
|
| 1441 |
ariadna |
13717 |
const normalizeNbsps = node => set(node, get$3(node).replace(new RegExp(`${ nbsp }$`), ' '));
|
|
|
13718 |
const normalizeNbspsBetween = (editor, caretContainer) => {
|
|
|
13719 |
const handler = () => {
|
|
|
13720 |
if (caretContainer !== null && !editor.dom.isEmpty(caretContainer)) {
|
|
|
13721 |
prevSibling(SugarElement.fromDom(caretContainer)).each(node => {
|
|
|
13722 |
if (isText$c(node)) {
|
|
|
13723 |
normalizeNbsps(node);
|
|
|
13724 |
} else {
|
|
|
13725 |
descendant$2(node, e => isText$c(e)).each(textNode => {
|
|
|
13726 |
if (isText$c(textNode)) {
|
|
|
13727 |
normalizeNbsps(textNode);
|
|
|
13728 |
}
|
|
|
13729 |
});
|
|
|
13730 |
}
|
|
|
13731 |
});
|
|
|
13732 |
}
|
|
|
13733 |
};
|
|
|
13734 |
editor.once('input', e => {
|
|
|
13735 |
if (e.data && !isWhiteSpace(e.data)) {
|
|
|
13736 |
if (!e.isComposing) {
|
|
|
13737 |
handler();
|
|
|
13738 |
} else {
|
|
|
13739 |
editor.once('compositionend', () => {
|
|
|
13740 |
handler();
|
|
|
13741 |
});
|
|
|
13742 |
}
|
|
|
13743 |
}
|
|
|
13744 |
});
|
|
|
13745 |
};
|
| 1 |
efrain |
13746 |
const applyCaretFormat = (editor, name, vars) => {
|
|
|
13747 |
let caretContainer;
|
|
|
13748 |
const selection = editor.selection;
|
|
|
13749 |
const formatList = editor.formatter.get(name);
|
|
|
13750 |
if (!formatList) {
|
|
|
13751 |
return;
|
|
|
13752 |
}
|
|
|
13753 |
const selectionRng = selection.getRng();
|
|
|
13754 |
let offset = selectionRng.startOffset;
|
|
|
13755 |
const container = selectionRng.startContainer;
|
|
|
13756 |
const text = container.nodeValue;
|
|
|
13757 |
caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
|
|
|
13758 |
const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
|
|
|
13759 |
if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
|
|
|
13760 |
const bookmark = selection.getBookmark();
|
|
|
13761 |
selectionRng.collapse(true);
|
|
|
13762 |
let rng = expandRng(editor.dom, selectionRng, formatList);
|
|
|
13763 |
rng = split(rng);
|
|
|
13764 |
editor.formatter.apply(name, vars, rng);
|
|
|
13765 |
selection.moveToBookmark(bookmark);
|
|
|
13766 |
} else {
|
|
|
13767 |
let textNode = caretContainer ? findFirstTextNode(caretContainer) : null;
|
|
|
13768 |
if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) {
|
|
|
13769 |
caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
|
|
|
13770 |
textNode = caretContainer.firstChild;
|
|
|
13771 |
selectionRng.insertNode(caretContainer);
|
|
|
13772 |
offset = 1;
|
| 1441 |
ariadna |
13773 |
normalizeNbspsBetween(editor, caretContainer);
|
| 1 |
efrain |
13774 |
editor.formatter.apply(name, vars, caretContainer);
|
|
|
13775 |
} else {
|
|
|
13776 |
editor.formatter.apply(name, vars, caretContainer);
|
|
|
13777 |
}
|
|
|
13778 |
selection.setCursorLocation(textNode, offset);
|
|
|
13779 |
}
|
|
|
13780 |
};
|
|
|
13781 |
const removeCaretFormat = (editor, name, vars, similar) => {
|
|
|
13782 |
const dom = editor.dom;
|
|
|
13783 |
const selection = editor.selection;
|
|
|
13784 |
let hasContentAfter = false;
|
|
|
13785 |
const formatList = editor.formatter.get(name);
|
|
|
13786 |
if (!formatList) {
|
|
|
13787 |
return;
|
|
|
13788 |
}
|
|
|
13789 |
const rng = selection.getRng();
|
|
|
13790 |
const container = rng.startContainer;
|
|
|
13791 |
const offset = rng.startOffset;
|
|
|
13792 |
let node = container;
|
| 1441 |
ariadna |
13793 |
if (isText$b(container)) {
|
| 1 |
efrain |
13794 |
if (offset !== container.data.length) {
|
|
|
13795 |
hasContentAfter = true;
|
|
|
13796 |
}
|
|
|
13797 |
node = node.parentNode;
|
|
|
13798 |
}
|
|
|
13799 |
const parents = [];
|
|
|
13800 |
let formatNode;
|
|
|
13801 |
while (node) {
|
|
|
13802 |
if (matchNode(editor, node, name, vars, similar)) {
|
|
|
13803 |
formatNode = node;
|
|
|
13804 |
break;
|
|
|
13805 |
}
|
|
|
13806 |
if (node.nextSibling) {
|
|
|
13807 |
hasContentAfter = true;
|
|
|
13808 |
}
|
|
|
13809 |
parents.push(node);
|
|
|
13810 |
node = node.parentNode;
|
|
|
13811 |
}
|
|
|
13812 |
if (!formatNode) {
|
|
|
13813 |
return;
|
|
|
13814 |
}
|
|
|
13815 |
if (hasContentAfter) {
|
|
|
13816 |
const bookmark = selection.getBookmark();
|
|
|
13817 |
rng.collapse(true);
|
| 1441 |
ariadna |
13818 |
let expandedRng = expandRng(dom, rng, formatList, { includeTrailingSpace: true });
|
| 1 |
efrain |
13819 |
expandedRng = split(expandedRng);
|
|
|
13820 |
editor.formatter.remove(name, vars, expandedRng, similar);
|
|
|
13821 |
selection.moveToBookmark(bookmark);
|
|
|
13822 |
} else {
|
|
|
13823 |
const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
|
|
|
13824 |
const parentsAfter = isNonNullable(caretContainer) ? dom.getParents(formatNode.parentNode, always, caretContainer) : [];
|
|
|
13825 |
const newCaretContainer = createCaretContainer(false).dom;
|
|
|
13826 |
insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode);
|
|
|
13827 |
const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar);
|
|
|
13828 |
const caretTextNode = insertFormatNodesIntoCaretContainer([
|
|
|
13829 |
...parents,
|
|
|
13830 |
...cleanedFormatNode.toArray(),
|
|
|
13831 |
...parentsAfter
|
|
|
13832 |
], newCaretContainer);
|
|
|
13833 |
if (caretContainer) {
|
|
|
13834 |
removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer));
|
|
|
13835 |
}
|
|
|
13836 |
selection.setCursorLocation(caretTextNode, 1);
|
| 1441 |
ariadna |
13837 |
normalizeNbspsBetween(editor, newCaretContainer);
|
| 1 |
efrain |
13838 |
if (dom.isEmpty(formatNode)) {
|
|
|
13839 |
dom.remove(formatNode);
|
|
|
13840 |
}
|
|
|
13841 |
}
|
|
|
13842 |
};
|
|
|
13843 |
const disableCaretContainer = (editor, keyCode, moveCaret) => {
|
|
|
13844 |
const selection = editor.selection, body = editor.getBody();
|
|
|
13845 |
removeCaretContainer(editor, null, moveCaret);
|
|
|
13846 |
if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
|
|
|
13847 |
removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
|
|
|
13848 |
}
|
|
|
13849 |
if (keyCode === 37 || keyCode === 39) {
|
|
|
13850 |
removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
|
|
|
13851 |
}
|
|
|
13852 |
};
|
| 1441 |
ariadna |
13853 |
const endsWithNbsp = element => isText$b(element) && endsWith(element.data, nbsp);
|
| 1 |
efrain |
13854 |
const setup$v = editor => {
|
|
|
13855 |
editor.on('mouseup keydown', e => {
|
|
|
13856 |
disableCaretContainer(editor, e.keyCode, endsWithNbsp(editor.selection.getRng().endContainer));
|
|
|
13857 |
});
|
|
|
13858 |
};
|
|
|
13859 |
const createCaretFormat = formatNodes => {
|
|
|
13860 |
const caretContainer = createCaretContainer(false);
|
|
|
13861 |
const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
|
|
|
13862 |
return {
|
|
|
13863 |
caretContainer,
|
|
|
13864 |
caretPosition: CaretPosition(innerMost, 0)
|
|
|
13865 |
};
|
|
|
13866 |
};
|
|
|
13867 |
const replaceWithCaretFormat = (targetNode, formatNodes) => {
|
|
|
13868 |
const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
|
|
|
13869 |
before$3(SugarElement.fromDom(targetNode), caretContainer);
|
| 1441 |
ariadna |
13870 |
remove$4(SugarElement.fromDom(targetNode));
|
| 1 |
efrain |
13871 |
return caretPosition;
|
|
|
13872 |
};
|
|
|
13873 |
const createCaretFormatAtStart$1 = (rng, formatNodes) => {
|
|
|
13874 |
const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
|
|
|
13875 |
rng.insertNode(caretContainer.dom);
|
|
|
13876 |
return caretPosition;
|
|
|
13877 |
};
|
|
|
13878 |
const isFormatElement = (editor, element) => {
|
|
|
13879 |
if (isCaretNode(element.dom)) {
|
|
|
13880 |
return false;
|
|
|
13881 |
}
|
|
|
13882 |
const inlineElements = editor.schema.getTextInlineElements();
|
| 1441 |
ariadna |
13883 |
return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$1(element.dom);
|
| 1 |
efrain |
13884 |
};
|
|
|
13885 |
|
|
|
13886 |
const postProcessHooks = {};
|
|
|
13887 |
const isPre = matchNodeNames(['pre']);
|
|
|
13888 |
const addPostProcessHook = (name, hook) => {
|
|
|
13889 |
const hooks = postProcessHooks[name];
|
|
|
13890 |
if (!hooks) {
|
|
|
13891 |
postProcessHooks[name] = [];
|
|
|
13892 |
}
|
|
|
13893 |
postProcessHooks[name].push(hook);
|
|
|
13894 |
};
|
|
|
13895 |
const postProcess$1 = (name, editor) => {
|
|
|
13896 |
if (has$2(postProcessHooks, name)) {
|
|
|
13897 |
each$e(postProcessHooks[name], hook => {
|
|
|
13898 |
hook(editor);
|
|
|
13899 |
});
|
|
|
13900 |
}
|
|
|
13901 |
};
|
|
|
13902 |
addPostProcessHook('pre', editor => {
|
|
|
13903 |
const rng = editor.selection.getRng();
|
|
|
13904 |
const hasPreSibling = blocks => pre => {
|
|
|
13905 |
const prev = pre.previousSibling;
|
|
|
13906 |
return isPre(prev) && contains$2(blocks, prev);
|
|
|
13907 |
};
|
|
|
13908 |
const joinPre = (pre1, pre2) => {
|
|
|
13909 |
const sPre2 = SugarElement.fromDom(pre2);
|
|
|
13910 |
const doc = documentOrOwner(sPre2).dom;
|
| 1441 |
ariadna |
13911 |
remove$4(sPre2);
|
| 1 |
efrain |
13912 |
append(SugarElement.fromDom(pre1), [
|
|
|
13913 |
SugarElement.fromTag('br', doc),
|
|
|
13914 |
SugarElement.fromTag('br', doc),
|
|
|
13915 |
...children$1(sPre2)
|
|
|
13916 |
]);
|
|
|
13917 |
};
|
|
|
13918 |
if (!rng.collapsed) {
|
|
|
13919 |
const blocks = editor.selection.getSelectedBlocks();
|
|
|
13920 |
const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks));
|
|
|
13921 |
each$e(preBlocks, pre => {
|
|
|
13922 |
joinPre(pre.previousSibling, pre);
|
|
|
13923 |
});
|
|
|
13924 |
}
|
|
|
13925 |
});
|
|
|
13926 |
|
|
|
13927 |
const listItemStyles = [
|
|
|
13928 |
'fontWeight',
|
|
|
13929 |
'fontStyle',
|
|
|
13930 |
'color',
|
|
|
13931 |
'fontSize',
|
|
|
13932 |
'fontFamily'
|
|
|
13933 |
];
|
|
|
13934 |
const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name));
|
|
|
13935 |
const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt));
|
|
|
13936 |
const getExpandedListItemFormat = (formatter, format) => {
|
|
|
13937 |
const formatList = formatter.get(format);
|
|
|
13938 |
return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none();
|
|
|
13939 |
};
|
|
|
13940 |
const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone();
|
|
|
13941 |
const isRngEndAtEndOfElement = (rng, elm) => {
|
|
|
13942 |
return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
|
|
|
13943 |
};
|
|
|
13944 |
const isEditableListItem = dom => elm => isListItem$2(elm) && dom.isEditable(elm);
|
|
|
13945 |
const getFullySelectedBlocks = selection => {
|
|
|
13946 |
const blocks = selection.getSelectedBlocks();
|
|
|
13947 |
const rng = selection.getRng();
|
|
|
13948 |
if (selection.isCollapsed()) {
|
|
|
13949 |
return [];
|
|
|
13950 |
}
|
|
|
13951 |
if (blocks.length === 1) {
|
|
|
13952 |
return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
|
|
|
13953 |
} else {
|
|
|
13954 |
const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray();
|
| 1441 |
ariadna |
13955 |
const last = last$2(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray();
|
| 1 |
efrain |
13956 |
const middle = blocks.slice(1, -1);
|
|
|
13957 |
return first.concat(middle).concat(last);
|
|
|
13958 |
}
|
|
|
13959 |
};
|
|
|
13960 |
const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
|
|
|
13961 |
const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
|
|
|
13962 |
|
|
|
13963 |
const each$8 = Tools.each;
|
| 1441 |
ariadna |
13964 |
const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
|
| 1 |
efrain |
13965 |
const findElementSibling = (node, siblingName) => {
|
|
|
13966 |
for (let sibling = node; sibling; sibling = sibling[siblingName]) {
|
| 1441 |
ariadna |
13967 |
if (isText$b(sibling) && isNotEmpty(sibling.data)) {
|
| 1 |
efrain |
13968 |
return node;
|
|
|
13969 |
}
|
|
|
13970 |
if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) {
|
|
|
13971 |
return sibling;
|
|
|
13972 |
}
|
|
|
13973 |
}
|
|
|
13974 |
return node;
|
|
|
13975 |
};
|
|
|
13976 |
const mergeSiblingsNodes = (editor, prev, next) => {
|
|
|
13977 |
const elementUtils = ElementUtils(editor);
|
|
|
13978 |
const isPrevEditable = isHTMLElement(prev) && editor.dom.isEditable(prev);
|
|
|
13979 |
const isNextEditable = isHTMLElement(next) && editor.dom.isEditable(next);
|
|
|
13980 |
if (isPrevEditable && isNextEditable) {
|
|
|
13981 |
const prevSibling = findElementSibling(prev, 'previousSibling');
|
|
|
13982 |
const nextSibling = findElementSibling(next, 'nextSibling');
|
|
|
13983 |
if (elementUtils.compare(prevSibling, nextSibling)) {
|
|
|
13984 |
for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) {
|
|
|
13985 |
const tmpSibling = sibling;
|
|
|
13986 |
sibling = sibling.nextSibling;
|
|
|
13987 |
prevSibling.appendChild(tmpSibling);
|
|
|
13988 |
}
|
|
|
13989 |
editor.dom.remove(nextSibling);
|
|
|
13990 |
Tools.each(Tools.grep(nextSibling.childNodes), node => {
|
|
|
13991 |
prevSibling.appendChild(node);
|
|
|
13992 |
});
|
|
|
13993 |
return prevSibling;
|
|
|
13994 |
}
|
|
|
13995 |
}
|
|
|
13996 |
return next;
|
|
|
13997 |
};
|
|
|
13998 |
const mergeSiblings = (editor, format, vars, node) => {
|
|
|
13999 |
var _a;
|
|
|
14000 |
if (node && format.merge_siblings !== false) {
|
|
|
14001 |
const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node;
|
|
|
14002 |
mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true));
|
|
|
14003 |
}
|
|
|
14004 |
};
|
|
|
14005 |
const clearChildStyles = (dom, format, node) => {
|
|
|
14006 |
if (format.clear_child_styles) {
|
|
|
14007 |
const selector = format.links ? '*:not(a)' : '*';
|
|
|
14008 |
each$8(dom.select(selector, node), childNode => {
|
|
|
14009 |
if (isElementNode(childNode) && dom.isEditable(childNode)) {
|
|
|
14010 |
each$8(format.styles, (_value, name) => {
|
|
|
14011 |
dom.setStyle(childNode, name, '');
|
|
|
14012 |
});
|
|
|
14013 |
}
|
|
|
14014 |
});
|
|
|
14015 |
}
|
|
|
14016 |
};
|
|
|
14017 |
const processChildElements = (node, filter, process) => {
|
|
|
14018 |
each$8(node.childNodes, node => {
|
|
|
14019 |
if (isElementNode(node)) {
|
|
|
14020 |
if (filter(node)) {
|
|
|
14021 |
process(node);
|
|
|
14022 |
}
|
|
|
14023 |
if (node.hasChildNodes()) {
|
|
|
14024 |
processChildElements(node, filter, process);
|
|
|
14025 |
}
|
|
|
14026 |
}
|
|
|
14027 |
});
|
|
|
14028 |
};
|
|
|
14029 |
const unwrapEmptySpan = (dom, node) => {
|
|
|
14030 |
if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
|
|
|
14031 |
dom.remove(node, true);
|
|
|
14032 |
}
|
|
|
14033 |
};
|
|
|
14034 |
const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name));
|
|
|
14035 |
const applyStyle = (dom, name, value) => node => {
|
|
|
14036 |
dom.setStyle(node, name, value);
|
|
|
14037 |
if (node.getAttribute('style') === '') {
|
|
|
14038 |
node.removeAttribute('style');
|
|
|
14039 |
}
|
|
|
14040 |
unwrapEmptySpan(dom, node);
|
|
|
14041 |
};
|
|
|
14042 |
|
|
|
14043 |
const removeResult = Adt.generate([
|
|
|
14044 |
{ keep: [] },
|
|
|
14045 |
{ rename: ['name'] },
|
|
|
14046 |
{ removed: [] }
|
|
|
14047 |
]);
|
|
|
14048 |
const MCE_ATTR_RE = /^(src|href|style)$/;
|
|
|
14049 |
const each$7 = Tools.each;
|
|
|
14050 |
const isEq$2 = isEq$5;
|
|
|
14051 |
const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName);
|
|
|
14052 |
const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
|
|
|
14053 |
const getContainer = (ed, rng, start) => {
|
|
|
14054 |
let container = rng[start ? 'startContainer' : 'endContainer'];
|
|
|
14055 |
let offset = rng[start ? 'startOffset' : 'endOffset'];
|
|
|
14056 |
if (isElement$6(container)) {
|
|
|
14057 |
const lastIdx = container.childNodes.length - 1;
|
|
|
14058 |
if (!start && offset) {
|
|
|
14059 |
offset--;
|
|
|
14060 |
}
|
|
|
14061 |
container = container.childNodes[offset > lastIdx ? lastIdx : offset];
|
|
|
14062 |
}
|
| 1441 |
ariadna |
14063 |
if (isText$b(container) && start && offset >= container.data.length) {
|
| 1 |
efrain |
14064 |
container = new DomTreeWalker(container, ed.getBody()).next() || container;
|
|
|
14065 |
}
|
| 1441 |
ariadna |
14066 |
if (isText$b(container) && !start && offset === 0) {
|
| 1 |
efrain |
14067 |
container = new DomTreeWalker(container, ed.getBody()).prev() || container;
|
|
|
14068 |
}
|
|
|
14069 |
return container;
|
|
|
14070 |
};
|
|
|
14071 |
const normalizeTableSelection = (node, start) => {
|
|
|
14072 |
const prop = start ? 'firstChild' : 'lastChild';
|
|
|
14073 |
const childNode = node[prop];
|
|
|
14074 |
if (isTableCellOrRow(node) && childNode) {
|
|
|
14075 |
if (node.nodeName === 'TR') {
|
|
|
14076 |
return childNode[prop] || childNode;
|
|
|
14077 |
} else {
|
|
|
14078 |
return childNode;
|
|
|
14079 |
}
|
|
|
14080 |
}
|
|
|
14081 |
return node;
|
|
|
14082 |
};
|
|
|
14083 |
const wrap$1 = (dom, node, name, attrs) => {
|
|
|
14084 |
var _a;
|
|
|
14085 |
const wrapper = dom.create(name, attrs);
|
|
|
14086 |
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node);
|
|
|
14087 |
wrapper.appendChild(node);
|
|
|
14088 |
return wrapper;
|
|
|
14089 |
};
|
|
|
14090 |
const wrapWithSiblings = (dom, node, next, name, attrs) => {
|
|
|
14091 |
const start = SugarElement.fromDom(node);
|
|
|
14092 |
const wrapper = SugarElement.fromDom(dom.create(name, attrs));
|
|
|
14093 |
const siblings = next ? nextSiblings(start) : prevSiblings(start);
|
|
|
14094 |
append(wrapper, siblings);
|
|
|
14095 |
if (next) {
|
|
|
14096 |
before$3(start, wrapper);
|
|
|
14097 |
prepend(wrapper, start);
|
|
|
14098 |
} else {
|
|
|
14099 |
after$4(start, wrapper);
|
|
|
14100 |
append$1(wrapper, start);
|
|
|
14101 |
}
|
|
|
14102 |
return wrapper.dom;
|
|
|
14103 |
};
|
|
|
14104 |
const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A';
|
|
|
14105 |
const removeNode = (ed, node, format) => {
|
|
|
14106 |
const parentNode = node.parentNode;
|
|
|
14107 |
let rootBlockElm;
|
|
|
14108 |
const dom = ed.dom;
|
|
|
14109 |
const forcedRootBlock = getForcedRootBlock(ed);
|
|
|
14110 |
if (isBlockFormat(format)) {
|
|
|
14111 |
if (parentNode === dom.getRoot()) {
|
|
|
14112 |
if (!format.list_block || !isEq$2(node, format.list_block)) {
|
|
|
14113 |
each$e(from(node.childNodes), node => {
|
|
|
14114 |
if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
|
|
|
14115 |
if (!rootBlockElm) {
|
|
|
14116 |
rootBlockElm = wrap$1(dom, node, forcedRootBlock);
|
|
|
14117 |
dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
|
|
|
14118 |
} else {
|
|
|
14119 |
rootBlockElm.appendChild(node);
|
|
|
14120 |
}
|
|
|
14121 |
} else {
|
|
|
14122 |
rootBlockElm = null;
|
|
|
14123 |
}
|
|
|
14124 |
});
|
|
|
14125 |
}
|
|
|
14126 |
}
|
|
|
14127 |
}
|
|
|
14128 |
if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
|
|
|
14129 |
return;
|
|
|
14130 |
}
|
|
|
14131 |
dom.remove(node, true);
|
|
|
14132 |
};
|
|
|
14133 |
const processFormatAttrOrStyle = (name, value, vars) => {
|
|
|
14134 |
if (isNumber(name)) {
|
|
|
14135 |
return {
|
|
|
14136 |
name: value,
|
|
|
14137 |
value: null
|
|
|
14138 |
};
|
|
|
14139 |
} else {
|
|
|
14140 |
return {
|
|
|
14141 |
name,
|
|
|
14142 |
value: replaceVars(value, vars)
|
|
|
14143 |
};
|
|
|
14144 |
}
|
|
|
14145 |
};
|
|
|
14146 |
const removeEmptyStyleAttributeIfNeeded = (dom, elm) => {
|
|
|
14147 |
if (dom.getAttrib(elm, 'style') === '') {
|
|
|
14148 |
elm.removeAttribute('style');
|
|
|
14149 |
elm.removeAttribute('data-mce-style');
|
|
|
14150 |
}
|
|
|
14151 |
};
|
|
|
14152 |
const removeStyles = (dom, elm, format, vars, compareNode) => {
|
|
|
14153 |
let stylesModified = false;
|
|
|
14154 |
each$7(format.styles, (value, name) => {
|
|
|
14155 |
const {
|
|
|
14156 |
name: styleName,
|
|
|
14157 |
value: styleValue
|
|
|
14158 |
} = processFormatAttrOrStyle(name, value, vars);
|
|
|
14159 |
const normalizedStyleValue = normalizeStyleValue(styleValue, styleName);
|
|
|
14160 |
if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) {
|
|
|
14161 |
dom.setStyle(elm, styleName, '');
|
|
|
14162 |
}
|
|
|
14163 |
stylesModified = true;
|
|
|
14164 |
});
|
|
|
14165 |
if (stylesModified) {
|
|
|
14166 |
removeEmptyStyleAttributeIfNeeded(dom, elm);
|
|
|
14167 |
}
|
|
|
14168 |
};
|
|
|
14169 |
const removeListStyleFormats = (editor, name, vars) => {
|
|
|
14170 |
if (name === 'removeformat') {
|
|
|
14171 |
each$e(getPartiallySelectedListItems(editor.selection), li => {
|
|
|
14172 |
each$e(listItemStyles, name => editor.dom.setStyle(li, name, ''));
|
|
|
14173 |
removeEmptyStyleAttributeIfNeeded(editor.dom, li);
|
|
|
14174 |
});
|
|
|
14175 |
} else {
|
|
|
14176 |
getExpandedListItemFormat(editor.formatter, name).each(liFmt => {
|
|
|
14177 |
each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null));
|
|
|
14178 |
});
|
|
|
14179 |
}
|
|
|
14180 |
};
|
|
|
14181 |
const removeNodeFormatInternal = (ed, format, vars, node, compareNode) => {
|
|
|
14182 |
const dom = ed.dom;
|
|
|
14183 |
const elementUtils = ElementUtils(ed);
|
|
|
14184 |
const schema = ed.schema;
|
|
|
14185 |
if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) {
|
|
|
14186 |
removeNode(ed, node, format);
|
|
|
14187 |
return removeResult.removed();
|
|
|
14188 |
}
|
|
|
14189 |
if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') {
|
|
|
14190 |
return removeResult.keep();
|
|
|
14191 |
}
|
|
|
14192 |
if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
|
|
|
14193 |
return removeResult.keep();
|
|
|
14194 |
}
|
|
|
14195 |
const elm = node;
|
|
|
14196 |
const preserveAttributes = format.preserve_attributes;
|
|
|
14197 |
if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) {
|
|
|
14198 |
const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase()));
|
|
|
14199 |
dom.removeAllAttribs(elm);
|
|
|
14200 |
each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value));
|
|
|
14201 |
if (attrsToPreserve.length > 0) {
|
|
|
14202 |
return removeResult.rename('span');
|
|
|
14203 |
}
|
|
|
14204 |
}
|
|
|
14205 |
if (format.remove !== 'all') {
|
|
|
14206 |
removeStyles(dom, elm, format, vars, compareNode);
|
|
|
14207 |
each$7(format.attributes, (value, name) => {
|
|
|
14208 |
const {
|
|
|
14209 |
name: attrName,
|
|
|
14210 |
value: attrValue
|
|
|
14211 |
} = processFormatAttrOrStyle(name, value, vars);
|
|
|
14212 |
if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) {
|
|
|
14213 |
if (attrName === 'class') {
|
|
|
14214 |
const currentValue = dom.getAttrib(elm, attrName);
|
|
|
14215 |
if (currentValue) {
|
|
|
14216 |
let valueOut = '';
|
|
|
14217 |
each$e(currentValue.split(/\s+/), cls => {
|
|
|
14218 |
if (/mce\-\w+/.test(cls)) {
|
|
|
14219 |
valueOut += (valueOut ? ' ' : '') + cls;
|
|
|
14220 |
}
|
|
|
14221 |
});
|
|
|
14222 |
if (valueOut) {
|
|
|
14223 |
dom.setAttrib(elm, attrName, valueOut);
|
|
|
14224 |
return;
|
|
|
14225 |
}
|
|
|
14226 |
}
|
|
|
14227 |
}
|
|
|
14228 |
if (MCE_ATTR_RE.test(attrName)) {
|
|
|
14229 |
elm.removeAttribute('data-mce-' + attrName);
|
|
|
14230 |
}
|
|
|
14231 |
if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') {
|
|
|
14232 |
elm.removeAttribute(attrName);
|
|
|
14233 |
dom.setStyle(elm, 'list-style-type', 'none');
|
|
|
14234 |
return;
|
|
|
14235 |
}
|
|
|
14236 |
if (attrName === 'class') {
|
|
|
14237 |
elm.removeAttribute('className');
|
|
|
14238 |
}
|
|
|
14239 |
elm.removeAttribute(attrName);
|
|
|
14240 |
}
|
|
|
14241 |
});
|
|
|
14242 |
each$7(format.classes, value => {
|
|
|
14243 |
value = replaceVars(value, vars);
|
|
|
14244 |
if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) {
|
|
|
14245 |
dom.removeClass(elm, value);
|
|
|
14246 |
}
|
|
|
14247 |
});
|
|
|
14248 |
const attrs = dom.getAttribs(elm);
|
|
|
14249 |
for (let i = 0; i < attrs.length; i++) {
|
|
|
14250 |
const attrName = attrs[i].nodeName;
|
|
|
14251 |
if (!elementUtils.isAttributeInternal(attrName)) {
|
|
|
14252 |
return removeResult.keep();
|
|
|
14253 |
}
|
|
|
14254 |
}
|
|
|
14255 |
}
|
|
|
14256 |
if (format.remove !== 'none') {
|
|
|
14257 |
removeNode(ed, elm, format);
|
|
|
14258 |
return removeResult.removed();
|
|
|
14259 |
}
|
|
|
14260 |
return removeResult.keep();
|
|
|
14261 |
};
|
|
|
14262 |
const findFormatRoot = (editor, container, name, vars, similar) => {
|
|
|
14263 |
let formatRoot;
|
|
|
14264 |
if (container.parentNode) {
|
|
|
14265 |
each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => {
|
|
|
14266 |
if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') {
|
|
|
14267 |
const format = matchNode(editor, parent, name, vars, similar);
|
|
|
14268 |
if (format && format.split !== false) {
|
|
|
14269 |
formatRoot = parent;
|
|
|
14270 |
}
|
|
|
14271 |
}
|
|
|
14272 |
});
|
|
|
14273 |
}
|
|
|
14274 |
return formatRoot;
|
|
|
14275 |
};
|
|
|
14276 |
const removeNodeFormatFromClone = (editor, format, vars, clone) => removeNodeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => {
|
|
|
14277 |
const fragment = editor.dom.createFragment();
|
|
|
14278 |
fragment.appendChild(clone);
|
|
|
14279 |
return editor.dom.rename(clone, newName);
|
|
|
14280 |
}, constant(null));
|
|
|
14281 |
const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => {
|
|
|
14282 |
var _a, _b;
|
|
|
14283 |
let lastClone;
|
|
|
14284 |
let firstClone;
|
|
|
14285 |
const dom = editor.dom;
|
|
|
14286 |
if (formatRoot) {
|
|
|
14287 |
const formatRootParent = formatRoot.parentNode;
|
|
|
14288 |
for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
|
|
|
14289 |
let clone = dom.clone(parent, false);
|
|
|
14290 |
for (let i = 0; i < formatList.length; i++) {
|
|
|
14291 |
clone = removeNodeFormatFromClone(editor, formatList[i], vars, clone);
|
|
|
14292 |
if (clone === null) {
|
|
|
14293 |
break;
|
|
|
14294 |
}
|
|
|
14295 |
}
|
|
|
14296 |
if (clone) {
|
|
|
14297 |
if (lastClone) {
|
|
|
14298 |
clone.appendChild(lastClone);
|
|
|
14299 |
}
|
|
|
14300 |
if (!firstClone) {
|
|
|
14301 |
firstClone = clone;
|
|
|
14302 |
}
|
|
|
14303 |
lastClone = clone;
|
|
|
14304 |
}
|
|
|
14305 |
}
|
|
|
14306 |
if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
|
|
|
14307 |
container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container;
|
|
|
14308 |
}
|
|
|
14309 |
if (lastClone && firstClone) {
|
|
|
14310 |
(_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target);
|
|
|
14311 |
firstClone.appendChild(target);
|
|
|
14312 |
if (isInlineFormat(format)) {
|
|
|
14313 |
mergeSiblings(editor, format, vars, lastClone);
|
|
|
14314 |
}
|
|
|
14315 |
}
|
|
|
14316 |
}
|
|
|
14317 |
return container;
|
|
|
14318 |
};
|
|
|
14319 |
const removeFormatInternal = (ed, name, vars, node, similar) => {
|
|
|
14320 |
const formatList = ed.formatter.get(name);
|
|
|
14321 |
const format = formatList[0];
|
|
|
14322 |
const dom = ed.dom;
|
|
|
14323 |
const selection = ed.selection;
|
|
|
14324 |
const splitToFormatRoot = container => {
|
|
|
14325 |
const formatRoot = findFormatRoot(ed, container, name, vars, similar);
|
|
|
14326 |
return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
|
|
|
14327 |
};
|
|
|
14328 |
const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end');
|
|
|
14329 |
const removeFormatOnNode = node => exists(formatList, fmt => removeNodeFormat(ed, fmt, vars, node, node));
|
|
|
14330 |
const process = node => {
|
|
|
14331 |
const children = from(node.childNodes);
|
|
|
14332 |
const removed = removeFormatOnNode(node);
|
|
|
14333 |
const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f));
|
|
|
14334 |
const parentNode = node.parentNode;
|
|
|
14335 |
if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
|
|
|
14336 |
removeFormatOnNode(parentNode);
|
|
|
14337 |
}
|
|
|
14338 |
if (format.deep) {
|
|
|
14339 |
if (children.length) {
|
|
|
14340 |
for (let i = 0; i < children.length; i++) {
|
|
|
14341 |
process(children[i]);
|
|
|
14342 |
}
|
|
|
14343 |
}
|
|
|
14344 |
}
|
|
|
14345 |
const textDecorations = [
|
|
|
14346 |
'underline',
|
|
|
14347 |
'line-through',
|
|
|
14348 |
'overline'
|
|
|
14349 |
];
|
|
|
14350 |
each$e(textDecorations, decoration => {
|
|
|
14351 |
if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) {
|
|
|
14352 |
removeNodeFormat(ed, {
|
|
|
14353 |
deep: false,
|
|
|
14354 |
exact: true,
|
|
|
14355 |
inline: 'span',
|
|
|
14356 |
styles: { textDecoration: decoration }
|
|
|
14357 |
}, undefined, node);
|
|
|
14358 |
}
|
|
|
14359 |
});
|
|
|
14360 |
};
|
|
|
14361 |
const unwrap = start => {
|
|
|
14362 |
const node = dom.get(start ? '_start' : '_end');
|
|
|
14363 |
if (node) {
|
|
|
14364 |
let out = node[start ? 'firstChild' : 'lastChild'];
|
|
|
14365 |
if (isRemoveBookmarkNode(out)) {
|
|
|
14366 |
out = out[start ? 'firstChild' : 'lastChild'];
|
|
|
14367 |
}
|
| 1441 |
ariadna |
14368 |
if (isText$b(out) && out.data.length === 0) {
|
| 1 |
efrain |
14369 |
out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
|
|
|
14370 |
}
|
|
|
14371 |
dom.remove(node, true);
|
|
|
14372 |
return out;
|
|
|
14373 |
} else {
|
|
|
14374 |
return null;
|
|
|
14375 |
}
|
|
|
14376 |
};
|
|
|
14377 |
const removeRngStyle = rng => {
|
|
|
14378 |
let startContainer;
|
|
|
14379 |
let endContainer;
|
| 1441 |
ariadna |
14380 |
let expandedRng = expandRng(dom, rng, formatList, { includeTrailingSpace: rng.collapsed });
|
| 1 |
efrain |
14381 |
if (format.split) {
|
|
|
14382 |
expandedRng = split(expandedRng);
|
|
|
14383 |
startContainer = getContainer(ed, expandedRng, true);
|
|
|
14384 |
endContainer = getContainer(ed, expandedRng);
|
|
|
14385 |
if (startContainer !== endContainer) {
|
|
|
14386 |
startContainer = normalizeTableSelection(startContainer, true);
|
|
|
14387 |
endContainer = normalizeTableSelection(endContainer, false);
|
|
|
14388 |
if (isChildOfInlineParent(dom, startContainer, endContainer)) {
|
|
|
14389 |
const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
|
|
|
14390 |
splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
|
|
|
14391 |
'id': '_start',
|
|
|
14392 |
'data-mce-type': 'bookmark'
|
|
|
14393 |
}));
|
|
|
14394 |
unwrap(true);
|
|
|
14395 |
return;
|
|
|
14396 |
}
|
|
|
14397 |
if (isChildOfInlineParent(dom, endContainer, startContainer)) {
|
|
|
14398 |
const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
|
|
|
14399 |
splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
|
|
|
14400 |
'id': '_end',
|
|
|
14401 |
'data-mce-type': 'bookmark'
|
|
|
14402 |
}));
|
|
|
14403 |
unwrap(false);
|
|
|
14404 |
return;
|
|
|
14405 |
}
|
|
|
14406 |
startContainer = wrap$1(dom, startContainer, 'span', {
|
|
|
14407 |
'id': '_start',
|
|
|
14408 |
'data-mce-type': 'bookmark'
|
|
|
14409 |
});
|
|
|
14410 |
endContainer = wrap$1(dom, endContainer, 'span', {
|
|
|
14411 |
'id': '_end',
|
|
|
14412 |
'data-mce-type': 'bookmark'
|
|
|
14413 |
});
|
|
|
14414 |
const newRng = dom.createRng();
|
|
|
14415 |
newRng.setStartAfter(startContainer);
|
|
|
14416 |
newRng.setEndBefore(endContainer);
|
|
|
14417 |
walk$3(dom, newRng, nodes => {
|
|
|
14418 |
each$e(nodes, n => {
|
|
|
14419 |
if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
|
|
|
14420 |
splitToFormatRoot(n);
|
|
|
14421 |
}
|
|
|
14422 |
});
|
|
|
14423 |
});
|
|
|
14424 |
splitToFormatRoot(startContainer);
|
|
|
14425 |
splitToFormatRoot(endContainer);
|
|
|
14426 |
startContainer = unwrap(true);
|
|
|
14427 |
endContainer = unwrap();
|
|
|
14428 |
} else {
|
|
|
14429 |
startContainer = endContainer = splitToFormatRoot(startContainer);
|
|
|
14430 |
}
|
|
|
14431 |
expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
|
|
|
14432 |
expandedRng.startOffset = dom.nodeIndex(startContainer);
|
|
|
14433 |
expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
|
|
|
14434 |
expandedRng.endOffset = dom.nodeIndex(endContainer) + 1;
|
|
|
14435 |
}
|
|
|
14436 |
walk$3(dom, expandedRng, nodes => {
|
|
|
14437 |
each$e(nodes, process);
|
|
|
14438 |
});
|
|
|
14439 |
};
|
|
|
14440 |
if (node) {
|
|
|
14441 |
if (isNode(node)) {
|
|
|
14442 |
const rng = dom.createRng();
|
|
|
14443 |
rng.setStartBefore(node);
|
|
|
14444 |
rng.setEndAfter(node);
|
|
|
14445 |
removeRngStyle(rng);
|
|
|
14446 |
} else {
|
|
|
14447 |
removeRngStyle(node);
|
|
|
14448 |
}
|
|
|
14449 |
fireFormatRemove(ed, name, node, vars);
|
|
|
14450 |
return;
|
|
|
14451 |
}
|
|
|
14452 |
if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
|
|
|
14453 |
preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode));
|
|
|
14454 |
ed.nodeChanged();
|
|
|
14455 |
} else {
|
|
|
14456 |
removeCaretFormat(ed, name, vars, similar);
|
|
|
14457 |
}
|
|
|
14458 |
removeListStyleFormats(ed, name, vars);
|
|
|
14459 |
fireFormatRemove(ed, name, node, vars);
|
|
|
14460 |
};
|
|
|
14461 |
const removeFormat$1 = (ed, name, vars, node, similar) => {
|
|
|
14462 |
if (node || ed.selection.isEditable()) {
|
|
|
14463 |
removeFormatInternal(ed, name, vars, node, similar);
|
|
|
14464 |
}
|
|
|
14465 |
};
|
|
|
14466 |
const removeNodeFormat = (editor, format, vars, node, compareNode) => {
|
|
|
14467 |
return removeNodeFormatInternal(editor, format, vars, node, compareNode).fold(never, newName => {
|
|
|
14468 |
editor.dom.rename(node, newName);
|
|
|
14469 |
return true;
|
|
|
14470 |
}, always);
|
|
|
14471 |
};
|
|
|
14472 |
|
|
|
14473 |
const each$6 = Tools.each;
|
|
|
14474 |
const mergeTextDecorationsAndColor = (dom, format, vars, node) => {
|
|
|
14475 |
const processTextDecorationsAndColor = n => {
|
|
|
14476 |
if (isHTMLElement(n) && isElement$6(n.parentNode) && dom.isEditable(n)) {
|
|
|
14477 |
const parentTextDecoration = getTextDecoration(dom, n.parentNode);
|
|
|
14478 |
if (dom.getStyle(n, 'color') && parentTextDecoration) {
|
|
|
14479 |
dom.setStyle(n, 'text-decoration', parentTextDecoration);
|
|
|
14480 |
} else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) {
|
|
|
14481 |
dom.setStyle(n, 'text-decoration', null);
|
|
|
14482 |
}
|
|
|
14483 |
}
|
|
|
14484 |
};
|
|
|
14485 |
if (format.styles && (format.styles.color || format.styles.textDecoration)) {
|
|
|
14486 |
Tools.walk(node, processTextDecorationsAndColor, 'childNodes');
|
|
|
14487 |
processTextDecorationsAndColor(node);
|
|
|
14488 |
}
|
|
|
14489 |
};
|
|
|
14490 |
const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => {
|
|
|
14491 |
if (format.styles && format.styles.backgroundColor) {
|
|
|
14492 |
const hasFontSize = hasStyle(dom, 'fontSize');
|
|
|
14493 |
processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars)));
|
|
|
14494 |
}
|
|
|
14495 |
};
|
|
|
14496 |
const mergeSubSup = (dom, format, vars, node) => {
|
|
|
14497 |
if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) {
|
|
|
14498 |
const hasFontSize = hasStyle(dom, 'fontSize');
|
|
|
14499 |
processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'fontSize', ''));
|
|
|
14500 |
const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), dom.isEditable);
|
|
|
14501 |
dom.remove(inverseTagDescendants, true);
|
|
|
14502 |
}
|
|
|
14503 |
};
|
|
|
14504 |
const mergeWithChildren = (editor, formatList, vars, node) => {
|
|
|
14505 |
each$6(formatList, format => {
|
|
|
14506 |
if (isInlineFormat(format)) {
|
|
|
14507 |
each$6(editor.dom.select(format.inline, node), child => {
|
|
|
14508 |
if (isElementNode(child)) {
|
|
|
14509 |
removeNodeFormat(editor, format, vars, child, format.exact ? child : null);
|
|
|
14510 |
}
|
|
|
14511 |
});
|
|
|
14512 |
}
|
|
|
14513 |
clearChildStyles(editor.dom, format, node);
|
|
|
14514 |
});
|
|
|
14515 |
};
|
|
|
14516 |
const mergeWithParents = (editor, format, name, vars, node) => {
|
|
|
14517 |
const parentNode = node.parentNode;
|
|
|
14518 |
if (matchNode(editor, parentNode, name, vars)) {
|
|
|
14519 |
if (removeNodeFormat(editor, format, vars, node)) {
|
|
|
14520 |
return;
|
|
|
14521 |
}
|
|
|
14522 |
}
|
|
|
14523 |
if (format.merge_with_parents && parentNode) {
|
|
|
14524 |
editor.dom.getParent(parentNode, parent => {
|
|
|
14525 |
if (matchNode(editor, parent, name, vars)) {
|
|
|
14526 |
removeNodeFormat(editor, format, vars, node);
|
|
|
14527 |
return true;
|
|
|
14528 |
} else {
|
|
|
14529 |
return false;
|
|
|
14530 |
}
|
|
|
14531 |
});
|
|
|
14532 |
}
|
|
|
14533 |
};
|
|
|
14534 |
|
|
|
14535 |
const each$5 = Tools.each;
|
|
|
14536 |
const canFormatBR = (editor, format, node, parentName) => {
|
|
|
14537 |
if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) {
|
|
|
14538 |
const validBRParentElements = getTextRootBlockElements(editor.schema);
|
|
|
14539 |
const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom));
|
| 1441 |
ariadna |
14540 |
return hasNonNullableKey(validBRParentElements, parentName) && isEmptyNode(editor.schema, node.parentNode, {
|
|
|
14541 |
skipBogus: false,
|
|
|
14542 |
includeZwsp: true
|
|
|
14543 |
}) && !hasCaretNodeSibling;
|
| 1 |
efrain |
14544 |
} else {
|
|
|
14545 |
return false;
|
|
|
14546 |
}
|
|
|
14547 |
};
|
|
|
14548 |
const applyStyles = (dom, elm, format, vars) => {
|
|
|
14549 |
each$5(format.styles, (value, name) => {
|
|
|
14550 |
dom.setStyle(elm, name, replaceVars(value, vars));
|
|
|
14551 |
});
|
|
|
14552 |
if (format.styles) {
|
|
|
14553 |
const styleVal = dom.getAttrib(elm, 'style');
|
|
|
14554 |
if (styleVal) {
|
|
|
14555 |
dom.setAttrib(elm, 'data-mce-style', styleVal);
|
|
|
14556 |
}
|
|
|
14557 |
}
|
|
|
14558 |
};
|
|
|
14559 |
const applyFormatAction = (ed, name, vars, node) => {
|
|
|
14560 |
const formatList = ed.formatter.get(name);
|
|
|
14561 |
const format = formatList[0];
|
|
|
14562 |
const isCollapsed = !node && ed.selection.isCollapsed();
|
|
|
14563 |
const dom = ed.dom;
|
|
|
14564 |
const selection = ed.selection;
|
|
|
14565 |
const setElementFormat = (elm, fmt = format) => {
|
|
|
14566 |
if (isFunction(fmt.onformat)) {
|
|
|
14567 |
fmt.onformat(elm, fmt, vars, node);
|
|
|
14568 |
}
|
|
|
14569 |
applyStyles(dom, elm, fmt, vars);
|
|
|
14570 |
each$5(fmt.attributes, (value, name) => {
|
|
|
14571 |
dom.setAttrib(elm, name, replaceVars(value, vars));
|
|
|
14572 |
});
|
|
|
14573 |
each$5(fmt.classes, value => {
|
|
|
14574 |
const newValue = replaceVars(value, vars);
|
|
|
14575 |
if (!dom.hasClass(elm, newValue)) {
|
|
|
14576 |
dom.addClass(elm, newValue);
|
|
|
14577 |
}
|
|
|
14578 |
});
|
|
|
14579 |
};
|
|
|
14580 |
const applyNodeStyle = (formatList, node) => {
|
|
|
14581 |
let found = false;
|
|
|
14582 |
each$5(formatList, format => {
|
|
|
14583 |
if (!isSelectorFormat(format)) {
|
|
|
14584 |
return false;
|
|
|
14585 |
}
|
|
|
14586 |
if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) {
|
|
|
14587 |
return true;
|
|
|
14588 |
}
|
|
|
14589 |
if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) {
|
|
|
14590 |
return true;
|
|
|
14591 |
}
|
|
|
14592 |
if (dom.is(node, format.selector) && !isCaretNode(node)) {
|
|
|
14593 |
setElementFormat(node, format);
|
|
|
14594 |
found = true;
|
|
|
14595 |
return false;
|
|
|
14596 |
}
|
|
|
14597 |
return true;
|
|
|
14598 |
});
|
|
|
14599 |
return found;
|
|
|
14600 |
};
|
|
|
14601 |
const createWrapElement = wrapName => {
|
|
|
14602 |
if (isString(wrapName)) {
|
|
|
14603 |
const wrapElm = dom.create(wrapName);
|
|
|
14604 |
setElementFormat(wrapElm);
|
|
|
14605 |
return wrapElm;
|
|
|
14606 |
} else {
|
|
|
14607 |
return null;
|
|
|
14608 |
}
|
|
|
14609 |
};
|
|
|
14610 |
const applyRngStyle = (dom, rng, nodeSpecific) => {
|
|
|
14611 |
const newWrappers = [];
|
|
|
14612 |
let contentEditable = true;
|
|
|
14613 |
const wrapName = format.inline || format.block;
|
|
|
14614 |
const wrapElm = createWrapElement(wrapName);
|
|
|
14615 |
const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars);
|
|
|
14616 |
const canRenameBlock = (node, parentName, isEditableDescendant) => {
|
|
|
14617 |
const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName);
|
|
|
14618 |
return isEditableDescendant && isValidBlockFormatForNode;
|
|
|
14619 |
};
|
|
|
14620 |
const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
|
|
|
14621 |
const nodeName = node.nodeName.toLowerCase();
|
|
|
14622 |
const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName);
|
| 1441 |
ariadna |
14623 |
const isZwsp$1 = !nodeSpecific && isText$b(node) && isZwsp(node.data);
|
| 1 |
efrain |
14624 |
const isCaret = isCaretNode(node);
|
|
|
14625 |
const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node);
|
| 1441 |
ariadna |
14626 |
return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp$1 && !isCaret && isCorrectFormatForNode;
|
| 1 |
efrain |
14627 |
};
|
|
|
14628 |
walk$3(dom, rng, nodes => {
|
|
|
14629 |
let currentWrapElm;
|
|
|
14630 |
const process = node => {
|
|
|
14631 |
let hasContentEditableState = false;
|
|
|
14632 |
let lastContentEditable = contentEditable;
|
|
|
14633 |
let isWrappableNoneditableElm = false;
|
|
|
14634 |
const parentNode = node.parentNode;
|
|
|
14635 |
const parentName = parentNode.nodeName.toLowerCase();
|
|
|
14636 |
const contentEditableValue = dom.getContentEditable(node);
|
|
|
14637 |
if (isNonNullable(contentEditableValue)) {
|
|
|
14638 |
lastContentEditable = contentEditable;
|
|
|
14639 |
contentEditable = contentEditableValue === 'true';
|
|
|
14640 |
hasContentEditableState = true;
|
|
|
14641 |
isWrappableNoneditableElm = isWrappableNoneditable(ed, node);
|
|
|
14642 |
}
|
|
|
14643 |
const isEditableDescendant = contentEditable && !hasContentEditableState;
|
|
|
14644 |
if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) {
|
|
|
14645 |
currentWrapElm = null;
|
|
|
14646 |
if (isBlockFormat(format)) {
|
|
|
14647 |
dom.remove(node);
|
|
|
14648 |
}
|
|
|
14649 |
return;
|
|
|
14650 |
}
|
|
|
14651 |
if (isMatchingWrappingBlock(node)) {
|
|
|
14652 |
currentWrapElm = null;
|
|
|
14653 |
return;
|
|
|
14654 |
}
|
|
|
14655 |
if (canRenameBlock(node, parentName, isEditableDescendant)) {
|
|
|
14656 |
const elm = dom.rename(node, wrapName);
|
|
|
14657 |
setElementFormat(elm);
|
|
|
14658 |
newWrappers.push(elm);
|
|
|
14659 |
currentWrapElm = null;
|
|
|
14660 |
return;
|
|
|
14661 |
}
|
|
|
14662 |
if (isSelectorFormat(format)) {
|
|
|
14663 |
let found = applyNodeStyle(formatList, node);
|
|
|
14664 |
if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
|
|
|
14665 |
found = applyNodeStyle(formatList, parentNode);
|
|
|
14666 |
}
|
|
|
14667 |
if (!isInlineFormat(format) || found) {
|
|
|
14668 |
currentWrapElm = null;
|
|
|
14669 |
return;
|
|
|
14670 |
}
|
|
|
14671 |
}
|
|
|
14672 |
if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) {
|
|
|
14673 |
if (!currentWrapElm) {
|
|
|
14674 |
currentWrapElm = dom.clone(wrapElm, false);
|
|
|
14675 |
parentNode.insertBefore(currentWrapElm, node);
|
|
|
14676 |
newWrappers.push(currentWrapElm);
|
|
|
14677 |
}
|
|
|
14678 |
if (isWrappableNoneditableElm && hasContentEditableState) {
|
|
|
14679 |
contentEditable = lastContentEditable;
|
|
|
14680 |
}
|
|
|
14681 |
currentWrapElm.appendChild(node);
|
|
|
14682 |
} else {
|
|
|
14683 |
currentWrapElm = null;
|
|
|
14684 |
each$e(from(node.childNodes), process);
|
|
|
14685 |
if (hasContentEditableState) {
|
|
|
14686 |
contentEditable = lastContentEditable;
|
|
|
14687 |
}
|
|
|
14688 |
currentWrapElm = null;
|
|
|
14689 |
}
|
|
|
14690 |
};
|
|
|
14691 |
each$e(nodes, process);
|
|
|
14692 |
});
|
|
|
14693 |
if (format.links === true) {
|
|
|
14694 |
each$e(newWrappers, node => {
|
|
|
14695 |
const process = node => {
|
|
|
14696 |
if (node.nodeName === 'A') {
|
|
|
14697 |
setElementFormat(node, format);
|
|
|
14698 |
}
|
|
|
14699 |
each$e(from(node.childNodes), process);
|
|
|
14700 |
};
|
|
|
14701 |
process(node);
|
|
|
14702 |
});
|
|
|
14703 |
}
|
|
|
14704 |
each$e(newWrappers, node => {
|
|
|
14705 |
const getChildCount = node => {
|
|
|
14706 |
let count = 0;
|
|
|
14707 |
each$e(node.childNodes, node => {
|
|
|
14708 |
if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) {
|
|
|
14709 |
count++;
|
|
|
14710 |
}
|
|
|
14711 |
});
|
|
|
14712 |
return count;
|
|
|
14713 |
};
|
|
|
14714 |
const mergeStyles = node => {
|
|
|
14715 |
const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format));
|
|
|
14716 |
return childElement.map(child => {
|
|
|
14717 |
const clone = dom.clone(child, false);
|
|
|
14718 |
setElementFormat(clone);
|
|
|
14719 |
dom.replace(clone, node, true);
|
|
|
14720 |
dom.remove(child, true);
|
|
|
14721 |
return clone;
|
|
|
14722 |
}).getOr(node);
|
|
|
14723 |
};
|
|
|
14724 |
const childCount = getChildCount(node);
|
|
|
14725 |
if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
|
|
|
14726 |
dom.remove(node, true);
|
|
|
14727 |
return;
|
|
|
14728 |
}
|
|
|
14729 |
if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
|
|
|
14730 |
if (!format.exact && childCount === 1) {
|
|
|
14731 |
node = mergeStyles(node);
|
|
|
14732 |
}
|
|
|
14733 |
mergeWithChildren(ed, formatList, vars, node);
|
|
|
14734 |
mergeWithParents(ed, format, name, vars, node);
|
|
|
14735 |
mergeBackgroundColorAndFontSize(dom, format, vars, node);
|
|
|
14736 |
mergeTextDecorationsAndColor(dom, format, vars, node);
|
|
|
14737 |
mergeSubSup(dom, format, vars, node);
|
|
|
14738 |
mergeSiblings(ed, format, vars, node);
|
|
|
14739 |
}
|
|
|
14740 |
});
|
|
|
14741 |
};
|
|
|
14742 |
const targetNode = isNode(node) ? node : selection.getNode();
|
|
|
14743 |
if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) {
|
|
|
14744 |
node = targetNode;
|
|
|
14745 |
applyNodeStyle(formatList, node);
|
|
|
14746 |
fireFormatApply(ed, name, node, vars);
|
|
|
14747 |
return;
|
|
|
14748 |
}
|
|
|
14749 |
if (format) {
|
|
|
14750 |
if (node) {
|
|
|
14751 |
if (isNode(node)) {
|
|
|
14752 |
if (!applyNodeStyle(formatList, node)) {
|
|
|
14753 |
const rng = dom.createRng();
|
|
|
14754 |
rng.setStartBefore(node);
|
|
|
14755 |
rng.setEndAfter(node);
|
|
|
14756 |
applyRngStyle(dom, expandRng(dom, rng, formatList), true);
|
|
|
14757 |
}
|
|
|
14758 |
} else {
|
|
|
14759 |
applyRngStyle(dom, node, true);
|
|
|
14760 |
}
|
|
|
14761 |
} else {
|
|
|
14762 |
if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
|
|
|
14763 |
selection.setRng(normalize(selection.getRng()));
|
|
|
14764 |
preserveSelection(ed, () => {
|
|
|
14765 |
runOnRanges(ed, (selectionRng, fake) => {
|
|
|
14766 |
const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList);
|
|
|
14767 |
applyRngStyle(dom, expandedRng, false);
|
|
|
14768 |
});
|
|
|
14769 |
}, always);
|
|
|
14770 |
ed.nodeChanged();
|
|
|
14771 |
} else {
|
|
|
14772 |
applyCaretFormat(ed, name, vars);
|
|
|
14773 |
}
|
|
|
14774 |
getExpandedListItemFormat(ed.formatter, name).each(liFmt => {
|
|
|
14775 |
each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars));
|
|
|
14776 |
});
|
|
|
14777 |
}
|
|
|
14778 |
postProcess$1(name, ed);
|
|
|
14779 |
}
|
|
|
14780 |
fireFormatApply(ed, name, node, vars);
|
|
|
14781 |
};
|
|
|
14782 |
const applyFormat$1 = (editor, name, vars, node) => {
|
|
|
14783 |
if (node || editor.selection.isEditable()) {
|
|
|
14784 |
applyFormatAction(editor, name, vars, node);
|
|
|
14785 |
}
|
|
|
14786 |
};
|
|
|
14787 |
|
|
|
14788 |
const hasVars = value => has$2(value, 'vars');
|
|
|
14789 |
const setup$u = (registeredFormatListeners, editor) => {
|
|
|
14790 |
registeredFormatListeners.set({});
|
|
|
14791 |
editor.on('NodeChange', e => {
|
|
|
14792 |
updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
|
|
|
14793 |
});
|
|
|
14794 |
editor.on('FormatApply FormatRemove', e => {
|
|
|
14795 |
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));
|
|
|
14796 |
updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
|
|
|
14797 |
});
|
|
|
14798 |
};
|
|
|
14799 |
const fallbackElement = editor => editor.selection.getStart();
|
|
|
14800 |
const matchingNode = (editor, parents, format, similar, vars) => {
|
|
|
14801 |
const isMatchingNode = node => {
|
|
|
14802 |
const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
|
|
|
14803 |
return !isUndefined(matchingFormat);
|
|
|
14804 |
};
|
|
|
14805 |
const isUnableToMatch = node => {
|
|
|
14806 |
if (matchesUnInheritedFormatSelector(editor, node, format)) {
|
|
|
14807 |
return true;
|
|
|
14808 |
} else {
|
|
|
14809 |
if (!similar) {
|
|
|
14810 |
return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
|
|
|
14811 |
} else {
|
|
|
14812 |
return false;
|
|
|
14813 |
}
|
|
|
14814 |
}
|
|
|
14815 |
};
|
|
|
14816 |
return findUntil$1(parents, isMatchingNode, isUnableToMatch);
|
|
|
14817 |
};
|
|
|
14818 |
const getParents = (editor, elm) => {
|
|
|
14819 |
const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
|
| 1441 |
ariadna |
14820 |
return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$1(node));
|
| 1 |
efrain |
14821 |
};
|
|
|
14822 |
const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
|
|
|
14823 |
const parents = getParents(editor, elm);
|
|
|
14824 |
each$d(registeredCallbacks, (data, format) => {
|
|
|
14825 |
const runIfChanged = spec => {
|
|
|
14826 |
const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined);
|
|
|
14827 |
const isSet = match.isSome();
|
|
|
14828 |
if (spec.state.get() !== isSet) {
|
|
|
14829 |
spec.state.set(isSet);
|
|
|
14830 |
const node = match.getOr(elm);
|
|
|
14831 |
if (hasVars(spec)) {
|
|
|
14832 |
spec.callback(isSet, {
|
|
|
14833 |
node,
|
|
|
14834 |
format,
|
|
|
14835 |
parents
|
|
|
14836 |
});
|
|
|
14837 |
} else {
|
|
|
14838 |
each$e(spec.callbacks, callback => callback(isSet, {
|
|
|
14839 |
node,
|
|
|
14840 |
format,
|
|
|
14841 |
parents
|
|
|
14842 |
}));
|
|
|
14843 |
}
|
|
|
14844 |
}
|
|
|
14845 |
};
|
|
|
14846 |
each$e([
|
|
|
14847 |
data.withSimilar,
|
|
|
14848 |
data.withoutSimilar
|
|
|
14849 |
], runIfChanged);
|
|
|
14850 |
each$e(data.withVars, runIfChanged);
|
|
|
14851 |
});
|
|
|
14852 |
};
|
|
|
14853 |
const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
|
|
|
14854 |
const formatChangeItems = registeredFormatListeners.get();
|
|
|
14855 |
each$e(formats.split(','), format => {
|
|
|
14856 |
const group = get$a(formatChangeItems, format).getOrThunk(() => {
|
|
|
14857 |
const base = {
|
|
|
14858 |
withSimilar: {
|
|
|
14859 |
state: Cell(false),
|
|
|
14860 |
similar: true,
|
|
|
14861 |
callbacks: []
|
|
|
14862 |
},
|
|
|
14863 |
withoutSimilar: {
|
|
|
14864 |
state: Cell(false),
|
|
|
14865 |
similar: false,
|
|
|
14866 |
callbacks: []
|
|
|
14867 |
},
|
|
|
14868 |
withVars: []
|
|
|
14869 |
};
|
|
|
14870 |
formatChangeItems[format] = base;
|
|
|
14871 |
return base;
|
|
|
14872 |
});
|
|
|
14873 |
const getCurrent = () => {
|
|
|
14874 |
const parents = getParents(editor);
|
|
|
14875 |
return matchingNode(editor, parents, format, similar, vars).isSome();
|
|
|
14876 |
};
|
|
|
14877 |
if (isUndefined(vars)) {
|
|
|
14878 |
const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
|
|
|
14879 |
toAppendTo.callbacks.push(callback);
|
|
|
14880 |
if (toAppendTo.callbacks.length === 1) {
|
|
|
14881 |
toAppendTo.state.set(getCurrent());
|
|
|
14882 |
}
|
|
|
14883 |
} else {
|
|
|
14884 |
group.withVars.push({
|
|
|
14885 |
state: Cell(getCurrent()),
|
|
|
14886 |
similar,
|
|
|
14887 |
vars,
|
|
|
14888 |
callback
|
|
|
14889 |
});
|
|
|
14890 |
}
|
|
|
14891 |
});
|
|
|
14892 |
registeredFormatListeners.set(formatChangeItems);
|
|
|
14893 |
};
|
|
|
14894 |
const removeListeners = (registeredFormatListeners, formats, callback) => {
|
|
|
14895 |
const formatChangeItems = registeredFormatListeners.get();
|
|
|
14896 |
each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => {
|
|
|
14897 |
formatChangeItems[format] = {
|
|
|
14898 |
withSimilar: {
|
|
|
14899 |
...group.withSimilar,
|
|
|
14900 |
callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback)
|
|
|
14901 |
},
|
|
|
14902 |
withoutSimilar: {
|
|
|
14903 |
...group.withoutSimilar,
|
|
|
14904 |
callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback)
|
|
|
14905 |
},
|
|
|
14906 |
withVars: filter$5(group.withVars, item => item.callback !== callback)
|
|
|
14907 |
};
|
|
|
14908 |
}));
|
|
|
14909 |
registeredFormatListeners.set(formatChangeItems);
|
|
|
14910 |
};
|
|
|
14911 |
const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
|
|
|
14912 |
addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
|
|
|
14913 |
return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
|
|
|
14914 |
};
|
|
|
14915 |
|
|
|
14916 |
const toggle = (editor, name, vars, node) => {
|
|
|
14917 |
const fmt = editor.formatter.get(name);
|
|
|
14918 |
if (fmt) {
|
|
|
14919 |
if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
|
|
|
14920 |
removeFormat$1(editor, name, vars, node);
|
|
|
14921 |
} else {
|
|
|
14922 |
applyFormat$1(editor, name, vars, node);
|
|
|
14923 |
}
|
|
|
14924 |
}
|
|
|
14925 |
};
|
|
|
14926 |
|
|
|
14927 |
const explode$1 = Tools.explode;
|
|
|
14928 |
const create$8 = () => {
|
|
|
14929 |
const filters = {};
|
|
|
14930 |
const addFilter = (name, callback) => {
|
|
|
14931 |
each$e(explode$1(name), name => {
|
|
|
14932 |
if (!has$2(filters, name)) {
|
|
|
14933 |
filters[name] = {
|
|
|
14934 |
name,
|
|
|
14935 |
callbacks: []
|
|
|
14936 |
};
|
|
|
14937 |
}
|
|
|
14938 |
filters[name].callbacks.push(callback);
|
|
|
14939 |
});
|
|
|
14940 |
};
|
|
|
14941 |
const getFilters = () => values(filters);
|
|
|
14942 |
const removeFilter = (name, callback) => {
|
|
|
14943 |
each$e(explode$1(name), name => {
|
|
|
14944 |
if (has$2(filters, name)) {
|
|
|
14945 |
if (isNonNullable(callback)) {
|
|
|
14946 |
const filter = filters[name];
|
|
|
14947 |
const newCallbacks = filter$5(filter.callbacks, c => c !== callback);
|
|
|
14948 |
if (newCallbacks.length > 0) {
|
|
|
14949 |
filter.callbacks = newCallbacks;
|
|
|
14950 |
} else {
|
|
|
14951 |
delete filters[name];
|
|
|
14952 |
}
|
|
|
14953 |
} else {
|
|
|
14954 |
delete filters[name];
|
|
|
14955 |
}
|
|
|
14956 |
}
|
|
|
14957 |
});
|
|
|
14958 |
};
|
|
|
14959 |
return {
|
|
|
14960 |
addFilter,
|
|
|
14961 |
getFilters,
|
|
|
14962 |
removeFilter
|
|
|
14963 |
};
|
|
|
14964 |
};
|
|
|
14965 |
|
|
|
14966 |
const removeAttrs = (node, names) => {
|
|
|
14967 |
each$e(names, name => {
|
|
|
14968 |
node.attr(name, null);
|
|
|
14969 |
});
|
|
|
14970 |
};
|
|
|
14971 |
const addFontToSpansFilter = (domParser, styles, fontSizes) => {
|
|
|
14972 |
domParser.addNodeFilter('font', nodes => {
|
|
|
14973 |
each$e(nodes, node => {
|
|
|
14974 |
const props = styles.parse(node.attr('style'));
|
|
|
14975 |
const color = node.attr('color');
|
|
|
14976 |
const face = node.attr('face');
|
|
|
14977 |
const size = node.attr('size');
|
|
|
14978 |
if (color) {
|
|
|
14979 |
props.color = color;
|
|
|
14980 |
}
|
|
|
14981 |
if (face) {
|
|
|
14982 |
props['font-family'] = face;
|
|
|
14983 |
}
|
|
|
14984 |
if (size) {
|
|
|
14985 |
toInt(size).each(num => {
|
|
|
14986 |
props['font-size'] = fontSizes[num - 1];
|
|
|
14987 |
});
|
|
|
14988 |
}
|
|
|
14989 |
node.name = 'span';
|
|
|
14990 |
node.attr('style', styles.serialize(props));
|
|
|
14991 |
removeAttrs(node, [
|
|
|
14992 |
'color',
|
|
|
14993 |
'face',
|
|
|
14994 |
'size'
|
|
|
14995 |
]);
|
|
|
14996 |
});
|
|
|
14997 |
});
|
|
|
14998 |
};
|
|
|
14999 |
const addStrikeFilter = (domParser, schema, styles) => {
|
|
|
15000 |
domParser.addNodeFilter('strike', nodes => {
|
|
|
15001 |
const convertToSTag = schema.type !== 'html4';
|
|
|
15002 |
each$e(nodes, node => {
|
|
|
15003 |
if (convertToSTag) {
|
|
|
15004 |
node.name = 's';
|
|
|
15005 |
} else {
|
|
|
15006 |
const props = styles.parse(node.attr('style'));
|
|
|
15007 |
props['text-decoration'] = 'line-through';
|
|
|
15008 |
node.name = 'span';
|
|
|
15009 |
node.attr('style', styles.serialize(props));
|
|
|
15010 |
}
|
|
|
15011 |
});
|
|
|
15012 |
});
|
|
|
15013 |
};
|
|
|
15014 |
const addFilters = (domParser, settings, schema) => {
|
|
|
15015 |
var _a;
|
|
|
15016 |
const styles = Styles();
|
|
|
15017 |
if (settings.convert_fonts_to_spans) {
|
|
|
15018 |
addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : ''));
|
|
|
15019 |
}
|
|
|
15020 |
addStrikeFilter(domParser, schema, styles);
|
|
|
15021 |
};
|
|
|
15022 |
const register$5 = (domParser, settings, schema) => {
|
|
|
15023 |
if (settings.inline_styles) {
|
|
|
15024 |
addFilters(domParser, settings, schema);
|
|
|
15025 |
}
|
|
|
15026 |
};
|
|
|
15027 |
|
|
|
15028 |
const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject({
|
|
|
15029 |
message: `Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`,
|
|
|
15030 |
uriType: 'blob'
|
|
|
15031 |
}));
|
|
|
15032 |
const extractBase64Data = data => {
|
|
|
15033 |
const matches = /([a-z0-9+\/=\s]+)/i.exec(data);
|
|
|
15034 |
return matches ? matches[1] : '';
|
|
|
15035 |
};
|
| 1441 |
ariadna |
15036 |
const decodeData = data => {
|
|
|
15037 |
try {
|
|
|
15038 |
return decodeURIComponent(data);
|
|
|
15039 |
} catch (_a) {
|
|
|
15040 |
return data;
|
|
|
15041 |
}
|
|
|
15042 |
};
|
| 1 |
efrain |
15043 |
const parseDataUri = uri => {
|
|
|
15044 |
const [type, ...rest] = uri.split(',');
|
|
|
15045 |
const data = rest.join(',');
|
|
|
15046 |
const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type);
|
|
|
15047 |
if (matches) {
|
|
|
15048 |
const base64Encoded = matches[2] === ';base64';
|
| 1441 |
ariadna |
15049 |
const decodedData = decodeData(data);
|
|
|
15050 |
const extractedData = base64Encoded ? extractBase64Data(decodedData) : decodedData;
|
| 1 |
efrain |
15051 |
return Optional.some({
|
|
|
15052 |
type: matches[1],
|
|
|
15053 |
data: extractedData,
|
|
|
15054 |
base64Encoded
|
|
|
15055 |
});
|
|
|
15056 |
} else {
|
|
|
15057 |
return Optional.none();
|
|
|
15058 |
}
|
|
|
15059 |
};
|
|
|
15060 |
const buildBlob = (type, data, base64Encoded = true) => {
|
|
|
15061 |
let str = data;
|
|
|
15062 |
if (base64Encoded) {
|
|
|
15063 |
try {
|
|
|
15064 |
str = atob(data);
|
| 1441 |
ariadna |
15065 |
} catch (_a) {
|
| 1 |
efrain |
15066 |
return Optional.none();
|
|
|
15067 |
}
|
|
|
15068 |
}
|
|
|
15069 |
const arr = new Uint8Array(str.length);
|
|
|
15070 |
for (let i = 0; i < arr.length; i++) {
|
|
|
15071 |
arr[i] = str.charCodeAt(i);
|
|
|
15072 |
}
|
|
|
15073 |
return Optional.some(new Blob([arr], { type }));
|
|
|
15074 |
};
|
|
|
15075 |
const dataUriToBlob = uri => {
|
|
|
15076 |
return new Promise((resolve, reject) => {
|
|
|
15077 |
parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve);
|
|
|
15078 |
});
|
|
|
15079 |
};
|
|
|
15080 |
const uriToBlob = url => {
|
|
|
15081 |
if (startsWith(url, 'blob:')) {
|
|
|
15082 |
return blobUriToBlob(url);
|
|
|
15083 |
} else if (startsWith(url, 'data:')) {
|
|
|
15084 |
return dataUriToBlob(url);
|
|
|
15085 |
} else {
|
|
|
15086 |
return Promise.reject('Unknown URI format');
|
|
|
15087 |
}
|
|
|
15088 |
};
|
|
|
15089 |
const blobToDataUri = blob => {
|
|
|
15090 |
return new Promise((resolve, reject) => {
|
|
|
15091 |
const reader = new FileReader();
|
|
|
15092 |
reader.onloadend = () => {
|
|
|
15093 |
resolve(reader.result);
|
|
|
15094 |
};
|
|
|
15095 |
reader.onerror = () => {
|
|
|
15096 |
var _a;
|
|
|
15097 |
reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
|
|
|
15098 |
};
|
|
|
15099 |
reader.readAsDataURL(blob);
|
|
|
15100 |
});
|
|
|
15101 |
};
|
|
|
15102 |
|
|
|
15103 |
let count$1 = 0;
|
|
|
15104 |
const uniqueId$1 = prefix => {
|
|
|
15105 |
return (prefix || 'blobid') + count$1++;
|
|
|
15106 |
};
|
|
|
15107 |
const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
|
|
|
15108 |
return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => {
|
|
|
15109 |
if (base64Only && !base64Encoded) {
|
|
|
15110 |
return Optional.none();
|
|
|
15111 |
} else {
|
|
|
15112 |
const base64 = base64Encoded ? data : btoa(data);
|
|
|
15113 |
return generateBlobInfo(base64, type);
|
|
|
15114 |
}
|
|
|
15115 |
});
|
|
|
15116 |
};
|
|
|
15117 |
const createBlobInfo$1 = (blobCache, blob, base64) => {
|
|
|
15118 |
const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
|
|
|
15119 |
blobCache.add(blobInfo);
|
|
|
15120 |
return blobInfo;
|
|
|
15121 |
};
|
|
|
15122 |
const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
|
|
|
15123 |
return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64))));
|
|
|
15124 |
};
|
|
|
15125 |
const imageToBlobInfo = (blobCache, imageSrc) => {
|
|
|
15126 |
const invalidDataUri = () => Promise.reject('Invalid data URI');
|
|
|
15127 |
if (startsWith(imageSrc, 'blob:')) {
|
|
|
15128 |
const blobInfo = blobCache.getByUri(imageSrc);
|
|
|
15129 |
if (isNonNullable(blobInfo)) {
|
|
|
15130 |
return Promise.resolve(blobInfo);
|
|
|
15131 |
} else {
|
|
|
15132 |
return uriToBlob(imageSrc).then(blob => {
|
|
|
15133 |
return blobToDataUri(blob).then(dataUri => {
|
|
|
15134 |
return processDataUri(dataUri, false, base64 => {
|
|
|
15135 |
return Optional.some(createBlobInfo$1(blobCache, blob, base64));
|
|
|
15136 |
}).getOrThunk(invalidDataUri);
|
|
|
15137 |
});
|
|
|
15138 |
});
|
|
|
15139 |
}
|
|
|
15140 |
} else if (startsWith(imageSrc, 'data:')) {
|
|
|
15141 |
return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo));
|
|
|
15142 |
} else {
|
|
|
15143 |
return Promise.reject('Unknown image data format');
|
|
|
15144 |
}
|
|
|
15145 |
};
|
|
|
15146 |
|
| 1441 |
ariadna |
15147 |
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]+)?)?)$/;
|
|
|
15148 |
const extractHost = url => Optional.from(url.match(hostCaptureRegex)).bind(ms => get$b(ms, 1)).map(h => startsWith(h, 'www.') ? h.substring(4) : h);
|
|
|
15149 |
|
|
|
15150 |
const sandboxIframe = (iframeNode, exclusions) => {
|
|
|
15151 |
if (Optional.from(iframeNode.attr('src')).bind(extractHost).forall(host => !contains$2(exclusions, host))) {
|
|
|
15152 |
iframeNode.attr('sandbox', '');
|
| 1 |
efrain |
15153 |
}
|
|
|
15154 |
};
|
|
|
15155 |
const isMimeType = (mime, type) => startsWith(mime, `${ type }/`);
|
| 1441 |
ariadna |
15156 |
const getEmbedType = type => {
|
|
|
15157 |
if (isUndefined(type)) {
|
|
|
15158 |
return 'iframe';
|
|
|
15159 |
} else if (isMimeType(type, 'image')) {
|
|
|
15160 |
return 'img';
|
|
|
15161 |
} else if (isMimeType(type, 'video')) {
|
|
|
15162 |
return 'video';
|
|
|
15163 |
} else if (isMimeType(type, 'audio')) {
|
|
|
15164 |
return 'audio';
|
| 1 |
efrain |
15165 |
} else {
|
| 1441 |
ariadna |
15166 |
return 'iframe';
|
| 1 |
efrain |
15167 |
}
|
| 1441 |
ariadna |
15168 |
};
|
|
|
15169 |
const createSafeEmbed = ({type, src, width, height} = {}, sandboxIframes, sandboxIframesExclusions) => {
|
|
|
15170 |
const name = getEmbedType(type);
|
| 1 |
efrain |
15171 |
const embed = new AstNode(name, 1);
|
|
|
15172 |
embed.attr(name === 'audio' ? { src } : {
|
|
|
15173 |
src,
|
|
|
15174 |
width,
|
|
|
15175 |
height
|
|
|
15176 |
});
|
|
|
15177 |
if (name === 'audio' || name === 'video') {
|
|
|
15178 |
embed.attr('controls', '');
|
|
|
15179 |
}
|
|
|
15180 |
if (name === 'iframe' && sandboxIframes) {
|
| 1441 |
ariadna |
15181 |
sandboxIframe(embed, sandboxIframesExclusions);
|
| 1 |
efrain |
15182 |
}
|
|
|
15183 |
return embed;
|
|
|
15184 |
};
|
| 1441 |
ariadna |
15185 |
|
|
|
15186 |
const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus'));
|
|
|
15187 |
const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder'));
|
|
|
15188 |
const registerBase64ImageFilter = (parser, settings) => {
|
|
|
15189 |
const {blob_cache: blobCache} = settings;
|
|
|
15190 |
if (blobCache) {
|
|
|
15191 |
const processImage = img => {
|
|
|
15192 |
const inputSrc = img.attr('src');
|
|
|
15193 |
if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) {
|
|
|
15194 |
return;
|
|
|
15195 |
}
|
|
|
15196 |
dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => {
|
|
|
15197 |
img.attr('src', blobInfo.blobUri());
|
|
|
15198 |
});
|
|
|
15199 |
};
|
|
|
15200 |
parser.addAttributeFilter('src', nodes => each$e(nodes, processImage));
|
|
|
15201 |
}
|
|
|
15202 |
};
|
| 1 |
efrain |
15203 |
const register$4 = (parser, settings) => {
|
| 1441 |
ariadna |
15204 |
var _a, _b;
|
| 1 |
efrain |
15205 |
const schema = parser.schema;
|
|
|
15206 |
parser.addAttributeFilter('href', nodes => {
|
|
|
15207 |
let i = nodes.length;
|
|
|
15208 |
const appendRel = rel => {
|
|
|
15209 |
const parts = rel.split(' ').filter(p => p.length > 0);
|
|
|
15210 |
return parts.concat(['noopener']).sort().join(' ');
|
|
|
15211 |
};
|
|
|
15212 |
const addNoOpener = rel => {
|
|
|
15213 |
const newRel = rel ? Tools.trim(rel) : '';
|
|
|
15214 |
if (!/\b(noopener)\b/g.test(newRel)) {
|
|
|
15215 |
return appendRel(newRel);
|
|
|
15216 |
} else {
|
|
|
15217 |
return newRel;
|
|
|
15218 |
}
|
|
|
15219 |
};
|
|
|
15220 |
if (!settings.allow_unsafe_link_target) {
|
|
|
15221 |
while (i--) {
|
|
|
15222 |
const node = nodes[i];
|
|
|
15223 |
if (node.name === 'a' && node.attr('target') === '_blank') {
|
|
|
15224 |
node.attr('rel', addNoOpener(node.attr('rel')));
|
|
|
15225 |
}
|
|
|
15226 |
}
|
|
|
15227 |
}
|
|
|
15228 |
});
|
|
|
15229 |
if (!settings.allow_html_in_named_anchor) {
|
|
|
15230 |
parser.addAttributeFilter('id,name', nodes => {
|
|
|
15231 |
let i = nodes.length, sibling, prevSibling, parent, node;
|
|
|
15232 |
while (i--) {
|
|
|
15233 |
node = nodes[i];
|
|
|
15234 |
if (node.name === 'a' && node.firstChild && !node.attr('href')) {
|
|
|
15235 |
parent = node.parent;
|
|
|
15236 |
sibling = node.lastChild;
|
|
|
15237 |
while (sibling && parent) {
|
|
|
15238 |
prevSibling = sibling.prev;
|
|
|
15239 |
parent.insert(sibling, node);
|
|
|
15240 |
sibling = prevSibling;
|
|
|
15241 |
}
|
|
|
15242 |
}
|
|
|
15243 |
}
|
|
|
15244 |
});
|
|
|
15245 |
}
|
|
|
15246 |
if (settings.fix_list_elements) {
|
|
|
15247 |
parser.addNodeFilter('ul,ol', nodes => {
|
|
|
15248 |
let i = nodes.length, node, parentNode;
|
|
|
15249 |
while (i--) {
|
|
|
15250 |
node = nodes[i];
|
|
|
15251 |
parentNode = node.parent;
|
|
|
15252 |
if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) {
|
|
|
15253 |
if (node.prev && node.prev.name === 'li') {
|
|
|
15254 |
node.prev.append(node);
|
|
|
15255 |
} else {
|
|
|
15256 |
const li = new AstNode('li', 1);
|
|
|
15257 |
li.attr('style', 'list-style-type: none');
|
|
|
15258 |
node.wrap(li);
|
|
|
15259 |
}
|
|
|
15260 |
}
|
|
|
15261 |
}
|
|
|
15262 |
});
|
|
|
15263 |
}
|
|
|
15264 |
const validClasses = schema.getValidClasses();
|
|
|
15265 |
if (settings.validate && validClasses) {
|
|
|
15266 |
parser.addAttributeFilter('class', nodes => {
|
|
|
15267 |
var _a;
|
|
|
15268 |
let i = nodes.length;
|
|
|
15269 |
while (i--) {
|
|
|
15270 |
const node = nodes[i];
|
|
|
15271 |
const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : '';
|
|
|
15272 |
const classList = Tools.explode(clazz, ' ');
|
|
|
15273 |
let classValue = '';
|
|
|
15274 |
for (let ci = 0; ci < classList.length; ci++) {
|
|
|
15275 |
const className = classList[ci];
|
|
|
15276 |
let valid = false;
|
|
|
15277 |
let validClassesMap = validClasses['*'];
|
|
|
15278 |
if (validClassesMap && validClassesMap[className]) {
|
|
|
15279 |
valid = true;
|
|
|
15280 |
}
|
|
|
15281 |
validClassesMap = validClasses[node.name];
|
|
|
15282 |
if (!valid && validClassesMap && validClassesMap[className]) {
|
|
|
15283 |
valid = true;
|
|
|
15284 |
}
|
|
|
15285 |
if (valid) {
|
|
|
15286 |
if (classValue) {
|
|
|
15287 |
classValue += ' ';
|
|
|
15288 |
}
|
|
|
15289 |
classValue += className;
|
|
|
15290 |
}
|
|
|
15291 |
}
|
|
|
15292 |
if (!classValue.length) {
|
|
|
15293 |
classValue = null;
|
|
|
15294 |
}
|
|
|
15295 |
node.attr('class', classValue);
|
|
|
15296 |
}
|
|
|
15297 |
});
|
|
|
15298 |
}
|
|
|
15299 |
registerBase64ImageFilter(parser, settings);
|
| 1441 |
ariadna |
15300 |
const shouldSandboxIframes = (_a = settings.sandbox_iframes) !== null && _a !== void 0 ? _a : false;
|
|
|
15301 |
const sandboxIframesExclusions = unique$1((_b = settings.sandbox_iframes_exclusions) !== null && _b !== void 0 ? _b : []);
|
| 1 |
efrain |
15302 |
if (settings.convert_unsafe_embeds) {
|
|
|
15303 |
parser.addNodeFilter('object,embed', nodes => each$e(nodes, node => {
|
| 1441 |
ariadna |
15304 |
node.replace(createSafeEmbed({
|
|
|
15305 |
type: node.attr('type'),
|
|
|
15306 |
src: node.name === 'object' ? node.attr('data') : node.attr('src'),
|
|
|
15307 |
width: node.attr('width'),
|
|
|
15308 |
height: node.attr('height')
|
|
|
15309 |
}, shouldSandboxIframes, sandboxIframesExclusions));
|
| 1 |
efrain |
15310 |
}));
|
|
|
15311 |
}
|
| 1441 |
ariadna |
15312 |
if (shouldSandboxIframes) {
|
|
|
15313 |
parser.addNodeFilter('iframe', nodes => each$e(nodes, node => sandboxIframe(node, sandboxIframesExclusions)));
|
| 1 |
efrain |
15314 |
}
|
|
|
15315 |
};
|
|
|
15316 |
|
| 1441 |
ariadna |
15317 |
/*! @license DOMPurify 3.2.4 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.4/LICENSE */
|
|
|
15318 |
|
|
|
15319 |
const {
|
|
|
15320 |
entries,
|
|
|
15321 |
setPrototypeOf,
|
|
|
15322 |
isFrozen,
|
|
|
15323 |
getPrototypeOf,
|
|
|
15324 |
getOwnPropertyDescriptor
|
|
|
15325 |
} = Object;
|
|
|
15326 |
let {
|
|
|
15327 |
freeze,
|
|
|
15328 |
seal,
|
|
|
15329 |
create: create$7
|
|
|
15330 |
} = Object; // eslint-disable-line import/no-mutable-exports
|
|
|
15331 |
let {
|
|
|
15332 |
apply,
|
|
|
15333 |
construct
|
|
|
15334 |
} = typeof Reflect !== 'undefined' && Reflect;
|
| 1 |
efrain |
15335 |
if (!freeze) {
|
|
|
15336 |
freeze = function freeze(x) {
|
|
|
15337 |
return x;
|
|
|
15338 |
};
|
|
|
15339 |
}
|
|
|
15340 |
if (!seal) {
|
|
|
15341 |
seal = function seal(x) {
|
|
|
15342 |
return x;
|
|
|
15343 |
};
|
|
|
15344 |
}
|
| 1441 |
ariadna |
15345 |
if (!apply) {
|
|
|
15346 |
apply = function apply(fun, thisValue, args) {
|
|
|
15347 |
return fun.apply(thisValue, args);
|
|
|
15348 |
};
|
|
|
15349 |
}
|
| 1 |
efrain |
15350 |
if (!construct) {
|
|
|
15351 |
construct = function construct(Func, args) {
|
|
|
15352 |
return new Func(...args);
|
|
|
15353 |
};
|
|
|
15354 |
}
|
|
|
15355 |
const arrayForEach = unapply(Array.prototype.forEach);
|
| 1441 |
ariadna |
15356 |
const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
|
| 1 |
efrain |
15357 |
const arrayPop = unapply(Array.prototype.pop);
|
|
|
15358 |
const arrayPush = unapply(Array.prototype.push);
|
| 1441 |
ariadna |
15359 |
const arraySplice = unapply(Array.prototype.splice);
|
| 1 |
efrain |
15360 |
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
|
15361 |
const stringToString = unapply(String.prototype.toString);
|
|
|
15362 |
const stringMatch = unapply(String.prototype.match);
|
|
|
15363 |
const stringReplace = unapply(String.prototype.replace);
|
|
|
15364 |
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
|
15365 |
const stringTrim = unapply(String.prototype.trim);
|
| 1441 |
ariadna |
15366 |
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
| 1 |
efrain |
15367 |
const regExpTest = unapply(RegExp.prototype.test);
|
|
|
15368 |
const typeErrorCreate = unconstruct(TypeError);
|
| 1441 |
ariadna |
15369 |
/**
|
|
|
15370 |
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
|
|
15371 |
*
|
|
|
15372 |
* @param func - The function to be wrapped and called.
|
|
|
15373 |
* @returns A new function that calls the given function with a specified thisArg and arguments.
|
|
|
15374 |
*/
|
| 1 |
efrain |
15375 |
function unapply(func) {
|
|
|
15376 |
return function (thisArg) {
|
|
|
15377 |
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
|
15378 |
args[_key - 1] = arguments[_key];
|
|
|
15379 |
}
|
|
|
15380 |
return apply(func, thisArg, args);
|
|
|
15381 |
};
|
|
|
15382 |
}
|
| 1441 |
ariadna |
15383 |
/**
|
|
|
15384 |
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
|
|
|
15385 |
*
|
|
|
15386 |
* @param func - The constructor function to be wrapped and called.
|
|
|
15387 |
* @returns A new function that constructs an instance of the given constructor function with the provided arguments.
|
|
|
15388 |
*/
|
| 1 |
efrain |
15389 |
function unconstruct(func) {
|
|
|
15390 |
return function () {
|
|
|
15391 |
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
|
15392 |
args[_key2] = arguments[_key2];
|
|
|
15393 |
}
|
|
|
15394 |
return construct(func, args);
|
|
|
15395 |
};
|
|
|
15396 |
}
|
| 1441 |
ariadna |
15397 |
/**
|
|
|
15398 |
* Add properties to a lookup table
|
|
|
15399 |
*
|
|
|
15400 |
* @param set - The set to which elements will be added.
|
|
|
15401 |
* @param array - The array containing elements to be added to the set.
|
|
|
15402 |
* @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
|
|
|
15403 |
* @returns The modified set with added elements.
|
|
|
15404 |
*/
|
|
|
15405 |
function addToSet(set, array) {
|
|
|
15406 |
let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
|
| 1 |
efrain |
15407 |
if (setPrototypeOf) {
|
| 1441 |
ariadna |
15408 |
// Make 'in' and truthy checks like Boolean(set.constructor)
|
|
|
15409 |
// independent of any properties defined on Object.prototype.
|
|
|
15410 |
// Prevent prototype setters from intercepting set as a this value.
|
| 1 |
efrain |
15411 |
setPrototypeOf(set, null);
|
|
|
15412 |
}
|
|
|
15413 |
let l = array.length;
|
|
|
15414 |
while (l--) {
|
|
|
15415 |
let element = array[l];
|
|
|
15416 |
if (typeof element === 'string') {
|
|
|
15417 |
const lcElement = transformCaseFunc(element);
|
|
|
15418 |
if (lcElement !== element) {
|
| 1441 |
ariadna |
15419 |
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
| 1 |
efrain |
15420 |
if (!isFrozen(array)) {
|
|
|
15421 |
array[l] = lcElement;
|
|
|
15422 |
}
|
|
|
15423 |
element = lcElement;
|
|
|
15424 |
}
|
|
|
15425 |
}
|
|
|
15426 |
set[element] = true;
|
|
|
15427 |
}
|
|
|
15428 |
return set;
|
|
|
15429 |
}
|
| 1441 |
ariadna |
15430 |
/**
|
|
|
15431 |
* Clean up an array to harden against CSPP
|
|
|
15432 |
*
|
|
|
15433 |
* @param array - The array to be cleaned.
|
|
|
15434 |
* @returns The cleaned version of the array
|
|
|
15435 |
*/
|
|
|
15436 |
function cleanArray(array) {
|
|
|
15437 |
for (let index = 0; index < array.length; index++) {
|
|
|
15438 |
const isPropertyExist = objectHasOwnProperty(array, index);
|
|
|
15439 |
if (!isPropertyExist) {
|
|
|
15440 |
array[index] = null;
|
|
|
15441 |
}
|
|
|
15442 |
}
|
|
|
15443 |
return array;
|
|
|
15444 |
}
|
|
|
15445 |
/**
|
|
|
15446 |
* Shallow clone an object
|
|
|
15447 |
*
|
|
|
15448 |
* @param object - The object to be cloned.
|
|
|
15449 |
* @returns A new object that copies the original.
|
|
|
15450 |
*/
|
| 1 |
efrain |
15451 |
function clone(object) {
|
|
|
15452 |
const newObject = create$7(null);
|
|
|
15453 |
for (const [property, value] of entries(object)) {
|
| 1441 |
ariadna |
15454 |
const isPropertyExist = objectHasOwnProperty(object, property);
|
|
|
15455 |
if (isPropertyExist) {
|
|
|
15456 |
if (Array.isArray(value)) {
|
|
|
15457 |
newObject[property] = cleanArray(value);
|
|
|
15458 |
} else if (value && typeof value === 'object' && value.constructor === Object) {
|
|
|
15459 |
newObject[property] = clone(value);
|
|
|
15460 |
} else {
|
|
|
15461 |
newObject[property] = value;
|
|
|
15462 |
}
|
|
|
15463 |
}
|
| 1 |
efrain |
15464 |
}
|
|
|
15465 |
return newObject;
|
|
|
15466 |
}
|
| 1441 |
ariadna |
15467 |
/**
|
|
|
15468 |
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
|
|
15469 |
*
|
|
|
15470 |
* @param object - The object to look up the getter function in its prototype chain.
|
|
|
15471 |
* @param prop - The property name for which to find the getter function.
|
|
|
15472 |
* @returns The getter function found in the prototype chain or a fallback function.
|
|
|
15473 |
*/
|
| 1 |
efrain |
15474 |
function lookupGetter(object, prop) {
|
|
|
15475 |
while (object !== null) {
|
|
|
15476 |
const desc = getOwnPropertyDescriptor(object, prop);
|
|
|
15477 |
if (desc) {
|
|
|
15478 |
if (desc.get) {
|
|
|
15479 |
return unapply(desc.get);
|
|
|
15480 |
}
|
|
|
15481 |
if (typeof desc.value === 'function') {
|
|
|
15482 |
return unapply(desc.value);
|
|
|
15483 |
}
|
|
|
15484 |
}
|
|
|
15485 |
object = getPrototypeOf(object);
|
|
|
15486 |
}
|
| 1441 |
ariadna |
15487 |
function fallbackValue() {
|
| 1 |
efrain |
15488 |
return null;
|
|
|
15489 |
}
|
|
|
15490 |
return fallbackValue;
|
|
|
15491 |
}
|
| 1441 |
ariadna |
15492 |
|
|
|
15493 |
const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
|
|
|
15494 |
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
|
15495 |
const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
|
|
|
15496 |
// List of SVG elements that are disallowed by default.
|
|
|
15497 |
// We still need to know them so that we can do namespace
|
|
|
15498 |
// checks properly in case one wants to add them to
|
|
|
15499 |
// allow-list.
|
|
|
15500 |
const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
|
|
|
15501 |
const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
|
|
|
15502 |
// Similarly to SVG, we want to know all MathML elements,
|
|
|
15503 |
// even those that we disallow by default.
|
|
|
15504 |
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
| 1 |
efrain |
15505 |
const text = freeze(['#text']);
|
| 1441 |
ariadna |
15506 |
|
|
|
15507 |
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
|
|
|
15508 |
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
|
15509 |
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
|
15510 |
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
|
15511 |
|
|
|
15512 |
// eslint-disable-next-line unicorn/better-regex
|
|
|
15513 |
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
| 1 |
efrain |
15514 |
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
| 1441 |
ariadna |
15515 |
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
|
|
15516 |
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
|
|
15517 |
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
|
15518 |
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
|
15519 |
);
|
| 1 |
efrain |
15520 |
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
| 1441 |
ariadna |
15521 |
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
|
15522 |
);
|
| 1 |
efrain |
15523 |
const DOCTYPE_NAME = seal(/^html$/i);
|
| 1441 |
ariadna |
15524 |
const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
|
|
15525 |
|
|
|
15526 |
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
| 1 |
efrain |
15527 |
__proto__: null,
|
| 1441 |
ariadna |
15528 |
ARIA_ATTR: ARIA_ATTR,
|
|
|
15529 |
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
|
15530 |
CUSTOM_ELEMENT: CUSTOM_ELEMENT,
|
|
|
15531 |
DATA_ATTR: DATA_ATTR,
|
|
|
15532 |
DOCTYPE_NAME: DOCTYPE_NAME,
|
| 1 |
efrain |
15533 |
ERB_EXPR: ERB_EXPR,
|
|
|
15534 |
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
|
15535 |
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
| 1441 |
ariadna |
15536 |
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
|
15537 |
TMPLIT_EXPR: TMPLIT_EXPR
|
| 1 |
efrain |
15538 |
});
|
| 1441 |
ariadna |
15539 |
|
|
|
15540 |
/* eslint-disable @typescript-eslint/indent */
|
|
|
15541 |
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
|
15542 |
const NODE_TYPE = {
|
|
|
15543 |
element: 1,
|
|
|
15544 |
attribute: 2,
|
|
|
15545 |
text: 3,
|
|
|
15546 |
cdataSection: 4,
|
|
|
15547 |
entityReference: 5,
|
|
|
15548 |
// Deprecated
|
|
|
15549 |
entityNode: 6,
|
|
|
15550 |
// Deprecated
|
|
|
15551 |
progressingInstruction: 7,
|
|
|
15552 |
comment: 8,
|
|
|
15553 |
document: 9,
|
|
|
15554 |
documentType: 10,
|
|
|
15555 |
documentFragment: 11,
|
|
|
15556 |
notation: 12 // Deprecated
|
|
|
15557 |
};
|
|
|
15558 |
const getGlobal = function getGlobal() {
|
|
|
15559 |
return typeof window === 'undefined' ? null : window;
|
|
|
15560 |
};
|
|
|
15561 |
/**
|
|
|
15562 |
* Creates a no-op policy for internal use only.
|
|
|
15563 |
* Don't export this function outside this module!
|
|
|
15564 |
* @param trustedTypes The policy factory.
|
|
|
15565 |
* @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
|
|
|
15566 |
* @return The policy created (or null, if Trusted Types
|
|
|
15567 |
* are not supported or creating the policy failed).
|
|
|
15568 |
*/
|
| 1 |
efrain |
15569 |
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
|
|
15570 |
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
|
15571 |
return null;
|
|
|
15572 |
}
|
| 1441 |
ariadna |
15573 |
// Allow the callers to control the unique policy name
|
|
|
15574 |
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
|
15575 |
// Policy creation with duplicate names throws in Trusted Types.
|
| 1 |
efrain |
15576 |
let suffix = null;
|
|
|
15577 |
const ATTR_NAME = 'data-tt-policy-suffix';
|
|
|
15578 |
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
|
|
|
15579 |
suffix = purifyHostElement.getAttribute(ATTR_NAME);
|
|
|
15580 |
}
|
|
|
15581 |
const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
|
|
|
15582 |
try {
|
|
|
15583 |
return trustedTypes.createPolicy(policyName, {
|
|
|
15584 |
createHTML(html) {
|
|
|
15585 |
return html;
|
|
|
15586 |
},
|
|
|
15587 |
createScriptURL(scriptUrl) {
|
|
|
15588 |
return scriptUrl;
|
|
|
15589 |
}
|
|
|
15590 |
});
|
|
|
15591 |
} catch (_) {
|
| 1441 |
ariadna |
15592 |
// Policy creation failed (most likely another DOMPurify script has
|
|
|
15593 |
// already run). Skip creating the policy, as this will only cause errors
|
|
|
15594 |
// if TT are enforced.
|
| 1 |
efrain |
15595 |
console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
|
|
|
15596 |
return null;
|
|
|
15597 |
}
|
|
|
15598 |
};
|
| 1441 |
ariadna |
15599 |
const _createHooksMap = function _createHooksMap() {
|
|
|
15600 |
return {
|
|
|
15601 |
afterSanitizeAttributes: [],
|
|
|
15602 |
afterSanitizeElements: [],
|
|
|
15603 |
afterSanitizeShadowDOM: [],
|
|
|
15604 |
beforeSanitizeAttributes: [],
|
|
|
15605 |
beforeSanitizeElements: [],
|
|
|
15606 |
beforeSanitizeShadowDOM: [],
|
|
|
15607 |
uponSanitizeAttribute: [],
|
|
|
15608 |
uponSanitizeElement: [],
|
|
|
15609 |
uponSanitizeShadowNode: []
|
|
|
15610 |
};
|
|
|
15611 |
};
|
| 1 |
efrain |
15612 |
function createDOMPurify() {
|
|
|
15613 |
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
|
15614 |
const DOMPurify = root => createDOMPurify(root);
|
| 1441 |
ariadna |
15615 |
DOMPurify.version = '3.2.4';
|
| 1 |
efrain |
15616 |
DOMPurify.removed = [];
|
| 1441 |
ariadna |
15617 |
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
|
15618 |
// Not running in a browser, provide a factory function
|
|
|
15619 |
// so that you can pass your own Window
|
| 1 |
efrain |
15620 |
DOMPurify.isSupported = false;
|
|
|
15621 |
return DOMPurify;
|
|
|
15622 |
}
|
| 1441 |
ariadna |
15623 |
let {
|
|
|
15624 |
document
|
|
|
15625 |
} = window;
|
|
|
15626 |
const originalDocument = document;
|
| 1 |
efrain |
15627 |
const currentScript = originalDocument.currentScript;
|
| 1441 |
ariadna |
15628 |
const {
|
|
|
15629 |
DocumentFragment,
|
|
|
15630 |
HTMLTemplateElement,
|
|
|
15631 |
Node,
|
|
|
15632 |
Element,
|
|
|
15633 |
NodeFilter,
|
|
|
15634 |
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
|
|
|
15635 |
HTMLFormElement,
|
|
|
15636 |
DOMParser,
|
|
|
15637 |
trustedTypes
|
|
|
15638 |
} = window;
|
| 1 |
efrain |
15639 |
const ElementPrototype = Element.prototype;
|
|
|
15640 |
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
| 1441 |
ariadna |
15641 |
const remove = lookupGetter(ElementPrototype, 'remove');
|
| 1 |
efrain |
15642 |
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
|
15643 |
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
|
15644 |
const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
| 1441 |
ariadna |
15645 |
// As per issue #47, the web-components registry is inherited by a
|
|
|
15646 |
// new document created via createHTMLDocument. As per the spec
|
|
|
15647 |
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
|
15648 |
// a new empty registry is used when creating a template contents owner
|
|
|
15649 |
// document, so we use that as our parent document to ensure nothing
|
|
|
15650 |
// is inherited.
|
| 1 |
efrain |
15651 |
if (typeof HTMLTemplateElement === 'function') {
|
|
|
15652 |
const template = document.createElement('template');
|
|
|
15653 |
if (template.content && template.content.ownerDocument) {
|
|
|
15654 |
document = template.content.ownerDocument;
|
|
|
15655 |
}
|
|
|
15656 |
}
|
|
|
15657 |
let trustedTypesPolicy;
|
|
|
15658 |
let emptyHTML = '';
|
| 1441 |
ariadna |
15659 |
const {
|
|
|
15660 |
implementation,
|
|
|
15661 |
createNodeIterator,
|
|
|
15662 |
createDocumentFragment,
|
|
|
15663 |
getElementsByTagName
|
|
|
15664 |
} = document;
|
|
|
15665 |
const {
|
|
|
15666 |
importNode
|
|
|
15667 |
} = originalDocument;
|
|
|
15668 |
let hooks = _createHooksMap();
|
|
|
15669 |
/**
|
|
|
15670 |
* Expose whether this browser supports running the full DOMPurify.
|
|
|
15671 |
*/
|
| 1 |
efrain |
15672 |
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
| 1441 |
ariadna |
15673 |
const {
|
|
|
15674 |
MUSTACHE_EXPR,
|
|
|
15675 |
ERB_EXPR,
|
|
|
15676 |
TMPLIT_EXPR,
|
|
|
15677 |
DATA_ATTR,
|
|
|
15678 |
ARIA_ATTR,
|
|
|
15679 |
IS_SCRIPT_OR_DATA,
|
|
|
15680 |
ATTR_WHITESPACE,
|
|
|
15681 |
CUSTOM_ELEMENT
|
|
|
15682 |
} = EXPRESSIONS;
|
|
|
15683 |
let {
|
|
|
15684 |
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
|
15685 |
} = EXPRESSIONS;
|
|
|
15686 |
/**
|
|
|
15687 |
* We consider the elements and attributes below to be safe. Ideally
|
|
|
15688 |
* don't add any new ones but feel free to remove unwanted ones.
|
|
|
15689 |
*/
|
|
|
15690 |
/* allowed element names */
|
| 1 |
efrain |
15691 |
let ALLOWED_TAGS = null;
|
| 1441 |
ariadna |
15692 |
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
|
|
15693 |
/* Allowed attribute names */
|
| 1 |
efrain |
15694 |
let ALLOWED_ATTR = null;
|
| 1441 |
ariadna |
15695 |
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
|
|
15696 |
/*
|
|
|
15697 |
* Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
|
|
|
15698 |
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
|
15699 |
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
|
|
15700 |
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
|
15701 |
*/
|
|
|
15702 |
let CUSTOM_ELEMENT_HANDLING = Object.seal(create$7(null, {
|
| 1 |
efrain |
15703 |
tagNameCheck: {
|
|
|
15704 |
writable: true,
|
|
|
15705 |
configurable: false,
|
|
|
15706 |
enumerable: true,
|
|
|
15707 |
value: null
|
|
|
15708 |
},
|
|
|
15709 |
attributeNameCheck: {
|
|
|
15710 |
writable: true,
|
|
|
15711 |
configurable: false,
|
|
|
15712 |
enumerable: true,
|
|
|
15713 |
value: null
|
|
|
15714 |
},
|
|
|
15715 |
allowCustomizedBuiltInElements: {
|
|
|
15716 |
writable: true,
|
|
|
15717 |
configurable: false,
|
|
|
15718 |
enumerable: true,
|
|
|
15719 |
value: false
|
|
|
15720 |
}
|
|
|
15721 |
}));
|
| 1441 |
ariadna |
15722 |
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
| 1 |
efrain |
15723 |
let FORBID_TAGS = null;
|
| 1441 |
ariadna |
15724 |
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
| 1 |
efrain |
15725 |
let FORBID_ATTR = null;
|
| 1441 |
ariadna |
15726 |
/* Decide if ARIA attributes are okay */
|
| 1 |
efrain |
15727 |
let ALLOW_ARIA_ATTR = true;
|
| 1441 |
ariadna |
15728 |
/* Decide if custom data attributes are okay */
|
| 1 |
efrain |
15729 |
let ALLOW_DATA_ATTR = true;
|
| 1441 |
ariadna |
15730 |
/* Decide if unknown protocols are okay */
|
| 1 |
efrain |
15731 |
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
| 1441 |
ariadna |
15732 |
/* Decide if self-closing tags in attributes are allowed.
|
|
|
15733 |
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
| 1 |
efrain |
15734 |
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
| 1441 |
ariadna |
15735 |
/* Output should be safe for common template engines.
|
|
|
15736 |
* This means, DOMPurify removes data attributes, mustaches and ERB
|
|
|
15737 |
*/
|
| 1 |
efrain |
15738 |
let SAFE_FOR_TEMPLATES = false;
|
| 1441 |
ariadna |
15739 |
/* Output should be safe even for XML used within HTML and alike.
|
|
|
15740 |
* This means, DOMPurify removes comments when containing risky content.
|
|
|
15741 |
*/
|
|
|
15742 |
let SAFE_FOR_XML = true;
|
|
|
15743 |
/* Decide if document with <html>... should be returned */
|
| 1 |
efrain |
15744 |
let WHOLE_DOCUMENT = false;
|
| 1441 |
ariadna |
15745 |
/* Track whether config is already set on this instance of DOMPurify. */
|
| 1 |
efrain |
15746 |
let SET_CONFIG = false;
|
| 1441 |
ariadna |
15747 |
/* Decide if all elements (e.g. style, script) must be children of
|
|
|
15748 |
* document.body. By default, browsers might move them to document.head */
|
| 1 |
efrain |
15749 |
let FORCE_BODY = false;
|
| 1441 |
ariadna |
15750 |
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
|
15751 |
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
|
15752 |
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
|
15753 |
*/
|
| 1 |
efrain |
15754 |
let RETURN_DOM = false;
|
| 1441 |
ariadna |
15755 |
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
|
15756 |
* string (or a TrustedHTML object if Trusted Types are supported) */
|
| 1 |
efrain |
15757 |
let RETURN_DOM_FRAGMENT = false;
|
| 1441 |
ariadna |
15758 |
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
|
15759 |
* case Trusted Types are not supported */
|
| 1 |
efrain |
15760 |
let RETURN_TRUSTED_TYPE = false;
|
| 1441 |
ariadna |
15761 |
/* Output should be free from DOM clobbering attacks?
|
|
|
15762 |
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
|
|
15763 |
*/
|
| 1 |
efrain |
15764 |
let SANITIZE_DOM = true;
|
| 1441 |
ariadna |
15765 |
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
|
|
15766 |
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
|
|
15767 |
*
|
|
|
15768 |
* HTML/DOM spec rules that enable DOM Clobbering:
|
|
|
15769 |
* - Named Access on Window (§7.3.3)
|
|
|
15770 |
* - DOM Tree Accessors (§3.1.5)
|
|
|
15771 |
* - Form Element Parent-Child Relations (§4.10.3)
|
|
|
15772 |
* - Iframe srcdoc / Nested WindowProxies (§4.8.5)
|
|
|
15773 |
* - HTMLCollection (§4.2.10.2)
|
|
|
15774 |
*
|
|
|
15775 |
* Namespace isolation is implemented by prefixing `id` and `name` attributes
|
|
|
15776 |
* with a constant string, i.e., `user-content-`
|
|
|
15777 |
*/
|
| 1 |
efrain |
15778 |
let SANITIZE_NAMED_PROPS = false;
|
|
|
15779 |
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
| 1441 |
ariadna |
15780 |
/* Keep element content when removing element? */
|
| 1 |
efrain |
15781 |
let KEEP_CONTENT = true;
|
| 1441 |
ariadna |
15782 |
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
|
|
15783 |
* of importing it into a new Document and returning a sanitized copy */
|
| 1 |
efrain |
15784 |
let IN_PLACE = false;
|
| 1441 |
ariadna |
15785 |
/* Allow usage of profiles like html, svg and mathMl */
|
| 1 |
efrain |
15786 |
let USE_PROFILES = {};
|
| 1441 |
ariadna |
15787 |
/* Tags to ignore content of when KEEP_CONTENT is true */
|
| 1 |
efrain |
15788 |
let FORBID_CONTENTS = null;
|
| 1441 |
ariadna |
15789 |
const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
|
|
|
15790 |
/* Tags that are safe for data: URIs */
|
| 1 |
efrain |
15791 |
let DATA_URI_TAGS = null;
|
| 1441 |
ariadna |
15792 |
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
|
|
15793 |
/* Attributes safe for values like "javascript:" */
|
| 1 |
efrain |
15794 |
let URI_SAFE_ATTRIBUTES = null;
|
| 1441 |
ariadna |
15795 |
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
| 1 |
efrain |
15796 |
const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
|
15797 |
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
|
15798 |
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
| 1441 |
ariadna |
15799 |
/* Document namespace */
|
| 1 |
efrain |
15800 |
let NAMESPACE = HTML_NAMESPACE;
|
|
|
15801 |
let IS_EMPTY_INPUT = false;
|
| 1441 |
ariadna |
15802 |
/* Allowed XHTML+XML namespaces */
|
| 1 |
efrain |
15803 |
let ALLOWED_NAMESPACES = null;
|
| 1441 |
ariadna |
15804 |
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
|
|
15805 |
let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
|
15806 |
let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
|
|
|
15807 |
// Certain elements are allowed in both SVG and HTML
|
|
|
15808 |
// namespace. We need to specify them explicitly
|
|
|
15809 |
// so that they don't get erroneously deleted from
|
|
|
15810 |
// HTML namespace.
|
|
|
15811 |
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
|
|
15812 |
/* Parsing of strict XHTML documents */
|
|
|
15813 |
let PARSER_MEDIA_TYPE = null;
|
|
|
15814 |
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
| 1 |
efrain |
15815 |
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
| 1441 |
ariadna |
15816 |
let transformCaseFunc = null;
|
|
|
15817 |
/* Keep a reference to config to pass to hooks */
|
| 1 |
efrain |
15818 |
let CONFIG = null;
|
| 1441 |
ariadna |
15819 |
/* Ideally, do not touch anything below this line */
|
|
|
15820 |
/* ______________________________________________ */
|
| 1 |
efrain |
15821 |
const formElement = document.createElement('form');
|
|
|
15822 |
const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
|
|
15823 |
return testValue instanceof RegExp || testValue instanceof Function;
|
|
|
15824 |
};
|
| 1441 |
ariadna |
15825 |
/**
|
|
|
15826 |
* _parseConfig
|
|
|
15827 |
*
|
|
|
15828 |
* @param cfg optional config literal
|
|
|
15829 |
*/
|
|
|
15830 |
// eslint-disable-next-line complexity
|
|
|
15831 |
const _parseConfig = function _parseConfig() {
|
|
|
15832 |
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
| 1 |
efrain |
15833 |
if (CONFIG && CONFIG === cfg) {
|
|
|
15834 |
return;
|
|
|
15835 |
}
|
| 1441 |
ariadna |
15836 |
/* Shield configuration object from tampering */
|
| 1 |
efrain |
15837 |
if (!cfg || typeof cfg !== 'object') {
|
|
|
15838 |
cfg = {};
|
|
|
15839 |
}
|
| 1441 |
ariadna |
15840 |
/* Shield configuration object from prototype pollution */
|
| 1 |
efrain |
15841 |
cfg = clone(cfg);
|
| 1441 |
ariadna |
15842 |
PARSER_MEDIA_TYPE =
|
|
|
15843 |
// eslint-disable-next-line unicorn/prefer-includes
|
|
|
15844 |
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
|
|
|
15845 |
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
| 1 |
efrain |
15846 |
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
| 1441 |
ariadna |
15847 |
/* Set configuration parameters */
|
|
|
15848 |
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
|
|
15849 |
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
|
15850 |
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
|
15851 |
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
|
15852 |
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
|
|
15853 |
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
|
15854 |
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
|
|
15855 |
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
|
|
15856 |
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
|
|
|
15857 |
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
|
15858 |
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
|
15859 |
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
|
|
|
15860 |
ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
|
|
|
15861 |
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
|
|
|
15862 |
SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
|
|
|
15863 |
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
|
|
|
15864 |
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
|
|
|
15865 |
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
|
|
|
15866 |
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
|
|
|
15867 |
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
|
|
|
15868 |
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
|
|
|
15869 |
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
|
|
|
15870 |
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
|
15871 |
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
| 1 |
efrain |
15872 |
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
|
|
15873 |
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
| 1441 |
ariadna |
15874 |
MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
|
|
|
15875 |
HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
|
| 1 |
efrain |
15876 |
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
|
15877 |
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
|
|
15878 |
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
|
|
15879 |
}
|
|
|
15880 |
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
|
|
|
15881 |
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
|
|
|
15882 |
}
|
|
|
15883 |
if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
|
|
|
15884 |
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
|
|
|
15885 |
}
|
|
|
15886 |
if (SAFE_FOR_TEMPLATES) {
|
|
|
15887 |
ALLOW_DATA_ATTR = false;
|
|
|
15888 |
}
|
|
|
15889 |
if (RETURN_DOM_FRAGMENT) {
|
|
|
15890 |
RETURN_DOM = true;
|
|
|
15891 |
}
|
| 1441 |
ariadna |
15892 |
/* Parse profile info */
|
| 1 |
efrain |
15893 |
if (USE_PROFILES) {
|
| 1441 |
ariadna |
15894 |
ALLOWED_TAGS = addToSet({}, text);
|
| 1 |
efrain |
15895 |
ALLOWED_ATTR = [];
|
|
|
15896 |
if (USE_PROFILES.html === true) {
|
|
|
15897 |
addToSet(ALLOWED_TAGS, html$1);
|
|
|
15898 |
addToSet(ALLOWED_ATTR, html);
|
|
|
15899 |
}
|
|
|
15900 |
if (USE_PROFILES.svg === true) {
|
|
|
15901 |
addToSet(ALLOWED_TAGS, svg$1);
|
|
|
15902 |
addToSet(ALLOWED_ATTR, svg);
|
|
|
15903 |
addToSet(ALLOWED_ATTR, xml);
|
|
|
15904 |
}
|
|
|
15905 |
if (USE_PROFILES.svgFilters === true) {
|
|
|
15906 |
addToSet(ALLOWED_TAGS, svgFilters);
|
|
|
15907 |
addToSet(ALLOWED_ATTR, svg);
|
|
|
15908 |
addToSet(ALLOWED_ATTR, xml);
|
|
|
15909 |
}
|
|
|
15910 |
if (USE_PROFILES.mathMl === true) {
|
|
|
15911 |
addToSet(ALLOWED_TAGS, mathMl$1);
|
|
|
15912 |
addToSet(ALLOWED_ATTR, mathMl);
|
|
|
15913 |
addToSet(ALLOWED_ATTR, xml);
|
|
|
15914 |
}
|
|
|
15915 |
}
|
| 1441 |
ariadna |
15916 |
/* Merge configuration parameters */
|
| 1 |
efrain |
15917 |
if (cfg.ADD_TAGS) {
|
|
|
15918 |
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
|
15919 |
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
|
15920 |
}
|
|
|
15921 |
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
|
15922 |
}
|
|
|
15923 |
if (cfg.ADD_ATTR) {
|
|
|
15924 |
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
|
15925 |
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
|
15926 |
}
|
|
|
15927 |
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
|
15928 |
}
|
|
|
15929 |
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
|
15930 |
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
|
15931 |
}
|
|
|
15932 |
if (cfg.FORBID_CONTENTS) {
|
|
|
15933 |
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
|
15934 |
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
|
15935 |
}
|
|
|
15936 |
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
|
15937 |
}
|
| 1441 |
ariadna |
15938 |
/* Add #text in case KEEP_CONTENT is set to true */
|
| 1 |
efrain |
15939 |
if (KEEP_CONTENT) {
|
|
|
15940 |
ALLOWED_TAGS['#text'] = true;
|
|
|
15941 |
}
|
| 1441 |
ariadna |
15942 |
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
|
| 1 |
efrain |
15943 |
if (WHOLE_DOCUMENT) {
|
| 1441 |
ariadna |
15944 |
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
|
| 1 |
efrain |
15945 |
}
|
| 1441 |
ariadna |
15946 |
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
| 1 |
efrain |
15947 |
if (ALLOWED_TAGS.table) {
|
|
|
15948 |
addToSet(ALLOWED_TAGS, ['tbody']);
|
|
|
15949 |
delete FORBID_TAGS.tbody;
|
|
|
15950 |
}
|
|
|
15951 |
if (cfg.TRUSTED_TYPES_POLICY) {
|
|
|
15952 |
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
|
|
|
15953 |
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
|
|
|
15954 |
}
|
|
|
15955 |
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
|
|
15956 |
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
|
|
15957 |
}
|
| 1441 |
ariadna |
15958 |
// Overwrite existing TrustedTypes policy.
|
| 1 |
efrain |
15959 |
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
|
| 1441 |
ariadna |
15960 |
// Sign local variables required by `sanitize`.
|
| 1 |
efrain |
15961 |
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
|
15962 |
} else {
|
| 1441 |
ariadna |
15963 |
// Uninitialized policy, attempt to initialize the internal dompurify policy.
|
| 1 |
efrain |
15964 |
if (trustedTypesPolicy === undefined) {
|
|
|
15965 |
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
|
|
15966 |
}
|
| 1441 |
ariadna |
15967 |
// If creating the internal policy succeeded sign internal variables.
|
| 1 |
efrain |
15968 |
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
|
|
|
15969 |
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
|
15970 |
}
|
|
|
15971 |
}
|
| 1441 |
ariadna |
15972 |
// Prevent further manipulation of configuration.
|
|
|
15973 |
// Not available in IE8, Safari 5, etc.
|
| 1 |
efrain |
15974 |
if (freeze) {
|
|
|
15975 |
freeze(cfg);
|
|
|
15976 |
}
|
|
|
15977 |
CONFIG = cfg;
|
|
|
15978 |
};
|
| 1441 |
ariadna |
15979 |
/* Keep track of all possible SVG and MathML tags
|
|
|
15980 |
* so that we can perform the namespace checks
|
|
|
15981 |
* correctly. */
|
|
|
15982 |
const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
|
|
|
15983 |
const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
|
|
|
15984 |
/**
|
|
|
15985 |
* @param element a DOM element whose namespace is being checked
|
|
|
15986 |
* @returns Return false if the element has a
|
|
|
15987 |
* namespace that a spec-compliant parser would never
|
|
|
15988 |
* return. Return true otherwise.
|
|
|
15989 |
*/
|
| 1 |
efrain |
15990 |
const _checkValidNamespace = function _checkValidNamespace(element) {
|
|
|
15991 |
let parent = getParentNode(element);
|
| 1441 |
ariadna |
15992 |
// In JSDOM, if we're inside shadow DOM, then parentNode
|
|
|
15993 |
// can be null. We just simulate parent in this case.
|
| 1 |
efrain |
15994 |
if (!parent || !parent.tagName) {
|
|
|
15995 |
parent = {
|
|
|
15996 |
namespaceURI: NAMESPACE,
|
|
|
15997 |
tagName: 'template'
|
|
|
15998 |
};
|
|
|
15999 |
}
|
|
|
16000 |
const tagName = stringToLowerCase(element.tagName);
|
|
|
16001 |
const parentTagName = stringToLowerCase(parent.tagName);
|
|
|
16002 |
if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
|
16003 |
return false;
|
|
|
16004 |
}
|
|
|
16005 |
if (element.namespaceURI === SVG_NAMESPACE) {
|
| 1441 |
ariadna |
16006 |
// The only way to switch from HTML namespace to SVG
|
|
|
16007 |
// is via <svg>. If it happens via any other tag, then
|
|
|
16008 |
// it should be killed.
|
| 1 |
efrain |
16009 |
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
|
16010 |
return tagName === 'svg';
|
|
|
16011 |
}
|
| 1441 |
ariadna |
16012 |
// The only way to switch from MathML to SVG is via`
|
|
|
16013 |
// svg if parent is either <annotation-xml> or MathML
|
|
|
16014 |
// text integration points.
|
| 1 |
efrain |
16015 |
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
|
|
16016 |
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
|
|
16017 |
}
|
| 1441 |
ariadna |
16018 |
// We only allow elements that are defined in SVG
|
|
|
16019 |
// spec. All others are disallowed in SVG namespace.
|
| 1 |
efrain |
16020 |
return Boolean(ALL_SVG_TAGS[tagName]);
|
|
|
16021 |
}
|
|
|
16022 |
if (element.namespaceURI === MATHML_NAMESPACE) {
|
| 1441 |
ariadna |
16023 |
// The only way to switch from HTML namespace to MathML
|
|
|
16024 |
// is via <math>. If it happens via any other tag, then
|
|
|
16025 |
// it should be killed.
|
| 1 |
efrain |
16026 |
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
|
16027 |
return tagName === 'math';
|
|
|
16028 |
}
|
| 1441 |
ariadna |
16029 |
// The only way to switch from SVG to MathML is via
|
|
|
16030 |
// <math> and HTML integration points
|
| 1 |
efrain |
16031 |
if (parent.namespaceURI === SVG_NAMESPACE) {
|
|
|
16032 |
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
|
|
16033 |
}
|
| 1441 |
ariadna |
16034 |
// We only allow elements that are defined in MathML
|
|
|
16035 |
// spec. All others are disallowed in MathML namespace.
|
| 1 |
efrain |
16036 |
return Boolean(ALL_MATHML_TAGS[tagName]);
|
|
|
16037 |
}
|
|
|
16038 |
if (element.namespaceURI === HTML_NAMESPACE) {
|
| 1441 |
ariadna |
16039 |
// The only way to switch from SVG to HTML is via
|
|
|
16040 |
// HTML integration points, and from MathML to HTML
|
|
|
16041 |
// is via MathML text integration points
|
| 1 |
efrain |
16042 |
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
|
|
|
16043 |
return false;
|
|
|
16044 |
}
|
|
|
16045 |
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
|
|
16046 |
return false;
|
|
|
16047 |
}
|
| 1441 |
ariadna |
16048 |
// We disallow tags that are specific for MathML
|
|
|
16049 |
// or SVG and should never appear in HTML namespace
|
| 1 |
efrain |
16050 |
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
|
|
16051 |
}
|
| 1441 |
ariadna |
16052 |
// For XHTML and XML documents that support custom namespaces
|
| 1 |
efrain |
16053 |
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
|
16054 |
return true;
|
|
|
16055 |
}
|
| 1441 |
ariadna |
16056 |
// The code should never reach this place (this means
|
|
|
16057 |
// that the element somehow got namespace that is not
|
|
|
16058 |
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
|
|
|
16059 |
// Return false just in case.
|
| 1 |
efrain |
16060 |
return false;
|
|
|
16061 |
};
|
| 1441 |
ariadna |
16062 |
/**
|
|
|
16063 |
* _forceRemove
|
|
|
16064 |
*
|
|
|
16065 |
* @param node a DOM node
|
|
|
16066 |
*/
|
| 1 |
efrain |
16067 |
const _forceRemove = function _forceRemove(node) {
|
| 1441 |
ariadna |
16068 |
arrayPush(DOMPurify.removed, {
|
|
|
16069 |
element: node
|
|
|
16070 |
});
|
| 1 |
efrain |
16071 |
try {
|
| 1441 |
ariadna |
16072 |
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
|
|
16073 |
getParentNode(node).removeChild(node);
|
| 1 |
efrain |
16074 |
} catch (_) {
|
| 1441 |
ariadna |
16075 |
remove(node);
|
| 1 |
efrain |
16076 |
}
|
|
|
16077 |
};
|
| 1441 |
ariadna |
16078 |
/**
|
|
|
16079 |
* _removeAttribute
|
|
|
16080 |
*
|
|
|
16081 |
* @param name an Attribute name
|
|
|
16082 |
* @param element a DOM node
|
|
|
16083 |
*/
|
|
|
16084 |
const _removeAttribute = function _removeAttribute(name, element) {
|
| 1 |
efrain |
16085 |
try {
|
|
|
16086 |
arrayPush(DOMPurify.removed, {
|
| 1441 |
ariadna |
16087 |
attribute: element.getAttributeNode(name),
|
|
|
16088 |
from: element
|
| 1 |
efrain |
16089 |
});
|
|
|
16090 |
} catch (_) {
|
|
|
16091 |
arrayPush(DOMPurify.removed, {
|
|
|
16092 |
attribute: null,
|
| 1441 |
ariadna |
16093 |
from: element
|
| 1 |
efrain |
16094 |
});
|
|
|
16095 |
}
|
| 1441 |
ariadna |
16096 |
element.removeAttribute(name);
|
|
|
16097 |
// We void attribute values for unremovable "is" attributes
|
|
|
16098 |
if (name === 'is') {
|
| 1 |
efrain |
16099 |
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
|
|
16100 |
try {
|
| 1441 |
ariadna |
16101 |
_forceRemove(element);
|
|
|
16102 |
} catch (_) {}
|
| 1 |
efrain |
16103 |
} else {
|
|
|
16104 |
try {
|
| 1441 |
ariadna |
16105 |
element.setAttribute(name, '');
|
|
|
16106 |
} catch (_) {}
|
| 1 |
efrain |
16107 |
}
|
|
|
16108 |
}
|
|
|
16109 |
};
|
| 1441 |
ariadna |
16110 |
/**
|
|
|
16111 |
* _initDocument
|
|
|
16112 |
*
|
|
|
16113 |
* @param dirty - a string of dirty markup
|
|
|
16114 |
* @return a DOM, filled with the dirty markup
|
|
|
16115 |
*/
|
| 1 |
efrain |
16116 |
const _initDocument = function _initDocument(dirty) {
|
| 1441 |
ariadna |
16117 |
/* Create a HTML document */
|
|
|
16118 |
let doc = null;
|
|
|
16119 |
let leadingWhitespace = null;
|
| 1 |
efrain |
16120 |
if (FORCE_BODY) {
|
|
|
16121 |
dirty = '<remove></remove>' + dirty;
|
|
|
16122 |
} else {
|
| 1441 |
ariadna |
16123 |
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
| 1 |
efrain |
16124 |
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
|
|
|
16125 |
leadingWhitespace = matches && matches[0];
|
|
|
16126 |
}
|
|
|
16127 |
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
|
| 1441 |
ariadna |
16128 |
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
|
| 1 |
efrain |
16129 |
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
|
16130 |
}
|
|
|
16131 |
const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
| 1441 |
ariadna |
16132 |
/*
|
|
|
16133 |
* Use the DOMParser API by default, fallback later if needs be
|
|
|
16134 |
* DOMParser not work for svg when has multiple root element.
|
|
|
16135 |
*/
|
| 1 |
efrain |
16136 |
if (NAMESPACE === HTML_NAMESPACE) {
|
|
|
16137 |
try {
|
|
|
16138 |
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
| 1441 |
ariadna |
16139 |
} catch (_) {}
|
| 1 |
efrain |
16140 |
}
|
| 1441 |
ariadna |
16141 |
/* Use createHTMLDocument in case DOMParser is not available */
|
| 1 |
efrain |
16142 |
if (!doc || !doc.documentElement) {
|
|
|
16143 |
doc = implementation.createDocument(NAMESPACE, 'template', null);
|
|
|
16144 |
try {
|
|
|
16145 |
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
|
|
|
16146 |
} catch (_) {
|
| 1441 |
ariadna |
16147 |
// Syntax error if dirtyPayload is invalid xml
|
| 1 |
efrain |
16148 |
}
|
|
|
16149 |
}
|
|
|
16150 |
const body = doc.body || doc.documentElement;
|
|
|
16151 |
if (dirty && leadingWhitespace) {
|
|
|
16152 |
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
|
|
16153 |
}
|
| 1441 |
ariadna |
16154 |
/* Work on whole document or just its body */
|
| 1 |
efrain |
16155 |
if (NAMESPACE === HTML_NAMESPACE) {
|
|
|
16156 |
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
|
|
16157 |
}
|
|
|
16158 |
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
|
|
16159 |
};
|
| 1441 |
ariadna |
16160 |
/**
|
|
|
16161 |
* Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
|
|
|
16162 |
*
|
|
|
16163 |
* @param root The root element or node to start traversing on.
|
|
|
16164 |
* @return The created NodeIterator
|
|
|
16165 |
*/
|
|
|
16166 |
const _createNodeIterator = function _createNodeIterator(root) {
|
|
|
16167 |
return createNodeIterator.call(root.ownerDocument || root, root,
|
|
|
16168 |
// eslint-disable-next-line no-bitwise
|
|
|
16169 |
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
|
| 1 |
efrain |
16170 |
};
|
| 1441 |
ariadna |
16171 |
/**
|
|
|
16172 |
* _isClobbered
|
|
|
16173 |
*
|
|
|
16174 |
* @param element element to check for clobbering attacks
|
|
|
16175 |
* @return true if clobbered, false if safe
|
|
|
16176 |
*/
|
|
|
16177 |
const _isClobbered = function _isClobbered(element) {
|
|
|
16178 |
return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
|
| 1 |
efrain |
16179 |
};
|
| 1441 |
ariadna |
16180 |
/**
|
|
|
16181 |
* Checks whether the given object is a DOM node.
|
|
|
16182 |
*
|
|
|
16183 |
* @param value object to check whether it's a DOM node
|
|
|
16184 |
* @return true is object is a DOM node
|
|
|
16185 |
*/
|
|
|
16186 |
const _isNode = function _isNode(value) {
|
|
|
16187 |
return typeof Node === 'function' && value instanceof Node;
|
| 1 |
efrain |
16188 |
};
|
| 1441 |
ariadna |
16189 |
function _executeHooks(hooks, currentNode, data) {
|
|
|
16190 |
arrayForEach(hooks, hook => {
|
| 1 |
efrain |
16191 |
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
|
16192 |
});
|
| 1441 |
ariadna |
16193 |
}
|
|
|
16194 |
/**
|
|
|
16195 |
* _sanitizeElements
|
|
|
16196 |
*
|
|
|
16197 |
* @protect nodeName
|
|
|
16198 |
* @protect textContent
|
|
|
16199 |
* @protect removeChild
|
|
|
16200 |
* @param currentNode to check for permission to exist
|
|
|
16201 |
* @return true if node was killed, false if left alive
|
|
|
16202 |
*/
|
| 1 |
efrain |
16203 |
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
| 1441 |
ariadna |
16204 |
let content = null;
|
|
|
16205 |
/* Execute a hook if present */
|
|
|
16206 |
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
|
|
16207 |
/* Check if element is clobbered or can clobber */
|
| 1 |
efrain |
16208 |
if (_isClobbered(currentNode)) {
|
|
|
16209 |
_forceRemove(currentNode);
|
|
|
16210 |
return true;
|
|
|
16211 |
}
|
| 1441 |
ariadna |
16212 |
/* Now let's check the element's type and name */
|
| 1 |
efrain |
16213 |
const tagName = transformCaseFunc(currentNode.nodeName);
|
| 1441 |
ariadna |
16214 |
/* Execute a hook if present */
|
|
|
16215 |
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
| 1 |
efrain |
16216 |
tagName,
|
|
|
16217 |
allowedTags: ALLOWED_TAGS
|
|
|
16218 |
});
|
| 1441 |
ariadna |
16219 |
/* Detect mXSS attempts abusing namespace confusion */
|
|
|
16220 |
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
|
| 1 |
efrain |
16221 |
_forceRemove(currentNode);
|
|
|
16222 |
return true;
|
|
|
16223 |
}
|
| 1441 |
ariadna |
16224 |
/* Remove any occurrence of processing instructions */
|
|
|
16225 |
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
|
|
16226 |
_forceRemove(currentNode);
|
|
|
16227 |
return true;
|
|
|
16228 |
}
|
|
|
16229 |
/* Remove any kind of possibly harmful comments */
|
|
|
16230 |
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
|
|
|
16231 |
_forceRemove(currentNode);
|
|
|
16232 |
return true;
|
|
|
16233 |
}
|
|
|
16234 |
/* Remove element if anything forbids its presence */
|
| 1 |
efrain |
16235 |
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
| 1441 |
ariadna |
16236 |
/* Check if we have a custom element to handle */
|
|
|
16237 |
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
|
16238 |
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
| 1 |
efrain |
16239 |
return false;
|
| 1441 |
ariadna |
16240 |
}
|
|
|
16241 |
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
|
| 1 |
efrain |
16242 |
return false;
|
| 1441 |
ariadna |
16243 |
}
|
| 1 |
efrain |
16244 |
}
|
| 1441 |
ariadna |
16245 |
/* Keep content except for bad-listed elements */
|
| 1 |
efrain |
16246 |
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
|
16247 |
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
|
16248 |
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
|
|
16249 |
if (childNodes && parentNode) {
|
|
|
16250 |
const childCount = childNodes.length;
|
|
|
16251 |
for (let i = childCount - 1; i >= 0; --i) {
|
| 1441 |
ariadna |
16252 |
const childClone = cloneNode(childNodes[i], true);
|
|
|
16253 |
childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
|
|
|
16254 |
parentNode.insertBefore(childClone, getNextSibling(currentNode));
|
| 1 |
efrain |
16255 |
}
|
|
|
16256 |
}
|
|
|
16257 |
}
|
|
|
16258 |
_forceRemove(currentNode);
|
|
|
16259 |
return true;
|
|
|
16260 |
}
|
| 1441 |
ariadna |
16261 |
/* Check whether element has a valid namespace */
|
| 1 |
efrain |
16262 |
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
|
|
16263 |
_forceRemove(currentNode);
|
|
|
16264 |
return true;
|
|
|
16265 |
}
|
| 1441 |
ariadna |
16266 |
/* Make sure that older browsers don't get fallback-tag mXSS */
|
| 1 |
efrain |
16267 |
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
|
|
|
16268 |
_forceRemove(currentNode);
|
|
|
16269 |
return true;
|
|
|
16270 |
}
|
| 1441 |
ariadna |
16271 |
/* Sanitize element content to be template-safe */
|
|
|
16272 |
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
|
|
16273 |
/* Get the element's text content */
|
| 1 |
efrain |
16274 |
content = currentNode.textContent;
|
| 1441 |
ariadna |
16275 |
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
|
16276 |
content = stringReplace(content, expr, ' ');
|
|
|
16277 |
});
|
| 1 |
efrain |
16278 |
if (currentNode.textContent !== content) {
|
| 1441 |
ariadna |
16279 |
arrayPush(DOMPurify.removed, {
|
|
|
16280 |
element: currentNode.cloneNode()
|
|
|
16281 |
});
|
| 1 |
efrain |
16282 |
currentNode.textContent = content;
|
|
|
16283 |
}
|
|
|
16284 |
}
|
| 1441 |
ariadna |
16285 |
/* Execute a hook if present */
|
|
|
16286 |
_executeHooks(hooks.afterSanitizeElements, currentNode, null);
|
| 1 |
efrain |
16287 |
return false;
|
|
|
16288 |
};
|
| 1441 |
ariadna |
16289 |
/**
|
|
|
16290 |
* _isValidAttribute
|
|
|
16291 |
*
|
|
|
16292 |
* @param lcTag Lowercase tag name of containing element.
|
|
|
16293 |
* @param lcName Lowercase attribute name.
|
|
|
16294 |
* @param value Attribute value.
|
|
|
16295 |
* @return Returns true if `value` is valid, otherwise false.
|
|
|
16296 |
*/
|
|
|
16297 |
// eslint-disable-next-line complexity
|
| 1 |
efrain |
16298 |
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
| 1441 |
ariadna |
16299 |
/* Make sure attribute cannot clobber */
|
| 1 |
efrain |
16300 |
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
|
16301 |
return false;
|
|
|
16302 |
}
|
| 1441 |
ariadna |
16303 |
/* Allow valid data-* attributes: At least one character after "-"
|
|
|
16304 |
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
|
16305 |
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
|
16306 |
We don't need to check the value; it's always URI safe. */
|
|
|
16307 |
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
|
16308 |
if (
|
|
|
16309 |
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
|
16310 |
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
|
16311 |
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
|
16312 |
_isBasicCustomElement(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)) ||
|
|
|
16313 |
// Alternative, second condition checks if it's an `is`-attribute, AND
|
|
|
16314 |
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
|
16315 |
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))) ; else {
|
| 1 |
efrain |
16316 |
return false;
|
|
|
16317 |
}
|
| 1441 |
ariadna |
16318 |
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
|
16319 |
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
|
| 1 |
efrain |
16320 |
return false;
|
|
|
16321 |
} else ;
|
|
|
16322 |
return true;
|
|
|
16323 |
};
|
| 1441 |
ariadna |
16324 |
/**
|
|
|
16325 |
* _isBasicCustomElement
|
|
|
16326 |
* checks if at least one dash is included in tagName, and it's not the first char
|
|
|
16327 |
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
|
|
16328 |
*
|
|
|
16329 |
* @param tagName name of the tag of the node to sanitize
|
|
|
16330 |
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
|
|
|
16331 |
*/
|
|
|
16332 |
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
|
|
|
16333 |
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
|
| 1 |
efrain |
16334 |
};
|
| 1441 |
ariadna |
16335 |
/**
|
|
|
16336 |
* _sanitizeAttributes
|
|
|
16337 |
*
|
|
|
16338 |
* @protect attributes
|
|
|
16339 |
* @protect nodeName
|
|
|
16340 |
* @protect removeAttribute
|
|
|
16341 |
* @protect setAttribute
|
|
|
16342 |
*
|
|
|
16343 |
* @param currentNode to sanitize
|
|
|
16344 |
*/
|
| 1 |
efrain |
16345 |
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
| 1441 |
ariadna |
16346 |
/* Execute a hook if present */
|
|
|
16347 |
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
|
|
|
16348 |
const {
|
|
|
16349 |
attributes
|
|
|
16350 |
} = currentNode;
|
|
|
16351 |
/* Check if we have attributes; if not we might have a text node */
|
|
|
16352 |
if (!attributes || _isClobbered(currentNode)) {
|
| 1 |
efrain |
16353 |
return;
|
|
|
16354 |
}
|
|
|
16355 |
const hookEvent = {
|
|
|
16356 |
attrName: '',
|
|
|
16357 |
attrValue: '',
|
|
|
16358 |
keepAttr: true,
|
| 1441 |
ariadna |
16359 |
allowedAttributes: ALLOWED_ATTR,
|
|
|
16360 |
forceKeepAttr: undefined
|
| 1 |
efrain |
16361 |
};
|
| 1441 |
ariadna |
16362 |
let l = attributes.length;
|
|
|
16363 |
/* Go backwards over all attributes; safely remove bad ones */
|
| 1 |
efrain |
16364 |
while (l--) {
|
| 1441 |
ariadna |
16365 |
const attr = attributes[l];
|
|
|
16366 |
const {
|
|
|
16367 |
name,
|
|
|
16368 |
namespaceURI,
|
|
|
16369 |
value: attrValue
|
|
|
16370 |
} = attr;
|
|
|
16371 |
const lcName = transformCaseFunc(name);
|
|
|
16372 |
let value = name === 'value' ? attrValue : stringTrim(attrValue);
|
| 1 |
efrain |
16373 |
const initValue = value;
|
| 1441 |
ariadna |
16374 |
/* Execute a hook if present */
|
| 1 |
efrain |
16375 |
hookEvent.attrName = lcName;
|
|
|
16376 |
hookEvent.attrValue = value;
|
|
|
16377 |
hookEvent.keepAttr = true;
|
| 1441 |
ariadna |
16378 |
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
|
|
16379 |
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
|
| 1 |
efrain |
16380 |
value = hookEvent.attrValue;
|
| 1441 |
ariadna |
16381 |
/* Full DOM Clobbering protection via namespace isolation,
|
|
|
16382 |
* Prefix id and name attributes with `user-content-`
|
|
|
16383 |
*/
|
|
|
16384 |
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
|
16385 |
// Remove the attribute with this value
|
|
|
16386 |
_removeAttribute(name, currentNode);
|
|
|
16387 |
// Prefix the value and later re-create the attribute with the sanitized value
|
|
|
16388 |
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
|
16389 |
}
|
|
|
16390 |
/* Work around a security issue with comments inside attributes */
|
|
|
16391 |
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
|
|
|
16392 |
_removeAttribute(name, currentNode);
|
|
|
16393 |
continue;
|
|
|
16394 |
}
|
|
|
16395 |
/* Did the hooks approve of the attribute? */
|
| 1 |
efrain |
16396 |
if (hookEvent.forceKeepAttr) {
|
|
|
16397 |
continue;
|
|
|
16398 |
}
|
| 1441 |
ariadna |
16399 |
/* Remove attribute */
|
|
|
16400 |
/* Did the hooks approve of the attribute? */
|
| 1 |
efrain |
16401 |
if (!hookEvent.keepAttr) {
|
|
|
16402 |
_removeAttribute(name, currentNode);
|
|
|
16403 |
continue;
|
|
|
16404 |
}
|
| 1441 |
ariadna |
16405 |
/* Work around a security issue in jQuery 3.0 */
|
| 1 |
efrain |
16406 |
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
|
|
16407 |
_removeAttribute(name, currentNode);
|
|
|
16408 |
continue;
|
|
|
16409 |
}
|
| 1441 |
ariadna |
16410 |
/* Sanitize attribute content to be template-safe */
|
| 1 |
efrain |
16411 |
if (SAFE_FOR_TEMPLATES) {
|
| 1441 |
ariadna |
16412 |
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
|
16413 |
value = stringReplace(value, expr, ' ');
|
|
|
16414 |
});
|
| 1 |
efrain |
16415 |
}
|
| 1441 |
ariadna |
16416 |
/* Is `value` valid for this attribute? */
|
| 1 |
efrain |
16417 |
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
|
16418 |
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
|
16419 |
_removeAttribute(name, currentNode);
|
|
|
16420 |
continue;
|
|
|
16421 |
}
|
| 1441 |
ariadna |
16422 |
/* Handle attributes that require Trusted Types */
|
| 1 |
efrain |
16423 |
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
| 1441 |
ariadna |
16424 |
if (namespaceURI) ; else {
|
| 1 |
efrain |
16425 |
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
| 1441 |
ariadna |
16426 |
case 'TrustedHTML':
|
|
|
16427 |
{
|
|
|
16428 |
value = trustedTypesPolicy.createHTML(value);
|
|
|
16429 |
break;
|
|
|
16430 |
}
|
|
|
16431 |
case 'TrustedScriptURL':
|
|
|
16432 |
{
|
|
|
16433 |
value = trustedTypesPolicy.createScriptURL(value);
|
|
|
16434 |
break;
|
|
|
16435 |
}
|
| 1 |
efrain |
16436 |
}
|
|
|
16437 |
}
|
|
|
16438 |
}
|
| 1441 |
ariadna |
16439 |
/* Handle invalid data-* attribute set by try-catching it */
|
| 1 |
efrain |
16440 |
if (value !== initValue) {
|
|
|
16441 |
try {
|
|
|
16442 |
if (namespaceURI) {
|
|
|
16443 |
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
|
16444 |
} else {
|
| 1441 |
ariadna |
16445 |
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
| 1 |
efrain |
16446 |
currentNode.setAttribute(name, value);
|
|
|
16447 |
}
|
| 1441 |
ariadna |
16448 |
if (_isClobbered(currentNode)) {
|
|
|
16449 |
_forceRemove(currentNode);
|
|
|
16450 |
} else {
|
|
|
16451 |
arrayPop(DOMPurify.removed);
|
|
|
16452 |
}
|
|
|
16453 |
} catch (_) {}
|
| 1 |
efrain |
16454 |
}
|
|
|
16455 |
}
|
| 1441 |
ariadna |
16456 |
/* Execute a hook if present */
|
|
|
16457 |
_executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
|
| 1 |
efrain |
16458 |
};
|
| 1441 |
ariadna |
16459 |
/**
|
|
|
16460 |
* _sanitizeShadowDOM
|
|
|
16461 |
*
|
|
|
16462 |
* @param fragment to iterate over recursively
|
|
|
16463 |
*/
|
| 1 |
efrain |
16464 |
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
| 1441 |
ariadna |
16465 |
let shadowNode = null;
|
|
|
16466 |
const shadowIterator = _createNodeIterator(fragment);
|
|
|
16467 |
/* Execute a hook if present */
|
|
|
16468 |
_executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
|
| 1 |
efrain |
16469 |
while (shadowNode = shadowIterator.nextNode()) {
|
| 1441 |
ariadna |
16470 |
/* Execute a hook if present */
|
|
|
16471 |
_executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
|
|
|
16472 |
/* Sanitize tags and elements */
|
|
|
16473 |
_sanitizeElements(shadowNode);
|
|
|
16474 |
/* Check attributes next */
|
|
|
16475 |
_sanitizeAttributes(shadowNode);
|
|
|
16476 |
/* Deep shadow DOM detected */
|
| 1 |
efrain |
16477 |
if (shadowNode.content instanceof DocumentFragment) {
|
|
|
16478 |
_sanitizeShadowDOM(shadowNode.content);
|
|
|
16479 |
}
|
|
|
16480 |
}
|
| 1441 |
ariadna |
16481 |
/* Execute a hook if present */
|
|
|
16482 |
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
|
| 1 |
efrain |
16483 |
};
|
| 1441 |
ariadna |
16484 |
// eslint-disable-next-line complexity
|
| 1 |
efrain |
16485 |
DOMPurify.sanitize = function (dirty) {
|
|
|
16486 |
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
| 1441 |
ariadna |
16487 |
let body = null;
|
|
|
16488 |
let importedNode = null;
|
|
|
16489 |
let currentNode = null;
|
|
|
16490 |
let returnNode = null;
|
|
|
16491 |
/* Make sure we have a string to sanitize.
|
|
|
16492 |
DO NOT return early, as this will return the wrong type if
|
|
|
16493 |
the user has requested a DOM object rather than a string */
|
| 1 |
efrain |
16494 |
IS_EMPTY_INPUT = !dirty;
|
|
|
16495 |
if (IS_EMPTY_INPUT) {
|
|
|
16496 |
dirty = '<!-->';
|
|
|
16497 |
}
|
| 1441 |
ariadna |
16498 |
/* Stringify, in case dirty is an object */
|
| 1 |
efrain |
16499 |
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
|
16500 |
if (typeof dirty.toString === 'function') {
|
|
|
16501 |
dirty = dirty.toString();
|
|
|
16502 |
if (typeof dirty !== 'string') {
|
|
|
16503 |
throw typeErrorCreate('dirty is not a string, aborting');
|
|
|
16504 |
}
|
|
|
16505 |
} else {
|
|
|
16506 |
throw typeErrorCreate('toString is not a function');
|
|
|
16507 |
}
|
|
|
16508 |
}
|
| 1441 |
ariadna |
16509 |
/* Return dirty HTML if DOMPurify cannot run */
|
| 1 |
efrain |
16510 |
if (!DOMPurify.isSupported) {
|
|
|
16511 |
return dirty;
|
|
|
16512 |
}
|
| 1441 |
ariadna |
16513 |
/* Assign config vars */
|
| 1 |
efrain |
16514 |
if (!SET_CONFIG) {
|
|
|
16515 |
_parseConfig(cfg);
|
|
|
16516 |
}
|
| 1441 |
ariadna |
16517 |
/* Clean up removed elements */
|
| 1 |
efrain |
16518 |
DOMPurify.removed = [];
|
| 1441 |
ariadna |
16519 |
/* Check if dirty is correctly typed for IN_PLACE */
|
| 1 |
efrain |
16520 |
if (typeof dirty === 'string') {
|
|
|
16521 |
IN_PLACE = false;
|
|
|
16522 |
}
|
|
|
16523 |
if (IN_PLACE) {
|
| 1441 |
ariadna |
16524 |
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
| 1 |
efrain |
16525 |
if (dirty.nodeName) {
|
|
|
16526 |
const tagName = transformCaseFunc(dirty.nodeName);
|
|
|
16527 |
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
|
16528 |
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
|
16529 |
}
|
|
|
16530 |
}
|
|
|
16531 |
} else if (dirty instanceof Node) {
|
| 1441 |
ariadna |
16532 |
/* If dirty is a DOM element, append to an empty document to avoid
|
|
|
16533 |
elements being stripped by the parser */
|
| 1 |
efrain |
16534 |
body = _initDocument('<!---->');
|
|
|
16535 |
importedNode = body.ownerDocument.importNode(dirty, true);
|
| 1441 |
ariadna |
16536 |
if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
|
|
|
16537 |
/* Node is already a body, use as is */
|
| 1 |
efrain |
16538 |
body = importedNode;
|
|
|
16539 |
} else if (importedNode.nodeName === 'HTML') {
|
|
|
16540 |
body = importedNode;
|
|
|
16541 |
} else {
|
| 1441 |
ariadna |
16542 |
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
| 1 |
efrain |
16543 |
body.appendChild(importedNode);
|
|
|
16544 |
}
|
|
|
16545 |
} else {
|
| 1441 |
ariadna |
16546 |
/* Exit directly if we have nothing to do */
|
|
|
16547 |
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
|
|
|
16548 |
// eslint-disable-next-line unicorn/prefer-includes
|
|
|
16549 |
dirty.indexOf('<') === -1) {
|
| 1 |
efrain |
16550 |
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
|
16551 |
}
|
| 1441 |
ariadna |
16552 |
/* Initialize the document to work on */
|
| 1 |
efrain |
16553 |
body = _initDocument(dirty);
|
| 1441 |
ariadna |
16554 |
/* Check we have a DOM node from the data */
|
| 1 |
efrain |
16555 |
if (!body) {
|
|
|
16556 |
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
|
|
16557 |
}
|
|
|
16558 |
}
|
| 1441 |
ariadna |
16559 |
/* Remove first element node (ours) if FORCE_BODY is set */
|
| 1 |
efrain |
16560 |
if (body && FORCE_BODY) {
|
|
|
16561 |
_forceRemove(body.firstChild);
|
|
|
16562 |
}
|
| 1441 |
ariadna |
16563 |
/* Get node iterator */
|
|
|
16564 |
const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
|
|
|
16565 |
/* Now start iterating over the created document */
|
| 1 |
efrain |
16566 |
while (currentNode = nodeIterator.nextNode()) {
|
| 1441 |
ariadna |
16567 |
/* Sanitize tags and elements */
|
|
|
16568 |
_sanitizeElements(currentNode);
|
|
|
16569 |
/* Check attributes next */
|
|
|
16570 |
_sanitizeAttributes(currentNode);
|
|
|
16571 |
/* Shadow DOM detected, sanitize it */
|
| 1 |
efrain |
16572 |
if (currentNode.content instanceof DocumentFragment) {
|
|
|
16573 |
_sanitizeShadowDOM(currentNode.content);
|
|
|
16574 |
}
|
|
|
16575 |
}
|
| 1441 |
ariadna |
16576 |
/* If we sanitized `dirty` in-place, return it. */
|
| 1 |
efrain |
16577 |
if (IN_PLACE) {
|
|
|
16578 |
return dirty;
|
|
|
16579 |
}
|
| 1441 |
ariadna |
16580 |
/* Return sanitized string or DOM */
|
| 1 |
efrain |
16581 |
if (RETURN_DOM) {
|
|
|
16582 |
if (RETURN_DOM_FRAGMENT) {
|
|
|
16583 |
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
|
16584 |
while (body.firstChild) {
|
| 1441 |
ariadna |
16585 |
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
| 1 |
efrain |
16586 |
returnNode.appendChild(body.firstChild);
|
|
|
16587 |
}
|
|
|
16588 |
} else {
|
|
|
16589 |
returnNode = body;
|
|
|
16590 |
}
|
|
|
16591 |
if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
|
| 1441 |
ariadna |
16592 |
/*
|
|
|
16593 |
AdoptNode() is not used because internal state is not reset
|
|
|
16594 |
(e.g. the past names map of a HTMLFormElement), this is safe
|
|
|
16595 |
in theory but we would rather not risk another attack vector.
|
|
|
16596 |
The state that is cloned by importNode() is explicitly defined
|
|
|
16597 |
by the specs.
|
|
|
16598 |
*/
|
| 1 |
efrain |
16599 |
returnNode = importNode.call(originalDocument, returnNode, true);
|
|
|
16600 |
}
|
|
|
16601 |
return returnNode;
|
|
|
16602 |
}
|
|
|
16603 |
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
| 1441 |
ariadna |
16604 |
/* Serialize doctype if allowed */
|
| 1 |
efrain |
16605 |
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
|
16606 |
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
|
|
16607 |
}
|
| 1441 |
ariadna |
16608 |
/* Sanitize final string template-safe */
|
| 1 |
efrain |
16609 |
if (SAFE_FOR_TEMPLATES) {
|
| 1441 |
ariadna |
16610 |
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
|
16611 |
serializedHTML = stringReplace(serializedHTML, expr, ' ');
|
|
|
16612 |
});
|
| 1 |
efrain |
16613 |
}
|
|
|
16614 |
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
|
16615 |
};
|
| 1441 |
ariadna |
16616 |
DOMPurify.setConfig = function () {
|
|
|
16617 |
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
| 1 |
efrain |
16618 |
_parseConfig(cfg);
|
|
|
16619 |
SET_CONFIG = true;
|
|
|
16620 |
};
|
|
|
16621 |
DOMPurify.clearConfig = function () {
|
|
|
16622 |
CONFIG = null;
|
|
|
16623 |
SET_CONFIG = false;
|
|
|
16624 |
};
|
|
|
16625 |
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
| 1441 |
ariadna |
16626 |
/* Initialize shared config vars if necessary. */
|
| 1 |
efrain |
16627 |
if (!CONFIG) {
|
|
|
16628 |
_parseConfig({});
|
|
|
16629 |
}
|
|
|
16630 |
const lcTag = transformCaseFunc(tag);
|
|
|
16631 |
const lcName = transformCaseFunc(attr);
|
|
|
16632 |
return _isValidAttribute(lcTag, lcName, value);
|
|
|
16633 |
};
|
|
|
16634 |
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
|
|
16635 |
if (typeof hookFunction !== 'function') {
|
|
|
16636 |
return;
|
|
|
16637 |
}
|
|
|
16638 |
arrayPush(hooks[entryPoint], hookFunction);
|
|
|
16639 |
};
|
| 1441 |
ariadna |
16640 |
DOMPurify.removeHook = function (entryPoint, hookFunction) {
|
|
|
16641 |
if (hookFunction !== undefined) {
|
|
|
16642 |
const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
|
|
|
16643 |
return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
|
| 1 |
efrain |
16644 |
}
|
| 1441 |
ariadna |
16645 |
return arrayPop(hooks[entryPoint]);
|
| 1 |
efrain |
16646 |
};
|
|
|
16647 |
DOMPurify.removeHooks = function (entryPoint) {
|
| 1441 |
ariadna |
16648 |
hooks[entryPoint] = [];
|
| 1 |
efrain |
16649 |
};
|
|
|
16650 |
DOMPurify.removeAllHooks = function () {
|
| 1441 |
ariadna |
16651 |
hooks = _createHooksMap();
|
| 1 |
efrain |
16652 |
};
|
|
|
16653 |
return DOMPurify;
|
|
|
16654 |
}
|
|
|
16655 |
var purify = createDOMPurify();
|
|
|
16656 |
|
|
|
16657 |
const each$4 = Tools.each, trim = Tools.trim;
|
|
|
16658 |
const queryParts = [
|
|
|
16659 |
'source',
|
|
|
16660 |
'protocol',
|
|
|
16661 |
'authority',
|
|
|
16662 |
'userInfo',
|
|
|
16663 |
'user',
|
|
|
16664 |
'password',
|
|
|
16665 |
'host',
|
|
|
16666 |
'port',
|
|
|
16667 |
'relative',
|
|
|
16668 |
'path',
|
|
|
16669 |
'directory',
|
|
|
16670 |
'file',
|
|
|
16671 |
'query',
|
|
|
16672 |
'anchor'
|
|
|
16673 |
];
|
|
|
16674 |
const DEFAULT_PORTS = {
|
|
|
16675 |
ftp: 21,
|
|
|
16676 |
http: 80,
|
|
|
16677 |
https: 443,
|
|
|
16678 |
mailto: 25
|
|
|
16679 |
};
|
|
|
16680 |
const safeSvgDataUrlElements = [
|
|
|
16681 |
'img',
|
|
|
16682 |
'video'
|
|
|
16683 |
];
|
|
|
16684 |
const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
|
|
|
16685 |
if (isNonNullable(allowSvgDataUrls)) {
|
|
|
16686 |
return !allowSvgDataUrls;
|
|
|
16687 |
} else {
|
|
|
16688 |
return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
|
|
|
16689 |
}
|
|
|
16690 |
};
|
|
|
16691 |
const decodeUri = encodedUri => {
|
|
|
16692 |
try {
|
|
|
16693 |
return decodeURIComponent(encodedUri);
|
| 1441 |
ariadna |
16694 |
} catch (_a) {
|
| 1 |
efrain |
16695 |
return unescape(encodedUri);
|
|
|
16696 |
}
|
|
|
16697 |
};
|
|
|
16698 |
const isInvalidUri = (settings, uri, tagName) => {
|
|
|
16699 |
const decodedUri = decodeUri(uri).replace(/\s/g, '');
|
|
|
16700 |
if (settings.allow_script_urls) {
|
|
|
16701 |
return false;
|
|
|
16702 |
} else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
|
|
|
16703 |
return true;
|
|
|
16704 |
} else if (settings.allow_html_data_urls) {
|
|
|
16705 |
return false;
|
|
|
16706 |
} else if (/^data:image\//i.test(decodedUri)) {
|
|
|
16707 |
return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
|
|
|
16708 |
} else {
|
|
|
16709 |
return /^data:/i.test(decodedUri);
|
|
|
16710 |
}
|
|
|
16711 |
};
|
|
|
16712 |
class URI {
|
|
|
16713 |
static parseDataUri(uri) {
|
|
|
16714 |
let type;
|
|
|
16715 |
const uriComponents = decodeURIComponent(uri).split(',');
|
|
|
16716 |
const matches = /data:([^;]+)/.exec(uriComponents[0]);
|
|
|
16717 |
if (matches) {
|
|
|
16718 |
type = matches[1];
|
|
|
16719 |
}
|
|
|
16720 |
return {
|
|
|
16721 |
type,
|
|
|
16722 |
data: uriComponents[1]
|
|
|
16723 |
};
|
|
|
16724 |
}
|
|
|
16725 |
static isDomSafe(uri, context, options = {}) {
|
|
|
16726 |
if (options.allow_script_urls) {
|
|
|
16727 |
return true;
|
|
|
16728 |
} else {
|
|
|
16729 |
const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, '');
|
|
|
16730 |
return !isInvalidUri(options, decodedUri, context);
|
|
|
16731 |
}
|
|
|
16732 |
}
|
|
|
16733 |
static getDocumentBaseUrl(loc) {
|
|
|
16734 |
var _a;
|
|
|
16735 |
let baseUrl;
|
|
|
16736 |
if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
|
|
|
16737 |
baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : '';
|
|
|
16738 |
} else {
|
|
|
16739 |
baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
|
|
|
16740 |
}
|
|
|
16741 |
if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
|
|
|
16742 |
baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
|
|
16743 |
if (!/[\/\\]$/.test(baseUrl)) {
|
|
|
16744 |
baseUrl += '/';
|
|
|
16745 |
}
|
|
|
16746 |
}
|
|
|
16747 |
return baseUrl;
|
|
|
16748 |
}
|
|
|
16749 |
constructor(url, settings = {}) {
|
|
|
16750 |
this.path = '';
|
|
|
16751 |
this.directory = '';
|
|
|
16752 |
url = trim(url);
|
|
|
16753 |
this.settings = settings;
|
|
|
16754 |
const baseUri = settings.base_uri;
|
|
|
16755 |
const self = this;
|
|
|
16756 |
if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
|
|
|
16757 |
self.source = url;
|
|
|
16758 |
return;
|
|
|
16759 |
}
|
|
|
16760 |
const isProtocolRelative = url.indexOf('//') === 0;
|
|
|
16761 |
if (url.indexOf('/') === 0 && !isProtocolRelative) {
|
|
|
16762 |
url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
|
|
|
16763 |
}
|
|
|
16764 |
if (!/^[\w\-]*:?\/\//.test(url)) {
|
|
|
16765 |
const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory;
|
|
|
16766 |
if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') {
|
|
|
16767 |
url = '//mce_host' + self.toAbsPath(baseUrl, url);
|
|
|
16768 |
} else {
|
|
|
16769 |
const match = /([^#?]*)([#?]?.*)/.exec(url);
|
|
|
16770 |
if (match) {
|
|
|
16771 |
url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
|
|
|
16772 |
}
|
|
|
16773 |
}
|
|
|
16774 |
}
|
|
|
16775 |
url = url.replace(/@@/g, '(mce_at)');
|
|
|
16776 |
const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
|
|
|
16777 |
if (urlMatch) {
|
|
|
16778 |
each$4(queryParts, (v, i) => {
|
|
|
16779 |
let part = urlMatch[i];
|
|
|
16780 |
if (part) {
|
|
|
16781 |
part = part.replace(/\(mce_at\)/g, '@@');
|
|
|
16782 |
}
|
|
|
16783 |
self[v] = part;
|
|
|
16784 |
});
|
|
|
16785 |
}
|
|
|
16786 |
if (baseUri) {
|
|
|
16787 |
if (!self.protocol) {
|
|
|
16788 |
self.protocol = baseUri.protocol;
|
|
|
16789 |
}
|
|
|
16790 |
if (!self.userInfo) {
|
|
|
16791 |
self.userInfo = baseUri.userInfo;
|
|
|
16792 |
}
|
|
|
16793 |
if (!self.port && self.host === 'mce_host') {
|
|
|
16794 |
self.port = baseUri.port;
|
|
|
16795 |
}
|
|
|
16796 |
if (!self.host || self.host === 'mce_host') {
|
|
|
16797 |
self.host = baseUri.host;
|
|
|
16798 |
}
|
|
|
16799 |
self.source = '';
|
|
|
16800 |
}
|
|
|
16801 |
if (isProtocolRelative) {
|
|
|
16802 |
self.protocol = '';
|
|
|
16803 |
}
|
|
|
16804 |
}
|
|
|
16805 |
setPath(path) {
|
|
|
16806 |
const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
|
|
|
16807 |
if (pathMatch) {
|
|
|
16808 |
this.path = pathMatch[0];
|
|
|
16809 |
this.directory = pathMatch[1];
|
|
|
16810 |
this.file = pathMatch[2];
|
|
|
16811 |
}
|
|
|
16812 |
this.source = '';
|
|
|
16813 |
this.getURI();
|
|
|
16814 |
}
|
|
|
16815 |
toRelative(uri) {
|
|
|
16816 |
if (uri === './') {
|
|
|
16817 |
return uri;
|
|
|
16818 |
}
|
|
|
16819 |
const relativeUri = new URI(uri, { base_uri: this });
|
|
|
16820 |
if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
|
|
|
16821 |
return relativeUri.getURI();
|
|
|
16822 |
}
|
|
|
16823 |
const tu = this.getURI(), uu = relativeUri.getURI();
|
|
|
16824 |
if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
|
|
|
16825 |
return tu;
|
|
|
16826 |
}
|
|
|
16827 |
let output = this.toRelPath(this.path, relativeUri.path);
|
|
|
16828 |
if (relativeUri.query) {
|
|
|
16829 |
output += '?' + relativeUri.query;
|
|
|
16830 |
}
|
|
|
16831 |
if (relativeUri.anchor) {
|
|
|
16832 |
output += '#' + relativeUri.anchor;
|
|
|
16833 |
}
|
|
|
16834 |
return output;
|
|
|
16835 |
}
|
|
|
16836 |
toAbsolute(uri, noHost) {
|
|
|
16837 |
const absoluteUri = new URI(uri, { base_uri: this });
|
|
|
16838 |
return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
|
|
|
16839 |
}
|
|
|
16840 |
isSameOrigin(uri) {
|
|
|
16841 |
if (this.host == uri.host && this.protocol == uri.protocol) {
|
|
|
16842 |
if (this.port == uri.port) {
|
|
|
16843 |
return true;
|
|
|
16844 |
}
|
|
|
16845 |
const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null;
|
|
|
16846 |
if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
|
|
|
16847 |
return true;
|
|
|
16848 |
}
|
|
|
16849 |
}
|
|
|
16850 |
return false;
|
|
|
16851 |
}
|
|
|
16852 |
toRelPath(base, path) {
|
|
|
16853 |
let breakPoint = 0, out = '', i, l;
|
|
|
16854 |
const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
|
|
|
16855 |
const items = path.split('/');
|
|
|
16856 |
if (normalizedBase.length >= items.length) {
|
|
|
16857 |
for (i = 0, l = normalizedBase.length; i < l; i++) {
|
|
|
16858 |
if (i >= items.length || normalizedBase[i] !== items[i]) {
|
|
|
16859 |
breakPoint = i + 1;
|
|
|
16860 |
break;
|
|
|
16861 |
}
|
|
|
16862 |
}
|
|
|
16863 |
}
|
|
|
16864 |
if (normalizedBase.length < items.length) {
|
|
|
16865 |
for (i = 0, l = items.length; i < l; i++) {
|
|
|
16866 |
if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
|
|
|
16867 |
breakPoint = i + 1;
|
|
|
16868 |
break;
|
|
|
16869 |
}
|
|
|
16870 |
}
|
|
|
16871 |
}
|
|
|
16872 |
if (breakPoint === 1) {
|
|
|
16873 |
return path;
|
|
|
16874 |
}
|
|
|
16875 |
for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
|
|
|
16876 |
out += '../';
|
|
|
16877 |
}
|
|
|
16878 |
for (i = breakPoint - 1, l = items.length; i < l; i++) {
|
|
|
16879 |
if (i !== breakPoint - 1) {
|
|
|
16880 |
out += '/' + items[i];
|
|
|
16881 |
} else {
|
|
|
16882 |
out += items[i];
|
|
|
16883 |
}
|
|
|
16884 |
}
|
|
|
16885 |
return out;
|
|
|
16886 |
}
|
|
|
16887 |
toAbsPath(base, path) {
|
|
|
16888 |
let nb = 0;
|
|
|
16889 |
const tr = /\/$/.test(path) ? '/' : '';
|
|
|
16890 |
const normalizedBase = base.split('/');
|
|
|
16891 |
const normalizedPath = path.split('/');
|
|
|
16892 |
const baseParts = [];
|
|
|
16893 |
each$4(normalizedBase, k => {
|
|
|
16894 |
if (k) {
|
|
|
16895 |
baseParts.push(k);
|
|
|
16896 |
}
|
|
|
16897 |
});
|
|
|
16898 |
const pathParts = [];
|
|
|
16899 |
for (let i = normalizedPath.length - 1; i >= 0; i--) {
|
|
|
16900 |
if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
|
|
|
16901 |
continue;
|
|
|
16902 |
}
|
|
|
16903 |
if (normalizedPath[i] === '..') {
|
|
|
16904 |
nb++;
|
|
|
16905 |
continue;
|
|
|
16906 |
}
|
|
|
16907 |
if (nb > 0) {
|
|
|
16908 |
nb--;
|
|
|
16909 |
continue;
|
|
|
16910 |
}
|
|
|
16911 |
pathParts.push(normalizedPath[i]);
|
|
|
16912 |
}
|
|
|
16913 |
const i = baseParts.length - nb;
|
|
|
16914 |
let outPath;
|
|
|
16915 |
if (i <= 0) {
|
|
|
16916 |
outPath = reverse(pathParts).join('/');
|
|
|
16917 |
} else {
|
|
|
16918 |
outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/');
|
|
|
16919 |
}
|
|
|
16920 |
if (outPath.indexOf('/') !== 0) {
|
|
|
16921 |
outPath = '/' + outPath;
|
|
|
16922 |
}
|
|
|
16923 |
if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
|
|
|
16924 |
outPath += tr;
|
|
|
16925 |
}
|
|
|
16926 |
return outPath;
|
|
|
16927 |
}
|
|
|
16928 |
getURI(noProtoHost = false) {
|
|
|
16929 |
let s;
|
|
|
16930 |
if (!this.source || noProtoHost) {
|
|
|
16931 |
s = '';
|
|
|
16932 |
if (!noProtoHost) {
|
|
|
16933 |
if (this.protocol) {
|
|
|
16934 |
s += this.protocol + '://';
|
|
|
16935 |
} else {
|
|
|
16936 |
s += '//';
|
|
|
16937 |
}
|
|
|
16938 |
if (this.userInfo) {
|
|
|
16939 |
s += this.userInfo + '@';
|
|
|
16940 |
}
|
|
|
16941 |
if (this.host) {
|
|
|
16942 |
s += this.host;
|
|
|
16943 |
}
|
|
|
16944 |
if (this.port) {
|
|
|
16945 |
s += ':' + this.port;
|
|
|
16946 |
}
|
|
|
16947 |
}
|
|
|
16948 |
if (this.path) {
|
|
|
16949 |
s += this.path;
|
|
|
16950 |
}
|
|
|
16951 |
if (this.query) {
|
|
|
16952 |
s += '?' + this.query;
|
|
|
16953 |
}
|
|
|
16954 |
if (this.anchor) {
|
|
|
16955 |
s += '#' + this.anchor;
|
|
|
16956 |
}
|
|
|
16957 |
this.source = s;
|
|
|
16958 |
}
|
|
|
16959 |
return this.source;
|
|
|
16960 |
}
|
|
|
16961 |
}
|
|
|
16962 |
|
|
|
16963 |
const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href');
|
|
|
16964 |
const internalElementAttr = 'data-mce-type';
|
|
|
16965 |
let uid = 0;
|
|
|
16966 |
const processNode = (node, settings, schema, scope, evt) => {
|
|
|
16967 |
var _a, _b, _c, _d;
|
|
|
16968 |
const validate = settings.validate;
|
|
|
16969 |
const specialElements = schema.getSpecialElements();
|
|
|
16970 |
if (node.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '')) {
|
|
|
16971 |
node.nodeValue = ' ' + node.nodeValue;
|
|
|
16972 |
}
|
|
|
16973 |
const lcTagName = (_b = evt === null || evt === void 0 ? void 0 : evt.tagName) !== null && _b !== void 0 ? _b : node.nodeName.toLowerCase();
|
|
|
16974 |
if (scope !== 'html' && schema.isValid(scope)) {
|
|
|
16975 |
if (isNonNullable(evt)) {
|
|
|
16976 |
evt.allowedTags[lcTagName] = true;
|
|
|
16977 |
}
|
|
|
16978 |
return;
|
|
|
16979 |
}
|
|
|
16980 |
if (node.nodeType !== ELEMENT || lcTagName === 'body') {
|
|
|
16981 |
return;
|
|
|
16982 |
}
|
|
|
16983 |
const element = SugarElement.fromDom(node);
|
|
|
16984 |
const isInternalElement = has$1(element, internalElementAttr);
|
|
|
16985 |
const bogus = get$9(element, 'data-mce-bogus');
|
|
|
16986 |
if (!isInternalElement && isString(bogus)) {
|
|
|
16987 |
if (bogus === 'all') {
|
| 1441 |
ariadna |
16988 |
remove$4(element);
|
| 1 |
efrain |
16989 |
} else {
|
|
|
16990 |
unwrap(element);
|
|
|
16991 |
}
|
|
|
16992 |
return;
|
|
|
16993 |
}
|
|
|
16994 |
const rule = schema.getElementRule(lcTagName);
|
|
|
16995 |
if (validate && !rule) {
|
|
|
16996 |
if (has$2(specialElements, lcTagName)) {
|
| 1441 |
ariadna |
16997 |
remove$4(element);
|
| 1 |
efrain |
16998 |
} else {
|
|
|
16999 |
unwrap(element);
|
|
|
17000 |
}
|
|
|
17001 |
return;
|
|
|
17002 |
} else {
|
|
|
17003 |
if (isNonNullable(evt)) {
|
|
|
17004 |
evt.allowedTags[lcTagName] = true;
|
|
|
17005 |
}
|
|
|
17006 |
}
|
|
|
17007 |
if (validate && rule && !isInternalElement) {
|
|
|
17008 |
each$e((_c = rule.attributesForced) !== null && _c !== void 0 ? _c : [], attr => {
|
| 1441 |
ariadna |
17009 |
set$4(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
|
| 1 |
efrain |
17010 |
});
|
|
|
17011 |
each$e((_d = rule.attributesDefault) !== null && _d !== void 0 ? _d : [], attr => {
|
|
|
17012 |
if (!has$1(element, attr.name)) {
|
| 1441 |
ariadna |
17013 |
set$4(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
|
| 1 |
efrain |
17014 |
}
|
|
|
17015 |
});
|
|
|
17016 |
if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) {
|
|
|
17017 |
unwrap(element);
|
|
|
17018 |
return;
|
|
|
17019 |
}
|
|
|
17020 |
if (rule.removeEmptyAttrs && hasNone(element)) {
|
|
|
17021 |
unwrap(element);
|
|
|
17022 |
return;
|
|
|
17023 |
}
|
|
|
17024 |
if (rule.outputName && rule.outputName !== lcTagName) {
|
|
|
17025 |
mutate(element, rule.outputName);
|
|
|
17026 |
}
|
|
|
17027 |
}
|
|
|
17028 |
};
|
|
|
17029 |
const processAttr = (ele, settings, schema, scope, evt) => {
|
|
|
17030 |
const tagName = ele.tagName.toLowerCase();
|
|
|
17031 |
const {attrName, attrValue} = evt;
|
|
|
17032 |
evt.keepAttr = shouldKeepAttribute(settings, schema, scope, tagName, attrName, attrValue);
|
|
|
17033 |
if (evt.keepAttr) {
|
|
|
17034 |
evt.allowedAttributes[attrName] = true;
|
|
|
17035 |
if (isBooleanAttribute(attrName, schema)) {
|
|
|
17036 |
evt.attrValue = attrName;
|
|
|
17037 |
}
|
|
|
17038 |
if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) {
|
|
|
17039 |
evt.forceKeepAttr = true;
|
|
|
17040 |
}
|
|
|
17041 |
} else if (isRequiredAttributeOfInternalElement(ele, attrName)) {
|
|
|
17042 |
evt.forceKeepAttr = true;
|
|
|
17043 |
}
|
|
|
17044 |
};
|
|
|
17045 |
const shouldKeepAttribute = (settings, schema, scope, tagName, attrName, attrValue) => {
|
|
|
17046 |
if (scope !== 'html' && !isNonHtmlElementRootName(tagName)) {
|
|
|
17047 |
return true;
|
|
|
17048 |
}
|
|
|
17049 |
return !(attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) && (!settings.validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-'));
|
|
|
17050 |
};
|
|
|
17051 |
const isRequiredAttributeOfInternalElement = (ele, attrName) => ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style');
|
|
|
17052 |
const isBooleanAttribute = (attrName, schema) => attrName in schema.getBoolAttrs();
|
|
|
17053 |
const filterAttributes = (ele, settings, schema, scope) => {
|
|
|
17054 |
const {attributes} = ele;
|
|
|
17055 |
for (let i = attributes.length - 1; i >= 0; i--) {
|
|
|
17056 |
const attr = attributes[i];
|
|
|
17057 |
const attrName = attr.name;
|
|
|
17058 |
const attrValue = attr.value;
|
|
|
17059 |
if (!shouldKeepAttribute(settings, schema, scope, ele.tagName.toLowerCase(), attrName, attrValue) && !isRequiredAttributeOfInternalElement(ele, attrName)) {
|
|
|
17060 |
ele.removeAttribute(attrName);
|
|
|
17061 |
} else if (isBooleanAttribute(attrName, schema)) {
|
|
|
17062 |
ele.setAttribute(attrName, attrName);
|
|
|
17063 |
}
|
|
|
17064 |
}
|
|
|
17065 |
};
|
|
|
17066 |
const setupPurify = (settings, schema, namespaceTracker) => {
|
|
|
17067 |
const purify$1 = purify();
|
|
|
17068 |
purify$1.addHook('uponSanitizeElement', (ele, evt) => {
|
|
|
17069 |
processNode(ele, settings, schema, namespaceTracker.track(ele), evt);
|
|
|
17070 |
});
|
|
|
17071 |
purify$1.addHook('uponSanitizeAttribute', (ele, evt) => {
|
|
|
17072 |
processAttr(ele, settings, schema, namespaceTracker.current(), evt);
|
|
|
17073 |
});
|
|
|
17074 |
return purify$1;
|
|
|
17075 |
};
|
|
|
17076 |
const getPurifyConfig = (settings, mimeType) => {
|
|
|
17077 |
const basePurifyConfig = {
|
|
|
17078 |
IN_PLACE: true,
|
|
|
17079 |
ALLOW_UNKNOWN_PROTOCOLS: true,
|
|
|
17080 |
ALLOWED_TAGS: [
|
|
|
17081 |
'#comment',
|
|
|
17082 |
'#cdata-section',
|
|
|
17083 |
'body'
|
|
|
17084 |
],
|
| 1441 |
ariadna |
17085 |
ALLOWED_ATTR: [],
|
|
|
17086 |
SAFE_FOR_XML: false
|
| 1 |
efrain |
17087 |
};
|
|
|
17088 |
const config = { ...basePurifyConfig };
|
|
|
17089 |
config.PARSER_MEDIA_TYPE = mimeType;
|
|
|
17090 |
if (settings.allow_script_urls) {
|
|
|
17091 |
config.ALLOWED_URI_REGEXP = /.*/;
|
|
|
17092 |
} else if (settings.allow_html_data_urls) {
|
|
|
17093 |
config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
|
|
|
17094 |
}
|
|
|
17095 |
return config;
|
|
|
17096 |
};
|
| 1441 |
ariadna |
17097 |
const sanitizeSvgElement = ele => {
|
| 1 |
efrain |
17098 |
const xlinkAttrs = [
|
|
|
17099 |
'type',
|
|
|
17100 |
'href',
|
|
|
17101 |
'role',
|
|
|
17102 |
'arcrole',
|
|
|
17103 |
'title',
|
|
|
17104 |
'show',
|
|
|
17105 |
'actuate',
|
|
|
17106 |
'label',
|
|
|
17107 |
'from',
|
|
|
17108 |
'to'
|
|
|
17109 |
].map(name => `xlink:${ name }`);
|
|
|
17110 |
const config = {
|
|
|
17111 |
IN_PLACE: true,
|
|
|
17112 |
USE_PROFILES: {
|
|
|
17113 |
html: true,
|
|
|
17114 |
svg: true,
|
|
|
17115 |
svgFilters: true
|
|
|
17116 |
},
|
|
|
17117 |
ALLOWED_ATTR: xlinkAttrs
|
|
|
17118 |
};
|
|
|
17119 |
purify().sanitize(ele, config);
|
|
|
17120 |
};
|
| 1441 |
ariadna |
17121 |
const sanitizeMathmlElement = (node, settings) => {
|
|
|
17122 |
const config = {
|
|
|
17123 |
IN_PLACE: true,
|
|
|
17124 |
USE_PROFILES: { mathMl: true }
|
|
|
17125 |
};
|
|
|
17126 |
const purify$1 = purify();
|
|
|
17127 |
const allowedEncodings = settings.allow_mathml_annotation_encodings;
|
|
|
17128 |
const hasAllowedEncodings = isArray$1(allowedEncodings) && allowedEncodings.length > 0;
|
|
|
17129 |
const hasValidEncoding = el => {
|
|
|
17130 |
const encoding = el.getAttribute('encoding');
|
|
|
17131 |
return hasAllowedEncodings && isString(encoding) && contains$2(allowedEncodings, encoding);
|
|
|
17132 |
};
|
|
|
17133 |
purify$1.addHook('uponSanitizeElement', (node, evt) => {
|
|
|
17134 |
var _a;
|
|
|
17135 |
const lcTagName = (_a = evt.tagName) !== null && _a !== void 0 ? _a : node.nodeName.toLowerCase();
|
|
|
17136 |
if (hasAllowedEncodings && lcTagName === 'semantics') {
|
|
|
17137 |
evt.allowedTags[lcTagName] = true;
|
|
|
17138 |
}
|
|
|
17139 |
if (lcTagName === 'annotation') {
|
|
|
17140 |
const elm = node;
|
|
|
17141 |
const keepElement = hasValidEncoding(elm);
|
|
|
17142 |
evt.allowedTags[lcTagName] = keepElement;
|
|
|
17143 |
if (!keepElement) {
|
|
|
17144 |
elm.remove();
|
|
|
17145 |
}
|
|
|
17146 |
}
|
|
|
17147 |
});
|
|
|
17148 |
purify$1.sanitize(node, config);
|
|
|
17149 |
};
|
|
|
17150 |
const mkSanitizeNamespaceElement = settings => ele => {
|
|
|
17151 |
const namespaceType = toScopeType(ele);
|
|
|
17152 |
if (namespaceType === 'svg') {
|
|
|
17153 |
sanitizeSvgElement(ele);
|
|
|
17154 |
} else if (namespaceType === 'math') {
|
|
|
17155 |
sanitizeMathmlElement(ele, settings);
|
|
|
17156 |
} else {
|
|
|
17157 |
throw new Error('Not a namespace element');
|
|
|
17158 |
}
|
|
|
17159 |
};
|
| 1 |
efrain |
17160 |
const getSanitizer = (settings, schema) => {
|
|
|
17161 |
const namespaceTracker = createNamespaceTracker();
|
|
|
17162 |
if (settings.sanitize) {
|
|
|
17163 |
const purify = setupPurify(settings, schema, namespaceTracker);
|
|
|
17164 |
const sanitizeHtmlElement = (body, mimeType) => {
|
|
|
17165 |
purify.sanitize(body, getPurifyConfig(settings, mimeType));
|
|
|
17166 |
purify.removed = [];
|
|
|
17167 |
namespaceTracker.reset();
|
|
|
17168 |
};
|
|
|
17169 |
return {
|
|
|
17170 |
sanitizeHtmlElement,
|
| 1441 |
ariadna |
17171 |
sanitizeNamespaceElement: mkSanitizeNamespaceElement(settings)
|
| 1 |
efrain |
17172 |
};
|
|
|
17173 |
} else {
|
|
|
17174 |
const sanitizeHtmlElement = (body, _mimeType) => {
|
|
|
17175 |
const nodeIterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT);
|
|
|
17176 |
let node;
|
|
|
17177 |
while (node = nodeIterator.nextNode()) {
|
|
|
17178 |
const currentScope = namespaceTracker.track(node);
|
|
|
17179 |
processNode(node, settings, schema, currentScope);
|
|
|
17180 |
if (isElement$6(node)) {
|
|
|
17181 |
filterAttributes(node, settings, schema, currentScope);
|
|
|
17182 |
}
|
|
|
17183 |
}
|
|
|
17184 |
namespaceTracker.reset();
|
|
|
17185 |
};
|
|
|
17186 |
const sanitizeNamespaceElement = noop;
|
|
|
17187 |
return {
|
|
|
17188 |
sanitizeHtmlElement,
|
|
|
17189 |
sanitizeNamespaceElement
|
|
|
17190 |
};
|
|
|
17191 |
}
|
|
|
17192 |
};
|
|
|
17193 |
|
|
|
17194 |
const makeMap = Tools.makeMap, extend$1 = Tools.extend;
|
|
|
17195 |
const transferChildren = (parent, nativeParent, specialElements, nsSanitizer) => {
|
|
|
17196 |
const parentName = parent.name;
|
| 1441 |
ariadna |
17197 |
const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea' && parentName !== 'noscript';
|
| 1 |
efrain |
17198 |
const childNodes = nativeParent.childNodes;
|
|
|
17199 |
for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
|
|
|
17200 |
const nativeChild = childNodes[ni];
|
|
|
17201 |
const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
|
|
|
17202 |
if (isElement$6(nativeChild)) {
|
|
|
17203 |
const attributes = nativeChild.attributes;
|
|
|
17204 |
for (let ai = 0, al = attributes.length; ai < al; ai++) {
|
|
|
17205 |
const attr = attributes[ai];
|
|
|
17206 |
child.attr(attr.name, attr.value);
|
|
|
17207 |
}
|
|
|
17208 |
if (isNonHtmlElementRootName(child.name)) {
|
|
|
17209 |
nsSanitizer(nativeChild);
|
|
|
17210 |
child.value = nativeChild.innerHTML;
|
|
|
17211 |
}
|
| 1441 |
ariadna |
17212 |
} else if (isText$b(nativeChild)) {
|
| 1 |
efrain |
17213 |
child.value = nativeChild.data;
|
|
|
17214 |
if (isSpecial) {
|
|
|
17215 |
child.raw = true;
|
|
|
17216 |
}
|
|
|
17217 |
} else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
|
|
|
17218 |
child.value = nativeChild.data;
|
|
|
17219 |
}
|
|
|
17220 |
if (!isNonHtmlElementRootName(child.name)) {
|
|
|
17221 |
transferChildren(child, nativeChild, specialElements, nsSanitizer);
|
|
|
17222 |
}
|
|
|
17223 |
parent.append(child);
|
|
|
17224 |
}
|
|
|
17225 |
};
|
|
|
17226 |
const walkTree = (root, preprocessors, postprocessors) => {
|
|
|
17227 |
const traverseOrder = [];
|
|
|
17228 |
for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) {
|
|
|
17229 |
const tempNode = node;
|
|
|
17230 |
each$e(preprocessors, preprocess => preprocess(tempNode));
|
|
|
17231 |
if (isNullable(tempNode.parent) && tempNode !== root) {
|
|
|
17232 |
node = lastNode;
|
|
|
17233 |
} else {
|
|
|
17234 |
traverseOrder.push(tempNode);
|
|
|
17235 |
}
|
|
|
17236 |
}
|
|
|
17237 |
for (let i = traverseOrder.length - 1; i >= 0; i--) {
|
|
|
17238 |
const node = traverseOrder[i];
|
|
|
17239 |
each$e(postprocessors, postprocess => postprocess(node));
|
|
|
17240 |
}
|
|
|
17241 |
};
|
|
|
17242 |
const whitespaceCleaner = (root, schema, settings, args) => {
|
|
|
17243 |
const validate = settings.validate;
|
|
|
17244 |
const nonEmptyElements = schema.getNonEmptyElements();
|
|
|
17245 |
const whitespaceElements = schema.getWhitespaceElements();
|
|
|
17246 |
const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
|
|
|
17247 |
const textRootBlockElements = getTextRootBlockElements(schema);
|
|
|
17248 |
const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
|
|
|
17249 |
const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
|
|
|
17250 |
const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
|
|
|
17251 |
const hasWhitespaceParent = node => {
|
|
|
17252 |
let tempNode = node.parent;
|
|
|
17253 |
while (isNonNullable(tempNode)) {
|
|
|
17254 |
if (tempNode.name in whitespaceElements) {
|
|
|
17255 |
return true;
|
|
|
17256 |
} else {
|
|
|
17257 |
tempNode = tempNode.parent;
|
|
|
17258 |
}
|
|
|
17259 |
}
|
|
|
17260 |
return false;
|
|
|
17261 |
};
|
|
|
17262 |
const isTextRootBlockEmpty = node => {
|
|
|
17263 |
let tempNode = node;
|
|
|
17264 |
while (isNonNullable(tempNode)) {
|
|
|
17265 |
if (tempNode.name in textRootBlockElements) {
|
|
|
17266 |
return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
|
|
|
17267 |
} else {
|
|
|
17268 |
tempNode = tempNode.parent;
|
|
|
17269 |
}
|
|
|
17270 |
}
|
|
|
17271 |
return false;
|
|
|
17272 |
};
|
|
|
17273 |
const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node) || isNonHtmlElementRootName(node.name) && node.parent === root;
|
|
|
17274 |
const isAtEdgeOfBlock = (node, start) => {
|
|
|
17275 |
const neighbour = start ? node.prev : node.next;
|
|
|
17276 |
if (isNonNullable(neighbour) || isNullable(node.parent)) {
|
|
|
17277 |
return false;
|
|
|
17278 |
}
|
|
|
17279 |
return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
|
|
|
17280 |
};
|
|
|
17281 |
const preprocess = node => {
|
|
|
17282 |
var _a;
|
|
|
17283 |
if (node.type === 3) {
|
|
|
17284 |
if (!hasWhitespaceParent(node)) {
|
|
|
17285 |
let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
|
|
|
17286 |
text = text.replace(allWhiteSpaceRegExp, ' ');
|
|
|
17287 |
if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
|
|
|
17288 |
text = text.replace(startWhiteSpaceRegExp, '');
|
|
|
17289 |
}
|
|
|
17290 |
if (text.length === 0) {
|
|
|
17291 |
node.remove();
|
| 1441 |
ariadna |
17292 |
} else if (text === ' ' && node.prev && node.prev.type === COMMENT && node.next && node.next.type === COMMENT) {
|
|
|
17293 |
node.remove();
|
| 1 |
efrain |
17294 |
} else {
|
|
|
17295 |
node.value = text;
|
|
|
17296 |
}
|
|
|
17297 |
}
|
|
|
17298 |
}
|
|
|
17299 |
};
|
|
|
17300 |
const postprocess = node => {
|
|
|
17301 |
var _a;
|
|
|
17302 |
if (node.type === 1) {
|
|
|
17303 |
const elementRule = schema.getElementRule(node.name);
|
|
|
17304 |
if (validate && elementRule) {
|
|
|
17305 |
const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
|
|
|
17306 |
if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
|
|
|
17307 |
paddEmptyNode(settings, args, isBlock, node);
|
|
|
17308 |
} else if (elementRule.removeEmpty && isNodeEmpty) {
|
|
|
17309 |
if (isBlock(node)) {
|
|
|
17310 |
node.remove();
|
|
|
17311 |
} else {
|
|
|
17312 |
node.unwrap();
|
|
|
17313 |
}
|
|
|
17314 |
} else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
|
|
|
17315 |
paddEmptyNode(settings, args, isBlock, node);
|
|
|
17316 |
}
|
|
|
17317 |
}
|
|
|
17318 |
} else if (node.type === 3) {
|
|
|
17319 |
if (!hasWhitespaceParent(node)) {
|
|
|
17320 |
let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
|
|
|
17321 |
if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) {
|
|
|
17322 |
text = text.replace(endWhiteSpaceRegExp, '');
|
|
|
17323 |
}
|
|
|
17324 |
if (text.length === 0) {
|
|
|
17325 |
node.remove();
|
|
|
17326 |
} else {
|
|
|
17327 |
node.value = text;
|
|
|
17328 |
}
|
|
|
17329 |
}
|
|
|
17330 |
}
|
|
|
17331 |
};
|
|
|
17332 |
return [
|
|
|
17333 |
preprocess,
|
|
|
17334 |
postprocess
|
|
|
17335 |
];
|
|
|
17336 |
};
|
|
|
17337 |
const getRootBlockName = (settings, args) => {
|
|
|
17338 |
var _a;
|
|
|
17339 |
const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
|
|
|
17340 |
if (name === false) {
|
|
|
17341 |
return '';
|
|
|
17342 |
} else if (name === true) {
|
|
|
17343 |
return 'p';
|
|
|
17344 |
} else {
|
|
|
17345 |
return name;
|
|
|
17346 |
}
|
|
|
17347 |
};
|
|
|
17348 |
const DomParser = (settings = {}, schema = Schema()) => {
|
|
|
17349 |
const nodeFilterRegistry = create$8();
|
|
|
17350 |
const attributeFilterRegistry = create$8();
|
|
|
17351 |
const defaultedSettings = {
|
|
|
17352 |
validate: true,
|
|
|
17353 |
root_name: 'body',
|
|
|
17354 |
sanitize: true,
|
|
|
17355 |
...settings
|
|
|
17356 |
};
|
|
|
17357 |
const parser = new DOMParser();
|
|
|
17358 |
const sanitizer = getSanitizer(defaultedSettings, schema);
|
|
|
17359 |
const parseAndSanitizeWithContext = (html, rootName, format = 'html') => {
|
|
|
17360 |
const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
|
|
|
17361 |
const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
|
|
|
17362 |
const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html;
|
| 1441 |
ariadna |
17363 |
const makeWrap = () => {
|
|
|
17364 |
if (format === 'xhtml') {
|
|
|
17365 |
return `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>`;
|
|
|
17366 |
} else if (/^[\s]*<head/i.test(html) || /^[\s]*<html/i.test(html) || /^[\s]*<!DOCTYPE/i.test(html)) {
|
|
|
17367 |
return `<html>${ content }</html>`;
|
|
|
17368 |
} else {
|
|
|
17369 |
return `<body>${ content }</body>`;
|
|
|
17370 |
}
|
|
|
17371 |
};
|
|
|
17372 |
const body = parser.parseFromString(makeWrap(), mimeType).body;
|
| 1 |
efrain |
17373 |
sanitizer.sanitizeHtmlElement(body, mimeType);
|
|
|
17374 |
return isSpecialRoot ? body.firstChild : body;
|
|
|
17375 |
};
|
|
|
17376 |
const addNodeFilter = nodeFilterRegistry.addFilter;
|
|
|
17377 |
const getNodeFilters = nodeFilterRegistry.getFilters;
|
|
|
17378 |
const removeNodeFilter = nodeFilterRegistry.removeFilter;
|
|
|
17379 |
const addAttributeFilter = attributeFilterRegistry.addFilter;
|
|
|
17380 |
const getAttributeFilters = attributeFilterRegistry.getFilters;
|
|
|
17381 |
const removeAttributeFilter = attributeFilterRegistry.removeFilter;
|
|
|
17382 |
const findInvalidChildren = (node, invalidChildren) => {
|
|
|
17383 |
if (isInvalid(schema, node)) {
|
|
|
17384 |
invalidChildren.push(node);
|
|
|
17385 |
}
|
|
|
17386 |
};
|
|
|
17387 |
const isWrappableNode = (blockElements, node) => {
|
|
|
17388 |
const isInternalElement = isString(node.attr(internalElementAttr));
|
|
|
17389 |
const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node)) && !isNonHtmlElementRootName(node.name);
|
|
|
17390 |
return node.type === 3 || isInlineElement && !isInternalElement;
|
|
|
17391 |
};
|
|
|
17392 |
const addRootBlocks = (rootNode, rootBlockName) => {
|
|
|
17393 |
const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
|
|
|
17394 |
const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
|
|
|
17395 |
const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
|
|
|
17396 |
let node = rootNode.firstChild, rootBlockNode = null;
|
|
|
17397 |
const trim = rootBlock => {
|
|
|
17398 |
var _a, _b;
|
|
|
17399 |
if (rootBlock) {
|
|
|
17400 |
node = rootBlock.firstChild;
|
|
|
17401 |
if (node && node.type === 3) {
|
|
|
17402 |
node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, '');
|
|
|
17403 |
}
|
|
|
17404 |
node = rootBlock.lastChild;
|
|
|
17405 |
if (node && node.type === 3) {
|
|
|
17406 |
node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, '');
|
|
|
17407 |
}
|
|
|
17408 |
}
|
|
|
17409 |
};
|
|
|
17410 |
if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
|
|
|
17411 |
return;
|
|
|
17412 |
}
|
|
|
17413 |
while (node) {
|
|
|
17414 |
const next = node.next;
|
|
|
17415 |
if (isWrappableNode(blockElements, node)) {
|
|
|
17416 |
if (!rootBlockNode) {
|
|
|
17417 |
rootBlockNode = new AstNode(rootBlockName, 1);
|
|
|
17418 |
rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
|
|
|
17419 |
rootNode.insert(rootBlockNode, node);
|
|
|
17420 |
rootBlockNode.append(node);
|
|
|
17421 |
} else {
|
|
|
17422 |
rootBlockNode.append(node);
|
|
|
17423 |
}
|
|
|
17424 |
} else {
|
|
|
17425 |
trim(rootBlockNode);
|
|
|
17426 |
rootBlockNode = null;
|
|
|
17427 |
}
|
|
|
17428 |
node = next;
|
|
|
17429 |
}
|
|
|
17430 |
trim(rootBlockNode);
|
|
|
17431 |
};
|
|
|
17432 |
const parse = (html, args = {}) => {
|
|
|
17433 |
var _a;
|
|
|
17434 |
const validate = defaultedSettings.validate;
|
|
|
17435 |
const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
|
|
|
17436 |
const element = parseAndSanitizeWithContext(html, rootName, args.format);
|
|
|
17437 |
updateChildren(schema, element);
|
|
|
17438 |
const rootNode = new AstNode(rootName, 11);
|
|
|
17439 |
transferChildren(rootNode, element, schema.getSpecialElements(), sanitizer.sanitizeNamespaceElement);
|
|
|
17440 |
element.innerHTML = '';
|
|
|
17441 |
const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
|
|
|
17442 |
const invalidChildren = [];
|
|
|
17443 |
const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop;
|
|
|
17444 |
const matches = {
|
|
|
17445 |
nodes: {},
|
|
|
17446 |
attributes: {}
|
|
|
17447 |
};
|
|
|
17448 |
const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
|
|
|
17449 |
walkTree(rootNode, [
|
|
|
17450 |
whitespacePre,
|
|
|
17451 |
matchFinder
|
|
|
17452 |
], [
|
|
|
17453 |
whitespacePost,
|
|
|
17454 |
invalidFinder
|
|
|
17455 |
]);
|
|
|
17456 |
invalidChildren.reverse();
|
|
|
17457 |
if (validate && invalidChildren.length > 0) {
|
|
|
17458 |
if (args.context) {
|
|
|
17459 |
const {
|
|
|
17460 |
pass: topLevelChildren,
|
|
|
17461 |
fail: otherChildren
|
|
|
17462 |
} = partition$2(invalidChildren, child => child.parent === rootNode);
|
|
|
17463 |
cleanInvalidNodes(otherChildren, schema, rootNode, matchFinder);
|
|
|
17464 |
args.invalid = topLevelChildren.length > 0;
|
|
|
17465 |
} else {
|
|
|
17466 |
cleanInvalidNodes(invalidChildren, schema, rootNode, matchFinder);
|
|
|
17467 |
}
|
|
|
17468 |
}
|
|
|
17469 |
const rootBlockName = getRootBlockName(defaultedSettings, args);
|
|
|
17470 |
if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
|
|
|
17471 |
addRootBlocks(rootNode, rootBlockName);
|
|
|
17472 |
}
|
|
|
17473 |
if (!args.invalid) {
|
|
|
17474 |
runFilters(matches, args);
|
|
|
17475 |
}
|
|
|
17476 |
return rootNode;
|
|
|
17477 |
};
|
|
|
17478 |
const exports = {
|
|
|
17479 |
schema,
|
|
|
17480 |
addAttributeFilter,
|
|
|
17481 |
getAttributeFilters,
|
|
|
17482 |
removeAttributeFilter,
|
|
|
17483 |
addNodeFilter,
|
|
|
17484 |
getNodeFilters,
|
|
|
17485 |
removeNodeFilter,
|
|
|
17486 |
parse
|
|
|
17487 |
};
|
|
|
17488 |
register$4(exports, defaultedSettings);
|
|
|
17489 |
register$5(exports, defaultedSettings, schema);
|
|
|
17490 |
return exports;
|
|
|
17491 |
};
|
|
|
17492 |
|
|
|
17493 |
const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
|
|
|
17494 |
const withSerializedContent = (content, fireEvent, parserSettings) => {
|
|
|
17495 |
const serializedContent = serializeContent(content);
|
|
|
17496 |
const eventArgs = fireEvent(serializedContent);
|
|
|
17497 |
if (eventArgs.isDefaultPrevented()) {
|
|
|
17498 |
return eventArgs;
|
|
|
17499 |
} else if (isTreeNode(content)) {
|
|
|
17500 |
if (eventArgs.content !== serializedContent) {
|
|
|
17501 |
const rootNode = DomParser({
|
|
|
17502 |
validate: false,
|
|
|
17503 |
forced_root_block: false,
|
|
|
17504 |
...parserSettings
|
|
|
17505 |
}).parse(eventArgs.content, { context: content.name });
|
|
|
17506 |
return {
|
|
|
17507 |
...eventArgs,
|
|
|
17508 |
content: rootNode
|
|
|
17509 |
};
|
|
|
17510 |
} else {
|
|
|
17511 |
return {
|
|
|
17512 |
...eventArgs,
|
|
|
17513 |
content
|
|
|
17514 |
};
|
|
|
17515 |
}
|
|
|
17516 |
} else {
|
|
|
17517 |
return eventArgs;
|
|
|
17518 |
}
|
|
|
17519 |
};
|
| 1441 |
ariadna |
17520 |
const makeParserSettings = editor => ({
|
|
|
17521 |
sanitize: shouldSanitizeXss(editor),
|
|
|
17522 |
sandbox_iframes: shouldSandboxIframes(editor),
|
|
|
17523 |
sandbox_iframes_exclusions: getSandboxIframesExclusions(editor)
|
|
|
17524 |
});
|
| 1 |
efrain |
17525 |
const preProcessGetContent = (editor, args) => {
|
|
|
17526 |
if (args.no_events) {
|
|
|
17527 |
return Result.value(args);
|
|
|
17528 |
} else {
|
|
|
17529 |
const eventArgs = fireBeforeGetContent(editor, args);
|
|
|
17530 |
if (eventArgs.isDefaultPrevented()) {
|
|
|
17531 |
return Result.error(fireGetContent(editor, {
|
|
|
17532 |
content: '',
|
|
|
17533 |
...eventArgs
|
|
|
17534 |
}).content);
|
|
|
17535 |
} else {
|
|
|
17536 |
return Result.value(eventArgs);
|
|
|
17537 |
}
|
|
|
17538 |
}
|
|
|
17539 |
};
|
|
|
17540 |
const postProcessGetContent = (editor, content, args) => {
|
|
|
17541 |
if (args.no_events) {
|
|
|
17542 |
return content;
|
|
|
17543 |
} else {
|
|
|
17544 |
const processedEventArgs = withSerializedContent(content, content => fireGetContent(editor, {
|
|
|
17545 |
...args,
|
|
|
17546 |
content
|
| 1441 |
ariadna |
17547 |
}), makeParserSettings(editor));
|
| 1 |
efrain |
17548 |
return processedEventArgs.content;
|
|
|
17549 |
}
|
|
|
17550 |
};
|
|
|
17551 |
const preProcessSetContent = (editor, args) => {
|
|
|
17552 |
if (args.no_events) {
|
|
|
17553 |
return Result.value(args);
|
|
|
17554 |
} else {
|
|
|
17555 |
const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, {
|
|
|
17556 |
...args,
|
|
|
17557 |
content
|
| 1441 |
ariadna |
17558 |
}), makeParserSettings(editor));
|
| 1 |
efrain |
17559 |
if (processedEventArgs.isDefaultPrevented()) {
|
|
|
17560 |
fireSetContent(editor, processedEventArgs);
|
|
|
17561 |
return Result.error(undefined);
|
|
|
17562 |
} else {
|
|
|
17563 |
return Result.value(processedEventArgs);
|
|
|
17564 |
}
|
|
|
17565 |
}
|
|
|
17566 |
};
|
|
|
17567 |
const postProcessSetContent = (editor, content, args) => {
|
|
|
17568 |
if (!args.no_events) {
|
|
|
17569 |
fireSetContent(editor, {
|
|
|
17570 |
...args,
|
|
|
17571 |
content
|
|
|
17572 |
});
|
|
|
17573 |
}
|
|
|
17574 |
};
|
|
|
17575 |
|
|
|
17576 |
const tableModel = (element, width, rows) => ({
|
|
|
17577 |
element,
|
|
|
17578 |
width,
|
|
|
17579 |
rows
|
|
|
17580 |
});
|
|
|
17581 |
const tableRow = (element, cells) => ({
|
|
|
17582 |
element,
|
|
|
17583 |
cells
|
|
|
17584 |
});
|
|
|
17585 |
const cellPosition = (x, y) => ({
|
|
|
17586 |
x,
|
|
|
17587 |
y
|
|
|
17588 |
});
|
|
|
17589 |
const getSpan = (td, key) => {
|
|
|
17590 |
return getOpt(td, key).bind(toInt).getOr(1);
|
|
|
17591 |
};
|
|
|
17592 |
const fillout = (table, x, y, tr, td) => {
|
|
|
17593 |
const rowspan = getSpan(td, 'rowspan');
|
|
|
17594 |
const colspan = getSpan(td, 'colspan');
|
|
|
17595 |
const rows = table.rows;
|
|
|
17596 |
for (let y2 = y; y2 < y + rowspan; y2++) {
|
|
|
17597 |
if (!rows[y2]) {
|
|
|
17598 |
rows[y2] = tableRow(deep$1(tr), []);
|
|
|
17599 |
}
|
|
|
17600 |
for (let x2 = x; x2 < x + colspan; x2++) {
|
|
|
17601 |
const cells = rows[y2].cells;
|
|
|
17602 |
cells[x2] = y2 === y && x2 === x ? td : shallow$1(td);
|
|
|
17603 |
}
|
|
|
17604 |
}
|
|
|
17605 |
};
|
|
|
17606 |
const cellExists = (table, x, y) => {
|
|
|
17607 |
const rows = table.rows;
|
|
|
17608 |
const cells = rows[y] ? rows[y].cells : [];
|
|
|
17609 |
return !!cells[x];
|
|
|
17610 |
};
|
|
|
17611 |
const skipCellsX = (table, x, y) => {
|
|
|
17612 |
while (cellExists(table, x, y)) {
|
|
|
17613 |
x++;
|
|
|
17614 |
}
|
|
|
17615 |
return x;
|
|
|
17616 |
};
|
|
|
17617 |
const getWidth = rows => {
|
|
|
17618 |
return foldl(rows, (acc, row) => {
|
|
|
17619 |
return row.cells.length > acc ? row.cells.length : acc;
|
|
|
17620 |
}, 0);
|
|
|
17621 |
};
|
|
|
17622 |
const findElementPos = (table, element) => {
|
|
|
17623 |
const rows = table.rows;
|
|
|
17624 |
for (let y = 0; y < rows.length; y++) {
|
|
|
17625 |
const cells = rows[y].cells;
|
|
|
17626 |
for (let x = 0; x < cells.length; x++) {
|
|
|
17627 |
if (eq(cells[x], element)) {
|
|
|
17628 |
return Optional.some(cellPosition(x, y));
|
|
|
17629 |
}
|
|
|
17630 |
}
|
|
|
17631 |
}
|
|
|
17632 |
return Optional.none();
|
|
|
17633 |
};
|
|
|
17634 |
const extractRows = (table, sx, sy, ex, ey) => {
|
|
|
17635 |
const newRows = [];
|
|
|
17636 |
const rows = table.rows;
|
|
|
17637 |
for (let y = sy; y <= ey; y++) {
|
|
|
17638 |
const cells = rows[y].cells;
|
|
|
17639 |
const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
|
|
|
17640 |
newRows.push(tableRow(rows[y].element, slice));
|
|
|
17641 |
}
|
|
|
17642 |
return newRows;
|
|
|
17643 |
};
|
|
|
17644 |
const subTable = (table, startPos, endPos) => {
|
|
|
17645 |
const sx = startPos.x, sy = startPos.y;
|
|
|
17646 |
const ex = endPos.x, ey = endPos.y;
|
|
|
17647 |
const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
|
|
|
17648 |
return tableModel(table.element, getWidth(newRows), newRows);
|
|
|
17649 |
};
|
|
|
17650 |
const createDomTable = (table, rows) => {
|
|
|
17651 |
const tableElement = shallow$1(table.element);
|
|
|
17652 |
const tableBody = SugarElement.fromTag('tbody');
|
|
|
17653 |
append(tableBody, rows);
|
|
|
17654 |
append$1(tableElement, tableBody);
|
|
|
17655 |
return tableElement;
|
|
|
17656 |
};
|
|
|
17657 |
const modelRowsToDomRows = table => {
|
|
|
17658 |
return map$3(table.rows, row => {
|
|
|
17659 |
const cells = map$3(row.cells, cell => {
|
|
|
17660 |
const td = deep$1(cell);
|
| 1441 |
ariadna |
17661 |
remove$9(td, 'colspan');
|
|
|
17662 |
remove$9(td, 'rowspan');
|
| 1 |
efrain |
17663 |
return td;
|
|
|
17664 |
});
|
|
|
17665 |
const tr = shallow$1(row.element);
|
|
|
17666 |
append(tr, cells);
|
|
|
17667 |
return tr;
|
|
|
17668 |
});
|
|
|
17669 |
};
|
|
|
17670 |
const fromDom = tableElm => {
|
|
|
17671 |
const table = tableModel(shallow$1(tableElm), 0, []);
|
|
|
17672 |
each$e(descendants(tableElm, 'tr'), (tr, y) => {
|
|
|
17673 |
each$e(descendants(tr, 'td,th'), (td, x) => {
|
|
|
17674 |
fillout(table, skipCellsX(table, x, y), y, tr, td);
|
|
|
17675 |
});
|
|
|
17676 |
});
|
|
|
17677 |
return tableModel(table.element, getWidth(table.rows), table.rows);
|
|
|
17678 |
};
|
|
|
17679 |
const toDom = table => {
|
|
|
17680 |
return createDomTable(table, modelRowsToDomRows(table));
|
|
|
17681 |
};
|
|
|
17682 |
const subsection = (table, startElement, endElement) => {
|
|
|
17683 |
return findElementPos(table, startElement).bind(startPos => {
|
|
|
17684 |
return findElementPos(table, endElement).map(endPos => {
|
|
|
17685 |
return subTable(table, startPos, endPos);
|
|
|
17686 |
});
|
|
|
17687 |
});
|
|
|
17688 |
};
|
|
|
17689 |
|
|
|
17690 |
const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol');
|
|
|
17691 |
const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => {
|
|
|
17692 |
const listElm = SugarElement.fromTag(name(listCont));
|
|
|
17693 |
const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style'));
|
|
|
17694 |
setAll(listElm, listStyles);
|
|
|
17695 |
return [
|
|
|
17696 |
SugarElement.fromTag('li'),
|
|
|
17697 |
listElm
|
|
|
17698 |
];
|
|
|
17699 |
}).getOr([]));
|
|
|
17700 |
const wrap = (innerElm, elms) => {
|
|
|
17701 |
const wrapped = foldl(elms, (acc, elm) => {
|
|
|
17702 |
append$1(elm, acc);
|
|
|
17703 |
return elm;
|
|
|
17704 |
}, innerElm);
|
|
|
17705 |
return elms.length > 0 ? fromElements([wrapped]) : wrapped;
|
|
|
17706 |
};
|
|
|
17707 |
const directListWrappers = commonAnchorContainer => {
|
|
|
17708 |
if (isListItem$1(commonAnchorContainer)) {
|
|
|
17709 |
return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [
|
|
|
17710 |
commonAnchorContainer,
|
|
|
17711 |
listElm
|
|
|
17712 |
]);
|
|
|
17713 |
} else {
|
|
|
17714 |
return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
|
|
|
17715 |
}
|
|
|
17716 |
};
|
|
|
17717 |
const getWrapElements = (rootNode, rng, schema) => {
|
|
|
17718 |
const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
|
|
|
17719 |
const parents = parentsAndSelf(commonAnchorContainer, rootNode);
|
|
|
17720 |
const wrapElements = filter$5(parents, el => schema.isWrapper(name(el)));
|
|
|
17721 |
const listWrappers = getFullySelectedListWrappers(parents, rng);
|
|
|
17722 |
const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
|
|
|
17723 |
return map$3(allWrappers, shallow$1);
|
|
|
17724 |
};
|
|
|
17725 |
const emptyFragment = () => fromElements([]);
|
|
|
17726 |
const getFragmentFromRange = (rootNode, rng, schema) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng, schema));
|
|
|
17727 |
const getParentTable = (rootElm, cell) => ancestor$3(cell, 'table', curry(eq, rootElm));
|
|
|
17728 |
const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => {
|
|
|
17729 |
const firstCell = selectedTableCells[0];
|
|
|
17730 |
const lastCell = selectedTableCells[selectedTableCells.length - 1];
|
|
|
17731 |
const fullTableModel = fromDom(tableElm);
|
|
|
17732 |
return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)]));
|
|
|
17733 |
}).getOrThunk(emptyFragment);
|
|
|
17734 |
const getSelectionFragment = (rootNode, ranges, schema) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0], schema);
|
|
|
17735 |
const read$3 = (rootNode, ranges, schema) => {
|
|
|
17736 |
const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
|
|
|
17737 |
return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges, schema);
|
|
|
17738 |
};
|
|
|
17739 |
|
|
|
17740 |
const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index));
|
|
|
17741 |
const getInnerText = bin => {
|
|
|
17742 |
return trim$2(bin.innerText);
|
|
|
17743 |
};
|
|
|
17744 |
const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase();
|
|
|
17745 |
const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => {
|
|
|
17746 |
var _a;
|
|
|
17747 |
const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
|
|
|
17748 |
const body = editor.getBody();
|
|
|
17749 |
const contextNodeName = getContextNodeName(parentBlockOpt);
|
|
|
17750 |
const rangeContentClone = SugarElement.fromDom(rng.cloneContents());
|
|
|
17751 |
cleanupBogusElements(rangeContentClone);
|
|
|
17752 |
cleanupInputNames(rangeContentClone);
|
|
|
17753 |
const bin = editor.dom.add(body, contextNodeName, {
|
|
|
17754 |
'data-mce-bogus': 'all',
|
|
|
17755 |
'style': 'overflow: hidden; opacity: 0;'
|
|
|
17756 |
}, rangeContentClone.dom);
|
|
|
17757 |
const text = getInnerText(bin);
|
|
|
17758 |
const nonRenderedText = trim$2((_a = bin.textContent) !== null && _a !== void 0 ? _a : '');
|
|
|
17759 |
editor.dom.remove(bin);
|
|
|
17760 |
if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
|
|
|
17761 |
const parentBlock = parentBlockOpt.getOr(body);
|
|
|
17762 |
const parentBlockText = getInnerText(parentBlock);
|
|
|
17763 |
const textIndex = parentBlockText.indexOf(text);
|
|
|
17764 |
if (textIndex === -1) {
|
|
|
17765 |
return text;
|
|
|
17766 |
} else {
|
|
|
17767 |
const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
|
|
|
17768 |
const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length);
|
|
|
17769 |
return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : '');
|
|
|
17770 |
}
|
|
|
17771 |
} else {
|
|
|
17772 |
return text;
|
|
|
17773 |
}
|
|
|
17774 |
}).getOr('');
|
|
|
17775 |
const getSerializedContent = (editor, args) => {
|
|
|
17776 |
const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
|
|
|
17777 |
const sel = editor.selection.getSel();
|
|
|
17778 |
const ranges = processRanges(editor, getRanges$1(sel));
|
|
|
17779 |
const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges, editor.schema).dom : rng.cloneContents();
|
|
|
17780 |
if (fragment) {
|
|
|
17781 |
tmpElm.appendChild(fragment);
|
|
|
17782 |
}
|
|
|
17783 |
return editor.selection.serializer.serialize(tmpElm, args);
|
|
|
17784 |
};
|
|
|
17785 |
const extractSelectedContent = (editor, args) => {
|
|
|
17786 |
if (args.format === 'text') {
|
|
|
17787 |
return getTextContent(editor);
|
|
|
17788 |
} else {
|
|
|
17789 |
const content = getSerializedContent(editor, args);
|
|
|
17790 |
if (args.format === 'tree') {
|
|
|
17791 |
return content;
|
|
|
17792 |
} else {
|
|
|
17793 |
return editor.selection.isCollapsed() ? '' : content;
|
|
|
17794 |
}
|
|
|
17795 |
}
|
|
|
17796 |
};
|
|
|
17797 |
const setupArgs$3 = (args, format) => ({
|
|
|
17798 |
...args,
|
|
|
17799 |
format,
|
|
|
17800 |
get: true,
|
|
|
17801 |
selection: true,
|
|
|
17802 |
getInner: true
|
|
|
17803 |
});
|
|
|
17804 |
const getSelectedContentInternal = (editor, format, args = {}) => {
|
|
|
17805 |
const defaultedArgs = setupArgs$3(args, format);
|
|
|
17806 |
return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
|
|
|
17807 |
const content = extractSelectedContent(editor, updatedArgs);
|
|
|
17808 |
return postProcessGetContent(editor, content, updatedArgs);
|
|
|
17809 |
});
|
|
|
17810 |
};
|
|
|
17811 |
|
|
|
17812 |
const KEEP = 0, INSERT = 1, DELETE = 2;
|
|
|
17813 |
const diff = (left, right) => {
|
|
|
17814 |
const size = left.length + right.length + 2;
|
|
|
17815 |
const vDown = new Array(size);
|
|
|
17816 |
const vUp = new Array(size);
|
|
|
17817 |
const snake = (start, end, diag) => {
|
|
|
17818 |
return {
|
|
|
17819 |
start,
|
|
|
17820 |
end,
|
|
|
17821 |
diag
|
|
|
17822 |
};
|
|
|
17823 |
};
|
|
|
17824 |
const buildScript = (start1, end1, start2, end2, script) => {
|
|
|
17825 |
const middle = getMiddleSnake(start1, end1, start2, end2);
|
|
|
17826 |
if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
|
|
|
17827 |
let i = start1;
|
|
|
17828 |
let j = start2;
|
|
|
17829 |
while (i < end1 || j < end2) {
|
|
|
17830 |
if (i < end1 && j < end2 && left[i] === right[j]) {
|
|
|
17831 |
script.push([
|
|
|
17832 |
KEEP,
|
|
|
17833 |
left[i]
|
|
|
17834 |
]);
|
|
|
17835 |
++i;
|
|
|
17836 |
++j;
|
|
|
17837 |
} else {
|
|
|
17838 |
if (end1 - start1 > end2 - start2) {
|
|
|
17839 |
script.push([
|
|
|
17840 |
DELETE,
|
|
|
17841 |
left[i]
|
|
|
17842 |
]);
|
|
|
17843 |
++i;
|
|
|
17844 |
} else {
|
|
|
17845 |
script.push([
|
|
|
17846 |
INSERT,
|
|
|
17847 |
right[j]
|
|
|
17848 |
]);
|
|
|
17849 |
++j;
|
|
|
17850 |
}
|
|
|
17851 |
}
|
|
|
17852 |
}
|
|
|
17853 |
} else {
|
|
|
17854 |
buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
|
|
|
17855 |
for (let i2 = middle.start; i2 < middle.end; ++i2) {
|
|
|
17856 |
script.push([
|
|
|
17857 |
KEEP,
|
|
|
17858 |
left[i2]
|
|
|
17859 |
]);
|
|
|
17860 |
}
|
|
|
17861 |
buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
|
|
|
17862 |
}
|
|
|
17863 |
};
|
|
|
17864 |
const buildSnake = (start, diag, end1, end2) => {
|
|
|
17865 |
let end = start;
|
|
|
17866 |
while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
|
|
|
17867 |
++end;
|
|
|
17868 |
}
|
|
|
17869 |
return snake(start, end, diag);
|
|
|
17870 |
};
|
|
|
17871 |
const getMiddleSnake = (start1, end1, start2, end2) => {
|
|
|
17872 |
const m = end1 - start1;
|
|
|
17873 |
const n = end2 - start2;
|
|
|
17874 |
if (m === 0 || n === 0) {
|
|
|
17875 |
return null;
|
|
|
17876 |
}
|
|
|
17877 |
const delta = m - n;
|
|
|
17878 |
const sum = n + m;
|
|
|
17879 |
const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
|
|
|
17880 |
vDown[1 + offset] = start1;
|
|
|
17881 |
vUp[1 + offset] = end1 + 1;
|
|
|
17882 |
let d, k, i, x, y;
|
|
|
17883 |
for (d = 0; d <= offset; ++d) {
|
|
|
17884 |
for (k = -d; k <= d; k += 2) {
|
|
|
17885 |
i = k + offset;
|
|
|
17886 |
if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
|
|
|
17887 |
vDown[i] = vDown[i + 1];
|
|
|
17888 |
} else {
|
|
|
17889 |
vDown[i] = vDown[i - 1] + 1;
|
|
|
17890 |
}
|
|
|
17891 |
x = vDown[i];
|
|
|
17892 |
y = x - start1 + start2 - k;
|
|
|
17893 |
while (x < end1 && y < end2 && left[x] === right[y]) {
|
|
|
17894 |
vDown[i] = ++x;
|
|
|
17895 |
++y;
|
|
|
17896 |
}
|
|
|
17897 |
if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
|
|
|
17898 |
if (vUp[i - delta] <= vDown[i]) {
|
|
|
17899 |
return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
|
|
|
17900 |
}
|
|
|
17901 |
}
|
|
|
17902 |
}
|
|
|
17903 |
for (k = delta - d; k <= delta + d; k += 2) {
|
|
|
17904 |
i = k + offset - delta;
|
|
|
17905 |
if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
|
|
|
17906 |
vUp[i] = vUp[i + 1] - 1;
|
|
|
17907 |
} else {
|
|
|
17908 |
vUp[i] = vUp[i - 1];
|
|
|
17909 |
}
|
|
|
17910 |
x = vUp[i] - 1;
|
|
|
17911 |
y = x - start1 + start2 - k;
|
|
|
17912 |
while (x >= start1 && y >= start2 && left[x] === right[y]) {
|
|
|
17913 |
vUp[i] = x--;
|
|
|
17914 |
y--;
|
|
|
17915 |
}
|
|
|
17916 |
if (delta % 2 === 0 && -d <= k && k <= d) {
|
|
|
17917 |
if (vUp[i] <= vDown[i + delta]) {
|
|
|
17918 |
return buildSnake(vUp[i], k + start1 - start2, end1, end2);
|
|
|
17919 |
}
|
|
|
17920 |
}
|
|
|
17921 |
}
|
|
|
17922 |
}
|
|
|
17923 |
return null;
|
|
|
17924 |
};
|
|
|
17925 |
const script = [];
|
|
|
17926 |
buildScript(0, left.length, 0, right.length, script);
|
|
|
17927 |
return script;
|
|
|
17928 |
};
|
|
|
17929 |
|
|
|
17930 |
const getOuterHtml = elm => {
|
|
|
17931 |
if (isElement$6(elm)) {
|
|
|
17932 |
return elm.outerHTML;
|
| 1441 |
ariadna |
17933 |
} else if (isText$b(elm)) {
|
| 1 |
efrain |
17934 |
return Entities.encodeRaw(elm.data, false);
|
|
|
17935 |
} else if (isComment(elm)) {
|
|
|
17936 |
return '<!--' + elm.data + '-->';
|
|
|
17937 |
}
|
|
|
17938 |
return '';
|
|
|
17939 |
};
|
|
|
17940 |
const createFragment = html => {
|
|
|
17941 |
let node;
|
|
|
17942 |
const container = document.createElement('div');
|
|
|
17943 |
const frag = document.createDocumentFragment();
|
|
|
17944 |
if (html) {
|
|
|
17945 |
container.innerHTML = html;
|
|
|
17946 |
}
|
|
|
17947 |
while (node = container.firstChild) {
|
|
|
17948 |
frag.appendChild(node);
|
|
|
17949 |
}
|
|
|
17950 |
return frag;
|
|
|
17951 |
};
|
|
|
17952 |
const insertAt = (elm, html, index) => {
|
|
|
17953 |
const fragment = createFragment(html);
|
|
|
17954 |
if (elm.hasChildNodes() && index < elm.childNodes.length) {
|
|
|
17955 |
const target = elm.childNodes[index];
|
|
|
17956 |
elm.insertBefore(fragment, target);
|
|
|
17957 |
} else {
|
|
|
17958 |
elm.appendChild(fragment);
|
|
|
17959 |
}
|
|
|
17960 |
};
|
|
|
17961 |
const removeAt = (elm, index) => {
|
|
|
17962 |
if (elm.hasChildNodes() && index < elm.childNodes.length) {
|
|
|
17963 |
const target = elm.childNodes[index];
|
|
|
17964 |
elm.removeChild(target);
|
|
|
17965 |
}
|
|
|
17966 |
};
|
|
|
17967 |
const applyDiff = (diff, elm) => {
|
|
|
17968 |
let index = 0;
|
|
|
17969 |
each$e(diff, action => {
|
|
|
17970 |
if (action[0] === KEEP) {
|
|
|
17971 |
index++;
|
|
|
17972 |
} else if (action[0] === INSERT) {
|
|
|
17973 |
insertAt(elm, action[1], index);
|
|
|
17974 |
index++;
|
|
|
17975 |
} else if (action[0] === DELETE) {
|
|
|
17976 |
removeAt(elm, index);
|
|
|
17977 |
}
|
|
|
17978 |
});
|
|
|
17979 |
};
|
|
|
17980 |
const read$2 = (elm, trimZwsp) => filter$5(map$3(from(elm.childNodes), trimZwsp ? compose(trim$2, getOuterHtml) : getOuterHtml), item => {
|
|
|
17981 |
return item.length > 0;
|
|
|
17982 |
});
|
|
|
17983 |
const write = (fragments, elm) => {
|
|
|
17984 |
const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
|
|
|
17985 |
applyDiff(diff(currentFragments, fragments), elm);
|
|
|
17986 |
return elm;
|
|
|
17987 |
};
|
|
|
17988 |
|
|
|
17989 |
const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo'));
|
|
|
17990 |
const hasIframes = body => body.querySelector('iframe') !== null;
|
|
|
17991 |
const createFragmentedLevel = fragments => {
|
|
|
17992 |
return {
|
|
|
17993 |
type: 'fragmented',
|
|
|
17994 |
fragments,
|
|
|
17995 |
content: '',
|
|
|
17996 |
bookmark: null,
|
|
|
17997 |
beforeBookmark: null
|
|
|
17998 |
};
|
|
|
17999 |
};
|
|
|
18000 |
const createCompleteLevel = content => {
|
|
|
18001 |
return {
|
|
|
18002 |
type: 'complete',
|
|
|
18003 |
fragments: null,
|
|
|
18004 |
content,
|
|
|
18005 |
bookmark: null,
|
|
|
18006 |
beforeBookmark: null
|
|
|
18007 |
};
|
|
|
18008 |
};
|
|
|
18009 |
const createFromEditor = editor => {
|
|
|
18010 |
const tempAttrs = editor.serializer.getTempAttrs();
|
|
|
18011 |
const body = trim$1(editor.getBody(), tempAttrs);
|
|
|
18012 |
return hasIframes(body) ? createFragmentedLevel(read$2(body, true)) : createCompleteLevel(trim$2(body.innerHTML));
|
|
|
18013 |
};
|
|
|
18014 |
const applyToEditor = (editor, level, before) => {
|
|
|
18015 |
const bookmark = before ? level.beforeBookmark : level.bookmark;
|
|
|
18016 |
if (level.type === 'fragmented') {
|
|
|
18017 |
write(level.fragments, editor.getBody());
|
|
|
18018 |
} else {
|
|
|
18019 |
editor.setContent(level.content, {
|
|
|
18020 |
format: 'raw',
|
|
|
18021 |
no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
|
|
|
18022 |
});
|
|
|
18023 |
}
|
|
|
18024 |
if (bookmark) {
|
|
|
18025 |
editor.selection.moveToBookmark(bookmark);
|
|
|
18026 |
editor.selection.scrollIntoView();
|
|
|
18027 |
}
|
|
|
18028 |
};
|
|
|
18029 |
const getLevelContent = level => {
|
|
|
18030 |
return level.type === 'fragmented' ? level.fragments.join('') : level.content;
|
|
|
18031 |
};
|
|
|
18032 |
const getCleanLevelContent = level => {
|
|
|
18033 |
const elm = SugarElement.fromTag('body', lazyTempDocument());
|
|
|
18034 |
set$1(elm, getLevelContent(level));
|
|
|
18035 |
each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
|
|
|
18036 |
return get$6(elm);
|
|
|
18037 |
};
|
|
|
18038 |
const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
|
|
|
18039 |
const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
|
|
|
18040 |
const isEq$1 = (level1, level2) => {
|
|
|
18041 |
if (!level1 || !level2) {
|
|
|
18042 |
return false;
|
|
|
18043 |
} else if (hasEqualContent(level1, level2)) {
|
|
|
18044 |
return true;
|
|
|
18045 |
} else {
|
|
|
18046 |
return hasEqualCleanedContent(level1, level2);
|
|
|
18047 |
}
|
|
|
18048 |
};
|
|
|
18049 |
|
|
|
18050 |
const isUnlocked = locks => locks.get() === 0;
|
|
|
18051 |
|
|
|
18052 |
const setTyping = (undoManager, typing, locks) => {
|
|
|
18053 |
if (isUnlocked(locks)) {
|
|
|
18054 |
undoManager.typing = typing;
|
|
|
18055 |
}
|
|
|
18056 |
};
|
|
|
18057 |
const endTyping = (undoManager, locks) => {
|
|
|
18058 |
if (undoManager.typing) {
|
|
|
18059 |
setTyping(undoManager, false, locks);
|
|
|
18060 |
undoManager.add();
|
|
|
18061 |
}
|
|
|
18062 |
};
|
|
|
18063 |
const endTypingLevelIgnoreLocks = undoManager => {
|
|
|
18064 |
if (undoManager.typing) {
|
|
|
18065 |
undoManager.typing = false;
|
|
|
18066 |
undoManager.add();
|
|
|
18067 |
}
|
|
|
18068 |
};
|
|
|
18069 |
|
|
|
18070 |
const beforeChange$1 = (editor, locks, beforeBookmark) => {
|
|
|
18071 |
if (isUnlocked(locks)) {
|
|
|
18072 |
beforeBookmark.set(getUndoBookmark(editor.selection));
|
|
|
18073 |
}
|
|
|
18074 |
};
|
|
|
18075 |
const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => {
|
|
|
18076 |
const currentLevel = createFromEditor(editor);
|
|
|
18077 |
const newLevel = Tools.extend(level || {}, currentLevel);
|
|
|
18078 |
if (!isUnlocked(locks) || editor.removed) {
|
|
|
18079 |
return null;
|
|
|
18080 |
}
|
|
|
18081 |
const lastLevel = undoManager.data[index.get()];
|
|
|
18082 |
if (editor.dispatch('BeforeAddUndo', {
|
|
|
18083 |
level: newLevel,
|
|
|
18084 |
lastLevel,
|
|
|
18085 |
originalEvent: event
|
|
|
18086 |
}).isDefaultPrevented()) {
|
|
|
18087 |
return null;
|
|
|
18088 |
}
|
|
|
18089 |
if (lastLevel && isEq$1(lastLevel, newLevel)) {
|
|
|
18090 |
return null;
|
|
|
18091 |
}
|
|
|
18092 |
if (undoManager.data[index.get()]) {
|
|
|
18093 |
beforeBookmark.get().each(bm => {
|
|
|
18094 |
undoManager.data[index.get()].beforeBookmark = bm;
|
|
|
18095 |
});
|
|
|
18096 |
}
|
|
|
18097 |
const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
|
|
|
18098 |
if (customUndoRedoLevels) {
|
|
|
18099 |
if (undoManager.data.length > customUndoRedoLevels) {
|
|
|
18100 |
for (let i = 0; i < undoManager.data.length - 1; i++) {
|
|
|
18101 |
undoManager.data[i] = undoManager.data[i + 1];
|
|
|
18102 |
}
|
|
|
18103 |
undoManager.data.length--;
|
|
|
18104 |
index.set(undoManager.data.length);
|
|
|
18105 |
}
|
|
|
18106 |
}
|
|
|
18107 |
newLevel.bookmark = getUndoBookmark(editor.selection);
|
|
|
18108 |
if (index.get() < undoManager.data.length - 1) {
|
|
|
18109 |
undoManager.data.length = index.get() + 1;
|
|
|
18110 |
}
|
|
|
18111 |
undoManager.data.push(newLevel);
|
|
|
18112 |
index.set(undoManager.data.length - 1);
|
|
|
18113 |
const args = {
|
|
|
18114 |
level: newLevel,
|
|
|
18115 |
lastLevel,
|
|
|
18116 |
originalEvent: event
|
|
|
18117 |
};
|
|
|
18118 |
if (index.get() > 0) {
|
|
|
18119 |
editor.setDirty(true);
|
|
|
18120 |
editor.dispatch('AddUndo', args);
|
|
|
18121 |
editor.dispatch('change', args);
|
|
|
18122 |
} else {
|
|
|
18123 |
editor.dispatch('AddUndo', args);
|
|
|
18124 |
}
|
|
|
18125 |
return newLevel;
|
|
|
18126 |
};
|
|
|
18127 |
const clear$1 = (editor, undoManager, index) => {
|
|
|
18128 |
undoManager.data = [];
|
|
|
18129 |
index.set(0);
|
|
|
18130 |
undoManager.typing = false;
|
|
|
18131 |
editor.dispatch('ClearUndos');
|
|
|
18132 |
};
|
|
|
18133 |
const extra$1 = (editor, undoManager, index, callback1, callback2) => {
|
|
|
18134 |
if (undoManager.transact(callback1)) {
|
|
|
18135 |
const bookmark = undoManager.data[index.get()].bookmark;
|
|
|
18136 |
const lastLevel = undoManager.data[index.get() - 1];
|
|
|
18137 |
applyToEditor(editor, lastLevel, true);
|
|
|
18138 |
if (undoManager.transact(callback2)) {
|
|
|
18139 |
undoManager.data[index.get() - 1].beforeBookmark = bookmark;
|
|
|
18140 |
}
|
|
|
18141 |
}
|
|
|
18142 |
};
|
|
|
18143 |
const redo$1 = (editor, index, data) => {
|
|
|
18144 |
let level;
|
|
|
18145 |
if (index.get() < data.length - 1) {
|
|
|
18146 |
index.set(index.get() + 1);
|
|
|
18147 |
level = data[index.get()];
|
|
|
18148 |
applyToEditor(editor, level, false);
|
|
|
18149 |
editor.setDirty(true);
|
|
|
18150 |
editor.dispatch('Redo', { level });
|
|
|
18151 |
}
|
|
|
18152 |
return level;
|
|
|
18153 |
};
|
|
|
18154 |
const undo$1 = (editor, undoManager, locks, index) => {
|
|
|
18155 |
let level;
|
|
|
18156 |
if (undoManager.typing) {
|
|
|
18157 |
undoManager.add();
|
|
|
18158 |
undoManager.typing = false;
|
|
|
18159 |
setTyping(undoManager, false, locks);
|
|
|
18160 |
}
|
|
|
18161 |
if (index.get() > 0) {
|
|
|
18162 |
index.set(index.get() - 1);
|
|
|
18163 |
level = undoManager.data[index.get()];
|
|
|
18164 |
applyToEditor(editor, level, true);
|
|
|
18165 |
editor.setDirty(true);
|
|
|
18166 |
editor.dispatch('Undo', { level });
|
|
|
18167 |
}
|
|
|
18168 |
return level;
|
|
|
18169 |
};
|
|
|
18170 |
const reset$1 = undoManager => {
|
|
|
18171 |
undoManager.clear();
|
|
|
18172 |
undoManager.add();
|
|
|
18173 |
};
|
|
|
18174 |
const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
|
|
|
18175 |
const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
|
|
|
18176 |
const transact$1 = (undoManager, locks, callback) => {
|
|
|
18177 |
endTyping(undoManager, locks);
|
|
|
18178 |
undoManager.beforeChange();
|
|
|
18179 |
undoManager.ignore(callback);
|
|
|
18180 |
return undoManager.add();
|
|
|
18181 |
};
|
|
|
18182 |
const ignore$1 = (locks, callback) => {
|
|
|
18183 |
try {
|
|
|
18184 |
locks.set(locks.get() + 1);
|
|
|
18185 |
callback();
|
|
|
18186 |
} finally {
|
|
|
18187 |
locks.set(locks.get() - 1);
|
|
|
18188 |
}
|
|
|
18189 |
};
|
|
|
18190 |
|
|
|
18191 |
const addVisualInternal = (editor, elm) => {
|
|
|
18192 |
const dom = editor.dom;
|
|
|
18193 |
const scope = isNonNullable(elm) ? elm : editor.getBody();
|
|
|
18194 |
each$e(dom.select('table,a', scope), matchedElm => {
|
|
|
18195 |
switch (matchedElm.nodeName) {
|
|
|
18196 |
case 'TABLE':
|
|
|
18197 |
const cls = getVisualAidsTableClass(editor);
|
|
|
18198 |
const value = dom.getAttrib(matchedElm, 'border');
|
|
|
18199 |
if ((!value || value === '0') && editor.hasVisual) {
|
|
|
18200 |
dom.addClass(matchedElm, cls);
|
|
|
18201 |
} else {
|
|
|
18202 |
dom.removeClass(matchedElm, cls);
|
|
|
18203 |
}
|
|
|
18204 |
break;
|
|
|
18205 |
case 'A':
|
|
|
18206 |
if (!dom.getAttrib(matchedElm, 'href')) {
|
|
|
18207 |
const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id;
|
|
|
18208 |
const cls = getVisualAidsAnchorClass(editor);
|
|
|
18209 |
if (value && editor.hasVisual) {
|
|
|
18210 |
dom.addClass(matchedElm, cls);
|
|
|
18211 |
} else {
|
|
|
18212 |
dom.removeClass(matchedElm, cls);
|
|
|
18213 |
}
|
|
|
18214 |
}
|
|
|
18215 |
break;
|
|
|
18216 |
}
|
|
|
18217 |
});
|
|
|
18218 |
editor.dispatch('VisualAid', {
|
|
|
18219 |
element: elm,
|
|
|
18220 |
hasVisual: editor.hasVisual
|
|
|
18221 |
});
|
|
|
18222 |
};
|
|
|
18223 |
|
|
|
18224 |
const makePlainAdaptor = editor => ({
|
|
|
18225 |
init: { bindEvents: noop },
|
|
|
18226 |
undoManager: {
|
|
|
18227 |
beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
|
|
|
18228 |
add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event),
|
|
|
18229 |
undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index),
|
|
|
18230 |
redo: (index, data) => redo$1(editor, index, data),
|
|
|
18231 |
clear: (undoManager, index) => clear$1(editor, undoManager, index),
|
|
|
18232 |
reset: undoManager => reset$1(undoManager),
|
|
|
18233 |
hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index),
|
|
|
18234 |
hasRedo: (undoManager, index) => hasRedo$1(undoManager, index),
|
|
|
18235 |
transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
|
|
|
18236 |
ignore: (locks, callback) => ignore$1(locks, callback),
|
|
|
18237 |
extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2)
|
|
|
18238 |
},
|
|
|
18239 |
formatter: {
|
|
|
18240 |
match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar),
|
|
|
18241 |
matchAll: (names, vars) => matchAll(editor, names, vars),
|
|
|
18242 |
matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar),
|
|
|
18243 |
canApply: name => canApply(editor, name),
|
|
|
18244 |
closest: names => closest(editor, names),
|
|
|
18245 |
apply: (name, vars, node) => applyFormat$1(editor, name, vars, node),
|
|
|
18246 |
remove: (name, vars, node, similar) => removeFormat$1(editor, name, vars, node, similar),
|
|
|
18247 |
toggle: (name, vars, node) => toggle(editor, name, vars, node),
|
|
|
18248 |
formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
|
|
|
18249 |
},
|
|
|
18250 |
editor: {
|
|
|
18251 |
getContent: args => getContentInternal(editor, args),
|
|
|
18252 |
setContent: (content, args) => setContentInternal(editor, content, args),
|
|
|
18253 |
insertContent: (value, details) => insertHtmlAtCaret(editor, value, details),
|
|
|
18254 |
addVisual: elm => addVisualInternal(editor, elm)
|
|
|
18255 |
},
|
|
|
18256 |
selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
|
|
|
18257 |
autocompleter: {
|
| 1441 |
ariadna |
18258 |
addDecoration: noop,
|
|
|
18259 |
removeDecoration: noop
|
| 1 |
efrain |
18260 |
},
|
|
|
18261 |
raw: { getModel: () => Optional.none() }
|
|
|
18262 |
});
|
|
|
18263 |
const makeRtcAdaptor = rtcEditor => {
|
|
|
18264 |
const defaultVars = vars => isObject(vars) ? vars : {};
|
|
|
18265 |
const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor;
|
|
|
18266 |
return {
|
|
|
18267 |
init: { bindEvents: init.bindEvents },
|
|
|
18268 |
undoManager: {
|
|
|
18269 |
beforeChange: undoManager.beforeChange,
|
|
|
18270 |
add: undoManager.add,
|
|
|
18271 |
undo: undoManager.undo,
|
|
|
18272 |
redo: undoManager.redo,
|
|
|
18273 |
clear: undoManager.clear,
|
|
|
18274 |
reset: undoManager.reset,
|
|
|
18275 |
hasUndo: undoManager.hasUndo,
|
|
|
18276 |
hasRedo: undoManager.hasRedo,
|
|
|
18277 |
transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
|
|
|
18278 |
ignore: (_locks, callback) => undoManager.ignore(callback),
|
|
|
18279 |
extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
|
|
|
18280 |
},
|
|
|
18281 |
formatter: {
|
|
|
18282 |
match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar),
|
|
|
18283 |
matchAll: formatter.matchAll,
|
|
|
18284 |
matchNode: formatter.matchNode,
|
|
|
18285 |
canApply: name => formatter.canApply(name),
|
|
|
18286 |
closest: names => formatter.closest(names),
|
|
|
18287 |
apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)),
|
|
|
18288 |
remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)),
|
|
|
18289 |
toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)),
|
|
|
18290 |
formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
|
|
|
18291 |
},
|
|
|
18292 |
editor: {
|
|
|
18293 |
getContent: args => editor.getContent(args),
|
|
|
18294 |
setContent: (content, args) => {
|
|
|
18295 |
return {
|
|
|
18296 |
content: editor.setContent(content, args),
|
|
|
18297 |
html: ''
|
|
|
18298 |
};
|
|
|
18299 |
},
|
|
|
18300 |
insertContent: (content, _details) => {
|
|
|
18301 |
editor.insertContent(content);
|
|
|
18302 |
return '';
|
|
|
18303 |
},
|
|
|
18304 |
addVisual: editor.addVisual
|
|
|
18305 |
},
|
|
|
18306 |
selection: { getContent: (_format, args) => selection.getContent(args) },
|
|
|
18307 |
autocompleter: {
|
|
|
18308 |
addDecoration: autocompleter.addDecoration,
|
|
|
18309 |
removeDecoration: autocompleter.removeDecoration
|
|
|
18310 |
},
|
|
|
18311 |
raw: { getModel: () => Optional.some(raw.getRawModel()) }
|
|
|
18312 |
};
|
|
|
18313 |
};
|
|
|
18314 |
const makeNoopAdaptor = () => {
|
|
|
18315 |
const nul = constant(null);
|
|
|
18316 |
const empty = constant('');
|
|
|
18317 |
return {
|
|
|
18318 |
init: { bindEvents: noop },
|
|
|
18319 |
undoManager: {
|
|
|
18320 |
beforeChange: noop,
|
|
|
18321 |
add: nul,
|
|
|
18322 |
undo: nul,
|
|
|
18323 |
redo: nul,
|
|
|
18324 |
clear: noop,
|
|
|
18325 |
reset: noop,
|
|
|
18326 |
hasUndo: never,
|
|
|
18327 |
hasRedo: never,
|
|
|
18328 |
transact: nul,
|
|
|
18329 |
ignore: noop,
|
|
|
18330 |
extra: noop
|
|
|
18331 |
},
|
|
|
18332 |
formatter: {
|
|
|
18333 |
match: never,
|
|
|
18334 |
matchAll: constant([]),
|
|
|
18335 |
matchNode: constant(undefined),
|
|
|
18336 |
canApply: never,
|
|
|
18337 |
closest: empty,
|
|
|
18338 |
apply: noop,
|
|
|
18339 |
remove: noop,
|
|
|
18340 |
toggle: noop,
|
|
|
18341 |
formatChanged: constant({ unbind: noop })
|
|
|
18342 |
},
|
|
|
18343 |
editor: {
|
|
|
18344 |
getContent: empty,
|
|
|
18345 |
setContent: constant({
|
|
|
18346 |
content: '',
|
|
|
18347 |
html: ''
|
|
|
18348 |
}),
|
|
|
18349 |
insertContent: constant(''),
|
|
|
18350 |
addVisual: noop
|
|
|
18351 |
},
|
|
|
18352 |
selection: { getContent: empty },
|
|
|
18353 |
autocompleter: {
|
|
|
18354 |
addDecoration: noop,
|
|
|
18355 |
removeDecoration: noop
|
|
|
18356 |
},
|
|
|
18357 |
raw: { getModel: constant(Optional.none()) }
|
|
|
18358 |
};
|
|
|
18359 |
};
|
|
|
18360 |
const isRtc = editor => has$2(editor.plugins, 'rtc');
|
|
|
18361 |
const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup));
|
|
|
18362 |
const setup$t = editor => {
|
|
|
18363 |
const editorCast = editor;
|
|
|
18364 |
return getRtcSetup(editor).fold(() => {
|
|
|
18365 |
editorCast.rtcInstance = makePlainAdaptor(editor);
|
|
|
18366 |
return Optional.none();
|
|
|
18367 |
}, setup => {
|
|
|
18368 |
editorCast.rtcInstance = makeNoopAdaptor();
|
|
|
18369 |
return Optional.some(() => setup().then(rtcEditor => {
|
|
|
18370 |
editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
|
|
|
18371 |
return rtcEditor.rtc.isRemote;
|
|
|
18372 |
}));
|
|
|
18373 |
});
|
|
|
18374 |
};
|
|
|
18375 |
const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
|
|
|
18376 |
const getRtcInstanceWithError = editor => {
|
|
|
18377 |
const rtcInstance = editor.rtcInstance;
|
|
|
18378 |
if (!rtcInstance) {
|
|
|
18379 |
throw new Error('Failed to get RTC instance not yet initialized.');
|
|
|
18380 |
} else {
|
|
|
18381 |
return rtcInstance;
|
|
|
18382 |
}
|
|
|
18383 |
};
|
|
|
18384 |
const beforeChange = (editor, locks, beforeBookmark) => {
|
|
|
18385 |
getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
|
|
|
18386 |
};
|
|
|
18387 |
const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event);
|
|
|
18388 |
const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index);
|
|
|
18389 |
const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data);
|
|
|
18390 |
const clear = (editor, undoManager, index) => {
|
|
|
18391 |
getRtcInstanceWithError(editor).undoManager.clear(undoManager, index);
|
|
|
18392 |
};
|
|
|
18393 |
const reset = (editor, undoManager) => {
|
|
|
18394 |
getRtcInstanceWithError(editor).undoManager.reset(undoManager);
|
|
|
18395 |
};
|
|
|
18396 |
const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index);
|
|
|
18397 |
const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index);
|
|
|
18398 |
const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
|
|
|
18399 |
const ignore = (editor, locks, callback) => {
|
|
|
18400 |
getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
|
|
|
18401 |
};
|
|
|
18402 |
const extra = (editor, undoManager, index, callback1, callback2) => {
|
|
|
18403 |
getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2);
|
|
|
18404 |
};
|
|
|
18405 |
const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar);
|
|
|
18406 |
const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
|
|
|
18407 |
const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar);
|
|
|
18408 |
const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name);
|
|
|
18409 |
const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
|
|
|
18410 |
const applyFormat = (editor, name, vars, node) => {
|
|
|
18411 |
getRtcInstanceWithError(editor).formatter.apply(name, vars, node);
|
|
|
18412 |
};
|
|
|
18413 |
const removeFormat = (editor, name, vars, node, similar) => {
|
|
|
18414 |
getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar);
|
|
|
18415 |
};
|
|
|
18416 |
const toggleFormat = (editor, name, vars, node) => {
|
|
|
18417 |
getRtcInstanceWithError(editor).formatter.toggle(name, vars, node);
|
|
|
18418 |
};
|
|
|
18419 |
const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
|
|
|
18420 |
const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
|
|
|
18421 |
const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
|
|
|
18422 |
const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details);
|
|
|
18423 |
const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
|
|
|
18424 |
const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
|
|
|
18425 |
const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents();
|
|
|
18426 |
|
|
|
18427 |
const getContent$1 = (editor, args = {}) => {
|
|
|
18428 |
const format = args.format ? args.format : 'html';
|
|
|
18429 |
return getSelectedContent(editor, format, args);
|
|
|
18430 |
};
|
|
|
18431 |
|
|
|
18432 |
const removeEmpty = text => {
|
|
|
18433 |
if (text.dom.length === 0) {
|
| 1441 |
ariadna |
18434 |
remove$4(text);
|
| 1 |
efrain |
18435 |
return Optional.none();
|
|
|
18436 |
} else {
|
|
|
18437 |
return Optional.some(text);
|
|
|
18438 |
}
|
|
|
18439 |
};
|
|
|
18440 |
const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling);
|
|
|
18441 |
const merge$1 = (outer, inner, rng, start, schema) => {
|
|
|
18442 |
const outerElm = outer.dom;
|
|
|
18443 |
const innerElm = inner.dom;
|
|
|
18444 |
const oldLength = start ? outerElm.length : innerElm.length;
|
|
|
18445 |
if (start) {
|
|
|
18446 |
mergeTextNodes(outerElm, innerElm, schema, false, !start);
|
|
|
18447 |
rng.setStart(innerElm, oldLength);
|
|
|
18448 |
} else {
|
|
|
18449 |
mergeTextNodes(innerElm, outerElm, schema, false, !start);
|
|
|
18450 |
rng.setEnd(innerElm, oldLength);
|
|
|
18451 |
}
|
|
|
18452 |
};
|
|
|
18453 |
const normalizeTextIfRequired = (inner, start, schema) => {
|
|
|
18454 |
parent(inner).each(root => {
|
|
|
18455 |
const text = inner.dom;
|
|
|
18456 |
if (start && needsToBeNbspLeft(root, CaretPosition(text, 0), schema)) {
|
|
|
18457 |
normalizeWhitespaceAfter(text, 0, schema);
|
|
|
18458 |
} else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length), schema)) {
|
|
|
18459 |
normalizeWhitespaceBefore(text, text.length, schema);
|
|
|
18460 |
}
|
|
|
18461 |
});
|
|
|
18462 |
};
|
|
|
18463 |
const mergeAndNormalizeText = (outerNode, innerNode, rng, start, schema) => {
|
|
|
18464 |
outerNode.bind(outer => {
|
|
|
18465 |
const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
|
|
|
18466 |
normalizer(outer.dom, start ? outer.dom.length : 0, schema);
|
| 1441 |
ariadna |
18467 |
return innerNode.filter(isText$c).map(inner => merge$1(outer, inner, rng, start, schema));
|
| 1 |
efrain |
18468 |
}).orThunk(() => {
|
| 1441 |
ariadna |
18469 |
const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$c);
|
| 1 |
efrain |
18470 |
return innerTextNode.map(inner => normalizeTextIfRequired(inner, start, schema));
|
|
|
18471 |
});
|
|
|
18472 |
};
|
|
|
18473 |
const rngSetContent = (rng, fragment, schema) => {
|
|
|
18474 |
const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
|
|
|
18475 |
const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
|
|
|
18476 |
rng.deleteContents();
|
|
|
18477 |
rng.insertNode(fragment);
|
| 1441 |
ariadna |
18478 |
const prevText = firstChild.bind(prevSibling).filter(isText$c).bind(removeEmpty);
|
|
|
18479 |
const nextText = lastChild.bind(nextSibling).filter(isText$c).bind(removeEmpty);
|
| 1 |
efrain |
18480 |
mergeAndNormalizeText(prevText, firstChild, rng, true, schema);
|
|
|
18481 |
mergeAndNormalizeText(nextText, lastChild, rng, false, schema);
|
|
|
18482 |
rng.collapse(false);
|
|
|
18483 |
};
|
|
|
18484 |
const setupArgs$2 = (args, content) => ({
|
|
|
18485 |
format: 'html',
|
|
|
18486 |
...args,
|
|
|
18487 |
set: true,
|
|
|
18488 |
selection: true,
|
|
|
18489 |
content
|
|
|
18490 |
});
|
|
|
18491 |
const cleanContent = (editor, args) => {
|
|
|
18492 |
if (args.format !== 'raw') {
|
|
|
18493 |
const rng = editor.selection.getRng();
|
|
|
18494 |
const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
|
|
|
18495 |
const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
|
|
|
18496 |
const node = editor.parser.parse(args.content, {
|
|
|
18497 |
forced_root_block: false,
|
|
|
18498 |
...contextArgs,
|
|
|
18499 |
...args
|
|
|
18500 |
});
|
|
|
18501 |
return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
|
|
|
18502 |
} else {
|
|
|
18503 |
return args.content;
|
|
|
18504 |
}
|
|
|
18505 |
};
|
|
|
18506 |
const setContent$1 = (editor, content, args = {}) => {
|
|
|
18507 |
const defaultedArgs = setupArgs$2(args, content);
|
|
|
18508 |
preProcessSetContent(editor, defaultedArgs).each(updatedArgs => {
|
|
|
18509 |
const cleanedContent = cleanContent(editor, updatedArgs);
|
|
|
18510 |
const rng = editor.selection.getRng();
|
|
|
18511 |
rngSetContent(rng, rng.createContextualFragment(cleanedContent), editor.schema);
|
|
|
18512 |
editor.selection.setRng(rng);
|
|
|
18513 |
scrollRangeIntoView(editor, rng);
|
|
|
18514 |
postProcessSetContent(editor, cleanedContent, updatedArgs);
|
|
|
18515 |
});
|
|
|
18516 |
};
|
|
|
18517 |
|
|
|
18518 |
const deleteFromCallbackMap = (callbackMap, selector, callback) => {
|
|
|
18519 |
if (has$2(callbackMap, selector)) {
|
|
|
18520 |
const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback);
|
|
|
18521 |
if (newCallbacks.length === 0) {
|
|
|
18522 |
delete callbackMap[selector];
|
|
|
18523 |
} else {
|
|
|
18524 |
callbackMap[selector] = newCallbacks;
|
|
|
18525 |
}
|
|
|
18526 |
}
|
|
|
18527 |
};
|
|
|
18528 |
var SelectorChanged = (dom, editor) => {
|
|
|
18529 |
let selectorChangedData;
|
|
|
18530 |
let currentSelectors;
|
|
|
18531 |
const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector));
|
|
|
18532 |
const getParents = elem => dom.getParents(elem, undefined, dom.getRoot());
|
|
|
18533 |
const setup = () => {
|
|
|
18534 |
selectorChangedData = {};
|
|
|
18535 |
currentSelectors = {};
|
|
|
18536 |
editor.on('NodeChange', e => {
|
|
|
18537 |
const node = e.element;
|
|
|
18538 |
const parents = getParents(node);
|
|
|
18539 |
const matchedSelectors = {};
|
|
|
18540 |
each$d(selectorChangedData, (callbacks, selector) => {
|
|
|
18541 |
findMatchingNode(selector, parents).each(node => {
|
|
|
18542 |
if (!currentSelectors[selector]) {
|
|
|
18543 |
each$e(callbacks, callback => {
|
|
|
18544 |
callback(true, {
|
|
|
18545 |
node,
|
|
|
18546 |
selector,
|
|
|
18547 |
parents
|
|
|
18548 |
});
|
|
|
18549 |
});
|
|
|
18550 |
currentSelectors[selector] = callbacks;
|
|
|
18551 |
}
|
|
|
18552 |
matchedSelectors[selector] = callbacks;
|
|
|
18553 |
});
|
|
|
18554 |
});
|
|
|
18555 |
each$d(currentSelectors, (callbacks, selector) => {
|
|
|
18556 |
if (!matchedSelectors[selector]) {
|
|
|
18557 |
delete currentSelectors[selector];
|
|
|
18558 |
each$e(callbacks, callback => {
|
|
|
18559 |
callback(false, {
|
|
|
18560 |
node,
|
|
|
18561 |
selector,
|
|
|
18562 |
parents
|
|
|
18563 |
});
|
|
|
18564 |
});
|
|
|
18565 |
}
|
|
|
18566 |
});
|
|
|
18567 |
});
|
|
|
18568 |
};
|
|
|
18569 |
return {
|
|
|
18570 |
selectorChangedWithUnbind: (selector, callback) => {
|
|
|
18571 |
if (!selectorChangedData) {
|
|
|
18572 |
setup();
|
|
|
18573 |
}
|
|
|
18574 |
if (!selectorChangedData[selector]) {
|
|
|
18575 |
selectorChangedData[selector] = [];
|
|
|
18576 |
}
|
|
|
18577 |
selectorChangedData[selector].push(callback);
|
|
|
18578 |
findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => {
|
|
|
18579 |
currentSelectors[selector] = selectorChangedData[selector];
|
|
|
18580 |
});
|
|
|
18581 |
return {
|
|
|
18582 |
unbind: () => {
|
|
|
18583 |
deleteFromCallbackMap(selectorChangedData, selector, callback);
|
|
|
18584 |
deleteFromCallbackMap(currentSelectors, selector, callback);
|
|
|
18585 |
}
|
|
|
18586 |
};
|
|
|
18587 |
}
|
|
|
18588 |
};
|
|
|
18589 |
};
|
|
|
18590 |
|
|
|
18591 |
const isAttachedToDom = node => {
|
|
|
18592 |
return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
|
|
|
18593 |
};
|
|
|
18594 |
const isValidRange = rng => {
|
|
|
18595 |
if (!rng) {
|
|
|
18596 |
return false;
|
|
|
18597 |
} else {
|
|
|
18598 |
return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
|
|
|
18599 |
}
|
|
|
18600 |
};
|
|
|
18601 |
const EditorSelection = (dom, win, serializer, editor) => {
|
|
|
18602 |
let selectedRange;
|
|
|
18603 |
let explicitRange;
|
|
|
18604 |
const {selectorChangedWithUnbind} = SelectorChanged(dom, editor);
|
|
|
18605 |
const setCursorLocation = (node, offset) => {
|
|
|
18606 |
const rng = dom.createRng();
|
|
|
18607 |
if (isNonNullable(node) && isNonNullable(offset)) {
|
|
|
18608 |
rng.setStart(node, offset);
|
|
|
18609 |
rng.setEnd(node, offset);
|
|
|
18610 |
setRng(rng);
|
|
|
18611 |
collapse(false);
|
|
|
18612 |
} else {
|
|
|
18613 |
moveEndPoint(dom, rng, editor.getBody(), true);
|
|
|
18614 |
setRng(rng);
|
|
|
18615 |
}
|
|
|
18616 |
};
|
|
|
18617 |
const getContent = args => getContent$1(editor, args);
|
|
|
18618 |
const setContent = (content, args) => setContent$1(editor, content, args);
|
|
|
18619 |
const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real);
|
| 1441 |
ariadna |
18620 |
const getEnd$1 = real => getEnd(editor.getBody(), getRng$1(), real);
|
| 1 |
efrain |
18621 |
const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized);
|
|
|
18622 |
const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark);
|
|
|
18623 |
const select$1 = (node, content) => {
|
|
|
18624 |
select(dom, node, content).each(setRng);
|
|
|
18625 |
return node;
|
|
|
18626 |
};
|
|
|
18627 |
const isCollapsed = () => {
|
|
|
18628 |
const rng = getRng$1(), sel = getSel();
|
|
|
18629 |
if (!rng || rng.item) {
|
|
|
18630 |
return false;
|
|
|
18631 |
}
|
|
|
18632 |
if (rng.compareEndPoints) {
|
|
|
18633 |
return rng.compareEndPoints('StartToEnd', rng) === 0;
|
|
|
18634 |
}
|
|
|
18635 |
return !sel || rng.collapsed;
|
|
|
18636 |
};
|
|
|
18637 |
const isEditable = () => {
|
| 1441 |
ariadna |
18638 |
if (editor.mode.isReadOnly()) {
|
|
|
18639 |
return false;
|
|
|
18640 |
}
|
| 1 |
efrain |
18641 |
const rng = getRng$1();
|
|
|
18642 |
const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]');
|
|
|
18643 |
if (fakeSelectedElements.length > 0) {
|
|
|
18644 |
return forall(fakeSelectedElements, el => dom.isEditable(el.parentElement));
|
|
|
18645 |
} else {
|
|
|
18646 |
return isEditableRange(dom, rng);
|
|
|
18647 |
}
|
|
|
18648 |
};
|
|
|
18649 |
const collapse = toStart => {
|
|
|
18650 |
const rng = getRng$1();
|
|
|
18651 |
rng.collapse(!!toStart);
|
|
|
18652 |
setRng(rng);
|
|
|
18653 |
};
|
|
|
18654 |
const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
|
|
|
18655 |
const getRng$1 = () => {
|
|
|
18656 |
let rng;
|
|
|
18657 |
const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
|
|
|
18658 |
try {
|
|
|
18659 |
return sourceRange.compareBoundaryPoints(how, destinationRange);
|
| 1441 |
ariadna |
18660 |
} catch (_a) {
|
| 1 |
efrain |
18661 |
return -1;
|
|
|
18662 |
}
|
|
|
18663 |
};
|
|
|
18664 |
const doc = win.document;
|
|
|
18665 |
if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
|
|
|
18666 |
const bookmark = getRng(editor);
|
|
|
18667 |
if (bookmark.isSome()) {
|
|
|
18668 |
return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange());
|
|
|
18669 |
}
|
|
|
18670 |
}
|
|
|
18671 |
try {
|
|
|
18672 |
const selection = getSel();
|
|
|
18673 |
if (selection && !isRestrictedNode(selection.anchorNode)) {
|
|
|
18674 |
if (selection.rangeCount > 0) {
|
|
|
18675 |
rng = selection.getRangeAt(0);
|
|
|
18676 |
} else {
|
|
|
18677 |
rng = doc.createRange();
|
|
|
18678 |
}
|
|
|
18679 |
rng = processRanges(editor, [rng])[0];
|
|
|
18680 |
}
|
| 1441 |
ariadna |
18681 |
} catch (_a) {
|
| 1 |
efrain |
18682 |
}
|
|
|
18683 |
if (!rng) {
|
|
|
18684 |
rng = doc.createRange();
|
|
|
18685 |
}
|
|
|
18686 |
if (isDocument$1(rng.startContainer) && rng.collapsed) {
|
|
|
18687 |
const elm = dom.getRoot();
|
|
|
18688 |
rng.setStart(elm, 0);
|
|
|
18689 |
rng.setEnd(elm, 0);
|
|
|
18690 |
}
|
|
|
18691 |
if (selectedRange && explicitRange) {
|
|
|
18692 |
if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
|
|
|
18693 |
rng = explicitRange;
|
|
|
18694 |
} else {
|
|
|
18695 |
selectedRange = null;
|
|
|
18696 |
explicitRange = null;
|
|
|
18697 |
}
|
|
|
18698 |
}
|
|
|
18699 |
return rng;
|
|
|
18700 |
};
|
|
|
18701 |
const setRng = (rng, forward) => {
|
|
|
18702 |
if (!isValidRange(rng)) {
|
|
|
18703 |
return;
|
|
|
18704 |
}
|
|
|
18705 |
const sel = getSel();
|
|
|
18706 |
const evt = editor.dispatch('SetSelectionRange', {
|
|
|
18707 |
range: rng,
|
|
|
18708 |
forward
|
|
|
18709 |
});
|
|
|
18710 |
rng = evt.range;
|
|
|
18711 |
if (sel) {
|
|
|
18712 |
explicitRange = rng;
|
|
|
18713 |
try {
|
|
|
18714 |
sel.removeAllRanges();
|
|
|
18715 |
sel.addRange(rng);
|
| 1441 |
ariadna |
18716 |
} catch (_a) {
|
| 1 |
efrain |
18717 |
}
|
|
|
18718 |
if (forward === false && sel.extend) {
|
|
|
18719 |
sel.collapse(rng.endContainer, rng.endOffset);
|
|
|
18720 |
sel.extend(rng.startContainer, rng.startOffset);
|
|
|
18721 |
}
|
|
|
18722 |
selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
|
|
|
18723 |
}
|
|
|
18724 |
if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) {
|
|
|
18725 |
if (rng.endOffset - rng.startOffset < 2) {
|
|
|
18726 |
if (rng.startContainer.hasChildNodes()) {
|
|
|
18727 |
const node = rng.startContainer.childNodes[rng.startOffset];
|
|
|
18728 |
if (node && node.nodeName === 'IMG') {
|
|
|
18729 |
sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
|
|
|
18730 |
if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
|
|
|
18731 |
sel.setBaseAndExtent(node, 0, node, 1);
|
|
|
18732 |
}
|
|
|
18733 |
}
|
|
|
18734 |
}
|
|
|
18735 |
}
|
|
|
18736 |
}
|
|
|
18737 |
editor.dispatch('AfterSetSelectionRange', {
|
|
|
18738 |
range: rng,
|
|
|
18739 |
forward
|
|
|
18740 |
});
|
|
|
18741 |
};
|
|
|
18742 |
const setNode = elm => {
|
|
|
18743 |
setContent(dom.getOuterHTML(elm));
|
|
|
18744 |
return elm;
|
|
|
18745 |
};
|
|
|
18746 |
const getNode$1 = () => getNode(editor.getBody(), getRng$1());
|
|
|
18747 |
const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm);
|
|
|
18748 |
const isForward = () => {
|
|
|
18749 |
const sel = getSel();
|
|
|
18750 |
const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
|
|
|
18751 |
const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
|
|
|
18752 |
if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
|
|
|
18753 |
return true;
|
|
|
18754 |
}
|
|
|
18755 |
const anchorRange = dom.createRng();
|
|
|
18756 |
const focusRange = dom.createRng();
|
|
|
18757 |
try {
|
|
|
18758 |
anchorRange.setStart(anchorNode, sel.anchorOffset);
|
|
|
18759 |
anchorRange.collapse(true);
|
|
|
18760 |
focusRange.setStart(focusNode, sel.focusOffset);
|
|
|
18761 |
focusRange.collapse(true);
|
| 1441 |
ariadna |
18762 |
} catch (_a) {
|
| 1 |
efrain |
18763 |
return true;
|
|
|
18764 |
}
|
|
|
18765 |
return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
|
|
|
18766 |
};
|
|
|
18767 |
const normalize = () => {
|
|
|
18768 |
const rng = getRng$1();
|
|
|
18769 |
const sel = getSel();
|
|
|
18770 |
if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
|
|
|
18771 |
const normRng = normalize$2(dom, rng);
|
|
|
18772 |
normRng.each(normRng => {
|
|
|
18773 |
setRng(normRng, isForward());
|
|
|
18774 |
});
|
|
|
18775 |
return normRng.getOr(rng);
|
|
|
18776 |
}
|
|
|
18777 |
return rng;
|
|
|
18778 |
};
|
|
|
18779 |
const selectorChanged = (selector, callback) => {
|
|
|
18780 |
selectorChangedWithUnbind(selector, callback);
|
|
|
18781 |
return exports;
|
|
|
18782 |
};
|
|
|
18783 |
const getScrollContainer = () => {
|
|
|
18784 |
let scrollContainer;
|
|
|
18785 |
let node = dom.getRoot();
|
|
|
18786 |
while (node && node.nodeName !== 'BODY') {
|
|
|
18787 |
if (node.scrollHeight > node.clientHeight) {
|
|
|
18788 |
scrollContainer = node;
|
|
|
18789 |
break;
|
|
|
18790 |
}
|
|
|
18791 |
node = node.parentNode;
|
|
|
18792 |
}
|
|
|
18793 |
return scrollContainer;
|
|
|
18794 |
};
|
|
|
18795 |
const scrollIntoView = (elm, alignToTop) => {
|
|
|
18796 |
if (isNonNullable(elm)) {
|
|
|
18797 |
scrollElementIntoView(editor, elm, alignToTop);
|
|
|
18798 |
} else {
|
|
|
18799 |
scrollRangeIntoView(editor, getRng$1(), alignToTop);
|
|
|
18800 |
}
|
|
|
18801 |
};
|
|
|
18802 |
const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
|
|
|
18803 |
const getBoundingClientRect = () => {
|
|
|
18804 |
const rng = getRng$1();
|
|
|
18805 |
return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
|
|
|
18806 |
};
|
|
|
18807 |
const destroy = () => {
|
|
|
18808 |
win = selectedRange = explicitRange = null;
|
|
|
18809 |
controlSelection.destroy();
|
|
|
18810 |
};
|
|
|
18811 |
const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options));
|
|
|
18812 |
const exports = {
|
|
|
18813 |
dom,
|
|
|
18814 |
win,
|
|
|
18815 |
serializer,
|
|
|
18816 |
editor,
|
|
|
18817 |
expand,
|
|
|
18818 |
collapse,
|
|
|
18819 |
setCursorLocation,
|
|
|
18820 |
getContent,
|
|
|
18821 |
setContent,
|
|
|
18822 |
getBookmark,
|
|
|
18823 |
moveToBookmark,
|
|
|
18824 |
select: select$1,
|
|
|
18825 |
isCollapsed,
|
|
|
18826 |
isEditable,
|
|
|
18827 |
isForward,
|
|
|
18828 |
setNode,
|
|
|
18829 |
getNode: getNode$1,
|
|
|
18830 |
getSel,
|
|
|
18831 |
setRng,
|
|
|
18832 |
getRng: getRng$1,
|
|
|
18833 |
getStart: getStart$1,
|
| 1441 |
ariadna |
18834 |
getEnd: getEnd$1,
|
| 1 |
efrain |
18835 |
getSelectedBlocks: getSelectedBlocks$1,
|
|
|
18836 |
normalize,
|
|
|
18837 |
selectorChanged,
|
|
|
18838 |
selectorChangedWithUnbind,
|
|
|
18839 |
getScrollContainer,
|
|
|
18840 |
scrollIntoView,
|
|
|
18841 |
placeCaretAt,
|
|
|
18842 |
getBoundingClientRect,
|
|
|
18843 |
destroy
|
|
|
18844 |
};
|
|
|
18845 |
const bookmarkManager = BookmarkManager(exports);
|
|
|
18846 |
const controlSelection = ControlSelection(exports, editor);
|
|
|
18847 |
exports.bookmarkManager = bookmarkManager;
|
|
|
18848 |
exports.controlSelection = controlSelection;
|
|
|
18849 |
return exports;
|
|
|
18850 |
};
|
|
|
18851 |
|
| 1441 |
ariadna |
18852 |
const addNodeFilter = (settings, htmlParser, schema) => {
|
|
|
18853 |
htmlParser.addNodeFilter('br', (nodes, _, args) => {
|
|
|
18854 |
const blockElements = Tools.extend({}, schema.getBlockElements());
|
|
|
18855 |
const nonEmptyElements = schema.getNonEmptyElements();
|
|
|
18856 |
const whitespaceElements = schema.getWhitespaceElements();
|
|
|
18857 |
blockElements.body = 1;
|
|
|
18858 |
const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node);
|
|
|
18859 |
for (let i = 0, l = nodes.length; i < l; i++) {
|
|
|
18860 |
let node = nodes[i];
|
|
|
18861 |
let parent = node.parent;
|
|
|
18862 |
if (parent && isBlock(parent) && node === parent.lastChild) {
|
|
|
18863 |
let prev = node.prev;
|
|
|
18864 |
while (prev) {
|
|
|
18865 |
const prevName = prev.name;
|
|
|
18866 |
if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
|
|
|
18867 |
if (prevName === 'br') {
|
|
|
18868 |
node = null;
|
|
|
18869 |
}
|
|
|
18870 |
break;
|
|
|
18871 |
}
|
|
|
18872 |
prev = prev.prev;
|
|
|
18873 |
}
|
|
|
18874 |
if (node) {
|
|
|
18875 |
node.remove();
|
|
|
18876 |
if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) {
|
|
|
18877 |
const elementRule = schema.getElementRule(parent.name);
|
|
|
18878 |
if (elementRule) {
|
|
|
18879 |
if (elementRule.removeEmpty) {
|
|
|
18880 |
parent.remove();
|
|
|
18881 |
} else if (elementRule.paddEmpty) {
|
|
|
18882 |
paddEmptyNode(settings, args, isBlock, parent);
|
|
|
18883 |
}
|
|
|
18884 |
}
|
|
|
18885 |
}
|
|
|
18886 |
}
|
|
|
18887 |
} else {
|
|
|
18888 |
let lastParent = node;
|
|
|
18889 |
while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
|
|
|
18890 |
lastParent = parent;
|
|
|
18891 |
if (blockElements[parent.name]) {
|
|
|
18892 |
break;
|
|
|
18893 |
}
|
|
|
18894 |
parent = parent.parent;
|
|
|
18895 |
}
|
|
|
18896 |
if (lastParent === parent) {
|
|
|
18897 |
const textNode = new AstNode('#text', 3);
|
|
|
18898 |
textNode.value = nbsp;
|
|
|
18899 |
node.replace(textNode);
|
|
|
18900 |
}
|
|
|
18901 |
}
|
|
|
18902 |
}
|
|
|
18903 |
});
|
|
|
18904 |
};
|
|
|
18905 |
|
| 1 |
efrain |
18906 |
const register$3 = (htmlParser, settings, dom) => {
|
|
|
18907 |
htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => {
|
|
|
18908 |
let i = nodes.length;
|
|
|
18909 |
while (i--) {
|
|
|
18910 |
const node = nodes[i];
|
|
|
18911 |
node.attr('tabindex', node.attr('data-mce-tabindex'));
|
|
|
18912 |
node.attr(name, null);
|
|
|
18913 |
}
|
|
|
18914 |
});
|
|
|
18915 |
htmlParser.addAttributeFilter('src,href,style', (nodes, name) => {
|
|
|
18916 |
const internalName = 'data-mce-' + name;
|
|
|
18917 |
const urlConverter = settings.url_converter;
|
|
|
18918 |
const urlConverterScope = settings.url_converter_scope;
|
|
|
18919 |
let i = nodes.length;
|
|
|
18920 |
while (i--) {
|
|
|
18921 |
const node = nodes[i];
|
|
|
18922 |
let value = node.attr(internalName);
|
|
|
18923 |
if (value !== undefined) {
|
|
|
18924 |
node.attr(name, value.length > 0 ? value : null);
|
|
|
18925 |
node.attr(internalName, null);
|
|
|
18926 |
} else {
|
|
|
18927 |
value = node.attr(name);
|
|
|
18928 |
if (name === 'style') {
|
|
|
18929 |
value = dom.serializeStyle(dom.parseStyle(value), node.name);
|
|
|
18930 |
} else if (urlConverter) {
|
|
|
18931 |
value = urlConverter.call(urlConverterScope, value, name, node.name);
|
|
|
18932 |
}
|
|
|
18933 |
node.attr(name, value.length > 0 ? value : null);
|
|
|
18934 |
}
|
|
|
18935 |
}
|
|
|
18936 |
});
|
|
|
18937 |
htmlParser.addAttributeFilter('class', nodes => {
|
|
|
18938 |
let i = nodes.length;
|
|
|
18939 |
while (i--) {
|
|
|
18940 |
const node = nodes[i];
|
|
|
18941 |
let value = node.attr('class');
|
|
|
18942 |
if (value) {
|
|
|
18943 |
value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
|
|
|
18944 |
node.attr('class', value.length > 0 ? value : null);
|
|
|
18945 |
}
|
|
|
18946 |
}
|
|
|
18947 |
});
|
|
|
18948 |
htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => {
|
|
|
18949 |
let i = nodes.length;
|
|
|
18950 |
while (i--) {
|
|
|
18951 |
const node = nodes[i];
|
|
|
18952 |
if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
|
|
|
18953 |
const hasChildren = Optional.from(node.firstChild).exists(firstChild => {
|
|
|
18954 |
var _a;
|
| 1441 |
ariadna |
18955 |
return !isZwsp((_a = firstChild.value) !== null && _a !== void 0 ? _a : '');
|
| 1 |
efrain |
18956 |
});
|
|
|
18957 |
if (hasChildren) {
|
|
|
18958 |
node.unwrap();
|
|
|
18959 |
} else {
|
|
|
18960 |
node.remove();
|
|
|
18961 |
}
|
|
|
18962 |
}
|
|
|
18963 |
}
|
|
|
18964 |
});
|
|
|
18965 |
htmlParser.addNodeFilter('script,style', (nodes, name) => {
|
|
|
18966 |
var _a;
|
|
|
18967 |
const trim = value => {
|
|
|
18968 |
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, '');
|
|
|
18969 |
};
|
|
|
18970 |
let i = nodes.length;
|
|
|
18971 |
while (i--) {
|
|
|
18972 |
const node = nodes[i];
|
|
|
18973 |
const firstChild = node.firstChild;
|
|
|
18974 |
const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : '';
|
|
|
18975 |
if (name === 'script') {
|
|
|
18976 |
const type = node.attr('type');
|
|
|
18977 |
if (type) {
|
|
|
18978 |
node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
|
|
|
18979 |
}
|
|
|
18980 |
if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
|
|
|
18981 |
firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
|
|
|
18982 |
}
|
|
|
18983 |
} else {
|
|
|
18984 |
if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
|
|
|
18985 |
firstChild.value = '<!--\n' + trim(value) + '\n-->';
|
|
|
18986 |
}
|
|
|
18987 |
}
|
|
|
18988 |
}
|
|
|
18989 |
});
|
|
|
18990 |
htmlParser.addNodeFilter('#comment', nodes => {
|
|
|
18991 |
let i = nodes.length;
|
|
|
18992 |
while (i--) {
|
|
|
18993 |
const node = nodes[i];
|
|
|
18994 |
const value = node.value;
|
|
|
18995 |
if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) {
|
|
|
18996 |
node.name = '#cdata';
|
|
|
18997 |
node.type = 4;
|
|
|
18998 |
node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, ''));
|
|
|
18999 |
} else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) {
|
|
|
19000 |
node.name = '#text';
|
|
|
19001 |
node.type = 3;
|
|
|
19002 |
node.raw = true;
|
|
|
19003 |
node.value = unescape(value).substr(14);
|
|
|
19004 |
}
|
|
|
19005 |
}
|
|
|
19006 |
});
|
|
|
19007 |
htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => {
|
|
|
19008 |
let i = nodes.length;
|
|
|
19009 |
while (i--) {
|
|
|
19010 |
const node = nodes[i];
|
|
|
19011 |
if (node.type === 7) {
|
|
|
19012 |
node.remove();
|
|
|
19013 |
} else if (node.type === 1) {
|
|
|
19014 |
if (name === 'input' && !node.attr('type')) {
|
|
|
19015 |
node.attr('type', 'text');
|
|
|
19016 |
}
|
|
|
19017 |
}
|
|
|
19018 |
}
|
|
|
19019 |
});
|
|
|
19020 |
htmlParser.addAttributeFilter('data-mce-type', nodes => {
|
|
|
19021 |
each$e(nodes, node => {
|
|
|
19022 |
if (node.attr('data-mce-type') === 'format-caret') {
|
|
|
19023 |
if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
|
|
|
19024 |
node.remove();
|
|
|
19025 |
} else {
|
|
|
19026 |
node.unwrap();
|
|
|
19027 |
}
|
|
|
19028 |
}
|
|
|
19029 |
});
|
|
|
19030 |
});
|
|
|
19031 |
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) => {
|
|
|
19032 |
let i = nodes.length;
|
|
|
19033 |
while (i--) {
|
|
|
19034 |
nodes[i].attr(name, null);
|
|
|
19035 |
}
|
|
|
19036 |
});
|
|
|
19037 |
if (settings.remove_trailing_brs) {
|
|
|
19038 |
addNodeFilter(settings, htmlParser, htmlParser.schema);
|
|
|
19039 |
}
|
|
|
19040 |
};
|
|
|
19041 |
const trimTrailingBr = rootNode => {
|
|
|
19042 |
const isBr = node => {
|
|
|
19043 |
return (node === null || node === void 0 ? void 0 : node.name) === 'br';
|
|
|
19044 |
};
|
|
|
19045 |
const brNode1 = rootNode.lastChild;
|
|
|
19046 |
if (isBr(brNode1)) {
|
|
|
19047 |
const brNode2 = brNode1.prev;
|
|
|
19048 |
if (isBr(brNode2)) {
|
|
|
19049 |
brNode1.remove();
|
|
|
19050 |
brNode2.remove();
|
|
|
19051 |
}
|
|
|
19052 |
}
|
|
|
19053 |
};
|
|
|
19054 |
|
|
|
19055 |
const preProcess$1 = (editor, node, args) => {
|
|
|
19056 |
let oldDoc;
|
|
|
19057 |
const dom = editor.dom;
|
|
|
19058 |
let clonedNode = node.cloneNode(true);
|
|
|
19059 |
const impl = document.implementation;
|
|
|
19060 |
if (impl.createHTMLDocument) {
|
|
|
19061 |
const doc = impl.createHTMLDocument('');
|
|
|
19062 |
Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => {
|
|
|
19063 |
doc.body.appendChild(doc.importNode(node, true));
|
|
|
19064 |
});
|
|
|
19065 |
if (clonedNode.nodeName !== 'BODY') {
|
|
|
19066 |
clonedNode = doc.body.firstChild;
|
|
|
19067 |
} else {
|
|
|
19068 |
clonedNode = doc.body;
|
|
|
19069 |
}
|
|
|
19070 |
oldDoc = dom.doc;
|
|
|
19071 |
dom.doc = doc;
|
|
|
19072 |
}
|
|
|
19073 |
firePreProcess(editor, {
|
|
|
19074 |
...args,
|
|
|
19075 |
node: clonedNode
|
|
|
19076 |
});
|
|
|
19077 |
if (oldDoc) {
|
|
|
19078 |
dom.doc = oldDoc;
|
|
|
19079 |
}
|
|
|
19080 |
return clonedNode;
|
|
|
19081 |
};
|
|
|
19082 |
const shouldFireEvent = (editor, args) => {
|
|
|
19083 |
return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events;
|
|
|
19084 |
};
|
|
|
19085 |
const process$1 = (editor, node, args) => {
|
|
|
19086 |
return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
|
|
|
19087 |
};
|
|
|
19088 |
|
|
|
19089 |
const addTempAttr = (htmlParser, tempAttrs, name) => {
|
|
|
19090 |
if (Tools.inArray(tempAttrs, name) === -1) {
|
|
|
19091 |
htmlParser.addAttributeFilter(name, (nodes, name) => {
|
|
|
19092 |
let i = nodes.length;
|
|
|
19093 |
while (i--) {
|
|
|
19094 |
nodes[i].attr(name, null);
|
|
|
19095 |
}
|
|
|
19096 |
});
|
|
|
19097 |
tempAttrs.push(name);
|
|
|
19098 |
}
|
|
|
19099 |
};
|
|
|
19100 |
const postProcess = (editor, args, content) => {
|
|
|
19101 |
if (!args.no_events && editor) {
|
|
|
19102 |
const outArgs = firePostProcess(editor, {
|
|
|
19103 |
...args,
|
|
|
19104 |
content
|
|
|
19105 |
});
|
|
|
19106 |
return outArgs.content;
|
|
|
19107 |
} else {
|
|
|
19108 |
return content;
|
|
|
19109 |
}
|
|
|
19110 |
};
|
|
|
19111 |
const getHtmlFromNode = (dom, node, args) => {
|
|
|
19112 |
const html = trim$2(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
|
|
|
19113 |
return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html);
|
|
|
19114 |
};
|
|
|
19115 |
const parseHtml = (htmlParser, html, args) => {
|
|
|
19116 |
const parserArgs = args.selection ? {
|
|
|
19117 |
forced_root_block: false,
|
|
|
19118 |
...args
|
|
|
19119 |
} : args;
|
|
|
19120 |
const rootNode = htmlParser.parse(html, parserArgs);
|
|
|
19121 |
trimTrailingBr(rootNode);
|
|
|
19122 |
return rootNode;
|
|
|
19123 |
};
|
|
|
19124 |
const serializeNode = (settings, schema, node) => {
|
|
|
19125 |
const htmlSerializer = HtmlSerializer(settings, schema);
|
|
|
19126 |
return htmlSerializer.serialize(node);
|
|
|
19127 |
};
|
|
|
19128 |
const toHtml = (editor, settings, schema, rootNode, args) => {
|
|
|
19129 |
const content = serializeNode(settings, schema, rootNode);
|
|
|
19130 |
return postProcess(editor, args, content);
|
|
|
19131 |
};
|
|
|
19132 |
const DomSerializerImpl = (settings, editor) => {
|
|
|
19133 |
const tempAttrs = ['data-mce-selected'];
|
|
|
19134 |
const defaultedSettings = {
|
|
|
19135 |
entity_encoding: 'named',
|
|
|
19136 |
remove_trailing_brs: true,
|
|
|
19137 |
pad_empty_with_br: false,
|
|
|
19138 |
...settings
|
|
|
19139 |
};
|
|
|
19140 |
const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM;
|
|
|
19141 |
const schema = editor && editor.schema ? editor.schema : Schema(defaultedSettings);
|
|
|
19142 |
const htmlParser = DomParser(defaultedSettings, schema);
|
|
|
19143 |
register$3(htmlParser, defaultedSettings, dom);
|
|
|
19144 |
const serialize = (node, parserArgs = {}) => {
|
|
|
19145 |
const args = {
|
|
|
19146 |
format: 'html',
|
|
|
19147 |
...parserArgs
|
|
|
19148 |
};
|
|
|
19149 |
const targetNode = process$1(editor, node, args);
|
|
|
19150 |
const html = getHtmlFromNode(dom, targetNode, args);
|
|
|
19151 |
const rootNode = parseHtml(htmlParser, html, args);
|
|
|
19152 |
return args.format === 'tree' ? rootNode : toHtml(editor, defaultedSettings, schema, rootNode, args);
|
|
|
19153 |
};
|
|
|
19154 |
return {
|
|
|
19155 |
schema,
|
|
|
19156 |
addNodeFilter: htmlParser.addNodeFilter,
|
|
|
19157 |
addAttributeFilter: htmlParser.addAttributeFilter,
|
|
|
19158 |
serialize: serialize,
|
|
|
19159 |
addRules: schema.addValidElements,
|
|
|
19160 |
setRules: schema.setValidElements,
|
|
|
19161 |
addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
|
|
|
19162 |
getTempAttrs: constant(tempAttrs),
|
|
|
19163 |
getNodeFilters: htmlParser.getNodeFilters,
|
|
|
19164 |
getAttributeFilters: htmlParser.getAttributeFilters,
|
|
|
19165 |
removeNodeFilter: htmlParser.removeNodeFilter,
|
|
|
19166 |
removeAttributeFilter: htmlParser.removeAttributeFilter
|
|
|
19167 |
};
|
|
|
19168 |
};
|
|
|
19169 |
|
|
|
19170 |
const DomSerializer = (settings, editor) => {
|
|
|
19171 |
const domSerializer = DomSerializerImpl(settings, editor);
|
|
|
19172 |
return {
|
|
|
19173 |
schema: domSerializer.schema,
|
|
|
19174 |
addNodeFilter: domSerializer.addNodeFilter,
|
|
|
19175 |
addAttributeFilter: domSerializer.addAttributeFilter,
|
|
|
19176 |
serialize: domSerializer.serialize,
|
|
|
19177 |
addRules: domSerializer.addRules,
|
|
|
19178 |
setRules: domSerializer.setRules,
|
|
|
19179 |
addTempAttr: domSerializer.addTempAttr,
|
|
|
19180 |
getTempAttrs: domSerializer.getTempAttrs,
|
|
|
19181 |
getNodeFilters: domSerializer.getNodeFilters,
|
|
|
19182 |
getAttributeFilters: domSerializer.getAttributeFilters,
|
|
|
19183 |
removeNodeFilter: domSerializer.removeNodeFilter,
|
|
|
19184 |
removeAttributeFilter: domSerializer.removeAttributeFilter
|
|
|
19185 |
};
|
|
|
19186 |
};
|
|
|
19187 |
|
|
|
19188 |
const defaultFormat$1 = 'html';
|
|
|
19189 |
const setupArgs$1 = (args, format) => ({
|
|
|
19190 |
...args,
|
|
|
19191 |
format,
|
|
|
19192 |
get: true,
|
|
|
19193 |
getInner: true
|
|
|
19194 |
});
|
|
|
19195 |
const getContent = (editor, args = {}) => {
|
|
|
19196 |
const format = args.format ? args.format : defaultFormat$1;
|
|
|
19197 |
const defaultedArgs = setupArgs$1(args, format);
|
|
|
19198 |
return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
|
|
|
19199 |
const content = getContent$2(editor, updatedArgs);
|
|
|
19200 |
return postProcessGetContent(editor, content, updatedArgs);
|
|
|
19201 |
});
|
|
|
19202 |
};
|
|
|
19203 |
|
|
|
19204 |
const defaultFormat = 'html';
|
|
|
19205 |
const setupArgs = (args, content) => ({
|
|
|
19206 |
format: defaultFormat,
|
|
|
19207 |
...args,
|
|
|
19208 |
set: true,
|
|
|
19209 |
content
|
|
|
19210 |
});
|
|
|
19211 |
const setContent = (editor, content, args = {}) => {
|
|
|
19212 |
const defaultedArgs = setupArgs(args, content);
|
|
|
19213 |
return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => {
|
|
|
19214 |
const result = setContent$2(editor, updatedArgs.content, updatedArgs);
|
|
|
19215 |
postProcessSetContent(editor, result.html, updatedArgs);
|
|
|
19216 |
return result.content;
|
|
|
19217 |
}).getOr(content);
|
|
|
19218 |
};
|
|
|
19219 |
|
| 1441 |
ariadna |
19220 |
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(',');
|
|
|
19221 |
const deprecatedOptions = [];
|
|
|
19222 |
const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,template,textcolor,rtc'.split(',');
|
|
|
19223 |
const deprecatedPlugins = [];
|
| 1 |
efrain |
19224 |
const getMatchingOptions = (options, searchingFor) => {
|
|
|
19225 |
const settingNames = filter$5(searchingFor, setting => has$2(options, setting));
|
|
|
19226 |
return sort(settingNames);
|
|
|
19227 |
};
|
|
|
19228 |
const getRemovedOptions = options => {
|
|
|
19229 |
const settingNames = getMatchingOptions(options, removedOptions);
|
|
|
19230 |
const forcedRootBlock = options.forced_root_block;
|
|
|
19231 |
if (forcedRootBlock === false || forcedRootBlock === '') {
|
|
|
19232 |
settingNames.push('forced_root_block (false only)');
|
|
|
19233 |
}
|
|
|
19234 |
return sort(settingNames);
|
|
|
19235 |
};
|
|
|
19236 |
const getDeprecatedOptions = options => getMatchingOptions(options, deprecatedOptions);
|
|
|
19237 |
const getMatchingPlugins = (options, searchingFor) => {
|
|
|
19238 |
const plugins = Tools.makeMap(options.plugins, ' ');
|
|
|
19239 |
const hasPlugin = plugin => has$2(plugins, plugin);
|
|
|
19240 |
const pluginNames = filter$5(searchingFor, hasPlugin);
|
|
|
19241 |
return sort(pluginNames);
|
|
|
19242 |
};
|
|
|
19243 |
const getRemovedPlugins = options => getMatchingPlugins(options, removedPlugins);
|
|
|
19244 |
const getDeprecatedPlugins = options => getMatchingPlugins(options, deprecatedPlugins.map(entry => entry.name));
|
|
|
19245 |
const logRemovedWarnings = (rawOptions, normalizedOptions) => {
|
|
|
19246 |
const removedOptions = getRemovedOptions(rawOptions);
|
|
|
19247 |
const removedPlugins = getRemovedPlugins(normalizedOptions);
|
|
|
19248 |
const hasRemovedPlugins = removedPlugins.length > 0;
|
|
|
19249 |
const hasRemovedOptions = removedOptions.length > 0;
|
|
|
19250 |
const isLegacyMobileTheme = normalizedOptions.theme === 'mobile';
|
|
|
19251 |
if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
|
|
|
19252 |
const listJoiner = '\n- ';
|
|
|
19253 |
const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : '';
|
|
|
19254 |
const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : '';
|
|
|
19255 |
const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : '';
|
| 1441 |
ariadna |
19256 |
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);
|
| 1 |
efrain |
19257 |
}
|
|
|
19258 |
};
|
|
|
19259 |
const getPluginDescription = name => find$2(deprecatedPlugins, entry => entry.name === name).fold(() => name, entry => {
|
|
|
19260 |
if (entry.replacedWith) {
|
|
|
19261 |
return `${ name }, replaced by ${ entry.replacedWith }`;
|
|
|
19262 |
} else {
|
|
|
19263 |
return name;
|
|
|
19264 |
}
|
|
|
19265 |
});
|
|
|
19266 |
const logDeprecatedWarnings = (rawOptions, normalizedOptions) => {
|
|
|
19267 |
const deprecatedOptions = getDeprecatedOptions(rawOptions);
|
|
|
19268 |
const deprecatedPlugins = getDeprecatedPlugins(normalizedOptions);
|
|
|
19269 |
const hasDeprecatedPlugins = deprecatedPlugins.length > 0;
|
|
|
19270 |
const hasDeprecatedOptions = deprecatedOptions.length > 0;
|
|
|
19271 |
if (hasDeprecatedPlugins || hasDeprecatedOptions) {
|
|
|
19272 |
const listJoiner = '\n- ';
|
|
|
19273 |
const pluginsMessage = hasDeprecatedPlugins ? `\n\nPlugins:${ listJoiner }${ deprecatedPlugins.map(getPluginDescription).join(listJoiner) }` : '';
|
|
|
19274 |
const optionsMessage = hasDeprecatedOptions ? `\n\nOptions:${ listJoiner }${ deprecatedOptions.join(listJoiner) }` : '';
|
|
|
19275 |
console.warn('The following deprecated features are currently enabled but will be removed soon.' + pluginsMessage + optionsMessage);
|
|
|
19276 |
}
|
|
|
19277 |
};
|
|
|
19278 |
const logWarnings = (rawOptions, normalizedOptions) => {
|
|
|
19279 |
logRemovedWarnings(rawOptions, normalizedOptions);
|
|
|
19280 |
logDeprecatedWarnings(rawOptions, normalizedOptions);
|
|
|
19281 |
};
|
|
|
19282 |
|
|
|
19283 |
const DOM$8 = DOMUtils.DOM;
|
|
|
19284 |
const restoreOriginalStyles = editor => {
|
|
|
19285 |
DOM$8.setStyle(editor.id, 'display', editor.orgDisplay);
|
|
|
19286 |
};
|
|
|
19287 |
const safeDestroy = x => Optional.from(x).each(x => x.destroy());
|
|
|
19288 |
const clearDomReferences = editor => {
|
|
|
19289 |
const ed = editor;
|
|
|
19290 |
ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null;
|
|
|
19291 |
ed.bodyElement = ed.contentDocument = ed.contentWindow = null;
|
|
|
19292 |
ed.iframeElement = ed.targetElm = null;
|
|
|
19293 |
const selection = editor.selection;
|
|
|
19294 |
if (selection) {
|
|
|
19295 |
const dom = selection.dom;
|
|
|
19296 |
ed.selection = selection.win = selection.dom = dom.doc = null;
|
|
|
19297 |
}
|
|
|
19298 |
};
|
|
|
19299 |
const restoreForm = editor => {
|
|
|
19300 |
const form = editor.formElement;
|
|
|
19301 |
if (form) {
|
|
|
19302 |
if (form._mceOldSubmit) {
|
|
|
19303 |
form.submit = form._mceOldSubmit;
|
|
|
19304 |
delete form._mceOldSubmit;
|
|
|
19305 |
}
|
|
|
19306 |
DOM$8.unbind(form, 'submit reset', editor.formEventDelegate);
|
|
|
19307 |
}
|
|
|
19308 |
};
|
|
|
19309 |
const remove$1 = editor => {
|
|
|
19310 |
if (!editor.removed) {
|
|
|
19311 |
const {_selectionOverrides, editorUpload} = editor;
|
|
|
19312 |
const body = editor.getBody();
|
|
|
19313 |
const element = editor.getElement();
|
|
|
19314 |
if (body) {
|
|
|
19315 |
editor.save({ is_removing: true });
|
|
|
19316 |
}
|
|
|
19317 |
editor.removed = true;
|
|
|
19318 |
editor.unbindAllNativeEvents();
|
|
|
19319 |
if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) {
|
|
|
19320 |
DOM$8.remove(element.nextSibling);
|
|
|
19321 |
}
|
|
|
19322 |
fireRemove(editor);
|
|
|
19323 |
editor.editorManager.remove(editor);
|
|
|
19324 |
if (!editor.inline && body) {
|
|
|
19325 |
restoreOriginalStyles(editor);
|
|
|
19326 |
}
|
|
|
19327 |
fireDetach(editor);
|
|
|
19328 |
DOM$8.remove(editor.getContainer());
|
|
|
19329 |
safeDestroy(_selectionOverrides);
|
|
|
19330 |
safeDestroy(editorUpload);
|
|
|
19331 |
editor.destroy();
|
|
|
19332 |
}
|
|
|
19333 |
};
|
|
|
19334 |
const destroy = (editor, automatic) => {
|
|
|
19335 |
const {selection, dom} = editor;
|
|
|
19336 |
if (editor.destroyed) {
|
|
|
19337 |
return;
|
|
|
19338 |
}
|
|
|
19339 |
if (!automatic && !editor.removed) {
|
|
|
19340 |
editor.remove();
|
|
|
19341 |
return;
|
|
|
19342 |
}
|
|
|
19343 |
if (!automatic) {
|
|
|
19344 |
editor.editorManager.off('beforeunload', editor._beforeUnload);
|
|
|
19345 |
if (editor.theme && editor.theme.destroy) {
|
|
|
19346 |
editor.theme.destroy();
|
|
|
19347 |
}
|
|
|
19348 |
safeDestroy(selection);
|
|
|
19349 |
safeDestroy(dom);
|
|
|
19350 |
}
|
|
|
19351 |
restoreForm(editor);
|
|
|
19352 |
clearDomReferences(editor);
|
|
|
19353 |
editor.destroyed = true;
|
|
|
19354 |
};
|
|
|
19355 |
|
|
|
19356 |
const CreateIconManager = () => {
|
|
|
19357 |
const lookup = {};
|
|
|
19358 |
const add = (id, iconPack) => {
|
|
|
19359 |
lookup[id] = iconPack;
|
|
|
19360 |
};
|
|
|
19361 |
const get = id => {
|
|
|
19362 |
if (lookup[id]) {
|
|
|
19363 |
return lookup[id];
|
|
|
19364 |
} else {
|
|
|
19365 |
return { icons: {} };
|
|
|
19366 |
}
|
|
|
19367 |
};
|
|
|
19368 |
const has = id => has$2(lookup, id);
|
|
|
19369 |
return {
|
|
|
19370 |
add,
|
|
|
19371 |
get,
|
|
|
19372 |
has
|
|
|
19373 |
};
|
|
|
19374 |
};
|
|
|
19375 |
const IconManager = CreateIconManager();
|
|
|
19376 |
|
|
|
19377 |
const ModelManager = AddOnManager.ModelManager;
|
|
|
19378 |
|
|
|
19379 |
const getProp = (propName, elm) => {
|
|
|
19380 |
const rawElm = elm.dom;
|
|
|
19381 |
return rawElm[propName];
|
|
|
19382 |
};
|
|
|
19383 |
const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
|
|
|
19384 |
const getClientWidth = curry(getProp, 'clientWidth');
|
|
|
19385 |
const getClientHeight = curry(getProp, 'clientHeight');
|
|
|
19386 |
const getMarginTop = curry(getComputedSizeProp, 'margin-top');
|
|
|
19387 |
const getMarginLeft = curry(getComputedSizeProp, 'margin-left');
|
|
|
19388 |
const getBoundingClientRect = elm => elm.dom.getBoundingClientRect();
|
|
|
19389 |
const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
|
|
|
19390 |
const clientWidth = getClientWidth(bodyElm);
|
|
|
19391 |
const clientHeight = getClientHeight(bodyElm);
|
|
|
19392 |
return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
|
|
|
19393 |
};
|
|
|
19394 |
const transpose = (inline, elm, clientX, clientY) => {
|
|
|
19395 |
const clientRect = getBoundingClientRect(elm);
|
|
|
19396 |
const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
|
|
|
19397 |
const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
|
|
|
19398 |
const x = clientX - deltaX;
|
|
|
19399 |
const y = clientY - deltaY;
|
|
|
19400 |
return {
|
|
|
19401 |
x,
|
|
|
19402 |
y
|
|
|
19403 |
};
|
|
|
19404 |
};
|
|
|
19405 |
const isXYInContentArea = (editor, clientX, clientY) => {
|
|
|
19406 |
const bodyElm = SugarElement.fromDom(editor.getBody());
|
|
|
19407 |
const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
|
|
|
19408 |
const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
|
|
|
19409 |
return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
|
|
|
19410 |
};
|
|
|
19411 |
const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom);
|
|
|
19412 |
const isEditorAttachedToDom = editor => {
|
|
|
19413 |
const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
|
|
|
19414 |
return fromDomSafe(rawContainer).map(inBody).getOr(false);
|
|
|
19415 |
};
|
|
|
19416 |
|
|
|
19417 |
var NotificationManagerImpl = () => {
|
|
|
19418 |
const unimplemented = () => {
|
|
|
19419 |
throw new Error('Theme did not provide a NotificationManager implementation.');
|
|
|
19420 |
};
|
|
|
19421 |
return {
|
|
|
19422 |
open: unimplemented,
|
|
|
19423 |
close: unimplemented,
|
|
|
19424 |
getArgs: unimplemented
|
|
|
19425 |
};
|
|
|
19426 |
};
|
|
|
19427 |
|
|
|
19428 |
const NotificationManager = editor => {
|
|
|
19429 |
const notifications = [];
|
|
|
19430 |
const getImplementation = () => {
|
|
|
19431 |
const theme = editor.theme;
|
|
|
19432 |
return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
|
|
|
19433 |
};
|
|
|
19434 |
const getTopNotification = () => {
|
|
|
19435 |
return Optional.from(notifications[0]);
|
|
|
19436 |
};
|
|
|
19437 |
const isEqual = (a, b) => {
|
|
|
19438 |
return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
|
|
|
19439 |
};
|
|
|
19440 |
const reposition = () => {
|
| 1441 |
ariadna |
19441 |
getTopNotification().each(notification => {
|
| 1 |
efrain |
19442 |
notification.reposition();
|
|
|
19443 |
});
|
|
|
19444 |
};
|
|
|
19445 |
const addNotification = notification => {
|
|
|
19446 |
notifications.push(notification);
|
|
|
19447 |
};
|
|
|
19448 |
const closeNotification = notification => {
|
|
|
19449 |
findIndex$2(notifications, otherNotification => {
|
|
|
19450 |
return otherNotification === notification;
|
|
|
19451 |
}).each(index => {
|
|
|
19452 |
notifications.splice(index, 1);
|
|
|
19453 |
});
|
|
|
19454 |
};
|
|
|
19455 |
const open = (spec, fireEvent = true) => {
|
|
|
19456 |
if (editor.removed || !isEditorAttachedToDom(editor)) {
|
|
|
19457 |
return {};
|
|
|
19458 |
}
|
|
|
19459 |
if (fireEvent) {
|
|
|
19460 |
editor.dispatch('BeforeOpenNotification', { notification: spec });
|
|
|
19461 |
}
|
|
|
19462 |
return find$2(notifications, notification => {
|
|
|
19463 |
return isEqual(getImplementation().getArgs(notification), spec);
|
|
|
19464 |
}).getOrThunk(() => {
|
|
|
19465 |
editor.editorManager.setActive(editor);
|
|
|
19466 |
const notification = getImplementation().open(spec, () => {
|
|
|
19467 |
closeNotification(notification);
|
| 1441 |
ariadna |
19468 |
}, () => hasEditorOrUiFocus(editor));
|
| 1 |
efrain |
19469 |
addNotification(notification);
|
|
|
19470 |
reposition();
|
|
|
19471 |
editor.dispatch('OpenNotification', { notification: { ...notification } });
|
|
|
19472 |
return notification;
|
|
|
19473 |
});
|
|
|
19474 |
};
|
|
|
19475 |
const close = () => {
|
|
|
19476 |
getTopNotification().each(notification => {
|
|
|
19477 |
getImplementation().close(notification);
|
|
|
19478 |
closeNotification(notification);
|
|
|
19479 |
reposition();
|
|
|
19480 |
});
|
|
|
19481 |
};
|
|
|
19482 |
const getNotifications = constant(notifications);
|
|
|
19483 |
const registerEvents = editor => {
|
|
|
19484 |
editor.on('SkinLoaded', () => {
|
|
|
19485 |
const serviceMessage = getServiceMessage(editor);
|
|
|
19486 |
if (serviceMessage) {
|
|
|
19487 |
open({
|
|
|
19488 |
text: serviceMessage,
|
|
|
19489 |
type: 'warning',
|
|
|
19490 |
timeout: 0
|
|
|
19491 |
}, false);
|
|
|
19492 |
}
|
|
|
19493 |
reposition();
|
|
|
19494 |
});
|
| 1441 |
ariadna |
19495 |
editor.on('show ResizeEditor ResizeWindow NodeChange ToggleView FullscreenStateChanged', () => {
|
| 1 |
efrain |
19496 |
requestAnimationFrame(reposition);
|
|
|
19497 |
});
|
|
|
19498 |
editor.on('remove', () => {
|
|
|
19499 |
each$e(notifications.slice(), notification => {
|
|
|
19500 |
getImplementation().close(notification);
|
|
|
19501 |
});
|
|
|
19502 |
});
|
| 1441 |
ariadna |
19503 |
editor.on('keydown', e => {
|
|
|
19504 |
var _a;
|
|
|
19505 |
const isF12 = ((_a = e.key) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'f12' || e.keyCode === 123;
|
|
|
19506 |
if (e.altKey && isF12) {
|
|
|
19507 |
e.preventDefault();
|
|
|
19508 |
getTopNotification().map(notificationApi => SugarElement.fromDom(notificationApi.getEl())).each(elm => focus$1(elm));
|
|
|
19509 |
}
|
|
|
19510 |
});
|
| 1 |
efrain |
19511 |
};
|
|
|
19512 |
registerEvents(editor);
|
|
|
19513 |
return {
|
|
|
19514 |
open,
|
|
|
19515 |
close,
|
|
|
19516 |
getNotifications
|
|
|
19517 |
};
|
|
|
19518 |
};
|
|
|
19519 |
|
|
|
19520 |
const PluginManager = AddOnManager.PluginManager;
|
|
|
19521 |
|
|
|
19522 |
const ThemeManager = AddOnManager.ThemeManager;
|
|
|
19523 |
|
|
|
19524 |
var WindowManagerImpl = () => {
|
|
|
19525 |
const unimplemented = () => {
|
|
|
19526 |
throw new Error('Theme did not provide a WindowManager implementation.');
|
|
|
19527 |
};
|
|
|
19528 |
return {
|
|
|
19529 |
open: unimplemented,
|
|
|
19530 |
openUrl: unimplemented,
|
|
|
19531 |
alert: unimplemented,
|
|
|
19532 |
confirm: unimplemented,
|
|
|
19533 |
close: unimplemented
|
|
|
19534 |
};
|
|
|
19535 |
};
|
|
|
19536 |
|
|
|
19537 |
const WindowManager = editor => {
|
|
|
19538 |
let dialogs = [];
|
|
|
19539 |
const getImplementation = () => {
|
|
|
19540 |
const theme = editor.theme;
|
|
|
19541 |
return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
|
|
|
19542 |
};
|
|
|
19543 |
const funcBind = (scope, f) => {
|
|
|
19544 |
return (...args) => {
|
|
|
19545 |
return f ? f.apply(scope, args) : undefined;
|
|
|
19546 |
};
|
|
|
19547 |
};
|
|
|
19548 |
const fireOpenEvent = dialog => {
|
|
|
19549 |
editor.dispatch('OpenWindow', { dialog });
|
|
|
19550 |
};
|
|
|
19551 |
const fireCloseEvent = dialog => {
|
|
|
19552 |
editor.dispatch('CloseWindow', { dialog });
|
|
|
19553 |
};
|
|
|
19554 |
const addDialog = dialog => {
|
|
|
19555 |
dialogs.push(dialog);
|
|
|
19556 |
fireOpenEvent(dialog);
|
|
|
19557 |
};
|
|
|
19558 |
const closeDialog = dialog => {
|
|
|
19559 |
fireCloseEvent(dialog);
|
|
|
19560 |
dialogs = filter$5(dialogs, otherDialog => {
|
|
|
19561 |
return otherDialog !== dialog;
|
|
|
19562 |
});
|
|
|
19563 |
if (dialogs.length === 0) {
|
|
|
19564 |
editor.focus();
|
|
|
19565 |
}
|
|
|
19566 |
};
|
|
|
19567 |
const getTopDialog = () => {
|
|
|
19568 |
return Optional.from(dialogs[dialogs.length - 1]);
|
|
|
19569 |
};
|
|
|
19570 |
const storeSelectionAndOpenDialog = openDialog => {
|
|
|
19571 |
editor.editorManager.setActive(editor);
|
|
|
19572 |
store(editor);
|
|
|
19573 |
editor.ui.show();
|
|
|
19574 |
const dialog = openDialog();
|
|
|
19575 |
addDialog(dialog);
|
|
|
19576 |
return dialog;
|
|
|
19577 |
};
|
|
|
19578 |
const open = (args, params) => {
|
|
|
19579 |
return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
|
|
|
19580 |
};
|
|
|
19581 |
const openUrl = args => {
|
|
|
19582 |
return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
|
|
|
19583 |
};
|
|
|
19584 |
const alert = (message, callback, scope) => {
|
|
|
19585 |
const windowManagerImpl = getImplementation();
|
|
|
19586 |
windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
|
|
|
19587 |
};
|
|
|
19588 |
const confirm = (message, callback, scope) => {
|
|
|
19589 |
const windowManagerImpl = getImplementation();
|
|
|
19590 |
windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
|
|
|
19591 |
};
|
|
|
19592 |
const close = () => {
|
|
|
19593 |
getTopDialog().each(dialog => {
|
|
|
19594 |
getImplementation().close(dialog);
|
|
|
19595 |
closeDialog(dialog);
|
|
|
19596 |
});
|
|
|
19597 |
};
|
|
|
19598 |
editor.on('remove', () => {
|
|
|
19599 |
each$e(dialogs, dialog => {
|
|
|
19600 |
getImplementation().close(dialog);
|
|
|
19601 |
});
|
|
|
19602 |
});
|
|
|
19603 |
return {
|
|
|
19604 |
open,
|
|
|
19605 |
openUrl,
|
|
|
19606 |
alert,
|
|
|
19607 |
confirm,
|
|
|
19608 |
close
|
|
|
19609 |
};
|
|
|
19610 |
};
|
|
|
19611 |
|
|
|
19612 |
const displayNotification = (editor, message) => {
|
|
|
19613 |
editor.notificationManager.open({
|
|
|
19614 |
type: 'error',
|
|
|
19615 |
text: message
|
|
|
19616 |
});
|
|
|
19617 |
};
|
|
|
19618 |
const displayError = (editor, message) => {
|
|
|
19619 |
if (editor._skinLoaded) {
|
|
|
19620 |
displayNotification(editor, message);
|
|
|
19621 |
} else {
|
|
|
19622 |
editor.on('SkinLoaded', () => {
|
|
|
19623 |
displayNotification(editor, message);
|
|
|
19624 |
});
|
|
|
19625 |
}
|
|
|
19626 |
};
|
|
|
19627 |
const uploadError = (editor, message) => {
|
|
|
19628 |
displayError(editor, I18n.translate([
|
|
|
19629 |
'Failed to upload image: {0}',
|
|
|
19630 |
message
|
|
|
19631 |
]));
|
|
|
19632 |
};
|
|
|
19633 |
const logError = (editor, errorType, msg) => {
|
|
|
19634 |
fireError(editor, errorType, { message: msg });
|
|
|
19635 |
console.error(msg);
|
|
|
19636 |
};
|
|
|
19637 |
const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`;
|
|
|
19638 |
const pluginLoadError = (editor, url, name) => {
|
|
|
19639 |
logError(editor, 'PluginLoadError', createLoadError('plugin', url, name));
|
|
|
19640 |
};
|
|
|
19641 |
const iconsLoadError = (editor, url, name) => {
|
|
|
19642 |
logError(editor, 'IconsLoadError', createLoadError('icons', url, name));
|
|
|
19643 |
};
|
|
|
19644 |
const languageLoadError = (editor, url, name) => {
|
|
|
19645 |
logError(editor, 'LanguageLoadError', createLoadError('language', url, name));
|
|
|
19646 |
};
|
|
|
19647 |
const themeLoadError = (editor, url, name) => {
|
|
|
19648 |
logError(editor, 'ThemeLoadError', createLoadError('theme', url, name));
|
|
|
19649 |
};
|
|
|
19650 |
const modelLoadError = (editor, url, name) => {
|
|
|
19651 |
logError(editor, 'ModelLoadError', createLoadError('model', url, name));
|
|
|
19652 |
};
|
|
|
19653 |
const pluginInitError = (editor, name, err) => {
|
|
|
19654 |
const message = I18n.translate([
|
|
|
19655 |
'Failed to initialize plugin: {0}',
|
|
|
19656 |
name
|
|
|
19657 |
]);
|
|
|
19658 |
fireError(editor, 'PluginLoadError', { message });
|
|
|
19659 |
initError(message, err);
|
|
|
19660 |
displayError(editor, message);
|
|
|
19661 |
};
|
|
|
19662 |
const initError = (message, ...x) => {
|
|
|
19663 |
const console = window.console;
|
|
|
19664 |
if (console) {
|
|
|
19665 |
if (console.error) {
|
|
|
19666 |
console.error(message, ...x);
|
|
|
19667 |
} else {
|
|
|
19668 |
console.log(message, ...x);
|
|
|
19669 |
}
|
|
|
19670 |
}
|
|
|
19671 |
};
|
|
|
19672 |
|
| 1441 |
ariadna |
19673 |
const removeFakeSelection = editor => {
|
|
|
19674 |
Optional.from(editor.selection.getNode()).each(elm => {
|
|
|
19675 |
elm.removeAttribute('data-mce-selected');
|
|
|
19676 |
});
|
|
|
19677 |
};
|
|
|
19678 |
const setEditorCommandState = (editor, cmd, state) => {
|
|
|
19679 |
try {
|
|
|
19680 |
editor.getDoc().execCommand(cmd, false, String(state));
|
|
|
19681 |
} catch (_a) {
|
|
|
19682 |
}
|
|
|
19683 |
};
|
|
|
19684 |
const setCommonEditorCommands = (editor, state) => {
|
|
|
19685 |
setEditorCommandState(editor, 'StyleWithCSS', state);
|
|
|
19686 |
setEditorCommandState(editor, 'enableInlineTableEditing', state);
|
|
|
19687 |
setEditorCommandState(editor, 'enableObjectResizing', state);
|
|
|
19688 |
};
|
|
|
19689 |
const restoreFakeSelection = editor => {
|
|
|
19690 |
editor.selection.setRng(editor.selection.getRng());
|
|
|
19691 |
};
|
|
|
19692 |
const toggleClass = (elm, cls, state) => {
|
|
|
19693 |
if (has(elm, cls) && !state) {
|
|
|
19694 |
remove$6(elm, cls);
|
|
|
19695 |
} else if (state) {
|
|
|
19696 |
add$2(elm, cls);
|
|
|
19697 |
}
|
|
|
19698 |
};
|
|
|
19699 |
const disableEditor = editor => {
|
|
|
19700 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
19701 |
toggleClass(body, 'mce-content-readonly', true);
|
|
|
19702 |
editor.selection.controlSelection.hideResizeRect();
|
|
|
19703 |
editor._selectionOverrides.hideFakeCaret();
|
|
|
19704 |
removeFakeSelection(editor);
|
|
|
19705 |
};
|
|
|
19706 |
const enableEditor = editor => {
|
|
|
19707 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
19708 |
toggleClass(body, 'mce-content-readonly', false);
|
|
|
19709 |
if (editor.hasEditableRoot()) {
|
|
|
19710 |
set$3(body, true);
|
|
|
19711 |
}
|
|
|
19712 |
setCommonEditorCommands(editor, false);
|
|
|
19713 |
if (hasEditorOrUiFocus(editor)) {
|
|
|
19714 |
editor.focus();
|
|
|
19715 |
}
|
|
|
19716 |
restoreFakeSelection(editor);
|
|
|
19717 |
editor.nodeChanged();
|
|
|
19718 |
};
|
|
|
19719 |
|
|
|
19720 |
const isDisabled = editor => isDisabled$1(editor);
|
|
|
19721 |
const internalContentEditableAttr = 'data-mce-contenteditable';
|
|
|
19722 |
const switchOffContentEditableTrue = elm => {
|
|
|
19723 |
each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
|
|
|
19724 |
set$4(elm, internalContentEditableAttr, 'true');
|
|
|
19725 |
set$3(elm, false);
|
|
|
19726 |
});
|
|
|
19727 |
};
|
|
|
19728 |
const switchOnContentEditableTrue = elm => {
|
|
|
19729 |
each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
|
|
|
19730 |
remove$9(elm, internalContentEditableAttr);
|
|
|
19731 |
set$3(elm, true);
|
|
|
19732 |
});
|
|
|
19733 |
};
|
|
|
19734 |
const toggleDisabled = (editor, state) => {
|
|
|
19735 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
19736 |
if (state) {
|
|
|
19737 |
disableEditor(editor);
|
|
|
19738 |
set$3(body, false);
|
|
|
19739 |
switchOffContentEditableTrue(body);
|
|
|
19740 |
} else {
|
|
|
19741 |
switchOnContentEditableTrue(body);
|
|
|
19742 |
enableEditor(editor);
|
|
|
19743 |
}
|
|
|
19744 |
};
|
|
|
19745 |
const registerDisabledContentFilters = editor => {
|
|
|
19746 |
if (editor.serializer) {
|
|
|
19747 |
registerFilters(editor);
|
|
|
19748 |
} else {
|
|
|
19749 |
editor.on('PreInit', () => {
|
|
|
19750 |
registerFilters(editor);
|
|
|
19751 |
});
|
|
|
19752 |
}
|
|
|
19753 |
};
|
|
|
19754 |
const registerFilters = editor => {
|
|
|
19755 |
editor.parser.addAttributeFilter('contenteditable', nodes => {
|
|
|
19756 |
if (isDisabled(editor)) {
|
|
|
19757 |
each$e(nodes, node => {
|
|
|
19758 |
node.attr(internalContentEditableAttr, node.attr('contenteditable'));
|
|
|
19759 |
node.attr('contenteditable', 'false');
|
|
|
19760 |
});
|
|
|
19761 |
}
|
|
|
19762 |
});
|
|
|
19763 |
editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
|
|
|
19764 |
if (isDisabled(editor)) {
|
|
|
19765 |
each$e(nodes, node => {
|
|
|
19766 |
node.attr('contenteditable', node.attr(internalContentEditableAttr));
|
|
|
19767 |
});
|
|
|
19768 |
}
|
|
|
19769 |
});
|
|
|
19770 |
editor.serializer.addTempAttr(internalContentEditableAttr);
|
|
|
19771 |
};
|
|
|
19772 |
const isClickEvent = e => e.type === 'click';
|
|
|
19773 |
const allowedEvents = ['copy'];
|
|
|
19774 |
const isAllowedEventInDisabledMode = e => contains$2(allowedEvents, e.type);
|
|
|
19775 |
const getAnchorHrefOpt = (editor, elm) => {
|
|
|
19776 |
const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
|
|
|
19777 |
return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href'));
|
|
|
19778 |
};
|
|
|
19779 |
const processDisabledEvents = (editor, e) => {
|
|
|
19780 |
if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
|
|
|
19781 |
const elm = SugarElement.fromDom(e.target);
|
|
|
19782 |
getAnchorHrefOpt(editor, elm).each(href => {
|
|
|
19783 |
e.preventDefault();
|
|
|
19784 |
if (/^#/.test(href)) {
|
|
|
19785 |
const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`);
|
|
|
19786 |
if (targetEl.length) {
|
|
|
19787 |
editor.selection.scrollIntoView(targetEl[0], true);
|
|
|
19788 |
}
|
|
|
19789 |
} else {
|
|
|
19790 |
window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes');
|
|
|
19791 |
}
|
|
|
19792 |
});
|
|
|
19793 |
} else if (isAllowedEventInDisabledMode(e)) {
|
|
|
19794 |
editor.dispatch(e.type, e);
|
|
|
19795 |
}
|
|
|
19796 |
};
|
|
|
19797 |
const registerDisabledModeEventHandlers = editor => {
|
|
|
19798 |
editor.on('ShowCaret ObjectSelected', e => {
|
|
|
19799 |
if (isDisabled(editor)) {
|
|
|
19800 |
e.preventDefault();
|
|
|
19801 |
}
|
|
|
19802 |
});
|
|
|
19803 |
editor.on('DisabledStateChange', e => {
|
|
|
19804 |
if (!e.isDefaultPrevented()) {
|
|
|
19805 |
toggleDisabled(editor, e.state);
|
|
|
19806 |
}
|
|
|
19807 |
});
|
|
|
19808 |
};
|
|
|
19809 |
const registerEventsAndFilters$1 = editor => {
|
|
|
19810 |
registerDisabledContentFilters(editor);
|
|
|
19811 |
registerDisabledModeEventHandlers(editor);
|
|
|
19812 |
};
|
|
|
19813 |
|
| 1 |
efrain |
19814 |
const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url);
|
|
|
19815 |
const toContentSkinResourceName = url => 'content/' + url + '/content.css';
|
|
|
19816 |
const isBundledCssSkinName = url => tinymce.Resource.has(toContentSkinResourceName(url));
|
|
|
19817 |
const getContentCssUrls = editor => {
|
|
|
19818 |
return transformToUrls(editor, getContentCss(editor));
|
|
|
19819 |
};
|
|
|
19820 |
const getFontCssUrls = editor => {
|
|
|
19821 |
return transformToUrls(editor, getFontCss(editor));
|
|
|
19822 |
};
|
|
|
19823 |
const transformToUrls = (editor, cssLinks) => {
|
|
|
19824 |
const skinUrl = editor.editorManager.baseURL + '/skins/content';
|
|
|
19825 |
const suffix = editor.editorManager.suffix;
|
|
|
19826 |
const contentCssFile = `content${ suffix }.css`;
|
|
|
19827 |
return map$3(cssLinks, url => {
|
|
|
19828 |
if (isBundledCssSkinName(url)) {
|
|
|
19829 |
return url;
|
|
|
19830 |
} else if (isContentCssSkinName(url) && !editor.inline) {
|
|
|
19831 |
return `${ skinUrl }/${ url }/${ contentCssFile }`;
|
|
|
19832 |
} else {
|
|
|
19833 |
return editor.documentBaseURI.toAbsolute(url);
|
|
|
19834 |
}
|
|
|
19835 |
});
|
|
|
19836 |
};
|
|
|
19837 |
const appendContentCssFromSettings = editor => {
|
|
|
19838 |
editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
|
|
|
19839 |
};
|
|
|
19840 |
|
|
|
19841 |
const getAllImages = elm => {
|
|
|
19842 |
return elm ? from(elm.getElementsByTagName('img')) : [];
|
|
|
19843 |
};
|
|
|
19844 |
const ImageScanner = (uploadStatus, blobCache) => {
|
|
|
19845 |
const cachedPromises = {};
|
|
|
19846 |
const findAll = (elm, predicate = always) => {
|
|
|
19847 |
const images = filter$5(getAllImages(elm), img => {
|
|
|
19848 |
const src = img.src;
|
|
|
19849 |
if (img.hasAttribute('data-mce-bogus')) {
|
|
|
19850 |
return false;
|
|
|
19851 |
}
|
|
|
19852 |
if (img.hasAttribute('data-mce-placeholder')) {
|
|
|
19853 |
return false;
|
|
|
19854 |
}
|
|
|
19855 |
if (!src || src === Env.transparentSrc) {
|
|
|
19856 |
return false;
|
|
|
19857 |
}
|
|
|
19858 |
if (startsWith(src, 'blob:')) {
|
|
|
19859 |
return !uploadStatus.isUploaded(src) && predicate(img);
|
|
|
19860 |
}
|
|
|
19861 |
if (startsWith(src, 'data:')) {
|
|
|
19862 |
return predicate(img);
|
|
|
19863 |
}
|
|
|
19864 |
return false;
|
|
|
19865 |
});
|
|
|
19866 |
const promises = map$3(images, img => {
|
|
|
19867 |
const imageSrc = img.src;
|
|
|
19868 |
if (has$2(cachedPromises, imageSrc)) {
|
|
|
19869 |
return cachedPromises[imageSrc].then(imageInfo => {
|
|
|
19870 |
if (isString(imageInfo)) {
|
|
|
19871 |
return imageInfo;
|
|
|
19872 |
} else {
|
|
|
19873 |
return {
|
|
|
19874 |
image: img,
|
|
|
19875 |
blobInfo: imageInfo.blobInfo
|
|
|
19876 |
};
|
|
|
19877 |
}
|
|
|
19878 |
});
|
|
|
19879 |
} else {
|
|
|
19880 |
const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => {
|
|
|
19881 |
delete cachedPromises[imageSrc];
|
|
|
19882 |
return {
|
|
|
19883 |
image: img,
|
|
|
19884 |
blobInfo
|
|
|
19885 |
};
|
|
|
19886 |
}).catch(error => {
|
|
|
19887 |
delete cachedPromises[imageSrc];
|
|
|
19888 |
return error;
|
|
|
19889 |
});
|
|
|
19890 |
cachedPromises[imageSrc] = newPromise;
|
|
|
19891 |
return newPromise;
|
|
|
19892 |
}
|
|
|
19893 |
});
|
|
|
19894 |
return Promise.all(promises);
|
|
|
19895 |
};
|
|
|
19896 |
return { findAll };
|
|
|
19897 |
};
|
|
|
19898 |
|
|
|
19899 |
const UploadStatus = () => {
|
|
|
19900 |
const PENDING = 1, UPLOADED = 2;
|
|
|
19901 |
let blobUriStatuses = {};
|
|
|
19902 |
const createStatus = (status, resultUri) => {
|
|
|
19903 |
return {
|
|
|
19904 |
status,
|
|
|
19905 |
resultUri
|
|
|
19906 |
};
|
|
|
19907 |
};
|
|
|
19908 |
const hasBlobUri = blobUri => {
|
|
|
19909 |
return blobUri in blobUriStatuses;
|
|
|
19910 |
};
|
|
|
19911 |
const getResultUri = blobUri => {
|
|
|
19912 |
const result = blobUriStatuses[blobUri];
|
|
|
19913 |
return result ? result.resultUri : null;
|
|
|
19914 |
};
|
|
|
19915 |
const isPending = blobUri => {
|
|
|
19916 |
return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
|
|
|
19917 |
};
|
|
|
19918 |
const isUploaded = blobUri => {
|
|
|
19919 |
return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
|
|
|
19920 |
};
|
|
|
19921 |
const markPending = blobUri => {
|
|
|
19922 |
blobUriStatuses[blobUri] = createStatus(PENDING, null);
|
|
|
19923 |
};
|
|
|
19924 |
const markUploaded = (blobUri, resultUri) => {
|
|
|
19925 |
blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
|
|
|
19926 |
};
|
|
|
19927 |
const removeFailed = blobUri => {
|
|
|
19928 |
delete blobUriStatuses[blobUri];
|
|
|
19929 |
};
|
|
|
19930 |
const destroy = () => {
|
|
|
19931 |
blobUriStatuses = {};
|
|
|
19932 |
};
|
|
|
19933 |
return {
|
|
|
19934 |
hasBlobUri,
|
|
|
19935 |
getResultUri,
|
|
|
19936 |
isPending,
|
|
|
19937 |
isUploaded,
|
|
|
19938 |
markPending,
|
|
|
19939 |
markUploaded,
|
|
|
19940 |
removeFailed,
|
|
|
19941 |
destroy
|
|
|
19942 |
};
|
|
|
19943 |
};
|
|
|
19944 |
|
|
|
19945 |
let count = 0;
|
|
|
19946 |
const seed = () => {
|
|
|
19947 |
const rnd = () => {
|
| 1441 |
ariadna |
19948 |
return Math.round(random() * 4294967295).toString(36);
|
| 1 |
efrain |
19949 |
};
|
|
|
19950 |
const now = new Date().getTime();
|
|
|
19951 |
return 's' + now.toString(36) + rnd() + rnd() + rnd();
|
|
|
19952 |
};
|
|
|
19953 |
const uuid = prefix => {
|
|
|
19954 |
return prefix + count++ + seed();
|
|
|
19955 |
};
|
|
|
19956 |
|
|
|
19957 |
const BlobCache = () => {
|
|
|
19958 |
let cache = [];
|
|
|
19959 |
const mimeToExt = mime => {
|
|
|
19960 |
const mimes = {
|
|
|
19961 |
'image/jpeg': 'jpg',
|
|
|
19962 |
'image/jpg': 'jpg',
|
|
|
19963 |
'image/gif': 'gif',
|
|
|
19964 |
'image/png': 'png',
|
|
|
19965 |
'image/apng': 'apng',
|
|
|
19966 |
'image/avif': 'avif',
|
|
|
19967 |
'image/svg+xml': 'svg',
|
|
|
19968 |
'image/webp': 'webp',
|
|
|
19969 |
'image/bmp': 'bmp',
|
|
|
19970 |
'image/tiff': 'tiff'
|
|
|
19971 |
};
|
|
|
19972 |
return mimes[mime.toLowerCase()] || 'dat';
|
|
|
19973 |
};
|
|
|
19974 |
const create = (o, blob, base64, name, filename) => {
|
|
|
19975 |
if (isString(o)) {
|
|
|
19976 |
const id = o;
|
|
|
19977 |
return toBlobInfo({
|
|
|
19978 |
id,
|
|
|
19979 |
name,
|
|
|
19980 |
filename,
|
|
|
19981 |
blob: blob,
|
|
|
19982 |
base64: base64
|
|
|
19983 |
});
|
|
|
19984 |
} else if (isObject(o)) {
|
|
|
19985 |
return toBlobInfo(o);
|
|
|
19986 |
} else {
|
|
|
19987 |
throw new Error('Unknown input type');
|
|
|
19988 |
}
|
|
|
19989 |
};
|
|
|
19990 |
const toBlobInfo = o => {
|
|
|
19991 |
if (!o.blob || !o.base64) {
|
|
|
19992 |
throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
|
|
|
19993 |
}
|
|
|
19994 |
const id = o.id || uuid('blobid');
|
|
|
19995 |
const name = o.name || id;
|
|
|
19996 |
const blob = o.blob;
|
|
|
19997 |
return {
|
|
|
19998 |
id: constant(id),
|
|
|
19999 |
name: constant(name),
|
|
|
20000 |
filename: constant(o.filename || name + '.' + mimeToExt(blob.type)),
|
|
|
20001 |
blob: constant(blob),
|
|
|
20002 |
base64: constant(o.base64),
|
|
|
20003 |
blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
|
|
|
20004 |
uri: constant(o.uri)
|
|
|
20005 |
};
|
|
|
20006 |
};
|
|
|
20007 |
const add = blobInfo => {
|
|
|
20008 |
if (!get(blobInfo.id())) {
|
|
|
20009 |
cache.push(blobInfo);
|
|
|
20010 |
}
|
|
|
20011 |
};
|
|
|
20012 |
const findFirst = predicate => find$2(cache, predicate).getOrUndefined();
|
|
|
20013 |
const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id);
|
|
|
20014 |
const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri);
|
|
|
20015 |
const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type);
|
|
|
20016 |
const removeByUri = blobUri => {
|
|
|
20017 |
cache = filter$5(cache, blobInfo => {
|
|
|
20018 |
if (blobInfo.blobUri() === blobUri) {
|
|
|
20019 |
URL.revokeObjectURL(blobInfo.blobUri());
|
|
|
20020 |
return false;
|
|
|
20021 |
}
|
|
|
20022 |
return true;
|
|
|
20023 |
});
|
|
|
20024 |
};
|
|
|
20025 |
const destroy = () => {
|
|
|
20026 |
each$e(cache, cachedBlobInfo => {
|
|
|
20027 |
URL.revokeObjectURL(cachedBlobInfo.blobUri());
|
|
|
20028 |
});
|
|
|
20029 |
cache = [];
|
|
|
20030 |
};
|
|
|
20031 |
return {
|
|
|
20032 |
create,
|
|
|
20033 |
add,
|
|
|
20034 |
get,
|
|
|
20035 |
getByUri,
|
|
|
20036 |
getByData,
|
|
|
20037 |
findFirst,
|
|
|
20038 |
removeByUri,
|
|
|
20039 |
destroy
|
|
|
20040 |
};
|
|
|
20041 |
};
|
|
|
20042 |
|
|
|
20043 |
const Uploader = (uploadStatus, settings) => {
|
|
|
20044 |
const pendingPromises = {};
|
|
|
20045 |
const pathJoin = (path1, path2) => {
|
|
|
20046 |
if (path1) {
|
|
|
20047 |
return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
|
|
|
20048 |
}
|
|
|
20049 |
return path2;
|
|
|
20050 |
};
|
|
|
20051 |
const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
|
|
|
20052 |
const xhr = new XMLHttpRequest();
|
|
|
20053 |
xhr.open('POST', settings.url);
|
|
|
20054 |
xhr.withCredentials = settings.credentials;
|
|
|
20055 |
xhr.upload.onprogress = e => {
|
|
|
20056 |
progress(e.loaded / e.total * 100);
|
|
|
20057 |
};
|
|
|
20058 |
xhr.onerror = () => {
|
|
|
20059 |
failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
|
|
|
20060 |
};
|
|
|
20061 |
xhr.onload = () => {
|
|
|
20062 |
if (xhr.status < 200 || xhr.status >= 300) {
|
|
|
20063 |
failure('HTTP Error: ' + xhr.status);
|
|
|
20064 |
return;
|
|
|
20065 |
}
|
|
|
20066 |
const json = JSON.parse(xhr.responseText);
|
|
|
20067 |
if (!json || !isString(json.location)) {
|
|
|
20068 |
failure('Invalid JSON: ' + xhr.responseText);
|
|
|
20069 |
return;
|
|
|
20070 |
}
|
|
|
20071 |
success(pathJoin(settings.basePath, json.location));
|
|
|
20072 |
};
|
|
|
20073 |
const formData = new FormData();
|
|
|
20074 |
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
|
|
20075 |
xhr.send(formData);
|
|
|
20076 |
});
|
|
|
20077 |
const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler;
|
|
|
20078 |
const noUpload = () => new Promise(resolve => {
|
|
|
20079 |
resolve([]);
|
|
|
20080 |
});
|
|
|
20081 |
const handlerSuccess = (blobInfo, url) => ({
|
|
|
20082 |
url,
|
|
|
20083 |
blobInfo,
|
|
|
20084 |
status: true
|
|
|
20085 |
});
|
|
|
20086 |
const handlerFailure = (blobInfo, error) => ({
|
|
|
20087 |
url: '',
|
|
|
20088 |
blobInfo,
|
|
|
20089 |
status: false,
|
|
|
20090 |
error
|
|
|
20091 |
});
|
|
|
20092 |
const resolvePending = (blobUri, result) => {
|
|
|
20093 |
Tools.each(pendingPromises[blobUri], resolve => {
|
|
|
20094 |
resolve(result);
|
|
|
20095 |
});
|
|
|
20096 |
delete pendingPromises[blobUri];
|
|
|
20097 |
};
|
|
|
20098 |
const uploadBlobInfo = (blobInfo, handler, openNotification) => {
|
|
|
20099 |
uploadStatus.markPending(blobInfo.blobUri());
|
|
|
20100 |
return new Promise(resolve => {
|
|
|
20101 |
let notification;
|
|
|
20102 |
let progress;
|
|
|
20103 |
try {
|
|
|
20104 |
const closeNotification = () => {
|
|
|
20105 |
if (notification) {
|
|
|
20106 |
notification.close();
|
|
|
20107 |
progress = noop;
|
|
|
20108 |
}
|
|
|
20109 |
};
|
|
|
20110 |
const success = url => {
|
|
|
20111 |
closeNotification();
|
|
|
20112 |
uploadStatus.markUploaded(blobInfo.blobUri(), url);
|
|
|
20113 |
resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
|
|
|
20114 |
resolve(handlerSuccess(blobInfo, url));
|
|
|
20115 |
};
|
|
|
20116 |
const failure = error => {
|
|
|
20117 |
closeNotification();
|
|
|
20118 |
uploadStatus.removeFailed(blobInfo.blobUri());
|
|
|
20119 |
resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
|
|
|
20120 |
resolve(handlerFailure(blobInfo, error));
|
|
|
20121 |
};
|
|
|
20122 |
progress = percent => {
|
|
|
20123 |
if (percent < 0 || percent > 100) {
|
|
|
20124 |
return;
|
|
|
20125 |
}
|
|
|
20126 |
Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => {
|
|
|
20127 |
notification = n;
|
|
|
20128 |
n.progressBar.value(percent);
|
|
|
20129 |
});
|
|
|
20130 |
};
|
|
|
20131 |
handler(blobInfo, progress).then(success, err => {
|
|
|
20132 |
failure(isString(err) ? { message: err } : err);
|
|
|
20133 |
});
|
|
|
20134 |
} catch (ex) {
|
|
|
20135 |
resolve(handlerFailure(blobInfo, ex));
|
|
|
20136 |
}
|
|
|
20137 |
});
|
|
|
20138 |
};
|
|
|
20139 |
const isDefaultHandler = handler => handler === defaultHandler;
|
|
|
20140 |
const pendingUploadBlobInfo = blobInfo => {
|
|
|
20141 |
const blobUri = blobInfo.blobUri();
|
|
|
20142 |
return new Promise(resolve => {
|
|
|
20143 |
pendingPromises[blobUri] = pendingPromises[blobUri] || [];
|
|
|
20144 |
pendingPromises[blobUri].push(resolve);
|
|
|
20145 |
});
|
|
|
20146 |
};
|
|
|
20147 |
const uploadBlobs = (blobInfos, openNotification) => {
|
|
|
20148 |
blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri()));
|
|
|
20149 |
return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification)));
|
|
|
20150 |
};
|
|
|
20151 |
const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
|
|
|
20152 |
return { upload };
|
|
|
20153 |
};
|
|
|
20154 |
|
|
|
20155 |
const openNotification = editor => () => editor.notificationManager.open({
|
|
|
20156 |
text: editor.translate('Image uploading...'),
|
|
|
20157 |
type: 'info',
|
|
|
20158 |
timeout: -1,
|
|
|
20159 |
progressBar: true
|
|
|
20160 |
});
|
|
|
20161 |
const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
|
|
|
20162 |
url: getImageUploadUrl(editor),
|
|
|
20163 |
basePath: getImageUploadBasePath(editor),
|
|
|
20164 |
credentials: getImagesUploadCredentials(editor),
|
|
|
20165 |
handler: getImagesUploadHandler(editor)
|
|
|
20166 |
});
|
|
|
20167 |
const ImageUploader = editor => {
|
|
|
20168 |
const uploadStatus = UploadStatus();
|
|
|
20169 |
const uploader = createUploader(editor, uploadStatus);
|
|
|
20170 |
return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) };
|
|
|
20171 |
};
|
|
|
20172 |
|
|
|
20173 |
const isEmptyForPadding = (editor, element) => editor.dom.isEmpty(element.dom) && isNonNullable(editor.schema.getTextBlockElements()[name(element)]);
|
|
|
20174 |
const addPaddingToEmpty = editor => element => {
|
|
|
20175 |
if (isEmptyForPadding(editor, element)) {
|
|
|
20176 |
append$1(element, SugarElement.fromHtml('<br data-mce-bogus="1" />'));
|
|
|
20177 |
}
|
|
|
20178 |
};
|
|
|
20179 |
const EditorUpload = editor => {
|
|
|
20180 |
const blobCache = BlobCache();
|
|
|
20181 |
let uploader, imageScanner;
|
|
|
20182 |
const uploadStatus = UploadStatus();
|
|
|
20183 |
const urlFilters = [];
|
|
|
20184 |
const aliveGuard = callback => {
|
|
|
20185 |
return result => {
|
|
|
20186 |
if (editor.selection) {
|
|
|
20187 |
return callback(result);
|
|
|
20188 |
}
|
|
|
20189 |
return [];
|
|
|
20190 |
};
|
|
|
20191 |
};
|
|
|
20192 |
const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime();
|
|
|
20193 |
const replaceString = (content, search, replace) => {
|
|
|
20194 |
let index = 0;
|
|
|
20195 |
do {
|
|
|
20196 |
index = content.indexOf(search, index);
|
|
|
20197 |
if (index !== -1) {
|
|
|
20198 |
content = content.substring(0, index) + replace + content.substr(index + search.length);
|
|
|
20199 |
index += replace.length - search.length + 1;
|
|
|
20200 |
}
|
|
|
20201 |
} while (index !== -1);
|
|
|
20202 |
return content;
|
|
|
20203 |
};
|
|
|
20204 |
const replaceImageUrl = (content, targetUrl, replacementUrl) => {
|
|
|
20205 |
const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`;
|
|
|
20206 |
content = replaceString(content, `src="${ targetUrl }"`, replacementString);
|
|
|
20207 |
content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
|
|
|
20208 |
return content;
|
|
|
20209 |
};
|
|
|
20210 |
const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
|
|
|
20211 |
each$e(editor.undoManager.data, level => {
|
|
|
20212 |
if (level.type === 'fragmented') {
|
|
|
20213 |
level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl));
|
|
|
20214 |
} else {
|
|
|
20215 |
level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
|
|
|
20216 |
}
|
|
|
20217 |
});
|
|
|
20218 |
};
|
|
|
20219 |
const replaceImageUriInView = (image, resultUri) => {
|
|
|
20220 |
const src = editor.convertURL(resultUri, 'src');
|
|
|
20221 |
replaceUrlInUndoStack(image.src, resultUri);
|
|
|
20222 |
setAll$1(SugarElement.fromDom(image), {
|
|
|
20223 |
'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
|
|
|
20224 |
'data-mce-src': src
|
|
|
20225 |
});
|
|
|
20226 |
};
|
|
|
20227 |
const uploadImages = () => {
|
|
|
20228 |
if (!uploader) {
|
|
|
20229 |
uploader = createUploader(editor, uploadStatus);
|
|
|
20230 |
}
|
|
|
20231 |
return scanForImages().then(aliveGuard(imageInfos => {
|
|
|
20232 |
const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo);
|
|
|
20233 |
return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => {
|
|
|
20234 |
const imagesToRemove = [];
|
|
|
20235 |
let shouldDispatchChange = false;
|
|
|
20236 |
const filteredResult = map$3(result, (uploadInfo, index) => {
|
|
|
20237 |
const {blobInfo, image} = imageInfos[index];
|
|
|
20238 |
let removed = false;
|
|
|
20239 |
if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
|
|
|
20240 |
if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
|
|
|
20241 |
shouldDispatchChange = true;
|
|
|
20242 |
}
|
|
|
20243 |
blobCache.removeByUri(image.src);
|
|
|
20244 |
if (isRtc(editor)) ; else {
|
|
|
20245 |
replaceImageUriInView(image, uploadInfo.url);
|
|
|
20246 |
}
|
|
|
20247 |
} else if (uploadInfo.error) {
|
|
|
20248 |
if (uploadInfo.error.remove) {
|
|
|
20249 |
replaceUrlInUndoStack(image.src, Env.transparentSrc);
|
|
|
20250 |
imagesToRemove.push(image);
|
|
|
20251 |
removed = true;
|
|
|
20252 |
}
|
|
|
20253 |
uploadError(editor, uploadInfo.error.message);
|
|
|
20254 |
}
|
|
|
20255 |
return {
|
|
|
20256 |
element: image,
|
|
|
20257 |
status: uploadInfo.status,
|
|
|
20258 |
uploadUri: uploadInfo.url,
|
|
|
20259 |
blobInfo,
|
|
|
20260 |
removed
|
|
|
20261 |
};
|
|
|
20262 |
});
|
|
|
20263 |
if (imagesToRemove.length > 0 && !isRtc(editor)) {
|
|
|
20264 |
editor.undoManager.transact(() => {
|
|
|
20265 |
each$e(fromDom$1(imagesToRemove), sugarElement => {
|
|
|
20266 |
const parentOpt = parent(sugarElement);
|
| 1441 |
ariadna |
20267 |
remove$4(sugarElement);
|
| 1 |
efrain |
20268 |
parentOpt.each(addPaddingToEmpty(editor));
|
|
|
20269 |
blobCache.removeByUri(sugarElement.dom.src);
|
|
|
20270 |
});
|
|
|
20271 |
});
|
|
|
20272 |
} else if (shouldDispatchChange) {
|
|
|
20273 |
editor.undoManager.dispatchChange();
|
|
|
20274 |
}
|
|
|
20275 |
return filteredResult;
|
|
|
20276 |
}));
|
|
|
20277 |
}));
|
|
|
20278 |
};
|
|
|
20279 |
const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
|
|
|
20280 |
const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm));
|
|
|
20281 |
const addFilter = filter => {
|
|
|
20282 |
urlFilters.push(filter);
|
|
|
20283 |
};
|
|
|
20284 |
const scanForImages = () => {
|
|
|
20285 |
if (!imageScanner) {
|
|
|
20286 |
imageScanner = ImageScanner(uploadStatus, blobCache);
|
|
|
20287 |
}
|
|
|
20288 |
return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => {
|
|
|
20289 |
const filteredResult = filter$5(result, resultItem => {
|
|
|
20290 |
if (isString(resultItem)) {
|
|
|
20291 |
displayError(editor, resultItem);
|
|
|
20292 |
return false;
|
|
|
20293 |
} else if (resultItem.uriType === 'blob') {
|
|
|
20294 |
return false;
|
|
|
20295 |
} else {
|
|
|
20296 |
return true;
|
|
|
20297 |
}
|
|
|
20298 |
});
|
|
|
20299 |
if (isRtc(editor)) ; else {
|
|
|
20300 |
each$e(filteredResult, resultItem => {
|
|
|
20301 |
replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
|
|
|
20302 |
resultItem.image.src = resultItem.blobInfo.blobUri();
|
|
|
20303 |
resultItem.image.removeAttribute('data-mce-src');
|
|
|
20304 |
});
|
|
|
20305 |
}
|
|
|
20306 |
return filteredResult;
|
|
|
20307 |
}));
|
|
|
20308 |
};
|
|
|
20309 |
const destroy = () => {
|
|
|
20310 |
blobCache.destroy();
|
|
|
20311 |
uploadStatus.destroy();
|
|
|
20312 |
imageScanner = uploader = null;
|
|
|
20313 |
};
|
|
|
20314 |
const replaceBlobUris = content => {
|
|
|
20315 |
return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => {
|
|
|
20316 |
const resultUri = uploadStatus.getResultUri(blobUri);
|
|
|
20317 |
if (resultUri) {
|
|
|
20318 |
return 'src="' + resultUri + '"';
|
|
|
20319 |
}
|
|
|
20320 |
let blobInfo = blobCache.getByUri(blobUri);
|
|
|
20321 |
if (!blobInfo) {
|
|
|
20322 |
blobInfo = foldl(editor.editorManager.get(), (result, editor) => {
|
|
|
20323 |
return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
|
|
|
20324 |
}, undefined);
|
|
|
20325 |
}
|
|
|
20326 |
if (blobInfo) {
|
|
|
20327 |
const blob = blobInfo.blob();
|
|
|
20328 |
return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
|
|
|
20329 |
}
|
|
|
20330 |
return match;
|
|
|
20331 |
});
|
|
|
20332 |
};
|
|
|
20333 |
editor.on('SetContent', () => {
|
|
|
20334 |
if (isAutomaticUploadsEnabled(editor)) {
|
|
|
20335 |
uploadImagesAuto();
|
|
|
20336 |
} else {
|
|
|
20337 |
scanForImages();
|
|
|
20338 |
}
|
|
|
20339 |
});
|
|
|
20340 |
editor.on('RawSaveContent', e => {
|
|
|
20341 |
e.content = replaceBlobUris(e.content);
|
|
|
20342 |
});
|
|
|
20343 |
editor.on('GetContent', e => {
|
|
|
20344 |
if (e.source_view || e.format === 'raw' || e.format === 'tree') {
|
|
|
20345 |
return;
|
|
|
20346 |
}
|
|
|
20347 |
e.content = replaceBlobUris(e.content);
|
|
|
20348 |
});
|
|
|
20349 |
editor.on('PostRender', () => {
|
|
|
20350 |
editor.parser.addNodeFilter('img', images => {
|
|
|
20351 |
each$e(images, img => {
|
|
|
20352 |
const src = img.attr('src');
|
|
|
20353 |
if (!src || blobCache.getByUri(src)) {
|
|
|
20354 |
return;
|
|
|
20355 |
}
|
|
|
20356 |
const resultUri = uploadStatus.getResultUri(src);
|
|
|
20357 |
if (resultUri) {
|
|
|
20358 |
img.attr('src', resultUri);
|
|
|
20359 |
}
|
|
|
20360 |
});
|
|
|
20361 |
});
|
|
|
20362 |
});
|
|
|
20363 |
return {
|
|
|
20364 |
blobCache,
|
|
|
20365 |
addFilter,
|
|
|
20366 |
uploadImages,
|
|
|
20367 |
uploadImagesAuto,
|
|
|
20368 |
scanForImages,
|
|
|
20369 |
destroy
|
|
|
20370 |
};
|
|
|
20371 |
};
|
|
|
20372 |
|
|
|
20373 |
const get$1 = editor => {
|
|
|
20374 |
const dom = editor.dom;
|
|
|
20375 |
const schemaType = editor.schema.type;
|
|
|
20376 |
const formats = {
|
|
|
20377 |
valigntop: [{
|
|
|
20378 |
selector: 'td,th',
|
|
|
20379 |
styles: { verticalAlign: 'top' }
|
|
|
20380 |
}],
|
|
|
20381 |
valignmiddle: [{
|
|
|
20382 |
selector: 'td,th',
|
|
|
20383 |
styles: { verticalAlign: 'middle' }
|
|
|
20384 |
}],
|
|
|
20385 |
valignbottom: [{
|
|
|
20386 |
selector: 'td,th',
|
|
|
20387 |
styles: { verticalAlign: 'bottom' }
|
|
|
20388 |
}],
|
|
|
20389 |
alignleft: [
|
|
|
20390 |
{
|
|
|
20391 |
selector: 'figure.image',
|
|
|
20392 |
collapsed: false,
|
|
|
20393 |
classes: 'align-left',
|
|
|
20394 |
ceFalseOverride: true,
|
|
|
20395 |
preview: 'font-family font-size'
|
|
|
20396 |
},
|
|
|
20397 |
{
|
|
|
20398 |
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
|
|
20399 |
styles: { textAlign: 'left' },
|
|
|
20400 |
inherit: false,
|
|
|
20401 |
preview: false
|
|
|
20402 |
},
|
|
|
20403 |
{
|
|
|
20404 |
selector: 'img,audio,video',
|
|
|
20405 |
collapsed: false,
|
|
|
20406 |
styles: { float: 'left' },
|
|
|
20407 |
preview: 'font-family font-size'
|
|
|
20408 |
},
|
|
|
20409 |
{
|
| 1441 |
ariadna |
20410 |
selector: '.mce-placeholder',
|
|
|
20411 |
styles: { float: 'left' },
|
|
|
20412 |
ceFalseOverride: true
|
|
|
20413 |
},
|
|
|
20414 |
{
|
| 1 |
efrain |
20415 |
selector: 'table',
|
|
|
20416 |
collapsed: false,
|
|
|
20417 |
styles: {
|
|
|
20418 |
marginLeft: '0px',
|
|
|
20419 |
marginRight: 'auto'
|
|
|
20420 |
},
|
|
|
20421 |
onformat: table => {
|
|
|
20422 |
dom.setStyle(table, 'float', null);
|
|
|
20423 |
},
|
|
|
20424 |
preview: 'font-family font-size'
|
|
|
20425 |
},
|
|
|
20426 |
{
|
|
|
20427 |
selector: '.mce-preview-object,[data-ephox-embed-iri]',
|
|
|
20428 |
ceFalseOverride: true,
|
|
|
20429 |
styles: { float: 'left' }
|
|
|
20430 |
}
|
|
|
20431 |
],
|
|
|
20432 |
aligncenter: [
|
|
|
20433 |
{
|
|
|
20434 |
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
|
|
20435 |
styles: { textAlign: 'center' },
|
|
|
20436 |
inherit: false,
|
|
|
20437 |
preview: 'font-family font-size'
|
|
|
20438 |
},
|
|
|
20439 |
{
|
|
|
20440 |
selector: 'figure.image',
|
|
|
20441 |
collapsed: false,
|
|
|
20442 |
classes: 'align-center',
|
|
|
20443 |
ceFalseOverride: true,
|
|
|
20444 |
preview: 'font-family font-size'
|
|
|
20445 |
},
|
|
|
20446 |
{
|
|
|
20447 |
selector: 'img,audio,video',
|
|
|
20448 |
collapsed: false,
|
|
|
20449 |
styles: {
|
|
|
20450 |
display: 'block',
|
|
|
20451 |
marginLeft: 'auto',
|
|
|
20452 |
marginRight: 'auto'
|
|
|
20453 |
},
|
|
|
20454 |
preview: false
|
|
|
20455 |
},
|
|
|
20456 |
{
|
| 1441 |
ariadna |
20457 |
selector: '.mce-placeholder',
|
|
|
20458 |
styles: {
|
|
|
20459 |
display: 'block',
|
|
|
20460 |
marginLeft: 'auto',
|
|
|
20461 |
marginRight: 'auto'
|
|
|
20462 |
},
|
|
|
20463 |
ceFalseOverride: true
|
|
|
20464 |
},
|
|
|
20465 |
{
|
| 1 |
efrain |
20466 |
selector: 'table',
|
|
|
20467 |
collapsed: false,
|
|
|
20468 |
styles: {
|
|
|
20469 |
marginLeft: 'auto',
|
|
|
20470 |
marginRight: 'auto'
|
|
|
20471 |
},
|
|
|
20472 |
preview: 'font-family font-size'
|
|
|
20473 |
},
|
|
|
20474 |
{
|
|
|
20475 |
selector: '.mce-preview-object',
|
|
|
20476 |
ceFalseOverride: true,
|
|
|
20477 |
styles: {
|
|
|
20478 |
display: 'table',
|
|
|
20479 |
marginLeft: 'auto',
|
|
|
20480 |
marginRight: 'auto'
|
|
|
20481 |
},
|
|
|
20482 |
preview: false
|
|
|
20483 |
},
|
|
|
20484 |
{
|
|
|
20485 |
selector: '[data-ephox-embed-iri]',
|
|
|
20486 |
ceFalseOverride: true,
|
|
|
20487 |
styles: {
|
|
|
20488 |
marginLeft: 'auto',
|
|
|
20489 |
marginRight: 'auto'
|
|
|
20490 |
},
|
|
|
20491 |
preview: false
|
|
|
20492 |
}
|
|
|
20493 |
],
|
|
|
20494 |
alignright: [
|
|
|
20495 |
{
|
|
|
20496 |
selector: 'figure.image',
|
|
|
20497 |
collapsed: false,
|
|
|
20498 |
classes: 'align-right',
|
|
|
20499 |
ceFalseOverride: true,
|
|
|
20500 |
preview: 'font-family font-size'
|
|
|
20501 |
},
|
|
|
20502 |
{
|
|
|
20503 |
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
|
|
20504 |
styles: { textAlign: 'right' },
|
|
|
20505 |
inherit: false,
|
|
|
20506 |
preview: 'font-family font-size'
|
|
|
20507 |
},
|
|
|
20508 |
{
|
|
|
20509 |
selector: 'img,audio,video',
|
|
|
20510 |
collapsed: false,
|
|
|
20511 |
styles: { float: 'right' },
|
|
|
20512 |
preview: 'font-family font-size'
|
|
|
20513 |
},
|
|
|
20514 |
{
|
| 1441 |
ariadna |
20515 |
selector: '.mce-placeholder',
|
|
|
20516 |
styles: { float: 'right' },
|
|
|
20517 |
ceFalseOverride: true
|
|
|
20518 |
},
|
|
|
20519 |
{
|
| 1 |
efrain |
20520 |
selector: 'table',
|
|
|
20521 |
collapsed: false,
|
|
|
20522 |
styles: {
|
|
|
20523 |
marginRight: '0px',
|
|
|
20524 |
marginLeft: 'auto'
|
|
|
20525 |
},
|
|
|
20526 |
onformat: table => {
|
|
|
20527 |
dom.setStyle(table, 'float', null);
|
|
|
20528 |
},
|
|
|
20529 |
preview: 'font-family font-size'
|
|
|
20530 |
},
|
|
|
20531 |
{
|
|
|
20532 |
selector: '.mce-preview-object,[data-ephox-embed-iri]',
|
|
|
20533 |
ceFalseOverride: true,
|
|
|
20534 |
styles: { float: 'right' },
|
|
|
20535 |
preview: false
|
|
|
20536 |
}
|
|
|
20537 |
],
|
|
|
20538 |
alignjustify: [{
|
|
|
20539 |
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
|
|
|
20540 |
styles: { textAlign: 'justify' },
|
|
|
20541 |
inherit: false,
|
|
|
20542 |
preview: 'font-family font-size'
|
|
|
20543 |
}],
|
|
|
20544 |
bold: [
|
|
|
20545 |
{
|
|
|
20546 |
inline: 'strong',
|
|
|
20547 |
remove: 'all',
|
|
|
20548 |
preserve_attributes: [
|
|
|
20549 |
'class',
|
|
|
20550 |
'style'
|
|
|
20551 |
]
|
|
|
20552 |
},
|
|
|
20553 |
{
|
|
|
20554 |
inline: 'span',
|
|
|
20555 |
styles: { fontWeight: 'bold' }
|
|
|
20556 |
},
|
|
|
20557 |
{
|
|
|
20558 |
inline: 'b',
|
|
|
20559 |
remove: 'all',
|
|
|
20560 |
preserve_attributes: [
|
|
|
20561 |
'class',
|
|
|
20562 |
'style'
|
|
|
20563 |
]
|
|
|
20564 |
}
|
|
|
20565 |
],
|
|
|
20566 |
italic: [
|
|
|
20567 |
{
|
|
|
20568 |
inline: 'em',
|
|
|
20569 |
remove: 'all',
|
|
|
20570 |
preserve_attributes: [
|
|
|
20571 |
'class',
|
|
|
20572 |
'style'
|
|
|
20573 |
]
|
|
|
20574 |
},
|
|
|
20575 |
{
|
|
|
20576 |
inline: 'span',
|
|
|
20577 |
styles: { fontStyle: 'italic' }
|
|
|
20578 |
},
|
|
|
20579 |
{
|
|
|
20580 |
inline: 'i',
|
|
|
20581 |
remove: 'all',
|
|
|
20582 |
preserve_attributes: [
|
|
|
20583 |
'class',
|
|
|
20584 |
'style'
|
|
|
20585 |
]
|
|
|
20586 |
}
|
|
|
20587 |
],
|
|
|
20588 |
underline: [
|
|
|
20589 |
{
|
|
|
20590 |
inline: 'span',
|
|
|
20591 |
styles: { textDecoration: 'underline' },
|
|
|
20592 |
exact: true
|
|
|
20593 |
},
|
|
|
20594 |
{
|
|
|
20595 |
inline: 'u',
|
|
|
20596 |
remove: 'all',
|
|
|
20597 |
preserve_attributes: [
|
|
|
20598 |
'class',
|
|
|
20599 |
'style'
|
|
|
20600 |
]
|
|
|
20601 |
}
|
|
|
20602 |
],
|
|
|
20603 |
strikethrough: (() => {
|
|
|
20604 |
const span = {
|
|
|
20605 |
inline: 'span',
|
|
|
20606 |
styles: { textDecoration: 'line-through' },
|
|
|
20607 |
exact: true
|
|
|
20608 |
};
|
|
|
20609 |
const strike = {
|
|
|
20610 |
inline: 'strike',
|
|
|
20611 |
remove: 'all',
|
|
|
20612 |
preserve_attributes: [
|
|
|
20613 |
'class',
|
|
|
20614 |
'style'
|
|
|
20615 |
]
|
|
|
20616 |
};
|
|
|
20617 |
const s = {
|
|
|
20618 |
inline: 's',
|
|
|
20619 |
remove: 'all',
|
|
|
20620 |
preserve_attributes: [
|
|
|
20621 |
'class',
|
|
|
20622 |
'style'
|
|
|
20623 |
]
|
|
|
20624 |
};
|
|
|
20625 |
return schemaType !== 'html4' ? [
|
|
|
20626 |
s,
|
|
|
20627 |
span,
|
|
|
20628 |
strike
|
|
|
20629 |
] : [
|
|
|
20630 |
span,
|
|
|
20631 |
s,
|
|
|
20632 |
strike
|
|
|
20633 |
];
|
|
|
20634 |
})(),
|
|
|
20635 |
forecolor: {
|
|
|
20636 |
inline: 'span',
|
|
|
20637 |
styles: { color: '%value' },
|
|
|
20638 |
links: true,
|
|
|
20639 |
remove_similar: true,
|
|
|
20640 |
clear_child_styles: true
|
|
|
20641 |
},
|
|
|
20642 |
hilitecolor: {
|
|
|
20643 |
inline: 'span',
|
|
|
20644 |
styles: { backgroundColor: '%value' },
|
|
|
20645 |
links: true,
|
|
|
20646 |
remove_similar: true,
|
|
|
20647 |
clear_child_styles: true
|
|
|
20648 |
},
|
|
|
20649 |
fontname: {
|
|
|
20650 |
inline: 'span',
|
|
|
20651 |
toggle: false,
|
|
|
20652 |
styles: { fontFamily: '%value' },
|
|
|
20653 |
clear_child_styles: true
|
|
|
20654 |
},
|
|
|
20655 |
fontsize: {
|
|
|
20656 |
inline: 'span',
|
|
|
20657 |
toggle: false,
|
|
|
20658 |
styles: { fontSize: '%value' },
|
|
|
20659 |
clear_child_styles: true
|
|
|
20660 |
},
|
|
|
20661 |
lineheight: {
|
|
|
20662 |
selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div',
|
|
|
20663 |
styles: { lineHeight: '%value' }
|
|
|
20664 |
},
|
|
|
20665 |
fontsize_class: {
|
|
|
20666 |
inline: 'span',
|
|
|
20667 |
attributes: { class: '%value' }
|
|
|
20668 |
},
|
|
|
20669 |
blockquote: {
|
|
|
20670 |
block: 'blockquote',
|
|
|
20671 |
wrapper: true,
|
|
|
20672 |
remove: 'all'
|
|
|
20673 |
},
|
|
|
20674 |
subscript: { inline: 'sub' },
|
|
|
20675 |
superscript: { inline: 'sup' },
|
|
|
20676 |
code: { inline: 'code' },
|
| 1441 |
ariadna |
20677 |
samp: { inline: 'samp' },
|
| 1 |
efrain |
20678 |
link: {
|
|
|
20679 |
inline: 'a',
|
|
|
20680 |
selector: 'a',
|
|
|
20681 |
remove: 'all',
|
|
|
20682 |
split: true,
|
|
|
20683 |
deep: true,
|
|
|
20684 |
onmatch: (node, _fmt, _itemName) => {
|
|
|
20685 |
return isElement$6(node) && node.hasAttribute('href');
|
|
|
20686 |
},
|
|
|
20687 |
onformat: (elm, _fmt, vars) => {
|
|
|
20688 |
Tools.each(vars, (value, key) => {
|
|
|
20689 |
dom.setAttrib(elm, key, value);
|
|
|
20690 |
});
|
|
|
20691 |
}
|
|
|
20692 |
},
|
|
|
20693 |
lang: {
|
|
|
20694 |
inline: 'span',
|
|
|
20695 |
clear_child_styles: true,
|
|
|
20696 |
remove_similar: true,
|
|
|
20697 |
attributes: {
|
|
|
20698 |
'lang': '%value',
|
|
|
20699 |
'data-mce-lang': vars => {
|
|
|
20700 |
var _a;
|
|
|
20701 |
return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
|
|
|
20702 |
}
|
|
|
20703 |
}
|
|
|
20704 |
},
|
|
|
20705 |
removeformat: [
|
|
|
20706 |
{
|
|
|
20707 |
selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small',
|
|
|
20708 |
remove: 'all',
|
|
|
20709 |
split: true,
|
|
|
20710 |
expand: false,
|
|
|
20711 |
block_expand: true,
|
|
|
20712 |
deep: true
|
|
|
20713 |
},
|
|
|
20714 |
{
|
|
|
20715 |
selector: 'span',
|
|
|
20716 |
attributes: [
|
|
|
20717 |
'style',
|
|
|
20718 |
'class'
|
|
|
20719 |
],
|
|
|
20720 |
remove: 'empty',
|
|
|
20721 |
split: true,
|
|
|
20722 |
expand: false,
|
|
|
20723 |
deep: true
|
|
|
20724 |
},
|
|
|
20725 |
{
|
|
|
20726 |
selector: '*',
|
|
|
20727 |
attributes: [
|
|
|
20728 |
'style',
|
|
|
20729 |
'class'
|
|
|
20730 |
],
|
|
|
20731 |
split: false,
|
|
|
20732 |
expand: false,
|
|
|
20733 |
deep: true
|
|
|
20734 |
}
|
|
|
20735 |
]
|
|
|
20736 |
};
|
| 1441 |
ariadna |
20737 |
Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd'.split(/\s/), name => {
|
| 1 |
efrain |
20738 |
formats[name] = {
|
|
|
20739 |
block: name,
|
|
|
20740 |
remove: 'all'
|
|
|
20741 |
};
|
|
|
20742 |
});
|
|
|
20743 |
return formats;
|
|
|
20744 |
};
|
|
|
20745 |
|
|
|
20746 |
const genericBase = {
|
|
|
20747 |
remove_similar: true,
|
|
|
20748 |
inherit: false
|
|
|
20749 |
};
|
|
|
20750 |
const cellBase = {
|
|
|
20751 |
selector: 'td,th',
|
|
|
20752 |
...genericBase
|
|
|
20753 |
};
|
|
|
20754 |
const cellFormats = {
|
|
|
20755 |
tablecellbackgroundcolor: {
|
|
|
20756 |
styles: { backgroundColor: '%value' },
|
|
|
20757 |
...cellBase
|
|
|
20758 |
},
|
|
|
20759 |
tablecellverticalalign: {
|
|
|
20760 |
styles: { 'vertical-align': '%value' },
|
|
|
20761 |
...cellBase
|
|
|
20762 |
},
|
|
|
20763 |
tablecellbordercolor: {
|
|
|
20764 |
styles: { borderColor: '%value' },
|
|
|
20765 |
...cellBase
|
|
|
20766 |
},
|
|
|
20767 |
tablecellclass: {
|
|
|
20768 |
classes: ['%value'],
|
|
|
20769 |
...cellBase
|
|
|
20770 |
},
|
|
|
20771 |
tableclass: {
|
|
|
20772 |
selector: 'table',
|
|
|
20773 |
classes: ['%value'],
|
|
|
20774 |
...genericBase
|
|
|
20775 |
},
|
|
|
20776 |
tablecellborderstyle: {
|
|
|
20777 |
styles: { borderStyle: '%value' },
|
|
|
20778 |
...cellBase
|
|
|
20779 |
},
|
|
|
20780 |
tablecellborderwidth: {
|
|
|
20781 |
styles: { borderWidth: '%value' },
|
|
|
20782 |
...cellBase
|
|
|
20783 |
}
|
|
|
20784 |
};
|
|
|
20785 |
const get = constant(cellFormats);
|
|
|
20786 |
|
|
|
20787 |
const FormatRegistry = editor => {
|
|
|
20788 |
const formats = {};
|
|
|
20789 |
const get$2 = name => isNonNullable(name) ? formats[name] : formats;
|
|
|
20790 |
const has = name => has$2(formats, name);
|
|
|
20791 |
const register = (name, format) => {
|
|
|
20792 |
if (name) {
|
|
|
20793 |
if (!isString(name)) {
|
|
|
20794 |
each$d(name, (format, name) => {
|
|
|
20795 |
register(name, format);
|
|
|
20796 |
});
|
|
|
20797 |
} else {
|
|
|
20798 |
if (!isArray$1(format)) {
|
|
|
20799 |
format = [format];
|
|
|
20800 |
}
|
|
|
20801 |
each$e(format, format => {
|
|
|
20802 |
if (isUndefined(format.deep)) {
|
|
|
20803 |
format.deep = !isSelectorFormat(format);
|
|
|
20804 |
}
|
|
|
20805 |
if (isUndefined(format.split)) {
|
|
|
20806 |
format.split = !isSelectorFormat(format) || isInlineFormat(format);
|
|
|
20807 |
}
|
|
|
20808 |
if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) {
|
|
|
20809 |
format.remove = 'none';
|
|
|
20810 |
}
|
|
|
20811 |
if (isSelectorFormat(format) && isInlineFormat(format)) {
|
|
|
20812 |
format.mixed = true;
|
|
|
20813 |
format.block_expand = true;
|
|
|
20814 |
}
|
|
|
20815 |
if (isString(format.classes)) {
|
|
|
20816 |
format.classes = format.classes.split(/\s+/);
|
|
|
20817 |
}
|
|
|
20818 |
});
|
|
|
20819 |
formats[name] = format;
|
|
|
20820 |
}
|
|
|
20821 |
}
|
|
|
20822 |
};
|
|
|
20823 |
const unregister = name => {
|
|
|
20824 |
if (name && formats[name]) {
|
|
|
20825 |
delete formats[name];
|
|
|
20826 |
}
|
|
|
20827 |
return formats;
|
|
|
20828 |
};
|
|
|
20829 |
register(get$1(editor));
|
|
|
20830 |
register(get());
|
|
|
20831 |
register(getFormats(editor));
|
|
|
20832 |
return {
|
|
|
20833 |
get: get$2,
|
|
|
20834 |
has,
|
|
|
20835 |
register,
|
|
|
20836 |
unregister
|
|
|
20837 |
};
|
|
|
20838 |
};
|
|
|
20839 |
|
|
|
20840 |
const each$3 = Tools.each;
|
|
|
20841 |
const dom = DOMUtils.DOM;
|
|
|
20842 |
const isPreviewItem = item => isNonNullable(item) && isObject(item);
|
|
|
20843 |
const parsedSelectorToHtml = (ancestry, editor) => {
|
|
|
20844 |
const schema = editor && editor.schema || Schema({});
|
|
|
20845 |
const decorate = (elm, item) => {
|
|
|
20846 |
if (item.classes.length > 0) {
|
|
|
20847 |
dom.addClass(elm, item.classes.join(' '));
|
|
|
20848 |
}
|
|
|
20849 |
dom.setAttribs(elm, item.attrs);
|
|
|
20850 |
};
|
|
|
20851 |
const createElement = sItem => {
|
|
|
20852 |
const item = isString(sItem) ? {
|
|
|
20853 |
name: sItem,
|
|
|
20854 |
classes: [],
|
|
|
20855 |
attrs: {}
|
|
|
20856 |
} : sItem;
|
|
|
20857 |
const elm = dom.create(item.name);
|
|
|
20858 |
decorate(elm, item);
|
|
|
20859 |
return elm;
|
|
|
20860 |
};
|
|
|
20861 |
const getRequiredParent = (elm, candidate) => {
|
|
|
20862 |
const elmRule = schema.getElementRule(elm.nodeName.toLowerCase());
|
|
|
20863 |
const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired;
|
|
|
20864 |
if (parentsRequired && parentsRequired.length) {
|
|
|
20865 |
return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0];
|
|
|
20866 |
} else {
|
|
|
20867 |
return false;
|
|
|
20868 |
}
|
|
|
20869 |
};
|
|
|
20870 |
const wrapInHtml = (elm, ancestors, siblings) => {
|
|
|
20871 |
let parentCandidate;
|
|
|
20872 |
const ancestor = ancestors[0];
|
|
|
20873 |
const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined;
|
|
|
20874 |
const parentRequired = getRequiredParent(elm, ancestorName);
|
|
|
20875 |
if (parentRequired) {
|
|
|
20876 |
if (ancestorName === parentRequired) {
|
|
|
20877 |
parentCandidate = ancestor;
|
|
|
20878 |
ancestors = ancestors.slice(1);
|
|
|
20879 |
} else {
|
|
|
20880 |
parentCandidate = parentRequired;
|
|
|
20881 |
}
|
|
|
20882 |
} else if (ancestor) {
|
|
|
20883 |
parentCandidate = ancestor;
|
|
|
20884 |
ancestors = ancestors.slice(1);
|
|
|
20885 |
} else if (!siblings) {
|
|
|
20886 |
return elm;
|
|
|
20887 |
}
|
|
|
20888 |
const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div');
|
|
|
20889 |
parent.appendChild(elm);
|
|
|
20890 |
if (siblings) {
|
|
|
20891 |
Tools.each(siblings, sibling => {
|
|
|
20892 |
const siblingElm = createElement(sibling);
|
|
|
20893 |
parent.insertBefore(siblingElm, elm);
|
|
|
20894 |
});
|
|
|
20895 |
}
|
|
|
20896 |
const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined;
|
|
|
20897 |
return wrapInHtml(parent, ancestors, parentSiblings);
|
|
|
20898 |
};
|
|
|
20899 |
const fragment = dom.create('div');
|
|
|
20900 |
if (ancestry.length > 0) {
|
|
|
20901 |
const item = ancestry[0];
|
|
|
20902 |
const elm = createElement(item);
|
|
|
20903 |
const siblings = isPreviewItem(item) ? item.siblings : undefined;
|
|
|
20904 |
fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings));
|
|
|
20905 |
}
|
|
|
20906 |
return fragment;
|
|
|
20907 |
};
|
|
|
20908 |
const parseSelectorItem = item => {
|
|
|
20909 |
item = Tools.trim(item);
|
|
|
20910 |
let tagName = 'div';
|
|
|
20911 |
const obj = {
|
|
|
20912 |
name: tagName,
|
|
|
20913 |
classes: [],
|
|
|
20914 |
attrs: {},
|
|
|
20915 |
selector: item
|
|
|
20916 |
};
|
|
|
20917 |
if (item !== '*') {
|
|
|
20918 |
tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
|
|
|
20919 |
switch ($1) {
|
|
|
20920 |
case '#':
|
|
|
20921 |
obj.attrs.id = $2;
|
|
|
20922 |
break;
|
|
|
20923 |
case '.':
|
|
|
20924 |
obj.classes.push($2);
|
|
|
20925 |
break;
|
|
|
20926 |
case ':':
|
|
|
20927 |
if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
|
|
|
20928 |
obj.attrs[$2] = $2;
|
|
|
20929 |
}
|
|
|
20930 |
break;
|
|
|
20931 |
}
|
|
|
20932 |
if ($3 === '[') {
|
|
|
20933 |
const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
|
|
|
20934 |
if (m) {
|
|
|
20935 |
obj.attrs[m[1]] = m[2];
|
|
|
20936 |
}
|
|
|
20937 |
}
|
|
|
20938 |
return '';
|
|
|
20939 |
});
|
|
|
20940 |
}
|
|
|
20941 |
obj.name = tagName || 'div';
|
|
|
20942 |
return obj;
|
|
|
20943 |
};
|
|
|
20944 |
const parseSelector = selector => {
|
|
|
20945 |
if (!isString(selector)) {
|
|
|
20946 |
return [];
|
|
|
20947 |
}
|
|
|
20948 |
selector = selector.split(/\s*,\s*/)[0];
|
|
|
20949 |
selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
|
|
|
20950 |
return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => {
|
|
|
20951 |
const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
|
|
|
20952 |
const obj = siblings.pop();
|
|
|
20953 |
if (siblings.length) {
|
|
|
20954 |
obj.siblings = siblings;
|
|
|
20955 |
}
|
|
|
20956 |
return obj;
|
|
|
20957 |
}).reverse();
|
|
|
20958 |
};
|
|
|
20959 |
const getCssText = (editor, format) => {
|
|
|
20960 |
let previewCss = '';
|
|
|
20961 |
let previewStyles = getPreviewStyles(editor);
|
|
|
20962 |
if (previewStyles === '') {
|
|
|
20963 |
return '';
|
|
|
20964 |
}
|
|
|
20965 |
const removeVars = val => {
|
|
|
20966 |
return isString(val) ? val.replace(/%(\w+)/g, '') : '';
|
|
|
20967 |
};
|
|
|
20968 |
const getComputedStyle = (name, elm) => {
|
|
|
20969 |
return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true);
|
|
|
20970 |
};
|
|
|
20971 |
if (isString(format)) {
|
|
|
20972 |
const formats = editor.formatter.get(format);
|
|
|
20973 |
if (!formats) {
|
|
|
20974 |
return '';
|
|
|
20975 |
}
|
|
|
20976 |
format = formats[0];
|
|
|
20977 |
}
|
|
|
20978 |
if ('preview' in format) {
|
|
|
20979 |
const preview = format.preview;
|
|
|
20980 |
if (preview === false) {
|
|
|
20981 |
return '';
|
|
|
20982 |
} else {
|
|
|
20983 |
previewStyles = preview || previewStyles;
|
|
|
20984 |
}
|
|
|
20985 |
}
|
|
|
20986 |
let name = format.block || format.inline || 'span';
|
|
|
20987 |
let previewFrag;
|
|
|
20988 |
const items = parseSelector(format.selector);
|
|
|
20989 |
if (items.length > 0) {
|
|
|
20990 |
if (!items[0].name) {
|
|
|
20991 |
items[0].name = name;
|
|
|
20992 |
}
|
|
|
20993 |
name = format.selector;
|
|
|
20994 |
previewFrag = parsedSelectorToHtml(items, editor);
|
|
|
20995 |
} else {
|
|
|
20996 |
previewFrag = parsedSelectorToHtml([name], editor);
|
|
|
20997 |
}
|
|
|
20998 |
const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
|
|
|
20999 |
each$3(format.styles, (value, name) => {
|
|
|
21000 |
const newValue = removeVars(value);
|
|
|
21001 |
if (newValue) {
|
|
|
21002 |
dom.setStyle(previewElm, name, newValue);
|
|
|
21003 |
}
|
|
|
21004 |
});
|
|
|
21005 |
each$3(format.attributes, (value, name) => {
|
|
|
21006 |
const newValue = removeVars(value);
|
|
|
21007 |
if (newValue) {
|
|
|
21008 |
dom.setAttrib(previewElm, name, newValue);
|
|
|
21009 |
}
|
|
|
21010 |
});
|
|
|
21011 |
each$3(format.classes, value => {
|
|
|
21012 |
const newValue = removeVars(value);
|
|
|
21013 |
if (!dom.hasClass(previewElm, newValue)) {
|
|
|
21014 |
dom.addClass(previewElm, newValue);
|
|
|
21015 |
}
|
|
|
21016 |
});
|
|
|
21017 |
editor.dispatch('PreviewFormats');
|
|
|
21018 |
dom.setStyles(previewFrag, {
|
|
|
21019 |
position: 'absolute',
|
|
|
21020 |
left: -65535
|
|
|
21021 |
});
|
|
|
21022 |
editor.getBody().appendChild(previewFrag);
|
|
|
21023 |
const rawParentFontSize = getComputedStyle('fontSize');
|
|
|
21024 |
const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0;
|
|
|
21025 |
each$3(previewStyles.split(' '), name => {
|
|
|
21026 |
let value = getComputedStyle(name, previewElm);
|
|
|
21027 |
if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
|
|
|
21028 |
value = getComputedStyle(name);
|
|
|
21029 |
if (rgbaToHexString(value).toLowerCase() === '#ffffff') {
|
|
|
21030 |
return;
|
|
|
21031 |
}
|
|
|
21032 |
}
|
|
|
21033 |
if (name === 'color') {
|
|
|
21034 |
if (rgbaToHexString(value).toLowerCase() === '#000000') {
|
|
|
21035 |
return;
|
|
|
21036 |
}
|
|
|
21037 |
}
|
|
|
21038 |
if (name === 'font-size') {
|
|
|
21039 |
if (/em|%$/.test(value)) {
|
|
|
21040 |
if (parentFontSize === 0) {
|
|
|
21041 |
return;
|
|
|
21042 |
}
|
|
|
21043 |
const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
|
|
|
21044 |
value = numValue * parentFontSize + 'px';
|
|
|
21045 |
}
|
|
|
21046 |
}
|
|
|
21047 |
if (name === 'border' && value) {
|
|
|
21048 |
previewCss += 'padding:0 2px;';
|
|
|
21049 |
}
|
|
|
21050 |
previewCss += name + ':' + value + ';';
|
|
|
21051 |
});
|
|
|
21052 |
editor.dispatch('AfterPreviewFormats');
|
|
|
21053 |
dom.remove(previewFrag);
|
|
|
21054 |
return previewCss;
|
|
|
21055 |
};
|
|
|
21056 |
|
|
|
21057 |
const setup$s = editor => {
|
|
|
21058 |
editor.addShortcut('meta+b', '', 'Bold');
|
|
|
21059 |
editor.addShortcut('meta+i', '', 'Italic');
|
|
|
21060 |
editor.addShortcut('meta+u', '', 'Underline');
|
|
|
21061 |
for (let i = 1; i <= 6; i++) {
|
|
|
21062 |
editor.addShortcut('access+' + i, '', [
|
|
|
21063 |
'FormatBlock',
|
|
|
21064 |
false,
|
|
|
21065 |
'h' + i
|
|
|
21066 |
]);
|
|
|
21067 |
}
|
|
|
21068 |
editor.addShortcut('access+7', '', [
|
|
|
21069 |
'FormatBlock',
|
|
|
21070 |
false,
|
|
|
21071 |
'p'
|
|
|
21072 |
]);
|
|
|
21073 |
editor.addShortcut('access+8', '', [
|
|
|
21074 |
'FormatBlock',
|
|
|
21075 |
false,
|
|
|
21076 |
'div'
|
|
|
21077 |
]);
|
|
|
21078 |
editor.addShortcut('access+9', '', [
|
|
|
21079 |
'FormatBlock',
|
|
|
21080 |
false,
|
|
|
21081 |
'address'
|
|
|
21082 |
]);
|
|
|
21083 |
};
|
|
|
21084 |
|
|
|
21085 |
const Formatter = editor => {
|
|
|
21086 |
const formats = FormatRegistry(editor);
|
|
|
21087 |
const formatChangeState = Cell({});
|
|
|
21088 |
setup$s(editor);
|
|
|
21089 |
setup$v(editor);
|
|
|
21090 |
if (!isRtc(editor)) {
|
|
|
21091 |
setup$u(formatChangeState, editor);
|
|
|
21092 |
}
|
|
|
21093 |
return {
|
|
|
21094 |
get: formats.get,
|
|
|
21095 |
has: formats.has,
|
|
|
21096 |
register: formats.register,
|
|
|
21097 |
unregister: formats.unregister,
|
|
|
21098 |
apply: (name, vars, node) => {
|
|
|
21099 |
applyFormat(editor, name, vars, node);
|
|
|
21100 |
},
|
|
|
21101 |
remove: (name, vars, node, similar) => {
|
|
|
21102 |
removeFormat(editor, name, vars, node, similar);
|
|
|
21103 |
},
|
|
|
21104 |
toggle: (name, vars, node) => {
|
|
|
21105 |
toggleFormat(editor, name, vars, node);
|
|
|
21106 |
},
|
|
|
21107 |
match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar),
|
|
|
21108 |
closest: names => closestFormat(editor, names),
|
|
|
21109 |
matchAll: (names, vars) => matchAllFormats(editor, names, vars),
|
|
|
21110 |
matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar),
|
|
|
21111 |
canApply: name => canApplyFormat(editor, name),
|
|
|
21112 |
formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars),
|
|
|
21113 |
getCssText: curry(getCssText, editor)
|
|
|
21114 |
};
|
|
|
21115 |
};
|
|
|
21116 |
|
|
|
21117 |
const shouldIgnoreCommand = cmd => {
|
|
|
21118 |
switch (cmd.toLowerCase()) {
|
|
|
21119 |
case 'undo':
|
|
|
21120 |
case 'redo':
|
|
|
21121 |
case 'mcefocus':
|
|
|
21122 |
return true;
|
|
|
21123 |
default:
|
|
|
21124 |
return false;
|
|
|
21125 |
}
|
|
|
21126 |
};
|
|
|
21127 |
const registerEvents = (editor, undoManager, locks) => {
|
|
|
21128 |
const isFirstTypedCharacter = Cell(false);
|
|
|
21129 |
const addNonTypingUndoLevel = e => {
|
|
|
21130 |
setTyping(undoManager, false, locks);
|
|
|
21131 |
undoManager.add({}, e);
|
|
|
21132 |
};
|
|
|
21133 |
editor.on('init', () => {
|
|
|
21134 |
undoManager.add();
|
|
|
21135 |
});
|
|
|
21136 |
editor.on('BeforeExecCommand', e => {
|
|
|
21137 |
const cmd = e.command;
|
|
|
21138 |
if (!shouldIgnoreCommand(cmd)) {
|
|
|
21139 |
endTyping(undoManager, locks);
|
|
|
21140 |
undoManager.beforeChange();
|
|
|
21141 |
}
|
|
|
21142 |
});
|
|
|
21143 |
editor.on('ExecCommand', e => {
|
|
|
21144 |
const cmd = e.command;
|
|
|
21145 |
if (!shouldIgnoreCommand(cmd)) {
|
|
|
21146 |
addNonTypingUndoLevel(e);
|
|
|
21147 |
}
|
|
|
21148 |
});
|
|
|
21149 |
editor.on('ObjectResizeStart cut', () => {
|
|
|
21150 |
undoManager.beforeChange();
|
|
|
21151 |
});
|
|
|
21152 |
editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
|
|
|
21153 |
editor.on('dragend', addNonTypingUndoLevel);
|
|
|
21154 |
editor.on('keyup', e => {
|
|
|
21155 |
const keyCode = e.keyCode;
|
|
|
21156 |
if (e.isDefaultPrevented()) {
|
|
|
21157 |
return;
|
|
|
21158 |
}
|
|
|
21159 |
const isMeta = Env.os.isMacOS() && e.key === 'Meta';
|
|
|
21160 |
if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey || isMeta) {
|
|
|
21161 |
addNonTypingUndoLevel();
|
|
|
21162 |
editor.nodeChanged();
|
|
|
21163 |
}
|
|
|
21164 |
if (keyCode === 46 || keyCode === 8) {
|
|
|
21165 |
editor.nodeChanged();
|
|
|
21166 |
}
|
|
|
21167 |
if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
|
|
|
21168 |
if (!editor.isDirty()) {
|
|
|
21169 |
editor.setDirty(true);
|
|
|
21170 |
}
|
|
|
21171 |
editor.dispatch('TypingUndo');
|
|
|
21172 |
isFirstTypedCharacter.set(false);
|
|
|
21173 |
editor.nodeChanged();
|
|
|
21174 |
}
|
|
|
21175 |
});
|
|
|
21176 |
editor.on('keydown', e => {
|
|
|
21177 |
const keyCode = e.keyCode;
|
|
|
21178 |
if (e.isDefaultPrevented()) {
|
|
|
21179 |
return;
|
|
|
21180 |
}
|
|
|
21181 |
if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
|
|
|
21182 |
if (undoManager.typing) {
|
|
|
21183 |
addNonTypingUndoLevel(e);
|
|
|
21184 |
}
|
|
|
21185 |
return;
|
|
|
21186 |
}
|
|
|
21187 |
const modKey = e.ctrlKey && !e.altKey || e.metaKey;
|
|
|
21188 |
if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
|
|
|
21189 |
undoManager.beforeChange();
|
|
|
21190 |
setTyping(undoManager, true, locks);
|
|
|
21191 |
undoManager.add({}, e);
|
|
|
21192 |
isFirstTypedCharacter.set(true);
|
|
|
21193 |
return;
|
|
|
21194 |
}
|
|
|
21195 |
const hasOnlyMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey;
|
|
|
21196 |
if (hasOnlyMetaOrCtrlModifier) {
|
|
|
21197 |
undoManager.beforeChange();
|
|
|
21198 |
}
|
|
|
21199 |
});
|
|
|
21200 |
editor.on('mousedown', e => {
|
|
|
21201 |
if (undoManager.typing) {
|
|
|
21202 |
addNonTypingUndoLevel(e);
|
|
|
21203 |
}
|
|
|
21204 |
});
|
|
|
21205 |
const isInsertReplacementText = event => event.inputType === 'insertReplacementText';
|
|
|
21206 |
const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null;
|
|
|
21207 |
const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop';
|
|
|
21208 |
editor.on('input', e => {
|
|
|
21209 |
if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
|
|
|
21210 |
addNonTypingUndoLevel(e);
|
|
|
21211 |
}
|
|
|
21212 |
});
|
|
|
21213 |
editor.on('AddUndo Undo Redo ClearUndos', e => {
|
|
|
21214 |
if (!e.isDefaultPrevented()) {
|
|
|
21215 |
editor.nodeChanged();
|
|
|
21216 |
}
|
|
|
21217 |
});
|
|
|
21218 |
};
|
|
|
21219 |
const addKeyboardShortcuts = editor => {
|
|
|
21220 |
editor.addShortcut('meta+z', '', 'Undo');
|
|
|
21221 |
editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
|
|
|
21222 |
};
|
|
|
21223 |
|
|
|
21224 |
const UndoManager = editor => {
|
|
|
21225 |
const beforeBookmark = value$2();
|
|
|
21226 |
const locks = Cell(0);
|
|
|
21227 |
const index = Cell(0);
|
|
|
21228 |
const undoManager = {
|
|
|
21229 |
data: [],
|
|
|
21230 |
typing: false,
|
|
|
21231 |
beforeChange: () => {
|
|
|
21232 |
beforeChange(editor, locks, beforeBookmark);
|
|
|
21233 |
},
|
|
|
21234 |
add: (level, event) => {
|
|
|
21235 |
return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
|
|
|
21236 |
},
|
|
|
21237 |
dispatchChange: () => {
|
|
|
21238 |
editor.setDirty(true);
|
|
|
21239 |
const level = createFromEditor(editor);
|
|
|
21240 |
level.bookmark = getUndoBookmark(editor.selection);
|
|
|
21241 |
editor.dispatch('change', {
|
|
|
21242 |
level,
|
|
|
21243 |
lastLevel: get$b(undoManager.data, index.get()).getOrUndefined()
|
|
|
21244 |
});
|
|
|
21245 |
},
|
|
|
21246 |
undo: () => {
|
|
|
21247 |
return undo(editor, undoManager, locks, index);
|
|
|
21248 |
},
|
|
|
21249 |
redo: () => {
|
|
|
21250 |
return redo(editor, index, undoManager.data);
|
|
|
21251 |
},
|
|
|
21252 |
clear: () => {
|
|
|
21253 |
clear(editor, undoManager, index);
|
|
|
21254 |
},
|
|
|
21255 |
reset: () => {
|
|
|
21256 |
reset(editor, undoManager);
|
|
|
21257 |
},
|
|
|
21258 |
hasUndo: () => {
|
|
|
21259 |
return hasUndo(editor, undoManager, index);
|
|
|
21260 |
},
|
|
|
21261 |
hasRedo: () => {
|
|
|
21262 |
return hasRedo(editor, undoManager, index);
|
|
|
21263 |
},
|
|
|
21264 |
transact: callback => {
|
|
|
21265 |
return transact(editor, undoManager, locks, callback);
|
|
|
21266 |
},
|
|
|
21267 |
ignore: callback => {
|
|
|
21268 |
ignore(editor, locks, callback);
|
|
|
21269 |
},
|
|
|
21270 |
extra: (callback1, callback2) => {
|
|
|
21271 |
extra(editor, undoManager, index, callback1, callback2);
|
|
|
21272 |
}
|
|
|
21273 |
};
|
|
|
21274 |
if (!isRtc(editor)) {
|
|
|
21275 |
registerEvents(editor, undoManager, locks);
|
|
|
21276 |
}
|
|
|
21277 |
addKeyboardShortcuts(editor);
|
|
|
21278 |
return undoManager;
|
|
|
21279 |
};
|
|
|
21280 |
|
|
|
21281 |
const nonTypingKeycodes = [
|
|
|
21282 |
9,
|
|
|
21283 |
27,
|
|
|
21284 |
VK.HOME,
|
|
|
21285 |
VK.END,
|
|
|
21286 |
19,
|
|
|
21287 |
20,
|
|
|
21288 |
44,
|
|
|
21289 |
144,
|
|
|
21290 |
145,
|
|
|
21291 |
33,
|
|
|
21292 |
34,
|
|
|
21293 |
45,
|
|
|
21294 |
16,
|
|
|
21295 |
17,
|
|
|
21296 |
18,
|
|
|
21297 |
91,
|
|
|
21298 |
92,
|
|
|
21299 |
93,
|
|
|
21300 |
VK.DOWN,
|
|
|
21301 |
VK.UP,
|
|
|
21302 |
VK.LEFT,
|
|
|
21303 |
VK.RIGHT
|
|
|
21304 |
].concat(Env.browser.isFirefox() ? [224] : []);
|
|
|
21305 |
const placeholderAttr = 'data-mce-placeholder';
|
|
|
21306 |
const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup';
|
|
|
21307 |
const isDeleteEvent = e => {
|
|
|
21308 |
const keyCode = e.keyCode;
|
|
|
21309 |
return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
|
|
|
21310 |
};
|
|
|
21311 |
const isNonTypingKeyboardEvent = e => {
|
|
|
21312 |
if (isKeyboardEvent(e)) {
|
|
|
21313 |
const keyCode = e.keyCode;
|
|
|
21314 |
return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
|
|
|
21315 |
} else {
|
|
|
21316 |
return false;
|
|
|
21317 |
}
|
|
|
21318 |
};
|
|
|
21319 |
const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229);
|
|
|
21320 |
const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => {
|
| 1441 |
ariadna |
21321 |
if (dom.isEmpty(rootElm, undefined, {
|
|
|
21322 |
skipBogus: false,
|
|
|
21323 |
includeZwsp: true
|
|
|
21324 |
})) {
|
| 1 |
efrain |
21325 |
const firstElement = rootElm.firstElementChild;
|
|
|
21326 |
if (!firstElement) {
|
|
|
21327 |
return true;
|
|
|
21328 |
} else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) {
|
|
|
21329 |
return false;
|
|
|
21330 |
} else {
|
|
|
21331 |
return forcedRootBlock === firstElement.nodeName.toLowerCase();
|
|
|
21332 |
}
|
|
|
21333 |
} else {
|
|
|
21334 |
return false;
|
|
|
21335 |
}
|
|
|
21336 |
};
|
|
|
21337 |
const setup$r = editor => {
|
|
|
21338 |
var _a;
|
|
|
21339 |
const dom = editor.dom;
|
|
|
21340 |
const rootBlock = getForcedRootBlock(editor);
|
|
|
21341 |
const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : '';
|
|
|
21342 |
const updatePlaceholder = (e, initial) => {
|
|
|
21343 |
if (isNonTypingKeyboardEvent(e)) {
|
|
|
21344 |
return;
|
|
|
21345 |
}
|
|
|
21346 |
const body = editor.getBody();
|
|
|
21347 |
const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock);
|
|
|
21348 |
const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== '';
|
|
|
21349 |
if (isPlaceholderShown !== showPlaceholder || initial) {
|
|
|
21350 |
dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
|
|
|
21351 |
firePlaceholderToggle(editor, showPlaceholder);
|
|
|
21352 |
editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder);
|
|
|
21353 |
editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder);
|
|
|
21354 |
}
|
|
|
21355 |
};
|
|
|
21356 |
if (isNotEmpty(placeholder)) {
|
|
|
21357 |
editor.on('init', e => {
|
|
|
21358 |
updatePlaceholder(e, true);
|
|
|
21359 |
editor.on('change SetContent ExecCommand', updatePlaceholder);
|
|
|
21360 |
editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e)));
|
|
|
21361 |
});
|
|
|
21362 |
}
|
|
|
21363 |
};
|
|
|
21364 |
|
|
|
21365 |
const blockPosition = (block, position) => ({
|
|
|
21366 |
block,
|
|
|
21367 |
position
|
|
|
21368 |
});
|
|
|
21369 |
const blockBoundary = (from, to) => ({
|
|
|
21370 |
from,
|
|
|
21371 |
to
|
|
|
21372 |
});
|
|
|
21373 |
const getBlockPosition = (rootNode, pos) => {
|
|
|
21374 |
const rootElm = SugarElement.fromDom(rootNode);
|
|
|
21375 |
const containerElm = SugarElement.fromDom(pos.container());
|
|
|
21376 |
return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos));
|
|
|
21377 |
};
|
| 1441 |
ariadna |
21378 |
const isNotAncestorial = blockBoundary => !(contains(blockBoundary.to.block, blockBoundary.from.block) || contains(blockBoundary.from.block, blockBoundary.to.block));
|
| 1 |
efrain |
21379 |
const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block);
|
|
|
21380 |
const getClosestHost = (root, scope) => {
|
|
|
21381 |
const isRoot = node => eq(node, root);
|
|
|
21382 |
const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
|
|
|
21383 |
return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root);
|
|
|
21384 |
};
|
|
|
21385 |
const hasSameHost = (rootNode, blockBoundary) => {
|
|
|
21386 |
const root = SugarElement.fromDom(rootNode);
|
|
|
21387 |
return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block));
|
|
|
21388 |
};
|
|
|
21389 |
const isEditable$1 = blockBoundary => isContentEditableFalse$b(blockBoundary.from.block.dom) === false && isContentEditableFalse$b(blockBoundary.to.block.dom) === false;
|
|
|
21390 |
const hasValidBlocks = blockBoundary => {
|
| 1441 |
ariadna |
21391 |
const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom) || isListItem$1(block);
|
| 1 |
efrain |
21392 |
return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block);
|
|
|
21393 |
};
|
| 1441 |
ariadna |
21394 |
const skipLastBr = (schema, rootNode, forward, blockPosition) => {
|
|
|
21395 |
if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(schema, blockPosition.block)) {
|
| 1 |
efrain |
21396 |
return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => {
|
|
|
21397 |
if (lastPositionInBlock.isEqual(blockPosition.position)) {
|
|
|
21398 |
return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to));
|
|
|
21399 |
} else {
|
|
|
21400 |
return Optional.some(blockPosition);
|
|
|
21401 |
}
|
|
|
21402 |
}).getOr(blockPosition);
|
|
|
21403 |
} else {
|
|
|
21404 |
return blockPosition;
|
|
|
21405 |
}
|
|
|
21406 |
};
|
| 1441 |
ariadna |
21407 |
const readFromRange = (schema, rootNode, forward, rng) => {
|
| 1 |
efrain |
21408 |
const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
|
| 1441 |
ariadna |
21409 |
const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(schema, rootNode, forward, blockPos))));
|
|
|
21410 |
return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$1(blockBoundary) && hasValidBlocks(blockBoundary) && isNotAncestorial(blockBoundary));
|
| 1 |
efrain |
21411 |
};
|
| 1441 |
ariadna |
21412 |
const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
|
| 1 |
efrain |
21413 |
|
|
|
21414 |
const getChildrenUntilBlockBoundary = (block, schema) => {
|
|
|
21415 |
const children = children$1(block);
|
|
|
21416 |
return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
|
|
|
21417 |
};
|
|
|
21418 |
const extractChildren = (block, schema) => {
|
|
|
21419 |
const children = getChildrenUntilBlockBoundary(block, schema);
|
| 1441 |
ariadna |
21420 |
each$e(children, remove$4);
|
| 1 |
efrain |
21421 |
return children;
|
|
|
21422 |
};
|
| 1441 |
ariadna |
21423 |
const removeEmptyRoot = (schema, rootNode, block) => {
|
| 1 |
efrain |
21424 |
const parents = parentsAndSelf(block, rootNode);
|
| 1441 |
ariadna |
21425 |
return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4);
|
| 1 |
efrain |
21426 |
};
|
| 1441 |
ariadna |
21427 |
const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0;
|
| 1 |
efrain |
21428 |
const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => {
|
| 1441 |
ariadna |
21429 |
if (isEmpty$2(schema, toBlock)) {
|
| 1 |
efrain |
21430 |
fillWithPaddingBr(toBlock);
|
|
|
21431 |
return firstPositionIn(toBlock.dom);
|
|
|
21432 |
}
|
| 1441 |
ariadna |
21433 |
if (isEmptyBefore(schema, insertionPoint) && isEmpty$2(schema, fromBlock)) {
|
| 1 |
efrain |
21434 |
before$3(insertionPoint, SugarElement.fromTag('br'));
|
|
|
21435 |
}
|
|
|
21436 |
const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
|
|
|
21437 |
each$e(extractChildren(fromBlock, schema), child => {
|
|
|
21438 |
before$3(insertionPoint, child);
|
|
|
21439 |
});
|
| 1441 |
ariadna |
21440 |
removeEmptyRoot(schema, rootNode, fromBlock);
|
| 1 |
efrain |
21441 |
return position;
|
|
|
21442 |
};
|
|
|
21443 |
const isInline = (schema, node) => schema.isInline(name(node));
|
|
|
21444 |
const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => {
|
| 1441 |
ariadna |
21445 |
if (isEmpty$2(schema, toBlock)) {
|
|
|
21446 |
if (isEmpty$2(schema, fromBlock)) {
|
| 1 |
efrain |
21447 |
const getInlineToBlockDescendants = el => {
|
|
|
21448 |
const helper = (node, elements) => firstChild(node).fold(() => elements, child => isInline(schema, child) ? helper(child, elements.concat(shallow$1(child))) : elements);
|
|
|
21449 |
return helper(el, []);
|
|
|
21450 |
};
|
|
|
21451 |
const newFromBlockDescendants = foldr(getInlineToBlockDescendants(toBlock), (element, descendant) => {
|
|
|
21452 |
wrap$2(element, descendant);
|
|
|
21453 |
return descendant;
|
|
|
21454 |
}, createPaddingBr());
|
|
|
21455 |
empty(fromBlock);
|
|
|
21456 |
append$1(fromBlock, newFromBlockDescendants);
|
|
|
21457 |
}
|
| 1441 |
ariadna |
21458 |
remove$4(toBlock);
|
| 1 |
efrain |
21459 |
return firstPositionIn(fromBlock.dom);
|
|
|
21460 |
}
|
|
|
21461 |
const position = lastPositionIn(toBlock.dom);
|
|
|
21462 |
each$e(extractChildren(fromBlock, schema), child => {
|
|
|
21463 |
append$1(toBlock, child);
|
|
|
21464 |
});
|
| 1441 |
ariadna |
21465 |
removeEmptyRoot(schema, rootNode, fromBlock);
|
| 1 |
efrain |
21466 |
return position;
|
|
|
21467 |
};
|
|
|
21468 |
const findInsertionPoint = (toBlock, block) => {
|
|
|
21469 |
const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
|
|
|
21470 |
return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
|
|
|
21471 |
};
|
|
|
21472 |
const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
|
|
|
21473 |
const trimBr = (first, block) => {
|
| 1441 |
ariadna |
21474 |
positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4);
|
| 1 |
efrain |
21475 |
};
|
|
|
21476 |
const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => {
|
|
|
21477 |
trimBr(true, fromBlock);
|
|
|
21478 |
trimBr(false, toBlock);
|
|
|
21479 |
return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema));
|
|
|
21480 |
};
|
|
|
21481 |
const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema);
|
|
|
21482 |
|
| 1441 |
ariadna |
21483 |
const backspaceDelete$a = (editor, forward) => {
|
| 1 |
efrain |
21484 |
const rootNode = SugarElement.fromDom(editor.getBody());
|
| 1441 |
ariadna |
21485 |
const position = read$1(editor.schema, rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
|
| 1 |
efrain |
21486 |
mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => {
|
|
|
21487 |
editor.selection.setRng(pos.toRange());
|
|
|
21488 |
});
|
|
|
21489 |
});
|
|
|
21490 |
return position;
|
|
|
21491 |
};
|
|
|
21492 |
|
|
|
21493 |
const deleteRangeMergeBlocks = (rootNode, selection, schema) => {
|
|
|
21494 |
const rng = selection.getRng();
|
|
|
21495 |
return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
|
|
|
21496 |
if (!eq(block1, block2)) {
|
|
|
21497 |
return Optional.some(() => {
|
|
|
21498 |
rng.deleteContents();
|
|
|
21499 |
mergeBlocks(rootNode, true, block1, block2, schema).each(pos => {
|
|
|
21500 |
selection.setRng(pos.toRange());
|
|
|
21501 |
});
|
|
|
21502 |
});
|
|
|
21503 |
} else {
|
|
|
21504 |
return Optional.none();
|
|
|
21505 |
}
|
|
|
21506 |
}).getOr(Optional.none());
|
|
|
21507 |
};
|
|
|
21508 |
const isRawNodeInTable = (root, rawNode) => {
|
|
|
21509 |
const node = SugarElement.fromDom(rawNode);
|
|
|
21510 |
const isRoot = curry(eq, root);
|
|
|
21511 |
return ancestor$4(node, isTableCell$2, isRoot).isSome();
|
|
|
21512 |
};
|
|
|
21513 |
const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
|
|
|
21514 |
const isEverythingSelected = (root, rng) => {
|
|
|
21515 |
const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
|
|
|
21516 |
const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
|
|
|
21517 |
return !isSelectionInTable(root, rng) && noPrevious && noNext;
|
|
|
21518 |
};
|
|
|
21519 |
const emptyEditor = editor => {
|
|
|
21520 |
return Optional.some(() => {
|
|
|
21521 |
editor.setContent('');
|
|
|
21522 |
editor.selection.setCursorLocation();
|
|
|
21523 |
});
|
|
|
21524 |
};
|
|
|
21525 |
const deleteRange$2 = editor => {
|
|
|
21526 |
const rootNode = SugarElement.fromDom(editor.getBody());
|
|
|
21527 |
const rng = editor.selection.getRng();
|
|
|
21528 |
return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection, editor.schema);
|
|
|
21529 |
};
|
| 1441 |
ariadna |
21530 |
const backspaceDelete$9 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$2(editor);
|
| 1 |
efrain |
21531 |
|
|
|
21532 |
const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView));
|
|
|
21533 |
const getNodeRange = node => {
|
|
|
21534 |
const rng = node.ownerDocument.createRange();
|
|
|
21535 |
rng.selectNode(node);
|
|
|
21536 |
return rng;
|
|
|
21537 |
};
|
|
|
21538 |
const selectNode = (editor, node) => {
|
|
|
21539 |
const e = editor.dispatch('BeforeObjectSelected', { target: node });
|
|
|
21540 |
if (e.isDefaultPrevented()) {
|
|
|
21541 |
return Optional.none();
|
|
|
21542 |
}
|
|
|
21543 |
return Optional.some(getNodeRange(node));
|
|
|
21544 |
};
|
|
|
21545 |
const renderCaretAtRange = (editor, range, scrollIntoView) => {
|
|
|
21546 |
const normalizedRange = normalizeRange(1, editor.getBody(), range);
|
|
|
21547 |
const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
|
|
|
21548 |
const caretPositionNode = caretPosition.getNode();
|
|
|
21549 |
if (isInlineFakeCaretTarget(caretPositionNode)) {
|
|
|
21550 |
return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
|
|
|
21551 |
}
|
|
|
21552 |
const caretPositionBeforeNode = caretPosition.getNode(true);
|
|
|
21553 |
if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
|
|
|
21554 |
return showCaret(1, editor, caretPositionBeforeNode, false, false);
|
|
|
21555 |
}
|
|
|
21556 |
const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode());
|
|
|
21557 |
if (isInlineFakeCaretTarget(ceRoot)) {
|
|
|
21558 |
return showCaret(1, editor, ceRoot, false, scrollIntoView);
|
|
|
21559 |
}
|
|
|
21560 |
return Optional.none();
|
|
|
21561 |
};
|
|
|
21562 |
const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range;
|
|
|
21563 |
|
|
|
21564 |
const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
|
|
|
21565 |
const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
|
|
|
21566 |
const trimEmptyTextNode = (dom, node) => {
|
| 1441 |
ariadna |
21567 |
if (isText$b(node) && node.data.length === 0) {
|
| 1 |
efrain |
21568 |
dom.remove(node);
|
|
|
21569 |
}
|
|
|
21570 |
};
|
|
|
21571 |
const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => {
|
|
|
21572 |
showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => {
|
|
|
21573 |
if (range.collapsed) {
|
|
|
21574 |
const deleteRange = range.cloneRange();
|
|
|
21575 |
if (forward) {
|
|
|
21576 |
deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
|
|
|
21577 |
} else {
|
|
|
21578 |
deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
|
|
|
21579 |
}
|
|
|
21580 |
deleteRange.deleteContents();
|
|
|
21581 |
} else {
|
|
|
21582 |
range.deleteContents();
|
|
|
21583 |
}
|
|
|
21584 |
editor.selection.setRng(caretRange);
|
|
|
21585 |
});
|
|
|
21586 |
trimEmptyTextNode(editor.dom, node);
|
|
|
21587 |
};
|
|
|
21588 |
const deleteBoundaryText = (editor, forward) => {
|
|
|
21589 |
const range = editor.selection.getRng();
|
| 1441 |
ariadna |
21590 |
if (!isText$b(range.commonAncestorContainer)) {
|
| 1 |
efrain |
21591 |
return Optional.none();
|
|
|
21592 |
}
|
| 1441 |
ariadna |
21593 |
const direction = forward ? 1 : -1;
|
| 1 |
efrain |
21594 |
const caretWalker = CaretWalker(editor.getBody());
|
|
|
21595 |
const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
|
|
|
21596 |
const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
|
|
|
21597 |
const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
|
|
21598 |
const nextCaretPosition = getNextPosFn(caretPosition);
|
|
|
21599 |
const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition;
|
|
|
21600 |
if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) {
|
|
|
21601 |
return Optional.none();
|
|
|
21602 |
} else if (isBeforeFn(normalizedNextCaretPosition)) {
|
|
|
21603 |
return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition));
|
|
|
21604 |
}
|
|
|
21605 |
const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition);
|
|
|
21606 |
if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
|
|
|
21607 |
if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) {
|
|
|
21608 |
return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition));
|
|
|
21609 |
}
|
|
|
21610 |
}
|
|
|
21611 |
return Optional.none();
|
|
|
21612 |
};
|
| 1441 |
ariadna |
21613 |
const backspaceDelete$8 = (editor, forward) => deleteBoundaryText(editor, forward);
|
| 1 |
efrain |
21614 |
|
|
|
21615 |
const getEdgeCefPosition = (editor, atStart) => {
|
|
|
21616 |
const root = editor.getBody();
|
|
|
21617 |
return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
|
|
|
21618 |
};
|
|
|
21619 |
const isCefAtEdgeSelected = editor => {
|
|
|
21620 |
const rng = editor.selection.getRng();
|
|
|
21621 |
return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
|
|
|
21622 |
};
|
|
|
21623 |
|
|
|
21624 |
const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node)));
|
|
|
21625 |
const DeleteAction = Adt.generate([
|
|
|
21626 |
{ remove: ['element'] },
|
|
|
21627 |
{ moveToElement: ['element'] },
|
|
|
21628 |
{ moveToPosition: ['position'] }
|
|
|
21629 |
]);
|
|
|
21630 |
const isAtContentEditableBlockCaret = (forward, from) => {
|
|
|
21631 |
const elm = from.getNode(!forward);
|
|
|
21632 |
const caretLocation = forward ? 'after' : 'before';
|
|
|
21633 |
return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
|
|
|
21634 |
};
|
|
|
21635 |
const isDeleteFromCefDifferentBlocks = (root, forward, from, to, schema) => {
|
|
|
21636 |
const inSameBlock = elm => schema.isInline(elm.nodeName.toLowerCase()) && !isInSameBlock(from, to, root);
|
|
|
21637 |
return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock);
|
|
|
21638 |
};
|
| 1441 |
ariadna |
21639 |
const deleteEmptyBlockOrMoveToCef = (schema, root, forward, from, to) => {
|
| 1 |
efrain |
21640 |
const toCefElm = to.getNode(!forward);
|
| 1441 |
ariadna |
21641 |
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)));
|
| 1 |
efrain |
21642 |
};
|
|
|
21643 |
const findCefPosition = (root, forward, from, schema) => fromPosition(forward, root, from).bind(to => {
|
|
|
21644 |
if (isCompoundElement(to.getNode())) {
|
|
|
21645 |
return Optional.none();
|
|
|
21646 |
} else if (isDeleteFromCefDifferentBlocks(root, forward, from, to, schema)) {
|
|
|
21647 |
return Optional.none();
|
|
|
21648 |
} else if (forward && isContentEditableFalse$b(to.getNode())) {
|
| 1441 |
ariadna |
21649 |
return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
|
| 1 |
efrain |
21650 |
} else if (!forward && isContentEditableFalse$b(to.getNode(true))) {
|
| 1441 |
ariadna |
21651 |
return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
|
| 1 |
efrain |
21652 |
} else if (forward && isAfterContentEditableFalse(from)) {
|
|
|
21653 |
return Optional.some(DeleteAction.moveToPosition(to));
|
|
|
21654 |
} else if (!forward && isBeforeContentEditableFalse(from)) {
|
|
|
21655 |
return Optional.some(DeleteAction.moveToPosition(to));
|
|
|
21656 |
} else {
|
|
|
21657 |
return Optional.none();
|
|
|
21658 |
}
|
|
|
21659 |
});
|
|
|
21660 |
const getContentEditableBlockAction = (forward, elm) => {
|
|
|
21661 |
if (isNullable(elm)) {
|
|
|
21662 |
return Optional.none();
|
|
|
21663 |
} else if (forward && isContentEditableFalse$b(elm.nextSibling)) {
|
|
|
21664 |
return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
|
|
|
21665 |
} else if (!forward && isContentEditableFalse$b(elm.previousSibling)) {
|
|
|
21666 |
return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
|
|
|
21667 |
} else {
|
|
|
21668 |
return Optional.none();
|
|
|
21669 |
}
|
|
|
21670 |
};
|
|
|
21671 |
const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => {
|
|
|
21672 |
if (isInSameBlock(from, to, root)) {
|
|
|
21673 |
return Optional.none();
|
|
|
21674 |
} else {
|
|
|
21675 |
return Optional.some(DeleteAction.moveToPosition(to));
|
|
|
21676 |
}
|
|
|
21677 |
});
|
|
|
21678 |
const getContentEditableAction = (root, forward, from, schema) => {
|
|
|
21679 |
if (isAtContentEditableBlockCaret(forward, from)) {
|
|
|
21680 |
return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from, schema));
|
|
|
21681 |
} else {
|
|
|
21682 |
return findCefPosition(root, forward, from, schema).bind(deleteAction => skipMoveToActionFromInlineCefToContent(root, from, deleteAction));
|
|
|
21683 |
}
|
|
|
21684 |
};
|
|
|
21685 |
const read = (root, forward, rng, schema) => {
|
|
|
21686 |
const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
|
|
|
21687 |
const from = CaretPosition.fromRangeStart(normalizedRange);
|
|
|
21688 |
const rootElement = SugarElement.fromDom(root);
|
|
|
21689 |
if (!forward && isAfterContentEditableFalse(from)) {
|
|
|
21690 |
return Optional.some(DeleteAction.remove(from.getNode(true)));
|
|
|
21691 |
} else if (forward && isBeforeContentEditableFalse(from)) {
|
|
|
21692 |
return Optional.some(DeleteAction.remove(from.getNode()));
|
|
|
21693 |
} else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from, schema)) {
|
|
|
21694 |
return findPreviousBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
|
|
|
21695 |
} else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from, schema)) {
|
|
|
21696 |
return findNextBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
|
|
|
21697 |
} else {
|
|
|
21698 |
return getContentEditableAction(root, forward, from, schema);
|
|
|
21699 |
}
|
|
|
21700 |
};
|
|
|
21701 |
|
|
|
21702 |
const deleteElement$1 = (editor, forward) => element => {
|
|
|
21703 |
editor._selectionOverrides.hideFakeCaret();
|
|
|
21704 |
deleteElement$2(editor, forward, SugarElement.fromDom(element));
|
|
|
21705 |
return true;
|
|
|
21706 |
};
|
|
|
21707 |
const moveToElement = (editor, forward) => element => {
|
|
|
21708 |
const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
|
|
|
21709 |
editor.selection.setRng(pos.toRange());
|
|
|
21710 |
return true;
|
|
|
21711 |
};
|
|
|
21712 |
const moveToPosition = editor => pos => {
|
|
|
21713 |
editor.selection.setRng(pos.toRange());
|
|
|
21714 |
return true;
|
|
|
21715 |
};
|
|
|
21716 |
const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
|
|
|
21717 |
const backspaceDeleteCaret = (editor, forward) => {
|
|
|
21718 |
const selectedNode = editor.selection.getNode();
|
|
|
21719 |
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));
|
|
|
21720 |
};
|
|
|
21721 |
const deleteOffscreenSelection = rootElement => {
|
| 1441 |
ariadna |
21722 |
each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$4);
|
| 1 |
efrain |
21723 |
};
|
|
|
21724 |
const backspaceDeleteRange = (editor, forward) => {
|
|
|
21725 |
const selectedNode = editor.selection.getNode();
|
|
|
21726 |
if (isContentEditableFalse$b(selectedNode) && !isTableCell$3(selectedNode)) {
|
|
|
21727 |
const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b);
|
|
|
21728 |
return hasCefAncestor.fold(() => Optional.some(() => {
|
|
|
21729 |
deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
|
|
|
21730 |
deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
|
|
|
21731 |
paddEmptyBody(editor);
|
|
|
21732 |
}), () => Optional.some(noop));
|
|
|
21733 |
}
|
|
|
21734 |
if (isCefAtEdgeSelected(editor)) {
|
|
|
21735 |
return Optional.some(() => {
|
|
|
21736 |
deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
|
|
|
21737 |
});
|
|
|
21738 |
}
|
|
|
21739 |
return Optional.none();
|
|
|
21740 |
};
|
|
|
21741 |
const paddEmptyElement = editor => {
|
|
|
21742 |
const dom = editor.dom, selection = editor.selection;
|
|
|
21743 |
const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
|
|
|
21744 |
if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) {
|
|
|
21745 |
const br = dom.create('br', { 'data-mce-bogus': '1' });
|
|
|
21746 |
dom.setHTML(ceRoot, '');
|
|
|
21747 |
ceRoot.appendChild(br);
|
|
|
21748 |
selection.setRng(CaretPosition.before(br).toRange());
|
|
|
21749 |
}
|
|
|
21750 |
return true;
|
|
|
21751 |
};
|
| 1441 |
ariadna |
21752 |
const backspaceDelete$7 = (editor, forward) => {
|
| 1 |
efrain |
21753 |
if (editor.selection.isCollapsed()) {
|
|
|
21754 |
return backspaceDeleteCaret(editor, forward);
|
|
|
21755 |
} else {
|
|
|
21756 |
return backspaceDeleteRange(editor, forward);
|
|
|
21757 |
}
|
|
|
21758 |
};
|
|
|
21759 |
|
| 1441 |
ariadna |
21760 |
const isTextEndpoint = endpoint => endpoint.hasOwnProperty('text');
|
|
|
21761 |
const isElementEndpoint = endpoint => endpoint.hasOwnProperty('marker');
|
|
|
21762 |
const getBookmark = (range, createMarker) => {
|
|
|
21763 |
const getEndpoint = (container, offset) => {
|
|
|
21764 |
if (isText$b(container)) {
|
|
|
21765 |
return {
|
|
|
21766 |
text: container,
|
|
|
21767 |
offset
|
|
|
21768 |
};
|
|
|
21769 |
} else {
|
|
|
21770 |
const marker = createMarker();
|
|
|
21771 |
const children = container.childNodes;
|
|
|
21772 |
if (offset < children.length) {
|
|
|
21773 |
container.insertBefore(marker, children[offset]);
|
|
|
21774 |
return {
|
|
|
21775 |
marker,
|
|
|
21776 |
before: true
|
|
|
21777 |
};
|
|
|
21778 |
} else {
|
|
|
21779 |
container.appendChild(marker);
|
|
|
21780 |
return {
|
|
|
21781 |
marker,
|
|
|
21782 |
before: false
|
|
|
21783 |
};
|
|
|
21784 |
}
|
|
|
21785 |
}
|
|
|
21786 |
};
|
|
|
21787 |
const end = getEndpoint(range.endContainer, range.endOffset);
|
|
|
21788 |
const start = getEndpoint(range.startContainer, range.startOffset);
|
|
|
21789 |
return {
|
|
|
21790 |
start,
|
|
|
21791 |
end
|
|
|
21792 |
};
|
|
|
21793 |
};
|
|
|
21794 |
const resolveBookmark = bm => {
|
|
|
21795 |
var _a, _b;
|
|
|
21796 |
const {start, end} = bm;
|
|
|
21797 |
const rng = new window.Range();
|
|
|
21798 |
if (isTextEndpoint(start)) {
|
|
|
21799 |
rng.setStart(start.text, start.offset);
|
|
|
21800 |
} else {
|
|
|
21801 |
if (isElementEndpoint(start)) {
|
|
|
21802 |
if (start.before) {
|
|
|
21803 |
rng.setStartBefore(start.marker);
|
|
|
21804 |
} else {
|
|
|
21805 |
rng.setStartAfter(start.marker);
|
|
|
21806 |
}
|
|
|
21807 |
(_a = start.marker.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(start.marker);
|
|
|
21808 |
}
|
|
|
21809 |
}
|
|
|
21810 |
if (isTextEndpoint(end)) {
|
|
|
21811 |
rng.setEnd(end.text, end.offset);
|
|
|
21812 |
} else {
|
|
|
21813 |
if (isElementEndpoint(end)) {
|
|
|
21814 |
if (end.before) {
|
|
|
21815 |
rng.setEndBefore(end.marker);
|
|
|
21816 |
} else {
|
|
|
21817 |
rng.setEndAfter(end.marker);
|
|
|
21818 |
}
|
|
|
21819 |
(_b = end.marker.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(end.marker);
|
|
|
21820 |
}
|
|
|
21821 |
}
|
|
|
21822 |
return rng;
|
|
|
21823 |
};
|
|
|
21824 |
|
|
|
21825 |
const backspaceDelete$6 = (editor, forward) => {
|
|
|
21826 |
var _a;
|
|
|
21827 |
const dom = editor.dom;
|
|
|
21828 |
const startBlock = dom.getParent(editor.selection.getStart(), dom.isBlock);
|
|
|
21829 |
const endBlock = dom.getParent(editor.selection.getEnd(), dom.isBlock);
|
|
|
21830 |
const body = editor.getBody();
|
|
|
21831 |
const startBlockName = (_a = startBlock === null || startBlock === void 0 ? void 0 : startBlock.nodeName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
|
21832 |
if (startBlockName === 'div' && startBlock && endBlock && startBlock === body.firstChild && endBlock === body.lastChild && !dom.isEmpty(body)) {
|
|
|
21833 |
const wrapper = startBlock.cloneNode(false);
|
|
|
21834 |
const deleteAction = () => {
|
|
|
21835 |
if (forward) {
|
|
|
21836 |
execNativeForwardDeleteCommand(editor);
|
|
|
21837 |
} else {
|
|
|
21838 |
execNativeDeleteCommand(editor);
|
|
|
21839 |
}
|
|
|
21840 |
if (body.firstChild !== startBlock) {
|
|
|
21841 |
const bookmark = getBookmark(editor.selection.getRng(), () => document.createElement('span'));
|
|
|
21842 |
Array.from(body.childNodes).forEach(node => wrapper.appendChild(node));
|
|
|
21843 |
body.appendChild(wrapper);
|
|
|
21844 |
editor.selection.setRng(resolveBookmark(bookmark));
|
|
|
21845 |
}
|
|
|
21846 |
};
|
|
|
21847 |
return Optional.some(deleteAction);
|
|
|
21848 |
}
|
|
|
21849 |
return Optional.none();
|
|
|
21850 |
};
|
|
|
21851 |
|
| 1 |
efrain |
21852 |
const deleteCaret$2 = (editor, forward) => {
|
|
|
21853 |
const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
21854 |
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));
|
|
|
21855 |
};
|
|
|
21856 |
const backspaceDelete$5 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
|
|
|
21857 |
|
| 1441 |
ariadna |
21858 |
const isText$2 = isText$b;
|
| 1 |
efrain |
21859 |
const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1;
|
|
|
21860 |
const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
|
|
|
21861 |
const createZwsp = node => {
|
|
|
21862 |
var _a;
|
|
|
21863 |
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
|
|
|
21864 |
return doc.createTextNode(ZWSP$1);
|
|
|
21865 |
};
|
|
|
21866 |
const insertBefore$1 = node => {
|
|
|
21867 |
var _a;
|
|
|
21868 |
if (isText$2(node.previousSibling)) {
|
|
|
21869 |
if (endsWithCaretContainer(node.previousSibling)) {
|
|
|
21870 |
return node.previousSibling;
|
|
|
21871 |
} else {
|
|
|
21872 |
node.previousSibling.appendData(ZWSP$1);
|
|
|
21873 |
return node.previousSibling;
|
|
|
21874 |
}
|
|
|
21875 |
} else if (isText$2(node)) {
|
|
|
21876 |
if (startsWithCaretContainer(node)) {
|
|
|
21877 |
return node;
|
|
|
21878 |
} else {
|
|
|
21879 |
node.insertData(0, ZWSP$1);
|
|
|
21880 |
return node;
|
|
|
21881 |
}
|
|
|
21882 |
} else {
|
|
|
21883 |
const newNode = createZwsp(node);
|
|
|
21884 |
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node);
|
|
|
21885 |
return newNode;
|
|
|
21886 |
}
|
|
|
21887 |
};
|
|
|
21888 |
const insertAfter$1 = node => {
|
|
|
21889 |
var _a, _b;
|
|
|
21890 |
if (isText$2(node.nextSibling)) {
|
|
|
21891 |
if (startsWithCaretContainer(node.nextSibling)) {
|
|
|
21892 |
return node.nextSibling;
|
|
|
21893 |
} else {
|
|
|
21894 |
node.nextSibling.insertData(0, ZWSP$1);
|
|
|
21895 |
return node.nextSibling;
|
|
|
21896 |
}
|
|
|
21897 |
} else if (isText$2(node)) {
|
|
|
21898 |
if (endsWithCaretContainer(node)) {
|
|
|
21899 |
return node;
|
|
|
21900 |
} else {
|
|
|
21901 |
node.appendData(ZWSP$1);
|
|
|
21902 |
return node;
|
|
|
21903 |
}
|
|
|
21904 |
} else {
|
|
|
21905 |
const newNode = createZwsp(node);
|
|
|
21906 |
if (node.nextSibling) {
|
|
|
21907 |
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling);
|
|
|
21908 |
} else {
|
|
|
21909 |
(_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode);
|
|
|
21910 |
}
|
|
|
21911 |
return newNode;
|
|
|
21912 |
}
|
|
|
21913 |
};
|
|
|
21914 |
const insertInline = (before, node) => before ? insertBefore$1(node) : insertAfter$1(node);
|
|
|
21915 |
const insertInlineBefore = curry(insertInline, true);
|
|
|
21916 |
const insertInlineAfter = curry(insertInline, false);
|
|
|
21917 |
|
|
|
21918 |
const insertInlinePos = (pos, before) => {
|
| 1441 |
ariadna |
21919 |
if (isText$b(pos.container())) {
|
| 1 |
efrain |
21920 |
return insertInline(before, pos.container());
|
|
|
21921 |
} else {
|
|
|
21922 |
return insertInline(before, pos.getNode());
|
|
|
21923 |
}
|
|
|
21924 |
};
|
|
|
21925 |
const isPosCaretContainer = (pos, caret) => {
|
|
|
21926 |
const caretNode = caret.get();
|
|
|
21927 |
return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
|
|
|
21928 |
};
|
|
|
21929 |
const renderCaret = (caret, location) => location.fold(element => {
|
| 1441 |
ariadna |
21930 |
remove$2(caret.get());
|
| 1 |
efrain |
21931 |
const text = insertInlineBefore(element);
|
|
|
21932 |
caret.set(text);
|
|
|
21933 |
return Optional.some(CaretPosition(text, text.length - 1));
|
|
|
21934 |
}, element => firstPositionIn(element).map(pos => {
|
|
|
21935 |
if (!isPosCaretContainer(pos, caret)) {
|
| 1441 |
ariadna |
21936 |
remove$2(caret.get());
|
| 1 |
efrain |
21937 |
const text = insertInlinePos(pos, true);
|
|
|
21938 |
caret.set(text);
|
|
|
21939 |
return CaretPosition(text, 1);
|
|
|
21940 |
} else {
|
|
|
21941 |
const node = caret.get();
|
|
|
21942 |
return CaretPosition(node, 1);
|
|
|
21943 |
}
|
|
|
21944 |
}), element => lastPositionIn(element).map(pos => {
|
|
|
21945 |
if (!isPosCaretContainer(pos, caret)) {
|
| 1441 |
ariadna |
21946 |
remove$2(caret.get());
|
| 1 |
efrain |
21947 |
const text = insertInlinePos(pos, false);
|
|
|
21948 |
caret.set(text);
|
|
|
21949 |
return CaretPosition(text, text.length - 1);
|
|
|
21950 |
} else {
|
|
|
21951 |
const node = caret.get();
|
|
|
21952 |
return CaretPosition(node, node.length - 1);
|
|
|
21953 |
}
|
|
|
21954 |
}), element => {
|
| 1441 |
ariadna |
21955 |
remove$2(caret.get());
|
| 1 |
efrain |
21956 |
const text = insertInlineAfter(element);
|
|
|
21957 |
caret.set(text);
|
|
|
21958 |
return Optional.some(CaretPosition(text, 1));
|
|
|
21959 |
});
|
|
|
21960 |
|
|
|
21961 |
const evaluateUntil = (fns, args) => {
|
|
|
21962 |
for (let i = 0; i < fns.length; i++) {
|
|
|
21963 |
const result = fns[i].apply(null, args);
|
|
|
21964 |
if (result.isSome()) {
|
|
|
21965 |
return result;
|
|
|
21966 |
}
|
|
|
21967 |
}
|
|
|
21968 |
return Optional.none();
|
|
|
21969 |
};
|
|
|
21970 |
|
|
|
21971 |
const Location = Adt.generate([
|
|
|
21972 |
{ before: ['element'] },
|
|
|
21973 |
{ start: ['element'] },
|
|
|
21974 |
{ end: ['element'] },
|
|
|
21975 |
{ after: ['element'] }
|
|
|
21976 |
]);
|
|
|
21977 |
const rescope$1 = (rootNode, node) => {
|
|
|
21978 |
const parentBlock = getParentBlock$3(node, rootNode);
|
|
|
21979 |
return parentBlock ? parentBlock : rootNode;
|
|
|
21980 |
};
|
|
|
21981 |
const before = (isInlineTarget, rootNode, pos) => {
|
|
|
21982 |
const nPos = normalizeForwards(pos);
|
|
|
21983 |
const scope = rescope$1(rootNode, nPos.container());
|
|
|
21984 |
return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none);
|
|
|
21985 |
};
|
|
|
21986 |
const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
|
|
|
21987 |
const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
|
|
|
21988 |
const start$1 = (isInlineTarget, rootNode, pos) => {
|
|
|
21989 |
const nPos = normalizeBackwards(pos);
|
|
|
21990 |
return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
|
|
|
21991 |
const prevPos = prevPosition(inline, nPos);
|
|
|
21992 |
return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
|
|
|
21993 |
});
|
|
|
21994 |
};
|
|
|
21995 |
const end = (isInlineTarget, rootNode, pos) => {
|
|
|
21996 |
const nPos = normalizeForwards(pos);
|
|
|
21997 |
return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
|
|
|
21998 |
const nextPos = nextPosition(inline, nPos);
|
|
|
21999 |
return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
|
|
|
22000 |
});
|
|
|
22001 |
};
|
|
|
22002 |
const after = (isInlineTarget, rootNode, pos) => {
|
|
|
22003 |
const nPos = normalizeBackwards(pos);
|
|
|
22004 |
const scope = rescope$1(rootNode, nPos.container());
|
|
|
22005 |
return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none);
|
|
|
22006 |
};
|
|
|
22007 |
const isValidLocation = location => !isRtl(getElement(location));
|
|
|
22008 |
const readLocation = (isInlineTarget, rootNode, pos) => {
|
|
|
22009 |
const location = evaluateUntil([
|
|
|
22010 |
before,
|
|
|
22011 |
start$1,
|
|
|
22012 |
end,
|
|
|
22013 |
after
|
|
|
22014 |
], [
|
|
|
22015 |
isInlineTarget,
|
|
|
22016 |
rootNode,
|
|
|
22017 |
pos
|
|
|
22018 |
]);
|
|
|
22019 |
return location.filter(isValidLocation);
|
|
|
22020 |
};
|
|
|
22021 |
const getElement = location => location.fold(identity, identity, identity, identity);
|
|
|
22022 |
const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
|
|
|
22023 |
const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after);
|
|
|
22024 |
const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end);
|
|
|
22025 |
const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
|
|
|
22026 |
const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => {
|
|
|
22027 |
if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
|
|
|
22028 |
return Location.after(forward ? fromInline : toInline);
|
|
|
22029 |
} else {
|
|
|
22030 |
return location;
|
|
|
22031 |
}
|
|
|
22032 |
}).getOr(location);
|
|
|
22033 |
const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation));
|
|
|
22034 |
const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => {
|
|
|
22035 |
const from = normalizePosition(forward, pos);
|
|
|
22036 |
const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward));
|
|
|
22037 |
const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation)));
|
|
|
22038 |
return location.filter(isValidLocation);
|
|
|
22039 |
};
|
|
|
22040 |
const findLocationSimple = (forward, location) => {
|
|
|
22041 |
if (forward) {
|
|
|
22042 |
return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
|
|
|
22043 |
} else {
|
|
|
22044 |
return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
|
|
|
22045 |
}
|
|
|
22046 |
};
|
|
|
22047 |
const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => {
|
|
|
22048 |
const from = normalizePosition(forward, pos);
|
|
|
22049 |
const fromLocation = readLocation(isInlineTarget, rootNode, from);
|
|
|
22050 |
return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos));
|
|
|
22051 |
};
|
|
|
22052 |
|
|
|
22053 |
const hasSelectionModifyApi = editor => {
|
|
|
22054 |
return isFunction(editor.selection.getSel().modify);
|
|
|
22055 |
};
|
|
|
22056 |
const moveRel = (forward, selection, pos) => {
|
|
|
22057 |
const delta = forward ? 1 : -1;
|
|
|
22058 |
selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
|
|
|
22059 |
selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
|
|
|
22060 |
return true;
|
|
|
22061 |
};
|
|
|
22062 |
const moveByWord = (forward, editor) => {
|
|
|
22063 |
const rng = editor.selection.getRng();
|
|
|
22064 |
const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
|
|
|
22065 |
if (!hasSelectionModifyApi(editor)) {
|
|
|
22066 |
return false;
|
|
|
22067 |
} else if (forward && isBeforeInline(pos)) {
|
|
|
22068 |
return moveRel(true, editor.selection, pos);
|
|
|
22069 |
} else if (!forward && isAfterInline(pos)) {
|
|
|
22070 |
return moveRel(false, editor.selection, pos);
|
|
|
22071 |
} else {
|
|
|
22072 |
return false;
|
|
|
22073 |
}
|
|
|
22074 |
};
|
|
|
22075 |
|
|
|
22076 |
var BreakType;
|
|
|
22077 |
(function (BreakType) {
|
|
|
22078 |
BreakType[BreakType['Br'] = 0] = 'Br';
|
|
|
22079 |
BreakType[BreakType['Block'] = 1] = 'Block';
|
|
|
22080 |
BreakType[BreakType['Wrap'] = 2] = 'Wrap';
|
|
|
22081 |
BreakType[BreakType['Eol'] = 3] = 'Eol';
|
|
|
22082 |
}(BreakType || (BreakType = {})));
|
| 1441 |
ariadna |
22083 |
const flip = (direction, positions) => direction === -1 ? reverse(positions) : positions;
|
|
|
22084 |
const walk$1 = (direction, caretWalker, pos) => direction === 1 ? caretWalker.next(pos) : caretWalker.prev(pos);
|
| 1 |
efrain |
22085 |
const getBreakType = (scope, direction, currentPos, nextPos) => {
|
| 1441 |
ariadna |
22086 |
if (isBr$6(nextPos.getNode(direction === 1))) {
|
| 1 |
efrain |
22087 |
return BreakType.Br;
|
|
|
22088 |
} else if (isInSameBlock(currentPos, nextPos) === false) {
|
|
|
22089 |
return BreakType.Block;
|
|
|
22090 |
} else {
|
|
|
22091 |
return BreakType.Wrap;
|
|
|
22092 |
}
|
|
|
22093 |
};
|
|
|
22094 |
const getPositionsUntil = (predicate, direction, scope, start) => {
|
|
|
22095 |
const caretWalker = CaretWalker(scope);
|
|
|
22096 |
let currentPos = start;
|
|
|
22097 |
const positions = [];
|
|
|
22098 |
while (currentPos) {
|
|
|
22099 |
const nextPos = walk$1(direction, caretWalker, currentPos);
|
|
|
22100 |
if (!nextPos) {
|
|
|
22101 |
break;
|
|
|
22102 |
}
|
|
|
22103 |
if (isBr$6(nextPos.getNode(false))) {
|
| 1441 |
ariadna |
22104 |
if (direction === 1) {
|
| 1 |
efrain |
22105 |
return {
|
|
|
22106 |
positions: flip(direction, positions).concat([nextPos]),
|
|
|
22107 |
breakType: BreakType.Br,
|
|
|
22108 |
breakAt: Optional.some(nextPos)
|
|
|
22109 |
};
|
|
|
22110 |
} else {
|
|
|
22111 |
return {
|
|
|
22112 |
positions: flip(direction, positions),
|
|
|
22113 |
breakType: BreakType.Br,
|
|
|
22114 |
breakAt: Optional.some(nextPos)
|
|
|
22115 |
};
|
|
|
22116 |
}
|
|
|
22117 |
}
|
|
|
22118 |
if (!nextPos.isVisible()) {
|
|
|
22119 |
currentPos = nextPos;
|
|
|
22120 |
continue;
|
|
|
22121 |
}
|
|
|
22122 |
if (predicate(currentPos, nextPos)) {
|
|
|
22123 |
const breakType = getBreakType(scope, direction, currentPos, nextPos);
|
|
|
22124 |
return {
|
|
|
22125 |
positions: flip(direction, positions),
|
|
|
22126 |
breakType,
|
|
|
22127 |
breakAt: Optional.some(nextPos)
|
|
|
22128 |
};
|
|
|
22129 |
}
|
|
|
22130 |
positions.push(nextPos);
|
|
|
22131 |
currentPos = nextPos;
|
|
|
22132 |
}
|
|
|
22133 |
return {
|
|
|
22134 |
positions: flip(direction, positions),
|
|
|
22135 |
breakType: BreakType.Eol,
|
|
|
22136 |
breakAt: Optional.none()
|
|
|
22137 |
};
|
|
|
22138 |
};
|
|
|
22139 |
const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => {
|
|
|
22140 |
const positions = getPositionsUntilBreak(scope, pos).positions;
|
| 1441 |
ariadna |
22141 |
return direction === -1 ? positions.concat(pos) : [pos].concat(positions);
|
| 1 |
efrain |
22142 |
}).getOr([]);
|
|
|
22143 |
const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
|
|
|
22144 |
const lastDist = Math.abs(x - lastRect.left);
|
|
|
22145 |
const newDist = Math.abs(x - newRect.left);
|
|
|
22146 |
return newDist <= lastDist ? newPos : lastPos;
|
|
|
22147 |
}).or(acc)), Optional.none());
|
|
|
22148 |
const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
|
|
|
22149 |
const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
|
|
|
22150 |
const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
|
|
|
22151 |
const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
|
|
|
22152 |
const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
|
|
|
22153 |
const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
|
|
|
22154 |
const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
|
|
|
22155 |
const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
|
|
|
22156 |
const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
|
|
|
22157 |
const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
|
|
|
22158 |
const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
|
|
|
22159 |
|
| 1441 |
ariadna |
22160 |
const isContentEditableFalse$5 = isContentEditableFalse$b;
|
| 1 |
efrain |
22161 |
const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
|
|
|
22162 |
const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
|
|
|
22163 |
const isNodeClientRect = rect => hasNonNullableKey(rect, 'node');
|
|
|
22164 |
const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
|
|
|
22165 |
const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
|
|
|
22166 |
const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
|
| 1441 |
ariadna |
22167 |
if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$5(clientRect.node)) {
|
| 1 |
efrain |
22168 |
return clientRect;
|
|
|
22169 |
}
|
|
|
22170 |
if (newDistance < oldDistance) {
|
|
|
22171 |
return clientRect;
|
|
|
22172 |
}
|
|
|
22173 |
return oldClientRect;
|
|
|
22174 |
});
|
|
|
22175 |
|
|
|
22176 |
const getNodeClientRects = node => {
|
|
|
22177 |
const toArrayWithNode = clientRects => {
|
|
|
22178 |
return map$3(clientRects, rect => {
|
|
|
22179 |
const clientRect = clone$1(rect);
|
|
|
22180 |
clientRect.node = node;
|
|
|
22181 |
return clientRect;
|
|
|
22182 |
});
|
|
|
22183 |
};
|
|
|
22184 |
if (isElement$6(node)) {
|
|
|
22185 |
return toArrayWithNode(node.getClientRects());
|
| 1441 |
ariadna |
22186 |
} else if (isText$b(node)) {
|
| 1 |
efrain |
22187 |
const rng = node.ownerDocument.createRange();
|
|
|
22188 |
rng.setStart(node, 0);
|
|
|
22189 |
rng.setEnd(node, node.data.length);
|
|
|
22190 |
return toArrayWithNode(rng.getClientRects());
|
|
|
22191 |
} else {
|
|
|
22192 |
return [];
|
|
|
22193 |
}
|
|
|
22194 |
};
|
|
|
22195 |
const getClientRects = nodes => bind$3(nodes, getNodeClientRects);
|
|
|
22196 |
|
|
|
22197 |
var VDirection;
|
|
|
22198 |
(function (VDirection) {
|
|
|
22199 |
VDirection[VDirection['Up'] = -1] = 'Up';
|
|
|
22200 |
VDirection[VDirection['Down'] = 1] = 'Down';
|
|
|
22201 |
}(VDirection || (VDirection = {})));
|
|
|
22202 |
const findUntil = (direction, root, predicateFn, node) => {
|
|
|
22203 |
let currentNode = node;
|
|
|
22204 |
while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) {
|
|
|
22205 |
if (predicateFn(currentNode)) {
|
|
|
22206 |
return;
|
|
|
22207 |
}
|
|
|
22208 |
}
|
|
|
22209 |
};
|
|
|
22210 |
const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
|
|
|
22211 |
let line = 0;
|
|
|
22212 |
const result = [];
|
|
|
22213 |
const add = node => {
|
|
|
22214 |
let clientRects = getClientRects([node]);
|
| 1441 |
ariadna |
22215 |
if (direction === VDirection.Up) {
|
| 1 |
efrain |
22216 |
clientRects = clientRects.reverse();
|
|
|
22217 |
}
|
|
|
22218 |
for (let i = 0; i < clientRects.length; i++) {
|
|
|
22219 |
const clientRect = clientRects[i];
|
|
|
22220 |
if (isBeflowFn(clientRect, targetClientRect)) {
|
|
|
22221 |
continue;
|
|
|
22222 |
}
|
| 1441 |
ariadna |
22223 |
if (result.length > 0 && isAboveFn(clientRect, last$1(result))) {
|
| 1 |
efrain |
22224 |
line++;
|
|
|
22225 |
}
|
|
|
22226 |
clientRect.line = line;
|
|
|
22227 |
if (predicateFn(clientRect)) {
|
|
|
22228 |
return true;
|
|
|
22229 |
}
|
|
|
22230 |
result.push(clientRect);
|
|
|
22231 |
}
|
|
|
22232 |
return false;
|
|
|
22233 |
};
|
| 1441 |
ariadna |
22234 |
const targetClientRect = last$1(caretPosition.getClientRects());
|
| 1 |
efrain |
22235 |
if (!targetClientRect) {
|
|
|
22236 |
return result;
|
|
|
22237 |
}
|
|
|
22238 |
const node = caretPosition.getNode();
|
|
|
22239 |
if (node) {
|
|
|
22240 |
add(node);
|
|
|
22241 |
findUntil(direction, root, add, node);
|
|
|
22242 |
}
|
|
|
22243 |
return result;
|
|
|
22244 |
};
|
|
|
22245 |
const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
|
|
|
22246 |
const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
|
|
|
22247 |
const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
|
|
|
22248 |
const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
|
|
|
22249 |
const getLastClientRect = caretPosition => {
|
| 1441 |
ariadna |
22250 |
return last$1(caretPosition.getClientRects());
|
| 1 |
efrain |
22251 |
};
|
|
|
22252 |
const positionsUntil = (direction, root, predicateFn, node) => {
|
|
|
22253 |
const caretWalker = CaretWalker(root);
|
|
|
22254 |
let walkFn;
|
|
|
22255 |
let isBelowFn;
|
|
|
22256 |
let isAboveFn;
|
|
|
22257 |
let caretPosition;
|
|
|
22258 |
const result = [];
|
|
|
22259 |
let line = 0;
|
| 1441 |
ariadna |
22260 |
if (direction === VDirection.Down) {
|
| 1 |
efrain |
22261 |
walkFn = caretWalker.next;
|
|
|
22262 |
isBelowFn = isBelow$1;
|
|
|
22263 |
isAboveFn = isAbove$1;
|
|
|
22264 |
caretPosition = CaretPosition.after(node);
|
|
|
22265 |
} else {
|
|
|
22266 |
walkFn = caretWalker.prev;
|
|
|
22267 |
isBelowFn = isAbove$1;
|
|
|
22268 |
isAboveFn = isBelow$1;
|
|
|
22269 |
caretPosition = CaretPosition.before(node);
|
|
|
22270 |
}
|
|
|
22271 |
const targetClientRect = getLastClientRect(caretPosition);
|
|
|
22272 |
do {
|
|
|
22273 |
if (!caretPosition.isVisible()) {
|
|
|
22274 |
continue;
|
|
|
22275 |
}
|
|
|
22276 |
const rect = getLastClientRect(caretPosition);
|
|
|
22277 |
if (isAboveFn(rect, targetClientRect)) {
|
|
|
22278 |
continue;
|
|
|
22279 |
}
|
| 1441 |
ariadna |
22280 |
if (result.length > 0 && isBelowFn(rect, last$1(result))) {
|
| 1 |
efrain |
22281 |
line++;
|
|
|
22282 |
}
|
|
|
22283 |
const clientRect = clone$1(rect);
|
|
|
22284 |
clientRect.position = caretPosition;
|
|
|
22285 |
clientRect.line = line;
|
|
|
22286 |
if (predicateFn(clientRect)) {
|
|
|
22287 |
return result;
|
|
|
22288 |
}
|
|
|
22289 |
result.push(clientRect);
|
|
|
22290 |
} while (caretPosition = walkFn(caretPosition));
|
|
|
22291 |
return result;
|
|
|
22292 |
};
|
|
|
22293 |
const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect);
|
|
|
22294 |
const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect);
|
|
|
22295 |
|
|
|
22296 |
const moveToRange = (editor, rng) => {
|
|
|
22297 |
editor.selection.setRng(rng);
|
|
|
22298 |
scrollRangeIntoView(editor, editor.selection.getRng());
|
|
|
22299 |
};
|
|
|
22300 |
const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView));
|
|
|
22301 |
const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => {
|
| 1441 |
ariadna |
22302 |
const forwards = direction === 1;
|
| 1 |
efrain |
22303 |
const caretWalker = CaretWalker(editor.getBody());
|
|
|
22304 |
const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
|
|
|
22305 |
const isBeforeFn = forwards ? isBefore : isAfter;
|
|
|
22306 |
if (!range.collapsed) {
|
|
|
22307 |
const node = getSelectedNode(range);
|
|
|
22308 |
if (isElement(node)) {
|
| 1441 |
ariadna |
22309 |
return showCaret(direction, editor, node, direction === -1, false);
|
| 1 |
efrain |
22310 |
} else if (isCefAtEdgeSelected(editor)) {
|
|
|
22311 |
const newRange = range.cloneRange();
|
| 1441 |
ariadna |
22312 |
newRange.collapse(direction === -1);
|
| 1 |
efrain |
22313 |
return Optional.from(newRange);
|
|
|
22314 |
}
|
|
|
22315 |
}
|
|
|
22316 |
const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
|
|
22317 |
if (isBeforeFn(caretPosition)) {
|
|
|
22318 |
return selectNode(editor, caretPosition.getNode(!forwards));
|
|
|
22319 |
}
|
|
|
22320 |
let nextCaretPosition = getNextPosFn(caretPosition);
|
|
|
22321 |
const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
|
|
|
22322 |
if (!nextCaretPosition) {
|
|
|
22323 |
return rangeIsInContainerBlock ? Optional.some(range) : Optional.none();
|
|
|
22324 |
} else {
|
|
|
22325 |
nextCaretPosition = normalizePosition(forwards, nextCaretPosition);
|
|
|
22326 |
}
|
|
|
22327 |
if (isBeforeFn(nextCaretPosition)) {
|
|
|
22328 |
return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
|
|
|
22329 |
}
|
|
|
22330 |
const peekCaretPosition = getNextPosFn(nextCaretPosition);
|
|
|
22331 |
if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
|
|
|
22332 |
if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
|
|
|
22333 |
return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
|
|
|
22334 |
}
|
|
|
22335 |
}
|
|
|
22336 |
if (rangeIsInContainerBlock) {
|
|
|
22337 |
return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
|
|
|
22338 |
}
|
|
|
22339 |
return Optional.none();
|
|
|
22340 |
};
|
|
|
22341 |
const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => {
|
|
|
22342 |
const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
|
| 1441 |
ariadna |
22343 |
const caretClientRect = last$1(caretPosition.getClientRects());
|
| 1 |
efrain |
22344 |
const forwards = direction === VDirection.Down;
|
|
|
22345 |
const root = editor.getBody();
|
|
|
22346 |
if (!caretClientRect) {
|
|
|
22347 |
return Optional.none();
|
|
|
22348 |
}
|
|
|
22349 |
if (isCefAtEdgeSelected(editor)) {
|
|
|
22350 |
const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range);
|
|
|
22351 |
const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
|
|
|
22352 |
return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange());
|
|
|
22353 |
}
|
|
|
22354 |
const walkerFn = forwards ? downUntil : upUntil;
|
|
|
22355 |
const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
|
|
|
22356 |
const nextLinePositions = filter$5(linePositions, isLine(1));
|
|
|
22357 |
const clientX = caretClientRect.left;
|
|
|
22358 |
const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
|
|
|
22359 |
if (nextLineRect && isElement(nextLineRect.node)) {
|
|
|
22360 |
const dist1 = Math.abs(clientX - nextLineRect.left);
|
|
|
22361 |
const dist2 = Math.abs(clientX - nextLineRect.right);
|
|
|
22362 |
return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
|
|
|
22363 |
}
|
|
|
22364 |
let currentNode;
|
|
|
22365 |
if (isBefore(caretPosition)) {
|
|
|
22366 |
currentNode = caretPosition.getNode();
|
|
|
22367 |
} else if (isAfter(caretPosition)) {
|
|
|
22368 |
currentNode = caretPosition.getNode(true);
|
|
|
22369 |
} else {
|
|
|
22370 |
currentNode = getSelectedNode(range);
|
|
|
22371 |
}
|
|
|
22372 |
if (currentNode) {
|
|
|
22373 |
const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
|
|
|
22374 |
let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX);
|
|
|
22375 |
if (closestNextLineRect) {
|
|
|
22376 |
return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
|
|
|
22377 |
}
|
| 1441 |
ariadna |
22378 |
closestNextLineRect = last$1(filter$5(caretPositions, isLine(0)));
|
| 1 |
efrain |
22379 |
if (closestNextLineRect) {
|
|
|
22380 |
return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
|
|
|
22381 |
}
|
|
|
22382 |
}
|
|
|
22383 |
if (nextLinePositions.length === 0) {
|
|
|
22384 |
return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false));
|
|
|
22385 |
}
|
|
|
22386 |
return Optional.none();
|
|
|
22387 |
};
|
|
|
22388 |
const getLineEndPoint = (editor, forward) => {
|
|
|
22389 |
const rng = editor.selection.getRng();
|
|
|
22390 |
const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
|
|
|
22391 |
const host = getEditingHost(from.container(), editor.getBody());
|
|
|
22392 |
if (forward) {
|
|
|
22393 |
const lineInfo = getPositionsUntilNextLine(host, from);
|
| 1441 |
ariadna |
22394 |
return last$2(lineInfo.positions);
|
| 1 |
efrain |
22395 |
} else {
|
|
|
22396 |
const lineInfo = getPositionsUntilPreviousLine(host, from);
|
|
|
22397 |
return head(lineInfo.positions);
|
|
|
22398 |
}
|
|
|
22399 |
};
|
|
|
22400 |
const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => {
|
|
|
22401 |
editor.selection.setRng(pos.toRange());
|
|
|
22402 |
return true;
|
|
|
22403 |
});
|
|
|
22404 |
|
|
|
22405 |
const setCaretPosition = (editor, pos) => {
|
|
|
22406 |
const rng = editor.dom.createRng();
|
|
|
22407 |
rng.setStart(pos.container(), pos.offset());
|
|
|
22408 |
rng.setEnd(pos.container(), pos.offset());
|
|
|
22409 |
editor.selection.setRng(rng);
|
|
|
22410 |
};
|
|
|
22411 |
const setSelected = (state, elm) => {
|
|
|
22412 |
if (state) {
|
|
|
22413 |
elm.setAttribute('data-mce-selected', 'inline-boundary');
|
|
|
22414 |
} else {
|
|
|
22415 |
elm.removeAttribute('data-mce-selected');
|
|
|
22416 |
}
|
|
|
22417 |
};
|
|
|
22418 |
const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => {
|
|
|
22419 |
setCaretPosition(editor, pos);
|
|
|
22420 |
return location;
|
|
|
22421 |
});
|
|
|
22422 |
const getPositionFromRange = (range, root, forward) => {
|
|
|
22423 |
const start = CaretPosition.fromRangeStart(range);
|
|
|
22424 |
if (range.collapsed) {
|
|
|
22425 |
return start;
|
|
|
22426 |
} else {
|
|
|
22427 |
const end = CaretPosition.fromRangeEnd(range);
|
|
|
22428 |
return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start);
|
|
|
22429 |
}
|
|
|
22430 |
};
|
|
|
22431 |
const findLocation = (editor, caret, forward) => {
|
|
|
22432 |
const rootNode = editor.getBody();
|
|
|
22433 |
const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
|
|
|
22434 |
const isInlineTarget$1 = curry(isInlineTarget, editor);
|
|
|
22435 |
const location = findLocation$1(forward, isInlineTarget$1, rootNode, from);
|
|
|
22436 |
return location.bind(location => renderCaretLocation(editor, caret, location));
|
|
|
22437 |
};
|
|
|
22438 |
const toggleInlines = (isInlineTarget, dom, elms) => {
|
|
|
22439 |
const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom);
|
|
|
22440 |
const selectedInlines = filter$5(inlineBoundaries, isInlineTarget);
|
|
|
22441 |
const targetInlines = filter$5(elms, isInlineTarget);
|
|
|
22442 |
each$e(difference(selectedInlines, targetInlines), curry(setSelected, false));
|
|
|
22443 |
each$e(difference(targetInlines, selectedInlines), curry(setSelected, true));
|
|
|
22444 |
};
|
|
|
22445 |
const safeRemoveCaretContainer = (editor, caret) => {
|
|
|
22446 |
const caretValue = caret.get();
|
|
|
22447 |
if (editor.selection.isCollapsed() && !editor.composing && caretValue) {
|
|
|
22448 |
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
22449 |
if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) {
|
|
|
22450 |
setCaretPosition(editor, removeAndReposition(caretValue, pos));
|
|
|
22451 |
caret.set(null);
|
|
|
22452 |
}
|
|
|
22453 |
}
|
|
|
22454 |
};
|
|
|
22455 |
const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => {
|
|
|
22456 |
if (editor.selection.isCollapsed()) {
|
|
|
22457 |
const inlines = filter$5(elms, isInlineTarget);
|
|
|
22458 |
each$e(inlines, _inline => {
|
|
|
22459 |
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
22460 |
readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location));
|
|
|
22461 |
});
|
|
|
22462 |
}
|
|
|
22463 |
};
|
|
|
22464 |
const move$3 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
|
|
|
22465 |
const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
|
|
|
22466 |
const setupSelectedState = editor => {
|
|
|
22467 |
const caret = Cell(null);
|
|
|
22468 |
const isInlineTarget$1 = curry(isInlineTarget, editor);
|
|
|
22469 |
editor.on('NodeChange', e => {
|
|
|
22470 |
if (isInlineBoundariesEnabled(editor)) {
|
|
|
22471 |
toggleInlines(isInlineTarget$1, editor.dom, e.parents);
|
|
|
22472 |
safeRemoveCaretContainer(editor, caret);
|
|
|
22473 |
renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
|
|
|
22474 |
}
|
|
|
22475 |
});
|
|
|
22476 |
return caret;
|
|
|
22477 |
};
|
|
|
22478 |
const moveNextWord = curry(moveWord, true);
|
|
|
22479 |
const movePrevWord = curry(moveWord, false);
|
|
|
22480 |
const moveToLineEndPoint$2 = (editor, forward, caret) => {
|
|
|
22481 |
if (isInlineBoundariesEnabled(editor)) {
|
|
|
22482 |
const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
|
|
|
22483 |
const rng = editor.selection.getRng();
|
|
|
22484 |
return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
|
|
|
22485 |
});
|
|
|
22486 |
return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => {
|
|
|
22487 |
const outsideLoc = outside(loc);
|
|
|
22488 |
return renderCaret(caret, outsideLoc).exists(pos => {
|
|
|
22489 |
setCaretPosition(editor, pos);
|
|
|
22490 |
return true;
|
|
|
22491 |
});
|
|
|
22492 |
});
|
|
|
22493 |
} else {
|
|
|
22494 |
return false;
|
|
|
22495 |
}
|
|
|
22496 |
};
|
|
|
22497 |
|
|
|
22498 |
const rangeFromPositions = (from, to) => {
|
|
|
22499 |
const range = document.createRange();
|
|
|
22500 |
range.setStart(from.container(), from.offset());
|
|
|
22501 |
range.setEnd(to.container(), to.offset());
|
|
|
22502 |
return range;
|
|
|
22503 |
};
|
|
|
22504 |
const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
|
|
|
22505 |
const normalizedFirstPos = normalizePosition(true, firstPos);
|
|
|
22506 |
const normalizedLastPos = normalizePosition(false, lastPos);
|
|
|
22507 |
return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos));
|
|
|
22508 |
}).getOr(true);
|
|
|
22509 |
const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos));
|
|
|
22510 |
const deleteFromTo = (editor, caret, from, to) => {
|
|
|
22511 |
const rootNode = editor.getBody();
|
|
|
22512 |
const isInlineTarget$1 = curry(isInlineTarget, editor);
|
|
|
22513 |
editor.undoManager.ignore(() => {
|
|
|
22514 |
editor.selection.setRng(rangeFromPositions(from, to));
|
|
|
22515 |
execNativeDeleteCommand(editor);
|
|
|
22516 |
readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
|
|
|
22517 |
});
|
|
|
22518 |
editor.nodeChanged();
|
|
|
22519 |
};
|
|
|
22520 |
const rescope = (rootNode, node) => {
|
|
|
22521 |
const parentBlock = getParentBlock$3(node, rootNode);
|
|
|
22522 |
return parentBlock ? parentBlock : rootNode;
|
|
|
22523 |
};
|
|
|
22524 |
const backspaceDeleteCollapsed = (editor, caret, forward, from) => {
|
|
|
22525 |
const rootNode = rescope(editor.getBody(), from.container());
|
|
|
22526 |
const isInlineTarget$1 = curry(isInlineTarget, editor);
|
|
|
22527 |
const fromLocation = readLocation(isInlineTarget$1, rootNode, from);
|
|
|
22528 |
const location = fromLocation.bind(location => {
|
|
|
22529 |
if (forward) {
|
|
|
22530 |
return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none);
|
|
|
22531 |
} else {
|
|
|
22532 |
return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location))));
|
|
|
22533 |
}
|
|
|
22534 |
});
|
|
|
22535 |
return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
|
|
|
22536 |
const toPosition = navigate(forward, rootNode, from);
|
|
|
22537 |
const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos));
|
|
|
22538 |
return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => {
|
|
|
22539 |
if (hasOnlyTwoOrLessPositionsLeft(elm)) {
|
|
|
22540 |
return Optional.some(() => {
|
|
|
22541 |
deleteElement$2(editor, forward, SugarElement.fromDom(elm));
|
|
|
22542 |
});
|
|
|
22543 |
} else {
|
|
|
22544 |
return Optional.none();
|
|
|
22545 |
}
|
|
|
22546 |
})).getOrThunk(() => toLocation.bind(() => toPosition.map(to => {
|
|
|
22547 |
return () => {
|
|
|
22548 |
if (forward) {
|
|
|
22549 |
deleteFromTo(editor, caret, from, to);
|
|
|
22550 |
} else {
|
|
|
22551 |
deleteFromTo(editor, caret, to, from);
|
|
|
22552 |
}
|
|
|
22553 |
};
|
|
|
22554 |
})));
|
|
|
22555 |
});
|
|
|
22556 |
};
|
|
|
22557 |
const backspaceDelete$4 = (editor, caret, forward) => {
|
|
|
22558 |
if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
|
|
|
22559 |
const from = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
22560 |
return backspaceDeleteCollapsed(editor, caret, forward, from);
|
|
|
22561 |
}
|
|
|
22562 |
return Optional.none();
|
|
|
22563 |
};
|
|
|
22564 |
|
|
|
22565 |
const hasMultipleChildren = elm => childNodesCount(elm) > 1;
|
|
|
22566 |
const getParentsUntil = (editor, pred) => {
|
|
|
22567 |
const rootElm = SugarElement.fromDom(editor.getBody());
|
|
|
22568 |
const startElm = SugarElement.fromDom(editor.selection.getStart());
|
|
|
22569 |
const parents = parentsAndSelf(startElm, rootElm);
|
|
|
22570 |
return findIndex$2(parents, pred).fold(constant(parents), index => parents.slice(0, index));
|
|
|
22571 |
};
|
|
|
22572 |
const hasOnlyOneChild = elm => childNodesCount(elm) === 1;
|
|
|
22573 |
const getParentInlinesUntilMultichildInline = editor => getParentsUntil(editor, elm => editor.schema.isBlock(name(elm)) || hasMultipleChildren(elm));
|
|
|
22574 |
const getParentInlines = editor => getParentsUntil(editor, el => editor.schema.isBlock(name(el)));
|
|
|
22575 |
const getFormatNodes = (editor, parentInlines) => {
|
|
|
22576 |
const isFormatElement$1 = curry(isFormatElement, editor);
|
|
|
22577 |
return bind$3(parentInlines, elm => isFormatElement$1(elm) ? [elm.dom] : []);
|
|
|
22578 |
};
|
|
|
22579 |
const getFormatNodesAtStart = editor => {
|
|
|
22580 |
const parentInlines = getParentInlines(editor);
|
|
|
22581 |
return getFormatNodes(editor, parentInlines);
|
|
|
22582 |
};
|
|
|
22583 |
const deleteLastPosition = (forward, editor, target, parentInlines) => {
|
|
|
22584 |
const formatNodes = getFormatNodes(editor, parentInlines);
|
|
|
22585 |
if (formatNodes.length === 0) {
|
|
|
22586 |
deleteElement$2(editor, forward, target);
|
|
|
22587 |
} else {
|
|
|
22588 |
const pos = replaceWithCaretFormat(target.dom, formatNodes);
|
|
|
22589 |
editor.selection.setRng(pos.toRange());
|
|
|
22590 |
}
|
|
|
22591 |
};
|
|
|
22592 |
const deleteCaret$1 = (editor, forward) => {
|
|
|
22593 |
const parentInlines = filter$5(getParentInlinesUntilMultichildInline(editor), hasOnlyOneChild);
|
| 1441 |
ariadna |
22594 |
return last$2(parentInlines).bind(target => {
|
| 1 |
efrain |
22595 |
const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
22596 |
if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
|
|
|
22597 |
return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
|
|
|
22598 |
} else {
|
|
|
22599 |
return Optional.none();
|
|
|
22600 |
}
|
|
|
22601 |
});
|
|
|
22602 |
};
|
|
|
22603 |
const isBrInEmptyElement = (editor, elm) => {
|
|
|
22604 |
const parentElm = elm.parentElement;
|
|
|
22605 |
return isBr$6(elm) && !isNull(parentElm) && editor.dom.isEmpty(parentElm);
|
|
|
22606 |
};
|
|
|
22607 |
const isEmptyCaret = elm => isEmptyCaretFormatElement(SugarElement.fromDom(elm));
|
|
|
22608 |
const createCaretFormatAtStart = (editor, formatNodes) => {
|
|
|
22609 |
const startElm = editor.selection.getStart();
|
|
|
22610 |
const pos = isBrInEmptyElement(editor, startElm) || isEmptyCaret(startElm) ? replaceWithCaretFormat(startElm, formatNodes) : createCaretFormatAtStart$1(editor.selection.getRng(), formatNodes);
|
|
|
22611 |
editor.selection.setRng(pos.toRange());
|
|
|
22612 |
};
|
|
|
22613 |
const updateCaretFormat = (editor, updateFormats) => {
|
|
|
22614 |
const missingFormats = difference(updateFormats, getFormatNodesAtStart(editor));
|
|
|
22615 |
if (missingFormats.length > 0) {
|
|
|
22616 |
createCaretFormatAtStart(editor, missingFormats);
|
|
|
22617 |
}
|
|
|
22618 |
};
|
| 1441 |
ariadna |
22619 |
const rangeStartsAtTextContainer = rng => isText$b(rng.startContainer);
|
| 1 |
efrain |
22620 |
const rangeStartsAtStartOfTextContainer = rng => rng.startOffset === 0 && rangeStartsAtTextContainer(rng);
|
|
|
22621 |
const rangeStartParentIsFormatElement = (editor, rng) => {
|
|
|
22622 |
const startParent = rng.startContainer.parentElement;
|
|
|
22623 |
return !isNull(startParent) && isFormatElement(editor, SugarElement.fromDom(startParent));
|
|
|
22624 |
};
|
|
|
22625 |
const rangeStartAndEndHaveSameParent = rng => {
|
|
|
22626 |
const startParent = rng.startContainer.parentNode;
|
|
|
22627 |
const endParent = rng.endContainer.parentNode;
|
|
|
22628 |
return !isNull(startParent) && !isNull(endParent) && startParent.isEqualNode(endParent);
|
|
|
22629 |
};
|
|
|
22630 |
const rangeEndsAtEndOfEndContainer = rng => {
|
|
|
22631 |
const endContainer = rng.endContainer;
|
| 1441 |
ariadna |
22632 |
return rng.endOffset === (isText$b(endContainer) ? endContainer.length : endContainer.childNodes.length);
|
| 1 |
efrain |
22633 |
};
|
|
|
22634 |
const rangeEndsAtEndOfStartContainer = rng => rangeStartAndEndHaveSameParent(rng) && rangeEndsAtEndOfEndContainer(rng);
|
|
|
22635 |
const rangeEndsAfterEndOfStartContainer = rng => !rng.endContainer.isEqualNode(rng.commonAncestorContainer);
|
|
|
22636 |
const rangeEndsAtOrAfterEndOfStartContainer = rng => rangeEndsAtEndOfStartContainer(rng) || rangeEndsAfterEndOfStartContainer(rng);
|
|
|
22637 |
const requiresDeleteRangeOverride = editor => {
|
|
|
22638 |
const rng = editor.selection.getRng();
|
|
|
22639 |
return rangeStartsAtStartOfTextContainer(rng) && rangeStartParentIsFormatElement(editor, rng) && rangeEndsAtOrAfterEndOfStartContainer(rng);
|
|
|
22640 |
};
|
|
|
22641 |
const deleteRange$1 = editor => {
|
|
|
22642 |
if (requiresDeleteRangeOverride(editor)) {
|
|
|
22643 |
const formatNodes = getFormatNodesAtStart(editor);
|
|
|
22644 |
return Optional.some(() => {
|
|
|
22645 |
execNativeDeleteCommand(editor);
|
|
|
22646 |
updateCaretFormat(editor, formatNodes);
|
|
|
22647 |
});
|
|
|
22648 |
} else {
|
|
|
22649 |
return Optional.none();
|
|
|
22650 |
}
|
|
|
22651 |
};
|
|
|
22652 |
const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : deleteRange$1(editor);
|
| 1441 |
ariadna |
22653 |
const hasAncestorInlineCaret = (elm, schema) => ancestor$2(elm, node => isCaretNode(node.dom), el => schema.isBlock(name(el)));
|
| 1 |
efrain |
22654 |
const hasAncestorInlineCaretAtStart = editor => hasAncestorInlineCaret(SugarElement.fromDom(editor.selection.getStart()), editor.schema);
|
|
|
22655 |
const requiresRefreshCaretOverride = editor => {
|
|
|
22656 |
const rng = editor.selection.getRng();
|
|
|
22657 |
return rng.collapsed && (rangeStartsAtTextContainer(rng) || editor.dom.isEmpty(rng.startContainer)) && !hasAncestorInlineCaretAtStart(editor);
|
|
|
22658 |
};
|
|
|
22659 |
const refreshCaret = editor => {
|
|
|
22660 |
if (requiresRefreshCaretOverride(editor)) {
|
|
|
22661 |
createCaretFormatAtStart(editor, []);
|
|
|
22662 |
}
|
|
|
22663 |
return true;
|
|
|
22664 |
};
|
|
|
22665 |
|
|
|
22666 |
const deleteElement = (editor, forward, element) => {
|
|
|
22667 |
if (isNonNullable(element)) {
|
|
|
22668 |
return Optional.some(() => {
|
|
|
22669 |
editor._selectionOverrides.hideFakeCaret();
|
|
|
22670 |
deleteElement$2(editor, forward, SugarElement.fromDom(element));
|
|
|
22671 |
});
|
|
|
22672 |
} else {
|
|
|
22673 |
return Optional.none();
|
|
|
22674 |
}
|
|
|
22675 |
};
|
|
|
22676 |
const deleteCaret = (editor, forward) => {
|
|
|
22677 |
const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
|
| 1441 |
ariadna |
22678 |
const direction = forward ? 1 : -1;
|
| 1 |
efrain |
22679 |
const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
|
|
|
22680 |
if (isNearMedia(fromPos)) {
|
|
|
22681 |
return deleteElement(editor, forward, fromPos.getNode(!forward));
|
|
|
22682 |
} else {
|
|
|
22683 |
return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward)));
|
|
|
22684 |
}
|
|
|
22685 |
};
|
|
|
22686 |
const deleteRange = (editor, forward) => {
|
|
|
22687 |
const selectedNode = editor.selection.getNode();
|
|
|
22688 |
return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
|
|
|
22689 |
};
|
|
|
22690 |
const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
|
|
|
22691 |
|
|
|
22692 |
const isEditable = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$b(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom));
|
|
|
22693 |
const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0);
|
|
|
22694 |
const getIndentStyleName = (useMargin, element) => {
|
|
|
22695 |
const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
|
|
|
22696 |
const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left';
|
|
|
22697 |
return indentStyleName + suffix;
|
|
|
22698 |
};
|
|
|
22699 |
const indentElement = (dom, command, useMargin, value, unit, element) => {
|
|
|
22700 |
const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
|
|
|
22701 |
const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName));
|
|
|
22702 |
if (command === 'outdent') {
|
|
|
22703 |
const styleValue = Math.max(0, parsedValue - value);
|
|
|
22704 |
dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
|
|
|
22705 |
} else {
|
|
|
22706 |
const styleValue = parsedValue + value + unit;
|
|
|
22707 |
dom.setStyle(element, indentStyleName, styleValue);
|
|
|
22708 |
}
|
|
|
22709 |
};
|
|
|
22710 |
const validateBlocks = (editor, blocks) => forall(blocks, block => {
|
|
|
22711 |
const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
|
|
|
22712 |
const intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0);
|
|
|
22713 |
const contentEditable = editor.dom.getContentEditable(block.dom);
|
|
|
22714 |
return contentEditable !== 'false' && intentValue > 0;
|
|
|
22715 |
});
|
|
|
22716 |
const canOutdent = editor => {
|
|
|
22717 |
const blocks = getBlocksToIndent(editor);
|
|
|
22718 |
return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks));
|
|
|
22719 |
};
|
|
|
22720 |
const isListComponent = el => isList(el) || isListItem$1(el);
|
|
|
22721 |
const parentIsListComponent = el => parent(el).exists(isListComponent);
|
|
|
22722 |
const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el));
|
|
|
22723 |
const handle = (editor, command) => {
|
|
|
22724 |
var _a, _b;
|
| 1441 |
ariadna |
22725 |
if (editor.mode.isReadOnly()) {
|
|
|
22726 |
return;
|
|
|
22727 |
}
|
| 1 |
efrain |
22728 |
const {dom} = editor;
|
|
|
22729 |
const indentation = getIndentation(editor);
|
|
|
22730 |
const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
|
|
|
22731 |
const indentValue = parseIndentValue(indentation);
|
|
|
22732 |
const useMargin = shouldIndentUseMargin(editor);
|
|
|
22733 |
each$e(getBlocksToIndent(editor), block => {
|
|
|
22734 |
indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom);
|
|
|
22735 |
});
|
|
|
22736 |
};
|
|
|
22737 |
const indent = editor => handle(editor, 'indent');
|
|
|
22738 |
const outdent = editor => handle(editor, 'outdent');
|
|
|
22739 |
|
|
|
22740 |
const backspaceDelete$1 = editor => {
|
|
|
22741 |
if (editor.selection.isCollapsed() && canOutdent(editor)) {
|
|
|
22742 |
const dom = editor.dom;
|
|
|
22743 |
const rng = editor.selection.getRng();
|
|
|
22744 |
const pos = CaretPosition.fromRangeStart(rng);
|
|
|
22745 |
const block = dom.getParent(rng.startContainer, dom.isBlock);
|
|
|
22746 |
if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos, editor.schema)) {
|
|
|
22747 |
return Optional.some(() => outdent(editor));
|
|
|
22748 |
}
|
|
|
22749 |
}
|
|
|
22750 |
return Optional.none();
|
|
|
22751 |
};
|
|
|
22752 |
|
|
|
22753 |
const findAction = (editor, caret, forward) => findMap([
|
|
|
22754 |
backspaceDelete$1,
|
|
|
22755 |
backspaceDelete$7,
|
| 1441 |
ariadna |
22756 |
backspaceDelete$8,
|
| 1 |
efrain |
22757 |
(editor, forward) => backspaceDelete$4(editor, caret, forward),
|
|
|
22758 |
backspaceDelete$a,
|
| 1441 |
ariadna |
22759 |
backspaceDelete$b,
|
| 1 |
efrain |
22760 |
backspaceDelete$5,
|
|
|
22761 |
backspaceDelete$2,
|
| 1441 |
ariadna |
22762 |
backspaceDelete$9,
|
|
|
22763 |
backspaceDelete$3,
|
|
|
22764 |
backspaceDelete$6
|
| 1 |
efrain |
22765 |
], item => item(editor, forward)).filter(_ => editor.selection.isEditable());
|
|
|
22766 |
const deleteCommand = (editor, caret) => {
|
|
|
22767 |
const result = findAction(editor, caret, false);
|
|
|
22768 |
result.fold(() => {
|
|
|
22769 |
if (editor.selection.isEditable()) {
|
|
|
22770 |
execNativeDeleteCommand(editor);
|
|
|
22771 |
paddEmptyBody(editor);
|
|
|
22772 |
}
|
|
|
22773 |
}, call);
|
|
|
22774 |
};
|
|
|
22775 |
const forwardDeleteCommand = (editor, caret) => {
|
|
|
22776 |
const result = findAction(editor, caret, true);
|
|
|
22777 |
result.fold(() => {
|
|
|
22778 |
if (editor.selection.isEditable()) {
|
|
|
22779 |
execNativeForwardDeleteCommand(editor);
|
|
|
22780 |
}
|
|
|
22781 |
}, call);
|
|
|
22782 |
};
|
|
|
22783 |
const setup$q = (editor, caret) => {
|
|
|
22784 |
editor.addCommand('delete', () => {
|
|
|
22785 |
deleteCommand(editor, caret);
|
|
|
22786 |
});
|
|
|
22787 |
editor.addCommand('forwardDelete', () => {
|
|
|
22788 |
forwardDeleteCommand(editor, caret);
|
|
|
22789 |
});
|
|
|
22790 |
};
|
|
|
22791 |
|
|
|
22792 |
const SIGNIFICANT_MOVE = 5;
|
|
|
22793 |
const LONGPRESS_DELAY = 400;
|
|
|
22794 |
const getTouch = event => {
|
|
|
22795 |
if (event.touches === undefined || event.touches.length !== 1) {
|
|
|
22796 |
return Optional.none();
|
|
|
22797 |
}
|
|
|
22798 |
return Optional.some(event.touches[0]);
|
|
|
22799 |
};
|
|
|
22800 |
const isFarEnough = (touch, data) => {
|
|
|
22801 |
const distX = Math.abs(touch.clientX - data.x);
|
|
|
22802 |
const distY = Math.abs(touch.clientY - data.y);
|
|
|
22803 |
return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
|
|
|
22804 |
};
|
|
|
22805 |
const setup$p = editor => {
|
|
|
22806 |
const startData = value$2();
|
|
|
22807 |
const longpressFired = Cell(false);
|
| 1441 |
ariadna |
22808 |
const debounceLongpress = last(e => {
|
| 1 |
efrain |
22809 |
editor.dispatch('longpress', {
|
|
|
22810 |
...e,
|
|
|
22811 |
type: 'longpress'
|
|
|
22812 |
});
|
|
|
22813 |
longpressFired.set(true);
|
|
|
22814 |
}, LONGPRESS_DELAY);
|
|
|
22815 |
editor.on('touchstart', e => {
|
|
|
22816 |
getTouch(e).each(touch => {
|
|
|
22817 |
debounceLongpress.cancel();
|
|
|
22818 |
const data = {
|
|
|
22819 |
x: touch.clientX,
|
|
|
22820 |
y: touch.clientY,
|
|
|
22821 |
target: e.target
|
|
|
22822 |
};
|
|
|
22823 |
debounceLongpress.throttle(e);
|
|
|
22824 |
longpressFired.set(false);
|
|
|
22825 |
startData.set(data);
|
|
|
22826 |
});
|
|
|
22827 |
}, true);
|
|
|
22828 |
editor.on('touchmove', e => {
|
|
|
22829 |
debounceLongpress.cancel();
|
|
|
22830 |
getTouch(e).each(touch => {
|
|
|
22831 |
startData.on(data => {
|
|
|
22832 |
if (isFarEnough(touch, data)) {
|
|
|
22833 |
startData.clear();
|
|
|
22834 |
longpressFired.set(false);
|
|
|
22835 |
editor.dispatch('longpresscancel');
|
|
|
22836 |
}
|
|
|
22837 |
});
|
|
|
22838 |
});
|
|
|
22839 |
}, true);
|
|
|
22840 |
editor.on('touchend touchcancel', e => {
|
|
|
22841 |
debounceLongpress.cancel();
|
|
|
22842 |
if (e.type === 'touchcancel') {
|
|
|
22843 |
return;
|
|
|
22844 |
}
|
|
|
22845 |
startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => {
|
|
|
22846 |
if (longpressFired.get()) {
|
|
|
22847 |
e.preventDefault();
|
|
|
22848 |
} else {
|
|
|
22849 |
editor.dispatch('tap', {
|
|
|
22850 |
...e,
|
|
|
22851 |
type: 'tap'
|
|
|
22852 |
});
|
|
|
22853 |
}
|
|
|
22854 |
});
|
|
|
22855 |
}, true);
|
|
|
22856 |
};
|
|
|
22857 |
|
|
|
22858 |
const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
|
|
|
22859 |
const isValidTarget = (schema, node) => {
|
| 1441 |
ariadna |
22860 |
if (isText$b(node)) {
|
| 1 |
efrain |
22861 |
return true;
|
|
|
22862 |
} else if (isElement$6(node)) {
|
|
|
22863 |
return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node) && !isNonHtmlElementRoot(node);
|
|
|
22864 |
} else {
|
|
|
22865 |
return false;
|
|
|
22866 |
}
|
|
|
22867 |
};
|
|
|
22868 |
const hasBlockParent = (blockElements, root, node) => {
|
|
|
22869 |
return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => {
|
|
|
22870 |
return isBlockElement(blockElements, elm.dom);
|
|
|
22871 |
});
|
|
|
22872 |
};
|
|
|
22873 |
const shouldRemoveTextNode = (blockElements, node) => {
|
| 1441 |
ariadna |
22874 |
if (isText$b(node)) {
|
| 1 |
efrain |
22875 |
if (node.data.length === 0) {
|
|
|
22876 |
return true;
|
|
|
22877 |
} else if (/^\s+$/.test(node.data)) {
|
|
|
22878 |
return !node.nextSibling || isBlockElement(blockElements, node.nextSibling) || isNonHtmlElementRoot(node.nextSibling);
|
|
|
22879 |
}
|
|
|
22880 |
}
|
|
|
22881 |
return false;
|
|
|
22882 |
};
|
|
|
22883 |
const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
|
|
|
22884 |
const addRootBlocks = editor => {
|
|
|
22885 |
const dom = editor.dom, selection = editor.selection;
|
|
|
22886 |
const schema = editor.schema;
|
|
|
22887 |
const blockElements = schema.getBlockElements();
|
|
|
22888 |
const startNode = selection.getStart();
|
|
|
22889 |
const rootNode = editor.getBody();
|
|
|
22890 |
let rootBlockNode;
|
|
|
22891 |
let tempNode;
|
| 1441 |
ariadna |
22892 |
let bm = null;
|
| 1 |
efrain |
22893 |
const forcedRootBlock = getForcedRootBlock(editor);
|
|
|
22894 |
if (!startNode || !isElement$6(startNode)) {
|
|
|
22895 |
return;
|
|
|
22896 |
}
|
|
|
22897 |
const rootNodeName = rootNode.nodeName.toLowerCase();
|
|
|
22898 |
if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) {
|
|
|
22899 |
return;
|
|
|
22900 |
}
|
| 1441 |
ariadna |
22901 |
if (rootNode.firstChild === rootNode.lastChild && isBr$6(rootNode.firstChild)) {
|
|
|
22902 |
rootBlockNode = createRootBlock(editor);
|
|
|
22903 |
rootBlockNode.appendChild(createPaddingBr().dom);
|
|
|
22904 |
rootNode.replaceChild(rootBlockNode, rootNode.firstChild);
|
|
|
22905 |
editor.selection.setCursorLocation(rootBlockNode, 0);
|
|
|
22906 |
editor.nodeChanged();
|
|
|
22907 |
return;
|
|
|
22908 |
}
|
| 1 |
efrain |
22909 |
let node = rootNode.firstChild;
|
|
|
22910 |
while (node) {
|
|
|
22911 |
if (isElement$6(node)) {
|
|
|
22912 |
updateElement(schema, node);
|
|
|
22913 |
}
|
|
|
22914 |
if (isValidTarget(schema, node)) {
|
|
|
22915 |
if (shouldRemoveTextNode(blockElements, node)) {
|
|
|
22916 |
tempNode = node;
|
|
|
22917 |
node = node.nextSibling;
|
|
|
22918 |
dom.remove(tempNode);
|
|
|
22919 |
continue;
|
|
|
22920 |
}
|
|
|
22921 |
if (!rootBlockNode) {
|
| 1441 |
ariadna |
22922 |
if (!bm && editor.hasFocus()) {
|
|
|
22923 |
bm = getBookmark(editor.selection.getRng(), () => document.createElement('span'));
|
|
|
22924 |
}
|
|
|
22925 |
if (!node.parentNode) {
|
|
|
22926 |
node = null;
|
|
|
22927 |
break;
|
|
|
22928 |
}
|
| 1 |
efrain |
22929 |
rootBlockNode = createRootBlock(editor);
|
|
|
22930 |
rootNode.insertBefore(rootBlockNode, node);
|
|
|
22931 |
}
|
|
|
22932 |
tempNode = node;
|
|
|
22933 |
node = node.nextSibling;
|
|
|
22934 |
rootBlockNode.appendChild(tempNode);
|
|
|
22935 |
} else {
|
|
|
22936 |
rootBlockNode = null;
|
|
|
22937 |
node = node.nextSibling;
|
|
|
22938 |
}
|
|
|
22939 |
}
|
| 1441 |
ariadna |
22940 |
if (bm) {
|
|
|
22941 |
editor.selection.setRng(resolveBookmark(bm));
|
| 1 |
efrain |
22942 |
editor.nodeChanged();
|
|
|
22943 |
}
|
|
|
22944 |
};
|
|
|
22945 |
const insertEmptyLine = (editor, root, insertBlock) => {
|
|
|
22946 |
const block = SugarElement.fromDom(createRootBlock(editor));
|
|
|
22947 |
const br = createPaddingBr();
|
|
|
22948 |
append$1(block, br);
|
|
|
22949 |
insertBlock(root, block);
|
|
|
22950 |
const rng = document.createRange();
|
|
|
22951 |
rng.setStartBefore(br.dom);
|
|
|
22952 |
rng.setEndBefore(br.dom);
|
|
|
22953 |
return rng;
|
|
|
22954 |
};
|
|
|
22955 |
const setup$o = editor => {
|
| 1441 |
ariadna |
22956 |
editor.on('NodeChange', () => addRootBlocks(editor));
|
| 1 |
efrain |
22957 |
};
|
|
|
22958 |
|
|
|
22959 |
const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1;
|
|
|
22960 |
const replaceMatchWithSpan = (editor, content, cls) => {
|
|
|
22961 |
return function (match) {
|
|
|
22962 |
const args = arguments, index = args[args.length - 2];
|
|
|
22963 |
const prevChar = index > 0 ? content.charAt(index - 1) : '';
|
|
|
22964 |
if (prevChar === '"') {
|
|
|
22965 |
return match;
|
|
|
22966 |
}
|
|
|
22967 |
if (prevChar === '>') {
|
|
|
22968 |
const findStartTagIndex = content.lastIndexOf('<', index);
|
|
|
22969 |
if (findStartTagIndex !== -1) {
|
|
|
22970 |
const tagHtml = content.substring(findStartTagIndex, index);
|
|
|
22971 |
if (tagHtml.indexOf('contenteditable="false"') !== -1) {
|
|
|
22972 |
return match;
|
|
|
22973 |
}
|
|
|
22974 |
}
|
|
|
22975 |
}
|
|
|
22976 |
return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '</span>';
|
|
|
22977 |
};
|
|
|
22978 |
};
|
|
|
22979 |
const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
|
|
|
22980 |
let i = nonEditableRegExps.length, content = e.content;
|
|
|
22981 |
if (e.format === 'raw') {
|
|
|
22982 |
return;
|
|
|
22983 |
}
|
|
|
22984 |
while (i--) {
|
|
|
22985 |
content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
|
|
|
22986 |
}
|
|
|
22987 |
e.content = content;
|
|
|
22988 |
};
|
| 1441 |
ariadna |
22989 |
const isValidContent = (nonEditableRegExps, content) => {
|
|
|
22990 |
return forall(nonEditableRegExps, re => {
|
|
|
22991 |
const matches = content.match(re);
|
|
|
22992 |
return matches !== null && matches[0].length === content.length;
|
|
|
22993 |
});
|
|
|
22994 |
};
|
| 1 |
efrain |
22995 |
const setup$n = editor => {
|
|
|
22996 |
const contentEditableAttrName = 'contenteditable';
|
|
|
22997 |
const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' ';
|
|
|
22998 |
const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' ';
|
|
|
22999 |
const hasEditClass = hasClass(editClass);
|
|
|
23000 |
const hasNonEditClass = hasClass(nonEditClass);
|
|
|
23001 |
const nonEditableRegExps = getNonEditableRegExps(editor);
|
|
|
23002 |
if (nonEditableRegExps.length > 0) {
|
|
|
23003 |
editor.on('BeforeSetContent', e => {
|
|
|
23004 |
convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
|
|
|
23005 |
});
|
|
|
23006 |
}
|
|
|
23007 |
editor.parser.addAttributeFilter('class', nodes => {
|
|
|
23008 |
let i = nodes.length;
|
|
|
23009 |
while (i--) {
|
|
|
23010 |
const node = nodes[i];
|
|
|
23011 |
if (hasEditClass(node)) {
|
|
|
23012 |
node.attr(contentEditableAttrName, 'true');
|
|
|
23013 |
} else if (hasNonEditClass(node)) {
|
|
|
23014 |
node.attr(contentEditableAttrName, 'false');
|
|
|
23015 |
}
|
|
|
23016 |
}
|
|
|
23017 |
});
|
|
|
23018 |
editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => {
|
|
|
23019 |
let i = nodes.length;
|
|
|
23020 |
while (i--) {
|
|
|
23021 |
const node = nodes[i];
|
|
|
23022 |
if (!hasEditClass(node) && !hasNonEditClass(node)) {
|
|
|
23023 |
continue;
|
|
|
23024 |
}
|
| 1441 |
ariadna |
23025 |
const content = node.attr('data-mce-content');
|
|
|
23026 |
if (nonEditableRegExps.length > 0 && content) {
|
|
|
23027 |
if (isValidContent(nonEditableRegExps, content)) {
|
|
|
23028 |
node.name = '#text';
|
|
|
23029 |
node.type = 3;
|
|
|
23030 |
node.raw = true;
|
|
|
23031 |
node.value = content;
|
|
|
23032 |
} else {
|
|
|
23033 |
node.remove();
|
|
|
23034 |
}
|
| 1 |
efrain |
23035 |
} else {
|
|
|
23036 |
node.attr(contentEditableAttrName, null);
|
|
|
23037 |
}
|
|
|
23038 |
}
|
|
|
23039 |
});
|
|
|
23040 |
};
|
|
|
23041 |
|
|
|
23042 |
const findBlockCaretContainer = editor => descendant$1(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull();
|
|
|
23043 |
const showBlockCaretContainer = (editor, blockCaretContainer) => {
|
|
|
23044 |
if (blockCaretContainer.hasAttribute('data-mce-caret')) {
|
|
|
23045 |
showCaretContainerBlock(blockCaretContainer);
|
|
|
23046 |
editor.selection.setRng(editor.selection.getRng());
|
|
|
23047 |
editor.selection.scrollIntoView(blockCaretContainer);
|
|
|
23048 |
}
|
|
|
23049 |
};
|
|
|
23050 |
const handleBlockContainer = (editor, e) => {
|
|
|
23051 |
const blockCaretContainer = findBlockCaretContainer(editor);
|
|
|
23052 |
if (!blockCaretContainer) {
|
|
|
23053 |
return;
|
|
|
23054 |
}
|
|
|
23055 |
if (e.type === 'compositionstart') {
|
|
|
23056 |
e.preventDefault();
|
|
|
23057 |
e.stopPropagation();
|
|
|
23058 |
showBlockCaretContainer(editor, blockCaretContainer);
|
|
|
23059 |
return;
|
|
|
23060 |
}
|
|
|
23061 |
if (hasContent(blockCaretContainer)) {
|
|
|
23062 |
showBlockCaretContainer(editor, blockCaretContainer);
|
|
|
23063 |
editor.undoManager.add();
|
|
|
23064 |
}
|
|
|
23065 |
};
|
|
|
23066 |
const setup$m = editor => {
|
|
|
23067 |
editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
|
|
|
23068 |
};
|
|
|
23069 |
|
| 1441 |
ariadna |
23070 |
const isContentEditableFalse$4 = isContentEditableFalse$b;
|
|
|
23071 |
const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$4);
|
| 1 |
efrain |
23072 |
const moveToCeFalseVertically = (direction, editor, range) => {
|
|
|
23073 |
const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
|
|
|
23074 |
const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
|
| 1441 |
ariadna |
23075 |
return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$4);
|
| 1 |
efrain |
23076 |
};
|
|
|
23077 |
const createTextBlock = editor => {
|
|
|
23078 |
const textBlock = editor.dom.create(getForcedRootBlock(editor));
|
|
|
23079 |
textBlock.innerHTML = '<br data-mce-bogus="1">';
|
|
|
23080 |
return textBlock;
|
|
|
23081 |
};
|
|
|
23082 |
const exitPreBlock = (editor, direction, range) => {
|
|
|
23083 |
const caretWalker = CaretWalker(editor.getBody());
|
|
|
23084 |
const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
|
|
|
23085 |
if (range.collapsed) {
|
|
|
23086 |
const pre = editor.dom.getParent(range.startContainer, 'PRE');
|
|
|
23087 |
if (!pre) {
|
|
|
23088 |
return;
|
|
|
23089 |
}
|
|
|
23090 |
const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range));
|
|
|
23091 |
if (!caretPos) {
|
|
|
23092 |
const newBlock = SugarElement.fromDom(createTextBlock(editor));
|
|
|
23093 |
if (direction === 1) {
|
|
|
23094 |
after$4(SugarElement.fromDom(pre), newBlock);
|
|
|
23095 |
} else {
|
|
|
23096 |
before$3(SugarElement.fromDom(pre), newBlock);
|
|
|
23097 |
}
|
|
|
23098 |
editor.selection.select(newBlock.dom, true);
|
|
|
23099 |
editor.selection.collapse();
|
|
|
23100 |
}
|
|
|
23101 |
}
|
|
|
23102 |
};
|
|
|
23103 |
const getHorizontalRange = (editor, forward) => {
|
| 1441 |
ariadna |
23104 |
const direction = forward ? 1 : -1;
|
| 1 |
efrain |
23105 |
const range = editor.selection.getRng();
|
|
|
23106 |
return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => {
|
|
|
23107 |
exitPreBlock(editor, direction, range);
|
|
|
23108 |
return Optional.none();
|
|
|
23109 |
});
|
|
|
23110 |
};
|
|
|
23111 |
const getVerticalRange = (editor, down) => {
|
|
|
23112 |
const direction = down ? 1 : -1;
|
|
|
23113 |
const range = editor.selection.getRng();
|
|
|
23114 |
return moveToCeFalseVertically(direction, editor, range).orThunk(() => {
|
|
|
23115 |
exitPreBlock(editor, direction, range);
|
|
|
23116 |
return Optional.none();
|
|
|
23117 |
});
|
|
|
23118 |
};
|
|
|
23119 |
const flipDirection = (selection, forward) => {
|
|
|
23120 |
const elm = forward ? selection.getEnd(true) : selection.getStart(true);
|
|
|
23121 |
return isRtl(elm) ? !forward : forward;
|
|
|
23122 |
};
|
|
|
23123 |
const moveH$2 = (editor, forward) => getHorizontalRange(editor, flipDirection(editor.selection, forward)).exists(newRange => {
|
|
|
23124 |
moveToRange(editor, newRange);
|
|
|
23125 |
return true;
|
|
|
23126 |
});
|
|
|
23127 |
const moveV$4 = (editor, down) => getVerticalRange(editor, down).exists(newRange => {
|
|
|
23128 |
moveToRange(editor, newRange);
|
|
|
23129 |
return true;
|
|
|
23130 |
});
|
|
|
23131 |
const moveToLineEndPoint$1 = (editor, forward) => {
|
|
|
23132 |
const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
|
|
|
23133 |
return moveToLineEndPoint$3(editor, forward, isCefPosition);
|
|
|
23134 |
};
|
|
|
23135 |
const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => {
|
|
|
23136 |
const rng = pos.toRange();
|
|
|
23137 |
const curRng = editor.selection.getRng();
|
|
|
23138 |
if (forward) {
|
|
|
23139 |
rng.setStart(curRng.startContainer, curRng.startOffset);
|
|
|
23140 |
} else {
|
|
|
23141 |
rng.setEnd(curRng.endContainer, curRng.endOffset);
|
|
|
23142 |
}
|
|
|
23143 |
return rng;
|
|
|
23144 |
}).exists(rng => {
|
|
|
23145 |
moveToRange(editor, rng);
|
|
|
23146 |
return true;
|
|
|
23147 |
});
|
|
|
23148 |
|
|
|
23149 |
const isTarget = node => contains$2(['figcaption'], name(node));
|
|
|
23150 |
const getClosestTargetBlock = (pos, root, schema) => {
|
|
|
23151 |
const isRoot = curry(eq, root);
|
|
|
23152 |
return closest$4(SugarElement.fromDom(pos.container()), el => schema.isBlock(name(el)), isRoot).filter(isTarget);
|
|
|
23153 |
};
|
|
|
23154 |
const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
|
|
|
23155 |
const moveCaretToNewEmptyLine = (editor, forward) => {
|
|
|
23156 |
const root = SugarElement.fromDom(editor.getBody());
|
|
|
23157 |
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
23158 |
return getClosestTargetBlock(pos, root, editor.schema).exists(() => {
|
|
|
23159 |
if (isAtFirstOrLastLine(root, forward, pos)) {
|
|
|
23160 |
const insertFn = forward ? append$1 : prepend;
|
|
|
23161 |
const rng = insertEmptyLine(editor, root, insertFn);
|
|
|
23162 |
editor.selection.setRng(rng);
|
|
|
23163 |
return true;
|
|
|
23164 |
} else {
|
|
|
23165 |
return false;
|
|
|
23166 |
}
|
|
|
23167 |
});
|
|
|
23168 |
};
|
|
|
23169 |
const moveV$3 = (editor, forward) => {
|
|
|
23170 |
if (editor.selection.isCollapsed()) {
|
|
|
23171 |
return moveCaretToNewEmptyLine(editor, forward);
|
|
|
23172 |
} else {
|
|
|
23173 |
return false;
|
|
|
23174 |
}
|
|
|
23175 |
};
|
|
|
23176 |
|
|
|
23177 |
const moveUp = (editor, details, summary) => {
|
|
|
23178 |
const rng = editor.selection.getRng();
|
|
|
23179 |
const pos = CaretPosition.fromRangeStart(rng);
|
|
|
23180 |
const root = editor.getBody();
|
|
|
23181 |
if (root.firstChild === details && isAtFirstLine(summary, pos)) {
|
|
|
23182 |
editor.execCommand('InsertNewBlockBefore');
|
|
|
23183 |
return true;
|
|
|
23184 |
} else {
|
|
|
23185 |
return false;
|
|
|
23186 |
}
|
|
|
23187 |
};
|
|
|
23188 |
const moveDown = (editor, details) => {
|
|
|
23189 |
const rng = editor.selection.getRng();
|
|
|
23190 |
const pos = CaretPosition.fromRangeStart(rng);
|
|
|
23191 |
const root = editor.getBody();
|
|
|
23192 |
if (root.lastChild === details && isAtLastLine(details, pos)) {
|
|
|
23193 |
editor.execCommand('InsertNewBlockAfter');
|
|
|
23194 |
return true;
|
|
|
23195 |
} else {
|
|
|
23196 |
return false;
|
|
|
23197 |
}
|
|
|
23198 |
};
|
|
|
23199 |
const move$2 = (editor, forward) => {
|
|
|
23200 |
if (forward) {
|
|
|
23201 |
return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'details')).map(details => moveDown(editor, details)).getOr(false);
|
|
|
23202 |
} else {
|
|
|
23203 |
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);
|
|
|
23204 |
}
|
|
|
23205 |
};
|
|
|
23206 |
const moveV$2 = (editor, forward) => move$2(editor, forward);
|
|
|
23207 |
|
|
|
23208 |
const baseKeyPattern = {
|
|
|
23209 |
shiftKey: false,
|
|
|
23210 |
altKey: false,
|
|
|
23211 |
ctrlKey: false,
|
|
|
23212 |
metaKey: false,
|
|
|
23213 |
keyCode: 0
|
|
|
23214 |
};
|
|
|
23215 |
const defaultPatterns = patterns => map$3(patterns, pattern => ({
|
|
|
23216 |
...baseKeyPattern,
|
|
|
23217 |
...pattern
|
|
|
23218 |
}));
|
|
|
23219 |
const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({
|
|
|
23220 |
...baseKeyPattern,
|
|
|
23221 |
...pattern
|
|
|
23222 |
}));
|
|
|
23223 |
const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
|
|
|
23224 |
const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
|
|
|
23225 |
const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
|
|
|
23226 |
const action = (f, ...x) => () => f.apply(null, x);
|
|
|
23227 |
const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action());
|
|
|
23228 |
const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action());
|
|
|
23229 |
|
|
|
23230 |
const moveH$1 = (editor, forward) => {
|
| 1441 |
ariadna |
23231 |
const direction = forward ? 1 : -1;
|
| 1 |
efrain |
23232 |
const range = editor.selection.getRng();
|
|
|
23233 |
return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
|
|
|
23234 |
moveToRange(editor, newRange);
|
|
|
23235 |
return true;
|
|
|
23236 |
});
|
|
|
23237 |
};
|
|
|
23238 |
const moveV$1 = (editor, down) => {
|
|
|
23239 |
const direction = down ? 1 : -1;
|
|
|
23240 |
const range = editor.selection.getRng();
|
|
|
23241 |
return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
|
|
|
23242 |
moveToRange(editor, newRange);
|
|
|
23243 |
return true;
|
|
|
23244 |
});
|
|
|
23245 |
};
|
|
|
23246 |
const moveToLineEndPoint = (editor, forward) => {
|
|
|
23247 |
const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
|
|
|
23248 |
return moveToLineEndPoint$3(editor, forward, isNearMedia);
|
|
|
23249 |
};
|
|
|
23250 |
|
|
|
23251 |
const adt = Adt.generate([
|
|
|
23252 |
{ none: ['current'] },
|
|
|
23253 |
{ first: ['current'] },
|
|
|
23254 |
{
|
|
|
23255 |
middle: [
|
|
|
23256 |
'current',
|
|
|
23257 |
'target'
|
|
|
23258 |
]
|
|
|
23259 |
},
|
|
|
23260 |
{ last: ['current'] }
|
|
|
23261 |
]);
|
|
|
23262 |
const none = current => adt.none(current);
|
|
|
23263 |
const CellLocation = {
|
|
|
23264 |
...adt,
|
|
|
23265 |
none
|
|
|
23266 |
};
|
|
|
23267 |
|
|
|
23268 |
const firstLayer = (scope, selector) => {
|
|
|
23269 |
return filterFirstLayer(scope, selector, always);
|
|
|
23270 |
};
|
|
|
23271 |
const filterFirstLayer = (scope, selector, predicate) => {
|
|
|
23272 |
return bind$3(children$1(scope), x => {
|
|
|
23273 |
if (is$1(x, selector)) {
|
|
|
23274 |
return predicate(x) ? [x] : [];
|
|
|
23275 |
} else {
|
|
|
23276 |
return filterFirstLayer(x, selector, predicate);
|
|
|
23277 |
}
|
|
|
23278 |
});
|
|
|
23279 |
};
|
|
|
23280 |
|
|
|
23281 |
const lookup$1 = (tags, element, isRoot = never) => {
|
|
|
23282 |
if (isRoot(element)) {
|
|
|
23283 |
return Optional.none();
|
|
|
23284 |
}
|
|
|
23285 |
if (contains$2(tags, name(element))) {
|
|
|
23286 |
return Optional.some(element);
|
|
|
23287 |
}
|
|
|
23288 |
const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm);
|
|
|
23289 |
return ancestor$3(element, tags.join(','), isRootOrUpperTable);
|
|
|
23290 |
};
|
|
|
23291 |
const cell = (element, isRoot) => lookup$1([
|
|
|
23292 |
'td',
|
|
|
23293 |
'th'
|
|
|
23294 |
], element, isRoot);
|
|
|
23295 |
const cells = ancestor => firstLayer(ancestor, 'th,td');
|
|
|
23296 |
const table = (element, isRoot) => closest$3(element, 'table', isRoot);
|
|
|
23297 |
|
|
|
23298 |
const walk = (all, current, index, direction, isEligible = always) => {
|
|
|
23299 |
const forwards = direction === 1;
|
|
|
23300 |
if (!forwards && index <= 0) {
|
|
|
23301 |
return CellLocation.first(all[0]);
|
|
|
23302 |
} else if (forwards && index >= all.length - 1) {
|
|
|
23303 |
return CellLocation.last(all[all.length - 1]);
|
|
|
23304 |
} else {
|
|
|
23305 |
const newIndex = index + direction;
|
|
|
23306 |
const elem = all[newIndex];
|
|
|
23307 |
return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible);
|
|
|
23308 |
}
|
|
|
23309 |
};
|
|
|
23310 |
const detect = (current, isRoot) => {
|
|
|
23311 |
return table(current, isRoot).bind(table => {
|
|
|
23312 |
const all = cells(table);
|
|
|
23313 |
const index = findIndex$2(all, x => eq(current, x));
|
|
|
23314 |
return index.map(index => ({
|
|
|
23315 |
index,
|
|
|
23316 |
all
|
|
|
23317 |
}));
|
|
|
23318 |
});
|
|
|
23319 |
};
|
|
|
23320 |
const next = (current, isEligible, isRoot) => {
|
|
|
23321 |
const detection = detect(current, isRoot);
|
|
|
23322 |
return detection.fold(() => {
|
|
|
23323 |
return CellLocation.none(current);
|
|
|
23324 |
}, info => {
|
|
|
23325 |
return walk(info.all, current, info.index, 1, isEligible);
|
|
|
23326 |
});
|
|
|
23327 |
};
|
|
|
23328 |
const prev = (current, isEligible, isRoot) => {
|
|
|
23329 |
const detection = detect(current, isRoot);
|
|
|
23330 |
return detection.fold(() => {
|
|
|
23331 |
return CellLocation.none();
|
|
|
23332 |
}, info => {
|
|
|
23333 |
return walk(info.all, current, info.index, -1, isEligible);
|
|
|
23334 |
});
|
|
|
23335 |
};
|
|
|
23336 |
|
| 1441 |
ariadna |
23337 |
const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
|
|
|
23338 |
const isContentEditableFalse$3 = elem => isHTMLElement$1(elem) && get$9(elem, 'contenteditable') === 'false';
|
|
|
23339 |
const elementsWithCursorPosition = [
|
|
|
23340 |
'img',
|
|
|
23341 |
'br'
|
|
|
23342 |
];
|
|
|
23343 |
const isCursorPosition = elem => {
|
|
|
23344 |
const hasCursorPosition = isTextNodeWithCursorPosition(elem);
|
|
|
23345 |
return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse$3(elem);
|
|
|
23346 |
};
|
|
|
23347 |
|
|
|
23348 |
const first = element => descendant$2(element, isCursorPosition);
|
|
|
23349 |
|
| 1 |
efrain |
23350 |
const deflate = (rect, delta) => ({
|
|
|
23351 |
left: rect.left - delta,
|
|
|
23352 |
top: rect.top - delta,
|
|
|
23353 |
right: rect.right + delta * 2,
|
|
|
23354 |
bottom: rect.bottom + delta * 2,
|
|
|
23355 |
width: rect.width + delta,
|
|
|
23356 |
height: rect.height + delta
|
|
|
23357 |
});
|
|
|
23358 |
const getCorners = (getYAxisValue, tds) => bind$3(tds, td => {
|
|
|
23359 |
const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
|
|
|
23360 |
return [
|
|
|
23361 |
{
|
|
|
23362 |
x: rect.left,
|
|
|
23363 |
y: getYAxisValue(rect),
|
|
|
23364 |
cell: td
|
|
|
23365 |
},
|
|
|
23366 |
{
|
|
|
23367 |
x: rect.right,
|
|
|
23368 |
y: getYAxisValue(rect),
|
|
|
23369 |
cell: td
|
|
|
23370 |
}
|
|
|
23371 |
];
|
|
|
23372 |
});
|
|
|
23373 |
const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => {
|
|
|
23374 |
const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
|
|
|
23375 |
const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
|
|
|
23376 |
return Optional.some(newDist < oldDist ? newCorner : oldCorner);
|
|
|
23377 |
}), Optional.none());
|
|
|
23378 |
const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => {
|
|
|
23379 |
const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom);
|
|
|
23380 |
const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y));
|
|
|
23381 |
return findClosestCorner(corners, x, y).map(corner => corner.cell);
|
|
|
23382 |
};
|
|
|
23383 |
const getBottomValue = rect => rect.bottom;
|
|
|
23384 |
const getTopValue = rect => rect.top;
|
|
|
23385 |
const isAbove = (corner, y) => corner.y < y;
|
|
|
23386 |
const isBelow = (corner, y) => corner.y > y;
|
|
|
23387 |
const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
|
|
|
23388 |
const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
|
|
|
23389 |
const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos));
|
| 1441 |
ariadna |
23390 |
const findClosestPositionInBelowCell = (table, pos) => last$2(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos));
|
| 1 |
efrain |
23391 |
|
|
|
23392 |
const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome());
|
|
|
23393 |
const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
|
|
|
23394 |
const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
|
|
|
23395 |
const isAtTableCellLine = (getPositionsUntil, scope, pos) => {
|
|
|
23396 |
const lineInfo = getPositionsUntil(scope, pos);
|
|
|
23397 |
if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
|
|
|
23398 |
return !hasNextBreak(getPositionsUntil, scope, lineInfo);
|
|
|
23399 |
} else {
|
|
|
23400 |
return lineInfo.breakAt.isNone();
|
|
|
23401 |
}
|
|
|
23402 |
};
|
|
|
23403 |
const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
|
|
|
23404 |
const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
|
|
|
23405 |
const isCaretAtStartOrEndOfTable = (forward, rng, table) => {
|
|
|
23406 |
const caretPos = CaretPosition.fromRangeStart(rng);
|
|
|
23407 |
return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos));
|
|
|
23408 |
};
|
|
|
23409 |
const navigateHorizontally = (editor, forward, table, _td) => {
|
|
|
23410 |
const rng = editor.selection.getRng();
|
|
|
23411 |
const direction = forward ? 1 : -1;
|
|
|
23412 |
if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
|
|
|
23413 |
showCaret(direction, editor, table, !forward, false).each(newRng => {
|
|
|
23414 |
moveToRange(editor, newRng);
|
|
|
23415 |
});
|
|
|
23416 |
return true;
|
|
|
23417 |
}
|
|
|
23418 |
return false;
|
|
|
23419 |
};
|
|
|
23420 |
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));
|
|
|
23421 |
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));
|
|
|
23422 |
const getTable = (previous, pos) => {
|
|
|
23423 |
const node = pos.getNode(previous);
|
|
|
23424 |
return isTable$2(node) ? Optional.some(node) : Optional.none();
|
|
|
23425 |
};
|
|
|
23426 |
const renderBlock = (down, editor, table) => {
|
|
|
23427 |
editor.undoManager.transact(() => {
|
|
|
23428 |
const insertFn = down ? after$4 : before$3;
|
|
|
23429 |
const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn);
|
|
|
23430 |
moveToRange(editor, rng);
|
|
|
23431 |
});
|
|
|
23432 |
};
|
|
|
23433 |
const moveCaret = (editor, down, pos) => {
|
|
|
23434 |
const table = down ? getTable(true, pos) : getTable(false, pos);
|
|
|
23435 |
const last = down === false;
|
|
|
23436 |
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)));
|
|
|
23437 |
};
|
|
|
23438 |
const navigateVertically = (editor, down, table, td) => {
|
|
|
23439 |
const rng = editor.selection.getRng();
|
|
|
23440 |
const pos = CaretPosition.fromRangeStart(rng);
|
|
|
23441 |
const root = editor.getBody();
|
|
|
23442 |
if (!down && isAtFirstTableCellLine(td, pos)) {
|
|
|
23443 |
const newPos = getClosestAbovePosition(root, table, pos);
|
|
|
23444 |
moveCaret(editor, down, newPos);
|
|
|
23445 |
return true;
|
|
|
23446 |
} else if (down && isAtLastTableCellLine(td, pos)) {
|
|
|
23447 |
const newPos = getClosestBelowPosition(root, table, pos);
|
|
|
23448 |
moveCaret(editor, down, newPos);
|
|
|
23449 |
return true;
|
|
|
23450 |
} else {
|
|
|
23451 |
return false;
|
|
|
23452 |
}
|
|
|
23453 |
};
|
|
|
23454 |
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);
|
|
|
23455 |
const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
|
|
|
23456 |
const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
|
|
|
23457 |
const getCellFirstCursorPosition = cell => {
|
|
|
23458 |
const selection = SimSelection.exact(cell, 0, cell, 0);
|
|
|
23459 |
return toNative(selection);
|
|
|
23460 |
};
|
|
|
23461 |
const tabGo = (editor, isRoot, cell) => {
|
|
|
23462 |
return cell.fold(Optional.none, Optional.none, (_current, next) => {
|
|
|
23463 |
return first(next).map(cell => {
|
|
|
23464 |
return getCellFirstCursorPosition(cell);
|
|
|
23465 |
});
|
|
|
23466 |
}, current => {
|
| 1441 |
ariadna |
23467 |
if (editor.mode.isReadOnly()) {
|
|
|
23468 |
return Optional.none();
|
|
|
23469 |
}
|
| 1 |
efrain |
23470 |
editor.execCommand('mceTableInsertRowAfter');
|
|
|
23471 |
return tabForward(editor, isRoot, current);
|
|
|
23472 |
});
|
|
|
23473 |
};
|
|
|
23474 |
const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable$2));
|
|
|
23475 |
const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable$2));
|
|
|
23476 |
const handleTab = (editor, forward) => {
|
|
|
23477 |
const rootElements = [
|
|
|
23478 |
'table',
|
|
|
23479 |
'li',
|
|
|
23480 |
'dl'
|
|
|
23481 |
];
|
|
|
23482 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
23483 |
const isRoot = element => {
|
|
|
23484 |
const name$1 = name(element);
|
|
|
23485 |
return eq(element, body) || contains$2(rootElements, name$1);
|
|
|
23486 |
};
|
|
|
23487 |
const rng = editor.selection.getRng();
|
|
|
23488 |
const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
|
|
|
23489 |
return cell(container, isRoot).map(cell => {
|
|
|
23490 |
table(cell, isRoot).each(table => {
|
|
|
23491 |
editor.model.table.clearSelectedCells(table.dom);
|
|
|
23492 |
});
|
|
|
23493 |
editor.selection.collapse(!forward);
|
|
|
23494 |
const navigation = !forward ? tabBackward : tabForward;
|
|
|
23495 |
const rng = navigation(editor, isRoot, cell);
|
|
|
23496 |
rng.each(range => {
|
|
|
23497 |
editor.selection.setRng(range);
|
|
|
23498 |
});
|
|
|
23499 |
return true;
|
|
|
23500 |
}).getOr(false);
|
|
|
23501 |
};
|
|
|
23502 |
|
|
|
23503 |
const executeKeydownOverride$4 = (editor, caret, evt) => {
|
|
|
23504 |
const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
|
|
23505 |
execute([
|
|
|
23506 |
{
|
|
|
23507 |
keyCode: VK.RIGHT,
|
|
|
23508 |
action: action(moveH$2, editor, true)
|
|
|
23509 |
},
|
|
|
23510 |
{
|
|
|
23511 |
keyCode: VK.LEFT,
|
|
|
23512 |
action: action(moveH$2, editor, false)
|
|
|
23513 |
},
|
|
|
23514 |
{
|
|
|
23515 |
keyCode: VK.UP,
|
|
|
23516 |
action: action(moveV$4, editor, false)
|
|
|
23517 |
},
|
|
|
23518 |
{
|
|
|
23519 |
keyCode: VK.DOWN,
|
|
|
23520 |
action: action(moveV$4, editor, true)
|
|
|
23521 |
},
|
|
|
23522 |
...isMac ? [
|
|
|
23523 |
{
|
|
|
23524 |
keyCode: VK.UP,
|
|
|
23525 |
action: action(selectToEndPoint, editor, false),
|
|
|
23526 |
metaKey: true,
|
|
|
23527 |
shiftKey: true
|
|
|
23528 |
},
|
|
|
23529 |
{
|
|
|
23530 |
keyCode: VK.DOWN,
|
|
|
23531 |
action: action(selectToEndPoint, editor, true),
|
|
|
23532 |
metaKey: true,
|
|
|
23533 |
shiftKey: true
|
|
|
23534 |
}
|
|
|
23535 |
] : [],
|
|
|
23536 |
{
|
|
|
23537 |
keyCode: VK.RIGHT,
|
|
|
23538 |
action: action(moveH, editor, true)
|
|
|
23539 |
},
|
|
|
23540 |
{
|
|
|
23541 |
keyCode: VK.LEFT,
|
|
|
23542 |
action: action(moveH, editor, false)
|
|
|
23543 |
},
|
|
|
23544 |
{
|
|
|
23545 |
keyCode: VK.UP,
|
|
|
23546 |
action: action(moveV, editor, false)
|
|
|
23547 |
},
|
|
|
23548 |
{
|
|
|
23549 |
keyCode: VK.DOWN,
|
|
|
23550 |
action: action(moveV, editor, true)
|
|
|
23551 |
},
|
|
|
23552 |
{
|
|
|
23553 |
keyCode: VK.UP,
|
|
|
23554 |
action: action(moveV, editor, false)
|
|
|
23555 |
},
|
|
|
23556 |
{
|
|
|
23557 |
keyCode: VK.UP,
|
|
|
23558 |
action: action(moveV$2, editor, false)
|
|
|
23559 |
},
|
|
|
23560 |
{
|
|
|
23561 |
keyCode: VK.DOWN,
|
|
|
23562 |
action: action(moveV$2, editor, true)
|
|
|
23563 |
},
|
|
|
23564 |
{
|
|
|
23565 |
keyCode: VK.RIGHT,
|
|
|
23566 |
action: action(moveH$1, editor, true)
|
|
|
23567 |
},
|
|
|
23568 |
{
|
|
|
23569 |
keyCode: VK.LEFT,
|
|
|
23570 |
action: action(moveH$1, editor, false)
|
|
|
23571 |
},
|
|
|
23572 |
{
|
|
|
23573 |
keyCode: VK.UP,
|
|
|
23574 |
action: action(moveV$1, editor, false)
|
|
|
23575 |
},
|
|
|
23576 |
{
|
|
|
23577 |
keyCode: VK.DOWN,
|
|
|
23578 |
action: action(moveV$1, editor, true)
|
|
|
23579 |
},
|
|
|
23580 |
{
|
|
|
23581 |
keyCode: VK.RIGHT,
|
|
|
23582 |
action: action(move$3, editor, caret, true)
|
|
|
23583 |
},
|
|
|
23584 |
{
|
|
|
23585 |
keyCode: VK.LEFT,
|
|
|
23586 |
action: action(move$3, editor, caret, false)
|
|
|
23587 |
},
|
|
|
23588 |
{
|
|
|
23589 |
keyCode: VK.RIGHT,
|
|
|
23590 |
ctrlKey: !isMac,
|
|
|
23591 |
altKey: isMac,
|
|
|
23592 |
action: action(moveNextWord, editor, caret)
|
|
|
23593 |
},
|
|
|
23594 |
{
|
|
|
23595 |
keyCode: VK.LEFT,
|
|
|
23596 |
ctrlKey: !isMac,
|
|
|
23597 |
altKey: isMac,
|
|
|
23598 |
action: action(movePrevWord, editor, caret)
|
|
|
23599 |
},
|
|
|
23600 |
{
|
|
|
23601 |
keyCode: VK.UP,
|
|
|
23602 |
action: action(moveV$3, editor, false)
|
|
|
23603 |
},
|
|
|
23604 |
{
|
|
|
23605 |
keyCode: VK.DOWN,
|
|
|
23606 |
action: action(moveV$3, editor, true)
|
|
|
23607 |
}
|
|
|
23608 |
], evt).each(_ => {
|
|
|
23609 |
evt.preventDefault();
|
|
|
23610 |
});
|
|
|
23611 |
};
|
|
|
23612 |
const setup$l = (editor, caret) => {
|
|
|
23613 |
editor.on('keydown', evt => {
|
|
|
23614 |
if (!evt.isDefaultPrevented()) {
|
|
|
23615 |
executeKeydownOverride$4(editor, caret, evt);
|
|
|
23616 |
}
|
|
|
23617 |
});
|
|
|
23618 |
};
|
|
|
23619 |
|
|
|
23620 |
const point = (container, offset) => ({
|
|
|
23621 |
container,
|
|
|
23622 |
offset
|
|
|
23623 |
});
|
|
|
23624 |
|
|
|
23625 |
const DOM$7 = DOMUtils.DOM;
|
|
|
23626 |
const alwaysNext = startNode => node => startNode === node ? -1 : 0;
|
|
|
23627 |
const isBoundary = dom => node => dom.isBlock(node) || contains$2([
|
|
|
23628 |
'BR',
|
|
|
23629 |
'IMG',
|
|
|
23630 |
'HR',
|
|
|
23631 |
'INPUT'
|
|
|
23632 |
], node.nodeName) || dom.getContentEditable(node) === 'false';
|
|
|
23633 |
const textBefore = (node, offset, rootNode) => {
|
| 1441 |
ariadna |
23634 |
if (isText$b(node) && offset >= 0) {
|
| 1 |
efrain |
23635 |
return Optional.some(point(node, offset));
|
|
|
23636 |
} else {
|
|
|
23637 |
const textSeeker = TextSeeker(DOM$7);
|
|
|
23638 |
return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length));
|
|
|
23639 |
}
|
|
|
23640 |
};
|
|
|
23641 |
const textAfter = (node, offset, rootNode) => {
|
| 1441 |
ariadna |
23642 |
if (isText$b(node) && offset >= node.length) {
|
| 1 |
efrain |
23643 |
return Optional.some(point(node, offset));
|
|
|
23644 |
} else {
|
|
|
23645 |
const textSeeker = TextSeeker(DOM$7);
|
|
|
23646 |
return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0));
|
|
|
23647 |
}
|
|
|
23648 |
};
|
|
|
23649 |
const scanLeft = (node, offset, rootNode) => {
|
| 1441 |
ariadna |
23650 |
if (!isText$b(node)) {
|
| 1 |
efrain |
23651 |
return Optional.none();
|
|
|
23652 |
}
|
|
|
23653 |
const text = node.data;
|
|
|
23654 |
if (offset >= 0 && offset <= text.length) {
|
|
|
23655 |
return Optional.some(point(node, offset));
|
|
|
23656 |
} else {
|
|
|
23657 |
const textSeeker = TextSeeker(DOM$7);
|
|
|
23658 |
return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => {
|
|
|
23659 |
const prevText = prev.container.data;
|
|
|
23660 |
return scanLeft(prev.container, offset + prevText.length, rootNode);
|
|
|
23661 |
});
|
|
|
23662 |
}
|
|
|
23663 |
};
|
|
|
23664 |
const scanRight = (node, offset, rootNode) => {
|
| 1441 |
ariadna |
23665 |
if (!isText$b(node)) {
|
| 1 |
efrain |
23666 |
return Optional.none();
|
|
|
23667 |
}
|
|
|
23668 |
const text = node.data;
|
|
|
23669 |
if (offset <= text.length) {
|
|
|
23670 |
return Optional.some(point(node, offset));
|
|
|
23671 |
} else {
|
|
|
23672 |
const textSeeker = TextSeeker(DOM$7);
|
|
|
23673 |
return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode));
|
|
|
23674 |
}
|
|
|
23675 |
};
|
|
|
23676 |
const repeatLeft = (dom, node, offset, process, rootNode) => {
|
|
|
23677 |
const search = TextSeeker(dom, isBoundary(dom));
|
|
|
23678 |
return Optional.from(search.backwards(node, offset, process, rootNode));
|
|
|
23679 |
};
|
|
|
23680 |
|
| 1441 |
ariadna |
23681 |
const isValidTextRange = rng => rng.collapsed && isText$b(rng.startContainer);
|
| 1 |
efrain |
23682 |
const getText = rng => trim$2(rng.toString().replace(/\u00A0/g, ' '));
|
| 1441 |
ariadna |
23683 |
const isWhitespace = chr => chr !== '' && ' \xA0\uFEFF\f\n\r\t\x0B'.indexOf(chr) !== -1;
|
| 1 |
efrain |
23684 |
|
|
|
23685 |
const stripTrigger = (text, trigger) => text.substring(trigger.length);
|
| 1441 |
ariadna |
23686 |
const findTrigger = (text, index, trigger, includeWhitespace = false) => {
|
| 1 |
efrain |
23687 |
let i;
|
|
|
23688 |
const firstChar = trigger.charAt(0);
|
|
|
23689 |
for (i = index - 1; i >= 0; i--) {
|
|
|
23690 |
const char = text.charAt(i);
|
| 1441 |
ariadna |
23691 |
if (!includeWhitespace && isWhitespace(char)) {
|
| 1 |
efrain |
23692 |
return Optional.none();
|
|
|
23693 |
}
|
|
|
23694 |
if (firstChar === char && contains$1(text, trigger, i, index)) {
|
|
|
23695 |
break;
|
|
|
23696 |
}
|
|
|
23697 |
}
|
|
|
23698 |
return Optional.some(i);
|
|
|
23699 |
};
|
| 1441 |
ariadna |
23700 |
const getContext = (dom, initRange, trigger, includeWhitespace = false) => {
|
| 1 |
efrain |
23701 |
if (!isValidTextRange(initRange)) {
|
|
|
23702 |
return Optional.none();
|
|
|
23703 |
}
|
|
|
23704 |
const buffer = {
|
|
|
23705 |
text: '',
|
|
|
23706 |
offset: 0
|
|
|
23707 |
};
|
|
|
23708 |
const findTriggerIndex = (element, offset, text) => {
|
|
|
23709 |
buffer.text = text + buffer.text;
|
|
|
23710 |
buffer.offset += offset;
|
| 1441 |
ariadna |
23711 |
return findTrigger(buffer.text, buffer.offset, trigger, includeWhitespace).getOr(offset);
|
| 1 |
efrain |
23712 |
};
|
|
|
23713 |
const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot();
|
|
|
23714 |
return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => {
|
|
|
23715 |
const range = initRange.cloneRange();
|
|
|
23716 |
range.setStart(spot.container, spot.offset);
|
|
|
23717 |
range.setEnd(initRange.endContainer, initRange.endOffset);
|
|
|
23718 |
if (range.collapsed) {
|
|
|
23719 |
return Optional.none();
|
|
|
23720 |
}
|
|
|
23721 |
const text = getText(range);
|
|
|
23722 |
const triggerIndex = text.lastIndexOf(trigger);
|
| 1441 |
ariadna |
23723 |
if (triggerIndex !== 0) {
|
| 1 |
efrain |
23724 |
return Optional.none();
|
|
|
23725 |
} else {
|
|
|
23726 |
return Optional.some({
|
|
|
23727 |
text: stripTrigger(text, trigger),
|
|
|
23728 |
range,
|
|
|
23729 |
trigger
|
|
|
23730 |
});
|
|
|
23731 |
}
|
|
|
23732 |
});
|
|
|
23733 |
};
|
|
|
23734 |
|
|
|
23735 |
const isText$1 = node => node.nodeType === TEXT;
|
|
|
23736 |
const isElement = node => node.nodeType === ELEMENT;
|
|
|
23737 |
const toLast = node => {
|
|
|
23738 |
if (isText$1(node)) {
|
|
|
23739 |
return point(node, node.data.length);
|
|
|
23740 |
} else {
|
|
|
23741 |
const children = node.childNodes;
|
|
|
23742 |
return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length);
|
|
|
23743 |
}
|
|
|
23744 |
};
|
|
|
23745 |
const toLeaf = (node, offset) => {
|
|
|
23746 |
const children = node.childNodes;
|
|
|
23747 |
if (children.length > 0 && offset < children.length) {
|
|
|
23748 |
return toLeaf(children[offset], 0);
|
|
|
23749 |
} else if (children.length > 0 && isElement(node) && children.length === offset) {
|
|
|
23750 |
return toLast(children[children.length - 1]);
|
|
|
23751 |
} else {
|
|
|
23752 |
return point(node, offset);
|
|
|
23753 |
}
|
|
|
23754 |
};
|
|
|
23755 |
|
|
|
23756 |
const isPreviousCharContent = (dom, leaf) => {
|
|
|
23757 |
var _a;
|
|
|
23758 |
const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
|
|
|
23759 |
return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => {
|
|
|
23760 |
const char = spot.container.data.charAt(spot.offset - 1);
|
|
|
23761 |
return !isWhitespace(char);
|
|
|
23762 |
}).isSome();
|
|
|
23763 |
};
|
|
|
23764 |
const isStartOfWord = dom => rng => {
|
|
|
23765 |
const leaf = toLeaf(rng.startContainer, rng.startOffset);
|
|
|
23766 |
return !isPreviousCharContent(dom, leaf);
|
|
|
23767 |
};
|
|
|
23768 |
const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger));
|
|
|
23769 |
const lookup = (editor, getDatabase) => {
|
|
|
23770 |
const database = getDatabase();
|
|
|
23771 |
const rng = editor.selection.getRng();
|
|
|
23772 |
return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context));
|
|
|
23773 |
};
|
|
|
23774 |
const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => {
|
|
|
23775 |
var _a;
|
|
|
23776 |
const database = getDatabase();
|
|
|
23777 |
const rng = editor.selection.getRng();
|
|
|
23778 |
const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : '';
|
|
|
23779 |
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));
|
|
|
23780 |
if (autocompleters.length === 0) {
|
|
|
23781 |
return Optional.none();
|
|
|
23782 |
}
|
|
|
23783 |
const lookupData = Promise.all(map$3(autocompleters, ac => {
|
|
|
23784 |
const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions);
|
|
|
23785 |
return fetchResult.then(results => ({
|
|
|
23786 |
matchText: context.text,
|
|
|
23787 |
items: results,
|
|
|
23788 |
columns: ac.columns,
|
|
|
23789 |
onAction: ac.onAction,
|
|
|
23790 |
highlightOn: ac.highlightOn
|
|
|
23791 |
}));
|
|
|
23792 |
}));
|
|
|
23793 |
return Optional.some({
|
|
|
23794 |
lookupData,
|
|
|
23795 |
context
|
|
|
23796 |
});
|
|
|
23797 |
};
|
|
|
23798 |
|
|
|
23799 |
var SimpleResultType;
|
|
|
23800 |
(function (SimpleResultType) {
|
|
|
23801 |
SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
|
|
|
23802 |
SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
|
|
|
23803 |
}(SimpleResultType || (SimpleResultType = {})));
|
|
|
23804 |
const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
|
|
|
23805 |
const partition = results => {
|
|
|
23806 |
const values = [];
|
|
|
23807 |
const errors = [];
|
|
|
23808 |
each$e(results, obj => {
|
|
|
23809 |
fold$1(obj, err => errors.push(err), val => values.push(val));
|
|
|
23810 |
});
|
|
|
23811 |
return {
|
|
|
23812 |
values,
|
|
|
23813 |
errors
|
|
|
23814 |
};
|
|
|
23815 |
};
|
|
|
23816 |
const mapError = (res, f) => {
|
|
|
23817 |
if (res.stype === SimpleResultType.Error) {
|
|
|
23818 |
return {
|
|
|
23819 |
stype: SimpleResultType.Error,
|
|
|
23820 |
serror: f(res.serror)
|
|
|
23821 |
};
|
|
|
23822 |
} else {
|
|
|
23823 |
return res;
|
|
|
23824 |
}
|
|
|
23825 |
};
|
|
|
23826 |
const map = (res, f) => {
|
|
|
23827 |
if (res.stype === SimpleResultType.Value) {
|
|
|
23828 |
return {
|
|
|
23829 |
stype: SimpleResultType.Value,
|
|
|
23830 |
svalue: f(res.svalue)
|
|
|
23831 |
};
|
|
|
23832 |
} else {
|
|
|
23833 |
return res;
|
|
|
23834 |
}
|
|
|
23835 |
};
|
|
|
23836 |
const bind$1 = (res, f) => {
|
|
|
23837 |
if (res.stype === SimpleResultType.Value) {
|
|
|
23838 |
return f(res.svalue);
|
|
|
23839 |
} else {
|
|
|
23840 |
return res;
|
|
|
23841 |
}
|
|
|
23842 |
};
|
|
|
23843 |
const bindError = (res, f) => {
|
|
|
23844 |
if (res.stype === SimpleResultType.Error) {
|
|
|
23845 |
return f(res.serror);
|
|
|
23846 |
} else {
|
|
|
23847 |
return res;
|
|
|
23848 |
}
|
|
|
23849 |
};
|
|
|
23850 |
const svalue = v => ({
|
|
|
23851 |
stype: SimpleResultType.Value,
|
|
|
23852 |
svalue: v
|
|
|
23853 |
});
|
|
|
23854 |
const serror = e => ({
|
|
|
23855 |
stype: SimpleResultType.Error,
|
|
|
23856 |
serror: e
|
|
|
23857 |
});
|
|
|
23858 |
const toResult = res => fold$1(res, Result.error, Result.value);
|
|
|
23859 |
const fromResult = res => res.fold(serror, svalue);
|
|
|
23860 |
const SimpleResult = {
|
|
|
23861 |
fromResult,
|
|
|
23862 |
toResult,
|
|
|
23863 |
svalue,
|
|
|
23864 |
partition,
|
|
|
23865 |
serror,
|
|
|
23866 |
bind: bind$1,
|
|
|
23867 |
bindError,
|
|
|
23868 |
map,
|
|
|
23869 |
mapError,
|
|
|
23870 |
fold: fold$1
|
|
|
23871 |
};
|
|
|
23872 |
|
|
|
23873 |
const formatObj = input => {
|
|
|
23874 |
return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
|
|
|
23875 |
};
|
|
|
23876 |
const formatErrors = errors => {
|
|
|
23877 |
const es = errors.length > 10 ? errors.slice(0, 10).concat([{
|
|
|
23878 |
path: [],
|
|
|
23879 |
getErrorInfo: constant('... (only showing first ten failures)')
|
|
|
23880 |
}]) : errors;
|
|
|
23881 |
return map$3(es, e => {
|
|
|
23882 |
return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
|
|
|
23883 |
});
|
|
|
23884 |
};
|
|
|
23885 |
|
|
|
23886 |
const nu = (path, getErrorInfo) => {
|
|
|
23887 |
return SimpleResult.serror([{
|
|
|
23888 |
path,
|
|
|
23889 |
getErrorInfo
|
|
|
23890 |
}]);
|
|
|
23891 |
};
|
|
|
23892 |
const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
|
|
|
23893 |
const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
|
|
|
23894 |
const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
|
|
|
23895 |
const custom = (path, err) => nu(path, constant(err));
|
|
|
23896 |
|
|
|
23897 |
const chooseFrom = (path, input, branches, ch) => {
|
|
|
23898 |
const fields = get$a(branches, ch);
|
|
|
23899 |
return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
|
|
|
23900 |
};
|
|
|
23901 |
const choose$1 = (key, branches) => {
|
|
|
23902 |
const extract = (path, input) => {
|
|
|
23903 |
const choice = get$a(input, key);
|
|
|
23904 |
return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
|
|
|
23905 |
};
|
|
|
23906 |
const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
|
|
|
23907 |
return {
|
|
|
23908 |
extract,
|
|
|
23909 |
toString
|
|
|
23910 |
};
|
|
|
23911 |
};
|
|
|
23912 |
|
|
|
23913 |
const shallow = (old, nu) => {
|
|
|
23914 |
return nu;
|
|
|
23915 |
};
|
|
|
23916 |
const deep = (old, nu) => {
|
|
|
23917 |
const bothObjects = isPlainObject(old) && isPlainObject(nu);
|
|
|
23918 |
return bothObjects ? deepMerge(old, nu) : nu;
|
|
|
23919 |
};
|
|
|
23920 |
const baseMerge = merger => {
|
|
|
23921 |
return (...objects) => {
|
|
|
23922 |
if (objects.length === 0) {
|
|
|
23923 |
throw new Error(`Can't merge zero objects`);
|
|
|
23924 |
}
|
|
|
23925 |
const ret = {};
|
|
|
23926 |
for (let j = 0; j < objects.length; j++) {
|
|
|
23927 |
const curObject = objects[j];
|
|
|
23928 |
for (const key in curObject) {
|
|
|
23929 |
if (has$2(curObject, key)) {
|
|
|
23930 |
ret[key] = merger(ret[key], curObject[key]);
|
|
|
23931 |
}
|
|
|
23932 |
}
|
|
|
23933 |
}
|
|
|
23934 |
return ret;
|
|
|
23935 |
};
|
|
|
23936 |
};
|
|
|
23937 |
const deepMerge = baseMerge(deep);
|
|
|
23938 |
const merge = baseMerge(shallow);
|
|
|
23939 |
|
|
|
23940 |
const required = () => ({
|
|
|
23941 |
tag: 'required',
|
|
|
23942 |
process: {}
|
|
|
23943 |
});
|
|
|
23944 |
const defaultedThunk = fallbackThunk => ({
|
|
|
23945 |
tag: 'defaultedThunk',
|
|
|
23946 |
process: fallbackThunk
|
|
|
23947 |
});
|
|
|
23948 |
const defaulted$1 = fallback => defaultedThunk(constant(fallback));
|
|
|
23949 |
const asOption = () => ({
|
|
|
23950 |
tag: 'option',
|
|
|
23951 |
process: {}
|
|
|
23952 |
});
|
|
|
23953 |
|
|
|
23954 |
const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base);
|
|
|
23955 |
const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors);
|
|
|
23956 |
const consolidateObj = (objects, base) => {
|
|
|
23957 |
const partition = SimpleResult.partition(objects);
|
|
|
23958 |
return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
|
|
|
23959 |
};
|
|
|
23960 |
const consolidateArr = objects => {
|
|
|
23961 |
const partitions = SimpleResult.partition(objects);
|
|
|
23962 |
return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
|
|
|
23963 |
};
|
|
|
23964 |
const ResultCombine = {
|
|
|
23965 |
consolidateObj,
|
|
|
23966 |
consolidateArr
|
|
|
23967 |
};
|
|
|
23968 |
|
|
|
23969 |
const field$1 = (key, newKey, presence, prop) => ({
|
|
|
23970 |
tag: 'field',
|
|
|
23971 |
key,
|
|
|
23972 |
newKey,
|
|
|
23973 |
presence,
|
|
|
23974 |
prop
|
|
|
23975 |
});
|
|
|
23976 |
const customField$1 = (newKey, instantiator) => ({
|
|
|
23977 |
tag: 'custom',
|
|
|
23978 |
newKey,
|
|
|
23979 |
instantiator
|
|
|
23980 |
});
|
|
|
23981 |
const fold = (value, ifField, ifCustom) => {
|
|
|
23982 |
switch (value.tag) {
|
|
|
23983 |
case 'field':
|
|
|
23984 |
return ifField(value.key, value.newKey, value.presence, value.prop);
|
|
|
23985 |
case 'custom':
|
|
|
23986 |
return ifCustom(value.newKey, value.instantiator);
|
|
|
23987 |
}
|
|
|
23988 |
};
|
|
|
23989 |
|
|
|
23990 |
const value = validator => {
|
|
|
23991 |
const extract = (path, val) => {
|
|
|
23992 |
return SimpleResult.bindError(validator(val), err => custom(path, err));
|
|
|
23993 |
};
|
|
|
23994 |
const toString = constant('val');
|
|
|
23995 |
return {
|
|
|
23996 |
extract,
|
|
|
23997 |
toString
|
|
|
23998 |
};
|
|
|
23999 |
};
|
|
|
24000 |
const anyValue$1 = value(SimpleResult.svalue);
|
|
|
24001 |
|
|
|
24002 |
const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
|
|
|
24003 |
const fallbackAccess = (obj, key, fallback, bundle) => {
|
|
|
24004 |
const v = get$a(obj, key).getOrThunk(() => fallback(obj));
|
|
|
24005 |
return bundle(v);
|
|
|
24006 |
};
|
|
|
24007 |
const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
|
|
|
24008 |
const optionDefaultedAccess = (obj, key, fallback, bundle) => {
|
|
|
24009 |
const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val);
|
|
|
24010 |
return bundle(opt);
|
|
|
24011 |
};
|
|
|
24012 |
const extractField = (field, path, obj, key, prop) => {
|
|
|
24013 |
const bundle = av => prop.extract(path.concat([key]), av);
|
|
|
24014 |
const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
|
|
|
24015 |
const result = prop.extract(path.concat([key]), ov);
|
|
|
24016 |
return SimpleResult.map(result, Optional.some);
|
|
|
24017 |
});
|
|
|
24018 |
switch (field.tag) {
|
|
|
24019 |
case 'required':
|
|
|
24020 |
return requiredAccess(path, obj, key, bundle);
|
|
|
24021 |
case 'defaultedThunk':
|
|
|
24022 |
return fallbackAccess(obj, key, field.process, bundle);
|
|
|
24023 |
case 'option':
|
|
|
24024 |
return optionAccess(obj, key, bundleAsOption);
|
|
|
24025 |
case 'defaultedOptionThunk':
|
|
|
24026 |
return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
|
|
|
24027 |
case 'mergeWithThunk': {
|
|
|
24028 |
return fallbackAccess(obj, key, constant({}), v => {
|
|
|
24029 |
const result = deepMerge(field.process(obj), v);
|
|
|
24030 |
return bundle(result);
|
|
|
24031 |
});
|
|
|
24032 |
}
|
|
|
24033 |
}
|
|
|
24034 |
};
|
|
|
24035 |
const extractFields = (path, obj, fields) => {
|
|
|
24036 |
const success = {};
|
|
|
24037 |
const errors = [];
|
|
|
24038 |
for (const field of fields) {
|
|
|
24039 |
fold(field, (key, newKey, presence, prop) => {
|
|
|
24040 |
const result = extractField(presence, path, obj, key, prop);
|
|
|
24041 |
SimpleResult.fold(result, err => {
|
|
|
24042 |
errors.push(...err);
|
|
|
24043 |
}, res => {
|
|
|
24044 |
success[newKey] = res;
|
|
|
24045 |
});
|
|
|
24046 |
}, (newKey, instantiator) => {
|
|
|
24047 |
success[newKey] = instantiator(obj);
|
|
|
24048 |
});
|
|
|
24049 |
}
|
|
|
24050 |
return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
|
|
|
24051 |
};
|
|
|
24052 |
const objOf = values => {
|
|
|
24053 |
const extract = (path, o) => extractFields(path, o, values);
|
|
|
24054 |
const toString = () => {
|
|
|
24055 |
const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
|
|
|
24056 |
return 'obj{\n' + fieldStrings.join('\n') + '}';
|
|
|
24057 |
};
|
|
|
24058 |
return {
|
|
|
24059 |
extract,
|
|
|
24060 |
toString
|
|
|
24061 |
};
|
|
|
24062 |
};
|
|
|
24063 |
const arrOf = prop => {
|
|
|
24064 |
const extract = (path, array) => {
|
|
|
24065 |
const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
|
|
|
24066 |
return ResultCombine.consolidateArr(results);
|
|
|
24067 |
};
|
|
|
24068 |
const toString = () => 'array(' + prop.toString() + ')';
|
|
|
24069 |
return {
|
|
|
24070 |
extract,
|
|
|
24071 |
toString
|
|
|
24072 |
};
|
|
|
24073 |
};
|
| 1441 |
ariadna |
24074 |
const oneOf = (props, rawF) => {
|
|
|
24075 |
const f = rawF !== undefined ? rawF : identity;
|
|
|
24076 |
const extract = (path, val) => {
|
|
|
24077 |
const errors = [];
|
|
|
24078 |
for (const prop of props) {
|
|
|
24079 |
const res = prop.extract(path, val);
|
|
|
24080 |
if (res.stype === SimpleResultType.Value) {
|
|
|
24081 |
return {
|
|
|
24082 |
stype: SimpleResultType.Value,
|
|
|
24083 |
svalue: f(res.svalue)
|
|
|
24084 |
};
|
|
|
24085 |
}
|
|
|
24086 |
errors.push(res);
|
|
|
24087 |
}
|
|
|
24088 |
return ResultCombine.consolidateArr(errors);
|
|
|
24089 |
};
|
|
|
24090 |
const toString = () => 'oneOf(' + map$3(props, prop => prop.toString()).join(', ') + ')';
|
|
|
24091 |
return {
|
|
|
24092 |
extract,
|
|
|
24093 |
toString
|
|
|
24094 |
};
|
|
|
24095 |
};
|
|
|
24096 |
const arrOfObj = compose(arrOf, objOf);
|
| 1 |
efrain |
24097 |
|
|
|
24098 |
const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
|
|
|
24099 |
const extractValue = (label, prop, obj) => {
|
|
|
24100 |
const res = prop.extract([label], obj);
|
|
|
24101 |
return SimpleResult.mapError(res, errs => ({
|
|
|
24102 |
input: obj,
|
|
|
24103 |
errors: errs
|
|
|
24104 |
}));
|
|
|
24105 |
};
|
|
|
24106 |
const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
|
|
|
24107 |
const formatError = errInfo => {
|
|
|
24108 |
return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
|
|
|
24109 |
};
|
|
|
24110 |
const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
|
|
|
24111 |
|
|
|
24112 |
const anyValue = constant(anyValue$1);
|
|
|
24113 |
const typedValue = (validator, expectedType) => value(a => {
|
|
|
24114 |
const actualType = typeof a;
|
|
|
24115 |
return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
|
|
|
24116 |
});
|
|
|
24117 |
const number = typedValue(isNumber, 'number');
|
|
|
24118 |
const string = typedValue(isString, 'string');
|
|
|
24119 |
const boolean = typedValue(isBoolean, 'boolean');
|
|
|
24120 |
const functionProcessor = typedValue(isFunction, 'function');
|
|
|
24121 |
|
|
|
24122 |
const field = field$1;
|
|
|
24123 |
const customField = customField$1;
|
|
|
24124 |
const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
|
|
|
24125 |
const requiredOf = (key, schema) => field(key, key, required(), schema);
|
|
|
24126 |
const requiredString = key => requiredOf(key, string);
|
| 1441 |
ariadna |
24127 |
const requiredStringEnum = (key, values) => field(key, key, required(), validateEnum(values));
|
| 1 |
efrain |
24128 |
const requiredFunction = key => requiredOf(key, functionProcessor);
|
|
|
24129 |
const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
|
|
|
24130 |
const optionOf = (key, schema) => field(key, key, asOption(), schema);
|
|
|
24131 |
const optionString = key => optionOf(key, string);
|
|
|
24132 |
const optionFunction = key => optionOf(key, functionProcessor);
|
|
|
24133 |
const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
|
|
|
24134 |
const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
|
|
|
24135 |
const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
|
|
|
24136 |
const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
|
|
|
24137 |
const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
|
|
|
24138 |
const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
|
|
|
24139 |
const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
|
|
|
24140 |
const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
|
|
|
24141 |
|
|
|
24142 |
const type = requiredString('type');
|
|
|
24143 |
const fetch$1 = requiredFunction('fetch');
|
|
|
24144 |
const onAction = requiredFunction('onAction');
|
|
|
24145 |
const onSetup = defaultedFunction('onSetup', () => noop);
|
|
|
24146 |
const optionalText = optionString('text');
|
|
|
24147 |
const optionalIcon = optionString('icon');
|
|
|
24148 |
const optionalTooltip = optionString('tooltip');
|
|
|
24149 |
const optionalLabel = optionString('label');
|
|
|
24150 |
const active = defaultedBoolean('active', false);
|
|
|
24151 |
const enabled = defaultedBoolean('enabled', true);
|
|
|
24152 |
const primary = defaultedBoolean('primary', false);
|
|
|
24153 |
const defaultedColumns = num => defaulted('columns', num);
|
|
|
24154 |
const defaultedType = type => defaultedString('type', type);
|
|
|
24155 |
|
|
|
24156 |
const autocompleterSchema = objOf([
|
|
|
24157 |
type,
|
|
|
24158 |
requiredString('trigger'),
|
|
|
24159 |
defaultedNumber('minChars', 1),
|
|
|
24160 |
defaultedColumns(1),
|
|
|
24161 |
defaultedNumber('maxResults', 10),
|
|
|
24162 |
optionFunction('matches'),
|
|
|
24163 |
fetch$1,
|
|
|
24164 |
onAction,
|
|
|
24165 |
defaultedArrayOf('highlightOn', [], string)
|
|
|
24166 |
]);
|
| 1441 |
ariadna |
24167 |
const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, spec);
|
| 1 |
efrain |
24168 |
|
|
|
24169 |
const baseToolbarButtonFields = [
|
|
|
24170 |
enabled,
|
|
|
24171 |
optionalTooltip,
|
|
|
24172 |
optionalIcon,
|
|
|
24173 |
optionalText,
|
| 1441 |
ariadna |
24174 |
onSetup,
|
|
|
24175 |
defaultedString('context', 'mode:design')
|
| 1 |
efrain |
24176 |
];
|
|
|
24177 |
|
|
|
24178 |
const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
|
|
|
24179 |
|
|
|
24180 |
const contextBarFields = [
|
|
|
24181 |
defaultedFunction('predicate', never),
|
|
|
24182 |
defaultedStringEnum('scope', 'node', [
|
|
|
24183 |
'node',
|
|
|
24184 |
'editor'
|
|
|
24185 |
]),
|
|
|
24186 |
defaultedStringEnum('position', 'selection', [
|
|
|
24187 |
'node',
|
|
|
24188 |
'selection',
|
|
|
24189 |
'line'
|
|
|
24190 |
])
|
|
|
24191 |
];
|
|
|
24192 |
|
|
|
24193 |
const contextButtonFields = baseToolbarButtonFields.concat([
|
|
|
24194 |
defaultedType('contextformbutton'),
|
| 1441 |
ariadna |
24195 |
defaultedString('align', 'end'),
|
| 1 |
efrain |
24196 |
primary,
|
|
|
24197 |
onAction,
|
|
|
24198 |
customField('original', identity)
|
|
|
24199 |
]);
|
|
|
24200 |
const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
|
|
|
24201 |
defaultedType('contextformbutton'),
|
| 1441 |
ariadna |
24202 |
defaultedString('align', 'end'),
|
| 1 |
efrain |
24203 |
primary,
|
|
|
24204 |
onAction,
|
|
|
24205 |
customField('original', identity)
|
|
|
24206 |
]);
|
|
|
24207 |
const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
|
|
|
24208 |
const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
|
|
|
24209 |
const toggleOrNormal = choose('type', {
|
|
|
24210 |
contextformbutton: contextButtonFields,
|
|
|
24211 |
contextformtogglebutton: contextToggleButtonFields
|
|
|
24212 |
});
|
| 1441 |
ariadna |
24213 |
const baseContextFormFields = [
|
| 1 |
efrain |
24214 |
optionalLabel,
|
|
|
24215 |
requiredArrayOf('commands', toggleOrNormal),
|
|
|
24216 |
optionOf('launch', choose('type', {
|
|
|
24217 |
contextformbutton: launchButtonFields,
|
|
|
24218 |
contextformtogglebutton: launchToggleButtonFields
|
| 1441 |
ariadna |
24219 |
})),
|
|
|
24220 |
defaultedFunction('onInput', noop),
|
|
|
24221 |
defaultedFunction('onSetup', noop)
|
|
|
24222 |
];
|
|
|
24223 |
const contextFormFields = [
|
|
|
24224 |
...contextBarFields,
|
|
|
24225 |
...baseContextFormFields,
|
|
|
24226 |
requiredStringEnum('type', ['contextform']),
|
|
|
24227 |
defaultedFunction('initValue', constant('')),
|
|
|
24228 |
optionString('placeholder')
|
|
|
24229 |
];
|
|
|
24230 |
const contextSliderFormFields = [
|
|
|
24231 |
...contextBarFields,
|
|
|
24232 |
...baseContextFormFields,
|
|
|
24233 |
requiredStringEnum('type', ['contextsliderform']),
|
|
|
24234 |
defaultedFunction('initValue', constant(0)),
|
|
|
24235 |
defaultedFunction('min', constant(0)),
|
|
|
24236 |
defaultedFunction('max', constant(100))
|
|
|
24237 |
];
|
|
|
24238 |
const contextSizeInputFormFields = [
|
|
|
24239 |
...contextBarFields,
|
|
|
24240 |
...baseContextFormFields,
|
|
|
24241 |
requiredStringEnum('type', ['contextsizeinputform']),
|
|
|
24242 |
defaultedFunction('initValue', constant({
|
|
|
24243 |
width: '',
|
|
|
24244 |
height: ''
|
| 1 |
efrain |
24245 |
}))
|
| 1441 |
ariadna |
24246 |
];
|
|
|
24247 |
choose('type', {
|
|
|
24248 |
contextform: contextFormFields,
|
|
|
24249 |
contextsliderform: contextSliderFormFields,
|
|
|
24250 |
contextsizeinputform: contextSizeInputFormFields
|
|
|
24251 |
});
|
|
|
24252 |
|
|
|
24253 |
objOf([
|
|
|
24254 |
defaultedType('contexttoolbar'),
|
|
|
24255 |
requiredOf('items', oneOf([
|
|
|
24256 |
string,
|
|
|
24257 |
arrOfObj([
|
|
|
24258 |
optionString('name'),
|
|
|
24259 |
optionString('label'),
|
|
|
24260 |
requiredArrayOf('items', string)
|
|
|
24261 |
])
|
|
|
24262 |
]))
|
| 1 |
efrain |
24263 |
].concat(contextBarFields));
|
|
|
24264 |
|
|
|
24265 |
const register$2 = editor => {
|
|
|
24266 |
const popups = editor.ui.registry.getAll().popups;
|
|
|
24267 |
const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => {
|
|
|
24268 |
throw new Error(formatError(err));
|
|
|
24269 |
}, identity));
|
|
|
24270 |
const triggers = stringArray(mapToArray(dataset, v => v.trigger));
|
|
|
24271 |
const datasetValues = values(dataset);
|
|
|
24272 |
const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger);
|
|
|
24273 |
return {
|
|
|
24274 |
dataset,
|
|
|
24275 |
triggers,
|
|
|
24276 |
lookupByTrigger
|
|
|
24277 |
};
|
|
|
24278 |
};
|
|
|
24279 |
|
|
|
24280 |
const setupEditorInput = (editor, api) => {
|
| 1441 |
ariadna |
24281 |
const update = last(api.load, 50);
|
|
|
24282 |
editor.on('input', e => {
|
|
|
24283 |
if (e.inputType === 'insertCompositionText' && !editor.composing) {
|
| 1 |
efrain |
24284 |
return;
|
|
|
24285 |
}
|
|
|
24286 |
update.throttle();
|
|
|
24287 |
});
|
|
|
24288 |
editor.on('keydown', e => {
|
|
|
24289 |
const keyCode = e.which;
|
|
|
24290 |
if (keyCode === 8) {
|
|
|
24291 |
update.throttle();
|
|
|
24292 |
} else if (keyCode === 27) {
|
| 1441 |
ariadna |
24293 |
update.cancel();
|
| 1 |
efrain |
24294 |
api.cancelIfNecessary();
|
| 1441 |
ariadna |
24295 |
} else if (keyCode === 38 || keyCode === 40) {
|
|
|
24296 |
update.cancel();
|
| 1 |
efrain |
24297 |
}
|
| 1441 |
ariadna |
24298 |
}, true);
|
| 1 |
efrain |
24299 |
editor.on('remove', update.cancel);
|
|
|
24300 |
};
|
|
|
24301 |
const setup$k = editor => {
|
|
|
24302 |
const activeAutocompleter = value$2();
|
|
|
24303 |
const uiActive = Cell(false);
|
|
|
24304 |
const isActive = activeAutocompleter.isSet;
|
|
|
24305 |
const cancelIfNecessary = () => {
|
|
|
24306 |
if (isActive()) {
|
|
|
24307 |
fireAutocompleterEnd(editor);
|
|
|
24308 |
uiActive.set(false);
|
|
|
24309 |
activeAutocompleter.clear();
|
|
|
24310 |
}
|
|
|
24311 |
};
|
|
|
24312 |
const commenceIfNecessary = context => {
|
|
|
24313 |
if (!isActive()) {
|
|
|
24314 |
activeAutocompleter.set({
|
|
|
24315 |
trigger: context.trigger,
|
|
|
24316 |
matchLength: context.text.length
|
|
|
24317 |
});
|
|
|
24318 |
}
|
|
|
24319 |
};
|
|
|
24320 |
const getAutocompleters = cached(() => register$2(editor));
|
| 1441 |
ariadna |
24321 |
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));
|
| 1 |
efrain |
24322 |
const load = fetchOptions => {
|
|
|
24323 |
doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => {
|
|
|
24324 |
commenceIfNecessary(lookupInfo.context);
|
|
|
24325 |
lookupInfo.lookupData.then(lookupData => {
|
|
|
24326 |
activeAutocompleter.get().map(ac => {
|
|
|
24327 |
const context = lookupInfo.context;
|
| 1441 |
ariadna |
24328 |
if (ac.trigger !== context.trigger) {
|
|
|
24329 |
return;
|
| 1 |
efrain |
24330 |
}
|
| 1441 |
ariadna |
24331 |
activeAutocompleter.set({
|
|
|
24332 |
...ac,
|
|
|
24333 |
matchLength: context.text.length
|
|
|
24334 |
});
|
|
|
24335 |
if (uiActive.get()) {
|
|
|
24336 |
fireAutocompleterUpdateActiveRange(editor, { range: context.range });
|
|
|
24337 |
fireAutocompleterUpdate(editor, { lookupData });
|
|
|
24338 |
} else {
|
|
|
24339 |
uiActive.set(true);
|
|
|
24340 |
fireAutocompleterUpdateActiveRange(editor, { range: context.range });
|
|
|
24341 |
fireAutocompleterStart(editor, { lookupData });
|
|
|
24342 |
}
|
| 1 |
efrain |
24343 |
});
|
|
|
24344 |
});
|
|
|
24345 |
});
|
|
|
24346 |
};
|
| 1441 |
ariadna |
24347 |
const isRangeInsideOrEqual = (innerRange, outerRange) => {
|
|
|
24348 |
const startComparison = innerRange.compareBoundaryPoints(window.Range.START_TO_START, outerRange);
|
|
|
24349 |
const endComparison = innerRange.compareBoundaryPoints(window.Range.END_TO_END, outerRange);
|
|
|
24350 |
return startComparison >= 0 && endComparison <= 0;
|
|
|
24351 |
};
|
|
|
24352 |
const readActiveRange = () => {
|
|
|
24353 |
return activeAutocompleter.get().bind(({trigger}) => {
|
|
|
24354 |
const selRange = editor.selection.getRng();
|
|
|
24355 |
return getContext(editor.dom, selRange, trigger, uiActive.get()).filter(({range}) => isRangeInsideOrEqual(selRange, range)).map(({range}) => range);
|
|
|
24356 |
});
|
|
|
24357 |
};
|
| 1 |
efrain |
24358 |
editor.addCommand('mceAutocompleterReload', (_ui, value) => {
|
|
|
24359 |
const fetchOptions = isObject(value) ? value.fetchOptions : {};
|
|
|
24360 |
load(fetchOptions);
|
|
|
24361 |
});
|
|
|
24362 |
editor.addCommand('mceAutocompleterClose', cancelIfNecessary);
|
| 1441 |
ariadna |
24363 |
editor.addCommand('mceAutocompleterRefreshActiveRange', () => {
|
|
|
24364 |
readActiveRange().each(range => {
|
|
|
24365 |
fireAutocompleterUpdateActiveRange(editor, { range });
|
|
|
24366 |
});
|
|
|
24367 |
});
|
|
|
24368 |
editor.editorCommands.addQueryStateHandler('mceAutoCompleterInRange', () => readActiveRange().isSome());
|
| 1 |
efrain |
24369 |
setupEditorInput(editor, {
|
|
|
24370 |
cancelIfNecessary,
|
|
|
24371 |
load
|
|
|
24372 |
});
|
|
|
24373 |
};
|
|
|
24374 |
|
| 1441 |
ariadna |
24375 |
const browser$1 = detect$1().browser;
|
| 1 |
efrain |
24376 |
const isSafari = browser$1.isSafari();
|
|
|
24377 |
const emptyNodeContents = node => fillWithPaddingBr(SugarElement.fromDom(node));
|
|
|
24378 |
const isEntireNodeSelected = (rng, node) => {
|
|
|
24379 |
var _a;
|
|
|
24380 |
return rng.startOffset === 0 && rng.endOffset === ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length);
|
|
|
24381 |
};
|
|
|
24382 |
const getParentDetailsElementAtPos = (dom, pos) => Optional.from(dom.getParent(pos.container(), 'details'));
|
|
|
24383 |
const isInDetailsElement = (dom, pos) => getParentDetailsElementAtPos(dom, pos).isSome();
|
|
|
24384 |
const getDetailsElements = (dom, rng) => {
|
|
|
24385 |
const startDetails = Optional.from(dom.getParent(rng.startContainer, 'details'));
|
|
|
24386 |
const endDetails = Optional.from(dom.getParent(rng.endContainer, 'details'));
|
|
|
24387 |
if (startDetails.isSome() || endDetails.isSome()) {
|
|
|
24388 |
const startSummary = startDetails.bind(details => Optional.from(dom.select('summary', details)[0]));
|
|
|
24389 |
return Optional.some({
|
|
|
24390 |
startSummary,
|
|
|
24391 |
startDetails,
|
|
|
24392 |
endDetails
|
|
|
24393 |
});
|
|
|
24394 |
} else {
|
|
|
24395 |
return Optional.none();
|
|
|
24396 |
}
|
|
|
24397 |
};
|
|
|
24398 |
const isCaretInTheBeginningOf = (caretPos, element) => firstPositionIn(element).exists(pos => pos.isEqual(caretPos));
|
|
|
24399 |
const isCaretInTheEndOf = (caretPos, element) => {
|
|
|
24400 |
return lastPositionIn(element).exists(pos => {
|
|
|
24401 |
if (isBr$6(pos.getNode())) {
|
|
|
24402 |
return prevPosition(element, pos).exists(pos2 => pos2.isEqual(caretPos)) || pos.isEqual(caretPos);
|
|
|
24403 |
} else {
|
|
|
24404 |
return pos.isEqual(caretPos);
|
|
|
24405 |
}
|
|
|
24406 |
});
|
|
|
24407 |
};
|
|
|
24408 |
const isCaretAtStartOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheBeginningOf(caretPos, summary));
|
|
|
24409 |
const isCaretAtEndOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheEndOf(caretPos, summary));
|
|
|
24410 |
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()))));
|
|
|
24411 |
const isCaretInLastPositionInBody = (root, caretPos, detailsElements) => detailsElements.startDetails.exists(details => nextPosition(root, caretPos).forall(pos => !details.contains(pos.container())));
|
|
|
24412 |
const setCaretToPosition = (editor, position) => {
|
|
|
24413 |
const node = position.getNode();
|
|
|
24414 |
if (!isUndefined(node)) {
|
|
|
24415 |
editor.selection.setCursorLocation(node, position.offset());
|
|
|
24416 |
}
|
|
|
24417 |
};
|
|
|
24418 |
const moveCaretToDetailsPos = (editor, pos, forward) => {
|
|
|
24419 |
const details = editor.dom.getParent(pos.container(), 'details');
|
|
|
24420 |
if (details && !details.open) {
|
|
|
24421 |
const summary = editor.dom.select('summary', details)[0];
|
|
|
24422 |
if (summary) {
|
|
|
24423 |
const newPos = forward ? firstPositionIn(summary) : lastPositionIn(summary);
|
|
|
24424 |
newPos.each(pos => setCaretToPosition(editor, pos));
|
|
|
24425 |
}
|
|
|
24426 |
} else {
|
|
|
24427 |
setCaretToPosition(editor, pos);
|
|
|
24428 |
}
|
|
|
24429 |
};
|
|
|
24430 |
const isPartialDelete = (rng, detailsElements) => {
|
|
|
24431 |
const containsStart = element => element.contains(rng.startContainer);
|
|
|
24432 |
const containsEnd = element => element.contains(rng.endContainer);
|
|
|
24433 |
const startInSummary = detailsElements.startSummary.exists(containsStart);
|
|
|
24434 |
const endInSummary = detailsElements.startSummary.exists(containsEnd);
|
|
|
24435 |
const isPartiallySelectedDetailsElements = detailsElements.startDetails.forall(startDetails => detailsElements.endDetails.forall(endDetails => startDetails !== endDetails));
|
|
|
24436 |
const isInPartiallySelectedSummary = (startInSummary || endInSummary) && !(startInSummary && endInSummary);
|
|
|
24437 |
return isInPartiallySelectedSummary || isPartiallySelectedDetailsElements;
|
|
|
24438 |
};
|
|
|
24439 |
const shouldPreventDeleteIntoDetails = (editor, forward, granularity) => {
|
|
|
24440 |
const {dom, selection} = editor;
|
|
|
24441 |
const root = editor.getBody();
|
|
|
24442 |
if (granularity === 'character') {
|
|
|
24443 |
const caretPos = CaretPosition.fromRangeStart(selection.getRng());
|
|
|
24444 |
const parentBlock = dom.getParent(caretPos.container(), dom.isBlock);
|
|
|
24445 |
const parentDetailsAtCaret = getParentDetailsElementAtPos(dom, caretPos);
|
|
|
24446 |
const inEmptyParentBlock = parentBlock && dom.isEmpty(parentBlock);
|
|
|
24447 |
const isFirstBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.previousSibling);
|
|
|
24448 |
const isLastBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.nextSibling);
|
|
|
24449 |
if (inEmptyParentBlock) {
|
|
|
24450 |
const firstOrLast = forward ? isLastBlock : isFirstBlock;
|
|
|
24451 |
if (firstOrLast) {
|
|
|
24452 |
const isBeforeAfterDetails = navigate(!forward, root, caretPos).exists(pos => {
|
|
|
24453 |
return isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, getParentDetailsElementAtPos(dom, pos));
|
|
|
24454 |
});
|
|
|
24455 |
if (isBeforeAfterDetails) {
|
|
|
24456 |
return true;
|
|
|
24457 |
}
|
|
|
24458 |
}
|
|
|
24459 |
}
|
|
|
24460 |
return navigate(forward, root, caretPos).fold(never, pos => {
|
|
|
24461 |
const parentDetailsAtNewPos = getParentDetailsElementAtPos(dom, pos);
|
|
|
24462 |
if (isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, parentDetailsAtNewPos)) {
|
|
|
24463 |
if (!forward) {
|
|
|
24464 |
moveCaretToDetailsPos(editor, pos, false);
|
|
|
24465 |
}
|
|
|
24466 |
if (parentBlock && inEmptyParentBlock) {
|
|
|
24467 |
if (forward && isFirstBlock) {
|
|
|
24468 |
return true;
|
|
|
24469 |
} else if (!forward && isLastBlock) {
|
|
|
24470 |
return true;
|
|
|
24471 |
}
|
|
|
24472 |
moveCaretToDetailsPos(editor, pos, forward);
|
|
|
24473 |
editor.dom.remove(parentBlock);
|
|
|
24474 |
}
|
|
|
24475 |
return true;
|
|
|
24476 |
} else {
|
|
|
24477 |
return false;
|
|
|
24478 |
}
|
|
|
24479 |
});
|
|
|
24480 |
} else {
|
|
|
24481 |
return false;
|
|
|
24482 |
}
|
|
|
24483 |
};
|
|
|
24484 |
const shouldPreventDeleteSummaryAction = (editor, detailElements, forward, granularity) => {
|
|
|
24485 |
const selection = editor.selection;
|
|
|
24486 |
const rng = selection.getRng();
|
|
|
24487 |
const caretPos = CaretPosition.fromRangeStart(rng);
|
|
|
24488 |
const root = editor.getBody();
|
|
|
24489 |
if (granularity === 'selection') {
|
|
|
24490 |
return isPartialDelete(rng, detailElements);
|
|
|
24491 |
} else if (forward) {
|
|
|
24492 |
return isCaretAtEndOfSummary(caretPos, detailElements) || isCaretInLastPositionInBody(root, caretPos, detailElements);
|
|
|
24493 |
} else {
|
|
|
24494 |
return isCaretAtStartOfSummary(caretPos, detailElements) || isCaretInFirstPositionInBody(caretPos, detailElements);
|
|
|
24495 |
}
|
|
|
24496 |
};
|
|
|
24497 |
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));
|
|
|
24498 |
const handleDeleteActionSafari = (editor, forward, granularity) => {
|
|
|
24499 |
const selection = editor.selection;
|
|
|
24500 |
const node = selection.getNode();
|
|
|
24501 |
const rng = selection.getRng();
|
|
|
24502 |
const caretPos = CaretPosition.fromRangeStart(rng);
|
|
|
24503 |
if (isSummary$1(node)) {
|
|
|
24504 |
if (granularity === 'selection' && isEntireNodeSelected(rng, node) || willDeleteLastPositionInElement(forward, caretPos, node)) {
|
|
|
24505 |
emptyNodeContents(node);
|
|
|
24506 |
} else {
|
|
|
24507 |
editor.undoManager.transact(() => {
|
|
|
24508 |
const sel = selection.getSel();
|
|
|
24509 |
let {anchorNode, anchorOffset, focusNode, focusOffset} = sel !== null && sel !== void 0 ? sel : {};
|
|
|
24510 |
const applySelection = () => {
|
|
|
24511 |
if (isNonNullable(anchorNode) && isNonNullable(anchorOffset) && isNonNullable(focusNode) && isNonNullable(focusOffset)) {
|
|
|
24512 |
sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
|
|
|
24513 |
}
|
|
|
24514 |
};
|
|
|
24515 |
const updateSelection = () => {
|
|
|
24516 |
anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
|
|
|
24517 |
anchorOffset = sel === null || sel === void 0 ? void 0 : sel.anchorOffset;
|
|
|
24518 |
focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
|
|
|
24519 |
focusOffset = sel === null || sel === void 0 ? void 0 : sel.focusOffset;
|
|
|
24520 |
};
|
|
|
24521 |
const appendAllChildNodes = (from, to) => {
|
|
|
24522 |
each$e(from.childNodes, child => {
|
|
|
24523 |
if (isNode(child)) {
|
|
|
24524 |
to.appendChild(child);
|
|
|
24525 |
}
|
|
|
24526 |
});
|
|
|
24527 |
};
|
|
|
24528 |
const container = editor.dom.create('span', { 'data-mce-bogus': '1' });
|
|
|
24529 |
appendAllChildNodes(node, container);
|
|
|
24530 |
node.appendChild(container);
|
|
|
24531 |
applySelection();
|
|
|
24532 |
if (granularity === 'word' || granularity === 'line') {
|
|
|
24533 |
sel === null || sel === void 0 ? void 0 : sel.modify('extend', forward ? 'right' : 'left', granularity);
|
|
|
24534 |
}
|
|
|
24535 |
if (!selection.isCollapsed() && isEntireNodeSelected(selection.getRng(), container)) {
|
|
|
24536 |
emptyNodeContents(node);
|
|
|
24537 |
} else {
|
|
|
24538 |
editor.execCommand(forward ? 'ForwardDelete' : 'Delete');
|
|
|
24539 |
updateSelection();
|
|
|
24540 |
appendAllChildNodes(container, node);
|
|
|
24541 |
applySelection();
|
|
|
24542 |
}
|
|
|
24543 |
editor.dom.remove(container);
|
|
|
24544 |
});
|
|
|
24545 |
}
|
|
|
24546 |
return true;
|
|
|
24547 |
} else {
|
|
|
24548 |
return false;
|
|
|
24549 |
}
|
|
|
24550 |
};
|
|
|
24551 |
const backspaceDelete = (editor, forward, granularity) => shouldPreventDeleteAction(editor, forward, granularity) || isSafari && handleDeleteActionSafari(editor, forward, granularity) ? Optional.some(noop) : Optional.none();
|
|
|
24552 |
|
|
|
24553 |
const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => {
|
|
|
24554 |
const target = editor.getBody();
|
|
|
24555 |
const overrides = {
|
|
|
24556 |
bubbles: true,
|
|
|
24557 |
composed: true,
|
|
|
24558 |
data: null,
|
|
|
24559 |
isComposing: false,
|
|
|
24560 |
detail: 0,
|
|
|
24561 |
view: null,
|
|
|
24562 |
target,
|
|
|
24563 |
currentTarget: target,
|
|
|
24564 |
eventPhase: Event.AT_TARGET,
|
|
|
24565 |
originalTarget: target,
|
|
|
24566 |
explicitOriginalTarget: target,
|
|
|
24567 |
isTrusted: false,
|
|
|
24568 |
srcElement: target,
|
|
|
24569 |
cancelable: false,
|
|
|
24570 |
preventDefault: noop,
|
|
|
24571 |
inputType
|
|
|
24572 |
};
|
|
|
24573 |
const input = clone$3(new InputEvent(eventType));
|
|
|
24574 |
return editor.dispatch(eventType, {
|
|
|
24575 |
...input,
|
|
|
24576 |
...overrides,
|
|
|
24577 |
...specifics
|
|
|
24578 |
});
|
|
|
24579 |
};
|
|
|
24580 |
const fireInputEvent = createAndFireInputEvent('input');
|
|
|
24581 |
const fireBeforeInputEvent = createAndFireInputEvent('beforeinput');
|
|
|
24582 |
|
| 1441 |
ariadna |
24583 |
const platform$2 = detect$1();
|
| 1 |
efrain |
24584 |
const os = platform$2.os;
|
|
|
24585 |
const isMacOSOriOS = os.isMacOS() || os.isiOS();
|
|
|
24586 |
const browser = platform$2.browser;
|
|
|
24587 |
const isFirefox = browser.isFirefox();
|
|
|
24588 |
const executeKeydownOverride$3 = (editor, caret, evt) => {
|
|
|
24589 |
const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward';
|
|
|
24590 |
const isCollapsed = editor.selection.isCollapsed();
|
|
|
24591 |
const unmodifiedGranularity = isCollapsed ? 'character' : 'selection';
|
|
|
24592 |
const getModifiedGranularity = isWord => {
|
|
|
24593 |
if (isCollapsed) {
|
|
|
24594 |
return isWord ? 'word' : 'line';
|
|
|
24595 |
} else {
|
|
|
24596 |
return 'selection';
|
|
|
24597 |
}
|
|
|
24598 |
};
|
|
|
24599 |
executeWithDelayedAction([
|
|
|
24600 |
{
|
|
|
24601 |
keyCode: VK.BACKSPACE,
|
|
|
24602 |
action: action(backspaceDelete$1, editor)
|
|
|
24603 |
},
|
|
|
24604 |
{
|
|
|
24605 |
keyCode: VK.BACKSPACE,
|
| 1441 |
ariadna |
24606 |
action: action(backspaceDelete$7, editor, false)
|
| 1 |
efrain |
24607 |
},
|
|
|
24608 |
{
|
|
|
24609 |
keyCode: VK.DELETE,
|
| 1441 |
ariadna |
24610 |
action: action(backspaceDelete$7, editor, true)
|
| 1 |
efrain |
24611 |
},
|
|
|
24612 |
{
|
|
|
24613 |
keyCode: VK.BACKSPACE,
|
| 1441 |
ariadna |
24614 |
action: action(backspaceDelete$8, editor, false)
|
| 1 |
efrain |
24615 |
},
|
|
|
24616 |
{
|
|
|
24617 |
keyCode: VK.DELETE,
|
| 1441 |
ariadna |
24618 |
action: action(backspaceDelete$8, editor, true)
|
| 1 |
efrain |
24619 |
},
|
|
|
24620 |
{
|
|
|
24621 |
keyCode: VK.BACKSPACE,
|
|
|
24622 |
action: action(backspaceDelete$4, editor, caret, false)
|
|
|
24623 |
},
|
|
|
24624 |
{
|
|
|
24625 |
keyCode: VK.DELETE,
|
|
|
24626 |
action: action(backspaceDelete$4, editor, caret, true)
|
|
|
24627 |
},
|
|
|
24628 |
{
|
|
|
24629 |
keyCode: VK.BACKSPACE,
|
| 1441 |
ariadna |
24630 |
action: action(backspaceDelete$b, editor, false)
|
| 1 |
efrain |
24631 |
},
|
|
|
24632 |
{
|
|
|
24633 |
keyCode: VK.DELETE,
|
| 1441 |
ariadna |
24634 |
action: action(backspaceDelete$b, editor, true)
|
| 1 |
efrain |
24635 |
},
|
|
|
24636 |
{
|
|
|
24637 |
keyCode: VK.BACKSPACE,
|
|
|
24638 |
action: action(backspaceDelete, editor, false, unmodifiedGranularity)
|
|
|
24639 |
},
|
|
|
24640 |
{
|
|
|
24641 |
keyCode: VK.DELETE,
|
|
|
24642 |
action: action(backspaceDelete, editor, true, unmodifiedGranularity)
|
|
|
24643 |
},
|
|
|
24644 |
...isMacOSOriOS ? [
|
|
|
24645 |
{
|
|
|
24646 |
keyCode: VK.BACKSPACE,
|
|
|
24647 |
altKey: true,
|
|
|
24648 |
action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
|
|
|
24649 |
},
|
|
|
24650 |
{
|
|
|
24651 |
keyCode: VK.DELETE,
|
|
|
24652 |
altKey: true,
|
|
|
24653 |
action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
|
|
|
24654 |
},
|
|
|
24655 |
{
|
|
|
24656 |
keyCode: VK.BACKSPACE,
|
|
|
24657 |
metaKey: true,
|
|
|
24658 |
action: action(backspaceDelete, editor, false, getModifiedGranularity(false))
|
|
|
24659 |
}
|
|
|
24660 |
] : [
|
|
|
24661 |
{
|
|
|
24662 |
keyCode: VK.BACKSPACE,
|
|
|
24663 |
ctrlKey: true,
|
|
|
24664 |
action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
|
|
|
24665 |
},
|
|
|
24666 |
{
|
|
|
24667 |
keyCode: VK.DELETE,
|
|
|
24668 |
ctrlKey: true,
|
|
|
24669 |
action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
|
|
|
24670 |
}
|
|
|
24671 |
],
|
|
|
24672 |
{
|
|
|
24673 |
keyCode: VK.BACKSPACE,
|
|
|
24674 |
action: action(backspaceDelete$5, editor, false)
|
|
|
24675 |
},
|
|
|
24676 |
{
|
|
|
24677 |
keyCode: VK.DELETE,
|
|
|
24678 |
action: action(backspaceDelete$5, editor, true)
|
|
|
24679 |
},
|
|
|
24680 |
{
|
|
|
24681 |
keyCode: VK.BACKSPACE,
|
|
|
24682 |
action: action(backspaceDelete$2, editor, false)
|
|
|
24683 |
},
|
|
|
24684 |
{
|
|
|
24685 |
keyCode: VK.DELETE,
|
|
|
24686 |
action: action(backspaceDelete$2, editor, true)
|
|
|
24687 |
},
|
|
|
24688 |
{
|
|
|
24689 |
keyCode: VK.BACKSPACE,
|
| 1441 |
ariadna |
24690 |
action: action(backspaceDelete$9, editor, false)
|
| 1 |
efrain |
24691 |
},
|
|
|
24692 |
{
|
|
|
24693 |
keyCode: VK.DELETE,
|
| 1441 |
ariadna |
24694 |
action: action(backspaceDelete$9, editor, true)
|
| 1 |
efrain |
24695 |
},
|
|
|
24696 |
{
|
|
|
24697 |
keyCode: VK.BACKSPACE,
|
| 1441 |
ariadna |
24698 |
action: action(backspaceDelete$a, editor, false)
|
| 1 |
efrain |
24699 |
},
|
|
|
24700 |
{
|
|
|
24701 |
keyCode: VK.DELETE,
|
| 1441 |
ariadna |
24702 |
action: action(backspaceDelete$a, editor, true)
|
| 1 |
efrain |
24703 |
},
|
|
|
24704 |
{
|
|
|
24705 |
keyCode: VK.BACKSPACE,
|
|
|
24706 |
action: action(backspaceDelete$3, editor, false)
|
|
|
24707 |
},
|
|
|
24708 |
{
|
|
|
24709 |
keyCode: VK.DELETE,
|
|
|
24710 |
action: action(backspaceDelete$3, editor, true)
|
| 1441 |
ariadna |
24711 |
},
|
|
|
24712 |
{
|
|
|
24713 |
keyCode: VK.BACKSPACE,
|
|
|
24714 |
action: action(backspaceDelete$6, editor, false)
|
|
|
24715 |
},
|
|
|
24716 |
{
|
|
|
24717 |
keyCode: VK.DELETE,
|
|
|
24718 |
action: action(backspaceDelete$6, editor, true)
|
| 1 |
efrain |
24719 |
}
|
|
|
24720 |
], evt).filter(_ => editor.selection.isEditable()).each(applyAction => {
|
|
|
24721 |
evt.preventDefault();
|
|
|
24722 |
const beforeInput = fireBeforeInputEvent(editor, inputType);
|
|
|
24723 |
if (!beforeInput.isDefaultPrevented()) {
|
|
|
24724 |
applyAction();
|
|
|
24725 |
fireInputEvent(editor, inputType);
|
|
|
24726 |
}
|
|
|
24727 |
});
|
|
|
24728 |
};
|
|
|
24729 |
const executeKeyupOverride = (editor, evt, isBackspaceKeydown) => execute([
|
|
|
24730 |
{
|
|
|
24731 |
keyCode: VK.BACKSPACE,
|
|
|
24732 |
action: action(paddEmptyElement, editor)
|
|
|
24733 |
},
|
|
|
24734 |
{
|
|
|
24735 |
keyCode: VK.DELETE,
|
|
|
24736 |
action: action(paddEmptyElement, editor)
|
|
|
24737 |
},
|
|
|
24738 |
...isMacOSOriOS ? [
|
|
|
24739 |
{
|
|
|
24740 |
keyCode: VK.BACKSPACE,
|
|
|
24741 |
altKey: true,
|
|
|
24742 |
action: action(refreshCaret, editor)
|
|
|
24743 |
},
|
|
|
24744 |
{
|
|
|
24745 |
keyCode: VK.DELETE,
|
|
|
24746 |
altKey: true,
|
|
|
24747 |
action: action(refreshCaret, editor)
|
|
|
24748 |
},
|
|
|
24749 |
...isBackspaceKeydown ? [{
|
|
|
24750 |
keyCode: isFirefox ? 224 : 91,
|
|
|
24751 |
action: action(refreshCaret, editor)
|
|
|
24752 |
}] : []
|
|
|
24753 |
] : [
|
|
|
24754 |
{
|
|
|
24755 |
keyCode: VK.BACKSPACE,
|
|
|
24756 |
ctrlKey: true,
|
|
|
24757 |
action: action(refreshCaret, editor)
|
|
|
24758 |
},
|
|
|
24759 |
{
|
|
|
24760 |
keyCode: VK.DELETE,
|
|
|
24761 |
ctrlKey: true,
|
|
|
24762 |
action: action(refreshCaret, editor)
|
|
|
24763 |
}
|
|
|
24764 |
]
|
|
|
24765 |
], evt);
|
|
|
24766 |
const setup$j = (editor, caret) => {
|
|
|
24767 |
let isBackspaceKeydown = false;
|
|
|
24768 |
editor.on('keydown', evt => {
|
|
|
24769 |
isBackspaceKeydown = evt.keyCode === VK.BACKSPACE;
|
|
|
24770 |
if (!evt.isDefaultPrevented()) {
|
|
|
24771 |
executeKeydownOverride$3(editor, caret, evt);
|
|
|
24772 |
}
|
|
|
24773 |
});
|
|
|
24774 |
editor.on('keyup', evt => {
|
|
|
24775 |
if (!evt.isDefaultPrevented()) {
|
|
|
24776 |
executeKeyupOverride(editor, evt, isBackspaceKeydown);
|
|
|
24777 |
}
|
|
|
24778 |
isBackspaceKeydown = false;
|
|
|
24779 |
});
|
|
|
24780 |
};
|
|
|
24781 |
|
|
|
24782 |
const firstNonWhiteSpaceNodeSibling = node => {
|
|
|
24783 |
while (node) {
|
| 1441 |
ariadna |
24784 |
if (isElement$6(node) || isText$b(node) && node.data && /[\r\n\s]/.test(node.data)) {
|
| 1 |
efrain |
24785 |
return node;
|
|
|
24786 |
}
|
|
|
24787 |
node = node.nextSibling;
|
|
|
24788 |
}
|
|
|
24789 |
return null;
|
|
|
24790 |
};
|
|
|
24791 |
const moveToCaretPosition = (editor, root) => {
|
|
|
24792 |
const dom = editor.dom;
|
|
|
24793 |
const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
|
|
|
24794 |
if (!root) {
|
|
|
24795 |
return;
|
|
|
24796 |
}
|
|
|
24797 |
if (/^(LI|DT|DD)$/.test(root.nodeName)) {
|
|
|
24798 |
const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
|
|
|
24799 |
if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
|
|
|
24800 |
root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild);
|
|
|
24801 |
}
|
|
|
24802 |
}
|
|
|
24803 |
const rng = dom.createRng();
|
|
|
24804 |
root.normalize();
|
|
|
24805 |
if (root.hasChildNodes()) {
|
|
|
24806 |
const walker = new DomTreeWalker(root, root);
|
|
|
24807 |
let lastNode = root;
|
|
|
24808 |
let node;
|
|
|
24809 |
while (node = walker.current()) {
|
| 1441 |
ariadna |
24810 |
if (isText$b(node)) {
|
| 1 |
efrain |
24811 |
rng.setStart(node, 0);
|
|
|
24812 |
rng.setEnd(node, 0);
|
|
|
24813 |
break;
|
|
|
24814 |
}
|
|
|
24815 |
if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
|
|
|
24816 |
rng.setStartBefore(node);
|
|
|
24817 |
rng.setEndBefore(node);
|
|
|
24818 |
break;
|
|
|
24819 |
}
|
|
|
24820 |
lastNode = node;
|
|
|
24821 |
node = walker.next();
|
|
|
24822 |
}
|
|
|
24823 |
if (!node) {
|
|
|
24824 |
rng.setStart(lastNode, 0);
|
|
|
24825 |
rng.setEnd(lastNode, 0);
|
|
|
24826 |
}
|
|
|
24827 |
} else {
|
|
|
24828 |
if (isBr$6(root)) {
|
|
|
24829 |
if (root.nextSibling && dom.isBlock(root.nextSibling)) {
|
|
|
24830 |
rng.setStartBefore(root);
|
|
|
24831 |
rng.setEndBefore(root);
|
|
|
24832 |
} else {
|
|
|
24833 |
rng.setStartAfter(root);
|
|
|
24834 |
rng.setEndAfter(root);
|
|
|
24835 |
}
|
|
|
24836 |
} else {
|
|
|
24837 |
rng.setStart(root, 0);
|
|
|
24838 |
rng.setEnd(root, 0);
|
|
|
24839 |
}
|
|
|
24840 |
}
|
|
|
24841 |
editor.selection.setRng(rng);
|
|
|
24842 |
scrollRangeIntoView(editor, rng);
|
|
|
24843 |
};
|
|
|
24844 |
const getEditableRoot = (dom, node) => {
|
|
|
24845 |
const root = dom.getRoot();
|
|
|
24846 |
let editableRoot;
|
|
|
24847 |
let parent = node;
|
|
|
24848 |
while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') {
|
|
|
24849 |
if (dom.getContentEditable(parent) === 'true') {
|
|
|
24850 |
editableRoot = parent;
|
|
|
24851 |
break;
|
|
|
24852 |
}
|
|
|
24853 |
parent = parent.parentNode;
|
|
|
24854 |
}
|
|
|
24855 |
return parent !== root ? editableRoot : root;
|
|
|
24856 |
};
|
|
|
24857 |
const getParentBlock$1 = editor => {
|
|
|
24858 |
return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
|
|
|
24859 |
};
|
|
|
24860 |
const getParentBlockName = editor => {
|
|
|
24861 |
return getParentBlock$1(editor).fold(constant(''), parentBlock => {
|
|
|
24862 |
return parentBlock.nodeName.toUpperCase();
|
|
|
24863 |
});
|
|
|
24864 |
};
|
|
|
24865 |
const isListItemParentBlock = editor => {
|
|
|
24866 |
return getParentBlock$1(editor).filter(elm => {
|
|
|
24867 |
return isListItem$1(SugarElement.fromDom(elm));
|
|
|
24868 |
}).isSome();
|
|
|
24869 |
};
|
|
|
24870 |
const emptyBlock = elm => {
|
|
|
24871 |
elm.innerHTML = '<br data-mce-bogus="1">';
|
|
|
24872 |
};
|
|
|
24873 |
const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
|
|
|
24874 |
const dom = editor.dom;
|
|
|
24875 |
Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => {
|
|
|
24876 |
const currentStyles = getAllRaw(SugarElement.fromDom(node));
|
|
|
24877 |
const newStyles = {
|
|
|
24878 |
...currentStyles,
|
|
|
24879 |
...attrStyles
|
|
|
24880 |
};
|
|
|
24881 |
dom.setStyles(node, newStyles);
|
|
|
24882 |
});
|
|
|
24883 |
const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/));
|
|
|
24884 |
const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== ''));
|
|
|
24885 |
lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
|
|
|
24886 |
const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz));
|
|
|
24887 |
const newClasses = [
|
|
|
24888 |
...attrClasses,
|
|
|
24889 |
...filteredClasses
|
|
|
24890 |
];
|
|
|
24891 |
dom.setAttrib(node, 'class', newClasses.join(' '));
|
|
|
24892 |
});
|
|
|
24893 |
const appliedAttrs = [
|
|
|
24894 |
'style',
|
|
|
24895 |
'class'
|
|
|
24896 |
];
|
|
|
24897 |
const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
|
|
|
24898 |
dom.setAttribs(node, remainingAttrs);
|
|
|
24899 |
};
|
|
|
24900 |
const setForcedBlockAttrs = (editor, node) => {
|
|
|
24901 |
const forcedRootBlockName = getForcedRootBlock(editor);
|
|
|
24902 |
if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
|
|
|
24903 |
const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
|
|
|
24904 |
applyAttributes(editor, node, forcedRootBlockAttrs);
|
|
|
24905 |
}
|
|
|
24906 |
};
|
|
|
24907 |
const createNewBlock = (editor, container, parentBlock, editableRoot, keepStyles = true, name, styles) => {
|
|
|
24908 |
const dom = editor.dom;
|
|
|
24909 |
const schema = editor.schema;
|
|
|
24910 |
const newBlockName = getForcedRootBlock(editor);
|
|
|
24911 |
const parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
|
|
|
24912 |
let node = container;
|
|
|
24913 |
const textInlineElements = schema.getTextInlineElements();
|
|
|
24914 |
let block;
|
|
|
24915 |
if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
|
|
|
24916 |
block = dom.create(name || newBlockName, styles || {});
|
|
|
24917 |
} else {
|
|
|
24918 |
block = parentBlock.cloneNode(false);
|
|
|
24919 |
}
|
|
|
24920 |
let caretNode = block;
|
|
|
24921 |
if (!keepStyles) {
|
|
|
24922 |
dom.setAttrib(block, 'style', null);
|
|
|
24923 |
dom.setAttrib(block, 'class', null);
|
|
|
24924 |
} else {
|
|
|
24925 |
do {
|
|
|
24926 |
if (textInlineElements[node.nodeName]) {
|
|
|
24927 |
if (isCaretNode(node) || isBookmarkNode$1(node)) {
|
|
|
24928 |
continue;
|
|
|
24929 |
}
|
|
|
24930 |
const clonedNode = node.cloneNode(false);
|
|
|
24931 |
dom.setAttrib(clonedNode, 'id', '');
|
|
|
24932 |
if (block.hasChildNodes()) {
|
|
|
24933 |
clonedNode.appendChild(block.firstChild);
|
|
|
24934 |
block.appendChild(clonedNode);
|
|
|
24935 |
} else {
|
|
|
24936 |
caretNode = clonedNode;
|
|
|
24937 |
block.appendChild(clonedNode);
|
|
|
24938 |
}
|
|
|
24939 |
}
|
|
|
24940 |
} while ((node = node.parentNode) && node !== editableRoot);
|
|
|
24941 |
}
|
|
|
24942 |
setForcedBlockAttrs(editor, block);
|
|
|
24943 |
emptyBlock(caretNode);
|
|
|
24944 |
return block;
|
|
|
24945 |
};
|
|
|
24946 |
|
|
|
24947 |
const getDetailsRoot = (editor, element) => editor.dom.getParent(element, isDetails);
|
|
|
24948 |
const isAtDetailsEdge = (root, element, isTextBlock) => {
|
|
|
24949 |
let node = element;
|
|
|
24950 |
while (node && node !== root && isNull(node.nextSibling)) {
|
|
|
24951 |
const parent = node.parentElement;
|
|
|
24952 |
if (!parent || !isTextBlock(parent)) {
|
|
|
24953 |
return isDetails(parent);
|
|
|
24954 |
}
|
|
|
24955 |
node = parent;
|
|
|
24956 |
}
|
|
|
24957 |
return false;
|
|
|
24958 |
};
|
|
|
24959 |
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()));
|
|
|
24960 |
const insertNewLine = (editor, createNewBlock, parentBlock) => {
|
|
|
24961 |
var _a, _b, _c;
|
|
|
24962 |
const newBlock = createNewBlock(getForcedRootBlock(editor));
|
|
|
24963 |
const root = getDetailsRoot(editor, parentBlock);
|
|
|
24964 |
if (!root) {
|
|
|
24965 |
return;
|
|
|
24966 |
}
|
|
|
24967 |
editor.dom.insertAfter(newBlock, root);
|
|
|
24968 |
moveToCaretPosition(editor, newBlock);
|
|
|
24969 |
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) {
|
|
|
24970 |
editor.dom.remove(parentBlock);
|
|
|
24971 |
}
|
|
|
24972 |
};
|
|
|
24973 |
|
|
|
24974 |
const hasFirstChild = (elm, name) => {
|
|
|
24975 |
return elm.firstChild && elm.firstChild.nodeName === name;
|
|
|
24976 |
};
|
|
|
24977 |
const isFirstChild = elm => {
|
|
|
24978 |
var _a;
|
|
|
24979 |
return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
|
|
|
24980 |
};
|
|
|
24981 |
const hasParent = (elm, parentName) => {
|
|
|
24982 |
const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode;
|
|
|
24983 |
return isNonNullable(parentNode) && parentNode.nodeName === parentName;
|
|
|
24984 |
};
|
|
|
24985 |
const isListBlock = elm => {
|
|
|
24986 |
return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName);
|
|
|
24987 |
};
|
|
|
24988 |
const isListItem = elm => {
|
|
|
24989 |
return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName);
|
|
|
24990 |
};
|
|
|
24991 |
const isNestedList = elm => {
|
|
|
24992 |
return isListBlock(elm) && isListBlock(elm.parentNode);
|
|
|
24993 |
};
|
|
|
24994 |
const getContainerBlock = containerBlock => {
|
|
|
24995 |
const containerBlockParent = containerBlock.parentNode;
|
|
|
24996 |
return isListItem(containerBlockParent) ? containerBlockParent : containerBlock;
|
|
|
24997 |
};
|
|
|
24998 |
const isFirstOrLastLi = (containerBlock, parentBlock, first) => {
|
|
|
24999 |
let node = containerBlock[first ? 'firstChild' : 'lastChild'];
|
|
|
25000 |
while (node) {
|
|
|
25001 |
if (isElement$6(node)) {
|
|
|
25002 |
break;
|
|
|
25003 |
}
|
|
|
25004 |
node = node[first ? 'nextSibling' : 'previousSibling'];
|
|
|
25005 |
}
|
|
|
25006 |
return node === parentBlock;
|
|
|
25007 |
};
|
|
|
25008 |
const getStyles = elm => foldl(mapToArray(getAllRaw(SugarElement.fromDom(elm)), (style, styleName) => `${ styleName }: ${ style };`), (acc, s) => acc + s, '');
|
|
|
25009 |
const insert$4 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
|
|
|
25010 |
const dom = editor.dom;
|
|
|
25011 |
const rng = editor.selection.getRng();
|
|
|
25012 |
const containerParent = containerBlock.parentNode;
|
|
|
25013 |
if (containerBlock === editor.getBody() || !containerParent) {
|
|
|
25014 |
return;
|
|
|
25015 |
}
|
|
|
25016 |
if (isNestedList(containerBlock)) {
|
|
|
25017 |
newBlockName = 'LI';
|
|
|
25018 |
}
|
|
|
25019 |
const parentBlockStyles = isListItem(parentBlock) ? getStyles(parentBlock) : undefined;
|
|
|
25020 |
let newBlock = isListItem(parentBlock) && parentBlockStyles ? createNewBlock(newBlockName, { style: getStyles(parentBlock) }) : createNewBlock(newBlockName);
|
|
|
25021 |
if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
|
|
|
25022 |
if (hasParent(containerBlock, 'LI')) {
|
|
|
25023 |
const containerBlockParent = getContainerBlock(containerBlock);
|
|
|
25024 |
dom.insertAfter(newBlock, containerBlockParent);
|
|
|
25025 |
if (isFirstChild(containerBlock)) {
|
|
|
25026 |
dom.remove(containerBlockParent);
|
|
|
25027 |
} else {
|
|
|
25028 |
dom.remove(containerBlock);
|
|
|
25029 |
}
|
|
|
25030 |
} else {
|
|
|
25031 |
dom.replace(newBlock, containerBlock);
|
|
|
25032 |
}
|
|
|
25033 |
} else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
|
|
|
25034 |
if (hasParent(containerBlock, 'LI')) {
|
|
|
25035 |
dom.insertAfter(newBlock, getContainerBlock(containerBlock));
|
|
|
25036 |
newBlock.appendChild(dom.doc.createTextNode(' '));
|
|
|
25037 |
newBlock.appendChild(containerBlock);
|
|
|
25038 |
} else {
|
|
|
25039 |
containerParent.insertBefore(newBlock, containerBlock);
|
|
|
25040 |
}
|
|
|
25041 |
dom.remove(parentBlock);
|
|
|
25042 |
} else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
|
|
|
25043 |
dom.insertAfter(newBlock, getContainerBlock(containerBlock));
|
|
|
25044 |
dom.remove(parentBlock);
|
|
|
25045 |
} else {
|
|
|
25046 |
containerBlock = getContainerBlock(containerBlock);
|
|
|
25047 |
const tmpRng = rng.cloneRange();
|
|
|
25048 |
tmpRng.setStartAfter(parentBlock);
|
|
|
25049 |
tmpRng.setEndAfter(containerBlock);
|
|
|
25050 |
const fragment = tmpRng.extractContents();
|
|
|
25051 |
if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
|
|
|
25052 |
const previousChildren = filter$5(map$3(newBlock.children, SugarElement.fromDom), not(isTag('br')));
|
|
|
25053 |
newBlock = fragment.firstChild;
|
|
|
25054 |
dom.insertAfter(fragment, containerBlock);
|
|
|
25055 |
each$e(previousChildren, child => prepend(SugarElement.fromDom(newBlock), child));
|
|
|
25056 |
if (parentBlockStyles) {
|
|
|
25057 |
newBlock.setAttribute('style', parentBlockStyles);
|
|
|
25058 |
}
|
|
|
25059 |
} else {
|
|
|
25060 |
dom.insertAfter(fragment, containerBlock);
|
|
|
25061 |
dom.insertAfter(newBlock, containerBlock);
|
|
|
25062 |
}
|
|
|
25063 |
dom.remove(parentBlock);
|
|
|
25064 |
}
|
|
|
25065 |
moveToCaretPosition(editor, newBlock);
|
|
|
25066 |
};
|
|
|
25067 |
|
|
|
25068 |
const trimZwsp = fragment => {
|
| 1441 |
ariadna |
25069 |
each$e(descendants$1(SugarElement.fromDom(fragment), isText$c), text => {
|
| 1 |
efrain |
25070 |
const rawNode = text.dom;
|
|
|
25071 |
rawNode.nodeValue = trim$2(rawNode.data);
|
|
|
25072 |
});
|
|
|
25073 |
};
|
|
|
25074 |
const isWithinNonEditableList = (editor, node) => {
|
|
|
25075 |
const parentList = editor.dom.getParent(node, 'ol,ul,dl');
|
|
|
25076 |
return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false';
|
|
|
25077 |
};
|
|
|
25078 |
const isEmptyAnchor = (dom, elm) => {
|
|
|
25079 |
return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
|
|
|
25080 |
};
|
| 1441 |
ariadna |
25081 |
const containerAndPreviousSiblingName = (container, nodeName) => {
|
| 1 |
efrain |
25082 |
return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
|
|
|
25083 |
};
|
| 1441 |
ariadna |
25084 |
const containerAndNextSiblingName = (container, nodeName) => {
|
|
|
25085 |
return container.nodeName === nodeName || container.nextSibling && container.nextSibling.nodeName === nodeName;
|
|
|
25086 |
};
|
| 1 |
efrain |
25087 |
const canSplitBlock = (dom, node) => {
|
|
|
25088 |
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';
|
|
|
25089 |
};
|
|
|
25090 |
const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => {
|
|
|
25091 |
var _a;
|
|
|
25092 |
const firstChilds = [];
|
|
|
25093 |
if (!block) {
|
|
|
25094 |
return;
|
|
|
25095 |
}
|
|
|
25096 |
let currentNode = block;
|
|
|
25097 |
while (currentNode = currentNode.firstChild) {
|
|
|
25098 |
if (dom.isBlock(currentNode)) {
|
|
|
25099 |
return;
|
|
|
25100 |
}
|
|
|
25101 |
if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) {
|
|
|
25102 |
firstChilds.push(currentNode);
|
|
|
25103 |
}
|
|
|
25104 |
}
|
|
|
25105 |
let i = firstChilds.length;
|
|
|
25106 |
while (i--) {
|
|
|
25107 |
currentNode = firstChilds[i];
|
|
|
25108 |
if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') {
|
|
|
25109 |
dom.remove(currentNode);
|
|
|
25110 |
} else {
|
|
|
25111 |
if (isEmptyAnchor(dom, currentNode)) {
|
|
|
25112 |
dom.remove(currentNode);
|
|
|
25113 |
}
|
|
|
25114 |
}
|
|
|
25115 |
}
|
|
|
25116 |
};
|
|
|
25117 |
const normalizeZwspOffset = (start, container, offset) => {
|
| 1441 |
ariadna |
25118 |
if (!isText$b(container)) {
|
| 1 |
efrain |
25119 |
return offset;
|
|
|
25120 |
} else if (start) {
|
|
|
25121 |
return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
|
|
|
25122 |
} else {
|
|
|
25123 |
return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
|
|
|
25124 |
}
|
|
|
25125 |
};
|
|
|
25126 |
const includeZwspInRange = rng => {
|
|
|
25127 |
const newRng = rng.cloneRange();
|
|
|
25128 |
newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
|
|
|
25129 |
newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
|
|
|
25130 |
return newRng;
|
|
|
25131 |
};
|
|
|
25132 |
const trimLeadingLineBreaks = node => {
|
|
|
25133 |
let currentNode = node;
|
|
|
25134 |
do {
|
| 1441 |
ariadna |
25135 |
if (isText$b(currentNode)) {
|
| 1 |
efrain |
25136 |
currentNode.data = currentNode.data.replace(/^[\r\n]+/, '');
|
|
|
25137 |
}
|
|
|
25138 |
currentNode = currentNode.firstChild;
|
|
|
25139 |
} while (currentNode);
|
|
|
25140 |
};
|
|
|
25141 |
const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
|
|
|
25142 |
var _a, _b;
|
|
|
25143 |
const dom = editor.dom;
|
|
|
25144 |
const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot();
|
|
|
25145 |
let parentBlock = dom.getParent(container, dom.isBlock);
|
|
|
25146 |
if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
|
|
|
25147 |
parentBlock = parentBlock || editableRoot;
|
|
|
25148 |
if (!parentBlock.hasChildNodes()) {
|
|
|
25149 |
const newBlock = dom.create(newBlockName);
|
|
|
25150 |
setForcedBlockAttrs(editor, newBlock);
|
|
|
25151 |
parentBlock.appendChild(newBlock);
|
|
|
25152 |
rng.setStart(newBlock, 0);
|
|
|
25153 |
rng.setEnd(newBlock, 0);
|
|
|
25154 |
return newBlock;
|
|
|
25155 |
}
|
|
|
25156 |
let node = container;
|
|
|
25157 |
while (node && node.parentNode !== parentBlock) {
|
|
|
25158 |
node = node.parentNode;
|
|
|
25159 |
}
|
|
|
25160 |
let startNode;
|
|
|
25161 |
while (node && !dom.isBlock(node)) {
|
|
|
25162 |
startNode = node;
|
|
|
25163 |
node = node.previousSibling;
|
|
|
25164 |
}
|
|
|
25165 |
const startNodeName = (_b = startNode === null || startNode === void 0 ? void 0 : startNode.parentElement) === null || _b === void 0 ? void 0 : _b.nodeName;
|
|
|
25166 |
if (startNode && startNodeName && editor.schema.isValidChild(startNodeName, newBlockName.toLowerCase())) {
|
|
|
25167 |
const startNodeParent = startNode.parentNode;
|
|
|
25168 |
const newBlock = dom.create(newBlockName);
|
|
|
25169 |
setForcedBlockAttrs(editor, newBlock);
|
|
|
25170 |
startNodeParent.insertBefore(newBlock, startNode);
|
|
|
25171 |
node = startNode;
|
|
|
25172 |
while (node && !dom.isBlock(node)) {
|
|
|
25173 |
const next = node.nextSibling;
|
|
|
25174 |
newBlock.appendChild(node);
|
|
|
25175 |
node = next;
|
|
|
25176 |
}
|
|
|
25177 |
rng.setStart(container, offset);
|
|
|
25178 |
rng.setEnd(container, offset);
|
|
|
25179 |
}
|
|
|
25180 |
}
|
|
|
25181 |
return container;
|
|
|
25182 |
};
|
|
|
25183 |
const addBrToBlockIfNeeded = (dom, block) => {
|
|
|
25184 |
block.normalize();
|
|
|
25185 |
const lastChild = block.lastChild;
|
|
|
25186 |
if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
|
|
|
25187 |
dom.add(block, 'br');
|
|
|
25188 |
}
|
|
|
25189 |
};
|
|
|
25190 |
const shouldEndContainer = (editor, container) => {
|
|
|
25191 |
const optionValue = shouldEndContainerOnEmptyBlock(editor);
|
|
|
25192 |
if (isNullable(container)) {
|
|
|
25193 |
return false;
|
|
|
25194 |
} else if (isString(optionValue)) {
|
|
|
25195 |
return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
|
|
|
25196 |
} else {
|
|
|
25197 |
return optionValue;
|
|
|
25198 |
}
|
|
|
25199 |
};
|
|
|
25200 |
const insert$3 = (editor, evt) => {
|
|
|
25201 |
let container;
|
|
|
25202 |
let offset;
|
|
|
25203 |
let parentBlockName;
|
|
|
25204 |
let containerBlock;
|
|
|
25205 |
let isAfterLastNodeInContainer = false;
|
|
|
25206 |
const dom = editor.dom;
|
|
|
25207 |
const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
|
|
|
25208 |
const rng = editor.selection.getRng();
|
|
|
25209 |
const newBlockName = getForcedRootBlock(editor);
|
|
|
25210 |
const start = SugarElement.fromDom(rng.startContainer);
|
|
|
25211 |
const child = child$1(start, rng.startOffset);
|
|
|
25212 |
const isCef = child.exists(element => isHTMLElement$1(element) && !isEditable$2(element));
|
|
|
25213 |
const collapsedAndCef = rng.collapsed && isCef;
|
|
|
25214 |
const createNewBlock$1 = (name, styles) => {
|
|
|
25215 |
return createNewBlock(editor, container, parentBlock, editableRoot, shouldKeepStyles(editor), name, styles);
|
|
|
25216 |
};
|
|
|
25217 |
const isCaretAtStartOrEndOfBlock = start => {
|
|
|
25218 |
const normalizedOffset = normalizeZwspOffset(start, container, offset);
|
| 1441 |
ariadna |
25219 |
if (isText$b(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) {
|
| 1 |
efrain |
25220 |
return false;
|
|
|
25221 |
}
|
| 1441 |
ariadna |
25222 |
if ((container.parentNode === parentBlock || container === parentBlock) && isAfterLastNodeInContainer && !start) {
|
| 1 |
efrain |
25223 |
return true;
|
|
|
25224 |
}
|
|
|
25225 |
if (start && isElement$6(container) && container === parentBlock.firstChild) {
|
|
|
25226 |
return true;
|
|
|
25227 |
}
|
| 1441 |
ariadna |
25228 |
if (containerAndPreviousSiblingName(container, 'TABLE') || containerAndPreviousSiblingName(container, 'HR')) {
|
|
|
25229 |
if (containerAndNextSiblingName(container, 'BR')) {
|
|
|
25230 |
return !start;
|
|
|
25231 |
}
|
| 1 |
efrain |
25232 |
return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
|
|
|
25233 |
}
|
|
|
25234 |
const walker = new DomTreeWalker(container, parentBlock);
|
| 1441 |
ariadna |
25235 |
if (isText$b(container)) {
|
| 1 |
efrain |
25236 |
if (start && normalizedOffset === 0) {
|
|
|
25237 |
walker.prev();
|
|
|
25238 |
} else if (!start && normalizedOffset === container.data.length) {
|
|
|
25239 |
walker.next();
|
|
|
25240 |
}
|
|
|
25241 |
}
|
|
|
25242 |
let node;
|
|
|
25243 |
while (node = walker.current()) {
|
|
|
25244 |
if (isElement$6(node)) {
|
|
|
25245 |
if (!node.getAttribute('data-mce-bogus')) {
|
|
|
25246 |
const name = node.nodeName.toLowerCase();
|
|
|
25247 |
if (nonEmptyElementsMap[name] && name !== 'br') {
|
|
|
25248 |
return false;
|
|
|
25249 |
}
|
|
|
25250 |
}
|
| 1441 |
ariadna |
25251 |
} else if (isText$b(node) && !isWhitespaceText(node.data)) {
|
| 1 |
efrain |
25252 |
return false;
|
|
|
25253 |
}
|
|
|
25254 |
if (start) {
|
|
|
25255 |
walker.prev();
|
|
|
25256 |
} else {
|
|
|
25257 |
walker.next();
|
|
|
25258 |
}
|
|
|
25259 |
}
|
|
|
25260 |
return true;
|
|
|
25261 |
};
|
|
|
25262 |
const insertNewBlockAfter = () => {
|
|
|
25263 |
let block;
|
|
|
25264 |
if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
|
|
|
25265 |
block = createNewBlock$1(newBlockName);
|
|
|
25266 |
} else {
|
|
|
25267 |
block = createNewBlock$1();
|
|
|
25268 |
}
|
|
|
25269 |
if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock, undefined, { includeZwsp: true })) {
|
|
|
25270 |
block = dom.split(containerBlock, parentBlock);
|
|
|
25271 |
} else {
|
|
|
25272 |
dom.insertAfter(block, parentBlock);
|
|
|
25273 |
}
|
|
|
25274 |
moveToCaretPosition(editor, block);
|
|
|
25275 |
return block;
|
|
|
25276 |
};
|
|
|
25277 |
normalize$2(dom, rng).each(normRng => {
|
|
|
25278 |
rng.setStart(normRng.startContainer, normRng.startOffset);
|
|
|
25279 |
rng.setEnd(normRng.endContainer, normRng.endOffset);
|
|
|
25280 |
});
|
|
|
25281 |
container = rng.startContainer;
|
|
|
25282 |
offset = rng.startOffset;
|
|
|
25283 |
const shiftKey = !!(evt && evt.shiftKey);
|
|
|
25284 |
const ctrlKey = !!(evt && evt.ctrlKey);
|
|
|
25285 |
if (isElement$6(container) && container.hasChildNodes() && !collapsedAndCef) {
|
|
|
25286 |
isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
|
|
25287 |
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
| 1441 |
ariadna |
25288 |
if (isAfterLastNodeInContainer && isText$b(container)) {
|
| 1 |
efrain |
25289 |
offset = container.data.length;
|
|
|
25290 |
} else {
|
|
|
25291 |
offset = 0;
|
|
|
25292 |
}
|
|
|
25293 |
}
|
|
|
25294 |
const editableRoot = getEditableRoot(dom, container);
|
|
|
25295 |
if (!editableRoot || isWithinNonEditableList(editor, container)) {
|
|
|
25296 |
return;
|
|
|
25297 |
}
|
|
|
25298 |
if (!shiftKey) {
|
|
|
25299 |
container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
|
|
|
25300 |
}
|
|
|
25301 |
let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot();
|
|
|
25302 |
containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
|
|
|
25303 |
parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
|
|
|
25304 |
const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
|
|
|
25305 |
if (containerBlockName === 'LI' && !ctrlKey) {
|
|
|
25306 |
const liBlock = containerBlock;
|
|
|
25307 |
parentBlock = liBlock;
|
|
|
25308 |
containerBlock = liBlock.parentNode;
|
|
|
25309 |
parentBlockName = containerBlockName;
|
|
|
25310 |
}
|
|
|
25311 |
if (isElement$6(containerBlock) && isLastEmptyBlockInDetails(editor, shiftKey, parentBlock)) {
|
|
|
25312 |
return insertNewLine(editor, createNewBlock$1, parentBlock);
|
|
|
25313 |
}
|
|
|
25314 |
if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) {
|
|
|
25315 |
if (dom.isEmpty(parentBlock)) {
|
|
|
25316 |
insert$4(editor, createNewBlock$1, containerBlock, parentBlock, newBlockName);
|
|
|
25317 |
return;
|
|
|
25318 |
}
|
|
|
25319 |
}
|
|
|
25320 |
if (!collapsedAndCef && (parentBlock === editor.getBody() || !canSplitBlock(dom, parentBlock))) {
|
|
|
25321 |
return;
|
|
|
25322 |
}
|
|
|
25323 |
const parentBlockParent = parentBlock.parentNode;
|
|
|
25324 |
let newBlock;
|
|
|
25325 |
if (collapsedAndCef) {
|
|
|
25326 |
newBlock = createNewBlock$1(newBlockName);
|
|
|
25327 |
child.fold(() => {
|
|
|
25328 |
append$1(start, SugarElement.fromDom(newBlock));
|
|
|
25329 |
}, child => {
|
|
|
25330 |
before$3(child, SugarElement.fromDom(newBlock));
|
|
|
25331 |
});
|
|
|
25332 |
editor.selection.setCursorLocation(newBlock, 0);
|
|
|
25333 |
} else if (isCaretContainerBlock$1(parentBlock)) {
|
|
|
25334 |
newBlock = showCaretContainerBlock(parentBlock);
|
|
|
25335 |
if (dom.isEmpty(parentBlock)) {
|
|
|
25336 |
emptyBlock(parentBlock);
|
|
|
25337 |
}
|
|
|
25338 |
setForcedBlockAttrs(editor, newBlock);
|
|
|
25339 |
moveToCaretPosition(editor, newBlock);
|
|
|
25340 |
} else if (isCaretAtStartOrEndOfBlock(false)) {
|
|
|
25341 |
newBlock = insertNewBlockAfter();
|
|
|
25342 |
} else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) {
|
| 1441 |
ariadna |
25343 |
const caretPos = CaretPosition.fromRangeStart(rng);
|
|
|
25344 |
const afterTable = isAfterTable(caretPos);
|
|
|
25345 |
const parentBlockSugar = SugarElement.fromDom(parentBlock);
|
|
|
25346 |
const afterBr = isAfterBr(parentBlockSugar, caretPos, editor.schema);
|
|
|
25347 |
const prevBrOpt = afterBr ? findPreviousBr(parentBlockSugar, caretPos, editor.schema).bind(pos => Optional.from(pos.getNode())) : Optional.none();
|
| 1 |
efrain |
25348 |
newBlock = parentBlockParent.insertBefore(createNewBlock$1(), parentBlock);
|
| 1441 |
ariadna |
25349 |
const root = containerAndPreviousSiblingName(parentBlock, 'HR') || afterTable ? newBlock : prevBrOpt.getOr(parentBlock);
|
|
|
25350 |
moveToCaretPosition(editor, root);
|
| 1 |
efrain |
25351 |
} else {
|
|
|
25352 |
const tmpRng = includeZwspInRange(rng).cloneRange();
|
|
|
25353 |
tmpRng.setEndAfter(parentBlock);
|
|
|
25354 |
const fragment = tmpRng.extractContents();
|
|
|
25355 |
trimZwsp(fragment);
|
|
|
25356 |
trimLeadingLineBreaks(fragment);
|
|
|
25357 |
newBlock = fragment.firstChild;
|
|
|
25358 |
dom.insertAfter(fragment, parentBlock);
|
|
|
25359 |
trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
|
|
|
25360 |
addBrToBlockIfNeeded(dom, parentBlock);
|
|
|
25361 |
if (dom.isEmpty(parentBlock)) {
|
|
|
25362 |
emptyBlock(parentBlock);
|
|
|
25363 |
}
|
|
|
25364 |
newBlock.normalize();
|
|
|
25365 |
if (dom.isEmpty(newBlock)) {
|
|
|
25366 |
dom.remove(newBlock);
|
|
|
25367 |
insertNewBlockAfter();
|
|
|
25368 |
} else {
|
|
|
25369 |
setForcedBlockAttrs(editor, newBlock);
|
|
|
25370 |
moveToCaretPosition(editor, newBlock);
|
|
|
25371 |
}
|
|
|
25372 |
}
|
|
|
25373 |
dom.setAttrib(newBlock, 'id', '');
|
|
|
25374 |
editor.dispatch('NewBlock', { newBlock });
|
|
|
25375 |
};
|
|
|
25376 |
const fakeEventName$1 = 'insertParagraph';
|
|
|
25377 |
const blockbreak = {
|
|
|
25378 |
insert: insert$3,
|
|
|
25379 |
fakeEventName: fakeEventName$1
|
|
|
25380 |
};
|
|
|
25381 |
|
|
|
25382 |
const hasRightSideContent = (schema, container, parentBlock) => {
|
|
|
25383 |
const walker = new DomTreeWalker(container, parentBlock);
|
|
|
25384 |
let node;
|
|
|
25385 |
const nonEmptyElementsMap = schema.getNonEmptyElements();
|
|
|
25386 |
while (node = walker.next()) {
|
| 1441 |
ariadna |
25387 |
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$b(node) && node.length > 0) {
|
| 1 |
efrain |
25388 |
return true;
|
|
|
25389 |
}
|
|
|
25390 |
}
|
|
|
25391 |
return false;
|
|
|
25392 |
};
|
|
|
25393 |
const moveSelectionToBr = (editor, brElm, extraBr) => {
|
|
|
25394 |
const rng = editor.dom.createRng();
|
|
|
25395 |
if (!extraBr) {
|
|
|
25396 |
rng.setStartAfter(brElm);
|
|
|
25397 |
rng.setEndAfter(brElm);
|
|
|
25398 |
} else {
|
|
|
25399 |
rng.setStartBefore(brElm);
|
|
|
25400 |
rng.setEndBefore(brElm);
|
|
|
25401 |
}
|
|
|
25402 |
editor.selection.setRng(rng);
|
|
|
25403 |
scrollRangeIntoView(editor, rng);
|
|
|
25404 |
};
|
|
|
25405 |
const insertBrAtCaret = (editor, evt) => {
|
|
|
25406 |
const selection = editor.selection;
|
|
|
25407 |
const dom = editor.dom;
|
|
|
25408 |
const rng = selection.getRng();
|
|
|
25409 |
let brElm;
|
|
|
25410 |
let extraBr = false;
|
|
|
25411 |
normalize$2(dom, rng).each(normRng => {
|
|
|
25412 |
rng.setStart(normRng.startContainer, normRng.startOffset);
|
|
|
25413 |
rng.setEnd(normRng.endContainer, normRng.endOffset);
|
|
|
25414 |
});
|
|
|
25415 |
let offset = rng.startOffset;
|
|
|
25416 |
let container = rng.startContainer;
|
|
|
25417 |
if (isElement$6(container) && container.hasChildNodes()) {
|
|
|
25418 |
const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
|
|
25419 |
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
| 1441 |
ariadna |
25420 |
if (isAfterLastNodeInContainer && isText$b(container)) {
|
| 1 |
efrain |
25421 |
offset = container.data.length;
|
|
|
25422 |
} else {
|
|
|
25423 |
offset = 0;
|
|
|
25424 |
}
|
|
|
25425 |
}
|
|
|
25426 |
let parentBlock = dom.getParent(container, dom.isBlock);
|
|
|
25427 |
const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
|
|
|
25428 |
const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
|
|
|
25429 |
const isControlKey = !!(evt && evt.ctrlKey);
|
|
|
25430 |
if (containerBlockName === 'LI' && !isControlKey) {
|
|
|
25431 |
parentBlock = containerBlock;
|
|
|
25432 |
}
|
| 1441 |
ariadna |
25433 |
if (isText$b(container) && offset >= container.data.length) {
|
| 1 |
efrain |
25434 |
if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) {
|
|
|
25435 |
brElm = dom.create('br');
|
|
|
25436 |
rng.insertNode(brElm);
|
|
|
25437 |
rng.setStartAfter(brElm);
|
|
|
25438 |
rng.setEndAfter(brElm);
|
|
|
25439 |
extraBr = true;
|
|
|
25440 |
}
|
|
|
25441 |
}
|
|
|
25442 |
brElm = dom.create('br');
|
|
|
25443 |
rangeInsertNode(dom, rng, brElm);
|
|
|
25444 |
moveSelectionToBr(editor, brElm, extraBr);
|
|
|
25445 |
editor.undoManager.add();
|
|
|
25446 |
};
|
|
|
25447 |
const insertBrBefore = (editor, inline) => {
|
|
|
25448 |
const br = SugarElement.fromTag('br');
|
|
|
25449 |
before$3(SugarElement.fromDom(inline), br);
|
|
|
25450 |
editor.undoManager.add();
|
|
|
25451 |
};
|
|
|
25452 |
const insertBrAfter = (editor, inline) => {
|
|
|
25453 |
if (!hasBrAfter(editor.getBody(), inline)) {
|
|
|
25454 |
after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br'));
|
|
|
25455 |
}
|
|
|
25456 |
const br = SugarElement.fromTag('br');
|
|
|
25457 |
after$4(SugarElement.fromDom(inline), br);
|
|
|
25458 |
moveSelectionToBr(editor, br.dom, false);
|
|
|
25459 |
editor.undoManager.add();
|
|
|
25460 |
};
|
|
|
25461 |
const isBeforeBr = pos => {
|
|
|
25462 |
return isBr$6(pos.getNode());
|
|
|
25463 |
};
|
|
|
25464 |
const hasBrAfter = (rootNode, startNode) => {
|
|
|
25465 |
if (isBeforeBr(CaretPosition.after(startNode))) {
|
|
|
25466 |
return true;
|
|
|
25467 |
} else {
|
|
|
25468 |
return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => {
|
|
|
25469 |
return isBr$6(pos.getNode());
|
|
|
25470 |
}).getOr(false);
|
|
|
25471 |
}
|
|
|
25472 |
};
|
|
|
25473 |
const isAnchorLink = elm => {
|
|
|
25474 |
return elm && elm.nodeName === 'A' && 'href' in elm;
|
|
|
25475 |
};
|
|
|
25476 |
const isInsideAnchor = location => {
|
|
|
25477 |
return location.fold(never, isAnchorLink, isAnchorLink, never);
|
|
|
25478 |
};
|
|
|
25479 |
const readInlineAnchorLocation = editor => {
|
|
|
25480 |
const isInlineTarget$1 = curry(isInlineTarget, editor);
|
|
|
25481 |
const position = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
25482 |
return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
|
|
|
25483 |
};
|
|
|
25484 |
const insertBrOutsideAnchor = (editor, location) => {
|
|
|
25485 |
location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
|
|
|
25486 |
};
|
|
|
25487 |
const insert$2 = (editor, evt) => {
|
|
|
25488 |
const anchorLocation = readInlineAnchorLocation(editor);
|
|
|
25489 |
if (anchorLocation.isSome()) {
|
|
|
25490 |
anchorLocation.each(curry(insertBrOutsideAnchor, editor));
|
|
|
25491 |
} else {
|
|
|
25492 |
insertBrAtCaret(editor, evt);
|
|
|
25493 |
}
|
|
|
25494 |
};
|
|
|
25495 |
const fakeEventName = 'insertLineBreak';
|
|
|
25496 |
const linebreak = {
|
|
|
25497 |
insert: insert$2,
|
|
|
25498 |
fakeEventName
|
|
|
25499 |
};
|
|
|
25500 |
|
|
|
25501 |
const matchesSelector = (editor, selector) => {
|
|
|
25502 |
return getParentBlock$1(editor).filter(parentBlock => {
|
|
|
25503 |
return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
|
|
|
25504 |
}).isSome();
|
|
|
25505 |
};
|
|
|
25506 |
const shouldInsertBr = editor => {
|
|
|
25507 |
return matchesSelector(editor, getBrNewLineSelector(editor));
|
|
|
25508 |
};
|
|
|
25509 |
const shouldBlockNewLine$1 = editor => {
|
|
|
25510 |
return matchesSelector(editor, getNoNewLineSelector(editor));
|
|
|
25511 |
};
|
|
|
25512 |
|
|
|
25513 |
const newLineAction = Adt.generate([
|
|
|
25514 |
{ br: [] },
|
|
|
25515 |
{ block: [] },
|
|
|
25516 |
{ none: [] }
|
|
|
25517 |
]);
|
|
|
25518 |
const shouldBlockNewLine = (editor, _shiftKey) => {
|
|
|
25519 |
return shouldBlockNewLine$1(editor);
|
|
|
25520 |
};
|
|
|
25521 |
const inListBlock = requiredState => {
|
|
|
25522 |
return (editor, _shiftKey) => {
|
|
|
25523 |
return isListItemParentBlock(editor) === requiredState;
|
|
|
25524 |
};
|
|
|
25525 |
};
|
|
|
25526 |
const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
|
|
|
25527 |
const state = getParentBlockName(editor) === blockName.toUpperCase();
|
|
|
25528 |
return state === requiredState;
|
|
|
25529 |
};
|
|
|
25530 |
const inCefBlock = editor => {
|
|
|
25531 |
const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart());
|
|
|
25532 |
return isNullable(editableRoot);
|
|
|
25533 |
};
|
|
|
25534 |
const inPreBlock = requiredState => inBlock('pre', requiredState);
|
|
|
25535 |
const inSummaryBlock = () => inBlock('summary', true);
|
|
|
25536 |
const shouldPutBrInPre = requiredState => {
|
|
|
25537 |
return (editor, _shiftKey) => {
|
|
|
25538 |
return shouldPutBrInPre$1(editor) === requiredState;
|
|
|
25539 |
};
|
|
|
25540 |
};
|
|
|
25541 |
const inBrContext = (editor, _shiftKey) => {
|
|
|
25542 |
return shouldInsertBr(editor);
|
|
|
25543 |
};
|
|
|
25544 |
const hasShiftKey = (_editor, shiftKey) => {
|
|
|
25545 |
return shiftKey;
|
|
|
25546 |
};
|
|
|
25547 |
const canInsertIntoEditableRoot = editor => {
|
|
|
25548 |
const forcedRootBlock = getForcedRootBlock(editor);
|
|
|
25549 |
const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart());
|
|
|
25550 |
return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
|
|
|
25551 |
};
|
|
|
25552 |
const isInRootWithEmptyOrCEF = editor => {
|
|
|
25553 |
const rng = editor.selection.getRng();
|
|
|
25554 |
const start = SugarElement.fromDom(rng.startContainer);
|
|
|
25555 |
const child = child$1(start, rng.startOffset);
|
|
|
25556 |
const isCefOpt = child.map(element => isHTMLElement$1(element) && !isEditable$2(element));
|
|
|
25557 |
return rng.collapsed && isCefOpt.getOr(true);
|
|
|
25558 |
};
|
|
|
25559 |
const match = (predicates, action) => {
|
|
|
25560 |
return (editor, shiftKey) => {
|
|
|
25561 |
const isMatch = foldl(predicates, (res, p) => {
|
|
|
25562 |
return res && p(editor, shiftKey);
|
|
|
25563 |
}, true);
|
|
|
25564 |
return isMatch ? Optional.some(action) : Optional.none();
|
|
|
25565 |
};
|
|
|
25566 |
};
|
|
|
25567 |
const getAction = (editor, evt) => {
|
|
|
25568 |
return evaluateUntil([
|
|
|
25569 |
match([shouldBlockNewLine], newLineAction.none()),
|
|
|
25570 |
match([
|
|
|
25571 |
inPreBlock(true),
|
|
|
25572 |
inCefBlock
|
|
|
25573 |
], newLineAction.none()),
|
|
|
25574 |
match([inSummaryBlock()], newLineAction.br()),
|
|
|
25575 |
match([
|
|
|
25576 |
inPreBlock(true),
|
|
|
25577 |
shouldPutBrInPre(false),
|
|
|
25578 |
hasShiftKey
|
|
|
25579 |
], newLineAction.br()),
|
|
|
25580 |
match([
|
|
|
25581 |
inPreBlock(true),
|
|
|
25582 |
shouldPutBrInPre(false)
|
|
|
25583 |
], newLineAction.block()),
|
|
|
25584 |
match([
|
|
|
25585 |
inPreBlock(true),
|
|
|
25586 |
shouldPutBrInPre(true),
|
|
|
25587 |
hasShiftKey
|
|
|
25588 |
], newLineAction.block()),
|
|
|
25589 |
match([
|
|
|
25590 |
inPreBlock(true),
|
|
|
25591 |
shouldPutBrInPre(true)
|
|
|
25592 |
], newLineAction.br()),
|
|
|
25593 |
match([
|
|
|
25594 |
inListBlock(true),
|
|
|
25595 |
hasShiftKey
|
|
|
25596 |
], newLineAction.br()),
|
|
|
25597 |
match([inListBlock(true)], newLineAction.block()),
|
|
|
25598 |
match([inBrContext], newLineAction.br()),
|
|
|
25599 |
match([hasShiftKey], newLineAction.br()),
|
|
|
25600 |
match([canInsertIntoEditableRoot], newLineAction.block()),
|
|
|
25601 |
match([isInRootWithEmptyOrCEF], newLineAction.block())
|
|
|
25602 |
], [
|
|
|
25603 |
editor,
|
|
|
25604 |
!!(evt && evt.shiftKey)
|
|
|
25605 |
]).getOr(newLineAction.none());
|
|
|
25606 |
};
|
|
|
25607 |
|
|
|
25608 |
const insertBreak = (breakType, editor, evt) => {
|
| 1441 |
ariadna |
25609 |
if (editor.mode.isReadOnly()) {
|
|
|
25610 |
return;
|
|
|
25611 |
}
|
| 1 |
efrain |
25612 |
if (!editor.selection.isCollapsed()) {
|
|
|
25613 |
execEditorDeleteCommand(editor);
|
|
|
25614 |
}
|
|
|
25615 |
if (isNonNullable(evt)) {
|
|
|
25616 |
const event = fireBeforeInputEvent(editor, breakType.fakeEventName);
|
|
|
25617 |
if (event.isDefaultPrevented()) {
|
|
|
25618 |
return;
|
|
|
25619 |
}
|
|
|
25620 |
}
|
|
|
25621 |
breakType.insert(editor, evt);
|
|
|
25622 |
if (isNonNullable(evt)) {
|
|
|
25623 |
fireInputEvent(editor, breakType.fakeEventName);
|
|
|
25624 |
}
|
|
|
25625 |
};
|
|
|
25626 |
const insert$1 = (editor, evt) => {
|
| 1441 |
ariadna |
25627 |
if (editor.mode.isReadOnly()) {
|
|
|
25628 |
return;
|
|
|
25629 |
}
|
| 1 |
efrain |
25630 |
const br = () => insertBreak(linebreak, editor, evt);
|
|
|
25631 |
const block = () => insertBreak(blockbreak, editor, evt);
|
|
|
25632 |
const logicalAction = getAction(editor, evt);
|
|
|
25633 |
switch (getNewlineBehavior(editor)) {
|
|
|
25634 |
case 'linebreak':
|
|
|
25635 |
logicalAction.fold(br, br, noop);
|
|
|
25636 |
break;
|
|
|
25637 |
case 'block':
|
|
|
25638 |
logicalAction.fold(block, block, noop);
|
|
|
25639 |
break;
|
|
|
25640 |
case 'invert':
|
|
|
25641 |
logicalAction.fold(block, br, noop);
|
|
|
25642 |
break;
|
|
|
25643 |
default:
|
|
|
25644 |
logicalAction.fold(br, block, noop);
|
|
|
25645 |
break;
|
|
|
25646 |
}
|
|
|
25647 |
};
|
|
|
25648 |
|
| 1441 |
ariadna |
25649 |
const platform$1 = detect$1();
|
| 1 |
efrain |
25650 |
const isIOSSafari = platform$1.os.isiOS() && platform$1.browser.isSafari();
|
|
|
25651 |
const handleEnterKeyEvent = (editor, event) => {
|
|
|
25652 |
if (event.isDefaultPrevented()) {
|
|
|
25653 |
return;
|
|
|
25654 |
}
|
|
|
25655 |
event.preventDefault();
|
|
|
25656 |
endTypingLevelIgnoreLocks(editor.undoManager);
|
|
|
25657 |
editor.undoManager.transact(() => {
|
|
|
25658 |
insert$1(editor, event);
|
|
|
25659 |
});
|
|
|
25660 |
};
|
|
|
25661 |
const isCaretAfterKoreanCharacter = rng => {
|
|
|
25662 |
if (!rng.collapsed) {
|
|
|
25663 |
return false;
|
|
|
25664 |
}
|
|
|
25665 |
const startContainer = rng.startContainer;
|
| 1441 |
ariadna |
25666 |
if (isText$b(startContainer)) {
|
| 1 |
efrain |
25667 |
const koreanCharRegex = /^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/;
|
|
|
25668 |
const char = startContainer.data.charAt(rng.startOffset - 1);
|
|
|
25669 |
return koreanCharRegex.test(char);
|
|
|
25670 |
} else {
|
|
|
25671 |
return false;
|
|
|
25672 |
}
|
|
|
25673 |
};
|
|
|
25674 |
const setup$i = editor => {
|
|
|
25675 |
let iOSSafariKeydownBookmark = Optional.none();
|
|
|
25676 |
const iOSSafariKeydownOverride = editor => {
|
|
|
25677 |
iOSSafariKeydownBookmark = Optional.some(editor.selection.getBookmark());
|
|
|
25678 |
editor.undoManager.add();
|
|
|
25679 |
};
|
|
|
25680 |
const iOSSafariKeyupOverride = (editor, event) => {
|
|
|
25681 |
editor.undoManager.undo();
|
|
|
25682 |
iOSSafariKeydownBookmark.fold(noop, b => editor.selection.moveToBookmark(b));
|
|
|
25683 |
handleEnterKeyEvent(editor, event);
|
|
|
25684 |
iOSSafariKeydownBookmark = Optional.none();
|
|
|
25685 |
};
|
|
|
25686 |
editor.on('keydown', event => {
|
|
|
25687 |
if (event.keyCode === VK.ENTER) {
|
|
|
25688 |
if (isIOSSafari && isCaretAfterKoreanCharacter(editor.selection.getRng())) {
|
|
|
25689 |
iOSSafariKeydownOverride(editor);
|
|
|
25690 |
} else {
|
|
|
25691 |
handleEnterKeyEvent(editor, event);
|
|
|
25692 |
}
|
|
|
25693 |
}
|
|
|
25694 |
});
|
|
|
25695 |
editor.on('keyup', event => {
|
|
|
25696 |
if (event.keyCode === VK.ENTER) {
|
|
|
25697 |
iOSSafariKeydownBookmark.each(() => iOSSafariKeyupOverride(editor, event));
|
|
|
25698 |
}
|
|
|
25699 |
});
|
|
|
25700 |
};
|
|
|
25701 |
|
|
|
25702 |
const executeKeydownOverride$2 = (editor, caret, evt) => {
|
|
|
25703 |
const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
|
|
25704 |
execute([
|
|
|
25705 |
{
|
|
|
25706 |
keyCode: VK.END,
|
|
|
25707 |
action: action(moveToLineEndPoint$1, editor, true)
|
|
|
25708 |
},
|
|
|
25709 |
{
|
|
|
25710 |
keyCode: VK.HOME,
|
|
|
25711 |
action: action(moveToLineEndPoint$1, editor, false)
|
|
|
25712 |
},
|
|
|
25713 |
...!isMac ? [
|
|
|
25714 |
{
|
|
|
25715 |
keyCode: VK.HOME,
|
|
|
25716 |
action: action(selectToEndPoint, editor, false),
|
|
|
25717 |
ctrlKey: true,
|
|
|
25718 |
shiftKey: true
|
|
|
25719 |
},
|
|
|
25720 |
{
|
|
|
25721 |
keyCode: VK.END,
|
|
|
25722 |
action: action(selectToEndPoint, editor, true),
|
|
|
25723 |
ctrlKey: true,
|
|
|
25724 |
shiftKey: true
|
|
|
25725 |
}
|
|
|
25726 |
] : [],
|
|
|
25727 |
{
|
|
|
25728 |
keyCode: VK.END,
|
|
|
25729 |
action: action(moveToLineEndPoint, editor, true)
|
|
|
25730 |
},
|
|
|
25731 |
{
|
|
|
25732 |
keyCode: VK.HOME,
|
|
|
25733 |
action: action(moveToLineEndPoint, editor, false)
|
|
|
25734 |
},
|
|
|
25735 |
{
|
|
|
25736 |
keyCode: VK.END,
|
|
|
25737 |
action: action(moveToLineEndPoint$2, editor, true, caret)
|
|
|
25738 |
},
|
|
|
25739 |
{
|
|
|
25740 |
keyCode: VK.HOME,
|
|
|
25741 |
action: action(moveToLineEndPoint$2, editor, false, caret)
|
|
|
25742 |
}
|
|
|
25743 |
], evt).each(_ => {
|
|
|
25744 |
evt.preventDefault();
|
|
|
25745 |
});
|
|
|
25746 |
};
|
|
|
25747 |
const setup$h = (editor, caret) => {
|
|
|
25748 |
editor.on('keydown', evt => {
|
|
|
25749 |
if (!evt.isDefaultPrevented()) {
|
|
|
25750 |
executeKeydownOverride$2(editor, caret, evt);
|
|
|
25751 |
}
|
|
|
25752 |
});
|
|
|
25753 |
};
|
|
|
25754 |
|
|
|
25755 |
const setup$g = editor => {
|
|
|
25756 |
editor.on('input', e => {
|
|
|
25757 |
if (!e.isComposing) {
|
|
|
25758 |
normalizeNbspsInEditor(editor);
|
|
|
25759 |
}
|
|
|
25760 |
});
|
|
|
25761 |
};
|
|
|
25762 |
|
| 1441 |
ariadna |
25763 |
const platform = detect$1();
|
| 1 |
efrain |
25764 |
const executeKeyupAction = (editor, caret, evt) => {
|
|
|
25765 |
execute([
|
|
|
25766 |
{
|
|
|
25767 |
keyCode: VK.PAGE_UP,
|
|
|
25768 |
action: action(moveToLineEndPoint$2, editor, false, caret)
|
|
|
25769 |
},
|
|
|
25770 |
{
|
|
|
25771 |
keyCode: VK.PAGE_DOWN,
|
|
|
25772 |
action: action(moveToLineEndPoint$2, editor, true, caret)
|
|
|
25773 |
}
|
|
|
25774 |
], evt);
|
|
|
25775 |
};
|
|
|
25776 |
const stopImmediatePropagation = e => e.stopImmediatePropagation();
|
|
|
25777 |
const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
|
|
|
25778 |
const setNodeChangeBlocker = (blocked, editor, block) => {
|
|
|
25779 |
if (block && !blocked.get()) {
|
|
|
25780 |
editor.on('NodeChange', stopImmediatePropagation, true);
|
|
|
25781 |
} else if (!block && blocked.get()) {
|
|
|
25782 |
editor.off('NodeChange', stopImmediatePropagation);
|
|
|
25783 |
}
|
|
|
25784 |
blocked.set(block);
|
|
|
25785 |
};
|
|
|
25786 |
const setup$f = (editor, caret) => {
|
|
|
25787 |
if (platform.os.isMacOS()) {
|
|
|
25788 |
return;
|
|
|
25789 |
}
|
|
|
25790 |
const blocked = Cell(false);
|
|
|
25791 |
editor.on('keydown', evt => {
|
|
|
25792 |
if (isPageUpDown(evt)) {
|
|
|
25793 |
setNodeChangeBlocker(blocked, editor, true);
|
|
|
25794 |
}
|
|
|
25795 |
});
|
|
|
25796 |
editor.on('keyup', evt => {
|
|
|
25797 |
if (!evt.isDefaultPrevented()) {
|
|
|
25798 |
executeKeyupAction(editor, caret, evt);
|
|
|
25799 |
}
|
|
|
25800 |
if (isPageUpDown(evt) && blocked.get()) {
|
|
|
25801 |
setNodeChangeBlocker(blocked, editor, false);
|
|
|
25802 |
editor.nodeChanged();
|
|
|
25803 |
}
|
|
|
25804 |
});
|
|
|
25805 |
};
|
|
|
25806 |
|
| 1441 |
ariadna |
25807 |
const isValidContainer = (root, container) => root === container || root.contains(container);
|
|
|
25808 |
const isInEditableRange = (editor, range) => {
|
|
|
25809 |
if (!isValidContainer(editor.getBody(), range.startContainer) || !isValidContainer(editor.getBody(), range.endContainer)) {
|
|
|
25810 |
return true;
|
|
|
25811 |
}
|
|
|
25812 |
return isEditableRange(editor.dom, range);
|
|
|
25813 |
};
|
| 1 |
efrain |
25814 |
const setup$e = editor => {
|
|
|
25815 |
editor.on('beforeinput', e => {
|
| 1441 |
ariadna |
25816 |
if (!editor.selection.isEditable() || exists(e.getTargetRanges(), rng => !isInEditableRange(editor, rng))) {
|
| 1 |
efrain |
25817 |
e.preventDefault();
|
|
|
25818 |
}
|
|
|
25819 |
});
|
|
|
25820 |
};
|
|
|
25821 |
|
|
|
25822 |
const insertTextAtPosition = (text, pos) => {
|
|
|
25823 |
const container = pos.container();
|
|
|
25824 |
const offset = pos.offset();
|
| 1441 |
ariadna |
25825 |
if (isText$b(container)) {
|
| 1 |
efrain |
25826 |
container.insertData(offset, text);
|
|
|
25827 |
return Optional.some(CaretPosition(container, offset + text.length));
|
|
|
25828 |
} else {
|
|
|
25829 |
return getElementFromPosition(pos).map(elm => {
|
|
|
25830 |
const textNode = SugarElement.fromText(text);
|
|
|
25831 |
if (pos.isAtEnd()) {
|
|
|
25832 |
after$4(elm, textNode);
|
|
|
25833 |
} else {
|
|
|
25834 |
before$3(elm, textNode);
|
|
|
25835 |
}
|
|
|
25836 |
return CaretPosition(textNode.dom, text.length);
|
|
|
25837 |
});
|
|
|
25838 |
}
|
|
|
25839 |
};
|
|
|
25840 |
const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
|
|
|
25841 |
const insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
|
|
|
25842 |
|
|
|
25843 |
const insertSpaceOrNbspAtPosition = (root, pos, schema) => needsToHaveNbsp(root, pos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
|
|
|
25844 |
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)));
|
|
|
25845 |
const insertInlineBoundarySpaceOrNbsp = (root, pos, schema) => checkPos => needsToHaveNbsp(root, checkPos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
|
|
|
25846 |
const setSelection = editor => pos => {
|
|
|
25847 |
editor.selection.setRng(pos.toRange());
|
|
|
25848 |
editor.nodeChanged();
|
|
|
25849 |
};
|
|
|
25850 |
const isInsideSummary = (domUtils, node) => domUtils.isEditable(domUtils.getParent(node, 'summary'));
|
|
|
25851 |
const insertSpaceOrNbspAtSelection = editor => {
|
|
|
25852 |
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
25853 |
const root = SugarElement.fromDom(editor.getBody());
|
|
|
25854 |
if (editor.selection.isCollapsed()) {
|
|
|
25855 |
const isInlineTarget$1 = curry(isInlineTarget, editor);
|
|
|
25856 |
const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
25857 |
return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos, editor.schema)(checkPos).each(setSelection(editor)));
|
|
|
25858 |
} else {
|
|
|
25859 |
return Optional.none();
|
|
|
25860 |
}
|
|
|
25861 |
};
|
|
|
25862 |
const insertSpaceInSummaryAtSelectionOnFirefox = editor => {
|
|
|
25863 |
const insertSpaceThunk = () => {
|
|
|
25864 |
const root = SugarElement.fromDom(editor.getBody());
|
|
|
25865 |
if (!editor.selection.isCollapsed()) {
|
|
|
25866 |
editor.getDoc().execCommand('Delete');
|
|
|
25867 |
}
|
|
|
25868 |
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
|
|
|
25869 |
insertSpaceOrNbspAtPosition(root, pos, editor.schema).each(setSelection(editor));
|
|
|
25870 |
};
|
|
|
25871 |
return someIf(Env.browser.isFirefox() && editor.selection.isEditable() && isInsideSummary(editor.dom, editor.selection.getRng().startContainer), insertSpaceThunk);
|
|
|
25872 |
};
|
|
|
25873 |
|
|
|
25874 |
const executeKeydownOverride$1 = (editor, evt) => {
|
|
|
25875 |
executeWithDelayedAction([
|
|
|
25876 |
{
|
|
|
25877 |
keyCode: VK.SPACEBAR,
|
|
|
25878 |
action: action(insertSpaceOrNbspAtSelection, editor)
|
|
|
25879 |
},
|
|
|
25880 |
{
|
|
|
25881 |
keyCode: VK.SPACEBAR,
|
|
|
25882 |
action: action(insertSpaceInSummaryAtSelectionOnFirefox, editor)
|
|
|
25883 |
}
|
|
|
25884 |
], evt).each(applyAction => {
|
|
|
25885 |
evt.preventDefault();
|
|
|
25886 |
const event = fireBeforeInputEvent(editor, 'insertText', { data: ' ' });
|
|
|
25887 |
if (!event.isDefaultPrevented()) {
|
|
|
25888 |
applyAction();
|
|
|
25889 |
fireInputEvent(editor, 'insertText', { data: ' ' });
|
|
|
25890 |
}
|
|
|
25891 |
});
|
|
|
25892 |
};
|
|
|
25893 |
const setup$d = editor => {
|
|
|
25894 |
editor.on('keydown', evt => {
|
|
|
25895 |
if (!evt.isDefaultPrevented()) {
|
|
|
25896 |
executeKeydownOverride$1(editor, evt);
|
|
|
25897 |
}
|
|
|
25898 |
});
|
|
|
25899 |
};
|
|
|
25900 |
|
|
|
25901 |
const tableTabNavigation = editor => {
|
|
|
25902 |
if (hasTableTabNavigation(editor)) {
|
|
|
25903 |
return [
|
|
|
25904 |
{
|
|
|
25905 |
keyCode: VK.TAB,
|
|
|
25906 |
action: action(handleTab, editor, true)
|
|
|
25907 |
},
|
|
|
25908 |
{
|
|
|
25909 |
keyCode: VK.TAB,
|
|
|
25910 |
shiftKey: true,
|
|
|
25911 |
action: action(handleTab, editor, false)
|
|
|
25912 |
}
|
|
|
25913 |
];
|
|
|
25914 |
} else {
|
|
|
25915 |
return [];
|
|
|
25916 |
}
|
|
|
25917 |
};
|
|
|
25918 |
const executeKeydownOverride = (editor, evt) => {
|
|
|
25919 |
execute([...tableTabNavigation(editor)], evt).each(_ => {
|
|
|
25920 |
evt.preventDefault();
|
|
|
25921 |
});
|
|
|
25922 |
};
|
|
|
25923 |
const setup$c = editor => {
|
|
|
25924 |
editor.on('keydown', evt => {
|
|
|
25925 |
if (!evt.isDefaultPrevented()) {
|
|
|
25926 |
executeKeydownOverride(editor, evt);
|
|
|
25927 |
}
|
|
|
25928 |
});
|
|
|
25929 |
};
|
|
|
25930 |
|
|
|
25931 |
const setup$b = editor => {
|
|
|
25932 |
editor.addShortcut('Meta+P', '', 'mcePrint');
|
|
|
25933 |
setup$k(editor);
|
|
|
25934 |
if (isRtc(editor)) {
|
|
|
25935 |
return Cell(null);
|
|
|
25936 |
} else {
|
|
|
25937 |
const caret = setupSelectedState(editor);
|
|
|
25938 |
setup$e(editor);
|
|
|
25939 |
setup$m(editor);
|
|
|
25940 |
setup$l(editor, caret);
|
|
|
25941 |
setup$j(editor, caret);
|
|
|
25942 |
setup$i(editor);
|
|
|
25943 |
setup$d(editor);
|
|
|
25944 |
setup$g(editor);
|
|
|
25945 |
setup$c(editor);
|
|
|
25946 |
setup$h(editor, caret);
|
|
|
25947 |
setup$f(editor, caret);
|
|
|
25948 |
return caret;
|
|
|
25949 |
}
|
|
|
25950 |
};
|
|
|
25951 |
|
|
|
25952 |
class NodeChange {
|
|
|
25953 |
constructor(editor) {
|
|
|
25954 |
this.lastPath = [];
|
|
|
25955 |
this.editor = editor;
|
|
|
25956 |
let lastRng;
|
|
|
25957 |
const self = this;
|
|
|
25958 |
if (!('onselectionchange' in editor.getDoc())) {
|
|
|
25959 |
editor.on('NodeChange click mouseup keyup focus', e => {
|
|
|
25960 |
const nativeRng = editor.selection.getRng();
|
|
|
25961 |
const fakeRng = {
|
|
|
25962 |
startContainer: nativeRng.startContainer,
|
|
|
25963 |
startOffset: nativeRng.startOffset,
|
|
|
25964 |
endContainer: nativeRng.endContainer,
|
|
|
25965 |
endOffset: nativeRng.endOffset
|
|
|
25966 |
};
|
|
|
25967 |
if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) {
|
|
|
25968 |
editor.dispatch('SelectionChange');
|
|
|
25969 |
}
|
|
|
25970 |
lastRng = fakeRng;
|
|
|
25971 |
});
|
|
|
25972 |
}
|
|
|
25973 |
editor.on('contextmenu', () => {
|
| 1441 |
ariadna |
25974 |
store(editor);
|
| 1 |
efrain |
25975 |
editor.dispatch('SelectionChange');
|
|
|
25976 |
});
|
|
|
25977 |
editor.on('SelectionChange', () => {
|
|
|
25978 |
const startElm = editor.selection.getStart(true);
|
|
|
25979 |
if (!startElm) {
|
|
|
25980 |
return;
|
|
|
25981 |
}
|
|
|
25982 |
if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
|
|
|
25983 |
editor.nodeChanged({ selectionChange: true });
|
|
|
25984 |
}
|
|
|
25985 |
});
|
|
|
25986 |
editor.on('mouseup', e => {
|
|
|
25987 |
if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
|
|
|
25988 |
if (editor.selection.getNode().nodeName === 'IMG') {
|
|
|
25989 |
Delay.setEditorTimeout(editor, () => {
|
|
|
25990 |
editor.nodeChanged();
|
|
|
25991 |
});
|
|
|
25992 |
} else {
|
|
|
25993 |
editor.nodeChanged();
|
|
|
25994 |
}
|
|
|
25995 |
}
|
|
|
25996 |
});
|
|
|
25997 |
}
|
|
|
25998 |
nodeChanged(args = {}) {
|
| 1441 |
ariadna |
25999 |
const editor = this.editor;
|
|
|
26000 |
const selection = editor.selection;
|
| 1 |
efrain |
26001 |
let node;
|
| 1441 |
ariadna |
26002 |
if (editor.initialized && selection && !shouldDisableNodeChange(editor) && !isDisabled$1(editor)) {
|
|
|
26003 |
const root = editor.getBody();
|
| 1 |
efrain |
26004 |
node = selection.getStart(true) || root;
|
| 1441 |
ariadna |
26005 |
if (node.ownerDocument !== editor.getDoc() || !editor.dom.isChildOf(node, root)) {
|
| 1 |
efrain |
26006 |
node = root;
|
|
|
26007 |
}
|
|
|
26008 |
const parents = [];
|
| 1441 |
ariadna |
26009 |
editor.dom.getParent(node, node => {
|
| 1 |
efrain |
26010 |
if (node === root) {
|
|
|
26011 |
return true;
|
|
|
26012 |
} else {
|
|
|
26013 |
parents.push(node);
|
|
|
26014 |
return false;
|
|
|
26015 |
}
|
|
|
26016 |
});
|
| 1441 |
ariadna |
26017 |
editor.dispatch('NodeChange', {
|
| 1 |
efrain |
26018 |
...args,
|
|
|
26019 |
element: node,
|
|
|
26020 |
parents
|
|
|
26021 |
});
|
|
|
26022 |
}
|
|
|
26023 |
}
|
|
|
26024 |
isSameElementPath(startElm) {
|
|
|
26025 |
let i;
|
|
|
26026 |
const editor = this.editor;
|
|
|
26027 |
const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
|
|
|
26028 |
if (currentPath.length === this.lastPath.length) {
|
|
|
26029 |
for (i = currentPath.length; i >= 0; i--) {
|
|
|
26030 |
if (currentPath[i] !== this.lastPath[i]) {
|
|
|
26031 |
break;
|
|
|
26032 |
}
|
|
|
26033 |
}
|
|
|
26034 |
if (i === -1) {
|
|
|
26035 |
this.lastPath = currentPath;
|
|
|
26036 |
return true;
|
|
|
26037 |
}
|
|
|
26038 |
}
|
|
|
26039 |
this.lastPath = currentPath;
|
|
|
26040 |
return false;
|
|
|
26041 |
}
|
|
|
26042 |
}
|
|
|
26043 |
|
|
|
26044 |
const imageId = generate$1('image');
|
|
|
26045 |
const getDragImage = transfer => {
|
|
|
26046 |
const dt = transfer;
|
|
|
26047 |
return Optional.from(dt[imageId]);
|
|
|
26048 |
};
|
|
|
26049 |
const setDragImage = (transfer, imageData) => {
|
|
|
26050 |
const dt = transfer;
|
|
|
26051 |
dt[imageId] = imageData;
|
|
|
26052 |
};
|
|
|
26053 |
|
|
|
26054 |
const eventId = generate$1('event');
|
|
|
26055 |
const getEvent = transfer => {
|
|
|
26056 |
const dt = transfer;
|
|
|
26057 |
return Optional.from(dt[eventId]);
|
|
|
26058 |
};
|
|
|
26059 |
const mkSetEventFn = type => transfer => {
|
|
|
26060 |
const dt = transfer;
|
|
|
26061 |
dt[eventId] = type;
|
|
|
26062 |
};
|
|
|
26063 |
const setEvent = (transfer, type) => mkSetEventFn(type)(transfer);
|
|
|
26064 |
const setDragstartEvent = mkSetEventFn(0);
|
|
|
26065 |
const setDropEvent = mkSetEventFn(2);
|
|
|
26066 |
const setDragendEvent = mkSetEventFn(1);
|
|
|
26067 |
const checkEvent = expectedType => transfer => {
|
|
|
26068 |
const dt = transfer;
|
|
|
26069 |
return Optional.from(dt[eventId]).exists(type => type === expectedType);
|
|
|
26070 |
};
|
|
|
26071 |
const isInDragStartEvent = checkEvent(0);
|
|
|
26072 |
|
|
|
26073 |
const createEmptyFileList = () => Object.freeze({
|
|
|
26074 |
length: 0,
|
|
|
26075 |
item: _ => null
|
|
|
26076 |
});
|
|
|
26077 |
|
|
|
26078 |
const modeId = generate$1('mode');
|
|
|
26079 |
const getMode = transfer => {
|
|
|
26080 |
const dt = transfer;
|
|
|
26081 |
return Optional.from(dt[modeId]);
|
|
|
26082 |
};
|
|
|
26083 |
const mkSetModeFn = mode => transfer => {
|
|
|
26084 |
const dt = transfer;
|
|
|
26085 |
dt[modeId] = mode;
|
|
|
26086 |
};
|
|
|
26087 |
const setMode$1 = (transfer, mode) => mkSetModeFn(mode)(transfer);
|
|
|
26088 |
const setReadWriteMode = mkSetModeFn(0);
|
|
|
26089 |
const setReadOnlyMode = mkSetModeFn(2);
|
|
|
26090 |
const setProtectedMode = mkSetModeFn(1);
|
|
|
26091 |
const checkMode = expectedMode => transfer => {
|
|
|
26092 |
const dt = transfer;
|
|
|
26093 |
return Optional.from(dt[modeId]).exists(mode => mode === expectedMode);
|
|
|
26094 |
};
|
|
|
26095 |
const isInReadWriteMode = checkMode(0);
|
|
|
26096 |
const isInProtectedMode = checkMode(1);
|
|
|
26097 |
|
|
|
26098 |
const normalizeItems = (dataTransfer, itemsImpl) => ({
|
|
|
26099 |
...itemsImpl,
|
|
|
26100 |
get length() {
|
|
|
26101 |
return itemsImpl.length;
|
|
|
26102 |
},
|
|
|
26103 |
add: (data, type) => {
|
|
|
26104 |
if (isInReadWriteMode(dataTransfer)) {
|
|
|
26105 |
if (isString(data)) {
|
|
|
26106 |
if (!isUndefined(type)) {
|
|
|
26107 |
return itemsImpl.add(data, type);
|
|
|
26108 |
}
|
|
|
26109 |
} else {
|
|
|
26110 |
return itemsImpl.add(data);
|
|
|
26111 |
}
|
|
|
26112 |
}
|
|
|
26113 |
return null;
|
|
|
26114 |
},
|
|
|
26115 |
remove: idx => {
|
|
|
26116 |
if (isInReadWriteMode(dataTransfer)) {
|
|
|
26117 |
itemsImpl.remove(idx);
|
|
|
26118 |
}
|
|
|
26119 |
},
|
|
|
26120 |
clear: () => {
|
|
|
26121 |
if (isInReadWriteMode(dataTransfer)) {
|
|
|
26122 |
itemsImpl.clear();
|
|
|
26123 |
}
|
|
|
26124 |
}
|
|
|
26125 |
});
|
|
|
26126 |
|
|
|
26127 |
const validDropEffects = [
|
|
|
26128 |
'none',
|
|
|
26129 |
'copy',
|
|
|
26130 |
'link',
|
|
|
26131 |
'move'
|
|
|
26132 |
];
|
|
|
26133 |
const validEffectAlloweds = [
|
|
|
26134 |
'none',
|
|
|
26135 |
'copy',
|
|
|
26136 |
'copyLink',
|
|
|
26137 |
'copyMove',
|
|
|
26138 |
'link',
|
|
|
26139 |
'linkMove',
|
|
|
26140 |
'move',
|
|
|
26141 |
'all',
|
|
|
26142 |
'uninitialized'
|
|
|
26143 |
];
|
|
|
26144 |
const createDataTransfer = () => {
|
|
|
26145 |
const dataTransferImpl = new window.DataTransfer();
|
|
|
26146 |
let dropEffect = 'move';
|
|
|
26147 |
let effectAllowed = 'all';
|
|
|
26148 |
const dataTransfer = {
|
|
|
26149 |
get dropEffect() {
|
|
|
26150 |
return dropEffect;
|
|
|
26151 |
},
|
|
|
26152 |
set dropEffect(effect) {
|
|
|
26153 |
if (contains$2(validDropEffects, effect)) {
|
|
|
26154 |
dropEffect = effect;
|
|
|
26155 |
}
|
|
|
26156 |
},
|
|
|
26157 |
get effectAllowed() {
|
|
|
26158 |
return effectAllowed;
|
|
|
26159 |
},
|
|
|
26160 |
set effectAllowed(allowed) {
|
|
|
26161 |
if (isInDragStartEvent(dataTransfer) && contains$2(validEffectAlloweds, allowed)) {
|
|
|
26162 |
effectAllowed = allowed;
|
|
|
26163 |
}
|
|
|
26164 |
},
|
|
|
26165 |
get items() {
|
|
|
26166 |
return normalizeItems(dataTransfer, dataTransferImpl.items);
|
|
|
26167 |
},
|
|
|
26168 |
get files() {
|
|
|
26169 |
if (isInProtectedMode(dataTransfer)) {
|
|
|
26170 |
return createEmptyFileList();
|
|
|
26171 |
} else {
|
|
|
26172 |
return dataTransferImpl.files;
|
|
|
26173 |
}
|
|
|
26174 |
},
|
|
|
26175 |
get types() {
|
|
|
26176 |
return dataTransferImpl.types;
|
|
|
26177 |
},
|
|
|
26178 |
setDragImage: (image, x, y) => {
|
|
|
26179 |
if (isInReadWriteMode(dataTransfer)) {
|
|
|
26180 |
setDragImage(dataTransfer, {
|
|
|
26181 |
image,
|
|
|
26182 |
x,
|
|
|
26183 |
y
|
|
|
26184 |
});
|
|
|
26185 |
dataTransferImpl.setDragImage(image, x, y);
|
|
|
26186 |
}
|
|
|
26187 |
},
|
|
|
26188 |
getData: format => {
|
|
|
26189 |
if (isInProtectedMode(dataTransfer)) {
|
|
|
26190 |
return '';
|
|
|
26191 |
} else {
|
|
|
26192 |
return dataTransferImpl.getData(format);
|
|
|
26193 |
}
|
|
|
26194 |
},
|
|
|
26195 |
setData: (format, data) => {
|
|
|
26196 |
if (isInReadWriteMode(dataTransfer)) {
|
|
|
26197 |
dataTransferImpl.setData(format, data);
|
|
|
26198 |
}
|
|
|
26199 |
},
|
|
|
26200 |
clearData: format => {
|
|
|
26201 |
if (isInReadWriteMode(dataTransfer)) {
|
|
|
26202 |
dataTransferImpl.clearData(format);
|
|
|
26203 |
}
|
|
|
26204 |
}
|
|
|
26205 |
};
|
|
|
26206 |
setReadWriteMode(dataTransfer);
|
|
|
26207 |
return dataTransfer;
|
|
|
26208 |
};
|
|
|
26209 |
const cloneDataTransfer = original => {
|
|
|
26210 |
const clone = createDataTransfer();
|
|
|
26211 |
const originalMode = getMode(original);
|
|
|
26212 |
setReadOnlyMode(original);
|
|
|
26213 |
setDragstartEvent(clone);
|
|
|
26214 |
clone.dropEffect = original.dropEffect;
|
|
|
26215 |
clone.effectAllowed = original.effectAllowed;
|
|
|
26216 |
getDragImage(original).each(imageData => clone.setDragImage(imageData.image, imageData.x, imageData.y));
|
|
|
26217 |
each$e(original.types, type => {
|
|
|
26218 |
if (type !== 'Files') {
|
|
|
26219 |
clone.setData(type, original.getData(type));
|
|
|
26220 |
}
|
|
|
26221 |
});
|
|
|
26222 |
each$e(original.files, file => clone.items.add(file));
|
|
|
26223 |
getEvent(original).each(type => {
|
|
|
26224 |
setEvent(clone, type);
|
|
|
26225 |
});
|
|
|
26226 |
originalMode.each(mode => {
|
|
|
26227 |
setMode$1(original, mode);
|
|
|
26228 |
setMode$1(clone, mode);
|
|
|
26229 |
});
|
|
|
26230 |
return clone;
|
|
|
26231 |
};
|
|
|
26232 |
|
|
|
26233 |
const getHtmlData = dataTransfer => {
|
|
|
26234 |
const html = dataTransfer.getData('text/html');
|
|
|
26235 |
return html === '' ? Optional.none() : Optional.some(html);
|
|
|
26236 |
};
|
|
|
26237 |
const setHtmlData = (dataTransfer, html) => dataTransfer.setData('text/html', html);
|
|
|
26238 |
|
|
|
26239 |
const internalMimeType = 'x-tinymce/html';
|
|
|
26240 |
const internalHtmlMime = constant(internalMimeType);
|
|
|
26241 |
const internalMark = '<!-- ' + internalMimeType + ' -->';
|
|
|
26242 |
const mark = html => internalMark + html;
|
|
|
26243 |
const unmark = html => html.replace(internalMark, '');
|
|
|
26244 |
const isMarked = html => html.indexOf(internalMark) !== -1;
|
|
|
26245 |
|
|
|
26246 |
const isPlainText = text => {
|
|
|
26247 |
return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
|
|
|
26248 |
};
|
|
|
26249 |
const openContainer = (rootTag, rootAttrs) => {
|
|
|
26250 |
let tag = '<' + rootTag;
|
|
|
26251 |
const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"');
|
|
|
26252 |
if (attrs.length) {
|
|
|
26253 |
tag += ' ' + attrs.join(' ');
|
|
|
26254 |
}
|
|
|
26255 |
return tag + '>';
|
|
|
26256 |
};
|
|
|
26257 |
const toBlockElements = (text, rootTag, rootAttrs) => {
|
|
|
26258 |
const blocks = text.split(/\n\n/);
|
|
|
26259 |
const tagOpen = openContainer(rootTag, rootAttrs);
|
|
|
26260 |
const tagClose = '</' + rootTag + '>';
|
|
|
26261 |
const paragraphs = map$3(blocks, p => {
|
|
|
26262 |
return p.split(/\n/).join('<br />');
|
|
|
26263 |
});
|
|
|
26264 |
const stitch = p => {
|
|
|
26265 |
return tagOpen + p + tagClose;
|
|
|
26266 |
};
|
|
|
26267 |
return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join('');
|
|
|
26268 |
};
|
|
|
26269 |
|
|
|
26270 |
const pasteBinDefaultContent = '%MCEPASTEBIN%';
|
|
|
26271 |
const create$6 = (editor, lastRngCell) => {
|
|
|
26272 |
const {dom, selection} = editor;
|
|
|
26273 |
const body = editor.getBody();
|
|
|
26274 |
lastRngCell.set(selection.getRng());
|
|
|
26275 |
const pasteBinElm = dom.add(editor.getBody(), 'div', {
|
|
|
26276 |
'id': 'mcepastebin',
|
|
|
26277 |
'class': 'mce-pastebin',
|
|
|
26278 |
'contentEditable': true,
|
|
|
26279 |
'data-mce-bogus': 'all',
|
|
|
26280 |
'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0'
|
|
|
26281 |
}, pasteBinDefaultContent);
|
|
|
26282 |
if (Env.browser.isFirefox()) {
|
|
|
26283 |
dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535);
|
|
|
26284 |
}
|
|
|
26285 |
dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => {
|
|
|
26286 |
e.stopPropagation();
|
|
|
26287 |
});
|
|
|
26288 |
pasteBinElm.focus();
|
|
|
26289 |
selection.select(pasteBinElm, true);
|
|
|
26290 |
};
|
|
|
26291 |
const remove = (editor, lastRngCell) => {
|
|
|
26292 |
const dom = editor.dom;
|
|
|
26293 |
if (getEl(editor)) {
|
|
|
26294 |
let pasteBinClone;
|
|
|
26295 |
const lastRng = lastRngCell.get();
|
|
|
26296 |
while (pasteBinClone = getEl(editor)) {
|
|
|
26297 |
dom.remove(pasteBinClone);
|
|
|
26298 |
dom.unbind(pasteBinClone);
|
|
|
26299 |
}
|
|
|
26300 |
if (lastRng) {
|
|
|
26301 |
editor.selection.setRng(lastRng);
|
|
|
26302 |
}
|
|
|
26303 |
}
|
|
|
26304 |
lastRngCell.set(null);
|
|
|
26305 |
};
|
|
|
26306 |
const getEl = editor => editor.dom.get('mcepastebin');
|
|
|
26307 |
const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin';
|
|
|
26308 |
const getHtml = editor => {
|
|
|
26309 |
const dom = editor.dom;
|
|
|
26310 |
const copyAndRemove = (toElm, fromElm) => {
|
|
|
26311 |
toElm.appendChild(fromElm);
|
|
|
26312 |
dom.remove(fromElm, true);
|
|
|
26313 |
};
|
|
|
26314 |
const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin);
|
|
|
26315 |
each$e(pasteBinClones, pasteBinClone => {
|
|
|
26316 |
copyAndRemove(pasteBinElm, pasteBinClone);
|
|
|
26317 |
});
|
|
|
26318 |
const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm);
|
|
|
26319 |
for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
|
|
|
26320 |
const cleanWrapper = dom.create('div');
|
|
|
26321 |
pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
|
|
|
26322 |
copyAndRemove(cleanWrapper, dirtyWrappers[i]);
|
|
|
26323 |
}
|
|
|
26324 |
return pasteBinElm ? pasteBinElm.innerHTML : '';
|
|
|
26325 |
};
|
|
|
26326 |
const isDefaultPasteBinContent = content => content === pasteBinDefaultContent;
|
|
|
26327 |
const PasteBin = editor => {
|
|
|
26328 |
const lastRng = Cell(null);
|
|
|
26329 |
return {
|
|
|
26330 |
create: () => create$6(editor, lastRng),
|
|
|
26331 |
remove: () => remove(editor, lastRng),
|
|
|
26332 |
getEl: () => getEl(editor),
|
|
|
26333 |
getHtml: () => getHtml(editor),
|
|
|
26334 |
getLastRng: lastRng.get
|
|
|
26335 |
};
|
|
|
26336 |
};
|
|
|
26337 |
|
|
|
26338 |
const filter$1 = (content, items) => {
|
|
|
26339 |
Tools.each(items, v => {
|
|
|
26340 |
if (is$4(v, RegExp)) {
|
|
|
26341 |
content = content.replace(v, '');
|
|
|
26342 |
} else {
|
|
|
26343 |
content = content.replace(v[0], v[1]);
|
|
|
26344 |
}
|
|
|
26345 |
});
|
|
|
26346 |
return content;
|
|
|
26347 |
};
|
|
|
26348 |
const innerText = html => {
|
|
|
26349 |
const schema = Schema();
|
|
|
26350 |
const domParser = DomParser({}, schema);
|
|
|
26351 |
let text = '';
|
|
|
26352 |
const voidElements = schema.getVoidElements();
|
|
|
26353 |
const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
|
|
|
26354 |
const blockElements = schema.getBlockElements();
|
|
|
26355 |
const walk = node => {
|
|
|
26356 |
const name = node.name, currentNode = node;
|
|
|
26357 |
if (name === 'br') {
|
|
|
26358 |
text += '\n';
|
|
|
26359 |
return;
|
|
|
26360 |
}
|
|
|
26361 |
if (name === 'wbr') {
|
|
|
26362 |
return;
|
|
|
26363 |
}
|
|
|
26364 |
if (voidElements[name]) {
|
|
|
26365 |
text += ' ';
|
|
|
26366 |
}
|
|
|
26367 |
if (ignoreElements[name]) {
|
|
|
26368 |
text += ' ';
|
|
|
26369 |
return;
|
|
|
26370 |
}
|
|
|
26371 |
if (node.type === 3) {
|
|
|
26372 |
text += node.value;
|
|
|
26373 |
}
|
|
|
26374 |
if (!(node.name in schema.getVoidElements())) {
|
|
|
26375 |
let currentNode = node.firstChild;
|
|
|
26376 |
if (currentNode) {
|
|
|
26377 |
do {
|
|
|
26378 |
walk(currentNode);
|
|
|
26379 |
} while (currentNode = currentNode.next);
|
|
|
26380 |
}
|
|
|
26381 |
}
|
|
|
26382 |
if (blockElements[name] && currentNode.next) {
|
|
|
26383 |
text += '\n';
|
|
|
26384 |
if (name === 'p') {
|
|
|
26385 |
text += '\n';
|
|
|
26386 |
}
|
|
|
26387 |
}
|
|
|
26388 |
};
|
|
|
26389 |
html = filter$1(html, [/<!\[[^\]]+\]>/g]);
|
|
|
26390 |
walk(domParser.parse(html));
|
|
|
26391 |
return text;
|
|
|
26392 |
};
|
|
|
26393 |
const trimHtml = html => {
|
|
|
26394 |
const trimSpaces = (all, s1, s2) => {
|
|
|
26395 |
if (!s1 && !s2) {
|
|
|
26396 |
return ' ';
|
|
|
26397 |
}
|
|
|
26398 |
return nbsp;
|
|
|
26399 |
};
|
|
|
26400 |
html = filter$1(html, [
|
|
|
26401 |
/^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
|
|
|
26402 |
/<!--StartFragment-->|<!--EndFragment-->/g,
|
|
|
26403 |
[
|
|
|
26404 |
/( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,
|
|
|
26405 |
trimSpaces
|
|
|
26406 |
],
|
|
|
26407 |
/<br class="Apple-interchange-newline">/g,
|
|
|
26408 |
/<br>$/i
|
|
|
26409 |
]);
|
|
|
26410 |
return html;
|
|
|
26411 |
};
|
|
|
26412 |
const createIdGenerator = prefix => {
|
|
|
26413 |
let count = 0;
|
|
|
26414 |
return () => {
|
|
|
26415 |
return prefix + count++;
|
|
|
26416 |
};
|
|
|
26417 |
};
|
|
|
26418 |
const getImageMimeType = ext => {
|
|
|
26419 |
const lowerExt = ext.toLowerCase();
|
|
|
26420 |
const mimeOverrides = {
|
|
|
26421 |
jpg: 'jpeg',
|
|
|
26422 |
jpe: 'jpeg',
|
|
|
26423 |
jfi: 'jpeg',
|
|
|
26424 |
jif: 'jpeg',
|
|
|
26425 |
jfif: 'jpeg',
|
|
|
26426 |
pjpeg: 'jpeg',
|
|
|
26427 |
pjp: 'jpeg',
|
|
|
26428 |
svg: 'svg+xml'
|
|
|
26429 |
};
|
|
|
26430 |
return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt;
|
|
|
26431 |
};
|
|
|
26432 |
|
|
|
26433 |
const preProcess = (editor, html) => {
|
|
|
26434 |
const parser = DomParser({
|
|
|
26435 |
sanitize: shouldSanitizeXss(editor),
|
| 1441 |
ariadna |
26436 |
sandbox_iframes: shouldSandboxIframes(editor),
|
|
|
26437 |
sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
|
|
|
26438 |
convert_unsafe_embeds: shouldConvertUnsafeEmbeds(editor)
|
| 1 |
efrain |
26439 |
}, editor.schema);
|
|
|
26440 |
parser.addNodeFilter('meta', nodes => {
|
|
|
26441 |
Tools.each(nodes, node => {
|
|
|
26442 |
node.remove();
|
|
|
26443 |
});
|
|
|
26444 |
});
|
|
|
26445 |
const fragment = parser.parse(html, {
|
|
|
26446 |
forced_root_block: false,
|
|
|
26447 |
isRootContent: true
|
|
|
26448 |
});
|
|
|
26449 |
return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
|
|
|
26450 |
};
|
|
|
26451 |
const processResult = (content, cancelled) => ({
|
|
|
26452 |
content,
|
|
|
26453 |
cancelled
|
|
|
26454 |
});
|
|
|
26455 |
const postProcessFilter = (editor, html, internal) => {
|
|
|
26456 |
const tempBody = editor.dom.create('div', { style: 'display:none' }, html);
|
|
|
26457 |
const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
|
|
|
26458 |
return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
|
|
|
26459 |
};
|
|
|
26460 |
const filterContent = (editor, content, internal) => {
|
|
|
26461 |
const preProcessArgs = firePastePreProcess(editor, content, internal);
|
|
|
26462 |
const filteredContent = preProcess(editor, preProcessArgs.content);
|
|
|
26463 |
if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
|
|
|
26464 |
return postProcessFilter(editor, filteredContent, internal);
|
|
|
26465 |
} else {
|
|
|
26466 |
return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
|
|
|
26467 |
}
|
|
|
26468 |
};
|
|
|
26469 |
const process = (editor, html, internal) => {
|
|
|
26470 |
return filterContent(editor, html, internal);
|
|
|
26471 |
};
|
|
|
26472 |
|
|
|
26473 |
const pasteHtml$1 = (editor, html) => {
|
|
|
26474 |
editor.insertContent(html, {
|
|
|
26475 |
merge: shouldPasteMergeFormats(editor),
|
|
|
26476 |
paste: true
|
|
|
26477 |
});
|
|
|
26478 |
return true;
|
|
|
26479 |
};
|
|
|
26480 |
const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
|
|
|
26481 |
const isImageUrl = (editor, url) => {
|
|
|
26482 |
return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`));
|
|
|
26483 |
};
|
|
|
26484 |
const createImage = (editor, url, pasteHtmlFn) => {
|
|
|
26485 |
editor.undoManager.extra(() => {
|
|
|
26486 |
pasteHtmlFn(editor, url);
|
|
|
26487 |
}, () => {
|
|
|
26488 |
editor.insertContent('<img src="' + url + '">');
|
|
|
26489 |
});
|
|
|
26490 |
return true;
|
|
|
26491 |
};
|
|
|
26492 |
const createLink = (editor, url, pasteHtmlFn) => {
|
|
|
26493 |
editor.undoManager.extra(() => {
|
|
|
26494 |
pasteHtmlFn(editor, url);
|
|
|
26495 |
}, () => {
|
|
|
26496 |
editor.execCommand('mceInsertLink', false, url);
|
|
|
26497 |
});
|
|
|
26498 |
return true;
|
|
|
26499 |
};
|
|
|
26500 |
const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false;
|
|
|
26501 |
const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false;
|
|
|
26502 |
const smartInsertContent = (editor, html) => {
|
|
|
26503 |
Tools.each([
|
|
|
26504 |
linkSelection,
|
|
|
26505 |
insertImage,
|
|
|
26506 |
pasteHtml$1
|
|
|
26507 |
], action => {
|
|
|
26508 |
return !action(editor, html, pasteHtml$1);
|
|
|
26509 |
});
|
|
|
26510 |
};
|
|
|
26511 |
const insertContent = (editor, html, pasteAsText) => {
|
|
|
26512 |
if (pasteAsText || !isSmartPasteEnabled(editor)) {
|
|
|
26513 |
pasteHtml$1(editor, html);
|
|
|
26514 |
} else {
|
|
|
26515 |
smartInsertContent(editor, html);
|
|
|
26516 |
}
|
|
|
26517 |
};
|
|
|
26518 |
|
|
|
26519 |
const uniqueId = createIdGenerator('mceclip');
|
|
|
26520 |
const createPasteDataTransfer = html => {
|
|
|
26521 |
const dataTransfer = createDataTransfer();
|
|
|
26522 |
setHtmlData(dataTransfer, html);
|
|
|
26523 |
setReadOnlyMode(dataTransfer);
|
|
|
26524 |
return dataTransfer;
|
|
|
26525 |
};
|
|
|
26526 |
const doPaste = (editor, content, internal, pasteAsText, shouldSimulateInputEvent) => {
|
|
|
26527 |
const res = process(editor, content, internal);
|
|
|
26528 |
if (!res.cancelled) {
|
|
|
26529 |
const content = res.content;
|
|
|
26530 |
const doPasteAction = () => insertContent(editor, content, pasteAsText);
|
|
|
26531 |
if (shouldSimulateInputEvent) {
|
|
|
26532 |
const args = fireBeforeInputEvent(editor, 'insertFromPaste', { dataTransfer: createPasteDataTransfer(content) });
|
|
|
26533 |
if (!args.isDefaultPrevented()) {
|
|
|
26534 |
doPasteAction();
|
|
|
26535 |
fireInputEvent(editor, 'insertFromPaste');
|
|
|
26536 |
}
|
|
|
26537 |
} else {
|
|
|
26538 |
doPasteAction();
|
|
|
26539 |
}
|
|
|
26540 |
}
|
|
|
26541 |
};
|
|
|
26542 |
const pasteHtml = (editor, html, internalFlag, shouldSimulateInputEvent) => {
|
|
|
26543 |
const internal = internalFlag ? internalFlag : isMarked(html);
|
|
|
26544 |
doPaste(editor, unmark(html), internal, false, shouldSimulateInputEvent);
|
|
|
26545 |
};
|
|
|
26546 |
const pasteText = (editor, text, shouldSimulateInputEvent) => {
|
|
|
26547 |
const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n');
|
|
|
26548 |
const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
|
|
|
26549 |
const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
|
|
|
26550 |
doPaste(editor, html, false, true, shouldSimulateInputEvent);
|
|
|
26551 |
};
|
|
|
26552 |
const getDataTransferItems = dataTransfer => {
|
|
|
26553 |
const items = {};
|
|
|
26554 |
if (dataTransfer && dataTransfer.types) {
|
|
|
26555 |
for (let i = 0; i < dataTransfer.types.length; i++) {
|
|
|
26556 |
const contentType = dataTransfer.types[i];
|
|
|
26557 |
try {
|
|
|
26558 |
items[contentType] = dataTransfer.getData(contentType);
|
| 1441 |
ariadna |
26559 |
} catch (_a) {
|
| 1 |
efrain |
26560 |
items[contentType] = '';
|
|
|
26561 |
}
|
|
|
26562 |
}
|
|
|
26563 |
}
|
|
|
26564 |
return items;
|
|
|
26565 |
};
|
|
|
26566 |
const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
|
|
|
26567 |
const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
|
|
|
26568 |
const extractFilename = (editor, str) => {
|
|
|
26569 |
const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
|
|
|
26570 |
return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined;
|
|
|
26571 |
};
|
|
|
26572 |
const createBlobInfo = (editor, blobCache, file, base64) => {
|
|
|
26573 |
const id = uniqueId();
|
|
|
26574 |
const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
|
|
|
26575 |
const name = useFileName ? extractFilename(editor, file.name) : id;
|
|
|
26576 |
const filename = useFileName ? file.name : undefined;
|
|
|
26577 |
const blobInfo = blobCache.create(id, file, base64, name, filename);
|
|
|
26578 |
blobCache.add(blobInfo);
|
|
|
26579 |
return blobInfo;
|
|
|
26580 |
};
|
|
|
26581 |
const pasteImage = (editor, imageItem) => {
|
|
|
26582 |
parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => {
|
|
|
26583 |
const base64 = base64Encoded ? data : btoa(data);
|
|
|
26584 |
const file = imageItem.file;
|
|
|
26585 |
const blobCache = editor.editorUpload.blobCache;
|
|
|
26586 |
const existingBlobInfo = blobCache.getByData(base64, type);
|
|
|
26587 |
const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
|
|
|
26588 |
pasteHtml(editor, `<img src="${ blobInfo.blobUri() }">`, false, true);
|
|
|
26589 |
});
|
|
|
26590 |
};
|
|
|
26591 |
const isClipboardEvent = event => event.type === 'paste';
|
|
|
26592 |
const readFilesAsDataUris = items => Promise.all(map$3(items, file => {
|
|
|
26593 |
return blobToDataUri(file).then(uri => ({
|
|
|
26594 |
file,
|
|
|
26595 |
uri
|
|
|
26596 |
}));
|
|
|
26597 |
}));
|
|
|
26598 |
const isImage = editor => {
|
|
|
26599 |
const allowedExtensions = getAllowedImageFileTypes(editor);
|
|
|
26600 |
return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => {
|
|
|
26601 |
return getImageMimeType(extension) === file.type;
|
|
|
26602 |
});
|
|
|
26603 |
};
|
|
|
26604 |
const getImagesFromDataTransfer = (editor, dataTransfer) => {
|
|
|
26605 |
const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => {
|
|
|
26606 |
return item.kind === 'file' ? [item.getAsFile()] : [];
|
|
|
26607 |
}) : [];
|
|
|
26608 |
const files = dataTransfer.files ? from(dataTransfer.files) : [];
|
|
|
26609 |
return filter$5(items.length > 0 ? items : files, isImage(editor));
|
|
|
26610 |
};
|
|
|
26611 |
const pasteImageData = (editor, e, rng) => {
|
|
|
26612 |
const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
|
|
|
26613 |
if (shouldPasteDataImages(editor) && dataTransfer) {
|
|
|
26614 |
const images = getImagesFromDataTransfer(editor, dataTransfer);
|
|
|
26615 |
if (images.length > 0) {
|
|
|
26616 |
e.preventDefault();
|
|
|
26617 |
readFilesAsDataUris(images).then(fileResults => {
|
|
|
26618 |
if (rng) {
|
|
|
26619 |
editor.selection.setRng(rng);
|
|
|
26620 |
}
|
|
|
26621 |
each$e(fileResults, result => {
|
|
|
26622 |
pasteImage(editor, result);
|
|
|
26623 |
});
|
|
|
26624 |
});
|
|
|
26625 |
return true;
|
|
|
26626 |
}
|
|
|
26627 |
}
|
|
|
26628 |
return false;
|
|
|
26629 |
};
|
|
|
26630 |
const isBrokenAndroidClipboardEvent = e => {
|
|
|
26631 |
var _a, _b;
|
|
|
26632 |
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;
|
|
|
26633 |
};
|
|
|
26634 |
const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
|
|
|
26635 |
const insertClipboardContent = (editor, clipboardContent, html, plainTextMode, shouldSimulateInputEvent) => {
|
|
|
26636 |
let content = trimHtml(html);
|
|
|
26637 |
const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html);
|
|
|
26638 |
const isPlainTextHtml = !isInternal && isPlainText(content);
|
|
|
26639 |
const isAbsoluteUrl$1 = isAbsoluteUrl(content);
|
|
|
26640 |
if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
|
|
|
26641 |
plainTextMode = true;
|
|
|
26642 |
}
|
|
|
26643 |
if (plainTextMode || isAbsoluteUrl$1) {
|
|
|
26644 |
if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) {
|
|
|
26645 |
content = clipboardContent['text/plain'];
|
|
|
26646 |
} else {
|
|
|
26647 |
content = innerText(content);
|
|
|
26648 |
}
|
|
|
26649 |
}
|
|
|
26650 |
if (isDefaultPasteBinContent(content)) {
|
|
|
26651 |
return;
|
|
|
26652 |
}
|
|
|
26653 |
if (plainTextMode) {
|
|
|
26654 |
pasteText(editor, content, shouldSimulateInputEvent);
|
|
|
26655 |
} else {
|
|
|
26656 |
pasteHtml(editor, content, isInternal, shouldSimulateInputEvent);
|
|
|
26657 |
}
|
|
|
26658 |
};
|
|
|
26659 |
const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
|
|
|
26660 |
let keyboardPastePlainTextState;
|
|
|
26661 |
const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
|
|
|
26662 |
editor.on('keydown', e => {
|
|
|
26663 |
if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
|
|
|
26664 |
keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
|
|
|
26665 |
}
|
|
|
26666 |
});
|
|
|
26667 |
editor.on('paste', e => {
|
|
|
26668 |
if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
|
|
|
26669 |
return;
|
|
|
26670 |
}
|
|
|
26671 |
const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState;
|
|
|
26672 |
keyboardPastePlainTextState = false;
|
|
|
26673 |
const clipboardContent = getDataTransferItems(e.clipboardData);
|
|
|
26674 |
if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
|
|
|
26675 |
return;
|
|
|
26676 |
}
|
|
|
26677 |
if (hasContentType(clipboardContent, 'text/html')) {
|
|
|
26678 |
e.preventDefault();
|
|
|
26679 |
insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode, true);
|
|
|
26680 |
} else if (hasContentType(clipboardContent, 'text/plain') && hasContentType(clipboardContent, 'text/uri-list')) {
|
|
|
26681 |
e.preventDefault();
|
|
|
26682 |
insertClipboardContent(editor, clipboardContent, clipboardContent['text/plain'], plainTextMode, true);
|
|
|
26683 |
} else {
|
|
|
26684 |
pasteBin.create();
|
|
|
26685 |
Delay.setEditorTimeout(editor, () => {
|
|
|
26686 |
const html = pasteBin.getHtml();
|
|
|
26687 |
pasteBin.remove();
|
|
|
26688 |
insertClipboardContent(editor, clipboardContent, html, plainTextMode, false);
|
|
|
26689 |
}, 0);
|
|
|
26690 |
}
|
|
|
26691 |
});
|
|
|
26692 |
};
|
|
|
26693 |
const registerDataImageFilter = editor => {
|
|
|
26694 |
const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url');
|
|
|
26695 |
const isDataUri = src => startsWith(src, 'data:');
|
|
|
26696 |
const isPasteInsert = args => {
|
|
|
26697 |
var _a;
|
|
|
26698 |
return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
|
|
|
26699 |
};
|
|
|
26700 |
editor.parser.addNodeFilter('img', (nodes, name, args) => {
|
|
|
26701 |
if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
|
|
|
26702 |
for (const node of nodes) {
|
|
|
26703 |
const src = node.attr('src');
|
|
|
26704 |
if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) {
|
|
|
26705 |
if (isWebKitFakeUrl(src)) {
|
|
|
26706 |
node.remove();
|
|
|
26707 |
} else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
|
|
|
26708 |
node.remove();
|
|
|
26709 |
}
|
|
|
26710 |
}
|
|
|
26711 |
}
|
|
|
26712 |
}
|
|
|
26713 |
});
|
|
|
26714 |
};
|
|
|
26715 |
const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
|
|
|
26716 |
registerEventHandlers(editor, pasteBin, pasteFormat);
|
|
|
26717 |
registerDataImageFilter(editor);
|
|
|
26718 |
};
|
|
|
26719 |
|
|
|
26720 |
const togglePlainTextPaste = (editor, pasteFormat) => {
|
|
|
26721 |
if (pasteFormat.get() === 'text') {
|
|
|
26722 |
pasteFormat.set('html');
|
|
|
26723 |
firePastePlainTextToggle(editor, false);
|
|
|
26724 |
} else {
|
|
|
26725 |
pasteFormat.set('text');
|
|
|
26726 |
firePastePlainTextToggle(editor, true);
|
|
|
26727 |
}
|
|
|
26728 |
editor.focus();
|
|
|
26729 |
};
|
|
|
26730 |
const register$1 = (editor, pasteFormat) => {
|
|
|
26731 |
editor.addCommand('mceTogglePlainTextPaste', () => {
|
|
|
26732 |
togglePlainTextPaste(editor, pasteFormat);
|
|
|
26733 |
});
|
|
|
26734 |
editor.addCommand('mceInsertClipboardContent', (ui, value) => {
|
|
|
26735 |
if (value.html) {
|
|
|
26736 |
pasteHtml(editor, value.html, value.internal, false);
|
|
|
26737 |
}
|
|
|
26738 |
if (value.text) {
|
|
|
26739 |
pasteText(editor, value.text, false);
|
|
|
26740 |
}
|
|
|
26741 |
});
|
|
|
26742 |
};
|
|
|
26743 |
|
|
|
26744 |
const setHtml5Clipboard = (clipboardData, html, text) => {
|
|
|
26745 |
if (clipboardData) {
|
|
|
26746 |
try {
|
|
|
26747 |
clipboardData.clearData();
|
|
|
26748 |
clipboardData.setData('text/html', html);
|
|
|
26749 |
clipboardData.setData('text/plain', text);
|
|
|
26750 |
clipboardData.setData(internalHtmlMime(), html);
|
|
|
26751 |
return true;
|
| 1441 |
ariadna |
26752 |
} catch (_a) {
|
| 1 |
efrain |
26753 |
return false;
|
|
|
26754 |
}
|
|
|
26755 |
} else {
|
|
|
26756 |
return false;
|
|
|
26757 |
}
|
|
|
26758 |
};
|
|
|
26759 |
const setClipboardData = (evt, data, fallback, done) => {
|
|
|
26760 |
if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
|
|
|
26761 |
evt.preventDefault();
|
|
|
26762 |
done();
|
|
|
26763 |
} else {
|
|
|
26764 |
fallback(data.html, done);
|
|
|
26765 |
}
|
|
|
26766 |
};
|
|
|
26767 |
const fallback = editor => (html, done) => {
|
|
|
26768 |
const {dom, selection} = editor;
|
|
|
26769 |
const outer = dom.create('div', {
|
|
|
26770 |
'contenteditable': 'false',
|
|
|
26771 |
'data-mce-bogus': 'all'
|
|
|
26772 |
});
|
|
|
26773 |
const inner = dom.create('div', { contenteditable: 'true' }, html);
|
|
|
26774 |
dom.setStyles(outer, {
|
|
|
26775 |
position: 'fixed',
|
|
|
26776 |
top: '0',
|
|
|
26777 |
left: '-3000px',
|
|
|
26778 |
width: '1000px',
|
|
|
26779 |
overflow: 'hidden'
|
|
|
26780 |
});
|
|
|
26781 |
outer.appendChild(inner);
|
|
|
26782 |
dom.add(editor.getBody(), outer);
|
|
|
26783 |
const range = selection.getRng();
|
|
|
26784 |
inner.focus();
|
|
|
26785 |
const offscreenRange = dom.createRng();
|
|
|
26786 |
offscreenRange.selectNodeContents(inner);
|
|
|
26787 |
selection.setRng(offscreenRange);
|
|
|
26788 |
Delay.setEditorTimeout(editor, () => {
|
|
|
26789 |
selection.setRng(range);
|
|
|
26790 |
dom.remove(outer);
|
|
|
26791 |
done();
|
|
|
26792 |
}, 0);
|
|
|
26793 |
};
|
|
|
26794 |
const getData = editor => ({
|
|
|
26795 |
html: mark(editor.selection.getContent({ contextual: true })),
|
|
|
26796 |
text: editor.selection.getContent({ format: 'text' })
|
|
|
26797 |
});
|
|
|
26798 |
const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody());
|
|
|
26799 |
const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor);
|
|
|
26800 |
const cut = editor => evt => {
|
|
|
26801 |
if (!evt.isDefaultPrevented() && hasSelectedContent(editor) && editor.selection.isEditable()) {
|
|
|
26802 |
setClipboardData(evt, getData(editor), fallback(editor), () => {
|
|
|
26803 |
if (Env.browser.isChromium() || Env.browser.isFirefox()) {
|
|
|
26804 |
const rng = editor.selection.getRng();
|
|
|
26805 |
Delay.setEditorTimeout(editor, () => {
|
|
|
26806 |
editor.selection.setRng(rng);
|
|
|
26807 |
editor.execCommand('Delete');
|
|
|
26808 |
}, 0);
|
|
|
26809 |
} else {
|
|
|
26810 |
editor.execCommand('Delete');
|
|
|
26811 |
}
|
|
|
26812 |
});
|
|
|
26813 |
}
|
|
|
26814 |
};
|
|
|
26815 |
const copy = editor => evt => {
|
|
|
26816 |
if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
|
|
|
26817 |
setClipboardData(evt, getData(editor), fallback(editor), noop);
|
|
|
26818 |
}
|
|
|
26819 |
};
|
|
|
26820 |
const register = editor => {
|
|
|
26821 |
editor.on('cut', cut(editor));
|
|
|
26822 |
editor.on('copy', copy(editor));
|
|
|
26823 |
};
|
|
|
26824 |
|
|
|
26825 |
const getCaretRangeFromEvent = (editor, e) => {
|
|
|
26826 |
var _a, _b;
|
|
|
26827 |
return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
|
|
|
26828 |
};
|
|
|
26829 |
const isPlainTextFileUrl = content => {
|
|
|
26830 |
const plainTextContent = content['text/plain'];
|
|
|
26831 |
return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false;
|
|
|
26832 |
};
|
|
|
26833 |
const setFocusedRange = (editor, rng) => {
|
|
|
26834 |
editor.focus();
|
|
|
26835 |
if (rng) {
|
|
|
26836 |
editor.selection.setRng(rng);
|
|
|
26837 |
}
|
|
|
26838 |
};
|
|
|
26839 |
const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type));
|
|
|
26840 |
const needsCustomInternalDrop = (dom, schema, target, dropContent) => {
|
|
|
26841 |
const parentTransparent = dom.getParent(target, node => isTransparentBlock(schema, node));
|
|
|
26842 |
const inSummary = !isNull(dom.getParent(target, 'summary'));
|
|
|
26843 |
if (inSummary) {
|
|
|
26844 |
return true;
|
|
|
26845 |
} else if (parentTransparent && has$2(dropContent, 'text/html')) {
|
|
|
26846 |
const fragment = new DOMParser().parseFromString(dropContent['text/html'], 'text/html').body;
|
|
|
26847 |
return !isNull(fragment.querySelector(parentTransparent.nodeName.toLowerCase()));
|
|
|
26848 |
} else {
|
|
|
26849 |
return false;
|
|
|
26850 |
}
|
|
|
26851 |
};
|
|
|
26852 |
const setupSummaryDeleteByDragFix = editor => {
|
|
|
26853 |
editor.on('input', e => {
|
|
|
26854 |
const hasNoSummary = el => isNull(el.querySelector('summary'));
|
|
|
26855 |
if (e.inputType === 'deleteByDrag') {
|
|
|
26856 |
const brokenDetailElements = filter$5(editor.dom.select('details'), hasNoSummary);
|
|
|
26857 |
each$e(brokenDetailElements, details => {
|
|
|
26858 |
if (isBr$6(details.firstChild)) {
|
|
|
26859 |
details.firstChild.remove();
|
|
|
26860 |
}
|
|
|
26861 |
const summary = editor.dom.create('summary');
|
|
|
26862 |
summary.appendChild(createPaddingBr().dom);
|
|
|
26863 |
details.prepend(summary);
|
|
|
26864 |
});
|
|
|
26865 |
}
|
|
|
26866 |
});
|
|
|
26867 |
};
|
|
|
26868 |
const setup$a = (editor, draggingInternallyState) => {
|
|
|
26869 |
if (shouldPasteBlockDrop(editor)) {
|
|
|
26870 |
editor.on('dragend dragover draggesture dragdrop drop drag', e => {
|
|
|
26871 |
e.preventDefault();
|
|
|
26872 |
e.stopPropagation();
|
|
|
26873 |
});
|
|
|
26874 |
}
|
|
|
26875 |
if (!shouldPasteDataImages(editor)) {
|
|
|
26876 |
editor.on('drop', e => {
|
|
|
26877 |
const dataTransfer = e.dataTransfer;
|
|
|
26878 |
if (dataTransfer && hasImage(dataTransfer)) {
|
|
|
26879 |
e.preventDefault();
|
|
|
26880 |
}
|
|
|
26881 |
});
|
|
|
26882 |
}
|
|
|
26883 |
editor.on('drop', e => {
|
|
|
26884 |
if (e.isDefaultPrevented()) {
|
|
|
26885 |
return;
|
|
|
26886 |
}
|
|
|
26887 |
const rng = getCaretRangeFromEvent(editor, e);
|
|
|
26888 |
if (isNullable(rng)) {
|
|
|
26889 |
return;
|
|
|
26890 |
}
|
|
|
26891 |
const dropContent = getDataTransferItems(e.dataTransfer);
|
|
|
26892 |
const internal = hasContentType(dropContent, internalHtmlMime());
|
|
|
26893 |
if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
|
|
|
26894 |
return;
|
|
|
26895 |
}
|
|
|
26896 |
const internalContent = dropContent[internalHtmlMime()];
|
|
|
26897 |
const content = internalContent || dropContent['text/html'] || dropContent['text/plain'];
|
|
|
26898 |
const needsInternalDrop = needsCustomInternalDrop(editor.dom, editor.schema, rng.startContainer, dropContent);
|
|
|
26899 |
const isInternalDrop = draggingInternallyState.get();
|
|
|
26900 |
if (isInternalDrop && !needsInternalDrop) {
|
|
|
26901 |
return;
|
|
|
26902 |
}
|
|
|
26903 |
if (content) {
|
|
|
26904 |
e.preventDefault();
|
|
|
26905 |
Delay.setEditorTimeout(editor, () => {
|
|
|
26906 |
editor.undoManager.transact(() => {
|
|
|
26907 |
if (internalContent || isInternalDrop && needsInternalDrop) {
|
|
|
26908 |
editor.execCommand('Delete');
|
|
|
26909 |
}
|
|
|
26910 |
setFocusedRange(editor, rng);
|
|
|
26911 |
const trimmedContent = trimHtml(content);
|
|
|
26912 |
if (dropContent['text/html']) {
|
|
|
26913 |
pasteHtml(editor, trimmedContent, internal, true);
|
|
|
26914 |
} else {
|
|
|
26915 |
pasteText(editor, trimmedContent, true);
|
|
|
26916 |
}
|
|
|
26917 |
});
|
|
|
26918 |
});
|
|
|
26919 |
}
|
|
|
26920 |
});
|
|
|
26921 |
editor.on('dragstart', _e => {
|
|
|
26922 |
draggingInternallyState.set(true);
|
|
|
26923 |
});
|
|
|
26924 |
editor.on('dragover dragend', e => {
|
|
|
26925 |
if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) {
|
|
|
26926 |
e.preventDefault();
|
|
|
26927 |
setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
|
|
|
26928 |
}
|
|
|
26929 |
if (e.type === 'dragend') {
|
|
|
26930 |
draggingInternallyState.set(false);
|
|
|
26931 |
}
|
|
|
26932 |
});
|
|
|
26933 |
setupSummaryDeleteByDragFix(editor);
|
|
|
26934 |
};
|
|
|
26935 |
|
|
|
26936 |
const setup$9 = editor => {
|
|
|
26937 |
const processEvent = f => e => {
|
|
|
26938 |
f(editor, e);
|
|
|
26939 |
};
|
|
|
26940 |
const preProcess = getPastePreProcess(editor);
|
|
|
26941 |
if (isFunction(preProcess)) {
|
|
|
26942 |
editor.on('PastePreProcess', processEvent(preProcess));
|
|
|
26943 |
}
|
|
|
26944 |
const postProcess = getPastePostProcess(editor);
|
|
|
26945 |
if (isFunction(postProcess)) {
|
|
|
26946 |
editor.on('PastePostProcess', processEvent(postProcess));
|
|
|
26947 |
}
|
|
|
26948 |
};
|
|
|
26949 |
|
|
|
26950 |
const addPreProcessFilter = (editor, filterFunc) => {
|
|
|
26951 |
editor.on('PastePreProcess', e => {
|
|
|
26952 |
e.content = filterFunc(editor, e.content, e.internal);
|
|
|
26953 |
});
|
|
|
26954 |
};
|
|
|
26955 |
const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
|
|
|
26956 |
const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase();
|
|
|
26957 |
const removeWebKitStyles = (editor, content, internal) => {
|
|
|
26958 |
const webKitStylesOption = getPasteWebkitStyles(editor);
|
|
|
26959 |
if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) {
|
|
|
26960 |
return content;
|
|
|
26961 |
}
|
|
|
26962 |
const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
|
|
|
26963 |
if (webKitStyles && webKitStylesOption !== 'none') {
|
|
|
26964 |
const dom = editor.dom, node = editor.selection.getNode();
|
|
|
26965 |
content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => {
|
|
|
26966 |
const inputStyles = dom.parseStyle(dom.decode(value));
|
|
|
26967 |
const outputStyles = {};
|
|
|
26968 |
for (let i = 0; i < webKitStyles.length; i++) {
|
|
|
26969 |
const inputValue = inputStyles[webKitStyles[i]];
|
|
|
26970 |
let compareInput = inputValue;
|
|
|
26971 |
let currentValue = dom.getStyle(node, webKitStyles[i], true);
|
|
|
26972 |
if (/color/.test(webKitStyles[i])) {
|
|
|
26973 |
compareInput = rgbToHex(compareInput);
|
|
|
26974 |
currentValue = rgbToHex(currentValue);
|
|
|
26975 |
}
|
|
|
26976 |
if (currentValue !== compareInput) {
|
|
|
26977 |
outputStyles[webKitStyles[i]] = inputValue;
|
|
|
26978 |
}
|
|
|
26979 |
}
|
|
|
26980 |
const outputStyle = dom.serializeStyle(outputStyles, 'span');
|
|
|
26981 |
if (outputStyle) {
|
|
|
26982 |
return before + ' style="' + outputStyle + '"' + after;
|
|
|
26983 |
}
|
|
|
26984 |
return before + after;
|
|
|
26985 |
});
|
|
|
26986 |
} else {
|
|
|
26987 |
content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
|
|
|
26988 |
}
|
|
|
26989 |
content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => {
|
|
|
26990 |
return before + ' style="' + value + '"' + after;
|
|
|
26991 |
});
|
|
|
26992 |
return content;
|
|
|
26993 |
};
|
|
|
26994 |
const setup$8 = editor => {
|
|
|
26995 |
if (Env.browser.isChromium() || Env.browser.isSafari()) {
|
|
|
26996 |
addPreProcessFilter(editor, removeWebKitStyles);
|
|
|
26997 |
}
|
|
|
26998 |
};
|
|
|
26999 |
|
|
|
27000 |
const setup$7 = editor => {
|
|
|
27001 |
const draggingInternallyState = Cell(false);
|
|
|
27002 |
const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html');
|
|
|
27003 |
const pasteBin = PasteBin(editor);
|
|
|
27004 |
setup$8(editor);
|
|
|
27005 |
register$1(editor, pasteFormat);
|
|
|
27006 |
setup$9(editor);
|
| 1441 |
ariadna |
27007 |
editor.addQueryStateHandler('mceTogglePlainTextPaste', () => pasteFormat.get() === 'text');
|
| 1 |
efrain |
27008 |
editor.on('PreInit', () => {
|
|
|
27009 |
register(editor);
|
|
|
27010 |
setup$a(editor, draggingInternallyState);
|
|
|
27011 |
registerEventsAndFilters(editor, pasteBin, pasteFormat);
|
|
|
27012 |
});
|
|
|
27013 |
};
|
|
|
27014 |
|
|
|
27015 |
const preventSummaryToggle = editor => {
|
|
|
27016 |
editor.on('click', e => {
|
|
|
27017 |
if (editor.dom.getParent(e.target, 'details')) {
|
|
|
27018 |
e.preventDefault();
|
|
|
27019 |
}
|
|
|
27020 |
});
|
|
|
27021 |
};
|
|
|
27022 |
const filterDetails = editor => {
|
|
|
27023 |
editor.parser.addNodeFilter('details', elms => {
|
|
|
27024 |
const initialStateOption = getDetailsInitialState(editor);
|
|
|
27025 |
each$e(elms, details => {
|
|
|
27026 |
if (initialStateOption === 'expanded') {
|
|
|
27027 |
details.attr('open', 'open');
|
|
|
27028 |
} else if (initialStateOption === 'collapsed') {
|
|
|
27029 |
details.attr('open', null);
|
|
|
27030 |
}
|
|
|
27031 |
});
|
|
|
27032 |
});
|
|
|
27033 |
editor.serializer.addNodeFilter('details', elms => {
|
|
|
27034 |
const serializedStateOption = getDetailsSerializedState(editor);
|
|
|
27035 |
each$e(elms, details => {
|
|
|
27036 |
if (serializedStateOption === 'expanded') {
|
|
|
27037 |
details.attr('open', 'open');
|
|
|
27038 |
} else if (serializedStateOption === 'collapsed') {
|
|
|
27039 |
details.attr('open', null);
|
|
|
27040 |
}
|
|
|
27041 |
});
|
|
|
27042 |
});
|
|
|
27043 |
};
|
|
|
27044 |
const setup$6 = editor => {
|
|
|
27045 |
preventSummaryToggle(editor);
|
|
|
27046 |
filterDetails(editor);
|
|
|
27047 |
};
|
|
|
27048 |
|
|
|
27049 |
const isBr = isBr$6;
|
| 1441 |
ariadna |
27050 |
const isText = isText$b;
|
| 1 |
efrain |
27051 |
const isContentEditableFalse$2 = elm => isContentEditableFalse$b(elm.dom);
|
|
|
27052 |
const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom);
|
|
|
27053 |
const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm);
|
|
|
27054 |
const getClosestScope = (node, rootNode, schema) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
|
|
|
27055 |
const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
|
|
|
27056 |
const findEdgeCaretCandidate = (startNode, scope, forward) => {
|
|
|
27057 |
const walker = new DomTreeWalker(startNode, scope);
|
|
|
27058 |
const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
|
|
|
27059 |
let result = startNode;
|
|
|
27060 |
for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) {
|
|
|
27061 |
if (isCaretCandidate$3(current)) {
|
|
|
27062 |
result = current;
|
|
|
27063 |
}
|
|
|
27064 |
}
|
|
|
27065 |
return result;
|
|
|
27066 |
};
|
|
|
27067 |
const findClosestBlockRange = (startRng, rootNode, schema) => {
|
|
|
27068 |
const startPos = CaretPosition.fromRangeStart(startRng);
|
|
|
27069 |
const clickNode = startPos.getNode();
|
|
|
27070 |
const scope = getClosestScope(clickNode, rootNode, schema);
|
|
|
27071 |
const startNode = findEdgeCaretCandidate(clickNode, scope, false);
|
|
|
27072 |
const endNode = findEdgeCaretCandidate(clickNode, scope, true);
|
|
|
27073 |
const rng = document.createRange();
|
|
|
27074 |
getClosestCef(startNode, scope).fold(() => {
|
|
|
27075 |
if (isText(startNode)) {
|
|
|
27076 |
rng.setStart(startNode, 0);
|
|
|
27077 |
} else {
|
|
|
27078 |
rng.setStartBefore(startNode);
|
|
|
27079 |
}
|
|
|
27080 |
}, cef => rng.setStartBefore(cef.dom));
|
|
|
27081 |
getClosestCef(endNode, scope).fold(() => {
|
|
|
27082 |
if (isText(endNode)) {
|
|
|
27083 |
rng.setEnd(endNode, endNode.data.length);
|
|
|
27084 |
} else {
|
|
|
27085 |
rng.setEndAfter(endNode);
|
|
|
27086 |
}
|
|
|
27087 |
}, cef => rng.setEndAfter(cef.dom));
|
|
|
27088 |
return rng;
|
|
|
27089 |
};
|
|
|
27090 |
const onTripleClickSelect = editor => {
|
|
|
27091 |
const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody(), editor.schema);
|
|
|
27092 |
editor.selection.setRng(normalize(rng));
|
|
|
27093 |
};
|
|
|
27094 |
const setup$5 = editor => {
|
|
|
27095 |
editor.on('mousedown', e => {
|
|
|
27096 |
if (e.detail >= 3) {
|
|
|
27097 |
e.preventDefault();
|
|
|
27098 |
onTripleClickSelect(editor);
|
|
|
27099 |
}
|
|
|
27100 |
});
|
|
|
27101 |
};
|
|
|
27102 |
|
|
|
27103 |
var FakeCaretPosition;
|
|
|
27104 |
(function (FakeCaretPosition) {
|
|
|
27105 |
FakeCaretPosition['Before'] = 'before';
|
|
|
27106 |
FakeCaretPosition['After'] = 'after';
|
|
|
27107 |
}(FakeCaretPosition || (FakeCaretPosition = {})));
|
|
|
27108 |
const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
|
|
|
27109 |
const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
|
|
|
27110 |
const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
|
|
|
27111 |
const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
|
|
|
27112 |
const isOverlapping = (r1, r2) => {
|
|
|
27113 |
const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
|
|
|
27114 |
return collidesY(r1, r2) && overlap > 0.5;
|
|
|
27115 |
};
|
|
|
27116 |
const splitRectsPerAxis = (rects, y) => {
|
|
|
27117 |
const intersectingRects = filter$5(rects, rect => isInsideY(y, rect));
|
|
|
27118 |
return boundingClientRectFromRects(intersectingRects).fold(() => [
|
|
|
27119 |
[],
|
|
|
27120 |
rects
|
|
|
27121 |
], boundingRect => {
|
|
|
27122 |
const {
|
|
|
27123 |
pass: horizontal,
|
|
|
27124 |
fail: vertical
|
|
|
27125 |
} = partition$2(rects, rect => isOverlapping(rect, boundingRect));
|
|
|
27126 |
return [
|
|
|
27127 |
horizontal,
|
|
|
27128 |
vertical
|
|
|
27129 |
];
|
|
|
27130 |
});
|
|
|
27131 |
};
|
|
|
27132 |
const clientInfo = (rect, clientX) => {
|
|
|
27133 |
return {
|
|
|
27134 |
node: rect.node,
|
|
|
27135 |
position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
|
|
|
27136 |
};
|
|
|
27137 |
};
|
|
|
27138 |
const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
|
|
|
27139 |
const closestChildCaretCandidateNodeRect = (children, clientX, clientY, findCloserTextNode) => {
|
|
|
27140 |
const caretCandidateRect = rect => {
|
|
|
27141 |
if (isCaretCandidate$3(rect.node)) {
|
|
|
27142 |
return Optional.some(rect);
|
|
|
27143 |
} else if (isElement$6(rect.node)) {
|
|
|
27144 |
return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY, false);
|
|
|
27145 |
} else {
|
|
|
27146 |
return Optional.none();
|
|
|
27147 |
}
|
|
|
27148 |
};
|
|
|
27149 |
const tryFindSecondBestTextNode = (closest, sndClosest, distance) => {
|
|
|
27150 |
return caretCandidateRect(sndClosest).filter(rect => {
|
|
|
27151 |
const deltaDistance = Math.abs(distance(closest, clientX, clientY) - distance(rect, clientX, clientY));
|
| 1441 |
ariadna |
27152 |
return deltaDistance < 2 && isText$b(rect.node);
|
| 1 |
efrain |
27153 |
});
|
|
|
27154 |
};
|
|
|
27155 |
const findClosestCaretCandidateNodeRect = (rects, distance) => {
|
|
|
27156 |
const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
|
|
|
27157 |
return findMap(sortedRects, caretCandidateRect).map(closest => {
|
| 1441 |
ariadna |
27158 |
if (findCloserTextNode && !isText$b(closest.node) && sortedRects.length > 1) {
|
| 1 |
efrain |
27159 |
return tryFindSecondBestTextNode(closest, sortedRects[1], distance).getOr(closest);
|
|
|
27160 |
} else {
|
|
|
27161 |
return closest;
|
|
|
27162 |
}
|
|
|
27163 |
});
|
|
|
27164 |
};
|
|
|
27165 |
const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY);
|
|
|
27166 |
const {
|
|
|
27167 |
pass: above,
|
|
|
27168 |
fail: below
|
|
|
27169 |
} = partition$2(verticalRects, rect => rect.top < clientY);
|
|
|
27170 |
return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
|
|
|
27171 |
};
|
|
|
27172 |
const traverseUp = (rootElm, scope, clientX, clientY) => {
|
|
|
27173 |
const helper = (scope, prevScope) => {
|
|
|
27174 |
const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container');
|
|
|
27175 |
const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer));
|
|
|
27176 |
return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY, true), prevScope => {
|
|
|
27177 |
const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom);
|
|
|
27178 |
return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY, true);
|
|
|
27179 |
}).orThunk(() => {
|
|
|
27180 |
const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope);
|
|
|
27181 |
return parent.bind(newScope => helper(newScope, Optional.some(scope)));
|
|
|
27182 |
});
|
|
|
27183 |
};
|
|
|
27184 |
return helper(scope, Optional.none());
|
|
|
27185 |
};
|
|
|
27186 |
const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
|
|
|
27187 |
const rootElm = SugarElement.fromDom(root);
|
|
|
27188 |
const ownerDoc = documentOrOwner(rootElm);
|
|
|
27189 |
const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm));
|
|
|
27190 |
const element = elementAtPoint.getOr(rootElm);
|
|
|
27191 |
return traverseUp(rootElm, element, clientX, clientY);
|
|
|
27192 |
};
|
|
|
27193 |
const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX));
|
|
|
27194 |
|
|
|
27195 |
const getAbsolutePosition = elm => {
|
|
|
27196 |
var _a, _b;
|
|
|
27197 |
const clientRect = elm.getBoundingClientRect();
|
|
|
27198 |
const doc = elm.ownerDocument;
|
|
|
27199 |
const docElem = doc.documentElement;
|
|
|
27200 |
const win = doc.defaultView;
|
|
|
27201 |
return {
|
|
|
27202 |
top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop,
|
|
|
27203 |
left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft
|
|
|
27204 |
};
|
|
|
27205 |
};
|
|
|
27206 |
const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : {
|
|
|
27207 |
left: 0,
|
|
|
27208 |
top: 0
|
|
|
27209 |
};
|
|
|
27210 |
const getScrollPosition = editor => {
|
|
|
27211 |
const body = editor.getBody();
|
|
|
27212 |
return editor.inline ? {
|
|
|
27213 |
left: body.scrollLeft,
|
|
|
27214 |
top: body.scrollTop
|
|
|
27215 |
} : {
|
|
|
27216 |
left: 0,
|
|
|
27217 |
top: 0
|
|
|
27218 |
};
|
|
|
27219 |
};
|
|
|
27220 |
const getBodyScroll = editor => {
|
|
|
27221 |
const body = editor.getBody(), docElm = editor.getDoc().documentElement;
|
|
|
27222 |
const inlineScroll = {
|
|
|
27223 |
left: body.scrollLeft,
|
|
|
27224 |
top: body.scrollTop
|
|
|
27225 |
};
|
|
|
27226 |
const iframeScroll = {
|
|
|
27227 |
left: body.scrollLeft || docElm.scrollLeft,
|
|
|
27228 |
top: body.scrollTop || docElm.scrollTop
|
|
|
27229 |
};
|
|
|
27230 |
return editor.inline ? inlineScroll : iframeScroll;
|
|
|
27231 |
};
|
|
|
27232 |
const getMousePosition = (editor, event) => {
|
|
|
27233 |
if (event.target.ownerDocument !== editor.getDoc()) {
|
|
|
27234 |
const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
|
|
|
27235 |
const scrollPosition = getBodyScroll(editor);
|
|
|
27236 |
return {
|
|
|
27237 |
left: event.pageX - iframePosition.left + scrollPosition.left,
|
|
|
27238 |
top: event.pageY - iframePosition.top + scrollPosition.top
|
|
|
27239 |
};
|
|
|
27240 |
}
|
|
|
27241 |
return {
|
|
|
27242 |
left: event.pageX,
|
|
|
27243 |
top: event.pageY
|
|
|
27244 |
};
|
|
|
27245 |
};
|
|
|
27246 |
const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
|
|
|
27247 |
pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
|
|
|
27248 |
pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
|
|
|
27249 |
});
|
|
|
27250 |
const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
|
|
|
27251 |
|
|
|
27252 |
const getTargetProps = target => ({
|
|
|
27253 |
target,
|
|
|
27254 |
srcElement: target
|
|
|
27255 |
});
|
|
|
27256 |
const makeDndEventFromMouseEvent = (type, mouseEvent, target, dataTransfer) => ({
|
|
|
27257 |
...mouseEvent,
|
|
|
27258 |
dataTransfer,
|
|
|
27259 |
type,
|
|
|
27260 |
...getTargetProps(target)
|
|
|
27261 |
});
|
|
|
27262 |
const makeDndEvent = (type, target, dataTransfer) => {
|
|
|
27263 |
const fail = die('Function not supported on simulated event.');
|
|
|
27264 |
const event = {
|
|
|
27265 |
bubbles: true,
|
|
|
27266 |
cancelBubble: false,
|
|
|
27267 |
cancelable: true,
|
|
|
27268 |
composed: false,
|
|
|
27269 |
currentTarget: null,
|
|
|
27270 |
defaultPrevented: false,
|
|
|
27271 |
eventPhase: 0,
|
|
|
27272 |
isTrusted: true,
|
|
|
27273 |
returnValue: false,
|
|
|
27274 |
timeStamp: 0,
|
|
|
27275 |
type,
|
|
|
27276 |
composedPath: fail,
|
|
|
27277 |
initEvent: fail,
|
|
|
27278 |
preventDefault: noop,
|
|
|
27279 |
stopImmediatePropagation: noop,
|
|
|
27280 |
stopPropagation: noop,
|
|
|
27281 |
AT_TARGET: window.Event.AT_TARGET,
|
|
|
27282 |
BUBBLING_PHASE: window.Event.BUBBLING_PHASE,
|
|
|
27283 |
CAPTURING_PHASE: window.Event.CAPTURING_PHASE,
|
|
|
27284 |
NONE: window.Event.NONE,
|
|
|
27285 |
altKey: false,
|
|
|
27286 |
button: 0,
|
|
|
27287 |
buttons: 0,
|
|
|
27288 |
clientX: 0,
|
|
|
27289 |
clientY: 0,
|
|
|
27290 |
ctrlKey: false,
|
| 1441 |
ariadna |
27291 |
layerX: 0,
|
|
|
27292 |
layerY: 0,
|
| 1 |
efrain |
27293 |
metaKey: false,
|
|
|
27294 |
movementX: 0,
|
|
|
27295 |
movementY: 0,
|
|
|
27296 |
offsetX: 0,
|
|
|
27297 |
offsetY: 0,
|
|
|
27298 |
pageX: 0,
|
|
|
27299 |
pageY: 0,
|
|
|
27300 |
relatedTarget: null,
|
|
|
27301 |
screenX: 0,
|
|
|
27302 |
screenY: 0,
|
|
|
27303 |
shiftKey: false,
|
|
|
27304 |
x: 0,
|
|
|
27305 |
y: 0,
|
|
|
27306 |
detail: 0,
|
|
|
27307 |
view: null,
|
|
|
27308 |
which: 0,
|
|
|
27309 |
initUIEvent: fail,
|
|
|
27310 |
initMouseEvent: fail,
|
|
|
27311 |
getModifierState: fail,
|
|
|
27312 |
dataTransfer,
|
|
|
27313 |
...getTargetProps(target)
|
|
|
27314 |
};
|
|
|
27315 |
return event;
|
|
|
27316 |
};
|
|
|
27317 |
const makeDataTransferCopyForDragEvent = (dataTransfer, eventType) => {
|
|
|
27318 |
const copy = cloneDataTransfer(dataTransfer);
|
|
|
27319 |
if (eventType === 'dragstart') {
|
|
|
27320 |
setDragstartEvent(copy);
|
|
|
27321 |
setReadWriteMode(copy);
|
|
|
27322 |
} else if (eventType === 'drop') {
|
|
|
27323 |
setDropEvent(copy);
|
|
|
27324 |
setReadOnlyMode(copy);
|
|
|
27325 |
} else {
|
|
|
27326 |
setDragendEvent(copy);
|
|
|
27327 |
setProtectedMode(copy);
|
|
|
27328 |
}
|
|
|
27329 |
return copy;
|
|
|
27330 |
};
|
|
|
27331 |
const makeDragEvent = (type, target, dataTransfer, mouseEvent) => {
|
|
|
27332 |
const dataTransferForDispatch = makeDataTransferCopyForDragEvent(dataTransfer, type);
|
|
|
27333 |
return isUndefined(mouseEvent) ? makeDndEvent(type, target, dataTransferForDispatch) : makeDndEventFromMouseEvent(type, mouseEvent, target, dataTransferForDispatch);
|
|
|
27334 |
};
|
|
|
27335 |
|
|
|
27336 |
const scrollPixelsPerInterval = 32;
|
|
|
27337 |
const scrollIntervalValue = 100;
|
|
|
27338 |
const mouseRangeToTriggerScrollInsideEditor = 8;
|
|
|
27339 |
const mouseRangeToTriggerScrollOutsideEditor = 16;
|
|
|
27340 |
const isContentEditableFalse$1 = isContentEditableFalse$b;
|
|
|
27341 |
const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3);
|
|
|
27342 |
const isDraggable = (dom, rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm && dom.isEditable(elm.parentElement);
|
|
|
27343 |
const isValidDropTarget = (editor, targetElement, dragElement) => {
|
|
|
27344 |
if (isNullable(targetElement)) {
|
|
|
27345 |
return false;
|
|
|
27346 |
} else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
|
|
|
27347 |
return false;
|
|
|
27348 |
} else {
|
|
|
27349 |
return editor.dom.isEditable(targetElement);
|
|
|
27350 |
}
|
|
|
27351 |
};
|
|
|
27352 |
const createGhost = (editor, elm, width, height) => {
|
|
|
27353 |
const dom = editor.dom;
|
|
|
27354 |
const clonedElm = elm.cloneNode(true);
|
|
|
27355 |
dom.setStyles(clonedElm, {
|
|
|
27356 |
width,
|
|
|
27357 |
height
|
|
|
27358 |
});
|
|
|
27359 |
dom.setAttrib(clonedElm, 'data-mce-selected', null);
|
|
|
27360 |
const ghostElm = dom.create('div', {
|
|
|
27361 |
'class': 'mce-drag-container',
|
|
|
27362 |
'data-mce-bogus': 'all',
|
|
|
27363 |
'unselectable': 'on',
|
|
|
27364 |
'contenteditable': 'false'
|
|
|
27365 |
});
|
|
|
27366 |
dom.setStyles(ghostElm, {
|
|
|
27367 |
position: 'absolute',
|
|
|
27368 |
opacity: 0.5,
|
|
|
27369 |
overflow: 'hidden',
|
|
|
27370 |
border: 0,
|
|
|
27371 |
padding: 0,
|
|
|
27372 |
margin: 0,
|
|
|
27373 |
width,
|
|
|
27374 |
height
|
|
|
27375 |
});
|
|
|
27376 |
dom.setStyles(clonedElm, {
|
|
|
27377 |
margin: 0,
|
|
|
27378 |
boxSizing: 'border-box'
|
|
|
27379 |
});
|
|
|
27380 |
ghostElm.appendChild(clonedElm);
|
|
|
27381 |
return ghostElm;
|
|
|
27382 |
};
|
|
|
27383 |
const appendGhostToBody = (ghostElm, bodyElm) => {
|
|
|
27384 |
if (ghostElm.parentNode !== bodyElm) {
|
|
|
27385 |
bodyElm.appendChild(ghostElm);
|
|
|
27386 |
}
|
|
|
27387 |
};
|
|
|
27388 |
const scrollEditor = (direction, amount) => win => () => {
|
|
|
27389 |
const current = direction === 'left' ? win.scrollX : win.scrollY;
|
|
|
27390 |
win.scroll({
|
|
|
27391 |
[direction]: current + amount,
|
|
|
27392 |
behavior: 'smooth'
|
|
|
27393 |
});
|
|
|
27394 |
};
|
|
|
27395 |
const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval);
|
|
|
27396 |
const scrollRight = scrollEditor('left', scrollPixelsPerInterval);
|
|
|
27397 |
const scrollUp = scrollEditor('top', -scrollPixelsPerInterval);
|
|
|
27398 |
const scrollDown = scrollEditor('top', scrollPixelsPerInterval);
|
|
|
27399 |
const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => {
|
|
|
27400 |
let overflowX = 0, overflowY = 0;
|
|
|
27401 |
ghostElm.style.left = position.pageX + 'px';
|
|
|
27402 |
ghostElm.style.top = position.pageY + 'px';
|
|
|
27403 |
if (position.pageX + width > maxX) {
|
|
|
27404 |
overflowX = position.pageX + width - maxX;
|
|
|
27405 |
}
|
|
|
27406 |
if (position.pageY + height > maxY) {
|
|
|
27407 |
overflowY = position.pageY + height - maxY;
|
|
|
27408 |
}
|
|
|
27409 |
ghostElm.style.width = width - overflowX + 'px';
|
|
|
27410 |
ghostElm.style.height = height - overflowY + 'px';
|
|
|
27411 |
const clientHeight = contentAreaContainer.clientHeight;
|
|
|
27412 |
const clientWidth = contentAreaContainer.clientWidth;
|
|
|
27413 |
const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top;
|
|
|
27414 |
const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left;
|
|
|
27415 |
state.on(state => {
|
|
|
27416 |
state.intervalId.clear();
|
|
|
27417 |
if (state.dragging && mouseEventOriginatedFromWithinTheEditor) {
|
|
|
27418 |
if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) {
|
|
|
27419 |
state.intervalId.set(scrollDown(win));
|
|
|
27420 |
} else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) {
|
|
|
27421 |
state.intervalId.set(scrollUp(win));
|
|
|
27422 |
} else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) {
|
|
|
27423 |
state.intervalId.set(scrollRight(win));
|
|
|
27424 |
} else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) {
|
|
|
27425 |
state.intervalId.set(scrollLeft(win));
|
|
|
27426 |
} else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) {
|
|
|
27427 |
state.intervalId.set(scrollDown(window));
|
|
|
27428 |
} else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) {
|
|
|
27429 |
state.intervalId.set(scrollUp(window));
|
|
|
27430 |
} else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) {
|
|
|
27431 |
state.intervalId.set(scrollRight(window));
|
|
|
27432 |
} else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) {
|
|
|
27433 |
state.intervalId.set(scrollLeft(window));
|
|
|
27434 |
}
|
|
|
27435 |
}
|
|
|
27436 |
});
|
|
|
27437 |
};
|
|
|
27438 |
const removeElement = elm => {
|
|
|
27439 |
if (elm && elm.parentNode) {
|
|
|
27440 |
elm.parentNode.removeChild(elm);
|
|
|
27441 |
}
|
|
|
27442 |
};
|
|
|
27443 |
const removeElementWithPadding = (dom, elm) => {
|
|
|
27444 |
const parentBlock = dom.getParent(elm.parentNode, dom.isBlock);
|
|
|
27445 |
removeElement(elm);
|
|
|
27446 |
if (parentBlock && parentBlock !== dom.getRoot() && dom.isEmpty(parentBlock)) {
|
|
|
27447 |
fillWithPaddingBr(SugarElement.fromDom(parentBlock));
|
|
|
27448 |
}
|
|
|
27449 |
};
|
|
|
27450 |
const isLeftMouseButtonPressed = e => e.button === 0;
|
|
|
27451 |
const applyRelPos = (state, position) => ({
|
|
|
27452 |
pageX: position.pageX - state.relX,
|
|
|
27453 |
pageY: position.pageY + 5
|
|
|
27454 |
});
|
|
|
27455 |
const start = (state, editor) => e => {
|
|
|
27456 |
if (isLeftMouseButtonPressed(e)) {
|
|
|
27457 |
const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null);
|
|
|
27458 |
if (isNonNullable(ceElm) && isDraggable(editor.dom, editor.getBody(), ceElm)) {
|
|
|
27459 |
const elmPos = editor.dom.getPos(ceElm);
|
|
|
27460 |
const bodyElm = editor.getBody();
|
|
|
27461 |
const docElm = editor.getDoc().documentElement;
|
|
|
27462 |
state.set({
|
|
|
27463 |
element: ceElm,
|
|
|
27464 |
dataTransfer: createDataTransfer(),
|
|
|
27465 |
dragging: false,
|
|
|
27466 |
screenX: e.screenX,
|
|
|
27467 |
screenY: e.screenY,
|
|
|
27468 |
maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
|
|
|
27469 |
maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
|
|
|
27470 |
relX: e.pageX - elmPos.x,
|
|
|
27471 |
relY: e.pageY - elmPos.y,
|
|
|
27472 |
width: ceElm.offsetWidth,
|
|
|
27473 |
height: ceElm.offsetHeight,
|
|
|
27474 |
ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight),
|
|
|
27475 |
intervalId: repeatable(scrollIntervalValue)
|
|
|
27476 |
});
|
|
|
27477 |
}
|
|
|
27478 |
}
|
|
|
27479 |
};
|
|
|
27480 |
const placeCaretAt = (editor, clientX, clientY) => {
|
|
|
27481 |
editor._selectionOverrides.hideFakeCaret();
|
|
|
27482 |
closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => {
|
|
|
27483 |
const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
|
|
|
27484 |
if (range) {
|
|
|
27485 |
editor.selection.setRng(range);
|
|
|
27486 |
} else {
|
|
|
27487 |
editor.selection.placeCaretAt(clientX, clientY);
|
|
|
27488 |
}
|
|
|
27489 |
});
|
|
|
27490 |
};
|
|
|
27491 |
const dispatchDragEvent = (editor, type, target, dataTransfer, mouseEvent) => {
|
|
|
27492 |
if (type === 'dragstart') {
|
|
|
27493 |
setHtmlData(dataTransfer, editor.dom.getOuterHTML(target));
|
|
|
27494 |
}
|
|
|
27495 |
const event = makeDragEvent(type, target, dataTransfer, mouseEvent);
|
|
|
27496 |
const args = editor.dispatch(type, event);
|
|
|
27497 |
return args;
|
|
|
27498 |
};
|
|
|
27499 |
const move = (state, editor) => {
|
|
|
27500 |
const throttledPlaceCaretAt = first$1((clientX, clientY) => placeCaretAt(editor, clientX, clientY), 0);
|
|
|
27501 |
editor.on('remove', throttledPlaceCaretAt.cancel);
|
|
|
27502 |
const state_ = state;
|
|
|
27503 |
return e => state.on(state => {
|
|
|
27504 |
const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
|
|
|
27505 |
if (!state.dragging && movement > 10) {
|
|
|
27506 |
const args = dispatchDragEvent(editor, 'dragstart', state.element, state.dataTransfer, e);
|
|
|
27507 |
if (isNonNullable(args.dataTransfer)) {
|
|
|
27508 |
state.dataTransfer = args.dataTransfer;
|
|
|
27509 |
}
|
|
|
27510 |
if (args.isDefaultPrevented()) {
|
|
|
27511 |
return;
|
|
|
27512 |
}
|
|
|
27513 |
state.dragging = true;
|
|
|
27514 |
editor.focus();
|
|
|
27515 |
}
|
|
|
27516 |
if (state.dragging) {
|
|
|
27517 |
const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement;
|
|
|
27518 |
const targetPos = applyRelPos(state, calc(editor, e));
|
|
|
27519 |
appendGhostToBody(state.ghost, editor.getBody());
|
|
|
27520 |
moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor);
|
|
|
27521 |
throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
|
|
|
27522 |
}
|
|
|
27523 |
});
|
|
|
27524 |
};
|
|
|
27525 |
const getRawTarget = selection => {
|
|
|
27526 |
const sel = selection.getSel();
|
|
|
27527 |
if (isNonNullable(sel)) {
|
|
|
27528 |
const rng = sel.getRangeAt(0);
|
|
|
27529 |
const startContainer = rng.startContainer;
|
| 1441 |
ariadna |
27530 |
return isText$b(startContainer) ? startContainer.parentNode : startContainer;
|
| 1 |
efrain |
27531 |
} else {
|
|
|
27532 |
return null;
|
|
|
27533 |
}
|
|
|
27534 |
};
|
|
|
27535 |
const drop = (state, editor) => e => {
|
|
|
27536 |
state.on(state => {
|
|
|
27537 |
var _a;
|
|
|
27538 |
state.intervalId.clear();
|
|
|
27539 |
if (state.dragging) {
|
|
|
27540 |
if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
|
|
|
27541 |
const dropTarget = (_a = editor.getDoc().elementFromPoint(e.clientX, e.clientY)) !== null && _a !== void 0 ? _a : editor.getBody();
|
|
|
27542 |
const args = dispatchDragEvent(editor, 'drop', dropTarget, state.dataTransfer, e);
|
|
|
27543 |
if (!args.isDefaultPrevented()) {
|
|
|
27544 |
editor.undoManager.transact(() => {
|
|
|
27545 |
removeElementWithPadding(editor.dom, state.element);
|
|
|
27546 |
getHtmlData(state.dataTransfer).each(content => editor.insertContent(content));
|
|
|
27547 |
editor._selectionOverrides.hideFakeCaret();
|
|
|
27548 |
});
|
|
|
27549 |
}
|
|
|
27550 |
}
|
|
|
27551 |
dispatchDragEvent(editor, 'dragend', editor.getBody(), state.dataTransfer, e);
|
|
|
27552 |
}
|
|
|
27553 |
});
|
|
|
27554 |
removeDragState(state);
|
|
|
27555 |
};
|
|
|
27556 |
const stopDragging = (state, editor, e) => {
|
|
|
27557 |
state.on(state => {
|
|
|
27558 |
state.intervalId.clear();
|
|
|
27559 |
if (state.dragging) {
|
|
|
27560 |
e.fold(() => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer), mouseEvent => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer, mouseEvent));
|
|
|
27561 |
}
|
|
|
27562 |
});
|
|
|
27563 |
removeDragState(state);
|
|
|
27564 |
};
|
|
|
27565 |
const stop = (state, editor) => e => stopDragging(state, editor, Optional.some(e));
|
|
|
27566 |
const removeDragState = state => {
|
|
|
27567 |
state.on(state => {
|
|
|
27568 |
state.intervalId.clear();
|
|
|
27569 |
removeElement(state.ghost);
|
|
|
27570 |
});
|
|
|
27571 |
state.clear();
|
|
|
27572 |
};
|
|
|
27573 |
const bindFakeDragEvents = editor => {
|
|
|
27574 |
const state = value$2();
|
|
|
27575 |
const pageDom = DOMUtils.DOM;
|
|
|
27576 |
const rootDocument = document;
|
|
|
27577 |
const dragStartHandler = start(state, editor);
|
|
|
27578 |
const dragHandler = move(state, editor);
|
|
|
27579 |
const dropHandler = drop(state, editor);
|
|
|
27580 |
const dragEndHandler = stop(state, editor);
|
|
|
27581 |
editor.on('mousedown', dragStartHandler);
|
|
|
27582 |
editor.on('mousemove', dragHandler);
|
|
|
27583 |
editor.on('mouseup', dropHandler);
|
|
|
27584 |
pageDom.bind(rootDocument, 'mousemove', dragHandler);
|
|
|
27585 |
pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
|
|
|
27586 |
editor.on('remove', () => {
|
|
|
27587 |
pageDom.unbind(rootDocument, 'mousemove', dragHandler);
|
|
|
27588 |
pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
|
|
|
27589 |
});
|
|
|
27590 |
editor.on('keydown', e => {
|
|
|
27591 |
if (e.keyCode === VK.ESC) {
|
|
|
27592 |
stopDragging(state, editor, Optional.none());
|
|
|
27593 |
}
|
|
|
27594 |
});
|
|
|
27595 |
};
|
|
|
27596 |
const blockUnsupportedFileDrop = editor => {
|
|
|
27597 |
const preventFileDrop = e => {
|
|
|
27598 |
if (!e.isDefaultPrevented()) {
|
|
|
27599 |
const dataTransfer = e.dataTransfer;
|
|
|
27600 |
if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) {
|
|
|
27601 |
e.preventDefault();
|
|
|
27602 |
if (e.type === 'drop') {
|
|
|
27603 |
displayError(editor, 'Dropped file type is not supported');
|
|
|
27604 |
}
|
|
|
27605 |
}
|
|
|
27606 |
}
|
|
|
27607 |
};
|
|
|
27608 |
const preventFileDropIfUIElement = e => {
|
|
|
27609 |
if (isUIElement(editor, e.target)) {
|
|
|
27610 |
preventFileDrop(e);
|
|
|
27611 |
}
|
|
|
27612 |
};
|
|
|
27613 |
const setup = () => {
|
|
|
27614 |
const pageDom = DOMUtils.DOM;
|
|
|
27615 |
const dom = editor.dom;
|
|
|
27616 |
const doc = document;
|
|
|
27617 |
const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
|
|
|
27618 |
const eventNames = [
|
|
|
27619 |
'drop',
|
|
|
27620 |
'dragover'
|
|
|
27621 |
];
|
|
|
27622 |
each$e(eventNames, name => {
|
|
|
27623 |
pageDom.bind(doc, name, preventFileDropIfUIElement);
|
|
|
27624 |
dom.bind(editorRoot, name, preventFileDrop);
|
|
|
27625 |
});
|
|
|
27626 |
editor.on('remove', () => {
|
|
|
27627 |
each$e(eventNames, name => {
|
|
|
27628 |
pageDom.unbind(doc, name, preventFileDropIfUIElement);
|
|
|
27629 |
dom.unbind(editorRoot, name, preventFileDrop);
|
|
|
27630 |
});
|
|
|
27631 |
});
|
|
|
27632 |
};
|
|
|
27633 |
editor.on('init', () => {
|
|
|
27634 |
Delay.setEditorTimeout(editor, setup, 0);
|
|
|
27635 |
});
|
|
|
27636 |
};
|
|
|
27637 |
const init$2 = editor => {
|
|
|
27638 |
bindFakeDragEvents(editor);
|
|
|
27639 |
if (shouldBlockUnsupportedDrop(editor)) {
|
|
|
27640 |
blockUnsupportedFileDrop(editor);
|
|
|
27641 |
}
|
|
|
27642 |
};
|
|
|
27643 |
|
|
|
27644 |
const setup$4 = editor => {
|
|
|
27645 |
const renderFocusCaret = first$1(() => {
|
|
|
27646 |
if (!editor.removed && editor.getBody().contains(document.activeElement)) {
|
|
|
27647 |
const rng = editor.selection.getRng();
|
|
|
27648 |
if (rng.collapsed) {
|
|
|
27649 |
const caretRange = renderRangeCaret(editor, rng, false);
|
|
|
27650 |
editor.selection.setRng(caretRange);
|
|
|
27651 |
}
|
|
|
27652 |
}
|
|
|
27653 |
}, 0);
|
|
|
27654 |
editor.on('focus', () => {
|
|
|
27655 |
renderFocusCaret.throttle();
|
|
|
27656 |
});
|
|
|
27657 |
editor.on('blur', () => {
|
|
|
27658 |
renderFocusCaret.cancel();
|
|
|
27659 |
});
|
|
|
27660 |
};
|
|
|
27661 |
|
|
|
27662 |
const setup$3 = editor => {
|
|
|
27663 |
editor.on('init', () => {
|
|
|
27664 |
editor.on('focusin', e => {
|
|
|
27665 |
const target = e.target;
|
|
|
27666 |
if (isMedia$2(target)) {
|
|
|
27667 |
const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
|
|
|
27668 |
const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target;
|
|
|
27669 |
if (editor.selection.getNode() !== node) {
|
|
|
27670 |
selectNode(editor, node).each(rng => editor.selection.setRng(rng));
|
|
|
27671 |
}
|
|
|
27672 |
}
|
|
|
27673 |
});
|
|
|
27674 |
});
|
|
|
27675 |
};
|
|
|
27676 |
|
|
|
27677 |
const isContentEditableFalse = isContentEditableFalse$b;
|
|
|
27678 |
const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
|
|
|
27679 |
const SelectionOverrides = editor => {
|
|
|
27680 |
const selection = editor.selection, dom = editor.dom;
|
|
|
27681 |
const rootNode = editor.getBody();
|
|
|
27682 |
const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor));
|
|
|
27683 |
const realSelectionId = 'sel-' + dom.uniqueId();
|
|
|
27684 |
const elementSelectionAttr = 'data-mce-selected';
|
|
|
27685 |
let selectedElement;
|
|
|
27686 |
const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection');
|
|
|
27687 |
const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode) && dom.isEditable(node.parentNode);
|
|
|
27688 |
const setRange = range => {
|
|
|
27689 |
if (range) {
|
|
|
27690 |
selection.setRng(range);
|
|
|
27691 |
}
|
|
|
27692 |
};
|
|
|
27693 |
const showCaret = (direction, node, before, scrollIntoView = true) => {
|
|
|
27694 |
const e = editor.dispatch('ShowCaret', {
|
|
|
27695 |
target: node,
|
|
|
27696 |
direction,
|
|
|
27697 |
before
|
|
|
27698 |
});
|
|
|
27699 |
if (e.isDefaultPrevented()) {
|
|
|
27700 |
return null;
|
|
|
27701 |
}
|
|
|
27702 |
if (scrollIntoView) {
|
|
|
27703 |
selection.scrollIntoView(node, direction === -1);
|
|
|
27704 |
}
|
|
|
27705 |
return fakeCaret.show(before, node);
|
|
|
27706 |
};
|
|
|
27707 |
const showBlockCaretContainer = blockCaretContainer => {
|
|
|
27708 |
if (blockCaretContainer.hasAttribute('data-mce-caret')) {
|
|
|
27709 |
showCaretContainerBlock(blockCaretContainer);
|
|
|
27710 |
selection.scrollIntoView(blockCaretContainer);
|
|
|
27711 |
}
|
|
|
27712 |
};
|
|
|
27713 |
const registerEvents = () => {
|
|
|
27714 |
editor.on('click', e => {
|
|
|
27715 |
if (!dom.isEditable(e.target)) {
|
|
|
27716 |
e.preventDefault();
|
|
|
27717 |
editor.focus();
|
|
|
27718 |
}
|
|
|
27719 |
});
|
|
|
27720 |
editor.on('blur NewBlock', removeElementSelection);
|
|
|
27721 |
editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition);
|
|
|
27722 |
editor.on('tap', e => {
|
|
|
27723 |
const targetElm = e.target;
|
|
|
27724 |
const contentEditableRoot = getContentEditableRoot(editor, targetElm);
|
|
|
27725 |
if (isContentEditableFalse(contentEditableRoot)) {
|
|
|
27726 |
e.preventDefault();
|
|
|
27727 |
selectNode(editor, contentEditableRoot).each(setElementSelection);
|
|
|
27728 |
} else if (isFakeSelectionTargetElement(targetElm)) {
|
|
|
27729 |
selectNode(editor, targetElm).each(setElementSelection);
|
|
|
27730 |
}
|
|
|
27731 |
}, true);
|
|
|
27732 |
editor.on('mousedown', e => {
|
|
|
27733 |
const targetElm = e.target;
|
|
|
27734 |
if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) {
|
|
|
27735 |
return;
|
|
|
27736 |
}
|
|
|
27737 |
if (!isXYInContentArea(editor, e.clientX, e.clientY)) {
|
|
|
27738 |
return;
|
|
|
27739 |
}
|
|
|
27740 |
removeElementSelection();
|
|
|
27741 |
hideFakeCaret();
|
|
|
27742 |
const closestContentEditable = getContentEditableRoot(editor, targetElm);
|
|
|
27743 |
if (isContentEditableFalse(closestContentEditable)) {
|
|
|
27744 |
e.preventDefault();
|
|
|
27745 |
selectNode(editor, closestContentEditable).each(setElementSelection);
|
|
|
27746 |
} else {
|
|
|
27747 |
closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => {
|
|
|
27748 |
e.preventDefault();
|
|
|
27749 |
const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
|
|
|
27750 |
setRange(range);
|
|
|
27751 |
if (isHTMLElement(closestContentEditable)) {
|
|
|
27752 |
closestContentEditable.focus();
|
|
|
27753 |
} else {
|
|
|
27754 |
editor.getBody().focus();
|
|
|
27755 |
}
|
|
|
27756 |
});
|
|
|
27757 |
}
|
|
|
27758 |
});
|
|
|
27759 |
editor.on('keypress', e => {
|
|
|
27760 |
if (VK.modifierPressed(e)) {
|
|
|
27761 |
return;
|
|
|
27762 |
}
|
|
|
27763 |
if (isContentEditableFalse(selection.getNode())) {
|
|
|
27764 |
e.preventDefault();
|
|
|
27765 |
}
|
|
|
27766 |
});
|
|
|
27767 |
editor.on('GetSelectionRange', e => {
|
|
|
27768 |
let rng = e.range;
|
|
|
27769 |
if (selectedElement) {
|
|
|
27770 |
if (!selectedElement.parentNode) {
|
|
|
27771 |
selectedElement = null;
|
|
|
27772 |
return;
|
|
|
27773 |
}
|
|
|
27774 |
rng = rng.cloneRange();
|
|
|
27775 |
rng.selectNode(selectedElement);
|
|
|
27776 |
e.range = rng;
|
|
|
27777 |
}
|
|
|
27778 |
});
|
|
|
27779 |
editor.on('SetSelectionRange', e => {
|
|
|
27780 |
e.range = normalizeVoidElementSelection(e.range);
|
|
|
27781 |
const rng = setElementSelection(e.range, e.forward);
|
|
|
27782 |
if (rng) {
|
|
|
27783 |
e.range = rng;
|
|
|
27784 |
}
|
|
|
27785 |
});
|
|
|
27786 |
const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin';
|
|
|
27787 |
editor.on('AfterSetSelectionRange', e => {
|
|
|
27788 |
const rng = e.range;
|
|
|
27789 |
const parent = rng.startContainer.parentElement;
|
|
|
27790 |
if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) {
|
|
|
27791 |
hideFakeCaret();
|
|
|
27792 |
}
|
|
|
27793 |
if (!isFakeSelectionElement(parent)) {
|
|
|
27794 |
removeElementSelection();
|
|
|
27795 |
}
|
|
|
27796 |
});
|
|
|
27797 |
init$2(editor);
|
|
|
27798 |
setup$4(editor);
|
|
|
27799 |
setup$3(editor);
|
|
|
27800 |
};
|
|
|
27801 |
const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
|
|
|
27802 |
const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
|
|
|
27803 |
const normalizeVoidElementSelection = rng => {
|
|
|
27804 |
const voidElements = editor.schema.getVoidElements();
|
|
|
27805 |
const newRng = dom.createRng();
|
|
|
27806 |
const startContainer = rng.startContainer;
|
|
|
27807 |
const startOffset = rng.startOffset;
|
|
|
27808 |
const endContainer = rng.endContainer;
|
|
|
27809 |
const endOffset = rng.endOffset;
|
|
|
27810 |
if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
|
|
|
27811 |
if (startOffset === 0) {
|
|
|
27812 |
newRng.setStartBefore(startContainer);
|
|
|
27813 |
} else {
|
|
|
27814 |
newRng.setStartAfter(startContainer);
|
|
|
27815 |
}
|
|
|
27816 |
} else {
|
|
|
27817 |
newRng.setStart(startContainer, startOffset);
|
|
|
27818 |
}
|
|
|
27819 |
if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
|
|
|
27820 |
if (endOffset === 0) {
|
|
|
27821 |
newRng.setEndBefore(endContainer);
|
|
|
27822 |
} else {
|
|
|
27823 |
newRng.setEndAfter(endContainer);
|
|
|
27824 |
}
|
|
|
27825 |
} else {
|
|
|
27826 |
newRng.setEnd(endContainer, endOffset);
|
|
|
27827 |
}
|
|
|
27828 |
return newRng;
|
|
|
27829 |
};
|
|
|
27830 |
const setupOffscreenSelection = (node, targetClone) => {
|
|
|
27831 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
27832 |
const doc = editor.getDoc();
|
|
|
27833 |
const realSelectionContainer = descendant$1(body, '#' + realSelectionId).getOrThunk(() => {
|
|
|
27834 |
const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc);
|
| 1441 |
ariadna |
27835 |
set$4(newContainer, 'id', realSelectionId);
|
| 1 |
efrain |
27836 |
append$1(body, newContainer);
|
|
|
27837 |
return newContainer;
|
|
|
27838 |
});
|
|
|
27839 |
const newRange = dom.createRng();
|
|
|
27840 |
empty(realSelectionContainer);
|
|
|
27841 |
append(realSelectionContainer, [
|
|
|
27842 |
SugarElement.fromText(nbsp, doc),
|
|
|
27843 |
SugarElement.fromDom(targetClone),
|
|
|
27844 |
SugarElement.fromText(nbsp, doc)
|
|
|
27845 |
]);
|
|
|
27846 |
newRange.setStart(realSelectionContainer.dom.firstChild, 1);
|
|
|
27847 |
newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
|
|
|
27848 |
setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' });
|
|
|
27849 |
focus$1(realSelectionContainer);
|
|
|
27850 |
const sel = selection.getSel();
|
|
|
27851 |
if (sel) {
|
|
|
27852 |
sel.removeAllRanges();
|
|
|
27853 |
sel.addRange(newRange);
|
|
|
27854 |
}
|
|
|
27855 |
return newRange;
|
|
|
27856 |
};
|
|
|
27857 |
const selectElement = elm => {
|
|
|
27858 |
const targetClone = elm.cloneNode(true);
|
|
|
27859 |
const e = editor.dispatch('ObjectSelected', {
|
|
|
27860 |
target: elm,
|
|
|
27861 |
targetClone
|
|
|
27862 |
});
|
|
|
27863 |
if (e.isDefaultPrevented()) {
|
|
|
27864 |
return null;
|
|
|
27865 |
}
|
|
|
27866 |
const range = setupOffscreenSelection(elm, e.targetClone);
|
|
|
27867 |
const nodeElm = SugarElement.fromDom(elm);
|
|
|
27868 |
each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => {
|
|
|
27869 |
if (!eq(nodeElm, elm)) {
|
| 1441 |
ariadna |
27870 |
remove$9(elm, elementSelectionAttr);
|
| 1 |
efrain |
27871 |
}
|
|
|
27872 |
});
|
|
|
27873 |
if (!dom.getAttrib(elm, elementSelectionAttr)) {
|
|
|
27874 |
elm.setAttribute(elementSelectionAttr, '1');
|
|
|
27875 |
}
|
|
|
27876 |
selectedElement = elm;
|
|
|
27877 |
hideFakeCaret();
|
|
|
27878 |
return range;
|
|
|
27879 |
};
|
|
|
27880 |
const setElementSelection = (range, forward) => {
|
|
|
27881 |
if (!range) {
|
|
|
27882 |
return null;
|
|
|
27883 |
}
|
|
|
27884 |
if (range.collapsed) {
|
|
|
27885 |
if (!isRangeInCaretContainer(range)) {
|
|
|
27886 |
const dir = forward ? 1 : -1;
|
|
|
27887 |
const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range);
|
|
|
27888 |
const beforeNode = caretPosition.getNode(!forward);
|
|
|
27889 |
if (isNonNullable(beforeNode)) {
|
|
|
27890 |
if (isFakeCaretTarget(beforeNode)) {
|
|
|
27891 |
return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
|
|
|
27892 |
}
|
|
|
27893 |
if (isCaretContainerInline(beforeNode) && isContentEditableFalse$b(beforeNode.nextSibling)) {
|
|
|
27894 |
const rng = dom.createRng();
|
|
|
27895 |
rng.setStart(beforeNode, 0);
|
|
|
27896 |
rng.setEnd(beforeNode, 0);
|
|
|
27897 |
return rng;
|
|
|
27898 |
}
|
|
|
27899 |
}
|
|
|
27900 |
const afterNode = caretPosition.getNode(forward);
|
|
|
27901 |
if (isNonNullable(afterNode)) {
|
|
|
27902 |
if (isFakeCaretTarget(afterNode)) {
|
|
|
27903 |
return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
|
|
|
27904 |
}
|
|
|
27905 |
if (isCaretContainerInline(afterNode) && isContentEditableFalse$b(afterNode.previousSibling)) {
|
|
|
27906 |
const rng = dom.createRng();
|
|
|
27907 |
rng.setStart(afterNode, 1);
|
|
|
27908 |
rng.setEnd(afterNode, 1);
|
|
|
27909 |
return rng;
|
|
|
27910 |
}
|
|
|
27911 |
}
|
|
|
27912 |
}
|
|
|
27913 |
return null;
|
|
|
27914 |
}
|
|
|
27915 |
let startContainer = range.startContainer;
|
|
|
27916 |
let startOffset = range.startOffset;
|
|
|
27917 |
const endOffset = range.endOffset;
|
| 1441 |
ariadna |
27918 |
if (isText$b(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
|
| 1 |
efrain |
27919 |
startContainer = startContainer.parentNode;
|
|
|
27920 |
startOffset = dom.nodeIndex(startContainer);
|
|
|
27921 |
startContainer = startContainer.parentNode;
|
|
|
27922 |
}
|
|
|
27923 |
if (!isElement$6(startContainer)) {
|
|
|
27924 |
return null;
|
|
|
27925 |
}
|
|
|
27926 |
if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
|
|
|
27927 |
const node = startContainer.childNodes[startOffset];
|
|
|
27928 |
if (isFakeSelectionTargetElement(node)) {
|
|
|
27929 |
return selectElement(node);
|
|
|
27930 |
}
|
|
|
27931 |
}
|
|
|
27932 |
return null;
|
|
|
27933 |
};
|
|
|
27934 |
const removeElementSelection = () => {
|
|
|
27935 |
if (selectedElement) {
|
|
|
27936 |
selectedElement.removeAttribute(elementSelectionAttr);
|
|
|
27937 |
}
|
| 1441 |
ariadna |
27938 |
descendant$1(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$4);
|
| 1 |
efrain |
27939 |
selectedElement = null;
|
|
|
27940 |
};
|
|
|
27941 |
const destroy = () => {
|
|
|
27942 |
fakeCaret.destroy();
|
|
|
27943 |
selectedElement = null;
|
|
|
27944 |
};
|
|
|
27945 |
const hideFakeCaret = () => {
|
|
|
27946 |
fakeCaret.hide();
|
|
|
27947 |
};
|
|
|
27948 |
if (!isRtc(editor)) {
|
|
|
27949 |
registerEvents();
|
|
|
27950 |
}
|
|
|
27951 |
return {
|
|
|
27952 |
showCaret,
|
|
|
27953 |
showBlockCaretContainer,
|
|
|
27954 |
hideFakeCaret,
|
|
|
27955 |
destroy
|
|
|
27956 |
};
|
|
|
27957 |
};
|
|
|
27958 |
|
|
|
27959 |
const getNormalizedTextOffset = (container, offset) => {
|
|
|
27960 |
let normalizedOffset = offset;
|
| 1441 |
ariadna |
27961 |
for (let node = container.previousSibling; isText$b(node); node = node.previousSibling) {
|
| 1 |
efrain |
27962 |
normalizedOffset += node.data.length;
|
|
|
27963 |
}
|
|
|
27964 |
return normalizedOffset;
|
|
|
27965 |
};
|
|
|
27966 |
const generatePath = (dom, root, node, offset, normalized) => {
|
| 1441 |
ariadna |
27967 |
if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
|
| 1 |
efrain |
27968 |
return [];
|
|
|
27969 |
}
|
| 1441 |
ariadna |
27970 |
const p = normalized && isText$b(node) ? [getNormalizedTextOffset(node, offset)] : [offset];
|
| 1 |
efrain |
27971 |
let current = node;
|
|
|
27972 |
while (current !== root && current.parentNode) {
|
|
|
27973 |
p.push(dom.nodeIndex(current, normalized));
|
|
|
27974 |
current = current.parentNode;
|
|
|
27975 |
}
|
|
|
27976 |
return current === root ? p.reverse() : [];
|
|
|
27977 |
};
|
|
|
27978 |
const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => {
|
|
|
27979 |
const start = generatePath(dom, root, startNode, startOffset, normalized);
|
|
|
27980 |
const end = generatePath(dom, root, endNode, endOffset, normalized);
|
|
|
27981 |
return {
|
|
|
27982 |
start,
|
|
|
27983 |
end
|
|
|
27984 |
};
|
|
|
27985 |
};
|
|
|
27986 |
const resolvePath = (root, path) => {
|
|
|
27987 |
const nodePath = path.slice();
|
|
|
27988 |
const offset = nodePath.pop();
|
|
|
27989 |
if (!isNumber(offset)) {
|
|
|
27990 |
return Optional.none();
|
|
|
27991 |
} else {
|
|
|
27992 |
const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root));
|
|
|
27993 |
return resolvedNode.bind(node => {
|
| 1441 |
ariadna |
27994 |
if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
|
| 1 |
efrain |
27995 |
return Optional.none();
|
|
|
27996 |
} else {
|
|
|
27997 |
return Optional.some({
|
|
|
27998 |
node,
|
|
|
27999 |
offset
|
|
|
28000 |
});
|
|
|
28001 |
}
|
|
|
28002 |
});
|
|
|
28003 |
}
|
|
|
28004 |
};
|
|
|
28005 |
const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({
|
|
|
28006 |
node: startNode,
|
|
|
28007 |
offset: startOffset
|
|
|
28008 |
}) => resolvePath(root, range.end).map(({
|
|
|
28009 |
node: endNode,
|
|
|
28010 |
offset: endOffset
|
|
|
28011 |
}) => {
|
|
|
28012 |
const rng = document.createRange();
|
|
|
28013 |
rng.setStart(startNode, startOffset);
|
|
|
28014 |
rng.setEnd(endNode, endOffset);
|
|
|
28015 |
return rng;
|
|
|
28016 |
}));
|
|
|
28017 |
const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized);
|
|
|
28018 |
|
|
|
28019 |
const cleanEmptyNodes = (dom, node, isRoot) => {
|
|
|
28020 |
if (node && dom.isEmpty(node) && !isRoot(node)) {
|
|
|
28021 |
const parent = node.parentNode;
|
| 1441 |
ariadna |
28022 |
dom.remove(node, isText$b(node.firstChild) && isWhitespaceText(node.firstChild.data));
|
| 1 |
efrain |
28023 |
cleanEmptyNodes(dom, parent, isRoot);
|
|
|
28024 |
}
|
|
|
28025 |
};
|
|
|
28026 |
const deleteRng = (dom, rng, isRoot, clean = true) => {
|
|
|
28027 |
const startParent = rng.startContainer.parentNode;
|
|
|
28028 |
const endParent = rng.endContainer.parentNode;
|
|
|
28029 |
rng.deleteContents();
|
|
|
28030 |
if (clean && !isRoot(rng.startContainer)) {
|
| 1441 |
ariadna |
28031 |
if (isText$b(rng.startContainer) && rng.startContainer.data.length === 0) {
|
| 1 |
efrain |
28032 |
dom.remove(rng.startContainer);
|
|
|
28033 |
}
|
| 1441 |
ariadna |
28034 |
if (isText$b(rng.endContainer) && rng.endContainer.data.length === 0) {
|
| 1 |
efrain |
28035 |
dom.remove(rng.endContainer);
|
|
|
28036 |
}
|
|
|
28037 |
cleanEmptyNodes(dom, startParent, isRoot);
|
|
|
28038 |
if (startParent !== endParent) {
|
|
|
28039 |
cleanEmptyNodes(dom, endParent, isRoot);
|
|
|
28040 |
}
|
|
|
28041 |
}
|
|
|
28042 |
};
|
|
|
28043 |
const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
|
|
|
28044 |
const resolveFromDynamicPatterns = (patternSet, block, beforeText) => {
|
|
|
28045 |
const dynamicPatterns = patternSet.dynamicPatternsLookup({
|
|
|
28046 |
text: beforeText,
|
|
|
28047 |
block
|
|
|
28048 |
});
|
|
|
28049 |
return {
|
|
|
28050 |
...patternSet,
|
|
|
28051 |
blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns),
|
|
|
28052 |
inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns)
|
|
|
28053 |
};
|
|
|
28054 |
};
|
|
|
28055 |
const getBeforeText = (dom, block, node, offset) => {
|
|
|
28056 |
const rng = dom.createRng();
|
|
|
28057 |
rng.setStart(block, 0);
|
|
|
28058 |
rng.setEnd(node, offset);
|
|
|
28059 |
return rng.toString();
|
|
|
28060 |
};
|
|
|
28061 |
|
|
|
28062 |
const newMarker = (dom, id) => dom.create('span', {
|
|
|
28063 |
'data-mce-type': 'bookmark',
|
|
|
28064 |
id
|
|
|
28065 |
});
|
|
|
28066 |
const rangeFromMarker = (dom, marker) => {
|
|
|
28067 |
const rng = dom.createRng();
|
|
|
28068 |
rng.setStartAfter(marker.start);
|
|
|
28069 |
rng.setEndBefore(marker.end);
|
|
|
28070 |
return rng;
|
|
|
28071 |
};
|
|
|
28072 |
const createMarker = (dom, markerPrefix, pathRange) => {
|
|
|
28073 |
const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range');
|
|
|
28074 |
const startNode = rng.startContainer;
|
|
|
28075 |
const endNode = rng.endContainer;
|
|
|
28076 |
const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
|
|
|
28077 |
const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
|
|
|
28078 |
const startParentNode = textStart.parentNode;
|
|
|
28079 |
const endParentNode = textEnd.parentNode;
|
|
|
28080 |
return {
|
|
|
28081 |
prefix: markerPrefix,
|
|
|
28082 |
end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd),
|
|
|
28083 |
start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart)
|
|
|
28084 |
};
|
|
|
28085 |
};
|
|
|
28086 |
const removeMarker = (dom, marker, isRoot) => {
|
|
|
28087 |
cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot);
|
|
|
28088 |
cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot);
|
|
|
28089 |
};
|
|
|
28090 |
|
|
|
28091 |
const isReplacementPattern = pattern => pattern.start.length === 0;
|
|
|
28092 |
const matchesPattern = patternContent => (element, offset) => {
|
|
|
28093 |
const text = element.data;
|
|
|
28094 |
const searchText = text.substring(0, offset);
|
|
|
28095 |
const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
|
|
|
28096 |
const startIndex = searchText.lastIndexOf(patternContent);
|
|
|
28097 |
if (startIndex !== -1) {
|
|
|
28098 |
return startIndex + patternContent.length;
|
|
|
28099 |
} else if (startEndIndex !== -1) {
|
|
|
28100 |
return startEndIndex + 1;
|
|
|
28101 |
} else {
|
|
|
28102 |
return -1;
|
|
|
28103 |
}
|
|
|
28104 |
};
|
|
|
28105 |
const findPatternStartFromSpot = (dom, pattern, block, spot) => {
|
|
|
28106 |
const startPattern = pattern.start;
|
|
|
28107 |
const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block);
|
|
|
28108 |
return startSpot.bind(spot => {
|
|
|
28109 |
var _a, _b;
|
|
|
28110 |
const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1;
|
|
|
28111 |
const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length;
|
|
|
28112 |
if (isCompleteMatch) {
|
|
|
28113 |
const rng = dom.createRng();
|
|
|
28114 |
rng.setStart(spot.container, spot.offset - startPattern.length);
|
|
|
28115 |
rng.setEnd(spot.container, spot.offset);
|
|
|
28116 |
return Optional.some(rng);
|
|
|
28117 |
} else {
|
|
|
28118 |
const offset = spot.offset - startPattern.length;
|
|
|
28119 |
return scanLeft(spot.container, offset, block).map(nextSpot => {
|
|
|
28120 |
const rng = dom.createRng();
|
|
|
28121 |
rng.setStart(nextSpot.container, nextSpot.offset);
|
|
|
28122 |
rng.setEnd(spot.container, spot.offset);
|
|
|
28123 |
return rng;
|
|
|
28124 |
}).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0)));
|
|
|
28125 |
}
|
|
|
28126 |
});
|
|
|
28127 |
};
|
|
|
28128 |
const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => {
|
|
|
28129 |
if (pattern.start.length === 0 && !requireGap) {
|
|
|
28130 |
const rng = dom.createRng();
|
|
|
28131 |
rng.setStart(node, offset);
|
|
|
28132 |
rng.setEnd(node, offset);
|
|
|
28133 |
return Optional.some(rng);
|
|
|
28134 |
}
|
|
|
28135 |
return textBefore(node, offset, block).bind(spot => {
|
|
|
28136 |
const start = findPatternStartFromSpot(dom, pattern, block, spot);
|
|
|
28137 |
return start.bind(startRange => {
|
|
|
28138 |
var _a;
|
|
|
28139 |
if (requireGap) {
|
|
|
28140 |
if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
|
|
|
28141 |
return Optional.none();
|
|
|
28142 |
} else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) {
|
|
|
28143 |
return Optional.none();
|
|
|
28144 |
}
|
|
|
28145 |
}
|
|
|
28146 |
return Optional.some(startRange);
|
|
|
28147 |
});
|
|
|
28148 |
});
|
|
|
28149 |
};
|
| 1441 |
ariadna |
28150 |
const findPattern$3 = (editor, block, details, normalizedMatches) => {
|
| 1 |
efrain |
28151 |
const dom = editor.dom;
|
|
|
28152 |
const root = dom.getRoot();
|
|
|
28153 |
const pattern = details.pattern;
|
|
|
28154 |
const endNode = details.position.container;
|
|
|
28155 |
const endOffset = details.position.offset;
|
|
|
28156 |
return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => {
|
|
|
28157 |
const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches);
|
|
|
28158 |
if (isReplacementPattern(pattern)) {
|
|
|
28159 |
return Optional.some({
|
|
|
28160 |
matches: [{
|
|
|
28161 |
pattern,
|
|
|
28162 |
startRng: endPathRng,
|
|
|
28163 |
endRng: endPathRng
|
|
|
28164 |
}],
|
|
|
28165 |
position: spot
|
|
|
28166 |
});
|
|
|
28167 |
} else {
|
|
|
28168 |
const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches);
|
|
|
28169 |
const results = resultsOpt.getOr({
|
|
|
28170 |
matches: [],
|
|
|
28171 |
position: spot
|
|
|
28172 |
});
|
|
|
28173 |
const pos = results.position;
|
|
|
28174 |
const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
|
|
|
28175 |
return start.map(startRng => {
|
|
|
28176 |
const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches);
|
|
|
28177 |
return {
|
|
|
28178 |
matches: results.matches.concat([{
|
|
|
28179 |
pattern,
|
|
|
28180 |
startRng: startPathRng,
|
|
|
28181 |
endRng: endPathRng
|
|
|
28182 |
}]),
|
|
|
28183 |
position: point(startRng.startContainer, startRng.startOffset)
|
|
|
28184 |
};
|
|
|
28185 |
});
|
|
|
28186 |
}
|
|
|
28187 |
});
|
|
|
28188 |
};
|
|
|
28189 |
const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => {
|
|
|
28190 |
const dom = editor.dom;
|
|
|
28191 |
return textBefore(node, offset, dom.getRoot()).bind(endSpot => {
|
|
|
28192 |
const text = getBeforeText(dom, block, node, offset);
|
|
|
28193 |
for (let i = 0; i < patterns.length; i++) {
|
|
|
28194 |
const pattern = patterns[i];
|
|
|
28195 |
if (!endsWith(text, pattern.end)) {
|
|
|
28196 |
continue;
|
|
|
28197 |
}
|
|
|
28198 |
const patternsWithoutCurrent = patterns.slice();
|
|
|
28199 |
patternsWithoutCurrent.splice(i, 1);
|
| 1441 |
ariadna |
28200 |
const result = findPattern$3(editor, block, {
|
| 1 |
efrain |
28201 |
pattern,
|
|
|
28202 |
remainingPatterns: patternsWithoutCurrent,
|
|
|
28203 |
position: endSpot
|
|
|
28204 |
}, normalizedMatches);
|
|
|
28205 |
if (result.isNone() && offset > 0) {
|
|
|
28206 |
return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches);
|
|
|
28207 |
}
|
|
|
28208 |
if (result.isSome()) {
|
|
|
28209 |
return result;
|
|
|
28210 |
}
|
|
|
28211 |
}
|
|
|
28212 |
return Optional.none();
|
|
|
28213 |
});
|
|
|
28214 |
};
|
| 1441 |
ariadna |
28215 |
const applyPattern$2 = (editor, pattern, patternRange) => {
|
| 1 |
efrain |
28216 |
editor.selection.setRng(patternRange);
|
|
|
28217 |
if (pattern.type === 'inline-format') {
|
|
|
28218 |
each$e(pattern.format, format => {
|
|
|
28219 |
editor.formatter.apply(format);
|
|
|
28220 |
});
|
|
|
28221 |
} else {
|
|
|
28222 |
editor.execCommand(pattern.cmd, false, pattern.value);
|
|
|
28223 |
}
|
|
|
28224 |
};
|
|
|
28225 |
const applyReplacementPattern = (editor, pattern, marker, isRoot) => {
|
|
|
28226 |
const markerRange = rangeFromMarker(editor.dom, marker);
|
|
|
28227 |
deleteRng(editor.dom, markerRange, isRoot);
|
| 1441 |
ariadna |
28228 |
applyPattern$2(editor, pattern, markerRange);
|
| 1 |
efrain |
28229 |
};
|
|
|
28230 |
const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => {
|
|
|
28231 |
const dom = editor.dom;
|
|
|
28232 |
const markerEndRange = rangeFromMarker(dom, endMarker);
|
|
|
28233 |
const markerStartRange = rangeFromMarker(dom, startMarker);
|
|
|
28234 |
deleteRng(dom, markerStartRange, isRoot);
|
|
|
28235 |
deleteRng(dom, markerEndRange, isRoot);
|
|
|
28236 |
const patternMarker = {
|
|
|
28237 |
prefix: startMarker.prefix,
|
|
|
28238 |
start: startMarker.end,
|
|
|
28239 |
end: endMarker.start
|
|
|
28240 |
};
|
|
|
28241 |
const patternRange = rangeFromMarker(dom, patternMarker);
|
| 1441 |
ariadna |
28242 |
applyPattern$2(editor, pattern, patternRange);
|
| 1 |
efrain |
28243 |
};
|
|
|
28244 |
const addMarkers = (dom, matches) => {
|
|
|
28245 |
const markerPrefix = generate$1('mce_textpattern');
|
|
|
28246 |
const matchesWithEnds = foldr(matches, (acc, match) => {
|
|
|
28247 |
const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng);
|
|
|
28248 |
return acc.concat([{
|
|
|
28249 |
...match,
|
|
|
28250 |
endMarker
|
|
|
28251 |
}]);
|
|
|
28252 |
}, []);
|
|
|
28253 |
return foldr(matchesWithEnds, (acc, match) => {
|
|
|
28254 |
const idx = matchesWithEnds.length - acc.length - 1;
|
|
|
28255 |
const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng);
|
|
|
28256 |
return acc.concat([{
|
|
|
28257 |
...match,
|
|
|
28258 |
startMarker
|
|
|
28259 |
}]);
|
|
|
28260 |
}, []);
|
|
|
28261 |
};
|
| 1441 |
ariadna |
28262 |
const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.end.length - a.end.length);
|
| 1 |
efrain |
28263 |
const getBestMatches = (matches, matchesWithSortedPatterns) => {
|
|
|
28264 |
const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end));
|
|
|
28265 |
if (matches.length === matchesWithSortedPatterns.length) {
|
|
|
28266 |
if (hasSameMatches) {
|
|
|
28267 |
return matches;
|
|
|
28268 |
} else {
|
|
|
28269 |
return matchesWithSortedPatterns;
|
|
|
28270 |
}
|
|
|
28271 |
}
|
|
|
28272 |
return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns;
|
|
|
28273 |
};
|
| 1441 |
ariadna |
28274 |
const findPatterns$2 = (editor, block, node, offset, patternSet, normalizedMatches) => {
|
| 1 |
efrain |
28275 |
const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
|
| 1441 |
ariadna |
28276 |
const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns$1(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
|
| 1 |
efrain |
28277 |
return getBestMatches(matches, matchesWithSortedPatterns);
|
|
|
28278 |
};
|
| 1441 |
ariadna |
28279 |
const applyMatches$2 = (editor, matches) => {
|
| 1 |
efrain |
28280 |
if (matches.length === 0) {
|
|
|
28281 |
return;
|
|
|
28282 |
}
|
|
|
28283 |
const dom = editor.dom;
|
|
|
28284 |
const bookmark = editor.selection.getBookmark();
|
|
|
28285 |
const matchesWithMarkers = addMarkers(dom, matches);
|
|
|
28286 |
each$e(matchesWithMarkers, match => {
|
|
|
28287 |
const block = dom.getParent(match.startMarker.start, dom.isBlock);
|
|
|
28288 |
const isRoot = node => node === block;
|
|
|
28289 |
if (isReplacementPattern(match.pattern)) {
|
|
|
28290 |
applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot);
|
|
|
28291 |
} else {
|
|
|
28292 |
applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot);
|
|
|
28293 |
}
|
|
|
28294 |
removeMarker(dom, match.endMarker, isRoot);
|
|
|
28295 |
removeMarker(dom, match.startMarker, isRoot);
|
|
|
28296 |
});
|
|
|
28297 |
editor.selection.moveToBookmark(bookmark);
|
|
|
28298 |
};
|
|
|
28299 |
|
| 1441 |
ariadna |
28300 |
const stripPattern$1 = (dom, block, pattern) => {
|
|
|
28301 |
return textAfter(block, 0, block).map(spot => {
|
|
|
28302 |
const node = spot.container;
|
|
|
28303 |
scanRight(node, pattern.start.length, block).each(end => {
|
|
|
28304 |
const rng = dom.createRng();
|
|
|
28305 |
rng.setStart(node, 0);
|
|
|
28306 |
rng.setEnd(end.container, end.offset);
|
|
|
28307 |
deleteRng(dom, rng, e => e === block);
|
|
|
28308 |
});
|
|
|
28309 |
return node;
|
|
|
28310 |
});
|
|
|
28311 |
};
|
|
|
28312 |
const createApplyPattern = stripPattern => (editor, match) => {
|
|
|
28313 |
const dom = editor.dom;
|
|
|
28314 |
const pattern = match.pattern;
|
|
|
28315 |
const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range');
|
|
|
28316 |
const isBlockFormatName = (name, formatter) => {
|
|
|
28317 |
const formatSet = formatter.get(name);
|
|
|
28318 |
return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block'));
|
|
|
28319 |
};
|
|
|
28320 |
getParentBlock(editor, rng).each(block => {
|
|
|
28321 |
if (pattern.type === 'block-format') {
|
|
|
28322 |
if (isBlockFormatName(pattern.format, editor.formatter)) {
|
|
|
28323 |
editor.undoManager.transact(() => {
|
|
|
28324 |
stripPattern(editor.dom, block, pattern);
|
|
|
28325 |
editor.formatter.apply(pattern.format);
|
|
|
28326 |
});
|
|
|
28327 |
}
|
|
|
28328 |
} else if (pattern.type === 'block-command') {
|
|
|
28329 |
editor.undoManager.transact(() => {
|
|
|
28330 |
stripPattern(editor.dom, block, pattern);
|
|
|
28331 |
editor.execCommand(pattern.cmd, false, pattern.value);
|
|
|
28332 |
});
|
|
|
28333 |
}
|
|
|
28334 |
});
|
|
|
28335 |
return true;
|
|
|
28336 |
};
|
|
|
28337 |
const sortPatterns = patterns => sort(patterns, (a, b) => b.start.length - a.start.length);
|
|
|
28338 |
const findPattern$2 = predicate => (patterns, text) => {
|
|
|
28339 |
const sortedPatterns = sortPatterns(patterns);
|
|
|
28340 |
const nuText = text.replace(nbsp, ' ');
|
|
|
28341 |
return find$2(sortedPatterns, pattern => predicate(pattern, text, nuText));
|
|
|
28342 |
};
|
|
|
28343 |
const createFindPatterns = (findPattern, skipFullMatch) => (editor, block, patternSet, normalizedMatches, text) => {
|
|
|
28344 |
var _a;
|
|
|
28345 |
if (text === void 0) {
|
|
|
28346 |
text = (_a = block.textContent) !== null && _a !== void 0 ? _a : '';
|
|
|
28347 |
}
|
|
|
28348 |
const dom = editor.dom;
|
|
|
28349 |
const forcedRootBlock = getForcedRootBlock(editor);
|
|
|
28350 |
if (!dom.is(block, forcedRootBlock)) {
|
|
|
28351 |
return [];
|
|
|
28352 |
}
|
|
|
28353 |
return findPattern(patternSet.blockPatterns, text).map(pattern => {
|
|
|
28354 |
if (skipFullMatch && Tools.trim(text).length === pattern.start.length) {
|
|
|
28355 |
return [];
|
|
|
28356 |
}
|
|
|
28357 |
return [{
|
|
|
28358 |
pattern,
|
|
|
28359 |
range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches)
|
|
|
28360 |
}];
|
|
|
28361 |
}).getOr([]);
|
|
|
28362 |
};
|
|
|
28363 |
|
|
|
28364 |
const startsWithSingleSpace = s => /^\s[^\s]/.test(s);
|
|
|
28365 |
const stripPattern = (dom, block, pattern) => {
|
|
|
28366 |
stripPattern$1(dom, block, pattern).each(node => {
|
|
|
28367 |
const text = SugarElement.fromDom(node);
|
|
|
28368 |
const textContent = get$3(text);
|
|
|
28369 |
if (startsWithSingleSpace(textContent)) {
|
|
|
28370 |
set(text, textContent.slice(1));
|
|
|
28371 |
}
|
|
|
28372 |
});
|
|
|
28373 |
};
|
|
|
28374 |
const applyPattern$1 = createApplyPattern(stripPattern);
|
|
|
28375 |
const findPattern$1 = findPattern$2((pattern, text, nuText) => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
|
|
|
28376 |
const findPatterns$1 = createFindPatterns(findPattern$1, true);
|
|
|
28377 |
const getMatches$1 = (editor, patternSet) => {
|
| 1 |
efrain |
28378 |
const rng = editor.selection.getRng();
|
|
|
28379 |
return getParentBlock(editor, rng).map(block => {
|
|
|
28380 |
var _a;
|
|
|
28381 |
const offset = Math.max(0, rng.startOffset);
|
|
|
28382 |
const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : '');
|
| 1441 |
ariadna |
28383 |
const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, true);
|
| 1 |
efrain |
28384 |
const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true);
|
| 1441 |
ariadna |
28385 |
return {
|
|
|
28386 |
inlineMatches,
|
|
|
28387 |
blockMatches
|
|
|
28388 |
};
|
|
|
28389 |
}).filter(({inlineMatches, blockMatches}) => blockMatches.length > 0 || inlineMatches.length > 0);
|
| 1 |
efrain |
28390 |
};
|
| 1441 |
ariadna |
28391 |
const applyMatches$1 = (editor, matches) => {
|
|
|
28392 |
if (matches.length === 0) {
|
|
|
28393 |
return;
|
|
|
28394 |
}
|
|
|
28395 |
const bookmark = editor.selection.getBookmark();
|
|
|
28396 |
each$e(matches, match => applyPattern$1(editor, match));
|
|
|
28397 |
editor.selection.moveToBookmark(bookmark);
|
|
|
28398 |
};
|
|
|
28399 |
|
|
|
28400 |
const applyPattern = createApplyPattern(stripPattern$1);
|
|
|
28401 |
const findPattern = findPattern$2((pattern, text, nuText) => text === pattern.start || nuText === pattern.start);
|
|
|
28402 |
const findPatterns = createFindPatterns(findPattern, false);
|
|
|
28403 |
const getMatches = (editor, patternSet) => {
|
|
|
28404 |
const rng = editor.selection.getRng();
|
|
|
28405 |
return getParentBlock(editor, rng).map(block => {
|
|
|
28406 |
const offset = Math.max(0, rng.startOffset);
|
|
|
28407 |
const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
|
|
|
28408 |
const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
|
|
|
28409 |
return findPatterns(editor, block, dynamicPatternSet, false, beforeText);
|
|
|
28410 |
}).filter(matches => matches.length > 0);
|
|
|
28411 |
};
|
|
|
28412 |
const applyMatches = (editor, matches) => {
|
|
|
28413 |
each$e(matches, match => applyPattern(editor, match));
|
|
|
28414 |
};
|
|
|
28415 |
|
|
|
28416 |
const handleEnter = (editor, patternSet) => getMatches$1(editor, patternSet).fold(never, ({inlineMatches, blockMatches}) => {
|
|
|
28417 |
editor.undoManager.add();
|
|
|
28418 |
editor.undoManager.extra(() => {
|
|
|
28419 |
editor.execCommand('mceInsertNewLine');
|
|
|
28420 |
}, () => {
|
|
|
28421 |
insert$5(editor);
|
|
|
28422 |
applyMatches$2(editor, inlineMatches);
|
|
|
28423 |
applyMatches$1(editor, blockMatches);
|
|
|
28424 |
const range = editor.selection.getRng();
|
|
|
28425 |
const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot());
|
|
|
28426 |
editor.execCommand('mceInsertNewLine');
|
|
|
28427 |
spot.each(s => {
|
|
|
28428 |
const node = s.container;
|
|
|
28429 |
if (node.data.charAt(s.offset - 1) === zeroWidth) {
|
|
|
28430 |
node.deleteData(s.offset - 1, 1);
|
|
|
28431 |
cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot());
|
|
|
28432 |
}
|
|
|
28433 |
});
|
|
|
28434 |
});
|
|
|
28435 |
return true;
|
|
|
28436 |
});
|
| 1 |
efrain |
28437 |
const handleInlineKey = (editor, patternSet) => {
|
|
|
28438 |
const rng = editor.selection.getRng();
|
|
|
28439 |
getParentBlock(editor, rng).map(block => {
|
|
|
28440 |
const offset = Math.max(0, rng.startOffset - 1);
|
|
|
28441 |
const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
|
|
|
28442 |
const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
|
| 1441 |
ariadna |
28443 |
const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, false);
|
| 1 |
efrain |
28444 |
if (inlineMatches.length > 0) {
|
|
|
28445 |
editor.undoManager.transact(() => {
|
| 1441 |
ariadna |
28446 |
applyMatches$2(editor, inlineMatches);
|
| 1 |
efrain |
28447 |
});
|
|
|
28448 |
}
|
|
|
28449 |
});
|
|
|
28450 |
};
|
| 1441 |
ariadna |
28451 |
const handleBlockPatternOnSpace = (editor, patternSet) => getMatches(editor, patternSet).fold(never, matches => {
|
|
|
28452 |
editor.undoManager.transact(() => {
|
|
|
28453 |
applyMatches(editor, matches);
|
|
|
28454 |
});
|
|
|
28455 |
return true;
|
|
|
28456 |
});
|
| 1 |
efrain |
28457 |
const checkKeyEvent = (codes, event, predicate) => {
|
|
|
28458 |
for (let i = 0; i < codes.length; i++) {
|
|
|
28459 |
if (predicate(codes[i], event)) {
|
|
|
28460 |
return true;
|
|
|
28461 |
}
|
|
|
28462 |
}
|
|
|
28463 |
return false;
|
|
|
28464 |
};
|
|
|
28465 |
const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => {
|
|
|
28466 |
return code === event.keyCode && !VK.modifierPressed(event);
|
|
|
28467 |
});
|
|
|
28468 |
const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => {
|
|
|
28469 |
return chr.charCodeAt(0) === event.charCode;
|
|
|
28470 |
});
|
|
|
28471 |
|
|
|
28472 |
const setup$2 = editor => {
|
|
|
28473 |
const charCodes = [
|
|
|
28474 |
',',
|
|
|
28475 |
'.',
|
|
|
28476 |
';',
|
|
|
28477 |
':',
|
|
|
28478 |
'!',
|
|
|
28479 |
'?'
|
|
|
28480 |
];
|
|
|
28481 |
const keyCodes = [32];
|
| 1441 |
ariadna |
28482 |
const getPatternSet = () => createPatternSet(getTextPatterns(editor).filter(pattern => {
|
|
|
28483 |
if (pattern.type === 'inline-command' || pattern.type === 'block-command') {
|
|
|
28484 |
return editor.queryCommandSupported(pattern.cmd);
|
|
|
28485 |
}
|
|
|
28486 |
return true;
|
|
|
28487 |
}), getTextPatternsLookup(editor));
|
| 1 |
efrain |
28488 |
const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
|
|
|
28489 |
editor.on('keydown', e => {
|
| 1441 |
ariadna |
28490 |
if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed() && editor.selection.isEditable()) {
|
|
|
28491 |
const patternSet = filterByTrigger(getPatternSet(), 'enter');
|
| 1 |
efrain |
28492 |
const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
|
|
|
28493 |
if (hasPatterns && handleEnter(editor, patternSet)) {
|
|
|
28494 |
e.preventDefault();
|
|
|
28495 |
}
|
|
|
28496 |
}
|
|
|
28497 |
}, true);
|
| 1441 |
ariadna |
28498 |
editor.on('keydown', e => {
|
|
|
28499 |
if (e.keyCode === 32 && editor.selection.isCollapsed() && editor.selection.isEditable()) {
|
|
|
28500 |
const patternSet = filterByTrigger(getPatternSet(), 'space');
|
|
|
28501 |
const hasPatterns = patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
|
|
|
28502 |
if (hasPatterns && handleBlockPatternOnSpace(editor, patternSet)) {
|
|
|
28503 |
e.preventDefault();
|
|
|
28504 |
}
|
|
|
28505 |
}
|
|
|
28506 |
}, true);
|
| 1 |
efrain |
28507 |
const handleInlineTrigger = () => {
|
| 1441 |
ariadna |
28508 |
if (editor.selection.isCollapsed() && editor.selection.isEditable()) {
|
|
|
28509 |
const patternSet = filterByTrigger(getPatternSet(), 'space');
|
| 1 |
efrain |
28510 |
const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
|
|
|
28511 |
if (hasPatterns) {
|
|
|
28512 |
handleInlineKey(editor, patternSet);
|
|
|
28513 |
}
|
|
|
28514 |
}
|
|
|
28515 |
};
|
|
|
28516 |
editor.on('keyup', e => {
|
|
|
28517 |
if (checkKeyCode(keyCodes, e)) {
|
|
|
28518 |
handleInlineTrigger();
|
|
|
28519 |
}
|
|
|
28520 |
});
|
|
|
28521 |
editor.on('keypress', e => {
|
|
|
28522 |
if (checkCharCode(charCodes, e)) {
|
|
|
28523 |
Delay.setEditorTimeout(editor, handleInlineTrigger);
|
|
|
28524 |
}
|
|
|
28525 |
});
|
|
|
28526 |
};
|
|
|
28527 |
|
|
|
28528 |
const setup$1 = editor => {
|
|
|
28529 |
setup$2(editor);
|
|
|
28530 |
};
|
|
|
28531 |
|
|
|
28532 |
const Quirks = editor => {
|
|
|
28533 |
const each = Tools.each;
|
|
|
28534 |
const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser;
|
|
|
28535 |
const browser = Env.browser;
|
|
|
28536 |
const isGecko = browser.isFirefox();
|
|
|
28537 |
const isWebKit = browser.isChromium() || browser.isSafari();
|
|
|
28538 |
const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
|
|
|
28539 |
const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
|
|
28540 |
const setEditorCommandState = (cmd, state) => {
|
|
|
28541 |
try {
|
|
|
28542 |
editor.getDoc().execCommand(cmd, false, String(state));
|
| 1441 |
ariadna |
28543 |
} catch (_a) {
|
| 1 |
efrain |
28544 |
}
|
|
|
28545 |
};
|
|
|
28546 |
const isDefaultPrevented = e => {
|
|
|
28547 |
return e.isDefaultPrevented();
|
|
|
28548 |
};
|
|
|
28549 |
const emptyEditorWhenDeleting = () => {
|
|
|
28550 |
const serializeRng = rng => {
|
|
|
28551 |
const body = dom.create('body');
|
|
|
28552 |
const contents = rng.cloneContents();
|
|
|
28553 |
body.appendChild(contents);
|
|
|
28554 |
return selection.serializer.serialize(body, { format: 'html' });
|
|
|
28555 |
};
|
|
|
28556 |
const allContentsSelected = rng => {
|
|
|
28557 |
const selection = serializeRng(rng);
|
|
|
28558 |
const allRng = dom.createRng();
|
|
|
28559 |
allRng.selectNode(editor.getBody());
|
|
|
28560 |
const allSelection = serializeRng(allRng);
|
|
|
28561 |
return selection === allSelection;
|
|
|
28562 |
};
|
|
|
28563 |
editor.on('keydown', e => {
|
|
|
28564 |
const keyCode = e.keyCode;
|
|
|
28565 |
if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE) && editor.selection.isEditable()) {
|
|
|
28566 |
const isCollapsed = editor.selection.isCollapsed();
|
|
|
28567 |
const body = editor.getBody();
|
| 1441 |
ariadna |
28568 |
if (isCollapsed && !isEmptyNode(editor.schema, body)) {
|
| 1 |
efrain |
28569 |
return;
|
|
|
28570 |
}
|
|
|
28571 |
if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
|
|
|
28572 |
return;
|
|
|
28573 |
}
|
|
|
28574 |
e.preventDefault();
|
|
|
28575 |
editor.setContent('');
|
|
|
28576 |
if (body.firstChild && dom.isBlock(body.firstChild)) {
|
|
|
28577 |
editor.selection.setCursorLocation(body.firstChild, 0);
|
|
|
28578 |
} else {
|
|
|
28579 |
editor.selection.setCursorLocation(body, 0);
|
|
|
28580 |
}
|
|
|
28581 |
editor.nodeChanged();
|
|
|
28582 |
}
|
|
|
28583 |
});
|
|
|
28584 |
};
|
|
|
28585 |
const selectAll = () => {
|
|
|
28586 |
editor.shortcuts.add('meta+a', null, 'SelectAll');
|
|
|
28587 |
};
|
|
|
28588 |
const documentElementEditingFocus = () => {
|
|
|
28589 |
if (!editor.inline) {
|
|
|
28590 |
dom.bind(editor.getDoc(), 'mousedown mouseup', e => {
|
|
|
28591 |
let rng;
|
|
|
28592 |
if (e.target === editor.getDoc().documentElement) {
|
|
|
28593 |
rng = selection.getRng();
|
|
|
28594 |
editor.getBody().focus();
|
|
|
28595 |
if (e.type === 'mousedown') {
|
|
|
28596 |
if (isCaretContainer$2(rng.startContainer)) {
|
|
|
28597 |
return;
|
|
|
28598 |
}
|
|
|
28599 |
selection.placeCaretAt(e.clientX, e.clientY);
|
|
|
28600 |
} else {
|
|
|
28601 |
selection.setRng(rng);
|
|
|
28602 |
}
|
|
|
28603 |
}
|
|
|
28604 |
});
|
|
|
28605 |
}
|
|
|
28606 |
};
|
|
|
28607 |
const removeHrOnBackspace = () => {
|
|
|
28608 |
editor.on('keydown', e => {
|
|
|
28609 |
if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
|
|
|
28610 |
if (!editor.getBody().getElementsByTagName('hr').length) {
|
|
|
28611 |
return;
|
|
|
28612 |
}
|
|
|
28613 |
if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
|
|
|
28614 |
const node = selection.getNode();
|
|
|
28615 |
const previousSibling = node.previousSibling;
|
|
|
28616 |
if (node.nodeName === 'HR') {
|
|
|
28617 |
dom.remove(node);
|
|
|
28618 |
e.preventDefault();
|
|
|
28619 |
return;
|
|
|
28620 |
}
|
|
|
28621 |
if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
|
|
|
28622 |
dom.remove(previousSibling);
|
|
|
28623 |
e.preventDefault();
|
|
|
28624 |
}
|
|
|
28625 |
}
|
|
|
28626 |
}
|
|
|
28627 |
});
|
|
|
28628 |
};
|
|
|
28629 |
const focusBody = () => {
|
|
|
28630 |
if (!Range.prototype.getClientRects) {
|
|
|
28631 |
editor.on('mousedown', e => {
|
|
|
28632 |
if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
|
|
|
28633 |
const body = editor.getBody();
|
|
|
28634 |
body.blur();
|
|
|
28635 |
Delay.setEditorTimeout(editor, () => {
|
|
|
28636 |
body.focus();
|
|
|
28637 |
});
|
|
|
28638 |
}
|
|
|
28639 |
});
|
|
|
28640 |
}
|
|
|
28641 |
};
|
|
|
28642 |
const selectControlElements = () => {
|
|
|
28643 |
const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
|
|
|
28644 |
editor.on('click', e => {
|
|
|
28645 |
const target = e.target;
|
|
|
28646 |
if (/^(IMG|HR)$/.test(target.nodeName) && dom.isEditable(target)) {
|
|
|
28647 |
e.preventDefault();
|
|
|
28648 |
editor.selection.select(target);
|
|
|
28649 |
editor.nodeChanged();
|
|
|
28650 |
}
|
|
|
28651 |
if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0 && dom.isEditable(target.parentNode)) {
|
|
|
28652 |
e.preventDefault();
|
|
|
28653 |
selection.select(target);
|
|
|
28654 |
}
|
|
|
28655 |
});
|
|
|
28656 |
};
|
|
|
28657 |
const removeStylesWhenDeletingAcrossBlockElements = () => {
|
|
|
28658 |
const getAttributeApplyFunction = () => {
|
|
|
28659 |
const template = dom.getAttribs(selection.getStart().cloneNode(false));
|
|
|
28660 |
return () => {
|
|
|
28661 |
const target = selection.getStart();
|
|
|
28662 |
if (target !== editor.getBody()) {
|
|
|
28663 |
dom.setAttrib(target, 'style', null);
|
|
|
28664 |
each(template, attr => {
|
|
|
28665 |
target.setAttributeNode(attr.cloneNode(true));
|
|
|
28666 |
});
|
|
|
28667 |
}
|
|
|
28668 |
};
|
|
|
28669 |
};
|
|
|
28670 |
const isSelectionAcrossElements = () => {
|
|
|
28671 |
return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
|
|
|
28672 |
};
|
|
|
28673 |
editor.on('keypress', e => {
|
|
|
28674 |
let applyAttributes;
|
|
|
28675 |
if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
|
|
|
28676 |
applyAttributes = getAttributeApplyFunction();
|
|
|
28677 |
editor.getDoc().execCommand('delete', false);
|
|
|
28678 |
applyAttributes();
|
|
|
28679 |
e.preventDefault();
|
|
|
28680 |
return false;
|
|
|
28681 |
} else {
|
|
|
28682 |
return true;
|
|
|
28683 |
}
|
|
|
28684 |
});
|
|
|
28685 |
dom.bind(editor.getDoc(), 'cut', e => {
|
|
|
28686 |
if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
|
|
|
28687 |
const applyAttributes = getAttributeApplyFunction();
|
|
|
28688 |
Delay.setEditorTimeout(editor, () => {
|
|
|
28689 |
applyAttributes();
|
|
|
28690 |
});
|
|
|
28691 |
}
|
|
|
28692 |
});
|
|
|
28693 |
};
|
|
|
28694 |
const disableBackspaceIntoATable = () => {
|
|
|
28695 |
editor.on('keydown', e => {
|
|
|
28696 |
if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
|
|
|
28697 |
if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
|
|
|
28698 |
const previousSibling = selection.getNode().previousSibling;
|
|
|
28699 |
if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
|
|
|
28700 |
e.preventDefault();
|
|
|
28701 |
return false;
|
|
|
28702 |
}
|
|
|
28703 |
}
|
|
|
28704 |
}
|
|
|
28705 |
return true;
|
|
|
28706 |
});
|
|
|
28707 |
};
|
|
|
28708 |
const removeBlockQuoteOnBackSpace = () => {
|
|
|
28709 |
editor.on('keydown', e => {
|
|
|
28710 |
if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
|
|
|
28711 |
return;
|
|
|
28712 |
}
|
|
|
28713 |
let rng = selection.getRng();
|
|
|
28714 |
const container = rng.startContainer;
|
|
|
28715 |
const offset = rng.startOffset;
|
|
|
28716 |
const root = dom.getRoot();
|
|
|
28717 |
let parent = container;
|
|
|
28718 |
if (!rng.collapsed || offset !== 0) {
|
|
|
28719 |
return;
|
|
|
28720 |
}
|
|
|
28721 |
while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
|
|
|
28722 |
parent = parent.parentNode;
|
|
|
28723 |
}
|
|
|
28724 |
if (parent.nodeName === 'BLOCKQUOTE') {
|
|
|
28725 |
editor.formatter.toggle('blockquote', undefined, parent);
|
|
|
28726 |
rng = dom.createRng();
|
|
|
28727 |
rng.setStart(container, 0);
|
|
|
28728 |
rng.setEnd(container, 0);
|
|
|
28729 |
selection.setRng(rng);
|
|
|
28730 |
}
|
|
|
28731 |
});
|
|
|
28732 |
};
|
|
|
28733 |
const setGeckoEditingOptions = () => {
|
|
|
28734 |
const setOpts = () => {
|
|
|
28735 |
setEditorCommandState('StyleWithCSS', false);
|
|
|
28736 |
setEditorCommandState('enableInlineTableEditing', false);
|
|
|
28737 |
if (!getObjectResizing(editor)) {
|
|
|
28738 |
setEditorCommandState('enableObjectResizing', false);
|
|
|
28739 |
}
|
|
|
28740 |
};
|
|
|
28741 |
if (!isReadOnly$1(editor)) {
|
|
|
28742 |
editor.on('BeforeExecCommand mousedown', setOpts);
|
|
|
28743 |
}
|
|
|
28744 |
};
|
|
|
28745 |
const addBrAfterLastLinks = () => {
|
|
|
28746 |
const fixLinks = () => {
|
|
|
28747 |
each(dom.select('a:not([data-mce-block])'), node => {
|
|
|
28748 |
var _a;
|
|
|
28749 |
let parentNode = node.parentNode;
|
|
|
28750 |
const root = dom.getRoot();
|
|
|
28751 |
if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) {
|
|
|
28752 |
while (parentNode && !dom.isBlock(parentNode)) {
|
|
|
28753 |
if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) {
|
|
|
28754 |
return;
|
|
|
28755 |
}
|
|
|
28756 |
parentNode = parentNode.parentNode;
|
|
|
28757 |
}
|
|
|
28758 |
dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
|
|
|
28759 |
}
|
|
|
28760 |
});
|
|
|
28761 |
};
|
|
|
28762 |
editor.on('SetContent ExecCommand', e => {
|
|
|
28763 |
if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
|
|
|
28764 |
fixLinks();
|
|
|
28765 |
}
|
|
|
28766 |
});
|
|
|
28767 |
};
|
|
|
28768 |
const setDefaultBlockType = () => {
|
|
|
28769 |
editor.on('init', () => {
|
|
|
28770 |
setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor));
|
|
|
28771 |
});
|
|
|
28772 |
};
|
|
|
28773 |
const isAllContentSelected = editor => {
|
|
|
28774 |
const body = editor.getBody();
|
|
|
28775 |
const rng = editor.selection.getRng();
|
|
|
28776 |
return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
|
|
|
28777 |
};
|
|
|
28778 |
const normalizeSelection = () => {
|
|
|
28779 |
editor.on('keyup focusin mouseup', e => {
|
|
|
28780 |
if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
|
|
|
28781 |
selection.normalize();
|
|
|
28782 |
}
|
|
|
28783 |
}, true);
|
|
|
28784 |
};
|
|
|
28785 |
const showBrokenImageIcon = () => {
|
|
|
28786 |
editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
|
|
|
28787 |
};
|
|
|
28788 |
const restoreFocusOnKeyDown = () => {
|
|
|
28789 |
if (!editor.inline) {
|
|
|
28790 |
editor.on('keydown', () => {
|
|
|
28791 |
if (document.activeElement === document.body) {
|
|
|
28792 |
editor.getWin().focus();
|
|
|
28793 |
}
|
|
|
28794 |
});
|
|
|
28795 |
}
|
|
|
28796 |
};
|
|
|
28797 |
const bodyHeight = () => {
|
|
|
28798 |
if (!editor.inline) {
|
|
|
28799 |
editor.contentStyles.push('body {min-height: 150px}');
|
|
|
28800 |
editor.on('click', e => {
|
|
|
28801 |
let rng;
|
|
|
28802 |
if (e.target.nodeName === 'HTML') {
|
|
|
28803 |
rng = editor.selection.getRng();
|
|
|
28804 |
editor.getBody().focus();
|
|
|
28805 |
editor.selection.setRng(rng);
|
|
|
28806 |
editor.selection.normalize();
|
|
|
28807 |
editor.nodeChanged();
|
|
|
28808 |
}
|
|
|
28809 |
});
|
|
|
28810 |
}
|
|
|
28811 |
};
|
|
|
28812 |
const blockCmdArrowNavigation = () => {
|
|
|
28813 |
if (isMac) {
|
|
|
28814 |
editor.on('keydown', e => {
|
|
|
28815 |
if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
|
|
|
28816 |
e.preventDefault();
|
|
|
28817 |
const selection = editor.selection.getSel();
|
|
|
28818 |
selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
|
|
|
28819 |
}
|
|
|
28820 |
});
|
|
|
28821 |
}
|
|
|
28822 |
};
|
|
|
28823 |
const tapLinksAndImages = () => {
|
|
|
28824 |
editor.on('click', e => {
|
|
|
28825 |
let elm = e.target;
|
|
|
28826 |
do {
|
|
|
28827 |
if (elm.tagName === 'A') {
|
|
|
28828 |
e.preventDefault();
|
|
|
28829 |
return;
|
|
|
28830 |
}
|
|
|
28831 |
} while (elm = elm.parentNode);
|
|
|
28832 |
});
|
|
|
28833 |
editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
|
|
|
28834 |
};
|
|
|
28835 |
const blockFormSubmitInsideEditor = () => {
|
|
|
28836 |
editor.on('init', () => {
|
|
|
28837 |
editor.dom.bind(editor.getBody(), 'submit', e => {
|
|
|
28838 |
e.preventDefault();
|
|
|
28839 |
});
|
|
|
28840 |
});
|
|
|
28841 |
};
|
|
|
28842 |
const removeAppleInterchangeBrs = () => {
|
|
|
28843 |
parser.addNodeFilter('br', nodes => {
|
|
|
28844 |
let i = nodes.length;
|
|
|
28845 |
while (i--) {
|
|
|
28846 |
if (nodes[i].attr('class') === 'Apple-interchange-newline') {
|
|
|
28847 |
nodes[i].remove();
|
|
|
28848 |
}
|
|
|
28849 |
}
|
|
|
28850 |
});
|
|
|
28851 |
};
|
|
|
28852 |
const refreshContentEditable = noop;
|
|
|
28853 |
const isHidden = () => {
|
|
|
28854 |
if (!isGecko || editor.removed) {
|
|
|
28855 |
return false;
|
|
|
28856 |
}
|
|
|
28857 |
const sel = editor.selection.getSel();
|
|
|
28858 |
return !sel || !sel.rangeCount || sel.rangeCount === 0;
|
|
|
28859 |
};
|
|
|
28860 |
const setupRtc = () => {
|
|
|
28861 |
if (isWebKit) {
|
|
|
28862 |
documentElementEditingFocus();
|
|
|
28863 |
selectControlElements();
|
|
|
28864 |
blockFormSubmitInsideEditor();
|
|
|
28865 |
selectAll();
|
|
|
28866 |
if (isiOS) {
|
|
|
28867 |
restoreFocusOnKeyDown();
|
|
|
28868 |
bodyHeight();
|
|
|
28869 |
tapLinksAndImages();
|
|
|
28870 |
}
|
|
|
28871 |
}
|
|
|
28872 |
if (isGecko) {
|
|
|
28873 |
focusBody();
|
|
|
28874 |
setGeckoEditingOptions();
|
|
|
28875 |
showBrokenImageIcon();
|
|
|
28876 |
blockCmdArrowNavigation();
|
|
|
28877 |
}
|
|
|
28878 |
};
|
|
|
28879 |
const setup = () => {
|
|
|
28880 |
removeBlockQuoteOnBackSpace();
|
|
|
28881 |
emptyEditorWhenDeleting();
|
|
|
28882 |
if (!Env.windowsPhone) {
|
|
|
28883 |
normalizeSelection();
|
|
|
28884 |
}
|
|
|
28885 |
if (isWebKit) {
|
|
|
28886 |
documentElementEditingFocus();
|
|
|
28887 |
selectControlElements();
|
|
|
28888 |
setDefaultBlockType();
|
|
|
28889 |
blockFormSubmitInsideEditor();
|
|
|
28890 |
disableBackspaceIntoATable();
|
|
|
28891 |
removeAppleInterchangeBrs();
|
|
|
28892 |
if (isiOS) {
|
|
|
28893 |
restoreFocusOnKeyDown();
|
|
|
28894 |
bodyHeight();
|
|
|
28895 |
tapLinksAndImages();
|
|
|
28896 |
} else {
|
|
|
28897 |
selectAll();
|
|
|
28898 |
}
|
|
|
28899 |
}
|
|
|
28900 |
if (isGecko) {
|
|
|
28901 |
removeHrOnBackspace();
|
|
|
28902 |
focusBody();
|
|
|
28903 |
removeStylesWhenDeletingAcrossBlockElements();
|
|
|
28904 |
setGeckoEditingOptions();
|
|
|
28905 |
addBrAfterLastLinks();
|
|
|
28906 |
showBrokenImageIcon();
|
|
|
28907 |
blockCmdArrowNavigation();
|
|
|
28908 |
disableBackspaceIntoATable();
|
|
|
28909 |
}
|
|
|
28910 |
};
|
|
|
28911 |
if (isRtc(editor)) {
|
|
|
28912 |
setupRtc();
|
|
|
28913 |
} else {
|
|
|
28914 |
setup();
|
|
|
28915 |
}
|
|
|
28916 |
return {
|
|
|
28917 |
refreshContentEditable,
|
|
|
28918 |
isHidden
|
|
|
28919 |
};
|
|
|
28920 |
};
|
|
|
28921 |
|
| 1441 |
ariadna |
28922 |
const isGplKey = key => key.toLowerCase() === 'gpl';
|
|
|
28923 |
const isValidGeneratedKey = key => key.length >= 64 && key.length <= 255;
|
|
|
28924 |
const validateLicenseKey = key => isGplKey(key) || isValidGeneratedKey(key) ? 'VALID' : 'INVALID';
|
|
|
28925 |
const validateEditorLicenseKey = editor => {
|
|
|
28926 |
const licenseKey = getLicenseKey(editor);
|
|
|
28927 |
const hasApiKey = isString(getApiKey(editor));
|
|
|
28928 |
if (!hasApiKey && (isUndefined(licenseKey) || validateLicenseKey(licenseKey) === 'INVALID')) {
|
|
|
28929 |
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/`);
|
|
|
28930 |
}
|
|
|
28931 |
};
|
|
|
28932 |
|
| 1 |
efrain |
28933 |
const DOM$6 = DOMUtils.DOM;
|
|
|
28934 |
const appendStyle = (editor, text) => {
|
|
|
28935 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
28936 |
const container = getStyleContainer(getRootNode(body));
|
|
|
28937 |
const style = SugarElement.fromTag('style');
|
| 1441 |
ariadna |
28938 |
set$4(style, 'type', 'text/css');
|
| 1 |
efrain |
28939 |
append$1(style, SugarElement.fromText(text));
|
|
|
28940 |
append$1(container, style);
|
|
|
28941 |
editor.on('remove', () => {
|
| 1441 |
ariadna |
28942 |
remove$4(style);
|
| 1 |
efrain |
28943 |
});
|
|
|
28944 |
};
|
|
|
28945 |
const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined;
|
|
|
28946 |
const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false);
|
|
|
28947 |
const mkParserSettings = editor => {
|
|
|
28948 |
const getOption = editor.options.get;
|
|
|
28949 |
const blobCache = editor.editorUpload.blobCache;
|
|
|
28950 |
return removeUndefined({
|
|
|
28951 |
allow_conditional_comments: getOption('allow_conditional_comments'),
|
|
|
28952 |
allow_html_data_urls: getOption('allow_html_data_urls'),
|
|
|
28953 |
allow_svg_data_urls: getOption('allow_svg_data_urls'),
|
|
|
28954 |
allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
|
|
|
28955 |
allow_script_urls: getOption('allow_script_urls'),
|
| 1441 |
ariadna |
28956 |
allow_mathml_annotation_encodings: getOption('allow_mathml_annotation_encodings'),
|
| 1 |
efrain |
28957 |
allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
|
|
|
28958 |
convert_unsafe_embeds: getOption('convert_unsafe_embeds'),
|
|
|
28959 |
convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
|
|
|
28960 |
fix_list_elements: getOption('fix_list_elements'),
|
|
|
28961 |
font_size_legacy_values: getOption('font_size_legacy_values'),
|
|
|
28962 |
forced_root_block: getOption('forced_root_block'),
|
|
|
28963 |
forced_root_block_attrs: getOption('forced_root_block_attrs'),
|
|
|
28964 |
preserve_cdata: getOption('preserve_cdata'),
|
|
|
28965 |
inline_styles: getOption('inline_styles'),
|
|
|
28966 |
root_name: getRootName(editor),
|
|
|
28967 |
sandbox_iframes: getOption('sandbox_iframes'),
|
| 1441 |
ariadna |
28968 |
sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
|
| 1 |
efrain |
28969 |
sanitize: getOption('xss_sanitization'),
|
|
|
28970 |
validate: true,
|
|
|
28971 |
blob_cache: blobCache,
|
|
|
28972 |
document: editor.getDoc()
|
|
|
28973 |
});
|
|
|
28974 |
};
|
|
|
28975 |
const mkSchemaSettings = editor => {
|
|
|
28976 |
const getOption = editor.options.get;
|
|
|
28977 |
return removeUndefined({
|
|
|
28978 |
custom_elements: getOption('custom_elements'),
|
|
|
28979 |
extended_valid_elements: getOption('extended_valid_elements'),
|
|
|
28980 |
invalid_elements: getOption('invalid_elements'),
|
|
|
28981 |
invalid_styles: getOption('invalid_styles'),
|
|
|
28982 |
schema: getOption('schema'),
|
|
|
28983 |
valid_children: getOption('valid_children'),
|
|
|
28984 |
valid_classes: getOption('valid_classes'),
|
|
|
28985 |
valid_elements: getOption('valid_elements'),
|
|
|
28986 |
valid_styles: getOption('valid_styles'),
|
|
|
28987 |
verify_html: getOption('verify_html'),
|
|
|
28988 |
padd_empty_block_inline_children: getOption('format_empty_lines')
|
|
|
28989 |
});
|
|
|
28990 |
};
|
|
|
28991 |
const mkSerializerSettings = editor => {
|
|
|
28992 |
const getOption = editor.options.get;
|
|
|
28993 |
return {
|
|
|
28994 |
...mkParserSettings(editor),
|
|
|
28995 |
...mkSchemaSettings(editor),
|
|
|
28996 |
...removeUndefined({
|
|
|
28997 |
remove_trailing_brs: getOption('remove_trailing_brs'),
|
|
|
28998 |
pad_empty_with_br: getOption('pad_empty_with_br'),
|
|
|
28999 |
url_converter: getOption('url_converter'),
|
|
|
29000 |
url_converter_scope: getOption('url_converter_scope'),
|
|
|
29001 |
element_format: getOption('element_format'),
|
|
|
29002 |
entities: getOption('entities'),
|
|
|
29003 |
entity_encoding: getOption('entity_encoding'),
|
|
|
29004 |
indent: getOption('indent'),
|
|
|
29005 |
indent_after: getOption('indent_after'),
|
|
|
29006 |
indent_before: getOption('indent_before')
|
|
|
29007 |
})
|
|
|
29008 |
};
|
|
|
29009 |
};
|
|
|
29010 |
const createParser = editor => {
|
|
|
29011 |
const parser = DomParser(mkParserSettings(editor), editor.schema);
|
|
|
29012 |
parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => {
|
|
|
29013 |
const dom = editor.dom;
|
|
|
29014 |
const internalName = 'data-mce-' + name;
|
|
|
29015 |
let i = nodes.length;
|
|
|
29016 |
while (i--) {
|
|
|
29017 |
const node = nodes[i];
|
|
|
29018 |
let value = node.attr(name);
|
|
|
29019 |
if (value && !node.attr(internalName)) {
|
|
|
29020 |
if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
|
|
|
29021 |
continue;
|
|
|
29022 |
}
|
|
|
29023 |
if (name === 'style') {
|
|
|
29024 |
value = dom.serializeStyle(dom.parseStyle(value), node.name);
|
|
|
29025 |
if (!value.length) {
|
|
|
29026 |
value = null;
|
|
|
29027 |
}
|
|
|
29028 |
node.attr(internalName, value);
|
|
|
29029 |
node.attr(name, value);
|
|
|
29030 |
} else if (name === 'tabindex') {
|
|
|
29031 |
node.attr(internalName, value);
|
|
|
29032 |
node.attr(name, null);
|
|
|
29033 |
} else {
|
|
|
29034 |
node.attr(internalName, editor.convertURL(value, name, node.name));
|
|
|
29035 |
}
|
|
|
29036 |
}
|
|
|
29037 |
}
|
|
|
29038 |
});
|
|
|
29039 |
parser.addNodeFilter('script', nodes => {
|
|
|
29040 |
let i = nodes.length;
|
|
|
29041 |
while (i--) {
|
|
|
29042 |
const node = nodes[i];
|
|
|
29043 |
const type = node.attr('type') || 'no/type';
|
|
|
29044 |
if (type.indexOf('mce-') !== 0) {
|
|
|
29045 |
node.attr('type', 'mce-' + type);
|
|
|
29046 |
}
|
|
|
29047 |
}
|
|
|
29048 |
});
|
|
|
29049 |
if (shouldPreserveCData(editor)) {
|
|
|
29050 |
parser.addNodeFilter('#cdata', nodes => {
|
|
|
29051 |
var _a;
|
|
|
29052 |
let i = nodes.length;
|
|
|
29053 |
while (i--) {
|
|
|
29054 |
const node = nodes[i];
|
|
|
29055 |
node.type = 8;
|
|
|
29056 |
node.name = '#comment';
|
|
|
29057 |
node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]';
|
|
|
29058 |
}
|
|
|
29059 |
});
|
|
|
29060 |
}
|
|
|
29061 |
parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => {
|
|
|
29062 |
let i = nodes.length;
|
|
|
29063 |
const nonEmptyElements = editor.schema.getNonEmptyElements();
|
|
|
29064 |
while (i--) {
|
|
|
29065 |
const node = nodes[i];
|
|
|
29066 |
if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
|
|
|
29067 |
node.append(new AstNode('br', 1));
|
|
|
29068 |
}
|
|
|
29069 |
}
|
|
|
29070 |
});
|
|
|
29071 |
return parser;
|
|
|
29072 |
};
|
|
|
29073 |
const autoFocus = editor => {
|
|
|
29074 |
const autoFocus = getAutoFocus(editor);
|
|
|
29075 |
if (autoFocus) {
|
|
|
29076 |
Delay.setEditorTimeout(editor, () => {
|
|
|
29077 |
let focusEditor;
|
|
|
29078 |
if (autoFocus === true) {
|
|
|
29079 |
focusEditor = editor;
|
|
|
29080 |
} else {
|
|
|
29081 |
focusEditor = editor.editorManager.get(autoFocus);
|
|
|
29082 |
}
|
|
|
29083 |
if (focusEditor && !focusEditor.destroyed) {
|
|
|
29084 |
focusEditor.focus();
|
|
|
29085 |
focusEditor.selection.scrollIntoView();
|
|
|
29086 |
}
|
|
|
29087 |
}, 100);
|
|
|
29088 |
}
|
|
|
29089 |
};
|
|
|
29090 |
const moveSelectionToFirstCaretPosition = editor => {
|
|
|
29091 |
const root = editor.dom.getRoot();
|
|
|
29092 |
if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
|
|
|
29093 |
firstPositionIn(root).each(pos => {
|
|
|
29094 |
const node = pos.getNode();
|
|
|
29095 |
const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
|
|
|
29096 |
editor.selection.setRng(caretPos.toRange());
|
|
|
29097 |
});
|
|
|
29098 |
}
|
|
|
29099 |
};
|
|
|
29100 |
const initEditor = editor => {
|
|
|
29101 |
editor.bindPendingEventDelegates();
|
|
|
29102 |
editor.initialized = true;
|
|
|
29103 |
fireInit(editor);
|
|
|
29104 |
editor.focus(true);
|
|
|
29105 |
moveSelectionToFirstCaretPosition(editor);
|
|
|
29106 |
editor.nodeChanged({ initial: true });
|
|
|
29107 |
const initInstanceCallback = getInitInstanceCallback(editor);
|
|
|
29108 |
if (isFunction(initInstanceCallback)) {
|
|
|
29109 |
initInstanceCallback.call(editor, editor);
|
|
|
29110 |
}
|
|
|
29111 |
autoFocus(editor);
|
| 1441 |
ariadna |
29112 |
if (isDisabled(editor)) {
|
|
|
29113 |
toggleDisabled(editor, true);
|
|
|
29114 |
}
|
| 1 |
efrain |
29115 |
};
|
|
|
29116 |
const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
|
|
|
29117 |
const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
|
|
|
29118 |
const {
|
|
|
29119 |
pass: bundledCss,
|
|
|
29120 |
fail: normalCss
|
|
|
29121 |
} = partition$2(css, name => tinymce.Resource.has(toContentSkinResourceName(name)));
|
|
|
29122 |
const bundledPromises = bundledCss.map(url => {
|
|
|
29123 |
const css = tinymce.Resource.get(toContentSkinResourceName(url));
|
|
|
29124 |
if (isString(css)) {
|
|
|
29125 |
return Promise.resolve(getStyleSheetLoader$1(editor).loadRawCss(url, css));
|
|
|
29126 |
}
|
|
|
29127 |
return Promise.resolve();
|
|
|
29128 |
});
|
|
|
29129 |
const promises = [
|
|
|
29130 |
...bundledPromises,
|
|
|
29131 |
getStyleSheetLoader$1(editor).loadAll(normalCss)
|
|
|
29132 |
];
|
|
|
29133 |
if (editor.inline) {
|
|
|
29134 |
return promises;
|
|
|
29135 |
} else {
|
|
|
29136 |
return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
|
|
|
29137 |
}
|
|
|
29138 |
};
|
|
|
29139 |
const loadContentCss = editor => {
|
|
|
29140 |
const styleSheetLoader = getStyleSheetLoader$1(editor);
|
|
|
29141 |
const fontCss = getFontCss(editor);
|
|
|
29142 |
const css = editor.contentCSS;
|
|
|
29143 |
const removeCss = () => {
|
|
|
29144 |
styleSheetLoader.unloadAll(css);
|
|
|
29145 |
if (!editor.inline) {
|
|
|
29146 |
editor.ui.styleSheetLoader.unloadAll(fontCss);
|
|
|
29147 |
}
|
|
|
29148 |
};
|
|
|
29149 |
const loaded = () => {
|
|
|
29150 |
if (editor.removed) {
|
|
|
29151 |
removeCss();
|
|
|
29152 |
} else {
|
|
|
29153 |
editor.on('remove', removeCss);
|
|
|
29154 |
}
|
|
|
29155 |
};
|
|
|
29156 |
if (editor.contentStyles.length > 0) {
|
|
|
29157 |
let contentCssText = '';
|
|
|
29158 |
Tools.each(editor.contentStyles, style => {
|
|
|
29159 |
contentCssText += style + '\r\n';
|
|
|
29160 |
});
|
|
|
29161 |
editor.dom.addStyle(contentCssText);
|
|
|
29162 |
}
|
|
|
29163 |
const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
|
|
|
29164 |
const contentStyle = getContentStyle(editor);
|
|
|
29165 |
if (contentStyle) {
|
|
|
29166 |
appendStyle(editor, contentStyle);
|
|
|
29167 |
}
|
|
|
29168 |
return allStylesheets;
|
|
|
29169 |
};
|
|
|
29170 |
const preInit = editor => {
|
|
|
29171 |
const doc = editor.getDoc(), body = editor.getBody();
|
|
|
29172 |
firePreInit(editor);
|
|
|
29173 |
if (!shouldBrowserSpellcheck(editor)) {
|
|
|
29174 |
doc.body.spellcheck = false;
|
|
|
29175 |
DOM$6.setAttrib(body, 'spellcheck', 'false');
|
|
|
29176 |
}
|
|
|
29177 |
editor.quirks = Quirks(editor);
|
|
|
29178 |
firePostRender(editor);
|
|
|
29179 |
const directionality = getDirectionality(editor);
|
|
|
29180 |
if (directionality !== undefined) {
|
|
|
29181 |
body.dir = directionality;
|
|
|
29182 |
}
|
|
|
29183 |
const protect = getProtect(editor);
|
|
|
29184 |
if (protect) {
|
|
|
29185 |
editor.on('BeforeSetContent', e => {
|
|
|
29186 |
Tools.each(protect, pattern => {
|
|
|
29187 |
e.content = e.content.replace(pattern, str => {
|
|
|
29188 |
return '<!--mce:protected ' + escape(str) + '-->';
|
|
|
29189 |
});
|
|
|
29190 |
});
|
|
|
29191 |
});
|
|
|
29192 |
}
|
|
|
29193 |
editor.on('SetContent', () => {
|
|
|
29194 |
editor.addVisual(editor.getBody());
|
|
|
29195 |
});
|
|
|
29196 |
editor.on('compositionstart compositionend', e => {
|
|
|
29197 |
editor.composing = e.type === 'compositionstart';
|
|
|
29198 |
});
|
|
|
29199 |
};
|
|
|
29200 |
const loadInitialContent = editor => {
|
|
|
29201 |
if (!isRtc(editor)) {
|
|
|
29202 |
editor.load({
|
|
|
29203 |
initial: true,
|
|
|
29204 |
format: 'html'
|
|
|
29205 |
});
|
|
|
29206 |
}
|
|
|
29207 |
editor.startContent = editor.getContent({ format: 'raw' });
|
|
|
29208 |
};
|
|
|
29209 |
const initEditorWithInitialContent = editor => {
|
|
|
29210 |
if (editor.removed !== true) {
|
|
|
29211 |
loadInitialContent(editor);
|
|
|
29212 |
initEditor(editor);
|
|
|
29213 |
}
|
|
|
29214 |
};
|
|
|
29215 |
const startProgress = editor => {
|
|
|
29216 |
let canceled = false;
|
|
|
29217 |
const progressTimeout = setTimeout(() => {
|
|
|
29218 |
if (!canceled) {
|
|
|
29219 |
editor.setProgressState(true);
|
|
|
29220 |
}
|
|
|
29221 |
}, 500);
|
|
|
29222 |
return () => {
|
|
|
29223 |
clearTimeout(progressTimeout);
|
|
|
29224 |
canceled = true;
|
|
|
29225 |
editor.setProgressState(false);
|
|
|
29226 |
};
|
|
|
29227 |
};
|
|
|
29228 |
const contentBodyLoaded = editor => {
|
|
|
29229 |
const targetElm = editor.getElement();
|
|
|
29230 |
let doc = editor.getDoc();
|
|
|
29231 |
if (editor.inline) {
|
|
|
29232 |
DOM$6.addClass(targetElm, 'mce-content-body');
|
|
|
29233 |
editor.contentDocument = doc = document;
|
|
|
29234 |
editor.contentWindow = window;
|
|
|
29235 |
editor.bodyElement = targetElm;
|
|
|
29236 |
editor.contentAreaContainer = targetElm;
|
|
|
29237 |
}
|
|
|
29238 |
const body = editor.getBody();
|
|
|
29239 |
body.disabled = true;
|
|
|
29240 |
editor.readonly = isReadOnly$1(editor);
|
|
|
29241 |
editor._editableRoot = hasEditableRoot$1(editor);
|
| 1441 |
ariadna |
29242 |
if (!isDisabled$1(editor) && editor.hasEditableRoot()) {
|
| 1 |
efrain |
29243 |
if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
|
|
|
29244 |
body.style.position = 'relative';
|
|
|
29245 |
}
|
|
|
29246 |
body.contentEditable = 'true';
|
|
|
29247 |
}
|
|
|
29248 |
body.disabled = false;
|
|
|
29249 |
editor.editorUpload = EditorUpload(editor);
|
|
|
29250 |
editor.schema = Schema(mkSchemaSettings(editor));
|
|
|
29251 |
editor.dom = DOMUtils(doc, {
|
|
|
29252 |
keep_values: true,
|
|
|
29253 |
url_converter: editor.convertURL,
|
|
|
29254 |
url_converter_scope: editor,
|
|
|
29255 |
update_styles: true,
|
|
|
29256 |
root_element: editor.inline ? editor.getBody() : null,
|
|
|
29257 |
collect: editor.inline,
|
|
|
29258 |
schema: editor.schema,
|
|
|
29259 |
contentCssCors: shouldUseContentCssCors(editor),
|
|
|
29260 |
referrerPolicy: getReferrerPolicy(editor),
|
|
|
29261 |
onSetAttrib: e => {
|
|
|
29262 |
editor.dispatch('SetAttrib', e);
|
| 1441 |
ariadna |
29263 |
}
|
| 1 |
efrain |
29264 |
});
|
|
|
29265 |
editor.parser = createParser(editor);
|
|
|
29266 |
editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
|
|
|
29267 |
editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
|
|
|
29268 |
editor.annotator = Annotator(editor);
|
|
|
29269 |
editor.formatter = Formatter(editor);
|
|
|
29270 |
editor.undoManager = UndoManager(editor);
|
|
|
29271 |
editor._nodeChangeDispatcher = new NodeChange(editor);
|
|
|
29272 |
editor._selectionOverrides = SelectionOverrides(editor);
|
|
|
29273 |
setup$p(editor);
|
|
|
29274 |
setup$6(editor);
|
|
|
29275 |
setup$n(editor);
|
|
|
29276 |
if (!isRtc(editor)) {
|
|
|
29277 |
setup$5(editor);
|
|
|
29278 |
setup$1(editor);
|
|
|
29279 |
}
|
|
|
29280 |
const caret = setup$b(editor);
|
|
|
29281 |
setup$q(editor, caret);
|
|
|
29282 |
setup$o(editor);
|
|
|
29283 |
setup$r(editor);
|
|
|
29284 |
setup$7(editor);
|
|
|
29285 |
const setupRtcThunk = setup$t(editor);
|
|
|
29286 |
preInit(editor);
|
| 1441 |
ariadna |
29287 |
validateEditorLicenseKey(editor);
|
| 1 |
efrain |
29288 |
setupRtcThunk.fold(() => {
|
|
|
29289 |
const cancelProgress = startProgress(editor);
|
|
|
29290 |
loadContentCss(editor).then(() => {
|
|
|
29291 |
initEditorWithInitialContent(editor);
|
|
|
29292 |
cancelProgress();
|
|
|
29293 |
});
|
|
|
29294 |
}, setupRtc => {
|
|
|
29295 |
editor.setProgressState(true);
|
|
|
29296 |
loadContentCss(editor).then(() => {
|
|
|
29297 |
setupRtc().then(_rtcMode => {
|
|
|
29298 |
editor.setProgressState(false);
|
|
|
29299 |
initEditorWithInitialContent(editor);
|
|
|
29300 |
bindEvents(editor);
|
|
|
29301 |
}, err => {
|
|
|
29302 |
editor.notificationManager.open({
|
|
|
29303 |
type: 'error',
|
|
|
29304 |
text: String(err)
|
|
|
29305 |
});
|
|
|
29306 |
initEditorWithInitialContent(editor);
|
|
|
29307 |
bindEvents(editor);
|
|
|
29308 |
});
|
|
|
29309 |
});
|
|
|
29310 |
});
|
|
|
29311 |
};
|
|
|
29312 |
|
|
|
29313 |
const filter = always;
|
|
|
29314 |
const bind = (element, event, handler) => bind$2(element, event, filter, handler);
|
|
|
29315 |
|
|
|
29316 |
const DOM$5 = DOMUtils.DOM;
|
|
|
29317 |
const createIframeElement = (id, title, customAttrs, tabindex) => {
|
|
|
29318 |
const iframe = SugarElement.fromTag('iframe');
|
| 1441 |
ariadna |
29319 |
tabindex.each(t => set$4(iframe, 'tabindex', t));
|
| 1 |
efrain |
29320 |
setAll$1(iframe, customAttrs);
|
|
|
29321 |
setAll$1(iframe, {
|
|
|
29322 |
id: id + '_ifr',
|
|
|
29323 |
frameBorder: '0',
|
|
|
29324 |
allowTransparency: 'true',
|
|
|
29325 |
title
|
|
|
29326 |
});
|
|
|
29327 |
add$2(iframe, 'tox-edit-area__iframe');
|
|
|
29328 |
return iframe;
|
|
|
29329 |
};
|
|
|
29330 |
const getIframeHtml = editor => {
|
|
|
29331 |
let iframeHTML = getDocType(editor) + '<html><head>';
|
|
|
29332 |
if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
|
|
|
29333 |
iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
|
|
|
29334 |
}
|
|
|
29335 |
iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
|
|
|
29336 |
const bodyId = getBodyId(editor);
|
|
|
29337 |
const bodyClass = getBodyClass(editor);
|
|
|
29338 |
const translatedAriaText = editor.translate(getIframeAriaText(editor));
|
|
|
29339 |
if (getContentSecurityPolicy(editor)) {
|
|
|
29340 |
iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />';
|
|
|
29341 |
}
|
|
|
29342 |
iframeHTML += '</head>' + `<body id="${ bodyId }" class="mce-content-body ${ bodyClass }" data-id="${ editor.id }" aria-label="${ translatedAriaText }">` + '<br>' + '</body></html>';
|
|
|
29343 |
return iframeHTML;
|
|
|
29344 |
};
|
|
|
29345 |
const createIframe = (editor, boxInfo) => {
|
| 1441 |
ariadna |
29346 |
const iframeTitle = Env.browser.isFirefox() ? getIframeAriaText(editor) : 'Rich Text Area';
|
|
|
29347 |
const translatedTitle = editor.translate(iframeTitle);
|
| 1 |
efrain |
29348 |
const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt);
|
| 1441 |
ariadna |
29349 |
const ifr = createIframeElement(editor.id, translatedTitle, getIframeAttrs(editor), tabindex).dom;
|
| 1 |
efrain |
29350 |
ifr.onload = () => {
|
|
|
29351 |
ifr.onload = null;
|
|
|
29352 |
editor.dispatch('load');
|
|
|
29353 |
};
|
|
|
29354 |
editor.contentAreaContainer = boxInfo.iframeContainer;
|
|
|
29355 |
editor.iframeElement = ifr;
|
|
|
29356 |
editor.iframeHTML = getIframeHtml(editor);
|
|
|
29357 |
DOM$5.add(boxInfo.iframeContainer, ifr);
|
|
|
29358 |
};
|
|
|
29359 |
const setupIframeBody = editor => {
|
|
|
29360 |
const iframe = editor.iframeElement;
|
|
|
29361 |
const ready = () => {
|
|
|
29362 |
editor.contentDocument = iframe.contentDocument;
|
|
|
29363 |
contentBodyLoaded(editor);
|
|
|
29364 |
};
|
|
|
29365 |
if (shouldUseDocumentWrite(editor) || Env.browser.isFirefox()) {
|
|
|
29366 |
const doc = editor.getDoc();
|
|
|
29367 |
doc.open();
|
|
|
29368 |
doc.write(editor.iframeHTML);
|
|
|
29369 |
doc.close();
|
|
|
29370 |
ready();
|
|
|
29371 |
} else {
|
|
|
29372 |
const binder = bind(SugarElement.fromDom(iframe), 'load', () => {
|
|
|
29373 |
binder.unbind();
|
|
|
29374 |
ready();
|
|
|
29375 |
});
|
|
|
29376 |
iframe.srcdoc = editor.iframeHTML;
|
|
|
29377 |
}
|
|
|
29378 |
};
|
|
|
29379 |
const init$1 = (editor, boxInfo) => {
|
|
|
29380 |
createIframe(editor, boxInfo);
|
|
|
29381 |
if (boxInfo.editorContainer) {
|
|
|
29382 |
boxInfo.editorContainer.style.display = editor.orgDisplay;
|
|
|
29383 |
editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
|
|
|
29384 |
}
|
|
|
29385 |
editor.getElement().style.display = 'none';
|
|
|
29386 |
DOM$5.setAttrib(editor.id, 'aria-hidden', 'true');
|
|
|
29387 |
editor.getElement().style.visibility = editor.orgVisibility;
|
|
|
29388 |
setupIframeBody(editor);
|
|
|
29389 |
};
|
|
|
29390 |
|
|
|
29391 |
const DOM$4 = DOMUtils.DOM;
|
|
|
29392 |
const initPlugin = (editor, initializedPlugins, plugin) => {
|
|
|
29393 |
const Plugin = PluginManager.get(plugin);
|
|
|
29394 |
const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
|
|
|
29395 |
plugin = Tools.trim(plugin);
|
|
|
29396 |
if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
|
|
|
29397 |
if (editor.plugins[plugin]) {
|
|
|
29398 |
return;
|
|
|
29399 |
}
|
|
|
29400 |
try {
|
|
|
29401 |
const pluginInstance = Plugin(editor, pluginUrl) || {};
|
|
|
29402 |
editor.plugins[plugin] = pluginInstance;
|
|
|
29403 |
if (isFunction(pluginInstance.init)) {
|
|
|
29404 |
pluginInstance.init(editor, pluginUrl);
|
|
|
29405 |
initializedPlugins.push(plugin);
|
|
|
29406 |
}
|
|
|
29407 |
} catch (e) {
|
|
|
29408 |
pluginInitError(editor, plugin, e);
|
|
|
29409 |
}
|
|
|
29410 |
}
|
|
|
29411 |
};
|
|
|
29412 |
const trimLegacyPrefix = name => {
|
|
|
29413 |
return name.replace(/^\-/, '');
|
|
|
29414 |
};
|
|
|
29415 |
const initPlugins = editor => {
|
|
|
29416 |
const initializedPlugins = [];
|
|
|
29417 |
each$e(getPlugins(editor), name => {
|
|
|
29418 |
initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
|
|
|
29419 |
});
|
|
|
29420 |
};
|
|
|
29421 |
const initIcons = editor => {
|
|
|
29422 |
const iconPackName = Tools.trim(getIconPackName(editor));
|
|
|
29423 |
const currentIcons = editor.ui.registry.getAll().icons;
|
|
|
29424 |
const loadIcons = {
|
|
|
29425 |
...IconManager.get('default').icons,
|
|
|
29426 |
...IconManager.get(iconPackName).icons
|
|
|
29427 |
};
|
|
|
29428 |
each$d(loadIcons, (svgData, icon) => {
|
|
|
29429 |
if (!has$2(currentIcons, icon)) {
|
|
|
29430 |
editor.ui.registry.addIcon(icon, svgData);
|
|
|
29431 |
}
|
|
|
29432 |
});
|
|
|
29433 |
};
|
|
|
29434 |
const initTheme = editor => {
|
|
|
29435 |
const theme = getTheme(editor);
|
|
|
29436 |
if (isString(theme)) {
|
|
|
29437 |
const Theme = ThemeManager.get(theme);
|
|
|
29438 |
editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
|
|
|
29439 |
if (isFunction(editor.theme.init)) {
|
|
|
29440 |
editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''));
|
|
|
29441 |
}
|
|
|
29442 |
} else {
|
|
|
29443 |
editor.theme = {};
|
|
|
29444 |
}
|
|
|
29445 |
};
|
|
|
29446 |
const initModel = editor => {
|
|
|
29447 |
const model = getModel(editor);
|
|
|
29448 |
const Model = ModelManager.get(model);
|
|
|
29449 |
editor.model = Model(editor, ModelManager.urls[model]);
|
|
|
29450 |
};
|
|
|
29451 |
const renderFromLoadedTheme = editor => {
|
|
|
29452 |
const render = editor.theme.renderUI;
|
|
|
29453 |
return render ? render() : renderThemeFalse(editor);
|
|
|
29454 |
};
|
|
|
29455 |
const renderFromThemeFunc = editor => {
|
|
|
29456 |
const elm = editor.getElement();
|
|
|
29457 |
const theme = getTheme(editor);
|
|
|
29458 |
const info = theme(editor, elm);
|
|
|
29459 |
if (info.editorContainer.nodeType) {
|
|
|
29460 |
info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
|
|
|
29461 |
}
|
|
|
29462 |
if (info.iframeContainer && info.iframeContainer.nodeType) {
|
|
|
29463 |
info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
|
|
|
29464 |
}
|
|
|
29465 |
info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
|
|
|
29466 |
return info;
|
|
|
29467 |
};
|
|
|
29468 |
const createThemeFalseResult = (element, iframe) => {
|
|
|
29469 |
return {
|
|
|
29470 |
editorContainer: element,
|
|
|
29471 |
iframeContainer: iframe,
|
|
|
29472 |
api: {}
|
|
|
29473 |
};
|
|
|
29474 |
};
|
|
|
29475 |
const renderThemeFalseIframe = targetElement => {
|
|
|
29476 |
const iframeContainer = DOM$4.create('div');
|
|
|
29477 |
DOM$4.insertAfter(iframeContainer, targetElement);
|
|
|
29478 |
return createThemeFalseResult(iframeContainer, iframeContainer);
|
|
|
29479 |
};
|
|
|
29480 |
const renderThemeFalse = editor => {
|
|
|
29481 |
const targetElement = editor.getElement();
|
|
|
29482 |
return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
|
|
|
29483 |
};
|
|
|
29484 |
const renderThemeUi = editor => {
|
|
|
29485 |
const elm = editor.getElement();
|
|
|
29486 |
editor.orgDisplay = elm.style.display;
|
|
|
29487 |
if (isString(getTheme(editor))) {
|
|
|
29488 |
return renderFromLoadedTheme(editor);
|
|
|
29489 |
} else if (isFunction(getTheme(editor))) {
|
|
|
29490 |
return renderFromThemeFunc(editor);
|
|
|
29491 |
} else {
|
|
|
29492 |
return renderThemeFalse(editor);
|
|
|
29493 |
}
|
|
|
29494 |
};
|
|
|
29495 |
const augmentEditorUiApi = (editor, api) => {
|
|
|
29496 |
const uiApiFacade = {
|
|
|
29497 |
show: Optional.from(api.show).getOr(noop),
|
|
|
29498 |
hide: Optional.from(api.hide).getOr(noop),
|
|
|
29499 |
isEnabled: Optional.from(api.isEnabled).getOr(always),
|
|
|
29500 |
setEnabled: state => {
|
| 1441 |
ariadna |
29501 |
const shouldSkip = state && (editor.mode.get() === 'readonly' || isDisabled(editor));
|
|
|
29502 |
if (!shouldSkip) {
|
| 1 |
efrain |
29503 |
Optional.from(api.setEnabled).each(f => f(state));
|
|
|
29504 |
}
|
|
|
29505 |
}
|
|
|
29506 |
};
|
|
|
29507 |
editor.ui = {
|
|
|
29508 |
...editor.ui,
|
|
|
29509 |
...uiApiFacade
|
|
|
29510 |
};
|
|
|
29511 |
};
|
|
|
29512 |
const init = async editor => {
|
|
|
29513 |
editor.dispatch('ScriptsLoaded');
|
|
|
29514 |
initIcons(editor);
|
|
|
29515 |
initTheme(editor);
|
|
|
29516 |
initModel(editor);
|
|
|
29517 |
initPlugins(editor);
|
|
|
29518 |
const renderInfo = await renderThemeUi(editor);
|
|
|
29519 |
augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
|
|
|
29520 |
editor.editorContainer = renderInfo.editorContainer;
|
|
|
29521 |
appendContentCssFromSettings(editor);
|
|
|
29522 |
if (editor.inline) {
|
|
|
29523 |
contentBodyLoaded(editor);
|
|
|
29524 |
} else {
|
|
|
29525 |
init$1(editor, {
|
|
|
29526 |
editorContainer: renderInfo.editorContainer,
|
|
|
29527 |
iframeContainer: renderInfo.iframeContainer
|
|
|
29528 |
});
|
|
|
29529 |
}
|
|
|
29530 |
};
|
|
|
29531 |
|
|
|
29532 |
const DOM$3 = DOMUtils.DOM;
|
|
|
29533 |
const hasSkipLoadPrefix = name => name.charAt(0) === '-';
|
|
|
29534 |
const loadLanguage = (scriptLoader, editor) => {
|
|
|
29535 |
const languageCode = getLanguageCode(editor);
|
|
|
29536 |
const languageUrl = getLanguageUrl(editor);
|
|
|
29537 |
if (!I18n.hasCode(languageCode) && languageCode !== 'en') {
|
|
|
29538 |
const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`;
|
|
|
29539 |
scriptLoader.add(url).catch(() => {
|
|
|
29540 |
languageLoadError(editor, url, languageCode);
|
|
|
29541 |
});
|
|
|
29542 |
}
|
|
|
29543 |
};
|
|
|
29544 |
const loadTheme = (editor, suffix) => {
|
|
|
29545 |
const theme = getTheme(editor);
|
|
|
29546 |
if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
|
|
|
29547 |
const themeUrl = getThemeUrl(editor);
|
|
|
29548 |
const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`;
|
|
|
29549 |
ThemeManager.load(theme, url).catch(() => {
|
|
|
29550 |
themeLoadError(editor, url, theme);
|
|
|
29551 |
});
|
|
|
29552 |
}
|
|
|
29553 |
};
|
|
|
29554 |
const loadModel = (editor, suffix) => {
|
|
|
29555 |
const model = getModel(editor);
|
|
|
29556 |
if (model !== 'plugin' && !has$2(ModelManager.urls, model)) {
|
|
|
29557 |
const modelUrl = getModelUrl(editor);
|
|
|
29558 |
const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`;
|
|
|
29559 |
ModelManager.load(model, url).catch(() => {
|
|
|
29560 |
modelLoadError(editor, url, model);
|
|
|
29561 |
});
|
|
|
29562 |
}
|
|
|
29563 |
};
|
|
|
29564 |
const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({
|
|
|
29565 |
url,
|
|
|
29566 |
name: Optional.none()
|
|
|
29567 |
}));
|
|
|
29568 |
const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({
|
|
|
29569 |
url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`,
|
|
|
29570 |
name: Optional.some(name)
|
|
|
29571 |
}));
|
|
|
29572 |
const loadIcons = (scriptLoader, editor, suffix) => {
|
|
|
29573 |
const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix);
|
|
|
29574 |
const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ''));
|
|
|
29575 |
each$e(cat([
|
|
|
29576 |
defaultIconsUrl,
|
|
|
29577 |
customIconsUrl
|
|
|
29578 |
]), urlMeta => {
|
|
|
29579 |
scriptLoader.add(urlMeta.url).catch(() => {
|
|
|
29580 |
iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
|
|
|
29581 |
});
|
|
|
29582 |
});
|
|
|
29583 |
};
|
|
|
29584 |
const loadPlugins = (editor, suffix) => {
|
|
|
29585 |
const loadPlugin = (name, url) => {
|
|
|
29586 |
PluginManager.load(name, url).catch(() => {
|
|
|
29587 |
pluginLoadError(editor, url, name);
|
|
|
29588 |
});
|
|
|
29589 |
};
|
|
|
29590 |
each$d(getExternalPlugins$1(editor), (url, name) => {
|
|
|
29591 |
loadPlugin(name, url);
|
|
|
29592 |
editor.options.set('plugins', getPlugins(editor).concat(name));
|
|
|
29593 |
});
|
|
|
29594 |
each$e(getPlugins(editor), plugin => {
|
|
|
29595 |
plugin = Tools.trim(plugin);
|
|
|
29596 |
if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
|
|
|
29597 |
loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`);
|
|
|
29598 |
}
|
|
|
29599 |
});
|
|
|
29600 |
};
|
|
|
29601 |
const isThemeLoaded = editor => {
|
|
|
29602 |
const theme = getTheme(editor);
|
|
|
29603 |
return !isString(theme) || isNonNullable(ThemeManager.get(theme));
|
|
|
29604 |
};
|
|
|
29605 |
const isModelLoaded = editor => {
|
|
|
29606 |
const model = getModel(editor);
|
|
|
29607 |
return isNonNullable(ModelManager.get(model));
|
|
|
29608 |
};
|
|
|
29609 |
const loadScripts = (editor, suffix) => {
|
|
|
29610 |
const scriptLoader = ScriptLoader.ScriptLoader;
|
|
|
29611 |
const initEditor = () => {
|
|
|
29612 |
if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
|
|
|
29613 |
init(editor);
|
|
|
29614 |
}
|
|
|
29615 |
};
|
|
|
29616 |
loadTheme(editor, suffix);
|
|
|
29617 |
loadModel(editor, suffix);
|
|
|
29618 |
loadLanguage(scriptLoader, editor);
|
|
|
29619 |
loadIcons(scriptLoader, editor, suffix);
|
|
|
29620 |
loadPlugins(editor, suffix);
|
|
|
29621 |
scriptLoader.loadQueue().then(initEditor, initEditor);
|
|
|
29622 |
};
|
|
|
29623 |
const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
|
|
|
29624 |
contentCssCors: hasContentCssCors(editor),
|
|
|
29625 |
referrerPolicy: getReferrerPolicy(editor)
|
|
|
29626 |
});
|
|
|
29627 |
const render = editor => {
|
|
|
29628 |
const id = editor.id;
|
|
|
29629 |
I18n.setCode(getLanguageCode(editor));
|
|
|
29630 |
const readyHandler = () => {
|
|
|
29631 |
DOM$3.unbind(window, 'ready', readyHandler);
|
|
|
29632 |
editor.render();
|
|
|
29633 |
};
|
|
|
29634 |
if (!EventUtils.Event.domLoaded) {
|
|
|
29635 |
DOM$3.bind(window, 'ready', readyHandler);
|
|
|
29636 |
return;
|
|
|
29637 |
}
|
|
|
29638 |
if (!editor.getElement()) {
|
|
|
29639 |
return;
|
|
|
29640 |
}
|
|
|
29641 |
const element = SugarElement.fromDom(editor.getElement());
|
|
|
29642 |
const snapshot = clone$4(element);
|
|
|
29643 |
editor.on('remove', () => {
|
| 1441 |
ariadna |
29644 |
eachr(element.dom.attributes, attr => remove$9(element, attr.name));
|
| 1 |
efrain |
29645 |
setAll$1(element, snapshot);
|
|
|
29646 |
});
|
|
|
29647 |
editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
|
|
|
29648 |
if (!isInline$1(editor)) {
|
|
|
29649 |
editor.orgVisibility = editor.getElement().style.visibility;
|
|
|
29650 |
editor.getElement().style.visibility = 'hidden';
|
|
|
29651 |
} else {
|
|
|
29652 |
editor.inline = true;
|
|
|
29653 |
}
|
|
|
29654 |
const form = editor.getElement().form || DOM$3.getParent(id, 'form');
|
|
|
29655 |
if (form) {
|
|
|
29656 |
editor.formElement = form;
|
|
|
29657 |
if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
|
|
|
29658 |
DOM$3.insertAfter(DOM$3.create('input', {
|
|
|
29659 |
type: 'hidden',
|
|
|
29660 |
name: id
|
|
|
29661 |
}), id);
|
|
|
29662 |
editor.hasHiddenInput = true;
|
|
|
29663 |
}
|
|
|
29664 |
editor.formEventDelegate = e => {
|
|
|
29665 |
editor.dispatch(e.type, e);
|
|
|
29666 |
};
|
|
|
29667 |
DOM$3.bind(form, 'submit reset', editor.formEventDelegate);
|
|
|
29668 |
editor.on('reset', () => {
|
|
|
29669 |
editor.resetContent();
|
|
|
29670 |
});
|
|
|
29671 |
if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
|
|
|
29672 |
form._mceOldSubmit = form.submit;
|
|
|
29673 |
form.submit = () => {
|
|
|
29674 |
editor.editorManager.triggerSave();
|
|
|
29675 |
editor.setDirty(false);
|
|
|
29676 |
return form._mceOldSubmit(form);
|
|
|
29677 |
};
|
|
|
29678 |
}
|
|
|
29679 |
}
|
|
|
29680 |
editor.windowManager = WindowManager(editor);
|
|
|
29681 |
editor.notificationManager = NotificationManager(editor);
|
|
|
29682 |
if (isEncodingXml(editor)) {
|
|
|
29683 |
editor.on('GetContent', e => {
|
|
|
29684 |
if (e.save) {
|
|
|
29685 |
e.content = DOM$3.encode(e.content);
|
|
|
29686 |
}
|
|
|
29687 |
});
|
|
|
29688 |
}
|
|
|
29689 |
if (shouldAddFormSubmitTrigger(editor)) {
|
|
|
29690 |
editor.on('submit', () => {
|
|
|
29691 |
if (editor.initialized) {
|
|
|
29692 |
editor.save();
|
|
|
29693 |
}
|
|
|
29694 |
});
|
|
|
29695 |
}
|
|
|
29696 |
if (shouldAddUnloadTrigger(editor)) {
|
|
|
29697 |
editor._beforeUnload = () => {
|
|
|
29698 |
if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
|
|
|
29699 |
editor.save({
|
|
|
29700 |
format: 'raw',
|
|
|
29701 |
no_events: true,
|
|
|
29702 |
set_dirty: false
|
|
|
29703 |
});
|
|
|
29704 |
}
|
|
|
29705 |
};
|
|
|
29706 |
editor.editorManager.on('BeforeUnload', editor._beforeUnload);
|
|
|
29707 |
}
|
|
|
29708 |
editor.editorManager.add(editor);
|
|
|
29709 |
loadScripts(editor, editor.suffix);
|
|
|
29710 |
};
|
|
|
29711 |
|
|
|
29712 |
const setEditableRoot = (editor, state) => {
|
|
|
29713 |
if (editor._editableRoot !== state) {
|
|
|
29714 |
editor._editableRoot = state;
|
| 1441 |
ariadna |
29715 |
if (!isDisabled(editor)) {
|
| 1 |
efrain |
29716 |
editor.getBody().contentEditable = String(editor.hasEditableRoot());
|
|
|
29717 |
editor.nodeChanged();
|
|
|
29718 |
}
|
|
|
29719 |
fireEditableRootStateChange(editor, state);
|
|
|
29720 |
}
|
|
|
29721 |
};
|
|
|
29722 |
const hasEditableRoot = editor => editor._editableRoot;
|
|
|
29723 |
|
|
|
29724 |
const sectionResult = (sections, settings) => ({
|
|
|
29725 |
sections: constant(sections),
|
|
|
29726 |
options: constant(settings)
|
|
|
29727 |
});
|
| 1441 |
ariadna |
29728 |
const deviceDetection = detect$1().deviceType;
|
| 1 |
efrain |
29729 |
const isPhone = deviceDetection.isPhone();
|
|
|
29730 |
const isTablet = deviceDetection.isTablet();
|
|
|
29731 |
const normalizePlugins = plugins => {
|
|
|
29732 |
if (isNullable(plugins)) {
|
|
|
29733 |
return [];
|
|
|
29734 |
} else {
|
|
|
29735 |
const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
|
|
|
29736 |
const trimmedPlugins = map$3(pluginNames, trim$4);
|
|
|
29737 |
return filter$5(trimmedPlugins, isNotEmpty);
|
|
|
29738 |
}
|
|
|
29739 |
};
|
|
|
29740 |
const extractSections = (keys, options) => {
|
|
|
29741 |
const result = bifilter(options, (value, key) => {
|
|
|
29742 |
return contains$2(keys, key);
|
|
|
29743 |
});
|
|
|
29744 |
return sectionResult(result.t, result.f);
|
|
|
29745 |
};
|
|
|
29746 |
const getSection = (sectionResult, name, defaults = {}) => {
|
|
|
29747 |
const sections = sectionResult.sections();
|
|
|
29748 |
const sectionOptions = get$a(sections, name).getOr({});
|
|
|
29749 |
return Tools.extend({}, defaults, sectionOptions);
|
|
|
29750 |
};
|
|
|
29751 |
const hasSection = (sectionResult, name) => {
|
|
|
29752 |
return has$2(sectionResult.sections(), name);
|
|
|
29753 |
};
|
|
|
29754 |
const getSectionConfig = (sectionResult, name) => {
|
|
|
29755 |
return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
|
|
|
29756 |
};
|
|
|
29757 |
const getMobileOverrideOptions = (mobileOptions, isPhone) => {
|
|
|
29758 |
const defaultMobileOptions = {
|
|
|
29759 |
table_grid: false,
|
|
|
29760 |
object_resizing: false,
|
|
|
29761 |
resize: false,
|
|
|
29762 |
toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'),
|
|
|
29763 |
toolbar_sticky: false
|
|
|
29764 |
};
|
|
|
29765 |
const defaultPhoneOptions = { menubar: false };
|
|
|
29766 |
return {
|
|
|
29767 |
...defaultMobileOptions,
|
|
|
29768 |
...isPhone ? defaultPhoneOptions : {}
|
|
|
29769 |
};
|
|
|
29770 |
};
|
|
|
29771 |
const getExternalPlugins = (overrideOptions, options) => {
|
|
|
29772 |
var _a;
|
|
|
29773 |
const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
|
|
|
29774 |
if (overrideOptions && overrideOptions.external_plugins) {
|
|
|
29775 |
return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
|
|
|
29776 |
} else {
|
|
|
29777 |
return userDefinedExternalPlugins;
|
|
|
29778 |
}
|
|
|
29779 |
};
|
|
|
29780 |
const combinePlugins = (forcedPlugins, plugins) => [
|
|
|
29781 |
...normalizePlugins(forcedPlugins),
|
|
|
29782 |
...normalizePlugins(plugins)
|
|
|
29783 |
];
|
|
|
29784 |
const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => {
|
|
|
29785 |
if (isMobileDevice && hasSection(sectionResult, 'mobile')) {
|
|
|
29786 |
return mobilePlugins;
|
|
|
29787 |
} else {
|
|
|
29788 |
return desktopPlugins;
|
|
|
29789 |
}
|
|
|
29790 |
};
|
|
|
29791 |
const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => {
|
|
|
29792 |
const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
|
|
|
29793 |
const desktopPlugins = normalizePlugins(options.plugins);
|
|
|
29794 |
const mobileConfig = getSectionConfig(sectionResult, 'mobile');
|
|
|
29795 |
const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
|
|
|
29796 |
const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins);
|
|
|
29797 |
const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
|
|
|
29798 |
return Tools.extend(options, {
|
|
|
29799 |
forced_plugins: forcedPlugins,
|
|
|
29800 |
plugins: combinedPlugins
|
|
|
29801 |
});
|
|
|
29802 |
};
|
|
|
29803 |
const isOnMobile = (isMobileDevice, sectionResult) => {
|
|
|
29804 |
return isMobileDevice && hasSection(sectionResult, 'mobile');
|
|
|
29805 |
};
|
|
|
29806 |
const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => {
|
|
|
29807 |
var _a;
|
|
|
29808 |
const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {};
|
|
|
29809 |
const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options));
|
|
|
29810 |
const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) });
|
|
|
29811 |
return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions);
|
|
|
29812 |
};
|
| 1441 |
ariadna |
29813 |
const normalizeOptions = (defaultOverrideOptions, options) => {
|
|
|
29814 |
const copiedOptions = merge(options);
|
|
|
29815 |
return combineOptions(isPhone || isTablet, isPhone, copiedOptions, defaultOverrideOptions, copiedOptions);
|
|
|
29816 |
};
|
| 1 |
efrain |
29817 |
|
|
|
29818 |
const addVisual = (editor, elm) => addVisual$1(editor, elm);
|
|
|
29819 |
|
| 1441 |
ariadna |
29820 |
const registerExecCommands$2 = editor => {
|
| 1 |
efrain |
29821 |
const toggleFormat = (name, value) => {
|
|
|
29822 |
editor.formatter.toggle(name, value);
|
|
|
29823 |
editor.nodeChanged();
|
|
|
29824 |
};
|
|
|
29825 |
const toggleAlign = align => () => {
|
|
|
29826 |
each$e('left,center,right,justify'.split(','), name => {
|
|
|
29827 |
if (align !== name) {
|
|
|
29828 |
editor.formatter.remove('align' + name);
|
|
|
29829 |
}
|
|
|
29830 |
});
|
|
|
29831 |
if (align !== 'none') {
|
|
|
29832 |
toggleFormat('align' + align);
|
|
|
29833 |
}
|
|
|
29834 |
};
|
|
|
29835 |
editor.editorCommands.addCommands({
|
|
|
29836 |
JustifyLeft: toggleAlign('left'),
|
|
|
29837 |
JustifyCenter: toggleAlign('center'),
|
|
|
29838 |
JustifyRight: toggleAlign('right'),
|
|
|
29839 |
JustifyFull: toggleAlign('justify'),
|
|
|
29840 |
JustifyNone: toggleAlign('none')
|
|
|
29841 |
});
|
|
|
29842 |
};
|
| 1441 |
ariadna |
29843 |
const registerQueryStateCommands = editor => {
|
| 1 |
efrain |
29844 |
const alignStates = name => () => {
|
|
|
29845 |
const selection = editor.selection;
|
|
|
29846 |
const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
|
|
|
29847 |
return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name)));
|
|
|
29848 |
};
|
|
|
29849 |
editor.editorCommands.addCommands({
|
|
|
29850 |
JustifyLeft: alignStates('alignleft'),
|
|
|
29851 |
JustifyCenter: alignStates('aligncenter'),
|
|
|
29852 |
JustifyRight: alignStates('alignright'),
|
|
|
29853 |
JustifyFull: alignStates('alignjustify')
|
|
|
29854 |
}, 'state');
|
|
|
29855 |
};
|
| 1441 |
ariadna |
29856 |
const registerCommands$a = editor => {
|
|
|
29857 |
registerExecCommands$2(editor);
|
|
|
29858 |
registerQueryStateCommands(editor);
|
| 1 |
efrain |
29859 |
};
|
|
|
29860 |
|
| 1441 |
ariadna |
29861 |
const registerCommands$9 = editor => {
|
| 1 |
efrain |
29862 |
editor.editorCommands.addCommands({
|
|
|
29863 |
'Cut,Copy,Paste': command => {
|
|
|
29864 |
const doc = editor.getDoc();
|
|
|
29865 |
let failed;
|
|
|
29866 |
try {
|
|
|
29867 |
doc.execCommand(command);
|
| 1441 |
ariadna |
29868 |
} catch (_a) {
|
| 1 |
efrain |
29869 |
failed = true;
|
|
|
29870 |
}
|
|
|
29871 |
if (command === 'paste' && !doc.queryCommandEnabled(command)) {
|
|
|
29872 |
failed = true;
|
|
|
29873 |
}
|
|
|
29874 |
if (failed || !doc.queryCommandSupported(command)) {
|
|
|
29875 |
let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
|
|
|
29876 |
if (Env.os.isMacOS() || Env.os.isiOS()) {
|
|
|
29877 |
msg = msg.replace(/Ctrl\+/g, '\u2318+');
|
|
|
29878 |
}
|
|
|
29879 |
editor.notificationManager.open({
|
|
|
29880 |
text: msg,
|
|
|
29881 |
type: 'error'
|
|
|
29882 |
});
|
|
|
29883 |
}
|
|
|
29884 |
}
|
|
|
29885 |
});
|
|
|
29886 |
};
|
|
|
29887 |
|
|
|
29888 |
const trimOrPadLeftRight = (dom, rng, html, schema) => {
|
|
|
29889 |
const root = SugarElement.fromDom(dom.getRoot());
|
|
|
29890 |
if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng), schema)) {
|
|
|
29891 |
html = html.replace(/^ /, ' ');
|
|
|
29892 |
} else {
|
|
|
29893 |
html = html.replace(/^ /, ' ');
|
|
|
29894 |
}
|
|
|
29895 |
if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng), schema)) {
|
|
|
29896 |
html = html.replace(/( | )(<br( \/)>)?$/, ' ');
|
|
|
29897 |
} else {
|
|
|
29898 |
html = html.replace(/ (<br( \/)?>)?$/, ' ');
|
|
|
29899 |
}
|
|
|
29900 |
return html;
|
|
|
29901 |
};
|
|
|
29902 |
|
|
|
29903 |
const processValue$1 = value => {
|
|
|
29904 |
if (typeof value !== 'string') {
|
|
|
29905 |
const details = Tools.extend({
|
|
|
29906 |
paste: value.paste,
|
|
|
29907 |
data: { paste: value.paste }
|
|
|
29908 |
}, value);
|
|
|
29909 |
return {
|
|
|
29910 |
content: value.content,
|
|
|
29911 |
details
|
|
|
29912 |
};
|
|
|
29913 |
}
|
|
|
29914 |
return {
|
|
|
29915 |
content: value,
|
|
|
29916 |
details: {}
|
|
|
29917 |
};
|
|
|
29918 |
};
|
|
|
29919 |
const trimOrPad = (editor, value) => {
|
|
|
29920 |
const selection = editor.selection;
|
|
|
29921 |
const dom = editor.dom;
|
|
|
29922 |
if (/^ | $/.test(value)) {
|
|
|
29923 |
return trimOrPadLeftRight(dom, selection.getRng(), value, editor.schema);
|
|
|
29924 |
} else {
|
|
|
29925 |
return value;
|
|
|
29926 |
}
|
|
|
29927 |
};
|
|
|
29928 |
const insertAtCaret = (editor, value) => {
|
|
|
29929 |
if (editor.selection.isEditable()) {
|
|
|
29930 |
const {content, details} = processValue$1(value);
|
|
|
29931 |
preProcessSetContent(editor, {
|
|
|
29932 |
...details,
|
|
|
29933 |
content: trimOrPad(editor, content),
|
|
|
29934 |
format: 'html',
|
|
|
29935 |
set: false,
|
|
|
29936 |
selection: true
|
|
|
29937 |
}).each(args => {
|
|
|
29938 |
const insertedContent = insertContent$1(editor, args.content, details);
|
|
|
29939 |
postProcessSetContent(editor, insertedContent, args);
|
|
|
29940 |
editor.addVisual();
|
|
|
29941 |
});
|
|
|
29942 |
}
|
|
|
29943 |
};
|
|
|
29944 |
|
| 1441 |
ariadna |
29945 |
const registerCommands$8 = editor => {
|
| 1 |
efrain |
29946 |
editor.editorCommands.addCommands({
|
|
|
29947 |
mceCleanup: () => {
|
|
|
29948 |
const bm = editor.selection.getBookmark();
|
|
|
29949 |
editor.setContent(editor.getContent());
|
|
|
29950 |
editor.selection.moveToBookmark(bm);
|
|
|
29951 |
},
|
|
|
29952 |
insertImage: (_command, _ui, value) => {
|
|
|
29953 |
insertAtCaret(editor, editor.dom.createHTML('img', { src: value }));
|
|
|
29954 |
},
|
|
|
29955 |
insertHorizontalRule: () => {
|
|
|
29956 |
editor.execCommand('mceInsertContent', false, '<hr>');
|
|
|
29957 |
},
|
|
|
29958 |
insertText: (_command, _ui, value) => {
|
|
|
29959 |
insertAtCaret(editor, editor.dom.encode(value));
|
|
|
29960 |
},
|
|
|
29961 |
insertHTML: (_command, _ui, value) => {
|
|
|
29962 |
insertAtCaret(editor, value);
|
|
|
29963 |
},
|
|
|
29964 |
mceInsertContent: (_command, _ui, value) => {
|
|
|
29965 |
insertAtCaret(editor, value);
|
|
|
29966 |
},
|
|
|
29967 |
mceSetContent: (_command, _ui, value) => {
|
|
|
29968 |
editor.setContent(value);
|
|
|
29969 |
},
|
|
|
29970 |
mceReplaceContent: (_command, _ui, value) => {
|
|
|
29971 |
editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
|
|
|
29972 |
},
|
|
|
29973 |
mceNewDocument: () => {
|
|
|
29974 |
editor.setContent(getNewDocumentContent(editor));
|
|
|
29975 |
}
|
|
|
29976 |
});
|
|
|
29977 |
};
|
|
|
29978 |
|
|
|
29979 |
const legacyPropNames = {
|
|
|
29980 |
'font-size': 'size',
|
|
|
29981 |
'font-family': 'face'
|
|
|
29982 |
};
|
|
|
29983 |
const isFont = isTag('font');
|
|
|
29984 |
const getSpecifiedFontProp = (propName, rootElm, elm) => {
|
|
|
29985 |
const getProperty = elm => getRaw(elm, propName).orThunk(() => {
|
|
|
29986 |
if (isFont(elm)) {
|
|
|
29987 |
return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName));
|
|
|
29988 |
} else {
|
|
|
29989 |
return Optional.none();
|
|
|
29990 |
}
|
|
|
29991 |
});
|
|
|
29992 |
const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm);
|
|
|
29993 |
return closest$1(SugarElement.fromDom(elm), elm => getProperty(elm), isRoot);
|
|
|
29994 |
};
|
|
|
29995 |
const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
|
|
|
29996 |
const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
|
|
|
29997 |
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('');
|
|
|
29998 |
const getFontSize = getFontProp('font-size');
|
|
|
29999 |
const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family'));
|
|
|
30000 |
|
|
|
30001 |
const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => {
|
|
|
30002 |
const container = caret.container();
|
| 1441 |
ariadna |
30003 |
return Optional.from(isText$b(container) ? container.parentNode : container);
|
| 1 |
efrain |
30004 |
});
|
|
|
30005 |
const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => {
|
|
|
30006 |
const root = editor.getBody();
|
|
|
30007 |
const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
|
|
|
30008 |
return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
|
|
|
30009 |
});
|
|
|
30010 |
const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder);
|
|
|
30011 |
const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
|
|
|
30012 |
|
|
|
30013 |
const fromFontSizeNumber = (editor, value) => {
|
|
|
30014 |
if (/^[0-9.]+$/.test(value)) {
|
|
|
30015 |
const fontSizeNumber = parseInt(value, 10);
|
|
|
30016 |
if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
|
|
|
30017 |
const fontSizes = getFontStyleValues(editor);
|
|
|
30018 |
const fontClasses = getFontSizeClasses(editor);
|
|
|
30019 |
if (fontClasses.length > 0) {
|
|
|
30020 |
return fontClasses[fontSizeNumber - 1] || value;
|
|
|
30021 |
} else {
|
|
|
30022 |
return fontSizes[fontSizeNumber - 1] || value;
|
|
|
30023 |
}
|
|
|
30024 |
} else {
|
|
|
30025 |
return value;
|
|
|
30026 |
}
|
|
|
30027 |
} else {
|
|
|
30028 |
return value;
|
|
|
30029 |
}
|
|
|
30030 |
};
|
|
|
30031 |
const normalizeFontNames = font => {
|
|
|
30032 |
const fonts = font.split(/\s*,\s*/);
|
|
|
30033 |
return map$3(fonts, font => {
|
|
|
30034 |
if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) {
|
|
|
30035 |
return `'${ font }'`;
|
|
|
30036 |
} else {
|
|
|
30037 |
return font;
|
|
|
30038 |
}
|
|
|
30039 |
}).join(',');
|
|
|
30040 |
};
|
|
|
30041 |
const fontNameAction = (editor, value) => {
|
|
|
30042 |
const font = fromFontSizeNumber(editor, value);
|
|
|
30043 |
editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
|
|
|
30044 |
editor.nodeChanged();
|
|
|
30045 |
};
|
|
|
30046 |
const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr('');
|
|
|
30047 |
const fontSizeAction = (editor, value) => {
|
|
|
30048 |
editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
|
|
|
30049 |
editor.nodeChanged();
|
|
|
30050 |
};
|
|
|
30051 |
const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr('');
|
|
|
30052 |
|
|
|
30053 |
const lineHeightQuery = editor => mapRange(editor, elm => {
|
|
|
30054 |
const root = SugarElement.fromDom(editor.getBody());
|
|
|
30055 |
const specifiedStyle = closest$1(elm, elm => getRaw(elm, 'line-height'), curry(eq, root));
|
|
|
30056 |
const computedStyle = () => {
|
|
|
30057 |
const lineHeight = parseFloat(get$7(elm, 'line-height'));
|
|
|
30058 |
const fontSize = parseFloat(get$7(elm, 'font-size'));
|
|
|
30059 |
return String(lineHeight / fontSize);
|
|
|
30060 |
};
|
|
|
30061 |
return specifiedStyle.getOrThunk(computedStyle);
|
|
|
30062 |
}).getOr('');
|
|
|
30063 |
const lineHeightAction = (editor, lineHeight) => {
|
|
|
30064 |
editor.formatter.toggle('lineheight', { value: String(lineHeight) });
|
|
|
30065 |
editor.nodeChanged();
|
|
|
30066 |
};
|
|
|
30067 |
|
| 1441 |
ariadna |
30068 |
const registerExecCommands$1 = editor => {
|
| 1 |
efrain |
30069 |
const toggleFormat = (name, value) => {
|
|
|
30070 |
editor.formatter.toggle(name, value);
|
|
|
30071 |
editor.nodeChanged();
|
|
|
30072 |
};
|
|
|
30073 |
editor.editorCommands.addCommands({
|
|
|
30074 |
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => {
|
|
|
30075 |
toggleFormat(command);
|
|
|
30076 |
},
|
|
|
30077 |
'ForeColor,HiliteColor': (command, _ui, value) => {
|
|
|
30078 |
toggleFormat(command, { value });
|
|
|
30079 |
},
|
|
|
30080 |
'BackColor': (_command, _ui, value) => {
|
|
|
30081 |
toggleFormat('hilitecolor', { value });
|
|
|
30082 |
},
|
|
|
30083 |
'FontName': (_command, _ui, value) => {
|
|
|
30084 |
fontNameAction(editor, value);
|
|
|
30085 |
},
|
|
|
30086 |
'FontSize': (_command, _ui, value) => {
|
|
|
30087 |
fontSizeAction(editor, value);
|
|
|
30088 |
},
|
|
|
30089 |
'LineHeight': (_command, _ui, value) => {
|
|
|
30090 |
lineHeightAction(editor, value);
|
|
|
30091 |
},
|
|
|
30092 |
'Lang': (command, _ui, lang) => {
|
|
|
30093 |
var _a;
|
|
|
30094 |
toggleFormat(command, {
|
|
|
30095 |
value: lang.code,
|
|
|
30096 |
customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null
|
|
|
30097 |
});
|
|
|
30098 |
},
|
|
|
30099 |
'RemoveFormat': command => {
|
|
|
30100 |
editor.formatter.remove(command);
|
|
|
30101 |
},
|
|
|
30102 |
'mceBlockQuote': () => {
|
|
|
30103 |
toggleFormat('blockquote');
|
|
|
30104 |
},
|
|
|
30105 |
'FormatBlock': (_command, _ui, value) => {
|
|
|
30106 |
toggleFormat(isString(value) ? value : 'p');
|
|
|
30107 |
},
|
|
|
30108 |
'mceToggleFormat': (_command, _ui, value) => {
|
|
|
30109 |
toggleFormat(value);
|
|
|
30110 |
}
|
|
|
30111 |
});
|
|
|
30112 |
};
|
|
|
30113 |
const registerQueryValueCommands = editor => {
|
|
|
30114 |
const isFormatMatch = name => editor.formatter.match(name);
|
|
|
30115 |
editor.editorCommands.addCommands({
|
|
|
30116 |
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command),
|
|
|
30117 |
'mceBlockQuote': () => isFormatMatch('blockquote')
|
|
|
30118 |
}, 'state');
|
|
|
30119 |
editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor));
|
|
|
30120 |
editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor));
|
|
|
30121 |
editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor));
|
|
|
30122 |
};
|
| 1441 |
ariadna |
30123 |
const registerCommands$7 = editor => {
|
|
|
30124 |
registerExecCommands$1(editor);
|
| 1 |
efrain |
30125 |
registerQueryValueCommands(editor);
|
|
|
30126 |
};
|
|
|
30127 |
|
| 1441 |
ariadna |
30128 |
const registerCommands$6 = editor => {
|
| 1 |
efrain |
30129 |
editor.editorCommands.addCommands({
|
|
|
30130 |
mceAddUndoLevel: () => {
|
|
|
30131 |
editor.undoManager.add();
|
|
|
30132 |
},
|
|
|
30133 |
mceEndUndoLevel: () => {
|
|
|
30134 |
editor.undoManager.add();
|
|
|
30135 |
},
|
|
|
30136 |
Undo: () => {
|
|
|
30137 |
editor.undoManager.undo();
|
|
|
30138 |
},
|
|
|
30139 |
Redo: () => {
|
|
|
30140 |
editor.undoManager.redo();
|
|
|
30141 |
}
|
|
|
30142 |
});
|
|
|
30143 |
};
|
|
|
30144 |
|
| 1441 |
ariadna |
30145 |
const registerCommands$5 = editor => {
|
| 1 |
efrain |
30146 |
editor.editorCommands.addCommands({
|
|
|
30147 |
Indent: () => {
|
|
|
30148 |
indent(editor);
|
|
|
30149 |
},
|
|
|
30150 |
Outdent: () => {
|
|
|
30151 |
outdent(editor);
|
|
|
30152 |
}
|
|
|
30153 |
});
|
|
|
30154 |
editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state');
|
|
|
30155 |
};
|
|
|
30156 |
|
| 1441 |
ariadna |
30157 |
const registerCommands$4 = editor => {
|
| 1 |
efrain |
30158 |
const applyLinkToSelection = (_command, _ui, value) => {
|
| 1441 |
ariadna |
30159 |
if (editor.mode.isReadOnly()) {
|
|
|
30160 |
return;
|
|
|
30161 |
}
|
| 1 |
efrain |
30162 |
const linkDetails = isString(value) ? { href: value } : value;
|
|
|
30163 |
const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
|
|
|
30164 |
if (isObject(linkDetails) && isString(linkDetails.href)) {
|
|
|
30165 |
linkDetails.href = linkDetails.href.replace(/ /g, '%20');
|
|
|
30166 |
if (!anchor || !linkDetails.href) {
|
|
|
30167 |
editor.formatter.remove('link');
|
|
|
30168 |
}
|
|
|
30169 |
if (linkDetails.href) {
|
|
|
30170 |
editor.formatter.apply('link', linkDetails, anchor);
|
|
|
30171 |
}
|
|
|
30172 |
}
|
|
|
30173 |
};
|
|
|
30174 |
editor.editorCommands.addCommands({
|
|
|
30175 |
unlink: () => {
|
|
|
30176 |
if (editor.selection.isEditable()) {
|
|
|
30177 |
if (editor.selection.isCollapsed()) {
|
|
|
30178 |
const elm = editor.dom.getParent(editor.selection.getStart(), 'a');
|
|
|
30179 |
if (elm) {
|
|
|
30180 |
editor.dom.remove(elm, true);
|
|
|
30181 |
}
|
|
|
30182 |
return;
|
|
|
30183 |
}
|
|
|
30184 |
editor.formatter.remove('link');
|
|
|
30185 |
}
|
|
|
30186 |
},
|
|
|
30187 |
mceInsertLink: applyLinkToSelection,
|
|
|
30188 |
createLink: applyLinkToSelection
|
|
|
30189 |
});
|
|
|
30190 |
};
|
|
|
30191 |
|
|
|
30192 |
const getTopParentBlock = (editor, node, root, container) => {
|
|
|
30193 |
const dom = editor.dom;
|
|
|
30194 |
const selector = node => dom.isBlock(node) && node.parentElement === root;
|
|
|
30195 |
const topParentBlock = selector(node) ? node : dom.getParent(container, selector, root);
|
|
|
30196 |
return Optional.from(topParentBlock).map(SugarElement.fromDom);
|
|
|
30197 |
};
|
|
|
30198 |
const insert = (editor, before) => {
|
| 1441 |
ariadna |
30199 |
if (editor.mode.isReadOnly()) {
|
|
|
30200 |
return;
|
|
|
30201 |
}
|
| 1 |
efrain |
30202 |
const dom = editor.dom;
|
|
|
30203 |
const rng = editor.selection.getRng();
|
|
|
30204 |
const node = before ? editor.selection.getStart() : editor.selection.getEnd();
|
|
|
30205 |
const container = before ? rng.startContainer : rng.endContainer;
|
|
|
30206 |
const root = getEditableRoot(dom, container);
|
|
|
30207 |
if (!root || !root.isContentEditable) {
|
|
|
30208 |
return;
|
|
|
30209 |
}
|
|
|
30210 |
const insertFn = before ? before$3 : after$4;
|
|
|
30211 |
const newBlockName = getForcedRootBlock(editor);
|
|
|
30212 |
getTopParentBlock(editor, node, root, container).each(parentBlock => {
|
|
|
30213 |
const newBlock = createNewBlock(editor, container, parentBlock.dom, root, false, newBlockName);
|
|
|
30214 |
insertFn(parentBlock, SugarElement.fromDom(newBlock));
|
|
|
30215 |
editor.selection.setCursorLocation(newBlock, 0);
|
|
|
30216 |
editor.dispatch('NewBlock', { newBlock });
|
|
|
30217 |
fireInputEvent(editor, 'insertParagraph');
|
|
|
30218 |
});
|
|
|
30219 |
};
|
|
|
30220 |
const insertBefore = editor => insert(editor, true);
|
|
|
30221 |
const insertAfter = editor => insert(editor, false);
|
|
|
30222 |
|
|
|
30223 |
const registerCommands$3 = editor => {
|
|
|
30224 |
editor.editorCommands.addCommands({
|
|
|
30225 |
InsertNewBlockBefore: () => {
|
|
|
30226 |
insertBefore(editor);
|
|
|
30227 |
},
|
|
|
30228 |
InsertNewBlockAfter: () => {
|
|
|
30229 |
insertAfter(editor);
|
|
|
30230 |
}
|
|
|
30231 |
});
|
|
|
30232 |
};
|
|
|
30233 |
|
|
|
30234 |
const registerCommands$2 = editor => {
|
|
|
30235 |
editor.editorCommands.addCommands({
|
|
|
30236 |
insertParagraph: () => {
|
|
|
30237 |
insertBreak(blockbreak, editor);
|
|
|
30238 |
},
|
|
|
30239 |
mceInsertNewLine: (_command, _ui, value) => {
|
|
|
30240 |
insert$1(editor, value);
|
|
|
30241 |
},
|
|
|
30242 |
InsertLineBreak: (_command, _ui, _value) => {
|
|
|
30243 |
insertBreak(linebreak, editor);
|
|
|
30244 |
}
|
|
|
30245 |
});
|
|
|
30246 |
};
|
|
|
30247 |
|
|
|
30248 |
const registerCommands$1 = editor => {
|
|
|
30249 |
editor.editorCommands.addCommands({
|
|
|
30250 |
mceSelectNodeDepth: (_command, _ui, value) => {
|
|
|
30251 |
let counter = 0;
|
|
|
30252 |
editor.dom.getParent(editor.selection.getNode(), node => {
|
|
|
30253 |
if (isElement$6(node) && counter++ === value) {
|
|
|
30254 |
editor.selection.select(node);
|
|
|
30255 |
return false;
|
|
|
30256 |
} else {
|
|
|
30257 |
return true;
|
|
|
30258 |
}
|
|
|
30259 |
}, editor.getBody());
|
|
|
30260 |
},
|
|
|
30261 |
mceSelectNode: (_command, _ui, value) => {
|
|
|
30262 |
editor.selection.select(value);
|
|
|
30263 |
},
|
|
|
30264 |
selectAll: () => {
|
|
|
30265 |
const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3);
|
|
|
30266 |
if (editingHost) {
|
|
|
30267 |
const rng = editor.dom.createRng();
|
|
|
30268 |
rng.selectNodeContents(editingHost);
|
|
|
30269 |
editor.selection.setRng(rng);
|
|
|
30270 |
}
|
|
|
30271 |
}
|
|
|
30272 |
});
|
|
|
30273 |
};
|
|
|
30274 |
|
|
|
30275 |
const registerExecCommands = editor => {
|
|
|
30276 |
editor.editorCommands.addCommands({
|
|
|
30277 |
mceRemoveNode: (_command, _ui, value) => {
|
|
|
30278 |
const node = value !== null && value !== void 0 ? value : editor.selection.getNode();
|
|
|
30279 |
if (node !== editor.getBody()) {
|
|
|
30280 |
const bm = editor.selection.getBookmark();
|
|
|
30281 |
editor.dom.remove(node, true);
|
|
|
30282 |
editor.selection.moveToBookmark(bm);
|
|
|
30283 |
}
|
|
|
30284 |
},
|
|
|
30285 |
mcePrint: () => {
|
|
|
30286 |
editor.getWin().print();
|
|
|
30287 |
},
|
|
|
30288 |
mceFocus: (_command, _ui, value) => {
|
|
|
30289 |
focus(editor, value === true);
|
|
|
30290 |
},
|
|
|
30291 |
mceToggleVisualAid: () => {
|
|
|
30292 |
editor.hasVisual = !editor.hasVisual;
|
|
|
30293 |
editor.addVisual();
|
|
|
30294 |
}
|
|
|
30295 |
});
|
|
|
30296 |
};
|
|
|
30297 |
const registerCommands = editor => {
|
|
|
30298 |
registerCommands$a(editor);
|
| 1441 |
ariadna |
30299 |
registerCommands$9(editor);
|
|
|
30300 |
registerCommands$6(editor);
|
| 1 |
efrain |
30301 |
registerCommands$1(editor);
|
| 1441 |
ariadna |
30302 |
registerCommands$8(editor);
|
|
|
30303 |
registerCommands$4(editor);
|
| 1 |
efrain |
30304 |
registerCommands$5(editor);
|
|
|
30305 |
registerCommands$3(editor);
|
|
|
30306 |
registerCommands$2(editor);
|
| 1441 |
ariadna |
30307 |
registerCommands$7(editor);
|
| 1 |
efrain |
30308 |
registerExecCommands(editor);
|
|
|
30309 |
};
|
|
|
30310 |
|
|
|
30311 |
const selectionSafeCommands = ['toggleview'];
|
|
|
30312 |
const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase());
|
|
|
30313 |
class EditorCommands {
|
|
|
30314 |
constructor(editor) {
|
|
|
30315 |
this.commands = {
|
|
|
30316 |
state: {},
|
|
|
30317 |
exec: {},
|
|
|
30318 |
value: {}
|
|
|
30319 |
};
|
|
|
30320 |
this.editor = editor;
|
|
|
30321 |
}
|
|
|
30322 |
execCommand(command, ui = false, value, args) {
|
|
|
30323 |
const editor = this.editor;
|
|
|
30324 |
const lowerCaseCommand = command.toLowerCase();
|
|
|
30325 |
const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
|
|
|
30326 |
if (editor.removed) {
|
|
|
30327 |
return false;
|
|
|
30328 |
}
|
|
|
30329 |
if (lowerCaseCommand !== 'mcefocus') {
|
|
|
30330 |
if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
|
|
|
30331 |
editor.focus();
|
|
|
30332 |
} else {
|
|
|
30333 |
restore(editor);
|
|
|
30334 |
}
|
|
|
30335 |
}
|
|
|
30336 |
const eventArgs = editor.dispatch('BeforeExecCommand', {
|
|
|
30337 |
command,
|
|
|
30338 |
ui,
|
|
|
30339 |
value
|
|
|
30340 |
});
|
|
|
30341 |
if (eventArgs.isDefaultPrevented()) {
|
|
|
30342 |
return false;
|
|
|
30343 |
}
|
|
|
30344 |
const func = this.commands.exec[lowerCaseCommand];
|
|
|
30345 |
if (isFunction(func)) {
|
|
|
30346 |
func(lowerCaseCommand, ui, value);
|
|
|
30347 |
editor.dispatch('ExecCommand', {
|
|
|
30348 |
command,
|
|
|
30349 |
ui,
|
|
|
30350 |
value
|
|
|
30351 |
});
|
|
|
30352 |
return true;
|
|
|
30353 |
}
|
|
|
30354 |
return false;
|
|
|
30355 |
}
|
|
|
30356 |
queryCommandState(command) {
|
|
|
30357 |
if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
|
|
|
30358 |
return false;
|
|
|
30359 |
}
|
|
|
30360 |
const lowerCaseCommand = command.toLowerCase();
|
|
|
30361 |
const func = this.commands.state[lowerCaseCommand];
|
|
|
30362 |
if (isFunction(func)) {
|
|
|
30363 |
return func(lowerCaseCommand);
|
|
|
30364 |
}
|
|
|
30365 |
return false;
|
|
|
30366 |
}
|
|
|
30367 |
queryCommandValue(command) {
|
|
|
30368 |
if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
|
|
|
30369 |
return '';
|
|
|
30370 |
}
|
|
|
30371 |
const lowerCaseCommand = command.toLowerCase();
|
|
|
30372 |
const func = this.commands.value[lowerCaseCommand];
|
|
|
30373 |
if (isFunction(func)) {
|
|
|
30374 |
return func(lowerCaseCommand);
|
|
|
30375 |
}
|
|
|
30376 |
return '';
|
|
|
30377 |
}
|
|
|
30378 |
addCommands(commandList, type = 'exec') {
|
|
|
30379 |
const commands = this.commands;
|
|
|
30380 |
each$d(commandList, (callback, command) => {
|
|
|
30381 |
each$e(command.toLowerCase().split(','), command => {
|
|
|
30382 |
commands[type][command] = callback;
|
|
|
30383 |
});
|
|
|
30384 |
});
|
|
|
30385 |
}
|
|
|
30386 |
addCommand(command, callback, scope) {
|
|
|
30387 |
const lowerCaseCommand = command.toLowerCase();
|
|
|
30388 |
this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value);
|
|
|
30389 |
}
|
|
|
30390 |
queryCommandSupported(command) {
|
|
|
30391 |
const lowerCaseCommand = command.toLowerCase();
|
|
|
30392 |
if (this.commands.exec[lowerCaseCommand]) {
|
|
|
30393 |
return true;
|
|
|
30394 |
} else {
|
|
|
30395 |
return false;
|
|
|
30396 |
}
|
|
|
30397 |
}
|
|
|
30398 |
addQueryStateHandler(command, callback, scope) {
|
|
|
30399 |
this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
|
|
|
30400 |
}
|
|
|
30401 |
addQueryValueHandler(command, callback, scope) {
|
|
|
30402 |
this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
|
|
|
30403 |
}
|
|
|
30404 |
}
|
|
|
30405 |
|
|
|
30406 |
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', ' ');
|
|
|
30407 |
class EventDispatcher {
|
|
|
30408 |
static isNative(name) {
|
|
|
30409 |
return !!nativeEvents[name.toLowerCase()];
|
|
|
30410 |
}
|
|
|
30411 |
constructor(settings) {
|
|
|
30412 |
this.bindings = {};
|
|
|
30413 |
this.settings = settings || {};
|
|
|
30414 |
this.scope = this.settings.scope || this;
|
|
|
30415 |
this.toggleEvent = this.settings.toggleEvent || never;
|
|
|
30416 |
}
|
|
|
30417 |
fire(name, args) {
|
|
|
30418 |
return this.dispatch(name, args);
|
|
|
30419 |
}
|
|
|
30420 |
dispatch(name, args) {
|
|
|
30421 |
const lcName = name.toLowerCase();
|
|
|
30422 |
const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
|
|
|
30423 |
if (this.settings.beforeFire) {
|
|
|
30424 |
this.settings.beforeFire(event);
|
|
|
30425 |
}
|
|
|
30426 |
const handlers = this.bindings[lcName];
|
|
|
30427 |
if (handlers) {
|
|
|
30428 |
for (let i = 0, l = handlers.length; i < l; i++) {
|
|
|
30429 |
const callback = handlers[i];
|
|
|
30430 |
if (callback.removed) {
|
|
|
30431 |
continue;
|
|
|
30432 |
}
|
|
|
30433 |
if (callback.once) {
|
|
|
30434 |
this.off(lcName, callback.func);
|
|
|
30435 |
}
|
|
|
30436 |
if (event.isImmediatePropagationStopped()) {
|
|
|
30437 |
return event;
|
|
|
30438 |
}
|
|
|
30439 |
if (callback.func.call(this.scope, event) === false) {
|
|
|
30440 |
event.preventDefault();
|
|
|
30441 |
return event;
|
|
|
30442 |
}
|
|
|
30443 |
}
|
|
|
30444 |
}
|
|
|
30445 |
return event;
|
|
|
30446 |
}
|
|
|
30447 |
on(name, callback, prepend, extra) {
|
|
|
30448 |
if (callback === false) {
|
|
|
30449 |
callback = never;
|
|
|
30450 |
}
|
|
|
30451 |
if (callback) {
|
|
|
30452 |
const wrappedCallback = {
|
|
|
30453 |
func: callback,
|
|
|
30454 |
removed: false
|
|
|
30455 |
};
|
|
|
30456 |
if (extra) {
|
|
|
30457 |
Tools.extend(wrappedCallback, extra);
|
|
|
30458 |
}
|
|
|
30459 |
const names = name.toLowerCase().split(' ');
|
|
|
30460 |
let i = names.length;
|
|
|
30461 |
while (i--) {
|
|
|
30462 |
const currentName = names[i];
|
|
|
30463 |
let handlers = this.bindings[currentName];
|
|
|
30464 |
if (!handlers) {
|
|
|
30465 |
handlers = [];
|
|
|
30466 |
this.toggleEvent(currentName, true);
|
|
|
30467 |
}
|
|
|
30468 |
if (prepend) {
|
|
|
30469 |
handlers = [
|
|
|
30470 |
wrappedCallback,
|
|
|
30471 |
...handlers
|
|
|
30472 |
];
|
|
|
30473 |
} else {
|
|
|
30474 |
handlers = [
|
|
|
30475 |
...handlers,
|
|
|
30476 |
wrappedCallback
|
|
|
30477 |
];
|
|
|
30478 |
}
|
|
|
30479 |
this.bindings[currentName] = handlers;
|
|
|
30480 |
}
|
|
|
30481 |
}
|
|
|
30482 |
return this;
|
|
|
30483 |
}
|
|
|
30484 |
off(name, callback) {
|
|
|
30485 |
if (name) {
|
|
|
30486 |
const names = name.toLowerCase().split(' ');
|
|
|
30487 |
let i = names.length;
|
|
|
30488 |
while (i--) {
|
|
|
30489 |
const currentName = names[i];
|
|
|
30490 |
let handlers = this.bindings[currentName];
|
|
|
30491 |
if (!currentName) {
|
|
|
30492 |
each$d(this.bindings, (_value, bindingName) => {
|
|
|
30493 |
this.toggleEvent(bindingName, false);
|
|
|
30494 |
delete this.bindings[bindingName];
|
|
|
30495 |
});
|
|
|
30496 |
return this;
|
|
|
30497 |
}
|
|
|
30498 |
if (handlers) {
|
|
|
30499 |
if (!callback) {
|
|
|
30500 |
handlers.length = 0;
|
|
|
30501 |
} else {
|
|
|
30502 |
const filteredHandlers = partition$2(handlers, handler => handler.func === callback);
|
|
|
30503 |
handlers = filteredHandlers.fail;
|
|
|
30504 |
this.bindings[currentName] = handlers;
|
|
|
30505 |
each$e(filteredHandlers.pass, handler => {
|
|
|
30506 |
handler.removed = true;
|
|
|
30507 |
});
|
|
|
30508 |
}
|
|
|
30509 |
if (!handlers.length) {
|
|
|
30510 |
this.toggleEvent(name, false);
|
|
|
30511 |
delete this.bindings[currentName];
|
|
|
30512 |
}
|
|
|
30513 |
}
|
|
|
30514 |
}
|
|
|
30515 |
} else {
|
|
|
30516 |
each$d(this.bindings, (_value, name) => {
|
|
|
30517 |
this.toggleEvent(name, false);
|
|
|
30518 |
});
|
|
|
30519 |
this.bindings = {};
|
|
|
30520 |
}
|
|
|
30521 |
return this;
|
|
|
30522 |
}
|
|
|
30523 |
once(name, callback, prepend) {
|
|
|
30524 |
return this.on(name, callback, prepend, { once: true });
|
|
|
30525 |
}
|
|
|
30526 |
has(name) {
|
|
|
30527 |
name = name.toLowerCase();
|
|
|
30528 |
const binding = this.bindings[name];
|
|
|
30529 |
return !(!binding || binding.length === 0);
|
|
|
30530 |
}
|
|
|
30531 |
}
|
|
|
30532 |
|
|
|
30533 |
const getEventDispatcher = obj => {
|
|
|
30534 |
if (!obj._eventDispatcher) {
|
|
|
30535 |
obj._eventDispatcher = new EventDispatcher({
|
|
|
30536 |
scope: obj,
|
|
|
30537 |
toggleEvent: (name, state) => {
|
|
|
30538 |
if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
|
|
|
30539 |
obj.toggleNativeEvent(name, state);
|
|
|
30540 |
}
|
|
|
30541 |
}
|
|
|
30542 |
});
|
|
|
30543 |
}
|
|
|
30544 |
return obj._eventDispatcher;
|
|
|
30545 |
};
|
|
|
30546 |
const Observable = {
|
|
|
30547 |
fire(name, args, bubble) {
|
|
|
30548 |
return this.dispatch(name, args, bubble);
|
|
|
30549 |
},
|
|
|
30550 |
dispatch(name, args, bubble) {
|
|
|
30551 |
const self = this;
|
|
|
30552 |
if (self.removed && name !== 'remove' && name !== 'detach') {
|
|
|
30553 |
return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
|
|
|
30554 |
}
|
|
|
30555 |
const dispatcherArgs = getEventDispatcher(self).dispatch(name, args);
|
|
|
30556 |
if (bubble !== false && self.parent) {
|
|
|
30557 |
let parent = self.parent();
|
|
|
30558 |
while (parent && !dispatcherArgs.isPropagationStopped()) {
|
|
|
30559 |
parent.dispatch(name, dispatcherArgs, false);
|
|
|
30560 |
parent = parent.parent ? parent.parent() : undefined;
|
|
|
30561 |
}
|
|
|
30562 |
}
|
|
|
30563 |
return dispatcherArgs;
|
|
|
30564 |
},
|
|
|
30565 |
on(name, callback, prepend) {
|
|
|
30566 |
return getEventDispatcher(this).on(name, callback, prepend);
|
|
|
30567 |
},
|
|
|
30568 |
off(name, callback) {
|
|
|
30569 |
return getEventDispatcher(this).off(name, callback);
|
|
|
30570 |
},
|
|
|
30571 |
once(name, callback) {
|
|
|
30572 |
return getEventDispatcher(this).once(name, callback);
|
|
|
30573 |
},
|
|
|
30574 |
hasEventListeners(name) {
|
|
|
30575 |
return getEventDispatcher(this).has(name);
|
|
|
30576 |
}
|
|
|
30577 |
};
|
|
|
30578 |
|
|
|
30579 |
const DOM$2 = DOMUtils.DOM;
|
|
|
30580 |
let customEventRootDelegates;
|
|
|
30581 |
const getEventTarget = (editor, eventName) => {
|
|
|
30582 |
if (eventName === 'selectionchange') {
|
|
|
30583 |
return editor.getDoc();
|
|
|
30584 |
}
|
|
|
30585 |
if (!editor.inline && /^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(eventName)) {
|
|
|
30586 |
return editor.getDoc().documentElement;
|
|
|
30587 |
}
|
|
|
30588 |
const eventRoot = getEventRoot(editor);
|
|
|
30589 |
if (eventRoot) {
|
|
|
30590 |
if (!editor.eventRoot) {
|
|
|
30591 |
editor.eventRoot = DOM$2.select(eventRoot)[0];
|
|
|
30592 |
}
|
|
|
30593 |
return editor.eventRoot;
|
|
|
30594 |
}
|
|
|
30595 |
return editor.getBody();
|
|
|
30596 |
};
|
| 1441 |
ariadna |
30597 |
const isListening = editor => !editor.hidden && !isDisabled(editor);
|
| 1 |
efrain |
30598 |
const fireEvent = (editor, eventName, e) => {
|
|
|
30599 |
if (isListening(editor)) {
|
|
|
30600 |
editor.dispatch(eventName, e);
|
| 1441 |
ariadna |
30601 |
} else if (isDisabled(editor)) {
|
|
|
30602 |
processDisabledEvents(editor, e);
|
| 1 |
efrain |
30603 |
}
|
|
|
30604 |
};
|
|
|
30605 |
const bindEventDelegate = (editor, eventName) => {
|
|
|
30606 |
if (!editor.delegates) {
|
|
|
30607 |
editor.delegates = {};
|
|
|
30608 |
}
|
|
|
30609 |
if (editor.delegates[eventName] || editor.removed) {
|
|
|
30610 |
return;
|
|
|
30611 |
}
|
|
|
30612 |
const eventRootElm = getEventTarget(editor, eventName);
|
|
|
30613 |
if (getEventRoot(editor)) {
|
|
|
30614 |
if (!customEventRootDelegates) {
|
|
|
30615 |
customEventRootDelegates = {};
|
|
|
30616 |
editor.editorManager.on('removeEditor', () => {
|
|
|
30617 |
if (!editor.editorManager.activeEditor) {
|
|
|
30618 |
if (customEventRootDelegates) {
|
|
|
30619 |
each$d(customEventRootDelegates, (_value, name) => {
|
|
|
30620 |
editor.dom.unbind(getEventTarget(editor, name));
|
|
|
30621 |
});
|
|
|
30622 |
customEventRootDelegates = null;
|
|
|
30623 |
}
|
|
|
30624 |
}
|
|
|
30625 |
});
|
|
|
30626 |
}
|
|
|
30627 |
if (customEventRootDelegates[eventName]) {
|
|
|
30628 |
return;
|
|
|
30629 |
}
|
|
|
30630 |
const delegate = e => {
|
|
|
30631 |
const target = e.target;
|
|
|
30632 |
const editors = editor.editorManager.get();
|
|
|
30633 |
let i = editors.length;
|
|
|
30634 |
while (i--) {
|
|
|
30635 |
const body = editors[i].getBody();
|
|
|
30636 |
if (body === target || DOM$2.isChildOf(target, body)) {
|
|
|
30637 |
fireEvent(editors[i], eventName, e);
|
|
|
30638 |
}
|
|
|
30639 |
}
|
|
|
30640 |
};
|
|
|
30641 |
customEventRootDelegates[eventName] = delegate;
|
|
|
30642 |
DOM$2.bind(eventRootElm, eventName, delegate);
|
|
|
30643 |
} else {
|
|
|
30644 |
const delegate = e => {
|
|
|
30645 |
fireEvent(editor, eventName, e);
|
|
|
30646 |
};
|
|
|
30647 |
DOM$2.bind(eventRootElm, eventName, delegate);
|
|
|
30648 |
editor.delegates[eventName] = delegate;
|
|
|
30649 |
}
|
|
|
30650 |
};
|
|
|
30651 |
const EditorObservable = {
|
|
|
30652 |
...Observable,
|
|
|
30653 |
bindPendingEventDelegates() {
|
|
|
30654 |
const self = this;
|
|
|
30655 |
Tools.each(self._pendingNativeEvents, name => {
|
|
|
30656 |
bindEventDelegate(self, name);
|
|
|
30657 |
});
|
|
|
30658 |
},
|
|
|
30659 |
toggleNativeEvent(name, state) {
|
|
|
30660 |
const self = this;
|
|
|
30661 |
if (name === 'focus' || name === 'blur') {
|
|
|
30662 |
return;
|
|
|
30663 |
}
|
|
|
30664 |
if (self.removed) {
|
|
|
30665 |
return;
|
|
|
30666 |
}
|
|
|
30667 |
if (state) {
|
|
|
30668 |
if (self.initialized) {
|
|
|
30669 |
bindEventDelegate(self, name);
|
|
|
30670 |
} else {
|
|
|
30671 |
if (!self._pendingNativeEvents) {
|
|
|
30672 |
self._pendingNativeEvents = [name];
|
|
|
30673 |
} else {
|
|
|
30674 |
self._pendingNativeEvents.push(name);
|
|
|
30675 |
}
|
|
|
30676 |
}
|
|
|
30677 |
} else if (self.initialized && self.delegates) {
|
|
|
30678 |
self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
|
|
|
30679 |
delete self.delegates[name];
|
|
|
30680 |
}
|
|
|
30681 |
},
|
|
|
30682 |
unbindAllNativeEvents() {
|
|
|
30683 |
const self = this;
|
|
|
30684 |
const body = self.getBody();
|
|
|
30685 |
const dom = self.dom;
|
|
|
30686 |
if (self.delegates) {
|
|
|
30687 |
each$d(self.delegates, (value, name) => {
|
|
|
30688 |
self.dom.unbind(getEventTarget(self, name), name, value);
|
|
|
30689 |
});
|
|
|
30690 |
delete self.delegates;
|
|
|
30691 |
}
|
|
|
30692 |
if (!self.inline && body && dom) {
|
|
|
30693 |
body.onload = null;
|
|
|
30694 |
dom.unbind(self.getWin());
|
|
|
30695 |
dom.unbind(self.getDoc());
|
|
|
30696 |
}
|
|
|
30697 |
if (dom) {
|
|
|
30698 |
dom.unbind(body);
|
|
|
30699 |
dom.unbind(self.getContainer());
|
|
|
30700 |
}
|
|
|
30701 |
}
|
|
|
30702 |
};
|
|
|
30703 |
|
|
|
30704 |
const stringListProcessor = value => {
|
|
|
30705 |
if (isString(value)) {
|
|
|
30706 |
return {
|
|
|
30707 |
value: value.split(/[ ,]/),
|
|
|
30708 |
valid: true
|
|
|
30709 |
};
|
|
|
30710 |
} else if (isArrayOf(value, isString)) {
|
|
|
30711 |
return {
|
|
|
30712 |
value,
|
|
|
30713 |
valid: true
|
|
|
30714 |
};
|
|
|
30715 |
} else {
|
|
|
30716 |
return {
|
|
|
30717 |
valid: false,
|
|
|
30718 |
message: `The value must be a string[] or a comma/space separated string.`
|
|
|
30719 |
};
|
|
|
30720 |
}
|
|
|
30721 |
};
|
|
|
30722 |
const getBuiltInProcessor = type => {
|
|
|
30723 |
const validator = (() => {
|
|
|
30724 |
switch (type) {
|
|
|
30725 |
case 'array':
|
|
|
30726 |
return isArray$1;
|
|
|
30727 |
case 'boolean':
|
|
|
30728 |
return isBoolean;
|
|
|
30729 |
case 'function':
|
|
|
30730 |
return isFunction;
|
|
|
30731 |
case 'number':
|
|
|
30732 |
return isNumber;
|
|
|
30733 |
case 'object':
|
|
|
30734 |
return isObject;
|
|
|
30735 |
case 'string':
|
|
|
30736 |
return isString;
|
|
|
30737 |
case 'string[]':
|
|
|
30738 |
return stringListProcessor;
|
|
|
30739 |
case 'object[]':
|
|
|
30740 |
return val => isArrayOf(val, isObject);
|
|
|
30741 |
case 'regexp':
|
|
|
30742 |
return val => is$4(val, RegExp);
|
|
|
30743 |
default:
|
|
|
30744 |
return always;
|
|
|
30745 |
}
|
|
|
30746 |
})();
|
|
|
30747 |
return value => processValue(value, validator, `The value must be a ${ type }.`);
|
|
|
30748 |
};
|
|
|
30749 |
const isBuiltInSpec = spec => isString(spec.processor);
|
|
|
30750 |
const getErrorMessage = (message, result) => {
|
|
|
30751 |
const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`;
|
|
|
30752 |
return message + additionalText;
|
|
|
30753 |
};
|
|
|
30754 |
const isValidResult = result => result.valid;
|
|
|
30755 |
const processValue = (value, processor, message = '') => {
|
|
|
30756 |
const result = processor(value);
|
|
|
30757 |
if (isBoolean(result)) {
|
|
|
30758 |
return result ? {
|
|
|
30759 |
value: value,
|
|
|
30760 |
valid: true
|
|
|
30761 |
} : {
|
|
|
30762 |
valid: false,
|
|
|
30763 |
message
|
|
|
30764 |
};
|
|
|
30765 |
} else {
|
|
|
30766 |
return result;
|
|
|
30767 |
}
|
|
|
30768 |
};
|
|
|
30769 |
const processDefaultValue = (name, defaultValue, processor) => {
|
|
|
30770 |
if (!isUndefined(defaultValue)) {
|
|
|
30771 |
const result = processValue(defaultValue, processor);
|
|
|
30772 |
if (isValidResult(result)) {
|
|
|
30773 |
return result.value;
|
|
|
30774 |
} else {
|
|
|
30775 |
console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result));
|
|
|
30776 |
}
|
|
|
30777 |
}
|
|
|
30778 |
return undefined;
|
|
|
30779 |
};
|
| 1441 |
ariadna |
30780 |
const create$5 = (editor, initialOptions, rawInitialOptions = initialOptions) => {
|
| 1 |
efrain |
30781 |
const registry = {};
|
|
|
30782 |
const values = {};
|
|
|
30783 |
const setValue = (name, value, processor) => {
|
|
|
30784 |
const result = processValue(value, processor);
|
|
|
30785 |
if (isValidResult(result)) {
|
|
|
30786 |
values[name] = result.value;
|
|
|
30787 |
return true;
|
|
|
30788 |
} else {
|
|
|
30789 |
console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result));
|
|
|
30790 |
return false;
|
|
|
30791 |
}
|
|
|
30792 |
};
|
|
|
30793 |
const register = (name, spec) => {
|
|
|
30794 |
const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
|
|
|
30795 |
const defaultValue = processDefaultValue(name, spec.default, processor);
|
|
|
30796 |
registry[name] = {
|
|
|
30797 |
...spec,
|
|
|
30798 |
default: defaultValue,
|
|
|
30799 |
processor
|
|
|
30800 |
};
|
|
|
30801 |
const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name));
|
|
|
30802 |
initValue.each(value => setValue(name, value, processor));
|
|
|
30803 |
};
|
|
|
30804 |
const isRegistered = name => has$2(registry, name);
|
|
|
30805 |
const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined();
|
|
|
30806 |
const set = (name, value) => {
|
|
|
30807 |
if (!isRegistered(name)) {
|
|
|
30808 |
console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`);
|
|
|
30809 |
return false;
|
|
|
30810 |
} else {
|
|
|
30811 |
const spec = registry[name];
|
|
|
30812 |
if (spec.immutable) {
|
|
|
30813 |
console.error(`"${ name }" is an immutable option and cannot be updated`);
|
|
|
30814 |
return false;
|
|
|
30815 |
} else {
|
|
|
30816 |
return setValue(name, value, spec.processor);
|
|
|
30817 |
}
|
|
|
30818 |
}
|
|
|
30819 |
};
|
|
|
30820 |
const unset = name => {
|
|
|
30821 |
const registered = isRegistered(name);
|
|
|
30822 |
if (registered) {
|
|
|
30823 |
delete values[name];
|
|
|
30824 |
}
|
|
|
30825 |
return registered;
|
|
|
30826 |
};
|
|
|
30827 |
const isSet = name => has$2(values, name);
|
| 1441 |
ariadna |
30828 |
const debug = () => {
|
|
|
30829 |
try {
|
|
|
30830 |
console.log(JSON.parse(JSON.stringify(rawInitialOptions, (_key, value) => {
|
|
|
30831 |
if (isBoolean(value) || isNumber(value) || isString(value) || isNull(value) || isArray$1(value) || isPlainObject(value)) {
|
|
|
30832 |
return value;
|
|
|
30833 |
}
|
|
|
30834 |
return Object.prototype.toString.call(value);
|
|
|
30835 |
})));
|
|
|
30836 |
} catch (error) {
|
|
|
30837 |
console.error(error);
|
|
|
30838 |
}
|
|
|
30839 |
};
|
| 1 |
efrain |
30840 |
return {
|
|
|
30841 |
register,
|
|
|
30842 |
isRegistered,
|
|
|
30843 |
get,
|
|
|
30844 |
set,
|
|
|
30845 |
unset,
|
| 1441 |
ariadna |
30846 |
isSet,
|
|
|
30847 |
debug
|
| 1 |
efrain |
30848 |
};
|
|
|
30849 |
};
|
|
|
30850 |
|
| 1441 |
ariadna |
30851 |
const setContentEditable = (elm, state) => {
|
|
|
30852 |
elm.dom.contentEditable = state ? 'true' : 'false';
|
|
|
30853 |
};
|
|
|
30854 |
const toggleReadOnly = (editor, state) => {
|
|
|
30855 |
const body = SugarElement.fromDom(editor.getBody());
|
|
|
30856 |
if (state) {
|
|
|
30857 |
editor.readonly = true;
|
|
|
30858 |
if (editor.hasEditableRoot()) {
|
|
|
30859 |
setContentEditable(body, true);
|
|
|
30860 |
}
|
|
|
30861 |
disableEditor(editor);
|
|
|
30862 |
} else {
|
|
|
30863 |
editor.readonly = false;
|
|
|
30864 |
enableEditor(editor);
|
|
|
30865 |
}
|
|
|
30866 |
};
|
|
|
30867 |
const isReadOnly = editor => editor.readonly;
|
|
|
30868 |
const registerReadOnlyInputBlockers = editor => {
|
|
|
30869 |
editor.on('beforeinput paste cut dragend dragover draggesture dragdrop drop drag', e => {
|
|
|
30870 |
if (isReadOnly(editor)) {
|
|
|
30871 |
e.preventDefault();
|
|
|
30872 |
}
|
|
|
30873 |
});
|
|
|
30874 |
editor.on('BeforeExecCommand', e => {
|
|
|
30875 |
if ((e.command === 'Undo' || e.command === 'Redo') && isReadOnly(editor)) {
|
|
|
30876 |
e.preventDefault();
|
|
|
30877 |
}
|
|
|
30878 |
});
|
|
|
30879 |
editor.on('input', e => {
|
|
|
30880 |
if (!e.isComposing && isReadOnly(editor)) {
|
|
|
30881 |
const undoLevel = editor.undoManager.add();
|
|
|
30882 |
if (isNonNullable(undoLevel)) {
|
|
|
30883 |
editor.undoManager.undo();
|
|
|
30884 |
}
|
|
|
30885 |
}
|
|
|
30886 |
});
|
|
|
30887 |
editor.on('compositionend', () => {
|
|
|
30888 |
if (isReadOnly(editor)) {
|
|
|
30889 |
const undoLevel = editor.undoManager.add();
|
|
|
30890 |
if (isNonNullable(undoLevel)) {
|
|
|
30891 |
editor.undoManager.undo();
|
|
|
30892 |
}
|
|
|
30893 |
}
|
|
|
30894 |
});
|
|
|
30895 |
};
|
|
|
30896 |
|
| 1 |
efrain |
30897 |
const defaultModes = [
|
|
|
30898 |
'design',
|
|
|
30899 |
'readonly'
|
|
|
30900 |
];
|
|
|
30901 |
const switchToMode = (editor, activeMode, availableModes, mode) => {
|
|
|
30902 |
const oldMode = availableModes[activeMode.get()];
|
|
|
30903 |
const newMode = availableModes[mode];
|
|
|
30904 |
try {
|
|
|
30905 |
newMode.activate();
|
|
|
30906 |
} catch (e) {
|
|
|
30907 |
console.error(`problem while activating editor mode ${ mode }:`, e);
|
|
|
30908 |
return;
|
|
|
30909 |
}
|
|
|
30910 |
oldMode.deactivate();
|
|
|
30911 |
if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
|
|
|
30912 |
toggleReadOnly(editor, newMode.editorReadOnly);
|
|
|
30913 |
}
|
|
|
30914 |
activeMode.set(mode);
|
|
|
30915 |
fireSwitchMode(editor, mode);
|
|
|
30916 |
};
|
|
|
30917 |
const setMode = (editor, availableModes, activeMode, mode) => {
|
| 1441 |
ariadna |
30918 |
if (mode === activeMode.get() || editor.initialized && isDisabled(editor)) {
|
| 1 |
efrain |
30919 |
return;
|
|
|
30920 |
} else if (!has$2(availableModes, mode)) {
|
|
|
30921 |
throw new Error(`Editor mode '${ mode }' is invalid`);
|
|
|
30922 |
}
|
|
|
30923 |
if (editor.initialized) {
|
|
|
30924 |
switchToMode(editor, activeMode, availableModes, mode);
|
|
|
30925 |
} else {
|
|
|
30926 |
editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode));
|
|
|
30927 |
}
|
|
|
30928 |
};
|
|
|
30929 |
const registerMode = (availableModes, mode, api) => {
|
|
|
30930 |
if (contains$2(defaultModes, mode)) {
|
|
|
30931 |
throw new Error(`Cannot override default mode ${ mode }`);
|
|
|
30932 |
}
|
|
|
30933 |
return {
|
|
|
30934 |
...availableModes,
|
|
|
30935 |
[mode]: {
|
|
|
30936 |
...api,
|
|
|
30937 |
deactivate: () => {
|
|
|
30938 |
try {
|
|
|
30939 |
api.deactivate();
|
|
|
30940 |
} catch (e) {
|
|
|
30941 |
console.error(`problem while deactivating editor mode ${ mode }:`, e);
|
|
|
30942 |
}
|
|
|
30943 |
}
|
|
|
30944 |
}
|
|
|
30945 |
};
|
|
|
30946 |
};
|
|
|
30947 |
|
|
|
30948 |
const create$4 = editor => {
|
|
|
30949 |
const activeMode = Cell('design');
|
|
|
30950 |
const availableModes = Cell({
|
|
|
30951 |
design: {
|
|
|
30952 |
activate: noop,
|
|
|
30953 |
deactivate: noop,
|
|
|
30954 |
editorReadOnly: false
|
|
|
30955 |
},
|
|
|
30956 |
readonly: {
|
|
|
30957 |
activate: noop,
|
|
|
30958 |
deactivate: noop,
|
|
|
30959 |
editorReadOnly: true
|
|
|
30960 |
}
|
|
|
30961 |
});
|
| 1441 |
ariadna |
30962 |
registerReadOnlyInputBlockers(editor);
|
|
|
30963 |
registerEventsAndFilters$1(editor);
|
| 1 |
efrain |
30964 |
return {
|
|
|
30965 |
isReadOnly: () => isReadOnly(editor),
|
|
|
30966 |
set: mode => setMode(editor, availableModes.get(), activeMode, mode),
|
|
|
30967 |
get: () => activeMode.get(),
|
|
|
30968 |
register: (mode, api) => {
|
|
|
30969 |
availableModes.set(registerMode(availableModes.get(), mode, api));
|
|
|
30970 |
}
|
|
|
30971 |
};
|
|
|
30972 |
};
|
|
|
30973 |
|
|
|
30974 |
const each$2 = Tools.each, explode = Tools.explode;
|
|
|
30975 |
const keyCodeLookup = {
|
|
|
30976 |
f1: 112,
|
|
|
30977 |
f2: 113,
|
|
|
30978 |
f3: 114,
|
|
|
30979 |
f4: 115,
|
|
|
30980 |
f5: 116,
|
|
|
30981 |
f6: 117,
|
|
|
30982 |
f7: 118,
|
|
|
30983 |
f8: 119,
|
|
|
30984 |
f9: 120,
|
|
|
30985 |
f10: 121,
|
|
|
30986 |
f11: 122,
|
|
|
30987 |
f12: 123
|
|
|
30988 |
};
|
|
|
30989 |
const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
|
|
|
30990 |
const isModifier = key => key in modifierNames;
|
|
|
30991 |
const parseShortcut = pattern => {
|
|
|
30992 |
const shortcut = {};
|
|
|
30993 |
const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
|
|
30994 |
each$2(explode(pattern.toLowerCase(), '+'), value => {
|
|
|
30995 |
if (isModifier(value)) {
|
|
|
30996 |
shortcut[value] = true;
|
|
|
30997 |
} else {
|
|
|
30998 |
if (/^[0-9]{2,}$/.test(value)) {
|
|
|
30999 |
shortcut.keyCode = parseInt(value, 10);
|
|
|
31000 |
} else {
|
|
|
31001 |
shortcut.charCode = value.charCodeAt(0);
|
|
|
31002 |
shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
|
|
|
31003 |
}
|
|
|
31004 |
}
|
|
|
31005 |
});
|
|
|
31006 |
const id = [shortcut.keyCode];
|
|
|
31007 |
let key;
|
|
|
31008 |
for (key in modifierNames) {
|
|
|
31009 |
if (shortcut[key]) {
|
|
|
31010 |
id.push(key);
|
|
|
31011 |
} else {
|
|
|
31012 |
shortcut[key] = false;
|
|
|
31013 |
}
|
|
|
31014 |
}
|
|
|
31015 |
shortcut.id = id.join(',');
|
|
|
31016 |
if (shortcut.access) {
|
|
|
31017 |
shortcut.alt = true;
|
|
|
31018 |
if (isMac) {
|
|
|
31019 |
shortcut.ctrl = true;
|
|
|
31020 |
} else {
|
|
|
31021 |
shortcut.shift = true;
|
|
|
31022 |
}
|
|
|
31023 |
}
|
|
|
31024 |
if (shortcut.meta) {
|
|
|
31025 |
if (isMac) {
|
|
|
31026 |
shortcut.meta = true;
|
|
|
31027 |
} else {
|
|
|
31028 |
shortcut.ctrl = true;
|
|
|
31029 |
shortcut.meta = false;
|
|
|
31030 |
}
|
|
|
31031 |
}
|
|
|
31032 |
return shortcut;
|
|
|
31033 |
};
|
|
|
31034 |
class Shortcuts {
|
|
|
31035 |
constructor(editor) {
|
|
|
31036 |
this.shortcuts = {};
|
|
|
31037 |
this.pendingPatterns = [];
|
|
|
31038 |
this.editor = editor;
|
|
|
31039 |
const self = this;
|
|
|
31040 |
editor.on('keyup keypress keydown', e => {
|
|
|
31041 |
if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
|
|
|
31042 |
each$2(self.shortcuts, shortcut => {
|
|
|
31043 |
if (self.matchShortcut(e, shortcut)) {
|
|
|
31044 |
self.pendingPatterns = shortcut.subpatterns.slice(0);
|
|
|
31045 |
if (e.type === 'keydown') {
|
|
|
31046 |
self.executeShortcutAction(shortcut);
|
|
|
31047 |
}
|
|
|
31048 |
}
|
|
|
31049 |
});
|
|
|
31050 |
if (self.matchShortcut(e, self.pendingPatterns[0])) {
|
|
|
31051 |
if (self.pendingPatterns.length === 1) {
|
|
|
31052 |
if (e.type === 'keydown') {
|
|
|
31053 |
self.executeShortcutAction(self.pendingPatterns[0]);
|
|
|
31054 |
}
|
|
|
31055 |
}
|
|
|
31056 |
self.pendingPatterns.shift();
|
|
|
31057 |
}
|
|
|
31058 |
}
|
|
|
31059 |
});
|
|
|
31060 |
}
|
|
|
31061 |
add(pattern, desc, cmdFunc, scope) {
|
|
|
31062 |
const self = this;
|
|
|
31063 |
const func = self.normalizeCommandFunc(cmdFunc);
|
|
|
31064 |
each$2(explode(Tools.trim(pattern)), pattern => {
|
|
|
31065 |
const shortcut = self.createShortcut(pattern, desc, func, scope);
|
|
|
31066 |
self.shortcuts[shortcut.id] = shortcut;
|
|
|
31067 |
});
|
|
|
31068 |
return true;
|
|
|
31069 |
}
|
|
|
31070 |
remove(pattern) {
|
|
|
31071 |
const shortcut = this.createShortcut(pattern);
|
|
|
31072 |
if (this.shortcuts[shortcut.id]) {
|
|
|
31073 |
delete this.shortcuts[shortcut.id];
|
|
|
31074 |
return true;
|
|
|
31075 |
}
|
|
|
31076 |
return false;
|
|
|
31077 |
}
|
|
|
31078 |
normalizeCommandFunc(cmdFunc) {
|
|
|
31079 |
const self = this;
|
|
|
31080 |
const cmd = cmdFunc;
|
|
|
31081 |
if (typeof cmd === 'string') {
|
|
|
31082 |
return () => {
|
|
|
31083 |
self.editor.execCommand(cmd, false, null);
|
|
|
31084 |
};
|
|
|
31085 |
} else if (Tools.isArray(cmd)) {
|
|
|
31086 |
return () => {
|
|
|
31087 |
self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
|
|
|
31088 |
};
|
|
|
31089 |
} else {
|
|
|
31090 |
return cmd;
|
|
|
31091 |
}
|
|
|
31092 |
}
|
|
|
31093 |
createShortcut(pattern, desc, cmdFunc, scope) {
|
|
|
31094 |
const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
|
|
|
31095 |
shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
|
|
|
31096 |
func: cmdFunc,
|
|
|
31097 |
scope: scope || this.editor
|
|
|
31098 |
});
|
|
|
31099 |
return Tools.extend(shortcuts[0], {
|
|
|
31100 |
desc: this.editor.translate(desc),
|
|
|
31101 |
subpatterns: shortcuts.slice(1)
|
|
|
31102 |
});
|
|
|
31103 |
}
|
|
|
31104 |
hasModifier(e) {
|
|
|
31105 |
return e.altKey || e.ctrlKey || e.metaKey;
|
|
|
31106 |
}
|
|
|
31107 |
isFunctionKey(e) {
|
|
|
31108 |
return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
|
|
|
31109 |
}
|
|
|
31110 |
matchShortcut(e, shortcut) {
|
|
|
31111 |
if (!shortcut) {
|
|
|
31112 |
return false;
|
|
|
31113 |
}
|
|
|
31114 |
if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
|
|
|
31115 |
return false;
|
|
|
31116 |
}
|
|
|
31117 |
if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
|
|
|
31118 |
return false;
|
|
|
31119 |
}
|
|
|
31120 |
if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
|
|
|
31121 |
e.preventDefault();
|
|
|
31122 |
return true;
|
|
|
31123 |
}
|
|
|
31124 |
return false;
|
|
|
31125 |
}
|
|
|
31126 |
executeShortcutAction(shortcut) {
|
|
|
31127 |
return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
|
|
|
31128 |
}
|
|
|
31129 |
}
|
|
|
31130 |
|
|
|
31131 |
const create$3 = () => {
|
|
|
31132 |
const buttons = {};
|
|
|
31133 |
const menuItems = {};
|
|
|
31134 |
const popups = {};
|
|
|
31135 |
const icons = {};
|
|
|
31136 |
const contextMenus = {};
|
|
|
31137 |
const contextToolbars = {};
|
| 1441 |
ariadna |
31138 |
const contexts = {};
|
| 1 |
efrain |
31139 |
const sidebars = {};
|
|
|
31140 |
const views = {};
|
|
|
31141 |
const add = (collection, type) => (name, spec) => {
|
|
|
31142 |
collection[name.toLowerCase()] = {
|
|
|
31143 |
...spec,
|
|
|
31144 |
type
|
|
|
31145 |
};
|
|
|
31146 |
};
|
| 1441 |
ariadna |
31147 |
const addDefaulted = (collection, type) => (name, spec) => {
|
|
|
31148 |
collection[name.toLowerCase()] = {
|
|
|
31149 |
type,
|
|
|
31150 |
...spec
|
|
|
31151 |
};
|
|
|
31152 |
};
|
| 1 |
efrain |
31153 |
const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
|
| 1441 |
ariadna |
31154 |
const addContext = (name, pred) => contexts[name.toLowerCase()] = pred;
|
| 1 |
efrain |
31155 |
return {
|
|
|
31156 |
addButton: add(buttons, 'button'),
|
|
|
31157 |
addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
|
|
|
31158 |
addToggleButton: add(buttons, 'togglebutton'),
|
|
|
31159 |
addMenuButton: add(buttons, 'menubutton'),
|
|
|
31160 |
addSplitButton: add(buttons, 'splitbutton'),
|
|
|
31161 |
addMenuItem: add(menuItems, 'menuitem'),
|
|
|
31162 |
addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
|
|
|
31163 |
addToggleMenuItem: add(menuItems, 'togglemenuitem'),
|
|
|
31164 |
addAutocompleter: add(popups, 'autocompleter'),
|
|
|
31165 |
addContextMenu: add(contextMenus, 'contextmenu'),
|
|
|
31166 |
addContextToolbar: add(contextToolbars, 'contexttoolbar'),
|
| 1441 |
ariadna |
31167 |
addContextForm: addDefaulted(contextToolbars, 'contextform'),
|
| 1 |
efrain |
31168 |
addSidebar: add(sidebars, 'sidebar'),
|
|
|
31169 |
addView: add(views, 'views'),
|
|
|
31170 |
addIcon,
|
| 1441 |
ariadna |
31171 |
addContext,
|
| 1 |
efrain |
31172 |
getAll: () => ({
|
|
|
31173 |
buttons,
|
|
|
31174 |
menuItems,
|
|
|
31175 |
icons,
|
|
|
31176 |
popups,
|
|
|
31177 |
contextMenus,
|
|
|
31178 |
contextToolbars,
|
|
|
31179 |
sidebars,
|
| 1441 |
ariadna |
31180 |
views,
|
|
|
31181 |
contexts
|
| 1 |
efrain |
31182 |
})
|
|
|
31183 |
};
|
|
|
31184 |
};
|
|
|
31185 |
|
|
|
31186 |
const registry = () => {
|
|
|
31187 |
const bridge = create$3();
|
|
|
31188 |
return {
|
|
|
31189 |
addAutocompleter: bridge.addAutocompleter,
|
|
|
31190 |
addButton: bridge.addButton,
|
|
|
31191 |
addContextForm: bridge.addContextForm,
|
|
|
31192 |
addContextMenu: bridge.addContextMenu,
|
|
|
31193 |
addContextToolbar: bridge.addContextToolbar,
|
|
|
31194 |
addIcon: bridge.addIcon,
|
|
|
31195 |
addMenuButton: bridge.addMenuButton,
|
|
|
31196 |
addMenuItem: bridge.addMenuItem,
|
|
|
31197 |
addNestedMenuItem: bridge.addNestedMenuItem,
|
|
|
31198 |
addSidebar: bridge.addSidebar,
|
|
|
31199 |
addSplitButton: bridge.addSplitButton,
|
|
|
31200 |
addToggleButton: bridge.addToggleButton,
|
|
|
31201 |
addGroupToolbarButton: bridge.addGroupToolbarButton,
|
|
|
31202 |
addToggleMenuItem: bridge.addToggleMenuItem,
|
|
|
31203 |
addView: bridge.addView,
|
| 1441 |
ariadna |
31204 |
addContext: bridge.addContext,
|
| 1 |
efrain |
31205 |
getAll: bridge.getAll
|
|
|
31206 |
};
|
|
|
31207 |
};
|
|
|
31208 |
|
|
|
31209 |
const DOM$1 = DOMUtils.DOM;
|
|
|
31210 |
const extend = Tools.extend, each$1 = Tools.each;
|
|
|
31211 |
class Editor {
|
|
|
31212 |
constructor(id, options, editorManager) {
|
|
|
31213 |
this.plugins = {};
|
|
|
31214 |
this.contentCSS = [];
|
|
|
31215 |
this.contentStyles = [];
|
|
|
31216 |
this.loadedCSS = {};
|
|
|
31217 |
this.isNotDirty = false;
|
|
|
31218 |
this.composing = false;
|
|
|
31219 |
this.destroyed = false;
|
|
|
31220 |
this.hasHiddenInput = false;
|
|
|
31221 |
this.iframeElement = null;
|
|
|
31222 |
this.initialized = false;
|
|
|
31223 |
this.readonly = false;
|
|
|
31224 |
this.removed = false;
|
|
|
31225 |
this.startContent = '';
|
|
|
31226 |
this._pendingNativeEvents = [];
|
|
|
31227 |
this._skinLoaded = false;
|
|
|
31228 |
this._editableRoot = true;
|
|
|
31229 |
this.editorManager = editorManager;
|
|
|
31230 |
this.documentBaseUrl = editorManager.documentBaseURL;
|
|
|
31231 |
extend(this, EditorObservable);
|
|
|
31232 |
const self = this;
|
|
|
31233 |
this.id = id;
|
|
|
31234 |
this.hidden = false;
|
|
|
31235 |
const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
|
| 1441 |
ariadna |
31236 |
this.options = create$5(self, normalizedOptions, options);
|
| 1 |
efrain |
31237 |
register$7(self);
|
|
|
31238 |
const getOption = this.options.get;
|
|
|
31239 |
if (getOption('deprecation_warnings')) {
|
|
|
31240 |
logWarnings(options, normalizedOptions);
|
|
|
31241 |
}
|
|
|
31242 |
const suffix = getOption('suffix');
|
|
|
31243 |
if (suffix) {
|
|
|
31244 |
editorManager.suffix = suffix;
|
|
|
31245 |
}
|
|
|
31246 |
this.suffix = editorManager.suffix;
|
|
|
31247 |
const baseUrl = getOption('base_url');
|
|
|
31248 |
if (baseUrl) {
|
|
|
31249 |
editorManager._setBaseUrl(baseUrl);
|
|
|
31250 |
}
|
|
|
31251 |
this.baseUri = editorManager.baseURI;
|
|
|
31252 |
const referrerPolicy = getReferrerPolicy(self);
|
|
|
31253 |
if (referrerPolicy) {
|
|
|
31254 |
ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy);
|
|
|
31255 |
DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
|
|
|
31256 |
}
|
|
|
31257 |
const contentCssCors = hasContentCssCors(self);
|
|
|
31258 |
if (isNonNullable(contentCssCors)) {
|
|
|
31259 |
DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors);
|
|
|
31260 |
}
|
|
|
31261 |
AddOnManager.languageLoad = getOption('language_load');
|
|
|
31262 |
AddOnManager.baseURL = editorManager.baseURL;
|
|
|
31263 |
this.setDirty(false);
|
|
|
31264 |
this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
|
|
|
31265 |
this.baseURI = this.baseUri;
|
|
|
31266 |
this.inline = isInline$1(self);
|
|
|
31267 |
this.hasVisual = isVisualAidsEnabled(self);
|
|
|
31268 |
this.shortcuts = new Shortcuts(this);
|
|
|
31269 |
this.editorCommands = new EditorCommands(this);
|
|
|
31270 |
registerCommands(this);
|
|
|
31271 |
const cacheSuffix = getOption('cache_suffix');
|
|
|
31272 |
if (cacheSuffix) {
|
|
|
31273 |
Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, '');
|
|
|
31274 |
}
|
|
|
31275 |
this.ui = {
|
|
|
31276 |
registry: registry(),
|
|
|
31277 |
styleSheetLoader: undefined,
|
|
|
31278 |
show: noop,
|
|
|
31279 |
hide: noop,
|
|
|
31280 |
setEnabled: noop,
|
|
|
31281 |
isEnabled: always
|
|
|
31282 |
};
|
|
|
31283 |
this.mode = create$4(self);
|
|
|
31284 |
editorManager.dispatch('SetupEditor', { editor: this });
|
|
|
31285 |
const setupCallback = getSetupCallback(self);
|
|
|
31286 |
if (isFunction(setupCallback)) {
|
|
|
31287 |
setupCallback.call(self, self);
|
|
|
31288 |
}
|
|
|
31289 |
}
|
|
|
31290 |
render() {
|
|
|
31291 |
render(this);
|
|
|
31292 |
}
|
|
|
31293 |
focus(skipFocus) {
|
|
|
31294 |
this.execCommand('mceFocus', false, skipFocus);
|
|
|
31295 |
}
|
|
|
31296 |
hasFocus() {
|
|
|
31297 |
return hasFocus(this);
|
|
|
31298 |
}
|
|
|
31299 |
translate(text) {
|
|
|
31300 |
return I18n.translate(text);
|
|
|
31301 |
}
|
|
|
31302 |
getParam(name, defaultVal, type) {
|
|
|
31303 |
const options = this.options;
|
|
|
31304 |
if (!options.isRegistered(name)) {
|
|
|
31305 |
if (isNonNullable(type)) {
|
|
|
31306 |
options.register(name, {
|
|
|
31307 |
processor: type,
|
|
|
31308 |
default: defaultVal
|
|
|
31309 |
});
|
|
|
31310 |
} else {
|
|
|
31311 |
options.register(name, {
|
|
|
31312 |
processor: always,
|
|
|
31313 |
default: defaultVal
|
|
|
31314 |
});
|
|
|
31315 |
}
|
|
|
31316 |
}
|
|
|
31317 |
return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name);
|
|
|
31318 |
}
|
|
|
31319 |
hasPlugin(name, loaded) {
|
|
|
31320 |
const hasPlugin = contains$2(getPlugins(this), name);
|
|
|
31321 |
if (hasPlugin) {
|
|
|
31322 |
return loaded ? PluginManager.get(name) !== undefined : true;
|
|
|
31323 |
} else {
|
|
|
31324 |
return false;
|
|
|
31325 |
}
|
|
|
31326 |
}
|
|
|
31327 |
nodeChanged(args) {
|
|
|
31328 |
this._nodeChangeDispatcher.nodeChanged(args);
|
|
|
31329 |
}
|
|
|
31330 |
addCommand(name, callback, scope) {
|
|
|
31331 |
this.editorCommands.addCommand(name, callback, scope);
|
|
|
31332 |
}
|
|
|
31333 |
addQueryStateHandler(name, callback, scope) {
|
|
|
31334 |
this.editorCommands.addQueryStateHandler(name, callback, scope);
|
|
|
31335 |
}
|
|
|
31336 |
addQueryValueHandler(name, callback, scope) {
|
|
|
31337 |
this.editorCommands.addQueryValueHandler(name, callback, scope);
|
|
|
31338 |
}
|
|
|
31339 |
addShortcut(pattern, desc, cmdFunc, scope) {
|
|
|
31340 |
this.shortcuts.add(pattern, desc, cmdFunc, scope);
|
|
|
31341 |
}
|
|
|
31342 |
execCommand(cmd, ui, value, args) {
|
|
|
31343 |
return this.editorCommands.execCommand(cmd, ui, value, args);
|
|
|
31344 |
}
|
|
|
31345 |
queryCommandState(cmd) {
|
|
|
31346 |
return this.editorCommands.queryCommandState(cmd);
|
|
|
31347 |
}
|
|
|
31348 |
queryCommandValue(cmd) {
|
|
|
31349 |
return this.editorCommands.queryCommandValue(cmd);
|
|
|
31350 |
}
|
|
|
31351 |
queryCommandSupported(cmd) {
|
|
|
31352 |
return this.editorCommands.queryCommandSupported(cmd);
|
|
|
31353 |
}
|
|
|
31354 |
show() {
|
|
|
31355 |
const self = this;
|
|
|
31356 |
if (self.hidden) {
|
|
|
31357 |
self.hidden = false;
|
|
|
31358 |
if (self.inline) {
|
|
|
31359 |
self.getBody().contentEditable = 'true';
|
|
|
31360 |
} else {
|
|
|
31361 |
DOM$1.show(self.getContainer());
|
|
|
31362 |
DOM$1.hide(self.id);
|
|
|
31363 |
}
|
|
|
31364 |
self.load();
|
|
|
31365 |
self.dispatch('show');
|
|
|
31366 |
}
|
|
|
31367 |
}
|
|
|
31368 |
hide() {
|
|
|
31369 |
const self = this;
|
|
|
31370 |
if (!self.hidden) {
|
|
|
31371 |
self.save();
|
|
|
31372 |
if (self.inline) {
|
|
|
31373 |
self.getBody().contentEditable = 'false';
|
|
|
31374 |
if (self === self.editorManager.focusedEditor) {
|
|
|
31375 |
self.editorManager.focusedEditor = null;
|
|
|
31376 |
}
|
|
|
31377 |
} else {
|
|
|
31378 |
DOM$1.hide(self.getContainer());
|
|
|
31379 |
DOM$1.setStyle(self.id, 'display', self.orgDisplay);
|
|
|
31380 |
}
|
|
|
31381 |
self.hidden = true;
|
|
|
31382 |
self.dispatch('hide');
|
|
|
31383 |
}
|
|
|
31384 |
}
|
|
|
31385 |
isHidden() {
|
|
|
31386 |
return this.hidden;
|
|
|
31387 |
}
|
|
|
31388 |
setProgressState(state, time) {
|
|
|
31389 |
this.dispatch('ProgressState', {
|
|
|
31390 |
state,
|
|
|
31391 |
time
|
|
|
31392 |
});
|
|
|
31393 |
}
|
|
|
31394 |
load(args = {}) {
|
|
|
31395 |
const self = this;
|
|
|
31396 |
const elm = self.getElement();
|
|
|
31397 |
if (self.removed) {
|
|
|
31398 |
return '';
|
|
|
31399 |
}
|
|
|
31400 |
if (elm) {
|
|
|
31401 |
const loadArgs = {
|
|
|
31402 |
...args,
|
|
|
31403 |
load: true
|
|
|
31404 |
};
|
|
|
31405 |
const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
|
|
|
31406 |
const html = self.setContent(value, loadArgs);
|
|
|
31407 |
if (!loadArgs.no_events) {
|
|
|
31408 |
self.dispatch('LoadContent', {
|
|
|
31409 |
...loadArgs,
|
|
|
31410 |
element: elm
|
|
|
31411 |
});
|
|
|
31412 |
}
|
|
|
31413 |
return html;
|
|
|
31414 |
} else {
|
|
|
31415 |
return '';
|
|
|
31416 |
}
|
|
|
31417 |
}
|
|
|
31418 |
save(args = {}) {
|
|
|
31419 |
const self = this;
|
|
|
31420 |
let elm = self.getElement();
|
|
|
31421 |
if (!elm || !self.initialized || self.removed) {
|
|
|
31422 |
return '';
|
|
|
31423 |
}
|
|
|
31424 |
const getArgs = {
|
|
|
31425 |
...args,
|
|
|
31426 |
save: true,
|
|
|
31427 |
element: elm
|
|
|
31428 |
};
|
|
|
31429 |
let html = self.getContent(getArgs);
|
|
|
31430 |
const saveArgs = {
|
|
|
31431 |
...getArgs,
|
|
|
31432 |
content: html
|
|
|
31433 |
};
|
|
|
31434 |
if (!saveArgs.no_events) {
|
|
|
31435 |
self.dispatch('SaveContent', saveArgs);
|
|
|
31436 |
}
|
|
|
31437 |
if (saveArgs.format === 'raw') {
|
|
|
31438 |
self.dispatch('RawSaveContent', saveArgs);
|
|
|
31439 |
}
|
|
|
31440 |
html = saveArgs.content;
|
|
|
31441 |
if (!isTextareaOrInput(elm)) {
|
|
|
31442 |
if (args.is_removing || !self.inline) {
|
|
|
31443 |
elm.innerHTML = html;
|
|
|
31444 |
}
|
|
|
31445 |
const form = DOM$1.getParent(self.id, 'form');
|
|
|
31446 |
if (form) {
|
|
|
31447 |
each$1(form.elements, elm => {
|
|
|
31448 |
if (elm.name === self.id) {
|
|
|
31449 |
elm.value = html;
|
|
|
31450 |
return false;
|
|
|
31451 |
} else {
|
|
|
31452 |
return true;
|
|
|
31453 |
}
|
|
|
31454 |
});
|
|
|
31455 |
}
|
|
|
31456 |
} else {
|
|
|
31457 |
elm.value = html;
|
|
|
31458 |
}
|
|
|
31459 |
saveArgs.element = getArgs.element = elm = null;
|
|
|
31460 |
if (saveArgs.set_dirty !== false) {
|
|
|
31461 |
self.setDirty(false);
|
|
|
31462 |
}
|
|
|
31463 |
return html;
|
|
|
31464 |
}
|
|
|
31465 |
setContent(content, args) {
|
|
|
31466 |
return setContent(this, content, args);
|
|
|
31467 |
}
|
|
|
31468 |
getContent(args) {
|
|
|
31469 |
return getContent(this, args);
|
|
|
31470 |
}
|
|
|
31471 |
insertContent(content, args) {
|
|
|
31472 |
if (args) {
|
|
|
31473 |
content = extend({ content }, args);
|
|
|
31474 |
}
|
|
|
31475 |
this.execCommand('mceInsertContent', false, content);
|
|
|
31476 |
}
|
|
|
31477 |
resetContent(initialContent) {
|
|
|
31478 |
if (initialContent === undefined) {
|
|
|
31479 |
setContent(this, this.startContent, { format: 'raw' });
|
|
|
31480 |
} else {
|
|
|
31481 |
setContent(this, initialContent);
|
|
|
31482 |
}
|
|
|
31483 |
this.undoManager.reset();
|
|
|
31484 |
this.setDirty(false);
|
|
|
31485 |
this.nodeChanged();
|
|
|
31486 |
}
|
|
|
31487 |
isDirty() {
|
|
|
31488 |
return !this.isNotDirty;
|
|
|
31489 |
}
|
|
|
31490 |
setDirty(state) {
|
|
|
31491 |
const oldState = !this.isNotDirty;
|
|
|
31492 |
this.isNotDirty = !state;
|
|
|
31493 |
if (state && state !== oldState) {
|
|
|
31494 |
this.dispatch('dirty');
|
|
|
31495 |
}
|
|
|
31496 |
}
|
|
|
31497 |
getContainer() {
|
|
|
31498 |
const self = this;
|
|
|
31499 |
if (!self.container) {
|
|
|
31500 |
self.container = self.editorContainer || DOM$1.get(self.id + '_parent');
|
|
|
31501 |
}
|
|
|
31502 |
return self.container;
|
|
|
31503 |
}
|
|
|
31504 |
getContentAreaContainer() {
|
|
|
31505 |
return this.contentAreaContainer;
|
|
|
31506 |
}
|
|
|
31507 |
getElement() {
|
|
|
31508 |
if (!this.targetElm) {
|
|
|
31509 |
this.targetElm = DOM$1.get(this.id);
|
|
|
31510 |
}
|
|
|
31511 |
return this.targetElm;
|
|
|
31512 |
}
|
|
|
31513 |
getWin() {
|
|
|
31514 |
const self = this;
|
|
|
31515 |
if (!self.contentWindow) {
|
|
|
31516 |
const elm = self.iframeElement;
|
|
|
31517 |
if (elm) {
|
|
|
31518 |
self.contentWindow = elm.contentWindow;
|
|
|
31519 |
}
|
|
|
31520 |
}
|
|
|
31521 |
return self.contentWindow;
|
|
|
31522 |
}
|
|
|
31523 |
getDoc() {
|
|
|
31524 |
const self = this;
|
|
|
31525 |
if (!self.contentDocument) {
|
|
|
31526 |
const win = self.getWin();
|
|
|
31527 |
if (win) {
|
|
|
31528 |
self.contentDocument = win.document;
|
|
|
31529 |
}
|
|
|
31530 |
}
|
|
|
31531 |
return self.contentDocument;
|
|
|
31532 |
}
|
|
|
31533 |
getBody() {
|
|
|
31534 |
var _a, _b;
|
|
|
31535 |
const doc = this.getDoc();
|
|
|
31536 |
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;
|
|
|
31537 |
}
|
|
|
31538 |
convertURL(url, name, elm) {
|
|
|
31539 |
const self = this, getOption = self.options.get;
|
|
|
31540 |
const urlConverterCallback = getUrlConverterCallback(self);
|
|
|
31541 |
if (isFunction(urlConverterCallback)) {
|
|
|
31542 |
return urlConverterCallback.call(self, url, elm, true, name);
|
|
|
31543 |
}
|
|
|
31544 |
if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
|
|
|
31545 |
return url;
|
|
|
31546 |
}
|
|
|
31547 |
const urlObject = new URI(url);
|
|
|
31548 |
if (urlObject.protocol !== 'http' && urlObject.protocol !== 'https' && urlObject.protocol !== '') {
|
|
|
31549 |
return url;
|
|
|
31550 |
}
|
|
|
31551 |
if (getOption('relative_urls')) {
|
|
|
31552 |
return self.documentBaseURI.toRelative(url);
|
|
|
31553 |
}
|
|
|
31554 |
url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host'));
|
|
|
31555 |
return url;
|
|
|
31556 |
}
|
|
|
31557 |
addVisual(elm) {
|
|
|
31558 |
addVisual(this, elm);
|
|
|
31559 |
}
|
|
|
31560 |
setEditableRoot(state) {
|
|
|
31561 |
setEditableRoot(this, state);
|
|
|
31562 |
}
|
|
|
31563 |
hasEditableRoot() {
|
|
|
31564 |
return hasEditableRoot(this);
|
|
|
31565 |
}
|
|
|
31566 |
remove() {
|
|
|
31567 |
remove$1(this);
|
|
|
31568 |
}
|
|
|
31569 |
destroy(automatic) {
|
|
|
31570 |
destroy(this, automatic);
|
|
|
31571 |
}
|
|
|
31572 |
uploadImages() {
|
|
|
31573 |
return this.editorUpload.uploadImages();
|
|
|
31574 |
}
|
|
|
31575 |
_scanForImages() {
|
|
|
31576 |
return this.editorUpload.scanForImages();
|
|
|
31577 |
}
|
|
|
31578 |
}
|
|
|
31579 |
|
|
|
31580 |
const DOM = DOMUtils.DOM;
|
|
|
31581 |
const each = Tools.each;
|
|
|
31582 |
let boundGlobalEvents = false;
|
|
|
31583 |
let beforeUnloadDelegate;
|
|
|
31584 |
let editors = [];
|
|
|
31585 |
const globalEventDelegate = e => {
|
|
|
31586 |
const type = e.type;
|
|
|
31587 |
each(EditorManager.get(), editor => {
|
|
|
31588 |
switch (type) {
|
|
|
31589 |
case 'scroll':
|
|
|
31590 |
editor.dispatch('ScrollWindow', e);
|
|
|
31591 |
break;
|
|
|
31592 |
case 'resize':
|
|
|
31593 |
editor.dispatch('ResizeWindow', e);
|
|
|
31594 |
break;
|
|
|
31595 |
}
|
|
|
31596 |
});
|
|
|
31597 |
};
|
|
|
31598 |
const toggleGlobalEvents = state => {
|
|
|
31599 |
if (state !== boundGlobalEvents) {
|
|
|
31600 |
const DOM = DOMUtils.DOM;
|
|
|
31601 |
if (state) {
|
|
|
31602 |
DOM.bind(window, 'resize', globalEventDelegate);
|
|
|
31603 |
DOM.bind(window, 'scroll', globalEventDelegate);
|
|
|
31604 |
} else {
|
|
|
31605 |
DOM.unbind(window, 'resize', globalEventDelegate);
|
|
|
31606 |
DOM.unbind(window, 'scroll', globalEventDelegate);
|
|
|
31607 |
}
|
|
|
31608 |
boundGlobalEvents = state;
|
|
|
31609 |
}
|
|
|
31610 |
};
|
|
|
31611 |
const removeEditorFromList = targetEditor => {
|
|
|
31612 |
const oldEditors = editors;
|
|
|
31613 |
editors = filter$5(editors, editor => {
|
|
|
31614 |
return targetEditor !== editor;
|
|
|
31615 |
});
|
|
|
31616 |
if (EditorManager.activeEditor === targetEditor) {
|
|
|
31617 |
EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
|
|
|
31618 |
}
|
|
|
31619 |
if (EditorManager.focusedEditor === targetEditor) {
|
|
|
31620 |
EditorManager.focusedEditor = null;
|
|
|
31621 |
}
|
|
|
31622 |
return oldEditors.length !== editors.length;
|
|
|
31623 |
};
|
|
|
31624 |
const purgeDestroyedEditor = editor => {
|
|
|
31625 |
if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
|
|
|
31626 |
removeEditorFromList(editor);
|
|
|
31627 |
editor.unbindAllNativeEvents();
|
|
|
31628 |
editor.destroy(true);
|
|
|
31629 |
editor.removed = true;
|
|
|
31630 |
}
|
|
|
31631 |
};
|
|
|
31632 |
const isQuirksMode = document.compatMode !== 'CSS1Compat';
|
|
|
31633 |
const EditorManager = {
|
|
|
31634 |
...Observable,
|
|
|
31635 |
baseURI: null,
|
|
|
31636 |
baseURL: null,
|
|
|
31637 |
defaultOptions: {},
|
|
|
31638 |
documentBaseURL: null,
|
|
|
31639 |
suffix: null,
|
| 1441 |
ariadna |
31640 |
majorVersion: '7',
|
|
|
31641 |
minorVersion: '7.1',
|
|
|
31642 |
releaseDate: '2025-03-05',
|
| 1 |
efrain |
31643 |
i18n: I18n,
|
|
|
31644 |
activeEditor: null,
|
|
|
31645 |
focusedEditor: null,
|
|
|
31646 |
setup() {
|
|
|
31647 |
const self = this;
|
|
|
31648 |
let baseURL = '';
|
|
|
31649 |
let suffix = '';
|
|
|
31650 |
let documentBaseURL = URI.getDocumentBaseUrl(document.location);
|
|
|
31651 |
if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
|
|
|
31652 |
documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
|
|
|
31653 |
if (!/[\/\\]$/.test(documentBaseURL)) {
|
|
|
31654 |
documentBaseURL += '/';
|
|
|
31655 |
}
|
|
|
31656 |
}
|
|
|
31657 |
const preInit = window.tinymce || window.tinyMCEPreInit;
|
|
|
31658 |
if (preInit) {
|
|
|
31659 |
baseURL = preInit.base || preInit.baseURL;
|
|
|
31660 |
suffix = preInit.suffix;
|
|
|
31661 |
} else {
|
|
|
31662 |
const scripts = document.getElementsByTagName('script');
|
|
|
31663 |
for (let i = 0; i < scripts.length; i++) {
|
|
|
31664 |
const src = scripts[i].src || '';
|
|
|
31665 |
if (src === '') {
|
|
|
31666 |
continue;
|
|
|
31667 |
}
|
|
|
31668 |
const srcScript = src.substring(src.lastIndexOf('/'));
|
|
|
31669 |
if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
|
|
|
31670 |
if (srcScript.indexOf('.min') !== -1) {
|
|
|
31671 |
suffix = '.min';
|
|
|
31672 |
}
|
|
|
31673 |
baseURL = src.substring(0, src.lastIndexOf('/'));
|
|
|
31674 |
break;
|
|
|
31675 |
}
|
|
|
31676 |
}
|
|
|
31677 |
if (!baseURL && document.currentScript) {
|
|
|
31678 |
const src = document.currentScript.src;
|
|
|
31679 |
if (src.indexOf('.min') !== -1) {
|
|
|
31680 |
suffix = '.min';
|
|
|
31681 |
}
|
|
|
31682 |
baseURL = src.substring(0, src.lastIndexOf('/'));
|
|
|
31683 |
}
|
|
|
31684 |
}
|
|
|
31685 |
self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
|
|
|
31686 |
self.documentBaseURL = documentBaseURL;
|
|
|
31687 |
self.baseURI = new URI(self.baseURL);
|
|
|
31688 |
self.suffix = suffix;
|
|
|
31689 |
setup$w(self);
|
|
|
31690 |
},
|
|
|
31691 |
overrideDefaults(defaultOptions) {
|
|
|
31692 |
const baseUrl = defaultOptions.base_url;
|
|
|
31693 |
if (baseUrl) {
|
|
|
31694 |
this._setBaseUrl(baseUrl);
|
|
|
31695 |
}
|
|
|
31696 |
const suffix = defaultOptions.suffix;
|
|
|
31697 |
if (suffix) {
|
|
|
31698 |
this.suffix = suffix;
|
|
|
31699 |
}
|
|
|
31700 |
this.defaultOptions = defaultOptions;
|
|
|
31701 |
const pluginBaseUrls = defaultOptions.plugin_base_urls;
|
|
|
31702 |
if (pluginBaseUrls !== undefined) {
|
|
|
31703 |
each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
|
|
|
31704 |
AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
|
|
|
31705 |
});
|
|
|
31706 |
}
|
|
|
31707 |
},
|
|
|
31708 |
init(options) {
|
|
|
31709 |
const self = this;
|
|
|
31710 |
let result;
|
|
|
31711 |
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', ' ');
|
|
|
31712 |
const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
|
|
|
31713 |
const createId = elm => {
|
|
|
31714 |
let id = elm.id;
|
|
|
31715 |
if (!id) {
|
|
|
31716 |
id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId);
|
|
|
31717 |
elm.setAttribute('id', id);
|
|
|
31718 |
}
|
|
|
31719 |
return id;
|
|
|
31720 |
};
|
|
|
31721 |
const execCallback = name => {
|
|
|
31722 |
const callback = options[name];
|
|
|
31723 |
if (!callback) {
|
|
|
31724 |
return;
|
|
|
31725 |
}
|
|
|
31726 |
return callback.apply(self, []);
|
|
|
31727 |
};
|
|
|
31728 |
const findTargets = options => {
|
|
|
31729 |
if (Env.browser.isIE() || Env.browser.isEdge()) {
|
| 1441 |
ariadna |
31730 |
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');
|
| 1 |
efrain |
31731 |
return [];
|
|
|
31732 |
} else if (isQuirksMode) {
|
|
|
31733 |
initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
|
|
|
31734 |
return [];
|
|
|
31735 |
} else if (isString(options.selector)) {
|
|
|
31736 |
return DOM.select(options.selector);
|
|
|
31737 |
} else if (isNonNullable(options.target)) {
|
|
|
31738 |
return [options.target];
|
|
|
31739 |
} else {
|
|
|
31740 |
return [];
|
|
|
31741 |
}
|
|
|
31742 |
};
|
|
|
31743 |
let provideResults = editors => {
|
|
|
31744 |
result = editors;
|
|
|
31745 |
};
|
|
|
31746 |
const initEditors = () => {
|
|
|
31747 |
let initCount = 0;
|
|
|
31748 |
const editors = [];
|
|
|
31749 |
let targets;
|
|
|
31750 |
const createEditor = (id, options, targetElm) => {
|
|
|
31751 |
const editor = new Editor(id, options, self);
|
|
|
31752 |
editors.push(editor);
|
|
|
31753 |
editor.on('init', () => {
|
|
|
31754 |
if (++initCount === targets.length) {
|
|
|
31755 |
provideResults(editors);
|
|
|
31756 |
}
|
|
|
31757 |
});
|
|
|
31758 |
editor.targetElm = editor.targetElm || targetElm;
|
|
|
31759 |
editor.render();
|
|
|
31760 |
};
|
|
|
31761 |
DOM.unbind(window, 'ready', initEditors);
|
|
|
31762 |
execCallback('onpageload');
|
|
|
31763 |
targets = unique$1(findTargets(options));
|
|
|
31764 |
Tools.each(targets, elm => {
|
|
|
31765 |
purgeDestroyedEditor(self.get(elm.id));
|
|
|
31766 |
});
|
|
|
31767 |
targets = Tools.grep(targets, elm => {
|
|
|
31768 |
return !self.get(elm.id);
|
|
|
31769 |
});
|
|
|
31770 |
if (targets.length === 0) {
|
|
|
31771 |
provideResults([]);
|
|
|
31772 |
} else {
|
|
|
31773 |
each(targets, elm => {
|
|
|
31774 |
if (isInvalidInlineTarget(options, elm)) {
|
|
|
31775 |
initError('Could not initialize inline editor on invalid inline target element', elm);
|
|
|
31776 |
} else {
|
|
|
31777 |
createEditor(createId(elm), options, elm);
|
|
|
31778 |
}
|
|
|
31779 |
});
|
|
|
31780 |
}
|
|
|
31781 |
};
|
|
|
31782 |
DOM.bind(window, 'ready', initEditors);
|
|
|
31783 |
return new Promise(resolve => {
|
|
|
31784 |
if (result) {
|
|
|
31785 |
resolve(result);
|
|
|
31786 |
} else {
|
|
|
31787 |
provideResults = editors => {
|
|
|
31788 |
resolve(editors);
|
|
|
31789 |
};
|
|
|
31790 |
}
|
|
|
31791 |
});
|
|
|
31792 |
},
|
|
|
31793 |
get(id) {
|
|
|
31794 |
if (arguments.length === 0) {
|
|
|
31795 |
return editors.slice(0);
|
|
|
31796 |
} else if (isString(id)) {
|
|
|
31797 |
return find$2(editors, editor => {
|
|
|
31798 |
return editor.id === id;
|
|
|
31799 |
}).getOr(null);
|
|
|
31800 |
} else if (isNumber(id)) {
|
|
|
31801 |
return editors[id] ? editors[id] : null;
|
|
|
31802 |
} else {
|
|
|
31803 |
return null;
|
|
|
31804 |
}
|
|
|
31805 |
},
|
|
|
31806 |
add(editor) {
|
|
|
31807 |
const self = this;
|
|
|
31808 |
const existingEditor = self.get(editor.id);
|
|
|
31809 |
if (existingEditor === editor) {
|
|
|
31810 |
return editor;
|
|
|
31811 |
}
|
|
|
31812 |
if (existingEditor === null) {
|
|
|
31813 |
editors.push(editor);
|
|
|
31814 |
}
|
|
|
31815 |
toggleGlobalEvents(true);
|
|
|
31816 |
self.activeEditor = editor;
|
|
|
31817 |
self.dispatch('AddEditor', { editor });
|
|
|
31818 |
if (!beforeUnloadDelegate) {
|
|
|
31819 |
beforeUnloadDelegate = e => {
|
|
|
31820 |
const event = self.dispatch('BeforeUnload');
|
|
|
31821 |
if (event.returnValue) {
|
|
|
31822 |
e.preventDefault();
|
|
|
31823 |
e.returnValue = event.returnValue;
|
|
|
31824 |
return event.returnValue;
|
|
|
31825 |
}
|
|
|
31826 |
};
|
|
|
31827 |
window.addEventListener('beforeunload', beforeUnloadDelegate);
|
|
|
31828 |
}
|
|
|
31829 |
return editor;
|
|
|
31830 |
},
|
|
|
31831 |
createEditor(id, options) {
|
|
|
31832 |
return this.add(new Editor(id, options, this));
|
|
|
31833 |
},
|
|
|
31834 |
remove(selector) {
|
|
|
31835 |
const self = this;
|
|
|
31836 |
let editor;
|
|
|
31837 |
if (!selector) {
|
|
|
31838 |
for (let i = editors.length - 1; i >= 0; i--) {
|
|
|
31839 |
self.remove(editors[i]);
|
|
|
31840 |
}
|
|
|
31841 |
return;
|
|
|
31842 |
}
|
|
|
31843 |
if (isString(selector)) {
|
|
|
31844 |
each(DOM.select(selector), elm => {
|
|
|
31845 |
editor = self.get(elm.id);
|
|
|
31846 |
if (editor) {
|
|
|
31847 |
self.remove(editor);
|
|
|
31848 |
}
|
|
|
31849 |
});
|
|
|
31850 |
return;
|
|
|
31851 |
}
|
|
|
31852 |
editor = selector;
|
|
|
31853 |
if (isNull(self.get(editor.id))) {
|
|
|
31854 |
return null;
|
|
|
31855 |
}
|
|
|
31856 |
if (removeEditorFromList(editor)) {
|
|
|
31857 |
self.dispatch('RemoveEditor', { editor });
|
|
|
31858 |
}
|
|
|
31859 |
if (editors.length === 0) {
|
|
|
31860 |
window.removeEventListener('beforeunload', beforeUnloadDelegate);
|
|
|
31861 |
}
|
|
|
31862 |
editor.remove();
|
|
|
31863 |
toggleGlobalEvents(editors.length > 0);
|
|
|
31864 |
return editor;
|
|
|
31865 |
},
|
|
|
31866 |
execCommand(cmd, ui, value) {
|
|
|
31867 |
var _a;
|
|
|
31868 |
const self = this;
|
|
|
31869 |
const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value;
|
|
|
31870 |
switch (cmd) {
|
|
|
31871 |
case 'mceAddEditor': {
|
|
|
31872 |
if (!self.get(editorId)) {
|
|
|
31873 |
const editorOptions = value.options;
|
|
|
31874 |
new Editor(editorId, editorOptions, self).render();
|
|
|
31875 |
}
|
|
|
31876 |
return true;
|
|
|
31877 |
}
|
|
|
31878 |
case 'mceRemoveEditor': {
|
|
|
31879 |
const editor = self.get(editorId);
|
|
|
31880 |
if (editor) {
|
|
|
31881 |
editor.remove();
|
|
|
31882 |
}
|
|
|
31883 |
return true;
|
|
|
31884 |
}
|
|
|
31885 |
case 'mceToggleEditor': {
|
|
|
31886 |
const editor = self.get(editorId);
|
|
|
31887 |
if (!editor) {
|
|
|
31888 |
self.execCommand('mceAddEditor', false, value);
|
|
|
31889 |
return true;
|
|
|
31890 |
}
|
|
|
31891 |
if (editor.isHidden()) {
|
|
|
31892 |
editor.show();
|
|
|
31893 |
} else {
|
|
|
31894 |
editor.hide();
|
|
|
31895 |
}
|
|
|
31896 |
return true;
|
|
|
31897 |
}
|
|
|
31898 |
}
|
|
|
31899 |
if (self.activeEditor) {
|
|
|
31900 |
return self.activeEditor.execCommand(cmd, ui, value);
|
|
|
31901 |
}
|
|
|
31902 |
return false;
|
|
|
31903 |
},
|
|
|
31904 |
triggerSave: () => {
|
|
|
31905 |
each(editors, editor => {
|
|
|
31906 |
editor.save();
|
|
|
31907 |
});
|
|
|
31908 |
},
|
|
|
31909 |
addI18n: (code, items) => {
|
|
|
31910 |
I18n.add(code, items);
|
|
|
31911 |
},
|
|
|
31912 |
translate: text => {
|
|
|
31913 |
return I18n.translate(text);
|
|
|
31914 |
},
|
|
|
31915 |
setActive(editor) {
|
|
|
31916 |
const activeEditor = this.activeEditor;
|
|
|
31917 |
if (this.activeEditor !== editor) {
|
|
|
31918 |
if (activeEditor) {
|
|
|
31919 |
activeEditor.dispatch('deactivate', { relatedTarget: editor });
|
|
|
31920 |
}
|
|
|
31921 |
editor.dispatch('activate', { relatedTarget: activeEditor });
|
|
|
31922 |
}
|
|
|
31923 |
this.activeEditor = editor;
|
|
|
31924 |
},
|
|
|
31925 |
_setBaseUrl(baseUrl) {
|
|
|
31926 |
this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
|
|
|
31927 |
this.baseURI = new URI(this.baseURL);
|
|
|
31928 |
}
|
|
|
31929 |
};
|
|
|
31930 |
EditorManager.setup();
|
|
|
31931 |
|
|
|
31932 |
const setup = () => {
|
|
|
31933 |
const dataValue = value$2();
|
|
|
31934 |
const FakeClipboardItem = items => ({
|
|
|
31935 |
items,
|
|
|
31936 |
types: keys(items),
|
|
|
31937 |
getType: type => get$a(items, type).getOrUndefined()
|
|
|
31938 |
});
|
|
|
31939 |
const write = data => {
|
|
|
31940 |
dataValue.set(data);
|
|
|
31941 |
};
|
|
|
31942 |
const read = () => dataValue.get().getOrUndefined();
|
|
|
31943 |
const clear = dataValue.clear;
|
|
|
31944 |
return {
|
|
|
31945 |
FakeClipboardItem,
|
|
|
31946 |
write,
|
|
|
31947 |
read,
|
|
|
31948 |
clear
|
|
|
31949 |
};
|
|
|
31950 |
};
|
|
|
31951 |
const FakeClipboard = setup();
|
|
|
31952 |
|
|
|
31953 |
const min = Math.min, max = Math.max, round = Math.round;
|
|
|
31954 |
const relativePosition = (rect, targetRect, rel) => {
|
|
|
31955 |
let x = targetRect.x;
|
|
|
31956 |
let y = targetRect.y;
|
|
|
31957 |
const w = rect.w;
|
|
|
31958 |
const h = rect.h;
|
|
|
31959 |
const targetW = targetRect.w;
|
|
|
31960 |
const targetH = targetRect.h;
|
|
|
31961 |
const relChars = (rel || '').split('');
|
|
|
31962 |
if (relChars[0] === 'b') {
|
|
|
31963 |
y += targetH;
|
|
|
31964 |
}
|
|
|
31965 |
if (relChars[1] === 'r') {
|
|
|
31966 |
x += targetW;
|
|
|
31967 |
}
|
|
|
31968 |
if (relChars[0] === 'c') {
|
|
|
31969 |
y += round(targetH / 2);
|
|
|
31970 |
}
|
|
|
31971 |
if (relChars[1] === 'c') {
|
|
|
31972 |
x += round(targetW / 2);
|
|
|
31973 |
}
|
|
|
31974 |
if (relChars[3] === 'b') {
|
|
|
31975 |
y -= h;
|
|
|
31976 |
}
|
|
|
31977 |
if (relChars[4] === 'r') {
|
|
|
31978 |
x -= w;
|
|
|
31979 |
}
|
|
|
31980 |
if (relChars[3] === 'c') {
|
|
|
31981 |
y -= round(h / 2);
|
|
|
31982 |
}
|
|
|
31983 |
if (relChars[4] === 'c') {
|
|
|
31984 |
x -= round(w / 2);
|
|
|
31985 |
}
|
|
|
31986 |
return create$2(x, y, w, h);
|
|
|
31987 |
};
|
|
|
31988 |
const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
|
|
|
31989 |
for (let i = 0; i < rels.length; i++) {
|
|
|
31990 |
const pos = relativePosition(rect, targetRect, rels[i]);
|
|
|
31991 |
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) {
|
|
|
31992 |
return rels[i];
|
|
|
31993 |
}
|
|
|
31994 |
}
|
|
|
31995 |
return null;
|
|
|
31996 |
};
|
|
|
31997 |
const inflate = (rect, w, h) => {
|
|
|
31998 |
return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
|
|
|
31999 |
};
|
|
|
32000 |
const intersect = (rect, cropRect) => {
|
|
|
32001 |
const x1 = max(rect.x, cropRect.x);
|
|
|
32002 |
const y1 = max(rect.y, cropRect.y);
|
|
|
32003 |
const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
|
|
|
32004 |
const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
|
|
|
32005 |
if (x2 - x1 < 0 || y2 - y1 < 0) {
|
|
|
32006 |
return null;
|
|
|
32007 |
}
|
|
|
32008 |
return create$2(x1, y1, x2 - x1, y2 - y1);
|
|
|
32009 |
};
|
|
|
32010 |
const clamp = (rect, clampRect, fixedSize) => {
|
|
|
32011 |
let x1 = rect.x;
|
|
|
32012 |
let y1 = rect.y;
|
|
|
32013 |
let x2 = rect.x + rect.w;
|
|
|
32014 |
let y2 = rect.y + rect.h;
|
|
|
32015 |
const cx2 = clampRect.x + clampRect.w;
|
|
|
32016 |
const cy2 = clampRect.y + clampRect.h;
|
|
|
32017 |
const underflowX1 = max(0, clampRect.x - x1);
|
|
|
32018 |
const underflowY1 = max(0, clampRect.y - y1);
|
|
|
32019 |
const overflowX2 = max(0, x2 - cx2);
|
|
|
32020 |
const overflowY2 = max(0, y2 - cy2);
|
|
|
32021 |
x1 += underflowX1;
|
|
|
32022 |
y1 += underflowY1;
|
|
|
32023 |
if (fixedSize) {
|
|
|
32024 |
x2 += underflowX1;
|
|
|
32025 |
y2 += underflowY1;
|
|
|
32026 |
x1 -= overflowX2;
|
|
|
32027 |
y1 -= overflowY2;
|
|
|
32028 |
}
|
|
|
32029 |
x2 -= overflowX2;
|
|
|
32030 |
y2 -= overflowY2;
|
|
|
32031 |
return create$2(x1, y1, x2 - x1, y2 - y1);
|
|
|
32032 |
};
|
|
|
32033 |
const create$2 = (x, y, w, h) => {
|
|
|
32034 |
return {
|
|
|
32035 |
x,
|
|
|
32036 |
y,
|
|
|
32037 |
w,
|
|
|
32038 |
h
|
|
|
32039 |
};
|
|
|
32040 |
};
|
|
|
32041 |
const fromClientRect = clientRect => {
|
|
|
32042 |
return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
|
|
|
32043 |
};
|
|
|
32044 |
const Rect = {
|
|
|
32045 |
inflate,
|
|
|
32046 |
relativePosition,
|
|
|
32047 |
findBestRelativePosition,
|
|
|
32048 |
intersect,
|
|
|
32049 |
clamp,
|
|
|
32050 |
create: create$2,
|
|
|
32051 |
fromClientRect
|
|
|
32052 |
};
|
|
|
32053 |
|
|
|
32054 |
const awaiter = (resolveCb, rejectCb, timeout = 1000) => {
|
|
|
32055 |
let done = false;
|
|
|
32056 |
let timer = null;
|
|
|
32057 |
const complete = completer => (...args) => {
|
|
|
32058 |
if (!done) {
|
|
|
32059 |
done = true;
|
|
|
32060 |
if (timer !== null) {
|
|
|
32061 |
clearTimeout(timer);
|
|
|
32062 |
timer = null;
|
|
|
32063 |
}
|
|
|
32064 |
completer.apply(null, args);
|
|
|
32065 |
}
|
|
|
32066 |
};
|
|
|
32067 |
const resolve = complete(resolveCb);
|
|
|
32068 |
const reject = complete(rejectCb);
|
|
|
32069 |
const start = (...args) => {
|
|
|
32070 |
if (!done && timer === null) {
|
|
|
32071 |
timer = setTimeout(() => reject.apply(null, args), timeout);
|
|
|
32072 |
}
|
|
|
32073 |
};
|
|
|
32074 |
return {
|
|
|
32075 |
start,
|
|
|
32076 |
resolve,
|
|
|
32077 |
reject
|
|
|
32078 |
};
|
|
|
32079 |
};
|
|
|
32080 |
const create$1 = () => {
|
|
|
32081 |
const tasks = {};
|
|
|
32082 |
const resultFns = {};
|
|
|
32083 |
const resources = {};
|
|
|
32084 |
const load = (id, url) => {
|
|
|
32085 |
const loadErrMsg = `Script at URL "${ url }" failed to load`;
|
|
|
32086 |
const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`;
|
|
|
32087 |
if (tasks[id] !== undefined) {
|
|
|
32088 |
return tasks[id];
|
|
|
32089 |
} else {
|
|
|
32090 |
const task = new Promise((resolve, reject) => {
|
|
|
32091 |
const waiter = awaiter(resolve, reject);
|
|
|
32092 |
resultFns[id] = waiter.resolve;
|
|
|
32093 |
ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
|
|
|
32094 |
});
|
|
|
32095 |
tasks[id] = task;
|
|
|
32096 |
return task;
|
|
|
32097 |
}
|
|
|
32098 |
};
|
|
|
32099 |
const add = (id, data) => {
|
|
|
32100 |
if (resultFns[id] !== undefined) {
|
|
|
32101 |
resultFns[id](data);
|
|
|
32102 |
delete resultFns[id];
|
|
|
32103 |
}
|
|
|
32104 |
tasks[id] = Promise.resolve(data);
|
|
|
32105 |
resources[id] = data;
|
|
|
32106 |
};
|
|
|
32107 |
const has = id => {
|
|
|
32108 |
return id in resources;
|
|
|
32109 |
};
|
|
|
32110 |
const unload = id => {
|
|
|
32111 |
delete tasks[id];
|
| 1441 |
ariadna |
32112 |
delete resources[id];
|
| 1 |
efrain |
32113 |
};
|
|
|
32114 |
const get = id => resources[id];
|
|
|
32115 |
return {
|
|
|
32116 |
load,
|
|
|
32117 |
add,
|
|
|
32118 |
has,
|
|
|
32119 |
get,
|
|
|
32120 |
unload
|
|
|
32121 |
};
|
|
|
32122 |
};
|
|
|
32123 |
const Resource = create$1();
|
|
|
32124 |
|
|
|
32125 |
const create = () => (() => {
|
|
|
32126 |
let data = {};
|
|
|
32127 |
let keys = [];
|
|
|
32128 |
const storage = {
|
|
|
32129 |
getItem: key => {
|
|
|
32130 |
const item = data[key];
|
|
|
32131 |
return item ? item : null;
|
|
|
32132 |
},
|
|
|
32133 |
setItem: (key, value) => {
|
|
|
32134 |
keys.push(key);
|
|
|
32135 |
data[key] = String(value);
|
|
|
32136 |
},
|
|
|
32137 |
key: index => {
|
|
|
32138 |
return keys[index];
|
|
|
32139 |
},
|
|
|
32140 |
removeItem: key => {
|
|
|
32141 |
keys = keys.filter(k => k === key);
|
|
|
32142 |
delete data[key];
|
|
|
32143 |
},
|
|
|
32144 |
clear: () => {
|
|
|
32145 |
keys = [];
|
|
|
32146 |
data = {};
|
|
|
32147 |
},
|
|
|
32148 |
length: 0
|
|
|
32149 |
};
|
|
|
32150 |
Object.defineProperty(storage, 'length', {
|
|
|
32151 |
get: () => keys.length,
|
|
|
32152 |
configurable: false,
|
|
|
32153 |
enumerable: false
|
|
|
32154 |
});
|
|
|
32155 |
return storage;
|
|
|
32156 |
})();
|
|
|
32157 |
|
|
|
32158 |
let localStorage;
|
|
|
32159 |
try {
|
|
|
32160 |
const test = '__storage_test__';
|
|
|
32161 |
localStorage = window.localStorage;
|
|
|
32162 |
localStorage.setItem(test, test);
|
|
|
32163 |
localStorage.removeItem(test);
|
| 1441 |
ariadna |
32164 |
} catch (_a) {
|
| 1 |
efrain |
32165 |
localStorage = create();
|
|
|
32166 |
}
|
|
|
32167 |
var LocalStorage = localStorage;
|
|
|
32168 |
|
|
|
32169 |
const publicApi = {
|
|
|
32170 |
geom: { Rect },
|
|
|
32171 |
util: {
|
|
|
32172 |
Delay,
|
|
|
32173 |
Tools,
|
|
|
32174 |
VK,
|
|
|
32175 |
URI,
|
|
|
32176 |
EventDispatcher,
|
|
|
32177 |
Observable,
|
|
|
32178 |
I18n,
|
|
|
32179 |
LocalStorage,
|
|
|
32180 |
ImageUploader
|
|
|
32181 |
},
|
|
|
32182 |
dom: {
|
|
|
32183 |
EventUtils,
|
|
|
32184 |
TreeWalker: DomTreeWalker,
|
|
|
32185 |
TextSeeker,
|
|
|
32186 |
DOMUtils,
|
|
|
32187 |
ScriptLoader,
|
|
|
32188 |
RangeUtils,
|
|
|
32189 |
Serializer: DomSerializer,
|
|
|
32190 |
StyleSheetLoader,
|
|
|
32191 |
ControlSelection,
|
|
|
32192 |
BookmarkManager,
|
|
|
32193 |
Selection: EditorSelection,
|
|
|
32194 |
Event: EventUtils.Event
|
|
|
32195 |
},
|
|
|
32196 |
html: {
|
|
|
32197 |
Styles,
|
|
|
32198 |
Entities,
|
|
|
32199 |
Node: AstNode,
|
|
|
32200 |
Schema,
|
|
|
32201 |
DomParser,
|
|
|
32202 |
Writer,
|
|
|
32203 |
Serializer: HtmlSerializer
|
|
|
32204 |
},
|
|
|
32205 |
Env,
|
|
|
32206 |
AddOnManager,
|
|
|
32207 |
Annotator,
|
|
|
32208 |
Formatter,
|
|
|
32209 |
UndoManager,
|
|
|
32210 |
EditorCommands,
|
|
|
32211 |
WindowManager,
|
|
|
32212 |
NotificationManager,
|
|
|
32213 |
EditorObservable,
|
|
|
32214 |
Shortcuts,
|
|
|
32215 |
Editor,
|
|
|
32216 |
FocusManager,
|
|
|
32217 |
EditorManager,
|
|
|
32218 |
DOM: DOMUtils.DOM,
|
|
|
32219 |
ScriptLoader: ScriptLoader.ScriptLoader,
|
|
|
32220 |
PluginManager,
|
|
|
32221 |
ThemeManager,
|
|
|
32222 |
ModelManager,
|
|
|
32223 |
IconManager,
|
|
|
32224 |
Resource,
|
|
|
32225 |
FakeClipboard,
|
|
|
32226 |
trim: Tools.trim,
|
|
|
32227 |
isArray: Tools.isArray,
|
|
|
32228 |
is: Tools.is,
|
|
|
32229 |
toArray: Tools.toArray,
|
|
|
32230 |
makeMap: Tools.makeMap,
|
|
|
32231 |
each: Tools.each,
|
|
|
32232 |
map: Tools.map,
|
|
|
32233 |
grep: Tools.grep,
|
|
|
32234 |
inArray: Tools.inArray,
|
|
|
32235 |
extend: Tools.extend,
|
|
|
32236 |
walk: Tools.walk,
|
|
|
32237 |
resolve: Tools.resolve,
|
|
|
32238 |
explode: Tools.explode,
|
|
|
32239 |
_addCacheSuffix: Tools._addCacheSuffix
|
|
|
32240 |
};
|
|
|
32241 |
const tinymce$1 = Tools.extend(EditorManager, publicApi);
|
|
|
32242 |
|
|
|
32243 |
const exportToModuleLoaders = tinymce => {
|
|
|
32244 |
if (typeof module === 'object') {
|
|
|
32245 |
try {
|
|
|
32246 |
module.exports = tinymce;
|
| 1441 |
ariadna |
32247 |
} catch (_a) {
|
| 1 |
efrain |
32248 |
}
|
|
|
32249 |
}
|
|
|
32250 |
};
|
|
|
32251 |
const exportToWindowGlobal = tinymce => {
|
|
|
32252 |
window.tinymce = tinymce;
|
|
|
32253 |
window.tinyMCE = tinymce;
|
|
|
32254 |
};
|
|
|
32255 |
exportToWindowGlobal(tinymce$1);
|
|
|
32256 |
exportToModuleLoaders(tinymce$1);
|
|
|
32257 |
|
|
|
32258 |
})();
|