package.dist.libs.tinymce.tinymce.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
Premium and Open Source dashboard template with responsive and high quality UI.
The newest version!
/**
* TinyMCE version 7.3.0 (2024-08-07)
*/
(function () {
'use strict';
var typeOf$1 = function (x) {
if (x === null) {
return 'null';
}
if (x === undefined) {
return 'undefined';
}
var t = typeof x;
if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
return 'array';
}
if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
return 'string';
}
return t;
};
var isEquatableType = function (x) {
return [
'undefined',
'boolean',
'number',
'string',
'function',
'xml',
'null'
].indexOf(x) !== -1;
};
var sort$1 = function (xs, compareFn) {
var clone = Array.prototype.slice.call(xs);
return clone.sort(compareFn);
};
var contramap = function (eqa, f) {
return eq$2(function (x, y) {
return eqa.eq(f(x), f(y));
});
};
var eq$2 = function (f) {
return { eq: f };
};
var tripleEq = eq$2(function (x, y) {
return x === y;
});
var eqString = tripleEq;
var eqArray = function (eqa) {
return eq$2(function (x, y) {
if (x.length !== y.length) {
return false;
}
var len = x.length;
for (var i = 0; i < len; i++) {
if (!eqa.eq(x[i], y[i])) {
return false;
}
}
return true;
});
};
var eqSortedArray = function (eqa, compareFn) {
return contramap(eqArray(eqa), function (xs) {
return sort$1(xs, compareFn);
});
};
var eqRecord = function (eqa) {
return eq$2(function (x, y) {
var kx = Object.keys(x);
var ky = Object.keys(y);
if (!eqSortedArray(eqString).eq(kx, ky)) {
return false;
}
var len = kx.length;
for (var i = 0; i < len; i++) {
var q = kx[i];
if (!eqa.eq(x[q], y[q])) {
return false;
}
}
return true;
});
};
var eqAny = eq$2(function (x, y) {
if (x === y) {
return true;
}
var tx = typeOf$1(x);
var ty = typeOf$1(y);
if (tx !== ty) {
return false;
}
if (isEquatableType(tx)) {
return x === y;
} else if (tx === 'array') {
return eqArray(eqAny).eq(x, y);
} else if (tx === 'object') {
return eqRecord(eqAny).eq(x, y);
}
return false;
});
const getPrototypeOf$2 = Object.getPrototypeOf;
const hasProto = (v, constructor, predicate) => {
var _a;
if (predicate(v, constructor.prototype)) {
return true;
} else {
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
}
};
const typeOf = x => {
const t = typeof x;
if (x === null) {
return 'null';
} else if (t === 'object' && Array.isArray(x)) {
return 'array';
} else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
return 'string';
} else {
return t;
}
};
const isType$1 = type => value => typeOf(value) === type;
const isSimpleType = type => value => typeof value === type;
const eq$1 = t => a => t === a;
const is$4 = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf$2(o) === proto);
const isString = isType$1('string');
const isObject = isType$1('object');
const isPlainObject = value => is$4(value, Object);
const isArray$1 = isType$1('array');
const isNull = eq$1(null);
const isBoolean = isSimpleType('boolean');
const isUndefined = eq$1(undefined);
const isNullable = a => a === null || a === undefined;
const isNonNullable = a => !isNullable(a);
const isFunction = isSimpleType('function');
const isNumber = isSimpleType('number');
const isArrayOf = (value, pred) => {
if (isArray$1(value)) {
for (let i = 0, len = value.length; i < len; ++i) {
if (!pred(value[i])) {
return false;
}
}
return true;
}
return false;
};
const noop = () => {
};
const compose = (fa, fb) => {
return (...args) => {
return fa(fb.apply(null, args));
};
};
const compose1 = (fbc, fab) => a => fbc(fab(a));
const constant = value => {
return () => {
return value;
};
};
const identity = x => {
return x;
};
const tripleEquals = (a, b) => {
return a === b;
};
function curry(fn, ...initialArgs) {
return (...restArgs) => {
const all = initialArgs.concat(restArgs);
return fn.apply(null, all);
};
}
const not = f => t => !f(t);
const die = msg => {
return () => {
throw new Error(msg);
};
};
const apply$1 = f => {
return f();
};
const call = f => {
f();
};
const never = constant(false);
const always = constant(true);
class Optional {
constructor(tag, value) {
this.tag = tag;
this.value = value;
}
static some(value) {
return new Optional(true, value);
}
static none() {
return Optional.singletonNone;
}
fold(onNone, onSome) {
if (this.tag) {
return onSome(this.value);
} else {
return onNone();
}
}
isSome() {
return this.tag;
}
isNone() {
return !this.tag;
}
map(mapper) {
if (this.tag) {
return Optional.some(mapper(this.value));
} else {
return Optional.none();
}
}
bind(binder) {
if (this.tag) {
return binder(this.value);
} else {
return Optional.none();
}
}
exists(predicate) {
return this.tag && predicate(this.value);
}
forall(predicate) {
return !this.tag || predicate(this.value);
}
filter(predicate) {
if (!this.tag || predicate(this.value)) {
return this;
} else {
return Optional.none();
}
}
getOr(replacement) {
return this.tag ? this.value : replacement;
}
or(replacement) {
return this.tag ? this : replacement;
}
getOrThunk(thunk) {
return this.tag ? this.value : thunk();
}
orThunk(thunk) {
return this.tag ? this : thunk();
}
getOrDie(message) {
if (!this.tag) {
throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
} else {
return this.value;
}
}
static from(value) {
return isNonNullable(value) ? Optional.some(value) : Optional.none();
}
getOrNull() {
return this.tag ? this.value : null;
}
getOrUndefined() {
return this.value;
}
each(worker) {
if (this.tag) {
worker(this.value);
}
}
toArray() {
return this.tag ? [this.value] : [];
}
toString() {
return this.tag ? `some(${ this.value })` : 'none()';
}
}
Optional.singletonNone = new Optional(false);
const nativeSlice = Array.prototype.slice;
const nativeIndexOf = Array.prototype.indexOf;
const nativePush = Array.prototype.push;
const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
const indexOf$1 = (xs, x) => {
const r = rawIndexOf(xs, x);
return r === -1 ? Optional.none() : Optional.some(r);
};
const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
const exists = (xs, pred) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
return true;
}
}
return false;
};
const map$3 = (xs, f) => {
const len = xs.length;
const r = new Array(len);
for (let i = 0; i < len; i++) {
const x = xs[i];
r[i] = f(x, i);
}
return r;
};
const each$e = (xs, f) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
f(x, i);
}
};
const eachr = (xs, f) => {
for (let i = xs.length - 1; i >= 0; i--) {
const x = xs[i];
f(x, i);
}
};
const partition$2 = (xs, pred) => {
const pass = [];
const fail = [];
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
const arr = pred(x, i) ? pass : fail;
arr.push(x);
}
return {
pass,
fail
};
};
const filter$5 = (xs, pred) => {
const r = [];
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
r.push(x);
}
}
return r;
};
const foldr = (xs, f, acc) => {
eachr(xs, (x, i) => {
acc = f(acc, x, i);
});
return acc;
};
const foldl = (xs, f, acc) => {
each$e(xs, (x, i) => {
acc = f(acc, x, i);
});
return acc;
};
const findUntil$1 = (xs, pred, until) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
return Optional.some(x);
} else if (until(x, i)) {
break;
}
}
return Optional.none();
};
const find$2 = (xs, pred) => {
return findUntil$1(xs, pred, never);
};
const findIndex$2 = (xs, pred) => {
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (pred(x, i)) {
return Optional.some(i);
}
}
return Optional.none();
};
const flatten = xs => {
const r = [];
for (let i = 0, len = xs.length; i < len; ++i) {
if (!isArray$1(xs[i])) {
throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
}
nativePush.apply(r, xs[i]);
}
return r;
};
const bind$3 = (xs, f) => flatten(map$3(xs, f));
const forall = (xs, pred) => {
for (let i = 0, len = xs.length; i < len; ++i) {
const x = xs[i];
if (pred(x, i) !== true) {
return false;
}
}
return true;
};
const reverse = xs => {
const r = nativeSlice.call(xs, 0);
r.reverse();
return r;
};
const difference = (a1, a2) => filter$5(a1, x => !contains$2(a2, x));
const mapToObject = (xs, f) => {
const r = {};
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
r[String(x)] = f(x, i);
}
return r;
};
const sort = (xs, comparator) => {
const copy = nativeSlice.call(xs, 0);
copy.sort(comparator);
return copy;
};
const get$b = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
const head = xs => get$b(xs, 0);
const last$2 = xs => get$b(xs, xs.length - 1);
const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
const findMap = (arr, f) => {
for (let i = 0; i < arr.length; i++) {
const r = f(arr[i], i);
if (r.isSome()) {
return r;
}
}
return Optional.none();
};
const unique$1 = (xs, comparator) => {
const r = [];
const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$2(r, x);
for (let i = 0, len = xs.length; i < len; i++) {
const x = xs[i];
if (!isDuplicated(x)) {
r.push(x);
}
}
return r;
};
const keys = Object.keys;
const hasOwnProperty$1 = Object.hasOwnProperty;
const each$d = (obj, f) => {
const props = keys(obj);
for (let k = 0, len = props.length; k < len; k++) {
const i = props[k];
const x = obj[i];
f(x, i);
}
};
const map$2 = (obj, f) => {
return tupleMap(obj, (x, i) => ({
k: i,
v: f(x, i)
}));
};
const tupleMap = (obj, f) => {
const r = {};
each$d(obj, (x, i) => {
const tuple = f(x, i);
r[tuple.k] = tuple.v;
});
return r;
};
const objAcc = r => (x, i) => {
r[i] = x;
};
const internalFilter = (obj, pred, onTrue, onFalse) => {
each$d(obj, (x, i) => {
(pred(x, i) ? onTrue : onFalse)(x, i);
});
};
const bifilter = (obj, pred) => {
const t = {};
const f = {};
internalFilter(obj, pred, objAcc(t), objAcc(f));
return {
t,
f
};
};
const filter$4 = (obj, pred) => {
const t = {};
internalFilter(obj, pred, objAcc(t), noop);
return t;
};
const mapToArray = (obj, f) => {
const r = [];
each$d(obj, (value, name) => {
r.push(f(value, name));
});
return r;
};
const values = obj => {
return mapToArray(obj, identity);
};
const get$a = (obj, key) => {
return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
};
const has$2 = (obj, key) => hasOwnProperty$1.call(obj, key);
const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
const equal$1 = (a1, a2, eq = eqAny) => eqRecord(eq).eq(a1, a2);
const stringArray = a => {
const all = {};
each$e(a, key => {
all[key] = {};
});
return keys(all);
};
const isArrayLike = o => o.length !== undefined;
const isArray = Array.isArray;
const toArray$1 = obj => {
if (!isArray(obj)) {
const array = [];
for (let i = 0, l = obj.length; i < l; i++) {
array[i] = obj[i];
}
return array;
} else {
return obj;
}
};
const each$c = (o, cb, s) => {
if (!o) {
return false;
}
s = s || o;
if (isArrayLike(o)) {
for (let n = 0, l = o.length; n < l; n++) {
if (cb.call(s, o[n], n, o) === false) {
return false;
}
}
} else {
for (const n in o) {
if (has$2(o, n)) {
if (cb.call(s, o[n], n, o) === false) {
return false;
}
}
}
}
return true;
};
const map$1 = (array, callback) => {
const out = [];
each$c(array, (item, index) => {
out.push(callback(item, index, array));
});
return out;
};
const filter$3 = (a, f) => {
const o = [];
each$c(a, (v, index) => {
if (!f || f(v, index, a)) {
o.push(v);
}
});
return o;
};
const indexOf = (a, v) => {
if (a) {
for (let i = 0, l = a.length; i < l; i++) {
if (a[i] === v) {
return i;
}
}
}
return -1;
};
const reduce = (collection, iteratee, accumulator, thisArg) => {
let acc = isUndefined(accumulator) ? collection[0] : accumulator;
for (let i = 0; i < collection.length; i++) {
acc = iteratee.call(thisArg, acc, collection[i], i);
}
return acc;
};
const findIndex$1 = (array, predicate, thisArg) => {
for (let i = 0, l = array.length; i < l; i++) {
if (predicate.call(thisArg, array[i], i, array)) {
return i;
}
}
return -1;
};
const last$1 = collection => collection[collection.length - 1];
const cached = f => {
let called = false;
let r;
return (...args) => {
if (!called) {
called = true;
r = f.apply(null, args);
}
return r;
};
};
const DeviceType = (os, browser, userAgent, mediaMatch) => {
const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
const isiPhone = os.isiOS() && !isiPad;
const isMobile = os.isiOS() || os.isAndroid();
const isTouch = isMobile || mediaMatch('(pointer:coarse)');
const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
const isPhone = isiPhone || isMobile && !isTablet;
const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
const isDesktop = !isPhone && !isTablet && !iOSwebview;
return {
isiPad: constant(isiPad),
isiPhone: constant(isiPhone),
isTablet: constant(isTablet),
isPhone: constant(isPhone),
isTouch: constant(isTouch),
isAndroid: os.isAndroid,
isiOS: os.isiOS,
isWebView: constant(iOSwebview),
isDesktop: constant(isDesktop)
};
};
const firstMatch = (regexes, s) => {
for (let i = 0; i < regexes.length; i++) {
const x = regexes[i];
if (x.test(s)) {
return x;
}
}
return undefined;
};
const find$1 = (regexes, agent) => {
const r = firstMatch(regexes, agent);
if (!r) {
return {
major: 0,
minor: 0
};
}
const group = i => {
return Number(agent.replace(r, '$' + i));
};
return nu$3(group(1), group(2));
};
const detect$4 = (versionRegexes, agent) => {
const cleanedAgent = String(agent).toLowerCase();
if (versionRegexes.length === 0) {
return unknown$2();
}
return find$1(versionRegexes, cleanedAgent);
};
const unknown$2 = () => {
return nu$3(0, 0);
};
const nu$3 = (major, minor) => {
return {
major,
minor
};
};
const Version = {
nu: nu$3,
detect: detect$4,
unknown: unknown$2
};
const detectBrowser$1 = (browsers, userAgentData) => {
return findMap(userAgentData.brands, uaBrand => {
const lcBrand = uaBrand.brand.toLowerCase();
return find$2(browsers, browser => {
var _a;
return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
}).map(info => ({
current: info.name,
version: Version.nu(parseInt(uaBrand.version, 10), 0)
}));
});
};
const detect$3 = (candidates, userAgent) => {
const agent = String(userAgent).toLowerCase();
return find$2(candidates, candidate => {
return candidate.search(agent);
});
};
const detectBrowser = (browsers, userAgent) => {
return detect$3(browsers, userAgent).map(browser => {
const version = Version.detect(browser.versionRegexes, userAgent);
return {
current: browser.name,
version
};
});
};
const detectOs = (oses, userAgent) => {
return detect$3(oses, userAgent).map(os => {
const version = Version.detect(os.versionRegexes, userAgent);
return {
current: os.name,
version
};
});
};
const removeFromStart = (str, numChars) => {
return str.substring(numChars);
};
const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
const removeLeading = (str, prefix) => {
return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
};
const contains$1 = (str, substr, start = 0, end) => {
const idx = str.indexOf(substr, start);
if (idx !== -1) {
return isUndefined(end) ? true : idx + substr.length <= end;
} else {
return false;
}
};
const startsWith = (str, prefix) => {
return checkRange(str, prefix, 0);
};
const endsWith = (str, suffix) => {
return checkRange(str, suffix, str.length - suffix.length);
};
const blank = r => s => s.replace(r, '');
const trim$4 = blank(/^\s+|\s+$/g);
const lTrim = blank(/^\s+/g);
const rTrim = blank(/\s+$/g);
const isNotEmpty = s => s.length > 0;
const isEmpty$3 = s => !isNotEmpty(s);
const repeat = (s, count) => count <= 0 ? '' : new Array(count + 1).join(s);
const toInt = (value, radix = 10) => {
const num = parseInt(value, radix);
return isNaN(num) ? Optional.none() : Optional.some(num);
};
const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
const checkContains = target => {
return uastring => {
return contains$1(uastring, target);
};
};
const browsers = [
{
name: 'Edge',
versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
search: uastring => {
return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
}
},
{
name: 'Chromium',
brand: 'Chromium',
versionRegexes: [
/.*?chrome\/([0-9]+)\.([0-9]+).*/,
normalVersionRegex
],
search: uastring => {
return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
}
},
{
name: 'IE',
versionRegexes: [
/.*?msie\ ?([0-9]+)\.([0-9]+).*/,
/.*?rv:([0-9]+)\.([0-9]+).*/
],
search: uastring => {
return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
}
},
{
name: 'Opera',
versionRegexes: [
normalVersionRegex,
/.*?opera\/([0-9]+)\.([0-9]+).*/
],
search: checkContains('opera')
},
{
name: 'Firefox',
versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
search: checkContains('firefox')
},
{
name: 'Safari',
versionRegexes: [
normalVersionRegex,
/.*?cpu os ([0-9]+)_([0-9]+).*/
],
search: uastring => {
return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
}
}
];
const oses = [
{
name: 'Windows',
search: checkContains('win'),
versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
},
{
name: 'iOS',
search: uastring => {
return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
},
versionRegexes: [
/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
/.*cpu os ([0-9]+)_([0-9]+).*/,
/.*cpu iphone os ([0-9]+)_([0-9]+).*/
]
},
{
name: 'Android',
search: checkContains('android'),
versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
},
{
name: 'macOS',
search: checkContains('mac os x'),
versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
},
{
name: 'Linux',
search: checkContains('linux'),
versionRegexes: []
},
{
name: 'Solaris',
search: checkContains('sunos'),
versionRegexes: []
},
{
name: 'FreeBSD',
search: checkContains('freebsd'),
versionRegexes: []
},
{
name: 'ChromeOS',
search: checkContains('cros'),
versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
}
];
const PlatformInfo = {
browsers: constant(browsers),
oses: constant(oses)
};
const edge = 'Edge';
const chromium = 'Chromium';
const ie = 'IE';
const opera = 'Opera';
const firefox = 'Firefox';
const safari = 'Safari';
const unknown$1 = () => {
return nu$2({
current: undefined,
version: Version.unknown()
});
};
const nu$2 = info => {
const current = info.current;
const version = info.version;
const isBrowser = name => () => current === name;
return {
current,
version,
isEdge: isBrowser(edge),
isChromium: isBrowser(chromium),
isIE: isBrowser(ie),
isOpera: isBrowser(opera),
isFirefox: isBrowser(firefox),
isSafari: isBrowser(safari)
};
};
const Browser = {
unknown: unknown$1,
nu: nu$2,
edge: constant(edge),
chromium: constant(chromium),
ie: constant(ie),
opera: constant(opera),
firefox: constant(firefox),
safari: constant(safari)
};
const windows = 'Windows';
const ios = 'iOS';
const android = 'Android';
const linux = 'Linux';
const macos = 'macOS';
const solaris = 'Solaris';
const freebsd = 'FreeBSD';
const chromeos = 'ChromeOS';
const unknown = () => {
return nu$1({
current: undefined,
version: Version.unknown()
});
};
const nu$1 = info => {
const current = info.current;
const version = info.version;
const isOS = name => () => current === name;
return {
current,
version,
isWindows: isOS(windows),
isiOS: isOS(ios),
isAndroid: isOS(android),
isMacOS: isOS(macos),
isLinux: isOS(linux),
isSolaris: isOS(solaris),
isFreeBSD: isOS(freebsd),
isChromeOS: isOS(chromeos)
};
};
const OperatingSystem = {
unknown,
nu: nu$1,
windows: constant(windows),
ios: constant(ios),
android: constant(android),
linux: constant(linux),
macos: constant(macos),
solaris: constant(solaris),
freebsd: constant(freebsd),
chromeos: constant(chromeos)
};
const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => {
const browsers = PlatformInfo.browsers();
const oses = PlatformInfo.oses();
const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
return {
browser,
os,
deviceType
};
};
const PlatformDetection = { detect: detect$2 };
const mediaMatch = query => window.matchMedia(query).matches;
let platform$4 = cached(() => PlatformDetection.detect(window.navigator.userAgent, Optional.from(window.navigator.userAgentData), mediaMatch));
const detect$1 = () => platform$4();
const userAgent = window.navigator.userAgent;
const platform$3 = detect$1();
const browser$3 = platform$3.browser;
const os$1 = platform$3.os;
const deviceType = platform$3.deviceType;
const windowsPhone = userAgent.indexOf('Windows Phone') !== -1;
const Env = {
transparentSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
documentMode: browser$3.isIE() ? document.documentMode || 7 : 10,
cacheSuffix: null,
container: null,
canHaveCSP: !browser$3.isIE(),
windowsPhone,
browser: {
current: browser$3.current,
version: browser$3.version,
isChromium: browser$3.isChromium,
isEdge: browser$3.isEdge,
isFirefox: browser$3.isFirefox,
isIE: browser$3.isIE,
isOpera: browser$3.isOpera,
isSafari: browser$3.isSafari
},
os: {
current: os$1.current,
version: os$1.version,
isAndroid: os$1.isAndroid,
isChromeOS: os$1.isChromeOS,
isFreeBSD: os$1.isFreeBSD,
isiOS: os$1.isiOS,
isLinux: os$1.isLinux,
isMacOS: os$1.isMacOS,
isSolaris: os$1.isSolaris,
isWindows: os$1.isWindows
},
deviceType: {
isDesktop: deviceType.isDesktop,
isiPad: deviceType.isiPad,
isiPhone: deviceType.isiPhone,
isPhone: deviceType.isPhone,
isTablet: deviceType.isTablet,
isTouch: deviceType.isTouch,
isWebView: deviceType.isWebView
}
};
const whiteSpaceRegExp$1 = /^\s*|\s*$/g;
const trim$3 = str => {
return isNullable(str) ? '' : ('' + str).replace(whiteSpaceRegExp$1, '');
};
const is$3 = (obj, type) => {
if (!type) {
return obj !== undefined;
}
if (type === 'array' && isArray(obj)) {
return true;
}
return typeof obj === type;
};
const makeMap$4 = (items, delim, map = {}) => {
const resolvedItems = isString(items) ? items.split(delim || ',') : items || [];
let i = resolvedItems.length;
while (i--) {
map[resolvedItems[i]] = {};
}
return map;
};
const hasOwnProperty = has$2;
const extend$3 = (obj, ...exts) => {
for (let i = 0; i < exts.length; i++) {
const ext = exts[i];
for (const name in ext) {
if (has$2(ext, name)) {
const value = ext[name];
if (value !== undefined) {
obj[name] = value;
}
}
}
}
return obj;
};
const walk$4 = function (o, f, n, s) {
s = s || this;
if (o) {
if (n) {
o = o[n];
}
each$c(o, (o, i) => {
if (f.call(s, o, i, n) === false) {
return false;
} else {
walk$4(o, f, n, s);
return true;
}
});
}
};
const resolve$3 = (n, o = window) => {
const path = n.split('.');
for (let i = 0, l = path.length; i < l; i++) {
o = o[path[i]];
if (!o) {
break;
}
}
return o;
};
const explode$3 = (s, d) => {
if (isArray$1(s)) {
return s;
} else if (s === '') {
return [];
} else {
return map$1(s.split(d || ','), trim$3);
}
};
const _addCacheSuffix = url => {
const cacheSuffix = Env.cacheSuffix;
if (cacheSuffix) {
url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
}
return url;
};
const Tools = {
trim: trim$3,
isArray: isArray,
is: is$3,
toArray: toArray$1,
makeMap: makeMap$4,
each: each$c,
map: map$1,
grep: filter$3,
inArray: indexOf,
hasOwn: hasOwnProperty,
extend: extend$3,
walk: walk$4,
resolve: resolve$3,
explode: explode$3,
_addCacheSuffix
};
const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
const cat = arr => {
const r = [];
const push = x => {
r.push(x);
};
for (let i = 0; i < arr.length; i++) {
arr[i].each(push);
}
return r;
};
const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
const Global = typeof window !== 'undefined' ? window : Function('return this;')();
const path = (parts, scope) => {
let o = scope !== undefined && scope !== null ? scope : Global;
for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
o = o[parts[i]];
}
return o;
};
const resolve$2 = (p, scope) => {
const parts = p.split('.');
return path(parts, scope);
};
const unsafe = (name, scope) => {
return resolve$2(name, scope);
};
const getOrDie = (name, scope) => {
const actual = unsafe(name, scope);
if (actual === undefined || actual === null) {
throw new Error(name + ' not available on this browser');
}
return actual;
};
const getPrototypeOf$1 = Object.getPrototypeOf;
const sandHTMLElement = scope => {
return getOrDie('HTMLElement', scope);
};
const isPrototypeOf = x => {
const scope = resolve$2('ownerDocument.defaultView', x);
return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name));
};
const COMMENT = 8;
const DOCUMENT = 9;
const DOCUMENT_FRAGMENT = 11;
const ELEMENT = 1;
const TEXT = 3;
const name = element => {
const r = element.dom.nodeName;
return r.toLowerCase();
};
const type$1 = element => element.dom.nodeType;
const isType = t => element => type$1(element) === t;
const isComment$1 = element => type$1(element) === COMMENT || name(element) === '#comment';
const isHTMLElement$1 = element => isElement$7(element) && isPrototypeOf(element.dom);
const isElement$7 = isType(ELEMENT);
const isText$c = isType(TEXT);
const isDocument$2 = isType(DOCUMENT);
const isDocumentFragment$1 = isType(DOCUMENT_FRAGMENT);
const isTag = tag => e => isElement$7(e) && name(e) === tag;
const rawSet = (dom, key, value) => {
if (isString(value) || isBoolean(value) || isNumber(value)) {
dom.setAttribute(key, value + '');
} else {
console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
throw new Error('Attribute value was not simple');
}
};
const set$3 = (element, key, value) => {
rawSet(element.dom, key, value);
};
const setAll$1 = (element, attrs) => {
const dom = element.dom;
each$d(attrs, (v, k) => {
rawSet(dom, k, v);
});
};
const get$9 = (element, key) => {
const v = element.dom.getAttribute(key);
return v === null ? undefined : v;
};
const getOpt = (element, key) => Optional.from(get$9(element, key));
const has$1 = (element, key) => {
const dom = element.dom;
return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
};
const remove$9 = (element, key) => {
element.dom.removeAttribute(key);
};
const hasNone = element => {
const attrs = element.dom.attributes;
return attrs === undefined || attrs === null || attrs.length === 0;
};
const clone$4 = element => foldl(element.dom.attributes, (acc, attr) => {
acc[attr.name] = attr.value;
return acc;
}, {});
const read$4 = (element, attr) => {
const value = get$9(element, attr);
return value === undefined || value === '' ? [] : value.split(' ');
};
const add$4 = (element, attr, id) => {
const old = read$4(element, attr);
const nu = old.concat([id]);
set$3(element, attr, nu.join(' '));
return true;
};
const remove$8 = (element, attr, id) => {
const nu = filter$5(read$4(element, attr), v => v !== id);
if (nu.length > 0) {
set$3(element, attr, nu.join(' '));
} else {
remove$9(element, attr);
}
return false;
};
const supports = element => element.dom.classList !== undefined;
const get$8 = element => read$4(element, 'class');
const add$3 = (element, clazz) => add$4(element, 'class', clazz);
const remove$7 = (element, clazz) => remove$8(element, 'class', clazz);
const toggle$2 = (element, clazz) => {
if (contains$2(get$8(element), clazz)) {
return remove$7(element, clazz);
} else {
return add$3(element, clazz);
}
};
const add$2 = (element, clazz) => {
if (supports(element)) {
element.dom.classList.add(clazz);
} else {
add$3(element, clazz);
}
};
const cleanClass = element => {
const classList = supports(element) ? element.dom.classList : get$8(element);
if (classList.length === 0) {
remove$9(element, 'class');
}
};
const remove$6 = (element, clazz) => {
if (supports(element)) {
const classList = element.dom.classList;
classList.remove(clazz);
} else {
remove$7(element, clazz);
}
cleanClass(element);
};
const toggle$1 = (element, clazz) => {
const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$2(element, clazz);
cleanClass(element);
return result;
};
const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
const fromHtml$1 = (html, scope) => {
const doc = scope || document;
const div = doc.createElement('div');
div.innerHTML = html;
if (!div.hasChildNodes() || div.childNodes.length > 1) {
const message = 'HTML does not have a single root node';
console.error(message, html);
throw new Error(message);
}
return fromDom$2(div.childNodes[0]);
};
const fromTag = (tag, scope) => {
const doc = scope || document;
const node = doc.createElement(tag);
return fromDom$2(node);
};
const fromText = (text, scope) => {
const doc = scope || document;
const node = doc.createTextNode(text);
return fromDom$2(node);
};
const fromDom$2 = node => {
if (node === null || node === undefined) {
throw new Error('Node cannot be null or undefined');
}
return { dom: node };
};
const fromPoint$2 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$2);
const SugarElement = {
fromHtml: fromHtml$1,
fromTag,
fromText,
fromDom: fromDom$2,
fromPoint: fromPoint$2
};
const toArray = (target, f) => {
const r = [];
const recurse = e => {
r.push(e);
return f(e);
};
let cur = f(target);
do {
cur = cur.bind(recurse);
} while (cur.isSome());
return r;
};
const is$1 = (element, selector) => {
const dom = element.dom;
if (dom.nodeType !== ELEMENT) {
return false;
} else {
const elem = dom;
if (elem.matches !== undefined) {
return elem.matches(selector);
} else if (elem.msMatchesSelector !== undefined) {
return elem.msMatchesSelector(selector);
} else if (elem.webkitMatchesSelector !== undefined) {
return elem.webkitMatchesSelector(selector);
} else if (elem.mozMatchesSelector !== undefined) {
return elem.mozMatchesSelector(selector);
} else {
throw new Error('Browser lacks native selectors');
}
}
};
const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
const all = (selector, scope) => {
const base = scope === undefined ? document : scope.dom;
return bypassSelector(base) ? [] : map$3(base.querySelectorAll(selector), SugarElement.fromDom);
};
const one = (selector, scope) => {
const base = scope === undefined ? document : scope.dom;
return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
};
const eq = (e1, e2) => e1.dom === e2.dom;
const contains = (e1, e2) => {
const d1 = e1.dom;
const d2 = e2.dom;
return d1 === d2 ? false : d1.contains(d2);
};
const owner$1 = element => SugarElement.fromDom(element.dom.ownerDocument);
const documentOrOwner = dos => isDocument$2(dos) ? dos : owner$1(dos);
const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
const parents$1 = (element, isRoot) => {
const stop = isFunction(isRoot) ? isRoot : never;
let dom = element.dom;
const ret = [];
while (dom.parentNode !== null && dom.parentNode !== undefined) {
const rawParent = dom.parentNode;
const p = SugarElement.fromDom(rawParent);
ret.push(p);
if (stop(p) === true) {
break;
} else {
dom = rawParent;
}
}
return ret;
};
const siblings = element => {
const filterSelf = elements => filter$5(elements, x => !eq(element, x));
return parent(element).map(children$1).map(filterSelf).getOr([]);
};
const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
const prevSiblings = element => reverse(toArray(element, prevSibling));
const nextSiblings = element => toArray(element, nextSibling);
const children$1 = element => map$3(element.dom.childNodes, SugarElement.fromDom);
const child$1 = (element, index) => {
const cs = element.dom.childNodes;
return Optional.from(cs[index]).map(SugarElement.fromDom);
};
const firstChild = element => child$1(element, 0);
const lastChild = element => child$1(element, element.dom.childNodes.length - 1);
const childNodesCount = element => element.dom.childNodes.length;
const getHead = doc => {
const b = doc.dom.head;
if (b === null || b === undefined) {
throw new Error('Head is not available yet');
}
return SugarElement.fromDom(b);
};
const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode());
const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
const getShadowRoot = e => {
const r = getRootNode(e);
return isShadowRoot(r) ? Optional.some(r) : Optional.none();
};
const getShadowHost = e => SugarElement.fromDom(e.dom.host);
const getOriginalEventTarget = event => {
if (isNonNullable(event.target)) {
const el = SugarElement.fromDom(event.target);
if (isElement$7(el) && isOpenShadowHost(el)) {
if (event.composed && event.composedPath) {
const composedPath = event.composedPath();
if (composedPath) {
return head(composedPath);
}
}
}
}
return Optional.from(event.target);
};
const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
const inBody = element => {
const dom = isText$c(element) ? element.dom.parentNode : element.dom;
if (dom === undefined || dom === null || dom.ownerDocument === null) {
return false;
}
const doc = dom.ownerDocument;
return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
};
var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
if (is(scope, a)) {
return Optional.some(scope);
} else if (isFunction(isRoot) && isRoot(scope)) {
return Optional.none();
} else {
return ancestor(scope, a, isRoot);
}
};
const ancestor$4 = (scope, predicate, isRoot) => {
let element = scope.dom;
const stop = isFunction(isRoot) ? isRoot : never;
while (element.parentNode) {
element = element.parentNode;
const el = SugarElement.fromDom(element);
if (predicate(el)) {
return Optional.some(el);
} else if (stop(el)) {
break;
}
}
return Optional.none();
};
const closest$4 = (scope, predicate, isRoot) => {
const is = (s, test) => test(s);
return ClosestOrAncestor(is, ancestor$4, scope, predicate, isRoot);
};
const sibling$1 = (scope, predicate) => {
const element = scope.dom;
if (!element.parentNode) {
return Optional.none();
}
return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
};
const child = (scope, predicate) => {
const pred = node => predicate(SugarElement.fromDom(node));
const result = find$2(scope.dom.childNodes, pred);
return result.map(SugarElement.fromDom);
};
const descendant$2 = (scope, predicate) => {
const descend = node => {
for (let i = 0; i < node.childNodes.length; i++) {
const child = SugarElement.fromDom(node.childNodes[i]);
if (predicate(child)) {
return Optional.some(child);
}
const res = descend(node.childNodes[i]);
if (res.isSome()) {
return res;
}
}
return Optional.none();
};
return descend(scope.dom);
};
const ancestor$3 = (scope, selector, isRoot) => ancestor$4(scope, e => is$1(e, selector), isRoot);
const descendant$1 = (scope, selector) => one(selector, scope);
const closest$3 = (scope, selector, isRoot) => {
const is = (element, selector) => is$1(element, selector);
return ClosestOrAncestor(is, ancestor$3, scope, selector, isRoot);
};
const closest$2 = target => closest$3(target, '[contenteditable]');
const isEditable$2 = (element, assumeEditable = false) => {
if (inBody(element)) {
return element.dom.isContentEditable;
} else {
return closest$2(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
}
};
const getRaw$1 = element => element.dom.contentEditable;
const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
const internalSet = (dom, property, value) => {
if (!isString(value)) {
console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
throw new Error('CSS value must be a string: ' + value);
}
if (isSupported(dom)) {
dom.style.setProperty(property, value);
}
};
const internalRemove = (dom, property) => {
if (isSupported(dom)) {
dom.style.removeProperty(property);
}
};
const set$2 = (element, property, value) => {
const dom = element.dom;
internalSet(dom, property, value);
};
const setAll = (element, css) => {
const dom = element.dom;
each$d(css, (v, k) => {
internalSet(dom, k, v);
});
};
const get$7 = (element, property) => {
const dom = element.dom;
const styles = window.getComputedStyle(dom);
const r = styles.getPropertyValue(property);
return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
};
const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
const getRaw = (element, property) => {
const dom = element.dom;
const raw = getUnsafeProperty(dom, property);
return Optional.from(raw).filter(r => r.length > 0);
};
const getAllRaw = element => {
const css = {};
const dom = element.dom;
if (isSupported(dom)) {
for (let i = 0; i < dom.style.length; i++) {
const ruleName = dom.style.item(i);
css[ruleName] = dom.style[ruleName];
}
}
return css;
};
const remove$5 = (element, property) => {
const dom = element.dom;
internalRemove(dom, property);
if (is$2(getOpt(element, 'style').map(trim$4), '')) {
remove$9(element, 'style');
}
};
const reflow = e => e.dom.offsetWidth;
const before$3 = (marker, element) => {
const parent$1 = parent(marker);
parent$1.each(v => {
v.dom.insertBefore(element.dom, marker.dom);
});
};
const after$4 = (marker, element) => {
const sibling = nextSibling(marker);
sibling.fold(() => {
const parent$1 = parent(marker);
parent$1.each(v => {
append$1(v, element);
});
}, v => {
before$3(v, element);
});
};
const prepend = (parent, element) => {
const firstChild$1 = firstChild(parent);
firstChild$1.fold(() => {
append$1(parent, element);
}, v => {
parent.dom.insertBefore(element.dom, v.dom);
});
};
const append$1 = (parent, element) => {
parent.dom.appendChild(element.dom);
};
const wrap$2 = (element, wrapper) => {
before$3(element, wrapper);
append$1(wrapper, element);
};
const after$3 = (marker, elements) => {
each$e(elements, (x, i) => {
const e = i === 0 ? marker : elements[i - 1];
after$4(e, x);
});
};
const append = (parent, elements) => {
each$e(elements, x => {
append$1(parent, x);
});
};
const empty = element => {
element.dom.textContent = '';
each$e(children$1(element), rogue => {
remove$4(rogue);
});
};
const remove$4 = element => {
const dom = element.dom;
if (dom.parentNode !== null) {
dom.parentNode.removeChild(dom);
}
};
const unwrap = wrapper => {
const children = children$1(wrapper);
if (children.length > 0) {
after$3(wrapper, children);
}
remove$4(wrapper);
};
const fromHtml = (html, scope) => {
const doc = scope || document;
const div = doc.createElement('div');
div.innerHTML = html;
return children$1(SugarElement.fromDom(div));
};
const fromDom$1 = nodes => map$3(nodes, SugarElement.fromDom);
const get$6 = element => element.dom.innerHTML;
const set$1 = (element, content) => {
const owner = owner$1(element);
const docDom = owner.dom;
const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
const contentElements = fromHtml(content, docDom);
append(fragment, contentElements);
empty(element);
append$1(element, fragment);
};
const getOuter = element => {
const container = SugarElement.fromTag('div');
const clone = SugarElement.fromDom(element.dom.cloneNode(true));
append$1(container, clone);
return get$6(container);
};
const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
target,
x,
y,
stop,
prevent,
kill,
raw
});
const fromRawEvent = rawEvent => {
const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
const stop = () => rawEvent.stopPropagation();
const prevent = () => rawEvent.preventDefault();
const kill = compose(prevent, stop);
return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
};
const handle$1 = (filter, handler) => rawEvent => {
if (filter(rawEvent)) {
handler(fromRawEvent(rawEvent));
}
};
const binder = (element, event, filter, handler, useCapture) => {
const wrapped = handle$1(filter, handler);
element.dom.addEventListener(event, wrapped, useCapture);
return { unbind: curry(unbind, element, event, wrapped, useCapture) };
};
const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
const unbind = (element, event, handler, useCapture) => {
element.dom.removeEventListener(event, handler, useCapture);
};
const r = (left, top) => {
const translate = (x, y) => r(left + x, top + y);
return {
left,
top,
translate
};
};
const SugarPosition = r;
const boxPosition = dom => {
const box = dom.getBoundingClientRect();
return SugarPosition(box.left, box.top);
};
const firstDefinedOrZero = (a, b) => {
if (a !== undefined) {
return a;
} else {
return b !== undefined ? b : 0;
}
};
const absolute = element => {
const doc = element.dom.ownerDocument;
const body = doc.body;
const win = doc.defaultView;
const html = doc.documentElement;
if (body === element.dom) {
return SugarPosition(body.offsetLeft, body.offsetTop);
}
const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
};
const viewport = element => {
const dom = element.dom;
const doc = dom.ownerDocument;
const body = doc.body;
if (body === dom) {
return SugarPosition(body.offsetLeft, body.offsetTop);
}
if (!inBody(element)) {
return SugarPosition(0, 0);
}
return boxPosition(dom);
};
const get$5 = _DOC => {
const doc = _DOC !== undefined ? _DOC.dom : document;
const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
const y = doc.body.scrollTop || doc.documentElement.scrollTop;
return SugarPosition(x, y);
};
const to = (x, y, _DOC) => {
const doc = _DOC !== undefined ? _DOC.dom : document;
const win = doc.defaultView;
if (win) {
win.scrollTo(x, y);
}
};
const intoView = (element, alignToTop) => {
const isSafari = detect$1().browser.isSafari();
if (isSafari && isFunction(element.dom.scrollIntoViewIfNeeded)) {
element.dom.scrollIntoViewIfNeeded(false);
} else {
element.dom.scrollIntoView(alignToTop);
}
};
const get$4 = _win => {
const win = _win === undefined ? window : _win;
if (detect$1().browser.isFirefox()) {
return Optional.none();
} else {
return Optional.from(win.visualViewport);
}
};
const bounds = (x, y, width, height) => ({
x,
y,
width,
height,
right: x + width,
bottom: y + height
});
const getBounds = _win => {
const win = _win === undefined ? window : _win;
const doc = win.document;
const scroll = get$5(SugarElement.fromDom(doc));
return get$4(win).fold(() => {
const html = win.document.documentElement;
const width = html.clientWidth;
const height = html.clientHeight;
return bounds(scroll.left, scroll.top, width, height);
}, visualViewport => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
};
const children = (scope, predicate) => filter$5(children$1(scope), predicate);
const descendants$1 = (scope, predicate) => {
let result = [];
each$e(children$1(scope), x => {
if (predicate(x)) {
result = result.concat([x]);
}
result = result.concat(descendants$1(x, predicate));
});
return result;
};
const descendants = (scope, selector) => all(selector, scope);
const ancestor$2 = (scope, predicate, isRoot) => ancestor$4(scope, predicate, isRoot).isSome();
const sibling = (scope, predicate) => sibling$1(scope, predicate).isSome();
const descendant = (scope, predicate) => descendant$2(scope, predicate).isSome();
class DomTreeWalker {
constructor(startNode, rootNode) {
this.node = startNode;
this.rootNode = rootNode;
this.current = this.current.bind(this);
this.next = this.next.bind(this);
this.prev = this.prev.bind(this);
this.prev2 = this.prev2.bind(this);
}
current() {
return this.node;
}
next(shallow) {
this.node = this.findSibling(this.node, 'firstChild', 'nextSibling', shallow);
return this.node;
}
prev(shallow) {
this.node = this.findSibling(this.node, 'lastChild', 'previousSibling', shallow);
return this.node;
}
prev2(shallow) {
this.node = this.findPreviousNode(this.node, shallow);
return this.node;
}
findSibling(node, startName, siblingName, shallow) {
if (node) {
if (!shallow && node[startName]) {
return node[startName];
}
if (node !== this.rootNode) {
let sibling = node[siblingName];
if (sibling) {
return sibling;
}
for (let parent = node.parentNode; parent && parent !== this.rootNode; parent = parent.parentNode) {
sibling = parent[siblingName];
if (sibling) {
return sibling;
}
}
}
}
return undefined;
}
findPreviousNode(node, shallow) {
if (node) {
const sibling = node.previousSibling;
if (this.rootNode && sibling === this.rootNode) {
return;
}
if (sibling) {
if (!shallow) {
for (let child = sibling.lastChild; child; child = child.lastChild) {
if (!child.lastChild) {
return child;
}
}
}
return sibling;
}
const parent = node.parentNode;
if (parent && parent !== this.rootNode) {
return parent;
}
}
return undefined;
}
}
const zeroWidth = '\uFEFF';
const nbsp = '\xA0';
const isZwsp$2 = char => char === zeroWidth;
const removeZwsp = s => s.replace(/\uFEFF/g, '');
const whiteSpaceRegExp = /^[ \t\r\n]*$/;
const isWhitespaceText = text => whiteSpaceRegExp.test(text);
const isZwsp$1 = text => {
for (const c of text) {
if (!isZwsp$2(c)) {
return false;
}
}
return true;
};
const isCollapsibleWhitespace$1 = c => ' \f\t\x0B'.indexOf(c) !== -1;
const isNewLineChar = c => c === '\n' || c === '\r';
const isNewline = (text, idx) => idx < text.length && idx >= 0 ? isNewLineChar(text[idx]) : false;
const normalize$4 = (text, tabSpaces = 4, isStartOfContent = true, isEndOfContent = true) => {
const tabSpace = repeat(' ', tabSpaces);
const normalizedText = text.replace(/\t/g, tabSpace);
const result = foldl(normalizedText, (acc, c) => {
if (isCollapsibleWhitespace$1(c) || c === nbsp) {
if (acc.pcIsSpace || acc.str === '' && isStartOfContent || acc.str.length === normalizedText.length - 1 && isEndOfContent || isNewline(normalizedText, acc.str.length + 1)) {
return {
pcIsSpace: false,
str: acc.str + nbsp
};
} else {
return {
pcIsSpace: true,
str: acc.str + ' '
};
}
} else {
return {
pcIsSpace: isNewLineChar(c),
str: acc.str + c
};
}
}, {
pcIsSpace: false,
str: ''
});
return result.str;
};
const isNodeType = type => {
return node => {
return !!node && node.nodeType === type;
};
};
const isRestrictedNode = node => !!node && !Object.getPrototypeOf(node);
const isElement$6 = isNodeType(1);
const isHTMLElement = node => isElement$6(node) && isHTMLElement$1(SugarElement.fromDom(node));
const isSVGElement = node => isElement$6(node) && node.namespaceURI === 'http://www.w3.org/2000/svg';
const matchNodeName = name => {
const lowerCasedName = name.toLowerCase();
return node => isNonNullable(node) && node.nodeName.toLowerCase() === lowerCasedName;
};
const matchNodeNames = names => {
const lowerCasedNames = names.map(s => s.toLowerCase());
return node => {
if (node && node.nodeName) {
const nodeName = node.nodeName.toLowerCase();
return contains$2(lowerCasedNames, nodeName);
}
return false;
};
};
const matchStyleValues = (name, values) => {
const items = values.toLowerCase().split(' ');
return node => {
if (isElement$6(node)) {
const win = node.ownerDocument.defaultView;
if (win) {
for (let i = 0; i < items.length; i++) {
const computed = win.getComputedStyle(node, null);
const cssValue = computed ? computed.getPropertyValue(name) : null;
if (cssValue === items[i]) {
return true;
}
}
}
}
return false;
};
};
const hasAttribute = attrName => {
return node => {
return isElement$6(node) && node.hasAttribute(attrName);
};
};
const isBogus$1 = node => isElement$6(node) && node.hasAttribute('data-mce-bogus');
const isBogusAll = node => isElement$6(node) && node.getAttribute('data-mce-bogus') === 'all';
const isTable$2 = node => isElement$6(node) && node.tagName === 'TABLE';
const hasContentEditableState = value => {
return node => {
if (isHTMLElement(node)) {
if (node.contentEditable === value) {
return true;
}
if (node.getAttribute('data-mce-contenteditable') === value) {
return true;
}
}
return false;
};
};
const isTextareaOrInput = matchNodeNames([
'textarea',
'input'
]);
const isText$b = isNodeType(3);
const isCData = isNodeType(4);
const isPi = isNodeType(7);
const isComment = isNodeType(8);
const isDocument$1 = isNodeType(9);
const isDocumentFragment = isNodeType(11);
const isBr$6 = matchNodeName('br');
const isImg = matchNodeName('img');
const isContentEditableTrue$3 = hasContentEditableState('true');
const isContentEditableFalse$b = hasContentEditableState('false');
const isTableCell$3 = matchNodeNames([
'td',
'th'
]);
const isTableCellOrCaption = matchNodeNames([
'td',
'th',
'caption'
]);
const isMedia$2 = matchNodeNames([
'video',
'audio',
'object',
'embed'
]);
const isListItem$2 = matchNodeName('li');
const isDetails = matchNodeName('details');
const isSummary$1 = matchNodeName('summary');
const defaultOptionValues = {
skipBogus: true,
includeZwsp: false,
checkRootAsContent: false
};
const hasWhitespacePreserveParent = (node, rootNode, schema) => {
const rootElement = SugarElement.fromDom(rootNode);
const startNode = SugarElement.fromDom(node);
const whitespaceElements = schema.getWhitespaceElements();
const predicate = node => has$2(whitespaceElements, name(node));
return ancestor$2(startNode, predicate, curry(eq, rootElement));
};
const isNamedAnchor = node => {
return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id'));
};
const isNonEmptyElement$1 = (node, schema) => {
return isElement$6(node) && has$2(schema.getNonEmptyElements(), node.nodeName);
};
const isBookmark = hasAttribute('data-mce-bookmark');
const hasNonEditableParent = node => parentElement(SugarElement.fromDom(node)).exists(parent => !isEditable$2(parent));
const isWhitespace$1 = (node, rootNode, schema) => isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode, schema);
const isText$a = (node, rootNode, schema, options) => isText$b(node) && !isWhitespace$1(node, rootNode, schema) && (!options.includeZwsp || !isZwsp$1(node.data));
const isContentNode = (schema, node, rootNode, options) => {
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);
};
const isEmptyNode = (schema, targetNode, opts) => {
const options = {
...defaultOptionValues,
...opts
};
if (options.checkRootAsContent) {
if (isContentNode(schema, targetNode, targetNode, options)) {
return false;
}
}
let node = targetNode.firstChild;
let brCount = 0;
if (!node) {
return true;
}
const walker = new DomTreeWalker(node, targetNode);
do {
if (options.skipBogus && isElement$6(node)) {
const bogusValue = node.getAttribute('data-mce-bogus');
if (bogusValue) {
node = walker.next(bogusValue === 'all');
continue;
}
}
if (isComment(node)) {
node = walker.next(true);
continue;
}
if (isBr$6(node)) {
brCount++;
node = walker.next();
continue;
}
if (isContentNode(schema, node, targetNode, options)) {
return false;
}
node = walker.next();
} while (node);
return brCount <= 1;
};
const isEmpty$2 = (schema, elm, options) => {
return isEmptyNode(schema, elm.dom, {
checkRootAsContent: true,
...options
});
};
const isContent$1 = (schema, node, options) => {
return isContentNode(schema, node, node, {
includeZwsp: defaultOptionValues.includeZwsp,
...options
});
};
const Cell = initial => {
let value = initial;
const get = () => {
return value;
};
const set = v => {
value = v;
};
return {
get,
set
};
};
const singleton = doRevoke => {
const subject = Cell(Optional.none());
const revoke = () => subject.get().each(doRevoke);
const clear = () => {
revoke();
subject.set(Optional.none());
};
const isSet = () => subject.get().isSome();
const get = () => subject.get();
const set = s => {
revoke();
subject.set(Optional.some(s));
};
return {
clear,
isSet,
get,
set
};
};
const repeatable = delay => {
const intervalId = Cell(Optional.none());
const revoke = () => intervalId.get().each(id => clearInterval(id));
const clear = () => {
revoke();
intervalId.set(Optional.none());
};
const isSet = () => intervalId.get().isSome();
const get = () => intervalId.get();
const set = functionToRepeat => {
revoke();
intervalId.set(Optional.some(setInterval(functionToRepeat, delay)));
};
return {
clear,
isSet,
get,
set
};
};
const value$2 = () => {
const subject = singleton(noop);
const on = f => subject.get().each(f);
return {
...subject,
on
};
};
const nodeNameToNamespaceType = name => {
const lowerCaseName = name.toLowerCase();
if (lowerCaseName === 'svg') {
return 'svg';
} else if (lowerCaseName === 'math') {
return 'math';
} else {
return 'html';
}
};
const isNonHtmlElementRootName = name => nodeNameToNamespaceType(name) !== 'html';
const isNonHtmlElementRoot = node => isNonHtmlElementRootName(node.nodeName);
const toScopeType = node => nodeNameToNamespaceType(node.nodeName);
const namespaceElements = [
'svg',
'math'
];
const createNamespaceTracker = () => {
const currentScope = value$2();
const current = () => currentScope.get().map(toScopeType).getOr('html');
const track = node => {
if (isNonHtmlElementRoot(node)) {
currentScope.set(node);
} else if (currentScope.get().exists(scopeNode => !scopeNode.contains(node))) {
currentScope.clear();
}
return current();
};
const reset = () => {
currentScope.clear();
};
return {
track,
current,
reset
};
};
const transparentBlockAttr = 'data-mce-block';
const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key));
const makeSelectorFromSchemaMap = map => map$3(elementNames(map), name => {
const escapedName = CSS.escape(name);
return `${ escapedName }:` + map$3(namespaceElements, ns => `not(${ ns } ${ escapedName })`).join(':');
}).join(',');
const updateTransparent = (blocksSelector, transparent) => {
if (isNonNullable(transparent.querySelector(blocksSelector))) {
transparent.setAttribute(transparentBlockAttr, 'true');
if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') {
transparent.removeAttribute('data-mce-selected');
}
return true;
} else {
transparent.removeAttribute(transparentBlockAttr);
return false;
}
};
const updateBlockStateOnChildren = (schema, scope) => {
const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements());
const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent));
};
const trimEdge = (schema, el, leftSide) => {
var _a;
const childPropertyName = leftSide ? 'lastChild' : 'firstChild';
for (let child = el[childPropertyName]; child; child = child[childPropertyName]) {
if (isEmptyNode(schema, child, { checkRootAsContent: true })) {
(_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
return;
}
}
};
const split$2 = (schema, parentElm, splitElm) => {
const range = document.createRange();
const parentNode = parentElm.parentNode;
if (parentNode) {
range.setStartBefore(parentElm);
range.setEndBefore(splitElm);
const beforeFragment = range.extractContents();
trimEdge(schema, beforeFragment, true);
range.setStartAfter(splitElm);
range.setEndAfter(parentElm);
const afterFragment = range.extractContents();
trimEdge(schema, afterFragment, false);
if (!isEmptyNode(schema, beforeFragment, { checkRootAsContent: true })) {
parentNode.insertBefore(beforeFragment, parentElm);
}
if (!isEmptyNode(schema, splitElm, { checkRootAsContent: true })) {
parentNode.insertBefore(splitElm, parentElm);
}
if (!isEmptyNode(schema, afterFragment, { checkRootAsContent: true })) {
parentNode.insertBefore(afterFragment, parentElm);
}
parentNode.removeChild(parentElm);
}
};
const splitInvalidChildren = (schema, scope, transparentBlocks) => {
const blocksElements = schema.getBlockElements();
const rootNode = SugarElement.fromDom(scope);
const isBlock = el => name(el) in blocksElements;
const isRoot = el => eq(el, rootNode);
each$e(fromDom$1(transparentBlocks), transparentBlock => {
ancestor$4(transparentBlock, isBlock, isRoot).each(parentBlock => {
const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
if (invalidChildren.length > 0) {
const stateScope = parentElement(parentBlock);
each$e(invalidChildren, child => {
ancestor$4(child, isBlock, isRoot).each(parentBlock => {
split$2(schema, parentBlock.dom, child.dom);
});
});
stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom));
}
});
});
};
const unwrapInvalidChildren = (schema, scope, transparentBlocks) => {
each$e([
...transparentBlocks,
...isTransparentBlock(schema, scope) ? [scope] : []
], block => each$e(descendants(SugarElement.fromDom(block), block.nodeName.toLowerCase()), elm => {
if (isTransparentInline(schema, elm.dom)) {
unwrap(elm);
}
}));
};
const updateChildren = (schema, scope) => {
const transparentBlocks = updateBlockStateOnChildren(schema, scope);
splitInvalidChildren(schema, scope, transparentBlocks);
unwrapInvalidChildren(schema, scope, transparentBlocks);
};
const updateElement = (schema, target) => {
if (isTransparentElement(schema, target)) {
const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
updateTransparent(blocksSelector, target);
}
};
const updateCaret = (schema, root, caretParent) => {
const isRoot = el => eq(el, SugarElement.fromDom(root));
const parents = parents$1(SugarElement.fromDom(caretParent), isRoot);
get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom));
};
const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr);
const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name);
const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName);
const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node);
const isTransparentInline = (schema, node) => isTransparentElement(schema, node) && !hasBlockAttr(node);
const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr));
const browser$2 = detect$1().browser;
const firstElement = nodes => find$2(nodes, isElement$7);
const getTableCaptionDeltaY = elm => {
if (browser$2.isFirefox() && name(elm) === 'table') {
return firstElement(children$1(elm)).filter(elm => {
return name(elm) === 'caption';
}).bind(caption => {
return firstElement(nextSiblings(caption)).map(body => {
const bodyTop = body.dom.offsetTop;
const captionTop = caption.dom.offsetTop;
const captionHeight = caption.dom.offsetHeight;
return bodyTop <= captionTop ? -captionHeight : 0;
});
}).getOr(0);
} else {
return 0;
}
};
const hasChild = (elm, child) => elm.children && contains$2(elm.children, child);
const getPos = (body, elm, rootElm) => {
let x = 0, y = 0;
const doc = body.ownerDocument;
rootElm = rootElm ? rootElm : body;
if (elm) {
if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') {
const pos = elm.getBoundingClientRect();
x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
return {
x,
y
};
}
let offsetParent = elm;
while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
const castOffsetParent = offsetParent;
x += castOffsetParent.offsetLeft || 0;
y += castOffsetParent.offsetTop || 0;
offsetParent = castOffsetParent.offsetParent;
}
offsetParent = elm.parentNode;
while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
x -= offsetParent.scrollLeft || 0;
y -= offsetParent.scrollTop || 0;
offsetParent = offsetParent.parentNode;
}
y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
}
return {
x,
y
};
};
const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
let idCount = 0;
const loadedStates = {};
const edos = SugarElement.fromDom(documentOrShadowRoot);
const doc = documentOrOwner(edos);
const _setReferrerPolicy = referrerPolicy => {
settings.referrerPolicy = referrerPolicy;
};
const _setContentCssCors = contentCssCors => {
settings.contentCssCors = contentCssCors;
};
const addStyle = element => {
append$1(getStyleContainer(edos), element);
};
const removeStyle = id => {
const styleContainer = getStyleContainer(edos);
descendant$1(styleContainer, '#' + id).each(remove$4);
};
const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({
id: 'mce-u' + idCount++,
passed: [],
failed: [],
count: 0
}));
const load = url => new Promise((success, failure) => {
let link;
const urlWithSuffix = Tools._addCacheSuffix(url);
const state = getOrCreateState(urlWithSuffix);
loadedStates[urlWithSuffix] = state;
state.count++;
const resolve = (callbacks, status) => {
each$e(callbacks, call);
state.status = status;
state.passed = [];
state.failed = [];
if (link) {
link.onload = null;
link.onerror = null;
link = null;
}
};
const passed = () => resolve(state.passed, 2);
const failed = () => resolve(state.failed, 3);
if (success) {
state.passed.push(success);
}
if (failure) {
state.failed.push(failure);
}
if (state.status === 1) {
return;
}
if (state.status === 2) {
passed();
return;
}
if (state.status === 3) {
failed();
return;
}
state.status = 1;
const linkElem = SugarElement.fromTag('link', doc.dom);
setAll$1(linkElem, {
rel: 'stylesheet',
type: 'text/css',
id: state.id
});
if (settings.contentCssCors) {
set$3(linkElem, 'crossOrigin', 'anonymous');
}
if (settings.referrerPolicy) {
set$3(linkElem, 'referrerpolicy', settings.referrerPolicy);
}
link = linkElem.dom;
link.onload = passed;
link.onerror = failed;
addStyle(linkElem);
set$3(linkElem, 'href', urlWithSuffix);
});
const loadRawCss = (key, css) => {
const state = getOrCreateState(key);
loadedStates[key] = state;
state.count++;
const styleElem = SugarElement.fromTag('style', doc.dom);
setAll$1(styleElem, {
rel: 'stylesheet',
type: 'text/css',
id: state.id
});
styleElem.dom.innerHTML = css;
addStyle(styleElem);
};
const loadAll = urls => {
const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url))));
return loadedUrls.then(results => {
const parts = partition$2(results, r => r.status === 'fulfilled');
if (parts.fail.length > 0) {
return Promise.reject(map$3(parts.fail, result => result.reason));
} else {
return map$3(parts.pass, result => result.value);
}
});
};
const unload = url => {
const urlWithSuffix = Tools._addCacheSuffix(url);
get$a(loadedStates, urlWithSuffix).each(state => {
const count = --state.count;
if (count === 0) {
delete loadedStates[urlWithSuffix];
removeStyle(state.id);
}
});
};
const unloadRawCss = key => {
get$a(loadedStates, key).each(state => {
const count = --state.count;
if (count === 0) {
delete loadedStates[key];
removeStyle(state.id);
}
});
};
const unloadAll = urls => {
each$e(urls, url => {
unload(url);
});
};
return {
load,
loadRawCss,
loadAll,
unload,
unloadRawCss,
unloadAll,
_setReferrerPolicy,
_setContentCssCors
};
};
const create$c = () => {
const map = new WeakMap();
const forElement = (referenceElement, settings) => {
const root = getRootNode(referenceElement);
const rootDom = root.dom;
return Optional.from(map.get(rootDom)).getOrThunk(() => {
const sl = StyleSheetLoader(rootDom, settings);
map.set(rootDom, sl);
return sl;
});
};
return { forElement };
};
const instance = create$c();
const isSpan = node => node.nodeName.toLowerCase() === 'span';
const isInlineContent = (node, schema) => isNonNullable(node) && (isContent$1(schema, node) || schema.isInline(node.nodeName.toLowerCase()));
const surroundedByInlineContent = (node, root, schema) => {
const prev = new DomTreeWalker(node, root).prev(false);
const next = new DomTreeWalker(node, root).next(false);
const prevIsInline = isUndefined(prev) || isInlineContent(prev, schema);
const nextIsInline = isUndefined(next) || isInlineContent(next, schema);
return prevIsInline && nextIsInline;
};
const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark';
const isKeepTextNode = (node, root, schema) => isText$b(node) && node.data.length > 0 && surroundedByInlineContent(node, root, schema);
const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false;
const isDocument = node => isDocumentFragment(node) || isDocument$1(node);
const trimNode = (dom, node, schema, root) => {
var _a;
const rootNode = root || node;
if (isElement$6(node) && isBookmarkNode$2(node)) {
return node;
}
const children = node.childNodes;
for (let i = children.length - 1; i >= 0; i--) {
trimNode(dom, children[i], schema, rootNode);
}
if (isElement$6(node)) {
const currentChildren = node.childNodes;
if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node);
}
}
if (!isDocument(node) && !isContent$1(schema, node) && !isKeepElement(node) && !isKeepTextNode(node, rootNode, schema)) {
dom.remove(node);
}
return node;
};
const makeMap$3 = Tools.makeMap;
const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
const rawCharsRegExp = /[<>&\"\']/g;
const entityRegExp = /([a-z0-9]+);?|&([a-z0-9]+);/gi;
const asciiMap = {
128: '\u20AC',
130: '\u201A',
131: '\u0192',
132: '\u201E',
133: '\u2026',
134: '\u2020',
135: '\u2021',
136: '\u02c6',
137: '\u2030',
138: '\u0160',
139: '\u2039',
140: '\u0152',
142: '\u017d',
145: '\u2018',
146: '\u2019',
147: '\u201C',
148: '\u201D',
149: '\u2022',
150: '\u2013',
151: '\u2014',
152: '\u02DC',
153: '\u2122',
154: '\u0161',
155: '\u203A',
156: '\u0153',
158: '\u017e',
159: '\u0178'
};
const baseEntities = {
'"': '"',
'\'': ''',
'<': '<',
'>': '>',
'&': '&',
'`': '`'
};
const reverseEntities = {
'<': '<',
'>': '>',
'&': '&',
'"': '"',
''': `'`
};
const nativeDecode = text => {
const elm = SugarElement.fromTag('div').dom;
elm.innerHTML = text;
return elm.textContent || elm.innerText || text;
};
const buildEntitiesLookup = (items, radix) => {
const lookup = {};
if (items) {
const itemList = items.split(',');
radix = radix || 10;
for (let i = 0; i < itemList.length; i += 2) {
const chr = String.fromCharCode(parseInt(itemList[i], radix));
if (!baseEntities[chr]) {
const entity = '&' + itemList[i + 1] + ';';
lookup[chr] = entity;
lookup[entity] = chr;
}
}
return lookup;
} else {
return undefined;
}
};
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);
const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
return baseEntities[chr] || chr;
});
const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => {
return baseEntities[chr] || chr;
});
const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
if (chr.length > 1) {
return '' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
}
return baseEntities[chr] || '' + chr.charCodeAt(0) + ';';
});
const encodeNamed = (text, attr, entities) => {
const resolveEntities = entities || namedEntities;
return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
return baseEntities[chr] || resolveEntities[chr] || chr;
});
};
const getEncodeFunc = (name, entities) => {
const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
if (baseEntities[chr] !== undefined) {
return baseEntities[chr];
}
if (entitiesMap[chr] !== undefined) {
return entitiesMap[chr];
}
if (chr.length > 1) {
return '' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
}
return '' + chr.charCodeAt(0) + ';';
});
const encodeCustomNamed = (text, attr) => {
return encodeNamed(text, attr, entitiesMap);
};
const nameMap = makeMap$3(name.replace(/\+/g, ','));
if (nameMap.named && nameMap.numeric) {
return encodeNamedAndNumeric;
}
if (nameMap.named) {
if (entities) {
return encodeCustomNamed;
}
return encodeNamed;
}
if (nameMap.numeric) {
return encodeNumeric;
}
return encodeRaw;
};
const decode = text => text.replace(entityRegExp, (all, numeric) => {
if (numeric) {
if (numeric.charAt(0).toLowerCase() === 'x') {
numeric = parseInt(numeric.substr(1), 16);
} else {
numeric = parseInt(numeric, 10);
}
if (numeric > 65535) {
numeric -= 65536;
return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
}
return asciiMap[numeric] || String.fromCharCode(numeric);
}
return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
});
const Entities = {
encodeRaw,
encodeAllRaw,
encodeNumeric,
encodeNamed,
getEncodeFunc,
decode
};
const split$1 = (items, delim) => {
items = Tools.trim(items);
return items ? items.split(delim || ' ') : [];
};
const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
const isRegExp$1 = obj => isObject(obj) && obj.source && Object.prototype.toString.call(obj) === '[object RegExp]';
const deepCloneElementRule = obj => {
const helper = value => {
if (isArray$1(value)) {
return map$3(value, helper);
} else if (isRegExp$1(value)) {
return new RegExp(value.source, value.flags);
} else if (isObject(value)) {
return map$2(value, helper);
} else {
return value;
}
};
return helper(obj);
};
const parseCustomElementsRules = value => {
const customElementRegExp = /^(~)?(.+)$/;
return bind$3(split$1(value, ','), rule => {
const matches = customElementRegExp.exec(rule);
if (matches) {
const inline = matches[1] === '~';
const cloneName = inline ? 'span' : 'div';
const name = matches[2];
return [{
cloneName,
name
}];
} else {
return [];
}
});
};
const getGlobalAttributeSet = type => {
return Object.freeze([
'id',
'accesskey',
'class',
'dir',
'lang',
'style',
'tabindex',
'title',
'role',
...type !== 'html4' ? [
'contenteditable',
'contextmenu',
'draggable',
'dropzone',
'hidden',
'spellcheck',
'translate',
'itemprop',
'itemscope',
'itemtype'
] : [],
...type !== 'html5-strict' ? ['xml:lang'] : []
]);
};
const getElementSetsAsStrings = type => {
let blockContent;
let phrasingContent;
blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
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';
if (type !== 'html4') {
const transparentContent = 'a ins del canvas map';
blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent;
phrasingContent += ' audio canvas command data datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen svg';
}
if (type !== 'html5-strict') {
const html4PhrasingContent = 'acronym applet basefont big font strike tt';
phrasingContent = [
phrasingContent,
html4PhrasingContent
].join(' ');
const html4BlockContent = 'center dir isindex noframes';
blockContent = [
blockContent,
html4BlockContent
].join(' ');
}
const flowContent = [
blockContent,
phrasingContent
].join(' ');
return {
blockContent,
phrasingContent,
flowContent
};
};
const getElementSets = type => {
const {blockContent, phrasingContent, flowContent} = getElementSetsAsStrings(type);
const toArr = value => {
return Object.freeze(value.split(' '));
};
return Object.freeze({
blockContent: toArr(blockContent),
phrasingContent: toArr(phrasingContent),
flowContent: toArr(flowContent)
});
};
const cachedSets = {
'html4': cached(() => getElementSets('html4')),
'html5': cached(() => getElementSets('html5')),
'html5-strict': cached(() => getElementSets('html5-strict'))
};
const getElementsPreset = (type, name) => {
const {blockContent, phrasingContent, flowContent} = cachedSets[type]();
if (name === 'blocks') {
return Optional.some(blockContent);
} else if (name === 'phrasing') {
return Optional.some(phrasingContent);
} else if (name === 'flow') {
return Optional.some(flowContent);
} else {
return Optional.none();
}
};
const makeSchema = type => {
const globalAttributes = getGlobalAttributeSet(type);
const {phrasingContent, flowContent} = getElementSetsAsStrings(type);
const schema = {};
const addElement = (name, attributes, children) => {
schema[name] = {
attributes: mapToObject(attributes, constant({})),
attributesOrder: attributes,
children: mapToObject(children, constant({}))
};
};
const add = (name, attributes = '', children = '') => {
const childNames = split$1(children);
const names = split$1(name);
let ni = names.length;
const allAttributes = [
...globalAttributes,
...split$1(attributes)
];
while (ni--) {
addElement(names[ni], allAttributes.slice(), childNames);
}
};
const addAttrs = (name, attributes) => {
const names = split$1(name);
const attrs = split$1(attributes);
let ni = names.length;
while (ni--) {
const schemaItem = schema[names[ni]];
for (let i = 0, l = attrs.length; i < l; i++) {
schemaItem.attributes[attrs[i]] = {};
schemaItem.attributesOrder.push(attrs[i]);
}
}
};
if (type !== 'html5-strict') {
const html4PhrasingContent = 'acronym applet basefont big font strike tt';
each$e(split$1(html4PhrasingContent), name => {
add(name, '', phrasingContent);
});
const html4BlockContent = 'center dir isindex noframes';
each$e(split$1(html4BlockContent), name => {
add(name, '', flowContent);
});
}
add('html', 'manifest', 'head body');
add('head', '', 'base command link meta noscript script style title');
add('title hr noscript br');
add('base', 'href target');
add('link', 'href rel media hreflang type sizes hreflang');
add('meta', 'name http-equiv content charset');
add('style', 'media type scoped');
add('script', 'src async defer type charset');
add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
add('dd div', '', flowContent);
add('address dt caption', '', type === 'html4' ? phrasingContent : flowContent);
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);
add('blockquote', 'cite', flowContent);
add('ol', 'reversed start type', 'li');
add('ul', '', 'li');
add('li', 'value', flowContent);
add('dl', '', 'dt dd');
add('a', 'href target rel media hreflang type', type === 'html4' ? phrasingContent : flowContent);
add('q', 'cite', phrasingContent);
add('ins del', 'cite datetime', flowContent);
add('img', 'src sizes srcset alt usemap ismap width height');
add('iframe', 'src name width height', flowContent);
add('embed', 'src type width height');
add('object', 'data type typemustmatch name usemap form width height', [
flowContent,
'param'
].join(' '));
add('param', 'name value');
add('map', 'name', [
flowContent,
'area'
].join(' '));
add('area', 'alt coords shape href target rel media hreflang type');
add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
add('colgroup', 'span', 'col');
add('col', 'span');
add('tbody thead tfoot', '', 'tr');
add('tr', '', 'td th');
add('td', 'colspan rowspan headers', flowContent);
add('th', 'colspan rowspan headers scope abbr', flowContent);
add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
add('fieldset', 'disabled form name', [
flowContent,
'legend'
].join(' '));
add('label', 'form for', phrasingContent);
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');
add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
add('select', 'disabled form multiple name required size', 'option optgroup');
add('optgroup', 'disabled label', 'option');
add('option', 'disabled label selected value');
add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
add('menu', 'type label', [
flowContent,
'li'
].join(' '));
add('noscript', '', flowContent);
if (type !== 'html4') {
add('wbr');
add('ruby', '', [
phrasingContent,
'rt rp'
].join(' '));
add('figcaption', '', flowContent);
add('mark rt rp bdi', '', phrasingContent);
add('summary', '', [
phrasingContent,
'h1 h2 h3 h4 h5 h6'
].join(' '));
add('canvas', 'width height', flowContent);
add('data', 'value', phrasingContent);
add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
flowContent,
'track source'
].join(' '));
add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
flowContent,
'track source'
].join(' '));
add('picture', '', 'img source');
add('source', 'src srcset type media sizes');
add('track', 'kind src srclang label default');
add('datalist', '', [
phrasingContent,
'option'
].join(' '));
add('article section nav aside main header footer', '', flowContent);
add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
add('figure', '', [
flowContent,
'figcaption'
].join(' '));
add('time', 'datetime', phrasingContent);
add('dialog', 'open', flowContent);
add('command', 'type label icon disabled checked radiogroup command');
add('output', 'for form name', phrasingContent);
add('progress', 'value max', phrasingContent);
add('meter', 'value min max low high optimum', phrasingContent);
add('details', 'open', [
flowContent,
'summary'
].join(' '));
add('keygen', 'autofocus challenge disabled form keytype name');
addElement('svg', 'id tabindex lang xml:space class style x y width height viewBox preserveAspectRatio zoomAndPan transform'.split(' '), []);
}
if (type !== 'html5-strict') {
addAttrs('script', 'language xml:space');
addAttrs('style', 'xml:space');
addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
addAttrs('embed', 'align name hspace vspace');
addAttrs('param', 'valuetype type');
addAttrs('a', 'charset name rev shape coords');
addAttrs('br', 'clear');
addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
addAttrs('img', 'name longdesc align border hspace vspace');
addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
addAttrs('font basefont', 'size color face');
addAttrs('input', 'usemap align');
addAttrs('select');
addAttrs('textarea');
addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
addAttrs('ul', 'type compact');
addAttrs('li', 'type');
addAttrs('ol dl menu dir', 'compact');
addAttrs('pre', 'width xml:space');
addAttrs('hr', 'align noshade size width');
addAttrs('isindex', 'prompt');
addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
addAttrs('col', 'width align char charoff valign');
addAttrs('colgroup', 'width align char charoff valign');
addAttrs('thead', 'align char charoff valign');
addAttrs('tr', 'align char charoff valign bgcolor');
addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
addAttrs('form', 'accept');
addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
addAttrs('tfoot', 'align char charoff valign');
addAttrs('tbody', 'align char charoff valign');
addAttrs('area', 'nohref');
addAttrs('body', 'background bgcolor text link vlink alink');
}
if (type !== 'html4') {
addAttrs('input button select textarea', 'autofocus');
addAttrs('input textarea', 'placeholder');
addAttrs('a', 'download');
addAttrs('link script img', 'crossorigin');
addAttrs('img', 'loading');
addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading referrerpolicy');
}
if (type !== 'html4') {
each$e([
schema.video,
schema.audio
], item => {
delete item.children.audio;
delete item.children.video;
});
}
each$e(split$1('a form meter progress dfn'), name => {
if (schema[name]) {
delete schema[name].children[name];
}
});
delete schema.caption.children.table;
delete schema.script;
return schema;
};
const prefixToOperation = prefix => prefix === '-' ? 'remove' : 'add';
const parseValidChild = name => {
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]+)$/;
return Optional.from(validChildRegExp.exec(name)).map(matches => ({
preset: matches[1] === '@',
name: matches[2]
}));
};
const parseValidChildrenRules = value => {
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]+)\[([^\]]+)]$/;
return bind$3(split$1(value, ','), rule => {
const matches = childRuleRegExp.exec(rule);
if (matches) {
const prefix = matches[1];
const operation = prefix ? prefixToOperation(prefix) : 'replace';
const name = matches[2];
const validChildren = bind$3(split$1(matches[3], '|'), validChild => parseValidChild(validChild).toArray());
return [{
operation,
name,
validChildren
}];
} else {
return [];
}
});
};
const parseValidElementsAttrDataIntoElement = (attrData, targetElement) => {
const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/;
const hasPatternsRegExp = /[*?+]/;
const {attributes, attributesOrder} = targetElement;
return each$e(split$1(attrData, '|'), rule => {
const matches = attrRuleRegExp.exec(rule);
if (matches) {
const attr = {};
const attrType = matches[1];
const attrName = matches[2].replace(/[\\:]:/g, ':');
const attrPrefix = matches[3];
const value = matches[4];
if (attrType === '!') {
targetElement.attributesRequired = targetElement.attributesRequired || [];
targetElement.attributesRequired.push(attrName);
attr.required = true;
}
if (attrType === '-') {
delete attributes[attrName];
attributesOrder.splice(Tools.inArray(attributesOrder, attrName), 1);
return;
}
if (attrPrefix) {
if (attrPrefix === '=') {
targetElement.attributesDefault = targetElement.attributesDefault || [];
targetElement.attributesDefault.push({
name: attrName,
value
});
attr.defaultValue = value;
} else if (attrPrefix === '~') {
targetElement.attributesForced = targetElement.attributesForced || [];
targetElement.attributesForced.push({
name: attrName,
value
});
attr.forcedValue = value;
} else if (attrPrefix === '<') {
attr.validValues = Tools.makeMap(value, '?');
}
}
if (hasPatternsRegExp.test(attrName)) {
const attrPattern = attr;
targetElement.attributePatterns = targetElement.attributePatterns || [];
attrPattern.pattern = patternToRegExp(attrName);
targetElement.attributePatterns.push(attrPattern);
} else {
if (!attributes[attrName]) {
attributesOrder.push(attrName);
}
attributes[attrName] = attr;
}
}
});
};
const cloneAttributesInto = (from, to) => {
each$d(from.attributes, (value, key) => {
to.attributes[key] = value;
});
to.attributesOrder.push(...from.attributesOrder);
};
const parseValidElementsRules = (globalElement, validElements) => {
const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;
return bind$3(split$1(validElements, ','), rule => {
const matches = elementRuleRegExp.exec(rule);
if (matches) {
const prefix = matches[1];
const elementName = matches[2];
const outputName = matches[3];
const attrsPrefix = matches[4];
const attrData = matches[5];
const element = {
attributes: {},
attributesOrder: []
};
globalElement.each(el => cloneAttributesInto(el, element));
if (prefix === '#') {
element.paddEmpty = true;
} else if (prefix === '-') {
element.removeEmpty = true;
}
if (attrsPrefix === '!') {
element.removeEmptyAttrs = true;
}
if (attrData) {
parseValidElementsAttrDataIntoElement(attrData, element);
}
if (outputName) {
element.outputName = elementName;
}
if (elementName === '@') {
if (globalElement.isNone()) {
globalElement = Optional.some(element);
} else {
return [];
}
}
return [outputName ? {
name: elementName,
element,
aliasName: outputName
} : {
name: elementName,
element
}];
} else {
return [];
}
});
};
const mapCache = {};
const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode;
const createMap = (defaultValue, extendWith = {}) => {
const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
return extend$2(value, extendWith);
};
const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements());
const compileElementMap = (value, mode) => {
if (value) {
const styles = {};
if (isString(value)) {
value = { '*': value };
}
each$b(value, (value, key) => {
styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/);
});
return styles;
} else {
return undefined;
}
};
const Schema = (settings = {}) => {
var _a;
const elements = {};
const children = {};
let patternElements = [];
const customElementsMap = {};
const specialElements = {};
const createLookupTable = (option, defaultValue, extendWith) => {
const value = settings[option];
if (!value) {
let newValue = mapCache[option];
if (!newValue) {
newValue = createMap(defaultValue, extendWith);
mapCache[option] = newValue;
}
return newValue;
} else {
return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
}
};
const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5';
const schemaItems = makeSchema(schemaType);
if (settings.verify_html === false) {
settings.valid_elements = '*[*]';
}
const validStyles = compileElementMap(settings.valid_styles);
const invalidStyles = compileElementMap(settings.invalid_styles, 'map');
const validClasses = compileElementMap(settings.valid_classes, 'map');
const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen');
const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code';
const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre svg textarea summary', voidElementsMap);
const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap);
const headings = 'h1 h2 h3 h4 h5 h6';
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');
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);
const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp');
const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map');
const wrapBlockElementsMap = createLookupTable('wrap_block_elements', 'pre ' + headings);
each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => {
specialElements[name] = new RegExp('' + name + '[^>]*>', 'gi');
});
const addValidElements = validElements => {
const globalElement = Optional.from(elements['@']);
const hasPatternsRegExp = /[*?+]/;
each$e(parseValidElementsRules(globalElement, validElements !== null && validElements !== void 0 ? validElements : ''), ({name, element, aliasName}) => {
if (aliasName) {
elements[aliasName] = element;
}
if (hasPatternsRegExp.test(name)) {
const patternElement = element;
patternElement.pattern = patternToRegExp(name);
patternElements.push(patternElement);
} else {
elements[name] = element;
}
});
};
const setValidElements = validElements => {
patternElements = [];
each$e(keys(elements), name => {
delete elements[name];
});
addValidElements(validElements);
};
const addCustomElement = (name, spec) => {
var _a, _b;
delete mapCache.text_block_elements;
delete mapCache.block_elements;
const inline = spec.extends ? !isBlock(spec.extends) : false;
const cloneName = spec.extends;
children[name] = cloneName ? children[cloneName] : {};
customElementsMap[name] = cloneName !== null && cloneName !== void 0 ? cloneName : name;
nonEmptyElementsMap[name.toUpperCase()] = {};
nonEmptyElementsMap[name] = {};
if (!inline) {
blockElementsMap[name.toUpperCase()] = {};
blockElementsMap[name] = {};
}
if (cloneName && !elements[name] && elements[cloneName]) {
const customRule = deepCloneElementRule(elements[cloneName]);
delete customRule.removeEmptyAttrs;
delete customRule.removeEmpty;
elements[name] = customRule;
} else {
elements[name] = {
attributesOrder: [],
attributes: {}
};
}
if (isArray$1(spec.attributes)) {
const processAttrName = name => {
customRule.attributesOrder.push(name);
customRule.attributes[name] = {};
};
const customRule = (_a = elements[name]) !== null && _a !== void 0 ? _a : {};
delete customRule.attributesDefault;
delete customRule.attributesForced;
delete customRule.attributePatterns;
delete customRule.attributesRequired;
customRule.attributesOrder = [];
customRule.attributes = {};
each$e(spec.attributes, attrName => {
const globalAttrs = getGlobalAttributeSet(schemaType);
parseValidChild(attrName).each(({preset, name}) => {
if (preset) {
if (name === 'global') {
each$e(globalAttrs, processAttrName);
}
} else {
processAttrName(name);
}
});
});
elements[name] = customRule;
}
if (isBoolean(spec.padEmpty)) {
const customRule = (_b = elements[name]) !== null && _b !== void 0 ? _b : {};
customRule.paddEmpty = spec.padEmpty;
elements[name] = customRule;
}
if (isArray$1(spec.children)) {
const customElementChildren = {};
const processNodeName = name => {
customElementChildren[name] = {};
};
const processPreset = name => {
getElementsPreset(schemaType, name).each(names => {
each$e(names, processNodeName);
});
};
each$e(spec.children, child => {
parseValidChild(child).each(({preset, name}) => {
if (preset) {
processPreset(name);
} else {
processNodeName(name);
}
});
});
children[name] = customElementChildren;
}
if (cloneName) {
each$d(children, (element, elmName) => {
if (element[cloneName]) {
children[elmName] = element = extend$2({}, children[elmName]);
element[name] = element[cloneName];
}
});
}
};
const addCustomElementsFromString = customElements => {
each$e(parseCustomElementsRules(customElements !== null && customElements !== void 0 ? customElements : ''), ({name, cloneName}) => {
addCustomElement(name, { extends: cloneName });
});
};
const addCustomElements = customElements => {
if (isObject(customElements)) {
each$d(customElements, (spec, name) => addCustomElement(name, spec));
} else if (isString(customElements)) {
addCustomElementsFromString(customElements);
}
};
const addValidChildren = validChildren => {
each$e(parseValidChildrenRules(validChildren !== null && validChildren !== void 0 ? validChildren : ''), ({operation, name, validChildren}) => {
const parent = operation === 'replace' ? { '#comment': {} } : children[name];
const processNodeName = name => {
if (operation === 'remove') {
delete parent[name];
} else {
parent[name] = {};
}
};
const processPreset = name => {
getElementsPreset(schemaType, name).each(names => {
each$e(names, processNodeName);
});
};
each$e(validChildren, ({preset, name}) => {
if (preset) {
processPreset(name);
} else {
processNodeName(name);
}
});
children[name] = parent;
});
};
const getElementRule = name => {
const element = elements[name];
if (element) {
return element;
}
let i = patternElements.length;
while (i--) {
const patternElement = patternElements[i];
if (patternElement.pattern.test(name)) {
return patternElement;
}
}
return undefined;
};
const setup = () => {
if (!settings.valid_elements) {
each$b(schemaItems, (element, name) => {
elements[name] = {
attributes: element.attributes,
attributesOrder: element.attributesOrder
};
children[name] = element.children;
});
each$b(split$1('strong/b em/i'), item => {
const items = split$1(item, '/');
elements[items[1]].outputName = items[0];
});
each$b(textInlineElementsMap, (_val, name) => {
if (elements[name]) {
if (settings.padd_empty_block_inline_children) {
elements[name].paddInEmptyBlock = true;
}
elements[name].removeEmpty = true;
}
});
each$b(split$1('ol ul blockquote a table tbody'), name => {
if (elements[name]) {
elements[name].removeEmpty = true;
}
});
each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary'), name => {
if (elements[name]) {
elements[name].paddEmpty = true;
}
});
each$b(split$1('span'), name => {
elements[name].removeEmptyAttrs = true;
});
} else {
setValidElements(settings.valid_elements);
each$b(schemaItems, (element, name) => {
children[name] = element.children;
});
}
delete elements.svg;
addCustomElements(settings.custom_elements);
addValidChildren(settings.valid_children);
addValidElements(settings.extended_valid_elements);
addValidChildren('+ol[ul|ol],+ul[ul|ol]');
each$b({
dd: 'dl',
dt: 'dl',
li: 'ul ol',
td: 'tr',
th: 'tr',
tr: 'tbody thead tfoot',
tbody: 'table',
thead: 'table',
tfoot: 'table',
legend: 'fieldset',
area: 'map',
param: 'video audio object'
}, (parents, item) => {
if (elements[item]) {
elements[item].parentsRequired = split$1(parents);
}
});
if (settings.invalid_elements) {
each$b(explode$2(settings.invalid_elements), item => {
if (elements[item]) {
delete elements[item];
}
});
}
if (!getElementRule('span')) {
addValidElements('span[!data-mce-type|*]');
}
};
const getValidStyles = constant(validStyles);
const getInvalidStyles = constant(invalidStyles);
const getValidClasses = constant(validClasses);
const getBoolAttrs = constant(boolAttrMap);
const getBlockElements = constant(blockElementsMap);
const getTextBlockElements = constant(textBlockElementsMap);
const getTextInlineElements = constant(textInlineElementsMap);
const getVoidElements = constant(Object.seal(voidElementsMap));
const getSelfClosingElements = constant(selfClosingElementsMap);
const getNonEmptyElements = constant(nonEmptyElementsMap);
const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
const getWhitespaceElements = constant(whitespaceElementsMap);
const getTransparentElements = constant(transparentElementsMap);
const getWrapBlockElements = constant(wrapBlockElementsMap);
const getSpecialElements = constant(Object.seal(specialElements));
const isValidChild = (name, child) => {
const parent = children[name.toLowerCase()];
return !!(parent && parent[child.toLowerCase()]);
};
const isValid = (name, attr) => {
const rule = getElementRule(name);
if (rule) {
if (attr) {
if (rule.attributes[attr]) {
return true;
}
const attrPatterns = rule.attributePatterns;
if (attrPatterns) {
let i = attrPatterns.length;
while (i--) {
if (attrPatterns[i].pattern.test(attr)) {
return true;
}
}
}
} else {
return true;
}
}
return false;
};
const isBlock = name => has$2(getBlockElements(), name);
const isInline = name => !startsWith(name, '#') && isValid(name) && !isBlock(name);
const isWrapper = name => has$2(getWrapBlockElements(), name) || isInline(name);
const getCustomElements = constant(customElementsMap);
setup();
return {
type: schemaType,
children,
elements,
getValidStyles,
getValidClasses,
getBlockElements,
getInvalidStyles,
getVoidElements,
getTextBlockElements,
getTextInlineElements,
getBoolAttrs,
getElementRule,
getSelfClosingElements,
getNonEmptyElements,
getMoveCaretBeforeOnEnterElements,
getWhitespaceElements,
getTransparentElements,
getSpecialElements,
isValidChild,
isValid,
isBlock,
isInline,
isWrapper,
getCustomElements,
addValidElements,
setValidElements,
addCustomElements,
addValidChildren
};
};
const hexColour = value => ({ value: normalizeHex(value) });
const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
const toHex = component => {
const hex = component.toString(16);
return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
};
const fromRgba = rgbaColour => {
const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
return hexColour(value);
};
const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i;
const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*((?:\d?\.\d+|\d+)%?)\s*\)\s*$/i;
const rgbaColour = (red, green, blue, alpha) => ({
red,
green,
blue,
alpha
});
const fromStringValues = (red, green, blue, alpha) => {
const r = parseInt(red, 10);
const g = parseInt(green, 10);
const b = parseInt(blue, 10);
const a = parseFloat(alpha);
return rgbaColour(r, g, b, a);
};
const getColorFormat = colorString => {
if (rgbRegex.test(colorString)) {
return 'rgb';
} else if (rgbaRegex.test(colorString)) {
return 'rgba';
}
return 'other';
};
const fromString = rgbaString => {
const rgbMatch = rgbRegex.exec(rgbaString);
if (rgbMatch !== null) {
return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
}
const rgbaMatch = rgbaRegex.exec(rgbaString);
if (rgbaMatch !== null) {
return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
}
return Optional.none();
};
const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
const Styles = (settings = {}, schema) => {
const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
const trimRightRegExp = /\s+$/;
const encodingLookup = {};
let validStyles;
let invalidStyles;
const invisibleChar = zeroWidth;
if (schema) {
validStyles = schema.getValidStyles();
invalidStyles = schema.getInvalidStyles();
}
const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' ');
for (let i = 0; i < encodingItems.length; i++) {
encodingLookup[encodingItems[i]] = invisibleChar + i;
encodingLookup[invisibleChar + i] = encodingItems[i];
}
const self = {
parse: css => {
const styles = {};
let isEncoded = false;
const urlConverter = settings.url_converter;
const urlConverterScope = settings.url_converter_scope || self;
const compress = (prefix, suffix, noJoin) => {
const top = styles[prefix + '-top' + suffix];
if (!top) {
return;
}
const right = styles[prefix + '-right' + suffix];
if (!right) {
return;
}
const bottom = styles[prefix + '-bottom' + suffix];
if (!bottom) {
return;
}
const left = styles[prefix + '-left' + suffix];
if (!left) {
return;
}
const box = [
top,
right,
bottom,
left
];
let i = box.length - 1;
while (i--) {
if (box[i] !== box[i + 1]) {
break;
}
}
if (i > -1 && noJoin) {
return;
}
styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
delete styles[prefix + '-top' + suffix];
delete styles[prefix + '-right' + suffix];
delete styles[prefix + '-bottom' + suffix];
delete styles[prefix + '-left' + suffix];
};
const canCompress = key => {
const value = styles[key];
if (!value) {
return;
}
const values = value.indexOf(',') > -1 ? [value] : value.split(' ');
let i = values.length;
while (i--) {
if (values[i] !== values[0]) {
return false;
}
}
styles[key] = values[0];
return true;
};
const compress2 = (target, a, b, c) => {
if (!canCompress(a)) {
return;
}
if (!canCompress(b)) {
return;
}
if (!canCompress(c)) {
return;
}
styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
delete styles[a];
delete styles[b];
delete styles[c];
};
const encode = str => {
isEncoded = true;
return encodingLookup[str];
};
const decode = (str, keepSlashes) => {
if (isEncoded) {
str = str.replace(/\uFEFF[0-9]/g, str => {
return encodingLookup[str];
});
}
if (!keepSlashes) {
str = str.replace(/\\([\'\";:])/g, '$1');
}
return str;
};
const decodeSingleHexSequence = escSeq => {
return String.fromCharCode(parseInt(escSeq.slice(1), 16));
};
const decodeHexSequences = value => {
return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
};
const processUrl = (match, url, url2, url3, str, str2) => {
str = str || str2;
if (str) {
str = decode(str);
return `'` + str.replace(/\'/g, `\\'`) + `'`;
}
url = decode(url || url2 || url3 || '');
if (!settings.allow_script_urls) {
const scriptUrl = url.replace(/[\s\r\n]+/g, '');
if (/(java|vb)script:/i.test(scriptUrl)) {
return '';
}
if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
return '';
}
}
if (urlConverter) {
url = urlConverter.call(urlConverterScope, url, 'style');
}
return `url('` + url.replace(/\'/g, `\\'`) + `')`;
};
if (css) {
css = css.replace(/[\u0000-\u001F]/g, '');
css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => {
return str.replace(/[;:]/g, encode);
});
let matches;
while (matches = styleRegExp.exec(css)) {
styleRegExp.lastIndex = matches.index + matches[0].length;
let name = matches[1].replace(trimRightRegExp, '').toLowerCase();
let value = matches[2].replace(trimRightRegExp, '');
if (name && value) {
name = decodeHexSequences(name);
value = decodeHexSequences(value);
if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
continue;
}
if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
continue;
}
if (name === 'font-weight' && value === '700') {
value = 'bold';
} else if (name === 'color' || name === 'background-color') {
value = value.toLowerCase();
}
if (getColorFormat(value) === 'rgb') {
fromString(value).each(rgba => {
value = rgbaToHexString(toString(rgba)).toLowerCase();
});
}
value = value.replace(urlOrStrRegExp, processUrl);
styles[name] = isEncoded ? decode(value, true) : value;
}
}
compress('border', '', true);
compress('border', '-width');
compress('border', '-color');
compress('border', '-style');
compress('padding', '');
compress('margin', '');
compress2('border', 'border-width', 'border-style', 'border-color');
if (styles.border === 'medium none') {
delete styles.border;
}
if (styles['border-image'] === 'none') {
delete styles['border-image'];
}
}
return styles;
},
serialize: (styles, elementName) => {
let css = '';
const serializeStyles = (elemName, validStyleList) => {
const styleList = validStyleList[elemName];
if (styleList) {
for (let i = 0, l = styleList.length; i < l; i++) {
const name = styleList[i];
const value = styles[name];
if (value) {
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
}
}
}
};
const isValid = (name, elemName) => {
if (!invalidStyles || !elemName) {
return true;
}
let styleMap = invalidStyles['*'];
if (styleMap && styleMap[name]) {
return false;
}
styleMap = invalidStyles[elemName];
return !(styleMap && styleMap[name]);
};
if (elementName && validStyles) {
serializeStyles('*', validStyles);
serializeStyles(elementName, validStyles);
} else {
each$d(styles, (value, name) => {
if (value && isValid(name, elementName)) {
css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
}
});
}
return css;
}
};
return self;
};
const deprecated = {
keyLocation: true,
layerX: true,
layerY: true,
returnValue: true,
webkitMovementX: true,
webkitMovementY: true,
keyIdentifier: true,
mozPressure: true
};
const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent);
const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event);
const clone$3 = (originalEvent, data) => {
const event = data !== null && data !== void 0 ? data : {};
for (const name in originalEvent) {
if (!has$2(deprecated, name)) {
event[name] = originalEvent[name];
}
}
if (isNonNullable(originalEvent.composedPath)) {
event.composedPath = () => originalEvent.composedPath();
}
if (isNonNullable(originalEvent.getModifierState)) {
event.getModifierState = keyArg => originalEvent.getModifierState(keyArg);
}
if (isNonNullable(originalEvent.getTargetRanges)) {
event.getTargetRanges = () => originalEvent.getTargetRanges();
}
return event;
};
const normalize$3 = (type, originalEvent, fallbackTarget, data) => {
var _a;
const event = clone$3(originalEvent, data);
event.type = type;
if (isNullable(event.target)) {
event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
}
if (needsNormalizing(originalEvent)) {
event.preventDefault = () => {
event.defaultPrevented = true;
event.isDefaultPrevented = always;
if (isFunction(originalEvent.preventDefault)) {
originalEvent.preventDefault();
}
};
event.stopPropagation = () => {
event.cancelBubble = true;
event.isPropagationStopped = always;
if (isFunction(originalEvent.stopPropagation)) {
originalEvent.stopPropagation();
}
};
event.stopImmediatePropagation = () => {
event.isImmediatePropagationStopped = always;
event.stopPropagation();
};
if (!hasIsDefaultPrevented(event)) {
event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
event.isPropagationStopped = event.cancelBubble === true ? always : never;
event.isImmediatePropagationStopped = never;
}
}
return event;
};
const eventExpandoPrefix = 'mce-data-';
const mouseEventRe = /^(?:mouse|contextmenu)|click/;
const addEvent = (target, name, callback, capture) => {
target.addEventListener(name, callback, capture || false);
};
const removeEvent = (target, name, callback, capture) => {
target.removeEventListener(name, callback, capture || false);
};
const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type);
const fix = (originalEvent, data) => {
const event = normalize$3(originalEvent.type, originalEvent, document, data);
if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
const eventDoc = event.target.ownerDocument || document;
const doc = eventDoc.documentElement;
const body = eventDoc.body;
const mouseEvent = event;
mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
}
return event;
};
const bindOnReady = (win, callback, eventUtils) => {
const doc = win.document, event = { type: 'ready' };
if (eventUtils.domLoaded) {
callback(event);
return;
}
const isDocReady = () => {
return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
};
const readyHandler = () => {
removeEvent(win, 'DOMContentLoaded', readyHandler);
removeEvent(win, 'load', readyHandler);
if (!eventUtils.domLoaded) {
eventUtils.domLoaded = true;
callback(event);
}
win = null;
};
if (isDocReady()) {
readyHandler();
} else {
addEvent(win, 'DOMContentLoaded', readyHandler);
}
if (!eventUtils.domLoaded) {
addEvent(win, 'load', readyHandler);
}
};
class EventUtils {
constructor() {
this.domLoaded = false;
this.events = {};
this.count = 1;
this.expando = eventExpandoPrefix + (+new Date()).toString(32);
this.hasFocusIn = 'onfocusin' in document.documentElement;
this.count = 1;
}
bind(target, names, callback, scope) {
const self = this;
let callbackList;
const win = window;
const defaultNativeHandler = evt => {
self.executeHandlers(fix(evt || win.event), id);
};
if (!target || isText$b(target) || isComment(target)) {
return callback;
}
let id;
if (!target[self.expando]) {
id = self.count++;
target[self.expando] = id;
self.events[id] = {};
} else {
id = target[self.expando];
}
scope = scope || target;
const namesList = names.split(' ');
let i = namesList.length;
while (i--) {
let name = namesList[i];
let nativeHandler = defaultNativeHandler;
let capture = false;
let fakeName = false;
if (name === 'DOMContentLoaded') {
name = 'ready';
}
if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
callback.call(scope, fix({ type: name }));
continue;
}
if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
capture = true;
fakeName = name === 'focusin' ? 'focus' : 'blur';
nativeHandler = evt => {
const event = fix(evt || win.event);
event.type = event.type === 'focus' ? 'focusin' : 'focusout';
self.executeHandlers(event, id);
};
}
callbackList = self.events[id][name];
if (!callbackList) {
self.events[id][name] = callbackList = [{
func: callback,
scope
}];
callbackList.fakeName = fakeName;
callbackList.capture = capture;
callbackList.nativeHandler = nativeHandler;
if (name === 'ready') {
bindOnReady(target, nativeHandler, self);
} else {
addEvent(target, fakeName || name, nativeHandler, capture);
}
} else {
if (name === 'ready' && self.domLoaded) {
callback(fix({ type: name }));
} else {
callbackList.push({
func: callback,
scope
});
}
}
}
target = callbackList = null;
return callback;
}
unbind(target, names, callback) {
if (!target || isText$b(target) || isComment(target)) {
return this;
}
const id = target[this.expando];
if (id) {
let eventMap = this.events[id];
if (names) {
const namesList = names.split(' ');
let i = namesList.length;
while (i--) {
const name = namesList[i];
const callbackList = eventMap[name];
if (callbackList) {
if (callback) {
let ci = callbackList.length;
while (ci--) {
if (callbackList[ci].func === callback) {
const nativeHandler = callbackList.nativeHandler;
const fakeName = callbackList.fakeName, capture = callbackList.capture;
const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
newCallbackList.nativeHandler = nativeHandler;
newCallbackList.fakeName = fakeName;
newCallbackList.capture = capture;
eventMap[name] = newCallbackList;
}
}
}
if (!callback || callbackList.length === 0) {
delete eventMap[name];
removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
}
}
}
} else {
each$d(eventMap, (callbackList, name) => {
removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
});
eventMap = {};
}
for (const name in eventMap) {
if (has$2(eventMap, name)) {
return this;
}
}
delete this.events[id];
try {
delete target[this.expando];
} catch (ex) {
target[this.expando] = null;
}
}
return this;
}
fire(target, name, args) {
return this.dispatch(target, name, args);
}
dispatch(target, name, args) {
if (!target || isText$b(target) || isComment(target)) {
return this;
}
const event = fix({
type: name,
target
}, args);
do {
const id = target[this.expando];
if (id) {
this.executeHandlers(event, id);
}
target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
} while (target && !event.isPropagationStopped());
return this;
}
clean(target) {
if (!target || isText$b(target) || isComment(target)) {
return this;
}
if (target[this.expando]) {
this.unbind(target);
}
if (!target.getElementsByTagName) {
target = target.document;
}
if (target && target.getElementsByTagName) {
this.unbind(target);
const children = target.getElementsByTagName('*');
let i = children.length;
while (i--) {
target = children[i];
if (target[this.expando]) {
this.unbind(target);
}
}
}
return this;
}
destroy() {
this.events = {};
}
cancel(e) {
if (e) {
e.preventDefault();
e.stopImmediatePropagation();
}
return false;
}
executeHandlers(evt, id) {
const container = this.events[id];
const callbackList = container && container[evt.type];
if (callbackList) {
for (let i = 0, l = callbackList.length; i < l; i++) {
const callback = callbackList[i];
if (callback && callback.func.call(callback.scope, evt) === false) {
evt.preventDefault();
}
if (evt.isImmediatePropagationStopped()) {
return;
}
}
}
}
}
EventUtils.Event = new EventUtils();
const each$a = Tools.each;
const grep = Tools.grep;
const internalStyleName = 'data-mce-style';
const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' ');
const legacySetAttribute = (elm, name, value) => {
if (isNullable(value) || value === '') {
remove$9(elm, name);
} else {
set$3(elm, name, value);
}
};
const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase());
const findNodeIndex = (node, normalized) => {
let idx = 0;
if (node) {
for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) {
const nodeType = tempNode.nodeType;
if (normalized && isText$b(tempNode)) {
if (nodeType === lastNodeType || !tempNode.data.length) {
continue;
}
}
idx++;
lastNodeType = nodeType;
}
}
return idx;
};
const updateInternalStyleAttr = (styles, elm) => {
const rawValue = get$9(elm, 'style');
const value = styles.serialize(styles.parse(rawValue), name(elm));
legacySetAttribute(elm, internalStyleName, value);
};
const convertStyleToString = (cssValue, cssName) => {
if (isNumber(cssValue)) {
return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px';
} else {
return cssValue;
}
};
const applyStyle$1 = ($elm, cssName, cssValue) => {
const normalizedName = camelCaseToHyphens(cssName);
if (isNullable(cssValue) || cssValue === '') {
remove$5($elm, normalizedName);
} else {
set$2($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
}
};
const setupAttrHooks = (styles, settings, getContext) => {
const keepValues = settings.keep_values;
const keepUrlHook = {
set: (elm, value, name) => {
const sugarElm = SugarElement.fromDom(elm);
if (isFunction(settings.url_converter) && isNonNullable(value)) {
value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm);
}
const internalName = 'data-mce-' + name;
legacySetAttribute(sugarElm, internalName, value);
legacySetAttribute(sugarElm, name, value);
},
get: (elm, name) => {
const sugarElm = SugarElement.fromDom(elm);
return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name);
}
};
const attrHooks = {
style: {
set: (elm, value) => {
const sugarElm = SugarElement.fromDom(elm);
if (keepValues) {
legacySetAttribute(sugarElm, internalStyleName, value);
}
remove$9(sugarElm, 'style');
if (isString(value)) {
setAll(sugarElm, styles.parse(value));
}
},
get: elm => {
const sugarElm = SugarElement.fromDom(elm);
const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style');
return styles.serialize(styles.parse(value), name(sugarElm));
}
}
};
if (keepValues) {
attrHooks.href = attrHooks.src = keepUrlHook;
}
return attrHooks;
};
const DOMUtils = (doc, settings = {}) => {
const addedStyles = {};
const win = window;
const files = {};
let counter = 0;
const stdMode = true;
const boxModel = true;
const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
contentCssCors: settings.contentCssCors,
referrerPolicy: settings.referrerPolicy
});
const boundEvents = [];
const schema = settings.schema ? settings.schema : Schema({});
const styles = Styles({
url_converter: settings.url_converter,
url_converter_scope: settings.url_converter_scope
}, settings.schema);
const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
const blockElementsMap = schema.getBlockElements();
const isBlock = node => {
if (isString(node)) {
return has$2(blockElementsMap, node);
} else {
return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node));
}
};
const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
const _get = elm => {
const value = get(elm);
return isNonNullable(value) ? SugarElement.fromDom(value) : null;
};
const getAttrib = (elm, name, defaultVal = '') => {
let value;
const $elm = _get(elm);
if (isNonNullable($elm) && isElement$7($elm)) {
const hook = attrHooks[name];
if (hook && hook.get) {
value = hook.get($elm.dom, name);
} else {
value = get$9($elm, name);
}
}
return isNonNullable(value) ? value : defaultVal;
};
const getAttribs = elm => {
const node = get(elm);
return isNullable(node) ? [] : node.attributes;
};
const setAttrib = (elm, name, value) => {
run(elm, e => {
if (isElement$6(e)) {
const $elm = SugarElement.fromDom(e);
const val = value === '' ? null : value;
const originalValue = get$9($elm, name);
const hook = attrHooks[name];
if (hook && hook.set) {
hook.set($elm.dom, val, name);
} else {
legacySetAttribute($elm, name, val);
}
if (originalValue !== val && settings.onSetAttrib) {
settings.onSetAttrib({
attrElm: $elm.dom,
attrName: name,
attrValue: val
});
}
}
});
};
const clone = (node, deep) => {
return node.cloneNode(deep);
};
const getRoot = () => settings.root_element || doc.body;
const getViewPort = argWin => {
const vp = getBounds(argWin);
return {
x: vp.x,
y: vp.y,
w: vp.width,
h: vp.height
};
};
const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm);
const setStyle = (elm, name, value) => {
run(elm, e => {
const $elm = SugarElement.fromDom(e);
applyStyle$1($elm, name, value);
if (settings.update_styles) {
updateInternalStyleAttr(styles, $elm);
}
});
};
const setStyles = (elm, stylesArg) => {
run(elm, e => {
const $elm = SugarElement.fromDom(e);
each$d(stylesArg, (v, n) => {
applyStyle$1($elm, n, v);
});
if (settings.update_styles) {
updateInternalStyleAttr(styles, $elm);
}
});
};
const getStyle = (elm, name, computed) => {
const $elm = get(elm);
if (isNullable($elm) || !isHTMLElement($elm) && !isSVGElement($elm)) {
return undefined;
}
if (computed) {
return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name));
} else {
name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase());
if (name === 'float') {
name = 'cssFloat';
}
return $elm.style ? $elm.style[name] : undefined;
}
};
const getSize = elm => {
const $elm = get(elm);
if (!$elm) {
return {
w: 0,
h: 0
};
}
let w = getStyle($elm, 'width');
let h = getStyle($elm, 'height');
if (!w || w.indexOf('px') === -1) {
w = '0';
}
if (!h || h.indexOf('px') === -1) {
h = '0';
}
return {
w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight
};
};
const getRect = elm => {
const $elm = get(elm);
const pos = getPos$1($elm);
const size = getSize($elm);
return {
x: pos.x,
y: pos.y,
w: size.w,
h: size.h
};
};
const is = (elm, selector) => {
if (!elm) {
return false;
}
const elms = isArray$1(elm) ? elm : [elm];
return exists(elms, e => {
return is$1(SugarElement.fromDom(e), selector);
});
};
const getParents = (elm, selector, root, collect) => {
const result = [];
let node = get(elm);
collect = collect === undefined;
const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
if (isString(selector)) {
if (selector === '*') {
selector = isElement$6;
} else {
const selectorVal = selector;
selector = node => is(node, selectorVal);
}
}
while (node) {
if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
break;
}
if (!selector || selector(node)) {
if (collect) {
result.push(node);
} else {
return [node];
}
}
node = node.parentNode;
}
return collect ? result : null;
};
const getParent = (node, selector, root) => {
const parents = getParents(node, selector, root, false);
return parents && parents.length > 0 ? parents[0] : null;
};
const _findSib = (node, selector, name) => {
let func = selector;
if (node) {
if (isString(selector)) {
func = node => {
return is(node, selector);
};
}
for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) {
if (isFunction(func) && func(tempNode)) {
return tempNode;
}
}
}
return null;
};
const getNext = (node, selector) => _findSib(node, selector, 'nextSibling');
const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling');
const isParentNode = node => isFunction(node.querySelectorAll);
const select = (selector, scope) => {
var _a, _b;
const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : [];
};
const run = function (elm, func, scope) {
const context = scope !== null && scope !== void 0 ? scope : this;
if (isArray$1(elm)) {
const result = [];
each$a(elm, (e, i) => {
const node = get(e);
if (node) {
result.push(func.call(context, node, i));
}
});
return result;
} else {
const node = get(elm);
return !node ? false : func.call(context, node);
}
};
const setAttribs = (elm, attrs) => {
run(elm, $elm => {
each$d(attrs, (value, name) => {
setAttrib($elm, name, value);
});
});
};
const setHTML = (elm, html) => {
run(elm, e => {
const $elm = SugarElement.fromDom(e);
set$1($elm, html);
});
};
const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => {
const newElm = isString(name) ? doc.createElement(name) : name;
if (isNonNullable(attrs)) {
setAttribs(newElm, attrs);
}
if (html) {
if (!isString(html) && html.nodeType) {
newElm.appendChild(html);
} else if (isString(html)) {
setHTML(newElm, html);
}
}
return !create ? parentElm.appendChild(newElm) : newElm;
});
const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true);
const decode = Entities.decode;
const encode = Entities.encodeAllRaw;
const createHTML = (name, attrs, html = '') => {
let outHtml = '<' + name;
for (const key in attrs) {
if (hasNonNullableKey(attrs, key)) {
outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
}
}
if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) {
return outHtml + ' />';
} else {
return outHtml + '>' + html + '' + name + '>';
}
};
const createFragment = html => {
const container = doc.createElement('div');
const frag = doc.createDocumentFragment();
frag.appendChild(container);
if (html) {
container.innerHTML = html;
}
let node;
while (node = container.firstChild) {
frag.appendChild(node);
}
frag.removeChild(container);
return frag;
};
const remove = (node, keepChildren) => {
return run(node, n => {
const $node = SugarElement.fromDom(n);
if (keepChildren) {
each$e(children$1($node), child => {
if (isText$c(child) && child.dom.length === 0) {
remove$4(child);
} else {
before$3($node, child);
}
});
}
remove$4($node);
return $node.dom;
});
};
const removeAllAttribs = e => run(e, e => {
const attrs = e.attributes;
for (let i = attrs.length - 1; i >= 0; i--) {
e.removeAttributeNode(attrs.item(i));
}
});
const parseStyle = cssText => styles.parse(cssText);
const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name);
const addStyle = cssText => {
if (self !== DOMUtils.DOM && doc === document) {
if (addedStyles[cssText]) {
return;
}
addedStyles[cssText] = true;
}
let styleElm = doc.getElementById('mceDefaultStyles');
if (!styleElm) {
styleElm = doc.createElement('style');
styleElm.id = 'mceDefaultStyles';
styleElm.type = 'text/css';
const head = doc.head;
if (head.firstChild) {
head.insertBefore(styleElm, head.firstChild);
} else {
head.appendChild(styleElm);
}
}
if (styleElm.styleSheet) {
styleElm.styleSheet.cssText += cssText;
} else {
styleElm.appendChild(doc.createTextNode(cssText));
}
};
const loadCSS = urls => {
if (!urls) {
urls = '';
}
each$e(urls.split(','), url => {
files[url] = true;
styleSheetLoader.load(url).catch(noop);
});
};
const toggleClass = (elm, cls, state) => {
run(elm, e => {
if (isElement$6(e)) {
const $elm = SugarElement.fromDom(e);
const classes = cls.split(' ');
each$e(classes, c => {
if (isNonNullable(state)) {
const fn = state ? add$2 : remove$6;
fn($elm, c);
} else {
toggle$1($elm, c);
}
});
}
});
};
const addClass = (elm, cls) => {
toggleClass(elm, cls, true);
};
const removeClass = (elm, cls) => {
toggleClass(elm, cls, false);
};
const hasClass = (elm, cls) => {
const $elm = _get(elm);
const classes = cls.split(' ');
return isNonNullable($elm) && forall(classes, c => has($elm, c));
};
const show = elm => {
run(elm, e => remove$5(SugarElement.fromDom(e), 'display'));
};
const hide = elm => {
run(elm, e => set$2(SugarElement.fromDom(e), 'display', 'none'));
};
const isHidden = elm => {
const $elm = _get(elm);
return isNonNullable($elm) && is$2(getRaw($elm, 'display'), 'none');
};
const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++;
const getOuterHTML = elm => {
const $elm = _get(elm);
if (isNonNullable($elm)) {
return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
} else {
return '';
}
};
const setOuterHTML = (elm, html) => {
run(elm, $elm => {
if (isElement$6($elm)) {
$elm.outerHTML = html;
}
});
};
const insertAfter = (node, reference) => {
const referenceNode = get(reference);
return run(node, node => {
const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode;
const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling;
if (parent) {
if (nextSibling) {
parent.insertBefore(node, nextSibling);
} else {
parent.appendChild(node);
}
}
return node;
});
};
const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => {
var _a;
const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm;
if (keepChildren) {
each$a(grep(elm.childNodes), node => {
replacee.appendChild(node);
});
}
(_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm);
return elm;
});
const rename = (elm, name) => {
if (elm.nodeName !== name.toUpperCase()) {
const newElm = create(name);
each$a(getAttribs(elm), attrNode => {
setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
});
replace(newElm, elm, true);
return newElm;
} else {
return elm;
}
};
const findCommonAncestor = (a, b) => {
let ps = a;
while (ps) {
let pe = b;
while (pe && ps !== pe) {
pe = pe.parentNode;
}
if (ps === pe) {
break;
}
ps = ps.parentNode;
}
if (!ps && a.ownerDocument) {
return a.ownerDocument.documentElement;
} else {
return ps;
}
};
const isEmpty = (node, elements, options) => {
if (isPlainObject(elements)) {
const isContent = node => {
const name = node.nodeName.toLowerCase();
return Boolean(elements[name]);
};
return isEmptyNode(schema, node, {
...options,
isContent
});
} else {
return isEmptyNode(schema, node, options);
}
};
const createRng = () => doc.createRange();
const split = (parentElm, splitElm, replacementElm) => {
let range = createRng();
let beforeFragment;
let afterFragment;
if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) {
const parentNode = parentElm.parentNode;
range.setStart(parentNode, findNodeIndex(parentElm));
range.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
beforeFragment = range.extractContents();
range = createRng();
range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
range.setEnd(parentNode, findNodeIndex(parentElm) + 1);
afterFragment = range.extractContents();
parentNode.insertBefore(trimNode(self, beforeFragment, schema), parentElm);
if (replacementElm) {
parentNode.insertBefore(replacementElm, parentElm);
} else {
parentNode.insertBefore(splitElm, parentElm);
}
parentNode.insertBefore(trimNode(self, afterFragment, schema), parentElm);
remove(parentElm);
return replacementElm || splitElm;
} else {
return undefined;
}
};
const bind = (target, name, func, scope) => {
if (isArray$1(target)) {
let i = target.length;
const rv = [];
while (i--) {
rv[i] = bind(target[i], name, func, scope);
}
return rv;
} else {
if (settings.collect && (target === doc || target === win)) {
boundEvents.push([
target,
name,
func,
scope
]);
}
return events.bind(target, name, func, scope || self);
}
};
const unbind = (target, name, func) => {
if (isArray$1(target)) {
let i = target.length;
const rv = [];
while (i--) {
rv[i] = unbind(target[i], name, func);
}
return rv;
} else {
if (boundEvents.length > 0 && (target === doc || target === win)) {
let i = boundEvents.length;
while (i--) {
const [boundTarget, boundName, boundFunc] = boundEvents[i];
if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) {
events.unbind(boundTarget, boundName, boundFunc);
}
}
}
return events.unbind(target, name, func);
}
};
const dispatch = (target, name, evt) => events.dispatch(target, name, evt);
const fire = (target, name, evt) => events.dispatch(target, name, evt);
const getContentEditable = node => {
if (node && isHTMLElement(node)) {
const contentEditable = node.getAttribute('data-mce-contenteditable');
if (contentEditable && contentEditable !== 'inherit') {
return contentEditable;
}
return node.contentEditable !== 'inherit' ? node.contentEditable : null;
} else {
return null;
}
};
const getContentEditableParent = node => {
const root = getRoot();
let state = null;
for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
state = getContentEditable(tempNode);
if (state !== null) {
break;
}
}
return state;
};
const isEditable = node => {
if (isNonNullable(node)) {
const scope = isElement$6(node) ? node : node.parentElement;
return isNonNullable(scope) && isHTMLElement(scope) && isEditable$2(SugarElement.fromDom(scope));
} else {
return false;
}
};
const destroy = () => {
if (boundEvents.length > 0) {
let i = boundEvents.length;
while (i--) {
const [boundTarget, boundName, boundFunc] = boundEvents[i];
events.unbind(boundTarget, boundName, boundFunc);
}
}
each$d(files, (_, url) => {
styleSheetLoader.unload(url);
delete files[url];
});
};
const isChildOf = (node, parent) => {
return node === parent || parent.contains(node);
};
const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
const self = {
doc,
settings,
win,
files,
stdMode,
boxModel,
styleSheetLoader,
boundEvents,
styles,
schema,
events,
isBlock: isBlock,
root: null,
clone,
getRoot,
getViewPort,
getRect,
getSize,
getParent,
getParents: getParents,
get,
getNext,
getPrev,
select,
is,
add,
create,
createHTML,
createFragment,
remove,
setStyle,
getStyle: getStyle,
setStyles,
removeAllAttribs,
setAttrib,
setAttribs,
getAttrib,
getPos: getPos$1,
parseStyle,
serializeStyle,
addStyle,
loadCSS,
addClass,
removeClass,
hasClass,
toggleClass,
show,
hide,
isHidden,
uniqueId,
setHTML,
getOuterHTML,
setOuterHTML,
decode,
encode,
insertAfter,
replace,
rename,
findCommonAncestor,
run,
getAttribs,
isEmpty,
createRng,
nodeIndex: findNodeIndex,
split,
bind: bind,
unbind: unbind,
fire,
dispatch,
getContentEditable,
getContentEditableParent,
isEditable,
destroy,
isChildOf,
dumpRng
};
const attrHooks = setupAttrHooks(styles, settings, constant(self));
return self;
};
DOMUtils.DOM = DOMUtils(document);
DOMUtils.nodeIndex = findNodeIndex;
const DOM$b = DOMUtils.DOM;
const QUEUED = 0;
const LOADING = 1;
const LOADED = 2;
const FAILED = 3;
class ScriptLoader {
constructor(settings = {}) {
this.states = {};
this.queue = [];
this.scriptLoadedCallbacks = {};
this.queueLoadedCallbacks = [];
this.loading = false;
this.settings = settings;
}
_setReferrerPolicy(referrerPolicy) {
this.settings.referrerPolicy = referrerPolicy;
}
loadScript(url) {
return new Promise((resolve, reject) => {
const dom = DOM$b;
let elm;
const cleanup = () => {
dom.remove(id);
if (elm) {
elm.onerror = elm.onload = elm = null;
}
};
const done = () => {
cleanup();
resolve();
};
const error = () => {
cleanup();
reject('Failed to load script: ' + url);
};
const id = dom.uniqueId();
elm = document.createElement('script');
elm.id = id;
elm.type = 'text/javascript';
elm.src = Tools._addCacheSuffix(url);
if (this.settings.referrerPolicy) {
dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
}
elm.onload = done;
elm.onerror = error;
(document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
});
}
isDone(url) {
return this.states[url] === LOADED;
}
markDone(url) {
this.states[url] = LOADED;
}
add(url) {
const self = this;
self.queue.push(url);
const state = self.states[url];
if (state === undefined) {
self.states[url] = QUEUED;
}
return new Promise((resolve, reject) => {
if (!self.scriptLoadedCallbacks[url]) {
self.scriptLoadedCallbacks[url] = [];
}
self.scriptLoadedCallbacks[url].push({
resolve,
reject
});
});
}
load(url) {
return this.add(url);
}
remove(url) {
delete this.states[url];
delete this.scriptLoadedCallbacks[url];
}
loadQueue() {
const queue = this.queue;
this.queue = [];
return this.loadScripts(queue);
}
loadScripts(scripts) {
const self = this;
const execCallbacks = (name, url) => {
get$a(self.scriptLoadedCallbacks, url).each(callbacks => {
each$e(callbacks, callback => callback[name](url));
});
delete self.scriptLoadedCallbacks[url];
};
const processResults = results => {
const failures = filter$5(results, result => result.status === 'rejected');
if (failures.length > 0) {
return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason]));
} else {
return Promise.resolve();
}
};
const load = urls => Promise.allSettled(map$3(urls, url => {
if (self.states[url] === LOADED) {
execCallbacks('resolve', url);
return Promise.resolve();
} else if (self.states[url] === FAILED) {
execCallbacks('reject', url);
return Promise.reject(url);
} else {
self.states[url] = LOADING;
return self.loadScript(url).then(() => {
self.states[url] = LOADED;
execCallbacks('resolve', url);
const queue = self.queue;
if (queue.length > 0) {
self.queue = [];
return load(queue).then(processResults);
} else {
return Promise.resolve();
}
}, () => {
self.states[url] = FAILED;
execCallbacks('reject', url);
return Promise.reject(url);
});
}
}));
const processQueue = urls => {
self.loading = true;
return load(urls).then(results => {
self.loading = false;
const nextQueuedItem = self.queueLoadedCallbacks.shift();
Optional.from(nextQueuedItem).each(call);
return processResults(results);
});
};
const uniqueScripts = stringArray(scripts);
if (self.loading) {
return new Promise((resolve, reject) => {
self.queueLoadedCallbacks.push(() => {
processQueue(uniqueScripts).then(resolve, reject);
});
});
} else {
return processQueue(uniqueScripts);
}
}
}
ScriptLoader.ScriptLoader = new ScriptLoader();
const isDuplicated = (items, item) => {
const firstIndex = items.indexOf(item);
return firstIndex !== -1 && items.indexOf(item, firstIndex + 1) > firstIndex;
};
const isRaw = str => isObject(str) && has$2(str, 'raw');
const isTokenised = str => isArray$1(str) && str.length > 1;
const data = {};
const currentCode = Cell('en');
const getLanguageData = () => get$a(data, currentCode.get());
const getData$1 = () => map$2(data, value => ({ ...value }));
const setCode = newCode => {
if (newCode) {
currentCode.set(newCode);
}
};
const getCode = () => currentCode.get();
const add$1 = (code, items) => {
let langData = data[code];
if (!langData) {
data[code] = langData = {};
}
const lcNames = map$3(keys(items), name => name.toLowerCase());
each$d(items, (translation, name) => {
const lcName = name.toLowerCase();
if (lcName !== name && isDuplicated(lcNames, lcName)) {
if (!has$2(items, lcName)) {
langData[lcName] = translation;
}
langData[name] = translation;
} else {
langData[lcName] = translation;
}
});
};
const translate = text => {
const langData = getLanguageData().getOr({});
const toString = obj => {
if (isFunction(obj)) {
return Object.prototype.toString.call(obj);
}
return !isEmpty(obj) ? '' + obj : '';
};
const isEmpty = text => text === '' || text === null || text === undefined;
const getLangData = text => {
const textStr = toString(text);
return has$2(langData, textStr) ? toString(langData[textStr]) : get$a(langData, textStr.toLowerCase()).map(toString).getOr(textStr);
};
const removeContext = str => str.replace(/{context:\w+}$/, '');
if (isEmpty(text)) {
return '';
}
if (isRaw(text)) {
return toString(text.raw);
}
if (isTokenised(text)) {
const values = text.slice(1);
const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1);
return removeContext(substitued);
}
return removeContext(getLangData(text));
};
const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl');
const hasCode = code => has$2(data, code);
const I18n = {
getData: getData$1,
setCode,
getCode,
add: add$1,
translate,
isRtl: isRtl$1,
hasCode
};
const AddOnManager = () => {
const items = [];
const urls = {};
const lookup = {};
const _listeners = [];
const runListeners = (name, state) => {
const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state);
each$e(matchedListeners, listener => listener.resolve());
};
const isLoaded = name => has$2(urls, name);
const isAdded = name => has$2(lookup, name);
const get = name => {
if (lookup[name]) {
return lookup[name].instance;
}
return undefined;
};
const loadLanguagePack = (name, languages) => {
const language = I18n.getCode();
const wrappedLanguages = ',' + (languages || '') + ',';
if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) {
return;
}
ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
};
const requireLangPack = (name, languages) => {
if (AddOnManager.languageLoad !== false) {
if (isLoaded(name)) {
loadLanguagePack(name, languages);
} else {
waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages));
}
}
};
const add = (id, addOn) => {
items.push(addOn);
lookup[id] = { instance: addOn };
runListeners(id, 'added');
return addOn;
};
const remove = name => {
delete urls[name];
delete lookup[name];
};
const createUrl = (baseUrl, dep) => {
if (isString(dep)) {
return isString(baseUrl) ? {
prefix: '',
resource: dep,
suffix: ''
} : {
prefix: baseUrl.prefix,
resource: dep,
suffix: baseUrl.suffix
};
} else {
return dep;
}
};
const load = (name, addOnUrl) => {
if (urls[name]) {
return Promise.resolve();
}
let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
urlString = AddOnManager.baseURL + '/' + urlString;
}
urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
const done = () => {
runListeners(name, 'loaded');
return Promise.resolve();
};
if (lookup[name]) {
return done();
} else {
return ScriptLoader.ScriptLoader.add(urlString).then(done);
}
};
const waitFor = (name, state = 'added') => {
if (state === 'added' && isAdded(name)) {
return Promise.resolve();
} else if (state === 'loaded' && isLoaded(name)) {
return Promise.resolve();
} else {
return new Promise(resolve => {
_listeners.push({
name,
state,
resolve
});
});
}
};
return {
items,
urls,
lookup,
get,
requireLangPack,
add,
remove,
createUrl,
load,
waitFor
};
};
AddOnManager.languageLoad = true;
AddOnManager.baseURL = '';
AddOnManager.PluginManager = AddOnManager();
AddOnManager.ThemeManager = AddOnManager();
AddOnManager.ModelManager = AddOnManager();
const first$1 = (fn, rate) => {
let timer = null;
const cancel = () => {
if (!isNull(timer)) {
clearTimeout(timer);
timer = null;
}
};
const throttle = (...args) => {
if (isNull(timer)) {
timer = setTimeout(() => {
timer = null;
fn.apply(null, args);
}, rate);
}
};
return {
cancel,
throttle
};
};
const last = (fn, rate) => {
let timer = null;
const cancel = () => {
if (!isNull(timer)) {
clearTimeout(timer);
timer = null;
}
};
const throttle = (...args) => {
cancel();
timer = setTimeout(() => {
timer = null;
fn.apply(null, args);
}, rate);
};
return {
cancel,
throttle
};
};
const ancestor$1 = (scope, selector, isRoot) => ancestor$3(scope, selector, isRoot).isSome();
const annotation = constant('mce-annotation');
const dataAnnotation = constant('data-mce-annotation');
const dataAnnotationId = constant('data-mce-annotation-uid');
const dataAnnotationActive = constant('data-mce-annotation-active');
const dataAnnotationClasses = constant('data-mce-annotation-classes');
const dataAnnotationAttributes = constant('data-mce-annotation-attrs');
const isRoot$1 = root => node => eq(node, root);
const identify = (editor, annotationName) => {
const rng = editor.selection.getRng();
const start = SugarElement.fromDom(rng.startContainer);
const root = SugarElement.fromDom(editor.getBody());
const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`);
const newStart = child$1(start, rng.startOffset).getOr(start);
const closest = closest$3(newStart, selector, isRoot$1(root));
return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => {
const elements = findMarkers(editor, uid);
return {
uid,
name,
elements
};
})));
};
const isAnnotation = elem => isElement$7(elem) && has(elem, annotation());
const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root));
const findMarkers = (editor, uid) => {
const body = SugarElement.fromDom(editor.getBody());
const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`);
return filter$5(descendants$1, descendant => !isBogusElement(descendant, body));
};
const findAll = (editor, name) => {
const body = SugarElement.fromDom(editor.getBody());
const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`);
const directory = {};
each$e(markers, m => {
if (!isBogusElement(m, body)) {
const uid = get$9(m, dataAnnotationId());
const nodesAlready = get$a(directory, uid).getOr([]);
directory[uid] = nodesAlready.concat([m]);
}
});
return directory;
};
const setup$y = (editor, registry) => {
const changeCallbacks = Cell({});
const initData = () => ({
listeners: [],
previous: value$2()
});
const withCallbacks = (name, f) => {
updateCallbacks(name, data => {
f(data);
return data;
});
};
const updateCallbacks = (name, f) => {
const callbackMap = changeCallbacks.get();
const data = get$a(callbackMap, name).getOrThunk(initData);
const outputData = f(data);
callbackMap[name] = outputData;
changeCallbacks.set(callbackMap);
};
const fireCallbacks = (name, uid, elements) => {
withCallbacks(name, data => {
each$e(data.listeners, f => f(true, name, {
uid,
nodes: map$3(elements, elem => elem.dom)
}));
});
};
const fireNoAnnotation = name => {
withCallbacks(name, data => {
each$e(data.listeners, f => f(false, name));
});
};
const toggleActiveAttr = (uid, state) => {
each$e(findMarkers(editor, uid), elem => {
if (state) {
set$3(elem, dataAnnotationActive(), 'true');
} else {
remove$9(elem, dataAnnotationActive());
}
});
};
const onNodeChange = last(() => {
const annotations = sort(registry.getNames());
each$e(annotations, name => {
updateCallbacks(name, data => {
const prev = data.previous.get();
identify(editor, Optional.some(name)).fold(() => {
prev.each(uid => {
fireNoAnnotation(name);
data.previous.clear();
toggleActiveAttr(uid, false);
});
}, ({uid, name, elements}) => {
if (!is$2(prev, uid)) {
prev.each(uid => toggleActiveAttr(uid, false));
fireCallbacks(name, uid, elements);
data.previous.set(uid);
toggleActiveAttr(uid, true);
}
});
return {
previous: data.previous,
listeners: data.listeners
};
});
});
}, 30);
editor.on('remove', () => {
onNodeChange.cancel();
});
editor.on('NodeChange', () => {
onNodeChange.throttle();
});
const addListener = (name, f) => {
updateCallbacks(name, data => ({
previous: data.previous,
listeners: data.listeners.concat([f])
}));
};
return { addListener };
};
const setup$x = (editor, registry) => {
const dataAnnotation$1 = dataAnnotation();
const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup);
const removeDirectAnnotation = node => {
var _a, _b;
node.attr(dataAnnotationId(), null);
node.attr(dataAnnotation(), null);
node.attr(dataAnnotationActive(), null);
const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]);
const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]);
each$e(customAttrNames, name => node.attr(name, null));
const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
const newClassList = difference(classList, [annotation()].concat(customClasses));
node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null);
node.attr(dataAnnotationClasses(), null);
node.attr(dataAnnotationAttributes(), null);
};
editor.serializer.addTempAttr(dataAnnotationActive());
editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => {
for (const node of nodes) {
identifyParserNode(node).each(settings => {
if (settings.persistent === false) {
if (node.name === 'span') {
node.unwrap();
} else {
removeDirectAnnotation(node);
}
}
});
}
});
};
const create$b = () => {
const annotations = {};
const register = (name, settings) => {
annotations[name] = {
name,
settings
};
};
const lookup = name => get$a(annotations, name).map(a => a.settings);
const getNames = () => keys(annotations);
return {
register,
lookup,
getNames
};
};
const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295;
let unique = 0;
const generate$1 = prefix => {
const date = new Date();
const time = date.getTime();
const random$1 = Math.floor(random() * 1000000000);
unique++;
return prefix + '_' + random$1 + unique + String(time);
};
const add = (element, classes) => {
each$e(classes, x => {
add$2(element, x);
});
};
const remove$3 = (element, classes) => {
each$e(classes, x => {
remove$6(element, x);
});
};
const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
const shallow$1 = original => clone$2(original, false);
const deep$1 = original => clone$2(original, true);
const shallowAs = (original, tag) => {
const nu = SugarElement.fromTag(tag);
const attributes = clone$4(original);
setAll$1(nu, attributes);
return nu;
};
const mutate = (original, tag) => {
const nu = shallowAs(original, tag);
after$4(original, nu);
const children = children$1(original);
append(nu, children);
remove$4(original);
return nu;
};
const TextWalker = (startNode, rootNode, isBoundary = never) => {
const walker = new DomTreeWalker(startNode, rootNode);
const walk = direction => {
let next;
do {
next = walker[direction]();
} while (next && !isText$b(next) && !isBoundary(next));
return Optional.from(next).filter(isText$b);
};
return {
current: () => Optional.from(walker.current()).filter(isText$b),
next: () => walk('next'),
prev: () => walk('prev'),
prev2: () => walk('prev2')
};
};
const TextSeeker = (dom, isBoundary) => {
const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node);
const walk = (node, offset, walker, process) => {
if (isText$b(node)) {
const newOffset = process(node, offset, node.data);
if (newOffset !== -1) {
return Optional.some({
container: node,
offset: newOffset
});
}
}
return walker().bind(next => walk(next.container, next.offset, walker, process));
};
const backwards = (node, offset, process, root) => {
const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
return walk(node, offset, () => walker.prev().map(prev => ({
container: prev,
offset: prev.length
})), process).getOrNull();
};
const forwards = (node, offset, process, root) => {
const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
return walk(node, offset, () => walker.next().map(next => ({
container: next,
offset: 0
})), process).getOrNull();
};
return {
backwards,
forwards
};
};
const NodeValue = (is, name) => {
const get = element => {
if (!is(element)) {
throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
}
return getOption(element).getOr('');
};
const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
const set = (element, value) => {
if (!is(element)) {
throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
}
element.dom.nodeValue = value;
};
return {
get,
getOption,
set
};
};
const api$1 = NodeValue(isText$c, 'text');
const get$3 = element => api$1.get(element);
const getOption = element => api$1.getOption(element);
const set = (element, value) => api$1.set(element, value);
const tableCells = [
'td',
'th'
];
const tableSections = [
'thead',
'tbody',
'tfoot'
];
const textBlocks = [
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'p',
'div',
'address',
'pre',
'form',
'blockquote',
'center',
'dir',
'fieldset',
'header',
'footer',
'article',
'section',
'hgroup',
'aside',
'nav',
'figure'
];
const listItems$1 = [
'li',
'dd',
'dt'
];
const lists = [
'ul',
'ol',
'dl'
];
const wsElements = [
'pre',
'script',
'textarea',
'style'
];
const lazyLookup = items => {
let lookup;
return node => {
lookup = lookup ? lookup : mapToObject(items, always);
return has$2(lookup, name(node));
};
};
const isTable$1 = node => name(node) === 'table';
const isBr$5 = node => isElement$7(node) && name(node) === 'br';
const isTextBlock$2 = lazyLookup(textBlocks);
const isList = lazyLookup(lists);
const isListItem$1 = lazyLookup(listItems$1);
const isTableSection = lazyLookup(tableSections);
const isTableCell$2 = lazyLookup(tableCells);
const isWsPreserveElement = lazyLookup(wsElements);
const getLastChildren$1 = elm => {
const children = [];
let rawNode = elm.dom;
while (rawNode) {
children.push(SugarElement.fromDom(rawNode));
rawNode = rawNode.lastChild;
}
return children;
};
const removeTrailingBr = elm => {
const allBrs = descendants(elm, 'br');
const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5);
if (allBrs.length === brs.length) {
each$e(brs, remove$4);
}
};
const createPaddingBr = () => {
const br = SugarElement.fromTag('br');
set$3(br, 'data-mce-bogus', '1');
return br;
};
const fillWithPaddingBr = elm => {
empty(elm);
append$1(elm, createPaddingBr());
};
const trimBlockTrailingBr = (elm, schema) => {
lastChild(elm).each(lastChild => {
prevSibling(lastChild).each(lastChildPrevSibling => {
if (schema.isBlock(name(elm)) && isBr$5(lastChild) && schema.isBlock(name(lastChildPrevSibling))) {
remove$4(lastChild);
}
});
});
};
const ZWSP$1 = zeroWidth;
const isZwsp = isZwsp$2;
const trim$2 = removeZwsp;
const insert$5 = editor => editor.insertContent(ZWSP$1, { preserve_zwsp: true });
const isElement$5 = isElement$6;
const isText$9 = isText$b;
const isCaretContainerBlock$1 = node => {
if (isText$9(node)) {
node = node.parentNode;
}
return isElement$5(node) && node.hasAttribute('data-mce-caret');
};
const isCaretContainerInline = node => isText$9(node) && isZwsp(node.data);
const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
const insertInline$1 = (node, before) => {
var _a;
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
const textNode = doc.createTextNode(ZWSP$1);
const parentNode = node.parentNode;
if (!before) {
const sibling = node.nextSibling;
if (isText$9(sibling)) {
if (isCaretContainer$2(sibling)) {
return sibling;
}
if (startsWithCaretContainer$1(sibling)) {
sibling.splitText(1);
return sibling;
}
}
if (node.nextSibling) {
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling);
} else {
parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode);
}
} else {
const sibling = node.previousSibling;
if (isText$9(sibling)) {
if (isCaretContainer$2(sibling)) {
return sibling;
}
if (endsWithCaretContainer$1(sibling)) {
return sibling.splitText(sibling.data.length - 1);
}
}
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node);
}
return textNode;
};
const isBeforeInline = pos => {
const container = pos.container();
if (!isText$b(container)) {
return false;
}
return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
};
const isAfterInline = pos => {
const container = pos.container();
if (!isText$b(container)) {
return false;
}
return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
};
const insertBlock = (blockName, node, before) => {
var _a;
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
const blockNode = doc.createElement(blockName);
blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
blockNode.setAttribute('data-mce-bogus', 'all');
blockNode.appendChild(createPaddingBr().dom);
const parentNode = node.parentNode;
if (!before) {
if (node.nextSibling) {
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling);
} else {
parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode);
}
} else {
parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node);
}
return blockNode;
};
const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1;
const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1;
const trimBogusBr = elm => {
var _a;
const brs = elm.getElementsByTagName('br');
const lastBr = brs[brs.length - 1];
if (isBogus$1(lastBr)) {
(_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr);
}
};
const showCaretContainerBlock = caretContainer => {
if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
trimBogusBr(caretContainer);
caretContainer.removeAttribute('data-mce-caret');
caretContainer.removeAttribute('data-mce-bogus');
caretContainer.removeAttribute('style');
caretContainer.removeAttribute('data-mce-style');
caretContainer.removeAttribute('_moz_abspos');
return caretContainer;
}
return null;
};
const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer);
const round$2 = Math.round;
const clone$1 = rect => {
if (!rect) {
return {
left: 0,
top: 0,
bottom: 0,
right: 0,
width: 0,
height: 0
};
}
return {
left: round$2(rect.left),
top: round$2(rect.top),
bottom: round$2(rect.bottom),
right: round$2(rect.right),
width: round$2(rect.width),
height: round$2(rect.height)
};
};
const collapse = (rect, toStart) => {
rect = clone$1(rect);
if (toStart) {
rect.right = rect.left;
} else {
rect.left = rect.left + rect.width;
rect.right = rect.left;
}
rect.width = 0;
return rect;
};
const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
const isAbove$1 = (rect1, rect2) => {
const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
if (rect1.bottom - halfHeight < rect2.top) {
return true;
}
if (rect1.top > rect2.bottom) {
return false;
}
return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
};
const isBelow$1 = (rect1, rect2) => {
if (rect1.top > rect2.bottom) {
return true;
}
if (rect1.bottom < rect2.top) {
return false;
}
return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
};
const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
const boundingClientRectFromRects = rects => {
return foldl(rects, (acc, rect) => {
return acc.fold(() => Optional.some(rect), prevRect => {
const left = Math.min(rect.left, prevRect.left);
const top = Math.min(rect.top, prevRect.top);
const right = Math.max(rect.right, prevRect.right);
const bottom = Math.max(rect.bottom, prevRect.bottom);
return Optional.some({
top,
right,
bottom,
left,
width: right - left,
height: bottom - top
});
});
}, Optional.none());
};
const distanceToRectEdgeFromXY = (rect, x, y) => {
const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
};
const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
const getSelectedNode = range => {
const startContainer = range.startContainer, startOffset = range.startOffset;
if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
return startContainer.childNodes[startOffset];
}
return null;
};
const getNode$1 = (container, offset) => {
if (isElement$6(container) && container.hasChildNodes()) {
const childNodes = container.childNodes;
const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
return childNodes[safeOffset];
} else {
return container;
}
};
const getNodeUnsafe = (container, offset) => {
if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
return undefined;
} else {
return getNode$1(container, offset);
}
};
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]');
const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
const or = (...args) => {
return x => {
for (let i = 0; i < args.length; i++) {
if (args[i](x)) {
return true;
}
}
return false;
};
};
const and = (...args) => {
return x => {
for (let i = 0; i < args.length; i++) {
if (!args[i](x)) {
return false;
}
}
return true;
};
};
const isContentEditableTrue$2 = isContentEditableTrue$3;
const isContentEditableFalse$a = isContentEditableFalse$b;
const isBr$4 = isBr$6;
const isText$8 = isText$b;
const isInvalidTextElement = matchNodeNames([
'script',
'style',
'textarea'
]);
const isAtomicInline = matchNodeNames([
'img',
'input',
'textarea',
'hr',
'iframe',
'video',
'audio',
'object',
'embed'
]);
const isTable = matchNodeNames(['table']);
const isCaretContainer$1 = isCaretContainer$2;
const isCaretCandidate$3 = node => {
if (isCaretContainer$1(node)) {
return false;
}
if (isText$8(node)) {
return !isInvalidTextElement(node.parentNode);
}
return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node);
};
const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true';
const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$a(node);
const isInEditable = (node, root) => {
for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
if (isNonUiContentEditableFalse(tempNode)) {
return false;
}
if (isContentEditableTrue$2(tempNode)) {
return true;
}
}
return true;
};
const isAtomicContentEditableFalse = node => {
if (!isNonUiContentEditableFalse(node)) {
return false;
}
return !foldl(from(node.getElementsByTagName('*')), (result, elm) => {
return result || isContentEditableTrue$2(elm);
}, false);
};
const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node);
const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
const isElement$4 = isElement$6;
const isCaretCandidate$2 = isCaretCandidate$3;
const isBlock$2 = matchStyleValues('display', 'block table');
const isFloated = matchStyleValues('float', 'left right');
const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap'));
const isText$7 = isText$b;
const isBr$3 = isBr$6;
const nodeIndex$1 = DOMUtils.nodeIndex;
const resolveIndex$1 = getNodeUnsafe;
const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng();
const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr);
const isRange = rng => !!rng.setStart && !!rng.setEnd;
const isHiddenWhiteSpaceRange = range => {
const container = range.startContainer;
const offset = range.startOffset;
if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$b(container)) {
const text = container.data;
if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) {
return true;
}
}
return false;
};
const getBrClientRect = brNode => {
const doc = brNode.ownerDocument;
const rng = createRange$1(doc);
const nbsp$1 = doc.createTextNode(nbsp);
const parentNode = brNode.parentNode;
parentNode.insertBefore(nbsp$1, brNode);
rng.setStart(nbsp$1, 0);
rng.setEnd(nbsp$1, 1);
const clientRect = clone$1(rng.getBoundingClientRect());
parentNode.removeChild(nbsp$1);
return clientRect;
};
const getBoundingClientRectWebKitText = rng => {
const sc = rng.startContainer;
const ec = rng.endContainer;
const so = rng.startOffset;
const eo = rng.endOffset;
if (sc === ec && isText$b(ec) && so === 0 && eo === 1) {
const newRng = rng.cloneRange();
newRng.setEndAfter(ec);
return getBoundingClientRect$1(newRng);
} else {
return null;
}
};
const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
const getBoundingClientRect$1 = item => {
var _a;
let clientRect;
const clientRects = item.getClientRects();
if (clientRects.length > 0) {
clientRect = clone$1(clientRects[0]);
} else {
clientRect = clone$1(item.getBoundingClientRect());
}
if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
return getBrClientRect(item);
}
if (isZeroRect(clientRect) && isRange(item)) {
return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect;
}
return clientRect;
};
const collapseAndInflateWidth = (clientRect, toStart) => {
const newClientRect = collapse(clientRect, toStart);
newClientRect.width = 1;
newClientRect.right = newClientRect.left + 1;
return newClientRect;
};
const getCaretPositionClientRects = caretPosition => {
const clientRects = [];
const addUniqueAndValidRect = clientRect => {
if (clientRect.height === 0) {
return;
}
if (clientRects.length > 0) {
if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
return;
}
}
clientRects.push(clientRect);
};
const addCharacterOffset = (container, offset) => {
const range = createRange$1(container.ownerDocument);
if (offset < container.data.length) {
if (isExtendingChar(container.data[offset])) {
return;
}
if (isExtendingChar(container.data[offset - 1])) {
range.setStart(container, offset);
range.setEnd(container, offset + 1);
if (!isHiddenWhiteSpaceRange(range)) {
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
return;
}
}
}
if (offset > 0) {
range.setStart(container, offset - 1);
range.setEnd(container, offset);
if (!isHiddenWhiteSpaceRange(range)) {
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
}
}
if (offset < container.data.length) {
range.setStart(container, offset);
range.setEnd(container, offset + 1);
if (!isHiddenWhiteSpaceRange(range)) {
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true));
}
}
};
const container = caretPosition.container();
const offset = caretPosition.offset();
if (isText$7(container)) {
addCharacterOffset(container, offset);
return clientRects;
}
if (isElement$4(container)) {
if (caretPosition.isAtEnd()) {
const node = resolveIndex$1(container, offset);
if (isText$7(node)) {
addCharacterOffset(node, node.data.length);
}
if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
}
} else {
const node = resolveIndex$1(container, offset);
if (isText$7(node)) {
addCharacterOffset(node, 0);
}
if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
return clientRects;
}
const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
if (isBlock$2(beforeNode) || isBlock$2(node) || !isValidElementCaretCandidate(node)) {
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
}
}
if (isValidElementCaretCandidate(node)) {
addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
}
}
}
return clientRects;
};
const CaretPosition = (container, offset, clientRects) => {
const isAtStart = () => {
if (isText$7(container)) {
return offset === 0;
}
return offset === 0;
};
const isAtEnd = () => {
if (isText$7(container)) {
return offset >= container.data.length;
}
return offset >= container.childNodes.length;
};
const toRange = () => {
const range = createRange$1(container.ownerDocument);
range.setStart(container, offset);
range.setEnd(container, offset);
return range;
};
const getClientRects = () => {
if (!clientRects) {
clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
}
return clientRects;
};
const isVisible = () => getClientRects().length > 0;
const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset);
return {
container: constant(container),
offset: constant(offset),
toRange,
getClientRects,
isVisible,
isAtStart,
isAtEnd,
isEqual,
getNode
};
};
CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset);
CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset);
CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node));
CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$2(pos1.getClientRects()), isAbove$1).getOr(false);
CaretPosition.isBelow = (pos1, pos2) => lift2(last$2(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false;
CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false;
CaretPosition.isTextPosition = pos => pos ? isText$b(pos.container()) : false;
CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos);
const trimEmptyTextNode$1 = (dom, node) => {
if (isText$b(node) && node.data.length === 0) {
dom.remove(node);
}
};
const insertNode = (dom, rng, node) => {
rng.insertNode(node);
trimEmptyTextNode$1(dom, node.previousSibling);
trimEmptyTextNode$1(dom, node.nextSibling);
};
const insertFragment = (dom, rng, frag) => {
const firstChild = Optional.from(frag.firstChild);
const lastChild = Optional.from(frag.lastChild);
rng.insertNode(frag);
firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling));
lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling));
};
const rangeInsertNode = (dom, rng, node) => {
if (isDocumentFragment(node)) {
insertFragment(dom, rng, node);
} else {
insertNode(dom, rng, node);
}
};
const isText$6 = isText$b;
const isBogus = isBogus$1;
const nodeIndex = DOMUtils.nodeIndex;
const normalizedParent = node => {
const parentNode = node.parentNode;
if (isBogus(parentNode)) {
return normalizedParent(parentNode);
}
return parentNode;
};
const getChildNodes = node => {
if (!node) {
return [];
}
return reduce(node.childNodes, (result, node) => {
if (isBogus(node) && node.nodeName !== 'BR') {
result = result.concat(getChildNodes(node));
} else {
result.push(node);
}
return result;
}, []);
};
const normalizedTextOffset = (node, offset) => {
let tempNode = node;
while (tempNode = tempNode.previousSibling) {
if (!isText$6(tempNode)) {
break;
}
offset += tempNode.data.length;
}
return offset;
};
const equal = a => b => a === b;
const normalizedNodeIndex = node => {
let nodes, index;
nodes = getChildNodes(normalizedParent(node));
index = findIndex$1(nodes, equal(node), node);
nodes = nodes.slice(0, index + 1);
const numTextFragments = reduce(nodes, (result, node, i) => {
if (isText$6(node) && isText$6(nodes[i - 1])) {
result++;
}
return result;
}, 0);
nodes = filter$3(nodes, matchNodeNames([node.nodeName]));
index = findIndex$1(nodes, equal(node), node);
return index - numTextFragments;
};
const createPathItem = node => {
const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase();
return name + '[' + normalizedNodeIndex(node) + ']';
};
const parentsUntil$1 = (root, node, predicate) => {
const parents = [];
for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
if (predicate && predicate(tempNode)) {
break;
}
parents.push(tempNode);
}
return parents;
};
const create$a = (root, caretPosition) => {
let path = [];
let container = caretPosition.container();
let offset = caretPosition.offset();
let outputOffset;
if (isText$6(container)) {
outputOffset = normalizedTextOffset(container, offset);
} else {
const childNodes = container.childNodes;
if (offset >= childNodes.length) {
outputOffset = 'after';
offset = childNodes.length - 1;
} else {
outputOffset = 'before';
}
container = childNodes[offset];
}
path.push(createPathItem(container));
let parents = parentsUntil$1(root, container);
parents = filter$3(parents, not(isBogus$1));
path = path.concat(map$1(parents, node => {
return createPathItem(node);
}));
return path.reverse().join('/') + ',' + outputOffset;
};
const resolvePathItem = (node, name, index) => {
let nodes = getChildNodes(node);
nodes = filter$3(nodes, (node, index) => {
return !isText$6(node) || !isText$6(nodes[index - 1]);
});
nodes = filter$3(nodes, matchNodeNames([name]));
return nodes[index];
};
const findTextPosition = (container, offset) => {
let node = container;
let targetOffset = 0;
while (isText$6(node)) {
const dataLen = node.data.length;
if (offset >= targetOffset && offset <= targetOffset + dataLen) {
container = node;
offset = offset - targetOffset;
break;
}
if (!isText$6(node.nextSibling)) {
container = node;
offset = dataLen;
break;
}
targetOffset += dataLen;
node = node.nextSibling;
}
if (isText$6(container) && offset > container.data.length) {
offset = container.data.length;
}
return CaretPosition(container, offset);
};
const resolve$1 = (root, path) => {
if (!path) {
return null;
}
const parts = path.split(',');
const paths = parts[0].split('/');
const offset = parts.length > 1 ? parts[1] : 'before';
const container = reduce(paths, (result, value) => {
const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
if (!match) {
return null;
}
if (match[1] === 'text()') {
match[1] = '#text';
}
return resolvePathItem(result, match[1], parseInt(match[2], 10));
}, root);
if (!container) {
return null;
}
if (!isText$6(container) && container.parentNode) {
let nodeOffset;
if (offset === 'after') {
nodeOffset = nodeIndex(container) + 1;
} else {
nodeOffset = nodeIndex(container);
}
return CaretPosition(container.parentNode, nodeOffset);
}
return findTextPosition(container, parseInt(offset, 10));
};
const isContentEditableFalse$9 = isContentEditableFalse$b;
const getNormalizedTextOffset$1 = (trim, container, offset) => {
let trimmedOffset = trim(container.data.slice(0, offset)).length;
for (let node = container.previousSibling; node && isText$b(node); node = node.previousSibling) {
trimmedOffset += trim(node.data).length;
}
return trimmedOffset;
};
const getPoint = (dom, trim, normalized, rng, start) => {
const container = start ? rng.startContainer : rng.endContainer;
let offset = start ? rng.startOffset : rng.endOffset;
const point = [];
const root = dom.getRoot();
if (isText$b(container)) {
point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset);
} else {
let after = 0;
const childNodes = container.childNodes;
if (offset >= childNodes.length && childNodes.length) {
after = 1;
offset = Math.max(0, childNodes.length - 1);
}
point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
}
for (let node = container; node && node !== root; node = node.parentNode) {
point.push(dom.nodeIndex(node, normalized));
}
return point;
};
const getLocation = (trim, selection, normalized, rng) => {
const dom = selection.dom;
const start = getPoint(dom, trim, normalized, rng, true);
const forward = selection.isForward();
const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
if (!selection.isCollapsed()) {
const end = getPoint(dom, trim, normalized, rng, false);
return {
start,
end,
forward,
...fakeCaret
};
} else {
return {
start,
forward,
...fakeCaret
};
}
};
const findIndex = (dom, name, element) => {
let count = 0;
Tools.each(dom.select(name), node => {
if (node.getAttribute('data-mce-bogus') === 'all') {
return;
} else if (node === element) {
return false;
} else {
count++;
return;
}
});
return count;
};
const moveEndPoint$1 = (rng, start) => {
let container = start ? rng.startContainer : rng.endContainer;
let offset = start ? rng.startOffset : rng.endOffset;
if (isElement$6(container) && container.nodeName === 'TR') {
const childNodes = container.childNodes;
container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
if (container) {
offset = start ? 0 : container.childNodes.length;
if (start) {
rng.setStart(container, offset);
} else {
rng.setEnd(container, offset);
}
}
}
};
const normalizeTableCellSelection = rng => {
moveEndPoint$1(rng, true);
moveEndPoint$1(rng, false);
return rng;
};
const findSibling = (node, offset) => {
if (isElement$6(node)) {
node = getNode$1(node, offset);
if (isContentEditableFalse$9(node)) {
return node;
}
}
if (isCaretContainer$2(node)) {
if (isText$b(node) && isCaretContainerBlock$1(node)) {
node = node.parentNode;
}
let sibling = node.previousSibling;
if (isContentEditableFalse$9(sibling)) {
return sibling;
}
sibling = node.nextSibling;
if (isContentEditableFalse$9(sibling)) {
return sibling;
}
}
return undefined;
};
const findAdjacentContentEditableFalseElm = rng => {
return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
};
const getOffsetBookmark = (trim, normalized, selection) => {
const element = selection.getNode();
const rng = selection.getRng();
if (element.nodeName === 'IMG' || isContentEditableFalse$9(element)) {
const name = element.nodeName;
return {
name,
index: findIndex(selection.dom, name, element)
};
}
const sibling = findAdjacentContentEditableFalseElm(rng);
if (sibling) {
const name = sibling.tagName;
return {
name,
index: findIndex(selection.dom, name, sibling)
};
}
return getLocation(trim, selection, normalized, rng);
};
const getCaretBookmark = selection => {
const rng = selection.getRng();
return {
start: create$a(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
end: create$a(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
forward: selection.isForward()
};
};
const getRangeBookmark = selection => {
return {
rng: selection.getRng(),
forward: selection.isForward()
};
};
const createBookmarkSpan = (dom, id, filled) => {
const args = {
'data-mce-type': 'bookmark',
id,
'style': 'overflow:hidden;line-height:0px'
};
return filled ? dom.create('span', args, '') : dom.create('span', args);
};
const getPersistentBookmark = (selection, filled) => {
const dom = selection.dom;
let rng = selection.getRng();
const id = dom.uniqueId();
const collapsed = selection.isCollapsed();
const element = selection.getNode();
const name = element.nodeName;
const forward = selection.isForward();
if (name === 'IMG') {
return {
name,
index: findIndex(dom, name, element)
};
}
const rng2 = normalizeTableCellSelection(rng.cloneRange());
if (!collapsed) {
rng2.collapse(false);
const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
rangeInsertNode(dom, rng2, endBookmarkNode);
}
rng = normalizeTableCellSelection(rng);
rng.collapse(true);
const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
rangeInsertNode(dom, rng, startBookmarkNode);
selection.moveToBookmark({
id,
keep: true,
forward
});
return {
id,
forward
};
};
const getBookmark$3 = (selection, type, normalized = false) => {
if (type === 2) {
return getOffsetBookmark(trim$2, normalized, selection);
} else if (type === 3) {
return getCaretBookmark(selection);
} else if (type) {
return getRangeBookmark(selection);
} else {
return getPersistentBookmark(selection, false);
}
};
const getUndoBookmark = curry(getOffsetBookmark, identity, true);
const value$1 = value => {
const applyHelper = fn => fn(value);
const constHelper = constant(value);
const outputHelper = () => output;
const output = {
tag: true,
inner: value,
fold: (_onError, onValue) => onValue(value),
isValue: always,
isError: never,
map: mapper => Result.value(mapper(value)),
mapError: outputHelper,
bind: applyHelper,
exists: applyHelper,
forall: applyHelper,
getOr: constHelper,
or: outputHelper,
getOrThunk: constHelper,
orThunk: outputHelper,
getOrDie: constHelper,
each: fn => {
fn(value);
},
toOptional: () => Optional.some(value)
};
return output;
};
const error = error => {
const outputHelper = () => output;
const output = {
tag: false,
inner: error,
fold: (onError, _onValue) => onError(error),
isValue: never,
isError: always,
map: outputHelper,
mapError: mapper => Result.error(mapper(error)),
bind: outputHelper,
exists: never,
forall: always,
getOr: identity,
or: identity,
getOrThunk: apply$1,
orThunk: apply$1,
getOrDie: die(String(error)),
each: noop,
toOptional: Optional.none
};
return output;
};
const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
const Result = {
value: value$1,
error,
fromOption
};
const generate = cases => {
if (!isArray$1(cases)) {
throw new Error('cases must be an array');
}
if (cases.length === 0) {
throw new Error('there must be at least one case');
}
const constructors = [];
const adt = {};
each$e(cases, (acase, count) => {
const keys$1 = keys(acase);
if (keys$1.length !== 1) {
throw new Error('one and only one name per case');
}
const key = keys$1[0];
const value = acase[key];
if (adt[key] !== undefined) {
throw new Error('duplicate key detected:' + key);
} else if (key === 'cata') {
throw new Error('cannot have a case named cata (sorry)');
} else if (!isArray$1(value)) {
throw new Error('case arguments must be an array');
}
constructors.push(key);
adt[key] = (...args) => {
const argLength = args.length;
if (argLength !== value.length) {
throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
}
const match = branches => {
const branchKeys = keys(branches);
if (constructors.length !== branchKeys.length) {
throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
}
const allReqd = forall(constructors, reqKey => {
return contains$2(branchKeys, reqKey);
});
if (!allReqd) {
throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
}
return branches[key].apply(null, args);
};
return {
fold: (...foldArgs) => {
if (foldArgs.length !== cases.length) {
throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
}
const target = foldArgs[count];
return target.apply(null, args);
},
match,
log: label => {
console.log(label, {
constructors,
constructor: key,
params: args
});
}
};
};
});
return adt;
};
const Adt = { generate };
Adt.generate([
{
bothErrors: [
'error1',
'error2'
]
},
{
firstError: [
'error1',
'value2'
]
},
{
secondError: [
'value1',
'error2'
]
},
{
bothValues: [
'value1',
'value2'
]
}
]);
const partition$1 = results => {
const errors = [];
const values = [];
each$e(results, result => {
result.fold(err => {
errors.push(err);
}, value => {
values.push(value);
});
});
return {
errors,
values
};
};
const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format';
const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format';
const hasBlockTrigger = (pattern, trigger) => (pattern.type === 'block-command' || pattern.type === 'block-format') && pattern.trigger === trigger;
const normalizePattern = pattern => {
var _a;
const err = message => Result.error({
message,
pattern
});
const formatOrCmd = (name, onFormat, onCommand) => {
if (pattern.format !== undefined) {
let formats;
if (isArray$1(pattern.format)) {
if (!forall(pattern.format, isString)) {
return err(name + ' pattern has non-string items in the `format` array');
}
formats = pattern.format;
} else if (isString(pattern.format)) {
formats = [pattern.format];
} else {
return err(name + ' pattern has non-string `format` parameter');
}
return Result.value(onFormat(formats));
} else if (pattern.cmd !== undefined) {
if (!isString(pattern.cmd)) {
return err(name + ' pattern has non-string `cmd` parameter');
}
return Result.value(onCommand(pattern.cmd, pattern.value));
} else {
return err(name + ' pattern is missing both `format` and `cmd` parameters');
}
};
if (!isObject(pattern)) {
return err('Raw pattern is not an object');
}
if (!isString(pattern.start)) {
return err('Raw pattern is missing `start` parameter');
}
if (pattern.end !== undefined) {
if (!isString(pattern.end)) {
return err('Inline pattern has non-string `end` parameter');
}
if (pattern.start.length === 0 && pattern.end.length === 0) {
return err('Inline pattern has empty `start` and `end` parameters');
}
let start = pattern.start;
let end = pattern.end;
if (end.length === 0) {
end = start;
start = '';
}
return formatOrCmd('Inline', format => ({
type: 'inline-format',
start,
end,
format
}), (cmd, value) => ({
type: 'inline-command',
start,
end,
cmd,
value
}));
} else if (pattern.replacement !== undefined) {
if (!isString(pattern.replacement)) {
return err('Replacement pattern has non-string `replacement` parameter');
}
if (pattern.start.length === 0) {
return err('Replacement pattern has empty `start` parameter');
}
return Result.value({
type: 'inline-command',
start: '',
end: pattern.start,
cmd: 'mceInsertContent',
value: pattern.replacement
});
} else {
const trigger = (_a = pattern.trigger) !== null && _a !== void 0 ? _a : 'space';
if (pattern.start.length === 0) {
return err('Block pattern has empty `start` parameter');
}
return formatOrCmd('Block', formats => ({
type: 'block-format',
start: pattern.start,
format: formats[0],
trigger
}), (command, commandValue) => ({
type: 'block-command',
start: pattern.start,
cmd: command,
value: commandValue,
trigger
}));
}
};
const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern);
const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern);
const createPatternSet = (patterns, dynamicPatternsLookup) => ({
inlinePatterns: getInlinePatterns(patterns),
blockPatterns: getBlockPatterns(patterns),
dynamicPatternsLookup
});
const filterByTrigger = (patterns, trigger) => {
return {
...patterns,
blockPatterns: filter$5(patterns.blockPatterns, pattern => hasBlockTrigger(pattern, trigger))
};
};
const fromRawPatterns = patterns => {
const normalized = partition$1(map$3(patterns, normalizePattern));
each$e(normalized.errors, err => console.error(err.message, err.pattern));
return normalized.values;
};
const fromRawPatternsLookup = lookupFn => {
return ctx => {
const rawPatterns = lookupFn(ctx);
return fromRawPatterns(rawPatterns);
};
};
const deviceDetection$1 = detect$1().deviceType;
const isTouch = deviceDetection$1.isTouch();
const DOM$a = DOMUtils.DOM;
const getHash = value => {
const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(',');
return foldl(items, (output, item) => {
const arr = item.split('=');
const key = arr[0];
const val = arr.length > 1 ? arr[1] : key;
output[trim$4(key)] = trim$4(val);
return output;
}, {});
};
const isRegExp = x => is$4(x, RegExp);
const option = name => editor => editor.options.get(name);
const stringOrObjectProcessor = value => isString(value) || isObject(value);
const bodyOptionProcessor = (editor, defaultValue = '') => value => {
const valid = isString(value);
if (valid) {
if (value.indexOf('=') !== -1) {
const bodyObj = getHash(value);
return {
value: get$a(bodyObj, editor.id).getOr(defaultValue),
valid
};
} else {
return {
value,
valid
};
}
} else {
return {
valid: false,
message: 'Must be a string.'
};
}
};
const register$7 = editor => {
const registerOption = editor.options.register;
registerOption('id', {
processor: 'string',
default: editor.id
});
registerOption('selector', { processor: 'string' });
registerOption('target', { processor: 'object' });
registerOption('suffix', { processor: 'string' });
registerOption('cache_suffix', { processor: 'string' });
registerOption('base_url', { processor: 'string' });
registerOption('referrer_policy', {
processor: 'string',
default: ''
});
registerOption('language_load', {
processor: 'boolean',
default: true
});
registerOption('inline', {
processor: 'boolean',
default: false
});
registerOption('iframe_attrs', {
processor: 'object',
default: {}
});
registerOption('doctype', {
processor: 'string',
default: ''
});
registerOption('document_base_url', {
processor: 'string',
default: editor.documentBaseUrl
});
registerOption('body_id', {
processor: bodyOptionProcessor(editor, 'tinymce'),
default: 'tinymce'
});
registerOption('body_class', {
processor: bodyOptionProcessor(editor),
default: ''
});
registerOption('content_security_policy', {
processor: 'string',
default: ''
});
registerOption('br_in_pre', {
processor: 'boolean',
default: true
});
registerOption('forced_root_block', {
processor: value => {
const valid = isString(value) && isNotEmpty(value);
if (valid) {
return {
value,
valid
};
} else {
return {
valid: false,
message: 'Must be a non-empty string.'
};
}
},
default: 'p'
});
registerOption('forced_root_block_attrs', {
processor: 'object',
default: {}
});
registerOption('newline_behavior', {
processor: value => {
const valid = contains$2([
'block',
'linebreak',
'invert',
'default'
], value);
return valid ? {
value,
valid
} : {
valid: false,
message: 'Must be one of: block, linebreak, invert or default.'
};
},
default: 'default'
});
registerOption('br_newline_selector', {
processor: 'string',
default: '.mce-toc h2,figcaption,caption'
});
registerOption('no_newline_selector', {
processor: 'string',
default: ''
});
registerOption('keep_styles', {
processor: 'boolean',
default: true
});
registerOption('end_container_on_empty_block', {
processor: value => {
if (isBoolean(value)) {
return {
valid: true,
value
};
} else if (isString(value)) {
return {
valid: true,
value
};
} else {
return {
valid: false,
message: 'Must be boolean or a string'
};
}
},
default: 'blockquote'
});
registerOption('font_size_style_values', {
processor: 'string',
default: 'xx-small,x-small,small,medium,large,x-large,xx-large'
});
registerOption('font_size_legacy_values', {
processor: 'string',
default: 'xx-small,small,medium,large,x-large,xx-large,300%'
});
registerOption('font_size_classes', {
processor: 'string',
default: ''
});
registerOption('automatic_uploads', {
processor: 'boolean',
default: true
});
registerOption('images_reuse_filename', {
processor: 'boolean',
default: false
});
registerOption('images_replace_blob_uris', {
processor: 'boolean',
default: true
});
registerOption('icons', {
processor: 'string',
default: ''
});
registerOption('icons_url', {
processor: 'string',
default: ''
});
registerOption('images_upload_url', {
processor: 'string',
default: ''
});
registerOption('images_upload_base_path', {
processor: 'string',
default: ''
});
registerOption('images_upload_credentials', {
processor: 'boolean',
default: false
});
registerOption('images_upload_handler', { processor: 'function' });
registerOption('language', {
processor: 'string',
default: 'en'
});
registerOption('language_url', {
processor: 'string',
default: ''
});
registerOption('entity_encoding', {
processor: 'string',
default: 'named'
});
registerOption('indent', {
processor: 'boolean',
default: true
});
registerOption('indent_before', {
processor: 'string',
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'
});
registerOption('indent_after', {
processor: 'string',
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'
});
registerOption('indent_use_margin', {
processor: 'boolean',
default: false
});
registerOption('indentation', {
processor: 'string',
default: '40px'
});
registerOption('content_css', {
processor: value => {
const valid = value === false || isString(value) || isArrayOf(value, isString);
if (valid) {
if (isString(value)) {
return {
value: map$3(value.split(','), trim$4),
valid
};
} else if (isArray$1(value)) {
return {
value,
valid
};
} else if (value === false) {
return {
value: [],
valid
};
} else {
return {
value,
valid
};
}
} else {
return {
valid: false,
message: 'Must be false, a string or an array of strings.'
};
}
},
default: isInline$1(editor) ? [] : ['default']
});
registerOption('content_style', { processor: 'string' });
registerOption('content_css_cors', {
processor: 'boolean',
default: false
});
registerOption('font_css', {
processor: value => {
const valid = isString(value) || isArrayOf(value, isString);
if (valid) {
const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$4);
return {
value: newValue,
valid
};
} else {
return {
valid: false,
message: 'Must be a string or an array of strings.'
};
}
},
default: []
});
registerOption('inline_boundaries', {
processor: 'boolean',
default: true
});
registerOption('inline_boundaries_selector', {
processor: 'string',
default: 'a[href],code,span.mce-annotation'
});
registerOption('object_resizing', {
processor: value => {
const valid = isBoolean(value) || isString(value);
if (valid) {
if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
return {
value: '',
valid
};
} else {
return {
value: value === true ? 'table,img,figure.image,div,video,iframe' : value,
valid
};
}
} else {
return {
valid: false,
message: 'Must be boolean or a string'
};
}
},
default: !isTouch
});
registerOption('resize_img_proportional', {
processor: 'boolean',
default: true
});
registerOption('event_root', { processor: 'string' });
registerOption('service_message', { processor: 'string' });
registerOption('theme', {
processor: value => value === false || isString(value) || isFunction(value),
default: 'silver'
});
registerOption('theme_url', { processor: 'string' });
registerOption('formats', { processor: 'object' });
registerOption('format_empty_lines', {
processor: 'boolean',
default: false
});
registerOption('format_noneditable_selector', {
processor: 'string',
default: ''
});
registerOption('preview_styles', {
processor: value => {
const valid = value === false || isString(value);
if (valid) {
return {
value: value === false ? '' : value,
valid
};
} else {
return {
valid: false,
message: 'Must be false or a string'
};
}
},
default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow'
});
registerOption('custom_ui_selector', {
processor: 'string',
default: ''
});
registerOption('hidden_input', {
processor: 'boolean',
default: true
});
registerOption('submit_patch', {
processor: 'boolean',
default: true
});
registerOption('encoding', { processor: 'string' });
registerOption('add_form_submit_trigger', {
processor: 'boolean',
default: true
});
registerOption('add_unload_trigger', {
processor: 'boolean',
default: true
});
registerOption('custom_undo_redo_levels', {
processor: 'number',
default: 0
});
registerOption('disable_nodechange', {
processor: 'boolean',
default: false
});
registerOption('readonly', {
processor: 'boolean',
default: false
});
registerOption('editable_root', {
processor: 'boolean',
default: true
});
registerOption('plugins', {
processor: 'string[]',
default: []
});
registerOption('external_plugins', { processor: 'object' });
registerOption('forced_plugins', { processor: 'string[]' });
registerOption('model', {
processor: 'string',
default: editor.hasPlugin('rtc') ? 'plugin' : 'dom'
});
registerOption('model_url', { processor: 'string' });
registerOption('block_unsupported_drop', {
processor: 'boolean',
default: true
});
registerOption('visual', {
processor: 'boolean',
default: true
});
registerOption('visual_table_class', {
processor: 'string',
default: 'mce-item-table'
});
registerOption('visual_anchor_class', {
processor: 'string',
default: 'mce-item-anchor'
});
registerOption('iframe_aria_text', {
processor: 'string',
default: 'Rich Text Area. Press ALT-0 for help.'
});
registerOption('setup', { processor: 'function' });
registerOption('init_instance_callback', { processor: 'function' });
registerOption('url_converter', {
processor: 'function',
default: editor.convertURL
});
registerOption('url_converter_scope', {
processor: 'object',
default: editor
});
registerOption('urlconverter_callback', { processor: 'function' });
registerOption('allow_conditional_comments', {
processor: 'boolean',
default: false
});
registerOption('allow_html_data_urls', {
processor: 'boolean',
default: false
});
registerOption('allow_svg_data_urls', { processor: 'boolean' });
registerOption('allow_html_in_named_anchor', {
processor: 'boolean',
default: false
});
registerOption('allow_script_urls', {
processor: 'boolean',
default: false
});
registerOption('allow_unsafe_link_target', {
processor: 'boolean',
default: false
});
registerOption('convert_fonts_to_spans', {
processor: 'boolean',
default: true,
deprecated: true
});
registerOption('fix_list_elements', {
processor: 'boolean',
default: false
});
registerOption('preserve_cdata', {
processor: 'boolean',
default: false
});
registerOption('remove_trailing_brs', {
processor: 'boolean',
default: true
});
registerOption('pad_empty_with_br', {
processor: 'boolean',
default: false
});
registerOption('inline_styles', {
processor: 'boolean',
default: true,
deprecated: true
});
registerOption('element_format', {
processor: 'string',
default: 'html'
});
registerOption('entities', { processor: 'string' });
registerOption('schema', {
processor: 'string',
default: 'html5'
});
registerOption('convert_urls', {
processor: 'boolean',
default: true
});
registerOption('relative_urls', {
processor: 'boolean',
default: true
});
registerOption('remove_script_host', {
processor: 'boolean',
default: true
});
registerOption('custom_elements', { processor: stringOrObjectProcessor });
registerOption('extended_valid_elements', { processor: 'string' });
registerOption('invalid_elements', { processor: 'string' });
registerOption('invalid_styles', { processor: stringOrObjectProcessor });
registerOption('valid_children', { processor: 'string' });
registerOption('valid_classes', { processor: stringOrObjectProcessor });
registerOption('valid_elements', { processor: 'string' });
registerOption('valid_styles', { processor: stringOrObjectProcessor });
registerOption('verify_html', {
processor: 'boolean',
default: true
});
registerOption('auto_focus', { processor: value => isString(value) || value === true });
registerOption('browser_spellcheck', {
processor: 'boolean',
default: false
});
registerOption('protect', { processor: 'array' });
registerOption('images_file_types', {
processor: 'string',
default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'
});
registerOption('deprecation_warnings', {
processor: 'boolean',
default: true
});
registerOption('a11y_advanced_options', {
processor: 'boolean',
default: false
});
registerOption('api_key', { processor: 'string' });
registerOption('license_key', { processor: 'string' });
registerOption('paste_block_drop', {
processor: 'boolean',
default: false
});
registerOption('paste_data_images', {
processor: 'boolean',
default: true
});
registerOption('paste_preprocess', { processor: 'function' });
registerOption('paste_postprocess', { processor: 'function' });
registerOption('paste_webkit_styles', {
processor: 'string',
default: 'none'
});
registerOption('paste_remove_styles_if_webkit', {
processor: 'boolean',
default: true
});
registerOption('paste_merge_formats', {
processor: 'boolean',
default: true
});
registerOption('smart_paste', {
processor: 'boolean',
default: true
});
registerOption('paste_as_text', {
processor: 'boolean',
default: false
});
registerOption('paste_tab_spaces', {
processor: 'number',
default: 4
});
registerOption('text_patterns', {
processor: value => {
if (isArrayOf(value, isObject) || value === false) {
const patterns = value === false ? [] : value;
return {
value: fromRawPatterns(patterns),
valid: true
};
} else {
return {
valid: false,
message: 'Must be an array of objects or false.'
};
}
},
default: [
{
start: '*',
end: '*',
format: 'italic'
},
{
start: '**',
end: '**',
format: 'bold'
},
{
start: '#',
format: 'h1',
trigger: 'space'
},
{
start: '##',
format: 'h2',
trigger: 'space'
},
{
start: '###',
format: 'h3',
trigger: 'space'
},
{
start: '####',
format: 'h4',
trigger: 'space'
},
{
start: '#####',
format: 'h5',
trigger: 'space'
},
{
start: '######',
format: 'h6',
trigger: 'space'
},
{
start: '1.',
cmd: 'InsertOrderedList',
trigger: 'space'
},
{
start: '*',
cmd: 'InsertUnorderedList',
trigger: 'space'
},
{
start: '-',
cmd: 'InsertUnorderedList',
trigger: 'space'
},
{
start: '>',
cmd: 'mceBlockQuote',
trigger: 'space'
},
{
start: '---',
cmd: 'InsertHorizontalRule',
trigger: 'space'
}
]
});
registerOption('text_patterns_lookup', {
processor: value => {
if (isFunction(value)) {
return {
value: fromRawPatternsLookup(value),
valid: true
};
} else {
return {
valid: false,
message: 'Must be a single function'
};
}
},
default: _ctx => []
});
registerOption('noneditable_class', {
processor: 'string',
default: 'mceNonEditable'
});
registerOption('editable_class', {
processor: 'string',
default: 'mceEditable'
});
registerOption('noneditable_regexp', {
processor: value => {
if (isArrayOf(value, isRegExp)) {
return {
value,
valid: true
};
} else if (isRegExp(value)) {
return {
value: [value],
valid: true
};
} else {
return {
valid: false,
message: 'Must be a RegExp or an array of RegExp.'
};
}
},
default: []
});
registerOption('table_tab_navigation', {
processor: 'boolean',
default: true
});
registerOption('highlight_on_focus', {
processor: 'boolean',
default: true
});
registerOption('xss_sanitization', {
processor: 'boolean',
default: true
});
registerOption('details_initial_state', {
processor: value => {
const valid = contains$2([
'inherited',
'collapsed',
'expanded'
], value);
return valid ? {
value,
valid
} : {
valid: false,
message: 'Must be one of: inherited, collapsed, or expanded.'
};
},
default: 'inherited'
});
registerOption('details_serialized_state', {
processor: value => {
const valid = contains$2([
'inherited',
'collapsed',
'expanded'
], value);
return valid ? {
value,
valid
} : {
valid: false,
message: 'Must be one of: inherited, collapsed, or expanded.'
};
},
default: 'inherited'
});
registerOption('init_content_sync', {
processor: 'boolean',
default: false
});
registerOption('newdocument_content', {
processor: 'string',
default: ''
});
registerOption('sandbox_iframes', {
processor: 'boolean',
default: true
});
registerOption('sandbox_iframes_exclusions', {
processor: 'string[]',
default: [
'youtube.com',
'youtu.be',
'vimeo.com',
'player.vimeo.com',
'dailymotion.com',
'embed.music.apple.com',
'open.spotify.com',
'giphy.com',
'dai.ly',
'codepen.io'
]
});
registerOption('convert_unsafe_embeds', {
processor: 'boolean',
default: true
});
editor.on('ScriptsLoaded', () => {
registerOption('directionality', {
processor: 'string',
default: I18n.isRtl() ? 'rtl' : undefined
});
registerOption('placeholder', {
processor: 'string',
default: DOM$a.getAttrib(editor.getElement(), 'placeholder')
});
});
};
const getIframeAttrs = option('iframe_attrs');
const getDocType = option('doctype');
const getDocumentBaseUrl = option('document_base_url');
const getBodyId = option('body_id');
const getBodyClass = option('body_class');
const getContentSecurityPolicy = option('content_security_policy');
const shouldPutBrInPre$1 = option('br_in_pre');
const getForcedRootBlock = option('forced_root_block');
const getForcedRootBlockAttrs = option('forced_root_block_attrs');
const getNewlineBehavior = option('newline_behavior');
const getBrNewLineSelector = option('br_newline_selector');
const getNoNewLineSelector = option('no_newline_selector');
const shouldKeepStyles = option('keep_styles');
const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
const isAutomaticUploadsEnabled = option('automatic_uploads');
const shouldReuseFileName = option('images_reuse_filename');
const shouldReplaceBlobUris = option('images_replace_blob_uris');
const getIconPackName = option('icons');
const getIconsUrl = option('icons_url');
const getImageUploadUrl = option('images_upload_url');
const getImageUploadBasePath = option('images_upload_base_path');
const getImagesUploadCredentials = option('images_upload_credentials');
const getImagesUploadHandler = option('images_upload_handler');
const shouldUseContentCssCors = option('content_css_cors');
const getReferrerPolicy = option('referrer_policy');
const getLanguageCode = option('language');
const getLanguageUrl = option('language_url');
const shouldIndentUseMargin = option('indent_use_margin');
const getIndentation = option('indentation');
const getContentCss = option('content_css');
const getContentStyle = option('content_style');
const getFontCss = option('font_css');
const getDirectionality = option('directionality');
const getInlineBoundarySelector = option('inline_boundaries_selector');
const getObjectResizing = option('object_resizing');
const getResizeImgProportional = option('resize_img_proportional');
const getPlaceholder = option('placeholder');
const getEventRoot = option('event_root');
const getServiceMessage = option('service_message');
const getTheme = option('theme');
const getThemeUrl = option('theme_url');
const getModel = option('model');
const getModelUrl = option('model_url');
const isInlineBoundariesEnabled = option('inline_boundaries');
const getFormats = option('formats');
const getPreviewStyles = option('preview_styles');
const canFormatEmptyLines = option('format_empty_lines');
const getFormatNoneditableSelector = option('format_noneditable_selector');
const getCustomUiSelector = option('custom_ui_selector');
const isInline$1 = option('inline');
const hasHiddenInput = option('hidden_input');
const shouldPatchSubmit = option('submit_patch');
const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
const shouldAddUnloadTrigger = option('add_unload_trigger');
const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
const shouldDisableNodeChange = option('disable_nodechange');
const isReadOnly$1 = option('readonly');
const hasEditableRoot$1 = option('editable_root');
const hasContentCssCors = option('content_css_cors');
const getPlugins = option('plugins');
const getExternalPlugins$1 = option('external_plugins');
const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
const isVisualAidsEnabled = option('visual');
const getVisualAidsTableClass = option('visual_table_class');
const getVisualAidsAnchorClass = option('visual_anchor_class');
const getIframeAriaText = option('iframe_aria_text');
const getSetupCallback = option('setup');
const getInitInstanceCallback = option('init_instance_callback');
const getUrlConverterCallback = option('urlconverter_callback');
const getAutoFocus = option('auto_focus');
const shouldBrowserSpellcheck = option('browser_spellcheck');
const getProtect = option('protect');
const shouldPasteBlockDrop = option('paste_block_drop');
const shouldPasteDataImages = option('paste_data_images');
const getPastePreProcess = option('paste_preprocess');
const getPastePostProcess = option('paste_postprocess');
const getNewDocumentContent = option('newdocument_content');
const getPasteWebkitStyles = option('paste_webkit_styles');
const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
const shouldPasteMergeFormats = option('paste_merge_formats');
const isSmartPasteEnabled = option('smart_paste');
const isPasteAsTextEnabled = option('paste_as_text');
const getPasteTabSpaces = option('paste_tab_spaces');
const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
const getTextPatterns = option('text_patterns');
const getTextPatternsLookup = option('text_patterns_lookup');
const getNonEditableClass = option('noneditable_class');
const getEditableClass = option('editable_class');
const getNonEditableRegExps = option('noneditable_regexp');
const shouldPreserveCData = option('preserve_cdata');
const shouldHighlightOnFocus = option('highlight_on_focus');
const shouldSanitizeXss = option('xss_sanitization');
const shouldUseDocumentWrite = option('init_content_sync');
const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup');
const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values'));
const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes'));
const isEncodingXml = editor => editor.options.get('encoding') === 'xml';
const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types'));
const hasTableTabNavigation = option('table_tab_navigation');
const getDetailsInitialState = option('details_initial_state');
const getDetailsSerializedState = option('details_serialized_state');
const shouldSandboxIframes = option('sandbox_iframes');
const getSandboxIframesExclusions = editor => editor.options.get('sandbox_iframes_exclusions');
const shouldConvertUnsafeEmbeds = option('convert_unsafe_embeds');
const getLicenseKey = option('license_key');
const getApiKey = option('api_key');
const isElement$3 = isElement$6;
const isText$5 = isText$b;
const removeNode$1 = node => {
const parentNode = node.parentNode;
if (parentNode) {
parentNode.removeChild(node);
}
};
const trimCount = text => {
const trimmedText = trim$2(text);
return {
count: text.length - trimmedText.length,
text: trimmedText
};
};
const deleteZwspChars = caretContainer => {
let idx;
while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
caretContainer.deleteData(idx, 1);
}
};
const removeUnchanged = (caretContainer, pos) => {
remove$2(caretContainer);
return pos;
};
const removeTextAndReposition = (caretContainer, pos) => {
const before = trimCount(caretContainer.data.substr(0, pos.offset()));
const after = trimCount(caretContainer.data.substr(pos.offset()));
const text = before.text + after.text;
if (text.length > 0) {
deleteZwspChars(caretContainer);
return CaretPosition(caretContainer, pos.offset() - before.count);
} else {
return pos;
}
};
const removeElementAndReposition = (caretContainer, pos) => {
const parentNode = pos.container();
const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => {
return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
}).getOr(pos);
remove$2(caretContainer);
return newPosition;
};
const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
const remove$2 = caretContainerNode => {
if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
if (hasContent(caretContainerNode)) {
caretContainerNode.removeAttribute('data-mce-caret');
} else {
removeNode$1(caretContainerNode);
}
}
if (isText$5(caretContainerNode)) {
deleteZwspChars(caretContainerNode);
if (caretContainerNode.data.length === 0) {
removeNode$1(caretContainerNode);
}
}
};
const isContentEditableFalse$8 = isContentEditableFalse$b;
const isMedia$1 = isMedia$2;
const isTableCell$1 = isTableCell$3;
const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object';
const getAbsoluteClientRect = (root, element, before) => {
const clientRect = collapse(element.getBoundingClientRect(), before);
let scrollX;
let scrollY;
if (root.tagName === 'BODY') {
const docElm = root.ownerDocument.documentElement;
scrollX = root.scrollLeft || docElm.scrollLeft;
scrollY = root.scrollTop || docElm.scrollTop;
} else {
const rootRect = root.getBoundingClientRect();
scrollX = root.scrollLeft - rootRect.left;
scrollY = root.scrollTop - rootRect.top;
}
clientRect.left += scrollX;
clientRect.right += scrollX;
clientRect.top += scrollY;
clientRect.bottom += scrollY;
clientRect.width = 1;
let margin = element.offsetWidth - element.clientWidth;
if (margin > 0) {
if (before) {
margin *= -1;
}
clientRect.left += margin;
clientRect.right += margin;
}
return clientRect;
};
const trimInlineCaretContainers = root => {
var _a, _b;
const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
const node = fakeCaretTargetNodes[i].dom;
let sibling = node.previousSibling;
if (endsWithCaretContainer$1(sibling)) {
const data = sibling.data;
if (data.length === 1) {
(_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling);
} else {
sibling.deleteData(data.length - 1, 1);
}
}
sibling = node.nextSibling;
if (startsWithCaretContainer$1(sibling)) {
const data = sibling.data;
if (data.length === 1) {
(_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling);
} else {
sibling.deleteData(0, 1);
}
}
}
};
const FakeCaret = (editor, root, isBlock, hasFocus) => {
const lastVisualCaret = value$2();
let cursorInterval;
let caretContainerNode;
const caretBlock = getForcedRootBlock(editor);
const dom = editor.dom;
const show = (before, element) => {
let rng;
hide();
if (isTableCell$1(element)) {
return null;
}
if (isBlock(element)) {
const caretContainer = insertBlock(caretBlock, element, before);
const clientRect = getAbsoluteClientRect(root, element, before);
dom.setStyle(caretContainer, 'top', clientRect.top);
dom.setStyle(caretContainer, 'caret-color', 'transparent');
caretContainerNode = caretContainer;
const caret = dom.create('div', {
'class': 'mce-visual-caret',
'data-mce-bogus': 'all'
});
dom.setStyles(caret, { ...clientRect });
dom.add(root, caret);
lastVisualCaret.set({
caret,
element,
before
});
if (before) {
dom.addClass(caret, 'mce-visual-caret-before');
}
startBlink();
rng = element.ownerDocument.createRange();
rng.setStart(caretContainer, 0);
rng.setEnd(caretContainer, 0);
} else {
caretContainerNode = insertInline$1(element, before);
rng = element.ownerDocument.createRange();
if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
rng.setStart(caretContainerNode, 0);
rng.setEnd(caretContainerNode, 0);
} else {
rng.setStart(caretContainerNode, 1);
rng.setEnd(caretContainerNode, 1);
}
return rng;
}
return rng;
};
const hide = () => {
trimInlineCaretContainers(root);
if (caretContainerNode) {
remove$2(caretContainerNode);
caretContainerNode = null;
}
lastVisualCaret.on(caretState => {
dom.remove(caretState.caret);
lastVisualCaret.clear();
});
if (cursorInterval) {
clearInterval(cursorInterval);
cursorInterval = undefined;
}
};
const startBlink = () => {
cursorInterval = setInterval(() => {
lastVisualCaret.on(caretState => {
if (hasFocus()) {
dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden');
} else {
dom.addClass(caretState.caret, 'mce-visual-caret-hidden');
}
});
}, 500);
};
const reposition = () => {
lastVisualCaret.on(caretState => {
const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
dom.setStyles(caretState.caret, { ...clientRect });
});
};
const destroy = () => clearInterval(cursorInterval);
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;' + '}';
return {
show,
hide,
getCss,
reposition,
destroy
};
};
const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
const isInlineFakeCaretTarget = node => isContentEditableFalse$8(node) || isMedia$1(node);
const isFakeCaretTarget = node => {
const isTarget = isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser();
return isTarget && parentElement(SugarElement.fromDom(node)).exists(isEditable$2);
};
const isContentEditableTrue$1 = isContentEditableTrue$3;
const isContentEditableFalse$7 = isContentEditableFalse$b;
const isMedia = isMedia$2;
const isBlockLike = matchStyleValues('display', 'block table table-cell table-caption list-item');
const isCaretContainer = isCaretContainer$2;
const isCaretContainerBlock = isCaretContainerBlock$1;
const isElement$2 = isElement$6;
const isText$4 = isText$b;
const isCaretCandidate$1 = isCaretCandidate$3;
const isForwards = direction => direction > 0;
const isBackwards = direction => direction < 0;
const skipCaretContainers = (walk, shallow) => {
let node;
while (node = walk(shallow)) {
if (!isCaretContainerBlock(node)) {
return node;
}
}
return null;
};
const findNode = (node, direction, predicateFn, rootNode, shallow) => {
const walker = new DomTreeWalker(node, rootNode);
const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node);
let tempNode;
if (isBackwards(direction)) {
if (isCefOrCaretContainer) {
tempNode = skipCaretContainers(walker.prev.bind(walker), true);
if (predicateFn(tempNode)) {
return tempNode;
}
}
while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) {
if (predicateFn(tempNode)) {
return tempNode;
}
}
}
if (isForwards(direction)) {
if (isCefOrCaretContainer) {
tempNode = skipCaretContainers(walker.next.bind(walker), true);
if (predicateFn(tempNode)) {
return tempNode;
}
}
while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) {
if (predicateFn(tempNode)) {
return tempNode;
}
}
}
return null;
};
const getEditingHost = (node, rootNode) => {
const isCETrue = node => isContentEditableTrue$1(node.dom);
const isRoot = node => node.dom === rootNode;
return ancestor$4(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode);
};
const getParentBlock$3 = (node, rootNode) => {
while (node && node !== rootNode) {
if (isBlockLike(node)) {
return node;
}
node = node.parentNode;
}
return null;
};
const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
if (!caretPosition) {
return Optional.none();
}
const container = caretPosition.container();
const offset = caretPosition.offset();
if (!isElement$2(container)) {
return Optional.none();
}
return Optional.from(container.childNodes[offset + relativeOffset]);
};
const beforeAfter = (before, node) => {
var _a;
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
const range = doc.createRange();
if (before) {
range.setStartBefore(node);
range.setEndBefore(node);
} else {
range.setStartAfter(node);
range.setEndAfter(node);
}
return range;
};
const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
const lean = (left, root, node) => {
const siblingName = left ? 'previousSibling' : 'nextSibling';
let tempNode = node;
while (tempNode && tempNode !== root) {
let sibling = tempNode[siblingName];
if (sibling && isCaretContainer(sibling)) {
sibling = sibling[siblingName];
}
if (isContentEditableFalse$7(sibling) || isMedia(sibling)) {
if (isNodesInSameBlock(root, sibling, tempNode)) {
return sibling;
}
break;
}
if (isCaretCandidate$1(sibling)) {
break;
}
tempNode = tempNode.parentNode;
}
return null;
};
const before$2 = curry(beforeAfter, true);
const after$2 = curry(beforeAfter, false);
const normalizeRange = (direction, root, range) => {
let node;
const leanLeft = curry(lean, true, root);
const leanRight = curry(lean, false, root);
const container = range.startContainer;
const offset = range.startOffset;
if (isCaretContainerBlock$1(container)) {
const block = isText$4(container) ? container.parentNode : container;
const location = block.getAttribute('data-mce-caret');
if (location === 'before') {
node = block.nextSibling;
if (isFakeCaretTarget(node)) {
return before$2(node);
}
}
if (location === 'after') {
node = block.previousSibling;
if (isFakeCaretTarget(node)) {
return after$2(node);
}
}
}
if (!range.collapsed) {
return range;
}
if (isText$b(container)) {
if (isCaretContainer(container)) {
if (direction === 1) {
node = leanRight(container);
if (node) {
return before$2(node);
}
node = leanLeft(container);
if (node) {
return after$2(node);
}
}
if (direction === -1) {
node = leanLeft(container);
if (node) {
return after$2(node);
}
node = leanRight(container);
if (node) {
return before$2(node);
}
}
return range;
}
if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
if (direction === 1) {
node = leanRight(container);
if (node) {
return before$2(node);
}
}
return range;
}
if (startsWithCaretContainer$1(container) && offset <= 1) {
if (direction === -1) {
node = leanLeft(container);
if (node) {
return after$2(node);
}
}
return range;
}
if (offset === container.data.length) {
node = leanRight(container);
if (node) {
return before$2(node);
}
return range;
}
if (offset === 0) {
node = leanLeft(container);
if (node) {
return after$2(node);
}
return range;
}
}
return range;
};
const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$7);
const getNormalizedRangeEndPoint = (direction, root, range) => {
const normalizedRange = normalizeRange(direction, root, range);
return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange);
};
const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom);
const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
const getVisualCaretPosition = (walkFn, caretPosition) => {
let pos = caretPosition;
while (pos = walkFn(pos)) {
if (pos.isVisible()) {
return pos;
}
}
return pos;
};
const isMoveInsideSameBlock = (from, to) => {
const inSameBlock = isInSameBlock(from, to);
if (!inSameBlock && isBr$6(from.getNode())) {
return true;
}
return inSameBlock;
};
var HDirection;
(function (HDirection) {
HDirection[HDirection['Backwards'] = -1] = 'Backwards';
HDirection[HDirection['Forwards'] = 1] = 'Forwards';
}(HDirection || (HDirection = {})));
const isContentEditableFalse$6 = isContentEditableFalse$b;
const isText$3 = isText$b;
const isElement$1 = isElement$6;
const isBr$2 = isBr$6;
const isCaretCandidate = isCaretCandidate$3;
const isAtomic = isAtomic$1;
const isEditableCaretCandidate = isEditableCaretCandidate$1;
const getParents$3 = (node, root) => {
const parents = [];
let tempNode = node;
while (tempNode && tempNode !== root) {
parents.push(tempNode);
tempNode = tempNode.parentNode;
}
return parents;
};
const nodeAtIndex = (container, offset) => {
if (container.hasChildNodes() && offset < container.childNodes.length) {
return container.childNodes[offset];
}
return null;
};
const getCaretCandidatePosition = (direction, node) => {
if (isForwards(direction)) {
if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
return CaretPosition.before(node);
}
if (isText$3(node)) {
return CaretPosition(node, 0);
}
}
if (isBackwards(direction)) {
if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
return CaretPosition.after(node);
}
if (isText$3(node)) {
return CaretPosition(node, node.data.length);
}
}
if (isBackwards(direction)) {
if (isBr$2(node)) {
return CaretPosition.before(node);
}
return CaretPosition.after(node);
}
return CaretPosition.before(node);
};
const moveForwardFromBr = (root, nextNode) => {
const nextSibling = nextNode.nextSibling;
if (nextSibling && isCaretCandidate(nextSibling)) {
if (isText$3(nextSibling)) {
return CaretPosition(nextSibling, 0);
} else {
return CaretPosition.before(nextSibling);
}
} else {
return findCaretPosition$1(HDirection.Forwards, CaretPosition.after(nextNode), root);
}
};
const findCaretPosition$1 = (direction, startPos, root) => {
let node;
let nextNode;
let innerNode;
let caretPosition;
if (!isElement$1(root) || !startPos) {
return null;
}
if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
caretPosition = CaretPosition.after(root.lastChild);
if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
}
} else {
caretPosition = startPos;
}
const container = caretPosition.container();
let offset = caretPosition.offset();
if (isText$3(container)) {
if (isBackwards(direction) && offset > 0) {
return CaretPosition(container, --offset);
}
if (isForwards(direction) && offset < container.length) {
return CaretPosition(container, ++offset);
}
node = container;
} else {
if (isBackwards(direction) && offset > 0) {
nextNode = nodeAtIndex(container, offset - 1);
if (isCaretCandidate(nextNode)) {
if (!isAtomic(nextNode)) {
innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
if (innerNode) {
if (isText$3(innerNode)) {
return CaretPosition(innerNode, innerNode.data.length);
}
return CaretPosition.after(innerNode);
}
}
if (isText$3(nextNode)) {
return CaretPosition(nextNode, nextNode.data.length);
}
return CaretPosition.before(nextNode);
}
}
if (isForwards(direction) && offset < container.childNodes.length) {
nextNode = nodeAtIndex(container, offset);
if (isCaretCandidate(nextNode)) {
if (isBr$2(nextNode)) {
return moveForwardFromBr(root, nextNode);
}
if (!isAtomic(nextNode)) {
innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
if (innerNode) {
if (isText$3(innerNode)) {
return CaretPosition(innerNode, 0);
}
return CaretPosition.before(innerNode);
}
}
if (isText$3(nextNode)) {
return CaretPosition(nextNode, 0);
}
return CaretPosition.after(nextNode);
}
}
node = nextNode ? nextNode : caretPosition.getNode();
}
if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) {
node = findNode(node, direction, always, root, true);
if (isEditableCaretCandidate(node, root)) {
return getCaretCandidatePosition(direction, node);
}
}
nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node;
const rootContentEditableFalseElm = last$1(filter$5(getParents$3(container, root), isContentEditableFalse$6));
if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
if (isForwards(direction)) {
caretPosition = CaretPosition.after(rootContentEditableFalseElm);
} else {
caretPosition = CaretPosition.before(rootContentEditableFalseElm);
}
return caretPosition;
}
if (nextNode) {
return getCaretCandidatePosition(direction, nextNode);
}
return null;
};
const CaretWalker = root => ({
next: caretPosition => {
return findCaretPosition$1(HDirection.Forwards, caretPosition, root);
},
prev: caretPosition => {
return findCaretPosition$1(HDirection.Backwards, caretPosition, root);
}
});
const walkToPositionIn = (forward, root, start) => {
const position = forward ? CaretPosition.before(start) : CaretPosition.after(start);
return fromPosition(forward, root, position);
};
const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
const isBeforeOrStart = position => {
if (CaretPosition.isTextPosition(position)) {
return position.offset() === 0;
} else {
return isCaretCandidate$3(position.getNode());
}
};
const isAfterOrEnd = position => {
if (CaretPosition.isTextPosition(position)) {
const container = position.container();
return position.offset() === container.data.length;
} else {
return isCaretCandidate$3(position.getNode(true));
}
};
const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
const shouldSkipPosition = (forward, from, to) => {
if (forward) {
return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
} else {
return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
}
};
const fromPosition = (forward, root, pos) => {
const walker = CaretWalker(root);
return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
};
const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => {
if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
return fromPosition(forward, root, to);
} else {
return Optional.some(to);
}
});
const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
const positionIn = (forward, element) => {
const startNode = forward ? element.firstChild : element.lastChild;
if (isText$b(startNode)) {
return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
} else if (startNode) {
if (isCaretCandidate$3(startNode)) {
return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
} else {
return walkToPositionIn(forward, element, startNode);
}
} else {
return Optional.none();
}
};
const nextPosition = curry(fromPosition, true);
const prevPosition = curry(fromPosition, false);
const firstPositionIn = curry(positionIn, true);
const lastPositionIn = curry(positionIn, false);
const CARET_ID = '_mce_caret';
const isCaretNode = node => isElement$6(node) && node.id === CARET_ID;
const getParentCaretContainer = (body, node) => {
let currentNode = node;
while (currentNode && currentNode !== body) {
if (isCaretNode(currentNode)) {
return currentNode;
}
currentNode = currentNode.parentNode;
}
return null;
};
const isStringPathBookmark = bookmark => isString(bookmark.start);
const isRangeBookmark = bookmark => has$2(bookmark, 'rng');
const isIdBookmark = bookmark => has$2(bookmark, 'id');
const isIndexBookmark = bookmark => has$2(bookmark, 'name');
const isPathBookmark = bookmark => Tools.isArray(bookmark.start);
const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
const addBogus = (dom, node) => {
if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) {
node.innerHTML = '
';
}
return node;
};
const resolveCaretPositionBookmark = (dom, bookmark) => {
const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start));
const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end));
return lift2(startPos, endPos, (start, end) => {
const range = dom.createRng();
range.setStart(start.container(), start.offset());
range.setEnd(end.container(), end.offset());
return {
range,
forward: isForwardBookmark(bookmark)
};
});
};
const insertZwsp = (node, rng) => {
var _a;
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
const textNode = doc.createTextNode(ZWSP$1);
node.appendChild(textNode);
rng.setStart(textNode, 0);
rng.setEnd(textNode, 0);
};
const isEmpty$1 = node => !node.hasChildNodes();
const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => {
rng.setStart(pos.container(), pos.offset());
rng.setEnd(pos.container(), pos.offset());
return true;
});
const padEmptyCaretContainer = (root, node, rng) => {
if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
insertZwsp(node, rng);
return true;
} else {
return false;
}
};
const setEndPoint = (dom, start, bookmark, rng) => {
const point = bookmark[start ? 'start' : 'end'];
const root = dom.getRoot();
if (point) {
let node = root;
let offset = point[0];
for (let i = point.length - 1; node && i >= 1; i--) {
const children = node.childNodes;
if (padEmptyCaretContainer(root, node, rng)) {
return true;
}
if (point[i] > children.length - 1) {
if (padEmptyCaretContainer(root, node, rng)) {
return true;
}
return tryFindRangePosition(node, rng);
}
node = children[point[i]];
}
if (isText$b(node)) {
offset = Math.min(point[0], node.data.length);
}
if (isElement$6(node)) {
offset = Math.min(point[0], node.childNodes.length);
}
if (start) {
rng.setStart(node, offset);
} else {
rng.setEnd(node, offset);
}
}
return true;
};
const isValidTextNode = node => isText$b(node) && node.data.length > 0;
const restoreEndPoint = (dom, suffix, bookmark) => {
const marker = dom.get(bookmark.id + '_' + suffix);
const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode;
const keep = bookmark.keep;
if (marker && markerParent) {
let container;
let offset;
if (suffix === 'start') {
if (!keep) {
container = markerParent;
offset = dom.nodeIndex(marker);
} else {
if (marker.hasChildNodes()) {
container = marker.firstChild;
offset = 1;
} else if (isValidTextNode(marker.nextSibling)) {
container = marker.nextSibling;
offset = 0;
} else if (isValidTextNode(marker.previousSibling)) {
container = marker.previousSibling;
offset = marker.previousSibling.data.length;
} else {
container = markerParent;
offset = dom.nodeIndex(marker) + 1;
}
}
} else {
if (!keep) {
container = markerParent;
offset = dom.nodeIndex(marker);
} else {
if (marker.hasChildNodes()) {
container = marker.firstChild;
offset = 1;
} else if (isValidTextNode(marker.previousSibling)) {
container = marker.previousSibling;
offset = marker.previousSibling.data.length;
} else {
container = markerParent;
offset = dom.nodeIndex(marker);
}
}
}
if (!keep) {
const prev = marker.previousSibling;
const next = marker.nextSibling;
Tools.each(Tools.grep(marker.childNodes), node => {
if (isText$b(node)) {
node.data = node.data.replace(/\uFEFF/g, '');
}
});
let otherMarker;
while (otherMarker = dom.get(bookmark.id + '_' + suffix)) {
dom.remove(otherMarker, true);
}
if (isText$b(next) && isText$b(prev) && !Env.browser.isOpera()) {
const idx = prev.data.length;
prev.appendData(next.data);
dom.remove(next);
container = prev;
offset = idx;
}
}
return Optional.some(CaretPosition(container, offset));
} else {
return Optional.none();
}
};
const resolvePaths = (dom, bookmark) => {
const range = dom.createRng();
if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) {
return Optional.some({
range,
forward: isForwardBookmark(bookmark)
});
} else {
return Optional.none();
}
};
const resolveId = (dom, bookmark) => {
const startPos = restoreEndPoint(dom, 'start', bookmark);
const endPos = restoreEndPoint(dom, 'end', bookmark);
return lift2(startPos, endPos.or(startPos), (spos, epos) => {
const range = dom.createRng();
range.setStart(addBogus(dom, spos.container()), spos.offset());
range.setEnd(addBogus(dom, epos.container()), epos.offset());
return {
range,
forward: isForwardBookmark(bookmark)
};
});
};
const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => {
const range = dom.createRng();
range.selectNode(elm);
return {
range,
forward: true
};
});
const resolve = (selection, bookmark) => {
const dom = selection.dom;
if (bookmark) {
if (isPathBookmark(bookmark)) {
return resolvePaths(dom, bookmark);
} else if (isStringPathBookmark(bookmark)) {
return resolveCaretPositionBookmark(dom, bookmark);
} else if (isIdBookmark(bookmark)) {
return resolveId(dom, bookmark);
} else if (isIndexBookmark(bookmark)) {
return resolveIndex(dom, bookmark);
} else if (isRangeBookmark(bookmark)) {
return Optional.some({
range: bookmark.rng,
forward: isForwardBookmark(bookmark)
});
}
}
return Optional.none();
};
const getBookmark$2 = (selection, type, normalized) => {
return getBookmark$3(selection, type, normalized);
};
const moveToBookmark = (selection, bookmark) => {
resolve(selection, bookmark).each(({range, forward}) => {
selection.setRng(range, forward);
});
};
const isBookmarkNode$1 = node => {
return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
};
const is = expected => actual => expected === actual;
const isNbsp = is(nbsp);
const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1;
const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$2(chr);
const getRanges$1 = selection => {
const ranges = [];
if (selection) {
for (let i = 0; i < selection.rangeCount; i++) {
ranges.push(selection.getRangeAt(i));
}
}
return ranges;
};
const getSelectedNodes = ranges => {
return bind$3(ranges, range => {
const node = getSelectedNode(range);
return node ? [SugarElement.fromDom(node)] : [];
});
};
const hasMultipleRanges = selection => {
return getRanges$1(selection).length > 1;
};
const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2);
const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
const getCellsFromElementOrRanges = (ranges, element) => {
const selectedCells = getCellsFromElement(element);
return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
};
const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
const getClosestTable = (cell, isRoot) => ancestor$3(cell, 'table', isRoot);
const getStartNode = rng => {
const sc = rng.startContainer, so = rng.startOffset;
if (isText$b(sc)) {
return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
} else {
return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
}
};
const getEndNode = rng => {
const ec = rng.endContainer, eo = rng.endOffset;
if (isText$b(ec)) {
return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
} else {
return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
}
};
const getFirstChildren = node => {
return firstChild(node).fold(constant([node]), child => {
return [node].concat(getFirstChildren(child));
});
};
const getLastChildren = node => {
return lastChild(node).fold(constant([node]), child => {
if (name(child) === 'br') {
return prevSibling(child).map(sibling => {
return [node].concat(getLastChildren(sibling));
}).getOr([]);
} else {
return [node].concat(getLastChildren(child));
}
});
};
const hasAllContentsSelected = (elm, rng) => {
return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
const start = find$2(getFirstChildren(elm), curry(eq, startNode));
const end = find$2(getLastChildren(elm), curry(eq, endNode));
return start.isSome() && end.isSome();
}).getOr(false);
};
const moveEndPoint = (dom, rng, node, start) => {
const root = node;
const walker = new DomTreeWalker(node, root);
const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([
'td',
'th',
'table'
], name.toLowerCase()));
let currentNode = node;
do {
if (isText$b(currentNode) && Tools.trim(currentNode.data).length !== 0) {
if (start) {
rng.setStart(currentNode, 0);
} else {
rng.setEnd(currentNode, currentNode.data.length);
}
return;
}
if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) {
if (start) {
rng.setStartBefore(currentNode);
} else {
if (currentNode.nodeName === 'BR') {
rng.setEndBefore(currentNode);
} else {
rng.setEndAfter(currentNode);
}
}
return;
}
} while (currentNode = start ? walker.next() : walker.prev());
if (root.nodeName === 'BODY') {
if (start) {
rng.setStart(root, 0);
} else {
rng.setEnd(root, root.childNodes.length);
}
}
};
const hasAnyRanges = editor => {
const sel = editor.selection.getSel();
return isNonNullable(sel) && sel.rangeCount > 0;
};
const runOnRanges = (editor, executor) => {
const fakeSelectionNodes = getCellsFromEditor(editor);
if (fakeSelectionNodes.length > 0) {
each$e(fakeSelectionNodes, elem => {
const node = elem.dom;
const fakeNodeRng = editor.dom.createRng();
fakeNodeRng.setStartBefore(node);
fakeNodeRng.setEndAfter(node);
executor(fakeNodeRng, true);
});
} else {
executor(editor.selection.getRng(), false);
}
};
const preserve = (selection, fillBookmark, executor) => {
const bookmark = getPersistentBookmark(selection, fillBookmark);
executor(bookmark);
selection.moveToBookmark(bookmark);
};
const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType);
const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
const isElementDirectlySelected = (dom, node) => {
if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) {
const selectedAttr = dom.getAttrib(node, 'data-mce-selected');
const value = parseInt(selectedAttr, 10);
return !isNaN(value) && value > 0;
} else {
return false;
}
};
const preserveSelection = (editor, action, shouldMoveStart) => {
const {selection, dom} = editor;
const selectedNodeBeforeAction = selection.getNode();
const isSelectedBeforeNodeNoneditable = isContentEditableFalse$b(selectedNodeBeforeAction);
preserve(selection, true, () => {
action();
});
const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$b(selectedNodeBeforeAction);
if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) {
editor.selection.select(selectedNodeBeforeAction);
} else if (shouldMoveStart(selection.getStart())) {
moveStartToNearestText(dom, selection);
}
};
const moveStartToNearestText = (dom, selection) => {
var _a, _b;
const rng = selection.getRng();
const {startContainer, startOffset} = rng;
const selectedNode = selection.getNode();
if (isElementDirectlySelected(dom, selectedNode)) {
return;
}
if (isElement$6(startContainer)) {
const nodes = startContainer.childNodes;
const root = dom.getRoot();
let walker;
if (startOffset < nodes.length) {
const startNode = nodes[startOffset];
walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root);
} else {
const startNode = nodes[nodes.length - 1];
walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root);
walker.next(true);
}
for (let node = walker.current(); node; node = walker.next()) {
if (dom.getContentEditable(node) === 'false') {
return;
} else if (isText$b(node) && !isWhiteSpaceNode$1(node)) {
rng.setStart(node, 0);
selection.setRng(rng);
return;
}
}
}
};
const getNonWhiteSpaceSibling = (node, next, inc) => {
if (node) {
const nextName = next ? 'nextSibling' : 'previousSibling';
for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
return node;
}
}
}
return undefined;
};
const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node);
const isValid = (ed, parent, child) => {
return ed.schema.isValidChild(parent, child);
};
const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
if (isNonNullable(node) && isText$b(node)) {
const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data;
return isWhitespaceText(data);
} else {
return false;
}
};
const isEmptyTextNode$1 = node => {
return isNonNullable(node) && isText$b(node) && node.length === 0;
};
const isWrapNoneditableTarget = (editor, node) => {
const baseDataSelector = '[data-mce-cef-wrappable]';
const formatNoneditableSelector = getFormatNoneditableSelector(editor);
const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`;
return is$1(SugarElement.fromDom(node), selector);
};
const isWrappableNoneditable = (editor, node) => {
const dom = editor.dom;
return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0;
};
const replaceVars = (value, vars) => {
if (isFunction(value)) {
return value(vars);
} else if (isNonNullable(vars)) {
value = value.replace(/%(\w+)/g, (str, name) => {
return vars[name] || str;
});
}
return value;
};
const isEq$5 = (str1, str2) => {
str1 = str1 || '';
str2 = str2 || '';
str1 = '' + (str1.nodeName || str1);
str2 = '' + (str2.nodeName || str2);
return str1.toLowerCase() === str2.toLowerCase();
};
const normalizeStyleValue = (value, name) => {
if (isNullable(value)) {
return null;
} else {
let strValue = String(value);
if (name === 'color' || name === 'backgroundColor') {
strValue = rgbaToHexString(strValue);
}
if (name === 'fontWeight' && value === 700) {
strValue = 'bold';
}
if (name === 'fontFamily') {
strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
}
return strValue;
}
};
const getStyle = (dom, node, name) => {
const style = dom.getStyle(node, name);
return normalizeStyleValue(style, name);
};
const getTextDecoration = (dom, node) => {
let decoration;
dom.getParent(node, n => {
if (isElement$6(n)) {
decoration = dom.getStyle(n, 'text-decoration');
return !!decoration && decoration !== 'none';
} else {
return false;
}
});
return decoration;
};
const getParents$2 = (dom, node, selector) => {
return dom.getParents(node, selector, dom.getRoot());
};
const isFormatPredicate = (editor, formatName, predicate) => {
const formats = editor.formatter.get(formatName);
return isNonNullable(formats) && exists(formats, predicate);
};
const isVariableFormatName = (editor, formatName) => {
const hasVariableValues = format => {
const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%';
return exists([
'styles',
'attributes'
], key => get$a(format, key).exists(field => {
const fieldValues = isArray$1(field) ? field : values(field);
return exists(fieldValues, isVariableValue);
}));
};
return isFormatPredicate(editor, formatName, hasVariableValues);
};
const areSimilarFormats = (editor, formatName, otherFormatName) => {
const validKeys = [
'inline',
'block',
'selector',
'attributes',
'styles',
'classes'
];
const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key));
return isFormatPredicate(editor, formatName, fmt1 => {
const filteredFmt1 = filterObj(fmt1);
return isFormatPredicate(editor, otherFormatName, fmt2 => {
const filteredFmt2 = filterObj(fmt2);
return equal$1(filteredFmt1, filteredFmt2);
});
});
};
const isBlockFormat = format => hasNonNullableKey(format, 'block');
const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true;
const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true;
const isSelectorFormat = format => hasNonNullableKey(format, 'selector');
const isInlineFormat = format => hasNonNullableKey(format, 'inline');
const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true);
const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
const getEmptyCaretContainers = node => {
const nodes = [];
let tempNode = node;
while (tempNode) {
if (isText$b(tempNode) && tempNode.data !== ZWSP$1 || tempNode.childNodes.length > 1) {
return [];
}
if (isElement$6(tempNode)) {
nodes.push(tempNode);
}
tempNode = tempNode.firstChild;
}
return nodes;
};
const isCaretContainerEmpty = node => {
return getEmptyCaretContainers(node).length > 0;
};
const isEmptyCaretFormatElement = element => {
return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
};
const isBookmarkNode = isBookmarkNode$1;
const getParents$1 = getParents$2;
const isWhiteSpaceNode = isWhiteSpaceNode$1;
const isTextBlock = isTextBlock$1;
const isBogusBr = node => {
return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling;
};
const findParentContentEditable = (dom, node) => {
let parent = node;
while (parent) {
if (isElement$6(parent) && dom.getContentEditable(parent)) {
return dom.getContentEditable(parent) === 'false' ? parent : node;
}
parent = parent.parentNode;
}
return node;
};
const walkText = (start, node, offset, predicate) => {
const str = node.data;
if (start) {
for (let i = offset; i > 0; i--) {
if (predicate(str.charAt(i - 1))) {
return i;
}
}
} else {
for (let i = offset; i < str.length; i++) {
if (predicate(str.charAt(i))) {
return i;
}
}
}
return -1;
};
const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c));
const findContent = (start, node, offset) => walkText(start, node, offset, isContent);
const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => {
let lastTextNode;
const rootNode = dom.getParent(container, dom.isBlock) || body;
const walk = (container, offset, pred) => {
const textSeeker = TextSeeker(dom);
const walker = start ? textSeeker.backwards : textSeeker.forwards;
return Optional.from(walker(container, offset, (text, textOffset) => {
if (isBookmarkNode(text.parentNode)) {
return -1;
} else {
lastTextNode = text;
return pred(start, text, textOffset);
}
}, rootNode));
};
const spaceResult = walk(container, offset, findSpace);
return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
container: lastTextNode,
offset: start ? 0 : lastTextNode.length
}) : Optional.none());
};
const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => {
const sibling = container[siblingName];
if (isText$b(container) && isEmpty$3(container.data) && sibling) {
container = sibling;
}
const parents = getParents$1(dom, container);
for (let i = 0; i < parents.length; i++) {
for (let y = 0; y < formatList.length; y++) {
const curFormat = formatList[y];
if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
continue;
}
if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) {
return parents[i];
}
}
}
return container;
};
const findBlockEndPoint = (dom, formatList, container, siblingName) => {
var _a;
let node = container;
const root = dom.getRoot();
const format = formatList[0];
if (isBlockFormat(format)) {
node = format.wrapper ? null : dom.getParent(container, format.block, root);
}
if (!node) {
const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH,SUMMARY')) !== null && _a !== void 0 ? _a : root;
node = dom.getParent(isText$b(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot);
}
if (node && isBlockFormat(format) && format.wrapper) {
node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node;
}
if (!node) {
node = container;
while (node && node[siblingName] && !dom.isBlock(node[siblingName])) {
node = node[siblingName];
if (isEq$5(node, 'br')) {
break;
}
}
}
return node || container;
};
const isAtBlockBoundary$1 = (dom, root, container, siblingName) => {
const parent = container.parentNode;
if (isNonNullable(container[siblingName])) {
return false;
} else if (parent === root || isNullable(parent) || dom.isBlock(parent)) {
return true;
} else {
return isAtBlockBoundary$1(dom, root, parent, siblingName);
}
};
const findParentContainer = (dom, formatList, container, offset, start) => {
let parent = container;
const siblingName = start ? 'previousSibling' : 'nextSibling';
const root = dom.getRoot();
if (isText$b(container) && !isWhiteSpaceNode(container)) {
if (start ? offset > 0 : offset < container.data.length) {
return container;
}
}
while (parent) {
if (!formatList[0].block_expand && dom.isBlock(parent)) {
return parent;
}
for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
const allowSpaces = isText$b(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName);
if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) {
return parent;
}
}
if (parent === root || parent.parentNode === root) {
container = parent;
break;
}
parent = parent.parentNode;
}
return container;
};
const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
const expandRng = (dom, rng, formatList, includeTrailingSpace = false) => {
let {startContainer, startOffset, endContainer, endOffset} = rng;
const format = formatList[0];
if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
startContainer = getNode$1(startContainer, startOffset);
if (isText$b(startContainer)) {
startOffset = 0;
}
}
if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
if (isText$b(endContainer)) {
endOffset = endContainer.data.length;
}
}
startContainer = findParentContentEditable(dom, startContainer);
endContainer = findParentContentEditable(dom, endContainer);
if (isSelfOrParentBookmark(startContainer)) {
startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
if (rng.collapsed) {
startContainer = startContainer.previousSibling || startContainer;
} else {
startContainer = startContainer.nextSibling || startContainer;
}
if (isText$b(startContainer)) {
startOffset = rng.collapsed ? startContainer.length : 0;
}
}
if (isSelfOrParentBookmark(endContainer)) {
endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
if (rng.collapsed) {
endContainer = endContainer.nextSibling || endContainer;
} else {
endContainer = endContainer.previousSibling || endContainer;
}
if (isText$b(endContainer)) {
endOffset = rng.collapsed ? 0 : endContainer.length;
}
}
if (rng.collapsed) {
const startPoint = findWordEndPoint(dom, dom.getRoot(), startContainer, startOffset, true, includeTrailingSpace);
startPoint.each(({container, offset}) => {
startContainer = container;
startOffset = offset;
});
const endPoint = findWordEndPoint(dom, dom.getRoot(), endContainer, endOffset, false, includeTrailingSpace);
endPoint.each(({container, offset}) => {
endContainer = container;
endOffset = offset;
});
}
if (isInlineFormat(format) || format.block_expand) {
if (!isInlineFormat(format) || (!isText$b(startContainer) || startOffset === 0)) {
startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
}
if (!isInlineFormat(format) || (!isText$b(endContainer) || endOffset === endContainer.data.length)) {
endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
}
}
if (shouldExpandToSelector(format)) {
startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling');
endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling');
}
if (isBlockFormat(format) || isSelectorFormat(format)) {
startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling');
endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling');
if (isBlockFormat(format)) {
if (!dom.isBlock(startContainer)) {
startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
if (isText$b(startContainer)) {
startOffset = 0;
}
}
if (!dom.isBlock(endContainer)) {
endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
if (isText$b(endContainer)) {
endOffset = endContainer.data.length;
}
}
}
}
if (isElement$6(startContainer) && startContainer.parentNode) {
startOffset = dom.nodeIndex(startContainer);
startContainer = startContainer.parentNode;
}
if (isElement$6(endContainer) && endContainer.parentNode) {
endOffset = dom.nodeIndex(endContainer) + 1;
endContainer = endContainer.parentNode;
}
return {
startContainer,
startOffset,
endContainer,
endOffset
};
};
const walk$3 = (dom, rng, callback) => {
var _a;
const startOffset = rng.startOffset;
const startContainer = getNode$1(rng.startContainer, startOffset);
const endOffset = rng.endOffset;
const endContainer = getNode$1(rng.endContainer, endOffset - 1);
const exclude = nodes => {
const firstNode = nodes[0];
if (isText$b(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
nodes.splice(0, 1);
}
const lastNode = nodes[nodes.length - 1];
if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$b(lastNode)) {
nodes.splice(nodes.length - 1, 1);
}
return nodes;
};
const collectSiblings = (node, name, endNode) => {
const siblings = [];
for (; node && node !== endNode; node = node[name]) {
siblings.push(node);
}
return siblings;
};
const findEndPoint = (node, root) => dom.getParent(node, node => node.parentNode === root, root);
const walkBoundary = (startNode, endNode, next) => {
const siblingName = next ? 'nextSibling' : 'previousSibling';
for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
parent = node.parentNode;
const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
if (siblings.length) {
if (!next) {
siblings.reverse();
}
callback(exclude(siblings));
}
}
};
if (startContainer === endContainer) {
return callback(exclude([startContainer]));
}
const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot();
if (dom.isChildOf(startContainer, endContainer)) {
return walkBoundary(startContainer, ancestor, true);
}
if (dom.isChildOf(endContainer, startContainer)) {
return walkBoundary(endContainer, ancestor);
}
const startPoint = findEndPoint(startContainer, ancestor) || startContainer;
const endPoint = findEndPoint(endContainer, ancestor) || endContainer;
walkBoundary(startContainer, startPoint, true);
const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
if (siblings.length) {
callback(exclude(siblings));
}
walkBoundary(endContainer, endPoint);
};
const validBlocks = [
'pre[class*=language-][contenteditable="false"]',
'figure.image',
'div[data-ephox-embed-iri]',
'div.tiny-pageembed',
'div.mce-toc',
'div[data-mce-toc]'
];
const isZeroWidth = elem => isText$c(elem) && get$3(elem) === ZWSP$1;
const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => {
if (nodeName === 'br' || isZeroWidth(elem)) {
return 'valid';
} else if (isAnnotation(elem)) {
return 'existing';
} else if (isCaretNode(elem.dom)) {
return 'caret';
} else if (exists(validBlocks, selector => is$1(elem, selector))) {
return 'valid-block';
} else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) {
return 'invalid-child';
} else {
return 'valid';
}
});
const applyWordGrab = (editor, rng) => {
const r = expandRng(editor.dom, rng, [{ inline: 'span' }]);
rng.setStart(r.startContainer, r.startOffset);
rng.setEnd(r.endContainer, r.endOffset);
editor.selection.setRng(rng);
};
const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => {
const {uid = masterUId, ...otherData} = data;
add$2(elem, annotation());
set$3(elem, `${ dataAnnotationId() }`, uid);
set$3(elem, `${ dataAnnotation() }`, annotationName);
const {attributes = {}, classes = []} = decorate(uid, otherData);
setAll$1(elem, attributes);
add(elem, classes);
if (directAnnotation) {
if (classes.length > 0) {
set$3(elem, `${ dataAnnotationClasses() }`, classes.join(','));
}
const attributeNames = keys(attributes);
if (attributeNames.length > 0) {
set$3(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(','));
}
}
};
const removeDirectAnnotation = elem => {
remove$6(elem, annotation());
remove$9(elem, `${ dataAnnotationId() }`);
remove$9(elem, `${ dataAnnotation() }`);
remove$9(elem, `${ dataAnnotationActive() }`);
const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]);
const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]);
each$e(customAttrNames, name => remove$9(elem, name));
remove$3(elem, customClasses);
remove$9(elem, `${ dataAnnotationClasses() }`);
remove$9(elem, `${ dataAnnotationAttributes() }`);
};
const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => {
const master = SugarElement.fromTag('span', eDoc);
applyAnnotation(master, uid, data, annotationName, decorate, false);
return master;
};
const annotate = (editor, rng, uid, annotationName, decorate, data) => {
const newWrappers = [];
const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate);
const wrapper = value$2();
const finishWrapper = () => {
wrapper.clear();
};
const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
const nu = shallow$1(master);
newWrappers.push(nu);
wrapper.set(nu);
return nu;
});
const processElements = elems => {
each$e(elems, processElement);
};
const processElement = elem => {
const ctx = context(editor, elem, 'span', name(elem));
switch (ctx) {
case 'invalid-child': {
finishWrapper();
const children = children$1(elem);
processElements(children);
finishWrapper();
break;
}
case 'valid-block': {
finishWrapper();
applyAnnotation(elem, uid, data, annotationName, decorate, true);
break;
}
case 'valid': {
const w = getOrOpenWrapper();
wrap$2(elem, w);
break;
}
}
};
const processNodes = nodes => {
const elems = map$3(nodes, SugarElement.fromDom);
processElements(elems);
};
walk$3(editor.dom, rng, nodes => {
finishWrapper();
processNodes(nodes);
});
return newWrappers;
};
const annotateWithBookmark = (editor, name, settings, data) => {
editor.undoManager.transact(() => {
const selection = editor.selection;
const initialRng = selection.getRng();
const hasFakeSelection = getCellsFromEditor(editor).length > 0;
const masterUid = generate$1('mce-annotation');
if (initialRng.collapsed && !hasFakeSelection) {
applyWordGrab(editor, initialRng);
}
if (selection.getRng().collapsed && !hasFakeSelection) {
const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate);
set$1(wrapper, nbsp);
selection.getRng().insertNode(wrapper.dom);
selection.select(wrapper.dom);
} else {
preserve(selection, false, () => {
runOnRanges(editor, selectionRng => {
annotate(editor, selectionRng, masterUid, name, settings.decorate, data);
});
});
}
});
};
const Annotator = editor => {
const registry = create$b();
setup$x(editor, registry);
const changes = setup$y(editor, registry);
const isSpan = isTag('span');
const removeAnnotations = elements => {
each$e(elements, element => {
if (isSpan(element)) {
unwrap(element);
} else {
removeDirectAnnotation(element);
}
});
};
return {
register: (name, settings) => {
registry.register(name, settings);
},
annotate: (name, data) => {
registry.lookup(name).each(settings => {
annotateWithBookmark(editor, name, settings, data);
});
},
annotationChanged: (name, callback) => {
changes.addListener(name, callback);
},
remove: name => {
identify(editor, Optional.some(name)).each(({elements}) => {
const bookmark = editor.selection.getBookmark();
removeAnnotations(elements);
editor.selection.moveToBookmark(bookmark);
});
},
removeAll: name => {
const bookmark = editor.selection.getBookmark();
each$d(findAll(editor, name), (elements, _) => {
removeAnnotations(elements);
});
editor.selection.moveToBookmark(bookmark);
},
getAll: name => {
const directory = findAll(editor, name);
return map$2(directory, elems => map$3(elems, elem => elem.dom));
}
};
};
const BookmarkManager = selection => {
return {
getBookmark: curry(getBookmark$2, selection),
moveToBookmark: curry(moveToBookmark, selection)
};
};
BookmarkManager.isBookmarkNode = isBookmarkNode$1;
const isXYWithinRange = (clientX, clientY, range) => {
if (range.collapsed) {
return false;
} else {
return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY));
}
};
const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args);
const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args);
const fireRemove = editor => {
editor.dispatch('remove');
};
const fireDetach = editor => {
editor.dispatch('detach');
};
const fireSwitchMode = (editor, mode) => {
editor.dispatch('SwitchMode', { mode });
};
const fireObjectResizeStart = (editor, target, width, height, origin) => {
editor.dispatch('ObjectResizeStart', {
target,
width,
height,
origin
});
};
const fireObjectResized = (editor, target, width, height, origin) => {
editor.dispatch('ObjectResized', {
target,
width,
height,
origin
});
};
const firePreInit = editor => {
editor.dispatch('PreInit');
};
const firePostRender = editor => {
editor.dispatch('PostRender');
};
const fireInit = editor => {
editor.dispatch('Init');
};
const firePlaceholderToggle = (editor, state) => {
editor.dispatch('PlaceholderToggle', { state });
};
const fireError = (editor, errorType, error) => {
editor.dispatch(errorType, error);
};
const fireFormatApply = (editor, format, node, vars) => {
editor.dispatch('FormatApply', {
format,
node,
vars
});
};
const fireFormatRemove = (editor, format, node, vars) => {
editor.dispatch('FormatRemove', {
format,
node,
vars
});
};
const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args);
const fireSetContent = (editor, args) => editor.dispatch('SetContent', args);
const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args);
const fireGetContent = (editor, args) => editor.dispatch('GetContent', args);
const fireAutocompleterStart = (editor, args) => {
editor.dispatch('AutocompleterStart', args);
};
const fireAutocompleterUpdate = (editor, args) => {
editor.dispatch('AutocompleterUpdate', args);
};
const fireAutocompleterUpdateActiveRange = (editor, args) => {
editor.dispatch('AutocompleterUpdateActiveRange', args);
};
const fireAutocompleterEnd = editor => {
editor.dispatch('AutocompleterEnd');
};
const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', {
content: html,
internal
});
const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', {
node,
internal
});
const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state });
const fireEditableRootStateChange = (editor, state) => editor.dispatch('EditableRootStateChange', { state });
const VK = {
BACKSPACE: 8,
DELETE: 46,
DOWN: 40,
ENTER: 13,
ESC: 27,
LEFT: 37,
RIGHT: 39,
SPACEBAR: 32,
TAB: 9,
UP: 38,
PAGE_UP: 33,
PAGE_DOWN: 34,
END: 35,
HOME: 36,
modifierPressed: e => {
return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
},
metaKeyPressed: e => {
return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
}
};
const elementSelectionAttr = 'data-mce-selected';
const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object,details';
const abs = Math.abs;
const round$1 = Math.round;
const resizeHandles = {
nw: [
0,
0,
-1,
-1
],
ne: [
1,
0,
1,
-1
],
se: [
1,
1,
1,
1
],
sw: [
0,
1,
-1,
1
]
};
const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0;
const ControlSelection = (selection, editor) => {
const dom = editor.dom;
const editableDoc = editor.getDoc();
const rootDocument = document;
const rootElement = editor.getBody();
let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
let startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
let width;
let height;
let startScrollWidth;
let startScrollHeight;
const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image'));
const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object');
const isEventOnImageOutsideRange = (evt, range) => {
if (isTouchEvent(evt)) {
const touch = evt.touches[0];
return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range);
} else {
return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range);
}
};
const contextMenuSelectImage = evt => {
const target = evt.target;
if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
editor.selection.select(target);
}
};
const getResizeTargets = elm => {
if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
return [
elm,
elm.firstElementChild
];
} else if (dom.is(elm, 'figure.image')) {
return [elm.querySelector('img')];
} else {
return [elm];
}
};
const isResizable = elm => {
const selector = getObjectResizing(editor);
if (!selector) {
return false;
}
if (elm.getAttribute('data-mce-resize') === 'false') {
return false;
}
if (elm === editor.getBody()) {
return false;
}
if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
} else {
return is$1(SugarElement.fromDom(elm), selector);
}
};
const createGhostElement = (dom, elm) => {
if (isMedia(elm)) {
return dom.create('img', { src: Env.transparentSrc });
} else if (isTable$2(elm)) {
const isNorth = startsWith(selectedHandle.name, 'n');
const rowSelect = isNorth ? head : last$2;
const tableElm = elm.cloneNode(true);
rowSelect(dom.select('tr', tableElm)).each(tr => {
const cells = dom.select('td,th', tr);
dom.setStyle(tr, 'height', null);
each$e(cells, cell => dom.setStyle(cell, 'height', null));
});
return tableElm;
} else {
return elm.cloneNode(true);
}
};
const setSizeProp = (element, name, value) => {
if (isNonNullable(value)) {
const targets = getResizeTargets(element);
each$e(targets, target => {
if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
dom.setStyle(target, name, value);
} else {
dom.setAttrib(target, name, '' + value);
}
});
}
};
const setGhostElmSize = (ghostElm, width, height) => {
setSizeProp(ghostElm, 'width', width);
setSizeProp(ghostElm, 'height', height);
};
const resizeGhostElement = e => {
let deltaX, deltaY, proportional;
let resizeHelperX, resizeHelperY;
deltaX = e.screenX - startX;
deltaY = e.screenY - startY;
width = deltaX * selectedHandle[2] + startW;
height = deltaY * selectedHandle[3] + startH;
width = width < 5 ? 5 : width;
height = height < 5 ? 5 : height;
if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) {
proportional = !VK.modifierPressed(e);
} else {
proportional = VK.modifierPressed(e);
}
if (proportional) {
if (abs(deltaX) > abs(deltaY)) {
height = round$1(width * ratio);
width = round$1(height / ratio);
} else {
width = round$1(height / ratio);
height = round$1(width * ratio);
}
}
setGhostElmSize(selectedElmGhost, width, height);
resizeHelperX = selectedHandle.startPos.x + deltaX;
resizeHelperY = selectedHandle.startPos.y + deltaY;
resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
dom.setStyles(resizeHelper, {
left: resizeHelperX,
top: resizeHelperY,
display: 'block'
});
resizeHelper.innerHTML = width + ' × ' + height;
if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
}
if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
}
deltaX = rootElement.scrollWidth - startScrollWidth;
deltaY = rootElement.scrollHeight - startScrollHeight;
if (deltaX + deltaY !== 0) {
dom.setStyles(resizeHelper, {
left: resizeHelperX - deltaX,
top: resizeHelperY - deltaY
});
}
if (!resizeStarted) {
fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name);
resizeStarted = true;
}
};
const endGhostResize = () => {
const wasResizeStarted = resizeStarted;
resizeStarted = false;
if (wasResizeStarted) {
setSizeProp(selectedElm, 'width', width);
setSizeProp(selectedElm, 'height', height);
}
dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
dom.unbind(editableDoc, 'mouseup', endGhostResize);
if (rootDocument !== editableDoc) {
dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
dom.unbind(rootDocument, 'mouseup', endGhostResize);
}
dom.remove(selectedElmGhost);
dom.remove(resizeHelper);
dom.remove(resizeBackdrop);
showResizeRect(selectedElm);
if (wasResizeStarted) {
fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name);
dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
}
editor.nodeChanged();
};
const showResizeRect = targetElm => {
unbindResizeHandleEvents();
const position = dom.getPos(targetElm, rootElement);
const selectedElmX = position.x;
const selectedElmY = position.y;
const rect = targetElm.getBoundingClientRect();
const targetWidth = rect.width || rect.right - rect.left;
const targetHeight = rect.height || rect.bottom - rect.top;
if (selectedElm !== targetElm) {
hideResizeRect();
selectedElm = targetElm;
width = height = 0;
}
const e = editor.dispatch('ObjectSelected', { target: targetElm });
if (isResizable(targetElm) && !e.isDefaultPrevented()) {
each$d(resizeHandles, (handle, name) => {
const startDrag = e => {
const target = getResizeTargets(selectedElm)[0];
startX = e.screenX;
startY = e.screenY;
startW = target.clientWidth;
startH = target.clientHeight;
ratio = startH / startW;
selectedHandle = handle;
selectedHandle.name = name;
selectedHandle.startPos = {
x: targetWidth * handle[0] + selectedElmX,
y: targetHeight * handle[1] + selectedElmY
};
startScrollWidth = rootElement.scrollWidth;
startScrollHeight = rootElement.scrollHeight;
resizeBackdrop = dom.add(rootElement, 'div', {
'class': 'mce-resize-backdrop',
'data-mce-bogus': 'all'
});
dom.setStyles(resizeBackdrop, {
position: 'fixed',
left: '0',
top: '0',
width: '100%',
height: '100%'
});
selectedElmGhost = createGhostElement(dom, selectedElm);
dom.addClass(selectedElmGhost, 'mce-clonedresizable');
dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
selectedElmGhost.contentEditable = 'false';
dom.setStyles(selectedElmGhost, {
left: selectedElmX,
top: selectedElmY,
margin: 0
});
setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
selectedElmGhost.removeAttribute(elementSelectionAttr);
rootElement.appendChild(selectedElmGhost);
dom.bind(editableDoc, 'mousemove', resizeGhostElement);
dom.bind(editableDoc, 'mouseup', endGhostResize);
if (rootDocument !== editableDoc) {
dom.bind(rootDocument, 'mousemove', resizeGhostElement);
dom.bind(rootDocument, 'mouseup', endGhostResize);
}
resizeHelper = dom.add(rootElement, 'div', {
'class': 'mce-resize-helper',
'data-mce-bogus': 'all'
}, startW + ' × ' + startH);
};
let handleElm = dom.get('mceResizeHandle' + name);
if (handleElm) {
dom.remove(handleElm);
}
handleElm = dom.add(rootElement, 'div', {
'id': 'mceResizeHandle' + name,
'data-mce-bogus': 'all',
'class': 'mce-resizehandle',
'unselectable': true,
'style': 'cursor:' + name + '-resize; margin:0; padding:0'
});
dom.bind(handleElm, 'mousedown', e => {
e.stopImmediatePropagation();
e.preventDefault();
startDrag(e);
});
handle.elm = handleElm;
dom.setStyles(handleElm, {
left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
});
});
} else {
hideResizeRect(false);
}
};
const throttledShowResizeRect = first$1(showResizeRect, 0);
const hideResizeRect = (removeSelected = true) => {
throttledShowResizeRect.cancel();
unbindResizeHandleEvents();
if (selectedElm && removeSelected) {
selectedElm.removeAttribute(elementSelectionAttr);
}
each$d(resizeHandles, (value, name) => {
const handleElm = dom.get('mceResizeHandle' + name);
if (handleElm) {
dom.unbind(handleElm);
dom.remove(handleElm);
}
});
};
const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent);
const updateResizeRect = e => {
if (resizeStarted || editor.removed || editor.composing) {
return;
}
const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
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();
const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1';
each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => {
img.removeAttribute(elementSelectionAttr);
});
if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement) && editor.hasFocus()) {
disableGeckoResize();
const startElm = selection.getStart(true);
if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
dom.setAttrib(controlElm, elementSelectionAttr, selectedValue);
throttledShowResizeRect.throttle(controlElm);
return;
}
}
hideResizeRect();
};
const unbindResizeHandleEvents = () => {
each$d(resizeHandles, handle => {
if (handle.elm) {
dom.unbind(handle.elm);
delete handle.elm;
}
});
};
const disableGeckoResize = () => {
try {
editor.getDoc().execCommand('enableObjectResizing', false, 'false');
} catch (ex) {
}
};
editor.on('init', () => {
disableGeckoResize();
editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect);
editor.on('keyup compositionend', e => {
if (selectedElm && selectedElm.nodeName === 'TABLE') {
updateResizeRect(e);
}
});
editor.on('hide blur', hideResizeRect);
editor.on('contextmenu longpress', contextMenuSelectImage, true);
});
editor.on('remove', unbindResizeHandleEvents);
const destroy = () => {
throttledShowResizeRect.cancel();
selectedElm = selectedElmGhost = resizeBackdrop = null;
};
return {
isResizable,
showResizeRect,
hideResizeRect,
updateResizeRect,
destroy
};
};
const setStart = (rng, situ) => {
situ.fold(e => {
rng.setStartBefore(e.dom);
}, (e, o) => {
rng.setStart(e.dom, o);
}, e => {
rng.setStartAfter(e.dom);
});
};
const setFinish = (rng, situ) => {
situ.fold(e => {
rng.setEndBefore(e.dom);
}, (e, o) => {
rng.setEnd(e.dom, o);
}, e => {
rng.setEndAfter(e.dom);
});
};
const relativeToNative = (win, startSitu, finishSitu) => {
const range = win.document.createRange();
setStart(range, startSitu);
setFinish(range, finishSitu);
return range;
};
const exactToNative = (win, start, soffset, finish, foffset) => {
const rng = win.document.createRange();
rng.setStart(start.dom, soffset);
rng.setEnd(finish.dom, foffset);
return rng;
};
const adt$3 = Adt.generate([
{
ltr: [
'start',
'soffset',
'finish',
'foffset'
]
},
{
rtl: [
'start',
'soffset',
'finish',
'foffset'
]
}
]);
const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
const getRanges = (win, selection) => selection.match({
domRange: rng => {
return {
ltr: constant(rng),
rtl: Optional.none
};
},
relative: (startSitu, finishSitu) => {
return {
ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
};
},
exact: (start, soffset, finish, foffset) => {
return {
ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
};
}
});
const doDiagnose = (win, ranges) => {
const rng = ranges.ltr();
if (rng.collapsed) {
const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
return reversed.map(rev => adt$3.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$3.ltr, rng));
} else {
return fromRange(win, adt$3.ltr, rng);
}
};
const diagnose = (win, selection) => {
const ranges = getRanges(win, selection);
return doDiagnose(win, ranges);
};
adt$3.ltr;
adt$3.rtl;
const create$9 = (start, soffset, finish, foffset) => ({
start,
soffset,
finish,
foffset
});
const SimRange = { create: create$9 };
const caretPositionFromPoint = (doc, x, y) => {
var _a;
return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)).bind(pos => {
if (pos.offsetNode === null) {
return Optional.none();
}
const r = doc.createRange();
r.setStart(pos.offsetNode, pos.offset);
r.collapse();
return Optional.some(r);
});
};
const caretRangeFromPoint = (doc, x, y) => {
var _a;
return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y));
};
const availableSearch = (doc, x, y) => {
if (doc.caretPositionFromPoint) {
return caretPositionFromPoint(doc, x, y);
} else if (doc.caretRangeFromPoint) {
return caretRangeFromPoint(doc, x, y);
} else {
return Optional.none();
}
};
const fromPoint$1 = (win, x, y) => {
const doc = win.document;
return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
};
const adt$2 = Adt.generate([
{ before: ['element'] },
{
on: [
'element',
'offset'
]
},
{ after: ['element'] }
]);
const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
const getStart$2 = situ => situ.fold(identity, identity, identity);
const before$1 = adt$2.before;
const on = adt$2.on;
const after$1 = adt$2.after;
const Situ = {
before: before$1,
on,
after: after$1,
cata,
getStart: getStart$2
};
const adt$1 = Adt.generate([
{ domRange: ['rng'] },
{
relative: [
'startSitu',
'finishSitu'
]
},
{
exact: [
'start',
'soffset',
'finish',
'foffset'
]
}
]);
const exactFromRange = simRange => adt$1.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
const getStart$1 = selection => selection.match({
domRange: rng => SugarElement.fromDom(rng.startContainer),
relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
exact: (start, _soffset, _finish, _foffset) => start
});
const domRange = adt$1.domRange;
const relative = adt$1.relative;
const exact = adt$1.exact;
const getWin = selection => {
const start = getStart$1(selection);
return defaultView(start);
};
const range = SimRange.create;
const SimSelection = {
domRange,
relative,
exact,
exactFromRange,
getWin,
range
};
const beforeSpecial = (element, offset) => {
const name$1 = name(element);
if ('input' === name$1) {
return Situ.after(element);
} else if (!contains$2([
'br',
'img'
], name$1)) {
return Situ.on(element, offset);
} else {
return offset === 0 ? Situ.before(element) : Situ.after(element);
}
};
const preprocessRelative = (startSitu, finishSitu) => {
const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
return SimSelection.relative(start, finish);
};
const preprocessExact = (start, soffset, finish, foffset) => {
const startSitu = beforeSpecial(start, soffset);
const finishSitu = beforeSpecial(finish, foffset);
return SimSelection.relative(startSitu, finishSitu);
};
const preprocess = selection => selection.match({
domRange: rng => {
const start = SugarElement.fromDom(rng.startContainer);
const finish = SugarElement.fromDom(rng.endContainer);
return preprocessExact(start, rng.startOffset, finish, rng.endOffset);
},
relative: preprocessRelative,
exact: preprocessExact
});
const fromElements = (elements, scope) => {
const doc = scope || document;
const fragment = doc.createDocumentFragment();
each$e(elements, element => {
fragment.appendChild(element.dom);
});
return SugarElement.fromDom(fragment);
};
const toNative = selection => {
const win = SimSelection.getWin(selection).dom;
const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset);
const filtered = preprocess(selection);
return diagnose(win, filtered).match({
ltr: getDomRange,
rtl: getDomRange
});
};
const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
const fromPoint = (clientX, clientY, doc) => {
const win = defaultView(SugarElement.fromDom(doc));
return getAtPoint(win.dom, clientX, clientY).map(simRange => {
const rng = doc.createRange();
rng.setStart(simRange.start.dom, simRange.soffset);
rng.setEnd(simRange.finish.dom, simRange.foffset);
return rng;
}).getOrUndefined();
};
const isEq$4 = (rng1, rng2) => {
return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
};
const findParent = (node, rootNode, predicate) => {
let currentNode = node;
while (currentNode && currentNode !== rootNode) {
if (predicate(currentNode)) {
return currentNode;
}
currentNode = currentNode.parentNode;
}
return null;
};
const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name);
const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode);
const hasBrBeforeAfter = (dom, node, left) => {
const parentNode = node.parentNode;
if (parentNode) {
const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot());
let currentNode;
while (currentNode = walker[left ? 'prev' : 'next']()) {
if (isBr$6(currentNode)) {
return true;
}
}
}
return false;
};
const isPrevNode = (node, name) => {
var _a;
return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
};
const hasContentEditableFalseParent$1 = (root, node) => {
let currentNode = node;
while (currentNode && currentNode !== root) {
if (isContentEditableFalse$b(currentNode)) {
return true;
}
currentNode = currentNode.parentNode;
}
return false;
};
const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => {
const body = dom.getRoot();
const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
const parentNode = startNode.parentNode;
let lastInlineElement;
let node;
if (!parentNode) {
return Optional.none();
}
const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body;
if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode)));
}
const walker = new DomTreeWalker(startNode, parentBlockContainer);
while (node = walker[left ? 'prev' : 'next']()) {
if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
return Optional.none();
}
if (isText$b(node) && node.data.length > 0) {
if (!hasParentWithName(node, body, 'A')) {
return Optional.some(CaretPosition(node, left ? node.data.length : 0));
}
return Optional.none();
}
if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
return Optional.none();
}
lastInlineElement = node;
}
if (isComment(lastInlineElement)) {
return Optional.none();
}
if (collapsed && lastInlineElement) {
return Optional.some(CaretPosition(lastInlineElement, 0));
}
return Optional.none();
};
const normalizeEndPoint = (dom, collapsed, start, rng) => {
const body = dom.getRoot();
let node;
let normalized = false;
let container = start ? rng.startContainer : rng.endContainer;
let offset = start ? rng.startOffset : rng.endOffset;
const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
let directionLeft = start;
if (isCaretContainer$2(container)) {
return Optional.none();
}
if (isElement$6(container) && offset > container.childNodes.length - 1) {
directionLeft = false;
}
if (isDocument$1(container)) {
container = body;
offset = 0;
}
if (container === body) {
if (directionLeft) {
node = container.childNodes[offset > 0 ? offset - 1 : 0];
if (node) {
if (isCaretContainer$2(node)) {
return Optional.none();
}
if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) {
return Optional.none();
}
}
}
if (container.hasChildNodes()) {
offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
container = container.childNodes[offset];
offset = isText$b(container) && isAfterNode ? container.data.length : 0;
if (!collapsed && container === body.lastChild && isTable$2(container)) {
return Optional.none();
}
if (hasContentEditableFalseParent$1(body, container) || isCaretContainer$2(container)) {
return Optional.none();
}
if (isDetails(container)) {
return Optional.none();
}
if (container.hasChildNodes() && !isTable$2(container)) {
node = container;
const walker = new DomTreeWalker(container, body);
do {
if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) {
normalized = false;
break;
}
if (isText$b(node) && node.data.length > 0) {
offset = directionLeft ? 0 : node.data.length;
container = node;
normalized = true;
break;
}
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) {
offset = dom.nodeIndex(node);
container = node.parentNode;
if (!directionLeft) {
offset++;
}
normalized = true;
break;
}
} while (node = directionLeft ? walker.next() : walker.prev());
}
}
}
if (collapsed) {
if (isText$b(container) && offset === 0) {
findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => {
container = pos.container();
offset = pos.offset();
normalized = true;
});
}
if (isElement$6(container)) {
node = container.childNodes[offset];
if (!node) {
node = container.childNodes[offset - 1];
}
if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => {
container = pos.container();
offset = pos.offset();
normalized = true;
});
}
}
}
if (directionLeft && !collapsed && isText$b(container) && offset === container.data.length) {
findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => {
container = pos.container();
offset = pos.offset();
normalized = true;
});
}
return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none();
};
const normalize$2 = (dom, rng) => {
const collapsed = rng.collapsed, normRng = rng.cloneRange();
const startPos = CaretPosition.fromRangeStart(rng);
normalizeEndPoint(dom, collapsed, true, normRng).each(pos => {
if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
normRng.setStart(pos.container(), pos.offset());
}
});
if (!collapsed) {
normalizeEndPoint(dom, collapsed, false, normRng).each(pos => {
normRng.setEnd(pos.container(), pos.offset());
});
}
if (collapsed) {
normRng.collapse(true);
}
return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
};
const splitText = (node, offset) => {
return node.splitText(offset);
};
const split = rng => {
let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
if (startContainer === endContainer && isText$b(startContainer)) {
if (startOffset > 0 && startOffset < startContainer.data.length) {
endContainer = splitText(startContainer, startOffset);
startContainer = endContainer.previousSibling;
if (endOffset > startOffset) {
endOffset = endOffset - startOffset;
const newContainer = splitText(endContainer, endOffset).previousSibling;
startContainer = endContainer = newContainer;
endOffset = newContainer.data.length;
startOffset = 0;
} else {
endOffset = 0;
}
}
} else {
if (isText$b(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) {
startContainer = splitText(startContainer, startOffset);
startOffset = 0;
}
if (isText$b(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) {
const newContainer = splitText(endContainer, endOffset).previousSibling;
endContainer = newContainer;
endOffset = newContainer.data.length;
}
}
return {
startContainer,
startOffset,
endContainer,
endOffset
};
};
const RangeUtils = dom => {
const walk = (rng, callback) => {
return walk$3(dom, rng, callback);
};
const split$1 = split;
const normalize = rng => {
return normalize$2(dom, rng).fold(never, normalizedRng => {
rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
return true;
});
};
const expand = (rng, options = { type: 'word' }) => {
if (options.type === 'word') {
const rangeLike = expandRng(dom, rng, [{ inline: 'span' }]);
const newRange = dom.createRng();
newRange.setStart(rangeLike.startContainer, rangeLike.startOffset);
newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset);
return newRange;
}
return rng;
};
return {
walk,
split: split$1,
expand,
normalize
};
};
RangeUtils.compareRanges = isEq$4;
RangeUtils.getCaretRangeFromPoint = fromPoint;
RangeUtils.getSelectedNode = getSelectedNode;
RangeUtils.getNode = getNode$1;
const Dimension = (name, getOffset) => {
const set = (element, h) => {
if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
}
const dom = element.dom;
if (isSupported(dom)) {
dom.style[name] = h + 'px';
}
};
const get = element => {
const r = getOffset(element);
if (r <= 0 || r === null) {
const css = get$7(element, name);
return parseFloat(css) || 0;
}
return r;
};
const getOuter = get;
const aggregate = (element, properties) => foldl(properties, (acc, property) => {
const val = get$7(element, property);
const value = val === undefined ? 0 : parseInt(val, 10);
return isNaN(value) ? acc : acc + value;
}, 0);
const max = (element, value, properties) => {
const cumulativeInclusions = aggregate(element, properties);
const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
return absoluteMax;
};
return {
set,
get,
getOuter,
aggregate,
max
};
};
const api = Dimension('height', element => {
const dom = element.dom;
return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
});
const get$2 = element => api.get(element);
const getDocument = () => SugarElement.fromDom(document);
const walkUp = (navigation, doc) => {
const frame = navigation.view(doc);
return frame.fold(constant([]), f => {
const parent = navigation.owner(f);
const rest = walkUp(navigation, parent);
return [f].concat(rest);
});
};
const pathTo = (element, navigation) => {
const d = navigation.owner(element);
return walkUp(navigation, d);
};
const view = doc => {
var _a;
const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
return element.map(SugarElement.fromDom);
};
const owner = element => documentOrOwner(element);
var Navigation = /*#__PURE__*/Object.freeze({
__proto__: null,
view: view,
owner: owner
});
const find = element => {
const doc = getDocument();
const scroll = get$5(doc);
const frames = pathTo(element, Navigation);
const offset = viewport(element);
const r = foldr(frames, (b, a) => {
const loc = viewport(a);
return {
left: b.left + loc.left,
top: b.top + loc.top
};
}, {
left: 0,
top: 0
});
return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
};
const excludeFromDescend = element => name(element) === 'textarea';
const fireScrollIntoViewEvent = (editor, data) => {
const scrollEvent = editor.dispatch('ScrollIntoView', data);
return scrollEvent.isDefaultPrevented();
};
const fireAfterScrollIntoViewEvent = (editor, data) => {
editor.dispatch('AfterScrollIntoView', data);
};
const descend = (element, offset) => {
const children = children$1(element);
if (children.length === 0 || excludeFromDescend(element)) {
return {
element,
offset
};
} else if (offset < children.length && !excludeFromDescend(children[offset])) {
return {
element: children[offset],
offset: 0
};
} else {
const last = children[children.length - 1];
if (excludeFromDescend(last)) {
return {
element,
offset
};
} else {
if (name(last) === 'img') {
return {
element: last,
offset: 1
};
} else if (isText$c(last)) {
return {
element: last,
offset: get$3(last).length
};
} else {
return {
element: last,
offset: children$1(last).length
};
}
}
}
};
const markerInfo = (element, cleanupFun) => {
const pos = absolute(element);
const height = get$2(element);
return {
element,
bottom: pos.top + height,
height,
pos,
cleanup: cleanupFun
};
};
const createMarker$1 = (element, offset) => {
const startPoint = descend(element, offset);
const span = SugarElement.fromHtml('' + ZWSP$1 + '');
before$3(startPoint.element, span);
return markerInfo(span, () => remove$4(span));
};
const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop);
const withMarker = (editor, f, rng, alignToTop) => {
preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
};
const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
const data = {
elm: marker.element.dom,
alignToTop
};
if (fireScrollIntoViewEvent(editor, data)) {
return;
}
const scrollTop = get$5(doc).top;
f(editor, doc, scrollTop, marker, alignToTop);
fireAfterScrollIntoViewEvent(editor, data);
};
const applyWithMarker = (editor, f, rng, alignToTop) => {
const body = SugarElement.fromDom(editor.getBody());
const doc = SugarElement.fromDom(editor.getDoc());
reflow(body);
const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
withScrollEvents(editor, doc, f, marker, alignToTop);
marker.cleanup();
};
const withElement = (editor, element, f, alignToTop) => {
const doc = SugarElement.fromDom(editor.getDoc());
withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
};
const preserveWith = (editor, f, rng) => {
const startElement = rng.startContainer;
const startOffset = rng.startOffset;
const endElement = rng.endContainer;
const endOffset = rng.endOffset;
f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
const newRng = editor.dom.createRng();
newRng.setStart(startElement, startOffset);
newRng.setEnd(endElement, endOffset);
editor.selection.setRng(rng);
};
const scrollToMarker = (editor, marker, viewHeight, alignToTop, doc) => {
const pos = marker.pos;
if (alignToTop) {
to(pos.left, pos.top, doc);
} else {
const y = pos.top - viewHeight + marker.height;
to(-editor.getBody().getBoundingClientRect().left, y, doc);
}
};
const intoWindowIfNeeded = (editor, doc, scrollTop, viewHeight, marker, alignToTop) => {
const viewportBottom = viewHeight + scrollTop;
const markerTop = marker.pos.top;
const markerBottom = marker.bottom;
const largerThanViewport = markerBottom - markerTop >= viewHeight;
if (markerTop < scrollTop) {
scrollToMarker(editor, marker, viewHeight, alignToTop !== false, doc);
} else if (markerTop > viewportBottom) {
const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
scrollToMarker(editor, marker, viewHeight, align, doc);
} else if (markerBottom > viewportBottom && !largerThanViewport) {
scrollToMarker(editor, marker, viewHeight, alignToTop === true, doc);
}
};
const intoWindow = (editor, doc, scrollTop, marker, alignToTop) => {
const viewHeight = defaultView(doc).dom.innerHeight;
intoWindowIfNeeded(editor, doc, scrollTop, viewHeight, marker, alignToTop);
};
const intoFrame = (editor, doc, scrollTop, marker, alignToTop) => {
const frameViewHeight = defaultView(doc).dom.innerHeight;
intoWindowIfNeeded(editor, doc, scrollTop, frameViewHeight, marker, alignToTop);
const op = find(marker.element);
const viewportBounds = getBounds(window);
if (op.top < viewportBounds.y) {
intoView(marker.element, alignToTop !== false);
} else if (op.top > viewportBounds.bottom) {
intoView(marker.element, alignToTop === true);
}
};
const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
const scrollElementIntoView = (editor, element, alignToTop) => {
const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
scroller(editor, element, alignToTop);
};
const scrollRangeIntoView = (editor, rng, alignToTop) => {
const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
scroller(editor, rng, alignToTop);
};
const focus$1 = (element, preventScroll = false) => element.dom.focus({ preventScroll });
const hasFocus$1 = element => {
const root = getRootNode(element).dom;
return element.dom === root.activeElement;
};
const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
const clamp$1 = (offset, element) => {
const max = isText$c(element) ? get$3(element).length : children$1(element).length + 1;
if (offset > max) {
return max;
} else if (offset < 0) {
return 0;
}
return offset;
};
const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
const shouldStore = editor => editor.inline || Env.browser.isFirefox();
const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
const readRange = win => {
const selection = win.getSelection();
const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
return rng.map(nativeRangeToSelectionRange);
};
const getBookmark$1 = root => {
const win = defaultView(root);
return readRange(win.dom).filter(isRngInRoot(root));
};
const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
const bookmarkToNativeRng = bookmark => {
const rng = document.createRange();
try {
rng.setStart(bookmark.start.dom, bookmark.soffset);
rng.setEnd(bookmark.finish.dom, bookmark.foffset);
return Optional.some(rng);
} catch (_) {
return Optional.none();
}
};
const store = editor => {
const newBookmark = shouldStore(editor) ? getBookmark$1(SugarElement.fromDom(editor.getBody())) : Optional.none();
editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
};
const getRng = editor => {
const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
};
const restore = editor => {
getRng(editor).each(rng => editor.selection.setRng(rng));
};
const isEditorUIElement$1 = elm => {
const className = elm.className.toString();
return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
};
const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
const wrappedSetTimeout = (callback, time) => {
if (!isNumber(time)) {
time = 0;
}
return setTimeout(callback, time);
};
const wrappedSetInterval = (callback, time) => {
if (!isNumber(time)) {
time = 0;
}
return setInterval(callback, time);
};
const Delay = {
setEditorTimeout: (editor, callback, time) => {
return wrappedSetTimeout(() => {
if (!editor.removed) {
callback();
}
}, time);
},
setEditorInterval: (editor, callback, time) => {
const timer = wrappedSetInterval(() => {
if (!editor.removed) {
callback();
} else {
clearInterval(timer);
}
}, time);
return timer;
}
};
const isManualNodeChange = e => {
return e.type === 'nodechange' && e.selectionChange;
};
const registerPageMouseUp = (editor, throttledStore) => {
const mouseUpPage = () => {
throttledStore.throttle();
};
DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage);
editor.on('remove', () => {
DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage);
});
};
const registerMouseUp = (editor, throttledStore) => {
editor.on('mouseup touchend', _e => {
throttledStore.throttle();
});
};
const registerEditorEvents = (editor, throttledStore) => {
registerMouseUp(editor, throttledStore);
editor.on('keyup NodeChange AfterSetSelectionRange', e => {
if (!isManualNodeChange(e)) {
store(editor);
}
});
};
const register$6 = editor => {
const throttledStore = first$1(() => {
store(editor);
}, 0);
editor.on('init', () => {
if (editor.inline) {
registerPageMouseUp(editor, throttledStore);
}
registerEditorEvents(editor, throttledStore);
});
editor.on('remove', () => {
throttledStore.cancel();
});
};
let documentFocusInHandler;
const DOM$9 = DOMUtils.DOM;
const isEditorUIElement = elm => {
return isElement$6(elm) && FocusManager.isEditorUIElement(elm);
};
const isEditorContentAreaElement = elm => {
const classList = elm.classList;
if (classList !== undefined) {
return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
} else {
return false;
}
};
const isUIElement = (editor, elm) => {
const customSelector = getCustomUiSelector(editor);
const parent = DOM$9.getParent(elm, elm => {
return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
});
return parent !== null;
};
const getActiveElement = editor => {
try {
const root = getRootNode(SugarElement.fromDom(editor.getElement()));
return active$1(root).fold(() => document.body, x => x.dom);
} catch (ex) {
return document.body;
}
};
const registerEvents$1 = (editorManager, e) => {
const editor = e.editor;
register$6(editor);
const toggleContentAreaOnFocus = (editor, fn) => {
if (shouldHighlightOnFocus(editor) && editor.inline !== true) {
const contentArea = SugarElement.fromDom(editor.getContainer());
fn(contentArea, 'tox-edit-focus');
}
};
editor.on('focusin', () => {
const focusedEditor = editorManager.focusedEditor;
if (isEditorContentAreaElement(getActiveElement(editor))) {
toggleContentAreaOnFocus(editor, add$2);
}
if (focusedEditor !== editor) {
if (focusedEditor) {
focusedEditor.dispatch('blur', { focusedEditor: editor });
}
editorManager.setActive(editor);
editorManager.focusedEditor = editor;
editor.dispatch('focus', { blurredEditor: focusedEditor });
editor.focus(true);
}
});
editor.on('focusout', () => {
Delay.setEditorTimeout(editor, () => {
const focusedEditor = editorManager.focusedEditor;
if (!isEditorContentAreaElement(getActiveElement(editor)) || focusedEditor !== editor) {
toggleContentAreaOnFocus(editor, remove$6);
}
if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
editor.dispatch('blur', { focusedEditor: null });
editorManager.focusedEditor = null;
}
});
});
if (!documentFocusInHandler) {
documentFocusInHandler = e => {
const activeEditor = editorManager.activeEditor;
if (activeEditor) {
getOriginalEventTarget(e).each(target => {
const elem = target;
if (elem.ownerDocument === document) {
if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) {
activeEditor.dispatch('blur', { focusedEditor: null });
editorManager.focusedEditor = null;
}
}
});
}
};
DOM$9.bind(document, 'focusin', documentFocusInHandler);
}
};
const unregisterDocumentEvents = (editorManager, e) => {
if (editorManager.focusedEditor === e.editor) {
editorManager.focusedEditor = null;
}
if (!editorManager.activeEditor && documentFocusInHandler) {
DOM$9.unbind(document, 'focusin', documentFocusInHandler);
documentFocusInHandler = null;
}
};
const setup$w = editorManager => {
editorManager.on('AddEditor', curry(registerEvents$1, editorManager));
editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
};
const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
const hasContentEditableFalseParent = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'false') !== null;
const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
if (isTableSection(node)) {
return Optional.some(node);
} else if (!contains(root, node)) {
return Optional.some(root);
} else {
return Optional.none();
}
});
const normalizeSelection = (editor, rng) => {
getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => {
return firstPositionIn(elm.dom);
}).fold(() => {
editor.selection.normalize();
}, caretPos => editor.selection.setRng(caretPos.toRange()));
};
const focusBody = body => {
if (body.setActive) {
try {
body.setActive();
} catch (ex) {
body.focus();
}
} else {
body.focus();
}
};
const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome();
const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
const hasInlineFocus = editor => {
const rawBody = editor.getBody();
return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
};
const hasUiFocus = editor => {
const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
};
const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor);
const focusEditor = editor => {
const selection = editor.selection;
const body = editor.getBody();
let rng = selection.getRng();
editor.quirks.refreshContentEditable();
const restoreBookmark = editor => {
getRng(editor).each(bookmarkRng => {
editor.selection.setRng(bookmarkRng);
rng = bookmarkRng;
});
};
if (!hasFocus(editor) && editor.hasEditableRoot()) {
restoreBookmark(editor);
}
const contentEditableHost = getContentEditableHost(editor, selection.getNode());
if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
if (!hasContentEditableFalseParent(editor, contentEditableHost)) {
focusBody(body);
}
focusBody(contentEditableHost);
if (!editor.hasEditableRoot()) {
restoreBookmark(editor);
}
normalizeSelection(editor, rng);
activateEditor(editor);
return;
}
if (!editor.inline) {
if (!Env.browser.isOpera()) {
focusBody(body);
}
editor.getWin().focus();
}
if (Env.browser.isFirefox() || editor.inline) {
focusBody(body);
normalizeSelection(editor, rng);
}
activateEditor(editor);
};
const activateEditor = editor => editor.editorManager.setActive(editor);
const focus = (editor, skipFocus) => {
if (editor.removed) {
return;
}
if (skipFocus) {
activateEditor(editor);
} else {
focusEditor(editor);
}
};
const isEditableRange = (dom, rng) => {
if (rng.collapsed) {
return dom.isEditable(rng.startContainer);
} else {
return dom.isEditable(rng.startContainer) && dom.isEditable(rng.endContainer);
}
};
const getEndpointElement = (root, rng, start, real, resolve) => {
const container = start ? rng.startContainer : rng.endContainer;
const offset = start ? rng.startOffset : rng.endOffset;
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);
};
const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
const getEnd = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
const skipEmptyTextNodes = (node, forwards) => {
const orig = node;
while (node && isText$b(node) && node.length === 0) {
node = forwards ? node.nextSibling : node.previousSibling;
}
return node || orig;
};
const getNode = (root, rng) => {
if (!rng) {
return root;
}
let startContainer = rng.startContainer;
let endContainer = rng.endContainer;
const startOffset = rng.startOffset;
const endOffset = rng.endOffset;
let node = rng.commonAncestorContainer;
if (!rng.collapsed) {
if (startContainer === endContainer) {
if (endOffset - startOffset < 2) {
if (startContainer.hasChildNodes()) {
node = startContainer.childNodes[startOffset];
}
}
}
if (isText$b(startContainer) && isText$b(endContainer)) {
if (startContainer.length === startOffset) {
startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
} else {
startContainer = startContainer.parentNode;
}
if (endOffset === 0) {
endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
} else {
endContainer = endContainer.parentNode;
}
if (startContainer && startContainer === endContainer) {
node = startContainer;
}
}
}
const elm = isText$b(node) ? node.parentNode : node;
return isHTMLElement(elm) ? elm : root;
};
const getSelectedBlocks = (dom, rng, startElm, endElm) => {
const selectedBlocks = [];
const root = dom.getRoot();
const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock);
const end = dom.getParent(endElm || getEnd(root, rng, rng.collapsed), dom.isBlock);
if (start && start !== root) {
selectedBlocks.push(start);
}
if (start && end && start !== end) {
let node;
const walker = new DomTreeWalker(start, root);
while ((node = walker.next()) && node !== end) {
if (dom.isBlock(node)) {
selectedBlocks.push(node);
}
}
}
if (end && start !== end && end !== root) {
selectedBlocks.push(end);
}
return selectedBlocks;
};
const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => {
const idx = dom.nodeIndex(node);
const rng = dom.createRng();
rng.setStart(parent, idx);
rng.setEnd(parent, idx + 1);
if (content) {
moveEndPoint(dom, rng, node, true);
moveEndPoint(dom, rng, node, false);
}
return rng;
}));
const processRanges = (editor, ranges) => map$3(ranges, range => {
const evt = editor.dispatch('GetSelectionRange', { range });
return evt.range !== range ? evt.range : range;
});
const typeLookup = {
'#text': 3,
'#comment': 8,
'#cdata': 4,
'#pi': 7,
'#doctype': 10,
'#document-fragment': 11
};
const walk$2 = (node, root, prev) => {
const startName = prev ? 'lastChild' : 'firstChild';
const siblingName = prev ? 'prev' : 'next';
if (node[startName]) {
return node[startName];
}
if (node !== root) {
let sibling = node[siblingName];
if (sibling) {
return sibling;
}
for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
sibling = parent[siblingName];
if (sibling) {
return sibling;
}
}
}
return undefined;
};
const isEmptyTextNode = node => {
var _a;
const text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
if (!isWhitespaceText(text)) {
return false;
}
const parentNode = node.parent;
if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) {
return false;
}
return true;
};
const isNonEmptyElement = node => {
const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id');
return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor;
};
class AstNode {
static create(name, attrs) {
const node = new AstNode(name, typeLookup[name] || 1);
if (attrs) {
each$d(attrs, (value, attrName) => {
node.attr(attrName, value);
});
}
return node;
}
constructor(name, type) {
this.name = name;
this.type = type;
if (type === 1) {
this.attributes = [];
this.attributes.map = {};
}
}
replace(node) {
const self = this;
if (node.parent) {
node.remove();
}
self.insert(node, self);
self.remove();
return self;
}
attr(name, value) {
const self = this;
if (!isString(name)) {
if (isNonNullable(name)) {
each$d(name, (value, key) => {
self.attr(key, value);
});
}
return self;
}
const attrs = self.attributes;
if (attrs) {
if (value !== undefined) {
if (value === null) {
if (name in attrs.map) {
delete attrs.map[name];
let i = attrs.length;
while (i--) {
if (attrs[i].name === name) {
attrs.splice(i, 1);
return self;
}
}
}
return self;
}
if (name in attrs.map) {
let i = attrs.length;
while (i--) {
if (attrs[i].name === name) {
attrs[i].value = value;
break;
}
}
} else {
attrs.push({
name,
value
});
}
attrs.map[name] = value;
return self;
}
return attrs.map[name];
}
return undefined;
}
clone() {
const self = this;
const clone = new AstNode(self.name, self.type);
const selfAttrs = self.attributes;
if (selfAttrs) {
const cloneAttrs = [];
cloneAttrs.map = {};
for (let i = 0, l = selfAttrs.length; i < l; i++) {
const selfAttr = selfAttrs[i];
if (selfAttr.name !== 'id') {
cloneAttrs[cloneAttrs.length] = {
name: selfAttr.name,
value: selfAttr.value
};
cloneAttrs.map[selfAttr.name] = selfAttr.value;
}
}
clone.attributes = cloneAttrs;
}
clone.value = self.value;
return clone;
}
wrap(wrapper) {
const self = this;
if (self.parent) {
self.parent.insert(wrapper, self);
wrapper.append(self);
}
return self;
}
unwrap() {
const self = this;
for (let node = self.firstChild; node;) {
const next = node.next;
self.insert(node, self, true);
node = next;
}
self.remove();
}
remove() {
const self = this, parent = self.parent, next = self.next, prev = self.prev;
if (parent) {
if (parent.firstChild === self) {
parent.firstChild = next;
if (next) {
next.prev = null;
}
} else if (prev) {
prev.next = next;
}
if (parent.lastChild === self) {
parent.lastChild = prev;
if (prev) {
prev.next = null;
}
} else if (next) {
next.prev = prev;
}
self.parent = self.next = self.prev = null;
}
return self;
}
append(node) {
const self = this;
if (node.parent) {
node.remove();
}
const last = self.lastChild;
if (last) {
last.next = node;
node.prev = last;
self.lastChild = node;
} else {
self.lastChild = self.firstChild = node;
}
node.parent = self;
return node;
}
insert(node, refNode, before) {
if (node.parent) {
node.remove();
}
const parent = refNode.parent || this;
if (before) {
if (refNode === parent.firstChild) {
parent.firstChild = node;
} else if (refNode.prev) {
refNode.prev.next = node;
}
node.prev = refNode.prev;
node.next = refNode;
refNode.prev = node;
} else {
if (refNode === parent.lastChild) {
parent.lastChild = node;
} else if (refNode.next) {
refNode.next.prev = node;
}
node.next = refNode.next;
node.prev = refNode;
refNode.next = node;
}
node.parent = parent;
return node;
}
getAll(name) {
const self = this;
const collection = [];
for (let node = self.firstChild; node; node = walk$2(node, self)) {
if (node.name === name) {
collection.push(node);
}
}
return collection;
}
children() {
const self = this;
const collection = [];
for (let node = self.firstChild; node; node = node.next) {
collection.push(node);
}
return collection;
}
empty() {
const self = this;
if (self.firstChild) {
const nodes = [];
for (let node = self.firstChild; node; node = walk$2(node, self)) {
nodes.push(node);
}
let i = nodes.length;
while (i--) {
const node = nodes[i];
node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
}
}
self.firstChild = self.lastChild = null;
return self;
}
isEmpty(elements, whitespace = {}, predicate) {
var _a;
const self = this;
let node = self.firstChild;
if (isNonEmptyElement(self)) {
return false;
}
if (node) {
do {
if (node.type === 1) {
if (node.attr('data-mce-bogus')) {
continue;
}
if (elements[node.name]) {
return false;
}
if (isNonEmptyElement(node)) {
return false;
}
}
if (node.type === 8) {
return false;
}
if (node.type === 3 && !isEmptyTextNode(node)) {
return false;
}
if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) {
return false;
}
if (predicate && predicate(node)) {
return false;
}
} while (node = walk$2(node, self));
}
return true;
}
walk(prev) {
return walk$2(this, null, prev);
}
}
const unescapedTextParents = Tools.makeMap('NOSCRIPT STYLE SCRIPT XMP IFRAME NOEMBED NOFRAMES PLAINTEXT', ' ');
const containsZwsp = node => isString(node.nodeValue) && node.nodeValue.includes(ZWSP$1);
const getTemporaryNodeSelector = tempAttrs => `${ tempAttrs.length === 0 ? '' : `${ map$3(tempAttrs, attr => `[${ attr }]`).join(',') },` }[data-mce-bogus="all"]`;
const getTemporaryNodes = (tempAttrs, body) => body.querySelectorAll(getTemporaryNodeSelector(tempAttrs));
const createZwspCommentWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, node => containsZwsp(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP);
const createUnescapedZwspTextWalker = body => document.createTreeWalker(body, NodeFilter.SHOW_TEXT, node => {
if (containsZwsp(node)) {
const parent = node.parentNode;
return parent && has$2(unescapedTextParents, parent.nodeName) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
} else {
return NodeFilter.FILTER_SKIP;
}
});
const hasZwspComment = body => createZwspCommentWalker(body).nextNode() !== null;
const hasUnescapedZwspText = body => createUnescapedZwspTextWalker(body).nextNode() !== null;
const hasTemporaryNode = (tempAttrs, body) => body.querySelector(getTemporaryNodeSelector(tempAttrs)) !== null;
const trimTemporaryNodes = (tempAttrs, body) => {
each$e(getTemporaryNodes(tempAttrs, body), elm => {
const element = SugarElement.fromDom(elm);
if (get$9(element, 'data-mce-bogus') === 'all') {
remove$4(element);
} else {
each$e(tempAttrs, attr => {
if (has$1(element, attr)) {
remove$9(element, attr);
}
});
}
});
};
const emptyAllNodeValuesInWalker = walker => {
let curr = walker.nextNode();
while (curr !== null) {
curr.nodeValue = null;
curr = walker.nextNode();
}
};
const emptyZwspComments = compose(emptyAllNodeValuesInWalker, createZwspCommentWalker);
const emptyUnescapedZwspTexts = compose(emptyAllNodeValuesInWalker, createUnescapedZwspTextWalker);
const trim$1 = (body, tempAttrs) => {
const conditionalTrims = [
{
condition: curry(hasTemporaryNode, tempAttrs),
action: curry(trimTemporaryNodes, tempAttrs)
},
{
condition: hasZwspComment,
action: emptyZwspComments
},
{
condition: hasUnescapedZwspText,
action: emptyUnescapedZwspTexts
}
];
let trimmed = body;
let cloned = false;
each$e(conditionalTrims, ({condition, action}) => {
if (condition(trimmed)) {
if (!cloned) {
trimmed = body.cloneNode(true);
cloned = true;
}
action(trimmed);
}
});
return trimmed;
};
const cleanupBogusElements = parent => {
const bogusElements = descendants(parent, '[data-mce-bogus]');
each$e(bogusElements, elem => {
const bogusValue = get$9(elem, 'data-mce-bogus');
if (bogusValue === 'all') {
remove$4(elem);
} else if (isBr$5(elem)) {
before$3(elem, SugarElement.fromText(zeroWidth));
remove$4(elem);
} else {
unwrap(elem);
}
});
};
const cleanupInputNames = parent => {
const inputs = descendants(parent, 'input');
each$e(inputs, input => {
remove$9(input, 'name');
});
};
const trimEmptyContents = (editor, html) => {
const blockName = getForcedRootBlock(editor);
const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>( | |\\s|\u00a0|
|)<\\/${ blockName }>[\r\n]*|
[\r\n]*)$`);
return html.replace(emptyRegExp, '');
};
const getPlainTextContent = (editor, body) => {
const doc = editor.getDoc();
const dos = getRootNode(SugarElement.fromDom(editor.getBody()));
const offscreenDiv = SugarElement.fromTag('div', doc);
set$3(offscreenDiv, 'data-mce-bogus', 'all');
setAll(offscreenDiv, {
position: 'fixed',
left: '-9999999px',
top: '0'
});
set$1(offscreenDiv, body.innerHTML);
cleanupBogusElements(offscreenDiv);
cleanupInputNames(offscreenDiv);
const root = getContentContainer(dos);
append$1(root, offscreenDiv);
const content = trim$2(offscreenDiv.dom.innerText);
remove$4(offscreenDiv);
return content;
};
const getContentFromBody = (editor, args, body) => {
let content;
if (args.format === 'raw') {
content = Tools.trim(trim$2(trim$1(body, editor.serializer.getTempAttrs()).innerHTML));
} else if (args.format === 'text') {
content = getPlainTextContent(editor, body);
} else if (args.format === 'tree') {
content = editor.serializer.serialize(body, args);
} else {
content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
}
const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body));
return shouldTrim && isString(content) ? Tools.trim(content) : content;
};
const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body));
const makeMap$1 = Tools.makeMap;
const Writer = settings => {
const html = [];
settings = settings || {};
const indent = settings.indent;
const indentBefore = makeMap$1(settings.indent_before || '');
const indentAfter = makeMap$1(settings.indent_after || '');
const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
const htmlOutput = settings.element_format !== 'xhtml';
return {
start: (name, attrs, empty) => {
if (indent && indentBefore[name] && html.length > 0) {
const value = html[html.length - 1];
if (value.length > 0 && value !== '\n') {
html.push('\n');
}
}
html.push('<', name);
if (attrs) {
for (let i = 0, l = attrs.length; i < l; i++) {
const attr = attrs[i];
html.push(' ', attr.name, '="', encode(attr.value, true), '"');
}
}
if (!empty || htmlOutput) {
html[html.length] = '>';
} else {
html[html.length] = ' />';
}
if (empty && indent && indentAfter[name] && html.length > 0) {
const value = html[html.length - 1];
if (value.length > 0 && value !== '\n') {
html.push('\n');
}
}
},
end: name => {
let value;
html.push('', name, '>');
if (indent && indentAfter[name] && html.length > 0) {
value = html[html.length - 1];
if (value.length > 0 && value !== '\n') {
html.push('\n');
}
}
},
text: (text, raw) => {
if (text.length > 0) {
html[html.length] = raw ? text : encode(text);
}
},
cdata: text => {
html.push('');
},
comment: text => {
html.push('');
},
pi: (name, text) => {
if (text) {
html.push('', name, ' ', encode(text), '?>');
} else {
html.push('', name, '?>');
}
if (indent) {
html.push('\n');
}
},
doctype: text => {
html.push('', indent ? '\n' : '');
},
reset: () => {
html.length = 0;
},
getContent: () => {
return html.join('').replace(/\n$/, '');
}
};
};
const HtmlSerializer = (settings = {}, schema = Schema()) => {
const writer = Writer(settings);
settings.validate = 'validate' in settings ? settings.validate : true;
const serialize = node => {
const validate = settings.validate;
const handlers = {
3: node => {
var _a;
writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw);
},
8: node => {
var _a;
writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : '');
},
7: node => {
writer.pi(node.name, node.value);
},
10: node => {
var _a;
writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : '');
},
4: node => {
var _a;
writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : '');
},
11: node => {
let tempNode = node;
if (tempNode = tempNode.firstChild) {
do {
walk(tempNode);
} while (tempNode = tempNode.next);
}
}
};
writer.reset();
const walk = node => {
var _a;
const handler = handlers[node.type];
if (!handler) {
const name = node.name;
const isEmpty = name in schema.getVoidElements();
let attrs = node.attributes;
if (validate && attrs && attrs.length > 1) {
const sortedAttrs = [];
sortedAttrs.map = {};
const elementRule = schema.getElementRule(node.name);
if (elementRule) {
for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
const attrName = elementRule.attributesOrder[i];
if (attrName in attrs.map) {
const attrValue = attrs.map[attrName];
sortedAttrs.map[attrName] = attrValue;
sortedAttrs.push({
name: attrName,
value: attrValue
});
}
}
for (let i = 0, l = attrs.length; i < l; i++) {
const attrName = attrs[i].name;
if (!(attrName in sortedAttrs.map)) {
const attrValue = attrs.map[attrName];
sortedAttrs.map[attrName] = attrValue;
sortedAttrs.push({
name: attrName,
value: attrValue
});
}
}
attrs = sortedAttrs;
}
}
writer.start(name, attrs, isEmpty);
if (isNonHtmlElementRootName(name)) {
if (isString(node.value)) {
writer.text(node.value, true);
}
writer.end(name);
} else {
if (!isEmpty) {
let child = node.firstChild;
if (child) {
if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') {
writer.text('\n', true);
}
do {
walk(child);
} while (child = child.next);
}
writer.end(name);
}
}
} else {
handler(node);
}
};
if (node.type === 1 && !settings.inner) {
walk(node);
} else if (node.type === 3) {
handlers[3](node);
} else {
handlers[11](node);
}
return writer.getContent();
};
return { serialize };
};
const nonInheritableStyles = new Set();
(() => {
const nonInheritableStylesArr = [
'margin',
'margin-left',
'margin-right',
'margin-top',
'margin-bottom',
'padding',
'padding-left',
'padding-right',
'padding-top',
'padding-bottom',
'border',
'border-width',
'border-style',
'border-color',
'background',
'background-attachment',
'background-clip',
'background-image',
'background-origin',
'background-position',
'background-repeat',
'background-size',
'float',
'position',
'left',
'right',
'top',
'bottom',
'z-index',
'display',
'transform',
'width',
'max-width',
'min-width',
'height',
'max-height',
'min-height',
'overflow',
'overflow-x',
'overflow-y',
'text-overflow',
'vertical-align',
'transition',
'transition-delay',
'transition-duration',
'transition-property',
'transition-timing-function'
];
each$e(nonInheritableStylesArr, style => {
nonInheritableStyles.add(style);
});
})();
const conditionalNonInheritableStyles = new Set();
(() => {
const conditionalNonInheritableStylesArr = ['background-color'];
each$e(conditionalNonInheritableStylesArr, style => {
conditionalNonInheritableStyles.add(style);
});
})();
const shorthandStyleProps = [
'font',
'text-decoration',
'text-emphasis'
];
const getStyles$1 = (dom, node) => dom.parseStyle(dom.getAttrib(node, 'style'));
const getStyleProps = (dom, node) => keys(getStyles$1(dom, node));
const isNonInheritableStyle = style => nonInheritableStyles.has(style);
const isConditionalNonInheritableStyle = style => conditionalNonInheritableStyles.has(style);
const hasNonInheritableStyles = (dom, node) => exists(getStyleProps(dom, node), style => isNonInheritableStyle(style));
const hasConditionalNonInheritableStyles = (dom, node) => hasNonInheritableStyles(dom, node) && exists(getStyleProps(dom, node), style => isConditionalNonInheritableStyle(style));
const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop)));
const hasStyleConflict = (dom, node, parentNode) => {
const nodeStyleProps = getStyleProps(dom, node);
const parentNodeStyleProps = getStyleProps(dom, parentNode);
const valueMismatch = prop => {
var _a, _b;
const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : '';
const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : '';
return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
};
return exists(nodeStyleProps, nodeStyleProp => {
const propExists = props => exists(props, prop => prop === nodeStyleProp);
if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
return exists(longhandProps, valueMismatch);
} else {
return valueMismatch(nodeStyleProp);
}
});
};
const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$b).exists(text => {
const delta = forward ? 0 : -1;
return predicate(text.data.charAt(pos.offset() + delta));
});
const isBeforeSpace = curry(isChar, true, isWhiteSpace);
const isAfterSpace = curry(isChar, false, isWhiteSpace);
const isEmptyText = pos => {
const container = pos.container();
return isText$b(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
};
const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome();
const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block';
const isCefNode = node => isContentEditableFalse$b(node) && !isBogusAll(node);
const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
const isBeforeMedia = matchesElementPosition(true, isMedia$2);
const isAfterMedia = matchesElementPosition(false, isMedia$2);
const isBeforeTable = matchesElementPosition(true, isTable$2);
const isAfterTable = matchesElementPosition(false, isTable$2);
const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
const dropLast = xs => xs.slice(0, -1);
const parentsUntil = (start, root, predicate) => {
if (contains(root, start)) {
return dropLast(parents$1(start, elm => {
return predicate(elm) || eq(elm, root);
}));
} else {
return [];
}
};
const parents = (start, root) => parentsUntil(start, root, never);
const parentsAndSelf = (start, root) => [start].concat(parents(start, root));
const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText);
const isBlock$1 = schema => el => schema.isBlock(name(el));
const getClosestBlock$1 = (root, pos, schema) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$1(schema));
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()))));
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());
const isAtStartOfBlock = curry(isAtBlockBoundary, false);
const isAtEndOfBlock = curry(isAtBlockBoundary, true);
const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5);
const findBr = (forward, root, pos, schema) => {
const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
const scope = head(parentBlocks).getOr(root);
return fromPosition(forward, scope.dom, pos).filter(isBr$1);
};
const isBeforeBr$1 = (root, pos, schema) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos, schema).isSome();
const isAfterBr = (root, pos, schema) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos, schema).isSome();
const findPreviousBr = curry(findBr, false);
const findNextBr = curry(findBr, true);
const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
const getClosestBlock = (root, pos, schema) => {
const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), el => schema.isBlock(name(el)));
return head(parentBlocks).getOr(root);
};
const hasSpaceBefore = (root, pos, schema) => {
if (isInMiddleOfText(pos)) {
return isAfterSpace(pos);
} else {
return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isAfterSpace);
}
};
const hasSpaceAfter = (root, pos, schema) => {
if (isInMiddleOfText(pos)) {
return isBeforeSpace(pos);
} else {
return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos, schema).dom, pos).exists(isBeforeSpace);
}
};
const isPreValue = value => contains$2([
'pre',
'pre-wrap'
], value);
const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space')));
const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
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);
const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node);
const isSiblingCefBlock = (root, direction) => container => {
return isCefBlock(new DomTreeWalker(container, root)[direction]());
};
const isBeforeCefBlock = (root, pos) => {
const nextPos = nextPosition(root.dom, pos).getOr(pos);
const isNextCefBlock = isSiblingCefBlock(root.dom, 'next');
return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
};
const isAfterCefBlock = (root, pos) => {
const prevPos = prevPosition(root.dom, pos).getOr(pos);
const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev');
return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container()));
};
const needsToHaveNbsp = (root, pos, schema) => {
if (isInPre(pos)) {
return false;
} else {
return isAtLineBoundary(root, pos, schema) || hasSpaceBefore(root, pos, schema) || hasSpaceAfter(root, pos, schema);
}
};
const needsToBeNbspLeft = (root, pos, schema) => {
if (isInPre(pos)) {
return false;
} else {
return isAtStartOfBlock(root, pos, schema) || isBeforeBlock(root, pos, schema) || isAfterBr(root, pos, schema) || hasSpaceBefore(root, pos, schema) || isAfterCefBlock(root, pos);
}
};
const leanRight = pos => {
const container = pos.container();
const offset = pos.offset();
if (isText$b(container) && offset < container.data.length) {
return CaretPosition(container, offset + 1);
} else {
return pos;
}
};
const needsToBeNbspRight = (root, pos, schema) => {
if (isInPre(pos)) {
return false;
} else {
return isAtEndOfBlock(root, pos, schema) || isAfterBlock(root, pos, schema) || isBeforeBr$1(root, pos, schema) || hasSpaceAfter(root, pos, schema) || isBeforeCefBlock(root, pos);
}
};
const needsToBeNbsp = (root, pos, schema) => needsToBeNbspLeft(root, pos, schema) || needsToBeNbspRight(root, leanRight(pos), schema);
const isNbspAt = (text, offset) => isNbsp(text.charAt(offset));
const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset));
const hasNbsp = pos => {
const container = pos.container();
return isText$b(container) && contains$1(container.data, nbsp);
};
const normalizeNbspMiddle = text => {
const chars = text.split('');
return map$3(chars, (chr, i) => {
if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
return ' ';
} else {
return chr;
}
}).join('');
};
const normalizeNbspAtStart = (root, node, makeNbsp, schema) => {
const text = node.data;
const firstPos = CaretPosition(node, 0);
if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos, schema)) {
node.data = ' ' + text.slice(1);
return true;
} else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos, schema)) {
node.data = nbsp + text.slice(1);
return true;
} else {
return false;
}
};
const normalizeNbspInMiddleOfTextNode = node => {
const text = node.data;
const newText = normalizeNbspMiddle(text);
if (newText !== text) {
node.data = newText;
return true;
} else {
return false;
}
};
const normalizeNbspAtEnd = (root, node, makeNbsp, schema) => {
const text = node.data;
const lastPos = CaretPosition(node, text.length - 1);
if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos, schema)) {
node.data = text.slice(0, -1) + ' ';
return true;
} else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos, schema)) {
node.data = text.slice(0, -1) + nbsp;
return true;
} else {
return false;
}
};
const normalizeNbsps$1 = (root, pos, schema) => {
const container = pos.container();
if (!isText$b(container)) {
return Optional.none();
}
if (hasNbsp(pos)) {
const normalized = normalizeNbspAtStart(root, container, false, schema) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false, schema);
return someIf(normalized, pos);
} else if (needsToBeNbsp(root, pos, schema)) {
const normalized = normalizeNbspAtStart(root, container, true, schema) || normalizeNbspAtEnd(root, container, true, schema);
return someIf(normalized, pos);
} else {
return Optional.none();
}
};
const normalizeNbspsInEditor = editor => {
const root = SugarElement.fromDom(editor.getBody());
if (editor.selection.isCollapsed()) {
normalizeNbsps$1(root, CaretPosition.fromRangeStart(editor.selection.getRng()), editor.schema).each(pos => {
editor.selection.setRng(pos.toRange());
});
}
};
const normalize$1 = (node, offset, count, schema) => {
if (count === 0) {
return;
}
const elm = SugarElement.fromDom(node);
const root = ancestor$4(elm, el => schema.isBlock(name(el))).getOr(elm);
const whitespace = node.data.slice(offset, offset + count);
const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length), schema);
const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0), schema);
node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
};
const normalizeWhitespaceAfter = (node, offset, schema) => {
const content = node.data.slice(offset);
const whitespaceCount = content.length - lTrim(content).length;
normalize$1(node, offset, whitespaceCount, schema);
};
const normalizeWhitespaceBefore = (node, offset, schema) => {
const content = node.data.slice(0, offset);
const whitespaceCount = content.length - rTrim(content).length;
normalize$1(node, offset - whitespaceCount, whitespaceCount, schema);
};
const mergeTextNodes = (prevNode, nextNode, schema, normalizeWhitespace, mergeToPrev = true) => {
const whitespaceOffset = rTrim(prevNode.data).length;
const newNode = mergeToPrev ? prevNode : nextNode;
const removeNode = mergeToPrev ? nextNode : prevNode;
if (mergeToPrev) {
newNode.appendData(removeNode.data);
} else {
newNode.insertData(0, removeNode.data);
}
remove$4(SugarElement.fromDom(removeNode));
if (normalizeWhitespace) {
normalizeWhitespaceAfter(newNode, whitespaceOffset, schema);
}
return newNode;
};
const needsReposition = (pos, elm) => {
const container = pos.container();
const offset = pos.offset();
return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
};
const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
const beforeOrStartOf = node => isText$b(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
const afterOrEndOf = node => isText$b(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
const getPreviousSiblingCaretPosition = elm => {
if (isCaretCandidate$3(elm.previousSibling)) {
return Optional.some(afterOrEndOf(elm.previousSibling));
} else {
return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
}
};
const getNextSiblingCaretPosition = elm => {
if (isCaretCandidate$3(elm.nextSibling)) {
return Optional.some(beforeOrStartOf(elm.nextSibling));
} else {
return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
}
};
const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm)));
};
const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm)));
const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
const setSelection$1 = (editor, forward, pos) => {
pos.fold(() => {
editor.focus();
}, pos => {
editor.selection.setRng(pos.toRange(), forward);
});
};
const eqRawNode = rawNode => elm => elm.dom === rawNode;
const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
const paddEmptyBlock = (schema, elm, preserveEmptyCaret) => {
if (isEmpty$2(schema, elm)) {
const br = SugarElement.fromHtml('
');
if (preserveEmptyCaret) {
each$e(children$1(elm), node => {
if (!isEmptyCaretFormatElement(node)) {
remove$4(node);
}
});
} else {
empty(elm);
}
append$1(elm, br);
return Optional.some(CaretPosition.before(br.dom));
} else {
return Optional.none();
}
};
const deleteNormalized = (elm, afterDeletePosOpt, schema, normalizeWhitespace) => {
const prevTextOpt = prevSibling(elm).filter(isText$c);
const nextTextOpt = nextSibling(elm).filter(isText$c);
remove$4(elm);
return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => {
const prevNode = prev.dom, nextNode = next.dom;
const offset = prevNode.data.length;
mergeTextNodes(prevNode, nextNode, schema, normalizeWhitespace);
return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
}).orThunk(() => {
if (normalizeWhitespace) {
prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length, schema));
nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0, schema));
}
return afterDeletePosOpt;
});
};
const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
const deleteElement$2 = (editor, forward, elm, moveCaret = true, preserveEmptyCaret = false) => {
const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
const parentBlock = ancestor$4(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, editor.schema, isInlineElement(editor, elm));
if (editor.dom.isEmpty(editor.getBody())) {
editor.setContent('');
editor.selection.setCursorLocation();
} else {
parentBlock.bind(elm => paddEmptyBlock(editor.schema, elm, preserveEmptyCaret)).fold(() => {
if (moveCaret) {
setSelection$1(editor, forward, normalizedAfterDeletePos);
}
}, paddPos => {
if (moveCaret) {
setSelection$1(editor, forward, Optional.some(paddPos));
}
});
}
};
const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
const hasStrongRtl = text => strongRtl.test(text);
const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm) && editor.dom.isEditable(elm);
const isRtl = element => {
var _a;
return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : '');
};
const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
const findRootInline = (isInlineTarget, rootNode, pos) => {
const parents = findInlineParents(isInlineTarget, rootNode, pos);
return Optional.from(parents[parents.length - 1]);
};
const hasSameParentBlock = (rootNode, node1, node2) => {
const block1 = getParentBlock$3(node1, rootNode);
const block2 = getParentBlock$3(node2, rootNode);
return isNonNullable(block1) && block1 === block2;
};
const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos);
const normalizePosition = (forward, pos) => {
const container = pos.container(), offset = pos.offset();
if (forward) {
if (isCaretContainerInline(container)) {
if (isText$b(container.nextSibling)) {
return CaretPosition(container.nextSibling, 0);
} else {
return CaretPosition.after(container);
}
} else {
return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
}
} else {
if (isCaretContainerInline(container)) {
if (isText$b(container.previousSibling)) {
return CaretPosition(container.previousSibling, container.previousSibling.data.length);
} else {
return CaretPosition.before(container);
}
} else {
return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
}
}
};
const normalizeForwards = curry(normalizePosition, true);
const normalizeBackwards = curry(normalizePosition, false);
const execCommandIgnoreInputEvents = (editor, command) => {
const inputBlocker = e => e.stopImmediatePropagation();
editor.on('beforeinput input', inputBlocker, true);
editor.getDoc().execCommand(command);
editor.off('beforeinput input', inputBlocker);
};
const execEditorDeleteCommand = editor => {
editor.execCommand('delete');
};
const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete');
const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete');
const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq);
const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element);
const getParentBlock$2 = (rootNode, elm) => {
if (contains(rootNode, elm)) {
return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
} else {
return Optional.none();
}
};
const paddEmptyBody = (editor, moveSelection = true) => {
if (editor.dom.isEmpty(editor.getBody())) {
editor.setContent('', { no_selection: !moveSelection });
}
};
const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
const normalizedFirstPos = normalizePosition(true, firstPos);
const normalizedLastPos = normalizePosition(false, lastPos);
const normalizedFromPos = normalizePosition(false, fromPos);
if (forward) {
return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
} else {
return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
}
}).getOr(true);
const freefallRtl = root => {
const child = isComment$1(root) ? prevSibling(root) : lastChild(root);
return child.bind(freefallRtl).orThunk(() => Optional.some(root));
};
const deleteRangeContents = (editor, rng, root, moveSelection = true) => {
var _a;
rng.deleteContents();
const lastNode = freefallRtl(root).getOr(root);
const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom);
if (lastBlock.dom === editor.getBody()) {
paddEmptyBody(editor, moveSelection);
} else if (isEmpty$2(editor.schema, lastBlock, { checkRootAsContent: false })) {
fillWithPaddingBr(lastBlock);
if (moveSelection) {
editor.selection.setCursorLocation(lastBlock.dom, 0);
}
}
if (!eq(root, lastBlock)) {
const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
each$e(additionalCleanupNodes.concat(children$1(root)), node => {
if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(editor.schema, node)) {
remove$4(node);
}
});
}
};
const isRootFromElement = root => cur => eq(root, cur);
const getTableCells = table => descendants(table, 'td,th');
const getTable$1 = (node, isRoot) => getClosestTable(SugarElement.fromDom(node), isRoot);
const selectionInTableWithNestedTable = details => {
return lift2(details.startTable, details.endTable, (startTable, endTable) => {
const isStartTableParentOfEndTable = descendant(startTable, t => eq(t, endTable));
const isEndTableParentOfStartTable = descendant(endTable, t => eq(t, startTable));
return !isStartTableParentOfEndTable && !isEndTableParentOfStartTable ? details : {
...details,
startTable: isStartTableParentOfEndTable ? Optional.none() : details.startTable,
endTable: isEndTableParentOfStartTable ? Optional.none() : details.endTable,
isSameTable: false,
isMultiTable: false
};
}).getOr(details);
};
const adjustQuirksInDetails = details => {
return selectionInTableWithNestedTable(details);
};
const getTableDetailsFromRange = (rng, isRoot) => {
const startTable = getTable$1(rng.startContainer, isRoot);
const endTable = getTable$1(rng.endContainer, isRoot);
const isStartInTable = startTable.isSome();
const isEndInTable = endTable.isSome();
const isSameTable = lift2(startTable, endTable, eq).getOr(false);
const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
return adjustQuirksInDetails({
startTable,
endTable,
isStartInTable,
isEndInTable,
isSameTable,
isMultiTable
});
};
const tableCellRng = (start, end) => ({
start,
end
});
const tableSelection = (rng, table, cells) => ({
rng,
table,
cells
});
const deleteAction = Adt.generate([
{
singleCellTable: [
'rng',
'cell'
]
},
{ fullTable: ['table'] },
{
partialTable: [
'cells',
'outsideDetails'
]
},
{
multiTable: [
'startTableCells',
'endTableCells',
'betweenRng'
]
}
]);
const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end);
const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable)));
const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => {
const rows = table.dom.rows;
return rows.length === 1 && rows[0].cells.length === 1;
});
const getCellRng = (rng, isRoot) => {
const startCell = getClosestCell$1(rng.startContainer, isRoot);
const endCell = getClosestCell$1(rng.endContainer, isRoot);
return lift2(startCell, endCell, tableCellRng);
};
const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$2(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell)));
const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell)));
const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table)));
const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => {
if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
return Optional.none();
} else if (selectionDetails.isSameTable) {
const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot));
return Optional.some({
start: sameTableSelection,
end: sameTableSelection
});
} else {
const startCell = getClosestCell$1(rng.startContainer, isRoot);
const endCell = getClosestCell$1(rng.endContainer, isRoot);
const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
return Optional.some({
start: startTableSelection,
end: endTableSelection
});
}
};
const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell));
const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1));
const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng));
const unselectCells = (rng, selectionDetails) => {
const {startTable, endTable} = selectionDetails;
const otherContentRng = rng.cloneRange();
startTable.each(table => otherContentRng.setStartAfter(table.dom));
endTable.each(table => otherContentRng.setEndBefore(table.dom));
return otherContentRng;
};
const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => {
const {isSameTable} = selectionDetails;
const selectedCells = getSelectedCells(tableSelection).getOr([]);
if (isSameTable && tableSelection.cells.length === selectedCells.length) {
return Optional.some(deleteAction.fullTable(tableSelection.table));
} else if (selectedCells.length > 0) {
if (isSameTable) {
return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
} else {
const otherContentRng = unselectCells(rng, selectionDetails);
return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
...selectionDetails,
rng: otherContentRng
})));
}
} else {
return Optional.none();
}
});
const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => {
const startTableSelectedCells = start.bind(getSelectedCells).getOr([]);
const endTableSelectedCells = end.bind(getSelectedCells).getOr([]);
if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
const otherContentRng = unselectCells(rng, selectionDetails);
return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
} else {
return Optional.none();
}
});
const getActionFromRange = (root, rng) => {
const isRoot = isRootFromElement(root);
const optCellRng = getCellRng(rng, isRoot);
const selectionDetails = getTableDetailsFromRange(rng, isRoot);
if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) {
return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start));
} else if (selectionDetails.isMultiTable) {
return handleMultiTable(optCellRng, selectionDetails, rng, isRoot);
} else {
return handleSingleTable(optCellRng, selectionDetails, rng, isRoot);
}
};
const cleanCells = cells => each$e(cells, cell => {
remove$9(cell, 'contenteditable');
fillWithPaddingBr(cell);
});
const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
const handleEmptyBlock = (editor, startInTable, emptyBlock) => {
emptyBlock.each(block => {
if (startInTable) {
remove$4(block);
} else {
fillWithPaddingBr(block);
editor.selection.setCursorLocation(block.dom, 0);
}
});
};
const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => {
const insideTableRng = rng.cloneRange();
if (isFirstCellInSelection) {
insideTableRng.setStart(rng.startContainer, rng.startOffset);
insideTableRng.setEndAfter(cell.dom.lastChild);
} else {
insideTableRng.setStartBefore(cell.dom.firstChild);
insideTableRng.setEnd(rng.endContainer, rng.endOffset);
}
deleteCellContents(editor, insideTableRng, cell, false).each(action => action());
};
const collapseAndRestoreCellSelection = editor => {
const selectedCells = getCellsFromEditor(editor);
const selectedNode = SugarElement.fromDom(editor.selection.getNode());
if (isTableCell$3(selectedNode.dom) && isEmpty$2(editor.schema, selectedNode)) {
editor.selection.setCursorLocation(selectedNode.dom, 0);
} else {
editor.selection.collapse(true);
}
if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) {
set$3(selectedNode, 'data-mce-selected', '1');
}
};
const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => {
const editorRng = editor.selection.getRng();
const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => {
const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
rng.deleteContents();
handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(curry(isEmpty$2, editor.schema)));
const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1];
deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
if (!isEmpty$2(editor.schema, endPointCell)) {
return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1));
} else {
return Optional.none();
}
}).getOr(cells);
cleanCells(cellsToClean);
collapseAndRestoreCellSelection(editor);
});
const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
const rng = editor.selection.getRng();
const startCell = startTableCells[0];
const endCell = endTableCells[endTableCells.length - 1];
deleteContentInsideCell(editor, startCell, rng, true);
deleteContentInsideCell(editor, endCell, rng, false);
const startTableCellsToClean = isEmpty$2(editor.schema, startCell) ? startTableCells : startTableCells.slice(1);
const endTableCellsToClean = isEmpty$2(editor.schema, endCell) ? endTableCells : endTableCells.slice(0, -1);
cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
betweenRng.deleteContents();
collapseAndRestoreCellSelection(editor);
});
const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => {
deleteRangeContents(editor, rng, cell, moveSelection);
});
const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table));
const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption));
const deleteRange$3 = (editor, startElm, selectedCells) => {
const rootNode = SugarElement.fromDom(editor.getBody());
const rng = editor.selection.getRng();
return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
};
const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2);
const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption'));
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)));
const emptyElement = (editor, elm) => Optional.some(() => {
fillWithPaddingBr(elm);
editor.selection.setCursorLocation(elm.dom, 0);
});
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);
const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop));
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));
const deleteCaretCells = (editor, forward, rootElm, startElm) => {
const from = CaretPosition.fromRangeStart(editor.selection.getRng());
return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(editor.schema, fromCell, { checkRootAsContent: false }) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from));
};
const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
const from = CaretPosition.fromRangeStart(editor.selection.getRng());
return isEmpty$2(editor.schema, fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
};
const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
const isBeforeOrAfterTable = (editor, forward) => {
const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos));
};
const deleteCaret$3 = (editor, forward, startElm) => {
const rootElm = SugarElement.fromDom(editor.getBody());
return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption));
};
const backspaceDelete$b = (editor, forward) => {
const startElm = SugarElement.fromDom(editor.selection.getStart(true));
const cells = getCellsFromEditor(editor);
return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$3(editor, startElm, cells);
};
const getContentEditableRoot$1 = (root, node) => {
let tempNode = node;
while (tempNode && tempNode !== root) {
if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$b(tempNode)) {
return tempNode;
}
tempNode = tempNode.parentNode;
}
return null;
};
const internalAttributesPrefixes = [
'data-ephox-',
'data-mce-',
'data-alloy-',
'data-snooker-',
'_'
];
const each$9 = Tools.each;
const ElementUtils = editor => {
const dom = editor.dom;
const internalAttributes = new Set(editor.serializer.getTempAttrs());
const compare = (node1, node2) => {
if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) {
return false;
}
const getAttribs = node => {
const attribs = {};
each$9(dom.getAttribs(node), attr => {
const name = attr.nodeName.toLowerCase();
if (name !== 'style' && !isAttributeInternal(name)) {
attribs[name] = dom.getAttrib(node, name);
}
});
return attribs;
};
const compareObjects = (obj1, obj2) => {
for (const name in obj1) {
if (has$2(obj1, name)) {
const value = obj2[name];
if (isUndefined(value)) {
return false;
}
if (obj1[name] !== value) {
return false;
}
delete obj2[name];
}
}
for (const name in obj2) {
if (has$2(obj2, name)) {
return false;
}
}
return true;
};
if (isElement$6(node1) && isElement$6(node2)) {
if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
return false;
}
if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
return false;
}
}
return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
};
const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName);
return {
compare,
isAttributeInternal
};
};
const isHeading = node => [
'h1',
'h2',
'h3',
'h4',
'h5',
'h6'
].includes(node.name);
const isSummary = node => node.name === 'summary';
const traverse = (root, fn) => {
let node = root;
while (node = node.walk()) {
fn(node);
}
};
const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
const name = node.name;
for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
const filter = nodeFilters[ni];
if (filter.name === name) {
const match = matches.nodes[name];
if (match) {
match.nodes.push(node);
} else {
matches.nodes[name] = {
filter,
nodes: [node]
};
}
}
}
if (node.attributes) {
for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
const filter = attributeFilters[ai];
const attrName = filter.name;
if (attrName in node.attributes.map) {
const match = matches.attributes[attrName];
if (match) {
match.nodes.push(node);
} else {
matches.attributes[attrName] = {
filter,
nodes: [node]
};
}
}
}
}
};
const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
const matches = {
nodes: {},
attributes: {}
};
if (node.firstChild) {
traverse(node, childNode => {
matchNode$1(nodeFilters, attributeFilters, childNode, matches);
});
}
return matches;
};
const runFilters = (matches, args) => {
const run = (matchRecord, filteringAttributes) => {
each$d(matchRecord, match => {
const nodes = from(match.nodes);
each$e(match.filter.callbacks, callback => {
for (let i = nodes.length - 1; i >= 0; i--) {
const node = nodes[i];
const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name;
if (!valueMatches || isNullable(node.parent)) {
nodes.splice(i, 1);
}
}
if (nodes.length > 0) {
callback(nodes, match.filter.name, args);
}
});
});
};
run(matches.nodes, false);
run(matches.attributes, true);
};
const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => {
const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
runFilters(matches, args);
};
const paddEmptyNode = (settings, args, isBlock, node) => {
const brPreferred = settings.pad_empty_with_br || args.insert;
if (brPreferred && isBlock(node)) {
const astNode = new AstNode('br', 1);
if (args.insert) {
astNode.attr('data-mce-bogus', '1');
}
node.empty().append(astNode);
} else {
node.empty().append(new AstNode('#text', 3)).value = nbsp;
}
};
const isPaddedWithNbsp = node => {
var _a;
return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp;
};
const hasOnlyChild = (node, name) => {
const firstChild = node === null || node === void 0 ? void 0 : node.firstChild;
return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name;
};
const isPadded = (schema, node) => {
const rule = schema.getElementRule(node.name);
return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true;
};
const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node));
const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br');
const findClosestEditingHost = scope => {
let editableNode;
for (let node = scope; node; node = node.parent) {
const contentEditable = node.attr('contenteditable');
if (contentEditable === 'false') {
break;
} else if (contentEditable === 'true') {
editableNode = node;
}
}
return Optional.from(editableNode);
};
const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
if (schema.getSpecialElements()[node.name]) {
node.empty().remove();
} else {
const children = node.children();
for (const childNode of children) {
if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) {
removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
}
}
node.unwrap();
}
};
const cleanInvalidNodes = (nodes, schema, rootNode, onCreate = noop) => {
const textBlockElements = schema.getTextBlockElements();
const nonEmptyElements = schema.getNonEmptyElements();
const whitespaceElements = schema.getWhitespaceElements();
const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table,summary');
const fixed = new Set();
const isSplittableElement = node => node !== rootNode && !nonSplittableElements[node.name];
for (let ni = 0; ni < nodes.length; ni++) {
const node = nodes[ni];
let parent;
let newParent;
let tempNode;
if (!node.parent || fixed.has(node)) {
continue;
}
if (textBlockElements[node.name] && node.parent.name === 'li') {
let sibling = node.next;
while (sibling) {
if (textBlockElements[sibling.name]) {
sibling.name = 'li';
fixed.add(sibling);
node.parent.insert(sibling, node.parent);
} else {
break;
}
sibling = sibling.next;
}
node.unwrap();
continue;
}
const parents = [node];
for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && isSplittableElement(parent); parent = parent.parent) {
parents.push(parent);
}
if (parent && parents.length > 1) {
if (!isInvalid(schema, node, parent)) {
parents.reverse();
newParent = parents[0].clone();
onCreate(newParent);
let currentNode = newParent;
for (let i = 0; i < parents.length - 1; i++) {
if (schema.isValidChild(currentNode.name, parents[i].name) && i > 0) {
tempNode = parents[i].clone();
onCreate(tempNode);
currentNode.append(tempNode);
} else {
tempNode = currentNode;
}
for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
const nextNode = childNode.next;
tempNode.append(childNode);
childNode = nextNode;
}
currentNode = tempNode;
}
if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
parent.insert(newParent, parents[0], true);
parent.insert(node, newParent);
} else {
parent.insert(node, parents[0], true);
}
parent = parents[0];
if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
parent.empty().remove();
}
} else {
removeOrUnwrapInvalidNode(node, schema);
}
} else if (node.parent) {
if (node.name === 'li') {
let sibling = node.prev;
if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) {
sibling.append(node);
continue;
}
sibling = node.next;
if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) {
sibling.insert(node, sibling.firstChild, true);
continue;
}
const wrapper = new AstNode('ul', 1);
onCreate(wrapper);
node.wrap(wrapper);
continue;
}
if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
const wrapper = new AstNode('div', 1);
onCreate(wrapper);
node.wrap(wrapper);
} else {
removeOrUnwrapInvalidNode(node, schema);
}
}
}
};
const hasClosest = (node, parentName) => {
let tempNode = node;
while (tempNode) {
if (tempNode.name === parentName) {
return true;
}
tempNode = tempNode.parent;
}
return false;
};
const isInvalid = (schema, node, parent = node.parent) => {
if (!parent) {
return false;
}
if (schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) {
return true;
}
if (node.name === 'a' && hasClosest(parent, 'a')) {
return true;
}
if (isSummary(parent) && isHeading(node)) {
return !((parent === null || parent === void 0 ? void 0 : parent.firstChild) === node && (parent === null || parent === void 0 ? void 0 : parent.lastChild) === node);
}
return false;
};
const createRange = (sc, so, ec, eo) => {
const rng = document.createRange();
rng.setStart(sc, so);
rng.setEnd(ec, eo);
return rng;
};
const normalizeBlockSelectionRange = rng => {
const startPos = CaretPosition.fromRangeStart(rng);
const endPos = CaretPosition.fromRangeEnd(rng);
const rootNode = rng.commonAncestorContainer;
return fromPosition(false, rootNode, endPos).map(newEndPos => {
if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
} else {
return rng;
}
}).getOr(rng);
};
const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
const hasOnlyOneChild$1 = node => {
return isNonNullable(node.firstChild) && node.firstChild === node.lastChild;
};
const isPaddingNode = node => {
return node.name === 'br' || node.value === nbsp;
};
const isPaddedEmptyBlock = (schema, node) => {
const blockElements = schema.getBlockElements();
return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
};
const isEmptyFragmentElement = (schema, node) => {
const nonEmptyElements = schema.getNonEmptyElements();
return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
};
const isListFragment = (schema, fragment) => {
let firstChild = fragment.firstChild;
let lastChild = fragment.lastChild;
if (firstChild && firstChild.name === 'meta') {
firstChild = firstChild.next;
}
if (lastChild && lastChild.attr('id') === 'mce_marker') {
lastChild = lastChild.prev;
}
if (isEmptyFragmentElement(schema, lastChild)) {
lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev;
}
if (!firstChild || firstChild !== lastChild) {
return false;
}
return firstChild.name === 'ul' || firstChild.name === 'ol';
};
const cleanupDomFragment = domFragment => {
var _a, _b;
const firstChild = domFragment.firstChild;
const lastChild = domFragment.lastChild;
if (firstChild && firstChild.nodeName === 'META') {
(_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild);
}
if (lastChild && lastChild.id === 'mce_marker') {
(_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild);
}
return domFragment;
};
const toDomFragment = (dom, serializer, fragment) => {
const html = serializer.serialize(fragment);
const domFragment = dom.createFragment(html);
return cleanupDomFragment(domFragment);
};
const listItems = elm => {
var _a;
return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => {
return child.nodeName === 'LI';
});
};
const isPadding = node => {
return node.data === nbsp || isBr$6(node);
};
const isListItemPadded = node => {
return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild);
};
const isEmptyOrPadded = elm => {
return !elm.firstChild || isListItemPadded(elm);
};
const trimListItems = elms => {
return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
};
const getParentLi = (dom, node) => {
const parentBlock = dom.getParent(node, dom.isBlock);
return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
};
const isParentBlockLi = (dom, node) => {
return !!getParentLi(dom, node);
};
const getSplit = (parentNode, rng) => {
const beforeRng = rng.cloneRange();
const afterRng = rng.cloneRange();
beforeRng.setStartBefore(parentNode);
afterRng.setEndAfter(parentNode);
return [
beforeRng.cloneContents(),
afterRng.cloneContents()
];
};
const findFirstIn = (node, rootNode) => {
const caretPos = CaretPosition.before(node);
const caretWalker = CaretWalker(rootNode);
const newCaretPos = caretWalker.next(caretPos);
return newCaretPos ? newCaretPos.toRange() : null;
};
const findLastOf = (node, rootNode) => {
const caretPos = CaretPosition.after(node);
const caretWalker = CaretWalker(rootNode);
const newCaretPos = caretWalker.prev(caretPos);
return newCaretPos ? newCaretPos.toRange() : null;
};
const insertMiddle = (target, elms, rootNode, rng) => {
const parts = getSplit(target, rng);
const parentElm = target.parentNode;
if (parentElm) {
parentElm.insertBefore(parts[0], target);
Tools.each(elms, li => {
parentElm.insertBefore(li, target);
});
parentElm.insertBefore(parts[1], target);
parentElm.removeChild(target);
}
return findLastOf(elms[elms.length - 1], rootNode);
};
const insertBefore$2 = (target, elms, rootNode) => {
const parentElm = target.parentNode;
if (parentElm) {
Tools.each(elms, elm => {
parentElm.insertBefore(elm, target);
});
}
return findFirstIn(target, rootNode);
};
const insertAfter$2 = (target, elms, rootNode, dom) => {
dom.insertAfter(elms.reverse(), target);
return findLastOf(elms[0], rootNode);
};
const insertAtCaret$1 = (serializer, dom, rng, fragment) => {
const domFragment = toDomFragment(dom, serializer, fragment);
const liTarget = getParentLi(dom, rng.startContainer);
const liElms = trimListItems(listItems(domFragment.firstChild));
const BEGINNING = 1, END = 2;
const rootNode = dom.getRoot();
const isAt = location => {
const caretPos = CaretPosition.fromRangeStart(rng);
const caretWalker = CaretWalker(dom.getRoot());
const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode();
return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true;
};
if (!liTarget) {
return null;
} else if (isAt(BEGINNING)) {
return insertBefore$2(liTarget, liElms, rootNode);
} else if (isAt(END)) {
return insertAfter$2(liTarget, liElms, rootNode, dom);
} else {
return insertMiddle(liTarget, liElms, rootNode, rng);
}
};
const mergeableWrappedElements = ['pre'];
const shouldPasteContentOnly = (dom, fragment, parentNode, root) => {
var _a;
const firstNode = fragment.firstChild;
const lastNode = fragment.lastChild;
const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode;
const isPastingSingleElement = firstNode === last;
const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name);
if (isPastingSingleElement && isWrappedElement) {
const isContentEditable = firstNode.attr('contenteditable') !== 'false';
const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name;
const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3);
return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable;
} else {
return false;
}
};
const isTableCell = isTableCell$3;
const isTableCellContentSelected = (dom, rng, cell) => {
if (isNonNullable(cell)) {
const endCell = dom.getParent(rng.endContainer, isTableCell);
return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng);
} else {
return false;
}
};
const validInsertion = (editor, value, parentNode) => {
var _a;
if (parentNode.getAttribute('data-mce-bogus') === 'all') {
(_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode);
} else {
const node = parentNode.firstChild;
const node2 = parentNode.lastChild;
if (!node || node === node2 && node.nodeName === 'BR') {
editor.dom.setHTML(parentNode, value);
} else {
editor.selection.setContent(value, { no_events: true });
}
}
};
const trimBrsFromTableCell = (dom, elm, schema) => {
Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(el => trimBlockTrailingBr(el, schema));
};
const reduceInlineTextElements = (editor, merge) => {
const textInlineElements = editor.schema.getTextInlineElements();
const dom = editor.dom;
if (merge) {
const root = editor.getBody();
const elementUtils = ElementUtils(editor);
const fragmentSelector = '*[data-mce-fragment]';
const fragments = dom.select(fragmentSelector);
Tools.each(fragments, node => {
const isInline = currentNode => isNonNullable(textInlineElements[currentNode.nodeName.toLowerCase()]);
const hasOneChild = currentNode => currentNode.childNodes.length === 1;
const hasNoNonInheritableStyles = currentNode => !(hasNonInheritableStyles(dom, currentNode) || hasConditionalNonInheritableStyles(dom, currentNode));
if (hasNoNonInheritableStyles(node) && isInline(node) && hasOneChild(node)) {
const styles = getStyleProps(dom, node);
const isOverridden = (oldStyles, newStyles) => forall(oldStyles, style => contains$2(newStyles, style));
const overriddenByAllChildren = childNode => hasOneChild(node) && dom.is(childNode, fragmentSelector) && isInline(childNode) && (childNode.nodeName === node.nodeName && isOverridden(styles, getStyleProps(dom, childNode)) || overriddenByAllChildren(childNode.children[0]));
const identicalToParent = parentNode => isNonNullable(parentNode) && parentNode !== root && (elementUtils.compare(node, parentNode) || identicalToParent(parentNode.parentElement));
const conflictWithInsertedParent = parentNode => isNonNullable(parentNode) && parentNode !== root && dom.is(parentNode, fragmentSelector) && (hasStyleConflict(dom, node, parentNode) || conflictWithInsertedParent(parentNode.parentElement));
if (overriddenByAllChildren(node.children[0]) || identicalToParent(node.parentElement) && !conflictWithInsertedParent(node.parentElement)) {
dom.remove(node, true);
}
}
});
}
};
const markFragmentElements = fragment => {
let node = fragment;
while (node = node.walk()) {
if (node.type === 1) {
node.attr('data-mce-fragment', '1');
}
}
};
const unmarkFragmentElements = elm => {
Tools.each(elm.getElementsByTagName('*'), elm => {
elm.removeAttribute('data-mce-fragment');
});
};
const isPartOfFragment = node => {
return !!node.getAttribute('data-mce-fragment');
};
const canHaveChildren = (editor, node) => {
return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName];
};
const moveSelectionToMarker = (editor, marker) => {
var _a, _b, _c;
let nextRng;
const dom = editor.dom;
const selection = editor.selection;
if (!marker) {
return;
}
selection.scrollIntoView(marker);
const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') {
dom.remove(marker);
selection.select(parentEditableElm);
return;
}
let rng = dom.createRng();
const node = marker.previousSibling;
if (isText$b(node)) {
rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
const node2 = marker.nextSibling;
if (isText$b(node2)) {
node.appendData(node2.data);
(_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2);
}
} else {
rng.setStartBefore(marker);
rng.setEndBefore(marker);
}
const findNextCaretRng = rng => {
let caretPos = CaretPosition.fromRangeStart(rng);
const caretWalker = CaretWalker(editor.getBody());
caretPos = caretWalker.next(caretPos);
return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange();
};
const parentBlock = dom.getParent(marker, dom.isBlock);
dom.remove(marker);
if (parentBlock && dom.isEmpty(parentBlock)) {
const isCell = isTableCell(parentBlock);
empty(SugarElement.fromDom(parentBlock));
rng.setStart(parentBlock, 0);
rng.setEnd(parentBlock, 0);
if (!isCell && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
rng = nextRng;
dom.remove(parentBlock);
} else {
dom.add(parentBlock, dom.create('br', isCell ? {} : { 'data-mce-bogus': '1' }));
}
}
selection.setRng(rng);
};
const deleteSelectedContent = editor => {
const dom = editor.dom;
const rng = normalize(editor.selection.getRng());
editor.selection.setRng(rng);
const startCell = dom.getParent(rng.startContainer, isTableCell);
if (isTableCellContentSelected(dom, rng, startCell)) {
deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
} else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$b(rng.startContainer.childNodes[rng.startOffset])) {
rng.deleteContents();
} else {
editor.getDoc().execCommand('Delete', false);
}
};
const findMarkerNode = scope => {
for (let markerNode = scope; markerNode; markerNode = markerNode.walk()) {
if (markerNode.attr('id') === 'mce_marker') {
return Optional.some(markerNode);
}
}
return Optional.none();
};
const notHeadingsInSummary = (dom, node, fragment) => {
var _a;
return exists(fragment.children(), isHeading) && ((_a = dom.getParent(node, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName) === 'SUMMARY';
};
const insertHtmlAtCaret = (editor, value, details) => {
var _a, _b;
const selection = editor.selection;
const dom = editor.dom;
const parser = editor.parser;
const merge = details.merge;
const serializer = HtmlSerializer({ validate: true }, editor.schema);
const bookmarkHtml = '';
if (!details.preserve_zwsp) {
value = trim$2(value);
}
if (value.indexOf('{$caret}') === -1) {
value += '{$caret}';
}
value = value.replace(/\{\$caret\}/, bookmarkHtml);
let rng = selection.getRng();
const caretElement = rng.startContainer;
const body = editor.getBody();
if (caretElement === body && selection.isCollapsed()) {
if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
rng = dom.createRng();
rng.setStart(body.firstChild, 0);
rng.setEnd(body.firstChild, 0);
selection.setRng(rng);
}
}
if (!selection.isCollapsed()) {
deleteSelectedContent(editor);
}
const parentNode = selection.getNode();
const parserArgs = {
context: parentNode.nodeName.toLowerCase(),
data: details.data,
insert: true
};
const fragment = parser.parse(value, parserArgs);
if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) {
rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment);
if (rng) {
selection.setRng(rng);
}
return value;
}
if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) {
(_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap();
}
markFragmentElements(fragment);
let node = fragment.lastChild;
if (node && node.attr('id') === 'mce_marker') {
const marker = node;
for (node = node.prev; node; node = node.walk(true)) {
if (node.type === 3 || !dom.isBlock(node.name)) {
if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
node.parent.insert(marker, node, node.name === 'br');
}
break;
}
}
}
editor._selectionOverrides.showBlockCaretContainer(parentNode);
if (!parserArgs.invalid && !notHeadingsInSummary(dom, parentNode, fragment)) {
value = serializer.serialize(fragment);
validInsertion(editor, value, parentNode);
} else {
editor.selection.setContent(bookmarkHtml);
let parentNode = selection.getNode();
let tempNode;
const rootNode = editor.getBody();
if (isDocument$1(parentNode)) {
parentNode = tempNode = rootNode;
} else {
tempNode = parentNode;
}
while (tempNode && tempNode !== rootNode) {
parentNode = tempNode;
tempNode = tempNode.parentNode;
}
value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
const root = parser.parse(value);
const markerNode = findMarkerNode(root);
const editingHost = markerNode.bind(findClosestEditingHost).getOr(root);
markerNode.each(marker => marker.replace(fragment));
const toExtract = fragment.children();
const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root;
fragment.unwrap();
const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent));
cleanInvalidNodes(invalidChildren, editor.schema, editingHost);
filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root);
value = serializer.serialize(root);
if (parentNode === rootNode) {
dom.setHTML(rootNode, value);
} else {
dom.setOuterHTML(parentNode, value);
}
}
reduceInlineTextElements(editor, merge);
moveSelectionToMarker(editor, dom.get('mce_marker'));
unmarkFragmentElements(editor.getBody());
trimBrsFromTableCell(dom, selection.getStart(), editor.schema);
updateCaret(editor.schema, editor.getBody(), selection.getStart());
return value;
};
const isTreeNode = content => content instanceof AstNode;
const moveSelection = editor => {
if (hasFocus(editor)) {
firstPositionIn(editor.getBody()).each(pos => {
const node = pos.getNode();
const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
editor.selection.setRng(caretPos.toRange());
});
}
};
const setEditorHtml = (editor, html, noSelection) => {
editor.dom.setHTML(editor.getBody(), html);
if (noSelection !== true) {
moveSelection(editor);
}
};
const setContentString = (editor, body, content, args) => {
content = trim$2(content);
if (content.length === 0 || /^\s+$/.test(content)) {
const padd = '
';
if (body.nodeName === 'TABLE') {
content = '' + padd + ' ';
} else if (/^(UL|OL)$/.test(body.nodeName)) {
content = '' + padd + ' ';
}
const forcedRootBlockName = getForcedRootBlock(editor);
if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
content = padd;
content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
} else if (!content) {
content = padd;
}
setEditorHtml(editor, content, args.no_selection);
return {
content,
html: content
};
} else {
if (args.format !== 'raw') {
content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
isRootContent: true,
insert: true
}));
}
const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
setEditorHtml(editor, trimmedHtml, args.no_selection);
return {
content: trimmedHtml,
html: trimmedHtml
};
}
};
const setContentTree = (editor, body, content, args) => {
filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
const trimmedHtml = trim$2(isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html));
setEditorHtml(editor, trimmedHtml, args.no_selection);
return {
content,
html: trimmedHtml
};
};
const setContentInternal = (editor, content, args) => {
return Optional.from(editor.getBody()).map(body => {
if (isTreeNode(content)) {
return setContentTree(editor, body, content, args);
} else {
return setContentString(editor, body, content, args);
}
}).getOr({
content,
html: isTreeNode(args.content) ? '' : args.content
});
};
const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
const ancestor = (scope, transform, isRoot) => {
let element = scope.dom;
const stop = ensureIsRoot(isRoot);
while (element.parentNode) {
element = element.parentNode;
const el = SugarElement.fromDom(element);
const transformed = transform(el);
if (transformed.isSome()) {
return transformed;
} else if (stop(el)) {
break;
}
}
return Optional.none();
};
const closest$1 = (scope, transform, isRoot) => {
const current = transform(scope);
const stop = ensureIsRoot(isRoot);
return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop));
};
const isEq$3 = isEq$5;
const matchesUnInheritedFormatSelector = (ed, node, name) => {
const formatList = ed.formatter.get(name);
if (formatList) {
for (let i = 0; i < formatList.length; i++) {
const format = formatList[i];
if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
return true;
}
}
}
return false;
};
const matchParents = (editor, node, name, vars, similar) => {
const root = editor.dom.getRoot();
if (node === root) {
return false;
}
const matchedNode = editor.dom.getParent(node, elm => {
if (matchesUnInheritedFormatSelector(editor, elm, name)) {
return true;
}
return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true);
});
return !!matchNode(editor, matchedNode, name, vars, similar);
};
const matchName = (dom, node, format) => {
if (isInlineFormat(format) && isEq$3(node, format.inline)) {
return true;
}
if (isBlockFormat(format) && isEq$3(node, format.block)) {
return true;
}
if (isSelectorFormat(format)) {
return isElement$6(node) && dom.is(node, format.selector);
}
return false;
};
const matchItems = (dom, node, format, itemName, similar, vars) => {
const items = format[itemName];
const matchAttributes = itemName === 'attributes';
if (isFunction(format.onmatch)) {
return format.onmatch(node, format, itemName);
}
if (items) {
if (!isArrayLike(items)) {
for (const key in items) {
if (has$2(items, key)) {
const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key);
const expectedValue = replaceVars(items[key], vars);
const isEmptyValue = isNullable(value) || isEmpty$3(value);
if (isEmptyValue && isNullable(expectedValue)) {
continue;
}
if (similar && isEmptyValue && !format.exact) {
return false;
}
if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) {
return false;
}
}
}
} else {
for (let i = 0; i < items.length; i++) {
if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) {
return true;
}
}
}
}
return true;
};
const matchNode = (ed, node, name, vars, similar) => {
const formatList = ed.formatter.get(name);
const dom = ed.dom;
if (formatList && isElement$6(node)) {
for (let i = 0; i < formatList.length; i++) {
const format = formatList[i];
if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
const classes = format.classes;
if (classes) {
for (let x = 0; x < classes.length; x++) {
if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
return;
}
}
}
return format;
}
}
}
return undefined;
};
const match$2 = (editor, name, vars, node, similar) => {
if (node) {
return matchParents(editor, node, name, vars, similar);
}
node = editor.selection.getNode();
if (matchParents(editor, node, name, vars, similar)) {
return true;
}
const startNode = editor.selection.getStart();
if (startNode !== node) {
if (matchParents(editor, startNode, name, vars, similar)) {
return true;
}
}
return false;
};
const matchAll = (editor, names, vars) => {
const matchedFormatNames = [];
const checkedMap = {};
const startElement = editor.selection.getStart();
editor.dom.getParent(startElement, node => {
for (let i = 0; i < names.length; i++) {
const name = names[i];
if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
checkedMap[name] = true;
matchedFormatNames.push(name);
}
}
}, editor.dom.getRoot());
return matchedFormatNames;
};
const closest = (editor, names) => {
const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none();
return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$1(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull();
};
const canApply = (editor, name) => {
const formatList = editor.formatter.get(name);
const dom = editor.dom;
if (formatList && editor.selection.isEditable()) {
const startNode = editor.selection.getStart();
const parents = getParents$2(dom, startNode);
for (let x = formatList.length - 1; x >= 0; x--) {
const format = formatList[x];
if (!isSelectorFormat(format)) {
return true;
}
for (let i = parents.length - 1; i >= 0; i--) {
if (dom.is(parents[i], format.selector)) {
return true;
}
}
}
}
return false;
};
const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => {
const matchSimilar = isVariableFormatName(editor, name);
if (editor.formatter.matchNode(node, name, {}, matchSimilar)) {
return acc.concat([name]);
} else {
return acc;
}
}, []);
const ZWSP = ZWSP$1;
const importNode = (ownerDocument, node) => {
return ownerDocument.importNode(node, true);
};
const findFirstTextNode = node => {
if (node) {
const walker = new DomTreeWalker(node, node);
for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) {
if (isText$b(tempNode)) {
return tempNode;
}
}
}
return null;
};
const createCaretContainer = fill => {
const caretContainer = SugarElement.fromTag('span');
setAll$1(caretContainer, {
'id': CARET_ID,
'data-mce-bogus': '1',
'data-mce-type': 'format-caret'
});
if (fill) {
append$1(caretContainer, SugarElement.fromText(ZWSP));
}
return caretContainer;
};
const trimZwspFromCaretContainer = caretContainerNode => {
const textNode = findFirstTextNode(caretContainerNode);
if (textNode && textNode.data.charAt(0) === ZWSP) {
textNode.deleteData(0, 1);
}
return textNode;
};
const removeCaretContainerNode = (editor, node, moveCaret) => {
const dom = editor.dom, selection = editor.selection;
if (isCaretContainerEmpty(node)) {
deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret, true);
} else {
const rng = selection.getRng();
const block = dom.getParent(node, dom.isBlock);
const startContainer = rng.startContainer;
const startOffset = rng.startOffset;
const endContainer = rng.endContainer;
const endOffset = rng.endOffset;
const textNode = trimZwspFromCaretContainer(node);
dom.remove(node, true);
if (startContainer === textNode && startOffset > 0) {
rng.setStart(textNode, startOffset - 1);
}
if (endContainer === textNode && endOffset > 0) {
rng.setEnd(textNode, endOffset - 1);
}
if (block && dom.isEmpty(block)) {
fillWithPaddingBr(SugarElement.fromDom(block));
}
selection.setRng(rng);
}
};
const removeCaretContainer = (editor, node, moveCaret) => {
const dom = editor.dom, selection = editor.selection;
if (!node) {
node = getParentCaretContainer(editor.getBody(), selection.getStart());
if (!node) {
while (node = dom.get(CARET_ID)) {
removeCaretContainerNode(editor, node, moveCaret);
}
}
} else {
removeCaretContainerNode(editor, node, moveCaret);
}
};
const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
var _a, _b;
const dom = editor.dom;
const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema));
if (block && dom.isEmpty(block)) {
(_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode);
} else {
removeTrailingBr(SugarElement.fromDom(formatNode));
if (dom.isEmpty(formatNode)) {
(_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode);
} else {
dom.insertAfter(caretContainer, formatNode);
}
}
};
const appendNode = (parentNode, node) => {
parentNode.appendChild(node);
return node;
};
const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
var _a;
const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
return appendNode(parentNode, formatNode.cloneNode(false));
}, caretContainer);
const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document;
return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP));
};
const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => {
const formatter = editor.formatter;
const dom = editor.dom;
const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat'));
const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name));
if (uniqueFormats.length > 0) {
const clonedFormatNode = formatNode.cloneNode(false);
dom.add(caretContainer, clonedFormatNode);
formatter.remove(name, vars, clonedFormatNode, similar);
dom.remove(clonedFormatNode);
return Optional.some(clonedFormatNode);
} else {
return Optional.none();
}
};
const normalizeNbsps = node => set(node, get$3(node).replace(new RegExp(`${ nbsp }$`), ' '));
const normalizeNbspsBetween = (editor, caretContainer) => {
const handler = () => {
if (caretContainer !== null && !editor.dom.isEmpty(caretContainer)) {
prevSibling(SugarElement.fromDom(caretContainer)).each(node => {
if (isText$c(node)) {
normalizeNbsps(node);
} else {
descendant$2(node, e => isText$c(e)).each(textNode => {
if (isText$c(textNode)) {
normalizeNbsps(textNode);
}
});
}
});
}
};
editor.once('input', e => {
if (e.data && !isWhiteSpace(e.data)) {
if (!e.isComposing) {
handler();
} else {
editor.once('compositionend', () => {
handler();
});
}
}
});
};
const applyCaretFormat = (editor, name, vars) => {
let caretContainer;
const selection = editor.selection;
const formatList = editor.formatter.get(name);
if (!formatList) {
return;
}
const selectionRng = selection.getRng();
let offset = selectionRng.startOffset;
const container = selectionRng.startContainer;
const text = container.nodeValue;
caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
const bookmark = selection.getBookmark();
selectionRng.collapse(true);
let rng = expandRng(editor.dom, selectionRng, formatList);
rng = split(rng);
editor.formatter.apply(name, vars, rng);
selection.moveToBookmark(bookmark);
} else {
let textNode = caretContainer ? findFirstTextNode(caretContainer) : null;
if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) {
caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
textNode = caretContainer.firstChild;
selectionRng.insertNode(caretContainer);
offset = 1;
normalizeNbspsBetween(editor, caretContainer);
editor.formatter.apply(name, vars, caretContainer);
} else {
editor.formatter.apply(name, vars, caretContainer);
}
selection.setCursorLocation(textNode, offset);
}
};
const removeCaretFormat = (editor, name, vars, similar) => {
const dom = editor.dom;
const selection = editor.selection;
let hasContentAfter = false;
const formatList = editor.formatter.get(name);
if (!formatList) {
return;
}
const rng = selection.getRng();
const container = rng.startContainer;
const offset = rng.startOffset;
let node = container;
if (isText$b(container)) {
if (offset !== container.data.length) {
hasContentAfter = true;
}
node = node.parentNode;
}
const parents = [];
let formatNode;
while (node) {
if (matchNode(editor, node, name, vars, similar)) {
formatNode = node;
break;
}
if (node.nextSibling) {
hasContentAfter = true;
}
parents.push(node);
node = node.parentNode;
}
if (!formatNode) {
return;
}
if (hasContentAfter) {
const bookmark = selection.getBookmark();
rng.collapse(true);
let expandedRng = expandRng(dom, rng, formatList, true);
expandedRng = split(expandedRng);
editor.formatter.remove(name, vars, expandedRng, similar);
selection.moveToBookmark(bookmark);
} else {
const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
const parentsAfter = isNonNullable(caretContainer) ? dom.getParents(formatNode.parentNode, always, caretContainer) : [];
const newCaretContainer = createCaretContainer(false).dom;
insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode);
const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar);
const caretTextNode = insertFormatNodesIntoCaretContainer([
...parents,
...cleanedFormatNode.toArray(),
...parentsAfter
], newCaretContainer);
if (caretContainer) {
removeCaretContainerNode(editor, caretContainer, isNonNullable(caretContainer));
}
selection.setCursorLocation(caretTextNode, 1);
normalizeNbspsBetween(editor, newCaretContainer);
if (dom.isEmpty(formatNode)) {
dom.remove(formatNode);
}
}
};
const disableCaretContainer = (editor, keyCode, moveCaret) => {
const selection = editor.selection, body = editor.getBody();
removeCaretContainer(editor, null, moveCaret);
if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
}
if (keyCode === 37 || keyCode === 39) {
removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()), true);
}
};
const endsWithNbsp = element => isText$b(element) && endsWith(element.data, nbsp);
const setup$v = editor => {
editor.on('mouseup keydown', e => {
disableCaretContainer(editor, e.keyCode, endsWithNbsp(editor.selection.getRng().endContainer));
});
};
const createCaretFormat = formatNodes => {
const caretContainer = createCaretContainer(false);
const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
return {
caretContainer,
caretPosition: CaretPosition(innerMost, 0)
};
};
const replaceWithCaretFormat = (targetNode, formatNodes) => {
const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
before$3(SugarElement.fromDom(targetNode), caretContainer);
remove$4(SugarElement.fromDom(targetNode));
return caretPosition;
};
const createCaretFormatAtStart$1 = (rng, formatNodes) => {
const {caretContainer, caretPosition} = createCaretFormat(formatNodes);
rng.insertNode(caretContainer.dom);
return caretPosition;
};
const isFormatElement = (editor, element) => {
if (isCaretNode(element.dom)) {
return false;
}
const inlineElements = editor.schema.getTextInlineElements();
return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$1(element.dom);
};
const postProcessHooks = {};
const isPre = matchNodeNames(['pre']);
const addPostProcessHook = (name, hook) => {
const hooks = postProcessHooks[name];
if (!hooks) {
postProcessHooks[name] = [];
}
postProcessHooks[name].push(hook);
};
const postProcess$1 = (name, editor) => {
if (has$2(postProcessHooks, name)) {
each$e(postProcessHooks[name], hook => {
hook(editor);
});
}
};
addPostProcessHook('pre', editor => {
const rng = editor.selection.getRng();
const hasPreSibling = blocks => pre => {
const prev = pre.previousSibling;
return isPre(prev) && contains$2(blocks, prev);
};
const joinPre = (pre1, pre2) => {
const sPre2 = SugarElement.fromDom(pre2);
const doc = documentOrOwner(sPre2).dom;
remove$4(sPre2);
append(SugarElement.fromDom(pre1), [
SugarElement.fromTag('br', doc),
SugarElement.fromTag('br', doc),
...children$1(sPre2)
]);
};
if (!rng.collapsed) {
const blocks = editor.selection.getSelectedBlocks();
const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks));
each$e(preBlocks, pre => {
joinPre(pre.previousSibling, pre);
});
}
});
const listItemStyles = [
'fontWeight',
'fontStyle',
'color',
'fontSize',
'fontFamily'
];
const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name));
const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt));
const getExpandedListItemFormat = (formatter, format) => {
const formatList = formatter.get(format);
return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none();
};
const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone();
const isRngEndAtEndOfElement = (rng, elm) => {
return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
};
const isEditableListItem = dom => elm => isListItem$2(elm) && dom.isEditable(elm);
const getFullySelectedBlocks = selection => {
const blocks = selection.getSelectedBlocks();
const rng = selection.getRng();
if (selection.isCollapsed()) {
return [];
}
if (blocks.length === 1) {
return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
} else {
const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray();
const last = last$2(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray();
const middle = blocks.slice(1, -1);
return first.concat(middle).concat(last);
}
};
const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
const each$8 = Tools.each;
const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
const findElementSibling = (node, siblingName) => {
for (let sibling = node; sibling; sibling = sibling[siblingName]) {
if (isText$b(sibling) && isNotEmpty(sibling.data)) {
return node;
}
if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) {
return sibling;
}
}
return node;
};
const mergeSiblingsNodes = (editor, prev, next) => {
const elementUtils = ElementUtils(editor);
const isPrevEditable = isHTMLElement(prev) && editor.dom.isEditable(prev);
const isNextEditable = isHTMLElement(next) && editor.dom.isEditable(next);
if (isPrevEditable && isNextEditable) {
const prevSibling = findElementSibling(prev, 'previousSibling');
const nextSibling = findElementSibling(next, 'nextSibling');
if (elementUtils.compare(prevSibling, nextSibling)) {
for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) {
const tmpSibling = sibling;
sibling = sibling.nextSibling;
prevSibling.appendChild(tmpSibling);
}
editor.dom.remove(nextSibling);
Tools.each(Tools.grep(nextSibling.childNodes), node => {
prevSibling.appendChild(node);
});
return prevSibling;
}
}
return next;
};
const mergeSiblings = (editor, format, vars, node) => {
var _a;
if (node && format.merge_siblings !== false) {
const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node;
mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true));
}
};
const clearChildStyles = (dom, format, node) => {
if (format.clear_child_styles) {
const selector = format.links ? '*:not(a)' : '*';
each$8(dom.select(selector, node), childNode => {
if (isElementNode(childNode) && dom.isEditable(childNode)) {
each$8(format.styles, (_value, name) => {
dom.setStyle(childNode, name, '');
});
}
});
}
};
const processChildElements = (node, filter, process) => {
each$8(node.childNodes, node => {
if (isElementNode(node)) {
if (filter(node)) {
process(node);
}
if (node.hasChildNodes()) {
processChildElements(node, filter, process);
}
}
});
};
const unwrapEmptySpan = (dom, node) => {
if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
dom.remove(node, true);
}
};
const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name));
const applyStyle = (dom, name, value) => node => {
dom.setStyle(node, name, value);
if (node.getAttribute('style') === '') {
node.removeAttribute('style');
}
unwrapEmptySpan(dom, node);
};
const removeResult = Adt.generate([
{ keep: [] },
{ rename: ['name'] },
{ removed: [] }
]);
const MCE_ATTR_RE = /^(src|href|style)$/;
const each$7 = Tools.each;
const isEq$2 = isEq$5;
const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName);
const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
const getContainer = (ed, rng, start) => {
let container = rng[start ? 'startContainer' : 'endContainer'];
let offset = rng[start ? 'startOffset' : 'endOffset'];
if (isElement$6(container)) {
const lastIdx = container.childNodes.length - 1;
if (!start && offset) {
offset--;
}
container = container.childNodes[offset > lastIdx ? lastIdx : offset];
}
if (isText$b(container) && start && offset >= container.data.length) {
container = new DomTreeWalker(container, ed.getBody()).next() || container;
}
if (isText$b(container) && !start && offset === 0) {
container = new DomTreeWalker(container, ed.getBody()).prev() || container;
}
return container;
};
const normalizeTableSelection = (node, start) => {
const prop = start ? 'firstChild' : 'lastChild';
const childNode = node[prop];
if (isTableCellOrRow(node) && childNode) {
if (node.nodeName === 'TR') {
return childNode[prop] || childNode;
} else {
return childNode;
}
}
return node;
};
const wrap$1 = (dom, node, name, attrs) => {
var _a;
const wrapper = dom.create(name, attrs);
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node);
wrapper.appendChild(node);
return wrapper;
};
const wrapWithSiblings = (dom, node, next, name, attrs) => {
const start = SugarElement.fromDom(node);
const wrapper = SugarElement.fromDom(dom.create(name, attrs));
const siblings = next ? nextSiblings(start) : prevSiblings(start);
append(wrapper, siblings);
if (next) {
before$3(start, wrapper);
prepend(wrapper, start);
} else {
after$4(start, wrapper);
append$1(wrapper, start);
}
return wrapper.dom;
};
const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A';
const removeNode = (ed, node, format) => {
const parentNode = node.parentNode;
let rootBlockElm;
const dom = ed.dom;
const forcedRootBlock = getForcedRootBlock(ed);
if (isBlockFormat(format)) {
if (parentNode === dom.getRoot()) {
if (!format.list_block || !isEq$2(node, format.list_block)) {
each$e(from(node.childNodes), node => {
if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
if (!rootBlockElm) {
rootBlockElm = wrap$1(dom, node, forcedRootBlock);
dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
} else {
rootBlockElm.appendChild(node);
}
} else {
rootBlockElm = null;
}
});
}
}
}
if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
return;
}
dom.remove(node, true);
};
const processFormatAttrOrStyle = (name, value, vars) => {
if (isNumber(name)) {
return {
name: value,
value: null
};
} else {
return {
name,
value: replaceVars(value, vars)
};
}
};
const removeEmptyStyleAttributeIfNeeded = (dom, elm) => {
if (dom.getAttrib(elm, 'style') === '') {
elm.removeAttribute('style');
elm.removeAttribute('data-mce-style');
}
};
const removeStyles = (dom, elm, format, vars, compareNode) => {
let stylesModified = false;
each$7(format.styles, (value, name) => {
const {
name: styleName,
value: styleValue
} = processFormatAttrOrStyle(name, value, vars);
const normalizedStyleValue = normalizeStyleValue(styleValue, styleName);
if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) {
dom.setStyle(elm, styleName, '');
}
stylesModified = true;
});
if (stylesModified) {
removeEmptyStyleAttributeIfNeeded(dom, elm);
}
};
const removeListStyleFormats = (editor, name, vars) => {
if (name === 'removeformat') {
each$e(getPartiallySelectedListItems(editor.selection), li => {
each$e(listItemStyles, name => editor.dom.setStyle(li, name, ''));
removeEmptyStyleAttributeIfNeeded(editor.dom, li);
});
} else {
getExpandedListItemFormat(editor.formatter, name).each(liFmt => {
each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null));
});
}
};
const removeNodeFormatInternal = (ed, format, vars, node, compareNode) => {
const dom = ed.dom;
const elementUtils = ElementUtils(ed);
const schema = ed.schema;
if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) {
removeNode(ed, node, format);
return removeResult.removed();
}
if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') {
return removeResult.keep();
}
if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
return removeResult.keep();
}
const elm = node;
const preserveAttributes = format.preserve_attributes;
if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) {
const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase()));
dom.removeAllAttribs(elm);
each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value));
if (attrsToPreserve.length > 0) {
return removeResult.rename('span');
}
}
if (format.remove !== 'all') {
removeStyles(dom, elm, format, vars, compareNode);
each$7(format.attributes, (value, name) => {
const {
name: attrName,
value: attrValue
} = processFormatAttrOrStyle(name, value, vars);
if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) {
if (attrName === 'class') {
const currentValue = dom.getAttrib(elm, attrName);
if (currentValue) {
let valueOut = '';
each$e(currentValue.split(/\s+/), cls => {
if (/mce\-\w+/.test(cls)) {
valueOut += (valueOut ? ' ' : '') + cls;
}
});
if (valueOut) {
dom.setAttrib(elm, attrName, valueOut);
return;
}
}
}
if (MCE_ATTR_RE.test(attrName)) {
elm.removeAttribute('data-mce-' + attrName);
}
if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') {
elm.removeAttribute(attrName);
dom.setStyle(elm, 'list-style-type', 'none');
return;
}
if (attrName === 'class') {
elm.removeAttribute('className');
}
elm.removeAttribute(attrName);
}
});
each$7(format.classes, value => {
value = replaceVars(value, vars);
if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) {
dom.removeClass(elm, value);
}
});
const attrs = dom.getAttribs(elm);
for (let i = 0; i < attrs.length; i++) {
const attrName = attrs[i].nodeName;
if (!elementUtils.isAttributeInternal(attrName)) {
return removeResult.keep();
}
}
}
if (format.remove !== 'none') {
removeNode(ed, elm, format);
return removeResult.removed();
}
return removeResult.keep();
};
const findFormatRoot = (editor, container, name, vars, similar) => {
let formatRoot;
if (container.parentNode) {
each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => {
if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') {
const format = matchNode(editor, parent, name, vars, similar);
if (format && format.split !== false) {
formatRoot = parent;
}
}
});
}
return formatRoot;
};
const removeNodeFormatFromClone = (editor, format, vars, clone) => removeNodeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => {
const fragment = editor.dom.createFragment();
fragment.appendChild(clone);
return editor.dom.rename(clone, newName);
}, constant(null));
const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => {
var _a, _b;
let lastClone;
let firstClone;
const dom = editor.dom;
if (formatRoot) {
const formatRootParent = formatRoot.parentNode;
for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
let clone = dom.clone(parent, false);
for (let i = 0; i < formatList.length; i++) {
clone = removeNodeFormatFromClone(editor, formatList[i], vars, clone);
if (clone === null) {
break;
}
}
if (clone) {
if (lastClone) {
clone.appendChild(lastClone);
}
if (!firstClone) {
firstClone = clone;
}
lastClone = clone;
}
}
if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container;
}
if (lastClone && firstClone) {
(_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target);
firstClone.appendChild(target);
if (isInlineFormat(format)) {
mergeSiblings(editor, format, vars, lastClone);
}
}
}
return container;
};
const removeFormatInternal = (ed, name, vars, node, similar) => {
const formatList = ed.formatter.get(name);
const format = formatList[0];
const dom = ed.dom;
const selection = ed.selection;
const splitToFormatRoot = container => {
const formatRoot = findFormatRoot(ed, container, name, vars, similar);
return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
};
const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end');
const removeFormatOnNode = node => exists(formatList, fmt => removeNodeFormat(ed, fmt, vars, node, node));
const process = node => {
const children = from(node.childNodes);
const removed = removeFormatOnNode(node);
const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f));
const parentNode = node.parentNode;
if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
removeFormatOnNode(parentNode);
}
if (format.deep) {
if (children.length) {
for (let i = 0; i < children.length; i++) {
process(children[i]);
}
}
}
const textDecorations = [
'underline',
'line-through',
'overline'
];
each$e(textDecorations, decoration => {
if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) {
removeNodeFormat(ed, {
deep: false,
exact: true,
inline: 'span',
styles: { textDecoration: decoration }
}, undefined, node);
}
});
};
const unwrap = start => {
const node = dom.get(start ? '_start' : '_end');
if (node) {
let out = node[start ? 'firstChild' : 'lastChild'];
if (isRemoveBookmarkNode(out)) {
out = out[start ? 'firstChild' : 'lastChild'];
}
if (isText$b(out) && out.data.length === 0) {
out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
}
dom.remove(node, true);
return out;
} else {
return null;
}
};
const removeRngStyle = rng => {
let startContainer;
let endContainer;
let expandedRng = expandRng(dom, rng, formatList, rng.collapsed);
if (format.split) {
expandedRng = split(expandedRng);
startContainer = getContainer(ed, expandedRng, true);
endContainer = getContainer(ed, expandedRng);
if (startContainer !== endContainer) {
startContainer = normalizeTableSelection(startContainer, true);
endContainer = normalizeTableSelection(endContainer, false);
if (isChildOfInlineParent(dom, startContainer, endContainer)) {
const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
'id': '_start',
'data-mce-type': 'bookmark'
}));
unwrap(true);
return;
}
if (isChildOfInlineParent(dom, endContainer, startContainer)) {
const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
'id': '_end',
'data-mce-type': 'bookmark'
}));
unwrap(false);
return;
}
startContainer = wrap$1(dom, startContainer, 'span', {
'id': '_start',
'data-mce-type': 'bookmark'
});
endContainer = wrap$1(dom, endContainer, 'span', {
'id': '_end',
'data-mce-type': 'bookmark'
});
const newRng = dom.createRng();
newRng.setStartAfter(startContainer);
newRng.setEndBefore(endContainer);
walk$3(dom, newRng, nodes => {
each$e(nodes, n => {
if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
splitToFormatRoot(n);
}
});
});
splitToFormatRoot(startContainer);
splitToFormatRoot(endContainer);
startContainer = unwrap(true);
endContainer = unwrap();
} else {
startContainer = endContainer = splitToFormatRoot(startContainer);
}
expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
expandedRng.startOffset = dom.nodeIndex(startContainer);
expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
expandedRng.endOffset = dom.nodeIndex(endContainer) + 1;
}
walk$3(dom, expandedRng, nodes => {
each$e(nodes, process);
});
};
if (node) {
if (isNode(node)) {
const rng = dom.createRng();
rng.setStartBefore(node);
rng.setEndAfter(node);
removeRngStyle(rng);
} else {
removeRngStyle(node);
}
fireFormatRemove(ed, name, node, vars);
return;
}
if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode));
ed.nodeChanged();
} else {
removeCaretFormat(ed, name, vars, similar);
}
removeListStyleFormats(ed, name, vars);
fireFormatRemove(ed, name, node, vars);
};
const removeFormat$1 = (ed, name, vars, node, similar) => {
if (node || ed.selection.isEditable()) {
removeFormatInternal(ed, name, vars, node, similar);
}
};
const removeNodeFormat = (editor, format, vars, node, compareNode) => {
return removeNodeFormatInternal(editor, format, vars, node, compareNode).fold(never, newName => {
editor.dom.rename(node, newName);
return true;
}, always);
};
const each$6 = Tools.each;
const mergeTextDecorationsAndColor = (dom, format, vars, node) => {
const processTextDecorationsAndColor = n => {
if (isHTMLElement(n) && isElement$6(n.parentNode) && dom.isEditable(n)) {
const parentTextDecoration = getTextDecoration(dom, n.parentNode);
if (dom.getStyle(n, 'color') && parentTextDecoration) {
dom.setStyle(n, 'text-decoration', parentTextDecoration);
} else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) {
dom.setStyle(n, 'text-decoration', null);
}
}
};
if (format.styles && (format.styles.color || format.styles.textDecoration)) {
Tools.walk(node, processTextDecorationsAndColor, 'childNodes');
processTextDecorationsAndColor(node);
}
};
const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => {
if (format.styles && format.styles.backgroundColor) {
const hasFontSize = hasStyle(dom, 'fontSize');
processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars)));
}
};
const mergeSubSup = (dom, format, vars, node) => {
if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) {
const hasFontSize = hasStyle(dom, 'fontSize');
processChildElements(node, elm => hasFontSize(elm) && dom.isEditable(elm), applyStyle(dom, 'fontSize', ''));
const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), dom.isEditable);
dom.remove(inverseTagDescendants, true);
}
};
const mergeWithChildren = (editor, formatList, vars, node) => {
each$6(formatList, format => {
if (isInlineFormat(format)) {
each$6(editor.dom.select(format.inline, node), child => {
if (isElementNode(child)) {
removeNodeFormat(editor, format, vars, child, format.exact ? child : null);
}
});
}
clearChildStyles(editor.dom, format, node);
});
};
const mergeWithParents = (editor, format, name, vars, node) => {
const parentNode = node.parentNode;
if (matchNode(editor, parentNode, name, vars)) {
if (removeNodeFormat(editor, format, vars, node)) {
return;
}
}
if (format.merge_with_parents && parentNode) {
editor.dom.getParent(parentNode, parent => {
if (matchNode(editor, parent, name, vars)) {
removeNodeFormat(editor, format, vars, node);
return true;
} else {
return false;
}
});
}
};
const each$5 = Tools.each;
const canFormatBR = (editor, format, node, parentName) => {
if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) {
const validBRParentElements = getTextRootBlockElements(editor.schema);
const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom));
return hasNonNullableKey(validBRParentElements, parentName) && isEmptyNode(editor.schema, node.parentNode, {
skipBogus: false,
includeZwsp: true
}) && !hasCaretNodeSibling;
} else {
return false;
}
};
const applyStyles = (dom, elm, format, vars) => {
each$5(format.styles, (value, name) => {
dom.setStyle(elm, name, replaceVars(value, vars));
});
if (format.styles) {
const styleVal = dom.getAttrib(elm, 'style');
if (styleVal) {
dom.setAttrib(elm, 'data-mce-style', styleVal);
}
}
};
const applyFormatAction = (ed, name, vars, node) => {
const formatList = ed.formatter.get(name);
const format = formatList[0];
const isCollapsed = !node && ed.selection.isCollapsed();
const dom = ed.dom;
const selection = ed.selection;
const setElementFormat = (elm, fmt = format) => {
if (isFunction(fmt.onformat)) {
fmt.onformat(elm, fmt, vars, node);
}
applyStyles(dom, elm, fmt, vars);
each$5(fmt.attributes, (value, name) => {
dom.setAttrib(elm, name, replaceVars(value, vars));
});
each$5(fmt.classes, value => {
const newValue = replaceVars(value, vars);
if (!dom.hasClass(elm, newValue)) {
dom.addClass(elm, newValue);
}
});
};
const applyNodeStyle = (formatList, node) => {
let found = false;
each$5(formatList, format => {
if (!isSelectorFormat(format)) {
return false;
}
if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) {
return true;
}
if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) {
return true;
}
if (dom.is(node, format.selector) && !isCaretNode(node)) {
setElementFormat(node, format);
found = true;
return false;
}
return true;
});
return found;
};
const createWrapElement = wrapName => {
if (isString(wrapName)) {
const wrapElm = dom.create(wrapName);
setElementFormat(wrapElm);
return wrapElm;
} else {
return null;
}
};
const applyRngStyle = (dom, rng, nodeSpecific) => {
const newWrappers = [];
let contentEditable = true;
const wrapName = format.inline || format.block;
const wrapElm = createWrapElement(wrapName);
const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars);
const canRenameBlock = (node, parentName, isEditableDescendant) => {
const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName);
return isEditableDescendant && isValidBlockFormatForNode;
};
const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
const nodeName = node.nodeName.toLowerCase();
const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName);
const isZwsp$1 = !nodeSpecific && isText$b(node) && isZwsp(node.data);
const isCaret = isCaretNode(node);
const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node);
return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp$1 && !isCaret && isCorrectFormatForNode;
};
walk$3(dom, rng, nodes => {
let currentWrapElm;
const process = node => {
let hasContentEditableState = false;
let lastContentEditable = contentEditable;
let isWrappableNoneditableElm = false;
const parentNode = node.parentNode;
const parentName = parentNode.nodeName.toLowerCase();
const contentEditableValue = dom.getContentEditable(node);
if (isNonNullable(contentEditableValue)) {
lastContentEditable = contentEditable;
contentEditable = contentEditableValue === 'true';
hasContentEditableState = true;
isWrappableNoneditableElm = isWrappableNoneditable(ed, node);
}
const isEditableDescendant = contentEditable && !hasContentEditableState;
if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) {
currentWrapElm = null;
if (isBlockFormat(format)) {
dom.remove(node);
}
return;
}
if (isMatchingWrappingBlock(node)) {
currentWrapElm = null;
return;
}
if (canRenameBlock(node, parentName, isEditableDescendant)) {
const elm = dom.rename(node, wrapName);
setElementFormat(elm);
newWrappers.push(elm);
currentWrapElm = null;
return;
}
if (isSelectorFormat(format)) {
let found = applyNodeStyle(formatList, node);
if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
found = applyNodeStyle(formatList, parentNode);
}
if (!isInlineFormat(format) || found) {
currentWrapElm = null;
return;
}
}
if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) {
if (!currentWrapElm) {
currentWrapElm = dom.clone(wrapElm, false);
parentNode.insertBefore(currentWrapElm, node);
newWrappers.push(currentWrapElm);
}
if (isWrappableNoneditableElm && hasContentEditableState) {
contentEditable = lastContentEditable;
}
currentWrapElm.appendChild(node);
} else {
currentWrapElm = null;
each$e(from(node.childNodes), process);
if (hasContentEditableState) {
contentEditable = lastContentEditable;
}
currentWrapElm = null;
}
};
each$e(nodes, process);
});
if (format.links === true) {
each$e(newWrappers, node => {
const process = node => {
if (node.nodeName === 'A') {
setElementFormat(node, format);
}
each$e(from(node.childNodes), process);
};
process(node);
});
}
each$e(newWrappers, node => {
const getChildCount = node => {
let count = 0;
each$e(node.childNodes, node => {
if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) {
count++;
}
});
return count;
};
const mergeStyles = node => {
const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format));
return childElement.map(child => {
const clone = dom.clone(child, false);
setElementFormat(clone);
dom.replace(clone, node, true);
dom.remove(child, true);
return clone;
}).getOr(node);
};
const childCount = getChildCount(node);
if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
dom.remove(node, true);
return;
}
if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
if (!format.exact && childCount === 1) {
node = mergeStyles(node);
}
mergeWithChildren(ed, formatList, vars, node);
mergeWithParents(ed, format, name, vars, node);
mergeBackgroundColorAndFontSize(dom, format, vars, node);
mergeTextDecorationsAndColor(dom, format, vars, node);
mergeSubSup(dom, format, vars, node);
mergeSiblings(ed, format, vars, node);
}
});
};
const targetNode = isNode(node) ? node : selection.getNode();
if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) {
node = targetNode;
applyNodeStyle(formatList, node);
fireFormatApply(ed, name, node, vars);
return;
}
if (format) {
if (node) {
if (isNode(node)) {
if (!applyNodeStyle(formatList, node)) {
const rng = dom.createRng();
rng.setStartBefore(node);
rng.setEndAfter(node);
applyRngStyle(dom, expandRng(dom, rng, formatList), true);
}
} else {
applyRngStyle(dom, node, true);
}
} else {
if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
selection.setRng(normalize(selection.getRng()));
preserveSelection(ed, () => {
runOnRanges(ed, (selectionRng, fake) => {
const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList);
applyRngStyle(dom, expandedRng, false);
});
}, always);
ed.nodeChanged();
} else {
applyCaretFormat(ed, name, vars);
}
getExpandedListItemFormat(ed.formatter, name).each(liFmt => {
each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars));
});
}
postProcess$1(name, ed);
}
fireFormatApply(ed, name, node, vars);
};
const applyFormat$1 = (editor, name, vars, node) => {
if (node || editor.selection.isEditable()) {
applyFormatAction(editor, name, vars, node);
}
};
const hasVars = value => has$2(value, 'vars');
const setup$u = (registeredFormatListeners, editor) => {
registeredFormatListeners.set({});
editor.on('NodeChange', e => {
updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
});
editor.on('FormatApply FormatRemove', e => {
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));
updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
});
};
const fallbackElement = editor => editor.selection.getStart();
const matchingNode = (editor, parents, format, similar, vars) => {
const isMatchingNode = node => {
const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
return !isUndefined(matchingFormat);
};
const isUnableToMatch = node => {
if (matchesUnInheritedFormatSelector(editor, node, format)) {
return true;
} else {
if (!similar) {
return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
} else {
return false;
}
}
};
return findUntil$1(parents, isMatchingNode, isUnableToMatch);
};
const getParents = (editor, elm) => {
const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$1(node));
};
const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
const parents = getParents(editor, elm);
each$d(registeredCallbacks, (data, format) => {
const runIfChanged = spec => {
const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined);
const isSet = match.isSome();
if (spec.state.get() !== isSet) {
spec.state.set(isSet);
const node = match.getOr(elm);
if (hasVars(spec)) {
spec.callback(isSet, {
node,
format,
parents
});
} else {
each$e(spec.callbacks, callback => callback(isSet, {
node,
format,
parents
}));
}
}
};
each$e([
data.withSimilar,
data.withoutSimilar
], runIfChanged);
each$e(data.withVars, runIfChanged);
});
};
const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
const formatChangeItems = registeredFormatListeners.get();
each$e(formats.split(','), format => {
const group = get$a(formatChangeItems, format).getOrThunk(() => {
const base = {
withSimilar: {
state: Cell(false),
similar: true,
callbacks: []
},
withoutSimilar: {
state: Cell(false),
similar: false,
callbacks: []
},
withVars: []
};
formatChangeItems[format] = base;
return base;
});
const getCurrent = () => {
const parents = getParents(editor);
return matchingNode(editor, parents, format, similar, vars).isSome();
};
if (isUndefined(vars)) {
const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
toAppendTo.callbacks.push(callback);
if (toAppendTo.callbacks.length === 1) {
toAppendTo.state.set(getCurrent());
}
} else {
group.withVars.push({
state: Cell(getCurrent()),
similar,
vars,
callback
});
}
});
registeredFormatListeners.set(formatChangeItems);
};
const removeListeners = (registeredFormatListeners, formats, callback) => {
const formatChangeItems = registeredFormatListeners.get();
each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => {
formatChangeItems[format] = {
withSimilar: {
...group.withSimilar,
callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback)
},
withoutSimilar: {
...group.withoutSimilar,
callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback)
},
withVars: filter$5(group.withVars, item => item.callback !== callback)
};
}));
registeredFormatListeners.set(formatChangeItems);
};
const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
};
const toggle = (editor, name, vars, node) => {
const fmt = editor.formatter.get(name);
if (fmt) {
if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
removeFormat$1(editor, name, vars, node);
} else {
applyFormat$1(editor, name, vars, node);
}
}
};
const explode$1 = Tools.explode;
const create$8 = () => {
const filters = {};
const addFilter = (name, callback) => {
each$e(explode$1(name), name => {
if (!has$2(filters, name)) {
filters[name] = {
name,
callbacks: []
};
}
filters[name].callbacks.push(callback);
});
};
const getFilters = () => values(filters);
const removeFilter = (name, callback) => {
each$e(explode$1(name), name => {
if (has$2(filters, name)) {
if (isNonNullable(callback)) {
const filter = filters[name];
const newCallbacks = filter$5(filter.callbacks, c => c !== callback);
if (newCallbacks.length > 0) {
filter.callbacks = newCallbacks;
} else {
delete filters[name];
}
} else {
delete filters[name];
}
}
});
};
return {
addFilter,
getFilters,
removeFilter
};
};
const removeAttrs = (node, names) => {
each$e(names, name => {
node.attr(name, null);
});
};
const addFontToSpansFilter = (domParser, styles, fontSizes) => {
domParser.addNodeFilter('font', nodes => {
each$e(nodes, node => {
const props = styles.parse(node.attr('style'));
const color = node.attr('color');
const face = node.attr('face');
const size = node.attr('size');
if (color) {
props.color = color;
}
if (face) {
props['font-family'] = face;
}
if (size) {
toInt(size).each(num => {
props['font-size'] = fontSizes[num - 1];
});
}
node.name = 'span';
node.attr('style', styles.serialize(props));
removeAttrs(node, [
'color',
'face',
'size'
]);
});
});
};
const addStrikeFilter = (domParser, schema, styles) => {
domParser.addNodeFilter('strike', nodes => {
const convertToSTag = schema.type !== 'html4';
each$e(nodes, node => {
if (convertToSTag) {
node.name = 's';
} else {
const props = styles.parse(node.attr('style'));
props['text-decoration'] = 'line-through';
node.name = 'span';
node.attr('style', styles.serialize(props));
}
});
});
};
const addFilters = (domParser, settings, schema) => {
var _a;
const styles = Styles();
if (settings.convert_fonts_to_spans) {
addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : ''));
}
addStrikeFilter(domParser, schema, styles);
};
const register$5 = (domParser, settings, schema) => {
if (settings.inline_styles) {
addFilters(domParser, settings, schema);
}
};
const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject({
message: `Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`,
uriType: 'blob'
}));
const extractBase64Data = data => {
const matches = /([a-z0-9+\/=\s]+)/i.exec(data);
return matches ? matches[1] : '';
};
const parseDataUri = uri => {
const [type, ...rest] = uri.split(',');
const data = rest.join(',');
const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type);
if (matches) {
const base64Encoded = matches[2] === ';base64';
const extractedData = base64Encoded ? extractBase64Data(data) : decodeURIComponent(data);
return Optional.some({
type: matches[1],
data: extractedData,
base64Encoded
});
} else {
return Optional.none();
}
};
const buildBlob = (type, data, base64Encoded = true) => {
let str = data;
if (base64Encoded) {
try {
str = atob(data);
} catch (e) {
return Optional.none();
}
}
const arr = new Uint8Array(str.length);
for (let i = 0; i < arr.length; i++) {
arr[i] = str.charCodeAt(i);
}
return Optional.some(new Blob([arr], { type }));
};
const dataUriToBlob = uri => {
return new Promise((resolve, reject) => {
parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve);
});
};
const uriToBlob = url => {
if (startsWith(url, 'blob:')) {
return blobUriToBlob(url);
} else if (startsWith(url, 'data:')) {
return dataUriToBlob(url);
} else {
return Promise.reject('Unknown URI format');
}
};
const blobToDataUri = blob => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
resolve(reader.result);
};
reader.onerror = () => {
var _a;
reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
};
reader.readAsDataURL(blob);
});
};
let count$1 = 0;
const uniqueId$1 = prefix => {
return (prefix || 'blobid') + count$1++;
};
const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => {
if (base64Only && !base64Encoded) {
return Optional.none();
} else {
const base64 = base64Encoded ? data : btoa(data);
return generateBlobInfo(base64, type);
}
});
};
const createBlobInfo$1 = (blobCache, blob, base64) => {
const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
blobCache.add(blobInfo);
return blobInfo;
};
const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64))));
};
const imageToBlobInfo = (blobCache, imageSrc) => {
const invalidDataUri = () => Promise.reject('Invalid data URI');
if (startsWith(imageSrc, 'blob:')) {
const blobInfo = blobCache.getByUri(imageSrc);
if (isNonNullable(blobInfo)) {
return Promise.resolve(blobInfo);
} else {
return uriToBlob(imageSrc).then(blob => {
return blobToDataUri(blob).then(dataUri => {
return processDataUri(dataUri, false, base64 => {
return Optional.some(createBlobInfo$1(blobCache, blob, base64));
}).getOrThunk(invalidDataUri);
});
});
}
} else if (startsWith(imageSrc, 'data:')) {
return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo));
} else {
return Promise.reject('Unknown image data format');
}
};
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]+)?)?)$/;
const extractHost = url => Optional.from(url.match(hostCaptureRegex)).bind(ms => get$b(ms, 1)).map(h => startsWith(h, 'www.') ? h.substring(4) : h);
const sandboxIframe = (iframeNode, exclusions) => {
if (Optional.from(iframeNode.attr('src')).bind(extractHost).forall(host => !contains$2(exclusions, host))) {
iframeNode.attr('sandbox', '');
}
};
const isMimeType = (mime, type) => startsWith(mime, `${ type }/`);
const getEmbedType = type => {
if (isUndefined(type)) {
return 'iframe';
} else if (isMimeType(type, 'image')) {
return 'img';
} else if (isMimeType(type, 'video')) {
return 'video';
} else if (isMimeType(type, 'audio')) {
return 'audio';
} else {
return 'iframe';
}
};
const createSafeEmbed = ({type, src, width, height} = {}, sandboxIframes, sandboxIframesExclusions) => {
const name = getEmbedType(type);
const embed = new AstNode(name, 1);
embed.attr(name === 'audio' ? { src } : {
src,
width,
height
});
if (name === 'audio' || name === 'video') {
embed.attr('controls', '');
}
if (name === 'iframe' && sandboxIframes) {
sandboxIframe(embed, sandboxIframesExclusions);
}
return embed;
};
const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus'));
const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder'));
const registerBase64ImageFilter = (parser, settings) => {
const {blob_cache: blobCache} = settings;
if (blobCache) {
const processImage = img => {
const inputSrc = img.attr('src');
if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) {
return;
}
dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => {
img.attr('src', blobInfo.blobUri());
});
};
parser.addAttributeFilter('src', nodes => each$e(nodes, processImage));
}
};
const register$4 = (parser, settings) => {
var _a, _b;
const schema = parser.schema;
parser.addAttributeFilter('href', nodes => {
let i = nodes.length;
const appendRel = rel => {
const parts = rel.split(' ').filter(p => p.length > 0);
return parts.concat(['noopener']).sort().join(' ');
};
const addNoOpener = rel => {
const newRel = rel ? Tools.trim(rel) : '';
if (!/\b(noopener)\b/g.test(newRel)) {
return appendRel(newRel);
} else {
return newRel;
}
};
if (!settings.allow_unsafe_link_target) {
while (i--) {
const node = nodes[i];
if (node.name === 'a' && node.attr('target') === '_blank') {
node.attr('rel', addNoOpener(node.attr('rel')));
}
}
}
});
if (!settings.allow_html_in_named_anchor) {
parser.addAttributeFilter('id,name', nodes => {
let i = nodes.length, sibling, prevSibling, parent, node;
while (i--) {
node = nodes[i];
if (node.name === 'a' && node.firstChild && !node.attr('href')) {
parent = node.parent;
sibling = node.lastChild;
while (sibling && parent) {
prevSibling = sibling.prev;
parent.insert(sibling, node);
sibling = prevSibling;
}
}
}
});
}
if (settings.fix_list_elements) {
parser.addNodeFilter('ul,ol', nodes => {
let i = nodes.length, node, parentNode;
while (i--) {
node = nodes[i];
parentNode = node.parent;
if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) {
if (node.prev && node.prev.name === 'li') {
node.prev.append(node);
} else {
const li = new AstNode('li', 1);
li.attr('style', 'list-style-type: none');
node.wrap(li);
}
}
}
});
}
const validClasses = schema.getValidClasses();
if (settings.validate && validClasses) {
parser.addAttributeFilter('class', nodes => {
var _a;
let i = nodes.length;
while (i--) {
const node = nodes[i];
const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : '';
const classList = Tools.explode(clazz, ' ');
let classValue = '';
for (let ci = 0; ci < classList.length; ci++) {
const className = classList[ci];
let valid = false;
let validClassesMap = validClasses['*'];
if (validClassesMap && validClassesMap[className]) {
valid = true;
}
validClassesMap = validClasses[node.name];
if (!valid && validClassesMap && validClassesMap[className]) {
valid = true;
}
if (valid) {
if (classValue) {
classValue += ' ';
}
classValue += className;
}
}
if (!classValue.length) {
classValue = null;
}
node.attr('class', classValue);
}
});
}
registerBase64ImageFilter(parser, settings);
const shouldSandboxIframes = (_a = settings.sandbox_iframes) !== null && _a !== void 0 ? _a : false;
const sandboxIframesExclusions = unique$1((_b = settings.sandbox_iframes_exclusions) !== null && _b !== void 0 ? _b : []);
if (settings.convert_unsafe_embeds) {
parser.addNodeFilter('object,embed', nodes => each$e(nodes, node => {
node.replace(createSafeEmbed({
type: node.attr('type'),
src: node.name === 'object' ? node.attr('data') : node.attr('src'),
width: node.attr('width'),
height: node.attr('height')
}, shouldSandboxIframes, sandboxIframesExclusions));
}));
}
if (shouldSandboxIframes) {
parser.addNodeFilter('iframe', nodes => each$e(nodes, node => sandboxIframe(node, sandboxIframesExclusions)));
}
};
const {entries, setPrototypeOf, isFrozen, getPrototypeOf, getOwnPropertyDescriptor} = Object;
let {freeze, seal, create: create$7} = Object;
let {apply, construct} = typeof Reflect !== 'undefined' && Reflect;
if (!apply) {
apply = function apply(fun, thisValue, args) {
return fun.apply(thisValue, args);
};
}
if (!freeze) {
freeze = function freeze(x) {
return x;
};
}
if (!seal) {
seal = function seal(x) {
return x;
};
}
if (!construct) {
construct = function construct(Func, args) {
return new Func(...args);
};
}
const arrayForEach = unapply(Array.prototype.forEach);
const arrayPop = unapply(Array.prototype.pop);
const arrayPush = unapply(Array.prototype.push);
const stringToLowerCase = unapply(String.prototype.toLowerCase);
const stringToString = unapply(String.prototype.toString);
const stringMatch = unapply(String.prototype.match);
const stringReplace = unapply(String.prototype.replace);
const stringIndexOf = unapply(String.prototype.indexOf);
const stringTrim = unapply(String.prototype.trim);
const regExpTest = unapply(RegExp.prototype.test);
const typeErrorCreate = unconstruct(TypeError);
function unapply(func) {
return function (thisArg) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
return apply(func, thisArg, args);
};
}
function unconstruct(func) {
return function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return construct(func, args);
};
}
function addToSet(set, array, transformCaseFunc) {
var _transformCaseFunc;
transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;
if (setPrototypeOf) {
setPrototypeOf(set, null);
}
let l = array.length;
while (l--) {
let element = array[l];
if (typeof element === 'string') {
const lcElement = transformCaseFunc(element);
if (lcElement !== element) {
if (!isFrozen(array)) {
array[l] = lcElement;
}
element = lcElement;
}
}
set[element] = true;
}
return set;
}
function clone(object) {
const newObject = create$7(null);
for (const [property, value] of entries(object)) {
newObject[property] = value;
}
return newObject;
}
function lookupGetter(object, prop) {
while (object !== null) {
const desc = getOwnPropertyDescriptor(object, prop);
if (desc) {
if (desc.get) {
return unapply(desc.get);
}
if (typeof desc.value === 'function') {
return unapply(desc.value);
}
}
object = getPrototypeOf(object);
}
function fallbackValue(element) {
console.warn('fallback value for', element);
return null;
}
return fallbackValue;
}
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'
]);
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'
]);
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'
]);
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'
]);
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'
]);
const mathMlDisallowed = freeze([
'maction',
'maligngroup',
'malignmark',
'mlongdiv',
'mscarries',
'mscarry',
'msgroup',
'mstack',
'msline',
'msrow',
'semantics',
'annotation',
'annotation-xml',
'mprescripts',
'none'
]);
const text = freeze(['#text']);
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',
'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',
'xmlns',
'slot'
]);
const svg = freeze([
'accent-height',
'accumulate',
'additive',
'alignment-baseline',
'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',
'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',
'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',
'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',
'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'
]);
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'
]);
const xml = freeze([
'xlink:href',
'xml:id',
'xlink:title',
'xml:space',
'xmlns:xlink'
]);
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
const ARIA_ATTR = seal(/^aria-[\-\w]+$/);
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
const DOCTYPE_NAME = seal(/^html$/i);
var EXPRESSIONS = Object.freeze({
__proto__: null,
MUSTACHE_EXPR: MUSTACHE_EXPR,
ERB_EXPR: ERB_EXPR,
TMPLIT_EXPR: TMPLIT_EXPR,
DATA_ATTR: DATA_ATTR,
ARIA_ATTR: ARIA_ATTR,
IS_ALLOWED_URI: IS_ALLOWED_URI,
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
ATTR_WHITESPACE: ATTR_WHITESPACE,
DOCTYPE_NAME: DOCTYPE_NAME
});
const getGlobal = () => typeof window === 'undefined' ? null : window;
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
return null;
}
let suffix = null;
const ATTR_NAME = 'data-tt-policy-suffix';
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
suffix = purifyHostElement.getAttribute(ATTR_NAME);
}
const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
try {
return trustedTypes.createPolicy(policyName, {
createHTML(html) {
return html;
},
createScriptURL(scriptUrl) {
return scriptUrl;
}
});
} catch (_) {
console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
return null;
}
};
function createDOMPurify() {
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
const DOMPurify = root => createDOMPurify(root);
DOMPurify.version = '3.0.5';
DOMPurify.removed = [];
if (!window || !window.document || window.document.nodeType !== 9) {
DOMPurify.isSupported = false;
return DOMPurify;
}
const originalDocument = window.document;
const currentScript = originalDocument.currentScript;
let {document} = window;
const {DocumentFragment, HTMLTemplateElement, Node, Element, NodeFilter, NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap, HTMLFormElement, DOMParser, trustedTypes} = window;
const ElementPrototype = Element.prototype;
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
if (typeof HTMLTemplateElement === 'function') {
const template = document.createElement('template');
if (template.content && template.content.ownerDocument) {
document = template.content.ownerDocument;
}
}
let trustedTypesPolicy;
let emptyHTML = '';
const {implementation, createNodeIterator, createDocumentFragment, getElementsByTagName} = document;
const {importNode} = originalDocument;
let hooks = {};
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
const {MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR, DATA_ATTR, ARIA_ATTR, IS_SCRIPT_OR_DATA, ATTR_WHITESPACE} = EXPRESSIONS;
let {IS_ALLOWED_URI: IS_ALLOWED_URI$1} = EXPRESSIONS;
let ALLOWED_TAGS = null;
const DEFAULT_ALLOWED_TAGS = addToSet({}, [
...html$1,
...svg$1,
...svgFilters,
...mathMl$1,
...text
]);
let ALLOWED_ATTR = null;
const DEFAULT_ALLOWED_ATTR = addToSet({}, [
...html,
...svg,
...mathMl,
...xml
]);
let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
tagNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
attributeNameCheck: {
writable: true,
configurable: false,
enumerable: true,
value: null
},
allowCustomizedBuiltInElements: {
writable: true,
configurable: false,
enumerable: true,
value: false
}
}));
let FORBID_TAGS = null;
let FORBID_ATTR = null;
let ALLOW_ARIA_ATTR = true;
let ALLOW_DATA_ATTR = true;
let ALLOW_UNKNOWN_PROTOCOLS = false;
let ALLOW_SELF_CLOSE_IN_ATTR = true;
let SAFE_FOR_TEMPLATES = false;
let WHOLE_DOCUMENT = false;
let SET_CONFIG = false;
let FORCE_BODY = false;
let RETURN_DOM = false;
let RETURN_DOM_FRAGMENT = false;
let RETURN_TRUSTED_TYPE = false;
let SANITIZE_DOM = true;
let SANITIZE_NAMED_PROPS = false;
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
let KEEP_CONTENT = true;
let IN_PLACE = false;
let USE_PROFILES = {};
let FORBID_CONTENTS = null;
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'
]);
let DATA_URI_TAGS = null;
const DEFAULT_DATA_URI_TAGS = addToSet({}, [
'audio',
'video',
'img',
'source',
'image',
'track'
]);
let URI_SAFE_ATTRIBUTES = null;
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
'alt',
'class',
'for',
'id',
'label',
'name',
'pattern',
'placeholder',
'role',
'summary',
'title',
'value',
'style',
'xmlns'
]);
const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
let NAMESPACE = HTML_NAMESPACE;
let IS_EMPTY_INPUT = false;
let ALLOWED_NAMESPACES = null;
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [
MATHML_NAMESPACE,
SVG_NAMESPACE,
HTML_NAMESPACE
], stringToString);
let PARSER_MEDIA_TYPE;
const SUPPORTED_PARSER_MEDIA_TYPES = [
'application/xhtml+xml',
'text/html'
];
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
let transformCaseFunc;
let CONFIG = null;
const formElement = document.createElement('form');
const isRegexOrFunction = function isRegexOrFunction(testValue) {
return testValue instanceof RegExp || testValue instanceof Function;
};
const _parseConfig = function _parseConfig(cfg) {
if (CONFIG && CONFIG === cfg) {
return;
}
if (!cfg || typeof cfg !== 'object') {
cfg = {};
}
cfg = clone(cfg);
PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false;
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
RETURN_DOM = cfg.RETURN_DOM || false;
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
FORCE_BODY = cfg.FORCE_BODY || false;
SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false;
KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
IN_PLACE = cfg.IN_PLACE || false;
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
}
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
}
if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
}
if (SAFE_FOR_TEMPLATES) {
ALLOW_DATA_ATTR = false;
}
if (RETURN_DOM_FRAGMENT) {
RETURN_DOM = true;
}
if (USE_PROFILES) {
ALLOWED_TAGS = addToSet({}, [...text]);
ALLOWED_ATTR = [];
if (USE_PROFILES.html === true) {
addToSet(ALLOWED_TAGS, html$1);
addToSet(ALLOWED_ATTR, html);
}
if (USE_PROFILES.svg === true) {
addToSet(ALLOWED_TAGS, svg$1);
addToSet(ALLOWED_ATTR, svg);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.svgFilters === true) {
addToSet(ALLOWED_TAGS, svgFilters);
addToSet(ALLOWED_ATTR, svg);
addToSet(ALLOWED_ATTR, xml);
}
if (USE_PROFILES.mathMl === true) {
addToSet(ALLOWED_TAGS, mathMl$1);
addToSet(ALLOWED_ATTR, mathMl);
addToSet(ALLOWED_ATTR, xml);
}
}
if (cfg.ADD_TAGS) {
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
ALLOWED_TAGS = clone(ALLOWED_TAGS);
}
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
}
if (cfg.ADD_ATTR) {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
ALLOWED_ATTR = clone(ALLOWED_ATTR);
}
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
}
if (cfg.ADD_URI_SAFE_ATTR) {
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
}
if (cfg.FORBID_CONTENTS) {
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
FORBID_CONTENTS = clone(FORBID_CONTENTS);
}
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
}
if (KEEP_CONTENT) {
ALLOWED_TAGS['#text'] = true;
}
if (WHOLE_DOCUMENT) {
addToSet(ALLOWED_TAGS, [
'html',
'head',
'body'
]);
}
if (ALLOWED_TAGS.table) {
addToSet(ALLOWED_TAGS, ['tbody']);
delete FORBID_TAGS.tbody;
}
if (cfg.TRUSTED_TYPES_POLICY) {
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
}
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
}
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
emptyHTML = trustedTypesPolicy.createHTML('');
} else {
if (trustedTypesPolicy === undefined) {
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
}
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
emptyHTML = trustedTypesPolicy.createHTML('');
}
}
if (freeze) {
freeze(cfg);
}
CONFIG = cfg;
};
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
'mi',
'mo',
'mn',
'ms',
'mtext'
]);
const HTML_INTEGRATION_POINTS = addToSet({}, [
'foreignobject',
'desc',
'title',
'annotation-xml'
]);
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
'title',
'style',
'font',
'a',
'script'
]);
const ALL_SVG_TAGS = addToSet({}, svg$1);
addToSet(ALL_SVG_TAGS, svgFilters);
addToSet(ALL_SVG_TAGS, svgDisallowed);
const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
const _checkValidNamespace = function _checkValidNamespace(element) {
let parent = getParentNode(element);
if (!parent || !parent.tagName) {
parent = {
namespaceURI: NAMESPACE,
tagName: 'template'
};
}
const tagName = stringToLowerCase(element.tagName);
const parentTagName = stringToLowerCase(parent.tagName);
if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
return false;
}
if (element.namespaceURI === SVG_NAMESPACE) {
if (parent.namespaceURI === HTML_NAMESPACE) {
return tagName === 'svg';
}
if (parent.namespaceURI === MATHML_NAMESPACE) {
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
}
return Boolean(ALL_SVG_TAGS[tagName]);
}
if (element.namespaceURI === MATHML_NAMESPACE) {
if (parent.namespaceURI === HTML_NAMESPACE) {
return tagName === 'math';
}
if (parent.namespaceURI === SVG_NAMESPACE) {
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
}
return Boolean(ALL_MATHML_TAGS[tagName]);
}
if (element.namespaceURI === HTML_NAMESPACE) {
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
return false;
}
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
return false;
}
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
}
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
return true;
}
return false;
};
const _forceRemove = function _forceRemove(node) {
arrayPush(DOMPurify.removed, { element: node });
try {
node.parentNode.removeChild(node);
} catch (_) {
node.remove();
}
};
const _removeAttribute = function _removeAttribute(name, node) {
try {
arrayPush(DOMPurify.removed, {
attribute: node.getAttributeNode(name),
from: node
});
} catch (_) {
arrayPush(DOMPurify.removed, {
attribute: null,
from: node
});
}
node.removeAttribute(name);
if (name === 'is' && !ALLOWED_ATTR[name]) {
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
try {
_forceRemove(node);
} catch (_) {
}
} else {
try {
node.setAttribute(name, '');
} catch (_) {
}
}
}
};
const _initDocument = function _initDocument(dirty) {
let doc;
let leadingWhitespace;
if (FORCE_BODY) {
dirty = ' ' + dirty;
} else {
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
leadingWhitespace = matches && matches[0];
}
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
dirty = '' + dirty + '';
}
const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
if (NAMESPACE === HTML_NAMESPACE) {
try {
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
} catch (_) {
}
}
if (!doc || !doc.documentElement) {
doc = implementation.createDocument(NAMESPACE, 'template', null);
try {
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
} catch (_) {
}
}
const body = doc.body || doc.documentElement;
if (dirty && leadingWhitespace) {
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
}
if (NAMESPACE === HTML_NAMESPACE) {
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
}
return WHOLE_DOCUMENT ? doc.documentElement : body;
};
const _createIterator = function _createIterator(root) {
return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
};
const _isClobbered = function _isClobbered(elm) {
return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
};
const _isNode = function _isNode(object) {
return typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
};
const _executeHook = function _executeHook(entryPoint, currentNode, data) {
if (!hooks[entryPoint]) {
return;
}
arrayForEach(hooks[entryPoint], hook => {
hook.call(DOMPurify, currentNode, data, CONFIG);
});
};
const _sanitizeElements = function _sanitizeElements(currentNode) {
let content;
_executeHook('beforeSanitizeElements', currentNode, null);
if (_isClobbered(currentNode)) {
_forceRemove(currentNode);
return true;
}
const tagName = transformCaseFunc(currentNode.nodeName);
_executeHook('uponSanitizeElement', currentNode, {
tagName,
allowedTags: ALLOWED_TAGS
});
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
_forceRemove(currentNode);
return true;
}
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName))
return false;
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName))
return false;
}
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
if (childNodes && parentNode) {
const childCount = childNodes.length;
for (let i = childCount - 1; i >= 0; --i) {
parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
}
}
}
_forceRemove(currentNode);
return true;
}
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
_forceRemove(currentNode);
return true;
}
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
_forceRemove(currentNode);
return true;
}
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
content = currentNode.textContent;
content = stringReplace(content, MUSTACHE_EXPR, ' ');
content = stringReplace(content, ERB_EXPR, ' ');
content = stringReplace(content, TMPLIT_EXPR, ' ');
if (currentNode.textContent !== content) {
arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
currentNode.textContent = content;
}
}
_executeHook('afterSanitizeElements', currentNode, null);
return false;
};
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
return false;
}
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]) {
if (_basicCustomElementTest(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) || lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)));
else {
return false;
}
} 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) {
return false;
} else ;
return true;
};
const _basicCustomElementTest = function _basicCustomElementTest(tagName) {
return tagName.indexOf('-') > 0;
};
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
let attr;
let value;
let lcName;
let l;
_executeHook('beforeSanitizeAttributes', currentNode, null);
const {attributes} = currentNode;
if (!attributes) {
return;
}
const hookEvent = {
attrName: '',
attrValue: '',
keepAttr: true,
allowedAttributes: ALLOWED_ATTR
};
l = attributes.length;
while (l--) {
attr = attributes[l];
const {name, namespaceURI} = attr;
value = name === 'value' ? attr.value : stringTrim(attr.value);
const initValue = value;
lcName = transformCaseFunc(name);
hookEvent.attrName = lcName;
hookEvent.attrValue = value;
hookEvent.keepAttr = true;
hookEvent.forceKeepAttr = undefined;
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
value = hookEvent.attrValue;
if (hookEvent.forceKeepAttr) {
continue;
}
if (!hookEvent.keepAttr) {
_removeAttribute(name, currentNode);
continue;
}
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
_removeAttribute(name, currentNode);
continue;
}
if (SAFE_FOR_TEMPLATES) {
value = stringReplace(value, MUSTACHE_EXPR, ' ');
value = stringReplace(value, ERB_EXPR, ' ');
value = stringReplace(value, TMPLIT_EXPR, ' ');
}
const lcTag = transformCaseFunc(currentNode.nodeName);
if (!_isValidAttribute(lcTag, lcName, value)) {
_removeAttribute(name, currentNode);
continue;
}
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
_removeAttribute(name, currentNode);
value = SANITIZE_NAMED_PROPS_PREFIX + value;
}
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
if (namespaceURI);
else {
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
case 'TrustedHTML': {
value = trustedTypesPolicy.createHTML(value);
break;
}
case 'TrustedScriptURL': {
value = trustedTypesPolicy.createScriptURL(value);
break;
}
}
}
}
if (value !== initValue) {
try {
if (namespaceURI) {
currentNode.setAttributeNS(namespaceURI, name, value);
} else {
currentNode.setAttribute(name, value);
}
} catch (_) {
_removeAttribute(name, currentNode);
}
}
}
_executeHook('afterSanitizeAttributes', currentNode, null);
};
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
let shadowNode;
const shadowIterator = _createIterator(fragment);
_executeHook('beforeSanitizeShadowDOM', fragment, null);
while (shadowNode = shadowIterator.nextNode()) {
_executeHook('uponSanitizeShadowNode', shadowNode, null);
if (_sanitizeElements(shadowNode)) {
continue;
}
if (shadowNode.content instanceof DocumentFragment) {
_sanitizeShadowDOM(shadowNode.content);
}
_sanitizeAttributes(shadowNode);
}
_executeHook('afterSanitizeShadowDOM', fragment, null);
};
DOMPurify.sanitize = function (dirty) {
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
let body;
let importedNode;
let currentNode;
let returnNode;
IS_EMPTY_INPUT = !dirty;
if (IS_EMPTY_INPUT) {
dirty = '';
}
if (typeof dirty !== 'string' && !_isNode(dirty)) {
if (typeof dirty.toString === 'function') {
dirty = dirty.toString();
if (typeof dirty !== 'string') {
throw typeErrorCreate('dirty is not a string, aborting');
}
} else {
throw typeErrorCreate('toString is not a function');
}
}
if (!DOMPurify.isSupported) {
return dirty;
}
if (!SET_CONFIG) {
_parseConfig(cfg);
}
DOMPurify.removed = [];
if (typeof dirty === 'string') {
IN_PLACE = false;
}
if (IN_PLACE) {
if (dirty.nodeName) {
const tagName = transformCaseFunc(dirty.nodeName);
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
}
}
} else if (dirty instanceof Node) {
body = _initDocument('');
importedNode = body.ownerDocument.importNode(dirty, true);
if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
body = importedNode;
} else if (importedNode.nodeName === 'HTML') {
body = importedNode;
} else {
body.appendChild(importedNode);
}
} else {
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
}
body = _initDocument(dirty);
if (!body) {
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
}
}
if (body && FORCE_BODY) {
_forceRemove(body.firstChild);
}
const nodeIterator = _createIterator(IN_PLACE ? dirty : body);
while (currentNode = nodeIterator.nextNode()) {
if (_sanitizeElements(currentNode)) {
continue;
}
if (currentNode.content instanceof DocumentFragment) {
_sanitizeShadowDOM(currentNode.content);
}
_sanitizeAttributes(currentNode);
}
if (IN_PLACE) {
return dirty;
}
if (RETURN_DOM) {
if (RETURN_DOM_FRAGMENT) {
returnNode = createDocumentFragment.call(body.ownerDocument);
while (body.firstChild) {
returnNode.appendChild(body.firstChild);
}
} else {
returnNode = body;
}
if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
returnNode = importNode.call(originalDocument, returnNode, true);
}
return returnNode;
}
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
serializedHTML = '\n' + serializedHTML;
}
if (SAFE_FOR_TEMPLATES) {
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');
serializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');
}
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
};
DOMPurify.setConfig = function (cfg) {
_parseConfig(cfg);
SET_CONFIG = true;
};
DOMPurify.clearConfig = function () {
CONFIG = null;
SET_CONFIG = false;
};
DOMPurify.isValidAttribute = function (tag, attr, value) {
if (!CONFIG) {
_parseConfig({});
}
const lcTag = transformCaseFunc(tag);
const lcName = transformCaseFunc(attr);
return _isValidAttribute(lcTag, lcName, value);
};
DOMPurify.addHook = function (entryPoint, hookFunction) {
if (typeof hookFunction !== 'function') {
return;
}
hooks[entryPoint] = hooks[entryPoint] || [];
arrayPush(hooks[entryPoint], hookFunction);
};
DOMPurify.removeHook = function (entryPoint) {
if (hooks[entryPoint]) {
return arrayPop(hooks[entryPoint]);
}
};
DOMPurify.removeHooks = function (entryPoint) {
if (hooks[entryPoint]) {
hooks[entryPoint] = [];
}
};
DOMPurify.removeAllHooks = function () {
hooks = {};
};
return DOMPurify;
}
var purify = createDOMPurify();
const each$4 = Tools.each, trim = Tools.trim;
const queryParts = [
'source',
'protocol',
'authority',
'userInfo',
'user',
'password',
'host',
'port',
'relative',
'path',
'directory',
'file',
'query',
'anchor'
];
const DEFAULT_PORTS = {
ftp: 21,
http: 80,
https: 443,
mailto: 25
};
const safeSvgDataUrlElements = [
'img',
'video'
];
const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
if (isNonNullable(allowSvgDataUrls)) {
return !allowSvgDataUrls;
} else {
return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
}
};
const decodeUri = encodedUri => {
try {
return decodeURIComponent(encodedUri);
} catch (ex) {
return unescape(encodedUri);
}
};
const isInvalidUri = (settings, uri, tagName) => {
const decodedUri = decodeUri(uri).replace(/\s/g, '');
if (settings.allow_script_urls) {
return false;
} else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
return true;
} else if (settings.allow_html_data_urls) {
return false;
} else if (/^data:image\//i.test(decodedUri)) {
return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
} else {
return /^data:/i.test(decodedUri);
}
};
class URI {
static parseDataUri(uri) {
let type;
const uriComponents = decodeURIComponent(uri).split(',');
const matches = /data:([^;]+)/.exec(uriComponents[0]);
if (matches) {
type = matches[1];
}
return {
type,
data: uriComponents[1]
};
}
static isDomSafe(uri, context, options = {}) {
if (options.allow_script_urls) {
return true;
} else {
const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, '');
return !isInvalidUri(options, decodedUri, context);
}
}
static getDocumentBaseUrl(loc) {
var _a;
let baseUrl;
if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : '';
} else {
baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
}
if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
if (!/[\/\\]$/.test(baseUrl)) {
baseUrl += '/';
}
}
return baseUrl;
}
constructor(url, settings = {}) {
this.path = '';
this.directory = '';
url = trim(url);
this.settings = settings;
const baseUri = settings.base_uri;
const self = this;
if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
self.source = url;
return;
}
const isProtocolRelative = url.indexOf('//') === 0;
if (url.indexOf('/') === 0 && !isProtocolRelative) {
url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
}
if (!/^[\w\-]*:?\/\//.test(url)) {
const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory;
if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') {
url = '//mce_host' + self.toAbsPath(baseUrl, url);
} else {
const match = /([^#?]*)([#?]?.*)/.exec(url);
if (match) {
url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
}
}
}
url = url.replace(/@@/g, '(mce_at)');
const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
if (urlMatch) {
each$4(queryParts, (v, i) => {
let part = urlMatch[i];
if (part) {
part = part.replace(/\(mce_at\)/g, '@@');
}
self[v] = part;
});
}
if (baseUri) {
if (!self.protocol) {
self.protocol = baseUri.protocol;
}
if (!self.userInfo) {
self.userInfo = baseUri.userInfo;
}
if (!self.port && self.host === 'mce_host') {
self.port = baseUri.port;
}
if (!self.host || self.host === 'mce_host') {
self.host = baseUri.host;
}
self.source = '';
}
if (isProtocolRelative) {
self.protocol = '';
}
}
setPath(path) {
const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
if (pathMatch) {
this.path = pathMatch[0];
this.directory = pathMatch[1];
this.file = pathMatch[2];
}
this.source = '';
this.getURI();
}
toRelative(uri) {
if (uri === './') {
return uri;
}
const relativeUri = new URI(uri, { base_uri: this });
if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
return relativeUri.getURI();
}
const tu = this.getURI(), uu = relativeUri.getURI();
if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
return tu;
}
let output = this.toRelPath(this.path, relativeUri.path);
if (relativeUri.query) {
output += '?' + relativeUri.query;
}
if (relativeUri.anchor) {
output += '#' + relativeUri.anchor;
}
return output;
}
toAbsolute(uri, noHost) {
const absoluteUri = new URI(uri, { base_uri: this });
return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
}
isSameOrigin(uri) {
if (this.host == uri.host && this.protocol == uri.protocol) {
if (this.port == uri.port) {
return true;
}
const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null;
if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
return true;
}
}
return false;
}
toRelPath(base, path) {
let breakPoint = 0, out = '', i, l;
const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
const items = path.split('/');
if (normalizedBase.length >= items.length) {
for (i = 0, l = normalizedBase.length; i < l; i++) {
if (i >= items.length || normalizedBase[i] !== items[i]) {
breakPoint = i + 1;
break;
}
}
}
if (normalizedBase.length < items.length) {
for (i = 0, l = items.length; i < l; i++) {
if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
breakPoint = i + 1;
break;
}
}
}
if (breakPoint === 1) {
return path;
}
for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
out += '../';
}
for (i = breakPoint - 1, l = items.length; i < l; i++) {
if (i !== breakPoint - 1) {
out += '/' + items[i];
} else {
out += items[i];
}
}
return out;
}
toAbsPath(base, path) {
let nb = 0;
const tr = /\/$/.test(path) ? '/' : '';
const normalizedBase = base.split('/');
const normalizedPath = path.split('/');
const baseParts = [];
each$4(normalizedBase, k => {
if (k) {
baseParts.push(k);
}
});
const pathParts = [];
for (let i = normalizedPath.length - 1; i >= 0; i--) {
if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
continue;
}
if (normalizedPath[i] === '..') {
nb++;
continue;
}
if (nb > 0) {
nb--;
continue;
}
pathParts.push(normalizedPath[i]);
}
const i = baseParts.length - nb;
let outPath;
if (i <= 0) {
outPath = reverse(pathParts).join('/');
} else {
outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/');
}
if (outPath.indexOf('/') !== 0) {
outPath = '/' + outPath;
}
if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
outPath += tr;
}
return outPath;
}
getURI(noProtoHost = false) {
let s;
if (!this.source || noProtoHost) {
s = '';
if (!noProtoHost) {
if (this.protocol) {
s += this.protocol + '://';
} else {
s += '//';
}
if (this.userInfo) {
s += this.userInfo + '@';
}
if (this.host) {
s += this.host;
}
if (this.port) {
s += ':' + this.port;
}
}
if (this.path) {
s += this.path;
}
if (this.query) {
s += '?' + this.query;
}
if (this.anchor) {
s += '#' + this.anchor;
}
this.source = s;
}
return this.source;
}
}
const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href');
const internalElementAttr = 'data-mce-type';
let uid = 0;
const processNode = (node, settings, schema, scope, evt) => {
var _a, _b, _c, _d;
const validate = settings.validate;
const specialElements = schema.getSpecialElements();
if (node.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = node.nodeValue) !== null && _a !== void 0 ? _a : '')) {
node.nodeValue = ' ' + node.nodeValue;
}
const lcTagName = (_b = evt === null || evt === void 0 ? void 0 : evt.tagName) !== null && _b !== void 0 ? _b : node.nodeName.toLowerCase();
if (scope !== 'html' && schema.isValid(scope)) {
if (isNonNullable(evt)) {
evt.allowedTags[lcTagName] = true;
}
return;
}
if (node.nodeType !== ELEMENT || lcTagName === 'body') {
return;
}
const element = SugarElement.fromDom(node);
const isInternalElement = has$1(element, internalElementAttr);
const bogus = get$9(element, 'data-mce-bogus');
if (!isInternalElement && isString(bogus)) {
if (bogus === 'all') {
remove$4(element);
} else {
unwrap(element);
}
return;
}
const rule = schema.getElementRule(lcTagName);
if (validate && !rule) {
if (has$2(specialElements, lcTagName)) {
remove$4(element);
} else {
unwrap(element);
}
return;
} else {
if (isNonNullable(evt)) {
evt.allowedTags[lcTagName] = true;
}
}
if (validate && rule && !isInternalElement) {
each$e((_c = rule.attributesForced) !== null && _c !== void 0 ? _c : [], attr => {
set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
});
each$e((_d = rule.attributesDefault) !== null && _d !== void 0 ? _d : [], attr => {
if (!has$1(element, attr.name)) {
set$3(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
}
});
if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) {
unwrap(element);
return;
}
if (rule.removeEmptyAttrs && hasNone(element)) {
unwrap(element);
return;
}
if (rule.outputName && rule.outputName !== lcTagName) {
mutate(element, rule.outputName);
}
}
};
const processAttr = (ele, settings, schema, scope, evt) => {
const tagName = ele.tagName.toLowerCase();
const {attrName, attrValue} = evt;
evt.keepAttr = shouldKeepAttribute(settings, schema, scope, tagName, attrName, attrValue);
if (evt.keepAttr) {
evt.allowedAttributes[attrName] = true;
if (isBooleanAttribute(attrName, schema)) {
evt.attrValue = attrName;
}
if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) {
evt.forceKeepAttr = true;
}
} else if (isRequiredAttributeOfInternalElement(ele, attrName)) {
evt.forceKeepAttr = true;
}
};
const shouldKeepAttribute = (settings, schema, scope, tagName, attrName, attrValue) => {
if (scope !== 'html' && !isNonHtmlElementRootName(tagName)) {
return true;
}
return !(attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) && (!settings.validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-'));
};
const isRequiredAttributeOfInternalElement = (ele, attrName) => ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style');
const isBooleanAttribute = (attrName, schema) => attrName in schema.getBoolAttrs();
const filterAttributes = (ele, settings, schema, scope) => {
const {attributes} = ele;
for (let i = attributes.length - 1; i >= 0; i--) {
const attr = attributes[i];
const attrName = attr.name;
const attrValue = attr.value;
if (!shouldKeepAttribute(settings, schema, scope, ele.tagName.toLowerCase(), attrName, attrValue) && !isRequiredAttributeOfInternalElement(ele, attrName)) {
ele.removeAttribute(attrName);
} else if (isBooleanAttribute(attrName, schema)) {
ele.setAttribute(attrName, attrName);
}
}
};
const setupPurify = (settings, schema, namespaceTracker) => {
const purify$1 = purify();
purify$1.addHook('uponSanitizeElement', (ele, evt) => {
processNode(ele, settings, schema, namespaceTracker.track(ele), evt);
});
purify$1.addHook('uponSanitizeAttribute', (ele, evt) => {
processAttr(ele, settings, schema, namespaceTracker.current(), evt);
});
return purify$1;
};
const getPurifyConfig = (settings, mimeType) => {
const basePurifyConfig = {
IN_PLACE: true,
ALLOW_UNKNOWN_PROTOCOLS: true,
ALLOWED_TAGS: [
'#comment',
'#cdata-section',
'body'
],
ALLOWED_ATTR: []
};
const config = { ...basePurifyConfig };
config.PARSER_MEDIA_TYPE = mimeType;
if (settings.allow_script_urls) {
config.ALLOWED_URI_REGEXP = /.*/;
} else if (settings.allow_html_data_urls) {
config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
}
return config;
};
const sanitizeNamespaceElement = ele => {
const namespaceType = toScopeType(ele);
if (namespaceType === 'svg') {
const xlinkAttrs = [
'type',
'href',
'role',
'arcrole',
'title',
'show',
'actuate',
'label',
'from',
'to'
].map(name => `xlink:${ name }`);
const config = {
IN_PLACE: true,
USE_PROFILES: {
html: true,
svg: true,
svgFilters: true
},
ALLOWED_ATTR: xlinkAttrs
};
purify().sanitize(ele, config);
} else if (namespaceType === 'math') {
const config = {
IN_PLACE: true,
USE_PROFILES: { mathMl: true }
};
purify().sanitize(ele, config);
} else {
throw new Error('Not a namespace element');
}
};
const getSanitizer = (settings, schema) => {
const namespaceTracker = createNamespaceTracker();
if (settings.sanitize) {
const purify = setupPurify(settings, schema, namespaceTracker);
const sanitizeHtmlElement = (body, mimeType) => {
purify.sanitize(body, getPurifyConfig(settings, mimeType));
purify.removed = [];
namespaceTracker.reset();
};
return {
sanitizeHtmlElement,
sanitizeNamespaceElement
};
} else {
const sanitizeHtmlElement = (body, _mimeType) => {
const nodeIterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT);
let node;
while (node = nodeIterator.nextNode()) {
const currentScope = namespaceTracker.track(node);
processNode(node, settings, schema, currentScope);
if (isElement$6(node)) {
filterAttributes(node, settings, schema, currentScope);
}
}
namespaceTracker.reset();
};
const sanitizeNamespaceElement = noop;
return {
sanitizeHtmlElement,
sanitizeNamespaceElement
};
}
};
const makeMap = Tools.makeMap, extend$1 = Tools.extend;
const transferChildren = (parent, nativeParent, specialElements, nsSanitizer) => {
const parentName = parent.name;
const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea' && parentName !== 'noscript';
const childNodes = nativeParent.childNodes;
for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
const nativeChild = childNodes[ni];
const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
if (isElement$6(nativeChild)) {
const attributes = nativeChild.attributes;
for (let ai = 0, al = attributes.length; ai < al; ai++) {
const attr = attributes[ai];
child.attr(attr.name, attr.value);
}
if (isNonHtmlElementRootName(child.name)) {
nsSanitizer(nativeChild);
child.value = nativeChild.innerHTML;
}
} else if (isText$b(nativeChild)) {
child.value = nativeChild.data;
if (isSpecial) {
child.raw = true;
}
} else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
child.value = nativeChild.data;
}
if (!isNonHtmlElementRootName(child.name)) {
transferChildren(child, nativeChild, specialElements, nsSanitizer);
}
parent.append(child);
}
};
const walkTree = (root, preprocessors, postprocessors) => {
const traverseOrder = [];
for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) {
const tempNode = node;
each$e(preprocessors, preprocess => preprocess(tempNode));
if (isNullable(tempNode.parent) && tempNode !== root) {
node = lastNode;
} else {
traverseOrder.push(tempNode);
}
}
for (let i = traverseOrder.length - 1; i >= 0; i--) {
const node = traverseOrder[i];
each$e(postprocessors, postprocess => postprocess(node));
}
};
const whitespaceCleaner = (root, schema, settings, args) => {
const validate = settings.validate;
const nonEmptyElements = schema.getNonEmptyElements();
const whitespaceElements = schema.getWhitespaceElements();
const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
const textRootBlockElements = getTextRootBlockElements(schema);
const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
const hasWhitespaceParent = node => {
let tempNode = node.parent;
while (isNonNullable(tempNode)) {
if (tempNode.name in whitespaceElements) {
return true;
} else {
tempNode = tempNode.parent;
}
}
return false;
};
const isTextRootBlockEmpty = node => {
let tempNode = node;
while (isNonNullable(tempNode)) {
if (tempNode.name in textRootBlockElements) {
return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
} else {
tempNode = tempNode.parent;
}
}
return false;
};
const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node) || isNonHtmlElementRootName(node.name) && node.parent === root;
const isAtEdgeOfBlock = (node, start) => {
const neighbour = start ? node.prev : node.next;
if (isNonNullable(neighbour) || isNullable(node.parent)) {
return false;
}
return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
};
const preprocess = node => {
var _a;
if (node.type === 3) {
if (!hasWhitespaceParent(node)) {
let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
text = text.replace(allWhiteSpaceRegExp, ' ');
if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
text = text.replace(startWhiteSpaceRegExp, '');
}
if (text.length === 0) {
node.remove();
} else if (text === ' ' && node.prev && node.prev.type === COMMENT && node.next && node.next.type === COMMENT) {
node.remove();
} else {
node.value = text;
}
}
}
};
const postprocess = node => {
var _a;
if (node.type === 1) {
const elementRule = schema.getElementRule(node.name);
if (validate && elementRule) {
const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
paddEmptyNode(settings, args, isBlock, node);
} else if (elementRule.removeEmpty && isNodeEmpty) {
if (isBlock(node)) {
node.remove();
} else {
node.unwrap();
}
} else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
paddEmptyNode(settings, args, isBlock, node);
}
}
} else if (node.type === 3) {
if (!hasWhitespaceParent(node)) {
let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) {
text = text.replace(endWhiteSpaceRegExp, '');
}
if (text.length === 0) {
node.remove();
} else {
node.value = text;
}
}
}
};
return [
preprocess,
postprocess
];
};
const getRootBlockName = (settings, args) => {
var _a;
const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
if (name === false) {
return '';
} else if (name === true) {
return 'p';
} else {
return name;
}
};
const DomParser = (settings = {}, schema = Schema()) => {
const nodeFilterRegistry = create$8();
const attributeFilterRegistry = create$8();
const defaultedSettings = {
validate: true,
root_name: 'body',
sanitize: true,
...settings
};
const parser = new DOMParser();
const sanitizer = getSanitizer(defaultedSettings, schema);
const parseAndSanitizeWithContext = (html, rootName, format = 'html') => {
const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
const content = isSpecialRoot ? `<${ rootName }>${ html }${ rootName }>` : html;
const makeWrap = () => {
if (format === 'xhtml') {
return `${ content }`;
} else if (/^[\s]*${ content }`;
} else {
return `${ content }`;
}
};
const body = parser.parseFromString(makeWrap(), mimeType).body;
sanitizer.sanitizeHtmlElement(body, mimeType);
return isSpecialRoot ? body.firstChild : body;
};
const addNodeFilter = nodeFilterRegistry.addFilter;
const getNodeFilters = nodeFilterRegistry.getFilters;
const removeNodeFilter = nodeFilterRegistry.removeFilter;
const addAttributeFilter = attributeFilterRegistry.addFilter;
const getAttributeFilters = attributeFilterRegistry.getFilters;
const removeAttributeFilter = attributeFilterRegistry.removeFilter;
const findInvalidChildren = (node, invalidChildren) => {
if (isInvalid(schema, node)) {
invalidChildren.push(node);
}
};
const isWrappableNode = (blockElements, node) => {
const isInternalElement = isString(node.attr(internalElementAttr));
const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node)) && !isNonHtmlElementRootName(node.name);
return node.type === 3 || isInlineElement && !isInternalElement;
};
const addRootBlocks = (rootNode, rootBlockName) => {
const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
let node = rootNode.firstChild, rootBlockNode = null;
const trim = rootBlock => {
var _a, _b;
if (rootBlock) {
node = rootBlock.firstChild;
if (node && node.type === 3) {
node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, '');
}
node = rootBlock.lastChild;
if (node && node.type === 3) {
node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, '');
}
}
};
if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
return;
}
while (node) {
const next = node.next;
if (isWrappableNode(blockElements, node)) {
if (!rootBlockNode) {
rootBlockNode = new AstNode(rootBlockName, 1);
rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
rootNode.insert(rootBlockNode, node);
rootBlockNode.append(node);
} else {
rootBlockNode.append(node);
}
} else {
trim(rootBlockNode);
rootBlockNode = null;
}
node = next;
}
trim(rootBlockNode);
};
const parse = (html, args = {}) => {
var _a;
const validate = defaultedSettings.validate;
const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
const element = parseAndSanitizeWithContext(html, rootName, args.format);
updateChildren(schema, element);
const rootNode = new AstNode(rootName, 11);
transferChildren(rootNode, element, schema.getSpecialElements(), sanitizer.sanitizeNamespaceElement);
element.innerHTML = '';
const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
const invalidChildren = [];
const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop;
const matches = {
nodes: {},
attributes: {}
};
const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
walkTree(rootNode, [
whitespacePre,
matchFinder
], [
whitespacePost,
invalidFinder
]);
invalidChildren.reverse();
if (validate && invalidChildren.length > 0) {
if (args.context) {
const {
pass: topLevelChildren,
fail: otherChildren
} = partition$2(invalidChildren, child => child.parent === rootNode);
cleanInvalidNodes(otherChildren, schema, rootNode, matchFinder);
args.invalid = topLevelChildren.length > 0;
} else {
cleanInvalidNodes(invalidChildren, schema, rootNode, matchFinder);
}
}
const rootBlockName = getRootBlockName(defaultedSettings, args);
if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
addRootBlocks(rootNode, rootBlockName);
}
if (!args.invalid) {
runFilters(matches, args);
}
return rootNode;
};
const exports = {
schema,
addAttributeFilter,
getAttributeFilters,
removeAttributeFilter,
addNodeFilter,
getNodeFilters,
removeNodeFilter,
parse
};
register$4(exports, defaultedSettings);
register$5(exports, defaultedSettings, schema);
return exports;
};
const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
const withSerializedContent = (content, fireEvent, parserSettings) => {
const serializedContent = serializeContent(content);
const eventArgs = fireEvent(serializedContent);
if (eventArgs.isDefaultPrevented()) {
return eventArgs;
} else if (isTreeNode(content)) {
if (eventArgs.content !== serializedContent) {
const rootNode = DomParser({
validate: false,
forced_root_block: false,
...parserSettings
}).parse(eventArgs.content, { context: content.name });
return {
...eventArgs,
content: rootNode
};
} else {
return {
...eventArgs,
content
};
}
} else {
return eventArgs;
}
};
const makeParserSettings = editor => ({
sanitize: shouldSanitizeXss(editor),
sandbox_iframes: shouldSandboxIframes(editor),
sandbox_iframes_exclusions: getSandboxIframesExclusions(editor)
});
const preProcessGetContent = (editor, args) => {
if (args.no_events) {
return Result.value(args);
} else {
const eventArgs = fireBeforeGetContent(editor, args);
if (eventArgs.isDefaultPrevented()) {
return Result.error(fireGetContent(editor, {
content: '',
...eventArgs
}).content);
} else {
return Result.value(eventArgs);
}
}
};
const postProcessGetContent = (editor, content, args) => {
if (args.no_events) {
return content;
} else {
const processedEventArgs = withSerializedContent(content, content => fireGetContent(editor, {
...args,
content
}), makeParserSettings(editor));
return processedEventArgs.content;
}
};
const preProcessSetContent = (editor, args) => {
if (args.no_events) {
return Result.value(args);
} else {
const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, {
...args,
content
}), makeParserSettings(editor));
if (processedEventArgs.isDefaultPrevented()) {
fireSetContent(editor, processedEventArgs);
return Result.error(undefined);
} else {
return Result.value(processedEventArgs);
}
}
};
const postProcessSetContent = (editor, content, args) => {
if (!args.no_events) {
fireSetContent(editor, {
...args,
content
});
}
};
const tableModel = (element, width, rows) => ({
element,
width,
rows
});
const tableRow = (element, cells) => ({
element,
cells
});
const cellPosition = (x, y) => ({
x,
y
});
const getSpan = (td, key) => {
return getOpt(td, key).bind(toInt).getOr(1);
};
const fillout = (table, x, y, tr, td) => {
const rowspan = getSpan(td, 'rowspan');
const colspan = getSpan(td, 'colspan');
const rows = table.rows;
for (let y2 = y; y2 < y + rowspan; y2++) {
if (!rows[y2]) {
rows[y2] = tableRow(deep$1(tr), []);
}
for (let x2 = x; x2 < x + colspan; x2++) {
const cells = rows[y2].cells;
cells[x2] = y2 === y && x2 === x ? td : shallow$1(td);
}
}
};
const cellExists = (table, x, y) => {
const rows = table.rows;
const cells = rows[y] ? rows[y].cells : [];
return !!cells[x];
};
const skipCellsX = (table, x, y) => {
while (cellExists(table, x, y)) {
x++;
}
return x;
};
const getWidth = rows => {
return foldl(rows, (acc, row) => {
return row.cells.length > acc ? row.cells.length : acc;
}, 0);
};
const findElementPos = (table, element) => {
const rows = table.rows;
for (let y = 0; y < rows.length; y++) {
const cells = rows[y].cells;
for (let x = 0; x < cells.length; x++) {
if (eq(cells[x], element)) {
return Optional.some(cellPosition(x, y));
}
}
}
return Optional.none();
};
const extractRows = (table, sx, sy, ex, ey) => {
const newRows = [];
const rows = table.rows;
for (let y = sy; y <= ey; y++) {
const cells = rows[y].cells;
const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
newRows.push(tableRow(rows[y].element, slice));
}
return newRows;
};
const subTable = (table, startPos, endPos) => {
const sx = startPos.x, sy = startPos.y;
const ex = endPos.x, ey = endPos.y;
const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
return tableModel(table.element, getWidth(newRows), newRows);
};
const createDomTable = (table, rows) => {
const tableElement = shallow$1(table.element);
const tableBody = SugarElement.fromTag('tbody');
append(tableBody, rows);
append$1(tableElement, tableBody);
return tableElement;
};
const modelRowsToDomRows = table => {
return map$3(table.rows, row => {
const cells = map$3(row.cells, cell => {
const td = deep$1(cell);
remove$9(td, 'colspan');
remove$9(td, 'rowspan');
return td;
});
const tr = shallow$1(row.element);
append(tr, cells);
return tr;
});
};
const fromDom = tableElm => {
const table = tableModel(shallow$1(tableElm), 0, []);
each$e(descendants(tableElm, 'tr'), (tr, y) => {
each$e(descendants(tr, 'td,th'), (td, x) => {
fillout(table, skipCellsX(table, x, y), y, tr, td);
});
});
return tableModel(table.element, getWidth(table.rows), table.rows);
};
const toDom = table => {
return createDomTable(table, modelRowsToDomRows(table));
};
const subsection = (table, startElement, endElement) => {
return findElementPos(table, startElement).bind(startPos => {
return findElementPos(table, endElement).map(endPos => {
return subTable(table, startPos, endPos);
});
});
};
const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol');
const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => {
const listElm = SugarElement.fromTag(name(listCont));
const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style'));
setAll(listElm, listStyles);
return [
SugarElement.fromTag('li'),
listElm
];
}).getOr([]));
const wrap = (innerElm, elms) => {
const wrapped = foldl(elms, (acc, elm) => {
append$1(elm, acc);
return elm;
}, innerElm);
return elms.length > 0 ? fromElements([wrapped]) : wrapped;
};
const directListWrappers = commonAnchorContainer => {
if (isListItem$1(commonAnchorContainer)) {
return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [
commonAnchorContainer,
listElm
]);
} else {
return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
}
};
const getWrapElements = (rootNode, rng, schema) => {
const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
const parents = parentsAndSelf(commonAnchorContainer, rootNode);
const wrapElements = filter$5(parents, el => schema.isWrapper(name(el)));
const listWrappers = getFullySelectedListWrappers(parents, rng);
const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
return map$3(allWrappers, shallow$1);
};
const emptyFragment = () => fromElements([]);
const getFragmentFromRange = (rootNode, rng, schema) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng, schema));
const getParentTable = (rootElm, cell) => ancestor$3(cell, 'table', curry(eq, rootElm));
const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => {
const firstCell = selectedTableCells[0];
const lastCell = selectedTableCells[selectedTableCells.length - 1];
const fullTableModel = fromDom(tableElm);
return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)]));
}).getOrThunk(emptyFragment);
const getSelectionFragment = (rootNode, ranges, schema) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0], schema);
const read$3 = (rootNode, ranges, schema) => {
const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges, schema);
};
const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index));
const getInnerText = bin => {
return trim$2(bin.innerText);
};
const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase();
const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => {
var _a;
const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
const body = editor.getBody();
const contextNodeName = getContextNodeName(parentBlockOpt);
const rangeContentClone = SugarElement.fromDom(rng.cloneContents());
cleanupBogusElements(rangeContentClone);
cleanupInputNames(rangeContentClone);
const bin = editor.dom.add(body, contextNodeName, {
'data-mce-bogus': 'all',
'style': 'overflow: hidden; opacity: 0;'
}, rangeContentClone.dom);
const text = getInnerText(bin);
const nonRenderedText = trim$2((_a = bin.textContent) !== null && _a !== void 0 ? _a : '');
editor.dom.remove(bin);
if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
const parentBlock = parentBlockOpt.getOr(body);
const parentBlockText = getInnerText(parentBlock);
const textIndex = parentBlockText.indexOf(text);
if (textIndex === -1) {
return text;
} else {
const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length);
return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : '');
}
} else {
return text;
}
}).getOr('');
const getSerializedContent = (editor, args) => {
const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
const sel = editor.selection.getSel();
const ranges = processRanges(editor, getRanges$1(sel));
const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges, editor.schema).dom : rng.cloneContents();
if (fragment) {
tmpElm.appendChild(fragment);
}
return editor.selection.serializer.serialize(tmpElm, args);
};
const extractSelectedContent = (editor, args) => {
if (args.format === 'text') {
return getTextContent(editor);
} else {
const content = getSerializedContent(editor, args);
if (args.format === 'tree') {
return content;
} else {
return editor.selection.isCollapsed() ? '' : content;
}
}
};
const setupArgs$3 = (args, format) => ({
...args,
format,
get: true,
selection: true,
getInner: true
});
const getSelectedContentInternal = (editor, format, args = {}) => {
const defaultedArgs = setupArgs$3(args, format);
return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
const content = extractSelectedContent(editor, updatedArgs);
return postProcessGetContent(editor, content, updatedArgs);
});
};
const KEEP = 0, INSERT = 1, DELETE = 2;
const diff = (left, right) => {
const size = left.length + right.length + 2;
const vDown = new Array(size);
const vUp = new Array(size);
const snake = (start, end, diag) => {
return {
start,
end,
diag
};
};
const buildScript = (start1, end1, start2, end2, script) => {
const middle = getMiddleSnake(start1, end1, start2, end2);
if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
let i = start1;
let j = start2;
while (i < end1 || j < end2) {
if (i < end1 && j < end2 && left[i] === right[j]) {
script.push([
KEEP,
left[i]
]);
++i;
++j;
} else {
if (end1 - start1 > end2 - start2) {
script.push([
DELETE,
left[i]
]);
++i;
} else {
script.push([
INSERT,
right[j]
]);
++j;
}
}
}
} else {
buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
for (let i2 = middle.start; i2 < middle.end; ++i2) {
script.push([
KEEP,
left[i2]
]);
}
buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
}
};
const buildSnake = (start, diag, end1, end2) => {
let end = start;
while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
++end;
}
return snake(start, end, diag);
};
const getMiddleSnake = (start1, end1, start2, end2) => {
const m = end1 - start1;
const n = end2 - start2;
if (m === 0 || n === 0) {
return null;
}
const delta = m - n;
const sum = n + m;
const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
vDown[1 + offset] = start1;
vUp[1 + offset] = end1 + 1;
let d, k, i, x, y;
for (d = 0; d <= offset; ++d) {
for (k = -d; k <= d; k += 2) {
i = k + offset;
if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
vDown[i] = vDown[i + 1];
} else {
vDown[i] = vDown[i - 1] + 1;
}
x = vDown[i];
y = x - start1 + start2 - k;
while (x < end1 && y < end2 && left[x] === right[y]) {
vDown[i] = ++x;
++y;
}
if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
if (vUp[i - delta] <= vDown[i]) {
return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
}
}
}
for (k = delta - d; k <= delta + d; k += 2) {
i = k + offset - delta;
if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
vUp[i] = vUp[i + 1] - 1;
} else {
vUp[i] = vUp[i - 1];
}
x = vUp[i] - 1;
y = x - start1 + start2 - k;
while (x >= start1 && y >= start2 && left[x] === right[y]) {
vUp[i] = x--;
y--;
}
if (delta % 2 === 0 && -d <= k && k <= d) {
if (vUp[i] <= vDown[i + delta]) {
return buildSnake(vUp[i], k + start1 - start2, end1, end2);
}
}
}
}
return null;
};
const script = [];
buildScript(0, left.length, 0, right.length, script);
return script;
};
const getOuterHtml = elm => {
if (isElement$6(elm)) {
return elm.outerHTML;
} else if (isText$b(elm)) {
return Entities.encodeRaw(elm.data, false);
} else if (isComment(elm)) {
return '';
}
return '';
};
const createFragment = html => {
let node;
const container = document.createElement('div');
const frag = document.createDocumentFragment();
if (html) {
container.innerHTML = html;
}
while (node = container.firstChild) {
frag.appendChild(node);
}
return frag;
};
const insertAt = (elm, html, index) => {
const fragment = createFragment(html);
if (elm.hasChildNodes() && index < elm.childNodes.length) {
const target = elm.childNodes[index];
elm.insertBefore(fragment, target);
} else {
elm.appendChild(fragment);
}
};
const removeAt = (elm, index) => {
if (elm.hasChildNodes() && index < elm.childNodes.length) {
const target = elm.childNodes[index];
elm.removeChild(target);
}
};
const applyDiff = (diff, elm) => {
let index = 0;
each$e(diff, action => {
if (action[0] === KEEP) {
index++;
} else if (action[0] === INSERT) {
insertAt(elm, action[1], index);
index++;
} else if (action[0] === DELETE) {
removeAt(elm, index);
}
});
};
const read$2 = (elm, trimZwsp) => filter$5(map$3(from(elm.childNodes), trimZwsp ? compose(trim$2, getOuterHtml) : getOuterHtml), item => {
return item.length > 0;
});
const write = (fragments, elm) => {
const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
applyDiff(diff(currentFragments, fragments), elm);
return elm;
};
const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo'));
const hasIframes = body => body.querySelector('iframe') !== null;
const createFragmentedLevel = fragments => {
return {
type: 'fragmented',
fragments,
content: '',
bookmark: null,
beforeBookmark: null
};
};
const createCompleteLevel = content => {
return {
type: 'complete',
fragments: null,
content,
bookmark: null,
beforeBookmark: null
};
};
const createFromEditor = editor => {
const tempAttrs = editor.serializer.getTempAttrs();
const body = trim$1(editor.getBody(), tempAttrs);
return hasIframes(body) ? createFragmentedLevel(read$2(body, true)) : createCompleteLevel(trim$2(body.innerHTML));
};
const applyToEditor = (editor, level, before) => {
const bookmark = before ? level.beforeBookmark : level.bookmark;
if (level.type === 'fragmented') {
write(level.fragments, editor.getBody());
} else {
editor.setContent(level.content, {
format: 'raw',
no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
});
}
if (bookmark) {
editor.selection.moveToBookmark(bookmark);
editor.selection.scrollIntoView();
}
};
const getLevelContent = level => {
return level.type === 'fragmented' ? level.fragments.join('') : level.content;
};
const getCleanLevelContent = level => {
const elm = SugarElement.fromTag('body', lazyTempDocument());
set$1(elm, getLevelContent(level));
each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
return get$6(elm);
};
const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
const isEq$1 = (level1, level2) => {
if (!level1 || !level2) {
return false;
} else if (hasEqualContent(level1, level2)) {
return true;
} else {
return hasEqualCleanedContent(level1, level2);
}
};
const isUnlocked = locks => locks.get() === 0;
const setTyping = (undoManager, typing, locks) => {
if (isUnlocked(locks)) {
undoManager.typing = typing;
}
};
const endTyping = (undoManager, locks) => {
if (undoManager.typing) {
setTyping(undoManager, false, locks);
undoManager.add();
}
};
const endTypingLevelIgnoreLocks = undoManager => {
if (undoManager.typing) {
undoManager.typing = false;
undoManager.add();
}
};
const beforeChange$1 = (editor, locks, beforeBookmark) => {
if (isUnlocked(locks)) {
beforeBookmark.set(getUndoBookmark(editor.selection));
}
};
const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => {
const currentLevel = createFromEditor(editor);
const newLevel = Tools.extend(level || {}, currentLevel);
if (!isUnlocked(locks) || editor.removed) {
return null;
}
const lastLevel = undoManager.data[index.get()];
if (editor.dispatch('BeforeAddUndo', {
level: newLevel,
lastLevel,
originalEvent: event
}).isDefaultPrevented()) {
return null;
}
if (lastLevel && isEq$1(lastLevel, newLevel)) {
return null;
}
if (undoManager.data[index.get()]) {
beforeBookmark.get().each(bm => {
undoManager.data[index.get()].beforeBookmark = bm;
});
}
const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
if (customUndoRedoLevels) {
if (undoManager.data.length > customUndoRedoLevels) {
for (let i = 0; i < undoManager.data.length - 1; i++) {
undoManager.data[i] = undoManager.data[i + 1];
}
undoManager.data.length--;
index.set(undoManager.data.length);
}
}
newLevel.bookmark = getUndoBookmark(editor.selection);
if (index.get() < undoManager.data.length - 1) {
undoManager.data.length = index.get() + 1;
}
undoManager.data.push(newLevel);
index.set(undoManager.data.length - 1);
const args = {
level: newLevel,
lastLevel,
originalEvent: event
};
if (index.get() > 0) {
editor.setDirty(true);
editor.dispatch('AddUndo', args);
editor.dispatch('change', args);
} else {
editor.dispatch('AddUndo', args);
}
return newLevel;
};
const clear$1 = (editor, undoManager, index) => {
undoManager.data = [];
index.set(0);
undoManager.typing = false;
editor.dispatch('ClearUndos');
};
const extra$1 = (editor, undoManager, index, callback1, callback2) => {
if (undoManager.transact(callback1)) {
const bookmark = undoManager.data[index.get()].bookmark;
const lastLevel = undoManager.data[index.get() - 1];
applyToEditor(editor, lastLevel, true);
if (undoManager.transact(callback2)) {
undoManager.data[index.get() - 1].beforeBookmark = bookmark;
}
}
};
const redo$1 = (editor, index, data) => {
let level;
if (index.get() < data.length - 1) {
index.set(index.get() + 1);
level = data[index.get()];
applyToEditor(editor, level, false);
editor.setDirty(true);
editor.dispatch('Redo', { level });
}
return level;
};
const undo$1 = (editor, undoManager, locks, index) => {
let level;
if (undoManager.typing) {
undoManager.add();
undoManager.typing = false;
setTyping(undoManager, false, locks);
}
if (index.get() > 0) {
index.set(index.get() - 1);
level = undoManager.data[index.get()];
applyToEditor(editor, level, true);
editor.setDirty(true);
editor.dispatch('Undo', { level });
}
return level;
};
const reset$1 = undoManager => {
undoManager.clear();
undoManager.add();
};
const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
const transact$1 = (undoManager, locks, callback) => {
endTyping(undoManager, locks);
undoManager.beforeChange();
undoManager.ignore(callback);
return undoManager.add();
};
const ignore$1 = (locks, callback) => {
try {
locks.set(locks.get() + 1);
callback();
} finally {
locks.set(locks.get() - 1);
}
};
const addVisualInternal = (editor, elm) => {
const dom = editor.dom;
const scope = isNonNullable(elm) ? elm : editor.getBody();
each$e(dom.select('table,a', scope), matchedElm => {
switch (matchedElm.nodeName) {
case 'TABLE':
const cls = getVisualAidsTableClass(editor);
const value = dom.getAttrib(matchedElm, 'border');
if ((!value || value === '0') && editor.hasVisual) {
dom.addClass(matchedElm, cls);
} else {
dom.removeClass(matchedElm, cls);
}
break;
case 'A':
if (!dom.getAttrib(matchedElm, 'href')) {
const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id;
const cls = getVisualAidsAnchorClass(editor);
if (value && editor.hasVisual) {
dom.addClass(matchedElm, cls);
} else {
dom.removeClass(matchedElm, cls);
}
}
break;
}
});
editor.dispatch('VisualAid', {
element: elm,
hasVisual: editor.hasVisual
});
};
const makePlainAdaptor = editor => ({
init: { bindEvents: noop },
undoManager: {
beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event),
undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index),
redo: (index, data) => redo$1(editor, index, data),
clear: (undoManager, index) => clear$1(editor, undoManager, index),
reset: undoManager => reset$1(undoManager),
hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index),
hasRedo: (undoManager, index) => hasRedo$1(undoManager, index),
transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
ignore: (locks, callback) => ignore$1(locks, callback),
extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2)
},
formatter: {
match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar),
matchAll: (names, vars) => matchAll(editor, names, vars),
matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar),
canApply: name => canApply(editor, name),
closest: names => closest(editor, names),
apply: (name, vars, node) => applyFormat$1(editor, name, vars, node),
remove: (name, vars, node, similar) => removeFormat$1(editor, name, vars, node, similar),
toggle: (name, vars, node) => toggle(editor, name, vars, node),
formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
},
editor: {
getContent: args => getContentInternal(editor, args),
setContent: (content, args) => setContentInternal(editor, content, args),
insertContent: (value, details) => insertHtmlAtCaret(editor, value, details),
addVisual: elm => addVisualInternal(editor, elm)
},
selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
autocompleter: {
addDecoration: noop,
removeDecoration: noop
},
raw: { getModel: () => Optional.none() }
});
const makeRtcAdaptor = rtcEditor => {
const defaultVars = vars => isObject(vars) ? vars : {};
const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor;
return {
init: { bindEvents: init.bindEvents },
undoManager: {
beforeChange: undoManager.beforeChange,
add: undoManager.add,
undo: undoManager.undo,
redo: undoManager.redo,
clear: undoManager.clear,
reset: undoManager.reset,
hasUndo: undoManager.hasUndo,
hasRedo: undoManager.hasRedo,
transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
ignore: (_locks, callback) => undoManager.ignore(callback),
extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
},
formatter: {
match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar),
matchAll: formatter.matchAll,
matchNode: formatter.matchNode,
canApply: name => formatter.canApply(name),
closest: names => formatter.closest(names),
apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)),
remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)),
toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)),
formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
},
editor: {
getContent: args => editor.getContent(args),
setContent: (content, args) => {
return {
content: editor.setContent(content, args),
html: ''
};
},
insertContent: (content, _details) => {
editor.insertContent(content);
return '';
},
addVisual: editor.addVisual
},
selection: { getContent: (_format, args) => selection.getContent(args) },
autocompleter: {
addDecoration: autocompleter.addDecoration,
removeDecoration: autocompleter.removeDecoration
},
raw: { getModel: () => Optional.some(raw.getRawModel()) }
};
};
const makeNoopAdaptor = () => {
const nul = constant(null);
const empty = constant('');
return {
init: { bindEvents: noop },
undoManager: {
beforeChange: noop,
add: nul,
undo: nul,
redo: nul,
clear: noop,
reset: noop,
hasUndo: never,
hasRedo: never,
transact: nul,
ignore: noop,
extra: noop
},
formatter: {
match: never,
matchAll: constant([]),
matchNode: constant(undefined),
canApply: never,
closest: empty,
apply: noop,
remove: noop,
toggle: noop,
formatChanged: constant({ unbind: noop })
},
editor: {
getContent: empty,
setContent: constant({
content: '',
html: ''
}),
insertContent: constant(''),
addVisual: noop
},
selection: { getContent: empty },
autocompleter: {
addDecoration: noop,
removeDecoration: noop
},
raw: { getModel: constant(Optional.none()) }
};
};
const isRtc = editor => has$2(editor.plugins, 'rtc');
const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup));
const setup$t = editor => {
const editorCast = editor;
return getRtcSetup(editor).fold(() => {
editorCast.rtcInstance = makePlainAdaptor(editor);
return Optional.none();
}, setup => {
editorCast.rtcInstance = makeNoopAdaptor();
return Optional.some(() => setup().then(rtcEditor => {
editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
return rtcEditor.rtc.isRemote;
}));
});
};
const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
const getRtcInstanceWithError = editor => {
const rtcInstance = editor.rtcInstance;
if (!rtcInstance) {
throw new Error('Failed to get RTC instance not yet initialized.');
} else {
return rtcInstance;
}
};
const beforeChange = (editor, locks, beforeBookmark) => {
getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
};
const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event);
const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index);
const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data);
const clear = (editor, undoManager, index) => {
getRtcInstanceWithError(editor).undoManager.clear(undoManager, index);
};
const reset = (editor, undoManager) => {
getRtcInstanceWithError(editor).undoManager.reset(undoManager);
};
const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index);
const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index);
const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
const ignore = (editor, locks, callback) => {
getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
};
const extra = (editor, undoManager, index, callback1, callback2) => {
getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2);
};
const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar);
const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar);
const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name);
const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
const applyFormat = (editor, name, vars, node) => {
getRtcInstanceWithError(editor).formatter.apply(name, vars, node);
};
const removeFormat = (editor, name, vars, node, similar) => {
getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar);
};
const toggleFormat = (editor, name, vars, node) => {
getRtcInstanceWithError(editor).formatter.toggle(name, vars, node);
};
const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details);
const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents();
const getContent$1 = (editor, args = {}) => {
const format = args.format ? args.format : 'html';
return getSelectedContent(editor, format, args);
};
const removeEmpty = text => {
if (text.dom.length === 0) {
remove$4(text);
return Optional.none();
} else {
return Optional.some(text);
}
};
const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling);
const merge$1 = (outer, inner, rng, start, schema) => {
const outerElm = outer.dom;
const innerElm = inner.dom;
const oldLength = start ? outerElm.length : innerElm.length;
if (start) {
mergeTextNodes(outerElm, innerElm, schema, false, !start);
rng.setStart(innerElm, oldLength);
} else {
mergeTextNodes(innerElm, outerElm, schema, false, !start);
rng.setEnd(innerElm, oldLength);
}
};
const normalizeTextIfRequired = (inner, start, schema) => {
parent(inner).each(root => {
const text = inner.dom;
if (start && needsToBeNbspLeft(root, CaretPosition(text, 0), schema)) {
normalizeWhitespaceAfter(text, 0, schema);
} else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length), schema)) {
normalizeWhitespaceBefore(text, text.length, schema);
}
});
};
const mergeAndNormalizeText = (outerNode, innerNode, rng, start, schema) => {
outerNode.bind(outer => {
const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
normalizer(outer.dom, start ? outer.dom.length : 0, schema);
return innerNode.filter(isText$c).map(inner => merge$1(outer, inner, rng, start, schema));
}).orThunk(() => {
const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$c);
return innerTextNode.map(inner => normalizeTextIfRequired(inner, start, schema));
});
};
const rngSetContent = (rng, fragment, schema) => {
const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
rng.deleteContents();
rng.insertNode(fragment);
const prevText = firstChild.bind(prevSibling).filter(isText$c).bind(removeEmpty);
const nextText = lastChild.bind(nextSibling).filter(isText$c).bind(removeEmpty);
mergeAndNormalizeText(prevText, firstChild, rng, true, schema);
mergeAndNormalizeText(nextText, lastChild, rng, false, schema);
rng.collapse(false);
};
const setupArgs$2 = (args, content) => ({
format: 'html',
...args,
set: true,
selection: true,
content
});
const cleanContent = (editor, args) => {
if (args.format !== 'raw') {
const rng = editor.selection.getRng();
const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
const node = editor.parser.parse(args.content, {
forced_root_block: false,
...contextArgs,
...args
});
return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
} else {
return args.content;
}
};
const setContent$1 = (editor, content, args = {}) => {
const defaultedArgs = setupArgs$2(args, content);
preProcessSetContent(editor, defaultedArgs).each(updatedArgs => {
const cleanedContent = cleanContent(editor, updatedArgs);
const rng = editor.selection.getRng();
rngSetContent(rng, rng.createContextualFragment(cleanedContent), editor.schema);
editor.selection.setRng(rng);
scrollRangeIntoView(editor, rng);
postProcessSetContent(editor, cleanedContent, updatedArgs);
});
};
const deleteFromCallbackMap = (callbackMap, selector, callback) => {
if (has$2(callbackMap, selector)) {
const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback);
if (newCallbacks.length === 0) {
delete callbackMap[selector];
} else {
callbackMap[selector] = newCallbacks;
}
}
};
var SelectorChanged = (dom, editor) => {
let selectorChangedData;
let currentSelectors;
const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector));
const getParents = elem => dom.getParents(elem, undefined, dom.getRoot());
const setup = () => {
selectorChangedData = {};
currentSelectors = {};
editor.on('NodeChange', e => {
const node = e.element;
const parents = getParents(node);
const matchedSelectors = {};
each$d(selectorChangedData, (callbacks, selector) => {
findMatchingNode(selector, parents).each(node => {
if (!currentSelectors[selector]) {
each$e(callbacks, callback => {
callback(true, {
node,
selector,
parents
});
});
currentSelectors[selector] = callbacks;
}
matchedSelectors[selector] = callbacks;
});
});
each$d(currentSelectors, (callbacks, selector) => {
if (!matchedSelectors[selector]) {
delete currentSelectors[selector];
each$e(callbacks, callback => {
callback(false, {
node,
selector,
parents
});
});
}
});
});
};
return {
selectorChangedWithUnbind: (selector, callback) => {
if (!selectorChangedData) {
setup();
}
if (!selectorChangedData[selector]) {
selectorChangedData[selector] = [];
}
selectorChangedData[selector].push(callback);
findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => {
currentSelectors[selector] = selectorChangedData[selector];
});
return {
unbind: () => {
deleteFromCallbackMap(selectorChangedData, selector, callback);
deleteFromCallbackMap(currentSelectors, selector, callback);
}
};
}
};
};
const isAttachedToDom = node => {
return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
};
const isValidRange = rng => {
if (!rng) {
return false;
} else {
return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
}
};
const EditorSelection = (dom, win, serializer, editor) => {
let selectedRange;
let explicitRange;
const {selectorChangedWithUnbind} = SelectorChanged(dom, editor);
const setCursorLocation = (node, offset) => {
const rng = dom.createRng();
if (isNonNullable(node) && isNonNullable(offset)) {
rng.setStart(node, offset);
rng.setEnd(node, offset);
setRng(rng);
collapse(false);
} else {
moveEndPoint(dom, rng, editor.getBody(), true);
setRng(rng);
}
};
const getContent = args => getContent$1(editor, args);
const setContent = (content, args) => setContent$1(editor, content, args);
const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real);
const getEnd$1 = real => getEnd(editor.getBody(), getRng$1(), real);
const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized);
const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark);
const select$1 = (node, content) => {
select(dom, node, content).each(setRng);
return node;
};
const isCollapsed = () => {
const rng = getRng$1(), sel = getSel();
if (!rng || rng.item) {
return false;
}
if (rng.compareEndPoints) {
return rng.compareEndPoints('StartToEnd', rng) === 0;
}
return !sel || rng.collapsed;
};
const isEditable = () => {
const rng = getRng$1();
const fakeSelectedElements = editor.getBody().querySelectorAll('[data-mce-selected="1"]');
if (fakeSelectedElements.length > 0) {
return forall(fakeSelectedElements, el => dom.isEditable(el.parentElement));
} else {
return isEditableRange(dom, rng);
}
};
const collapse = toStart => {
const rng = getRng$1();
rng.collapse(!!toStart);
setRng(rng);
};
const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
const getRng$1 = () => {
let rng;
const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
try {
return sourceRange.compareBoundaryPoints(how, destinationRange);
} catch (ex) {
return -1;
}
};
const doc = win.document;
if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
const bookmark = getRng(editor);
if (bookmark.isSome()) {
return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange());
}
}
try {
const selection = getSel();
if (selection && !isRestrictedNode(selection.anchorNode)) {
if (selection.rangeCount > 0) {
rng = selection.getRangeAt(0);
} else {
rng = doc.createRange();
}
rng = processRanges(editor, [rng])[0];
}
} catch (ex) {
}
if (!rng) {
rng = doc.createRange();
}
if (isDocument$1(rng.startContainer) && rng.collapsed) {
const elm = dom.getRoot();
rng.setStart(elm, 0);
rng.setEnd(elm, 0);
}
if (selectedRange && explicitRange) {
if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
rng = explicitRange;
} else {
selectedRange = null;
explicitRange = null;
}
}
return rng;
};
const setRng = (rng, forward) => {
if (!isValidRange(rng)) {
return;
}
const sel = getSel();
const evt = editor.dispatch('SetSelectionRange', {
range: rng,
forward
});
rng = evt.range;
if (sel) {
explicitRange = rng;
try {
sel.removeAllRanges();
sel.addRange(rng);
} catch (ex) {
}
if (forward === false && sel.extend) {
sel.collapse(rng.endContainer, rng.endOffset);
sel.extend(rng.startContainer, rng.startOffset);
}
selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
}
if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) {
if (rng.endOffset - rng.startOffset < 2) {
if (rng.startContainer.hasChildNodes()) {
const node = rng.startContainer.childNodes[rng.startOffset];
if (node && node.nodeName === 'IMG') {
sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
sel.setBaseAndExtent(node, 0, node, 1);
}
}
}
}
}
editor.dispatch('AfterSetSelectionRange', {
range: rng,
forward
});
};
const setNode = elm => {
setContent(dom.getOuterHTML(elm));
return elm;
};
const getNode$1 = () => getNode(editor.getBody(), getRng$1());
const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm);
const isForward = () => {
const sel = getSel();
const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
return true;
}
const anchorRange = dom.createRng();
const focusRange = dom.createRng();
try {
anchorRange.setStart(anchorNode, sel.anchorOffset);
anchorRange.collapse(true);
focusRange.setStart(focusNode, sel.focusOffset);
focusRange.collapse(true);
} catch (e) {
return true;
}
return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
};
const normalize = () => {
const rng = getRng$1();
const sel = getSel();
if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
const normRng = normalize$2(dom, rng);
normRng.each(normRng => {
setRng(normRng, isForward());
});
return normRng.getOr(rng);
}
return rng;
};
const selectorChanged = (selector, callback) => {
selectorChangedWithUnbind(selector, callback);
return exports;
};
const getScrollContainer = () => {
let scrollContainer;
let node = dom.getRoot();
while (node && node.nodeName !== 'BODY') {
if (node.scrollHeight > node.clientHeight) {
scrollContainer = node;
break;
}
node = node.parentNode;
}
return scrollContainer;
};
const scrollIntoView = (elm, alignToTop) => {
if (isNonNullable(elm)) {
scrollElementIntoView(editor, elm, alignToTop);
} else {
scrollRangeIntoView(editor, getRng$1(), alignToTop);
}
};
const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
const getBoundingClientRect = () => {
const rng = getRng$1();
return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
};
const destroy = () => {
win = selectedRange = explicitRange = null;
controlSelection.destroy();
};
const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options));
const exports = {
dom,
win,
serializer,
editor,
expand,
collapse,
setCursorLocation,
getContent,
setContent,
getBookmark,
moveToBookmark,
select: select$1,
isCollapsed,
isEditable,
isForward,
setNode,
getNode: getNode$1,
getSel,
setRng,
getRng: getRng$1,
getStart: getStart$1,
getEnd: getEnd$1,
getSelectedBlocks: getSelectedBlocks$1,
normalize,
selectorChanged,
selectorChangedWithUnbind,
getScrollContainer,
scrollIntoView,
placeCaretAt,
getBoundingClientRect,
destroy
};
const bookmarkManager = BookmarkManager(exports);
const controlSelection = ControlSelection(exports, editor);
exports.bookmarkManager = bookmarkManager;
exports.controlSelection = controlSelection;
return exports;
};
const addNodeFilter = (settings, htmlParser, schema) => {
htmlParser.addNodeFilter('br', (nodes, _, args) => {
const blockElements = Tools.extend({}, schema.getBlockElements());
const nonEmptyElements = schema.getNonEmptyElements();
const whitespaceElements = schema.getWhitespaceElements();
blockElements.body = 1;
const isBlock = node => node.name in blockElements || isTransparentAstBlock(schema, node);
for (let i = 0, l = nodes.length; i < l; i++) {
let node = nodes[i];
let parent = node.parent;
if (parent && isBlock(parent) && node === parent.lastChild) {
let prev = node.prev;
while (prev) {
const prevName = prev.name;
if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
if (prevName === 'br') {
node = null;
}
break;
}
prev = prev.prev;
}
if (node) {
node.remove();
if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) {
const elementRule = schema.getElementRule(parent.name);
if (elementRule) {
if (elementRule.removeEmpty) {
parent.remove();
} else if (elementRule.paddEmpty) {
paddEmptyNode(settings, args, isBlock, parent);
}
}
}
}
} else {
let lastParent = node;
while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
lastParent = parent;
if (blockElements[parent.name]) {
break;
}
parent = parent.parent;
}
if (lastParent === parent) {
const textNode = new AstNode('#text', 3);
textNode.value = nbsp;
node.replace(textNode);
}
}
}
});
};
const register$3 = (htmlParser, settings, dom) => {
htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
node.attr('tabindex', node.attr('data-mce-tabindex'));
node.attr(name, null);
}
});
htmlParser.addAttributeFilter('src,href,style', (nodes, name) => {
const internalName = 'data-mce-' + name;
const urlConverter = settings.url_converter;
const urlConverterScope = settings.url_converter_scope;
let i = nodes.length;
while (i--) {
const node = nodes[i];
let value = node.attr(internalName);
if (value !== undefined) {
node.attr(name, value.length > 0 ? value : null);
node.attr(internalName, null);
} else {
value = node.attr(name);
if (name === 'style') {
value = dom.serializeStyle(dom.parseStyle(value), node.name);
} else if (urlConverter) {
value = urlConverter.call(urlConverterScope, value, name, node.name);
}
node.attr(name, value.length > 0 ? value : null);
}
}
});
htmlParser.addAttributeFilter('class', nodes => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
let value = node.attr('class');
if (value) {
value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
node.attr('class', value.length > 0 ? value : null);
}
}
});
htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
const hasChildren = Optional.from(node.firstChild).exists(firstChild => {
var _a;
return !isZwsp((_a = firstChild.value) !== null && _a !== void 0 ? _a : '');
});
if (hasChildren) {
node.unwrap();
} else {
node.remove();
}
}
}
});
htmlParser.addNodeFilter('script,style', (nodes, name) => {
var _a;
const trim = value => {
return value.replace(/()/g, '\n').replace(/^[\r\n]*|[\r\n]*$/g, '').replace(/^\s*(()?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
};
let i = nodes.length;
while (i--) {
const node = nodes[i];
const firstChild = node.firstChild;
const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : '';
if (name === 'script') {
const type = node.attr('type');
if (type) {
node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
}
if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
firstChild.value = '// ';
}
} else {
if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
firstChild.value = '';
}
}
}
});
htmlParser.addNodeFilter('#comment', nodes => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
const value = node.value;
if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) {
node.name = '#cdata';
node.type = 4;
node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, ''));
} else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) {
node.name = '#text';
node.type = 3;
node.raw = true;
node.value = unescape(value).substr(14);
}
}
});
htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
if (node.type === 7) {
node.remove();
} else if (node.type === 1) {
if (name === 'input' && !node.attr('type')) {
node.attr('type', 'text');
}
}
}
});
htmlParser.addAttributeFilter('data-mce-type', nodes => {
each$e(nodes, node => {
if (node.attr('data-mce-type') === 'format-caret') {
if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
node.remove();
} else {
node.unwrap();
}
}
});
});
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) => {
let i = nodes.length;
while (i--) {
nodes[i].attr(name, null);
}
});
if (settings.remove_trailing_brs) {
addNodeFilter(settings, htmlParser, htmlParser.schema);
}
};
const trimTrailingBr = rootNode => {
const isBr = node => {
return (node === null || node === void 0 ? void 0 : node.name) === 'br';
};
const brNode1 = rootNode.lastChild;
if (isBr(brNode1)) {
const brNode2 = brNode1.prev;
if (isBr(brNode2)) {
brNode1.remove();
brNode2.remove();
}
}
};
const preProcess$1 = (editor, node, args) => {
let oldDoc;
const dom = editor.dom;
let clonedNode = node.cloneNode(true);
const impl = document.implementation;
if (impl.createHTMLDocument) {
const doc = impl.createHTMLDocument('');
Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => {
doc.body.appendChild(doc.importNode(node, true));
});
if (clonedNode.nodeName !== 'BODY') {
clonedNode = doc.body.firstChild;
} else {
clonedNode = doc.body;
}
oldDoc = dom.doc;
dom.doc = doc;
}
firePreProcess(editor, {
...args,
node: clonedNode
});
if (oldDoc) {
dom.doc = oldDoc;
}
return clonedNode;
};
const shouldFireEvent = (editor, args) => {
return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events;
};
const process$1 = (editor, node, args) => {
return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
};
const addTempAttr = (htmlParser, tempAttrs, name) => {
if (Tools.inArray(tempAttrs, name) === -1) {
htmlParser.addAttributeFilter(name, (nodes, name) => {
let i = nodes.length;
while (i--) {
nodes[i].attr(name, null);
}
});
tempAttrs.push(name);
}
};
const postProcess = (editor, args, content) => {
if (!args.no_events && editor) {
const outArgs = firePostProcess(editor, {
...args,
content
});
return outArgs.content;
} else {
return content;
}
};
const getHtmlFromNode = (dom, node, args) => {
const html = trim$2(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html);
};
const parseHtml = (htmlParser, html, args) => {
const parserArgs = args.selection ? {
forced_root_block: false,
...args
} : args;
const rootNode = htmlParser.parse(html, parserArgs);
trimTrailingBr(rootNode);
return rootNode;
};
const serializeNode = (settings, schema, node) => {
const htmlSerializer = HtmlSerializer(settings, schema);
return htmlSerializer.serialize(node);
};
const toHtml = (editor, settings, schema, rootNode, args) => {
const content = serializeNode(settings, schema, rootNode);
return postProcess(editor, args, content);
};
const DomSerializerImpl = (settings, editor) => {
const tempAttrs = ['data-mce-selected'];
const defaultedSettings = {
entity_encoding: 'named',
remove_trailing_brs: true,
pad_empty_with_br: false,
...settings
};
const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM;
const schema = editor && editor.schema ? editor.schema : Schema(defaultedSettings);
const htmlParser = DomParser(defaultedSettings, schema);
register$3(htmlParser, defaultedSettings, dom);
const serialize = (node, parserArgs = {}) => {
const args = {
format: 'html',
...parserArgs
};
const targetNode = process$1(editor, node, args);
const html = getHtmlFromNode(dom, targetNode, args);
const rootNode = parseHtml(htmlParser, html, args);
return args.format === 'tree' ? rootNode : toHtml(editor, defaultedSettings, schema, rootNode, args);
};
return {
schema,
addNodeFilter: htmlParser.addNodeFilter,
addAttributeFilter: htmlParser.addAttributeFilter,
serialize: serialize,
addRules: schema.addValidElements,
setRules: schema.setValidElements,
addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
getTempAttrs: constant(tempAttrs),
getNodeFilters: htmlParser.getNodeFilters,
getAttributeFilters: htmlParser.getAttributeFilters,
removeNodeFilter: htmlParser.removeNodeFilter,
removeAttributeFilter: htmlParser.removeAttributeFilter
};
};
const DomSerializer = (settings, editor) => {
const domSerializer = DomSerializerImpl(settings, editor);
return {
schema: domSerializer.schema,
addNodeFilter: domSerializer.addNodeFilter,
addAttributeFilter: domSerializer.addAttributeFilter,
serialize: domSerializer.serialize,
addRules: domSerializer.addRules,
setRules: domSerializer.setRules,
addTempAttr: domSerializer.addTempAttr,
getTempAttrs: domSerializer.getTempAttrs,
getNodeFilters: domSerializer.getNodeFilters,
getAttributeFilters: domSerializer.getAttributeFilters,
removeNodeFilter: domSerializer.removeNodeFilter,
removeAttributeFilter: domSerializer.removeAttributeFilter
};
};
const defaultFormat$1 = 'html';
const setupArgs$1 = (args, format) => ({
...args,
format,
get: true,
getInner: true
});
const getContent = (editor, args = {}) => {
const format = args.format ? args.format : defaultFormat$1;
const defaultedArgs = setupArgs$1(args, format);
return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
const content = getContent$2(editor, updatedArgs);
return postProcessGetContent(editor, content, updatedArgs);
});
};
const defaultFormat = 'html';
const setupArgs = (args, content) => ({
format: defaultFormat,
...args,
set: true,
content
});
const setContent = (editor, content, args = {}) => {
const defaultedArgs = setupArgs(args, content);
return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => {
const result = setContent$2(editor, updatedArgs.content, updatedArgs);
postProcessSetContent(editor, result.html, updatedArgs);
return result.content;
}).getOr(content);
};
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(',');
const deprecatedOptions = [];
const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,template,textcolor,rtc'.split(',');
const deprecatedPlugins = [];
const getMatchingOptions = (options, searchingFor) => {
const settingNames = filter$5(searchingFor, setting => has$2(options, setting));
return sort(settingNames);
};
const getRemovedOptions = options => {
const settingNames = getMatchingOptions(options, removedOptions);
const forcedRootBlock = options.forced_root_block;
if (forcedRootBlock === false || forcedRootBlock === '') {
settingNames.push('forced_root_block (false only)');
}
return sort(settingNames);
};
const getDeprecatedOptions = options => getMatchingOptions(options, deprecatedOptions);
const getMatchingPlugins = (options, searchingFor) => {
const plugins = Tools.makeMap(options.plugins, ' ');
const hasPlugin = plugin => has$2(plugins, plugin);
const pluginNames = filter$5(searchingFor, hasPlugin);
return sort(pluginNames);
};
const getRemovedPlugins = options => getMatchingPlugins(options, removedPlugins);
const getDeprecatedPlugins = options => getMatchingPlugins(options, deprecatedPlugins.map(entry => entry.name));
const logRemovedWarnings = (rawOptions, normalizedOptions) => {
const removedOptions = getRemovedOptions(rawOptions);
const removedPlugins = getRemovedPlugins(normalizedOptions);
const hasRemovedPlugins = removedPlugins.length > 0;
const hasRemovedOptions = removedOptions.length > 0;
const isLegacyMobileTheme = normalizedOptions.theme === 'mobile';
if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
const listJoiner = '\n- ';
const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : '';
const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : '';
const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : '';
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);
}
};
const getPluginDescription = name => find$2(deprecatedPlugins, entry => entry.name === name).fold(() => name, entry => {
if (entry.replacedWith) {
return `${ name }, replaced by ${ entry.replacedWith }`;
} else {
return name;
}
});
const logDeprecatedWarnings = (rawOptions, normalizedOptions) => {
const deprecatedOptions = getDeprecatedOptions(rawOptions);
const deprecatedPlugins = getDeprecatedPlugins(normalizedOptions);
const hasDeprecatedPlugins = deprecatedPlugins.length > 0;
const hasDeprecatedOptions = deprecatedOptions.length > 0;
if (hasDeprecatedPlugins || hasDeprecatedOptions) {
const listJoiner = '\n- ';
const pluginsMessage = hasDeprecatedPlugins ? `\n\nPlugins:${ listJoiner }${ deprecatedPlugins.map(getPluginDescription).join(listJoiner) }` : '';
const optionsMessage = hasDeprecatedOptions ? `\n\nOptions:${ listJoiner }${ deprecatedOptions.join(listJoiner) }` : '';
console.warn('The following deprecated features are currently enabled but will be removed soon.' + pluginsMessage + optionsMessage);
}
};
const logWarnings = (rawOptions, normalizedOptions) => {
logRemovedWarnings(rawOptions, normalizedOptions);
logDeprecatedWarnings(rawOptions, normalizedOptions);
};
const DOM$8 = DOMUtils.DOM;
const restoreOriginalStyles = editor => {
DOM$8.setStyle(editor.id, 'display', editor.orgDisplay);
};
const safeDestroy = x => Optional.from(x).each(x => x.destroy());
const clearDomReferences = editor => {
const ed = editor;
ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null;
ed.bodyElement = ed.contentDocument = ed.contentWindow = null;
ed.iframeElement = ed.targetElm = null;
const selection = editor.selection;
if (selection) {
const dom = selection.dom;
ed.selection = selection.win = selection.dom = dom.doc = null;
}
};
const restoreForm = editor => {
const form = editor.formElement;
if (form) {
if (form._mceOldSubmit) {
form.submit = form._mceOldSubmit;
delete form._mceOldSubmit;
}
DOM$8.unbind(form, 'submit reset', editor.formEventDelegate);
}
};
const remove$1 = editor => {
if (!editor.removed) {
const {_selectionOverrides, editorUpload} = editor;
const body = editor.getBody();
const element = editor.getElement();
if (body) {
editor.save({ is_removing: true });
}
editor.removed = true;
editor.unbindAllNativeEvents();
if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) {
DOM$8.remove(element.nextSibling);
}
fireRemove(editor);
editor.editorManager.remove(editor);
if (!editor.inline && body) {
restoreOriginalStyles(editor);
}
fireDetach(editor);
DOM$8.remove(editor.getContainer());
safeDestroy(_selectionOverrides);
safeDestroy(editorUpload);
editor.destroy();
}
};
const destroy = (editor, automatic) => {
const {selection, dom} = editor;
if (editor.destroyed) {
return;
}
if (!automatic && !editor.removed) {
editor.remove();
return;
}
if (!automatic) {
editor.editorManager.off('beforeunload', editor._beforeUnload);
if (editor.theme && editor.theme.destroy) {
editor.theme.destroy();
}
safeDestroy(selection);
safeDestroy(dom);
}
restoreForm(editor);
clearDomReferences(editor);
editor.destroyed = true;
};
const CreateIconManager = () => {
const lookup = {};
const add = (id, iconPack) => {
lookup[id] = iconPack;
};
const get = id => {
if (lookup[id]) {
return lookup[id];
} else {
return { icons: {} };
}
};
const has = id => has$2(lookup, id);
return {
add,
get,
has
};
};
const IconManager = CreateIconManager();
const ModelManager = AddOnManager.ModelManager;
const getProp = (propName, elm) => {
const rawElm = elm.dom;
return rawElm[propName];
};
const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
const getClientWidth = curry(getProp, 'clientWidth');
const getClientHeight = curry(getProp, 'clientHeight');
const getMarginTop = curry(getComputedSizeProp, 'margin-top');
const getMarginLeft = curry(getComputedSizeProp, 'margin-left');
const getBoundingClientRect = elm => elm.dom.getBoundingClientRect();
const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
const clientWidth = getClientWidth(bodyElm);
const clientHeight = getClientHeight(bodyElm);
return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
};
const transpose = (inline, elm, clientX, clientY) => {
const clientRect = getBoundingClientRect(elm);
const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
const x = clientX - deltaX;
const y = clientY - deltaY;
return {
x,
y
};
};
const isXYInContentArea = (editor, clientX, clientY) => {
const bodyElm = SugarElement.fromDom(editor.getBody());
const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
};
const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom);
const isEditorAttachedToDom = editor => {
const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
return fromDomSafe(rawContainer).map(inBody).getOr(false);
};
var NotificationManagerImpl = () => {
const unimplemented = () => {
throw new Error('Theme did not provide a NotificationManager implementation.');
};
return {
open: unimplemented,
close: unimplemented,
getArgs: unimplemented
};
};
const NotificationManager = editor => {
const notifications = [];
const getImplementation = () => {
const theme = editor.theme;
return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
};
const getTopNotification = () => {
return Optional.from(notifications[0]);
};
const isEqual = (a, b) => {
return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
};
const reposition = () => {
getTopNotification().each(notification => {
notification.reposition();
});
};
const addNotification = notification => {
notifications.push(notification);
};
const closeNotification = notification => {
findIndex$2(notifications, otherNotification => {
return otherNotification === notification;
}).each(index => {
notifications.splice(index, 1);
});
};
const open = (spec, fireEvent = true) => {
if (editor.removed || !isEditorAttachedToDom(editor)) {
return {};
}
if (fireEvent) {
editor.dispatch('BeforeOpenNotification', { notification: spec });
}
return find$2(notifications, notification => {
return isEqual(getImplementation().getArgs(notification), spec);
}).getOrThunk(() => {
editor.editorManager.setActive(editor);
const notification = getImplementation().open(spec, () => {
closeNotification(notification);
}, () => hasEditorOrUiFocus(editor));
addNotification(notification);
reposition();
editor.dispatch('OpenNotification', { notification: { ...notification } });
return notification;
});
};
const close = () => {
getTopNotification().each(notification => {
getImplementation().close(notification);
closeNotification(notification);
reposition();
});
};
const getNotifications = constant(notifications);
const registerEvents = editor => {
editor.on('SkinLoaded', () => {
const serviceMessage = getServiceMessage(editor);
if (serviceMessage) {
open({
text: serviceMessage,
type: 'warning',
timeout: 0
}, false);
}
reposition();
});
editor.on('show ResizeEditor ResizeWindow NodeChange ToggleView FullscreenStateChanged', () => {
requestAnimationFrame(reposition);
});
editor.on('remove', () => {
each$e(notifications.slice(), notification => {
getImplementation().close(notification);
});
});
editor.addShortcut('alt+F12', 'Focus to notification', () => getTopNotification().map(notificationApi => SugarElement.fromDom(notificationApi.getEl())).each(elm => focus$1(elm)));
};
registerEvents(editor);
return {
open,
close,
getNotifications
};
};
const PluginManager = AddOnManager.PluginManager;
const ThemeManager = AddOnManager.ThemeManager;
var WindowManagerImpl = () => {
const unimplemented = () => {
throw new Error('Theme did not provide a WindowManager implementation.');
};
return {
open: unimplemented,
openUrl: unimplemented,
alert: unimplemented,
confirm: unimplemented,
close: unimplemented
};
};
const WindowManager = editor => {
let dialogs = [];
const getImplementation = () => {
const theme = editor.theme;
return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
};
const funcBind = (scope, f) => {
return (...args) => {
return f ? f.apply(scope, args) : undefined;
};
};
const fireOpenEvent = dialog => {
editor.dispatch('OpenWindow', { dialog });
};
const fireCloseEvent = dialog => {
editor.dispatch('CloseWindow', { dialog });
};
const addDialog = dialog => {
dialogs.push(dialog);
fireOpenEvent(dialog);
};
const closeDialog = dialog => {
fireCloseEvent(dialog);
dialogs = filter$5(dialogs, otherDialog => {
return otherDialog !== dialog;
});
if (dialogs.length === 0) {
editor.focus();
}
};
const getTopDialog = () => {
return Optional.from(dialogs[dialogs.length - 1]);
};
const storeSelectionAndOpenDialog = openDialog => {
editor.editorManager.setActive(editor);
store(editor);
editor.ui.show();
const dialog = openDialog();
addDialog(dialog);
return dialog;
};
const open = (args, params) => {
return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
};
const openUrl = args => {
return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
};
const alert = (message, callback, scope) => {
const windowManagerImpl = getImplementation();
windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
};
const confirm = (message, callback, scope) => {
const windowManagerImpl = getImplementation();
windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
};
const close = () => {
getTopDialog().each(dialog => {
getImplementation().close(dialog);
closeDialog(dialog);
});
};
editor.on('remove', () => {
each$e(dialogs, dialog => {
getImplementation().close(dialog);
});
});
return {
open,
openUrl,
alert,
confirm,
close
};
};
const displayNotification = (editor, message) => {
editor.notificationManager.open({
type: 'error',
text: message
});
};
const displayError = (editor, message) => {
if (editor._skinLoaded) {
displayNotification(editor, message);
} else {
editor.on('SkinLoaded', () => {
displayNotification(editor, message);
});
}
};
const uploadError = (editor, message) => {
displayError(editor, I18n.translate([
'Failed to upload image: {0}',
message
]));
};
const logError = (editor, errorType, msg) => {
fireError(editor, errorType, { message: msg });
console.error(msg);
};
const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`;
const pluginLoadError = (editor, url, name) => {
logError(editor, 'PluginLoadError', createLoadError('plugin', url, name));
};
const iconsLoadError = (editor, url, name) => {
logError(editor, 'IconsLoadError', createLoadError('icons', url, name));
};
const languageLoadError = (editor, url, name) => {
logError(editor, 'LanguageLoadError', createLoadError('language', url, name));
};
const themeLoadError = (editor, url, name) => {
logError(editor, 'ThemeLoadError', createLoadError('theme', url, name));
};
const modelLoadError = (editor, url, name) => {
logError(editor, 'ModelLoadError', createLoadError('model', url, name));
};
const pluginInitError = (editor, name, err) => {
const message = I18n.translate([
'Failed to initialize plugin: {0}',
name
]);
fireError(editor, 'PluginLoadError', { message });
initError(message, err);
displayError(editor, message);
};
const initError = (message, ...x) => {
const console = window.console;
if (console) {
if (console.error) {
console.error(message, ...x);
} else {
console.log(message, ...x);
}
}
};
const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url);
const toContentSkinResourceName = url => 'content/' + url + '/content.css';
const isBundledCssSkinName = url => tinymce.Resource.has(toContentSkinResourceName(url));
const getContentCssUrls = editor => {
return transformToUrls(editor, getContentCss(editor));
};
const getFontCssUrls = editor => {
return transformToUrls(editor, getFontCss(editor));
};
const transformToUrls = (editor, cssLinks) => {
const skinUrl = editor.editorManager.baseURL + '/skins/content';
const suffix = editor.editorManager.suffix;
const contentCssFile = `content${ suffix }.css`;
return map$3(cssLinks, url => {
if (isBundledCssSkinName(url)) {
return url;
} else if (isContentCssSkinName(url) && !editor.inline) {
return `${ skinUrl }/${ url }/${ contentCssFile }`;
} else {
return editor.documentBaseURI.toAbsolute(url);
}
});
};
const appendContentCssFromSettings = editor => {
editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
};
const getAllImages = elm => {
return elm ? from(elm.getElementsByTagName('img')) : [];
};
const ImageScanner = (uploadStatus, blobCache) => {
const cachedPromises = {};
const findAll = (elm, predicate = always) => {
const images = filter$5(getAllImages(elm), img => {
const src = img.src;
if (img.hasAttribute('data-mce-bogus')) {
return false;
}
if (img.hasAttribute('data-mce-placeholder')) {
return false;
}
if (!src || src === Env.transparentSrc) {
return false;
}
if (startsWith(src, 'blob:')) {
return !uploadStatus.isUploaded(src) && predicate(img);
}
if (startsWith(src, 'data:')) {
return predicate(img);
}
return false;
});
const promises = map$3(images, img => {
const imageSrc = img.src;
if (has$2(cachedPromises, imageSrc)) {
return cachedPromises[imageSrc].then(imageInfo => {
if (isString(imageInfo)) {
return imageInfo;
} else {
return {
image: img,
blobInfo: imageInfo.blobInfo
};
}
});
} else {
const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => {
delete cachedPromises[imageSrc];
return {
image: img,
blobInfo
};
}).catch(error => {
delete cachedPromises[imageSrc];
return error;
});
cachedPromises[imageSrc] = newPromise;
return newPromise;
}
});
return Promise.all(promises);
};
return { findAll };
};
const UploadStatus = () => {
const PENDING = 1, UPLOADED = 2;
let blobUriStatuses = {};
const createStatus = (status, resultUri) => {
return {
status,
resultUri
};
};
const hasBlobUri = blobUri => {
return blobUri in blobUriStatuses;
};
const getResultUri = blobUri => {
const result = blobUriStatuses[blobUri];
return result ? result.resultUri : null;
};
const isPending = blobUri => {
return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
};
const isUploaded = blobUri => {
return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
};
const markPending = blobUri => {
blobUriStatuses[blobUri] = createStatus(PENDING, null);
};
const markUploaded = (blobUri, resultUri) => {
blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
};
const removeFailed = blobUri => {
delete blobUriStatuses[blobUri];
};
const destroy = () => {
blobUriStatuses = {};
};
return {
hasBlobUri,
getResultUri,
isPending,
isUploaded,
markPending,
markUploaded,
removeFailed,
destroy
};
};
let count = 0;
const seed = () => {
const rnd = () => {
return Math.round(random() * 4294967295).toString(36);
};
const now = new Date().getTime();
return 's' + now.toString(36) + rnd() + rnd() + rnd();
};
const uuid = prefix => {
return prefix + count++ + seed();
};
const BlobCache = () => {
let cache = [];
const mimeToExt = mime => {
const mimes = {
'image/jpeg': 'jpg',
'image/jpg': 'jpg',
'image/gif': 'gif',
'image/png': 'png',
'image/apng': 'apng',
'image/avif': 'avif',
'image/svg+xml': 'svg',
'image/webp': 'webp',
'image/bmp': 'bmp',
'image/tiff': 'tiff'
};
return mimes[mime.toLowerCase()] || 'dat';
};
const create = (o, blob, base64, name, filename) => {
if (isString(o)) {
const id = o;
return toBlobInfo({
id,
name,
filename,
blob: blob,
base64: base64
});
} else if (isObject(o)) {
return toBlobInfo(o);
} else {
throw new Error('Unknown input type');
}
};
const toBlobInfo = o => {
if (!o.blob || !o.base64) {
throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
}
const id = o.id || uuid('blobid');
const name = o.name || id;
const blob = o.blob;
return {
id: constant(id),
name: constant(name),
filename: constant(o.filename || name + '.' + mimeToExt(blob.type)),
blob: constant(blob),
base64: constant(o.base64),
blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
uri: constant(o.uri)
};
};
const add = blobInfo => {
if (!get(blobInfo.id())) {
cache.push(blobInfo);
}
};
const findFirst = predicate => find$2(cache, predicate).getOrUndefined();
const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id);
const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri);
const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type);
const removeByUri = blobUri => {
cache = filter$5(cache, blobInfo => {
if (blobInfo.blobUri() === blobUri) {
URL.revokeObjectURL(blobInfo.blobUri());
return false;
}
return true;
});
};
const destroy = () => {
each$e(cache, cachedBlobInfo => {
URL.revokeObjectURL(cachedBlobInfo.blobUri());
});
cache = [];
};
return {
create,
add,
get,
getByUri,
getByData,
findFirst,
removeByUri,
destroy
};
};
const Uploader = (uploadStatus, settings) => {
const pendingPromises = {};
const pathJoin = (path1, path2) => {
if (path1) {
return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
}
return path2;
};
const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', settings.url);
xhr.withCredentials = settings.credentials;
xhr.upload.onprogress = e => {
progress(e.loaded / e.total * 100);
};
xhr.onerror = () => {
failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
};
xhr.onload = () => {
if (xhr.status < 200 || xhr.status >= 300) {
failure('HTTP Error: ' + xhr.status);
return;
}
const json = JSON.parse(xhr.responseText);
if (!json || !isString(json.location)) {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(pathJoin(settings.basePath, json.location));
};
const formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
});
const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler;
const noUpload = () => new Promise(resolve => {
resolve([]);
});
const handlerSuccess = (blobInfo, url) => ({
url,
blobInfo,
status: true
});
const handlerFailure = (blobInfo, error) => ({
url: '',
blobInfo,
status: false,
error
});
const resolvePending = (blobUri, result) => {
Tools.each(pendingPromises[blobUri], resolve => {
resolve(result);
});
delete pendingPromises[blobUri];
};
const uploadBlobInfo = (blobInfo, handler, openNotification) => {
uploadStatus.markPending(blobInfo.blobUri());
return new Promise(resolve => {
let notification;
let progress;
try {
const closeNotification = () => {
if (notification) {
notification.close();
progress = noop;
}
};
const success = url => {
closeNotification();
uploadStatus.markUploaded(blobInfo.blobUri(), url);
resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
resolve(handlerSuccess(blobInfo, url));
};
const failure = error => {
closeNotification();
uploadStatus.removeFailed(blobInfo.blobUri());
resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
resolve(handlerFailure(blobInfo, error));
};
progress = percent => {
if (percent < 0 || percent > 100) {
return;
}
Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => {
notification = n;
n.progressBar.value(percent);
});
};
handler(blobInfo, progress).then(success, err => {
failure(isString(err) ? { message: err } : err);
});
} catch (ex) {
resolve(handlerFailure(blobInfo, ex));
}
});
};
const isDefaultHandler = handler => handler === defaultHandler;
const pendingUploadBlobInfo = blobInfo => {
const blobUri = blobInfo.blobUri();
return new Promise(resolve => {
pendingPromises[blobUri] = pendingPromises[blobUri] || [];
pendingPromises[blobUri].push(resolve);
});
};
const uploadBlobs = (blobInfos, openNotification) => {
blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri()));
return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification)));
};
const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
return { upload };
};
const openNotification = editor => () => editor.notificationManager.open({
text: editor.translate('Image uploading...'),
type: 'info',
timeout: -1,
progressBar: true
});
const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
url: getImageUploadUrl(editor),
basePath: getImageUploadBasePath(editor),
credentials: getImagesUploadCredentials(editor),
handler: getImagesUploadHandler(editor)
});
const ImageUploader = editor => {
const uploadStatus = UploadStatus();
const uploader = createUploader(editor, uploadStatus);
return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) };
};
const isEmptyForPadding = (editor, element) => editor.dom.isEmpty(element.dom) && isNonNullable(editor.schema.getTextBlockElements()[name(element)]);
const addPaddingToEmpty = editor => element => {
if (isEmptyForPadding(editor, element)) {
append$1(element, SugarElement.fromHtml('
'));
}
};
const EditorUpload = editor => {
const blobCache = BlobCache();
let uploader, imageScanner;
const uploadStatus = UploadStatus();
const urlFilters = [];
const aliveGuard = callback => {
return result => {
if (editor.selection) {
return callback(result);
}
return [];
};
};
const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime();
const replaceString = (content, search, replace) => {
let index = 0;
do {
index = content.indexOf(search, index);
if (index !== -1) {
content = content.substring(0, index) + replace + content.substr(index + search.length);
index += replace.length - search.length + 1;
}
} while (index !== -1);
return content;
};
const replaceImageUrl = (content, targetUrl, replacementUrl) => {
const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`;
content = replaceString(content, `src="${ targetUrl }"`, replacementString);
content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
return content;
};
const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
each$e(editor.undoManager.data, level => {
if (level.type === 'fragmented') {
level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl));
} else {
level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
}
});
};
const replaceImageUriInView = (image, resultUri) => {
const src = editor.convertURL(resultUri, 'src');
replaceUrlInUndoStack(image.src, resultUri);
setAll$1(SugarElement.fromDom(image), {
'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
'data-mce-src': src
});
};
const uploadImages = () => {
if (!uploader) {
uploader = createUploader(editor, uploadStatus);
}
return scanForImages().then(aliveGuard(imageInfos => {
const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo);
return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => {
const imagesToRemove = [];
let shouldDispatchChange = false;
const filteredResult = map$3(result, (uploadInfo, index) => {
const {blobInfo, image} = imageInfos[index];
let removed = false;
if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
shouldDispatchChange = true;
}
blobCache.removeByUri(image.src);
if (isRtc(editor)) ; else {
replaceImageUriInView(image, uploadInfo.url);
}
} else if (uploadInfo.error) {
if (uploadInfo.error.remove) {
replaceUrlInUndoStack(image.src, Env.transparentSrc);
imagesToRemove.push(image);
removed = true;
}
uploadError(editor, uploadInfo.error.message);
}
return {
element: image,
status: uploadInfo.status,
uploadUri: uploadInfo.url,
blobInfo,
removed
};
});
if (imagesToRemove.length > 0 && !isRtc(editor)) {
editor.undoManager.transact(() => {
each$e(fromDom$1(imagesToRemove), sugarElement => {
const parentOpt = parent(sugarElement);
remove$4(sugarElement);
parentOpt.each(addPaddingToEmpty(editor));
blobCache.removeByUri(sugarElement.dom.src);
});
});
} else if (shouldDispatchChange) {
editor.undoManager.dispatchChange();
}
return filteredResult;
}));
}));
};
const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm));
const addFilter = filter => {
urlFilters.push(filter);
};
const scanForImages = () => {
if (!imageScanner) {
imageScanner = ImageScanner(uploadStatus, blobCache);
}
return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => {
const filteredResult = filter$5(result, resultItem => {
if (isString(resultItem)) {
displayError(editor, resultItem);
return false;
} else if (resultItem.uriType === 'blob') {
return false;
} else {
return true;
}
});
if (isRtc(editor)) ; else {
each$e(filteredResult, resultItem => {
replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
resultItem.image.src = resultItem.blobInfo.blobUri();
resultItem.image.removeAttribute('data-mce-src');
});
}
return filteredResult;
}));
};
const destroy = () => {
blobCache.destroy();
uploadStatus.destroy();
imageScanner = uploader = null;
};
const replaceBlobUris = content => {
return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => {
const resultUri = uploadStatus.getResultUri(blobUri);
if (resultUri) {
return 'src="' + resultUri + '"';
}
let blobInfo = blobCache.getByUri(blobUri);
if (!blobInfo) {
blobInfo = foldl(editor.editorManager.get(), (result, editor) => {
return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
}, undefined);
}
if (blobInfo) {
const blob = blobInfo.blob();
return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
}
return match;
});
};
editor.on('SetContent', () => {
if (isAutomaticUploadsEnabled(editor)) {
uploadImagesAuto();
} else {
scanForImages();
}
});
editor.on('RawSaveContent', e => {
e.content = replaceBlobUris(e.content);
});
editor.on('GetContent', e => {
if (e.source_view || e.format === 'raw' || e.format === 'tree') {
return;
}
e.content = replaceBlobUris(e.content);
});
editor.on('PostRender', () => {
editor.parser.addNodeFilter('img', images => {
each$e(images, img => {
const src = img.attr('src');
if (!src || blobCache.getByUri(src)) {
return;
}
const resultUri = uploadStatus.getResultUri(src);
if (resultUri) {
img.attr('src', resultUri);
}
});
});
});
return {
blobCache,
addFilter,
uploadImages,
uploadImagesAuto,
scanForImages,
destroy
};
};
const get$1 = editor => {
const dom = editor.dom;
const schemaType = editor.schema.type;
const formats = {
valigntop: [{
selector: 'td,th',
styles: { verticalAlign: 'top' }
}],
valignmiddle: [{
selector: 'td,th',
styles: { verticalAlign: 'middle' }
}],
valignbottom: [{
selector: 'td,th',
styles: { verticalAlign: 'bottom' }
}],
alignleft: [
{
selector: 'figure.image',
collapsed: false,
classes: 'align-left',
ceFalseOverride: true,
preview: 'font-family font-size'
},
{
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
styles: { textAlign: 'left' },
inherit: false,
preview: false
},
{
selector: 'img,audio,video',
collapsed: false,
styles: { float: 'left' },
preview: 'font-family font-size'
},
{
selector: 'table',
collapsed: false,
styles: {
marginLeft: '0px',
marginRight: 'auto'
},
onformat: table => {
dom.setStyle(table, 'float', null);
},
preview: 'font-family font-size'
},
{
selector: '.mce-preview-object,[data-ephox-embed-iri]',
ceFalseOverride: true,
styles: { float: 'left' }
}
],
aligncenter: [
{
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
styles: { textAlign: 'center' },
inherit: false,
preview: 'font-family font-size'
},
{
selector: 'figure.image',
collapsed: false,
classes: 'align-center',
ceFalseOverride: true,
preview: 'font-family font-size'
},
{
selector: 'img,audio,video',
collapsed: false,
styles: {
display: 'block',
marginLeft: 'auto',
marginRight: 'auto'
},
preview: false
},
{
selector: 'table',
collapsed: false,
styles: {
marginLeft: 'auto',
marginRight: 'auto'
},
preview: 'font-family font-size'
},
{
selector: '.mce-preview-object',
ceFalseOverride: true,
styles: {
display: 'table',
marginLeft: 'auto',
marginRight: 'auto'
},
preview: false
},
{
selector: '[data-ephox-embed-iri]',
ceFalseOverride: true,
styles: {
marginLeft: 'auto',
marginRight: 'auto'
},
preview: false
}
],
alignright: [
{
selector: 'figure.image',
collapsed: false,
classes: 'align-right',
ceFalseOverride: true,
preview: 'font-family font-size'
},
{
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
styles: { textAlign: 'right' },
inherit: false,
preview: 'font-family font-size'
},
{
selector: 'img,audio,video',
collapsed: false,
styles: { float: 'right' },
preview: 'font-family font-size'
},
{
selector: 'table',
collapsed: false,
styles: {
marginRight: '0px',
marginLeft: 'auto'
},
onformat: table => {
dom.setStyle(table, 'float', null);
},
preview: 'font-family font-size'
},
{
selector: '.mce-preview-object,[data-ephox-embed-iri]',
ceFalseOverride: true,
styles: { float: 'right' },
preview: false
}
],
alignjustify: [{
selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
styles: { textAlign: 'justify' },
inherit: false,
preview: 'font-family font-size'
}],
bold: [
{
inline: 'strong',
remove: 'all',
preserve_attributes: [
'class',
'style'
]
},
{
inline: 'span',
styles: { fontWeight: 'bold' }
},
{
inline: 'b',
remove: 'all',
preserve_attributes: [
'class',
'style'
]
}
],
italic: [
{
inline: 'em',
remove: 'all',
preserve_attributes: [
'class',
'style'
]
},
{
inline: 'span',
styles: { fontStyle: 'italic' }
},
{
inline: 'i',
remove: 'all',
preserve_attributes: [
'class',
'style'
]
}
],
underline: [
{
inline: 'span',
styles: { textDecoration: 'underline' },
exact: true
},
{
inline: 'u',
remove: 'all',
preserve_attributes: [
'class',
'style'
]
}
],
strikethrough: (() => {
const span = {
inline: 'span',
styles: { textDecoration: 'line-through' },
exact: true
};
const strike = {
inline: 'strike',
remove: 'all',
preserve_attributes: [
'class',
'style'
]
};
const s = {
inline: 's',
remove: 'all',
preserve_attributes: [
'class',
'style'
]
};
return schemaType !== 'html4' ? [
s,
span,
strike
] : [
span,
s,
strike
];
})(),
forecolor: {
inline: 'span',
styles: { color: '%value' },
links: true,
remove_similar: true,
clear_child_styles: true
},
hilitecolor: {
inline: 'span',
styles: { backgroundColor: '%value' },
links: true,
remove_similar: true,
clear_child_styles: true
},
fontname: {
inline: 'span',
toggle: false,
styles: { fontFamily: '%value' },
clear_child_styles: true
},
fontsize: {
inline: 'span',
toggle: false,
styles: { fontSize: '%value' },
clear_child_styles: true
},
lineheight: {
selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div',
styles: { lineHeight: '%value' }
},
fontsize_class: {
inline: 'span',
attributes: { class: '%value' }
},
blockquote: {
block: 'blockquote',
wrapper: true,
remove: 'all'
},
subscript: { inline: 'sub' },
superscript: { inline: 'sup' },
code: { inline: 'code' },
link: {
inline: 'a',
selector: 'a',
remove: 'all',
split: true,
deep: true,
onmatch: (node, _fmt, _itemName) => {
return isElement$6(node) && node.hasAttribute('href');
},
onformat: (elm, _fmt, vars) => {
Tools.each(vars, (value, key) => {
dom.setAttrib(elm, key, value);
});
}
},
lang: {
inline: 'span',
clear_child_styles: true,
remove_similar: true,
attributes: {
'lang': '%value',
'data-mce-lang': vars => {
var _a;
return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
}
}
},
removeformat: [
{
selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small',
remove: 'all',
split: true,
expand: false,
block_expand: true,
deep: true
},
{
selector: 'span',
attributes: [
'style',
'class'
],
remove: 'empty',
split: true,
expand: false,
deep: true
},
{
selector: '*',
attributes: [
'style',
'class'
],
split: false,
expand: false,
deep: true
}
]
};
Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd samp'.split(/\s/), name => {
formats[name] = {
block: name,
remove: 'all'
};
});
return formats;
};
const genericBase = {
remove_similar: true,
inherit: false
};
const cellBase = {
selector: 'td,th',
...genericBase
};
const cellFormats = {
tablecellbackgroundcolor: {
styles: { backgroundColor: '%value' },
...cellBase
},
tablecellverticalalign: {
styles: { 'vertical-align': '%value' },
...cellBase
},
tablecellbordercolor: {
styles: { borderColor: '%value' },
...cellBase
},
tablecellclass: {
classes: ['%value'],
...cellBase
},
tableclass: {
selector: 'table',
classes: ['%value'],
...genericBase
},
tablecellborderstyle: {
styles: { borderStyle: '%value' },
...cellBase
},
tablecellborderwidth: {
styles: { borderWidth: '%value' },
...cellBase
}
};
const get = constant(cellFormats);
const FormatRegistry = editor => {
const formats = {};
const get$2 = name => isNonNullable(name) ? formats[name] : formats;
const has = name => has$2(formats, name);
const register = (name, format) => {
if (name) {
if (!isString(name)) {
each$d(name, (format, name) => {
register(name, format);
});
} else {
if (!isArray$1(format)) {
format = [format];
}
each$e(format, format => {
if (isUndefined(format.deep)) {
format.deep = !isSelectorFormat(format);
}
if (isUndefined(format.split)) {
format.split = !isSelectorFormat(format) || isInlineFormat(format);
}
if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) {
format.remove = 'none';
}
if (isSelectorFormat(format) && isInlineFormat(format)) {
format.mixed = true;
format.block_expand = true;
}
if (isString(format.classes)) {
format.classes = format.classes.split(/\s+/);
}
});
formats[name] = format;
}
}
};
const unregister = name => {
if (name && formats[name]) {
delete formats[name];
}
return formats;
};
register(get$1(editor));
register(get());
register(getFormats(editor));
return {
get: get$2,
has,
register,
unregister
};
};
const each$3 = Tools.each;
const dom = DOMUtils.DOM;
const isPreviewItem = item => isNonNullable(item) && isObject(item);
const parsedSelectorToHtml = (ancestry, editor) => {
const schema = editor && editor.schema || Schema({});
const decorate = (elm, item) => {
if (item.classes.length > 0) {
dom.addClass(elm, item.classes.join(' '));
}
dom.setAttribs(elm, item.attrs);
};
const createElement = sItem => {
const item = isString(sItem) ? {
name: sItem,
classes: [],
attrs: {}
} : sItem;
const elm = dom.create(item.name);
decorate(elm, item);
return elm;
};
const getRequiredParent = (elm, candidate) => {
const elmRule = schema.getElementRule(elm.nodeName.toLowerCase());
const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired;
if (parentsRequired && parentsRequired.length) {
return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0];
} else {
return false;
}
};
const wrapInHtml = (elm, ancestors, siblings) => {
let parentCandidate;
const ancestor = ancestors[0];
const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined;
const parentRequired = getRequiredParent(elm, ancestorName);
if (parentRequired) {
if (ancestorName === parentRequired) {
parentCandidate = ancestor;
ancestors = ancestors.slice(1);
} else {
parentCandidate = parentRequired;
}
} else if (ancestor) {
parentCandidate = ancestor;
ancestors = ancestors.slice(1);
} else if (!siblings) {
return elm;
}
const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div');
parent.appendChild(elm);
if (siblings) {
Tools.each(siblings, sibling => {
const siblingElm = createElement(sibling);
parent.insertBefore(siblingElm, elm);
});
}
const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined;
return wrapInHtml(parent, ancestors, parentSiblings);
};
const fragment = dom.create('div');
if (ancestry.length > 0) {
const item = ancestry[0];
const elm = createElement(item);
const siblings = isPreviewItem(item) ? item.siblings : undefined;
fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings));
}
return fragment;
};
const parseSelectorItem = item => {
item = Tools.trim(item);
let tagName = 'div';
const obj = {
name: tagName,
classes: [],
attrs: {},
selector: item
};
if (item !== '*') {
tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
switch ($1) {
case '#':
obj.attrs.id = $2;
break;
case '.':
obj.classes.push($2);
break;
case ':':
if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
obj.attrs[$2] = $2;
}
break;
}
if ($3 === '[') {
const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
if (m) {
obj.attrs[m[1]] = m[2];
}
}
return '';
});
}
obj.name = tagName || 'div';
return obj;
};
const parseSelector = selector => {
if (!isString(selector)) {
return [];
}
selector = selector.split(/\s*,\s*/)[0];
selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => {
const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
const obj = siblings.pop();
if (siblings.length) {
obj.siblings = siblings;
}
return obj;
}).reverse();
};
const getCssText = (editor, format) => {
let previewCss = '';
let previewStyles = getPreviewStyles(editor);
if (previewStyles === '') {
return '';
}
const removeVars = val => {
return isString(val) ? val.replace(/%(\w+)/g, '') : '';
};
const getComputedStyle = (name, elm) => {
return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true);
};
if (isString(format)) {
const formats = editor.formatter.get(format);
if (!formats) {
return '';
}
format = formats[0];
}
if ('preview' in format) {
const preview = format.preview;
if (preview === false) {
return '';
} else {
previewStyles = preview || previewStyles;
}
}
let name = format.block || format.inline || 'span';
let previewFrag;
const items = parseSelector(format.selector);
if (items.length > 0) {
if (!items[0].name) {
items[0].name = name;
}
name = format.selector;
previewFrag = parsedSelectorToHtml(items, editor);
} else {
previewFrag = parsedSelectorToHtml([name], editor);
}
const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
each$3(format.styles, (value, name) => {
const newValue = removeVars(value);
if (newValue) {
dom.setStyle(previewElm, name, newValue);
}
});
each$3(format.attributes, (value, name) => {
const newValue = removeVars(value);
if (newValue) {
dom.setAttrib(previewElm, name, newValue);
}
});
each$3(format.classes, value => {
const newValue = removeVars(value);
if (!dom.hasClass(previewElm, newValue)) {
dom.addClass(previewElm, newValue);
}
});
editor.dispatch('PreviewFormats');
dom.setStyles(previewFrag, {
position: 'absolute',
left: -65535
});
editor.getBody().appendChild(previewFrag);
const rawParentFontSize = getComputedStyle('fontSize');
const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0;
each$3(previewStyles.split(' '), name => {
let value = getComputedStyle(name, previewElm);
if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
value = getComputedStyle(name);
if (rgbaToHexString(value).toLowerCase() === '#ffffff') {
return;
}
}
if (name === 'color') {
if (rgbaToHexString(value).toLowerCase() === '#000000') {
return;
}
}
if (name === 'font-size') {
if (/em|%$/.test(value)) {
if (parentFontSize === 0) {
return;
}
const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
value = numValue * parentFontSize + 'px';
}
}
if (name === 'border' && value) {
previewCss += 'padding:0 2px;';
}
previewCss += name + ':' + value + ';';
});
editor.dispatch('AfterPreviewFormats');
dom.remove(previewFrag);
return previewCss;
};
const setup$s = editor => {
editor.addShortcut('meta+b', '', 'Bold');
editor.addShortcut('meta+i', '', 'Italic');
editor.addShortcut('meta+u', '', 'Underline');
for (let i = 1; i <= 6; i++) {
editor.addShortcut('access+' + i, '', [
'FormatBlock',
false,
'h' + i
]);
}
editor.addShortcut('access+7', '', [
'FormatBlock',
false,
'p'
]);
editor.addShortcut('access+8', '', [
'FormatBlock',
false,
'div'
]);
editor.addShortcut('access+9', '', [
'FormatBlock',
false,
'address'
]);
};
const Formatter = editor => {
const formats = FormatRegistry(editor);
const formatChangeState = Cell({});
setup$s(editor);
setup$v(editor);
if (!isRtc(editor)) {
setup$u(formatChangeState, editor);
}
return {
get: formats.get,
has: formats.has,
register: formats.register,
unregister: formats.unregister,
apply: (name, vars, node) => {
applyFormat(editor, name, vars, node);
},
remove: (name, vars, node, similar) => {
removeFormat(editor, name, vars, node, similar);
},
toggle: (name, vars, node) => {
toggleFormat(editor, name, vars, node);
},
match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar),
closest: names => closestFormat(editor, names),
matchAll: (names, vars) => matchAllFormats(editor, names, vars),
matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar),
canApply: name => canApplyFormat(editor, name),
formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars),
getCssText: curry(getCssText, editor)
};
};
const shouldIgnoreCommand = cmd => {
switch (cmd.toLowerCase()) {
case 'undo':
case 'redo':
case 'mcefocus':
return true;
default:
return false;
}
};
const registerEvents = (editor, undoManager, locks) => {
const isFirstTypedCharacter = Cell(false);
const addNonTypingUndoLevel = e => {
setTyping(undoManager, false, locks);
undoManager.add({}, e);
};
editor.on('init', () => {
undoManager.add();
});
editor.on('BeforeExecCommand', e => {
const cmd = e.command;
if (!shouldIgnoreCommand(cmd)) {
endTyping(undoManager, locks);
undoManager.beforeChange();
}
});
editor.on('ExecCommand', e => {
const cmd = e.command;
if (!shouldIgnoreCommand(cmd)) {
addNonTypingUndoLevel(e);
}
});
editor.on('ObjectResizeStart cut', () => {
undoManager.beforeChange();
});
editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
editor.on('dragend', addNonTypingUndoLevel);
editor.on('keyup', e => {
const keyCode = e.keyCode;
if (e.isDefaultPrevented()) {
return;
}
const isMeta = Env.os.isMacOS() && e.key === 'Meta';
if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey || isMeta) {
addNonTypingUndoLevel();
editor.nodeChanged();
}
if (keyCode === 46 || keyCode === 8) {
editor.nodeChanged();
}
if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
if (!editor.isDirty()) {
editor.setDirty(true);
}
editor.dispatch('TypingUndo');
isFirstTypedCharacter.set(false);
editor.nodeChanged();
}
});
editor.on('keydown', e => {
const keyCode = e.keyCode;
if (e.isDefaultPrevented()) {
return;
}
if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
if (undoManager.typing) {
addNonTypingUndoLevel(e);
}
return;
}
const modKey = e.ctrlKey && !e.altKey || e.metaKey;
if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
undoManager.beforeChange();
setTyping(undoManager, true, locks);
undoManager.add({}, e);
isFirstTypedCharacter.set(true);
return;
}
const hasOnlyMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey;
if (hasOnlyMetaOrCtrlModifier) {
undoManager.beforeChange();
}
});
editor.on('mousedown', e => {
if (undoManager.typing) {
addNonTypingUndoLevel(e);
}
});
const isInsertReplacementText = event => event.inputType === 'insertReplacementText';
const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null;
const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop';
editor.on('input', e => {
if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
addNonTypingUndoLevel(e);
}
});
editor.on('AddUndo Undo Redo ClearUndos', e => {
if (!e.isDefaultPrevented()) {
editor.nodeChanged();
}
});
};
const addKeyboardShortcuts = editor => {
editor.addShortcut('meta+z', '', 'Undo');
editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
};
const UndoManager = editor => {
const beforeBookmark = value$2();
const locks = Cell(0);
const index = Cell(0);
const undoManager = {
data: [],
typing: false,
beforeChange: () => {
beforeChange(editor, locks, beforeBookmark);
},
add: (level, event) => {
return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
},
dispatchChange: () => {
editor.setDirty(true);
const level = createFromEditor(editor);
level.bookmark = getUndoBookmark(editor.selection);
editor.dispatch('change', {
level,
lastLevel: get$b(undoManager.data, index.get()).getOrUndefined()
});
},
undo: () => {
return undo(editor, undoManager, locks, index);
},
redo: () => {
return redo(editor, index, undoManager.data);
},
clear: () => {
clear(editor, undoManager, index);
},
reset: () => {
reset(editor, undoManager);
},
hasUndo: () => {
return hasUndo(editor, undoManager, index);
},
hasRedo: () => {
return hasRedo(editor, undoManager, index);
},
transact: callback => {
return transact(editor, undoManager, locks, callback);
},
ignore: callback => {
ignore(editor, locks, callback);
},
extra: (callback1, callback2) => {
extra(editor, undoManager, index, callback1, callback2);
}
};
if (!isRtc(editor)) {
registerEvents(editor, undoManager, locks);
}
addKeyboardShortcuts(editor);
return undoManager;
};
const nonTypingKeycodes = [
9,
27,
VK.HOME,
VK.END,
19,
20,
44,
144,
145,
33,
34,
45,
16,
17,
18,
91,
92,
93,
VK.DOWN,
VK.UP,
VK.LEFT,
VK.RIGHT
].concat(Env.browser.isFirefox() ? [224] : []);
const placeholderAttr = 'data-mce-placeholder';
const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup';
const isDeleteEvent = e => {
const keyCode = e.keyCode;
return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
};
const isNonTypingKeyboardEvent = e => {
if (isKeyboardEvent(e)) {
const keyCode = e.keyCode;
return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
} else {
return false;
}
};
const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229);
const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => {
if (dom.isEmpty(rootElm, undefined, {
skipBogus: false,
includeZwsp: true
})) {
const firstElement = rootElm.firstElementChild;
if (!firstElement) {
return true;
} else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) {
return false;
} else {
return forcedRootBlock === firstElement.nodeName.toLowerCase();
}
} else {
return false;
}
};
const setup$r = editor => {
var _a;
const dom = editor.dom;
const rootBlock = getForcedRootBlock(editor);
const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : '';
const updatePlaceholder = (e, initial) => {
if (isNonTypingKeyboardEvent(e)) {
return;
}
const body = editor.getBody();
const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock);
const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== '';
if (isPlaceholderShown !== showPlaceholder || initial) {
dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
firePlaceholderToggle(editor, showPlaceholder);
editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder);
editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder);
}
};
if (isNotEmpty(placeholder)) {
editor.on('init', e => {
updatePlaceholder(e, true);
editor.on('change SetContent ExecCommand', updatePlaceholder);
editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e)));
});
}
};
const blockPosition = (block, position) => ({
block,
position
});
const blockBoundary = (from, to) => ({
from,
to
});
const getBlockPosition = (rootNode, pos) => {
const rootElm = SugarElement.fromDom(rootNode);
const containerElm = SugarElement.fromDom(pos.container());
return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos));
};
const isNotAncestorial = blockBoundary => !(contains(blockBoundary.to.block, blockBoundary.from.block) || contains(blockBoundary.from.block, blockBoundary.to.block));
const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block);
const getClosestHost = (root, scope) => {
const isRoot = node => eq(node, root);
const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root);
};
const hasSameHost = (rootNode, blockBoundary) => {
const root = SugarElement.fromDom(rootNode);
return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block));
};
const isEditable$1 = blockBoundary => isContentEditableFalse$b(blockBoundary.from.block.dom) === false && isContentEditableFalse$b(blockBoundary.to.block.dom) === false;
const hasValidBlocks = blockBoundary => {
const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom) || isListItem$1(block);
return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block);
};
const skipLastBr = (schema, rootNode, forward, blockPosition) => {
if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(schema, blockPosition.block)) {
return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => {
if (lastPositionInBlock.isEqual(blockPosition.position)) {
return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to));
} else {
return Optional.some(blockPosition);
}
}).getOr(blockPosition);
} else {
return blockPosition;
}
};
const readFromRange = (schema, rootNode, forward, rng) => {
const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(schema, rootNode, forward, blockPos))));
return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$1(blockBoundary) && hasValidBlocks(blockBoundary) && isNotAncestorial(blockBoundary));
};
const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
const getChildrenUntilBlockBoundary = (block, schema) => {
const children = children$1(block);
return findIndex$2(children, el => schema.isBlock(name(el))).fold(constant(children), index => children.slice(0, index));
};
const extractChildren = (block, schema) => {
const children = getChildrenUntilBlockBoundary(block, schema);
each$e(children, remove$4);
return children;
};
const removeEmptyRoot = (schema, rootNode, block) => {
const parents = parentsAndSelf(block, rootNode);
return find$2(parents.reverse(), element => isEmpty$2(schema, element)).each(remove$4);
};
const isEmptyBefore = (schema, el) => filter$5(prevSiblings(el), el => !isEmpty$2(schema, el)).length === 0;
const nestedBlockMerge = (rootNode, fromBlock, toBlock, schema, insertionPoint) => {
if (isEmpty$2(schema, toBlock)) {
fillWithPaddingBr(toBlock);
return firstPositionIn(toBlock.dom);
}
if (isEmptyBefore(schema, insertionPoint) && isEmpty$2(schema, fromBlock)) {
before$3(insertionPoint, SugarElement.fromTag('br'));
}
const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
each$e(extractChildren(fromBlock, schema), child => {
before$3(insertionPoint, child);
});
removeEmptyRoot(schema, rootNode, fromBlock);
return position;
};
const isInline = (schema, node) => schema.isInline(name(node));
const sidelongBlockMerge = (rootNode, fromBlock, toBlock, schema) => {
if (isEmpty$2(schema, toBlock)) {
if (isEmpty$2(schema, fromBlock)) {
const getInlineToBlockDescendants = el => {
const helper = (node, elements) => firstChild(node).fold(() => elements, child => isInline(schema, child) ? helper(child, elements.concat(shallow$1(child))) : elements);
return helper(el, []);
};
const newFromBlockDescendants = foldr(getInlineToBlockDescendants(toBlock), (element, descendant) => {
wrap$2(element, descendant);
return descendant;
}, createPaddingBr());
empty(fromBlock);
append$1(fromBlock, newFromBlockDescendants);
}
remove$4(toBlock);
return firstPositionIn(fromBlock.dom);
}
const position = lastPositionIn(toBlock.dom);
each$e(extractChildren(fromBlock, schema), child => {
append$1(toBlock, child);
});
removeEmptyRoot(schema, rootNode, fromBlock);
return position;
};
const findInsertionPoint = (toBlock, block) => {
const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
};
const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
const trimBr = (first, block) => {
positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$4);
};
const mergeBlockInto = (rootNode, fromBlock, toBlock, schema) => {
trimBr(true, fromBlock);
trimBr(false, toBlock);
return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock, schema), curry(nestedBlockMerge, rootNode, fromBlock, toBlock, schema));
};
const mergeBlocks = (rootNode, forward, block1, block2, schema) => forward ? mergeBlockInto(rootNode, block2, block1, schema) : mergeBlockInto(rootNode, block1, block2, schema);
const backspaceDelete$a = (editor, forward) => {
const rootNode = SugarElement.fromDom(editor.getBody());
const position = read$1(editor.schema, rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block, editor.schema).each(pos => {
editor.selection.setRng(pos.toRange());
});
});
return position;
};
const deleteRangeMergeBlocks = (rootNode, selection, schema) => {
const rng = selection.getRng();
return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
if (!eq(block1, block2)) {
return Optional.some(() => {
rng.deleteContents();
mergeBlocks(rootNode, true, block1, block2, schema).each(pos => {
selection.setRng(pos.toRange());
});
});
} else {
return Optional.none();
}
}).getOr(Optional.none());
};
const isRawNodeInTable = (root, rawNode) => {
const node = SugarElement.fromDom(rawNode);
const isRoot = curry(eq, root);
return ancestor$4(node, isTableCell$2, isRoot).isSome();
};
const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
const isEverythingSelected = (root, rng) => {
const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
return !isSelectionInTable(root, rng) && noPrevious && noNext;
};
const emptyEditor = editor => {
return Optional.some(() => {
editor.setContent('');
editor.selection.setCursorLocation();
});
};
const deleteRange$2 = editor => {
const rootNode = SugarElement.fromDom(editor.getBody());
const rng = editor.selection.getRng();
return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection, editor.schema);
};
const backspaceDelete$9 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$2(editor);
const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView));
const getNodeRange = node => {
const rng = node.ownerDocument.createRange();
rng.selectNode(node);
return rng;
};
const selectNode = (editor, node) => {
const e = editor.dispatch('BeforeObjectSelected', { target: node });
if (e.isDefaultPrevented()) {
return Optional.none();
}
return Optional.some(getNodeRange(node));
};
const renderCaretAtRange = (editor, range, scrollIntoView) => {
const normalizedRange = normalizeRange(1, editor.getBody(), range);
const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
const caretPositionNode = caretPosition.getNode();
if (isInlineFakeCaretTarget(caretPositionNode)) {
return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
}
const caretPositionBeforeNode = caretPosition.getNode(true);
if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
return showCaret(1, editor, caretPositionBeforeNode, false, false);
}
const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode());
if (isInlineFakeCaretTarget(ceRoot)) {
return showCaret(1, editor, ceRoot, false, scrollIntoView);
}
return Optional.none();
};
const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range;
const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
const trimEmptyTextNode = (dom, node) => {
if (isText$b(node) && node.data.length === 0) {
dom.remove(node);
}
};
const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => {
showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => {
if (range.collapsed) {
const deleteRange = range.cloneRange();
if (forward) {
deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
} else {
deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
}
deleteRange.deleteContents();
} else {
range.deleteContents();
}
editor.selection.setRng(caretRange);
});
trimEmptyTextNode(editor.dom, node);
};
const deleteBoundaryText = (editor, forward) => {
const range = editor.selection.getRng();
if (!isText$b(range.commonAncestorContainer)) {
return Optional.none();
}
const direction = forward ? HDirection.Forwards : HDirection.Backwards;
const caretWalker = CaretWalker(editor.getBody());
const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
const nextCaretPosition = getNextPosFn(caretPosition);
const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition;
if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) {
return Optional.none();
} else if (isBeforeFn(normalizedNextCaretPosition)) {
return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition));
}
const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition);
if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) {
return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition));
}
}
return Optional.none();
};
const backspaceDelete$8 = (editor, forward) => deleteBoundaryText(editor, forward);
const getEdgeCefPosition = (editor, atStart) => {
const root = editor.getBody();
return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
};
const isCefAtEdgeSelected = editor => {
const rng = editor.selection.getRng();
return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
};
const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node)));
const DeleteAction = Adt.generate([
{ remove: ['element'] },
{ moveToElement: ['element'] },
{ moveToPosition: ['position'] }
]);
const isAtContentEditableBlockCaret = (forward, from) => {
const elm = from.getNode(!forward);
const caretLocation = forward ? 'after' : 'before';
return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
};
const isDeleteFromCefDifferentBlocks = (root, forward, from, to, schema) => {
const inSameBlock = elm => schema.isInline(elm.nodeName.toLowerCase()) && !isInSameBlock(from, to, root);
return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock);
};
const deleteEmptyBlockOrMoveToCef = (schema, root, forward, from, to) => {
const toCefElm = to.getNode(!forward);
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)));
};
const findCefPosition = (root, forward, from, schema) => fromPosition(forward, root, from).bind(to => {
if (isCompoundElement(to.getNode())) {
return Optional.none();
} else if (isDeleteFromCefDifferentBlocks(root, forward, from, to, schema)) {
return Optional.none();
} else if (forward && isContentEditableFalse$b(to.getNode())) {
return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
} else if (!forward && isContentEditableFalse$b(to.getNode(true))) {
return deleteEmptyBlockOrMoveToCef(schema, root, forward, from, to);
} else if (forward && isAfterContentEditableFalse(from)) {
return Optional.some(DeleteAction.moveToPosition(to));
} else if (!forward && isBeforeContentEditableFalse(from)) {
return Optional.some(DeleteAction.moveToPosition(to));
} else {
return Optional.none();
}
});
const getContentEditableBlockAction = (forward, elm) => {
if (isNullable(elm)) {
return Optional.none();
} else if (forward && isContentEditableFalse$b(elm.nextSibling)) {
return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
} else if (!forward && isContentEditableFalse$b(elm.previousSibling)) {
return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
} else {
return Optional.none();
}
};
const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => {
if (isInSameBlock(from, to, root)) {
return Optional.none();
} else {
return Optional.some(DeleteAction.moveToPosition(to));
}
});
const getContentEditableAction = (root, forward, from, schema) => {
if (isAtContentEditableBlockCaret(forward, from)) {
return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from, schema));
} else {
return findCefPosition(root, forward, from, schema).bind(deleteAction => skipMoveToActionFromInlineCefToContent(root, from, deleteAction));
}
};
const read = (root, forward, rng, schema) => {
const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
const from = CaretPosition.fromRangeStart(normalizedRange);
const rootElement = SugarElement.fromDom(root);
if (!forward && isAfterContentEditableFalse(from)) {
return Optional.some(DeleteAction.remove(from.getNode(true)));
} else if (forward && isBeforeContentEditableFalse(from)) {
return Optional.some(DeleteAction.remove(from.getNode()));
} else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from, schema)) {
return findPreviousBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
} else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from, schema)) {
return findNextBr(rootElement, from, schema).map(br => DeleteAction.remove(br.getNode()));
} else {
return getContentEditableAction(root, forward, from, schema);
}
};
const deleteElement$1 = (editor, forward) => element => {
editor._selectionOverrides.hideFakeCaret();
deleteElement$2(editor, forward, SugarElement.fromDom(element));
return true;
};
const moveToElement = (editor, forward) => element => {
const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
editor.selection.setRng(pos.toRange());
return true;
};
const moveToPosition = editor => pos => {
editor.selection.setRng(pos.toRange());
return true;
};
const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
const backspaceDeleteCaret = (editor, forward) => {
const selectedNode = editor.selection.getNode();
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));
};
const deleteOffscreenSelection = rootElement => {
each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$4);
};
const backspaceDeleteRange = (editor, forward) => {
const selectedNode = editor.selection.getNode();
if (isContentEditableFalse$b(selectedNode) && !isTableCell$3(selectedNode)) {
const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b);
return hasCefAncestor.fold(() => Optional.some(() => {
deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
paddEmptyBody(editor);
}), () => Optional.some(noop));
}
if (isCefAtEdgeSelected(editor)) {
return Optional.some(() => {
deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
});
}
return Optional.none();
};
const paddEmptyElement = editor => {
const dom = editor.dom, selection = editor.selection;
const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) {
const br = dom.create('br', { 'data-mce-bogus': '1' });
dom.setHTML(ceRoot, '');
ceRoot.appendChild(br);
selection.setRng(CaretPosition.before(br).toRange());
}
return true;
};
const backspaceDelete$7 = (editor, forward) => {
if (editor.selection.isCollapsed()) {
return backspaceDeleteCaret(editor, forward);
} else {
return backspaceDeleteRange(editor, forward);
}
};
const isTextEndpoint = endpoint => endpoint.hasOwnProperty('text');
const isElementEndpoint = endpoint => endpoint.hasOwnProperty('marker');
const getBookmark = (range, createMarker) => {
const getEndpoint = (container, offset) => {
if (isText$b(container)) {
return {
text: container,
offset
};
} else {
const marker = createMarker();
const children = container.childNodes;
if (offset < children.length) {
container.insertBefore(marker, children[offset]);
return {
marker,
before: true
};
} else {
container.appendChild(marker);
return {
marker,
before: false
};
}
}
};
const end = getEndpoint(range.endContainer, range.endOffset);
const start = getEndpoint(range.startContainer, range.startOffset);
return {
start,
end
};
};
const resolveBookmark = bm => {
var _a, _b;
const {start, end} = bm;
const rng = new window.Range();
if (isTextEndpoint(start)) {
rng.setStart(start.text, start.offset);
} else {
if (isElementEndpoint(start)) {
if (start.before) {
rng.setStartBefore(start.marker);
} else {
rng.setStartAfter(start.marker);
}
(_a = start.marker.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(start.marker);
}
}
if (isTextEndpoint(end)) {
rng.setEnd(end.text, end.offset);
} else {
if (isElementEndpoint(end)) {
if (end.before) {
rng.setEndBefore(end.marker);
} else {
rng.setEndAfter(end.marker);
}
(_b = end.marker.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(end.marker);
}
}
return rng;
};
const backspaceDelete$6 = (editor, forward) => {
var _a;
const dom = editor.dom;
const startBlock = dom.getParent(editor.selection.getStart(), dom.isBlock);
const endBlock = dom.getParent(editor.selection.getEnd(), dom.isBlock);
const body = editor.getBody();
const startBlockName = (_a = startBlock === null || startBlock === void 0 ? void 0 : startBlock.nodeName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
if (startBlockName === 'div' && startBlock && endBlock && startBlock === body.firstChild && endBlock === body.lastChild && !dom.isEmpty(body)) {
const wrapper = startBlock.cloneNode(false);
const deleteAction = () => {
if (forward) {
execNativeForwardDeleteCommand(editor);
} else {
execNativeDeleteCommand(editor);
}
if (body.firstChild !== startBlock) {
const bookmark = getBookmark(editor.selection.getRng(), () => document.createElement('span'));
Array.from(body.childNodes).forEach(node => wrapper.appendChild(node));
body.appendChild(wrapper);
editor.selection.setRng(resolveBookmark(bookmark));
}
};
return Optional.some(deleteAction);
}
return Optional.none();
};
const deleteCaret$2 = (editor, forward) => {
const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
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));
};
const backspaceDelete$5 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
const isText$2 = isText$b;
const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1;
const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
const createZwsp = node => {
var _a;
const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
return doc.createTextNode(ZWSP$1);
};
const insertBefore$1 = node => {
var _a;
if (isText$2(node.previousSibling)) {
if (endsWithCaretContainer(node.previousSibling)) {
return node.previousSibling;
} else {
node.previousSibling.appendData(ZWSP$1);
return node.previousSibling;
}
} else if (isText$2(node)) {
if (startsWithCaretContainer(node)) {
return node;
} else {
node.insertData(0, ZWSP$1);
return node;
}
} else {
const newNode = createZwsp(node);
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node);
return newNode;
}
};
const insertAfter$1 = node => {
var _a, _b;
if (isText$2(node.nextSibling)) {
if (startsWithCaretContainer(node.nextSibling)) {
return node.nextSibling;
} else {
node.nextSibling.insertData(0, ZWSP$1);
return node.nextSibling;
}
} else if (isText$2(node)) {
if (endsWithCaretContainer(node)) {
return node;
} else {
node.appendData(ZWSP$1);
return node;
}
} else {
const newNode = createZwsp(node);
if (node.nextSibling) {
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling);
} else {
(_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode);
}
return newNode;
}
};
const insertInline = (before, node) => before ? insertBefore$1(node) : insertAfter$1(node);
const insertInlineBefore = curry(insertInline, true);
const insertInlineAfter = curry(insertInline, false);
const insertInlinePos = (pos, before) => {
if (isText$b(pos.container())) {
return insertInline(before, pos.container());
} else {
return insertInline(before, pos.getNode());
}
};
const isPosCaretContainer = (pos, caret) => {
const caretNode = caret.get();
return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
};
const renderCaret = (caret, location) => location.fold(element => {
remove$2(caret.get());
const text = insertInlineBefore(element);
caret.set(text);
return Optional.some(CaretPosition(text, text.length - 1));
}, element => firstPositionIn(element).map(pos => {
if (!isPosCaretContainer(pos, caret)) {
remove$2(caret.get());
const text = insertInlinePos(pos, true);
caret.set(text);
return CaretPosition(text, 1);
} else {
const node = caret.get();
return CaretPosition(node, 1);
}
}), element => lastPositionIn(element).map(pos => {
if (!isPosCaretContainer(pos, caret)) {
remove$2(caret.get());
const text = insertInlinePos(pos, false);
caret.set(text);
return CaretPosition(text, text.length - 1);
} else {
const node = caret.get();
return CaretPosition(node, node.length - 1);
}
}), element => {
remove$2(caret.get());
const text = insertInlineAfter(element);
caret.set(text);
return Optional.some(CaretPosition(text, 1));
});
const evaluateUntil = (fns, args) => {
for (let i = 0; i < fns.length; i++) {
const result = fns[i].apply(null, args);
if (result.isSome()) {
return result;
}
}
return Optional.none();
};
const Location = Adt.generate([
{ before: ['element'] },
{ start: ['element'] },
{ end: ['element'] },
{ after: ['element'] }
]);
const rescope$1 = (rootNode, node) => {
const parentBlock = getParentBlock$3(node, rootNode);
return parentBlock ? parentBlock : rootNode;
};
const before = (isInlineTarget, rootNode, pos) => {
const nPos = normalizeForwards(pos);
const scope = rescope$1(rootNode, nPos.container());
return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none);
};
const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
const start$1 = (isInlineTarget, rootNode, pos) => {
const nPos = normalizeBackwards(pos);
return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
const prevPos = prevPosition(inline, nPos);
return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
});
};
const end = (isInlineTarget, rootNode, pos) => {
const nPos = normalizeForwards(pos);
return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
const nextPos = nextPosition(inline, nPos);
return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
});
};
const after = (isInlineTarget, rootNode, pos) => {
const nPos = normalizeBackwards(pos);
const scope = rescope$1(rootNode, nPos.container());
return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none);
};
const isValidLocation = location => !isRtl(getElement(location));
const readLocation = (isInlineTarget, rootNode, pos) => {
const location = evaluateUntil([
before,
start$1,
end,
after
], [
isInlineTarget,
rootNode,
pos
]);
return location.filter(isValidLocation);
};
const getElement = location => location.fold(identity, identity, identity, identity);
const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after);
const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end);
const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => {
if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
return Location.after(forward ? fromInline : toInline);
} else {
return location;
}
}).getOr(location);
const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation));
const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => {
const from = normalizePosition(forward, pos);
const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward));
const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation)));
return location.filter(isValidLocation);
};
const findLocationSimple = (forward, location) => {
if (forward) {
return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
} else {
return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
}
};
const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => {
const from = normalizePosition(forward, pos);
const fromLocation = readLocation(isInlineTarget, rootNode, from);
return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos));
};
const hasSelectionModifyApi = editor => {
return isFunction(editor.selection.getSel().modify);
};
const moveRel = (forward, selection, pos) => {
const delta = forward ? 1 : -1;
selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
return true;
};
const moveByWord = (forward, editor) => {
const rng = editor.selection.getRng();
const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
if (!hasSelectionModifyApi(editor)) {
return false;
} else if (forward && isBeforeInline(pos)) {
return moveRel(true, editor.selection, pos);
} else if (!forward && isAfterInline(pos)) {
return moveRel(false, editor.selection, pos);
} else {
return false;
}
};
var BreakType;
(function (BreakType) {
BreakType[BreakType['Br'] = 0] = 'Br';
BreakType[BreakType['Block'] = 1] = 'Block';
BreakType[BreakType['Wrap'] = 2] = 'Wrap';
BreakType[BreakType['Eol'] = 3] = 'Eol';
}(BreakType || (BreakType = {})));
const flip = (direction, positions) => direction === HDirection.Backwards ? reverse(positions) : positions;
const walk$1 = (direction, caretWalker, pos) => direction === HDirection.Forwards ? caretWalker.next(pos) : caretWalker.prev(pos);
const getBreakType = (scope, direction, currentPos, nextPos) => {
if (isBr$6(nextPos.getNode(direction === HDirection.Forwards))) {
return BreakType.Br;
} else if (isInSameBlock(currentPos, nextPos) === false) {
return BreakType.Block;
} else {
return BreakType.Wrap;
}
};
const getPositionsUntil = (predicate, direction, scope, start) => {
const caretWalker = CaretWalker(scope);
let currentPos = start;
const positions = [];
while (currentPos) {
const nextPos = walk$1(direction, caretWalker, currentPos);
if (!nextPos) {
break;
}
if (isBr$6(nextPos.getNode(false))) {
if (direction === HDirection.Forwards) {
return {
positions: flip(direction, positions).concat([nextPos]),
breakType: BreakType.Br,
breakAt: Optional.some(nextPos)
};
} else {
return {
positions: flip(direction, positions),
breakType: BreakType.Br,
breakAt: Optional.some(nextPos)
};
}
}
if (!nextPos.isVisible()) {
currentPos = nextPos;
continue;
}
if (predicate(currentPos, nextPos)) {
const breakType = getBreakType(scope, direction, currentPos, nextPos);
return {
positions: flip(direction, positions),
breakType,
breakAt: Optional.some(nextPos)
};
}
positions.push(nextPos);
currentPos = nextPos;
}
return {
positions: flip(direction, positions),
breakType: BreakType.Eol,
breakAt: Optional.none()
};
};
const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => {
const positions = getPositionsUntilBreak(scope, pos).positions;
return direction === HDirection.Backwards ? positions.concat(pos) : [pos].concat(positions);
}).getOr([]);
const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
const lastDist = Math.abs(x - lastRect.left);
const newDist = Math.abs(x - newRect.left);
return newDist <= lastDist ? newPos : lastPos;
}).or(acc)), Optional.none());
const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
const isContentEditableFalse$5 = isContentEditableFalse$b;
const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
const isNodeClientRect = rect => hasNonNullableKey(rect, 'node');
const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$5(clientRect.node)) {
return clientRect;
}
if (newDistance < oldDistance) {
return clientRect;
}
return oldClientRect;
});
const getNodeClientRects = node => {
const toArrayWithNode = clientRects => {
return map$3(clientRects, rect => {
const clientRect = clone$1(rect);
clientRect.node = node;
return clientRect;
});
};
if (isElement$6(node)) {
return toArrayWithNode(node.getClientRects());
} else if (isText$b(node)) {
const rng = node.ownerDocument.createRange();
rng.setStart(node, 0);
rng.setEnd(node, node.data.length);
return toArrayWithNode(rng.getClientRects());
} else {
return [];
}
};
const getClientRects = nodes => bind$3(nodes, getNodeClientRects);
var VDirection;
(function (VDirection) {
VDirection[VDirection['Up'] = -1] = 'Up';
VDirection[VDirection['Down'] = 1] = 'Down';
}(VDirection || (VDirection = {})));
const findUntil = (direction, root, predicateFn, node) => {
let currentNode = node;
while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) {
if (predicateFn(currentNode)) {
return;
}
}
};
const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
let line = 0;
const result = [];
const add = node => {
let clientRects = getClientRects([node]);
if (direction === -1) {
clientRects = clientRects.reverse();
}
for (let i = 0; i < clientRects.length; i++) {
const clientRect = clientRects[i];
if (isBeflowFn(clientRect, targetClientRect)) {
continue;
}
if (result.length > 0 && isAboveFn(clientRect, last$1(result))) {
line++;
}
clientRect.line = line;
if (predicateFn(clientRect)) {
return true;
}
result.push(clientRect);
}
return false;
};
const targetClientRect = last$1(caretPosition.getClientRects());
if (!targetClientRect) {
return result;
}
const node = caretPosition.getNode();
if (node) {
add(node);
findUntil(direction, root, add, node);
}
return result;
};
const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
const getLastClientRect = caretPosition => {
return last$1(caretPosition.getClientRects());
};
const positionsUntil = (direction, root, predicateFn, node) => {
const caretWalker = CaretWalker(root);
let walkFn;
let isBelowFn;
let isAboveFn;
let caretPosition;
const result = [];
let line = 0;
if (direction === 1) {
walkFn = caretWalker.next;
isBelowFn = isBelow$1;
isAboveFn = isAbove$1;
caretPosition = CaretPosition.after(node);
} else {
walkFn = caretWalker.prev;
isBelowFn = isAbove$1;
isAboveFn = isBelow$1;
caretPosition = CaretPosition.before(node);
}
const targetClientRect = getLastClientRect(caretPosition);
do {
if (!caretPosition.isVisible()) {
continue;
}
const rect = getLastClientRect(caretPosition);
if (isAboveFn(rect, targetClientRect)) {
continue;
}
if (result.length > 0 && isBelowFn(rect, last$1(result))) {
line++;
}
const clientRect = clone$1(rect);
clientRect.position = caretPosition;
clientRect.line = line;
if (predicateFn(clientRect)) {
return result;
}
result.push(clientRect);
} while (caretPosition = walkFn(caretPosition));
return result;
};
const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect);
const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect);
const moveToRange = (editor, rng) => {
editor.selection.setRng(rng);
scrollRangeIntoView(editor, editor.selection.getRng());
};
const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView));
const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => {
const forwards = direction === HDirection.Forwards;
const caretWalker = CaretWalker(editor.getBody());
const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
const isBeforeFn = forwards ? isBefore : isAfter;
if (!range.collapsed) {
const node = getSelectedNode(range);
if (isElement(node)) {
return showCaret(direction, editor, node, direction === HDirection.Backwards, false);
} else if (isCefAtEdgeSelected(editor)) {
const newRange = range.cloneRange();
newRange.collapse(direction === HDirection.Backwards);
return Optional.from(newRange);
}
}
const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
if (isBeforeFn(caretPosition)) {
return selectNode(editor, caretPosition.getNode(!forwards));
}
let nextCaretPosition = getNextPosFn(caretPosition);
const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
if (!nextCaretPosition) {
return rangeIsInContainerBlock ? Optional.some(range) : Optional.none();
} else {
nextCaretPosition = normalizePosition(forwards, nextCaretPosition);
}
if (isBeforeFn(nextCaretPosition)) {
return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
}
const peekCaretPosition = getNextPosFn(nextCaretPosition);
if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
}
}
if (rangeIsInContainerBlock) {
return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
}
return Optional.none();
};
const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => {
const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
const caretClientRect = last$1(caretPosition.getClientRects());
const forwards = direction === VDirection.Down;
const root = editor.getBody();
if (!caretClientRect) {
return Optional.none();
}
if (isCefAtEdgeSelected(editor)) {
const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range);
const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange());
}
const walkerFn = forwards ? downUntil : upUntil;
const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
const nextLinePositions = filter$5(linePositions, isLine(1));
const clientX = caretClientRect.left;
const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
if (nextLineRect && isElement(nextLineRect.node)) {
const dist1 = Math.abs(clientX - nextLineRect.left);
const dist2 = Math.abs(clientX - nextLineRect.right);
return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
}
let currentNode;
if (isBefore(caretPosition)) {
currentNode = caretPosition.getNode();
} else if (isAfter(caretPosition)) {
currentNode = caretPosition.getNode(true);
} else {
currentNode = getSelectedNode(range);
}
if (currentNode) {
const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX);
if (closestNextLineRect) {
return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
}
closestNextLineRect = last$1(filter$5(caretPositions, isLine(0)));
if (closestNextLineRect) {
return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
}
}
if (nextLinePositions.length === 0) {
return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false));
}
return Optional.none();
};
const getLineEndPoint = (editor, forward) => {
const rng = editor.selection.getRng();
const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
const host = getEditingHost(from.container(), editor.getBody());
if (forward) {
const lineInfo = getPositionsUntilNextLine(host, from);
return last$2(lineInfo.positions);
} else {
const lineInfo = getPositionsUntilPreviousLine(host, from);
return head(lineInfo.positions);
}
};
const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => {
editor.selection.setRng(pos.toRange());
return true;
});
const setCaretPosition = (editor, pos) => {
const rng = editor.dom.createRng();
rng.setStart(pos.container(), pos.offset());
rng.setEnd(pos.container(), pos.offset());
editor.selection.setRng(rng);
};
const setSelected = (state, elm) => {
if (state) {
elm.setAttribute('data-mce-selected', 'inline-boundary');
} else {
elm.removeAttribute('data-mce-selected');
}
};
const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => {
setCaretPosition(editor, pos);
return location;
});
const getPositionFromRange = (range, root, forward) => {
const start = CaretPosition.fromRangeStart(range);
if (range.collapsed) {
return start;
} else {
const end = CaretPosition.fromRangeEnd(range);
return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start);
}
};
const findLocation = (editor, caret, forward) => {
const rootNode = editor.getBody();
const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
const isInlineTarget$1 = curry(isInlineTarget, editor);
const location = findLocation$1(forward, isInlineTarget$1, rootNode, from);
return location.bind(location => renderCaretLocation(editor, caret, location));
};
const toggleInlines = (isInlineTarget, dom, elms) => {
const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom);
const selectedInlines = filter$5(inlineBoundaries, isInlineTarget);
const targetInlines = filter$5(elms, isInlineTarget);
each$e(difference(selectedInlines, targetInlines), curry(setSelected, false));
each$e(difference(targetInlines, selectedInlines), curry(setSelected, true));
};
const safeRemoveCaretContainer = (editor, caret) => {
const caretValue = caret.get();
if (editor.selection.isCollapsed() && !editor.composing && caretValue) {
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) {
setCaretPosition(editor, removeAndReposition(caretValue, pos));
caret.set(null);
}
}
};
const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => {
if (editor.selection.isCollapsed()) {
const inlines = filter$5(elms, isInlineTarget);
each$e(inlines, _inline => {
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location));
});
}
};
const move$3 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
const setupSelectedState = editor => {
const caret = Cell(null);
const isInlineTarget$1 = curry(isInlineTarget, editor);
editor.on('NodeChange', e => {
if (isInlineBoundariesEnabled(editor)) {
toggleInlines(isInlineTarget$1, editor.dom, e.parents);
safeRemoveCaretContainer(editor, caret);
renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
}
});
return caret;
};
const moveNextWord = curry(moveWord, true);
const movePrevWord = curry(moveWord, false);
const moveToLineEndPoint$2 = (editor, forward, caret) => {
if (isInlineBoundariesEnabled(editor)) {
const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
const rng = editor.selection.getRng();
return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
});
return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => {
const outsideLoc = outside(loc);
return renderCaret(caret, outsideLoc).exists(pos => {
setCaretPosition(editor, pos);
return true;
});
});
} else {
return false;
}
};
const rangeFromPositions = (from, to) => {
const range = document.createRange();
range.setStart(from.container(), from.offset());
range.setEnd(to.container(), to.offset());
return range;
};
const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
const normalizedFirstPos = normalizePosition(true, firstPos);
const normalizedLastPos = normalizePosition(false, lastPos);
return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos));
}).getOr(true);
const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos));
const deleteFromTo = (editor, caret, from, to) => {
const rootNode = editor.getBody();
const isInlineTarget$1 = curry(isInlineTarget, editor);
editor.undoManager.ignore(() => {
editor.selection.setRng(rangeFromPositions(from, to));
execNativeDeleteCommand(editor);
readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
});
editor.nodeChanged();
};
const rescope = (rootNode, node) => {
const parentBlock = getParentBlock$3(node, rootNode);
return parentBlock ? parentBlock : rootNode;
};
const backspaceDeleteCollapsed = (editor, caret, forward, from) => {
const rootNode = rescope(editor.getBody(), from.container());
const isInlineTarget$1 = curry(isInlineTarget, editor);
const fromLocation = readLocation(isInlineTarget$1, rootNode, from);
const location = fromLocation.bind(location => {
if (forward) {
return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none);
} else {
return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location))));
}
});
return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
const toPosition = navigate(forward, rootNode, from);
const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos));
return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => {
if (hasOnlyTwoOrLessPositionsLeft(elm)) {
return Optional.some(() => {
deleteElement$2(editor, forward, SugarElement.fromDom(elm));
});
} else {
return Optional.none();
}
})).getOrThunk(() => toLocation.bind(() => toPosition.map(to => {
return () => {
if (forward) {
deleteFromTo(editor, caret, from, to);
} else {
deleteFromTo(editor, caret, to, from);
}
};
})));
});
};
const backspaceDelete$4 = (editor, caret, forward) => {
if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
const from = CaretPosition.fromRangeStart(editor.selection.getRng());
return backspaceDeleteCollapsed(editor, caret, forward, from);
}
return Optional.none();
};
const hasMultipleChildren = elm => childNodesCount(elm) > 1;
const getParentsUntil = (editor, pred) => {
const rootElm = SugarElement.fromDom(editor.getBody());
const startElm = SugarElement.fromDom(editor.selection.getStart());
const parents = parentsAndSelf(startElm, rootElm);
return findIndex$2(parents, pred).fold(constant(parents), index => parents.slice(0, index));
};
const hasOnlyOneChild = elm => childNodesCount(elm) === 1;
const getParentInlinesUntilMultichildInline = editor => getParentsUntil(editor, elm => editor.schema.isBlock(name(elm)) || hasMultipleChildren(elm));
const getParentInlines = editor => getParentsUntil(editor, el => editor.schema.isBlock(name(el)));
const getFormatNodes = (editor, parentInlines) => {
const isFormatElement$1 = curry(isFormatElement, editor);
return bind$3(parentInlines, elm => isFormatElement$1(elm) ? [elm.dom] : []);
};
const getFormatNodesAtStart = editor => {
const parentInlines = getParentInlines(editor);
return getFormatNodes(editor, parentInlines);
};
const deleteLastPosition = (forward, editor, target, parentInlines) => {
const formatNodes = getFormatNodes(editor, parentInlines);
if (formatNodes.length === 0) {
deleteElement$2(editor, forward, target);
} else {
const pos = replaceWithCaretFormat(target.dom, formatNodes);
editor.selection.setRng(pos.toRange());
}
};
const deleteCaret$1 = (editor, forward) => {
const parentInlines = filter$5(getParentInlinesUntilMultichildInline(editor), hasOnlyOneChild);
return last$2(parentInlines).bind(target => {
const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
} else {
return Optional.none();
}
});
};
const isBrInEmptyElement = (editor, elm) => {
const parentElm = elm.parentElement;
return isBr$6(elm) && !isNull(parentElm) && editor.dom.isEmpty(parentElm);
};
const isEmptyCaret = elm => isEmptyCaretFormatElement(SugarElement.fromDom(elm));
const createCaretFormatAtStart = (editor, formatNodes) => {
const startElm = editor.selection.getStart();
const pos = isBrInEmptyElement(editor, startElm) || isEmptyCaret(startElm) ? replaceWithCaretFormat(startElm, formatNodes) : createCaretFormatAtStart$1(editor.selection.getRng(), formatNodes);
editor.selection.setRng(pos.toRange());
};
const updateCaretFormat = (editor, updateFormats) => {
const missingFormats = difference(updateFormats, getFormatNodesAtStart(editor));
if (missingFormats.length > 0) {
createCaretFormatAtStart(editor, missingFormats);
}
};
const rangeStartsAtTextContainer = rng => isText$b(rng.startContainer);
const rangeStartsAtStartOfTextContainer = rng => rng.startOffset === 0 && rangeStartsAtTextContainer(rng);
const rangeStartParentIsFormatElement = (editor, rng) => {
const startParent = rng.startContainer.parentElement;
return !isNull(startParent) && isFormatElement(editor, SugarElement.fromDom(startParent));
};
const rangeStartAndEndHaveSameParent = rng => {
const startParent = rng.startContainer.parentNode;
const endParent = rng.endContainer.parentNode;
return !isNull(startParent) && !isNull(endParent) && startParent.isEqualNode(endParent);
};
const rangeEndsAtEndOfEndContainer = rng => {
const endContainer = rng.endContainer;
return rng.endOffset === (isText$b(endContainer) ? endContainer.length : endContainer.childNodes.length);
};
const rangeEndsAtEndOfStartContainer = rng => rangeStartAndEndHaveSameParent(rng) && rangeEndsAtEndOfEndContainer(rng);
const rangeEndsAfterEndOfStartContainer = rng => !rng.endContainer.isEqualNode(rng.commonAncestorContainer);
const rangeEndsAtOrAfterEndOfStartContainer = rng => rangeEndsAtEndOfStartContainer(rng) || rangeEndsAfterEndOfStartContainer(rng);
const requiresDeleteRangeOverride = editor => {
const rng = editor.selection.getRng();
return rangeStartsAtStartOfTextContainer(rng) && rangeStartParentIsFormatElement(editor, rng) && rangeEndsAtOrAfterEndOfStartContainer(rng);
};
const deleteRange$1 = editor => {
if (requiresDeleteRangeOverride(editor)) {
const formatNodes = getFormatNodesAtStart(editor);
return Optional.some(() => {
execNativeDeleteCommand(editor);
updateCaretFormat(editor, formatNodes);
});
} else {
return Optional.none();
}
};
const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : deleteRange$1(editor);
const hasAncestorInlineCaret = (elm, schema) => ancestor$2(elm, node => isCaretNode(node.dom), el => schema.isBlock(name(el)));
const hasAncestorInlineCaretAtStart = editor => hasAncestorInlineCaret(SugarElement.fromDom(editor.selection.getStart()), editor.schema);
const requiresRefreshCaretOverride = editor => {
const rng = editor.selection.getRng();
return rng.collapsed && (rangeStartsAtTextContainer(rng) || editor.dom.isEmpty(rng.startContainer)) && !hasAncestorInlineCaretAtStart(editor);
};
const refreshCaret = editor => {
if (requiresRefreshCaretOverride(editor)) {
createCaretFormatAtStart(editor, []);
}
return true;
};
const deleteElement = (editor, forward, element) => {
if (isNonNullable(element)) {
return Optional.some(() => {
editor._selectionOverrides.hideFakeCaret();
deleteElement$2(editor, forward, SugarElement.fromDom(element));
});
} else {
return Optional.none();
}
};
const deleteCaret = (editor, forward) => {
const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
const direction = forward ? HDirection.Forwards : HDirection.Backwards;
const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
if (isNearMedia(fromPos)) {
return deleteElement(editor, forward, fromPos.getNode(!forward));
} else {
return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward)));
}
};
const deleteRange = (editor, forward) => {
const selectedNode = editor.selection.getNode();
return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
};
const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
const isEditable = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$b(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom));
const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0);
const getIndentStyleName = (useMargin, element) => {
const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left';
return indentStyleName + suffix;
};
const indentElement = (dom, command, useMargin, value, unit, element) => {
const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName));
if (command === 'outdent') {
const styleValue = Math.max(0, parsedValue - value);
dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
} else {
const styleValue = parsedValue + value + unit;
dom.setStyle(element, indentStyleName, styleValue);
}
};
const validateBlocks = (editor, blocks) => forall(blocks, block => {
const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
const intentValue = getRaw(block, indentStyleName).map(parseIndentValue).getOr(0);
const contentEditable = editor.dom.getContentEditable(block.dom);
return contentEditable !== 'false' && intentValue > 0;
});
const canOutdent = editor => {
const blocks = getBlocksToIndent(editor);
return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks));
};
const isListComponent = el => isList(el) || isListItem$1(el);
const parentIsListComponent = el => parent(el).exists(isListComponent);
const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el));
const handle = (editor, command) => {
var _a, _b;
const {dom} = editor;
const indentation = getIndentation(editor);
const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
const indentValue = parseIndentValue(indentation);
const useMargin = shouldIndentUseMargin(editor);
each$e(getBlocksToIndent(editor), block => {
indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom);
});
};
const indent = editor => handle(editor, 'indent');
const outdent = editor => handle(editor, 'outdent');
const backspaceDelete$1 = editor => {
if (editor.selection.isCollapsed() && canOutdent(editor)) {
const dom = editor.dom;
const rng = editor.selection.getRng();
const pos = CaretPosition.fromRangeStart(rng);
const block = dom.getParent(rng.startContainer, dom.isBlock);
if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos, editor.schema)) {
return Optional.some(() => outdent(editor));
}
}
return Optional.none();
};
const findAction = (editor, caret, forward) => findMap([
backspaceDelete$1,
backspaceDelete$7,
backspaceDelete$8,
(editor, forward) => backspaceDelete$4(editor, caret, forward),
backspaceDelete$a,
backspaceDelete$b,
backspaceDelete$5,
backspaceDelete$2,
backspaceDelete$9,
backspaceDelete$3,
backspaceDelete$6
], item => item(editor, forward)).filter(_ => editor.selection.isEditable());
const deleteCommand = (editor, caret) => {
const result = findAction(editor, caret, false);
result.fold(() => {
if (editor.selection.isEditable()) {
execNativeDeleteCommand(editor);
paddEmptyBody(editor);
}
}, call);
};
const forwardDeleteCommand = (editor, caret) => {
const result = findAction(editor, caret, true);
result.fold(() => {
if (editor.selection.isEditable()) {
execNativeForwardDeleteCommand(editor);
}
}, call);
};
const setup$q = (editor, caret) => {
editor.addCommand('delete', () => {
deleteCommand(editor, caret);
});
editor.addCommand('forwardDelete', () => {
forwardDeleteCommand(editor, caret);
});
};
const SIGNIFICANT_MOVE = 5;
const LONGPRESS_DELAY = 400;
const getTouch = event => {
if (event.touches === undefined || event.touches.length !== 1) {
return Optional.none();
}
return Optional.some(event.touches[0]);
};
const isFarEnough = (touch, data) => {
const distX = Math.abs(touch.clientX - data.x);
const distY = Math.abs(touch.clientY - data.y);
return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
};
const setup$p = editor => {
const startData = value$2();
const longpressFired = Cell(false);
const debounceLongpress = last(e => {
editor.dispatch('longpress', {
...e,
type: 'longpress'
});
longpressFired.set(true);
}, LONGPRESS_DELAY);
editor.on('touchstart', e => {
getTouch(e).each(touch => {
debounceLongpress.cancel();
const data = {
x: touch.clientX,
y: touch.clientY,
target: e.target
};
debounceLongpress.throttle(e);
longpressFired.set(false);
startData.set(data);
});
}, true);
editor.on('touchmove', e => {
debounceLongpress.cancel();
getTouch(e).each(touch => {
startData.on(data => {
if (isFarEnough(touch, data)) {
startData.clear();
longpressFired.set(false);
editor.dispatch('longpresscancel');
}
});
});
}, true);
editor.on('touchend touchcancel', e => {
debounceLongpress.cancel();
if (e.type === 'touchcancel') {
return;
}
startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => {
if (longpressFired.get()) {
e.preventDefault();
} else {
editor.dispatch('tap', {
...e,
type: 'tap'
});
}
});
}, true);
};
const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
const isValidTarget = (schema, node) => {
if (isText$b(node)) {
return true;
} else if (isElement$6(node)) {
return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node) && !isNonHtmlElementRoot(node);
} else {
return false;
}
};
const hasBlockParent = (blockElements, root, node) => {
return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => {
return isBlockElement(blockElements, elm.dom);
});
};
const shouldRemoveTextNode = (blockElements, node) => {
if (isText$b(node)) {
if (node.data.length === 0) {
return true;
} else if (/^\s+$/.test(node.data)) {
return !node.nextSibling || isBlockElement(blockElements, node.nextSibling) || isNonHtmlElementRoot(node.nextSibling);
}
}
return false;
};
const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
const addRootBlocks = editor => {
const dom = editor.dom, selection = editor.selection;
const schema = editor.schema;
const blockElements = schema.getBlockElements();
const startNode = selection.getStart();
const rootNode = editor.getBody();
let rootBlockNode;
let tempNode;
let bm = null;
const forcedRootBlock = getForcedRootBlock(editor);
if (!startNode || !isElement$6(startNode)) {
return;
}
const rootNodeName = rootNode.nodeName.toLowerCase();
if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) {
return;
}
if (rootNode.firstChild === rootNode.lastChild && isBr$6(rootNode.firstChild)) {
rootBlockNode = createRootBlock(editor);
rootBlockNode.appendChild(createPaddingBr().dom);
rootNode.replaceChild(rootBlockNode, rootNode.firstChild);
editor.selection.setCursorLocation(rootBlockNode, 0);
editor.nodeChanged();
return;
}
let node = rootNode.firstChild;
while (node) {
if (isElement$6(node)) {
updateElement(schema, node);
}
if (isValidTarget(schema, node)) {
if (shouldRemoveTextNode(blockElements, node)) {
tempNode = node;
node = node.nextSibling;
dom.remove(tempNode);
continue;
}
if (!rootBlockNode) {
if (!bm && editor.hasFocus()) {
bm = getBookmark(editor.selection.getRng(), () => document.createElement('span'));
}
if (!node.parentNode) {
node = null;
break;
}
rootBlockNode = createRootBlock(editor);
rootNode.insertBefore(rootBlockNode, node);
}
tempNode = node;
node = node.nextSibling;
rootBlockNode.appendChild(tempNode);
} else {
rootBlockNode = null;
node = node.nextSibling;
}
}
if (bm) {
editor.selection.setRng(resolveBookmark(bm));
editor.nodeChanged();
}
};
const insertEmptyLine = (editor, root, insertBlock) => {
const block = SugarElement.fromDom(createRootBlock(editor));
const br = createPaddingBr();
append$1(block, br);
insertBlock(root, block);
const rng = document.createRange();
rng.setStartBefore(br.dom);
rng.setEndBefore(br.dom);
return rng;
};
const setup$o = editor => {
editor.on('NodeChange', () => addRootBlocks(editor));
};
const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1;
const replaceMatchWithSpan = (editor, content, cls) => {
return function (match) {
const args = arguments, index = args[args.length - 2];
const prevChar = index > 0 ? content.charAt(index - 1) : '';
if (prevChar === '"') {
return match;
}
if (prevChar === '>') {
const findStartTagIndex = content.lastIndexOf('<', index);
if (findStartTagIndex !== -1) {
const tagHtml = content.substring(findStartTagIndex, index);
if (tagHtml.indexOf('contenteditable="false"') !== -1) {
return match;
}
}
}
return '' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '';
};
};
const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
let i = nonEditableRegExps.length, content = e.content;
if (e.format === 'raw') {
return;
}
while (i--) {
content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
}
e.content = content;
};
const isValidContent = (nonEditableRegExps, content) => {
return forall(nonEditableRegExps, re => {
const matches = content.match(re);
return matches !== null && matches[0].length === content.length;
});
};
const setup$n = editor => {
const contentEditableAttrName = 'contenteditable';
const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' ';
const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' ';
const hasEditClass = hasClass(editClass);
const hasNonEditClass = hasClass(nonEditClass);
const nonEditableRegExps = getNonEditableRegExps(editor);
if (nonEditableRegExps.length > 0) {
editor.on('BeforeSetContent', e => {
convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
});
}
editor.parser.addAttributeFilter('class', nodes => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
if (hasEditClass(node)) {
node.attr(contentEditableAttrName, 'true');
} else if (hasNonEditClass(node)) {
node.attr(contentEditableAttrName, 'false');
}
}
});
editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
if (!hasEditClass(node) && !hasNonEditClass(node)) {
continue;
}
const content = node.attr('data-mce-content');
if (nonEditableRegExps.length > 0 && content) {
if (isValidContent(nonEditableRegExps, content)) {
node.name = '#text';
node.type = 3;
node.raw = true;
node.value = content;
} else {
node.remove();
}
} else {
node.attr(contentEditableAttrName, null);
}
}
});
};
const findBlockCaretContainer = editor => descendant$1(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull();
const showBlockCaretContainer = (editor, blockCaretContainer) => {
if (blockCaretContainer.hasAttribute('data-mce-caret')) {
showCaretContainerBlock(blockCaretContainer);
editor.selection.setRng(editor.selection.getRng());
editor.selection.scrollIntoView(blockCaretContainer);
}
};
const handleBlockContainer = (editor, e) => {
const blockCaretContainer = findBlockCaretContainer(editor);
if (!blockCaretContainer) {
return;
}
if (e.type === 'compositionstart') {
e.preventDefault();
e.stopPropagation();
showBlockCaretContainer(editor, blockCaretContainer);
return;
}
if (hasContent(blockCaretContainer)) {
showBlockCaretContainer(editor, blockCaretContainer);
editor.undoManager.add();
}
};
const setup$m = editor => {
editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
};
const isContentEditableFalse$4 = isContentEditableFalse$b;
const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$4);
const moveToCeFalseVertically = (direction, editor, range) => {
const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$4);
};
const createTextBlock = editor => {
const textBlock = editor.dom.create(getForcedRootBlock(editor));
textBlock.innerHTML = '
';
return textBlock;
};
const exitPreBlock = (editor, direction, range) => {
const caretWalker = CaretWalker(editor.getBody());
const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
if (range.collapsed) {
const pre = editor.dom.getParent(range.startContainer, 'PRE');
if (!pre) {
return;
}
const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range));
if (!caretPos) {
const newBlock = SugarElement.fromDom(createTextBlock(editor));
if (direction === 1) {
after$4(SugarElement.fromDom(pre), newBlock);
} else {
before$3(SugarElement.fromDom(pre), newBlock);
}
editor.selection.select(newBlock.dom, true);
editor.selection.collapse();
}
}
};
const getHorizontalRange = (editor, forward) => {
const direction = forward ? HDirection.Forwards : HDirection.Backwards;
const range = editor.selection.getRng();
return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => {
exitPreBlock(editor, direction, range);
return Optional.none();
});
};
const getVerticalRange = (editor, down) => {
const direction = down ? 1 : -1;
const range = editor.selection.getRng();
return moveToCeFalseVertically(direction, editor, range).orThunk(() => {
exitPreBlock(editor, direction, range);
return Optional.none();
});
};
const flipDirection = (selection, forward) => {
const elm = forward ? selection.getEnd(true) : selection.getStart(true);
return isRtl(elm) ? !forward : forward;
};
const moveH$2 = (editor, forward) => getHorizontalRange(editor, flipDirection(editor.selection, forward)).exists(newRange => {
moveToRange(editor, newRange);
return true;
});
const moveV$4 = (editor, down) => getVerticalRange(editor, down).exists(newRange => {
moveToRange(editor, newRange);
return true;
});
const moveToLineEndPoint$1 = (editor, forward) => {
const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
return moveToLineEndPoint$3(editor, forward, isCefPosition);
};
const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => {
const rng = pos.toRange();
const curRng = editor.selection.getRng();
if (forward) {
rng.setStart(curRng.startContainer, curRng.startOffset);
} else {
rng.setEnd(curRng.endContainer, curRng.endOffset);
}
return rng;
}).exists(rng => {
moveToRange(editor, rng);
return true;
});
const isTarget = node => contains$2(['figcaption'], name(node));
const getClosestTargetBlock = (pos, root, schema) => {
const isRoot = curry(eq, root);
return closest$4(SugarElement.fromDom(pos.container()), el => schema.isBlock(name(el)), isRoot).filter(isTarget);
};
const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
const moveCaretToNewEmptyLine = (editor, forward) => {
const root = SugarElement.fromDom(editor.getBody());
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
return getClosestTargetBlock(pos, root, editor.schema).exists(() => {
if (isAtFirstOrLastLine(root, forward, pos)) {
const insertFn = forward ? append$1 : prepend;
const rng = insertEmptyLine(editor, root, insertFn);
editor.selection.setRng(rng);
return true;
} else {
return false;
}
});
};
const moveV$3 = (editor, forward) => {
if (editor.selection.isCollapsed()) {
return moveCaretToNewEmptyLine(editor, forward);
} else {
return false;
}
};
const moveUp = (editor, details, summary) => {
const rng = editor.selection.getRng();
const pos = CaretPosition.fromRangeStart(rng);
const root = editor.getBody();
if (root.firstChild === details && isAtFirstLine(summary, pos)) {
editor.execCommand('InsertNewBlockBefore');
return true;
} else {
return false;
}
};
const moveDown = (editor, details) => {
const rng = editor.selection.getRng();
const pos = CaretPosition.fromRangeStart(rng);
const root = editor.getBody();
if (root.lastChild === details && isAtLastLine(details, pos)) {
editor.execCommand('InsertNewBlockAfter');
return true;
} else {
return false;
}
};
const move$2 = (editor, forward) => {
if (forward) {
return Optional.from(editor.dom.getParent(editor.selection.getNode(), 'details')).map(details => moveDown(editor, details)).getOr(false);
} else {
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);
}
};
const moveV$2 = (editor, forward) => move$2(editor, forward);
const baseKeyPattern = {
shiftKey: false,
altKey: false,
ctrlKey: false,
metaKey: false,
keyCode: 0
};
const defaultPatterns = patterns => map$3(patterns, pattern => ({
...baseKeyPattern,
...pattern
}));
const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({
...baseKeyPattern,
...pattern
}));
const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
const action = (f, ...x) => () => f.apply(null, x);
const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action());
const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action());
const moveH$1 = (editor, forward) => {
const direction = forward ? HDirection.Forwards : HDirection.Backwards;
const range = editor.selection.getRng();
return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
moveToRange(editor, newRange);
return true;
});
};
const moveV$1 = (editor, down) => {
const direction = down ? 1 : -1;
const range = editor.selection.getRng();
return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
moveToRange(editor, newRange);
return true;
});
};
const moveToLineEndPoint = (editor, forward) => {
const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
return moveToLineEndPoint$3(editor, forward, isNearMedia);
};
const adt = Adt.generate([
{ none: ['current'] },
{ first: ['current'] },
{
middle: [
'current',
'target'
]
},
{ last: ['current'] }
]);
const none = current => adt.none(current);
const CellLocation = {
...adt,
none
};
const firstLayer = (scope, selector) => {
return filterFirstLayer(scope, selector, always);
};
const filterFirstLayer = (scope, selector, predicate) => {
return bind$3(children$1(scope), x => {
if (is$1(x, selector)) {
return predicate(x) ? [x] : [];
} else {
return filterFirstLayer(x, selector, predicate);
}
});
};
const lookup$1 = (tags, element, isRoot = never) => {
if (isRoot(element)) {
return Optional.none();
}
if (contains$2(tags, name(element))) {
return Optional.some(element);
}
const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm);
return ancestor$3(element, tags.join(','), isRootOrUpperTable);
};
const cell = (element, isRoot) => lookup$1([
'td',
'th'
], element, isRoot);
const cells = ancestor => firstLayer(ancestor, 'th,td');
const table = (element, isRoot) => closest$3(element, 'table', isRoot);
const walk = (all, current, index, direction, isEligible = always) => {
const forwards = direction === 1;
if (!forwards && index <= 0) {
return CellLocation.first(all[0]);
} else if (forwards && index >= all.length - 1) {
return CellLocation.last(all[all.length - 1]);
} else {
const newIndex = index + direction;
const elem = all[newIndex];
return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible);
}
};
const detect = (current, isRoot) => {
return table(current, isRoot).bind(table => {
const all = cells(table);
const index = findIndex$2(all, x => eq(current, x));
return index.map(index => ({
index,
all
}));
});
};
const next = (current, isEligible, isRoot) => {
const detection = detect(current, isRoot);
return detection.fold(() => {
return CellLocation.none(current);
}, info => {
return walk(info.all, current, info.index, 1, isEligible);
});
};
const prev = (current, isEligible, isRoot) => {
const detection = detect(current, isRoot);
return detection.fold(() => {
return CellLocation.none();
}, info => {
return walk(info.all, current, info.index, -1, isEligible);
});
};
const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
const isContentEditableFalse$3 = elem => isHTMLElement$1(elem) && get$9(elem, 'contenteditable') === 'false';
const elementsWithCursorPosition = [
'img',
'br'
];
const isCursorPosition = elem => {
const hasCursorPosition = isTextNodeWithCursorPosition(elem);
return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse$3(elem);
};
const first = element => descendant$2(element, isCursorPosition);
const deflate = (rect, delta) => ({
left: rect.left - delta,
top: rect.top - delta,
right: rect.right + delta * 2,
bottom: rect.bottom + delta * 2,
width: rect.width + delta,
height: rect.height + delta
});
const getCorners = (getYAxisValue, tds) => bind$3(tds, td => {
const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
return [
{
x: rect.left,
y: getYAxisValue(rect),
cell: td
},
{
x: rect.right,
y: getYAxisValue(rect),
cell: td
}
];
});
const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => {
const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
return Optional.some(newDist < oldDist ? newCorner : oldCorner);
}), Optional.none());
const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => {
const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom);
const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y));
return findClosestCorner(corners, x, y).map(corner => corner.cell);
};
const getBottomValue = rect => rect.bottom;
const getTopValue = rect => rect.top;
const isAbove = (corner, y) => corner.y < y;
const isBelow = (corner, y) => corner.y > y;
const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos));
const findClosestPositionInBelowCell = (table, pos) => last$2(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos));
const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome());
const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
const isAtTableCellLine = (getPositionsUntil, scope, pos) => {
const lineInfo = getPositionsUntil(scope, pos);
if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
return !hasNextBreak(getPositionsUntil, scope, lineInfo);
} else {
return lineInfo.breakAt.isNone();
}
};
const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
const isCaretAtStartOrEndOfTable = (forward, rng, table) => {
const caretPos = CaretPosition.fromRangeStart(rng);
return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos));
};
const navigateHorizontally = (editor, forward, table, _td) => {
const rng = editor.selection.getRng();
const direction = forward ? 1 : -1;
if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
showCaret(direction, editor, table, !forward, false).each(newRng => {
moveToRange(editor, newRng);
});
return true;
}
return false;
};
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));
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));
const getTable = (previous, pos) => {
const node = pos.getNode(previous);
return isTable$2(node) ? Optional.some(node) : Optional.none();
};
const renderBlock = (down, editor, table) => {
editor.undoManager.transact(() => {
const insertFn = down ? after$4 : before$3;
const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn);
moveToRange(editor, rng);
});
};
const moveCaret = (editor, down, pos) => {
const table = down ? getTable(true, pos) : getTable(false, pos);
const last = down === false;
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)));
};
const navigateVertically = (editor, down, table, td) => {
const rng = editor.selection.getRng();
const pos = CaretPosition.fromRangeStart(rng);
const root = editor.getBody();
if (!down && isAtFirstTableCellLine(td, pos)) {
const newPos = getClosestAbovePosition(root, table, pos);
moveCaret(editor, down, newPos);
return true;
} else if (down && isAtLastTableCellLine(td, pos)) {
const newPos = getClosestBelowPosition(root, table, pos);
moveCaret(editor, down, newPos);
return true;
} else {
return false;
}
};
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);
const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
const getCellFirstCursorPosition = cell => {
const selection = SimSelection.exact(cell, 0, cell, 0);
return toNative(selection);
};
const tabGo = (editor, isRoot, cell) => {
return cell.fold(Optional.none, Optional.none, (_current, next) => {
return first(next).map(cell => {
return getCellFirstCursorPosition(cell);
});
}, current => {
editor.execCommand('mceTableInsertRowAfter');
return tabForward(editor, isRoot, current);
});
};
const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable$2));
const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable$2));
const handleTab = (editor, forward) => {
const rootElements = [
'table',
'li',
'dl'
];
const body = SugarElement.fromDom(editor.getBody());
const isRoot = element => {
const name$1 = name(element);
return eq(element, body) || contains$2(rootElements, name$1);
};
const rng = editor.selection.getRng();
const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
return cell(container, isRoot).map(cell => {
table(cell, isRoot).each(table => {
editor.model.table.clearSelectedCells(table.dom);
});
editor.selection.collapse(!forward);
const navigation = !forward ? tabBackward : tabForward;
const rng = navigation(editor, isRoot, cell);
rng.each(range => {
editor.selection.setRng(range);
});
return true;
}).getOr(false);
};
const executeKeydownOverride$4 = (editor, caret, evt) => {
const isMac = Env.os.isMacOS() || Env.os.isiOS();
execute([
{
keyCode: VK.RIGHT,
action: action(moveH$2, editor, true)
},
{
keyCode: VK.LEFT,
action: action(moveH$2, editor, false)
},
{
keyCode: VK.UP,
action: action(moveV$4, editor, false)
},
{
keyCode: VK.DOWN,
action: action(moveV$4, editor, true)
},
...isMac ? [
{
keyCode: VK.UP,
action: action(selectToEndPoint, editor, false),
metaKey: true,
shiftKey: true
},
{
keyCode: VK.DOWN,
action: action(selectToEndPoint, editor, true),
metaKey: true,
shiftKey: true
}
] : [],
{
keyCode: VK.RIGHT,
action: action(moveH, editor, true)
},
{
keyCode: VK.LEFT,
action: action(moveH, editor, false)
},
{
keyCode: VK.UP,
action: action(moveV, editor, false)
},
{
keyCode: VK.DOWN,
action: action(moveV, editor, true)
},
{
keyCode: VK.UP,
action: action(moveV, editor, false)
},
{
keyCode: VK.UP,
action: action(moveV$2, editor, false)
},
{
keyCode: VK.DOWN,
action: action(moveV$2, editor, true)
},
{
keyCode: VK.RIGHT,
action: action(moveH$1, editor, true)
},
{
keyCode: VK.LEFT,
action: action(moveH$1, editor, false)
},
{
keyCode: VK.UP,
action: action(moveV$1, editor, false)
},
{
keyCode: VK.DOWN,
action: action(moveV$1, editor, true)
},
{
keyCode: VK.RIGHT,
action: action(move$3, editor, caret, true)
},
{
keyCode: VK.LEFT,
action: action(move$3, editor, caret, false)
},
{
keyCode: VK.RIGHT,
ctrlKey: !isMac,
altKey: isMac,
action: action(moveNextWord, editor, caret)
},
{
keyCode: VK.LEFT,
ctrlKey: !isMac,
altKey: isMac,
action: action(movePrevWord, editor, caret)
},
{
keyCode: VK.UP,
action: action(moveV$3, editor, false)
},
{
keyCode: VK.DOWN,
action: action(moveV$3, editor, true)
}
], evt).each(_ => {
evt.preventDefault();
});
};
const setup$l = (editor, caret) => {
editor.on('keydown', evt => {
if (!evt.isDefaultPrevented()) {
executeKeydownOverride$4(editor, caret, evt);
}
});
};
const point = (container, offset) => ({
container,
offset
});
const DOM$7 = DOMUtils.DOM;
const alwaysNext = startNode => node => startNode === node ? -1 : 0;
const isBoundary = dom => node => dom.isBlock(node) || contains$2([
'BR',
'IMG',
'HR',
'INPUT'
], node.nodeName) || dom.getContentEditable(node) === 'false';
const textBefore = (node, offset, rootNode) => {
if (isText$b(node) && offset >= 0) {
return Optional.some(point(node, offset));
} else {
const textSeeker = TextSeeker(DOM$7);
return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length));
}
};
const textAfter = (node, offset, rootNode) => {
if (isText$b(node) && offset >= node.length) {
return Optional.some(point(node, offset));
} else {
const textSeeker = TextSeeker(DOM$7);
return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0));
}
};
const scanLeft = (node, offset, rootNode) => {
if (!isText$b(node)) {
return Optional.none();
}
const text = node.data;
if (offset >= 0 && offset <= text.length) {
return Optional.some(point(node, offset));
} else {
const textSeeker = TextSeeker(DOM$7);
return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => {
const prevText = prev.container.data;
return scanLeft(prev.container, offset + prevText.length, rootNode);
});
}
};
const scanRight = (node, offset, rootNode) => {
if (!isText$b(node)) {
return Optional.none();
}
const text = node.data;
if (offset <= text.length) {
return Optional.some(point(node, offset));
} else {
const textSeeker = TextSeeker(DOM$7);
return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode));
}
};
const repeatLeft = (dom, node, offset, process, rootNode) => {
const search = TextSeeker(dom, isBoundary(dom));
return Optional.from(search.backwards(node, offset, process, rootNode));
};
const isValidTextRange = rng => rng.collapsed && isText$b(rng.startContainer);
const getText = rng => trim$2(rng.toString().replace(/\u00A0/g, ' '));
const isWhitespace = chr => chr !== '' && ' \xA0\f\n\r\t\x0B'.indexOf(chr) !== -1;
const stripTrigger = (text, trigger) => text.substring(trigger.length);
const findTrigger = (text, index, trigger, includeWhitespace = false) => {
let i;
const firstChar = trigger.charAt(0);
for (i = index - 1; i >= 0; i--) {
const char = text.charAt(i);
if (!includeWhitespace && isWhitespace(char)) {
return Optional.none();
}
if (firstChar === char && contains$1(text, trigger, i, index)) {
break;
}
}
return Optional.some(i);
};
const getContext = (dom, initRange, trigger, includeWhitespace = false) => {
if (!isValidTextRange(initRange)) {
return Optional.none();
}
const buffer = {
text: '',
offset: 0
};
const findTriggerIndex = (element, offset, text) => {
buffer.text = text + buffer.text;
buffer.offset += offset;
return findTrigger(buffer.text, buffer.offset, trigger, includeWhitespace).getOr(offset);
};
const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot();
return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => {
const range = initRange.cloneRange();
range.setStart(spot.container, spot.offset);
range.setEnd(initRange.endContainer, initRange.endOffset);
if (range.collapsed) {
return Optional.none();
}
const text = getText(range);
const triggerIndex = text.lastIndexOf(trigger);
if (triggerIndex !== 0) {
return Optional.none();
} else {
return Optional.some({
text: stripTrigger(text, trigger),
range,
trigger
});
}
});
};
const isText$1 = node => node.nodeType === TEXT;
const isElement = node => node.nodeType === ELEMENT;
const toLast = node => {
if (isText$1(node)) {
return point(node, node.data.length);
} else {
const children = node.childNodes;
return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length);
}
};
const toLeaf = (node, offset) => {
const children = node.childNodes;
if (children.length > 0 && offset < children.length) {
return toLeaf(children[offset], 0);
} else if (children.length > 0 && isElement(node) && children.length === offset) {
return toLast(children[children.length - 1]);
} else {
return point(node, offset);
}
};
const isPreviousCharContent = (dom, leaf) => {
var _a;
const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => {
const char = spot.container.data.charAt(spot.offset - 1);
return !isWhitespace(char);
}).isSome();
};
const isStartOfWord = dom => rng => {
const leaf = toLeaf(rng.startContainer, rng.startOffset);
return !isPreviousCharContent(dom, leaf);
};
const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger));
const lookup = (editor, getDatabase) => {
const database = getDatabase();
const rng = editor.selection.getRng();
return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context));
};
const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => {
var _a;
const database = getDatabase();
const rng = editor.selection.getRng();
const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : '';
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));
if (autocompleters.length === 0) {
return Optional.none();
}
const lookupData = Promise.all(map$3(autocompleters, ac => {
const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions);
return fetchResult.then(results => ({
matchText: context.text,
items: results,
columns: ac.columns,
onAction: ac.onAction,
highlightOn: ac.highlightOn
}));
}));
return Optional.some({
lookupData,
context
});
};
var SimpleResultType;
(function (SimpleResultType) {
SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
}(SimpleResultType || (SimpleResultType = {})));
const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
const partition = results => {
const values = [];
const errors = [];
each$e(results, obj => {
fold$1(obj, err => errors.push(err), val => values.push(val));
});
return {
values,
errors
};
};
const mapError = (res, f) => {
if (res.stype === SimpleResultType.Error) {
return {
stype: SimpleResultType.Error,
serror: f(res.serror)
};
} else {
return res;
}
};
const map = (res, f) => {
if (res.stype === SimpleResultType.Value) {
return {
stype: SimpleResultType.Value,
svalue: f(res.svalue)
};
} else {
return res;
}
};
const bind$1 = (res, f) => {
if (res.stype === SimpleResultType.Value) {
return f(res.svalue);
} else {
return res;
}
};
const bindError = (res, f) => {
if (res.stype === SimpleResultType.Error) {
return f(res.serror);
} else {
return res;
}
};
const svalue = v => ({
stype: SimpleResultType.Value,
svalue: v
});
const serror = e => ({
stype: SimpleResultType.Error,
serror: e
});
const toResult = res => fold$1(res, Result.error, Result.value);
const fromResult = res => res.fold(serror, svalue);
const SimpleResult = {
fromResult,
toResult,
svalue,
partition,
serror,
bind: bind$1,
bindError,
map,
mapError,
fold: fold$1
};
const formatObj = input => {
return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
};
const formatErrors = errors => {
const es = errors.length > 10 ? errors.slice(0, 10).concat([{
path: [],
getErrorInfo: constant('... (only showing first ten failures)')
}]) : errors;
return map$3(es, e => {
return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
});
};
const nu = (path, getErrorInfo) => {
return SimpleResult.serror([{
path,
getErrorInfo
}]);
};
const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
const custom = (path, err) => nu(path, constant(err));
const chooseFrom = (path, input, branches, ch) => {
const fields = get$a(branches, ch);
return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
};
const choose$1 = (key, branches) => {
const extract = (path, input) => {
const choice = get$a(input, key);
return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
};
const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
return {
extract,
toString
};
};
const shallow = (old, nu) => {
return nu;
};
const deep = (old, nu) => {
const bothObjects = isPlainObject(old) && isPlainObject(nu);
return bothObjects ? deepMerge(old, nu) : nu;
};
const baseMerge = merger => {
return (...objects) => {
if (objects.length === 0) {
throw new Error(`Can't merge zero objects`);
}
const ret = {};
for (let j = 0; j < objects.length; j++) {
const curObject = objects[j];
for (const key in curObject) {
if (has$2(curObject, key)) {
ret[key] = merger(ret[key], curObject[key]);
}
}
}
return ret;
};
};
const deepMerge = baseMerge(deep);
const merge = baseMerge(shallow);
const required = () => ({
tag: 'required',
process: {}
});
const defaultedThunk = fallbackThunk => ({
tag: 'defaultedThunk',
process: fallbackThunk
});
const defaulted$1 = fallback => defaultedThunk(constant(fallback));
const asOption = () => ({
tag: 'option',
process: {}
});
const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base);
const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors);
const consolidateObj = (objects, base) => {
const partition = SimpleResult.partition(objects);
return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
};
const consolidateArr = objects => {
const partitions = SimpleResult.partition(objects);
return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
};
const ResultCombine = {
consolidateObj,
consolidateArr
};
const field$1 = (key, newKey, presence, prop) => ({
tag: 'field',
key,
newKey,
presence,
prop
});
const customField$1 = (newKey, instantiator) => ({
tag: 'custom',
newKey,
instantiator
});
const fold = (value, ifField, ifCustom) => {
switch (value.tag) {
case 'field':
return ifField(value.key, value.newKey, value.presence, value.prop);
case 'custom':
return ifCustom(value.newKey, value.instantiator);
}
};
const value = validator => {
const extract = (path, val) => {
return SimpleResult.bindError(validator(val), err => custom(path, err));
};
const toString = constant('val');
return {
extract,
toString
};
};
const anyValue$1 = value(SimpleResult.svalue);
const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
const fallbackAccess = (obj, key, fallback, bundle) => {
const v = get$a(obj, key).getOrThunk(() => fallback(obj));
return bundle(v);
};
const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
const optionDefaultedAccess = (obj, key, fallback, bundle) => {
const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val);
return bundle(opt);
};
const extractField = (field, path, obj, key, prop) => {
const bundle = av => prop.extract(path.concat([key]), av);
const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
const result = prop.extract(path.concat([key]), ov);
return SimpleResult.map(result, Optional.some);
});
switch (field.tag) {
case 'required':
return requiredAccess(path, obj, key, bundle);
case 'defaultedThunk':
return fallbackAccess(obj, key, field.process, bundle);
case 'option':
return optionAccess(obj, key, bundleAsOption);
case 'defaultedOptionThunk':
return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
case 'mergeWithThunk': {
return fallbackAccess(obj, key, constant({}), v => {
const result = deepMerge(field.process(obj), v);
return bundle(result);
});
}
}
};
const extractFields = (path, obj, fields) => {
const success = {};
const errors = [];
for (const field of fields) {
fold(field, (key, newKey, presence, prop) => {
const result = extractField(presence, path, obj, key, prop);
SimpleResult.fold(result, err => {
errors.push(...err);
}, res => {
success[newKey] = res;
});
}, (newKey, instantiator) => {
success[newKey] = instantiator(obj);
});
}
return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
};
const objOf = values => {
const extract = (path, o) => extractFields(path, o, values);
const toString = () => {
const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
return 'obj{\n' + fieldStrings.join('\n') + '}';
};
return {
extract,
toString
};
};
const arrOf = prop => {
const extract = (path, array) => {
const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
return ResultCombine.consolidateArr(results);
};
const toString = () => 'array(' + prop.toString() + ')';
return {
extract,
toString
};
};
const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
const extractValue = (label, prop, obj) => {
const res = prop.extract([label], obj);
return SimpleResult.mapError(res, errs => ({
input: obj,
errors: errs
}));
};
const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
const formatError = errInfo => {
return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
};
const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
const anyValue = constant(anyValue$1);
const typedValue = (validator, expectedType) => value(a => {
const actualType = typeof a;
return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
});
const number = typedValue(isNumber, 'number');
const string = typedValue(isString, 'string');
const boolean = typedValue(isBoolean, 'boolean');
const functionProcessor = typedValue(isFunction, 'function');
const field = field$1;
const customField = customField$1;
const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
const requiredOf = (key, schema) => field(key, key, required(), schema);
const requiredString = key => requiredOf(key, string);
const requiredFunction = key => requiredOf(key, functionProcessor);
const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
const optionOf = (key, schema) => field(key, key, asOption(), schema);
const optionString = key => optionOf(key, string);
const optionFunction = key => optionOf(key, functionProcessor);
const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
const type = requiredString('type');
const fetch$1 = requiredFunction('fetch');
const onAction = requiredFunction('onAction');
const onSetup = defaultedFunction('onSetup', () => noop);
const optionalText = optionString('text');
const optionalIcon = optionString('icon');
const optionalTooltip = optionString('tooltip');
const optionalLabel = optionString('label');
const active = defaultedBoolean('active', false);
const enabled = defaultedBoolean('enabled', true);
const primary = defaultedBoolean('primary', false);
const defaultedColumns = num => defaulted('columns', num);
const defaultedType = type => defaultedString('type', type);
const autocompleterSchema = objOf([
type,
requiredString('trigger'),
defaultedNumber('minChars', 1),
defaultedColumns(1),
defaultedNumber('maxResults', 10),
optionFunction('matches'),
fetch$1,
onAction,
defaultedArrayOf('highlightOn', [], string)
]);
const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, spec);
const baseToolbarButtonFields = [
enabled,
optionalTooltip,
optionalIcon,
optionalText,
onSetup
];
const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
const contextBarFields = [
defaultedFunction('predicate', never),
defaultedStringEnum('scope', 'node', [
'node',
'editor'
]),
defaultedStringEnum('position', 'selection', [
'node',
'selection',
'line'
])
];
const contextButtonFields = baseToolbarButtonFields.concat([
defaultedType('contextformbutton'),
primary,
onAction,
customField('original', identity)
]);
const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
defaultedType('contextformbutton'),
primary,
onAction,
customField('original', identity)
]);
const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
const toggleOrNormal = choose('type', {
contextformbutton: contextButtonFields,
contextformtogglebutton: contextToggleButtonFields
});
objOf([
defaultedType('contextform'),
defaultedFunction('initValue', constant('')),
optionalLabel,
requiredArrayOf('commands', toggleOrNormal),
optionOf('launch', choose('type', {
contextformbutton: launchButtonFields,
contextformtogglebutton: launchToggleButtonFields
}))
].concat(contextBarFields));
const register$2 = editor => {
const popups = editor.ui.registry.getAll().popups;
const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => {
throw new Error(formatError(err));
}, identity));
const triggers = stringArray(mapToArray(dataset, v => v.trigger));
const datasetValues = values(dataset);
const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger);
return {
dataset,
triggers,
lookupByTrigger
};
};
const setupEditorInput = (editor, api) => {
const update = last(api.load, 50);
editor.on('input', e => {
if (e.inputType === 'insertCompositionText' && !editor.composing) {
return;
}
update.throttle();
});
editor.on('keydown', e => {
const keyCode = e.which;
if (keyCode === 8) {
update.throttle();
} else if (keyCode === 27) {
update.cancel();
api.cancelIfNecessary();
} else if (keyCode === 38 || keyCode === 40) {
update.cancel();
}
}, true);
editor.on('remove', update.cancel);
};
const setup$k = editor => {
const activeAutocompleter = value$2();
const uiActive = Cell(false);
const isActive = activeAutocompleter.isSet;
const cancelIfNecessary = () => {
if (isActive()) {
fireAutocompleterEnd(editor);
uiActive.set(false);
activeAutocompleter.clear();
}
};
const commenceIfNecessary = context => {
if (!isActive()) {
activeAutocompleter.set({
trigger: context.trigger,
matchLength: context.text.length
});
}
};
const getAutocompleters = cached(() => register$2(editor));
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));
const load = fetchOptions => {
doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => {
commenceIfNecessary(lookupInfo.context);
lookupInfo.lookupData.then(lookupData => {
activeAutocompleter.get().map(ac => {
const context = lookupInfo.context;
if (ac.trigger !== context.trigger) {
return;
}
activeAutocompleter.set({
...ac,
matchLength: context.text.length
});
if (uiActive.get()) {
fireAutocompleterUpdateActiveRange(editor, { range: context.range });
fireAutocompleterUpdate(editor, { lookupData });
} else {
uiActive.set(true);
fireAutocompleterUpdateActiveRange(editor, { range: context.range });
fireAutocompleterStart(editor, { lookupData });
}
});
});
});
};
const isRangeInsideOrEqual = (innerRange, outerRange) => {
const startComparison = innerRange.compareBoundaryPoints(window.Range.START_TO_START, outerRange);
const endComparison = innerRange.compareBoundaryPoints(window.Range.END_TO_END, outerRange);
return startComparison >= 0 && endComparison <= 0;
};
const readActiveRange = () => {
return activeAutocompleter.get().bind(({trigger}) => {
const selRange = editor.selection.getRng();
return getContext(editor.dom, selRange, trigger, uiActive.get()).filter(({range}) => isRangeInsideOrEqual(selRange, range)).map(({range}) => range);
});
};
editor.addCommand('mceAutocompleterReload', (_ui, value) => {
const fetchOptions = isObject(value) ? value.fetchOptions : {};
load(fetchOptions);
});
editor.addCommand('mceAutocompleterClose', cancelIfNecessary);
editor.addCommand('mceAutocompleterRefreshActiveRange', () => {
readActiveRange().each(range => {
fireAutocompleterUpdateActiveRange(editor, { range });
});
});
editor.editorCommands.addQueryStateHandler('mceAutoCompleterInRange', () => readActiveRange().isSome());
setupEditorInput(editor, {
cancelIfNecessary,
load
});
};
const browser$1 = detect$1().browser;
const isSafari = browser$1.isSafari();
const emptyNodeContents = node => fillWithPaddingBr(SugarElement.fromDom(node));
const isEntireNodeSelected = (rng, node) => {
var _a;
return rng.startOffset === 0 && rng.endOffset === ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length);
};
const getParentDetailsElementAtPos = (dom, pos) => Optional.from(dom.getParent(pos.container(), 'details'));
const isInDetailsElement = (dom, pos) => getParentDetailsElementAtPos(dom, pos).isSome();
const getDetailsElements = (dom, rng) => {
const startDetails = Optional.from(dom.getParent(rng.startContainer, 'details'));
const endDetails = Optional.from(dom.getParent(rng.endContainer, 'details'));
if (startDetails.isSome() || endDetails.isSome()) {
const startSummary = startDetails.bind(details => Optional.from(dom.select('summary', details)[0]));
return Optional.some({
startSummary,
startDetails,
endDetails
});
} else {
return Optional.none();
}
};
const isCaretInTheBeginningOf = (caretPos, element) => firstPositionIn(element).exists(pos => pos.isEqual(caretPos));
const isCaretInTheEndOf = (caretPos, element) => {
return lastPositionIn(element).exists(pos => {
if (isBr$6(pos.getNode())) {
return prevPosition(element, pos).exists(pos2 => pos2.isEqual(caretPos)) || pos.isEqual(caretPos);
} else {
return pos.isEqual(caretPos);
}
});
};
const isCaretAtStartOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheBeginningOf(caretPos, summary));
const isCaretAtEndOfSummary = (caretPos, detailsElements) => detailsElements.startSummary.exists(summary => isCaretInTheEndOf(caretPos, summary));
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()))));
const isCaretInLastPositionInBody = (root, caretPos, detailsElements) => detailsElements.startDetails.exists(details => nextPosition(root, caretPos).forall(pos => !details.contains(pos.container())));
const setCaretToPosition = (editor, position) => {
const node = position.getNode();
if (!isUndefined(node)) {
editor.selection.setCursorLocation(node, position.offset());
}
};
const moveCaretToDetailsPos = (editor, pos, forward) => {
const details = editor.dom.getParent(pos.container(), 'details');
if (details && !details.open) {
const summary = editor.dom.select('summary', details)[0];
if (summary) {
const newPos = forward ? firstPositionIn(summary) : lastPositionIn(summary);
newPos.each(pos => setCaretToPosition(editor, pos));
}
} else {
setCaretToPosition(editor, pos);
}
};
const isPartialDelete = (rng, detailsElements) => {
const containsStart = element => element.contains(rng.startContainer);
const containsEnd = element => element.contains(rng.endContainer);
const startInSummary = detailsElements.startSummary.exists(containsStart);
const endInSummary = detailsElements.startSummary.exists(containsEnd);
const isPartiallySelectedDetailsElements = detailsElements.startDetails.forall(startDetails => detailsElements.endDetails.forall(endDetails => startDetails !== endDetails));
const isInPartiallySelectedSummary = (startInSummary || endInSummary) && !(startInSummary && endInSummary);
return isInPartiallySelectedSummary || isPartiallySelectedDetailsElements;
};
const shouldPreventDeleteIntoDetails = (editor, forward, granularity) => {
const {dom, selection} = editor;
const root = editor.getBody();
if (granularity === 'character') {
const caretPos = CaretPosition.fromRangeStart(selection.getRng());
const parentBlock = dom.getParent(caretPos.container(), dom.isBlock);
const parentDetailsAtCaret = getParentDetailsElementAtPos(dom, caretPos);
const inEmptyParentBlock = parentBlock && dom.isEmpty(parentBlock);
const isFirstBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.previousSibling);
const isLastBlock = isNull(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.nextSibling);
if (inEmptyParentBlock) {
const firstOrLast = forward ? isLastBlock : isFirstBlock;
if (firstOrLast) {
const isBeforeAfterDetails = navigate(!forward, root, caretPos).exists(pos => {
return isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, getParentDetailsElementAtPos(dom, pos));
});
if (isBeforeAfterDetails) {
return true;
}
}
}
return navigate(forward, root, caretPos).fold(never, pos => {
const parentDetailsAtNewPos = getParentDetailsElementAtPos(dom, pos);
if (isInDetailsElement(dom, pos) && !equals(parentDetailsAtCaret, parentDetailsAtNewPos)) {
if (!forward) {
moveCaretToDetailsPos(editor, pos, false);
}
if (parentBlock && inEmptyParentBlock) {
if (forward && isFirstBlock) {
return true;
} else if (!forward && isLastBlock) {
return true;
}
moveCaretToDetailsPos(editor, pos, forward);
editor.dom.remove(parentBlock);
}
return true;
} else {
return false;
}
});
} else {
return false;
}
};
const shouldPreventDeleteSummaryAction = (editor, detailElements, forward, granularity) => {
const selection = editor.selection;
const rng = selection.getRng();
const caretPos = CaretPosition.fromRangeStart(rng);
const root = editor.getBody();
if (granularity === 'selection') {
return isPartialDelete(rng, detailElements);
} else if (forward) {
return isCaretAtEndOfSummary(caretPos, detailElements) || isCaretInLastPositionInBody(root, caretPos, detailElements);
} else {
return isCaretAtStartOfSummary(caretPos, detailElements) || isCaretInFirstPositionInBody(caretPos, detailElements);
}
};
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));
const handleDeleteActionSafari = (editor, forward, granularity) => {
const selection = editor.selection;
const node = selection.getNode();
const rng = selection.getRng();
const caretPos = CaretPosition.fromRangeStart(rng);
if (isSummary$1(node)) {
if (granularity === 'selection' && isEntireNodeSelected(rng, node) || willDeleteLastPositionInElement(forward, caretPos, node)) {
emptyNodeContents(node);
} else {
editor.undoManager.transact(() => {
const sel = selection.getSel();
let {anchorNode, anchorOffset, focusNode, focusOffset} = sel !== null && sel !== void 0 ? sel : {};
const applySelection = () => {
if (isNonNullable(anchorNode) && isNonNullable(anchorOffset) && isNonNullable(focusNode) && isNonNullable(focusOffset)) {
sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
}
};
const updateSelection = () => {
anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
anchorOffset = sel === null || sel === void 0 ? void 0 : sel.anchorOffset;
focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
focusOffset = sel === null || sel === void 0 ? void 0 : sel.focusOffset;
};
const appendAllChildNodes = (from, to) => {
each$e(from.childNodes, child => {
if (isNode(child)) {
to.appendChild(child);
}
});
};
const container = editor.dom.create('span', { 'data-mce-bogus': '1' });
appendAllChildNodes(node, container);
node.appendChild(container);
applySelection();
if (granularity === 'word' || granularity === 'line') {
sel === null || sel === void 0 ? void 0 : sel.modify('extend', forward ? 'right' : 'left', granularity);
}
if (!selection.isCollapsed() && isEntireNodeSelected(selection.getRng(), container)) {
emptyNodeContents(node);
} else {
editor.execCommand(forward ? 'ForwardDelete' : 'Delete');
updateSelection();
appendAllChildNodes(container, node);
applySelection();
}
editor.dom.remove(container);
});
}
return true;
} else {
return false;
}
};
const backspaceDelete = (editor, forward, granularity) => shouldPreventDeleteAction(editor, forward, granularity) || isSafari && handleDeleteActionSafari(editor, forward, granularity) ? Optional.some(noop) : Optional.none();
const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => {
const target = editor.getBody();
const overrides = {
bubbles: true,
composed: true,
data: null,
isComposing: false,
detail: 0,
view: null,
target,
currentTarget: target,
eventPhase: Event.AT_TARGET,
originalTarget: target,
explicitOriginalTarget: target,
isTrusted: false,
srcElement: target,
cancelable: false,
preventDefault: noop,
inputType
};
const input = clone$3(new InputEvent(eventType));
return editor.dispatch(eventType, {
...input,
...overrides,
...specifics
});
};
const fireInputEvent = createAndFireInputEvent('input');
const fireBeforeInputEvent = createAndFireInputEvent('beforeinput');
const platform$2 = detect$1();
const os = platform$2.os;
const isMacOSOriOS = os.isMacOS() || os.isiOS();
const browser = platform$2.browser;
const isFirefox = browser.isFirefox();
const executeKeydownOverride$3 = (editor, caret, evt) => {
const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward';
const isCollapsed = editor.selection.isCollapsed();
const unmodifiedGranularity = isCollapsed ? 'character' : 'selection';
const getModifiedGranularity = isWord => {
if (isCollapsed) {
return isWord ? 'word' : 'line';
} else {
return 'selection';
}
};
executeWithDelayedAction([
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$1, editor)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$7, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$7, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$8, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$8, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$4, editor, caret, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$4, editor, caret, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$b, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$b, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete, editor, false, unmodifiedGranularity)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete, editor, true, unmodifiedGranularity)
},
...isMacOSOriOS ? [
{
keyCode: VK.BACKSPACE,
altKey: true,
action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
},
{
keyCode: VK.DELETE,
altKey: true,
action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
},
{
keyCode: VK.BACKSPACE,
metaKey: true,
action: action(backspaceDelete, editor, false, getModifiedGranularity(false))
}
] : [
{
keyCode: VK.BACKSPACE,
ctrlKey: true,
action: action(backspaceDelete, editor, false, getModifiedGranularity(true))
},
{
keyCode: VK.DELETE,
ctrlKey: true,
action: action(backspaceDelete, editor, true, getModifiedGranularity(true))
}
],
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$5, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$5, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$2, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$2, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$9, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$9, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$a, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$a, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$3, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$3, editor, true)
},
{
keyCode: VK.BACKSPACE,
action: action(backspaceDelete$6, editor, false)
},
{
keyCode: VK.DELETE,
action: action(backspaceDelete$6, editor, true)
}
], evt).filter(_ => editor.selection.isEditable()).each(applyAction => {
evt.preventDefault();
const beforeInput = fireBeforeInputEvent(editor, inputType);
if (!beforeInput.isDefaultPrevented()) {
applyAction();
fireInputEvent(editor, inputType);
}
});
};
const executeKeyupOverride = (editor, evt, isBackspaceKeydown) => execute([
{
keyCode: VK.BACKSPACE,
action: action(paddEmptyElement, editor)
},
{
keyCode: VK.DELETE,
action: action(paddEmptyElement, editor)
},
...isMacOSOriOS ? [
{
keyCode: VK.BACKSPACE,
altKey: true,
action: action(refreshCaret, editor)
},
{
keyCode: VK.DELETE,
altKey: true,
action: action(refreshCaret, editor)
},
...isBackspaceKeydown ? [{
keyCode: isFirefox ? 224 : 91,
action: action(refreshCaret, editor)
}] : []
] : [
{
keyCode: VK.BACKSPACE,
ctrlKey: true,
action: action(refreshCaret, editor)
},
{
keyCode: VK.DELETE,
ctrlKey: true,
action: action(refreshCaret, editor)
}
]
], evt);
const setup$j = (editor, caret) => {
let isBackspaceKeydown = false;
editor.on('keydown', evt => {
isBackspaceKeydown = evt.keyCode === VK.BACKSPACE;
if (!evt.isDefaultPrevented()) {
executeKeydownOverride$3(editor, caret, evt);
}
});
editor.on('keyup', evt => {
if (!evt.isDefaultPrevented()) {
executeKeyupOverride(editor, evt, isBackspaceKeydown);
}
isBackspaceKeydown = false;
});
};
const firstNonWhiteSpaceNodeSibling = node => {
while (node) {
if (isElement$6(node) || isText$b(node) && node.data && /[\r\n\s]/.test(node.data)) {
return node;
}
node = node.nextSibling;
}
return null;
};
const moveToCaretPosition = (editor, root) => {
const dom = editor.dom;
const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
if (!root) {
return;
}
if (/^(LI|DT|DD)$/.test(root.nodeName)) {
const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild);
}
}
const rng = dom.createRng();
root.normalize();
if (root.hasChildNodes()) {
const walker = new DomTreeWalker(root, root);
let lastNode = root;
let node;
while (node = walker.current()) {
if (isText$b(node)) {
rng.setStart(node, 0);
rng.setEnd(node, 0);
break;
}
if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
rng.setStartBefore(node);
rng.setEndBefore(node);
break;
}
lastNode = node;
node = walker.next();
}
if (!node) {
rng.setStart(lastNode, 0);
rng.setEnd(lastNode, 0);
}
} else {
if (isBr$6(root)) {
if (root.nextSibling && dom.isBlock(root.nextSibling)) {
rng.setStartBefore(root);
rng.setEndBefore(root);
} else {
rng.setStartAfter(root);
rng.setEndAfter(root);
}
} else {
rng.setStart(root, 0);
rng.setEnd(root, 0);
}
}
editor.selection.setRng(rng);
scrollRangeIntoView(editor, rng);
};
const getEditableRoot = (dom, node) => {
const root = dom.getRoot();
let editableRoot;
let parent = node;
while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') {
if (dom.getContentEditable(parent) === 'true') {
editableRoot = parent;
break;
}
parent = parent.parentNode;
}
return parent !== root ? editableRoot : root;
};
const getParentBlock$1 = editor => {
return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
};
const getParentBlockName = editor => {
return getParentBlock$1(editor).fold(constant(''), parentBlock => {
return parentBlock.nodeName.toUpperCase();
});
};
const isListItemParentBlock = editor => {
return getParentBlock$1(editor).filter(elm => {
return isListItem$1(SugarElement.fromDom(elm));
}).isSome();
};
const emptyBlock = elm => {
elm.innerHTML = '
';
};
const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
const dom = editor.dom;
Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => {
const currentStyles = getAllRaw(SugarElement.fromDom(node));
const newStyles = {
...currentStyles,
...attrStyles
};
dom.setStyles(node, newStyles);
});
const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/));
const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== ''));
lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz));
const newClasses = [
...attrClasses,
...filteredClasses
];
dom.setAttrib(node, 'class', newClasses.join(' '));
});
const appliedAttrs = [
'style',
'class'
];
const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
dom.setAttribs(node, remainingAttrs);
};
const setForcedBlockAttrs = (editor, node) => {
const forcedRootBlockName = getForcedRootBlock(editor);
if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
applyAttributes(editor, node, forcedRootBlockAttrs);
}
};
const createNewBlock = (editor, container, parentBlock, editableRoot, keepStyles = true, name, styles) => {
const dom = editor.dom;
const schema = editor.schema;
const newBlockName = getForcedRootBlock(editor);
const parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
let node = container;
const textInlineElements = schema.getTextInlineElements();
let block;
if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
block = dom.create(name || newBlockName, styles || {});
} else {
block = parentBlock.cloneNode(false);
}
let caretNode = block;
if (!keepStyles) {
dom.setAttrib(block, 'style', null);
dom.setAttrib(block, 'class', null);
} else {
do {
if (textInlineElements[node.nodeName]) {
if (isCaretNode(node) || isBookmarkNode$1(node)) {
continue;
}
const clonedNode = node.cloneNode(false);
dom.setAttrib(clonedNode, 'id', '');
if (block.hasChildNodes()) {
clonedNode.appendChild(block.firstChild);
block.appendChild(clonedNode);
} else {
caretNode = clonedNode;
block.appendChild(clonedNode);
}
}
} while ((node = node.parentNode) && node !== editableRoot);
}
setForcedBlockAttrs(editor, block);
emptyBlock(caretNode);
return block;
};
const getDetailsRoot = (editor, element) => editor.dom.getParent(element, isDetails);
const isAtDetailsEdge = (root, element, isTextBlock) => {
let node = element;
while (node && node !== root && isNull(node.nextSibling)) {
const parent = node.parentElement;
if (!parent || !isTextBlock(parent)) {
return isDetails(parent);
}
node = parent;
}
return false;
};
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()));
const insertNewLine = (editor, createNewBlock, parentBlock) => {
var _a, _b, _c;
const newBlock = createNewBlock(getForcedRootBlock(editor));
const root = getDetailsRoot(editor, parentBlock);
if (!root) {
return;
}
editor.dom.insertAfter(newBlock, root);
moveToCaretPosition(editor, newBlock);
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) {
editor.dom.remove(parentBlock);
}
};
const hasFirstChild = (elm, name) => {
return elm.firstChild && elm.firstChild.nodeName === name;
};
const isFirstChild = elm => {
var _a;
return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
};
const hasParent = (elm, parentName) => {
const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode;
return isNonNullable(parentNode) && parentNode.nodeName === parentName;
};
const isListBlock = elm => {
return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName);
};
const isListItem = elm => {
return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName);
};
const isNestedList = elm => {
return isListBlock(elm) && isListBlock(elm.parentNode);
};
const getContainerBlock = containerBlock => {
const containerBlockParent = containerBlock.parentNode;
return isListItem(containerBlockParent) ? containerBlockParent : containerBlock;
};
const isFirstOrLastLi = (containerBlock, parentBlock, first) => {
let node = containerBlock[first ? 'firstChild' : 'lastChild'];
while (node) {
if (isElement$6(node)) {
break;
}
node = node[first ? 'nextSibling' : 'previousSibling'];
}
return node === parentBlock;
};
const getStyles = elm => foldl(mapToArray(getAllRaw(SugarElement.fromDom(elm)), (style, styleName) => `${ styleName }: ${ style };`), (acc, s) => acc + s, '');
const insert$4 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
const dom = editor.dom;
const rng = editor.selection.getRng();
const containerParent = containerBlock.parentNode;
if (containerBlock === editor.getBody() || !containerParent) {
return;
}
if (isNestedList(containerBlock)) {
newBlockName = 'LI';
}
const parentBlockStyles = isListItem(parentBlock) ? getStyles(parentBlock) : undefined;
let newBlock = isListItem(parentBlock) && parentBlockStyles ? createNewBlock(newBlockName, { style: getStyles(parentBlock) }) : createNewBlock(newBlockName);
if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
if (hasParent(containerBlock, 'LI')) {
const containerBlockParent = getContainerBlock(containerBlock);
dom.insertAfter(newBlock, containerBlockParent);
if (isFirstChild(containerBlock)) {
dom.remove(containerBlockParent);
} else {
dom.remove(containerBlock);
}
} else {
dom.replace(newBlock, containerBlock);
}
} else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
if (hasParent(containerBlock, 'LI')) {
dom.insertAfter(newBlock, getContainerBlock(containerBlock));
newBlock.appendChild(dom.doc.createTextNode(' '));
newBlock.appendChild(containerBlock);
} else {
containerParent.insertBefore(newBlock, containerBlock);
}
dom.remove(parentBlock);
} else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
dom.insertAfter(newBlock, getContainerBlock(containerBlock));
dom.remove(parentBlock);
} else {
containerBlock = getContainerBlock(containerBlock);
const tmpRng = rng.cloneRange();
tmpRng.setStartAfter(parentBlock);
tmpRng.setEndAfter(containerBlock);
const fragment = tmpRng.extractContents();
if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
const previousChildren = filter$5(map$3(newBlock.children, SugarElement.fromDom), not(isTag('br')));
newBlock = fragment.firstChild;
dom.insertAfter(fragment, containerBlock);
each$e(previousChildren, child => prepend(SugarElement.fromDom(newBlock), child));
if (parentBlockStyles) {
newBlock.setAttribute('style', parentBlockStyles);
}
} else {
dom.insertAfter(fragment, containerBlock);
dom.insertAfter(newBlock, containerBlock);
}
dom.remove(parentBlock);
}
moveToCaretPosition(editor, newBlock);
};
const trimZwsp = fragment => {
each$e(descendants$1(SugarElement.fromDom(fragment), isText$c), text => {
const rawNode = text.dom;
rawNode.nodeValue = trim$2(rawNode.data);
});
};
const isWithinNonEditableList = (editor, node) => {
const parentList = editor.dom.getParent(node, 'ol,ul,dl');
return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false';
};
const isEmptyAnchor = (dom, elm) => {
return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
};
const containerAndSiblingName = (container, nodeName) => {
return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
};
const canSplitBlock = (dom, node) => {
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';
};
const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => {
var _a;
const firstChilds = [];
if (!block) {
return;
}
let currentNode = block;
while (currentNode = currentNode.firstChild) {
if (dom.isBlock(currentNode)) {
return;
}
if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) {
firstChilds.push(currentNode);
}
}
let i = firstChilds.length;
while (i--) {
currentNode = firstChilds[i];
if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') {
dom.remove(currentNode);
} else {
if (isEmptyAnchor(dom, currentNode)) {
dom.remove(currentNode);
}
}
}
};
const normalizeZwspOffset = (start, container, offset) => {
if (!isText$b(container)) {
return offset;
} else if (start) {
return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
} else {
return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
}
};
const includeZwspInRange = rng => {
const newRng = rng.cloneRange();
newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
return newRng;
};
const trimLeadingLineBreaks = node => {
let currentNode = node;
do {
if (isText$b(currentNode)) {
currentNode.data = currentNode.data.replace(/^[\r\n]+/, '');
}
currentNode = currentNode.firstChild;
} while (currentNode);
};
const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
var _a, _b;
const dom = editor.dom;
const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot();
let parentBlock = dom.getParent(container, dom.isBlock);
if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
parentBlock = parentBlock || editableRoot;
if (!parentBlock.hasChildNodes()) {
const newBlock = dom.create(newBlockName);
setForcedBlockAttrs(editor, newBlock);
parentBlock.appendChild(newBlock);
rng.setStart(newBlock, 0);
rng.setEnd(newBlock, 0);
return newBlock;
}
let node = container;
while (node && node.parentNode !== parentBlock) {
node = node.parentNode;
}
let startNode;
while (node && !dom.isBlock(node)) {
startNode = node;
node = node.previousSibling;
}
const startNodeName = (_b = startNode === null || startNode === void 0 ? void 0 : startNode.parentElement) === null || _b === void 0 ? void 0 : _b.nodeName;
if (startNode && startNodeName && editor.schema.isValidChild(startNodeName, newBlockName.toLowerCase())) {
const startNodeParent = startNode.parentNode;
const newBlock = dom.create(newBlockName);
setForcedBlockAttrs(editor, newBlock);
startNodeParent.insertBefore(newBlock, startNode);
node = startNode;
while (node && !dom.isBlock(node)) {
const next = node.nextSibling;
newBlock.appendChild(node);
node = next;
}
rng.setStart(container, offset);
rng.setEnd(container, offset);
}
}
return container;
};
const addBrToBlockIfNeeded = (dom, block) => {
block.normalize();
const lastChild = block.lastChild;
if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
dom.add(block, 'br');
}
};
const shouldEndContainer = (editor, container) => {
const optionValue = shouldEndContainerOnEmptyBlock(editor);
if (isNullable(container)) {
return false;
} else if (isString(optionValue)) {
return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
} else {
return optionValue;
}
};
const insert$3 = (editor, evt) => {
let container;
let offset;
let parentBlockName;
let containerBlock;
let isAfterLastNodeInContainer = false;
const dom = editor.dom;
const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
const rng = editor.selection.getRng();
const newBlockName = getForcedRootBlock(editor);
const start = SugarElement.fromDom(rng.startContainer);
const child = child$1(start, rng.startOffset);
const isCef = child.exists(element => isHTMLElement$1(element) && !isEditable$2(element));
const collapsedAndCef = rng.collapsed && isCef;
const createNewBlock$1 = (name, styles) => {
return createNewBlock(editor, container, parentBlock, editableRoot, shouldKeepStyles(editor), name, styles);
};
const isCaretAtStartOrEndOfBlock = start => {
const normalizedOffset = normalizeZwspOffset(start, container, offset);
if (isText$b(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) {
return false;
}
if ((container.parentNode === parentBlock || container === parentBlock) && isAfterLastNodeInContainer && !start) {
return true;
}
if (start && isElement$6(container) && container === parentBlock.firstChild) {
return true;
}
if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
}
const walker = new DomTreeWalker(container, parentBlock);
if (isText$b(container)) {
if (start && normalizedOffset === 0) {
walker.prev();
} else if (!start && normalizedOffset === container.data.length) {
walker.next();
}
}
let node;
while (node = walker.current()) {
if (isElement$6(node)) {
if (!node.getAttribute('data-mce-bogus')) {
const name = node.nodeName.toLowerCase();
if (nonEmptyElementsMap[name] && name !== 'br') {
return false;
}
}
} else if (isText$b(node) && !isWhitespaceText(node.data)) {
return false;
}
if (start) {
walker.prev();
} else {
walker.next();
}
}
return true;
};
const insertNewBlockAfter = () => {
let block;
if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
block = createNewBlock$1(newBlockName);
} else {
block = createNewBlock$1();
}
if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock, undefined, { includeZwsp: true })) {
block = dom.split(containerBlock, parentBlock);
} else {
dom.insertAfter(block, parentBlock);
}
moveToCaretPosition(editor, block);
return block;
};
normalize$2(dom, rng).each(normRng => {
rng.setStart(normRng.startContainer, normRng.startOffset);
rng.setEnd(normRng.endContainer, normRng.endOffset);
});
container = rng.startContainer;
offset = rng.startOffset;
const shiftKey = !!(evt && evt.shiftKey);
const ctrlKey = !!(evt && evt.ctrlKey);
if (isElement$6(container) && container.hasChildNodes() && !collapsedAndCef) {
isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
if (isAfterLastNodeInContainer && isText$b(container)) {
offset = container.data.length;
} else {
offset = 0;
}
}
const editableRoot = getEditableRoot(dom, container);
if (!editableRoot || isWithinNonEditableList(editor, container)) {
return;
}
if (!shiftKey) {
container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
}
let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot();
containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
if (containerBlockName === 'LI' && !ctrlKey) {
const liBlock = containerBlock;
parentBlock = liBlock;
containerBlock = liBlock.parentNode;
parentBlockName = containerBlockName;
}
if (isElement$6(containerBlock) && isLastEmptyBlockInDetails(editor, shiftKey, parentBlock)) {
return insertNewLine(editor, createNewBlock$1, parentBlock);
}
if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) {
if (dom.isEmpty(parentBlock)) {
insert$4(editor, createNewBlock$1, containerBlock, parentBlock, newBlockName);
return;
}
}
if (!collapsedAndCef && (parentBlock === editor.getBody() || !canSplitBlock(dom, parentBlock))) {
return;
}
const parentBlockParent = parentBlock.parentNode;
let newBlock;
if (collapsedAndCef) {
newBlock = createNewBlock$1(newBlockName);
child.fold(() => {
append$1(start, SugarElement.fromDom(newBlock));
}, child => {
before$3(child, SugarElement.fromDom(newBlock));
});
editor.selection.setCursorLocation(newBlock, 0);
} else if (isCaretContainerBlock$1(parentBlock)) {
newBlock = showCaretContainerBlock(parentBlock);
if (dom.isEmpty(parentBlock)) {
emptyBlock(parentBlock);
}
setForcedBlockAttrs(editor, newBlock);
moveToCaretPosition(editor, newBlock);
} else if (isCaretAtStartOrEndOfBlock(false)) {
newBlock = insertNewBlockAfter();
} else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) {
const caretPos = CaretPosition.fromRangeStart(rng);
const afterTable = isAfterTable(caretPos);
const parentBlockSugar = SugarElement.fromDom(parentBlock);
const afterBr = isAfterBr(parentBlockSugar, caretPos, editor.schema);
const prevBrOpt = afterBr ? findPreviousBr(parentBlockSugar, caretPos, editor.schema).bind(pos => Optional.from(pos.getNode())) : Optional.none();
newBlock = parentBlockParent.insertBefore(createNewBlock$1(), parentBlock);
const root = containerAndSiblingName(parentBlock, 'HR') || afterTable ? newBlock : prevBrOpt.getOr(parentBlock);
moveToCaretPosition(editor, root);
} else {
const tmpRng = includeZwspInRange(rng).cloneRange();
tmpRng.setEndAfter(parentBlock);
const fragment = tmpRng.extractContents();
trimZwsp(fragment);
trimLeadingLineBreaks(fragment);
newBlock = fragment.firstChild;
dom.insertAfter(fragment, parentBlock);
trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
addBrToBlockIfNeeded(dom, parentBlock);
if (dom.isEmpty(parentBlock)) {
emptyBlock(parentBlock);
}
newBlock.normalize();
if (dom.isEmpty(newBlock)) {
dom.remove(newBlock);
insertNewBlockAfter();
} else {
setForcedBlockAttrs(editor, newBlock);
moveToCaretPosition(editor, newBlock);
}
}
dom.setAttrib(newBlock, 'id', '');
editor.dispatch('NewBlock', { newBlock });
};
const fakeEventName$1 = 'insertParagraph';
const blockbreak = {
insert: insert$3,
fakeEventName: fakeEventName$1
};
const hasRightSideContent = (schema, container, parentBlock) => {
const walker = new DomTreeWalker(container, parentBlock);
let node;
const nonEmptyElementsMap = schema.getNonEmptyElements();
while (node = walker.next()) {
if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$b(node) && node.length > 0) {
return true;
}
}
return false;
};
const moveSelectionToBr = (editor, brElm, extraBr) => {
const rng = editor.dom.createRng();
if (!extraBr) {
rng.setStartAfter(brElm);
rng.setEndAfter(brElm);
} else {
rng.setStartBefore(brElm);
rng.setEndBefore(brElm);
}
editor.selection.setRng(rng);
scrollRangeIntoView(editor, rng);
};
const insertBrAtCaret = (editor, evt) => {
const selection = editor.selection;
const dom = editor.dom;
const rng = selection.getRng();
let brElm;
let extraBr = false;
normalize$2(dom, rng).each(normRng => {
rng.setStart(normRng.startContainer, normRng.startOffset);
rng.setEnd(normRng.endContainer, normRng.endOffset);
});
let offset = rng.startOffset;
let container = rng.startContainer;
if (isElement$6(container) && container.hasChildNodes()) {
const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
if (isAfterLastNodeInContainer && isText$b(container)) {
offset = container.data.length;
} else {
offset = 0;
}
}
let parentBlock = dom.getParent(container, dom.isBlock);
const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
const isControlKey = !!(evt && evt.ctrlKey);
if (containerBlockName === 'LI' && !isControlKey) {
parentBlock = containerBlock;
}
if (isText$b(container) && offset >= container.data.length) {
if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) {
brElm = dom.create('br');
rng.insertNode(brElm);
rng.setStartAfter(brElm);
rng.setEndAfter(brElm);
extraBr = true;
}
}
brElm = dom.create('br');
rangeInsertNode(dom, rng, brElm);
moveSelectionToBr(editor, brElm, extraBr);
editor.undoManager.add();
};
const insertBrBefore = (editor, inline) => {
const br = SugarElement.fromTag('br');
before$3(SugarElement.fromDom(inline), br);
editor.undoManager.add();
};
const insertBrAfter = (editor, inline) => {
if (!hasBrAfter(editor.getBody(), inline)) {
after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br'));
}
const br = SugarElement.fromTag('br');
after$4(SugarElement.fromDom(inline), br);
moveSelectionToBr(editor, br.dom, false);
editor.undoManager.add();
};
const isBeforeBr = pos => {
return isBr$6(pos.getNode());
};
const hasBrAfter = (rootNode, startNode) => {
if (isBeforeBr(CaretPosition.after(startNode))) {
return true;
} else {
return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => {
return isBr$6(pos.getNode());
}).getOr(false);
}
};
const isAnchorLink = elm => {
return elm && elm.nodeName === 'A' && 'href' in elm;
};
const isInsideAnchor = location => {
return location.fold(never, isAnchorLink, isAnchorLink, never);
};
const readInlineAnchorLocation = editor => {
const isInlineTarget$1 = curry(isInlineTarget, editor);
const position = CaretPosition.fromRangeStart(editor.selection.getRng());
return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
};
const insertBrOutsideAnchor = (editor, location) => {
location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
};
const insert$2 = (editor, evt) => {
const anchorLocation = readInlineAnchorLocation(editor);
if (anchorLocation.isSome()) {
anchorLocation.each(curry(insertBrOutsideAnchor, editor));
} else {
insertBrAtCaret(editor, evt);
}
};
const fakeEventName = 'insertLineBreak';
const linebreak = {
insert: insert$2,
fakeEventName
};
const matchesSelector = (editor, selector) => {
return getParentBlock$1(editor).filter(parentBlock => {
return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
}).isSome();
};
const shouldInsertBr = editor => {
return matchesSelector(editor, getBrNewLineSelector(editor));
};
const shouldBlockNewLine$1 = editor => {
return matchesSelector(editor, getNoNewLineSelector(editor));
};
const newLineAction = Adt.generate([
{ br: [] },
{ block: [] },
{ none: [] }
]);
const shouldBlockNewLine = (editor, _shiftKey) => {
return shouldBlockNewLine$1(editor);
};
const inListBlock = requiredState => {
return (editor, _shiftKey) => {
return isListItemParentBlock(editor) === requiredState;
};
};
const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
const state = getParentBlockName(editor) === blockName.toUpperCase();
return state === requiredState;
};
const inCefBlock = editor => {
const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart());
return isNullable(editableRoot);
};
const inPreBlock = requiredState => inBlock('pre', requiredState);
const inSummaryBlock = () => inBlock('summary', true);
const shouldPutBrInPre = requiredState => {
return (editor, _shiftKey) => {
return shouldPutBrInPre$1(editor) === requiredState;
};
};
const inBrContext = (editor, _shiftKey) => {
return shouldInsertBr(editor);
};
const hasShiftKey = (_editor, shiftKey) => {
return shiftKey;
};
const canInsertIntoEditableRoot = editor => {
const forcedRootBlock = getForcedRootBlock(editor);
const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart());
return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
};
const isInRootWithEmptyOrCEF = editor => {
const rng = editor.selection.getRng();
const start = SugarElement.fromDom(rng.startContainer);
const child = child$1(start, rng.startOffset);
const isCefOpt = child.map(element => isHTMLElement$1(element) && !isEditable$2(element));
return rng.collapsed && isCefOpt.getOr(true);
};
const match = (predicates, action) => {
return (editor, shiftKey) => {
const isMatch = foldl(predicates, (res, p) => {
return res && p(editor, shiftKey);
}, true);
return isMatch ? Optional.some(action) : Optional.none();
};
};
const getAction = (editor, evt) => {
return evaluateUntil([
match([shouldBlockNewLine], newLineAction.none()),
match([
inPreBlock(true),
inCefBlock
], newLineAction.none()),
match([inSummaryBlock()], newLineAction.br()),
match([
inPreBlock(true),
shouldPutBrInPre(false),
hasShiftKey
], newLineAction.br()),
match([
inPreBlock(true),
shouldPutBrInPre(false)
], newLineAction.block()),
match([
inPreBlock(true),
shouldPutBrInPre(true),
hasShiftKey
], newLineAction.block()),
match([
inPreBlock(true),
shouldPutBrInPre(true)
], newLineAction.br()),
match([
inListBlock(true),
hasShiftKey
], newLineAction.br()),
match([inListBlock(true)], newLineAction.block()),
match([inBrContext], newLineAction.br()),
match([hasShiftKey], newLineAction.br()),
match([canInsertIntoEditableRoot], newLineAction.block()),
match([isInRootWithEmptyOrCEF], newLineAction.block())
], [
editor,
!!(evt && evt.shiftKey)
]).getOr(newLineAction.none());
};
const insertBreak = (breakType, editor, evt) => {
if (!editor.selection.isCollapsed()) {
execEditorDeleteCommand(editor);
}
if (isNonNullable(evt)) {
const event = fireBeforeInputEvent(editor, breakType.fakeEventName);
if (event.isDefaultPrevented()) {
return;
}
}
breakType.insert(editor, evt);
if (isNonNullable(evt)) {
fireInputEvent(editor, breakType.fakeEventName);
}
};
const insert$1 = (editor, evt) => {
const br = () => insertBreak(linebreak, editor, evt);
const block = () => insertBreak(blockbreak, editor, evt);
const logicalAction = getAction(editor, evt);
switch (getNewlineBehavior(editor)) {
case 'linebreak':
logicalAction.fold(br, br, noop);
break;
case 'block':
logicalAction.fold(block, block, noop);
break;
case 'invert':
logicalAction.fold(block, br, noop);
break;
default:
logicalAction.fold(br, block, noop);
break;
}
};
const platform$1 = detect$1();
const isIOSSafari = platform$1.os.isiOS() && platform$1.browser.isSafari();
const handleEnterKeyEvent = (editor, event) => {
if (event.isDefaultPrevented()) {
return;
}
event.preventDefault();
endTypingLevelIgnoreLocks(editor.undoManager);
editor.undoManager.transact(() => {
insert$1(editor, event);
});
};
const isCaretAfterKoreanCharacter = rng => {
if (!rng.collapsed) {
return false;
}
const startContainer = rng.startContainer;
if (isText$b(startContainer)) {
const koreanCharRegex = /^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/;
const char = startContainer.data.charAt(rng.startOffset - 1);
return koreanCharRegex.test(char);
} else {
return false;
}
};
const setup$i = editor => {
let iOSSafariKeydownBookmark = Optional.none();
const iOSSafariKeydownOverride = editor => {
iOSSafariKeydownBookmark = Optional.some(editor.selection.getBookmark());
editor.undoManager.add();
};
const iOSSafariKeyupOverride = (editor, event) => {
editor.undoManager.undo();
iOSSafariKeydownBookmark.fold(noop, b => editor.selection.moveToBookmark(b));
handleEnterKeyEvent(editor, event);
iOSSafariKeydownBookmark = Optional.none();
};
editor.on('keydown', event => {
if (event.keyCode === VK.ENTER) {
if (isIOSSafari && isCaretAfterKoreanCharacter(editor.selection.getRng())) {
iOSSafariKeydownOverride(editor);
} else {
handleEnterKeyEvent(editor, event);
}
}
});
editor.on('keyup', event => {
if (event.keyCode === VK.ENTER) {
iOSSafariKeydownBookmark.each(() => iOSSafariKeyupOverride(editor, event));
}
});
};
const executeKeydownOverride$2 = (editor, caret, evt) => {
const isMac = Env.os.isMacOS() || Env.os.isiOS();
execute([
{
keyCode: VK.END,
action: action(moveToLineEndPoint$1, editor, true)
},
{
keyCode: VK.HOME,
action: action(moveToLineEndPoint$1, editor, false)
},
...!isMac ? [
{
keyCode: VK.HOME,
action: action(selectToEndPoint, editor, false),
ctrlKey: true,
shiftKey: true
},
{
keyCode: VK.END,
action: action(selectToEndPoint, editor, true),
ctrlKey: true,
shiftKey: true
}
] : [],
{
keyCode: VK.END,
action: action(moveToLineEndPoint, editor, true)
},
{
keyCode: VK.HOME,
action: action(moveToLineEndPoint, editor, false)
},
{
keyCode: VK.END,
action: action(moveToLineEndPoint$2, editor, true, caret)
},
{
keyCode: VK.HOME,
action: action(moveToLineEndPoint$2, editor, false, caret)
}
], evt).each(_ => {
evt.preventDefault();
});
};
const setup$h = (editor, caret) => {
editor.on('keydown', evt => {
if (!evt.isDefaultPrevented()) {
executeKeydownOverride$2(editor, caret, evt);
}
});
};
const setup$g = editor => {
editor.on('input', e => {
if (!e.isComposing) {
normalizeNbspsInEditor(editor);
}
});
};
const platform = detect$1();
const executeKeyupAction = (editor, caret, evt) => {
execute([
{
keyCode: VK.PAGE_UP,
action: action(moveToLineEndPoint$2, editor, false, caret)
},
{
keyCode: VK.PAGE_DOWN,
action: action(moveToLineEndPoint$2, editor, true, caret)
}
], evt);
};
const stopImmediatePropagation = e => e.stopImmediatePropagation();
const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
const setNodeChangeBlocker = (blocked, editor, block) => {
if (block && !blocked.get()) {
editor.on('NodeChange', stopImmediatePropagation, true);
} else if (!block && blocked.get()) {
editor.off('NodeChange', stopImmediatePropagation);
}
blocked.set(block);
};
const setup$f = (editor, caret) => {
if (platform.os.isMacOS()) {
return;
}
const blocked = Cell(false);
editor.on('keydown', evt => {
if (isPageUpDown(evt)) {
setNodeChangeBlocker(blocked, editor, true);
}
});
editor.on('keyup', evt => {
if (!evt.isDefaultPrevented()) {
executeKeyupAction(editor, caret, evt);
}
if (isPageUpDown(evt) && blocked.get()) {
setNodeChangeBlocker(blocked, editor, false);
editor.nodeChanged();
}
});
};
const setup$e = editor => {
editor.on('beforeinput', e => {
if (!editor.selection.isEditable() || exists(e.getTargetRanges(), rng => !isEditableRange(editor.dom, rng))) {
e.preventDefault();
}
});
};
const insertTextAtPosition = (text, pos) => {
const container = pos.container();
const offset = pos.offset();
if (isText$b(container)) {
container.insertData(offset, text);
return Optional.some(CaretPosition(container, offset + text.length));
} else {
return getElementFromPosition(pos).map(elm => {
const textNode = SugarElement.fromText(text);
if (pos.isAtEnd()) {
after$4(elm, textNode);
} else {
before$3(elm, textNode);
}
return CaretPosition(textNode.dom, text.length);
});
}
};
const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
const insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
const insertSpaceOrNbspAtPosition = (root, pos, schema) => needsToHaveNbsp(root, pos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
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)));
const insertInlineBoundarySpaceOrNbsp = (root, pos, schema) => checkPos => needsToHaveNbsp(root, checkPos, schema) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
const setSelection = editor => pos => {
editor.selection.setRng(pos.toRange());
editor.nodeChanged();
};
const isInsideSummary = (domUtils, node) => domUtils.isEditable(domUtils.getParent(node, 'summary'));
const insertSpaceOrNbspAtSelection = editor => {
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
const root = SugarElement.fromDom(editor.getBody());
if (editor.selection.isCollapsed()) {
const isInlineTarget$1 = curry(isInlineTarget, editor);
const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos, editor.schema)(checkPos).each(setSelection(editor)));
} else {
return Optional.none();
}
};
const insertSpaceInSummaryAtSelectionOnFirefox = editor => {
const insertSpaceThunk = () => {
const root = SugarElement.fromDom(editor.getBody());
if (!editor.selection.isCollapsed()) {
editor.getDoc().execCommand('Delete');
}
const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
insertSpaceOrNbspAtPosition(root, pos, editor.schema).each(setSelection(editor));
};
return someIf(Env.browser.isFirefox() && editor.selection.isEditable() && isInsideSummary(editor.dom, editor.selection.getRng().startContainer), insertSpaceThunk);
};
const executeKeydownOverride$1 = (editor, evt) => {
executeWithDelayedAction([
{
keyCode: VK.SPACEBAR,
action: action(insertSpaceOrNbspAtSelection, editor)
},
{
keyCode: VK.SPACEBAR,
action: action(insertSpaceInSummaryAtSelectionOnFirefox, editor)
}
], evt).each(applyAction => {
evt.preventDefault();
const event = fireBeforeInputEvent(editor, 'insertText', { data: ' ' });
if (!event.isDefaultPrevented()) {
applyAction();
fireInputEvent(editor, 'insertText', { data: ' ' });
}
});
};
const setup$d = editor => {
editor.on('keydown', evt => {
if (!evt.isDefaultPrevented()) {
executeKeydownOverride$1(editor, evt);
}
});
};
const tableTabNavigation = editor => {
if (hasTableTabNavigation(editor)) {
return [
{
keyCode: VK.TAB,
action: action(handleTab, editor, true)
},
{
keyCode: VK.TAB,
shiftKey: true,
action: action(handleTab, editor, false)
}
];
} else {
return [];
}
};
const executeKeydownOverride = (editor, evt) => {
execute([...tableTabNavigation(editor)], evt).each(_ => {
evt.preventDefault();
});
};
const setup$c = editor => {
editor.on('keydown', evt => {
if (!evt.isDefaultPrevented()) {
executeKeydownOverride(editor, evt);
}
});
};
const setup$b = editor => {
editor.addShortcut('Meta+P', '', 'mcePrint');
setup$k(editor);
if (isRtc(editor)) {
return Cell(null);
} else {
const caret = setupSelectedState(editor);
setup$e(editor);
setup$m(editor);
setup$l(editor, caret);
setup$j(editor, caret);
setup$i(editor);
setup$d(editor);
setup$g(editor);
setup$c(editor);
setup$h(editor, caret);
setup$f(editor, caret);
return caret;
}
};
class NodeChange {
constructor(editor) {
this.lastPath = [];
this.editor = editor;
let lastRng;
const self = this;
if (!('onselectionchange' in editor.getDoc())) {
editor.on('NodeChange click mouseup keyup focus', e => {
const nativeRng = editor.selection.getRng();
const fakeRng = {
startContainer: nativeRng.startContainer,
startOffset: nativeRng.startOffset,
endContainer: nativeRng.endContainer,
endOffset: nativeRng.endOffset
};
if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) {
editor.dispatch('SelectionChange');
}
lastRng = fakeRng;
});
}
editor.on('contextmenu', () => {
store(editor);
editor.dispatch('SelectionChange');
});
editor.on('SelectionChange', () => {
const startElm = editor.selection.getStart(true);
if (!startElm) {
return;
}
if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
editor.nodeChanged({ selectionChange: true });
}
});
editor.on('mouseup', e => {
if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
if (editor.selection.getNode().nodeName === 'IMG') {
Delay.setEditorTimeout(editor, () => {
editor.nodeChanged();
});
} else {
editor.nodeChanged();
}
}
});
}
nodeChanged(args = {}) {
const selection = this.editor.selection;
let node;
if (this.editor.initialized && selection && !shouldDisableNodeChange(this.editor) && !this.editor.mode.isReadOnly()) {
const root = this.editor.getBody();
node = selection.getStart(true) || root;
if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
node = root;
}
const parents = [];
this.editor.dom.getParent(node, node => {
if (node === root) {
return true;
} else {
parents.push(node);
return false;
}
});
this.editor.dispatch('NodeChange', {
...args,
element: node,
parents
});
}
}
isSameElementPath(startElm) {
let i;
const editor = this.editor;
const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
if (currentPath.length === this.lastPath.length) {
for (i = currentPath.length; i >= 0; i--) {
if (currentPath[i] !== this.lastPath[i]) {
break;
}
}
if (i === -1) {
this.lastPath = currentPath;
return true;
}
}
this.lastPath = currentPath;
return false;
}
}
const imageId = generate$1('image');
const getDragImage = transfer => {
const dt = transfer;
return Optional.from(dt[imageId]);
};
const setDragImage = (transfer, imageData) => {
const dt = transfer;
dt[imageId] = imageData;
};
const eventId = generate$1('event');
const getEvent = transfer => {
const dt = transfer;
return Optional.from(dt[eventId]);
};
const mkSetEventFn = type => transfer => {
const dt = transfer;
dt[eventId] = type;
};
const setEvent = (transfer, type) => mkSetEventFn(type)(transfer);
const setDragstartEvent = mkSetEventFn(0);
const setDropEvent = mkSetEventFn(2);
const setDragendEvent = mkSetEventFn(1);
const checkEvent = expectedType => transfer => {
const dt = transfer;
return Optional.from(dt[eventId]).exists(type => type === expectedType);
};
const isInDragStartEvent = checkEvent(0);
const createEmptyFileList = () => Object.freeze({
length: 0,
item: _ => null
});
const modeId = generate$1('mode');
const getMode = transfer => {
const dt = transfer;
return Optional.from(dt[modeId]);
};
const mkSetModeFn = mode => transfer => {
const dt = transfer;
dt[modeId] = mode;
};
const setMode$1 = (transfer, mode) => mkSetModeFn(mode)(transfer);
const setReadWriteMode = mkSetModeFn(0);
const setReadOnlyMode = mkSetModeFn(2);
const setProtectedMode = mkSetModeFn(1);
const checkMode = expectedMode => transfer => {
const dt = transfer;
return Optional.from(dt[modeId]).exists(mode => mode === expectedMode);
};
const isInReadWriteMode = checkMode(0);
const isInProtectedMode = checkMode(1);
const normalizeItems = (dataTransfer, itemsImpl) => ({
...itemsImpl,
get length() {
return itemsImpl.length;
},
add: (data, type) => {
if (isInReadWriteMode(dataTransfer)) {
if (isString(data)) {
if (!isUndefined(type)) {
return itemsImpl.add(data, type);
}
} else {
return itemsImpl.add(data);
}
}
return null;
},
remove: idx => {
if (isInReadWriteMode(dataTransfer)) {
itemsImpl.remove(idx);
}
},
clear: () => {
if (isInReadWriteMode(dataTransfer)) {
itemsImpl.clear();
}
}
});
const validDropEffects = [
'none',
'copy',
'link',
'move'
];
const validEffectAlloweds = [
'none',
'copy',
'copyLink',
'copyMove',
'link',
'linkMove',
'move',
'all',
'uninitialized'
];
const createDataTransfer = () => {
const dataTransferImpl = new window.DataTransfer();
let dropEffect = 'move';
let effectAllowed = 'all';
const dataTransfer = {
get dropEffect() {
return dropEffect;
},
set dropEffect(effect) {
if (contains$2(validDropEffects, effect)) {
dropEffect = effect;
}
},
get effectAllowed() {
return effectAllowed;
},
set effectAllowed(allowed) {
if (isInDragStartEvent(dataTransfer) && contains$2(validEffectAlloweds, allowed)) {
effectAllowed = allowed;
}
},
get items() {
return normalizeItems(dataTransfer, dataTransferImpl.items);
},
get files() {
if (isInProtectedMode(dataTransfer)) {
return createEmptyFileList();
} else {
return dataTransferImpl.files;
}
},
get types() {
return dataTransferImpl.types;
},
setDragImage: (image, x, y) => {
if (isInReadWriteMode(dataTransfer)) {
setDragImage(dataTransfer, {
image,
x,
y
});
dataTransferImpl.setDragImage(image, x, y);
}
},
getData: format => {
if (isInProtectedMode(dataTransfer)) {
return '';
} else {
return dataTransferImpl.getData(format);
}
},
setData: (format, data) => {
if (isInReadWriteMode(dataTransfer)) {
dataTransferImpl.setData(format, data);
}
},
clearData: format => {
if (isInReadWriteMode(dataTransfer)) {
dataTransferImpl.clearData(format);
}
}
};
setReadWriteMode(dataTransfer);
return dataTransfer;
};
const cloneDataTransfer = original => {
const clone = createDataTransfer();
const originalMode = getMode(original);
setReadOnlyMode(original);
setDragstartEvent(clone);
clone.dropEffect = original.dropEffect;
clone.effectAllowed = original.effectAllowed;
getDragImage(original).each(imageData => clone.setDragImage(imageData.image, imageData.x, imageData.y));
each$e(original.types, type => {
if (type !== 'Files') {
clone.setData(type, original.getData(type));
}
});
each$e(original.files, file => clone.items.add(file));
getEvent(original).each(type => {
setEvent(clone, type);
});
originalMode.each(mode => {
setMode$1(original, mode);
setMode$1(clone, mode);
});
return clone;
};
const getHtmlData = dataTransfer => {
const html = dataTransfer.getData('text/html');
return html === '' ? Optional.none() : Optional.some(html);
};
const setHtmlData = (dataTransfer, html) => dataTransfer.setData('text/html', html);
const internalMimeType = 'x-tinymce/html';
const internalHtmlMime = constant(internalMimeType);
const internalMark = '';
const mark = html => internalMark + html;
const unmark = html => html.replace(internalMark, '');
const isMarked = html => html.indexOf(internalMark) !== -1;
const isPlainText = text => {
return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
};
const openContainer = (rootTag, rootAttrs) => {
let tag = '<' + rootTag;
const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"');
if (attrs.length) {
tag += ' ' + attrs.join(' ');
}
return tag + '>';
};
const toBlockElements = (text, rootTag, rootAttrs) => {
const blocks = text.split(/\n\n/);
const tagOpen = openContainer(rootTag, rootAttrs);
const tagClose = '' + rootTag + '>';
const paragraphs = map$3(blocks, p => {
return p.split(/\n/).join('
');
});
const stitch = p => {
return tagOpen + p + tagClose;
};
return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join('');
};
const pasteBinDefaultContent = '%MCEPASTEBIN%';
const create$6 = (editor, lastRngCell) => {
const {dom, selection} = editor;
const body = editor.getBody();
lastRngCell.set(selection.getRng());
const pasteBinElm = dom.add(editor.getBody(), 'div', {
'id': 'mcepastebin',
'class': 'mce-pastebin',
'contentEditable': true,
'data-mce-bogus': 'all',
'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0'
}, pasteBinDefaultContent);
if (Env.browser.isFirefox()) {
dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535);
}
dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => {
e.stopPropagation();
});
pasteBinElm.focus();
selection.select(pasteBinElm, true);
};
const remove = (editor, lastRngCell) => {
const dom = editor.dom;
if (getEl(editor)) {
let pasteBinClone;
const lastRng = lastRngCell.get();
while (pasteBinClone = getEl(editor)) {
dom.remove(pasteBinClone);
dom.unbind(pasteBinClone);
}
if (lastRng) {
editor.selection.setRng(lastRng);
}
}
lastRngCell.set(null);
};
const getEl = editor => editor.dom.get('mcepastebin');
const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin';
const getHtml = editor => {
const dom = editor.dom;
const copyAndRemove = (toElm, fromElm) => {
toElm.appendChild(fromElm);
dom.remove(fromElm, true);
};
const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin);
each$e(pasteBinClones, pasteBinClone => {
copyAndRemove(pasteBinElm, pasteBinClone);
});
const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm);
for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
const cleanWrapper = dom.create('div');
pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
copyAndRemove(cleanWrapper, dirtyWrappers[i]);
}
return pasteBinElm ? pasteBinElm.innerHTML : '';
};
const isDefaultPasteBinContent = content => content === pasteBinDefaultContent;
const PasteBin = editor => {
const lastRng = Cell(null);
return {
create: () => create$6(editor, lastRng),
remove: () => remove(editor, lastRng),
getEl: () => getEl(editor),
getHtml: () => getHtml(editor),
getLastRng: lastRng.get
};
};
const filter$1 = (content, items) => {
Tools.each(items, v => {
if (is$4(v, RegExp)) {
content = content.replace(v, '');
} else {
content = content.replace(v[0], v[1]);
}
});
return content;
};
const innerText = html => {
const schema = Schema();
const domParser = DomParser({}, schema);
let text = '';
const voidElements = schema.getVoidElements();
const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
const blockElements = schema.getBlockElements();
const walk = node => {
const name = node.name, currentNode = node;
if (name === 'br') {
text += '\n';
return;
}
if (name === 'wbr') {
return;
}
if (voidElements[name]) {
text += ' ';
}
if (ignoreElements[name]) {
text += ' ';
return;
}
if (node.type === 3) {
text += node.value;
}
if (!(node.name in schema.getVoidElements())) {
let currentNode = node.firstChild;
if (currentNode) {
do {
walk(currentNode);
} while (currentNode = currentNode.next);
}
}
if (blockElements[name] && currentNode.next) {
text += '\n';
if (name === 'p') {
text += '\n';
}
}
};
html = filter$1(html, [//g]);
walk(domParser.parse(html));
return text;
};
const trimHtml = html => {
const trimSpaces = (all, s1, s2) => {
if (!s1 && !s2) {
return ' ';
}
return nbsp;
};
html = filter$1(html, [
/^[\s\S]*]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
/|/g,
[
/( ?)\u00a0<\/span>( ?)/g,
trimSpaces
],
/
/g,
/
$/i
]);
return html;
};
const createIdGenerator = prefix => {
let count = 0;
return () => {
return prefix + count++;
};
};
const getImageMimeType = ext => {
const lowerExt = ext.toLowerCase();
const mimeOverrides = {
jpg: 'jpeg',
jpe: 'jpeg',
jfi: 'jpeg',
jif: 'jpeg',
jfif: 'jpeg',
pjpeg: 'jpeg',
pjp: 'jpeg',
svg: 'svg+xml'
};
return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt;
};
const preProcess = (editor, html) => {
const parser = DomParser({
sanitize: shouldSanitizeXss(editor),
sandbox_iframes: shouldSandboxIframes(editor),
sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
convert_unsafe_embeds: shouldConvertUnsafeEmbeds(editor)
}, editor.schema);
parser.addNodeFilter('meta', nodes => {
Tools.each(nodes, node => {
node.remove();
});
});
const fragment = parser.parse(html, {
forced_root_block: false,
isRootContent: true
});
return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
};
const processResult = (content, cancelled) => ({
content,
cancelled
});
const postProcessFilter = (editor, html, internal) => {
const tempBody = editor.dom.create('div', { style: 'display:none' }, html);
const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
};
const filterContent = (editor, content, internal) => {
const preProcessArgs = firePastePreProcess(editor, content, internal);
const filteredContent = preProcess(editor, preProcessArgs.content);
if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
return postProcessFilter(editor, filteredContent, internal);
} else {
return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
}
};
const process = (editor, html, internal) => {
return filterContent(editor, html, internal);
};
const pasteHtml$1 = (editor, html) => {
editor.insertContent(html, {
merge: shouldPasteMergeFormats(editor),
paste: true
});
return true;
};
const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
const isImageUrl = (editor, url) => {
return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`));
};
const createImage = (editor, url, pasteHtmlFn) => {
editor.undoManager.extra(() => {
pasteHtmlFn(editor, url);
}, () => {
editor.insertContent('');
});
return true;
};
const createLink = (editor, url, pasteHtmlFn) => {
editor.undoManager.extra(() => {
pasteHtmlFn(editor, url);
}, () => {
editor.execCommand('mceInsertLink', false, url);
});
return true;
};
const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false;
const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false;
const smartInsertContent = (editor, html) => {
Tools.each([
linkSelection,
insertImage,
pasteHtml$1
], action => {
return !action(editor, html, pasteHtml$1);
});
};
const insertContent = (editor, html, pasteAsText) => {
if (pasteAsText || !isSmartPasteEnabled(editor)) {
pasteHtml$1(editor, html);
} else {
smartInsertContent(editor, html);
}
};
const uniqueId = createIdGenerator('mceclip');
const createPasteDataTransfer = html => {
const dataTransfer = createDataTransfer();
setHtmlData(dataTransfer, html);
setReadOnlyMode(dataTransfer);
return dataTransfer;
};
const doPaste = (editor, content, internal, pasteAsText, shouldSimulateInputEvent) => {
const res = process(editor, content, internal);
if (!res.cancelled) {
const content = res.content;
const doPasteAction = () => insertContent(editor, content, pasteAsText);
if (shouldSimulateInputEvent) {
const args = fireBeforeInputEvent(editor, 'insertFromPaste', { dataTransfer: createPasteDataTransfer(content) });
if (!args.isDefaultPrevented()) {
doPasteAction();
fireInputEvent(editor, 'insertFromPaste');
}
} else {
doPasteAction();
}
}
};
const pasteHtml = (editor, html, internalFlag, shouldSimulateInputEvent) => {
const internal = internalFlag ? internalFlag : isMarked(html);
doPaste(editor, unmark(html), internal, false, shouldSimulateInputEvent);
};
const pasteText = (editor, text, shouldSimulateInputEvent) => {
const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n');
const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
doPaste(editor, html, false, true, shouldSimulateInputEvent);
};
const getDataTransferItems = dataTransfer => {
const items = {};
if (dataTransfer && dataTransfer.types) {
for (let i = 0; i < dataTransfer.types.length; i++) {
const contentType = dataTransfer.types[i];
try {
items[contentType] = dataTransfer.getData(contentType);
} catch (ex) {
items[contentType] = '';
}
}
}
return items;
};
const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
const extractFilename = (editor, str) => {
const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined;
};
const createBlobInfo = (editor, blobCache, file, base64) => {
const id = uniqueId();
const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
const name = useFileName ? extractFilename(editor, file.name) : id;
const filename = useFileName ? file.name : undefined;
const blobInfo = blobCache.create(id, file, base64, name, filename);
blobCache.add(blobInfo);
return blobInfo;
};
const pasteImage = (editor, imageItem) => {
parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => {
const base64 = base64Encoded ? data : btoa(data);
const file = imageItem.file;
const blobCache = editor.editorUpload.blobCache;
const existingBlobInfo = blobCache.getByData(base64, type);
const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
pasteHtml(editor, ``, false, true);
});
};
const isClipboardEvent = event => event.type === 'paste';
const readFilesAsDataUris = items => Promise.all(map$3(items, file => {
return blobToDataUri(file).then(uri => ({
file,
uri
}));
}));
const isImage = editor => {
const allowedExtensions = getAllowedImageFileTypes(editor);
return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => {
return getImageMimeType(extension) === file.type;
});
};
const getImagesFromDataTransfer = (editor, dataTransfer) => {
const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => {
return item.kind === 'file' ? [item.getAsFile()] : [];
}) : [];
const files = dataTransfer.files ? from(dataTransfer.files) : [];
return filter$5(items.length > 0 ? items : files, isImage(editor));
};
const pasteImageData = (editor, e, rng) => {
const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
if (shouldPasteDataImages(editor) && dataTransfer) {
const images = getImagesFromDataTransfer(editor, dataTransfer);
if (images.length > 0) {
e.preventDefault();
readFilesAsDataUris(images).then(fileResults => {
if (rng) {
editor.selection.setRng(rng);
}
each$e(fileResults, result => {
pasteImage(editor, result);
});
});
return true;
}
}
return false;
};
const isBrokenAndroidClipboardEvent = e => {
var _a, _b;
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;
};
const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
const insertClipboardContent = (editor, clipboardContent, html, plainTextMode, shouldSimulateInputEvent) => {
let content = trimHtml(html);
const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html);
const isPlainTextHtml = !isInternal && isPlainText(content);
const isAbsoluteUrl$1 = isAbsoluteUrl(content);
if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
plainTextMode = true;
}
if (plainTextMode || isAbsoluteUrl$1) {
if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) {
content = clipboardContent['text/plain'];
} else {
content = innerText(content);
}
}
if (isDefaultPasteBinContent(content)) {
return;
}
if (plainTextMode) {
pasteText(editor, content, shouldSimulateInputEvent);
} else {
pasteHtml(editor, content, isInternal, shouldSimulateInputEvent);
}
};
const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
let keyboardPastePlainTextState;
const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
editor.on('keydown', e => {
if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
}
});
editor.on('paste', e => {
if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
return;
}
const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState;
keyboardPastePlainTextState = false;
const clipboardContent = getDataTransferItems(e.clipboardData);
if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
return;
}
if (hasContentType(clipboardContent, 'text/html')) {
e.preventDefault();
insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode, true);
} else if (hasContentType(clipboardContent, 'text/plain') && hasContentType(clipboardContent, 'text/uri-list')) {
e.preventDefault();
insertClipboardContent(editor, clipboardContent, clipboardContent['text/plain'], plainTextMode, true);
} else {
pasteBin.create();
Delay.setEditorTimeout(editor, () => {
const html = pasteBin.getHtml();
pasteBin.remove();
insertClipboardContent(editor, clipboardContent, html, plainTextMode, false);
}, 0);
}
});
};
const registerDataImageFilter = editor => {
const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url');
const isDataUri = src => startsWith(src, 'data:');
const isPasteInsert = args => {
var _a;
return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
};
editor.parser.addNodeFilter('img', (nodes, name, args) => {
if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
for (const node of nodes) {
const src = node.attr('src');
if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) {
if (isWebKitFakeUrl(src)) {
node.remove();
} else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
node.remove();
}
}
}
}
});
};
const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
registerEventHandlers(editor, pasteBin, pasteFormat);
registerDataImageFilter(editor);
};
const togglePlainTextPaste = (editor, pasteFormat) => {
if (pasteFormat.get() === 'text') {
pasteFormat.set('html');
firePastePlainTextToggle(editor, false);
} else {
pasteFormat.set('text');
firePastePlainTextToggle(editor, true);
}
editor.focus();
};
const register$1 = (editor, pasteFormat) => {
editor.addCommand('mceTogglePlainTextPaste', () => {
togglePlainTextPaste(editor, pasteFormat);
});
editor.addCommand('mceInsertClipboardContent', (ui, value) => {
if (value.html) {
pasteHtml(editor, value.html, value.internal, false);
}
if (value.text) {
pasteText(editor, value.text, false);
}
});
};
const setHtml5Clipboard = (clipboardData, html, text) => {
if (clipboardData) {
try {
clipboardData.clearData();
clipboardData.setData('text/html', html);
clipboardData.setData('text/plain', text);
clipboardData.setData(internalHtmlMime(), html);
return true;
} catch (e) {
return false;
}
} else {
return false;
}
};
const setClipboardData = (evt, data, fallback, done) => {
if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
evt.preventDefault();
done();
} else {
fallback(data.html, done);
}
};
const fallback = editor => (html, done) => {
const {dom, selection} = editor;
const outer = dom.create('div', {
'contenteditable': 'false',
'data-mce-bogus': 'all'
});
const inner = dom.create('div', { contenteditable: 'true' }, html);
dom.setStyles(outer, {
position: 'fixed',
top: '0',
left: '-3000px',
width: '1000px',
overflow: 'hidden'
});
outer.appendChild(inner);
dom.add(editor.getBody(), outer);
const range = selection.getRng();
inner.focus();
const offscreenRange = dom.createRng();
offscreenRange.selectNodeContents(inner);
selection.setRng(offscreenRange);
Delay.setEditorTimeout(editor, () => {
selection.setRng(range);
dom.remove(outer);
done();
}, 0);
};
const getData = editor => ({
html: mark(editor.selection.getContent({ contextual: true })),
text: editor.selection.getContent({ format: 'text' })
});
const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody());
const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor);
const cut = editor => evt => {
if (!evt.isDefaultPrevented() && hasSelectedContent(editor) && editor.selection.isEditable()) {
setClipboardData(evt, getData(editor), fallback(editor), () => {
if (Env.browser.isChromium() || Env.browser.isFirefox()) {
const rng = editor.selection.getRng();
Delay.setEditorTimeout(editor, () => {
editor.selection.setRng(rng);
editor.execCommand('Delete');
}, 0);
} else {
editor.execCommand('Delete');
}
});
}
};
const copy = editor => evt => {
if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
setClipboardData(evt, getData(editor), fallback(editor), noop);
}
};
const register = editor => {
editor.on('cut', cut(editor));
editor.on('copy', copy(editor));
};
const getCaretRangeFromEvent = (editor, e) => {
var _a, _b;
return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
};
const isPlainTextFileUrl = content => {
const plainTextContent = content['text/plain'];
return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false;
};
const setFocusedRange = (editor, rng) => {
editor.focus();
if (rng) {
editor.selection.setRng(rng);
}
};
const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type));
const needsCustomInternalDrop = (dom, schema, target, dropContent) => {
const parentTransparent = dom.getParent(target, node => isTransparentBlock(schema, node));
const inSummary = !isNull(dom.getParent(target, 'summary'));
if (inSummary) {
return true;
} else if (parentTransparent && has$2(dropContent, 'text/html')) {
const fragment = new DOMParser().parseFromString(dropContent['text/html'], 'text/html').body;
return !isNull(fragment.querySelector(parentTransparent.nodeName.toLowerCase()));
} else {
return false;
}
};
const setupSummaryDeleteByDragFix = editor => {
editor.on('input', e => {
const hasNoSummary = el => isNull(el.querySelector('summary'));
if (e.inputType === 'deleteByDrag') {
const brokenDetailElements = filter$5(editor.dom.select('details'), hasNoSummary);
each$e(brokenDetailElements, details => {
if (isBr$6(details.firstChild)) {
details.firstChild.remove();
}
const summary = editor.dom.create('summary');
summary.appendChild(createPaddingBr().dom);
details.prepend(summary);
});
}
});
};
const setup$a = (editor, draggingInternallyState) => {
if (shouldPasteBlockDrop(editor)) {
editor.on('dragend dragover draggesture dragdrop drop drag', e => {
e.preventDefault();
e.stopPropagation();
});
}
if (!shouldPasteDataImages(editor)) {
editor.on('drop', e => {
const dataTransfer = e.dataTransfer;
if (dataTransfer && hasImage(dataTransfer)) {
e.preventDefault();
}
});
}
editor.on('drop', e => {
if (e.isDefaultPrevented()) {
return;
}
const rng = getCaretRangeFromEvent(editor, e);
if (isNullable(rng)) {
return;
}
const dropContent = getDataTransferItems(e.dataTransfer);
const internal = hasContentType(dropContent, internalHtmlMime());
if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
return;
}
const internalContent = dropContent[internalHtmlMime()];
const content = internalContent || dropContent['text/html'] || dropContent['text/plain'];
const needsInternalDrop = needsCustomInternalDrop(editor.dom, editor.schema, rng.startContainer, dropContent);
const isInternalDrop = draggingInternallyState.get();
if (isInternalDrop && !needsInternalDrop) {
return;
}
if (content) {
e.preventDefault();
Delay.setEditorTimeout(editor, () => {
editor.undoManager.transact(() => {
if (internalContent || isInternalDrop && needsInternalDrop) {
editor.execCommand('Delete');
}
setFocusedRange(editor, rng);
const trimmedContent = trimHtml(content);
if (dropContent['text/html']) {
pasteHtml(editor, trimmedContent, internal, true);
} else {
pasteText(editor, trimmedContent, true);
}
});
});
}
});
editor.on('dragstart', _e => {
draggingInternallyState.set(true);
});
editor.on('dragover dragend', e => {
if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) {
e.preventDefault();
setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
}
if (e.type === 'dragend') {
draggingInternallyState.set(false);
}
});
setupSummaryDeleteByDragFix(editor);
};
const setup$9 = editor => {
const processEvent = f => e => {
f(editor, e);
};
const preProcess = getPastePreProcess(editor);
if (isFunction(preProcess)) {
editor.on('PastePreProcess', processEvent(preProcess));
}
const postProcess = getPastePostProcess(editor);
if (isFunction(postProcess)) {
editor.on('PastePostProcess', processEvent(postProcess));
}
};
const addPreProcessFilter = (editor, filterFunc) => {
editor.on('PastePreProcess', e => {
e.content = filterFunc(editor, e.content, e.internal);
});
};
const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase();
const removeWebKitStyles = (editor, content, internal) => {
const webKitStylesOption = getPasteWebkitStyles(editor);
if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) {
return content;
}
const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
if (webKitStyles && webKitStylesOption !== 'none') {
const dom = editor.dom, node = editor.selection.getNode();
content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => {
const inputStyles = dom.parseStyle(dom.decode(value));
const outputStyles = {};
for (let i = 0; i < webKitStyles.length; i++) {
const inputValue = inputStyles[webKitStyles[i]];
let compareInput = inputValue;
let currentValue = dom.getStyle(node, webKitStyles[i], true);
if (/color/.test(webKitStyles[i])) {
compareInput = rgbToHex(compareInput);
currentValue = rgbToHex(currentValue);
}
if (currentValue !== compareInput) {
outputStyles[webKitStyles[i]] = inputValue;
}
}
const outputStyle = dom.serializeStyle(outputStyles, 'span');
if (outputStyle) {
return before + ' style="' + outputStyle + '"' + after;
}
return before + after;
});
} else {
content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
}
content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => {
return before + ' style="' + value + '"' + after;
});
return content;
};
const setup$8 = editor => {
if (Env.browser.isChromium() || Env.browser.isSafari()) {
addPreProcessFilter(editor, removeWebKitStyles);
}
};
const setup$7 = editor => {
const draggingInternallyState = Cell(false);
const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html');
const pasteBin = PasteBin(editor);
setup$8(editor);
register$1(editor, pasteFormat);
setup$9(editor);
editor.addQueryStateHandler('mceTogglePlainTextPaste', () => pasteFormat.get() === 'text');
editor.on('PreInit', () => {
register(editor);
setup$a(editor, draggingInternallyState);
registerEventsAndFilters(editor, pasteBin, pasteFormat);
});
};
const preventSummaryToggle = editor => {
editor.on('click', e => {
if (editor.dom.getParent(e.target, 'details')) {
e.preventDefault();
}
});
};
const filterDetails = editor => {
editor.parser.addNodeFilter('details', elms => {
const initialStateOption = getDetailsInitialState(editor);
each$e(elms, details => {
if (initialStateOption === 'expanded') {
details.attr('open', 'open');
} else if (initialStateOption === 'collapsed') {
details.attr('open', null);
}
});
});
editor.serializer.addNodeFilter('details', elms => {
const serializedStateOption = getDetailsSerializedState(editor);
each$e(elms, details => {
if (serializedStateOption === 'expanded') {
details.attr('open', 'open');
} else if (serializedStateOption === 'collapsed') {
details.attr('open', null);
}
});
});
};
const setup$6 = editor => {
preventSummaryToggle(editor);
filterDetails(editor);
};
const isBr = isBr$6;
const isText = isText$b;
const isContentEditableFalse$2 = elm => isContentEditableFalse$b(elm.dom);
const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom);
const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm);
const getClosestScope = (node, rootNode, schema) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
const findEdgeCaretCandidate = (startNode, scope, forward) => {
const walker = new DomTreeWalker(startNode, scope);
const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
let result = startNode;
for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) {
if (isCaretCandidate$3(current)) {
result = current;
}
}
return result;
};
const findClosestBlockRange = (startRng, rootNode, schema) => {
const startPos = CaretPosition.fromRangeStart(startRng);
const clickNode = startPos.getNode();
const scope = getClosestScope(clickNode, rootNode, schema);
const startNode = findEdgeCaretCandidate(clickNode, scope, false);
const endNode = findEdgeCaretCandidate(clickNode, scope, true);
const rng = document.createRange();
getClosestCef(startNode, scope).fold(() => {
if (isText(startNode)) {
rng.setStart(startNode, 0);
} else {
rng.setStartBefore(startNode);
}
}, cef => rng.setStartBefore(cef.dom));
getClosestCef(endNode, scope).fold(() => {
if (isText(endNode)) {
rng.setEnd(endNode, endNode.data.length);
} else {
rng.setEndAfter(endNode);
}
}, cef => rng.setEndAfter(cef.dom));
return rng;
};
const onTripleClickSelect = editor => {
const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody(), editor.schema);
editor.selection.setRng(normalize(rng));
};
const setup$5 = editor => {
editor.on('mousedown', e => {
if (e.detail >= 3) {
e.preventDefault();
onTripleClickSelect(editor);
}
});
};
var FakeCaretPosition;
(function (FakeCaretPosition) {
FakeCaretPosition['Before'] = 'before';
FakeCaretPosition['After'] = 'after';
}(FakeCaretPosition || (FakeCaretPosition = {})));
const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
const isOverlapping = (r1, r2) => {
const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
return collidesY(r1, r2) && overlap > 0.5;
};
const splitRectsPerAxis = (rects, y) => {
const intersectingRects = filter$5(rects, rect => isInsideY(y, rect));
return boundingClientRectFromRects(intersectingRects).fold(() => [
[],
rects
], boundingRect => {
const {
pass: horizontal,
fail: vertical
} = partition$2(rects, rect => isOverlapping(rect, boundingRect));
return [
horizontal,
vertical
];
});
};
const clientInfo = (rect, clientX) => {
return {
node: rect.node,
position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
};
};
const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
const closestChildCaretCandidateNodeRect = (children, clientX, clientY, findCloserTextNode) => {
const caretCandidateRect = rect => {
if (isCaretCandidate$3(rect.node)) {
return Optional.some(rect);
} else if (isElement$6(rect.node)) {
return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY, false);
} else {
return Optional.none();
}
};
const tryFindSecondBestTextNode = (closest, sndClosest, distance) => {
return caretCandidateRect(sndClosest).filter(rect => {
const deltaDistance = Math.abs(distance(closest, clientX, clientY) - distance(rect, clientX, clientY));
return deltaDistance < 2 && isText$b(rect.node);
});
};
const findClosestCaretCandidateNodeRect = (rects, distance) => {
const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
return findMap(sortedRects, caretCandidateRect).map(closest => {
if (findCloserTextNode && !isText$b(closest.node) && sortedRects.length > 1) {
return tryFindSecondBestTextNode(closest, sortedRects[1], distance).getOr(closest);
} else {
return closest;
}
});
};
const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY);
const {
pass: above,
fail: below
} = partition$2(verticalRects, rect => rect.top < clientY);
return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
};
const traverseUp = (rootElm, scope, clientX, clientY) => {
const helper = (scope, prevScope) => {
const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container');
const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer));
return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY, true), prevScope => {
const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom);
return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY, true);
}).orThunk(() => {
const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope);
return parent.bind(newScope => helper(newScope, Optional.some(scope)));
});
};
return helper(scope, Optional.none());
};
const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
const rootElm = SugarElement.fromDom(root);
const ownerDoc = documentOrOwner(rootElm);
const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm));
const element = elementAtPoint.getOr(rootElm);
return traverseUp(rootElm, element, clientX, clientY);
};
const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX));
const getAbsolutePosition = elm => {
var _a, _b;
const clientRect = elm.getBoundingClientRect();
const doc = elm.ownerDocument;
const docElem = doc.documentElement;
const win = doc.defaultView;
return {
top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop,
left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft
};
};
const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : {
left: 0,
top: 0
};
const getScrollPosition = editor => {
const body = editor.getBody();
return editor.inline ? {
left: body.scrollLeft,
top: body.scrollTop
} : {
left: 0,
top: 0
};
};
const getBodyScroll = editor => {
const body = editor.getBody(), docElm = editor.getDoc().documentElement;
const inlineScroll = {
left: body.scrollLeft,
top: body.scrollTop
};
const iframeScroll = {
left: body.scrollLeft || docElm.scrollLeft,
top: body.scrollTop || docElm.scrollTop
};
return editor.inline ? inlineScroll : iframeScroll;
};
const getMousePosition = (editor, event) => {
if (event.target.ownerDocument !== editor.getDoc()) {
const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
const scrollPosition = getBodyScroll(editor);
return {
left: event.pageX - iframePosition.left + scrollPosition.left,
top: event.pageY - iframePosition.top + scrollPosition.top
};
}
return {
left: event.pageX,
top: event.pageY
};
};
const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
});
const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
const getTargetProps = target => ({
target,
srcElement: target
});
const makeDndEventFromMouseEvent = (type, mouseEvent, target, dataTransfer) => ({
...mouseEvent,
dataTransfer,
type,
...getTargetProps(target)
});
const makeDndEvent = (type, target, dataTransfer) => {
const fail = die('Function not supported on simulated event.');
const event = {
bubbles: true,
cancelBubble: false,
cancelable: true,
composed: false,
currentTarget: null,
defaultPrevented: false,
eventPhase: 0,
isTrusted: true,
returnValue: false,
timeStamp: 0,
type,
composedPath: fail,
initEvent: fail,
preventDefault: noop,
stopImmediatePropagation: noop,
stopPropagation: noop,
AT_TARGET: window.Event.AT_TARGET,
BUBBLING_PHASE: window.Event.BUBBLING_PHASE,
CAPTURING_PHASE: window.Event.CAPTURING_PHASE,
NONE: window.Event.NONE,
altKey: false,
button: 0,
buttons: 0,
clientX: 0,
clientY: 0,
ctrlKey: false,
metaKey: false,
movementX: 0,
movementY: 0,
offsetX: 0,
offsetY: 0,
pageX: 0,
pageY: 0,
relatedTarget: null,
screenX: 0,
screenY: 0,
shiftKey: false,
x: 0,
y: 0,
detail: 0,
view: null,
which: 0,
initUIEvent: fail,
initMouseEvent: fail,
getModifierState: fail,
dataTransfer,
...getTargetProps(target)
};
return event;
};
const makeDataTransferCopyForDragEvent = (dataTransfer, eventType) => {
const copy = cloneDataTransfer(dataTransfer);
if (eventType === 'dragstart') {
setDragstartEvent(copy);
setReadWriteMode(copy);
} else if (eventType === 'drop') {
setDropEvent(copy);
setReadOnlyMode(copy);
} else {
setDragendEvent(copy);
setProtectedMode(copy);
}
return copy;
};
const makeDragEvent = (type, target, dataTransfer, mouseEvent) => {
const dataTransferForDispatch = makeDataTransferCopyForDragEvent(dataTransfer, type);
return isUndefined(mouseEvent) ? makeDndEvent(type, target, dataTransferForDispatch) : makeDndEventFromMouseEvent(type, mouseEvent, target, dataTransferForDispatch);
};
const scrollPixelsPerInterval = 32;
const scrollIntervalValue = 100;
const mouseRangeToTriggerScrollInsideEditor = 8;
const mouseRangeToTriggerScrollOutsideEditor = 16;
const isContentEditableFalse$1 = isContentEditableFalse$b;
const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3);
const isDraggable = (dom, rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm && dom.isEditable(elm.parentElement);
const isValidDropTarget = (editor, targetElement, dragElement) => {
if (isNullable(targetElement)) {
return false;
} else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
return false;
} else {
return editor.dom.isEditable(targetElement);
}
};
const createGhost = (editor, elm, width, height) => {
const dom = editor.dom;
const clonedElm = elm.cloneNode(true);
dom.setStyles(clonedElm, {
width,
height
});
dom.setAttrib(clonedElm, 'data-mce-selected', null);
const ghostElm = dom.create('div', {
'class': 'mce-drag-container',
'data-mce-bogus': 'all',
'unselectable': 'on',
'contenteditable': 'false'
});
dom.setStyles(ghostElm, {
position: 'absolute',
opacity: 0.5,
overflow: 'hidden',
border: 0,
padding: 0,
margin: 0,
width,
height
});
dom.setStyles(clonedElm, {
margin: 0,
boxSizing: 'border-box'
});
ghostElm.appendChild(clonedElm);
return ghostElm;
};
const appendGhostToBody = (ghostElm, bodyElm) => {
if (ghostElm.parentNode !== bodyElm) {
bodyElm.appendChild(ghostElm);
}
};
const scrollEditor = (direction, amount) => win => () => {
const current = direction === 'left' ? win.scrollX : win.scrollY;
win.scroll({
[direction]: current + amount,
behavior: 'smooth'
});
};
const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval);
const scrollRight = scrollEditor('left', scrollPixelsPerInterval);
const scrollUp = scrollEditor('top', -scrollPixelsPerInterval);
const scrollDown = scrollEditor('top', scrollPixelsPerInterval);
const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => {
let overflowX = 0, overflowY = 0;
ghostElm.style.left = position.pageX + 'px';
ghostElm.style.top = position.pageY + 'px';
if (position.pageX + width > maxX) {
overflowX = position.pageX + width - maxX;
}
if (position.pageY + height > maxY) {
overflowY = position.pageY + height - maxY;
}
ghostElm.style.width = width - overflowX + 'px';
ghostElm.style.height = height - overflowY + 'px';
const clientHeight = contentAreaContainer.clientHeight;
const clientWidth = contentAreaContainer.clientWidth;
const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top;
const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left;
state.on(state => {
state.intervalId.clear();
if (state.dragging && mouseEventOriginatedFromWithinTheEditor) {
if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) {
state.intervalId.set(scrollDown(win));
} else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) {
state.intervalId.set(scrollUp(win));
} else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) {
state.intervalId.set(scrollRight(win));
} else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) {
state.intervalId.set(scrollLeft(win));
} else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) {
state.intervalId.set(scrollDown(window));
} else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) {
state.intervalId.set(scrollUp(window));
} else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) {
state.intervalId.set(scrollRight(window));
} else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) {
state.intervalId.set(scrollLeft(window));
}
}
});
};
const removeElement = elm => {
if (elm && elm.parentNode) {
elm.parentNode.removeChild(elm);
}
};
const removeElementWithPadding = (dom, elm) => {
const parentBlock = dom.getParent(elm.parentNode, dom.isBlock);
removeElement(elm);
if (parentBlock && parentBlock !== dom.getRoot() && dom.isEmpty(parentBlock)) {
fillWithPaddingBr(SugarElement.fromDom(parentBlock));
}
};
const isLeftMouseButtonPressed = e => e.button === 0;
const applyRelPos = (state, position) => ({
pageX: position.pageX - state.relX,
pageY: position.pageY + 5
});
const start = (state, editor) => e => {
if (isLeftMouseButtonPressed(e)) {
const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null);
if (isNonNullable(ceElm) && isDraggable(editor.dom, editor.getBody(), ceElm)) {
const elmPos = editor.dom.getPos(ceElm);
const bodyElm = editor.getBody();
const docElm = editor.getDoc().documentElement;
state.set({
element: ceElm,
dataTransfer: createDataTransfer(),
dragging: false,
screenX: e.screenX,
screenY: e.screenY,
maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
relX: e.pageX - elmPos.x,
relY: e.pageY - elmPos.y,
width: ceElm.offsetWidth,
height: ceElm.offsetHeight,
ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight),
intervalId: repeatable(scrollIntervalValue)
});
}
}
};
const placeCaretAt = (editor, clientX, clientY) => {
editor._selectionOverrides.hideFakeCaret();
closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => {
const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
if (range) {
editor.selection.setRng(range);
} else {
editor.selection.placeCaretAt(clientX, clientY);
}
});
};
const dispatchDragEvent = (editor, type, target, dataTransfer, mouseEvent) => {
if (type === 'dragstart') {
setHtmlData(dataTransfer, editor.dom.getOuterHTML(target));
}
const event = makeDragEvent(type, target, dataTransfer, mouseEvent);
const args = editor.dispatch(type, event);
return args;
};
const move = (state, editor) => {
const throttledPlaceCaretAt = first$1((clientX, clientY) => placeCaretAt(editor, clientX, clientY), 0);
editor.on('remove', throttledPlaceCaretAt.cancel);
const state_ = state;
return e => state.on(state => {
const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
if (!state.dragging && movement > 10) {
const args = dispatchDragEvent(editor, 'dragstart', state.element, state.dataTransfer, e);
if (isNonNullable(args.dataTransfer)) {
state.dataTransfer = args.dataTransfer;
}
if (args.isDefaultPrevented()) {
return;
}
state.dragging = true;
editor.focus();
}
if (state.dragging) {
const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement;
const targetPos = applyRelPos(state, calc(editor, e));
appendGhostToBody(state.ghost, editor.getBody());
moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor);
throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
}
});
};
const getRawTarget = selection => {
const sel = selection.getSel();
if (isNonNullable(sel)) {
const rng = sel.getRangeAt(0);
const startContainer = rng.startContainer;
return isText$b(startContainer) ? startContainer.parentNode : startContainer;
} else {
return null;
}
};
const drop = (state, editor) => e => {
state.on(state => {
var _a;
state.intervalId.clear();
if (state.dragging) {
if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
const dropTarget = (_a = editor.getDoc().elementFromPoint(e.clientX, e.clientY)) !== null && _a !== void 0 ? _a : editor.getBody();
const args = dispatchDragEvent(editor, 'drop', dropTarget, state.dataTransfer, e);
if (!args.isDefaultPrevented()) {
editor.undoManager.transact(() => {
removeElementWithPadding(editor.dom, state.element);
getHtmlData(state.dataTransfer).each(content => editor.insertContent(content));
editor._selectionOverrides.hideFakeCaret();
});
}
}
dispatchDragEvent(editor, 'dragend', editor.getBody(), state.dataTransfer, e);
}
});
removeDragState(state);
};
const stopDragging = (state, editor, e) => {
state.on(state => {
state.intervalId.clear();
if (state.dragging) {
e.fold(() => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer), mouseEvent => dispatchDragEvent(editor, 'dragend', state.element, state.dataTransfer, mouseEvent));
}
});
removeDragState(state);
};
const stop = (state, editor) => e => stopDragging(state, editor, Optional.some(e));
const removeDragState = state => {
state.on(state => {
state.intervalId.clear();
removeElement(state.ghost);
});
state.clear();
};
const bindFakeDragEvents = editor => {
const state = value$2();
const pageDom = DOMUtils.DOM;
const rootDocument = document;
const dragStartHandler = start(state, editor);
const dragHandler = move(state, editor);
const dropHandler = drop(state, editor);
const dragEndHandler = stop(state, editor);
editor.on('mousedown', dragStartHandler);
editor.on('mousemove', dragHandler);
editor.on('mouseup', dropHandler);
pageDom.bind(rootDocument, 'mousemove', dragHandler);
pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
editor.on('remove', () => {
pageDom.unbind(rootDocument, 'mousemove', dragHandler);
pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
});
editor.on('keydown', e => {
if (e.keyCode === VK.ESC) {
stopDragging(state, editor, Optional.none());
}
});
};
const blockUnsupportedFileDrop = editor => {
const preventFileDrop = e => {
if (!e.isDefaultPrevented()) {
const dataTransfer = e.dataTransfer;
if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) {
e.preventDefault();
if (e.type === 'drop') {
displayError(editor, 'Dropped file type is not supported');
}
}
}
};
const preventFileDropIfUIElement = e => {
if (isUIElement(editor, e.target)) {
preventFileDrop(e);
}
};
const setup = () => {
const pageDom = DOMUtils.DOM;
const dom = editor.dom;
const doc = document;
const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
const eventNames = [
'drop',
'dragover'
];
each$e(eventNames, name => {
pageDom.bind(doc, name, preventFileDropIfUIElement);
dom.bind(editorRoot, name, preventFileDrop);
});
editor.on('remove', () => {
each$e(eventNames, name => {
pageDom.unbind(doc, name, preventFileDropIfUIElement);
dom.unbind(editorRoot, name, preventFileDrop);
});
});
};
editor.on('init', () => {
Delay.setEditorTimeout(editor, setup, 0);
});
};
const init$2 = editor => {
bindFakeDragEvents(editor);
if (shouldBlockUnsupportedDrop(editor)) {
blockUnsupportedFileDrop(editor);
}
};
const setup$4 = editor => {
const renderFocusCaret = first$1(() => {
if (!editor.removed && editor.getBody().contains(document.activeElement)) {
const rng = editor.selection.getRng();
if (rng.collapsed) {
const caretRange = renderRangeCaret(editor, rng, false);
editor.selection.setRng(caretRange);
}
}
}, 0);
editor.on('focus', () => {
renderFocusCaret.throttle();
});
editor.on('blur', () => {
renderFocusCaret.cancel();
});
};
const setup$3 = editor => {
editor.on('init', () => {
editor.on('focusin', e => {
const target = e.target;
if (isMedia$2(target)) {
const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target;
if (editor.selection.getNode() !== node) {
selectNode(editor, node).each(rng => editor.selection.setRng(rng));
}
}
});
});
};
const isContentEditableFalse = isContentEditableFalse$b;
const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
const SelectionOverrides = editor => {
const selection = editor.selection, dom = editor.dom;
const rootNode = editor.getBody();
const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor));
const realSelectionId = 'sel-' + dom.uniqueId();
const elementSelectionAttr = 'data-mce-selected';
let selectedElement;
const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection');
const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode) && dom.isEditable(node.parentNode);
const setRange = range => {
if (range) {
selection.setRng(range);
}
};
const showCaret = (direction, node, before, scrollIntoView = true) => {
const e = editor.dispatch('ShowCaret', {
target: node,
direction,
before
});
if (e.isDefaultPrevented()) {
return null;
}
if (scrollIntoView) {
selection.scrollIntoView(node, direction === -1);
}
return fakeCaret.show(before, node);
};
const showBlockCaretContainer = blockCaretContainer => {
if (blockCaretContainer.hasAttribute('data-mce-caret')) {
showCaretContainerBlock(blockCaretContainer);
selection.scrollIntoView(blockCaretContainer);
}
};
const registerEvents = () => {
editor.on('click', e => {
if (!dom.isEditable(e.target)) {
e.preventDefault();
editor.focus();
}
});
editor.on('blur NewBlock', removeElementSelection);
editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition);
editor.on('tap', e => {
const targetElm = e.target;
const contentEditableRoot = getContentEditableRoot(editor, targetElm);
if (isContentEditableFalse(contentEditableRoot)) {
e.preventDefault();
selectNode(editor, contentEditableRoot).each(setElementSelection);
} else if (isFakeSelectionTargetElement(targetElm)) {
selectNode(editor, targetElm).each(setElementSelection);
}
}, true);
editor.on('mousedown', e => {
const targetElm = e.target;
if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) {
return;
}
if (!isXYInContentArea(editor, e.clientX, e.clientY)) {
return;
}
removeElementSelection();
hideFakeCaret();
const closestContentEditable = getContentEditableRoot(editor, targetElm);
if (isContentEditableFalse(closestContentEditable)) {
e.preventDefault();
selectNode(editor, closestContentEditable).each(setElementSelection);
} else {
closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => {
e.preventDefault();
const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
setRange(range);
if (isHTMLElement(closestContentEditable)) {
closestContentEditable.focus();
} else {
editor.getBody().focus();
}
});
}
});
editor.on('keypress', e => {
if (VK.modifierPressed(e)) {
return;
}
if (isContentEditableFalse(selection.getNode())) {
e.preventDefault();
}
});
editor.on('GetSelectionRange', e => {
let rng = e.range;
if (selectedElement) {
if (!selectedElement.parentNode) {
selectedElement = null;
return;
}
rng = rng.cloneRange();
rng.selectNode(selectedElement);
e.range = rng;
}
});
editor.on('SetSelectionRange', e => {
e.range = normalizeVoidElementSelection(e.range);
const rng = setElementSelection(e.range, e.forward);
if (rng) {
e.range = rng;
}
});
const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin';
editor.on('AfterSetSelectionRange', e => {
const rng = e.range;
const parent = rng.startContainer.parentElement;
if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) {
hideFakeCaret();
}
if (!isFakeSelectionElement(parent)) {
removeElementSelection();
}
});
init$2(editor);
setup$4(editor);
setup$3(editor);
};
const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
const normalizeVoidElementSelection = rng => {
const voidElements = editor.schema.getVoidElements();
const newRng = dom.createRng();
const startContainer = rng.startContainer;
const startOffset = rng.startOffset;
const endContainer = rng.endContainer;
const endOffset = rng.endOffset;
if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
if (startOffset === 0) {
newRng.setStartBefore(startContainer);
} else {
newRng.setStartAfter(startContainer);
}
} else {
newRng.setStart(startContainer, startOffset);
}
if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
if (endOffset === 0) {
newRng.setEndBefore(endContainer);
} else {
newRng.setEndAfter(endContainer);
}
} else {
newRng.setEnd(endContainer, endOffset);
}
return newRng;
};
const setupOffscreenSelection = (node, targetClone) => {
const body = SugarElement.fromDom(editor.getBody());
const doc = editor.getDoc();
const realSelectionContainer = descendant$1(body, '#' + realSelectionId).getOrThunk(() => {
const newContainer = SugarElement.fromHtml('', doc);
set$3(newContainer, 'id', realSelectionId);
append$1(body, newContainer);
return newContainer;
});
const newRange = dom.createRng();
empty(realSelectionContainer);
append(realSelectionContainer, [
SugarElement.fromText(nbsp, doc),
SugarElement.fromDom(targetClone),
SugarElement.fromText(nbsp, doc)
]);
newRange.setStart(realSelectionContainer.dom.firstChild, 1);
newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' });
focus$1(realSelectionContainer);
const sel = selection.getSel();
if (sel) {
sel.removeAllRanges();
sel.addRange(newRange);
}
return newRange;
};
const selectElement = elm => {
const targetClone = elm.cloneNode(true);
const e = editor.dispatch('ObjectSelected', {
target: elm,
targetClone
});
if (e.isDefaultPrevented()) {
return null;
}
const range = setupOffscreenSelection(elm, e.targetClone);
const nodeElm = SugarElement.fromDom(elm);
each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => {
if (!eq(nodeElm, elm)) {
remove$9(elm, elementSelectionAttr);
}
});
if (!dom.getAttrib(elm, elementSelectionAttr)) {
elm.setAttribute(elementSelectionAttr, '1');
}
selectedElement = elm;
hideFakeCaret();
return range;
};
const setElementSelection = (range, forward) => {
if (!range) {
return null;
}
if (range.collapsed) {
if (!isRangeInCaretContainer(range)) {
const dir = forward ? 1 : -1;
const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range);
const beforeNode = caretPosition.getNode(!forward);
if (isNonNullable(beforeNode)) {
if (isFakeCaretTarget(beforeNode)) {
return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
}
if (isCaretContainerInline(beforeNode) && isContentEditableFalse$b(beforeNode.nextSibling)) {
const rng = dom.createRng();
rng.setStart(beforeNode, 0);
rng.setEnd(beforeNode, 0);
return rng;
}
}
const afterNode = caretPosition.getNode(forward);
if (isNonNullable(afterNode)) {
if (isFakeCaretTarget(afterNode)) {
return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
}
if (isCaretContainerInline(afterNode) && isContentEditableFalse$b(afterNode.previousSibling)) {
const rng = dom.createRng();
rng.setStart(afterNode, 1);
rng.setEnd(afterNode, 1);
return rng;
}
}
}
return null;
}
let startContainer = range.startContainer;
let startOffset = range.startOffset;
const endOffset = range.endOffset;
if (isText$b(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
startContainer = startContainer.parentNode;
startOffset = dom.nodeIndex(startContainer);
startContainer = startContainer.parentNode;
}
if (!isElement$6(startContainer)) {
return null;
}
if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
const node = startContainer.childNodes[startOffset];
if (isFakeSelectionTargetElement(node)) {
return selectElement(node);
}
}
return null;
};
const removeElementSelection = () => {
if (selectedElement) {
selectedElement.removeAttribute(elementSelectionAttr);
}
descendant$1(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$4);
selectedElement = null;
};
const destroy = () => {
fakeCaret.destroy();
selectedElement = null;
};
const hideFakeCaret = () => {
fakeCaret.hide();
};
if (!isRtc(editor)) {
registerEvents();
}
return {
showCaret,
showBlockCaretContainer,
hideFakeCaret,
destroy
};
};
const getNormalizedTextOffset = (container, offset) => {
let normalizedOffset = offset;
for (let node = container.previousSibling; isText$b(node); node = node.previousSibling) {
normalizedOffset += node.data.length;
}
return normalizedOffset;
};
const generatePath = (dom, root, node, offset, normalized) => {
if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
return [];
}
const p = normalized && isText$b(node) ? [getNormalizedTextOffset(node, offset)] : [offset];
let current = node;
while (current !== root && current.parentNode) {
p.push(dom.nodeIndex(current, normalized));
current = current.parentNode;
}
return current === root ? p.reverse() : [];
};
const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => {
const start = generatePath(dom, root, startNode, startOffset, normalized);
const end = generatePath(dom, root, endNode, endOffset, normalized);
return {
start,
end
};
};
const resolvePath = (root, path) => {
const nodePath = path.slice();
const offset = nodePath.pop();
if (!isNumber(offset)) {
return Optional.none();
} else {
const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root));
return resolvedNode.bind(node => {
if (isText$b(node) && (offset < 0 || offset > node.data.length)) {
return Optional.none();
} else {
return Optional.some({
node,
offset
});
}
});
}
};
const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({
node: startNode,
offset: startOffset
}) => resolvePath(root, range.end).map(({
node: endNode,
offset: endOffset
}) => {
const rng = document.createRange();
rng.setStart(startNode, startOffset);
rng.setEnd(endNode, endOffset);
return rng;
}));
const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized);
const cleanEmptyNodes = (dom, node, isRoot) => {
if (node && dom.isEmpty(node) && !isRoot(node)) {
const parent = node.parentNode;
dom.remove(node, isText$b(node.firstChild) && isWhitespaceText(node.firstChild.data));
cleanEmptyNodes(dom, parent, isRoot);
}
};
const deleteRng = (dom, rng, isRoot, clean = true) => {
const startParent = rng.startContainer.parentNode;
const endParent = rng.endContainer.parentNode;
rng.deleteContents();
if (clean && !isRoot(rng.startContainer)) {
if (isText$b(rng.startContainer) && rng.startContainer.data.length === 0) {
dom.remove(rng.startContainer);
}
if (isText$b(rng.endContainer) && rng.endContainer.data.length === 0) {
dom.remove(rng.endContainer);
}
cleanEmptyNodes(dom, startParent, isRoot);
if (startParent !== endParent) {
cleanEmptyNodes(dom, endParent, isRoot);
}
}
};
const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
const resolveFromDynamicPatterns = (patternSet, block, beforeText) => {
const dynamicPatterns = patternSet.dynamicPatternsLookup({
text: beforeText,
block
});
return {
...patternSet,
blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns),
inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns)
};
};
const getBeforeText = (dom, block, node, offset) => {
const rng = dom.createRng();
rng.setStart(block, 0);
rng.setEnd(node, offset);
return rng.toString();
};
const newMarker = (dom, id) => dom.create('span', {
'data-mce-type': 'bookmark',
id
});
const rangeFromMarker = (dom, marker) => {
const rng = dom.createRng();
rng.setStartAfter(marker.start);
rng.setEndBefore(marker.end);
return rng;
};
const createMarker = (dom, markerPrefix, pathRange) => {
const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range');
const startNode = rng.startContainer;
const endNode = rng.endContainer;
const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
const startParentNode = textStart.parentNode;
const endParentNode = textEnd.parentNode;
return {
prefix: markerPrefix,
end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd),
start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart)
};
};
const removeMarker = (dom, marker, isRoot) => {
cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot);
cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot);
};
const isReplacementPattern = pattern => pattern.start.length === 0;
const matchesPattern = patternContent => (element, offset) => {
const text = element.data;
const searchText = text.substring(0, offset);
const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
const startIndex = searchText.lastIndexOf(patternContent);
if (startIndex !== -1) {
return startIndex + patternContent.length;
} else if (startEndIndex !== -1) {
return startEndIndex + 1;
} else {
return -1;
}
};
const findPatternStartFromSpot = (dom, pattern, block, spot) => {
const startPattern = pattern.start;
const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block);
return startSpot.bind(spot => {
var _a, _b;
const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1;
const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length;
if (isCompleteMatch) {
const rng = dom.createRng();
rng.setStart(spot.container, spot.offset - startPattern.length);
rng.setEnd(spot.container, spot.offset);
return Optional.some(rng);
} else {
const offset = spot.offset - startPattern.length;
return scanLeft(spot.container, offset, block).map(nextSpot => {
const rng = dom.createRng();
rng.setStart(nextSpot.container, nextSpot.offset);
rng.setEnd(spot.container, spot.offset);
return rng;
}).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0)));
}
});
};
const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => {
if (pattern.start.length === 0 && !requireGap) {
const rng = dom.createRng();
rng.setStart(node, offset);
rng.setEnd(node, offset);
return Optional.some(rng);
}
return textBefore(node, offset, block).bind(spot => {
const start = findPatternStartFromSpot(dom, pattern, block, spot);
return start.bind(startRange => {
var _a;
if (requireGap) {
if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
return Optional.none();
} else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) {
return Optional.none();
}
}
return Optional.some(startRange);
});
});
};
const findPattern$3 = (editor, block, details, normalizedMatches) => {
const dom = editor.dom;
const root = dom.getRoot();
const pattern = details.pattern;
const endNode = details.position.container;
const endOffset = details.position.offset;
return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => {
const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches);
if (isReplacementPattern(pattern)) {
return Optional.some({
matches: [{
pattern,
startRng: endPathRng,
endRng: endPathRng
}],
position: spot
});
} else {
const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches);
const results = resultsOpt.getOr({
matches: [],
position: spot
});
const pos = results.position;
const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
return start.map(startRng => {
const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches);
return {
matches: results.matches.concat([{
pattern,
startRng: startPathRng,
endRng: endPathRng
}]),
position: point(startRng.startContainer, startRng.startOffset)
};
});
}
});
};
const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => {
const dom = editor.dom;
return textBefore(node, offset, dom.getRoot()).bind(endSpot => {
const text = getBeforeText(dom, block, node, offset);
for (let i = 0; i < patterns.length; i++) {
const pattern = patterns[i];
if (!endsWith(text, pattern.end)) {
continue;
}
const patternsWithoutCurrent = patterns.slice();
patternsWithoutCurrent.splice(i, 1);
const result = findPattern$3(editor, block, {
pattern,
remainingPatterns: patternsWithoutCurrent,
position: endSpot
}, normalizedMatches);
if (result.isNone() && offset > 0) {
return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches);
}
if (result.isSome()) {
return result;
}
}
return Optional.none();
});
};
const applyPattern$2 = (editor, pattern, patternRange) => {
editor.selection.setRng(patternRange);
if (pattern.type === 'inline-format') {
each$e(pattern.format, format => {
editor.formatter.apply(format);
});
} else {
editor.execCommand(pattern.cmd, false, pattern.value);
}
};
const applyReplacementPattern = (editor, pattern, marker, isRoot) => {
const markerRange = rangeFromMarker(editor.dom, marker);
deleteRng(editor.dom, markerRange, isRoot);
applyPattern$2(editor, pattern, markerRange);
};
const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => {
const dom = editor.dom;
const markerEndRange = rangeFromMarker(dom, endMarker);
const markerStartRange = rangeFromMarker(dom, startMarker);
deleteRng(dom, markerStartRange, isRoot);
deleteRng(dom, markerEndRange, isRoot);
const patternMarker = {
prefix: startMarker.prefix,
start: startMarker.end,
end: endMarker.start
};
const patternRange = rangeFromMarker(dom, patternMarker);
applyPattern$2(editor, pattern, patternRange);
};
const addMarkers = (dom, matches) => {
const markerPrefix = generate$1('mce_textpattern');
const matchesWithEnds = foldr(matches, (acc, match) => {
const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng);
return acc.concat([{
...match,
endMarker
}]);
}, []);
return foldr(matchesWithEnds, (acc, match) => {
const idx = matchesWithEnds.length - acc.length - 1;
const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng);
return acc.concat([{
...match,
startMarker
}]);
}, []);
};
const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.end.length - a.end.length);
const getBestMatches = (matches, matchesWithSortedPatterns) => {
const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end));
if (matches.length === matchesWithSortedPatterns.length) {
if (hasSameMatches) {
return matches;
} else {
return matchesWithSortedPatterns;
}
}
return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns;
};
const findPatterns$2 = (editor, block, node, offset, patternSet, normalizedMatches) => {
const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns$1(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
return getBestMatches(matches, matchesWithSortedPatterns);
};
const applyMatches$2 = (editor, matches) => {
if (matches.length === 0) {
return;
}
const dom = editor.dom;
const bookmark = editor.selection.getBookmark();
const matchesWithMarkers = addMarkers(dom, matches);
each$e(matchesWithMarkers, match => {
const block = dom.getParent(match.startMarker.start, dom.isBlock);
const isRoot = node => node === block;
if (isReplacementPattern(match.pattern)) {
applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot);
} else {
applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot);
}
removeMarker(dom, match.endMarker, isRoot);
removeMarker(dom, match.startMarker, isRoot);
});
editor.selection.moveToBookmark(bookmark);
};
const stripPattern$1 = (dom, block, pattern) => {
return textAfter(block, 0, block).map(spot => {
const node = spot.container;
scanRight(node, pattern.start.length, block).each(end => {
const rng = dom.createRng();
rng.setStart(node, 0);
rng.setEnd(end.container, end.offset);
deleteRng(dom, rng, e => e === block);
});
return node;
});
};
const createApplyPattern = stripPattern => (editor, match) => {
const dom = editor.dom;
const pattern = match.pattern;
const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range');
const isBlockFormatName = (name, formatter) => {
const formatSet = formatter.get(name);
return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block'));
};
getParentBlock(editor, rng).each(block => {
if (pattern.type === 'block-format') {
if (isBlockFormatName(pattern.format, editor.formatter)) {
editor.undoManager.transact(() => {
stripPattern(editor.dom, block, pattern);
editor.formatter.apply(pattern.format);
});
}
} else if (pattern.type === 'block-command') {
editor.undoManager.transact(() => {
stripPattern(editor.dom, block, pattern);
editor.execCommand(pattern.cmd, false, pattern.value);
});
}
});
return true;
};
const sortPatterns = patterns => sort(patterns, (a, b) => b.start.length - a.start.length);
const findPattern$2 = predicate => (patterns, text) => {
const sortedPatterns = sortPatterns(patterns);
const nuText = text.replace(nbsp, ' ');
return find$2(sortedPatterns, pattern => predicate(pattern, text, nuText));
};
const createFindPatterns = (findPattern, skipFullMatch) => (editor, block, patternSet, normalizedMatches, text) => {
var _a;
if (text === void 0) {
text = (_a = block.textContent) !== null && _a !== void 0 ? _a : '';
}
const dom = editor.dom;
const forcedRootBlock = getForcedRootBlock(editor);
if (!dom.is(block, forcedRootBlock)) {
return [];
}
return findPattern(patternSet.blockPatterns, text).map(pattern => {
if (skipFullMatch && Tools.trim(text).length === pattern.start.length) {
return [];
}
return [{
pattern,
range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches)
}];
}).getOr([]);
};
const startsWithSingleSpace = s => /^\s[^\s]/.test(s);
const stripPattern = (dom, block, pattern) => {
stripPattern$1(dom, block, pattern).each(node => {
const text = SugarElement.fromDom(node);
const textContent = get$3(text);
if (startsWithSingleSpace(textContent)) {
set(text, textContent.slice(1));
}
});
};
const applyPattern$1 = createApplyPattern(stripPattern);
const findPattern$1 = findPattern$2((pattern, text, nuText) => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
const findPatterns$1 = createFindPatterns(findPattern$1, true);
const getMatches$1 = (editor, patternSet) => {
const rng = editor.selection.getRng();
return getParentBlock(editor, rng).map(block => {
var _a;
const offset = Math.max(0, rng.startOffset);
const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : '');
const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, true);
const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true);
return {
inlineMatches,
blockMatches
};
}).filter(({inlineMatches, blockMatches}) => blockMatches.length > 0 || inlineMatches.length > 0);
};
const applyMatches$1 = (editor, matches) => {
if (matches.length === 0) {
return;
}
const bookmark = editor.selection.getBookmark();
each$e(matches, match => applyPattern$1(editor, match));
editor.selection.moveToBookmark(bookmark);
};
const applyPattern = createApplyPattern(stripPattern$1);
const findPattern = findPattern$2((pattern, text, nuText) => text === pattern.start || nuText === pattern.start);
const findPatterns = createFindPatterns(findPattern, false);
const getMatches = (editor, patternSet) => {
const rng = editor.selection.getRng();
return getParentBlock(editor, rng).map(block => {
const offset = Math.max(0, rng.startOffset);
const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
return findPatterns(editor, block, dynamicPatternSet, false, beforeText);
}).filter(matches => matches.length > 0);
};
const applyMatches = (editor, matches) => {
each$e(matches, match => applyPattern(editor, match));
};
const handleEnter = (editor, patternSet) => getMatches$1(editor, patternSet).fold(never, ({inlineMatches, blockMatches}) => {
editor.undoManager.add();
editor.undoManager.extra(() => {
editor.execCommand('mceInsertNewLine');
}, () => {
insert$5(editor);
applyMatches$2(editor, inlineMatches);
applyMatches$1(editor, blockMatches);
const range = editor.selection.getRng();
const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot());
editor.execCommand('mceInsertNewLine');
spot.each(s => {
const node = s.container;
if (node.data.charAt(s.offset - 1) === zeroWidth) {
node.deleteData(s.offset - 1, 1);
cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot());
}
});
});
return true;
});
const handleInlineKey = (editor, patternSet) => {
const rng = editor.selection.getRng();
getParentBlock(editor, rng).map(block => {
const offset = Math.max(0, rng.startOffset - 1);
const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
const inlineMatches = findPatterns$2(editor, block, rng.startContainer, offset, dynamicPatternSet, false);
if (inlineMatches.length > 0) {
editor.undoManager.transact(() => {
applyMatches$2(editor, inlineMatches);
});
}
});
};
const handleBlockPatternOnSpace = (editor, patternSet) => getMatches(editor, patternSet).fold(never, matches => {
editor.undoManager.transact(() => {
applyMatches(editor, matches);
});
return true;
});
const checkKeyEvent = (codes, event, predicate) => {
for (let i = 0; i < codes.length; i++) {
if (predicate(codes[i], event)) {
return true;
}
}
return false;
};
const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => {
return code === event.keyCode && !VK.modifierPressed(event);
});
const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => {
return chr.charCodeAt(0) === event.charCode;
});
const setup$2 = editor => {
const charCodes = [
',',
'.',
';',
':',
'!',
'?'
];
const keyCodes = [32];
const getPatternSet = () => createPatternSet(getTextPatterns(editor).filter(pattern => {
if (pattern.type === 'inline-command' || pattern.type === 'block-command') {
return editor.queryCommandSupported(pattern.cmd);
}
return true;
}), getTextPatternsLookup(editor));
const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
editor.on('keydown', e => {
if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
const patternSet = filterByTrigger(getPatternSet(), 'enter');
const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
if (hasPatterns && handleEnter(editor, patternSet)) {
e.preventDefault();
}
}
}, true);
editor.on('keydown', e => {
if (e.keyCode === 32 && editor.selection.isCollapsed()) {
const patternSet = filterByTrigger(getPatternSet(), 'space');
const hasPatterns = patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
if (hasPatterns && handleBlockPatternOnSpace(editor, patternSet)) {
e.preventDefault();
}
}
}, true);
const handleInlineTrigger = () => {
if (editor.selection.isCollapsed()) {
const patternSet = filterByTrigger(getPatternSet(), 'space');
const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
if (hasPatterns) {
handleInlineKey(editor, patternSet);
}
}
};
editor.on('keyup', e => {
if (checkKeyCode(keyCodes, e)) {
handleInlineTrigger();
}
});
editor.on('keypress', e => {
if (checkCharCode(charCodes, e)) {
Delay.setEditorTimeout(editor, handleInlineTrigger);
}
});
};
const setup$1 = editor => {
setup$2(editor);
};
const Quirks = editor => {
const each = Tools.each;
const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser;
const browser = Env.browser;
const isGecko = browser.isFirefox();
const isWebKit = browser.isChromium() || browser.isSafari();
const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
const isMac = Env.os.isMacOS() || Env.os.isiOS();
const setEditorCommandState = (cmd, state) => {
try {
editor.getDoc().execCommand(cmd, false, String(state));
} catch (ex) {
}
};
const isDefaultPrevented = e => {
return e.isDefaultPrevented();
};
const emptyEditorWhenDeleting = () => {
const serializeRng = rng => {
const body = dom.create('body');
const contents = rng.cloneContents();
body.appendChild(contents);
return selection.serializer.serialize(body, { format: 'html' });
};
const allContentsSelected = rng => {
const selection = serializeRng(rng);
const allRng = dom.createRng();
allRng.selectNode(editor.getBody());
const allSelection = serializeRng(allRng);
return selection === allSelection;
};
editor.on('keydown', e => {
const keyCode = e.keyCode;
if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE) && editor.selection.isEditable()) {
const isCollapsed = editor.selection.isCollapsed();
const body = editor.getBody();
if (isCollapsed && !isEmptyNode(editor.schema, body)) {
return;
}
if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
return;
}
e.preventDefault();
editor.setContent('');
if (body.firstChild && dom.isBlock(body.firstChild)) {
editor.selection.setCursorLocation(body.firstChild, 0);
} else {
editor.selection.setCursorLocation(body, 0);
}
editor.nodeChanged();
}
});
};
const selectAll = () => {
editor.shortcuts.add('meta+a', null, 'SelectAll');
};
const documentElementEditingFocus = () => {
if (!editor.inline) {
dom.bind(editor.getDoc(), 'mousedown mouseup', e => {
let rng;
if (e.target === editor.getDoc().documentElement) {
rng = selection.getRng();
editor.getBody().focus();
if (e.type === 'mousedown') {
if (isCaretContainer$2(rng.startContainer)) {
return;
}
selection.placeCaretAt(e.clientX, e.clientY);
} else {
selection.setRng(rng);
}
}
});
}
};
const removeHrOnBackspace = () => {
editor.on('keydown', e => {
if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
if (!editor.getBody().getElementsByTagName('hr').length) {
return;
}
if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
const node = selection.getNode();
const previousSibling = node.previousSibling;
if (node.nodeName === 'HR') {
dom.remove(node);
e.preventDefault();
return;
}
if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
dom.remove(previousSibling);
e.preventDefault();
}
}
}
});
};
const focusBody = () => {
if (!Range.prototype.getClientRects) {
editor.on('mousedown', e => {
if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
const body = editor.getBody();
body.blur();
Delay.setEditorTimeout(editor, () => {
body.focus();
});
}
});
}
};
const selectControlElements = () => {
const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
editor.on('click', e => {
const target = e.target;
if (/^(IMG|HR)$/.test(target.nodeName) && dom.isEditable(target)) {
e.preventDefault();
editor.selection.select(target);
editor.nodeChanged();
}
if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0 && dom.isEditable(target.parentNode)) {
e.preventDefault();
selection.select(target);
}
});
};
const removeStylesWhenDeletingAcrossBlockElements = () => {
const getAttributeApplyFunction = () => {
const template = dom.getAttribs(selection.getStart().cloneNode(false));
return () => {
const target = selection.getStart();
if (target !== editor.getBody()) {
dom.setAttrib(target, 'style', null);
each(template, attr => {
target.setAttributeNode(attr.cloneNode(true));
});
}
};
};
const isSelectionAcrossElements = () => {
return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
};
editor.on('keypress', e => {
let applyAttributes;
if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
applyAttributes = getAttributeApplyFunction();
editor.getDoc().execCommand('delete', false);
applyAttributes();
e.preventDefault();
return false;
} else {
return true;
}
});
dom.bind(editor.getDoc(), 'cut', e => {
if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
const applyAttributes = getAttributeApplyFunction();
Delay.setEditorTimeout(editor, () => {
applyAttributes();
});
}
});
};
const disableBackspaceIntoATable = () => {
editor.on('keydown', e => {
if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
const previousSibling = selection.getNode().previousSibling;
if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
e.preventDefault();
return false;
}
}
}
return true;
});
};
const removeBlockQuoteOnBackSpace = () => {
editor.on('keydown', e => {
if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
return;
}
let rng = selection.getRng();
const container = rng.startContainer;
const offset = rng.startOffset;
const root = dom.getRoot();
let parent = container;
if (!rng.collapsed || offset !== 0) {
return;
}
while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
parent = parent.parentNode;
}
if (parent.nodeName === 'BLOCKQUOTE') {
editor.formatter.toggle('blockquote', undefined, parent);
rng = dom.createRng();
rng.setStart(container, 0);
rng.setEnd(container, 0);
selection.setRng(rng);
}
});
};
const setGeckoEditingOptions = () => {
const setOpts = () => {
setEditorCommandState('StyleWithCSS', false);
setEditorCommandState('enableInlineTableEditing', false);
if (!getObjectResizing(editor)) {
setEditorCommandState('enableObjectResizing', false);
}
};
if (!isReadOnly$1(editor)) {
editor.on('BeforeExecCommand mousedown', setOpts);
}
};
const addBrAfterLastLinks = () => {
const fixLinks = () => {
each(dom.select('a:not([data-mce-block])'), node => {
var _a;
let parentNode = node.parentNode;
const root = dom.getRoot();
if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) {
while (parentNode && !dom.isBlock(parentNode)) {
if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) {
return;
}
parentNode = parentNode.parentNode;
}
dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
}
});
};
editor.on('SetContent ExecCommand', e => {
if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
fixLinks();
}
});
};
const setDefaultBlockType = () => {
editor.on('init', () => {
setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor));
});
};
const isAllContentSelected = editor => {
const body = editor.getBody();
const rng = editor.selection.getRng();
return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
};
const normalizeSelection = () => {
editor.on('keyup focusin mouseup', e => {
if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
selection.normalize();
}
}, true);
};
const showBrokenImageIcon = () => {
editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
};
const restoreFocusOnKeyDown = () => {
if (!editor.inline) {
editor.on('keydown', () => {
if (document.activeElement === document.body) {
editor.getWin().focus();
}
});
}
};
const bodyHeight = () => {
if (!editor.inline) {
editor.contentStyles.push('body {min-height: 150px}');
editor.on('click', e => {
let rng;
if (e.target.nodeName === 'HTML') {
rng = editor.selection.getRng();
editor.getBody().focus();
editor.selection.setRng(rng);
editor.selection.normalize();
editor.nodeChanged();
}
});
}
};
const blockCmdArrowNavigation = () => {
if (isMac) {
editor.on('keydown', e => {
if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
e.preventDefault();
const selection = editor.selection.getSel();
selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
}
});
}
};
const tapLinksAndImages = () => {
editor.on('click', e => {
let elm = e.target;
do {
if (elm.tagName === 'A') {
e.preventDefault();
return;
}
} while (elm = elm.parentNode);
});
editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
};
const blockFormSubmitInsideEditor = () => {
editor.on('init', () => {
editor.dom.bind(editor.getBody(), 'submit', e => {
e.preventDefault();
});
});
};
const removeAppleInterchangeBrs = () => {
parser.addNodeFilter('br', nodes => {
let i = nodes.length;
while (i--) {
if (nodes[i].attr('class') === 'Apple-interchange-newline') {
nodes[i].remove();
}
}
});
};
const refreshContentEditable = noop;
const isHidden = () => {
if (!isGecko || editor.removed) {
return false;
}
const sel = editor.selection.getSel();
return !sel || !sel.rangeCount || sel.rangeCount === 0;
};
const setupRtc = () => {
if (isWebKit) {
documentElementEditingFocus();
selectControlElements();
blockFormSubmitInsideEditor();
selectAll();
if (isiOS) {
restoreFocusOnKeyDown();
bodyHeight();
tapLinksAndImages();
}
}
if (isGecko) {
focusBody();
setGeckoEditingOptions();
showBrokenImageIcon();
blockCmdArrowNavigation();
}
};
const setup = () => {
removeBlockQuoteOnBackSpace();
emptyEditorWhenDeleting();
if (!Env.windowsPhone) {
normalizeSelection();
}
if (isWebKit) {
documentElementEditingFocus();
selectControlElements();
setDefaultBlockType();
blockFormSubmitInsideEditor();
disableBackspaceIntoATable();
removeAppleInterchangeBrs();
if (isiOS) {
restoreFocusOnKeyDown();
bodyHeight();
tapLinksAndImages();
} else {
selectAll();
}
}
if (isGecko) {
removeHrOnBackspace();
focusBody();
removeStylesWhenDeletingAcrossBlockElements();
setGeckoEditingOptions();
addBrAfterLastLinks();
showBrokenImageIcon();
blockCmdArrowNavigation();
disableBackspaceIntoATable();
}
};
if (isRtc(editor)) {
setupRtc();
} else {
setup();
}
return {
refreshContentEditable,
isHidden
};
};
const isGplKey = key => key.toLowerCase() === 'gpl';
const isValidGeneratedKey = key => key.length >= 64 && key.length <= 255;
const validateLicenseKey = key => isGplKey(key) || isValidGeneratedKey(key) ? 'VALID' : 'INVALID';
const validateEditorLicenseKey = editor => {
const licenseKey = getLicenseKey(editor);
const hasApiKey = isString(getApiKey(editor));
if (!hasApiKey && (isUndefined(licenseKey) || validateLicenseKey(licenseKey) === 'INVALID')) {
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/`);
}
};
const DOM$6 = DOMUtils.DOM;
const appendStyle = (editor, text) => {
const body = SugarElement.fromDom(editor.getBody());
const container = getStyleContainer(getRootNode(body));
const style = SugarElement.fromTag('style');
set$3(style, 'type', 'text/css');
append$1(style, SugarElement.fromText(text));
append$1(container, style);
editor.on('remove', () => {
remove$4(style);
});
};
const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined;
const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false);
const mkParserSettings = editor => {
const getOption = editor.options.get;
const blobCache = editor.editorUpload.blobCache;
return removeUndefined({
allow_conditional_comments: getOption('allow_conditional_comments'),
allow_html_data_urls: getOption('allow_html_data_urls'),
allow_svg_data_urls: getOption('allow_svg_data_urls'),
allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
allow_script_urls: getOption('allow_script_urls'),
allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
convert_unsafe_embeds: getOption('convert_unsafe_embeds'),
convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
fix_list_elements: getOption('fix_list_elements'),
font_size_legacy_values: getOption('font_size_legacy_values'),
forced_root_block: getOption('forced_root_block'),
forced_root_block_attrs: getOption('forced_root_block_attrs'),
preserve_cdata: getOption('preserve_cdata'),
inline_styles: getOption('inline_styles'),
root_name: getRootName(editor),
sandbox_iframes: getOption('sandbox_iframes'),
sandbox_iframes_exclusions: getSandboxIframesExclusions(editor),
sanitize: getOption('xss_sanitization'),
validate: true,
blob_cache: blobCache,
document: editor.getDoc()
});
};
const mkSchemaSettings = editor => {
const getOption = editor.options.get;
return removeUndefined({
custom_elements: getOption('custom_elements'),
extended_valid_elements: getOption('extended_valid_elements'),
invalid_elements: getOption('invalid_elements'),
invalid_styles: getOption('invalid_styles'),
schema: getOption('schema'),
valid_children: getOption('valid_children'),
valid_classes: getOption('valid_classes'),
valid_elements: getOption('valid_elements'),
valid_styles: getOption('valid_styles'),
verify_html: getOption('verify_html'),
padd_empty_block_inline_children: getOption('format_empty_lines')
});
};
const mkSerializerSettings = editor => {
const getOption = editor.options.get;
return {
...mkParserSettings(editor),
...mkSchemaSettings(editor),
...removeUndefined({
remove_trailing_brs: getOption('remove_trailing_brs'),
pad_empty_with_br: getOption('pad_empty_with_br'),
url_converter: getOption('url_converter'),
url_converter_scope: getOption('url_converter_scope'),
element_format: getOption('element_format'),
entities: getOption('entities'),
entity_encoding: getOption('entity_encoding'),
indent: getOption('indent'),
indent_after: getOption('indent_after'),
indent_before: getOption('indent_before')
})
};
};
const createParser = editor => {
const parser = DomParser(mkParserSettings(editor), editor.schema);
parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => {
const dom = editor.dom;
const internalName = 'data-mce-' + name;
let i = nodes.length;
while (i--) {
const node = nodes[i];
let value = node.attr(name);
if (value && !node.attr(internalName)) {
if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
continue;
}
if (name === 'style') {
value = dom.serializeStyle(dom.parseStyle(value), node.name);
if (!value.length) {
value = null;
}
node.attr(internalName, value);
node.attr(name, value);
} else if (name === 'tabindex') {
node.attr(internalName, value);
node.attr(name, null);
} else {
node.attr(internalName, editor.convertURL(value, name, node.name));
}
}
}
});
parser.addNodeFilter('script', nodes => {
let i = nodes.length;
while (i--) {
const node = nodes[i];
const type = node.attr('type') || 'no/type';
if (type.indexOf('mce-') !== 0) {
node.attr('type', 'mce-' + type);
}
}
});
if (shouldPreserveCData(editor)) {
parser.addNodeFilter('#cdata', nodes => {
var _a;
let i = nodes.length;
while (i--) {
const node = nodes[i];
node.type = 8;
node.name = '#comment';
node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]';
}
});
}
parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => {
let i = nodes.length;
const nonEmptyElements = editor.schema.getNonEmptyElements();
while (i--) {
const node = nodes[i];
if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
node.append(new AstNode('br', 1));
}
}
});
return parser;
};
const autoFocus = editor => {
const autoFocus = getAutoFocus(editor);
if (autoFocus) {
Delay.setEditorTimeout(editor, () => {
let focusEditor;
if (autoFocus === true) {
focusEditor = editor;
} else {
focusEditor = editor.editorManager.get(autoFocus);
}
if (focusEditor && !focusEditor.destroyed) {
focusEditor.focus();
focusEditor.selection.scrollIntoView();
}
}, 100);
}
};
const moveSelectionToFirstCaretPosition = editor => {
const root = editor.dom.getRoot();
if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
firstPositionIn(root).each(pos => {
const node = pos.getNode();
const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
editor.selection.setRng(caretPos.toRange());
});
}
};
const initEditor = editor => {
editor.bindPendingEventDelegates();
editor.initialized = true;
fireInit(editor);
editor.focus(true);
moveSelectionToFirstCaretPosition(editor);
editor.nodeChanged({ initial: true });
const initInstanceCallback = getInitInstanceCallback(editor);
if (isFunction(initInstanceCallback)) {
initInstanceCallback.call(editor, editor);
}
autoFocus(editor);
};
const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
const {
pass: bundledCss,
fail: normalCss
} = partition$2(css, name => tinymce.Resource.has(toContentSkinResourceName(name)));
const bundledPromises = bundledCss.map(url => {
const css = tinymce.Resource.get(toContentSkinResourceName(url));
if (isString(css)) {
return Promise.resolve(getStyleSheetLoader$1(editor).loadRawCss(url, css));
}
return Promise.resolve();
});
const promises = [
...bundledPromises,
getStyleSheetLoader$1(editor).loadAll(normalCss)
];
if (editor.inline) {
return promises;
} else {
return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
}
};
const loadContentCss = editor => {
const styleSheetLoader = getStyleSheetLoader$1(editor);
const fontCss = getFontCss(editor);
const css = editor.contentCSS;
const removeCss = () => {
styleSheetLoader.unloadAll(css);
if (!editor.inline) {
editor.ui.styleSheetLoader.unloadAll(fontCss);
}
};
const loaded = () => {
if (editor.removed) {
removeCss();
} else {
editor.on('remove', removeCss);
}
};
if (editor.contentStyles.length > 0) {
let contentCssText = '';
Tools.each(editor.contentStyles, style => {
contentCssText += style + '\r\n';
});
editor.dom.addStyle(contentCssText);
}
const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
const contentStyle = getContentStyle(editor);
if (contentStyle) {
appendStyle(editor, contentStyle);
}
return allStylesheets;
};
const preInit = editor => {
const doc = editor.getDoc(), body = editor.getBody();
firePreInit(editor);
if (!shouldBrowserSpellcheck(editor)) {
doc.body.spellcheck = false;
DOM$6.setAttrib(body, 'spellcheck', 'false');
}
editor.quirks = Quirks(editor);
firePostRender(editor);
const directionality = getDirectionality(editor);
if (directionality !== undefined) {
body.dir = directionality;
}
const protect = getProtect(editor);
if (protect) {
editor.on('BeforeSetContent', e => {
Tools.each(protect, pattern => {
e.content = e.content.replace(pattern, str => {
return '';
});
});
});
}
editor.on('SetContent', () => {
editor.addVisual(editor.getBody());
});
editor.on('compositionstart compositionend', e => {
editor.composing = e.type === 'compositionstart';
});
};
const loadInitialContent = editor => {
if (!isRtc(editor)) {
editor.load({
initial: true,
format: 'html'
});
}
editor.startContent = editor.getContent({ format: 'raw' });
};
const initEditorWithInitialContent = editor => {
if (editor.removed !== true) {
loadInitialContent(editor);
initEditor(editor);
}
};
const startProgress = editor => {
let canceled = false;
const progressTimeout = setTimeout(() => {
if (!canceled) {
editor.setProgressState(true);
}
}, 500);
return () => {
clearTimeout(progressTimeout);
canceled = true;
editor.setProgressState(false);
};
};
const contentBodyLoaded = editor => {
const targetElm = editor.getElement();
let doc = editor.getDoc();
if (editor.inline) {
DOM$6.addClass(targetElm, 'mce-content-body');
editor.contentDocument = doc = document;
editor.contentWindow = window;
editor.bodyElement = targetElm;
editor.contentAreaContainer = targetElm;
}
const body = editor.getBody();
body.disabled = true;
editor.readonly = isReadOnly$1(editor);
editor._editableRoot = hasEditableRoot$1(editor);
if (!editor.readonly && editor.hasEditableRoot()) {
if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
body.style.position = 'relative';
}
body.contentEditable = 'true';
}
body.disabled = false;
editor.editorUpload = EditorUpload(editor);
editor.schema = Schema(mkSchemaSettings(editor));
editor.dom = DOMUtils(doc, {
keep_values: true,
url_converter: editor.convertURL,
url_converter_scope: editor,
update_styles: true,
root_element: editor.inline ? editor.getBody() : null,
collect: editor.inline,
schema: editor.schema,
contentCssCors: shouldUseContentCssCors(editor),
referrerPolicy: getReferrerPolicy(editor),
onSetAttrib: e => {
editor.dispatch('SetAttrib', e);
}
});
editor.parser = createParser(editor);
editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
editor.annotator = Annotator(editor);
editor.formatter = Formatter(editor);
editor.undoManager = UndoManager(editor);
editor._nodeChangeDispatcher = new NodeChange(editor);
editor._selectionOverrides = SelectionOverrides(editor);
setup$p(editor);
setup$6(editor);
setup$n(editor);
if (!isRtc(editor)) {
setup$5(editor);
setup$1(editor);
}
const caret = setup$b(editor);
setup$q(editor, caret);
setup$o(editor);
setup$r(editor);
setup$7(editor);
const setupRtcThunk = setup$t(editor);
preInit(editor);
validateEditorLicenseKey(editor);
setupRtcThunk.fold(() => {
const cancelProgress = startProgress(editor);
loadContentCss(editor).then(() => {
initEditorWithInitialContent(editor);
cancelProgress();
});
}, setupRtc => {
editor.setProgressState(true);
loadContentCss(editor).then(() => {
setupRtc().then(_rtcMode => {
editor.setProgressState(false);
initEditorWithInitialContent(editor);
bindEvents(editor);
}, err => {
editor.notificationManager.open({
type: 'error',
text: String(err)
});
initEditorWithInitialContent(editor);
bindEvents(editor);
});
});
});
};
const filter = always;
const bind = (element, event, handler) => bind$2(element, event, filter, handler);
const DOM$5 = DOMUtils.DOM;
const createIframeElement = (id, title, customAttrs, tabindex) => {
const iframe = SugarElement.fromTag('iframe');
tabindex.each(t => set$3(iframe, 'tabindex', t));
setAll$1(iframe, customAttrs);
setAll$1(iframe, {
id: id + '_ifr',
frameBorder: '0',
allowTransparency: 'true',
title
});
add$2(iframe, 'tox-edit-area__iframe');
return iframe;
};
const getIframeHtml = editor => {
let iframeHTML = getDocType(editor) + '';
if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
iframeHTML += ' ';
}
iframeHTML += '';
const bodyId = getBodyId(editor);
const bodyClass = getBodyClass(editor);
const translatedAriaText = editor.translate(getIframeAriaText(editor));
if (getContentSecurityPolicy(editor)) {
iframeHTML += '';
}
iframeHTML += '' + `` + '
' + '';
return iframeHTML;
};
const createIframe = (editor, boxInfo) => {
const iframeTitle = Env.browser.isFirefox() ? getIframeAriaText(editor) : 'Rich Text Area';
const translatedTitle = editor.translate(iframeTitle);
const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt);
const ifr = createIframeElement(editor.id, translatedTitle, getIframeAttrs(editor), tabindex).dom;
ifr.onload = () => {
ifr.onload = null;
editor.dispatch('load');
};
editor.contentAreaContainer = boxInfo.iframeContainer;
editor.iframeElement = ifr;
editor.iframeHTML = getIframeHtml(editor);
DOM$5.add(boxInfo.iframeContainer, ifr);
};
const setupIframeBody = editor => {
const iframe = editor.iframeElement;
const ready = () => {
editor.contentDocument = iframe.contentDocument;
contentBodyLoaded(editor);
};
if (shouldUseDocumentWrite(editor) || Env.browser.isFirefox()) {
const doc = editor.getDoc();
doc.open();
doc.write(editor.iframeHTML);
doc.close();
ready();
} else {
const binder = bind(SugarElement.fromDom(iframe), 'load', () => {
binder.unbind();
ready();
});
iframe.srcdoc = editor.iframeHTML;
}
};
const init$1 = (editor, boxInfo) => {
createIframe(editor, boxInfo);
if (boxInfo.editorContainer) {
boxInfo.editorContainer.style.display = editor.orgDisplay;
editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
}
editor.getElement().style.display = 'none';
DOM$5.setAttrib(editor.id, 'aria-hidden', 'true');
editor.getElement().style.visibility = editor.orgVisibility;
setupIframeBody(editor);
};
const DOM$4 = DOMUtils.DOM;
const initPlugin = (editor, initializedPlugins, plugin) => {
const Plugin = PluginManager.get(plugin);
const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
plugin = Tools.trim(plugin);
if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
if (editor.plugins[plugin]) {
return;
}
try {
const pluginInstance = Plugin(editor, pluginUrl) || {};
editor.plugins[plugin] = pluginInstance;
if (isFunction(pluginInstance.init)) {
pluginInstance.init(editor, pluginUrl);
initializedPlugins.push(plugin);
}
} catch (e) {
pluginInitError(editor, plugin, e);
}
}
};
const trimLegacyPrefix = name => {
return name.replace(/^\-/, '');
};
const initPlugins = editor => {
const initializedPlugins = [];
each$e(getPlugins(editor), name => {
initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
});
};
const initIcons = editor => {
const iconPackName = Tools.trim(getIconPackName(editor));
const currentIcons = editor.ui.registry.getAll().icons;
const loadIcons = {
...IconManager.get('default').icons,
...IconManager.get(iconPackName).icons
};
each$d(loadIcons, (svgData, icon) => {
if (!has$2(currentIcons, icon)) {
editor.ui.registry.addIcon(icon, svgData);
}
});
};
const initTheme = editor => {
const theme = getTheme(editor);
if (isString(theme)) {
const Theme = ThemeManager.get(theme);
editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
if (isFunction(editor.theme.init)) {
editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''));
}
} else {
editor.theme = {};
}
};
const initModel = editor => {
const model = getModel(editor);
const Model = ModelManager.get(model);
editor.model = Model(editor, ModelManager.urls[model]);
};
const renderFromLoadedTheme = editor => {
const render = editor.theme.renderUI;
return render ? render() : renderThemeFalse(editor);
};
const renderFromThemeFunc = editor => {
const elm = editor.getElement();
const theme = getTheme(editor);
const info = theme(editor, elm);
if (info.editorContainer.nodeType) {
info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
}
if (info.iframeContainer && info.iframeContainer.nodeType) {
info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
}
info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
return info;
};
const createThemeFalseResult = (element, iframe) => {
return {
editorContainer: element,
iframeContainer: iframe,
api: {}
};
};
const renderThemeFalseIframe = targetElement => {
const iframeContainer = DOM$4.create('div');
DOM$4.insertAfter(iframeContainer, targetElement);
return createThemeFalseResult(iframeContainer, iframeContainer);
};
const renderThemeFalse = editor => {
const targetElement = editor.getElement();
return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
};
const renderThemeUi = editor => {
const elm = editor.getElement();
editor.orgDisplay = elm.style.display;
if (isString(getTheme(editor))) {
return renderFromLoadedTheme(editor);
} else if (isFunction(getTheme(editor))) {
return renderFromThemeFunc(editor);
} else {
return renderThemeFalse(editor);
}
};
const augmentEditorUiApi = (editor, api) => {
const uiApiFacade = {
show: Optional.from(api.show).getOr(noop),
hide: Optional.from(api.hide).getOr(noop),
isEnabled: Optional.from(api.isEnabled).getOr(always),
setEnabled: state => {
if (!editor.mode.isReadOnly()) {
Optional.from(api.setEnabled).each(f => f(state));
}
}
};
editor.ui = {
...editor.ui,
...uiApiFacade
};
};
const init = async editor => {
editor.dispatch('ScriptsLoaded');
initIcons(editor);
initTheme(editor);
initModel(editor);
initPlugins(editor);
const renderInfo = await renderThemeUi(editor);
augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
editor.editorContainer = renderInfo.editorContainer;
appendContentCssFromSettings(editor);
if (editor.inline) {
contentBodyLoaded(editor);
} else {
init$1(editor, {
editorContainer: renderInfo.editorContainer,
iframeContainer: renderInfo.iframeContainer
});
}
};
const DOM$3 = DOMUtils.DOM;
const hasSkipLoadPrefix = name => name.charAt(0) === '-';
const loadLanguage = (scriptLoader, editor) => {
const languageCode = getLanguageCode(editor);
const languageUrl = getLanguageUrl(editor);
if (!I18n.hasCode(languageCode) && languageCode !== 'en') {
const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`;
scriptLoader.add(url).catch(() => {
languageLoadError(editor, url, languageCode);
});
}
};
const loadTheme = (editor, suffix) => {
const theme = getTheme(editor);
if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
const themeUrl = getThemeUrl(editor);
const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`;
ThemeManager.load(theme, url).catch(() => {
themeLoadError(editor, url, theme);
});
}
};
const loadModel = (editor, suffix) => {
const model = getModel(editor);
if (model !== 'plugin' && !has$2(ModelManager.urls, model)) {
const modelUrl = getModelUrl(editor);
const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`;
ModelManager.load(model, url).catch(() => {
modelLoadError(editor, url, model);
});
}
};
const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({
url,
name: Optional.none()
}));
const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({
url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`,
name: Optional.some(name)
}));
const loadIcons = (scriptLoader, editor, suffix) => {
const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix);
const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ''));
each$e(cat([
defaultIconsUrl,
customIconsUrl
]), urlMeta => {
scriptLoader.add(urlMeta.url).catch(() => {
iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
});
});
};
const loadPlugins = (editor, suffix) => {
const loadPlugin = (name, url) => {
PluginManager.load(name, url).catch(() => {
pluginLoadError(editor, url, name);
});
};
each$d(getExternalPlugins$1(editor), (url, name) => {
loadPlugin(name, url);
editor.options.set('plugins', getPlugins(editor).concat(name));
});
each$e(getPlugins(editor), plugin => {
plugin = Tools.trim(plugin);
if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`);
}
});
};
const isThemeLoaded = editor => {
const theme = getTheme(editor);
return !isString(theme) || isNonNullable(ThemeManager.get(theme));
};
const isModelLoaded = editor => {
const model = getModel(editor);
return isNonNullable(ModelManager.get(model));
};
const loadScripts = (editor, suffix) => {
const scriptLoader = ScriptLoader.ScriptLoader;
const initEditor = () => {
if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
init(editor);
}
};
loadTheme(editor, suffix);
loadModel(editor, suffix);
loadLanguage(scriptLoader, editor);
loadIcons(scriptLoader, editor, suffix);
loadPlugins(editor, suffix);
scriptLoader.loadQueue().then(initEditor, initEditor);
};
const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
contentCssCors: hasContentCssCors(editor),
referrerPolicy: getReferrerPolicy(editor)
});
const render = editor => {
const id = editor.id;
I18n.setCode(getLanguageCode(editor));
const readyHandler = () => {
DOM$3.unbind(window, 'ready', readyHandler);
editor.render();
};
if (!EventUtils.Event.domLoaded) {
DOM$3.bind(window, 'ready', readyHandler);
return;
}
if (!editor.getElement()) {
return;
}
const element = SugarElement.fromDom(editor.getElement());
const snapshot = clone$4(element);
editor.on('remove', () => {
eachr(element.dom.attributes, attr => remove$9(element, attr.name));
setAll$1(element, snapshot);
});
editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
if (!isInline$1(editor)) {
editor.orgVisibility = editor.getElement().style.visibility;
editor.getElement().style.visibility = 'hidden';
} else {
editor.inline = true;
}
const form = editor.getElement().form || DOM$3.getParent(id, 'form');
if (form) {
editor.formElement = form;
if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
DOM$3.insertAfter(DOM$3.create('input', {
type: 'hidden',
name: id
}), id);
editor.hasHiddenInput = true;
}
editor.formEventDelegate = e => {
editor.dispatch(e.type, e);
};
DOM$3.bind(form, 'submit reset', editor.formEventDelegate);
editor.on('reset', () => {
editor.resetContent();
});
if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
form._mceOldSubmit = form.submit;
form.submit = () => {
editor.editorManager.triggerSave();
editor.setDirty(false);
return form._mceOldSubmit(form);
};
}
}
editor.windowManager = WindowManager(editor);
editor.notificationManager = NotificationManager(editor);
if (isEncodingXml(editor)) {
editor.on('GetContent', e => {
if (e.save) {
e.content = DOM$3.encode(e.content);
}
});
}
if (shouldAddFormSubmitTrigger(editor)) {
editor.on('submit', () => {
if (editor.initialized) {
editor.save();
}
});
}
if (shouldAddUnloadTrigger(editor)) {
editor._beforeUnload = () => {
if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
editor.save({
format: 'raw',
no_events: true,
set_dirty: false
});
}
};
editor.editorManager.on('BeforeUnload', editor._beforeUnload);
}
editor.editorManager.add(editor);
loadScripts(editor, editor.suffix);
};
const setEditableRoot = (editor, state) => {
if (editor._editableRoot !== state) {
editor._editableRoot = state;
if (!editor.readonly) {
editor.getBody().contentEditable = String(editor.hasEditableRoot());
editor.nodeChanged();
}
fireEditableRootStateChange(editor, state);
}
};
const hasEditableRoot = editor => editor._editableRoot;
const sectionResult = (sections, settings) => ({
sections: constant(sections),
options: constant(settings)
});
const deviceDetection = detect$1().deviceType;
const isPhone = deviceDetection.isPhone();
const isTablet = deviceDetection.isTablet();
const normalizePlugins = plugins => {
if (isNullable(plugins)) {
return [];
} else {
const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
const trimmedPlugins = map$3(pluginNames, trim$4);
return filter$5(trimmedPlugins, isNotEmpty);
}
};
const extractSections = (keys, options) => {
const result = bifilter(options, (value, key) => {
return contains$2(keys, key);
});
return sectionResult(result.t, result.f);
};
const getSection = (sectionResult, name, defaults = {}) => {
const sections = sectionResult.sections();
const sectionOptions = get$a(sections, name).getOr({});
return Tools.extend({}, defaults, sectionOptions);
};
const hasSection = (sectionResult, name) => {
return has$2(sectionResult.sections(), name);
};
const getSectionConfig = (sectionResult, name) => {
return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
};
const getMobileOverrideOptions = (mobileOptions, isPhone) => {
const defaultMobileOptions = {
table_grid: false,
object_resizing: false,
resize: false,
toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'),
toolbar_sticky: false
};
const defaultPhoneOptions = { menubar: false };
return {
...defaultMobileOptions,
...isPhone ? defaultPhoneOptions : {}
};
};
const getExternalPlugins = (overrideOptions, options) => {
var _a;
const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
if (overrideOptions && overrideOptions.external_plugins) {
return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
} else {
return userDefinedExternalPlugins;
}
};
const combinePlugins = (forcedPlugins, plugins) => [
...normalizePlugins(forcedPlugins),
...normalizePlugins(plugins)
];
const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => {
if (isMobileDevice && hasSection(sectionResult, 'mobile')) {
return mobilePlugins;
} else {
return desktopPlugins;
}
};
const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => {
const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
const desktopPlugins = normalizePlugins(options.plugins);
const mobileConfig = getSectionConfig(sectionResult, 'mobile');
const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins);
const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
return Tools.extend(options, {
forced_plugins: forcedPlugins,
plugins: combinedPlugins
});
};
const isOnMobile = (isMobileDevice, sectionResult) => {
return isMobileDevice && hasSection(sectionResult, 'mobile');
};
const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => {
var _a;
const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {};
const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options));
const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) });
return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions);
};
const normalizeOptions = (defaultOverrideOptions, options) => {
const copiedOptions = merge(options);
return combineOptions(isPhone || isTablet, isPhone, copiedOptions, defaultOverrideOptions, copiedOptions);
};
const addVisual = (editor, elm) => addVisual$1(editor, elm);
const registerExecCommands$2 = editor => {
const toggleFormat = (name, value) => {
editor.formatter.toggle(name, value);
editor.nodeChanged();
};
const toggleAlign = align => () => {
each$e('left,center,right,justify'.split(','), name => {
if (align !== name) {
editor.formatter.remove('align' + name);
}
});
if (align !== 'none') {
toggleFormat('align' + align);
}
};
editor.editorCommands.addCommands({
JustifyLeft: toggleAlign('left'),
JustifyCenter: toggleAlign('center'),
JustifyRight: toggleAlign('right'),
JustifyFull: toggleAlign('justify'),
JustifyNone: toggleAlign('none')
});
};
const registerQueryStateCommands = editor => {
const alignStates = name => () => {
const selection = editor.selection;
const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name)));
};
editor.editorCommands.addCommands({
JustifyLeft: alignStates('alignleft'),
JustifyCenter: alignStates('aligncenter'),
JustifyRight: alignStates('alignright'),
JustifyFull: alignStates('alignjustify')
}, 'state');
};
const registerCommands$a = editor => {
registerExecCommands$2(editor);
registerQueryStateCommands(editor);
};
const registerCommands$9 = editor => {
editor.editorCommands.addCommands({
'Cut,Copy,Paste': command => {
const doc = editor.getDoc();
let failed;
try {
doc.execCommand(command);
} catch (ex) {
failed = true;
}
if (command === 'paste' && !doc.queryCommandEnabled(command)) {
failed = true;
}
if (failed || !doc.queryCommandSupported(command)) {
let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
if (Env.os.isMacOS() || Env.os.isiOS()) {
msg = msg.replace(/Ctrl\+/g, '\u2318+');
}
editor.notificationManager.open({
text: msg,
type: 'error'
});
}
}
});
};
const trimOrPadLeftRight = (dom, rng, html, schema) => {
const root = SugarElement.fromDom(dom.getRoot());
if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng), schema)) {
html = html.replace(/^ /, ' ');
} else {
html = html.replace(/^ /, ' ');
}
if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng), schema)) {
html = html.replace(/( | )(
)?$/, ' ');
} else {
html = html.replace(/ (
)?$/, ' ');
}
return html;
};
const processValue$1 = value => {
if (typeof value !== 'string') {
const details = Tools.extend({
paste: value.paste,
data: { paste: value.paste }
}, value);
return {
content: value.content,
details
};
}
return {
content: value,
details: {}
};
};
const trimOrPad = (editor, value) => {
const selection = editor.selection;
const dom = editor.dom;
if (/^ | $/.test(value)) {
return trimOrPadLeftRight(dom, selection.getRng(), value, editor.schema);
} else {
return value;
}
};
const insertAtCaret = (editor, value) => {
if (editor.selection.isEditable()) {
const {content, details} = processValue$1(value);
preProcessSetContent(editor, {
...details,
content: trimOrPad(editor, content),
format: 'html',
set: false,
selection: true
}).each(args => {
const insertedContent = insertContent$1(editor, args.content, details);
postProcessSetContent(editor, insertedContent, args);
editor.addVisual();
});
}
};
const registerCommands$8 = editor => {
editor.editorCommands.addCommands({
mceCleanup: () => {
const bm = editor.selection.getBookmark();
editor.setContent(editor.getContent());
editor.selection.moveToBookmark(bm);
},
insertImage: (_command, _ui, value) => {
insertAtCaret(editor, editor.dom.createHTML('img', { src: value }));
},
insertHorizontalRule: () => {
editor.execCommand('mceInsertContent', false, '
');
},
insertText: (_command, _ui, value) => {
insertAtCaret(editor, editor.dom.encode(value));
},
insertHTML: (_command, _ui, value) => {
insertAtCaret(editor, value);
},
mceInsertContent: (_command, _ui, value) => {
insertAtCaret(editor, value);
},
mceSetContent: (_command, _ui, value) => {
editor.setContent(value);
},
mceReplaceContent: (_command, _ui, value) => {
editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
},
mceNewDocument: () => {
editor.setContent(getNewDocumentContent(editor));
}
});
};
const legacyPropNames = {
'font-size': 'size',
'font-family': 'face'
};
const isFont = isTag('font');
const getSpecifiedFontProp = (propName, rootElm, elm) => {
const getProperty = elm => getRaw(elm, propName).orThunk(() => {
if (isFont(elm)) {
return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName));
} else {
return Optional.none();
}
});
const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm);
return closest$1(SugarElement.fromDom(elm), elm => getProperty(elm), isRoot);
};
const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
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('');
const getFontSize = getFontProp('font-size');
const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family'));
const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => {
const container = caret.container();
return Optional.from(isText$b(container) ? container.parentNode : container);
});
const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => {
const root = editor.getBody();
const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
});
const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder);
const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
const fromFontSizeNumber = (editor, value) => {
if (/^[0-9.]+$/.test(value)) {
const fontSizeNumber = parseInt(value, 10);
if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
const fontSizes = getFontStyleValues(editor);
const fontClasses = getFontSizeClasses(editor);
if (fontClasses.length > 0) {
return fontClasses[fontSizeNumber - 1] || value;
} else {
return fontSizes[fontSizeNumber - 1] || value;
}
} else {
return value;
}
} else {
return value;
}
};
const normalizeFontNames = font => {
const fonts = font.split(/\s*,\s*/);
return map$3(fonts, font => {
if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) {
return `'${ font }'`;
} else {
return font;
}
}).join(',');
};
const fontNameAction = (editor, value) => {
const font = fromFontSizeNumber(editor, value);
editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
editor.nodeChanged();
};
const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr('');
const fontSizeAction = (editor, value) => {
editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
editor.nodeChanged();
};
const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr('');
const lineHeightQuery = editor => mapRange(editor, elm => {
const root = SugarElement.fromDom(editor.getBody());
const specifiedStyle = closest$1(elm, elm => getRaw(elm, 'line-height'), curry(eq, root));
const computedStyle = () => {
const lineHeight = parseFloat(get$7(elm, 'line-height'));
const fontSize = parseFloat(get$7(elm, 'font-size'));
return String(lineHeight / fontSize);
};
return specifiedStyle.getOrThunk(computedStyle);
}).getOr('');
const lineHeightAction = (editor, lineHeight) => {
editor.formatter.toggle('lineheight', { value: String(lineHeight) });
editor.nodeChanged();
};
const registerExecCommands$1 = editor => {
const toggleFormat = (name, value) => {
editor.formatter.toggle(name, value);
editor.nodeChanged();
};
editor.editorCommands.addCommands({
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => {
toggleFormat(command);
},
'ForeColor,HiliteColor': (command, _ui, value) => {
toggleFormat(command, { value });
},
'BackColor': (_command, _ui, value) => {
toggleFormat('hilitecolor', { value });
},
'FontName': (_command, _ui, value) => {
fontNameAction(editor, value);
},
'FontSize': (_command, _ui, value) => {
fontSizeAction(editor, value);
},
'LineHeight': (_command, _ui, value) => {
lineHeightAction(editor, value);
},
'Lang': (command, _ui, lang) => {
var _a;
toggleFormat(command, {
value: lang.code,
customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null
});
},
'RemoveFormat': command => {
editor.formatter.remove(command);
},
'mceBlockQuote': () => {
toggleFormat('blockquote');
},
'FormatBlock': (_command, _ui, value) => {
toggleFormat(isString(value) ? value : 'p');
},
'mceToggleFormat': (_command, _ui, value) => {
toggleFormat(value);
}
});
};
const registerQueryValueCommands = editor => {
const isFormatMatch = name => editor.formatter.match(name);
editor.editorCommands.addCommands({
'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command),
'mceBlockQuote': () => isFormatMatch('blockquote')
}, 'state');
editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor));
editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor));
editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor));
};
const registerCommands$7 = editor => {
registerExecCommands$1(editor);
registerQueryValueCommands(editor);
};
const registerCommands$6 = editor => {
editor.editorCommands.addCommands({
mceAddUndoLevel: () => {
editor.undoManager.add();
},
mceEndUndoLevel: () => {
editor.undoManager.add();
},
Undo: () => {
editor.undoManager.undo();
},
Redo: () => {
editor.undoManager.redo();
}
});
};
const registerCommands$5 = editor => {
editor.editorCommands.addCommands({
Indent: () => {
indent(editor);
},
Outdent: () => {
outdent(editor);
}
});
editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state');
};
const registerCommands$4 = editor => {
const applyLinkToSelection = (_command, _ui, value) => {
const linkDetails = isString(value) ? { href: value } : value;
const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
if (isObject(linkDetails) && isString(linkDetails.href)) {
linkDetails.href = linkDetails.href.replace(/ /g, '%20');
if (!anchor || !linkDetails.href) {
editor.formatter.remove('link');
}
if (linkDetails.href) {
editor.formatter.apply('link', linkDetails, anchor);
}
}
};
editor.editorCommands.addCommands({
unlink: () => {
if (editor.selection.isEditable()) {
if (editor.selection.isCollapsed()) {
const elm = editor.dom.getParent(editor.selection.getStart(), 'a');
if (elm) {
editor.dom.remove(elm, true);
}
return;
}
editor.formatter.remove('link');
}
},
mceInsertLink: applyLinkToSelection,
createLink: applyLinkToSelection
});
};
const getTopParentBlock = (editor, node, root, container) => {
const dom = editor.dom;
const selector = node => dom.isBlock(node) && node.parentElement === root;
const topParentBlock = selector(node) ? node : dom.getParent(container, selector, root);
return Optional.from(topParentBlock).map(SugarElement.fromDom);
};
const insert = (editor, before) => {
const dom = editor.dom;
const rng = editor.selection.getRng();
const node = before ? editor.selection.getStart() : editor.selection.getEnd();
const container = before ? rng.startContainer : rng.endContainer;
const root = getEditableRoot(dom, container);
if (!root || !root.isContentEditable) {
return;
}
const insertFn = before ? before$3 : after$4;
const newBlockName = getForcedRootBlock(editor);
getTopParentBlock(editor, node, root, container).each(parentBlock => {
const newBlock = createNewBlock(editor, container, parentBlock.dom, root, false, newBlockName);
insertFn(parentBlock, SugarElement.fromDom(newBlock));
editor.selection.setCursorLocation(newBlock, 0);
editor.dispatch('NewBlock', { newBlock });
fireInputEvent(editor, 'insertParagraph');
});
};
const insertBefore = editor => insert(editor, true);
const insertAfter = editor => insert(editor, false);
const registerCommands$3 = editor => {
editor.editorCommands.addCommands({
InsertNewBlockBefore: () => {
insertBefore(editor);
},
InsertNewBlockAfter: () => {
insertAfter(editor);
}
});
};
const registerCommands$2 = editor => {
editor.editorCommands.addCommands({
insertParagraph: () => {
insertBreak(blockbreak, editor);
},
mceInsertNewLine: (_command, _ui, value) => {
insert$1(editor, value);
},
InsertLineBreak: (_command, _ui, _value) => {
insertBreak(linebreak, editor);
}
});
};
const registerCommands$1 = editor => {
editor.editorCommands.addCommands({
mceSelectNodeDepth: (_command, _ui, value) => {
let counter = 0;
editor.dom.getParent(editor.selection.getNode(), node => {
if (isElement$6(node) && counter++ === value) {
editor.selection.select(node);
return false;
} else {
return true;
}
}, editor.getBody());
},
mceSelectNode: (_command, _ui, value) => {
editor.selection.select(value);
},
selectAll: () => {
const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3);
if (editingHost) {
const rng = editor.dom.createRng();
rng.selectNodeContents(editingHost);
editor.selection.setRng(rng);
}
}
});
};
const registerExecCommands = editor => {
editor.editorCommands.addCommands({
mceRemoveNode: (_command, _ui, value) => {
const node = value !== null && value !== void 0 ? value : editor.selection.getNode();
if (node !== editor.getBody()) {
const bm = editor.selection.getBookmark();
editor.dom.remove(node, true);
editor.selection.moveToBookmark(bm);
}
},
mcePrint: () => {
editor.getWin().print();
},
mceFocus: (_command, _ui, value) => {
focus(editor, value === true);
},
mceToggleVisualAid: () => {
editor.hasVisual = !editor.hasVisual;
editor.addVisual();
}
});
};
const registerCommands = editor => {
registerCommands$a(editor);
registerCommands$9(editor);
registerCommands$6(editor);
registerCommands$1(editor);
registerCommands$8(editor);
registerCommands$4(editor);
registerCommands$5(editor);
registerCommands$3(editor);
registerCommands$2(editor);
registerCommands$7(editor);
registerExecCommands(editor);
};
const selectionSafeCommands = ['toggleview'];
const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase());
class EditorCommands {
constructor(editor) {
this.commands = {
state: {},
exec: {},
value: {}
};
this.editor = editor;
}
execCommand(command, ui = false, value, args) {
const editor = this.editor;
const lowerCaseCommand = command.toLowerCase();
const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
if (editor.removed) {
return false;
}
if (lowerCaseCommand !== 'mcefocus') {
if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
editor.focus();
} else {
restore(editor);
}
}
const eventArgs = editor.dispatch('BeforeExecCommand', {
command,
ui,
value
});
if (eventArgs.isDefaultPrevented()) {
return false;
}
const func = this.commands.exec[lowerCaseCommand];
if (isFunction(func)) {
func(lowerCaseCommand, ui, value);
editor.dispatch('ExecCommand', {
command,
ui,
value
});
return true;
}
return false;
}
queryCommandState(command) {
if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
return false;
}
const lowerCaseCommand = command.toLowerCase();
const func = this.commands.state[lowerCaseCommand];
if (isFunction(func)) {
return func(lowerCaseCommand);
}
return false;
}
queryCommandValue(command) {
if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
return '';
}
const lowerCaseCommand = command.toLowerCase();
const func = this.commands.value[lowerCaseCommand];
if (isFunction(func)) {
return func(lowerCaseCommand);
}
return '';
}
addCommands(commandList, type = 'exec') {
const commands = this.commands;
each$d(commandList, (callback, command) => {
each$e(command.toLowerCase().split(','), command => {
commands[type][command] = callback;
});
});
}
addCommand(command, callback, scope) {
const lowerCaseCommand = command.toLowerCase();
this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value);
}
queryCommandSupported(command) {
const lowerCaseCommand = command.toLowerCase();
if (this.commands.exec[lowerCaseCommand]) {
return true;
} else {
return false;
}
}
addQueryStateHandler(command, callback, scope) {
this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
}
addQueryValueHandler(command, callback, scope) {
this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
}
}
const internalContentEditableAttr = 'data-mce-contenteditable';
const toggleClass = (elm, cls, state) => {
if (has(elm, cls) && !state) {
remove$6(elm, cls);
} else if (state) {
add$2(elm, cls);
}
};
const setEditorCommandState = (editor, cmd, state) => {
try {
editor.getDoc().execCommand(cmd, false, String(state));
} catch (ex) {
}
};
const setContentEditable = (elm, state) => {
elm.dom.contentEditable = state ? 'true' : 'false';
};
const switchOffContentEditableTrue = elm => {
each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
set$3(elm, internalContentEditableAttr, 'true');
setContentEditable(elm, false);
});
};
const switchOnContentEditableTrue = elm => {
each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
remove$9(elm, internalContentEditableAttr);
setContentEditable(elm, true);
});
};
const removeFakeSelection = editor => {
Optional.from(editor.selection.getNode()).each(elm => {
elm.removeAttribute('data-mce-selected');
});
};
const restoreFakeSelection = editor => {
editor.selection.setRng(editor.selection.getRng());
};
const toggleReadOnly = (editor, state) => {
const body = SugarElement.fromDom(editor.getBody());
toggleClass(body, 'mce-content-readonly', state);
if (state) {
editor.selection.controlSelection.hideResizeRect();
editor._selectionOverrides.hideFakeCaret();
removeFakeSelection(editor);
editor.readonly = true;
setContentEditable(body, false);
switchOffContentEditableTrue(body);
} else {
editor.readonly = false;
if (editor.hasEditableRoot()) {
setContentEditable(body, true);
}
switchOnContentEditableTrue(body);
setEditorCommandState(editor, 'StyleWithCSS', false);
setEditorCommandState(editor, 'enableInlineTableEditing', false);
setEditorCommandState(editor, 'enableObjectResizing', false);
if (hasEditorOrUiFocus(editor)) {
editor.focus();
}
restoreFakeSelection(editor);
editor.nodeChanged();
}
};
const isReadOnly = editor => editor.readonly;
const registerFilters = editor => {
editor.parser.addAttributeFilter('contenteditable', nodes => {
if (isReadOnly(editor)) {
each$e(nodes, node => {
node.attr(internalContentEditableAttr, node.attr('contenteditable'));
node.attr('contenteditable', 'false');
});
}
});
editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
if (isReadOnly(editor)) {
each$e(nodes, node => {
node.attr('contenteditable', node.attr(internalContentEditableAttr));
});
}
});
editor.serializer.addTempAttr(internalContentEditableAttr);
};
const registerReadOnlyContentFilters = editor => {
if (editor.serializer) {
registerFilters(editor);
} else {
editor.on('PreInit', () => {
registerFilters(editor);
});
}
};
const isClickEvent = e => e.type === 'click';
const allowedEvents = ['copy'];
const isReadOnlyAllowedEvent = e => contains$2(allowedEvents, e.type);
const getAnchorHrefOpt = (editor, elm) => {
const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href'));
};
const processReadonlyEvents = (editor, e) => {
if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
const elm = SugarElement.fromDom(e.target);
getAnchorHrefOpt(editor, elm).each(href => {
e.preventDefault();
if (/^#/.test(href)) {
const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`);
if (targetEl.length) {
editor.selection.scrollIntoView(targetEl[0], true);
}
} else {
window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes');
}
});
} else if (isReadOnlyAllowedEvent(e)) {
editor.dispatch(e.type, e);
}
};
const registerReadOnlySelectionBlockers = editor => {
editor.on('ShowCaret', e => {
if (isReadOnly(editor)) {
e.preventDefault();
}
});
editor.on('ObjectSelected', e => {
if (isReadOnly(editor)) {
e.preventDefault();
}
});
};
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', ' ');
class EventDispatcher {
static isNative(name) {
return !!nativeEvents[name.toLowerCase()];
}
constructor(settings) {
this.bindings = {};
this.settings = settings || {};
this.scope = this.settings.scope || this;
this.toggleEvent = this.settings.toggleEvent || never;
}
fire(name, args) {
return this.dispatch(name, args);
}
dispatch(name, args) {
const lcName = name.toLowerCase();
const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
if (this.settings.beforeFire) {
this.settings.beforeFire(event);
}
const handlers = this.bindings[lcName];
if (handlers) {
for (let i = 0, l = handlers.length; i < l; i++) {
const callback = handlers[i];
if (callback.removed) {
continue;
}
if (callback.once) {
this.off(lcName, callback.func);
}
if (event.isImmediatePropagationStopped()) {
return event;
}
if (callback.func.call(this.scope, event) === false) {
event.preventDefault();
return event;
}
}
}
return event;
}
on(name, callback, prepend, extra) {
if (callback === false) {
callback = never;
}
if (callback) {
const wrappedCallback = {
func: callback,
removed: false
};
if (extra) {
Tools.extend(wrappedCallback, extra);
}
const names = name.toLowerCase().split(' ');
let i = names.length;
while (i--) {
const currentName = names[i];
let handlers = this.bindings[currentName];
if (!handlers) {
handlers = [];
this.toggleEvent(currentName, true);
}
if (prepend) {
handlers = [
wrappedCallback,
...handlers
];
} else {
handlers = [
...handlers,
wrappedCallback
];
}
this.bindings[currentName] = handlers;
}
}
return this;
}
off(name, callback) {
if (name) {
const names = name.toLowerCase().split(' ');
let i = names.length;
while (i--) {
const currentName = names[i];
let handlers = this.bindings[currentName];
if (!currentName) {
each$d(this.bindings, (_value, bindingName) => {
this.toggleEvent(bindingName, false);
delete this.bindings[bindingName];
});
return this;
}
if (handlers) {
if (!callback) {
handlers.length = 0;
} else {
const filteredHandlers = partition$2(handlers, handler => handler.func === callback);
handlers = filteredHandlers.fail;
this.bindings[currentName] = handlers;
each$e(filteredHandlers.pass, handler => {
handler.removed = true;
});
}
if (!handlers.length) {
this.toggleEvent(name, false);
delete this.bindings[currentName];
}
}
}
} else {
each$d(this.bindings, (_value, name) => {
this.toggleEvent(name, false);
});
this.bindings = {};
}
return this;
}
once(name, callback, prepend) {
return this.on(name, callback, prepend, { once: true });
}
has(name) {
name = name.toLowerCase();
const binding = this.bindings[name];
return !(!binding || binding.length === 0);
}
}
const getEventDispatcher = obj => {
if (!obj._eventDispatcher) {
obj._eventDispatcher = new EventDispatcher({
scope: obj,
toggleEvent: (name, state) => {
if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
obj.toggleNativeEvent(name, state);
}
}
});
}
return obj._eventDispatcher;
};
const Observable = {
fire(name, args, bubble) {
return this.dispatch(name, args, bubble);
},
dispatch(name, args, bubble) {
const self = this;
if (self.removed && name !== 'remove' && name !== 'detach') {
return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
}
const dispatcherArgs = getEventDispatcher(self).dispatch(name, args);
if (bubble !== false && self.parent) {
let parent = self.parent();
while (parent && !dispatcherArgs.isPropagationStopped()) {
parent.dispatch(name, dispatcherArgs, false);
parent = parent.parent ? parent.parent() : undefined;
}
}
return dispatcherArgs;
},
on(name, callback, prepend) {
return getEventDispatcher(this).on(name, callback, prepend);
},
off(name, callback) {
return getEventDispatcher(this).off(name, callback);
},
once(name, callback) {
return getEventDispatcher(this).once(name, callback);
},
hasEventListeners(name) {
return getEventDispatcher(this).has(name);
}
};
const DOM$2 = DOMUtils.DOM;
let customEventRootDelegates;
const getEventTarget = (editor, eventName) => {
if (eventName === 'selectionchange') {
return editor.getDoc();
}
if (!editor.inline && /^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(eventName)) {
return editor.getDoc().documentElement;
}
const eventRoot = getEventRoot(editor);
if (eventRoot) {
if (!editor.eventRoot) {
editor.eventRoot = DOM$2.select(eventRoot)[0];
}
return editor.eventRoot;
}
return editor.getBody();
};
const isListening = editor => !editor.hidden && !isReadOnly(editor);
const fireEvent = (editor, eventName, e) => {
if (isListening(editor)) {
editor.dispatch(eventName, e);
} else if (isReadOnly(editor)) {
processReadonlyEvents(editor, e);
}
};
const bindEventDelegate = (editor, eventName) => {
if (!editor.delegates) {
editor.delegates = {};
}
if (editor.delegates[eventName] || editor.removed) {
return;
}
const eventRootElm = getEventTarget(editor, eventName);
if (getEventRoot(editor)) {
if (!customEventRootDelegates) {
customEventRootDelegates = {};
editor.editorManager.on('removeEditor', () => {
if (!editor.editorManager.activeEditor) {
if (customEventRootDelegates) {
each$d(customEventRootDelegates, (_value, name) => {
editor.dom.unbind(getEventTarget(editor, name));
});
customEventRootDelegates = null;
}
}
});
}
if (customEventRootDelegates[eventName]) {
return;
}
const delegate = e => {
const target = e.target;
const editors = editor.editorManager.get();
let i = editors.length;
while (i--) {
const body = editors[i].getBody();
if (body === target || DOM$2.isChildOf(target, body)) {
fireEvent(editors[i], eventName, e);
}
}
};
customEventRootDelegates[eventName] = delegate;
DOM$2.bind(eventRootElm, eventName, delegate);
} else {
const delegate = e => {
fireEvent(editor, eventName, e);
};
DOM$2.bind(eventRootElm, eventName, delegate);
editor.delegates[eventName] = delegate;
}
};
const EditorObservable = {
...Observable,
bindPendingEventDelegates() {
const self = this;
Tools.each(self._pendingNativeEvents, name => {
bindEventDelegate(self, name);
});
},
toggleNativeEvent(name, state) {
const self = this;
if (name === 'focus' || name === 'blur') {
return;
}
if (self.removed) {
return;
}
if (state) {
if (self.initialized) {
bindEventDelegate(self, name);
} else {
if (!self._pendingNativeEvents) {
self._pendingNativeEvents = [name];
} else {
self._pendingNativeEvents.push(name);
}
}
} else if (self.initialized && self.delegates) {
self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
delete self.delegates[name];
}
},
unbindAllNativeEvents() {
const self = this;
const body = self.getBody();
const dom = self.dom;
if (self.delegates) {
each$d(self.delegates, (value, name) => {
self.dom.unbind(getEventTarget(self, name), name, value);
});
delete self.delegates;
}
if (!self.inline && body && dom) {
body.onload = null;
dom.unbind(self.getWin());
dom.unbind(self.getDoc());
}
if (dom) {
dom.unbind(body);
dom.unbind(self.getContainer());
}
}
};
const stringListProcessor = value => {
if (isString(value)) {
return {
value: value.split(/[ ,]/),
valid: true
};
} else if (isArrayOf(value, isString)) {
return {
value,
valid: true
};
} else {
return {
valid: false,
message: `The value must be a string[] or a comma/space separated string.`
};
}
};
const getBuiltInProcessor = type => {
const validator = (() => {
switch (type) {
case 'array':
return isArray$1;
case 'boolean':
return isBoolean;
case 'function':
return isFunction;
case 'number':
return isNumber;
case 'object':
return isObject;
case 'string':
return isString;
case 'string[]':
return stringListProcessor;
case 'object[]':
return val => isArrayOf(val, isObject);
case 'regexp':
return val => is$4(val, RegExp);
default:
return always;
}
})();
return value => processValue(value, validator, `The value must be a ${ type }.`);
};
const isBuiltInSpec = spec => isString(spec.processor);
const getErrorMessage = (message, result) => {
const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`;
return message + additionalText;
};
const isValidResult = result => result.valid;
const processValue = (value, processor, message = '') => {
const result = processor(value);
if (isBoolean(result)) {
return result ? {
value: value,
valid: true
} : {
valid: false,
message
};
} else {
return result;
}
};
const processDefaultValue = (name, defaultValue, processor) => {
if (!isUndefined(defaultValue)) {
const result = processValue(defaultValue, processor);
if (isValidResult(result)) {
return result.value;
} else {
console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result));
}
}
return undefined;
};
const create$5 = (editor, initialOptions, rawInitialOptions = initialOptions) => {
const registry = {};
const values = {};
const setValue = (name, value, processor) => {
const result = processValue(value, processor);
if (isValidResult(result)) {
values[name] = result.value;
return true;
} else {
console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result));
return false;
}
};
const register = (name, spec) => {
const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
const defaultValue = processDefaultValue(name, spec.default, processor);
registry[name] = {
...spec,
default: defaultValue,
processor
};
const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name));
initValue.each(value => setValue(name, value, processor));
};
const isRegistered = name => has$2(registry, name);
const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined();
const set = (name, value) => {
if (!isRegistered(name)) {
console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`);
return false;
} else {
const spec = registry[name];
if (spec.immutable) {
console.error(`"${ name }" is an immutable option and cannot be updated`);
return false;
} else {
return setValue(name, value, spec.processor);
}
}
};
const unset = name => {
const registered = isRegistered(name);
if (registered) {
delete values[name];
}
return registered;
};
const isSet = name => has$2(values, name);
const debug = () => {
try {
console.log(JSON.parse(JSON.stringify(rawInitialOptions, (_key, value) => {
if (isBoolean(value) || isNumber(value) || isString(value) || isNull(value) || isArray$1(value) || isPlainObject(value)) {
return value;
}
return Object.prototype.toString.call(value);
})));
} catch (error) {
console.error(error);
}
};
return {
register,
isRegistered,
get,
set,
unset,
isSet,
debug
};
};
const defaultModes = [
'design',
'readonly'
];
const switchToMode = (editor, activeMode, availableModes, mode) => {
const oldMode = availableModes[activeMode.get()];
const newMode = availableModes[mode];
try {
newMode.activate();
} catch (e) {
console.error(`problem while activating editor mode ${ mode }:`, e);
return;
}
oldMode.deactivate();
if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
toggleReadOnly(editor, newMode.editorReadOnly);
}
activeMode.set(mode);
fireSwitchMode(editor, mode);
};
const setMode = (editor, availableModes, activeMode, mode) => {
if (mode === activeMode.get()) {
return;
} else if (!has$2(availableModes, mode)) {
throw new Error(`Editor mode '${ mode }' is invalid`);
}
if (editor.initialized) {
switchToMode(editor, activeMode, availableModes, mode);
} else {
editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode));
}
};
const registerMode = (availableModes, mode, api) => {
if (contains$2(defaultModes, mode)) {
throw new Error(`Cannot override default mode ${ mode }`);
}
return {
...availableModes,
[mode]: {
...api,
deactivate: () => {
try {
api.deactivate();
} catch (e) {
console.error(`problem while deactivating editor mode ${ mode }:`, e);
}
}
}
};
};
const create$4 = editor => {
const activeMode = Cell('design');
const availableModes = Cell({
design: {
activate: noop,
deactivate: noop,
editorReadOnly: false
},
readonly: {
activate: noop,
deactivate: noop,
editorReadOnly: true
}
});
registerReadOnlyContentFilters(editor);
registerReadOnlySelectionBlockers(editor);
return {
isReadOnly: () => isReadOnly(editor),
set: mode => setMode(editor, availableModes.get(), activeMode, mode),
get: () => activeMode.get(),
register: (mode, api) => {
availableModes.set(registerMode(availableModes.get(), mode, api));
}
};
};
const each$2 = Tools.each, explode = Tools.explode;
const keyCodeLookup = {
f1: 112,
f2: 113,
f3: 114,
f4: 115,
f5: 116,
f6: 117,
f7: 118,
f8: 119,
f9: 120,
f10: 121,
f11: 122,
f12: 123
};
const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
const isModifier = key => key in modifierNames;
const parseShortcut = pattern => {
const shortcut = {};
const isMac = Env.os.isMacOS() || Env.os.isiOS();
each$2(explode(pattern.toLowerCase(), '+'), value => {
if (isModifier(value)) {
shortcut[value] = true;
} else {
if (/^[0-9]{2,}$/.test(value)) {
shortcut.keyCode = parseInt(value, 10);
} else {
shortcut.charCode = value.charCodeAt(0);
shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
}
}
});
const id = [shortcut.keyCode];
let key;
for (key in modifierNames) {
if (shortcut[key]) {
id.push(key);
} else {
shortcut[key] = false;
}
}
shortcut.id = id.join(',');
if (shortcut.access) {
shortcut.alt = true;
if (isMac) {
shortcut.ctrl = true;
} else {
shortcut.shift = true;
}
}
if (shortcut.meta) {
if (isMac) {
shortcut.meta = true;
} else {
shortcut.ctrl = true;
shortcut.meta = false;
}
}
return shortcut;
};
class Shortcuts {
constructor(editor) {
this.shortcuts = {};
this.pendingPatterns = [];
this.editor = editor;
const self = this;
editor.on('keyup keypress keydown', e => {
if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
each$2(self.shortcuts, shortcut => {
if (self.matchShortcut(e, shortcut)) {
self.pendingPatterns = shortcut.subpatterns.slice(0);
if (e.type === 'keydown') {
self.executeShortcutAction(shortcut);
}
}
});
if (self.matchShortcut(e, self.pendingPatterns[0])) {
if (self.pendingPatterns.length === 1) {
if (e.type === 'keydown') {
self.executeShortcutAction(self.pendingPatterns[0]);
}
}
self.pendingPatterns.shift();
}
}
});
}
add(pattern, desc, cmdFunc, scope) {
const self = this;
const func = self.normalizeCommandFunc(cmdFunc);
each$2(explode(Tools.trim(pattern)), pattern => {
const shortcut = self.createShortcut(pattern, desc, func, scope);
self.shortcuts[shortcut.id] = shortcut;
});
return true;
}
remove(pattern) {
const shortcut = this.createShortcut(pattern);
if (this.shortcuts[shortcut.id]) {
delete this.shortcuts[shortcut.id];
return true;
}
return false;
}
normalizeCommandFunc(cmdFunc) {
const self = this;
const cmd = cmdFunc;
if (typeof cmd === 'string') {
return () => {
self.editor.execCommand(cmd, false, null);
};
} else if (Tools.isArray(cmd)) {
return () => {
self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
};
} else {
return cmd;
}
}
createShortcut(pattern, desc, cmdFunc, scope) {
const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
func: cmdFunc,
scope: scope || this.editor
});
return Tools.extend(shortcuts[0], {
desc: this.editor.translate(desc),
subpatterns: shortcuts.slice(1)
});
}
hasModifier(e) {
return e.altKey || e.ctrlKey || e.metaKey;
}
isFunctionKey(e) {
return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
}
matchShortcut(e, shortcut) {
if (!shortcut) {
return false;
}
if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
return false;
}
if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
return false;
}
if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
e.preventDefault();
return true;
}
return false;
}
executeShortcutAction(shortcut) {
return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
}
}
const create$3 = () => {
const buttons = {};
const menuItems = {};
const popups = {};
const icons = {};
const contextMenus = {};
const contextToolbars = {};
const sidebars = {};
const views = {};
const add = (collection, type) => (name, spec) => {
collection[name.toLowerCase()] = {
...spec,
type
};
};
const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
return {
addButton: add(buttons, 'button'),
addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
addToggleButton: add(buttons, 'togglebutton'),
addMenuButton: add(buttons, 'menubutton'),
addSplitButton: add(buttons, 'splitbutton'),
addMenuItem: add(menuItems, 'menuitem'),
addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
addToggleMenuItem: add(menuItems, 'togglemenuitem'),
addAutocompleter: add(popups, 'autocompleter'),
addContextMenu: add(contextMenus, 'contextmenu'),
addContextToolbar: add(contextToolbars, 'contexttoolbar'),
addContextForm: add(contextToolbars, 'contextform'),
addSidebar: add(sidebars, 'sidebar'),
addView: add(views, 'views'),
addIcon,
getAll: () => ({
buttons,
menuItems,
icons,
popups,
contextMenus,
contextToolbars,
sidebars,
views
})
};
};
const registry = () => {
const bridge = create$3();
return {
addAutocompleter: bridge.addAutocompleter,
addButton: bridge.addButton,
addContextForm: bridge.addContextForm,
addContextMenu: bridge.addContextMenu,
addContextToolbar: bridge.addContextToolbar,
addIcon: bridge.addIcon,
addMenuButton: bridge.addMenuButton,
addMenuItem: bridge.addMenuItem,
addNestedMenuItem: bridge.addNestedMenuItem,
addSidebar: bridge.addSidebar,
addSplitButton: bridge.addSplitButton,
addToggleButton: bridge.addToggleButton,
addGroupToolbarButton: bridge.addGroupToolbarButton,
addToggleMenuItem: bridge.addToggleMenuItem,
addView: bridge.addView,
getAll: bridge.getAll
};
};
const DOM$1 = DOMUtils.DOM;
const extend = Tools.extend, each$1 = Tools.each;
class Editor {
constructor(id, options, editorManager) {
this.plugins = {};
this.contentCSS = [];
this.contentStyles = [];
this.loadedCSS = {};
this.isNotDirty = false;
this.composing = false;
this.destroyed = false;
this.hasHiddenInput = false;
this.iframeElement = null;
this.initialized = false;
this.readonly = false;
this.removed = false;
this.startContent = '';
this._pendingNativeEvents = [];
this._skinLoaded = false;
this._editableRoot = true;
this.editorManager = editorManager;
this.documentBaseUrl = editorManager.documentBaseURL;
extend(this, EditorObservable);
const self = this;
this.id = id;
this.hidden = false;
const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
this.options = create$5(self, normalizedOptions, options);
register$7(self);
const getOption = this.options.get;
if (getOption('deprecation_warnings')) {
logWarnings(options, normalizedOptions);
}
const suffix = getOption('suffix');
if (suffix) {
editorManager.suffix = suffix;
}
this.suffix = editorManager.suffix;
const baseUrl = getOption('base_url');
if (baseUrl) {
editorManager._setBaseUrl(baseUrl);
}
this.baseUri = editorManager.baseURI;
const referrerPolicy = getReferrerPolicy(self);
if (referrerPolicy) {
ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy);
DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
}
const contentCssCors = hasContentCssCors(self);
if (isNonNullable(contentCssCors)) {
DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors);
}
AddOnManager.languageLoad = getOption('language_load');
AddOnManager.baseURL = editorManager.baseURL;
this.setDirty(false);
this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
this.baseURI = this.baseUri;
this.inline = isInline$1(self);
this.hasVisual = isVisualAidsEnabled(self);
this.shortcuts = new Shortcuts(this);
this.editorCommands = new EditorCommands(this);
registerCommands(this);
const cacheSuffix = getOption('cache_suffix');
if (cacheSuffix) {
Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, '');
}
this.ui = {
registry: registry(),
styleSheetLoader: undefined,
show: noop,
hide: noop,
setEnabled: noop,
isEnabled: always
};
this.mode = create$4(self);
editorManager.dispatch('SetupEditor', { editor: this });
const setupCallback = getSetupCallback(self);
if (isFunction(setupCallback)) {
setupCallback.call(self, self);
}
}
render() {
render(this);
}
focus(skipFocus) {
this.execCommand('mceFocus', false, skipFocus);
}
hasFocus() {
return hasFocus(this);
}
translate(text) {
return I18n.translate(text);
}
getParam(name, defaultVal, type) {
const options = this.options;
if (!options.isRegistered(name)) {
if (isNonNullable(type)) {
options.register(name, {
processor: type,
default: defaultVal
});
} else {
options.register(name, {
processor: always,
default: defaultVal
});
}
}
return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name);
}
hasPlugin(name, loaded) {
const hasPlugin = contains$2(getPlugins(this), name);
if (hasPlugin) {
return loaded ? PluginManager.get(name) !== undefined : true;
} else {
return false;
}
}
nodeChanged(args) {
this._nodeChangeDispatcher.nodeChanged(args);
}
addCommand(name, callback, scope) {
this.editorCommands.addCommand(name, callback, scope);
}
addQueryStateHandler(name, callback, scope) {
this.editorCommands.addQueryStateHandler(name, callback, scope);
}
addQueryValueHandler(name, callback, scope) {
this.editorCommands.addQueryValueHandler(name, callback, scope);
}
addShortcut(pattern, desc, cmdFunc, scope) {
this.shortcuts.add(pattern, desc, cmdFunc, scope);
}
execCommand(cmd, ui, value, args) {
return this.editorCommands.execCommand(cmd, ui, value, args);
}
queryCommandState(cmd) {
return this.editorCommands.queryCommandState(cmd);
}
queryCommandValue(cmd) {
return this.editorCommands.queryCommandValue(cmd);
}
queryCommandSupported(cmd) {
return this.editorCommands.queryCommandSupported(cmd);
}
show() {
const self = this;
if (self.hidden) {
self.hidden = false;
if (self.inline) {
self.getBody().contentEditable = 'true';
} else {
DOM$1.show(self.getContainer());
DOM$1.hide(self.id);
}
self.load();
self.dispatch('show');
}
}
hide() {
const self = this;
if (!self.hidden) {
self.save();
if (self.inline) {
self.getBody().contentEditable = 'false';
if (self === self.editorManager.focusedEditor) {
self.editorManager.focusedEditor = null;
}
} else {
DOM$1.hide(self.getContainer());
DOM$1.setStyle(self.id, 'display', self.orgDisplay);
}
self.hidden = true;
self.dispatch('hide');
}
}
isHidden() {
return this.hidden;
}
setProgressState(state, time) {
this.dispatch('ProgressState', {
state,
time
});
}
load(args = {}) {
const self = this;
const elm = self.getElement();
if (self.removed) {
return '';
}
if (elm) {
const loadArgs = {
...args,
load: true
};
const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
const html = self.setContent(value, loadArgs);
if (!loadArgs.no_events) {
self.dispatch('LoadContent', {
...loadArgs,
element: elm
});
}
return html;
} else {
return '';
}
}
save(args = {}) {
const self = this;
let elm = self.getElement();
if (!elm || !self.initialized || self.removed) {
return '';
}
const getArgs = {
...args,
save: true,
element: elm
};
let html = self.getContent(getArgs);
const saveArgs = {
...getArgs,
content: html
};
if (!saveArgs.no_events) {
self.dispatch('SaveContent', saveArgs);
}
if (saveArgs.format === 'raw') {
self.dispatch('RawSaveContent', saveArgs);
}
html = saveArgs.content;
if (!isTextareaOrInput(elm)) {
if (args.is_removing || !self.inline) {
elm.innerHTML = html;
}
const form = DOM$1.getParent(self.id, 'form');
if (form) {
each$1(form.elements, elm => {
if (elm.name === self.id) {
elm.value = html;
return false;
} else {
return true;
}
});
}
} else {
elm.value = html;
}
saveArgs.element = getArgs.element = elm = null;
if (saveArgs.set_dirty !== false) {
self.setDirty(false);
}
return html;
}
setContent(content, args) {
return setContent(this, content, args);
}
getContent(args) {
return getContent(this, args);
}
insertContent(content, args) {
if (args) {
content = extend({ content }, args);
}
this.execCommand('mceInsertContent', false, content);
}
resetContent(initialContent) {
if (initialContent === undefined) {
setContent(this, this.startContent, { format: 'raw' });
} else {
setContent(this, initialContent);
}
this.undoManager.reset();
this.setDirty(false);
this.nodeChanged();
}
isDirty() {
return !this.isNotDirty;
}
setDirty(state) {
const oldState = !this.isNotDirty;
this.isNotDirty = !state;
if (state && state !== oldState) {
this.dispatch('dirty');
}
}
getContainer() {
const self = this;
if (!self.container) {
self.container = self.editorContainer || DOM$1.get(self.id + '_parent');
}
return self.container;
}
getContentAreaContainer() {
return this.contentAreaContainer;
}
getElement() {
if (!this.targetElm) {
this.targetElm = DOM$1.get(this.id);
}
return this.targetElm;
}
getWin() {
const self = this;
if (!self.contentWindow) {
const elm = self.iframeElement;
if (elm) {
self.contentWindow = elm.contentWindow;
}
}
return self.contentWindow;
}
getDoc() {
const self = this;
if (!self.contentDocument) {
const win = self.getWin();
if (win) {
self.contentDocument = win.document;
}
}
return self.contentDocument;
}
getBody() {
var _a, _b;
const doc = this.getDoc();
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;
}
convertURL(url, name, elm) {
const self = this, getOption = self.options.get;
const urlConverterCallback = getUrlConverterCallback(self);
if (isFunction(urlConverterCallback)) {
return urlConverterCallback.call(self, url, elm, true, name);
}
if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
return url;
}
const urlObject = new URI(url);
if (urlObject.protocol !== 'http' && urlObject.protocol !== 'https' && urlObject.protocol !== '') {
return url;
}
if (getOption('relative_urls')) {
return self.documentBaseURI.toRelative(url);
}
url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host'));
return url;
}
addVisual(elm) {
addVisual(this, elm);
}
setEditableRoot(state) {
setEditableRoot(this, state);
}
hasEditableRoot() {
return hasEditableRoot(this);
}
remove() {
remove$1(this);
}
destroy(automatic) {
destroy(this, automatic);
}
uploadImages() {
return this.editorUpload.uploadImages();
}
_scanForImages() {
return this.editorUpload.scanForImages();
}
}
const DOM = DOMUtils.DOM;
const each = Tools.each;
let boundGlobalEvents = false;
let beforeUnloadDelegate;
let editors = [];
const globalEventDelegate = e => {
const type = e.type;
each(EditorManager.get(), editor => {
switch (type) {
case 'scroll':
editor.dispatch('ScrollWindow', e);
break;
case 'resize':
editor.dispatch('ResizeWindow', e);
break;
}
});
};
const toggleGlobalEvents = state => {
if (state !== boundGlobalEvents) {
const DOM = DOMUtils.DOM;
if (state) {
DOM.bind(window, 'resize', globalEventDelegate);
DOM.bind(window, 'scroll', globalEventDelegate);
} else {
DOM.unbind(window, 'resize', globalEventDelegate);
DOM.unbind(window, 'scroll', globalEventDelegate);
}
boundGlobalEvents = state;
}
};
const removeEditorFromList = targetEditor => {
const oldEditors = editors;
editors = filter$5(editors, editor => {
return targetEditor !== editor;
});
if (EditorManager.activeEditor === targetEditor) {
EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
}
if (EditorManager.focusedEditor === targetEditor) {
EditorManager.focusedEditor = null;
}
return oldEditors.length !== editors.length;
};
const purgeDestroyedEditor = editor => {
if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
removeEditorFromList(editor);
editor.unbindAllNativeEvents();
editor.destroy(true);
editor.removed = true;
}
};
const isQuirksMode = document.compatMode !== 'CSS1Compat';
const EditorManager = {
...Observable,
baseURI: null,
baseURL: null,
defaultOptions: {},
documentBaseURL: null,
suffix: null,
majorVersion: '7',
minorVersion: '3.0',
releaseDate: '2024-08-07',
i18n: I18n,
activeEditor: null,
focusedEditor: null,
setup() {
const self = this;
let baseURL = '';
let suffix = '';
let documentBaseURL = URI.getDocumentBaseUrl(document.location);
if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
if (!/[\/\\]$/.test(documentBaseURL)) {
documentBaseURL += '/';
}
}
const preInit = window.tinymce || window.tinyMCEPreInit;
if (preInit) {
baseURL = preInit.base || preInit.baseURL;
suffix = preInit.suffix;
} else {
const scripts = document.getElementsByTagName('script');
for (let i = 0; i < scripts.length; i++) {
const src = scripts[i].src || '';
if (src === '') {
continue;
}
const srcScript = src.substring(src.lastIndexOf('/'));
if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
if (srcScript.indexOf('.min') !== -1) {
suffix = '.min';
}
baseURL = src.substring(0, src.lastIndexOf('/'));
break;
}
}
if (!baseURL && document.currentScript) {
const src = document.currentScript.src;
if (src.indexOf('.min') !== -1) {
suffix = '.min';
}
baseURL = src.substring(0, src.lastIndexOf('/'));
}
}
self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
self.documentBaseURL = documentBaseURL;
self.baseURI = new URI(self.baseURL);
self.suffix = suffix;
setup$w(self);
},
overrideDefaults(defaultOptions) {
const baseUrl = defaultOptions.base_url;
if (baseUrl) {
this._setBaseUrl(baseUrl);
}
const suffix = defaultOptions.suffix;
if (suffix) {
this.suffix = suffix;
}
this.defaultOptions = defaultOptions;
const pluginBaseUrls = defaultOptions.plugin_base_urls;
if (pluginBaseUrls !== undefined) {
each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
});
}
},
init(options) {
const self = this;
let result;
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', ' ');
const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
const createId = elm => {
let id = elm.id;
if (!id) {
id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId);
elm.setAttribute('id', id);
}
return id;
};
const execCallback = name => {
const callback = options[name];
if (!callback) {
return;
}
return callback.apply(self, []);
};
const findTargets = options => {
if (Env.browser.isIE() || Env.browser.isEdge()) {
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');
return [];
} else if (isQuirksMode) {
initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
return [];
} else if (isString(options.selector)) {
return DOM.select(options.selector);
} else if (isNonNullable(options.target)) {
return [options.target];
} else {
return [];
}
};
let provideResults = editors => {
result = editors;
};
const initEditors = () => {
let initCount = 0;
const editors = [];
let targets;
const createEditor = (id, options, targetElm) => {
const editor = new Editor(id, options, self);
editors.push(editor);
editor.on('init', () => {
if (++initCount === targets.length) {
provideResults(editors);
}
});
editor.targetElm = editor.targetElm || targetElm;
editor.render();
};
DOM.unbind(window, 'ready', initEditors);
execCallback('onpageload');
targets = unique$1(findTargets(options));
Tools.each(targets, elm => {
purgeDestroyedEditor(self.get(elm.id));
});
targets = Tools.grep(targets, elm => {
return !self.get(elm.id);
});
if (targets.length === 0) {
provideResults([]);
} else {
each(targets, elm => {
if (isInvalidInlineTarget(options, elm)) {
initError('Could not initialize inline editor on invalid inline target element', elm);
} else {
createEditor(createId(elm), options, elm);
}
});
}
};
DOM.bind(window, 'ready', initEditors);
return new Promise(resolve => {
if (result) {
resolve(result);
} else {
provideResults = editors => {
resolve(editors);
};
}
});
},
get(id) {
if (arguments.length === 0) {
return editors.slice(0);
} else if (isString(id)) {
return find$2(editors, editor => {
return editor.id === id;
}).getOr(null);
} else if (isNumber(id)) {
return editors[id] ? editors[id] : null;
} else {
return null;
}
},
add(editor) {
const self = this;
const existingEditor = self.get(editor.id);
if (existingEditor === editor) {
return editor;
}
if (existingEditor === null) {
editors.push(editor);
}
toggleGlobalEvents(true);
self.activeEditor = editor;
self.dispatch('AddEditor', { editor });
if (!beforeUnloadDelegate) {
beforeUnloadDelegate = e => {
const event = self.dispatch('BeforeUnload');
if (event.returnValue) {
e.preventDefault();
e.returnValue = event.returnValue;
return event.returnValue;
}
};
window.addEventListener('beforeunload', beforeUnloadDelegate);
}
return editor;
},
createEditor(id, options) {
return this.add(new Editor(id, options, this));
},
remove(selector) {
const self = this;
let editor;
if (!selector) {
for (let i = editors.length - 1; i >= 0; i--) {
self.remove(editors[i]);
}
return;
}
if (isString(selector)) {
each(DOM.select(selector), elm => {
editor = self.get(elm.id);
if (editor) {
self.remove(editor);
}
});
return;
}
editor = selector;
if (isNull(self.get(editor.id))) {
return null;
}
if (removeEditorFromList(editor)) {
self.dispatch('RemoveEditor', { editor });
}
if (editors.length === 0) {
window.removeEventListener('beforeunload', beforeUnloadDelegate);
}
editor.remove();
toggleGlobalEvents(editors.length > 0);
return editor;
},
execCommand(cmd, ui, value) {
var _a;
const self = this;
const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value;
switch (cmd) {
case 'mceAddEditor': {
if (!self.get(editorId)) {
const editorOptions = value.options;
new Editor(editorId, editorOptions, self).render();
}
return true;
}
case 'mceRemoveEditor': {
const editor = self.get(editorId);
if (editor) {
editor.remove();
}
return true;
}
case 'mceToggleEditor': {
const editor = self.get(editorId);
if (!editor) {
self.execCommand('mceAddEditor', false, value);
return true;
}
if (editor.isHidden()) {
editor.show();
} else {
editor.hide();
}
return true;
}
}
if (self.activeEditor) {
return self.activeEditor.execCommand(cmd, ui, value);
}
return false;
},
triggerSave: () => {
each(editors, editor => {
editor.save();
});
},
addI18n: (code, items) => {
I18n.add(code, items);
},
translate: text => {
return I18n.translate(text);
},
setActive(editor) {
const activeEditor = this.activeEditor;
if (this.activeEditor !== editor) {
if (activeEditor) {
activeEditor.dispatch('deactivate', { relatedTarget: editor });
}
editor.dispatch('activate', { relatedTarget: activeEditor });
}
this.activeEditor = editor;
},
_setBaseUrl(baseUrl) {
this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
this.baseURI = new URI(this.baseURL);
}
};
EditorManager.setup();
const setup = () => {
const dataValue = value$2();
const FakeClipboardItem = items => ({
items,
types: keys(items),
getType: type => get$a(items, type).getOrUndefined()
});
const write = data => {
dataValue.set(data);
};
const read = () => dataValue.get().getOrUndefined();
const clear = dataValue.clear;
return {
FakeClipboardItem,
write,
read,
clear
};
};
const FakeClipboard = setup();
const min = Math.min, max = Math.max, round = Math.round;
const relativePosition = (rect, targetRect, rel) => {
let x = targetRect.x;
let y = targetRect.y;
const w = rect.w;
const h = rect.h;
const targetW = targetRect.w;
const targetH = targetRect.h;
const relChars = (rel || '').split('');
if (relChars[0] === 'b') {
y += targetH;
}
if (relChars[1] === 'r') {
x += targetW;
}
if (relChars[0] === 'c') {
y += round(targetH / 2);
}
if (relChars[1] === 'c') {
x += round(targetW / 2);
}
if (relChars[3] === 'b') {
y -= h;
}
if (relChars[4] === 'r') {
x -= w;
}
if (relChars[3] === 'c') {
y -= round(h / 2);
}
if (relChars[4] === 'c') {
x -= round(w / 2);
}
return create$2(x, y, w, h);
};
const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
for (let i = 0; i < rels.length; i++) {
const pos = relativePosition(rect, targetRect, rels[i]);
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) {
return rels[i];
}
}
return null;
};
const inflate = (rect, w, h) => {
return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
};
const intersect = (rect, cropRect) => {
const x1 = max(rect.x, cropRect.x);
const y1 = max(rect.y, cropRect.y);
const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
if (x2 - x1 < 0 || y2 - y1 < 0) {
return null;
}
return create$2(x1, y1, x2 - x1, y2 - y1);
};
const clamp = (rect, clampRect, fixedSize) => {
let x1 = rect.x;
let y1 = rect.y;
let x2 = rect.x + rect.w;
let y2 = rect.y + rect.h;
const cx2 = clampRect.x + clampRect.w;
const cy2 = clampRect.y + clampRect.h;
const underflowX1 = max(0, clampRect.x - x1);
const underflowY1 = max(0, clampRect.y - y1);
const overflowX2 = max(0, x2 - cx2);
const overflowY2 = max(0, y2 - cy2);
x1 += underflowX1;
y1 += underflowY1;
if (fixedSize) {
x2 += underflowX1;
y2 += underflowY1;
x1 -= overflowX2;
y1 -= overflowY2;
}
x2 -= overflowX2;
y2 -= overflowY2;
return create$2(x1, y1, x2 - x1, y2 - y1);
};
const create$2 = (x, y, w, h) => {
return {
x,
y,
w,
h
};
};
const fromClientRect = clientRect => {
return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
};
const Rect = {
inflate,
relativePosition,
findBestRelativePosition,
intersect,
clamp,
create: create$2,
fromClientRect
};
const awaiter = (resolveCb, rejectCb, timeout = 1000) => {
let done = false;
let timer = null;
const complete = completer => (...args) => {
if (!done) {
done = true;
if (timer !== null) {
clearTimeout(timer);
timer = null;
}
completer.apply(null, args);
}
};
const resolve = complete(resolveCb);
const reject = complete(rejectCb);
const start = (...args) => {
if (!done && timer === null) {
timer = setTimeout(() => reject.apply(null, args), timeout);
}
};
return {
start,
resolve,
reject
};
};
const create$1 = () => {
const tasks = {};
const resultFns = {};
const resources = {};
const load = (id, url) => {
const loadErrMsg = `Script at URL "${ url }" failed to load`;
const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`;
if (tasks[id] !== undefined) {
return tasks[id];
} else {
const task = new Promise((resolve, reject) => {
const waiter = awaiter(resolve, reject);
resultFns[id] = waiter.resolve;
ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
});
tasks[id] = task;
return task;
}
};
const add = (id, data) => {
if (resultFns[id] !== undefined) {
resultFns[id](data);
delete resultFns[id];
}
tasks[id] = Promise.resolve(data);
resources[id] = data;
};
const has = id => {
return id in resources;
};
const unload = id => {
delete tasks[id];
delete resources[id];
};
const get = id => resources[id];
return {
load,
add,
has,
get,
unload
};
};
const Resource = create$1();
const create = () => (() => {
let data = {};
let keys = [];
const storage = {
getItem: key => {
const item = data[key];
return item ? item : null;
},
setItem: (key, value) => {
keys.push(key);
data[key] = String(value);
},
key: index => {
return keys[index];
},
removeItem: key => {
keys = keys.filter(k => k === key);
delete data[key];
},
clear: () => {
keys = [];
data = {};
},
length: 0
};
Object.defineProperty(storage, 'length', {
get: () => keys.length,
configurable: false,
enumerable: false
});
return storage;
})();
let localStorage;
try {
const test = '__storage_test__';
localStorage = window.localStorage;
localStorage.setItem(test, test);
localStorage.removeItem(test);
} catch (e) {
localStorage = create();
}
var LocalStorage = localStorage;
const publicApi = {
geom: { Rect },
util: {
Delay,
Tools,
VK,
URI,
EventDispatcher,
Observable,
I18n,
LocalStorage,
ImageUploader
},
dom: {
EventUtils,
TreeWalker: DomTreeWalker,
TextSeeker,
DOMUtils,
ScriptLoader,
RangeUtils,
Serializer: DomSerializer,
StyleSheetLoader,
ControlSelection,
BookmarkManager,
Selection: EditorSelection,
Event: EventUtils.Event
},
html: {
Styles,
Entities,
Node: AstNode,
Schema,
DomParser,
Writer,
Serializer: HtmlSerializer
},
Env,
AddOnManager,
Annotator,
Formatter,
UndoManager,
EditorCommands,
WindowManager,
NotificationManager,
EditorObservable,
Shortcuts,
Editor,
FocusManager,
EditorManager,
DOM: DOMUtils.DOM,
ScriptLoader: ScriptLoader.ScriptLoader,
PluginManager,
ThemeManager,
ModelManager,
IconManager,
Resource,
FakeClipboard,
trim: Tools.trim,
isArray: Tools.isArray,
is: Tools.is,
toArray: Tools.toArray,
makeMap: Tools.makeMap,
each: Tools.each,
map: Tools.map,
grep: Tools.grep,
inArray: Tools.inArray,
extend: Tools.extend,
walk: Tools.walk,
resolve: Tools.resolve,
explode: Tools.explode,
_addCacheSuffix: Tools._addCacheSuffix
};
const tinymce$1 = Tools.extend(EditorManager, publicApi);
const exportToModuleLoaders = tinymce => {
if (typeof module === 'object') {
try {
module.exports = tinymce;
} catch (_) {
}
}
};
const exportToWindowGlobal = tinymce => {
window.tinymce = tinymce;
window.tinyMCE = tinymce;
};
exportToWindowGlobal(tinymce$1);
exportToModuleLoaders(tinymce$1);
})();