2 * TinyMCE version 6.2.0 (2022-09-08)
8 const getPrototypeOf$2 = Object.getPrototypeOf;
9 const hasProto = (v, constructor, predicate) => {
10 if (predicate(v, constructor.prototype)) {
13 return v.constructor?.name === constructor.name;
20 } else if (t === 'object' && Array.isArray(x)) {
22 } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
28 const isType$1 = type => value => typeOf(value) === type;
29 const isSimpleType = type => value => typeof value === type;
30 const eq$1 = t => a => t === a;
31 const is$2 = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf$2(o) === proto);
32 const isString = isType$1('string');
33 const isObject = isType$1('object');
34 const isPlainObject = value => is$2(value, Object);
35 const isArray = isType$1('array');
36 const isNull = eq$1(null);
37 const isBoolean = isSimpleType('boolean');
38 const isUndefined = eq$1(undefined);
39 const isNullable = a => a === null || a === undefined;
40 const isNonNullable = a => !isNullable(a);
41 const isFunction = isSimpleType('function');
42 const isNumber = isSimpleType('number');
43 const isArrayOf = (value, pred) => {
45 for (let i = 0, len = value.length; i < len; ++i) {
46 if (!pred(value[i])) {
57 const noarg = f => () => f();
58 const compose = (fa, fb) => {
60 return fa(fb.apply(null, args));
63 const compose1 = (fbc, fab) => a => fbc(fab(a));
64 const constant$1 = value => {
69 const identity = x => {
72 const tripleEquals = (a, b) => {
75 function curry(fn, ...initialArgs) {
76 return (...restArgs) => {
77 const all = initialArgs.concat(restArgs);
78 return fn.apply(null, all);
81 const not = f => t => !f(t);
87 const apply$1 = f => {
90 const never = constant$1(false);
91 const always = constant$1(true);
93 var global$a = tinymce.util.Tools.resolve('tinymce.ThemeManager');
96 constructor(tag, value) {
101 return new Optional(true, value);
104 return Optional.singletonNone;
106 fold(onNone, onSome) {
108 return onSome(this.value);
121 return Optional.some(mapper(this.value));
123 return Optional.none();
128 return binder(this.value);
130 return Optional.none();
134 return this.tag && predicate(this.value);
137 return !this.tag || predicate(this.value);
140 if (!this.tag || predicate(this.value)) {
143 return Optional.none();
147 return this.tag ? this.value : replacement;
150 return this.tag ? this : replacement;
153 return this.tag ? this.value : thunk();
156 return this.tag ? this : thunk();
160 throw new Error(message ?? 'Called getOrDie on None');
166 return isNonNullable(value) ? Optional.some(value) : Optional.none();
169 return this.tag ? this.value : null;
180 return this.tag ? [this.value] : [];
183 return this.tag ? `some(${ this.value })` : 'none()';
186 Optional.singletonNone = new Optional(false);
188 const nativeSlice = Array.prototype.slice;
189 const nativeIndexOf = Array.prototype.indexOf;
190 const nativePush = Array.prototype.push;
191 const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
192 const indexOf = (xs, x) => {
193 const r = rawIndexOf(xs, x);
194 return r === -1 ? Optional.none() : Optional.some(r);
196 const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
197 const exists = (xs, pred) => {
198 for (let i = 0, len = xs.length; i < len; i++) {
206 const range$2 = (num, f) => {
208 for (let i = 0; i < num; i++) {
213 const chunk$1 = (array, size) => {
215 for (let i = 0; i < array.length; i += size) {
216 const s = nativeSlice.call(array, i, i + size);
221 const map$2 = (xs, f) => {
222 const len = xs.length;
223 const r = new Array(len);
224 for (let i = 0; i < len; i++) {
230 const each$1 = (xs, f) => {
231 for (let i = 0, len = xs.length; i < len; i++) {
236 const eachr = (xs, f) => {
237 for (let i = xs.length - 1; i >= 0; i--) {
242 const partition$3 = (xs, pred) => {
245 for (let i = 0, len = xs.length; i < len; i++) {
247 const arr = pred(x, i) ? pass : fail;
255 const filter$2 = (xs, pred) => {
257 for (let i = 0, len = xs.length; i < len; i++) {
265 const foldr = (xs, f, acc) => {
266 eachr(xs, (x, i) => {
271 const foldl = (xs, f, acc) => {
272 each$1(xs, (x, i) => {
277 const findUntil = (xs, pred, until) => {
278 for (let i = 0, len = xs.length; i < len; i++) {
281 return Optional.some(x);
282 } else if (until(x, i)) {
286 return Optional.none();
288 const find$5 = (xs, pred) => {
289 return findUntil(xs, pred, never);
291 const findIndex$1 = (xs, pred) => {
292 for (let i = 0, len = xs.length; i < len; i++) {
295 return Optional.some(i);
298 return Optional.none();
300 const flatten = xs => {
302 for (let i = 0, len = xs.length; i < len; ++i) {
303 if (!isArray(xs[i])) {
304 throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
306 nativePush.apply(r, xs[i]);
310 const bind$3 = (xs, f) => flatten(map$2(xs, f));
311 const forall = (xs, pred) => {
312 for (let i = 0, len = xs.length; i < len; ++i) {
314 if (pred(x, i) !== true) {
320 const reverse = xs => {
321 const r = nativeSlice.call(xs, 0);
325 const difference = (a1, a2) => filter$2(a1, x => !contains$2(a2, x));
326 const mapToObject = (xs, f) => {
328 for (let i = 0, len = xs.length; i < len; i++) {
330 r[String(x)] = f(x, i);
334 const pure$2 = x => [x];
335 const sort = (xs, comparator) => {
336 const copy = nativeSlice.call(xs, 0);
337 copy.sort(comparator);
340 const get$h = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
341 const head = xs => get$h(xs, 0);
342 const last$1 = xs => get$h(xs, xs.length - 1);
343 const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
344 const findMap = (arr, f) => {
345 for (let i = 0; i < arr.length; i++) {
346 const r = f(arr[i], i);
351 return Optional.none();
354 const keys = Object.keys;
355 const hasOwnProperty$1 = Object.hasOwnProperty;
356 const each = (obj, f) => {
357 const props = keys(obj);
358 for (let k = 0, len = props.length; k < len; k++) {
364 const map$1 = (obj, f) => {
365 return tupleMap(obj, (x, i) => ({
370 const tupleMap = (obj, f) => {
372 each(obj, (x, i) => {
373 const tuple = f(x, i);
374 r[tuple.k] = tuple.v;
378 const objAcc = r => (x, i) => {
381 const internalFilter = (obj, pred, onTrue, onFalse) => {
382 each(obj, (x, i) => {
383 (pred(x, i) ? onTrue : onFalse)(x, i);
386 const bifilter = (obj, pred) => {
389 internalFilter(obj, pred, objAcc(t), objAcc(f));
395 const filter$1 = (obj, pred) => {
397 internalFilter(obj, pred, objAcc(t), noop);
400 const mapToArray = (obj, f) => {
402 each(obj, (value, name) => {
403 r.push(f(value, name));
407 const find$4 = (obj, pred) => {
408 const props = keys(obj);
409 for (let k = 0, len = props.length; k < len; k++) {
412 if (pred(x, i, obj)) {
413 return Optional.some(x);
416 return Optional.none();
418 const values = obj => {
419 return mapToArray(obj, identity);
421 const get$g = (obj, key) => {
422 return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
424 const has$2 = (obj, key) => hasOwnProperty$1.call(obj, key);
425 const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
427 const is$1 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
428 const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
434 for (let i = 0; i < arr.length; i++) {
439 const sequence = arr => {
441 for (let i = 0; i < arr.length; i++) {
444 r.push(x.getOrDie());
446 return Optional.none();
449 return Optional.some(r);
451 const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
452 const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
453 const mapFrom = (a, f) => a !== undefined && a !== null ? Optional.some(f(a)) : Optional.none();
454 const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
456 const addToEnd = (str, suffix) => {
459 const removeFromStart = (str, numChars) => {
460 return str.substring(numChars);
463 const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
464 const removeLeading = (str, prefix) => {
465 return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
467 const ensureTrailing = (str, suffix) => {
468 return endsWith(str, suffix) ? str : addToEnd(str, suffix);
470 const contains$1 = (str, substr, start = 0, end) => {
471 const idx = str.indexOf(substr, start);
473 return isUndefined(end) ? true : idx + substr.length <= end;
478 const startsWith = (str, prefix) => {
479 return checkRange(str, prefix, 0);
481 const endsWith = (str, suffix) => {
482 return checkRange(str, suffix, str.length - suffix.length);
484 const blank = r => s => s.replace(r, '');
485 const trim$1 = blank(/^\s+|\s+$/g);
486 const isNotEmpty = s => s.length > 0;
487 const isEmpty = s => !isNotEmpty(s);
489 const isSupported$1 = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
491 const fromHtml$2 = (html, scope) => {
492 const doc = scope || document;
493 const div = doc.createElement('div');
494 div.innerHTML = html;
495 if (!div.hasChildNodes() || div.childNodes.length > 1) {
496 const message = 'HTML does not have a single root node';
497 console.error(message, html);
498 throw new Error(message);
500 return fromDom(div.childNodes[0]);
502 const fromTag = (tag, scope) => {
503 const doc = scope || document;
504 const node = doc.createElement(tag);
505 return fromDom(node);
507 const fromText = (text, scope) => {
508 const doc = scope || document;
509 const node = doc.createTextNode(text);
510 return fromDom(node);
512 const fromDom = node => {
513 if (node === null || node === undefined) {
514 throw new Error('Node cannot be null or undefined');
516 return { dom: node };
518 const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
519 const SugarElement = {
520 fromHtml: fromHtml$2,
527 const Global = typeof window !== 'undefined' ? window : Function('return this;')();
529 const path$1 = (parts, scope) => {
530 let o = scope !== undefined && scope !== null ? scope : Global;
531 for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
536 const resolve = (p, scope) => {
537 const parts = p.split('.');
538 return path$1(parts, scope);
541 const unsafe = (name, scope) => {
542 return resolve(name, scope);
544 const getOrDie$1 = (name, scope) => {
545 const actual = unsafe(name, scope);
546 if (actual === undefined || actual === null) {
547 throw new Error(name + ' not available on this browser');
552 const getPrototypeOf$1 = Object.getPrototypeOf;
553 const sandHTMLElement = scope => {
554 return getOrDie$1('HTMLElement', scope);
556 const isPrototypeOf = x => {
557 const scope = resolve('ownerDocument.defaultView', x);
558 return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name));
562 const DOCUMENT_FRAGMENT = 11;
566 const name$3 = element => {
567 const r = element.dom.nodeName;
568 return r.toLowerCase();
570 const type$1 = element => element.dom.nodeType;
571 const isType = t => element => type$1(element) === t;
572 const isHTMLElement = element => isElement$1(element) && isPrototypeOf(element.dom);
573 const isElement$1 = isType(ELEMENT);
574 const isText = isType(TEXT);
575 const isDocument = isType(DOCUMENT);
576 const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
577 const isTag = tag => e => isElement$1(e) && name$3(e) === tag;
579 const is = (element, selector) => {
580 const dom = element.dom;
581 if (dom.nodeType !== ELEMENT) {
585 if (elem.matches !== undefined) {
586 return elem.matches(selector);
587 } else if (elem.msMatchesSelector !== undefined) {
588 return elem.msMatchesSelector(selector);
589 } else if (elem.webkitMatchesSelector !== undefined) {
590 return elem.webkitMatchesSelector(selector);
591 } else if (elem.mozMatchesSelector !== undefined) {
592 return elem.mozMatchesSelector(selector);
594 throw new Error('Browser lacks native selectors');
598 const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
599 const all$3 = (selector, scope) => {
600 const base = scope === undefined ? document : scope.dom;
601 return bypassSelector(base) ? [] : map$2(base.querySelectorAll(selector), SugarElement.fromDom);
603 const one = (selector, scope) => {
604 const base = scope === undefined ? document : scope.dom;
605 return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
608 const eq = (e1, e2) => e1.dom === e2.dom;
609 const contains = (e1, e2) => {
612 return d1 === d2 ? false : d1.contains(d2);
615 const owner$4 = element => SugarElement.fromDom(element.dom.ownerDocument);
616 const documentOrOwner = dos => isDocument(dos) ? dos : owner$4(dos);
617 const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
618 const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
619 const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
620 const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
621 const offsetParent = element => Optional.from(element.dom.offsetParent).map(SugarElement.fromDom);
622 const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
623 const children = element => map$2(element.dom.childNodes, SugarElement.fromDom);
624 const child$2 = (element, index) => {
625 const cs = element.dom.childNodes;
626 return Optional.from(cs[index]).map(SugarElement.fromDom);
628 const firstChild = element => child$2(element, 0);
629 const spot = (element, offset) => ({
633 const leaf = (element, offset) => {
634 const cs = children(element);
635 return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
638 const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
639 const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
640 const isSupported = constant$1(supported);
641 const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
642 const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
643 const isInShadowRoot = e => getShadowRoot(e).isSome();
644 const getShadowRoot = e => {
645 const r = getRootNode(e);
646 return isShadowRoot(r) ? Optional.some(r) : Optional.none();
648 const getShadowHost = e => SugarElement.fromDom(e.dom.host);
649 const getOriginalEventTarget = event => {
650 if (isSupported() && isNonNullable(event.target)) {
651 const el = SugarElement.fromDom(event.target);
652 if (isElement$1(el) && isOpenShadowHost(el)) {
653 if (event.composed && event.composedPath) {
654 const composedPath = event.composedPath();
656 return head(composedPath);
661 return Optional.from(event.target);
663 const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
665 const inBody = element => {
666 const dom = isText(element) ? element.dom.parentNode : element.dom;
667 if (dom === undefined || dom === null || dom.ownerDocument === null) {
670 const doc = dom.ownerDocument;
671 return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
673 const body = () => getBody(SugarElement.fromDom(document));
674 const getBody = doc => {
675 const b = doc.dom.body;
676 if (b === null || b === undefined) {
677 throw new Error('Body is not available yet');
679 return SugarElement.fromDom(b);
682 const rawSet = (dom, key, value) => {
683 if (isString(value) || isBoolean(value) || isNumber(value)) {
684 dom.setAttribute(key, value + '');
686 console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
687 throw new Error('Attribute value was not simple');
690 const set$9 = (element, key, value) => {
691 rawSet(element.dom, key, value);
693 const setAll$1 = (element, attrs) => {
694 const dom = element.dom;
695 each(attrs, (v, k) => {
699 const get$f = (element, key) => {
700 const v = element.dom.getAttribute(key);
701 return v === null ? undefined : v;
703 const getOpt = (element, key) => Optional.from(get$f(element, key));
704 const has$1 = (element, key) => {
705 const dom = element.dom;
706 return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
708 const remove$7 = (element, key) => {
709 element.dom.removeAttribute(key);
711 const clone$2 = element => foldl(element.dom.attributes, (acc, attr) => {
712 acc[attr.name] = attr.value;
716 const internalSet = (dom, property, value) => {
717 if (!isString(value)) {
718 console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
719 throw new Error('CSS value must be a string: ' + value);
721 if (isSupported$1(dom)) {
722 dom.style.setProperty(property, value);
725 const internalRemove = (dom, property) => {
726 if (isSupported$1(dom)) {
727 dom.style.removeProperty(property);
730 const set$8 = (element, property, value) => {
731 const dom = element.dom;
732 internalSet(dom, property, value);
734 const setAll = (element, css) => {
735 const dom = element.dom;
736 each(css, (v, k) => {
737 internalSet(dom, k, v);
740 const setOptions = (element, css) => {
741 const dom = element.dom;
742 each(css, (v, k) => {
744 internalRemove(dom, k);
746 internalSet(dom, k, value);
750 const get$e = (element, property) => {
751 const dom = element.dom;
752 const styles = window.getComputedStyle(dom);
753 const r = styles.getPropertyValue(property);
754 return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
756 const getUnsafeProperty = (dom, property) => isSupported$1(dom) ? dom.style.getPropertyValue(property) : '';
757 const getRaw = (element, property) => {
758 const dom = element.dom;
759 const raw = getUnsafeProperty(dom, property);
760 return Optional.from(raw).filter(r => r.length > 0);
762 const getAllRaw = element => {
764 const dom = element.dom;
765 if (isSupported$1(dom)) {
766 for (let i = 0; i < dom.style.length; i++) {
767 const ruleName = dom.style.item(i);
768 css[ruleName] = dom.style[ruleName];
773 const isValidValue = (tag, property, value) => {
774 const element = SugarElement.fromTag(tag);
775 set$8(element, property, value);
776 const style = getRaw(element, property);
777 return style.isSome();
779 const remove$6 = (element, property) => {
780 const dom = element.dom;
781 internalRemove(dom, property);
782 if (is$1(getOpt(element, 'style').map(trim$1), '')) {
783 remove$7(element, 'style');
786 const reflow = e => e.dom.offsetWidth;
788 const Dimension = (name, getOffset) => {
789 const set = (element, h) => {
790 if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
791 throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
793 const dom = element.dom;
794 if (isSupported$1(dom)) {
795 dom.style[name] = h + 'px';
798 const get = element => {
799 const r = getOffset(element);
800 if (r <= 0 || r === null) {
801 const css = get$e(element, name);
802 return parseFloat(css) || 0;
806 const getOuter = get;
807 const aggregate = (element, properties) => foldl(properties, (acc, property) => {
808 const val = get$e(element, property);
809 const value = val === undefined ? 0 : parseInt(val, 10);
810 return isNaN(value) ? acc : acc + value;
812 const max = (element, value, properties) => {
813 const cumulativeInclusions = aggregate(element, properties);
814 const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
826 const api$2 = Dimension('height', element => {
827 const dom = element.dom;
828 return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
830 const get$d = element => api$2.get(element);
831 const getOuter$2 = element => api$2.getOuter(element);
832 const setMax$1 = (element, value) => {
838 'border-bottom-width',
841 const absMax = api$2.max(element, value, inclusions);
842 set$8(element, 'max-height', absMax + 'px');
845 const r$1 = (left, top) => {
846 const translate = (x, y) => r$1(left + x, top + y);
853 const SugarPosition = r$1;
855 const boxPosition = dom => {
856 const box = dom.getBoundingClientRect();
857 return SugarPosition(box.left, box.top);
859 const firstDefinedOrZero = (a, b) => {
860 if (a !== undefined) {
863 return b !== undefined ? b : 0;
866 const absolute$3 = element => {
867 const doc = element.dom.ownerDocument;
868 const body = doc.body;
869 const win = doc.defaultView;
870 const html = doc.documentElement;
871 if (body === element.dom) {
872 return SugarPosition(body.offsetLeft, body.offsetTop);
874 const scrollTop = firstDefinedOrZero(win?.pageYOffset, html.scrollTop);
875 const scrollLeft = firstDefinedOrZero(win?.pageXOffset, html.scrollLeft);
876 const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
877 const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
878 return viewport$1(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
880 const viewport$1 = element => {
881 const dom = element.dom;
882 const doc = dom.ownerDocument;
883 const body = doc.body;
885 return SugarPosition(body.offsetLeft, body.offsetTop);
887 if (!inBody(element)) {
888 return SugarPosition(0, 0);
890 return boxPosition(dom);
893 const api$1 = Dimension('width', element => element.dom.offsetWidth);
894 const set$7 = (element, h) => api$1.set(element, h);
895 const get$c = element => api$1.get(element);
896 const getOuter$1 = element => api$1.getOuter(element);
897 const setMax = (element, value) => {
903 'border-right-width',
906 const absMax = api$1.max(element, value, inclusions);
907 set$8(element, 'max-width', absMax + 'px');
910 const cached = f => {
913 return (...args) => {
916 r = f.apply(null, args);
922 const DeviceType = (os, browser, userAgent, mediaMatch) => {
923 const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
924 const isiPhone = os.isiOS() && !isiPad;
925 const isMobile = os.isiOS() || os.isAndroid();
926 const isTouch = isMobile || mediaMatch('(pointer:coarse)');
927 const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
928 const isPhone = isiPhone || isMobile && !isTablet;
929 const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
930 const isDesktop = !isPhone && !isTablet && !iOSwebview;
932 isiPad: constant$1(isiPad),
933 isiPhone: constant$1(isiPhone),
934 isTablet: constant$1(isTablet),
935 isPhone: constant$1(isPhone),
936 isTouch: constant$1(isTouch),
937 isAndroid: os.isAndroid,
939 isWebView: constant$1(iOSwebview),
940 isDesktop: constant$1(isDesktop)
944 const firstMatch = (regexes, s) => {
945 for (let i = 0; i < regexes.length; i++) {
946 const x = regexes[i];
953 const find$3 = (regexes, agent) => {
954 const r = firstMatch(regexes, agent);
962 return Number(agent.replace(r, '$' + i));
964 return nu$d(group(1), group(2));
966 const detect$4 = (versionRegexes, agent) => {
967 const cleanedAgent = String(agent).toLowerCase();
968 if (versionRegexes.length === 0) {
971 return find$3(versionRegexes, cleanedAgent);
973 const unknown$3 = () => {
976 const nu$d = (major, minor) => {
988 const detectBrowser$1 = (browsers, userAgentData) => {
989 return findMap(userAgentData.brands, uaBrand => {
990 const lcBrand = uaBrand.brand.toLowerCase();
991 return find$5(browsers, browser => lcBrand === browser.brand?.toLowerCase()).map(info => ({
993 version: Version.nu(parseInt(uaBrand.version, 10), 0)
998 const detect$3 = (candidates, userAgent) => {
999 const agent = String(userAgent).toLowerCase();
1000 return find$5(candidates, candidate => {
1001 return candidate.search(agent);
1004 const detectBrowser = (browsers, userAgent) => {
1005 return detect$3(browsers, userAgent).map(browser => {
1006 const version = Version.detect(browser.versionRegexes, userAgent);
1008 current: browser.name,
1013 const detectOs = (oses, userAgent) => {
1014 return detect$3(oses, userAgent).map(os => {
1015 const version = Version.detect(os.versionRegexes, userAgent);
1023 const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
1024 const checkContains = target => {
1025 return uastring => {
1026 return contains$1(uastring, target);
1032 versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
1033 search: uastring => {
1034 return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
1041 /.*?chrome\/([0-9]+)\.([0-9]+).*/,
1044 search: uastring => {
1045 return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
1051 /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
1052 /.*?rv:([0-9]+)\.([0-9]+).*/
1054 search: uastring => {
1055 return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
1062 /.*?opera\/([0-9]+)\.([0-9]+).*/
1064 search: checkContains('opera')
1068 versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
1069 search: checkContains('firefox')
1075 /.*?cpu os ([0-9]+)_([0-9]+).*/
1077 search: uastring => {
1078 return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
1085 search: checkContains('win'),
1086 versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
1090 search: uastring => {
1091 return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
1094 /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
1095 /.*cpu os ([0-9]+)_([0-9]+).*/,
1096 /.*cpu iphone os ([0-9]+)_([0-9]+).*/
1101 search: checkContains('android'),
1102 versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
1106 search: checkContains('mac os x'),
1107 versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
1111 search: checkContains('linux'),
1116 search: checkContains('sunos'),
1121 search: checkContains('freebsd'),
1126 search: checkContains('cros'),
1127 versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
1130 const PlatformInfo = {
1131 browsers: constant$1(browsers),
1132 oses: constant$1(oses)
1135 const edge = 'Edge';
1136 const chromium = 'Chromium';
1138 const opera = 'Opera';
1139 const firefox = 'Firefox';
1140 const safari = 'Safari';
1141 const unknown$2 = () => {
1144 version: Version.unknown()
1147 const nu$c = info => {
1148 const current = info.current;
1149 const version = info.version;
1150 const isBrowser = name => () => current === name;
1154 isEdge: isBrowser(edge),
1155 isChromium: isBrowser(chromium),
1156 isIE: isBrowser(ie),
1157 isOpera: isBrowser(opera),
1158 isFirefox: isBrowser(firefox),
1159 isSafari: isBrowser(safari)
1165 edge: constant$1(edge),
1166 chromium: constant$1(chromium),
1168 opera: constant$1(opera),
1169 firefox: constant$1(firefox),
1170 safari: constant$1(safari)
1173 const windows = 'Windows';
1175 const android = 'Android';
1176 const linux = 'Linux';
1177 const macos = 'macOS';
1178 const solaris = 'Solaris';
1179 const freebsd = 'FreeBSD';
1180 const chromeos = 'ChromeOS';
1181 const unknown$1 = () => {
1184 version: Version.unknown()
1187 const nu$b = info => {
1188 const current = info.current;
1189 const version = info.version;
1190 const isOS = name => () => current === name;
1194 isWindows: isOS(windows),
1196 isAndroid: isOS(android),
1197 isMacOS: isOS(macos),
1198 isLinux: isOS(linux),
1199 isSolaris: isOS(solaris),
1200 isFreeBSD: isOS(freebsd),
1201 isChromeOS: isOS(chromeos)
1204 const OperatingSystem = {
1207 windows: constant$1(windows),
1208 ios: constant$1(ios),
1209 android: constant$1(android),
1210 linux: constant$1(linux),
1211 macos: constant$1(macos),
1212 solaris: constant$1(solaris),
1213 freebsd: constant$1(freebsd),
1214 chromeos: constant$1(chromeos)
1217 const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => {
1218 const browsers = PlatformInfo.browsers();
1219 const oses = PlatformInfo.oses();
1220 const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
1221 const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
1222 const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
1229 const PlatformDetection = { detect: detect$2 };
1231 const mediaMatch = query => window.matchMedia(query).matches;
1232 let platform = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
1233 const detect$1 = () => platform();
1235 const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
1244 const fromRawEvent$1 = rawEvent => {
1245 const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
1246 const stop = () => rawEvent.stopPropagation();
1247 const prevent = () => rawEvent.preventDefault();
1248 const kill = compose(prevent, stop);
1249 return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
1251 const handle = (filter, handler) => rawEvent => {
1252 if (filter(rawEvent)) {
1253 handler(fromRawEvent$1(rawEvent));
1256 const binder = (element, event, filter, handler, useCapture) => {
1257 const wrapped = handle(filter, handler);
1258 element.dom.addEventListener(event, wrapped, useCapture);
1259 return { unbind: curry(unbind, element, event, wrapped, useCapture) };
1261 const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
1262 const capture$1 = (element, event, filter, handler) => binder(element, event, filter, handler, true);
1263 const unbind = (element, event, handler, useCapture) => {
1264 element.dom.removeEventListener(event, handler, useCapture);
1267 const before$1 = (marker, element) => {
1268 const parent$1 = parent(marker);
1269 parent$1.each(v => {
1270 v.dom.insertBefore(element.dom, marker.dom);
1273 const after$2 = (marker, element) => {
1274 const sibling = nextSibling(marker);
1275 sibling.fold(() => {
1276 const parent$1 = parent(marker);
1277 parent$1.each(v => {
1278 append$2(v, element);
1281 before$1(v, element);
1284 const prepend$1 = (parent, element) => {
1285 const firstChild$1 = firstChild(parent);
1286 firstChild$1.fold(() => {
1287 append$2(parent, element);
1289 parent.dom.insertBefore(element.dom, v.dom);
1292 const append$2 = (parent, element) => {
1293 parent.dom.appendChild(element.dom);
1295 const appendAt = (parent, element, index) => {
1296 child$2(parent, index).fold(() => {
1297 append$2(parent, element);
1299 before$1(v, element);
1303 const append$1 = (parent, elements) => {
1304 each$1(elements, x => {
1305 append$2(parent, x);
1309 const empty = element => {
1310 element.dom.textContent = '';
1311 each$1(children(element), rogue => {
1315 const remove$5 = element => {
1316 const dom = element.dom;
1317 if (dom.parentNode !== null) {
1318 dom.parentNode.removeChild(dom);
1322 const get$b = _DOC => {
1323 const doc = _DOC !== undefined ? _DOC.dom : document;
1324 const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
1325 const y = doc.body.scrollTop || doc.documentElement.scrollTop;
1326 return SugarPosition(x, y);
1328 const to = (x, y, _DOC) => {
1329 const doc = _DOC !== undefined ? _DOC.dom : document;
1330 const win = doc.defaultView;
1336 const get$a = _win => {
1337 const win = _win === undefined ? window : _win;
1338 if (detect$1().browser.isFirefox()) {
1339 return Optional.none();
1341 return Optional.from(win.visualViewport);
1344 const bounds$1 = (x, y, width, height) => ({
1352 const getBounds$3 = _win => {
1353 const win = _win === undefined ? window : _win;
1354 const doc = win.document;
1355 const scroll = get$b(SugarElement.fromDom(doc));
1356 return get$a(win).fold(() => {
1357 const html = win.document.documentElement;
1358 const width = html.clientWidth;
1359 const height = html.clientHeight;
1360 return bounds$1(scroll.left, scroll.top, width, height);
1361 }, visualViewport => bounds$1(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
1364 const getDocument = () => SugarElement.fromDom(document);
1366 const walkUp = (navigation, doc) => {
1367 const frame = navigation.view(doc);
1368 return frame.fold(constant$1([]), f => {
1369 const parent = navigation.owner(f);
1370 const rest = walkUp(navigation, parent);
1371 return [f].concat(rest);
1374 const pathTo = (element, navigation) => {
1375 const d = navigation.owner(element);
1376 const paths = walkUp(navigation, d);
1377 return Optional.some(paths);
1380 const view = doc => {
1381 const element = doc.dom === document ? Optional.none() : Optional.from(doc.dom.defaultView?.frameElement);
1382 return element.map(SugarElement.fromDom);
1384 const owner$3 = element => owner$4(element);
1386 var Navigation = /*#__PURE__*/Object.freeze({
1392 const find$2 = element => {
1393 const doc = getDocument();
1394 const scroll = get$b(doc);
1395 const path = pathTo(element, Navigation);
1396 return path.fold(curry(absolute$3, element), frames => {
1397 const offset = viewport$1(element);
1398 const r = foldr(frames, (b, a) => {
1399 const loc = viewport$1(a);
1401 left: b.left + loc.left,
1402 top: b.top + loc.top
1408 return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
1412 const pointed = (point, width, height) => ({
1417 const rect = (x, y, width, height) => ({
1423 const bounds = (x, y, width, height) => ({
1431 const box$1 = element => {
1432 const xy = absolute$3(element);
1433 const w = getOuter$1(element);
1434 const h = getOuter$2(element);
1435 return bounds(xy.left, xy.top, w, h);
1437 const absolute$2 = element => {
1438 const position = find$2(element);
1439 const width = getOuter$1(element);
1440 const height = getOuter$2(element);
1441 return bounds(position.left, position.top, width, height);
1443 const win = () => getBounds$3(window);
1445 const value$4 = value => {
1446 const applyHelper = fn => fn(value);
1447 const constHelper = constant$1(value);
1448 const outputHelper = () => output;
1452 fold: (_onError, onValue) => onValue(value),
1455 map: mapper => Result.value(mapper(value)),
1456 mapError: outputHelper,
1458 exists: applyHelper,
1459 forall: applyHelper,
1462 getOrThunk: constHelper,
1463 orThunk: outputHelper,
1464 getOrDie: constHelper,
1468 toOptional: () => Optional.some(value)
1472 const error$1 = error => {
1473 const outputHelper = () => output;
1477 fold: (onError, _onValue) => onError(error),
1481 mapError: mapper => Result.error(mapper(error)),
1487 getOrThunk: apply$1,
1489 getOrDie: die(String(error)),
1491 toOptional: Optional.none
1495 const fromOption = (optional, err) => optional.fold(() => error$1(err), value$4);
1502 var SimpleResultType;
1503 (function (SimpleResultType) {
1504 SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
1505 SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
1506 }(SimpleResultType || (SimpleResultType = {})));
1507 const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
1508 const partition$2 = results => {
1511 each$1(results, obj => {
1512 fold$1(obj, err => errors.push(err), val => values.push(val));
1519 const mapError = (res, f) => {
1520 if (res.stype === SimpleResultType.Error) {
1522 stype: SimpleResultType.Error,
1523 serror: f(res.serror)
1529 const map = (res, f) => {
1530 if (res.stype === SimpleResultType.Value) {
1532 stype: SimpleResultType.Value,
1533 svalue: f(res.svalue)
1539 const bind$1 = (res, f) => {
1540 if (res.stype === SimpleResultType.Value) {
1541 return f(res.svalue);
1546 const bindError = (res, f) => {
1547 if (res.stype === SimpleResultType.Error) {
1548 return f(res.serror);
1553 const svalue = v => ({
1554 stype: SimpleResultType.Value,
1557 const serror = e => ({
1558 stype: SimpleResultType.Error,
1561 const toResult$1 = res => fold$1(res, Result.error, Result.value);
1562 const fromResult$1 = res => res.fold(serror, svalue);
1563 const SimpleResult = {
1564 fromResult: fromResult$1,
1565 toResult: toResult$1,
1567 partition: partition$2,
1576 const field$2 = (key, newKey, presence, prop) => ({
1583 const customField$1 = (newKey, instantiator) => ({
1588 const fold = (value, ifField, ifCustom) => {
1589 switch (value.tag) {
1591 return ifField(value.key, value.newKey, value.presence, value.prop);
1593 return ifCustom(value.newKey, value.instantiator);
1597 const shallow$1 = (old, nu) => {
1600 const deep = (old, nu) => {
1601 const bothObjects = isPlainObject(old) && isPlainObject(nu);
1602 return bothObjects ? deepMerge(old, nu) : nu;
1604 const baseMerge = merger => {
1605 return (...objects) => {
1606 if (objects.length === 0) {
1607 throw new Error(`Can't merge zero objects`);
1610 for (let j = 0; j < objects.length; j++) {
1611 const curObject = objects[j];
1612 for (const key in curObject) {
1613 if (has$2(curObject, key)) {
1614 ret[key] = merger(ret[key], curObject[key]);
1621 const deepMerge = baseMerge(deep);
1622 const merge$1 = baseMerge(shallow$1);
1624 const required$2 = () => ({
1628 const defaultedThunk = fallbackThunk => ({
1629 tag: 'defaultedThunk',
1630 process: fallbackThunk
1632 const defaulted$1 = fallback => defaultedThunk(constant$1(fallback));
1633 const asOption = () => ({
1637 const mergeWithThunk = baseThunk => ({
1638 tag: 'mergeWithThunk',
1641 const mergeWith = base => mergeWithThunk(constant$1(base));
1643 const mergeValues$1 = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values))) : SimpleResult.svalue(base);
1644 const mergeErrors$1 = errors => compose(SimpleResult.serror, flatten)(errors);
1645 const consolidateObj = (objects, base) => {
1646 const partition = SimpleResult.partition(objects);
1647 return partition.errors.length > 0 ? mergeErrors$1(partition.errors) : mergeValues$1(partition.values, base);
1649 const consolidateArr = objects => {
1650 const partitions = SimpleResult.partition(objects);
1651 return partitions.errors.length > 0 ? mergeErrors$1(partitions.errors) : SimpleResult.svalue(partitions.values);
1653 const ResultCombine = {
1658 const formatObj = input => {
1659 return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
1661 const formatErrors = errors => {
1662 const es = errors.length > 10 ? errors.slice(0, 10).concat([{
1664 getErrorInfo: constant$1('... (only showing first ten failures)')
1666 return map$2(es, e => {
1667 return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
1671 const nu$a = (path, getErrorInfo) => {
1672 return SimpleResult.serror([{
1677 const missingRequired = (path, key, obj) => nu$a(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
1678 const missingKey = (path, key) => nu$a(path, () => 'Choice schema did not contain choice key: "' + key + '"');
1679 const missingBranch = (path, branches, branch) => nu$a(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
1680 const unsupportedFields = (path, unsupported) => nu$a(path, () => 'There are unsupported fields: [' + unsupported.join(', ') + '] specified');
1681 const custom = (path, err) => nu$a(path, constant$1(err));
1683 const value$3 = validator => {
1684 const extract = (path, val) => {
1685 return SimpleResult.bindError(validator(val), err => custom(path, err));
1687 const toString = constant$1('val');
1693 const anyValue$1 = value$3(SimpleResult.svalue);
1695 const requiredAccess = (path, obj, key, bundle) => get$g(obj, key).fold(() => missingRequired(path, key, obj), bundle);
1696 const fallbackAccess = (obj, key, fallback, bundle) => {
1697 const v = get$g(obj, key).getOrThunk(() => fallback(obj));
1700 const optionAccess = (obj, key, bundle) => bundle(get$g(obj, key));
1701 const optionDefaultedAccess = (obj, key, fallback, bundle) => {
1702 const opt = get$g(obj, key).map(val => val === true ? fallback(obj) : val);
1705 const extractField = (field, path, obj, key, prop) => {
1706 const bundle = av => prop.extract(path.concat([key]), av);
1707 const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
1708 const result = prop.extract(path.concat([key]), ov);
1709 return SimpleResult.map(result, Optional.some);
1711 switch (field.tag) {
1713 return requiredAccess(path, obj, key, bundle);
1714 case 'defaultedThunk':
1715 return fallbackAccess(obj, key, field.process, bundle);
1717 return optionAccess(obj, key, bundleAsOption);
1718 case 'defaultedOptionThunk':
1719 return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
1720 case 'mergeWithThunk': {
1721 return fallbackAccess(obj, key, constant$1({}), v => {
1722 const result = deepMerge(field.process(obj), v);
1723 return bundle(result);
1728 const extractFields = (path, obj, fields) => {
1731 for (const field of fields) {
1732 fold(field, (key, newKey, presence, prop) => {
1733 const result = extractField(presence, path, obj, key, prop);
1734 SimpleResult.fold(result, err => {
1735 errors.push(...err);
1737 success[newKey] = res;
1739 }, (newKey, instantiator) => {
1740 success[newKey] = instantiator(obj);
1743 return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
1745 const valueThunk = getDelegate => {
1746 const extract = (path, val) => getDelegate().extract(path, val);
1747 const toString = () => getDelegate().toString();
1753 const getSetKeys = obj => keys(filter$1(obj, isNonNullable));
1754 const objOfOnly = fields => {
1755 const delegate = objOf(fields);
1756 const fieldNames = foldr(fields, (acc, value) => {
1757 return fold(value, key => deepMerge(acc, { [key]: true }), constant$1(acc));
1759 const extract = (path, o) => {
1760 const keys = isBoolean(o) ? [] : getSetKeys(o);
1761 const extra = filter$2(keys, k => !hasNonNullableKey(fieldNames, k));
1762 return extra.length === 0 ? delegate.extract(path, o) : unsupportedFields(path, extra);
1766 toString: delegate.toString
1769 const objOf = values => {
1770 const extract = (path, o) => extractFields(path, o, values);
1771 const toString = () => {
1772 const fieldStrings = map$2(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
1773 return 'obj{\n' + fieldStrings.join('\n') + '}';
1780 const arrOf = prop => {
1781 const extract = (path, array) => {
1782 const results = map$2(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
1783 return ResultCombine.consolidateArr(results);
1785 const toString = () => 'array(' + prop.toString() + ')';
1791 const oneOf = (props, rawF) => {
1792 const f = rawF !== undefined ? rawF : identity;
1793 const extract = (path, val) => {
1795 for (const prop of props) {
1796 const res = prop.extract(path, val);
1797 if (res.stype === SimpleResultType.Value) {
1799 stype: SimpleResultType.Value,
1800 svalue: f(res.svalue)
1805 return ResultCombine.consolidateArr(errors);
1807 const toString = () => 'oneOf(' + map$2(props, prop => prop.toString()).join(', ') + ')';
1813 const setOf$1 = (validator, prop) => {
1814 const validateKeys = (path, keys) => arrOf(value$3(validator)).extract(path, keys);
1815 const extract = (path, o) => {
1816 const keys$1 = keys(o);
1817 const validatedKeys = validateKeys(path, keys$1);
1818 return SimpleResult.bind(validatedKeys, validKeys => {
1819 const schema = map$2(validKeys, vk => {
1820 return field$2(vk, vk, required$2(), prop);
1822 return objOf(schema).extract(path, o);
1825 const toString = () => 'setOf(' + prop.toString() + ')';
1831 const thunk = (_desc, processor) => {
1832 const getP = cached(processor);
1833 const extract = (path, val) => getP().extract(path, val);
1834 const toString = () => getP().toString();
1840 const arrOfObj = compose(arrOf, objOf);
1842 const anyValue = constant$1(anyValue$1);
1843 const typedValue = (validator, expectedType) => value$3(a => {
1844 const actualType = typeof a;
1845 return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
1847 const number = typedValue(isNumber, 'number');
1848 const string = typedValue(isString, 'string');
1849 const boolean = typedValue(isBoolean, 'boolean');
1850 const functionProcessor = typedValue(isFunction, 'function');
1851 const isPostMessageable = val => {
1852 if (Object(val) !== val) {
1855 switch ({}.toString.call(val).slice(8, -1)) {
1869 return Object.keys(val).every(prop => isPostMessageable(val[prop]));
1874 const postMessageable = value$3(a => {
1875 if (isPostMessageable(a)) {
1876 return SimpleResult.svalue(a);
1878 return SimpleResult.serror('Expected value to be acceptable for sending via postMessage');
1882 const chooseFrom = (path, input, branches, ch) => {
1883 const fields = get$g(branches, ch);
1884 return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
1886 const choose$2 = (key, branches) => {
1887 const extract = (path, input) => {
1888 const choice = get$g(input, key);
1889 return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
1891 const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
1898 const arrOfVal = () => arrOf(anyValue$1);
1899 const valueOf = validator => value$3(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
1900 const setOf = (validator, prop) => setOf$1(v => SimpleResult.fromResult(validator(v)), prop);
1901 const extractValue = (label, prop, obj) => {
1902 const res = prop.extract([label], obj);
1903 return SimpleResult.mapError(res, errs => ({
1908 const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
1909 const getOrDie = extraction => {
1910 return extraction.fold(errInfo => {
1911 throw new Error(formatError(errInfo));
1914 const asRawOrDie$1 = (label, prop, obj) => getOrDie(asRaw(label, prop, obj));
1915 const formatError = errInfo => {
1916 return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
1918 const choose$1 = (key, branches) => choose$2(key, map$1(branches, objOf));
1919 const thunkOf = (desc, schema) => thunk(desc, schema);
1921 const field$1 = field$2;
1922 const customField = customField$1;
1923 const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
1924 const required$1 = key => field$1(key, key, required$2(), anyValue());
1925 const requiredOf = (key, schema) => field$1(key, key, required$2(), schema);
1926 const requiredNumber = key => requiredOf(key, number);
1927 const requiredString = key => requiredOf(key, string);
1928 const requiredStringEnum = (key, values) => field$1(key, key, required$2(), validateEnum(values));
1929 const requiredBoolean = key => requiredOf(key, boolean);
1930 const requiredFunction = key => requiredOf(key, functionProcessor);
1931 const forbid = (key, message) => field$1(key, key, asOption(), value$3(_v => SimpleResult.serror('The field: ' + key + ' is forbidden. ' + message)));
1932 const requiredObjOf = (key, objSchema) => field$1(key, key, required$2(), objOf(objSchema));
1933 const requiredArrayOfObj = (key, objFields) => field$1(key, key, required$2(), arrOfObj(objFields));
1934 const requiredArrayOf = (key, schema) => field$1(key, key, required$2(), arrOf(schema));
1935 const option$3 = key => field$1(key, key, asOption(), anyValue());
1936 const optionOf = (key, schema) => field$1(key, key, asOption(), schema);
1937 const optionNumber = key => optionOf(key, number);
1938 const optionString = key => optionOf(key, string);
1939 const optionStringEnum = (key, values) => optionOf(key, validateEnum(values));
1940 const optionFunction = key => optionOf(key, functionProcessor);
1941 const optionArrayOf = (key, schema) => optionOf(key, arrOf(schema));
1942 const optionObjOf = (key, objSchema) => optionOf(key, objOf(objSchema));
1943 const optionObjOfOnly = (key, objSchema) => optionOf(key, objOfOnly(objSchema));
1944 const defaulted = (key, fallback) => field$1(key, key, defaulted$1(fallback), anyValue());
1945 const defaultedOf = (key, fallback, schema) => field$1(key, key, defaulted$1(fallback), schema);
1946 const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
1947 const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
1948 const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
1949 const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
1950 const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
1951 const defaultedPostMsg = (key, fallback) => defaultedOf(key, fallback, postMessageable);
1952 const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
1953 const defaultedObjOf = (key, fallback, objSchema) => defaultedOf(key, fallback, objOf(objSchema));
1955 const Cell = initial => {
1956 let value = initial;
1969 const generate$7 = cases => {
1970 if (!isArray(cases)) {
1971 throw new Error('cases must be an array');
1973 if (cases.length === 0) {
1974 throw new Error('there must be at least one case');
1976 const constructors = [];
1978 each$1(cases, (acase, count) => {
1979 const keys$1 = keys(acase);
1980 if (keys$1.length !== 1) {
1981 throw new Error('one and only one name per case');
1983 const key = keys$1[0];
1984 const value = acase[key];
1985 if (adt[key] !== undefined) {
1986 throw new Error('duplicate key detected:' + key);
1987 } else if (key === 'cata') {
1988 throw new Error('cannot have a case named cata (sorry)');
1989 } else if (!isArray(value)) {
1990 throw new Error('case arguments must be an array');
1992 constructors.push(key);
1993 adt[key] = (...args) => {
1994 const argLength = args.length;
1995 if (argLength !== value.length) {
1996 throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
1998 const match = branches => {
1999 const branchKeys = keys(branches);
2000 if (constructors.length !== branchKeys.length) {
2001 throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
2003 const allReqd = forall(constructors, reqKey => {
2004 return contains$2(branchKeys, reqKey);
2007 throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
2009 return branches[key].apply(null, args);
2012 fold: (...foldArgs) => {
2013 if (foldArgs.length !== cases.length) {
2014 throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
2016 const target = foldArgs[count];
2017 return target.apply(null, args);
2021 console.log(label, {
2032 const Adt = { generate: generate$7 };
2060 const partition$1 = results => {
2063 each$1(results, result => {
2064 result.fold(err => {
2076 const exclude$1 = (obj, fields) => {
2078 each(obj, (v, k) => {
2079 if (!contains$2(fields, k)) {
2086 const wrap$2 = (key, value) => ({ [key]: value });
2087 const wrapAll$1 = keyvalues => {
2089 each$1(keyvalues, kv => {
2090 r[kv.key] = kv.value;
2095 const exclude = (obj, fields) => exclude$1(obj, fields);
2096 const wrap$1 = (key, value) => wrap$2(key, value);
2097 const wrapAll = keyvalues => wrapAll$1(keyvalues);
2098 const mergeValues = (values, base) => {
2099 return values.length === 0 ? Result.value(base) : Result.value(deepMerge(base, merge$1.apply(undefined, values)));
2101 const mergeErrors = errors => Result.error(flatten(errors));
2102 const consolidate = (objs, base) => {
2103 const partitions = partition$1(objs);
2104 return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : mergeValues(partitions.values, base);
2107 const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
2108 const ancestor$2 = (scope, transform, isRoot) => {
2109 let element = scope.dom;
2110 const stop = ensureIsRoot(isRoot);
2111 while (element.parentNode) {
2112 element = element.parentNode;
2113 const el = SugarElement.fromDom(element);
2114 const transformed = transform(el);
2115 if (transformed.isSome()) {
2117 } else if (stop(el)) {
2121 return Optional.none();
2123 const closest$4 = (scope, transform, isRoot) => {
2124 const current = transform(scope);
2125 const stop = ensureIsRoot(isRoot);
2126 return current.orThunk(() => stop(scope) ? Optional.none() : ancestor$2(scope, transform, stop));
2129 const isSource = (component, simulatedEvent) => eq(component.element, simulatedEvent.event.target);
2131 const defaultEventHandler = {
2136 const nu$9 = parts => {
2137 if (!hasNonNullableKey(parts, 'can') && !hasNonNullableKey(parts, 'abort') && !hasNonNullableKey(parts, 'run')) {
2138 throw new Error('EventHandler defined by: ' + JSON.stringify(parts, null, 2) + ' does not have can, abort, or run!');
2141 ...defaultEventHandler,
2145 const all$2 = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc && f(handler).apply(undefined, args), true);
2146 const any = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc || f(handler).apply(undefined, args), false);
2147 const read$2 = handler => isFunction(handler) ? {
2152 const fuse$1 = handlers => {
2153 const can = all$2(handlers, handler => handler.can);
2154 const abort = any(handlers, handler => handler.abort);
2155 const run = (...args) => {
2156 each$1(handlers, handler => {
2157 handler.run.apply(undefined, args);
2167 const constant = constant$1;
2168 const touchstart = constant('touchstart');
2169 const touchmove = constant('touchmove');
2170 const touchend = constant('touchend');
2171 const touchcancel = constant('touchcancel');
2172 const mousedown = constant('mousedown');
2173 const mousemove = constant('mousemove');
2174 const mouseout = constant('mouseout');
2175 const mouseup = constant('mouseup');
2176 const mouseover = constant('mouseover');
2177 const focusin = constant('focusin');
2178 const focusout = constant('focusout');
2179 const keydown = constant('keydown');
2180 const keyup = constant('keyup');
2181 const input = constant('input');
2182 const change = constant('change');
2183 const click = constant('click');
2184 const transitioncancel = constant('transitioncancel');
2185 const transitionend = constant('transitionend');
2186 const transitionstart = constant('transitionstart');
2187 const selectstart = constant('selectstart');
2189 const prefixName = name => constant$1('alloy.' + name);
2190 const alloy = { tap: prefixName('tap') };
2191 const focus$4 = prefixName('focus');
2192 const postBlur = prefixName('blur.post');
2193 const postPaste = prefixName('paste.post');
2194 const receive = prefixName('receive');
2195 const execute$5 = prefixName('execute');
2196 const focusItem = prefixName('focus.item');
2197 const tap = alloy.tap;
2198 const longpress = prefixName('longpress');
2199 const sandboxClose = prefixName('sandbox.close');
2200 const typeaheadCancel = prefixName('typeahead.cancel');
2201 const systemInit = prefixName('system.init');
2202 const documentTouchmove = prefixName('system.touchmove');
2203 const documentTouchend = prefixName('system.touchend');
2204 const windowScroll = prefixName('system.scroll');
2205 const windowResize = prefixName('system.resize');
2206 const attachedToDom = prefixName('system.attached');
2207 const detachedFromDom = prefixName('system.detached');
2208 const dismissRequested = prefixName('system.dismissRequested');
2209 const repositionRequested = prefixName('system.repositionRequested');
2210 const focusShifted = prefixName('focusmanager.shifted');
2211 const slotVisibility = prefixName('slotcontainer.visibility');
2212 const changeTab = prefixName('change.tab');
2213 const dismissTab = prefixName('dismiss.tab');
2214 const highlight$1 = prefixName('highlight');
2215 const dehighlight$1 = prefixName('dehighlight');
2217 const emit = (component, event) => {
2218 dispatchWith(component, component.element, event, {});
2220 const emitWith = (component, event, properties) => {
2221 dispatchWith(component, component.element, event, properties);
2223 const emitExecute = component => {
2224 emit(component, execute$5());
2226 const dispatch = (component, target, event) => {
2227 dispatchWith(component, target, event, {});
2229 const dispatchWith = (component, target, event, properties) => {
2234 component.getSystem().triggerEvent(event, target, data);
2236 const retargetAndDispatchWith = (component, target, eventName, properties) => {
2241 component.getSystem().triggerEvent(eventName, target, data);
2243 const dispatchEvent = (component, target, event, simulatedEvent) => {
2244 component.getSystem().triggerEvent(event, target, simulatedEvent.event);
2247 const derive$2 = configs => wrapAll(configs);
2248 const abort = (name, predicate) => {
2251 value: nu$9({ abort: predicate })
2254 const can = (name, predicate) => {
2257 value: nu$9({ can: predicate })
2260 const preventDefault = name => {
2264 run: (component, simulatedEvent) => {
2265 simulatedEvent.event.prevent();
2270 const run$1 = (name, handler) => {
2273 value: nu$9({ run: handler })
2276 const runActionExtra = (name, action, extra) => {
2280 run: (component, simulatedEvent) => {
2281 action.apply(undefined, [
2289 const runOnName = name => {
2290 return handler => run$1(name, handler);
2292 const runOnSourceName = name => {
2293 return handler => ({
2296 run: (component, simulatedEvent) => {
2297 if (isSource(component, simulatedEvent)) {
2298 handler(component, simulatedEvent);
2304 const redirectToUid = (name, uid) => {
2305 return run$1(name, (component, simulatedEvent) => {
2306 component.getSystem().getByUid(uid).each(redirectee => {
2307 dispatchEvent(redirectee, redirectee.element, name, simulatedEvent);
2311 const redirectToPart = (name, detail, partName) => {
2312 const uid = detail.partUids[partName];
2313 return redirectToUid(name, uid);
2315 const runWithTarget = (name, f) => {
2316 return run$1(name, (component, simulatedEvent) => {
2317 const ev = simulatedEvent.event;
2318 const target = component.getSystem().getByDom(ev.target).getOrThunk(() => {
2319 const closest = closest$4(ev.target, el => component.getSystem().getByDom(el).toOptional(), never);
2320 return closest.getOr(component);
2322 f(component, target, simulatedEvent);
2325 const cutter = name => {
2326 return run$1(name, (component, simulatedEvent) => {
2327 simulatedEvent.cut();
2330 const stopper = name => {
2331 return run$1(name, (component, simulatedEvent) => {
2332 simulatedEvent.stop();
2335 const runOnSource = (name, f) => {
2336 return runOnSourceName(name)(f);
2338 const runOnAttached = runOnSourceName(attachedToDom());
2339 const runOnDetached = runOnSourceName(detachedFromDom());
2340 const runOnInit = runOnSourceName(systemInit());
2341 const runOnExecute$1 = runOnName(execute$5());
2343 const fromHtml$1 = (html, scope) => {
2344 const doc = scope || document;
2345 const div = doc.createElement('div');
2346 div.innerHTML = html;
2347 return children(SugarElement.fromDom(div));
2350 const get$9 = element => element.dom.innerHTML;
2351 const set$6 = (element, content) => {
2352 const owner = owner$4(element);
2353 const docDom = owner.dom;
2354 const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
2355 const contentElements = fromHtml$1(content, docDom);
2356 append$1(fragment, contentElements);
2358 append$2(element, fragment);
2360 const getOuter = element => {
2361 const container = SugarElement.fromTag('div');
2362 const clone = SugarElement.fromDom(element.dom.cloneNode(true));
2363 append$2(container, clone);
2364 return get$9(container);
2367 const clone$1 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
2368 const shallow = original => clone$1(original, false);
2370 const getHtml = element => {
2371 if (isShadowRoot(element)) {
2372 return '#shadow-root';
2374 const clone = shallow(element);
2375 return getOuter(clone);
2379 const element = elem => getHtml(elem);
2381 const isRecursive = (component, originator, target) => eq(originator, component.element) && !eq(originator, target);
2382 const events$i = derive$2([can(focus$4(), (component, simulatedEvent) => {
2383 const event = simulatedEvent.event;
2384 const originator = event.originator;
2385 const target = event.target;
2386 if (isRecursive(component, originator, target)) {
2387 console.warn(focus$4() + ' did not get interpreted by the desired target. ' + '\nOriginator: ' + element(originator) + '\nTarget: ' + element(target) + '\nCheck the ' + focus$4() + ' event handlers');
2394 var DefaultEvents = /*#__PURE__*/Object.freeze({
2400 const generate$6 = prefix => {
2401 const date = new Date();
2402 const time = date.getTime();
2403 const random = Math.floor(Math.random() * 1000000000);
2405 return prefix + '_' + random + unique + String(time);
2408 const prefix$1 = constant$1('alloy-id-');
2409 const idAttr$1 = constant$1('data-alloy-id');
2411 const prefix = prefix$1();
2412 const idAttr = idAttr$1();
2413 const write = (label, elem) => {
2414 const id = generate$6(prefix + label);
2415 writeOnly(elem, id);
2418 const writeOnly = (elem, uid) => {
2419 Object.defineProperty(elem.dom, idAttr, {
2424 const read$1 = elem => {
2425 const id = isElement$1(elem) ? elem.dom[idAttr] : null;
2426 return Optional.from(id);
2428 const generate$5 = prefix => generate$6(prefix);
2430 const make$8 = identity;
2432 const NoContextApi = getComp => {
2433 const getMessage = event => `The component must be in a context to execute: ${ event }` + (getComp ? '\n' + element(getComp().element) + ' is not in context.' : '');
2434 const fail = event => () => {
2435 throw new Error(getMessage(event));
2437 const warn = event => () => {
2438 console.warn(getMessage(event));
2441 debugInfo: constant$1('fake'),
2442 triggerEvent: warn('triggerEvent'),
2443 triggerFocus: warn('triggerFocus'),
2444 triggerEscape: warn('triggerEscape'),
2445 broadcast: warn('broadcast'),
2446 broadcastOn: warn('broadcastOn'),
2447 broadcastEvent: warn('broadcastEvent'),
2448 build: fail('build'),
2449 buildOrPatch: fail('buildOrPatch'),
2450 addToWorld: fail('addToWorld'),
2451 removeFromWorld: fail('removeFromWorld'),
2452 addToGui: fail('addToGui'),
2453 removeFromGui: fail('removeFromGui'),
2454 getByUid: fail('getByUid'),
2455 getByDom: fail('getByDom'),
2459 const singleton$1 = NoContextApi();
2461 const markAsBehaviourApi = (f, apiName, apiFunction) => {
2462 const delegate = apiFunction.toString();
2463 const endIndex = delegate.indexOf(')') + 1;
2464 const openBracketIndex = delegate.indexOf('(');
2465 const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
2466 f.toFunctionAnnotation = () => ({
2468 parameters: cleanParameters(parameters.slice(0, 1).concat(parameters.slice(3)))
2472 const cleanParameters = parameters => map$2(parameters, p => endsWith(p, '/*') ? p.substring(0, p.length - '/*'.length) : p);
2473 const markAsExtraApi = (f, extraName) => {
2474 const delegate = f.toString();
2475 const endIndex = delegate.indexOf(')') + 1;
2476 const openBracketIndex = delegate.indexOf('(');
2477 const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
2478 f.toFunctionAnnotation = () => ({
2480 parameters: cleanParameters(parameters)
2484 const markAsSketchApi = (f, apiFunction) => {
2485 const delegate = apiFunction.toString();
2486 const endIndex = delegate.indexOf(')') + 1;
2487 const openBracketIndex = delegate.indexOf('(');
2488 const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
2489 f.toFunctionAnnotation = () => ({
2491 parameters: cleanParameters(parameters.slice(1))
2496 const premadeTag = generate$6('alloy-premade');
2497 const premade$1 = comp => {
2498 Object.defineProperty(comp.element.dom, premadeTag, {
2502 return wrap$1(premadeTag, comp);
2504 const isPremade = element => has$2(element.dom, premadeTag);
2505 const getPremade = spec => get$g(spec, premadeTag);
2506 const makeApi = f => markAsSketchApi((component, ...rest) => f(component.getApis(), component, ...rest), f);
2508 const NoState = { init: () => nu$8({ readState: constant$1('No State required') }) };
2509 const nu$8 = spec => spec;
2511 const generateFrom$1 = (spec, all) => {
2512 const schema = map$2(all, a => optionObjOf(a.name(), [
2513 required$1('config'),
2514 defaulted('state', NoState)
2516 const validated = asRaw('component.behaviours', objOf(schema), spec.behaviours).fold(errInfo => {
2517 throw new Error(formatError(errInfo) + '\nComplete spec:\n' + JSON.stringify(spec, null, 2));
2521 data: map$1(validated, optBlobThunk => {
2522 const output = optBlobThunk.map(blob => ({
2523 config: blob.config,
2524 state: blob.state.init(blob.config)
2526 return constant$1(output);
2530 const getBehaviours$3 = bData => bData.list;
2531 const getData$2 = bData => bData.data;
2533 const byInnerKey = (data, tuple) => {
2535 each(data, (detail, key) => {
2536 each(detail, (value, indexKey) => {
2537 const chain = get$g(r, indexKey).getOr([]);
2538 r[indexKey] = chain.concat([tuple(key, value)]);
2544 const nu$7 = s => ({
2545 classes: isUndefined(s.classes) ? [] : s.classes,
2546 attributes: isUndefined(s.attributes) ? {} : s.attributes,
2547 styles: isUndefined(s.styles) ? {} : s.styles
2549 const merge = (defnA, mod) => ({
2552 ...defnA.attributes,
2559 classes: defnA.classes.concat(mod.classes)
2562 const combine$2 = (info, baseMod, behaviours, base) => {
2563 const modsByBehaviour = { ...baseMod };
2564 each$1(behaviours, behaviour => {
2565 modsByBehaviour[behaviour.name()] = behaviour.exhibit(info, base);
2567 const byAspect = byInnerKey(modsByBehaviour, (name, modification) => ({
2571 const combineObjects = objects => foldr(objects, (b, a) => ({
2575 const combinedClasses = foldr(byAspect.classes, (b, a) => a.modification.concat(b), []);
2576 const combinedAttributes = combineObjects(byAspect.attributes);
2577 const combinedStyles = combineObjects(byAspect.styles);
2579 classes: combinedClasses,
2580 attributes: combinedAttributes,
2581 styles: combinedStyles
2585 const sortKeys = (label, keyName, array, order) => {
2587 const sorted = sort(array, (a, b) => {
2588 const aKey = a[keyName];
2589 const bKey = b[keyName];
2590 const aIndex = order.indexOf(aKey);
2591 const bIndex = order.indexOf(bKey);
2592 if (aIndex === -1) {
2593 throw new Error('The ordering for ' + label + ' does not have an entry for ' + aKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
2595 if (bIndex === -1) {
2596 throw new Error('The ordering for ' + label + ' does not have an entry for ' + bKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
2598 if (aIndex < bIndex) {
2600 } else if (bIndex < aIndex) {
2606 return Result.value(sorted);
2608 return Result.error([err]);
2612 const uncurried = (handler, purpose) => ({
2616 const curried = (handler, purpose) => ({
2620 const curryArgs = (descHandler, extraArgs) => curried(curry.apply(undefined, [descHandler.handler].concat(extraArgs)), descHandler.purpose);
2621 const getCurried = descHandler => descHandler.cHandler;
2623 const behaviourTuple = (name, handler) => ({
2627 const nameToHandlers = (behaviours, info) => {
2629 each$1(behaviours, behaviour => {
2630 r[behaviour.name()] = behaviour.handlers(info);
2634 const groupByEvents = (info, behaviours, base) => {
2635 const behaviourEvents = {
2637 ...nameToHandlers(behaviours, info)
2639 return byInnerKey(behaviourEvents, behaviourTuple);
2641 const combine$1 = (info, eventOrder, behaviours, base) => {
2642 const byEventName = groupByEvents(info, behaviours, base);
2643 return combineGroups(byEventName, eventOrder);
2645 const assemble = rawHandler => {
2646 const handler = read$2(rawHandler);
2647 return (component, simulatedEvent, ...rest) => {
2652 if (handler.abort.apply(undefined, args)) {
2653 simulatedEvent.stop();
2654 } else if (handler.can.apply(undefined, args)) {
2655 handler.run.apply(undefined, args);
2659 const missingOrderError = (eventName, tuples) => Result.error(['The event (' + eventName + ') has more than one behaviour that listens to it.\nWhen this occurs, you must ' + 'specify an event ordering for the behaviours in your spec (e.g. [ "listing", "toggling" ]).\nThe behaviours that ' + 'can trigger it are: ' + JSON.stringify(map$2(tuples, c => c.name), null, 2)]);
2660 const fuse = (tuples, eventOrder, eventName) => {
2661 const order = eventOrder[eventName];
2663 return missingOrderError(eventName, tuples);
2665 return sortKeys('Event: ' + eventName, 'name', tuples, order).map(sortedTuples => {
2666 const handlers = map$2(sortedTuples, tuple => tuple.handler);
2667 return fuse$1(handlers);
2671 const combineGroups = (byEventName, eventOrder) => {
2672 const r = mapToArray(byEventName, (tuples, eventName) => {
2673 const combined = tuples.length === 1 ? Result.value(tuples[0].handler) : fuse(tuples, eventOrder, eventName);
2674 return combined.map(handler => {
2675 const assembled = assemble(handler);
2676 const purpose = tuples.length > 1 ? filter$2(eventOrder[eventName], o => exists(tuples, t => t.name === o)).join(' > ') : tuples[0].name;
2677 return wrap$1(eventName, uncurried(assembled, purpose));
2680 return consolidate(r, {});
2683 const baseBehaviour = 'alloy.base.behaviour';
2684 const schema$z = objOf([
2685 field$1('dom', 'dom', required$2(), objOf([
2687 defaulted('styles', {}),
2688 defaulted('classes', []),
2689 defaulted('attributes', {}),
2691 option$3('innerHtml')
2693 required$1('components'),
2695 defaulted('events', {}),
2696 defaulted('apis', {}),
2697 field$1('eventOrder', 'eventOrder', mergeWith({
2721 [detachedFromDom()]: [
2747 option$3('domModification')
2749 const toInfo = spec => asRaw('custom.definition', schema$z, spec);
2750 const toDefinition = detail => ({
2753 domChildren: map$2(detail.components, comp => comp.element)
2755 const toModification = detail => detail.domModification.fold(() => nu$7({}), nu$7);
2756 const toEvents = info => info.events;
2758 const read = (element, attr) => {
2759 const value = get$f(element, attr);
2760 return value === undefined || value === '' ? [] : value.split(' ');
2762 const add$4 = (element, attr, id) => {
2763 const old = read(element, attr);
2764 const nu = old.concat([id]);
2765 set$9(element, attr, nu.join(' '));
2768 const remove$4 = (element, attr, id) => {
2769 const nu = filter$2(read(element, attr), v => v !== id);
2770 if (nu.length > 0) {
2771 set$9(element, attr, nu.join(' '));
2773 remove$7(element, attr);
2778 const supports = element => element.dom.classList !== undefined;
2779 const get$8 = element => read(element, 'class');
2780 const add$3 = (element, clazz) => add$4(element, 'class', clazz);
2781 const remove$3 = (element, clazz) => remove$4(element, 'class', clazz);
2783 const add$2 = (element, clazz) => {
2784 if (supports(element)) {
2785 element.dom.classList.add(clazz);
2787 add$3(element, clazz);
2790 const cleanClass = element => {
2791 const classList = supports(element) ? element.dom.classList : get$8(element);
2792 if (classList.length === 0) {
2793 remove$7(element, 'class');
2796 const remove$2 = (element, clazz) => {
2797 if (supports(element)) {
2798 const classList = element.dom.classList;
2799 classList.remove(clazz);
2801 remove$3(element, clazz);
2803 cleanClass(element);
2805 const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
2807 const add$1 = (element, classes) => {
2808 each$1(classes, x => {
2812 const remove$1 = (element, classes) => {
2813 each$1(classes, x => {
2814 remove$2(element, x);
2817 const hasAll = (element, classes) => forall(classes, clazz => has(element, clazz));
2818 const getNative = element => {
2819 const classList = element.dom.classList;
2820 const r = new Array(classList.length);
2821 for (let i = 0; i < classList.length; i++) {
2822 const item = classList.item(i);
2823 if (item !== null) {
2829 const get$7 = element => supports(element) ? getNative(element) : get$8(element);
2831 const get$6 = element => element.dom.value;
2832 const set$5 = (element, value) => {
2833 if (value === undefined) {
2834 throw new Error('Value.set was undefined');
2836 element.dom.value = value;
2839 const determineObsoleted = (parent, index, oldObsoleted) => {
2840 const newObsoleted = child$2(parent, index);
2841 return newObsoleted.map(newObs => {
2842 const elemChanged = oldObsoleted.exists(o => !eq(o, newObs));
2844 const oldTag = oldObsoleted.map(name$3).getOr('span');
2845 const marker = SugarElement.fromTag(oldTag);
2846 before$1(newObs, marker);
2853 const ensureInDom = (parent, child, obsoleted) => {
2854 obsoleted.fold(() => append$2(parent, child), obs => {
2855 if (!eq(obs, child)) {
2856 before$1(obs, child);
2861 const patchChildrenWith = (parent, nu, f) => {
2862 const builtChildren = map$2(nu, f);
2863 const currentChildren = children(parent);
2864 each$1(currentChildren.slice(builtChildren.length), remove$5);
2865 return builtChildren;
2867 const patchSpecChild = (parent, index, spec, build) => {
2868 const oldObsoleted = child$2(parent, index);
2869 const childComp = build(spec, oldObsoleted);
2870 const obsoleted = determineObsoleted(parent, index, oldObsoleted);
2871 ensureInDom(parent, childComp.element, obsoleted);
2874 const patchSpecChildren = (parent, specs, build) => patchChildrenWith(parent, specs, (spec, index) => patchSpecChild(parent, index, spec, build));
2875 const patchDomChildren = (parent, nodes) => patchChildrenWith(parent, nodes, (node, index) => {
2876 const optObsoleted = child$2(parent, index);
2877 ensureInDom(parent, node, optObsoleted);
2881 const diffKeyValueSet = (newObj, oldObj) => {
2882 const newKeys = keys(newObj);
2883 const oldKeys = keys(oldObj);
2884 const toRemove = difference(oldKeys, newKeys);
2885 const toSet = bifilter(newObj, (v, k) => {
2886 return !has$2(oldObj, k) || v !== oldObj[k];
2893 const reconcileToDom = (definition, obsoleted) => {
2897 ...existingAttributes
2898 } = clone$2(obsoleted);
2901 toRemove: attrsToRemove
2902 } = diffKeyValueSet(definition.attributes, existingAttributes);
2903 const updateAttrs = () => {
2904 each$1(attrsToRemove, a => remove$7(obsoleted, a));
2905 setAll$1(obsoleted, attrsToSet);
2907 const existingStyles = getAllRaw(obsoleted);
2910 toRemove: stylesToRemove
2911 } = diffKeyValueSet(definition.styles, existingStyles);
2912 const updateStyles = () => {
2913 each$1(stylesToRemove, s => remove$6(obsoleted, s));
2914 setAll(obsoleted, stylesToSet);
2916 const existingClasses = get$7(obsoleted);
2917 const classesToRemove = difference(existingClasses, definition.classes);
2918 const classesToAdd = difference(definition.classes, existingClasses);
2919 const updateClasses = () => {
2920 add$1(obsoleted, classesToAdd);
2921 remove$1(obsoleted, classesToRemove);
2923 const updateHtml = html => {
2924 set$6(obsoleted, html);
2926 const updateChildren = () => {
2927 const children = definition.domChildren;
2928 patchDomChildren(obsoleted, children);
2930 const updateValue = () => {
2931 const valueElement = obsoleted;
2932 const value = definition.value.getOrUndefined();
2933 if (value !== get$6(valueElement)) {
2934 set$5(valueElement, value ?? '');
2940 definition.innerHtml.fold(updateChildren, updateHtml);
2945 const introduceToDom = definition => {
2946 const subject = SugarElement.fromTag(definition.tag);
2947 setAll$1(subject, definition.attributes);
2948 add$1(subject, definition.classes);
2949 setAll(subject, definition.styles);
2950 definition.innerHtml.each(html => set$6(subject, html));
2951 const children = definition.domChildren;
2952 append$1(subject, children);
2953 definition.value.each(value => {
2954 set$5(subject, value);
2958 const attemptPatch = (definition, obsoleted) => {
2960 const e = reconcileToDom(definition, obsoleted);
2961 return Optional.some(e);
2963 return Optional.none();
2966 const hasMixedChildren = definition => definition.innerHtml.isSome() && definition.domChildren.length > 0;
2967 const renderToDom = (definition, optObsoleted) => {
2968 const canBePatched = candidate => name$3(candidate) === definition.tag && !hasMixedChildren(definition) && !isPremade(candidate);
2969 const elem = optObsoleted.filter(canBePatched).bind(obsoleted => attemptPatch(definition, obsoleted)).getOrThunk(() => introduceToDom(definition));
2970 writeOnly(elem, definition.uid);
2974 const getBehaviours$2 = spec => {
2975 const behaviours = get$g(spec, 'behaviours').getOr({});
2976 return bind$3(keys(behaviours), name => {
2977 const behaviour = behaviours[name];
2978 return isNonNullable(behaviour) ? [behaviour.me] : [];
2981 const generateFrom = (spec, all) => generateFrom$1(spec, all);
2982 const generate$4 = spec => {
2983 const all = getBehaviours$2(spec);
2984 return generateFrom(spec, all);
2987 const getDomDefinition = (info, bList, bData) => {
2988 const definition = toDefinition(info);
2989 const infoModification = toModification(info);
2990 const baseModification = { 'alloy.base.modification': infoModification };
2991 const modification = bList.length > 0 ? combine$2(bData, baseModification, bList, definition) : infoModification;
2992 return merge(definition, modification);
2994 const getEvents = (info, bList, bData) => {
2995 const baseEvents = { 'alloy.base.behaviour': toEvents(info) };
2996 return combine$1(bData, info.eventOrder, bList, baseEvents).getOrDie();
2998 const build$2 = (spec, obsoleted) => {
2999 const getMe = () => me;
3000 const systemApi = Cell(singleton$1);
3001 const info = getOrDie(toInfo(spec));
3002 const bBlob = generate$4(spec);
3003 const bList = getBehaviours$3(bBlob);
3004 const bData = getData$2(bBlob);
3005 const modDefinition = getDomDefinition(info, bList, bData);
3006 const item = renderToDom(modDefinition, obsoleted);
3007 const events = getEvents(info, bList, bData);
3008 const subcomponents = Cell(info.components);
3009 const connect = newApi => {
3010 systemApi.set(newApi);
3012 const disconnect = () => {
3013 systemApi.set(NoContextApi(getMe));
3015 const syncComponents = () => {
3016 const children$1 = children(item);
3017 const subs = bind$3(children$1, child => systemApi.get().getByDom(child).fold(() => [], pure$2));
3018 subcomponents.set(subs);
3020 const config = behaviour => {
3022 const f = isFunction(b[behaviour.name()]) ? b[behaviour.name()] : () => {
3023 throw new Error('Could not find ' + behaviour.name() + ' in ' + JSON.stringify(spec, null, 2));
3027 const hasConfigured = behaviour => isFunction(bData[behaviour.name()]);
3028 const getApis = () => info.apis;
3029 const readState = behaviourName => bData[behaviourName]().map(b => b.state.readState()).getOr('not enabled');
3032 getSystem: systemApi.get,
3042 components: subcomponents.get,
3048 const buildSubcomponents = (spec, obsoleted) => {
3049 const components = get$g(spec, 'components').getOr([]);
3050 return obsoleted.fold(() => map$2(components, build$1), obs => map$2(components, (c, i) => {
3051 return buildOrPatch(c, child$2(obs, i));
3054 const buildFromSpec = (userSpec, obsoleted) => {
3058 } = make$8(userSpec);
3059 const components = buildSubcomponents(spec, obsoleted);
3060 const completeSpec = {
3068 return Result.value(build$2(completeSpec, obsoleted));
3070 const text$2 = textContent => {
3071 const element = SugarElement.fromText(textContent);
3072 return external$1({ element });
3074 const external$1 = spec => {
3075 const extSpec = asRawOrDie$1('external.component', objOfOnly([
3076 required$1('element'),
3079 const systemApi = Cell(NoContextApi());
3080 const connect = newApi => {
3081 systemApi.set(newApi);
3083 const disconnect = () => {
3084 systemApi.set(NoContextApi(() => me));
3086 const uid = extSpec.uid.getOrThunk(() => generate$5('external'));
3087 writeOnly(extSpec.element, uid);
3090 getSystem: systemApi.get,
3091 config: Optional.none,
3092 hasConfigured: never,
3095 getApis: () => ({}),
3096 element: extSpec.element,
3098 readState: constant$1('No state'),
3099 syncComponents: noop,
3100 components: constant$1([]),
3103 return premade$1(me);
3105 const uids = generate$5;
3106 const isSketchSpec$1 = spec => has$2(spec, 'uid');
3107 const buildOrPatch = (spec, obsoleted) => getPremade(spec).getOrThunk(() => {
3108 const userSpecWithUid = isSketchSpec$1(spec) ? spec : {
3112 return buildFromSpec(userSpecWithUid, obsoleted).getOrDie();
3114 const build$1 = spec => buildOrPatch(spec, Optional.none());
3115 const premade = premade$1;
3117 var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
3119 return Optional.some(scope);
3120 } else if (isFunction(isRoot) && isRoot(scope)) {
3121 return Optional.none();
3123 return ancestor(scope, a, isRoot);
3127 const ancestor$1 = (scope, predicate, isRoot) => {
3128 let element = scope.dom;
3129 const stop = isFunction(isRoot) ? isRoot : never;
3130 while (element.parentNode) {
3131 element = element.parentNode;
3132 const el = SugarElement.fromDom(element);
3133 if (predicate(el)) {
3134 return Optional.some(el);
3135 } else if (stop(el)) {
3139 return Optional.none();
3141 const closest$3 = (scope, predicate, isRoot) => {
3142 const is = (s, test) => test(s);
3143 return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
3145 const child$1 = (scope, predicate) => {
3146 const pred = node => predicate(SugarElement.fromDom(node));
3147 const result = find$5(scope.dom.childNodes, pred);
3148 return result.map(SugarElement.fromDom);
3150 const descendant$1 = (scope, predicate) => {
3151 const descend = node => {
3152 for (let i = 0; i < node.childNodes.length; i++) {
3153 const child = SugarElement.fromDom(node.childNodes[i]);
3154 if (predicate(child)) {
3155 return Optional.some(child);
3157 const res = descend(node.childNodes[i]);
3162 return Optional.none();
3164 return descend(scope.dom);
3167 const closest$2 = (scope, predicate, isRoot) => closest$3(scope, predicate, isRoot).isSome();
3169 const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is(e, selector), isRoot);
3170 const child = (scope, selector) => child$1(scope, e => is(e, selector));
3171 const descendant = (scope, selector) => one(selector, scope);
3172 const closest$1 = (scope, selector, isRoot) => {
3173 const is$1 = (element, selector) => is(element, selector);
3174 return ClosestOrAncestor(is$1, ancestor, scope, selector, isRoot);
3177 const attribute = 'aria-controls';
3178 const find$1 = queryElem => {
3179 const dependent = closest$3(queryElem, elem => {
3180 if (!isElement$1(elem)) {
3183 const id = get$f(elem, 'id');
3184 return id !== undefined && id.indexOf(attribute) > -1;
3186 return dependent.bind(dep => {
3187 const id = get$f(dep, 'id');
3188 const dos = getRootNode(dep);
3189 return descendant(dos, `[${ attribute }="${ id }"]`);
3192 const manager = () => {
3193 const ariaId = generate$6(attribute);
3194 const link = elem => {
3195 set$9(elem, attribute, ariaId);
3197 const unlink = elem => {
3198 remove$7(elem, attribute);
3207 const isAriaPartOf = (component, queryElem) => find$1(queryElem).exists(owner => isPartOf$1(component, owner));
3208 const isPartOf$1 = (component, queryElem) => closest$2(queryElem, el => eq(el, component.element), never) || isAriaPartOf(component, queryElem);
3210 const unknown = 'unknown';
3211 var EventConfiguration;
3212 (function (EventConfiguration) {
3213 EventConfiguration[EventConfiguration['STOP'] = 0] = 'STOP';
3214 EventConfiguration[EventConfiguration['NORMAL'] = 1] = 'NORMAL';
3215 EventConfiguration[EventConfiguration['LOGGING'] = 2] = 'LOGGING';
3216 }(EventConfiguration || (EventConfiguration = {})));
3217 const eventConfig = Cell({});
3218 const makeEventLogger = (eventName, initialTarget) => {
3219 const sequence = [];
3220 const startTime = new Date().getTime();
3222 logEventCut: (_name, target, purpose) => {
3229 logEventStopped: (_name, target, purpose) => {
3236 logNoParent: (_name, target, purpose) => {
3238 outcome: 'no-parent',
3243 logEventNoHandlers: (_name, target) => {
3245 outcome: 'no-handlers-left',
3249 logEventResponse: (_name, target, purpose) => {
3251 outcome: 'response',
3257 const finishTime = new Date().getTime();
3266 console.log(eventName, {
3268 time: finishTime - startTime,
3269 target: initialTarget.dom,
3270 sequence: map$2(sequence, s => {
3278 return '{' + s.purpose + '} ' + s.outcome + ' at (' + element(s.target) + ')';
3285 const processEvent = (eventName, initialTarget, f) => {
3286 const status = get$g(eventConfig.get(), eventName).orThunk(() => {
3287 const patterns = keys(eventConfig.get());
3288 return findMap(patterns, p => eventName.indexOf(p) > -1 ? Optional.some(eventConfig.get()[p]) : Optional.none());
3289 }).getOr(EventConfiguration.NORMAL);
3291 case EventConfiguration.NORMAL:
3292 return f(noLogger());
3293 case EventConfiguration.LOGGING: {
3294 const logger = makeEventLogger(eventName, initialTarget);
3295 const output = f(logger);
3299 case EventConfiguration.STOP:
3304 'alloy/data/Fields',
3305 'alloy/debugging/Debugging'
3307 const getTrace = () => {
3308 const err = new Error();
3309 if (err.stack !== undefined) {
3310 const lines = err.stack.split('\n');
3311 return find$5(lines, line => line.indexOf('alloy') > 0 && !exists(path, p => line.indexOf(p) > -1)).getOr(unknown);
3316 const ignoreEvent = {
3318 logEventStopped: noop,
3320 logEventNoHandlers: noop,
3321 logEventResponse: noop,
3324 const monitorEvent = (eventName, initialTarget, f) => processEvent(eventName, initialTarget, f);
3325 const noLogger = constant$1(ignoreEvent);
3327 const menuFields = constant$1([
3329 required$1('selectedMenu')
3331 const itemFields = constant$1([
3333 required$1('selectedItem')
3335 constant$1(objOf(itemFields().concat(menuFields())));
3336 const itemSchema$3 = constant$1(objOf(itemFields()));
3338 const _initSize = requiredObjOf('initSize', [
3339 required$1('numColumns'),
3340 required$1('numRows')
3342 const itemMarkers = () => requiredOf('markers', itemSchema$3());
3343 const tieredMenuMarkers = () => requiredObjOf('markers', [required$1('backgroundMenu')].concat(menuFields()).concat(itemFields()));
3344 const markers$1 = required => requiredObjOf('markers', map$2(required, required$1));
3345 const onPresenceHandler = (label, fieldName, presence) => {
3347 return field$1(fieldName, fieldName, presence, valueOf(f => Result.value((...args) => {
3348 return f.apply(undefined, args);
3351 const onHandler = fieldName => onPresenceHandler('onHandler', fieldName, defaulted$1(noop));
3352 const onKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, defaulted$1(Optional.none));
3353 const onStrictHandler = fieldName => onPresenceHandler('onHandler', fieldName, required$2());
3354 const onStrictKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, required$2());
3355 const output$1 = (name, value) => customField(name, constant$1(value));
3356 const snapshot = name => customField(name, identity);
3357 const initSize = constant$1(_initSize);
3359 const nu$6 = (x, y, bubble, direction, placement, boundsRestriction, labelPrefix, alwaysFit = false) => ({
3365 restriction: boundsRestriction,
3366 label: `${ labelPrefix }-${ placement }`,
3370 const adt$a = Adt.generate([
3380 const cata$2 = (subject, southeast, southwest, northeast, northwest, south, north, east, west) => subject.fold(southeast, southwest, northeast, northwest, south, north, east, west);
3381 const cataVertical = (subject, south, middle, north) => subject.fold(south, south, north, north, south, north, middle, middle);
3382 const cataHorizontal = (subject, east, middle, west) => subject.fold(east, west, east, west, middle, middle, east, west);
3383 const southeast$3 = adt$a.southeast;
3384 const southwest$3 = adt$a.southwest;
3385 const northeast$3 = adt$a.northeast;
3386 const northwest$3 = adt$a.northwest;
3387 const south$3 = adt$a.south;
3388 const north$3 = adt$a.north;
3389 const east$3 = adt$a.east;
3390 const west$3 = adt$a.west;
3392 const cycleBy = (value, delta, min, max) => {
3393 const r = value + delta;
3396 } else if (r < min) {
3402 const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
3404 const getRestriction = (anchor, restriction) => {
3405 switch (restriction) {
3409 return anchor.x + anchor.width;
3413 return anchor.y + anchor.height;
3416 const boundsRestriction = (anchor, restrictions) => mapToObject([
3421 ], dir => get$g(restrictions, dir).map(restriction => getRestriction(anchor, restriction)));
3422 const adjustBounds = (bounds$1, restriction, bubbleOffset) => {
3423 const applyRestriction = (dir, current) => restriction[dir].map(pos => {
3424 const isVerticalAxis = dir === 'top' || dir === 'bottom';
3425 const offset = isVerticalAxis ? bubbleOffset.top : bubbleOffset.left;
3426 const comparator = dir === 'left' || dir === 'top' ? Math.max : Math.min;
3427 const newPos = comparator(pos, current) + offset;
3428 return isVerticalAxis ? clamp(newPos, bounds$1.y, bounds$1.bottom) : clamp(newPos, bounds$1.x, bounds$1.right);
3430 const adjustedLeft = applyRestriction('left', bounds$1.x);
3431 const adjustedTop = applyRestriction('top', bounds$1.y);
3432 const adjustedRight = applyRestriction('right', bounds$1.right);
3433 const adjustedBottom = applyRestriction('bottom', bounds$1.bottom);
3434 return bounds(adjustedLeft, adjustedTop, adjustedRight - adjustedLeft, adjustedBottom - adjustedTop);
3437 const labelPrefix$2 = 'layout';
3438 const eastX$1 = anchor => anchor.x;
3439 const middleX$1 = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
3440 const westX$1 = (anchor, element) => anchor.x + anchor.width - element.width;
3441 const northY$2 = (anchor, element) => anchor.y - element.height;
3442 const southY$2 = anchor => anchor.y + anchor.height;
3443 const centreY$1 = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
3444 const eastEdgeX$1 = anchor => anchor.x + anchor.width;
3445 const westEdgeX$1 = (anchor, element) => anchor.x - element.width;
3446 const southeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), southY$2(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
3450 const southwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), southY$2(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
3454 const northeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), northY$2(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
3458 const northwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), northY$2(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
3462 const north$2 = (anchor, element, bubbles) => nu$6(middleX$1(anchor, element), northY$2(anchor, element), bubbles.north(), north$3(), 'north', boundsRestriction(anchor, { bottom: 2 }), labelPrefix$2);
3463 const south$2 = (anchor, element, bubbles) => nu$6(middleX$1(anchor, element), southY$2(anchor), bubbles.south(), south$3(), 'south', boundsRestriction(anchor, { top: 3 }), labelPrefix$2);
3464 const east$2 = (anchor, element, bubbles) => nu$6(eastEdgeX$1(anchor), centreY$1(anchor, element), bubbles.east(), east$3(), 'east', boundsRestriction(anchor, { left: 0 }), labelPrefix$2);
3465 const west$2 = (anchor, element, bubbles) => nu$6(westEdgeX$1(anchor, element), centreY$1(anchor, element), bubbles.west(), west$3(), 'west', boundsRestriction(anchor, { right: 1 }), labelPrefix$2);
3466 const all$1 = () => [
3476 const allRtl$1 = () => [
3486 const aboveOrBelow = () => [
3494 const aboveOrBelowRtl = () => [
3502 const belowOrAbove = () => [
3510 const belowOrAboveRtl = () => [
3519 const chooseChannels = (channels, message) => message.universal ? channels : filter$2(channels, ch => contains$2(message.channels, ch));
3520 const events$h = receiveConfig => derive$2([run$1(receive(), (component, message) => {
3521 const channelMap = receiveConfig.channels;
3522 const channels = keys(channelMap);
3523 const receivingData = message;
3524 const targetChannels = chooseChannels(channels, receivingData);
3525 each$1(targetChannels, ch => {
3526 const channelInfo = channelMap[ch];
3527 const channelSchema = channelInfo.schema;
3528 const data = asRawOrDie$1('channel[' + ch + '] data\nReceiver: ' + element(component.element), channelSchema, receivingData.data);
3529 channelInfo.onReceive(component, data);
3533 var ActiveReceiving = /*#__PURE__*/Object.freeze({
3538 var ReceivingSchema = [requiredOf('channels', setOf(Result.value, objOfOnly([
3539 onStrictHandler('onReceive'),
3540 defaulted('schema', anyValue())
3543 const executeEvent = (bConfig, bState, executor) => runOnExecute$1(component => {
3544 executor(component, bConfig, bState);
3546 const loadEvent = (bConfig, bState, f) => runOnInit((component, _simulatedEvent) => {
3547 f(component, bConfig, bState);
3549 const create$5 = (schema, name, active, apis, extra, state) => {
3550 const configSchema = objOfOnly(schema);
3551 const schemaSchema = optionObjOf(name, [optionObjOfOnly('config', schema)]);
3552 return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
3554 const createModes$1 = (modes, name, active, apis, extra, state) => {
3555 const configSchema = modes;
3556 const schemaSchema = optionObjOf(name, [optionOf('config', modes)]);
3557 return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
3559 const wrapApi = (bName, apiFunction, apiName) => {
3560 const f = (component, ...rest) => {
3561 const args = [component].concat(rest);
3562 return component.config({ name: constant$1(bName) }).fold(() => {
3563 throw new Error('We could not find any behaviour configuration for: ' + bName + '. Using API: ' + apiName);
3565 const rest = Array.prototype.slice.call(args, 1);
3566 return apiFunction.apply(undefined, [
3573 return markAsBehaviourApi(f, apiName, apiFunction);
3575 const revokeBehaviour = name => ({
3579 const doCreate = (configSchema, schemaSchema, name, active, apis, extra, state) => {
3580 const getConfig = info => hasNonNullableKey(info, name) ? info[name]() : Optional.none();
3581 const wrappedApis = map$1(apis, (apiF, apiName) => wrapApi(name, apiF, apiName));
3582 const wrappedExtra = map$1(extra, (extraF, extraName) => markAsExtraApi(extraF, extraName));
3586 revoke: curry(revokeBehaviour, name),
3588 const prepared = asRawOrDie$1(name + '-config', configSchema, spec);
3594 configAsRaw: cached(() => asRawOrDie$1(name + '-config', configSchema, spec)),
3595 initialConfig: spec,
3600 schema: constant$1(schemaSchema),
3601 exhibit: (info, base) => {
3602 return lift2(getConfig(info), get$g(active, 'exhibit'), (behaviourInfo, exhibitor) => {
3603 return exhibitor(base, behaviourInfo.config, behaviourInfo.state);
3604 }).getOrThunk(() => nu$7({}));
3606 name: constant$1(name),
3608 return getConfig(info).map(behaviourInfo => {
3609 const getEvents = get$g(active, 'events').getOr(() => ({}));
3610 return getEvents(behaviourInfo.config, behaviourInfo.state);
3617 const derive$1 = capabilities => wrapAll(capabilities);
3618 const simpleSchema = objOfOnly([
3619 required$1('fields'),
3621 defaulted('active', {}),
3622 defaulted('apis', {}),
3623 defaulted('state', NoState),
3624 defaulted('extra', {})
3626 const create$4 = data => {
3627 const value = asRawOrDie$1('Creating behaviour: ' + data.name, simpleSchema, data);
3628 return create$5(value.fields, value.name, value.active, value.apis, value.extra, value.state);
3630 const modeSchema = objOfOnly([
3631 required$1('branchKey'),
3632 required$1('branches'),
3634 defaulted('active', {}),
3635 defaulted('apis', {}),
3636 defaulted('state', NoState),
3637 defaulted('extra', {})
3639 const createModes = data => {
3640 const value = asRawOrDie$1('Creating behaviour: ' + data.name, modeSchema, data);
3641 return createModes$1(choose$1(value.branchKey, value.branches), value.name, value.active, value.apis, value.extra, value.state);
3643 const revoke = constant$1(undefined);
3645 const Receiving = create$4({
3646 fields: ReceivingSchema,
3648 active: ActiveReceiving
3651 const exhibit$6 = (base, posConfig) => nu$7({
3653 styles: posConfig.useFixed() ? {} : { position: 'relative' }
3656 var ActivePosition = /*#__PURE__*/Object.freeze({
3661 const focus$3 = element => element.dom.focus();
3662 const blur$1 = element => element.dom.blur();
3663 const hasFocus = element => {
3664 const root = getRootNode(element).dom;
3665 return element.dom === root.activeElement;
3667 const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
3668 const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
3670 const preserve$1 = (f, container) => {
3671 const dos = getRootNode(container);
3672 const refocus = active$1(dos).bind(focused => {
3673 const hasFocus = elem => eq(focused, elem);
3674 return hasFocus(container) ? Optional.some(container) : descendant$1(container, hasFocus);
3676 const result = f(container);
3677 refocus.each(oldFocus => {
3678 active$1(dos).filter(newFocus => eq(newFocus, oldFocus)).fold(() => {
3685 const NuPositionCss = (position, left, top, right, bottom) => {
3686 const toPx = num => num + 'px';
3689 left: left.map(toPx),
3691 right: right.map(toPx),
3692 bottom: bottom.map(toPx)
3695 const toOptions = position => ({
3697 position: Optional.some(position.position)
3699 const applyPositionCss = (element, position) => {
3700 setOptions(element, toOptions(position));
3703 const adt$9 = Adt.generate([
3722 const positionWithDirection = (posName, decision, x, y, width, height) => {
3723 const decisionRect = decision.rect;
3724 const decisionX = decisionRect.x - x;
3725 const decisionY = decisionRect.y - y;
3726 const decisionWidth = decisionRect.width;
3727 const decisionHeight = decisionRect.height;
3728 const decisionRight = width - (decisionX + decisionWidth);
3729 const decisionBottom = height - (decisionY + decisionHeight);
3730 const left = Optional.some(decisionX);
3731 const top = Optional.some(decisionY);
3732 const right = Optional.some(decisionRight);
3733 const bottom = Optional.some(decisionBottom);
3734 const none = Optional.none();
3735 return cata$2(decision.direction, () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, none, top, right, none), () => NuPositionCss(posName, left, none, none, bottom), () => NuPositionCss(posName, none, none, right, bottom), () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, left, none, none, bottom), () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, none, top, right, none));
3737 const reposition = (origin, decision) => origin.fold(() => {
3738 const decisionRect = decision.rect;
3739 return NuPositionCss('absolute', Optional.some(decisionRect.x), Optional.some(decisionRect.y), Optional.none(), Optional.none());
3740 }, (x, y, width, height) => {
3741 return positionWithDirection('absolute', decision, x, y, width, height);
3742 }, (x, y, width, height) => {
3743 return positionWithDirection('fixed', decision, x, y, width, height);
3745 const toBox = (origin, element) => {
3746 const rel = curry(find$2, element);
3747 const position = origin.fold(rel, rel, () => {
3748 const scroll = get$b();
3749 return find$2(element).translate(-scroll.left, -scroll.top);
3751 const width = getOuter$1(element);
3752 const height = getOuter$2(element);
3753 return bounds(position.left, position.top, width, height);
3755 const viewport = (origin, getBounds) => getBounds.fold(() => origin.fold(win, win, bounds), b => origin.fold(b, b, () => {
3756 const bounds$1 = b();
3757 const pos = translate$2(origin, bounds$1.x, bounds$1.y);
3758 return bounds(pos.left, pos.top, bounds$1.width, bounds$1.height);
3760 const translate$2 = (origin, x, y) => {
3761 const pos = SugarPosition(x, y);
3762 const removeScroll = () => {
3763 const outerScroll = get$b();
3764 return pos.translate(-outerScroll.left, -outerScroll.top);
3766 return origin.fold(constant$1(pos), constant$1(pos), removeScroll);
3768 const cata$1 = (subject, onNone, onRelative, onFixed) => subject.fold(onNone, onRelative, onFixed);
3770 const relative$1 = adt$9.relative;
3771 const fixed$1 = adt$9.fixed;
3773 const anchor = (anchorBox, origin) => ({
3777 const box = (anchorBox, origin) => anchor(anchorBox, origin);
3779 const placementAttribute = 'data-alloy-placement';
3780 const setPlacement$1 = (element, placement) => {
3781 set$9(element, placementAttribute, placement);
3783 const getPlacement = element => getOpt(element, placementAttribute);
3784 const reset$2 = element => remove$7(element, placementAttribute);
3786 const adt$8 = Adt.generate([
3787 { fit: ['reposition'] },
3797 const determinePosition = (box, bounds) => {
3802 bottom: boundsBottom
3804 const {x, y, right, bottom, width, height} = box;
3805 const xInBounds = x >= boundsX && x <= boundsRight;
3806 const yInBounds = y >= boundsY && y <= boundsBottom;
3807 const originInBounds = xInBounds && yInBounds;
3808 const rightInBounds = right <= boundsRight && right >= boundsX;
3809 const bottomInBounds = bottom <= boundsBottom && bottom >= boundsY;
3810 const sizeInBounds = rightInBounds && bottomInBounds;
3811 const visibleW = Math.min(width, x >= boundsX ? boundsRight - x : right - boundsX);
3812 const visibleH = Math.min(height, y >= boundsY ? boundsBottom - y : bottom - boundsY);
3820 const calcReposition = (box, bounds$1) => {
3825 bottom: boundsBottom
3827 const {x, y, width, height} = box;
3828 const maxX = Math.max(boundsX, boundsRight - width);
3829 const maxY = Math.max(boundsY, boundsBottom - height);
3830 const restrictedX = clamp(x, boundsX, maxX);
3831 const restrictedY = clamp(y, boundsY, maxY);
3832 const restrictedWidth = Math.min(restrictedX + width, boundsRight) - restrictedX;
3833 const restrictedHeight = Math.min(restrictedY + height, boundsBottom) - restrictedY;
3834 return bounds(restrictedX, restrictedY, restrictedWidth, restrictedHeight);
3836 const calcMaxSizes = (direction, box, bounds) => {
3837 const upAvailable = constant$1(box.bottom - bounds.y);
3838 const downAvailable = constant$1(bounds.bottom - box.y);
3839 const maxHeight = cataVertical(direction, downAvailable, downAvailable, upAvailable);
3840 const westAvailable = constant$1(box.right - bounds.x);
3841 const eastAvailable = constant$1(bounds.right - box.x);
3842 const maxWidth = cataHorizontal(direction, eastAvailable, eastAvailable, westAvailable);
3848 const attempt = (candidate, width, height, bounds$1) => {
3849 const bubble = candidate.bubble;
3850 const bubbleOffset = bubble.offset;
3851 const adjustedBounds = adjustBounds(bounds$1, candidate.restriction, bubbleOffset);
3852 const newX = candidate.x + bubbleOffset.left;
3853 const newY = candidate.y + bubbleOffset.top;
3854 const box = bounds(newX, newY, width, height);
3855 const {originInBounds, sizeInBounds, visibleW, visibleH} = determinePosition(box, adjustedBounds);
3856 const fits = originInBounds && sizeInBounds;
3857 const fittedBox = fits ? box : calcReposition(box, adjustedBounds);
3858 const isPartlyVisible = fittedBox.width > 0 && fittedBox.height > 0;
3859 const {maxWidth, maxHeight} = calcMaxSizes(candidate.direction, fittedBox, bounds$1);
3860 const reposition = {
3864 direction: candidate.direction,
3865 placement: candidate.placement,
3867 on: bubble.classesOn,
3868 off: bubble.classesOff
3870 layout: candidate.label,
3873 return fits || candidate.alwaysFit ? adt$8.fit(reposition) : adt$8.nofit(reposition, visibleW, visibleH, isPartlyVisible);
3875 const attempts = (element, candidates, anchorBox, elementBox, bubbles, bounds) => {
3876 const panelWidth = elementBox.width;
3877 const panelHeight = elementBox.height;
3878 const attemptBestFit = (layout, reposition, visibleW, visibleH, isVisible) => {
3879 const next = layout(anchorBox, elementBox, bubbles, element, bounds);
3880 const attemptLayout = attempt(next, panelWidth, panelHeight, bounds);
3881 return attemptLayout.fold(constant$1(attemptLayout), (newReposition, newVisibleW, newVisibleH, newIsVisible) => {
3882 const improved = isVisible === newIsVisible ? newVisibleH > visibleH || newVisibleW > visibleW : !isVisible && newIsVisible;
3883 return improved ? attemptLayout : adt$8.nofit(reposition, visibleW, visibleH, isVisible);
3886 const abc = foldl(candidates, (b, a) => {
3887 const bestNext = curry(attemptBestFit, a);
3888 return b.fold(constant$1(b), bestNext);
3891 maxHeight: elementBox.height,
3892 maxWidth: elementBox.width,
3893 direction: southeast$3(),
3894 placement: 'southeast',
3902 return abc.fold(identity, identity);
3905 const singleton = doRevoke => {
3906 const subject = Cell(Optional.none());
3907 const revoke = () => subject.get().each(doRevoke);
3908 const clear = () => {
3910 subject.set(Optional.none());
3912 const isSet = () => subject.get().isSome();
3913 const get = () => subject.get();
3916 subject.set(Optional.some(s));
3925 const destroyable = () => singleton(s => s.destroy());
3926 const unbindable = () => singleton(s => s.unbind());
3927 const value$2 = () => {
3928 const subject = singleton(noop);
3929 const on = f => subject.get().each(f);
3936 const filter = always;
3937 const bind = (element, event, handler) => bind$2(element, event, filter, handler);
3938 const capture = (element, event, handler) => capture$1(element, event, filter, handler);
3939 const fromRawEvent = fromRawEvent$1;
3941 const properties = [
3947 const timerAttr = 'data-alloy-transition-timer';
3948 const isTransitioning$1 = (element, transition) => hasAll(element, transition.classes);
3949 const shouldApplyTransitionCss = (transition, decision, lastPlacement) => {
3950 return lastPlacement.exists(placer => {
3951 const mode = transition.mode;
3952 return mode === 'all' ? true : placer[mode] !== decision[mode];
3955 const hasChanges = (position, intermediate) => {
3956 const round = value => parseFloat(value).toFixed(3);
3957 return find$4(intermediate, (value, key) => {
3958 const newValue = position[key].map(round);
3959 const val = value.map(round);
3960 return !equals(newValue, val);
3963 const getTransitionDuration = element => {
3964 const get = name => {
3965 const style = get$e(element, name);
3966 const times = style.split(/\s*,\s*/);
3967 return filter$2(times, isNotEmpty);
3969 const parse = value => {
3970 if (isString(value) && /^[\d.]+/.test(value)) {
3971 const num = parseFloat(value);
3972 return endsWith(value, 'ms') ? num : num * 1000;
3977 const delay = get('transition-delay');
3978 const duration = get('transition-duration');
3979 return foldl(duration, (acc, dur, i) => {
3980 const time = parse(delay[i]) + parse(dur);
3981 return Math.max(acc, time);
3984 const setupTransitionListeners = (element, transition) => {
3985 const transitionEnd = unbindable();
3986 const transitionCancel = unbindable();
3988 const isSourceTransition = e => {
3989 const pseudoElement = e.raw.pseudoElement ?? '';
3990 return eq(e.target, element) && isEmpty(pseudoElement) && contains$2(properties, e.raw.propertyName);
3992 const transitionDone = e => {
3993 if (isNullable(e) || isSourceTransition(e)) {
3994 transitionEnd.clear();
3995 transitionCancel.clear();
3996 const type = e?.raw.type;
3997 if (isNullable(type) || type === transitionend()) {
3998 clearTimeout(timer);
3999 remove$7(element, timerAttr);
4000 remove$1(element, transition.classes);
4004 const transitionStart = bind(element, transitionstart(), e => {
4005 if (isSourceTransition(e)) {
4006 transitionStart.unbind();
4007 transitionEnd.set(bind(element, transitionend(), transitionDone));
4008 transitionCancel.set(bind(element, transitioncancel(), transitionDone));
4011 const duration = getTransitionDuration(element);
4012 requestAnimationFrame(() => {
4013 timer = setTimeout(transitionDone, duration + 17);
4014 set$9(element, timerAttr, timer);
4017 const startTransitioning = (element, transition) => {
4018 add$1(element, transition.classes);
4019 getOpt(element, timerAttr).each(timerId => {
4020 clearTimeout(parseInt(timerId, 10));
4021 remove$7(element, timerAttr);
4023 setupTransitionListeners(element, transition);
4025 const applyTransitionCss = (element, origin, position, transition, decision, lastPlacement) => {
4026 const shouldTransition = shouldApplyTransitionCss(transition, decision, lastPlacement);
4027 if (shouldTransition || isTransitioning$1(element, transition)) {
4028 set$8(element, 'position', position.position);
4029 const rect = toBox(origin, element);
4030 const intermediatePosition = reposition(origin, {
4034 const intermediateCssOptions = mapToObject(properties, prop => intermediatePosition[prop]);
4035 if (hasChanges(position, intermediateCssOptions)) {
4036 setOptions(element, intermediateCssOptions);
4037 if (shouldTransition) {
4038 startTransitioning(element, transition);
4043 remove$1(element, transition.classes);
4047 const elementSize = p => ({
4048 width: getOuter$1(p),
4049 height: getOuter$2(p)
4051 const layout = (anchorBox, element, bubbles, options) => {
4052 remove$6(element, 'max-height');
4053 remove$6(element, 'max-width');
4054 const elementBox = elementSize(element);
4055 return attempts(element, options.preference, anchorBox, elementBox, bubbles, options.bounds);
4057 const setClasses = (element, decision) => {
4058 const classInfo = decision.classes;
4059 remove$1(element, classInfo.off);
4060 add$1(element, classInfo.on);
4062 const setHeight = (element, decision, options) => {
4063 const maxHeightFunction = options.maxHeightFunction;
4064 maxHeightFunction(element, decision.maxHeight);
4066 const setWidth = (element, decision, options) => {
4067 const maxWidthFunction = options.maxWidthFunction;
4068 maxWidthFunction(element, decision.maxWidth);
4070 const position$2 = (element, decision, options) => {
4071 const positionCss = reposition(options.origin, decision);
4072 options.transition.each(transition => {
4073 applyTransitionCss(element, options.origin, positionCss, transition, decision, options.lastPlacement);
4075 applyPositionCss(element, positionCss);
4077 const setPlacement = (element, decision) => {
4078 setPlacement$1(element, decision.placement);
4081 const setMaxHeight = (element, maxHeight) => {
4082 setMax$1(element, Math.floor(maxHeight));
4084 const anchored = constant$1((element, available) => {
4085 setMaxHeight(element, available);
4087 'overflow-x': 'hidden',
4088 'overflow-y': 'auto'
4091 const expandable$1 = constant$1((element, available) => {
4092 setMaxHeight(element, available);
4095 const defaultOr = (options, key, dephault) => options[key] === undefined ? dephault : options[key];
4096 const simple = (anchor, element, bubble, layouts, lastPlacement, getBounds, overrideOptions, transition) => {
4097 const maxHeightFunction = defaultOr(overrideOptions, 'maxHeightFunction', anchored());
4098 const maxWidthFunction = defaultOr(overrideOptions, 'maxWidthFunction', noop);
4099 const anchorBox = anchor.anchorBox;
4100 const origin = anchor.origin;
4102 bounds: viewport(origin, getBounds),
4104 preference: layouts,
4110 return go(anchorBox, element, bubble, options);
4112 const go = (anchorBox, element, bubble, options) => {
4113 const decision = layout(anchorBox, element, bubble, options);
4114 position$2(element, decision, options);
4115 setPlacement(element, decision);
4116 setClasses(element, decision);
4117 setHeight(element, decision, options);
4118 setWidth(element, decision, options);
4120 layout: decision.layout,
4121 placement: decision.placement
4125 const allAlignments = [
4136 const nu$5 = (xOffset, yOffset, classes, insetModifier = 1) => {
4137 const insetXOffset = xOffset * insetModifier;
4138 const insetYOffset = yOffset * insetModifier;
4139 const getClasses = prop => get$g(classes, prop).getOr([]);
4140 const make = (xDelta, yDelta, alignmentsOn) => {
4141 const alignmentsOff = difference(allAlignments, alignmentsOn);
4143 offset: SugarPosition(xDelta, yDelta),
4144 classesOn: bind$3(alignmentsOn, getClasses),
4145 classesOff: bind$3(alignmentsOff, getClasses)
4149 southeast: () => make(-xOffset, yOffset, [
4153 southwest: () => make(xOffset, yOffset, [
4157 south: () => make(-xOffset / 2, yOffset, [
4161 northeast: () => make(-xOffset, -yOffset, [
4165 northwest: () => make(xOffset, -yOffset, [
4169 north: () => make(-xOffset / 2, -yOffset, [
4173 east: () => make(xOffset, -yOffset / 2, [
4177 west: () => make(-xOffset, -yOffset / 2, [
4181 insetNortheast: () => make(insetXOffset, insetYOffset, [
4186 insetNorthwest: () => make(-insetXOffset, insetYOffset, [
4191 insetNorth: () => make(-insetXOffset / 2, insetYOffset, [
4196 insetSoutheast: () => make(insetXOffset, -insetYOffset, [
4201 insetSouthwest: () => make(-insetXOffset, -insetYOffset, [
4206 insetSouth: () => make(-insetXOffset / 2, -insetYOffset, [
4211 insetEast: () => make(-insetXOffset, -insetYOffset / 2, [
4216 insetWest: () => make(insetXOffset, -insetYOffset / 2, [
4223 const fallback = () => nu$5(0, 0, {});
4225 const nu$4 = identity;
4227 const onDirection = (isLtr, isRtl) => element => getDirection(element) === 'rtl' ? isRtl : isLtr;
4228 const getDirection = element => get$e(element, 'direction') === 'rtl' ? 'rtl' : 'ltr';
4231 (function (AttributeValue) {
4232 AttributeValue['TopToBottom'] = 'toptobottom';
4233 AttributeValue['BottomToTop'] = 'bottomtotop';
4234 }(AttributeValue || (AttributeValue = {})));
4235 const Attribute = 'data-alloy-vertical-dir';
4236 const isBottomToTopDir = el => closest$2(el, current => isElement$1(current) && get$f(current, 'data-alloy-vertical-dir') === AttributeValue.BottomToTop);
4238 const schema$y = () => optionObjOf('layouts', [
4239 required$1('onLtr'),
4240 required$1('onRtl'),
4241 option$3('onBottomLtr'),
4242 option$3('onBottomRtl')
4244 const get$5 = (elem, info, defaultLtr, defaultRtl, defaultBottomLtr, defaultBottomRtl, dirElement) => {
4245 const isBottomToTop = dirElement.map(isBottomToTopDir).getOr(false);
4246 const customLtr = info.layouts.map(ls => ls.onLtr(elem));
4247 const customRtl = info.layouts.map(ls => ls.onRtl(elem));
4248 const ltr = isBottomToTop ? info.layouts.bind(ls => ls.onBottomLtr.map(f => f(elem))).or(customLtr).getOr(defaultBottomLtr) : customLtr.getOr(defaultLtr);
4249 const rtl = isBottomToTop ? info.layouts.bind(ls => ls.onBottomRtl.map(f => f(elem))).or(customRtl).getOr(defaultBottomRtl) : customRtl.getOr(defaultRtl);
4250 const f = onDirection(ltr, rtl);
4254 const placement$4 = (component, anchorInfo, origin) => {
4255 const hotspot = anchorInfo.hotspot;
4256 const anchorBox = toBox(origin, hotspot.element);
4257 const layouts = get$5(component.element, anchorInfo, belowOrAbove(), belowOrAboveRtl(), aboveOrBelow(), aboveOrBelowRtl(), Optional.some(anchorInfo.hotspot.element));
4258 return Optional.some(nu$4({
4260 bubble: anchorInfo.bubble.getOr(fallback()),
4261 overrides: anchorInfo.overrides,
4263 placer: Optional.none()
4266 var HotspotAnchor = [
4267 required$1('hotspot'),
4269 defaulted('overrides', {}),
4271 output$1('placement', placement$4)
4274 const placement$3 = (component, anchorInfo, origin) => {
4275 const pos = translate$2(origin, anchorInfo.x, anchorInfo.y);
4276 const anchorBox = bounds(pos.left, pos.top, anchorInfo.width, anchorInfo.height);
4277 const layouts = get$5(component.element, anchorInfo, all$1(), allRtl$1(), all$1(), allRtl$1(), Optional.none());
4278 return Optional.some(nu$4({
4280 bubble: anchorInfo.bubble,
4281 overrides: anchorInfo.overrides,
4283 placer: Optional.none()
4286 var MakeshiftAnchor = [
4289 defaulted('height', 0),
4290 defaulted('width', 0),
4291 defaulted('bubble', fallback()),
4292 defaulted('overrides', {}),
4294 output$1('placement', placement$3)
4297 const adt$7 = Adt.generate([
4298 { screen: ['point'] },
4307 const toFixed = pos => pos.fold(identity, (point, scrollLeft, scrollTop) => point.translate(-scrollLeft, -scrollTop));
4308 const toAbsolute = pos => pos.fold(identity, identity);
4309 const sum = points => foldl(points, (b, a) => b.translate(a.left, a.top), SugarPosition(0, 0));
4310 const sumAsFixed = positions => {
4311 const points = map$2(positions, toFixed);
4314 const sumAsAbsolute = positions => {
4315 const points = map$2(positions, toAbsolute);
4318 const screen = adt$7.screen;
4319 const absolute$1 = adt$7.absolute;
4321 const getOffset = (component, origin, anchorInfo) => {
4322 const win = defaultView(anchorInfo.root).dom;
4323 const hasSameOwner = frame => {
4324 const frameOwner = owner$4(frame);
4325 const compOwner = owner$4(component.element);
4326 return eq(frameOwner, compOwner);
4328 return Optional.from(win.frameElement).map(SugarElement.fromDom).filter(hasSameOwner).map(absolute$3);
4330 const getRootPoint = (component, origin, anchorInfo) => {
4331 const doc = owner$4(component.element);
4332 const outerScroll = get$b(doc);
4333 const offset = getOffset(component, origin, anchorInfo).getOr(outerScroll);
4334 return absolute$1(offset, outerScroll.left, outerScroll.top);
4337 const getBox = (left, top, width, height) => {
4338 const point = screen(SugarPosition(left, top));
4339 return Optional.some(pointed(point, width, height));
4341 const calcNewAnchor = (optBox, rootPoint, anchorInfo, origin, elem) => optBox.map(box => {
4346 const topLeft = cata$1(origin, () => sumAsAbsolute(points), () => sumAsAbsolute(points), () => sumAsFixed(points));
4347 const anchorBox = rect(topLeft.left, topLeft.top, box.width, box.height);
4348 const layoutsLtr = anchorInfo.showAbove ? aboveOrBelow() : belowOrAbove();
4349 const layoutsRtl = anchorInfo.showAbove ? aboveOrBelowRtl() : belowOrAboveRtl();
4350 const layouts = get$5(elem, anchorInfo, layoutsLtr, layoutsRtl, layoutsLtr, layoutsRtl, Optional.none());
4353 bubble: anchorInfo.bubble.getOr(fallback()),
4354 overrides: anchorInfo.overrides,
4356 placer: Optional.none()
4360 const placement$2 = (component, anchorInfo, origin) => {
4361 const rootPoint = getRootPoint(component, origin, anchorInfo);
4362 return anchorInfo.node.filter(inBody).bind(target => {
4363 const rect = target.dom.getBoundingClientRect();
4364 const nodeBox = getBox(rect.left, rect.top, rect.width, rect.height);
4365 const elem = anchorInfo.node.getOr(component.element);
4366 return calcNewAnchor(nodeBox, rootPoint, anchorInfo, origin, elem);
4374 defaulted('overrides', {}),
4375 defaulted('showAbove', false),
4376 output$1('placement', placement$2)
4379 const zeroWidth = '\uFEFF';
4380 const nbsp = '\xA0';
4382 const create$3 = (start, soffset, finish, foffset) => ({
4388 const SimRange = { create: create$3 };
4390 const adt$6 = Adt.generate([
4391 { before: ['element'] },
4398 { after: ['element'] }
4400 const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
4401 const getStart$1 = situ => situ.fold(identity, identity, identity);
4402 const before = adt$6.before;
4403 const on$1 = adt$6.on;
4404 const after$1 = adt$6.after;
4410 getStart: getStart$1
4413 const adt$5 = Adt.generate([
4414 { domRange: ['rng'] },
4430 const exactFromRange = simRange => adt$5.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
4431 const getStart = selection => selection.match({
4432 domRange: rng => SugarElement.fromDom(rng.startContainer),
4433 relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
4434 exact: (start, _soffset, _finish, _foffset) => start
4436 const domRange = adt$5.domRange;
4437 const relative = adt$5.relative;
4438 const exact = adt$5.exact;
4439 const getWin = selection => {
4440 const start = getStart(selection);
4441 return defaultView(start);
4443 const range$1 = SimRange.create;
4444 const SimSelection = {
4453 const setStart = (rng, situ) => {
4455 rng.setStartBefore(e.dom);
4457 rng.setStart(e.dom, o);
4459 rng.setStartAfter(e.dom);
4462 const setFinish = (rng, situ) => {
4464 rng.setEndBefore(e.dom);
4466 rng.setEnd(e.dom, o);
4468 rng.setEndAfter(e.dom);
4471 const relativeToNative = (win, startSitu, finishSitu) => {
4472 const range = win.document.createRange();
4473 setStart(range, startSitu);
4474 setFinish(range, finishSitu);
4477 const exactToNative = (win, start, soffset, finish, foffset) => {
4478 const rng = win.document.createRange();
4479 rng.setStart(start.dom, soffset);
4480 rng.setEnd(finish.dom, foffset);
4483 const toRect = rect => ({
4487 bottom: rect.bottom,
4491 const getFirstRect$1 = rng => {
4492 const rects = rng.getClientRects();
4493 const rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect();
4494 return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
4496 const getBounds$2 = rng => {
4497 const rect = rng.getBoundingClientRect();
4498 return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
4501 const adt$4 = Adt.generate([
4519 const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
4520 const getRanges = (win, selection) => selection.match({
4523 ltr: constant$1(rng),
4527 relative: (startSitu, finishSitu) => {
4529 ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
4530 rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
4533 exact: (start, soffset, finish, foffset) => {
4535 ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
4536 rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
4540 const doDiagnose = (win, ranges) => {
4541 const rng = ranges.ltr();
4542 if (rng.collapsed) {
4543 const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
4544 return reversed.map(rev => adt$4.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$4.ltr, rng));
4546 return fromRange(win, adt$4.ltr, rng);
4549 const diagnose = (win, selection) => {
4550 const ranges = getRanges(win, selection);
4551 return doDiagnose(win, ranges);
4553 const asLtrRange = (win, selection) => {
4554 const diagnosis = diagnose(win, selection);
4555 return diagnosis.match({
4556 ltr: (start, soffset, finish, foffset) => {
4557 const rng = win.document.createRange();
4558 rng.setStart(start.dom, soffset);
4559 rng.setEnd(finish.dom, foffset);
4562 rtl: (start, soffset, finish, foffset) => {
4563 const rng = win.document.createRange();
4564 rng.setStart(finish.dom, foffset);
4565 rng.setEnd(start.dom, soffset);
4573 const descendants = (scope, selector) => all$3(selector, scope);
4575 const makeRange = (start, soffset, finish, foffset) => {
4576 const doc = owner$4(start);
4577 const rng = doc.dom.createRange();
4578 rng.setStart(start.dom, soffset);
4579 rng.setEnd(finish.dom, foffset);
4582 const after = (start, soffset, finish, foffset) => {
4583 const r = makeRange(start, soffset, finish, foffset);
4584 const same = eq(start, finish) && soffset === foffset;
4585 return r.collapsed && !same;
4588 const getNativeSelection = win => Optional.from(win.getSelection());
4589 const readRange = selection => {
4590 if (selection.rangeCount > 0) {
4591 const firstRng = selection.getRangeAt(0);
4592 const lastRng = selection.getRangeAt(selection.rangeCount - 1);
4593 return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset));
4595 return Optional.none();
4598 const doGetExact = selection => {
4599 if (selection.anchorNode === null || selection.focusNode === null) {
4600 return readRange(selection);
4602 const anchor = SugarElement.fromDom(selection.anchorNode);
4603 const focus = SugarElement.fromDom(selection.focusNode);
4604 return after(anchor, selection.anchorOffset, focus, selection.focusOffset) ? Optional.some(SimRange.create(anchor, selection.anchorOffset, focus, selection.focusOffset)) : readRange(selection);
4607 const getExact = win => getNativeSelection(win).filter(sel => sel.rangeCount > 0).bind(doGetExact);
4608 const getFirstRect = (win, selection) => {
4609 const rng = asLtrRange(win, selection);
4610 return getFirstRect$1(rng);
4612 const getBounds$1 = (win, selection) => {
4613 const rng = asLtrRange(win, selection);
4614 return getBounds$2(rng);
4617 const NodeValue = (is, name) => {
4618 const get = element => {
4620 throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
4622 return getOption(element).getOr('');
4624 const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
4625 const set = (element, value) => {
4627 throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
4629 element.dom.nodeValue = value;
4638 const api = NodeValue(isText, 'text');
4639 const get$4 = element => api.get(element);
4641 const point = (element, offset) => ({
4645 const descendOnce$1 = (element, offset) => {
4646 const children$1 = children(element);
4647 if (children$1.length === 0) {
4648 return point(element, offset);
4649 } else if (offset < children$1.length) {
4650 return point(children$1[offset], 0);
4652 const last = children$1[children$1.length - 1];
4653 const len = isText(last) ? get$4(last).length : children(last).length;
4654 return point(last, len);
4658 const descendOnce = (element, offset) => isText(element) ? point(element, offset) : descendOnce$1(element, offset);
4659 const getAnchorSelection = (win, anchorInfo) => {
4660 const getSelection = anchorInfo.getSelection.getOrThunk(() => () => getExact(win));
4661 return getSelection().map(sel => {
4662 const modStart = descendOnce(sel.start, sel.soffset);
4663 const modFinish = descendOnce(sel.finish, sel.foffset);
4664 return SimSelection.range(modStart.element, modStart.offset, modFinish.element, modFinish.offset);
4667 const placement$1 = (component, anchorInfo, origin) => {
4668 const win = defaultView(anchorInfo.root).dom;
4669 const rootPoint = getRootPoint(component, origin, anchorInfo);
4670 const selectionBox = getAnchorSelection(win, anchorInfo).bind(sel => {
4671 const optRect = getBounds$1(win, SimSelection.exactFromRange(sel)).orThunk(() => {
4672 const x = SugarElement.fromText(zeroWidth);
4673 before$1(sel.start, x);
4674 const rect = getFirstRect(win, SimSelection.exact(x, 0, x, 1));
4678 return optRect.bind(rawRect => getBox(rawRect.left, rawRect.top, rawRect.width, rawRect.height));
4680 const targetElement = getAnchorSelection(win, anchorInfo).bind(sel => isElement$1(sel.start) ? Optional.some(sel.start) : parentElement(sel.start));
4681 const elem = targetElement.getOr(component.element);
4682 return calcNewAnchor(selectionBox, rootPoint, anchorInfo, origin, elem);
4684 var SelectionAnchor = [
4685 option$3('getSelection'),
4689 defaulted('overrides', {}),
4690 defaulted('showAbove', false),
4691 output$1('placement', placement$1)
4694 const labelPrefix$1 = 'link-layout';
4695 const eastX = anchor => anchor.x + anchor.width;
4696 const westX = (anchor, element) => anchor.x - element.width;
4697 const northY$1 = (anchor, element) => anchor.y - element.height + anchor.height;
4698 const southY$1 = anchor => anchor.y;
4699 const southeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), southY$1(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
4703 const southwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), southY$1(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
4707 const northeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), northY$1(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
4711 const northwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), northY$1(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
4721 const allRtl = () => [
4728 const placement = (component, submenuInfo, origin) => {
4729 const anchorBox = toBox(origin, submenuInfo.item.element);
4730 const layouts = get$5(component.element, submenuInfo, all(), allRtl(), all(), allRtl(), Optional.none());
4731 return Optional.some(nu$4({
4734 overrides: submenuInfo.overrides,
4736 placer: Optional.none()
4739 var SubmenuAnchor = [
4742 defaulted('overrides', {}),
4743 output$1('placement', placement)
4746 var AnchorSchema = choose$1('type', {
4747 selection: SelectionAnchor,
4749 hotspot: HotspotAnchor,
4750 submenu: SubmenuAnchor,
4751 makeshift: MakeshiftAnchor
4754 const TransitionSchema = [
4755 requiredArrayOf('classes', string),
4756 defaultedStringEnum('mode', 'all', [
4762 const PositionSchema = [
4763 defaulted('useFixed', never),
4764 option$3('getBounds')
4766 const PlacementSchema = [
4767 requiredOf('anchor', AnchorSchema),
4768 optionObjOf('transition', TransitionSchema)
4771 const getFixedOrigin = () => {
4772 const html = document.documentElement;
4773 return fixed$1(0, 0, html.clientWidth, html.clientHeight);
4775 const getRelativeOrigin = component => {
4776 const position = absolute$3(component.element);
4777 const bounds = component.element.dom.getBoundingClientRect();
4778 return relative$1(position.left, position.top, bounds.width, bounds.height);
4780 const place = (component, origin, anchoring, getBounds, placee, lastPlace, transition) => {
4781 const anchor = box(anchoring.anchorBox, origin);
4782 return simple(anchor, placee.element, anchoring.bubble, anchoring.layouts, lastPlace, getBounds, anchoring.overrides, transition);
4784 const position$1 = (component, posConfig, posState, placee, placementSpec) => {
4785 positionWithin(component, posConfig, posState, placee, placementSpec, Optional.none());
4787 const positionWithin = (component, posConfig, posState, placee, placementSpec, boxElement) => {
4788 const boundsBox = boxElement.map(box$1);
4789 return positionWithinBounds(component, posConfig, posState, placee, placementSpec, boundsBox);
4791 const positionWithinBounds = (component, posConfig, posState, placee, placementSpec, bounds) => {
4792 const placeeDetail = asRawOrDie$1('placement.info', objOf(PlacementSchema), placementSpec);
4793 const anchorage = placeeDetail.anchor;
4794 const element = placee.element;
4795 const placeeState = posState.get(placee.uid);
4797 set$8(element, 'position', 'fixed');
4798 const oldVisibility = getRaw(element, 'visibility');
4799 set$8(element, 'visibility', 'hidden');
4800 const origin = posConfig.useFixed() ? getFixedOrigin() : getRelativeOrigin(component);
4801 const placer = anchorage.placement;
4802 const getBounds = bounds.map(constant$1).or(posConfig.getBounds);
4803 placer(component, anchorage, origin).each(anchoring => {
4804 const doPlace = anchoring.placer.getOr(place);
4805 const newState = doPlace(component, origin, anchoring, getBounds, placee, placeeState, placeeDetail.transition);
4806 posState.set(placee.uid, newState);
4808 oldVisibility.fold(() => {
4809 remove$6(element, 'visibility');
4811 set$8(element, 'visibility', vis);
4813 if (getRaw(element, 'left').isNone() && getRaw(element, 'top').isNone() && getRaw(element, 'right').isNone() && getRaw(element, 'bottom').isNone() && is$1(getRaw(element, 'position'), 'fixed')) {
4814 remove$6(element, 'position');
4818 const getMode = (component, pConfig, _pState) => pConfig.useFixed() ? 'fixed' : 'absolute';
4819 const reset$1 = (component, pConfig, posState, placee) => {
4820 const element = placee.element;
4827 ], prop => remove$6(element, prop));
4829 posState.clear(placee.uid);
4832 var PositionApis = /*#__PURE__*/Object.freeze({
4834 position: position$1,
4835 positionWithin: positionWithin,
4836 positionWithinBounds: positionWithinBounds,
4841 const init$g = () => {
4843 const set = (id, data) => {
4846 const get = id => get$g(state, id);
4847 const clear = id => {
4848 if (isNonNullable(id)) {
4855 readState: () => state,
4862 var PositioningState = /*#__PURE__*/Object.freeze({
4867 const Positioning = create$4({
4868 fields: PositionSchema,
4869 name: 'positioning',
4870 active: ActivePosition,
4872 state: PositioningState
4875 const isConnected = comp => comp.getSystem().isConnected();
4876 const fireDetaching = component => {
4877 emit(component, detachedFromDom());
4878 const children = component.components();
4879 each$1(children, fireDetaching);
4881 const fireAttaching = component => {
4882 const children = component.components();
4883 each$1(children, fireAttaching);
4884 emit(component, attachedToDom());
4886 const virtualAttach = (parent, child) => {
4887 parent.getSystem().addToWorld(child);
4888 if (inBody(parent.element)) {
4889 fireAttaching(child);
4892 const virtualDetach = comp => {
4893 fireDetaching(comp);
4894 comp.getSystem().removeFromWorld(comp);
4896 const attach$1 = (parent, child) => {
4897 append$2(parent.element, child.element);
4899 const detachChildren$1 = component => {
4900 each$1(component.components(), childComp => remove$5(childComp.element));
4901 empty(component.element);
4902 component.syncComponents();
4904 const replaceChildren = (component, newSpecs, buildNewChildren) => {
4905 const subs = component.components();
4906 detachChildren$1(component);
4907 const newChildren = buildNewChildren(newSpecs);
4908 const deleted = difference(subs, newChildren);
4909 each$1(deleted, comp => {
4910 fireDetaching(comp);
4911 component.getSystem().removeFromWorld(comp);
4913 each$1(newChildren, childComp => {
4914 if (!isConnected(childComp)) {
4915 component.getSystem().addToWorld(childComp);
4916 attach$1(component, childComp);
4917 if (inBody(component.element)) {
4918 fireAttaching(childComp);
4921 attach$1(component, childComp);
4924 component.syncComponents();
4926 const virtualReplaceChildren = (component, newSpecs, buildNewChildren) => {
4927 const subs = component.components();
4928 const existingComps = bind$3(newSpecs, spec => getPremade(spec).toArray());
4929 each$1(subs, childComp => {
4930 if (!contains$2(existingComps, childComp)) {
4931 virtualDetach(childComp);
4934 const newChildren = buildNewChildren(newSpecs);
4935 const deleted = difference(subs, newChildren);
4936 each$1(deleted, deletedComp => {
4937 if (isConnected(deletedComp)) {
4938 virtualDetach(deletedComp);
4941 each$1(newChildren, childComp => {
4942 if (!isConnected(childComp)) {
4943 virtualAttach(component, childComp);
4946 component.syncComponents();
4949 const attach = (parent, child) => {
4950 attachWith(parent, child, append$2);
4952 const attachWith = (parent, child, insertion) => {
4953 parent.getSystem().addToWorld(child);
4954 insertion(parent.element, child.element);
4955 if (inBody(parent.element)) {
4956 fireAttaching(child);
4958 parent.syncComponents();
4960 const doDetach = component => {
4961 fireDetaching(component);
4962 remove$5(component.element);
4963 component.getSystem().removeFromWorld(component);
4965 const detach = component => {
4966 const parent$1 = parent(component.element).bind(p => component.getSystem().getByDom(p).toOptional());
4967 doDetach(component);
4968 parent$1.each(p => {
4972 const detachChildren = component => {
4973 const subs = component.components();
4974 each$1(subs, doDetach);
4975 empty(component.element);
4976 component.syncComponents();
4978 const attachSystem = (element, guiSystem) => {
4979 attachSystemWith(element, guiSystem, append$2);
4981 const attachSystemAfter = (element, guiSystem) => {
4982 attachSystemWith(element, guiSystem, after$2);
4984 const attachSystemWith = (element, guiSystem, inserter) => {
4985 inserter(element, guiSystem.element);
4986 const children$1 = children(guiSystem.element);
4987 each$1(children$1, child => {
4988 guiSystem.getByDom(child).each(fireAttaching);
4991 const detachSystem = guiSystem => {
4992 const children$1 = children(guiSystem.element);
4993 each$1(children$1, child => {
4994 guiSystem.getByDom(child).each(fireDetaching);
4996 remove$5(guiSystem.element);
4999 const rebuild = (sandbox, sConfig, sState, data) => {
5000 sState.get().each(_data => {
5001 detachChildren(sandbox);
5003 const point = sConfig.getAttachPoint(sandbox);
5004 attach(point, sandbox);
5005 const built = sandbox.getSystem().build(data);
5006 attach(sandbox, built);
5010 const open$1 = (sandbox, sConfig, sState, data) => {
5011 const newState = rebuild(sandbox, sConfig, sState, data);
5012 sConfig.onOpen(sandbox, newState);
5015 const setContent = (sandbox, sConfig, sState, data) => sState.get().map(() => rebuild(sandbox, sConfig, sState, data));
5016 const openWhileCloaked = (sandbox, sConfig, sState, data, transaction) => {
5017 cloak(sandbox, sConfig);
5018 open$1(sandbox, sConfig, sState, data);
5020 decloak(sandbox, sConfig);
5022 const close$1 = (sandbox, sConfig, sState) => {
5023 sState.get().each(data => {
5024 detachChildren(sandbox);
5026 sConfig.onClose(sandbox, data);
5030 const isOpen$1 = (_sandbox, _sConfig, sState) => sState.isOpen();
5031 const isPartOf = (sandbox, sConfig, sState, queryElem) => isOpen$1(sandbox, sConfig, sState) && sState.get().exists(data => sConfig.isPartOf(sandbox, data, queryElem));
5032 const getState$2 = (_sandbox, _sConfig, sState) => sState.get();
5033 const store = (sandbox, cssKey, attr, newValue) => {
5034 getRaw(sandbox.element, cssKey).fold(() => {
5035 remove$7(sandbox.element, attr);
5037 set$9(sandbox.element, attr, v);
5039 set$8(sandbox.element, cssKey, newValue);
5041 const restore = (sandbox, cssKey, attr) => {
5042 getOpt(sandbox.element, attr).fold(() => remove$6(sandbox.element, cssKey), oldValue => set$8(sandbox.element, cssKey, oldValue));
5044 const cloak = (sandbox, sConfig, _sState) => {
5045 const sink = sConfig.getAttachPoint(sandbox);
5046 set$8(sandbox.element, 'position', Positioning.getMode(sink));
5047 store(sandbox, 'visibility', sConfig.cloakVisibilityAttr, 'hidden');
5049 const hasPosition = element => exists([
5054 ], pos => getRaw(element, pos).isSome());
5055 const decloak = (sandbox, sConfig, _sState) => {
5056 if (!hasPosition(sandbox.element)) {
5057 remove$6(sandbox.element, 'position');
5059 restore(sandbox, 'visibility', sConfig.cloakVisibilityAttr);
5062 var SandboxApis = /*#__PURE__*/Object.freeze({
5067 openWhileCloaked: openWhileCloaked,
5071 getState: getState$2,
5072 setContent: setContent
5075 const events$g = (sandboxConfig, sandboxState) => derive$2([run$1(sandboxClose(), (sandbox, _simulatedEvent) => {
5076 close$1(sandbox, sandboxConfig, sandboxState);
5079 var ActiveSandbox = /*#__PURE__*/Object.freeze({
5084 var SandboxSchema = [
5085 onHandler('onOpen'),
5086 onHandler('onClose'),
5087 required$1('isPartOf'),
5088 required$1('getAttachPoint'),
5089 defaulted('cloakVisibilityAttr', 'data-precloak-visibility')
5092 const init$f = () => {
5093 const contents = value$2();
5094 const readState = constant$1('not-implemented');
5097 isOpen: contents.isSet,
5098 clear: contents.clear,
5104 var SandboxState = /*#__PURE__*/Object.freeze({
5109 const Sandboxing = create$4({
5110 fields: SandboxSchema,
5112 active: ActiveSandbox,
5117 const dismissPopups = constant$1('dismiss.popups');
5118 const repositionPopups = constant$1('reposition.popups');
5119 const mouseReleased = constant$1('mouse.released');
5121 const schema$x = objOfOnly([
5122 defaulted('isExtraPart', never),
5123 optionObjOf('fireEventInstead', [defaulted('event', dismissRequested())])
5125 const receivingChannel$1 = rawSpec => {
5126 const detail = asRawOrDie$1('Dismissal', schema$x, rawSpec);
5128 [dismissPopups()]: {
5129 schema: objOfOnly([required$1('target')]),
5130 onReceive: (sandbox, data) => {
5131 if (Sandboxing.isOpen(sandbox)) {
5132 const isPart = Sandboxing.isPartOf(sandbox, data.target) || detail.isExtraPart(sandbox, data.target);
5134 detail.fireEventInstead.fold(() => Sandboxing.close(sandbox), fe => emit(sandbox, fe.event));
5142 const schema$w = objOfOnly([
5143 optionObjOf('fireEventInstead', [defaulted('event', repositionRequested())]),
5144 requiredFunction('doReposition')
5146 const receivingChannel = rawSpec => {
5147 const detail = asRawOrDie$1('Reposition', schema$w, rawSpec);
5149 [repositionPopups()]: {
5150 onReceive: sandbox => {
5151 if (Sandboxing.isOpen(sandbox)) {
5152 detail.fireEventInstead.fold(() => detail.doReposition(sandbox), fe => emit(sandbox, fe.event));
5159 const onLoad$5 = (component, repConfig, repState) => {
5160 repConfig.store.manager.onLoad(component, repConfig, repState);
5162 const onUnload$2 = (component, repConfig, repState) => {
5163 repConfig.store.manager.onUnload(component, repConfig, repState);
5165 const setValue$3 = (component, repConfig, repState, data) => {
5166 repConfig.store.manager.setValue(component, repConfig, repState, data);
5168 const getValue$3 = (component, repConfig, repState) => repConfig.store.manager.getValue(component, repConfig, repState);
5169 const getState$1 = (component, repConfig, repState) => repState;
5171 var RepresentApis = /*#__PURE__*/Object.freeze({
5174 onUnload: onUnload$2,
5175 setValue: setValue$3,
5176 getValue: getValue$3,
5177 getState: getState$1
5180 const events$f = (repConfig, repState) => {
5181 const es = repConfig.resetOnDom ? [
5182 runOnAttached((comp, _se) => {
5183 onLoad$5(comp, repConfig, repState);
5185 runOnDetached((comp, _se) => {
5186 onUnload$2(comp, repConfig, repState);
5188 ] : [loadEvent(repConfig, repState, onLoad$5)];
5189 return derive$2(es);
5192 var ActiveRepresenting = /*#__PURE__*/Object.freeze({
5197 const memory$1 = () => {
5198 const data = Cell(null);
5199 const readState = () => ({
5203 const isNotSet = () => data.get() === null;
5204 const clear = () => {
5215 const manual = () => {
5216 const readState = noop;
5217 return nu$8({ readState });
5219 const dataset = () => {
5220 const dataByValue = Cell({});
5221 const dataByText = Cell({});
5222 const readState = () => ({
5224 dataByValue: dataByValue.get(),
5225 dataByText: dataByText.get()
5227 const clear = () => {
5228 dataByValue.set({});
5231 const lookup = itemString => get$g(dataByValue.get(), itemString).orThunk(() => get$g(dataByText.get(), itemString));
5232 const update = items => {
5233 const currentDataByValue = dataByValue.get();
5234 const currentDataByText = dataByText.get();
5235 const newDataByValue = {};
5236 const newDataByText = {};
5237 each$1(items, item => {
5238 newDataByValue[item.value] = item;
5239 get$g(item, 'meta').each(meta => {
5240 get$g(meta, 'text').each(text => {
5241 newDataByText[text] = item;
5246 ...currentDataByValue,
5250 ...currentDataByText,
5261 const init$e = spec => spec.store.manager.state(spec);
5263 var RepresentState = /*#__PURE__*/Object.freeze({
5271 const setValue$2 = (component, repConfig, repState, data) => {
5272 const store = repConfig.store;
5273 repState.update([data]);
5274 store.setValue(component, data);
5275 repConfig.onSetValue(component, data);
5277 const getValue$2 = (component, repConfig, repState) => {
5278 const store = repConfig.store;
5279 const key = store.getDataKey(component);
5280 return repState.lookup(key).getOrThunk(() => store.getFallbackEntry(key));
5282 const onLoad$4 = (component, repConfig, repState) => {
5283 const store = repConfig.store;
5284 store.initialValue.each(data => {
5285 setValue$2(component, repConfig, repState, data);
5288 const onUnload$1 = (component, repConfig, repState) => {
5291 var DatasetStore = [
5292 option$3('initialValue'),
5293 required$1('getFallbackEntry'),
5294 required$1('getDataKey'),
5295 required$1('setValue'),
5296 output$1('manager', {
5297 setValue: setValue$2,
5298 getValue: getValue$2,
5300 onUnload: onUnload$1,
5305 const getValue$1 = (component, repConfig, _repState) => repConfig.store.getValue(component);
5306 const setValue$1 = (component, repConfig, _repState, data) => {
5307 repConfig.store.setValue(component, data);
5308 repConfig.onSetValue(component, data);
5310 const onLoad$3 = (component, repConfig, _repState) => {
5311 repConfig.store.initialValue.each(data => {
5312 repConfig.store.setValue(component, data);
5316 required$1('getValue'),
5317 defaulted('setValue', noop),
5318 option$3('initialValue'),
5319 output$1('manager', {
5320 setValue: setValue$1,
5321 getValue: getValue$1,
5328 const setValue = (component, repConfig, repState, data) => {
5330 repConfig.onSetValue(component, data);
5332 const getValue = (component, repConfig, repState) => repState.get();
5333 const onLoad$2 = (component, repConfig, repState) => {
5334 repConfig.store.initialValue.each(initVal => {
5335 if (repState.isNotSet()) {
5336 repState.set(initVal);
5340 const onUnload = (component, repConfig, repState) => {
5344 option$3('initialValue'),
5345 output$1('manager', {
5354 var RepresentSchema = [
5355 defaultedOf('store', { mode: 'memory' }, choose$1('mode', {
5356 memory: MemoryStore,
5357 manual: ManualStore,
5358 dataset: DatasetStore
5360 onHandler('onSetValue'),
5361 defaulted('resetOnDom', false)
5364 const Representing = create$4({
5365 fields: RepresentSchema,
5366 name: 'representing',
5367 active: ActiveRepresenting,
5368 apis: RepresentApis,
5370 setValueFrom: (component, source) => {
5371 const value = Representing.getValue(source);
5372 Representing.setValue(component, value);
5375 state: RepresentState
5378 const field = (name, forbidden) => defaultedObjOf(name, {}, map$2(forbidden, f => forbid(f.name(), 'Cannot configure ' + f.name() + ' for ' + name)).concat([customField('dump', identity)]));
5379 const get$3 = data => data.dump;
5380 const augment = (data, original) => ({
5381 ...derive$1(original),
5384 const SketchBehaviours = {
5390 const _placeholder = 'placeholder';
5391 const adt$3 = Adt.generate([
5405 const isSubstituted = spec => has$2(spec, 'uiType');
5406 const subPlaceholder = (owner, detail, compSpec, placeholders) => {
5407 if (owner.exists(o => o !== compSpec.owner)) {
5408 return adt$3.single(true, constant$1(compSpec));
5410 return get$g(placeholders, compSpec.name).fold(() => {
5411 throw new Error('Unknown placeholder component: ' + compSpec.name + '\nKnown: [' + keys(placeholders) + ']\nNamespace: ' + owner.getOr('none') + '\nSpec: ' + JSON.stringify(compSpec, null, 2));
5412 }, newSpec => newSpec.replace());
5414 const scan = (owner, detail, compSpec, placeholders) => {
5415 if (isSubstituted(compSpec) && compSpec.uiType === _placeholder) {
5416 return subPlaceholder(owner, detail, compSpec, placeholders);
5418 return adt$3.single(false, constant$1(compSpec));
5421 const substitute = (owner, detail, compSpec, placeholders) => {
5422 const base = scan(owner, detail, compSpec, placeholders);
5423 return base.fold((req, valueThunk) => {
5424 const value = isSubstituted(compSpec) ? valueThunk(detail, compSpec.config, compSpec.validated) : valueThunk(detail);
5425 const childSpecs = get$g(value, 'components').getOr([]);
5426 const substituted = bind$3(childSpecs, c => substitute(owner, detail, c, placeholders));
5429 components: substituted
5431 }, (req, valuesThunk) => {
5432 if (isSubstituted(compSpec)) {
5433 const values = valuesThunk(detail, compSpec.config, compSpec.validated);
5434 const preprocessor = compSpec.validated.preprocess.getOr(identity);
5435 return preprocessor(values);
5437 return valuesThunk(detail);
5441 const substituteAll = (owner, detail, components, placeholders) => bind$3(components, c => substitute(owner, detail, c, placeholders));
5442 const oneReplace = (label, replacements) => {
5444 const used = () => called;
5445 const replace = () => {
5447 throw new Error('Trying to use the same placeholder more than once: ' + label);
5450 return replacements;
5452 const required = () => replacements.fold((req, _) => req, (req, _) => req);
5454 name: constant$1(label),
5460 const substitutePlaces = (owner, detail, components, placeholders) => {
5461 const ps = map$1(placeholders, (ph, name) => oneReplace(name, ph));
5462 const outcome = substituteAll(owner, detail, components, ps);
5464 if (p.used() === false && p.required()) {
5465 throw new Error('Placeholder: ' + p.name() + ' was not found in components list\nNamespace: ' + owner.getOr('none') + '\nComponents: ' + JSON.stringify(detail.components, null, 2));
5470 const single$2 = adt$3.single;
5471 const multiple = adt$3.multiple;
5472 const placeholder = constant$1(_placeholder);
5474 const adt$2 = Adt.generate([
5475 { required: ['data'] },
5476 { external: ['data'] },
5477 { optional: ['data'] },
5480 const fFactory = defaulted('factory', { sketch: identity });
5481 const fSchema = defaulted('schema', []);
5482 const fName = required$1('name');
5483 const fPname = field$1('pname', 'pname', defaultedThunk(typeSpec => '<alloy.' + generate$6(typeSpec.name) + '>'), anyValue());
5484 const fGroupSchema = customField('schema', () => [option$3('preprocess')]);
5485 const fDefaults = defaulted('defaults', constant$1({}));
5486 const fOverrides = defaulted('overrides', constant$1({}));
5487 const requiredSpec = objOf([
5495 const externalSpec = objOf([
5502 const optionalSpec = objOf([
5510 const groupSpec = objOf([
5519 const asNamedPart = part => {
5520 return part.fold(Optional.some, Optional.none, Optional.some, Optional.some);
5522 const name$2 = part => {
5523 const get = data => data.name;
5524 return part.fold(get, get, get, get);
5526 const asCommon = part => {
5527 return part.fold(identity, identity, identity, identity);
5529 const convert = (adtConstructor, partSchema) => spec => {
5530 const data = asRawOrDie$1('Converting part type', partSchema, spec);
5531 return adtConstructor(data);
5533 const required = convert(adt$2.required, requiredSpec);
5534 const external = convert(adt$2.external, externalSpec);
5535 const optional = convert(adt$2.optional, optionalSpec);
5536 const group = convert(adt$2.group, groupSpec);
5537 const original = constant$1('entirety');
5539 var PartType = /*#__PURE__*/Object.freeze({
5545 asNamedPart: asNamedPart,
5551 const combine = (detail, data, partSpec, partValidated) => deepMerge(data.defaults(detail, partSpec, partValidated), partSpec, { uid: detail.partUids[data.name] }, data.overrides(detail, partSpec, partValidated));
5552 const subs = (owner, detail, parts) => {
5553 const internals = {};
5554 const externals = {};
5555 each$1(parts, part => {
5557 internals[data.pname] = single$2(true, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
5559 const partSpec = detail.parts[data.name];
5560 externals[data.name] = constant$1(data.factory.sketch(combine(detail, data, partSpec[original()]), partSpec));
5562 internals[data.pname] = single$2(false, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
5564 internals[data.pname] = multiple(true, (detail, _partSpec, _partValidated) => {
5565 const units = detail[data.name];
5566 return map$2(units, u => data.factory.sketch(deepMerge(data.defaults(detail, u, _partValidated), u, data.overrides(detail, u))));
5571 internals: constant$1(internals),
5572 externals: constant$1(externals)
5576 const generate$3 = (owner, parts) => {
5578 each$1(parts, part => {
5579 asNamedPart(part).each(np => {
5580 const g = doGenerateOne(owner, np.pname);
5581 r[np.name] = config => {
5582 const validated = asRawOrDie$1('Part: ' + np.name + ' in ' + owner, objOf(np.schema), config);
5593 const doGenerateOne = (owner, pname) => ({
5594 uiType: placeholder(),
5598 const generateOne$1 = (owner, pname, config) => ({
5599 uiType: placeholder(),
5605 const schemas = parts => bind$3(parts, part => part.fold(Optional.none, Optional.some, Optional.none, Optional.none).map(data => requiredObjOf(data.name, data.schema.concat([snapshot(original())]))).toArray());
5606 const names = parts => map$2(parts, name$2);
5607 const substitutes = (owner, detail, parts) => subs(owner, detail, parts);
5608 const components$1 = (owner, detail, internals) => substitutePlaces(Optional.some(owner), detail, detail.components, internals);
5609 const getPart = (component, detail, partKey) => {
5610 const uid = detail.partUids[partKey];
5611 return component.getSystem().getByUid(uid).toOptional();
5613 const getPartOrDie = (component, detail, partKey) => getPart(component, detail, partKey).getOrDie('Could not find part: ' + partKey);
5614 const getParts = (component, detail, partKeys) => {
5616 const uids = detail.partUids;
5617 const system = component.getSystem();
5618 each$1(partKeys, pk => {
5619 r[pk] = constant$1(system.getByUid(uids[pk]));
5623 const getAllParts = (component, detail) => {
5624 const system = component.getSystem();
5625 return map$1(detail.partUids, (pUid, _k) => constant$1(system.getByUid(pUid)));
5627 const getAllPartNames = detail => keys(detail.partUids);
5628 const getPartsOrDie = (component, detail, partKeys) => {
5630 const uids = detail.partUids;
5631 const system = component.getSystem();
5632 each$1(partKeys, pk => {
5633 r[pk] = constant$1(system.getByUid(uids[pk]).getOrDie());
5637 const defaultUids = (baseUid, partTypes) => {
5638 const partNames = names(partTypes);
5639 return wrapAll(map$2(partNames, pn => ({
5641 value: baseUid + '-' + pn
5644 const defaultUidsSchema = partTypes => field$1('partUids', 'partUids', mergeWithThunk(spec => defaultUids(spec.uid, partTypes)), anyValue());
5646 var AlloyParts = /*#__PURE__*/Object.freeze({
5648 generate: generate$3,
5649 generateOne: generateOne$1,
5652 substitutes: substitutes,
5653 components: components$1,
5654 defaultUids: defaultUids,
5655 defaultUidsSchema: defaultUidsSchema,
5656 getAllParts: getAllParts,
5657 getAllPartNames: getAllPartNames,
5659 getPartOrDie: getPartOrDie,
5661 getPartsOrDie: getPartsOrDie
5664 const base = (partSchemas, partUidsSchemas) => {
5665 const ps = partSchemas.length > 0 ? [requiredObjOf('parts', partSchemas)] : [];
5668 defaulted('dom', {}),
5669 defaulted('components', []),
5670 snapshot('originalSpec'),
5671 defaulted('debug.sketcher', {})
5672 ]).concat(partUidsSchemas);
5674 const asRawOrDie = (label, schema, spec, partSchemas, partUidsSchemas) => {
5675 const baseS = base(partSchemas, partUidsSchemas);
5676 return asRawOrDie$1(label + ' [SpecSchema]', objOfOnly(baseS.concat(schema)), spec);
5679 const single$1 = (owner, schema, factory, spec) => {
5680 const specWithUid = supplyUid(spec);
5681 const detail = asRawOrDie(owner, schema, specWithUid, [], []);
5682 return factory(detail, specWithUid);
5684 const composite$1 = (owner, schema, partTypes, factory, spec) => {
5685 const specWithUid = supplyUid(spec);
5686 const partSchemas = schemas(partTypes);
5687 const partUidsSchema = defaultUidsSchema(partTypes);
5688 const detail = asRawOrDie(owner, schema, specWithUid, partSchemas, [partUidsSchema]);
5689 const subs = substitutes(owner, detail, partTypes);
5690 const components = components$1(owner, detail, subs.internals());
5691 return factory(detail, components, specWithUid, subs.externals());
5693 const hasUid = spec => has$2(spec, 'uid');
5694 const supplyUid = spec => {
5695 return hasUid(spec) ? spec : {
5697 uid: generate$5('uid')
5701 const isSketchSpec = spec => {
5702 return spec.uid !== undefined;
5704 const singleSchema = objOfOnly([
5706 required$1('factory'),
5707 required$1('configFields'),
5708 defaulted('apis', {}),
5709 defaulted('extraApis', {})
5711 const compositeSchema = objOfOnly([
5713 required$1('factory'),
5714 required$1('configFields'),
5715 required$1('partFields'),
5716 defaulted('apis', {}),
5717 defaulted('extraApis', {})
5719 const single = rawConfig => {
5720 const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, singleSchema, rawConfig);
5721 const sketch = spec => single$1(config.name, config.configFields, config.factory, spec);
5722 const apis = map$1(config.apis, makeApi);
5723 const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
5726 configFields: config.configFields,
5732 const composite = rawConfig => {
5733 const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, compositeSchema, rawConfig);
5734 const sketch = spec => composite$1(config.name, config.configFields, config.partFields, config.factory, spec);
5735 const parts = generate$3(config.name, config.partFields);
5736 const apis = map$1(config.apis, makeApi);
5737 const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
5740 partFields: config.partFields,
5741 configFields: config.configFields,
5749 const inside = target => isTag('input')(target) && get$f(target, 'type') !== 'radio' || isTag('textarea')(target);
5751 const getCurrent = (component, composeConfig, _composeState) => composeConfig.find(component);
5753 var ComposeApis = /*#__PURE__*/Object.freeze({
5755 getCurrent: getCurrent
5758 const ComposeSchema = [required$1('find')];
5760 const Composing = create$4({
5761 fields: ComposeSchema,
5766 const nativeDisabled = [
5772 const onLoad$1 = (component, disableConfig, disableState) => {
5773 const f = disableConfig.disabled() ? disable : enable;
5774 f(component, disableConfig);
5776 const hasNative = (component, config) => config.useNative === true && contains$2(nativeDisabled, name$3(component.element));
5777 const nativeIsDisabled = component => has$1(component.element, 'disabled');
5778 const nativeDisable = component => {
5779 set$9(component.element, 'disabled', 'disabled');
5781 const nativeEnable = component => {
5782 remove$7(component.element, 'disabled');
5784 const ariaIsDisabled = component => get$f(component.element, 'aria-disabled') === 'true';
5785 const ariaDisable = component => {
5786 set$9(component.element, 'aria-disabled', 'true');
5788 const ariaEnable = component => {
5789 set$9(component.element, 'aria-disabled', 'false');
5791 const disable = (component, disableConfig, _disableState) => {
5792 disableConfig.disableClass.each(disableClass => {
5793 add$2(component.element, disableClass);
5795 const f = hasNative(component, disableConfig) ? nativeDisable : ariaDisable;
5797 disableConfig.onDisabled(component);
5799 const enable = (component, disableConfig, _disableState) => {
5800 disableConfig.disableClass.each(disableClass => {
5801 remove$2(component.element, disableClass);
5803 const f = hasNative(component, disableConfig) ? nativeEnable : ariaEnable;
5805 disableConfig.onEnabled(component);
5807 const isDisabled = (component, disableConfig) => hasNative(component, disableConfig) ? nativeIsDisabled(component) : ariaIsDisabled(component);
5808 const set$4 = (component, disableConfig, disableState, disabled) => {
5809 const f = disabled ? disable : enable;
5810 f(component, disableConfig);
5813 var DisableApis = /*#__PURE__*/Object.freeze({
5817 isDisabled: isDisabled,
5822 const exhibit$5 = (base, disableConfig) => nu$7({ classes: disableConfig.disabled() ? disableConfig.disableClass.toArray() : [] });
5823 const events$e = (disableConfig, disableState) => derive$2([
5824 abort(execute$5(), (component, _simulatedEvent) => isDisabled(component, disableConfig)),
5825 loadEvent(disableConfig, disableState, onLoad$1)
5828 var ActiveDisable = /*#__PURE__*/Object.freeze({
5834 var DisableSchema = [
5835 defaultedFunction('disabled', never),
5836 defaulted('useNative', true),
5837 option$3('disableClass'),
5838 onHandler('onDisabled'),
5839 onHandler('onEnabled')
5842 const Disabling = create$4({
5843 fields: DisableSchema,
5845 active: ActiveDisable,
5849 const dehighlightAllExcept = (component, hConfig, hState, skip) => {
5850 const highlighted = descendants(component.element, '.' + hConfig.highlightClass);
5851 each$1(highlighted, h => {
5852 const shouldSkip = exists(skip, skipComp => eq(skipComp.element, h));
5854 remove$2(h, hConfig.highlightClass);
5855 component.getSystem().getByDom(h).each(target => {
5856 hConfig.onDehighlight(component, target);
5857 emit(target, dehighlight$1());
5862 const dehighlightAll = (component, hConfig, hState) => dehighlightAllExcept(component, hConfig, hState, []);
5863 const dehighlight = (component, hConfig, hState, target) => {
5864 if (isHighlighted(component, hConfig, hState, target)) {
5865 remove$2(target.element, hConfig.highlightClass);
5866 hConfig.onDehighlight(component, target);
5867 emit(target, dehighlight$1());
5870 const highlight = (component, hConfig, hState, target) => {
5871 dehighlightAllExcept(component, hConfig, hState, [target]);
5872 if (!isHighlighted(component, hConfig, hState, target)) {
5873 add$2(target.element, hConfig.highlightClass);
5874 hConfig.onHighlight(component, target);
5875 emit(target, highlight$1());
5878 const highlightFirst = (component, hConfig, hState) => {
5879 getFirst(component, hConfig).each(firstComp => {
5880 highlight(component, hConfig, hState, firstComp);
5883 const highlightLast = (component, hConfig, hState) => {
5884 getLast(component, hConfig).each(lastComp => {
5885 highlight(component, hConfig, hState, lastComp);
5888 const highlightAt = (component, hConfig, hState, index) => {
5889 getByIndex(component, hConfig, hState, index).fold(err => {
5892 highlight(component, hConfig, hState, firstComp);
5895 const highlightBy = (component, hConfig, hState, predicate) => {
5896 const candidates = getCandidates(component, hConfig);
5897 const targetComp = find$5(candidates, predicate);
5898 targetComp.each(c => {
5899 highlight(component, hConfig, hState, c);
5902 const isHighlighted = (component, hConfig, hState, queryTarget) => has(queryTarget.element, hConfig.highlightClass);
5903 const getHighlighted = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.highlightClass).bind(e => component.getSystem().getByDom(e).toOptional());
5904 const getByIndex = (component, hConfig, hState, index) => {
5905 const items = descendants(component.element, '.' + hConfig.itemClass);
5906 return Optional.from(items[index]).fold(() => Result.error(new Error('No element found with index ' + index)), component.getSystem().getByDom);
5908 const getFirst = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.itemClass).bind(e => component.getSystem().getByDom(e).toOptional());
5909 const getLast = (component, hConfig, _hState) => {
5910 const items = descendants(component.element, '.' + hConfig.itemClass);
5911 const last = items.length > 0 ? Optional.some(items[items.length - 1]) : Optional.none();
5912 return last.bind(c => component.getSystem().getByDom(c).toOptional());
5914 const getDelta$2 = (component, hConfig, hState, delta) => {
5915 const items = descendants(component.element, '.' + hConfig.itemClass);
5916 const current = findIndex$1(items, item => has(item, hConfig.highlightClass));
5917 return current.bind(selected => {
5918 const dest = cycleBy(selected, delta, 0, items.length - 1);
5919 return component.getSystem().getByDom(items[dest]).toOptional();
5922 const getPrevious = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, -1);
5923 const getNext = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, +1);
5924 const getCandidates = (component, hConfig, _hState) => {
5925 const items = descendants(component.element, '.' + hConfig.itemClass);
5926 return cat(map$2(items, i => component.getSystem().getByDom(i).toOptional()));
5929 var HighlightApis = /*#__PURE__*/Object.freeze({
5931 dehighlightAll: dehighlightAll,
5932 dehighlight: dehighlight,
5933 highlight: highlight,
5934 highlightFirst: highlightFirst,
5935 highlightLast: highlightLast,
5936 highlightAt: highlightAt,
5937 highlightBy: highlightBy,
5938 isHighlighted: isHighlighted,
5939 getHighlighted: getHighlighted,
5942 getPrevious: getPrevious,
5944 getCandidates: getCandidates
5947 var HighlightSchema = [
5948 required$1('highlightClass'),
5949 required$1('itemClass'),
5950 onHandler('onHighlight'),
5951 onHandler('onDehighlight')
5954 const Highlighting = create$4({
5955 fields: HighlightSchema,
5956 name: 'highlighting',
5960 const BACKSPACE = [8];
5963 const ESCAPE = [27];
5970 const cyclePrev = (values, index, predicate) => {
5971 const before = reverse(values.slice(0, index));
5972 const after = reverse(values.slice(index + 1));
5973 return find$5(before.concat(after), predicate);
5975 const tryPrev = (values, index, predicate) => {
5976 const before = reverse(values.slice(0, index));
5977 return find$5(before, predicate);
5979 const cycleNext = (values, index, predicate) => {
5980 const before = values.slice(0, index);
5981 const after = values.slice(index + 1);
5982 return find$5(after.concat(before), predicate);
5984 const tryNext = (values, index, predicate) => {
5985 const after = values.slice(index + 1);
5986 return find$5(after, predicate);
5989 const inSet = keys => event => {
5990 const raw = event.raw;
5991 return contains$2(keys, raw.which);
5993 const and = preds => event => forall(preds, pred => pred(event));
5994 const isShift = event => {
5995 const raw = event.raw;
5996 return raw.shiftKey === true;
5998 const isControl = event => {
5999 const raw = event.raw;
6000 return raw.ctrlKey === true;
6002 const isNotShift = not(isShift);
6004 const rule = (matches, action) => ({
6006 classification: action
6008 const choose = (transitions, event) => {
6009 const transition = find$5(transitions, t => t.matches(event));
6010 return transition.map(t => t.classification);
6013 const reportFocusShifting = (component, prevFocus, newFocus) => {
6014 const noChange = prevFocus.exists(p => newFocus.exists(n => eq(n, p)));
6016 emitWith(component, focusShifted(), {
6022 const dom$2 = () => {
6023 const get = component => search(component.element);
6024 const set = (component, focusee) => {
6025 const prevFocus = get(component);
6026 component.getSystem().triggerFocus(focusee, component.element);
6027 const newFocus = get(component);
6028 reportFocusShifting(component, prevFocus, newFocus);
6035 const highlights = () => {
6036 const get = component => Highlighting.getHighlighted(component).map(item => item.element);
6037 const set = (component, element) => {
6038 const prevFocus = get(component);
6039 component.getSystem().getByDom(element).fold(noop, item => {
6040 Highlighting.highlight(component, item);
6042 const newFocus = get(component);
6043 reportFocusShifting(component, prevFocus, newFocus);
6051 var FocusInsideModes;
6052 (function (FocusInsideModes) {
6053 FocusInsideModes['OnFocusMode'] = 'onFocus';
6054 FocusInsideModes['OnEnterOrSpaceMode'] = 'onEnterOrSpace';
6055 FocusInsideModes['OnApiMode'] = 'onApi';
6056 }(FocusInsideModes || (FocusInsideModes = {})));
6058 const typical = (infoSchema, stateInit, getKeydownRules, getKeyupRules, optFocusIn) => {
6059 const schema = () => infoSchema.concat([
6060 defaulted('focusManager', dom$2()),
6061 defaultedOf('focusInside', 'onFocus', valueOf(val => contains$2([
6065 ], val) ? Result.value(val) : Result.error('Invalid value for focusInside'))),
6066 output$1('handler', me),
6067 output$1('state', stateInit),
6068 output$1('sendFocusIn', optFocusIn)
6070 const processKey = (component, simulatedEvent, getRules, keyingConfig, keyingState) => {
6071 const rules = getRules(component, simulatedEvent, keyingConfig, keyingState);
6072 return choose(rules, simulatedEvent.event).bind(rule => rule(component, simulatedEvent, keyingConfig, keyingState));
6074 const toEvents = (keyingConfig, keyingState) => {
6075 const onFocusHandler = keyingConfig.focusInside !== FocusInsideModes.OnFocusMode ? Optional.none() : optFocusIn(keyingConfig).map(focusIn => run$1(focus$4(), (component, simulatedEvent) => {
6076 focusIn(component, keyingConfig, keyingState);
6077 simulatedEvent.stop();
6079 const tryGoInsideComponent = (component, simulatedEvent) => {
6080 const isEnterOrSpace = inSet(SPACE.concat(ENTER))(simulatedEvent.event);
6081 if (keyingConfig.focusInside === FocusInsideModes.OnEnterOrSpaceMode && isEnterOrSpace && isSource(component, simulatedEvent)) {
6082 optFocusIn(keyingConfig).each(focusIn => {
6083 focusIn(component, keyingConfig, keyingState);
6084 simulatedEvent.stop();
6088 const keyboardEvents = [
6089 run$1(keydown(), (component, simulatedEvent) => {
6090 processKey(component, simulatedEvent, getKeydownRules, keyingConfig, keyingState).fold(() => {
6091 tryGoInsideComponent(component, simulatedEvent);
6093 simulatedEvent.stop();
6096 run$1(keyup(), (component, simulatedEvent) => {
6097 processKey(component, simulatedEvent, getKeyupRules, keyingConfig, keyingState).each(_ => {
6098 simulatedEvent.stop();
6102 return derive$2(onFocusHandler.toArray().concat(keyboardEvents));
6112 const create$2 = cyclicField => {
6114 option$3('onEscape'),
6115 option$3('onEnter'),
6116 defaulted('selector', '[data-alloy-tabstop="true"]:not(:disabled)'),
6117 defaulted('firstTabstop', 0),
6118 defaulted('useTabstopAt', always),
6119 option$3('visibilitySelector')
6120 ].concat([cyclicField]);
6121 const isVisible = (tabbingConfig, element) => {
6122 const target = tabbingConfig.visibilitySelector.bind(sel => closest$1(element, sel)).getOr(element);
6123 return get$d(target) > 0;
6125 const findInitial = (component, tabbingConfig) => {
6126 const tabstops = descendants(component.element, tabbingConfig.selector);
6127 const visibles = filter$2(tabstops, elem => isVisible(tabbingConfig, elem));
6128 return Optional.from(visibles[tabbingConfig.firstTabstop]);
6130 const findCurrent = (component, tabbingConfig) => tabbingConfig.focusManager.get(component).bind(elem => closest$1(elem, tabbingConfig.selector));
6131 const isTabstop = (tabbingConfig, element) => isVisible(tabbingConfig, element) && tabbingConfig.useTabstopAt(element);
6132 const focusIn = (component, tabbingConfig, _tabbingState) => {
6133 findInitial(component, tabbingConfig).each(target => {
6134 tabbingConfig.focusManager.set(component, target);
6137 const goFromTabstop = (component, tabstops, stopIndex, tabbingConfig, cycle) => cycle(tabstops, stopIndex, elem => isTabstop(tabbingConfig, elem)).fold(() => tabbingConfig.cyclic ? Optional.some(true) : Optional.none(), target => {
6138 tabbingConfig.focusManager.set(component, target);
6139 return Optional.some(true);
6141 const go = (component, _simulatedEvent, tabbingConfig, cycle) => {
6142 const tabstops = descendants(component.element, tabbingConfig.selector);
6143 return findCurrent(component, tabbingConfig).bind(tabstop => {
6144 const optStopIndex = findIndex$1(tabstops, curry(eq, tabstop));
6145 return optStopIndex.bind(stopIndex => goFromTabstop(component, tabstops, stopIndex, tabbingConfig, cycle));
6148 const goBackwards = (component, simulatedEvent, tabbingConfig) => {
6149 const navigate = tabbingConfig.cyclic ? cyclePrev : tryPrev;
6150 return go(component, simulatedEvent, tabbingConfig, navigate);
6152 const goForwards = (component, simulatedEvent, tabbingConfig) => {
6153 const navigate = tabbingConfig.cyclic ? cycleNext : tryNext;
6154 return go(component, simulatedEvent, tabbingConfig, navigate);
6156 const execute = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEnter.bind(f => f(component, simulatedEvent));
6157 const exit = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEscape.bind(f => f(component, simulatedEvent));
6158 const getKeydownRules = constant$1([
6163 rule(inSet(TAB), goForwards),
6169 const getKeyupRules = constant$1([rule(inSet(ESCAPE), exit)]);
6170 return typical(schema, NoState.init, getKeydownRules, getKeyupRules, () => Optional.some(focusIn));
6173 var AcyclicType = create$2(customField('cyclic', never));
6175 var CyclicType = create$2(customField('cyclic', always));
6177 const doDefaultExecute = (component, _simulatedEvent, focused) => {
6178 dispatch(component, focused, execute$5());
6179 return Optional.some(true);
6181 const defaultExecute = (component, simulatedEvent, focused) => {
6182 const isComplex = inside(focused) && inSet(SPACE)(simulatedEvent.event);
6183 return isComplex ? Optional.none() : doDefaultExecute(component, simulatedEvent, focused);
6185 const stopEventForFirefox = (_component, _simulatedEvent) => Optional.some(true);
6188 defaulted('execute', defaultExecute),
6189 defaulted('useSpace', false),
6190 defaulted('useEnter', true),
6191 defaulted('useControlEnter', false),
6192 defaulted('useDown', false)
6194 const execute$4 = (component, simulatedEvent, executeConfig) => executeConfig.execute(component, simulatedEvent, component.element);
6195 const getKeydownRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => {
6196 const spaceExec = executeConfig.useSpace && !inside(component.element) ? SPACE : [];
6197 const enterExec = executeConfig.useEnter ? ENTER : [];
6198 const downExec = executeConfig.useDown ? DOWN : [];
6199 const execKeys = spaceExec.concat(enterExec).concat(downExec);
6200 return [rule(inSet(execKeys), execute$4)].concat(executeConfig.useControlEnter ? [rule(and([
6203 ]), execute$4)] : []);
6205 const getKeyupRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => executeConfig.useSpace && !inside(component.element) ? [rule(inSet(SPACE), stopEventForFirefox)] : [];
6206 var ExecutionType = typical(schema$v, NoState.init, getKeydownRules$5, getKeyupRules$5, () => Optional.none());
6208 const flatgrid$1 = () => {
6209 const dimensions = value$2();
6210 const setGridSize = (numRows, numColumns) => {
6216 const getNumRows = () => dimensions.get().map(d => d.numRows);
6217 const getNumColumns = () => dimensions.get().map(d => d.numColumns);
6219 readState: () => dimensions.get().map(d => ({
6220 numRows: String(d.numRows),
6221 numColumns: String(d.numColumns)
6231 const init$d = spec => spec.state(spec);
6233 var KeyingState = /*#__PURE__*/Object.freeze({
6235 flatgrid: flatgrid$1,
6239 const useH = movement => (component, simulatedEvent, config, state) => {
6240 const move = movement(component.element);
6241 return use(move, component, simulatedEvent, config, state);
6243 const west$1 = (moveLeft, moveRight) => {
6244 const movement = onDirection(moveLeft, moveRight);
6245 return useH(movement);
6247 const east$1 = (moveLeft, moveRight) => {
6248 const movement = onDirection(moveRight, moveLeft);
6249 return useH(movement);
6251 const useV = move => (component, simulatedEvent, config, state) => use(move, component, simulatedEvent, config, state);
6252 const use = (move, component, simulatedEvent, config, state) => {
6253 const outcome = config.focusManager.get(component).bind(focused => move(component.element, focused, config, state));
6254 return outcome.map(newFocus => {
6255 config.focusManager.set(component, newFocus);
6259 const north$1 = useV;
6260 const south$1 = useV;
6261 const move$1 = useV;
6263 const isHidden$1 = dom => dom.offsetWidth <= 0 && dom.offsetHeight <= 0;
6264 const isVisible = element => !isHidden$1(element.dom);
6266 const locate = (candidates, predicate) => findIndex$1(candidates, predicate).map(index => ({
6271 const locateVisible = (container, current, selector) => {
6272 const predicate = x => eq(x, current);
6273 const candidates = descendants(container, selector);
6274 const visible = filter$2(candidates, isVisible);
6275 return locate(visible, predicate);
6277 const findIndex = (elements, target) => findIndex$1(elements, elem => eq(target, elem));
6279 const withGrid = (values, index, numCols, f) => {
6280 const oldRow = Math.floor(index / numCols);
6281 const oldColumn = index % numCols;
6282 return f(oldRow, oldColumn).bind(address => {
6283 const newIndex = address.row * numCols + address.column;
6284 return newIndex >= 0 && newIndex < values.length ? Optional.some(values[newIndex]) : Optional.none();
6287 const cycleHorizontal$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
6288 const onLastRow = oldRow === numRows - 1;
6289 const colsInRow = onLastRow ? values.length - oldRow * numCols : numCols;
6290 const newColumn = cycleBy(oldColumn, delta, 0, colsInRow - 1);
6291 return Optional.some({
6296 const cycleVertical$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
6297 const newRow = cycleBy(oldRow, delta, 0, numRows - 1);
6298 const onLastRow = newRow === numRows - 1;
6299 const colsInRow = onLastRow ? values.length - newRow * numCols : numCols;
6300 const newCol = clamp(oldColumn, 0, colsInRow - 1);
6301 return Optional.some({
6306 const cycleRight$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, +1);
6307 const cycleLeft$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, -1);
6308 const cycleUp$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, -1);
6309 const cycleDown$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, +1);
6312 required$1('selector'),
6313 defaulted('execute', defaultExecute),
6314 onKeyboardHandler('onEscape'),
6315 defaulted('captureTab', false),
6318 const focusIn$3 = (component, gridConfig, _gridState) => {
6319 descendant(component.element, gridConfig.selector).each(first => {
6320 gridConfig.focusManager.set(component, first);
6323 const findCurrent$1 = (component, gridConfig) => gridConfig.focusManager.get(component).bind(elem => closest$1(elem, gridConfig.selector));
6324 const execute$3 = (component, simulatedEvent, gridConfig, _gridState) => findCurrent$1(component, gridConfig).bind(focused => gridConfig.execute(component, simulatedEvent, focused));
6325 const doMove$2 = cycle => (element, focused, gridConfig, gridState) => locateVisible(element, focused, gridConfig.selector).bind(identified => cycle(identified.candidates, identified.index, gridState.getNumRows().getOr(gridConfig.initSize.numRows), gridState.getNumColumns().getOr(gridConfig.initSize.numColumns)));
6326 const handleTab = (_component, _simulatedEvent, gridConfig) => gridConfig.captureTab ? Optional.some(true) : Optional.none();
6327 const doEscape$1 = (component, simulatedEvent, gridConfig) => gridConfig.onEscape(component, simulatedEvent);
6328 const moveLeft$3 = doMove$2(cycleLeft$1);
6329 const moveRight$3 = doMove$2(cycleRight$1);
6330 const moveNorth$1 = doMove$2(cycleUp$1);
6331 const moveSouth$1 = doMove$2(cycleDown$1);
6332 const getKeydownRules$4 = constant$1([
6333 rule(inSet(LEFT), west$1(moveLeft$3, moveRight$3)),
6334 rule(inSet(RIGHT), east$1(moveLeft$3, moveRight$3)),
6335 rule(inSet(UP), north$1(moveNorth$1)),
6336 rule(inSet(DOWN), south$1(moveSouth$1)),
6345 rule(inSet(SPACE.concat(ENTER)), execute$3)
6347 const getKeyupRules$4 = constant$1([
6348 rule(inSet(ESCAPE), doEscape$1),
6349 rule(inSet(SPACE), stopEventForFirefox)
6351 var FlatgridType = typical(schema$u, flatgrid$1, getKeydownRules$4, getKeyupRules$4, () => Optional.some(focusIn$3));
6353 const horizontal = (container, selector, current, delta) => {
6354 const isDisabledButton = candidate => name$3(candidate) === 'button' && get$f(candidate, 'disabled') === 'disabled';
6355 const tryCycle = (initial, index, candidates) => {
6356 const newIndex = cycleBy(index, delta, 0, candidates.length - 1);
6357 if (newIndex === initial) {
6358 return Optional.none();
6360 return isDisabledButton(candidates[newIndex]) ? tryCycle(initial, newIndex, candidates) : Optional.from(candidates[newIndex]);
6363 return locateVisible(container, current, selector).bind(identified => {
6364 const index = identified.index;
6365 const candidates = identified.candidates;
6366 return tryCycle(index, index, candidates);
6371 required$1('selector'),
6372 defaulted('getInitial', Optional.none),
6373 defaulted('execute', defaultExecute),
6374 onKeyboardHandler('onEscape'),
6375 defaulted('executeOnMove', false),
6376 defaulted('allowVertical', true)
6378 const findCurrent = (component, flowConfig) => flowConfig.focusManager.get(component).bind(elem => closest$1(elem, flowConfig.selector));
6379 const execute$2 = (component, simulatedEvent, flowConfig) => findCurrent(component, flowConfig).bind(focused => flowConfig.execute(component, simulatedEvent, focused));
6380 const focusIn$2 = (component, flowConfig, _state) => {
6381 flowConfig.getInitial(component).orThunk(() => descendant(component.element, flowConfig.selector)).each(first => {
6382 flowConfig.focusManager.set(component, first);
6385 const moveLeft$2 = (element, focused, info) => horizontal(element, info.selector, focused, -1);
6386 const moveRight$2 = (element, focused, info) => horizontal(element, info.selector, focused, +1);
6387 const doMove$1 = movement => (component, simulatedEvent, flowConfig, flowState) => movement(component, simulatedEvent, flowConfig, flowState).bind(() => flowConfig.executeOnMove ? execute$2(component, simulatedEvent, flowConfig) : Optional.some(true));
6388 const doEscape = (component, simulatedEvent, flowConfig) => flowConfig.onEscape(component, simulatedEvent);
6389 const getKeydownRules$3 = (_component, _se, flowConfig, _flowState) => {
6390 const westMovers = LEFT.concat(flowConfig.allowVertical ? UP : []);
6391 const eastMovers = RIGHT.concat(flowConfig.allowVertical ? DOWN : []);
6393 rule(inSet(westMovers), doMove$1(west$1(moveLeft$2, moveRight$2))),
6394 rule(inSet(eastMovers), doMove$1(east$1(moveLeft$2, moveRight$2))),
6395 rule(inSet(ENTER), execute$2),
6396 rule(inSet(SPACE), execute$2)
6399 const getKeyupRules$3 = constant$1([
6400 rule(inSet(SPACE), stopEventForFirefox),
6401 rule(inSet(ESCAPE), doEscape)
6403 var FlowType = typical(schema$t, NoState.init, getKeydownRules$3, getKeyupRules$3, () => Optional.some(focusIn$2));
6405 const toCell = (matrix, rowIndex, columnIndex) => Optional.from(matrix[rowIndex]).bind(row => Optional.from(row[columnIndex]).map(cell => ({
6410 const cycleHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
6411 const row = matrix[rowIndex];
6412 const colsInRow = row.length;
6413 const newColIndex = cycleBy(startCol, deltaCol, 0, colsInRow - 1);
6414 return toCell(matrix, rowIndex, newColIndex);
6416 const cycleVertical = (matrix, colIndex, startRow, deltaRow) => {
6417 const nextRowIndex = cycleBy(startRow, deltaRow, 0, matrix.length - 1);
6418 const colsInNextRow = matrix[nextRowIndex].length;
6419 const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
6420 return toCell(matrix, nextRowIndex, nextColIndex);
6422 const moveHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
6423 const row = matrix[rowIndex];
6424 const colsInRow = row.length;
6425 const newColIndex = clamp(startCol + deltaCol, 0, colsInRow - 1);
6426 return toCell(matrix, rowIndex, newColIndex);
6428 const moveVertical = (matrix, colIndex, startRow, deltaRow) => {
6429 const nextRowIndex = clamp(startRow + deltaRow, 0, matrix.length - 1);
6430 const colsInNextRow = matrix[nextRowIndex].length;
6431 const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
6432 return toCell(matrix, nextRowIndex, nextColIndex);
6434 const cycleRight = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, +1);
6435 const cycleLeft = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, -1);
6436 const cycleUp = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, -1);
6437 const cycleDown = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, +1);
6438 const moveLeft$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, -1);
6439 const moveRight$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, +1);
6440 const moveUp$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, -1);
6441 const moveDown$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, +1);
6444 requiredObjOf('selectors', [
6448 defaulted('cycles', true),
6449 defaulted('previousSelector', Optional.none),
6450 defaulted('execute', defaultExecute)
6452 const focusIn$1 = (component, matrixConfig, _state) => {
6453 const focused = matrixConfig.previousSelector(component).orThunk(() => {
6454 const selectors = matrixConfig.selectors;
6455 return descendant(component.element, selectors.cell);
6457 focused.each(cell => {
6458 matrixConfig.focusManager.set(component, cell);
6461 const execute$1 = (component, simulatedEvent, matrixConfig) => search(component.element).bind(focused => matrixConfig.execute(component, simulatedEvent, focused));
6462 const toMatrix = (rows, matrixConfig) => map$2(rows, row => descendants(row, matrixConfig.selectors.cell));
6463 const doMove = (ifCycle, ifMove) => (element, focused, matrixConfig) => {
6464 const move = matrixConfig.cycles ? ifCycle : ifMove;
6465 return closest$1(focused, matrixConfig.selectors.row).bind(inRow => {
6466 const cellsInRow = descendants(inRow, matrixConfig.selectors.cell);
6467 return findIndex(cellsInRow, focused).bind(colIndex => {
6468 const allRows = descendants(element, matrixConfig.selectors.row);
6469 return findIndex(allRows, inRow).bind(rowIndex => {
6470 const matrix = toMatrix(allRows, matrixConfig);
6471 return move(matrix, rowIndex, colIndex).map(next => next.cell);
6476 const moveLeft = doMove(cycleLeft, moveLeft$1);
6477 const moveRight = doMove(cycleRight, moveRight$1);
6478 const moveNorth = doMove(cycleUp, moveUp$1);
6479 const moveSouth = doMove(cycleDown, moveDown$1);
6480 const getKeydownRules$2 = constant$1([
6481 rule(inSet(LEFT), west$1(moveLeft, moveRight)),
6482 rule(inSet(RIGHT), east$1(moveLeft, moveRight)),
6483 rule(inSet(UP), north$1(moveNorth)),
6484 rule(inSet(DOWN), south$1(moveSouth)),
6485 rule(inSet(SPACE.concat(ENTER)), execute$1)
6487 const getKeyupRules$2 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
6488 var MatrixType = typical(schema$s, NoState.init, getKeydownRules$2, getKeyupRules$2, () => Optional.some(focusIn$1));
6491 required$1('selector'),
6492 defaulted('execute', defaultExecute),
6493 defaulted('moveOnTab', false)
6495 const execute = (component, simulatedEvent, menuConfig) => menuConfig.focusManager.get(component).bind(focused => menuConfig.execute(component, simulatedEvent, focused));
6496 const focusIn = (component, menuConfig, _state) => {
6497 descendant(component.element, menuConfig.selector).each(first => {
6498 menuConfig.focusManager.set(component, first);
6501 const moveUp = (element, focused, info) => horizontal(element, info.selector, focused, -1);
6502 const moveDown = (element, focused, info) => horizontal(element, info.selector, focused, +1);
6503 const fireShiftTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveUp)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
6504 const fireTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveDown)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
6505 const getKeydownRules$1 = constant$1([
6506 rule(inSet(UP), move$1(moveUp)),
6507 rule(inSet(DOWN), move$1(moveDown)),
6516 rule(inSet(ENTER), execute),
6517 rule(inSet(SPACE), execute)
6519 const getKeyupRules$1 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
6520 var MenuType = typical(schema$r, NoState.init, getKeydownRules$1, getKeyupRules$1, () => Optional.some(focusIn));
6523 onKeyboardHandler('onSpace'),
6524 onKeyboardHandler('onEnter'),
6525 onKeyboardHandler('onShiftEnter'),
6526 onKeyboardHandler('onLeft'),
6527 onKeyboardHandler('onRight'),
6528 onKeyboardHandler('onTab'),
6529 onKeyboardHandler('onShiftTab'),
6530 onKeyboardHandler('onUp'),
6531 onKeyboardHandler('onDown'),
6532 onKeyboardHandler('onEscape'),
6533 defaulted('stopSpaceKeyup', false),
6536 const getKeydownRules = (component, simulatedEvent, specialInfo) => [
6537 rule(inSet(SPACE), specialInfo.onSpace),
6541 ]), specialInfo.onEnter),
6545 ]), specialInfo.onShiftEnter),
6549 ]), specialInfo.onShiftTab),
6553 ]), specialInfo.onTab),
6554 rule(inSet(UP), specialInfo.onUp),
6555 rule(inSet(DOWN), specialInfo.onDown),
6556 rule(inSet(LEFT), specialInfo.onLeft),
6557 rule(inSet(RIGHT), specialInfo.onRight),
6558 rule(inSet(SPACE), specialInfo.onSpace)
6560 const getKeyupRules = (component, simulatedEvent, specialInfo) => [
6561 ...specialInfo.stopSpaceKeyup ? [rule(inSet(SPACE), stopEventForFirefox)] : [],
6562 rule(inSet(ESCAPE), specialInfo.onEscape)
6564 var SpecialType = typical(schema$q, NoState.init, getKeydownRules, getKeyupRules, specialInfo => specialInfo.focusIn);
6566 const acyclic = AcyclicType.schema();
6567 const cyclic = CyclicType.schema();
6568 const flow = FlowType.schema();
6569 const flatgrid = FlatgridType.schema();
6570 const matrix = MatrixType.schema();
6571 const execution = ExecutionType.schema();
6572 const menu = MenuType.schema();
6573 const special = SpecialType.schema();
6575 var KeyboardBranches = /*#__PURE__*/Object.freeze({
6582 execution: execution,
6587 const isFlatgridState = keyState => hasNonNullableKey(keyState, 'setGridSize');
6588 const Keying = createModes({
6590 branches: KeyboardBranches,
6593 events: (keyingConfig, keyingState) => {
6594 const handler = keyingConfig.handler;
6595 return handler.toEvents(keyingConfig, keyingState);
6599 focusIn: (component, keyConfig, keyState) => {
6600 keyConfig.sendFocusIn(keyConfig).fold(() => {
6601 component.getSystem().triggerFocus(component.element, component.element);
6603 sendFocusIn(component, keyConfig, keyState);
6606 setGridSize: (component, keyConfig, keyState, numRows, numColumns) => {
6607 if (!isFlatgridState(keyState)) {
6608 console.error('Layout does not support setGridSize');
6610 keyState.setGridSize(numRows, numColumns);
6617 const withoutReuse = (parent, data) => {
6619 replaceChildren(parent, data, () => map$2(data, parent.getSystem().build));
6622 const withReuse = (parent, data) => {
6624 virtualReplaceChildren(parent, data, () => {
6625 return patchSpecChildren(parent.element, data, parent.getSystem().buildOrPatch);
6630 const virtualReplace = (component, replacee, replaceeIndex, childSpec) => {
6631 virtualDetach(replacee);
6632 const child = patchSpecChild(component.element, replaceeIndex, childSpec, component.getSystem().buildOrPatch);
6633 virtualAttach(component, child);
6634 component.syncComponents();
6636 const insert = (component, insertion, childSpec) => {
6637 const child = component.getSystem().build(childSpec);
6638 attachWith(component, child, insertion);
6640 const replace = (component, replacee, replaceeIndex, childSpec) => {
6642 insert(component, (p, c) => appendAt(p, c, replaceeIndex), childSpec);
6644 const set$3 = (component, replaceConfig, replaceState, data) => {
6645 const replacer = replaceConfig.reuseDom ? withReuse : withoutReuse;
6646 return replacer(component, data);
6648 const append = (component, replaceConfig, replaceState, appendee) => {
6649 insert(component, append$2, appendee);
6651 const prepend = (component, replaceConfig, replaceState, prependee) => {
6652 insert(component, prepend$1, prependee);
6654 const remove = (component, replaceConfig, replaceState, removee) => {
6655 const children = contents(component);
6656 const foundChild = find$5(children, child => eq(removee.element, child.element));
6657 foundChild.each(detach);
6659 const contents = (component, _replaceConfig) => component.components();
6660 const replaceAt = (component, replaceConfig, replaceState, replaceeIndex, replacer) => {
6661 const children = contents(component);
6662 return Optional.from(children[replaceeIndex]).map(replacee => {
6663 replacer.fold(() => detach(replacee), r => {
6664 const replacer = replaceConfig.reuseDom ? virtualReplace : replace;
6665 replacer(component, replacee, replaceeIndex, r);
6670 const replaceBy = (component, replaceConfig, replaceState, replaceePred, replacer) => {
6671 const children = contents(component);
6672 return findIndex$1(children, replaceePred).bind(replaceeIndex => replaceAt(component, replaceConfig, replaceState, replaceeIndex, replacer));
6675 var ReplaceApis = /*#__PURE__*/Object.freeze({
6680 replaceAt: replaceAt,
6681 replaceBy: replaceBy,
6686 const Replacing = create$4({
6687 fields: [defaultedBoolean('reuseDom', true)],
6692 const events$d = (name, eventHandlers) => {
6693 const events = derive$2(eventHandlers);
6695 fields: [required$1('enabled')],
6697 active: { events: constant$1(events) }
6700 const config = (name, eventHandlers) => {
6701 const me = events$d(name, eventHandlers);
6707 configAsRaw: constant$1({}),
6714 const focus$2 = (component, focusConfig) => {
6715 if (!focusConfig.ignore) {
6716 focus$3(component.element);
6717 focusConfig.onFocus(component);
6720 const blur = (component, focusConfig) => {
6721 if (!focusConfig.ignore) {
6722 blur$1(component.element);
6725 const isFocused = component => hasFocus(component.element);
6727 var FocusApis = /*#__PURE__*/Object.freeze({
6731 isFocused: isFocused
6734 const exhibit$4 = (base, focusConfig) => {
6735 const mod = focusConfig.ignore ? {} : { attributes: { tabindex: '-1' } };
6738 const events$c = focusConfig => derive$2([run$1(focus$4(), (component, simulatedEvent) => {
6739 focus$2(component, focusConfig);
6740 simulatedEvent.stop();
6741 })].concat(focusConfig.stopMousedown ? [run$1(mousedown(), (_, simulatedEvent) => {
6742 simulatedEvent.event.prevent();
6745 var ActiveFocus = /*#__PURE__*/Object.freeze({
6752 onHandler('onFocus'),
6753 defaulted('stopMousedown', false),
6754 defaulted('ignore', false)
6757 const Focusing = create$4({
6758 fields: FocusSchema,
6760 active: ActiveFocus,
6764 const SetupBehaviourCellState = initialState => {
6765 const init = () => {
6766 const cell = Cell(initialState);
6767 const get = () => cell.get();
6768 const set = newState => cell.set(newState);
6769 const clear = () => cell.set(initialState);
6770 const readState = () => cell.get();
6781 const updateAriaState = (component, toggleConfig, toggleState) => {
6782 const ariaInfo = toggleConfig.aria;
6783 ariaInfo.update(component, ariaInfo, toggleState.get());
6785 const updateClass = (component, toggleConfig, toggleState) => {
6786 toggleConfig.toggleClass.each(toggleClass => {
6787 if (toggleState.get()) {
6788 add$2(component.element, toggleClass);
6790 remove$2(component.element, toggleClass);
6794 const set$2 = (component, toggleConfig, toggleState, state) => {
6795 const initialState = toggleState.get();
6796 toggleState.set(state);
6797 updateClass(component, toggleConfig, toggleState);
6798 updateAriaState(component, toggleConfig, toggleState);
6799 if (initialState !== state) {
6800 toggleConfig.onToggled(component, state);
6803 const toggle$2 = (component, toggleConfig, toggleState) => {
6804 set$2(component, toggleConfig, toggleState, !toggleState.get());
6806 const on = (component, toggleConfig, toggleState) => {
6807 set$2(component, toggleConfig, toggleState, true);
6809 const off = (component, toggleConfig, toggleState) => {
6810 set$2(component, toggleConfig, toggleState, false);
6812 const isOn = (component, toggleConfig, toggleState) => toggleState.get();
6813 const onLoad = (component, toggleConfig, toggleState) => {
6814 set$2(component, toggleConfig, toggleState, toggleConfig.selected);
6817 var ToggleApis = /*#__PURE__*/Object.freeze({
6827 const exhibit$3 = () => nu$7({});
6828 const events$b = (toggleConfig, toggleState) => {
6829 const execute = executeEvent(toggleConfig, toggleState, toggle$2);
6830 const load = loadEvent(toggleConfig, toggleState, onLoad);
6831 return derive$2(flatten([
6832 toggleConfig.toggleOnExecute ? [execute] : [],
6837 var ActiveToggle = /*#__PURE__*/Object.freeze({
6843 const updatePressed = (component, ariaInfo, status) => {
6844 set$9(component.element, 'aria-pressed', status);
6845 if (ariaInfo.syncWithExpanded) {
6846 updateExpanded(component, ariaInfo, status);
6849 const updateSelected = (component, ariaInfo, status) => {
6850 set$9(component.element, 'aria-selected', status);
6852 const updateChecked = (component, ariaInfo, status) => {
6853 set$9(component.element, 'aria-checked', status);
6855 const updateExpanded = (component, ariaInfo, status) => {
6856 set$9(component.element, 'aria-expanded', status);
6859 var ToggleSchema = [
6860 defaulted('selected', false),
6861 option$3('toggleClass'),
6862 defaulted('toggleOnExecute', true),
6863 onHandler('onToggled'),
6864 defaultedOf('aria', { mode: 'none' }, choose$1('mode', {
6866 defaulted('syncWithExpanded', false),
6867 output$1('update', updatePressed)
6869 checked: [output$1('update', updateChecked)],
6870 expanded: [output$1('update', updateExpanded)],
6871 selected: [output$1('update', updateSelected)],
6872 none: [output$1('update', noop)]
6876 const Toggling = create$4({
6877 fields: ToggleSchema,
6879 active: ActiveToggle,
6881 state: SetupBehaviourCellState(false)
6884 const pointerEvents = () => {
6885 const onClick = (component, simulatedEvent) => {
6886 simulatedEvent.stop();
6887 emitExecute(component);
6890 run$1(click(), onClick),
6891 run$1(tap(), onClick),
6892 cutter(touchstart()),
6896 const events$a = optAction => {
6897 const executeHandler = action => runOnExecute$1((component, simulatedEvent) => {
6899 simulatedEvent.stop();
6901 return derive$2(flatten([
6902 optAction.map(executeHandler).toArray(),
6907 const hoverEvent = 'alloy.item-hover';
6908 const focusEvent = 'alloy.item-focus';
6909 const toggledEvent = 'alloy.item-toggled';
6910 const onHover = item => {
6911 if (search(item.element).isNone() || Focusing.isFocused(item)) {
6912 if (!Focusing.isFocused(item)) {
6913 Focusing.focus(item);
6915 emitWith(item, hoverEvent, { item });
6918 const onFocus$1 = item => {
6919 emitWith(item, focusEvent, { item });
6921 const onToggled = (item, state) => {
6922 emitWith(item, toggledEvent, {
6927 const hover = constant$1(hoverEvent);
6928 const focus$1 = constant$1(focusEvent);
6929 const toggled = constant$1(toggledEvent);
6931 const getItemRole = detail => detail.toggling.map(toggling => toggling.exclusive ? 'menuitemradio' : 'menuitemcheckbox').getOr('menuitem');
6932 const getTogglingSpec = tConfig => ({
6933 aria: { mode: 'checked' },
6934 ...filter$1(tConfig, (_value, name) => name !== 'exclusive'),
6935 onToggled: (component, state) => {
6936 if (isFunction(tConfig.onToggled)) {
6937 tConfig.onToggled(component, state);
6939 onToggled(component, state);
6942 const builder$2 = detail => ({
6945 ...detail.domModification,
6947 'role': getItemRole(detail),
6948 ...detail.domModification.attributes,
6949 'aria-haspopup': detail.hasSubmenu,
6950 ...detail.hasSubmenu ? { 'aria-expanded': false } : {}
6953 behaviours: SketchBehaviours.augment(detail.itemBehaviours, [
6954 detail.toggling.fold(Toggling.revoke, tConfig => Toggling.config(getTogglingSpec(tConfig))),
6956 ignore: detail.ignoreFocus,
6957 stopMousedown: detail.ignoreFocus,
6958 onFocus: component => {
6959 onFocus$1(component);
6962 Keying.config({ mode: 'execution' }),
6963 Representing.config({
6966 initialValue: detail.data
6969 config('item-type-events', [
6971 run$1(mouseover(), onHover),
6972 run$1(focusItem(), Focusing.focus)
6975 components: detail.components,
6976 eventOrder: detail.eventOrder
6980 required$1('components'),
6982 defaulted('hasSubmenu', false),
6983 option$3('toggling'),
6984 SketchBehaviours.field('itemBehaviours', [
6990 defaulted('ignoreFocus', false),
6991 defaulted('domModification', {}),
6992 output$1('builder', builder$2),
6993 defaulted('eventOrder', {})
6996 const builder$1 = detail => ({
6998 components: detail.components,
6999 events: derive$2([stopper(focusItem())])
7003 required$1('components'),
7004 output$1('builder', builder$1)
7007 const owner$2 = constant$1('item-widget');
7008 const parts$h = constant$1([required({
7010 overrides: detail => {
7012 behaviours: derive$1([Representing.config({
7015 getValue: _component => {
7025 const builder = detail => {
7026 const subs = substitutes(owner$2(), detail, parts$h());
7027 const components = components$1(owner$2(), detail, subs.internals());
7028 const focusWidget = component => getPart(component, detail, 'widget').map(widget => {
7029 Keying.focusIn(widget);
7032 const onHorizontalArrow = (component, simulatedEvent) => inside(simulatedEvent.event.target) ? Optional.none() : (() => {
7033 if (detail.autofocus) {
7034 simulatedEvent.setSource(component.element);
7035 return Optional.none();
7037 return Optional.none();
7043 domModification: detail.domModification,
7045 runOnExecute$1((component, simulatedEvent) => {
7046 focusWidget(component).each(_widget => {
7047 simulatedEvent.stop();
7050 run$1(mouseover(), onHover),
7051 run$1(focusItem(), (component, _simulatedEvent) => {
7052 if (detail.autofocus) {
7053 focusWidget(component);
7055 Focusing.focus(component);
7059 behaviours: SketchBehaviours.augment(detail.widgetBehaviours, [
7060 Representing.config({
7063 initialValue: detail.data
7067 ignore: detail.ignoreFocus,
7068 onFocus: component => {
7069 onFocus$1(component);
7074 focusIn: detail.autofocus ? component => {
7075 focusWidget(component);
7077 onLeft: onHorizontalArrow,
7078 onRight: onHorizontalArrow,
7079 onEscape: (component, simulatedEvent) => {
7080 if (!Focusing.isFocused(component) && !detail.autofocus) {
7081 Focusing.focus(component);
7082 return Optional.some(true);
7083 } else if (detail.autofocus) {
7084 simulatedEvent.setSource(component.element);
7085 return Optional.none();
7087 return Optional.none();
7097 required$1('components'),
7099 defaulted('autofocus', false),
7100 defaulted('ignoreFocus', false),
7101 SketchBehaviours.field('widgetBehaviours', [
7106 defaulted('domModification', {}),
7107 defaultUidsSchema(parts$h()),
7108 output$1('builder', builder)
7111 const itemSchema$2 = choose$1('type', {
7116 const configureGrid = (detail, movementInfo) => ({
7118 selector: '.' + detail.markers.item,
7120 numColumns: movementInfo.initSize.numColumns,
7121 numRows: movementInfo.initSize.numRows
7123 focusManager: detail.focusManager
7125 const configureMatrix = (detail, movementInfo) => ({
7128 row: movementInfo.rowSelector,
7129 cell: '.' + detail.markers.item
7131 focusManager: detail.focusManager
7133 const configureMenu = (detail, movementInfo) => ({
7135 selector: '.' + detail.markers.item,
7136 moveOnTab: movementInfo.moveOnTab,
7137 focusManager: detail.focusManager
7139 const parts$g = constant$1([group({
7142 const itemInfo = asRawOrDie$1('menu.spec item', itemSchema$2, spec);
7143 return itemInfo.builder(itemInfo);
7148 defaults: (detail, u) => {
7149 return has$2(u, 'uid') ? u : {
7151 uid: generate$5('item')
7154 overrides: (detail, u) => {
7157 ignoreFocus: detail.fakeFocus,
7158 domModification: { classes: [detail.markers.item] }
7162 const schema$m = constant$1([
7163 required$1('value'),
7164 required$1('items'),
7166 required$1('components'),
7167 defaulted('eventOrder', {}),
7168 field('menuBehaviours', [
7174 defaultedOf('movement', {
7177 }, choose$1('mode', {
7180 output$1('config', configureGrid)
7183 output$1('config', configureMatrix),
7184 required$1('rowSelector')
7187 defaulted('moveOnTab', true),
7188 output$1('config', configureMenu)
7192 defaulted('fakeFocus', false),
7193 defaulted('focusManager', dom$2()),
7194 onHandler('onHighlight'),
7195 onHandler('onDehighlight')
7198 const focus = constant$1('alloy.menu-focus');
7200 const deselectOtherRadioItems = (menu, item) => {
7201 const checkedRadioItems = descendants(menu.element, '[role="menuitemradio"][aria-checked="true"]');
7202 each$1(checkedRadioItems, ele => {
7203 if (!eq(ele, item.element)) {
7204 menu.getSystem().getByDom(ele).each(c => {
7210 const make$7 = (detail, components, _spec, _externals) => ({
7213 markers: detail.markers,
7214 behaviours: augment(detail.menuBehaviours, [
7215 Highlighting.config({
7216 highlightClass: detail.markers.selectedItem,
7217 itemClass: detail.markers.item,
7218 onHighlight: detail.onHighlight,
7219 onDehighlight: detail.onDehighlight
7221 Representing.config({
7224 initialValue: detail.value
7227 Composing.config({ find: Optional.some }),
7228 Keying.config(detail.movement.config(detail, detail.movement))
7231 run$1(focus$1(), (menu, simulatedEvent) => {
7232 const event = simulatedEvent.event;
7233 menu.getSystem().getByDom(event.target).each(item => {
7234 Highlighting.highlight(menu, item);
7235 simulatedEvent.stop();
7236 emitWith(menu, focus(), {
7242 run$1(hover(), (menu, simulatedEvent) => {
7243 const item = simulatedEvent.event.item;
7244 Highlighting.highlight(menu, item);
7246 run$1(toggled(), (menu, simulatedEvent) => {
7247 const {item, state} = simulatedEvent.event;
7248 if (state && get$f(item.element, 'role') === 'menuitemradio') {
7249 deselectOtherRadioItems(menu, item);
7254 eventOrder: detail.eventOrder,
7255 domModification: { attributes: { role: 'menu' } }
7258 const Menu = composite({
7260 configFields: schema$m(),
7261 partFields: parts$g(),
7265 const transpose$1 = obj => tupleMap(obj, (v, k) => ({
7269 const trace = (items, byItem, byMenu, finish) => get$g(byMenu, finish).bind(triggerItem => get$g(items, triggerItem).bind(triggerMenu => {
7270 const rest = trace(items, byItem, byMenu, triggerMenu);
7271 return Optional.some([triggerMenu].concat(rest));
7273 const generate$2 = (menus, expansions) => {
7275 each(menus, (menuItems, menu) => {
7276 each$1(menuItems, item => {
7280 const byItem = expansions;
7281 const byMenu = transpose$1(expansions);
7282 const menuPaths = map$1(byMenu, (_triggerItem, submenu) => [submenu].concat(trace(items, byItem, byMenu, submenu)));
7283 return map$1(items, menu => get$g(menuPaths, menu).getOr([menu]));
7286 const init$c = () => {
7287 const expansions = Cell({});
7288 const menus = Cell({});
7289 const paths = Cell({});
7290 const primary = value$2();
7291 const directory = Cell({});
7292 const clear = () => {
7298 const isClear = () => primary.get().isNone();
7299 const setMenuBuilt = (menuName, built) => {
7308 const setContents = (sPrimary, sMenus, sExpansions, dir) => {
7309 primary.set(sPrimary);
7310 expansions.set(sExpansions);
7313 const sPaths = generate$2(dir, sExpansions);
7316 const getTriggeringItem = menuValue => find$4(expansions.get(), (v, _k) => v === menuValue);
7317 const getTriggerData = (menuValue, getItemByValue, path) => getPreparedMenu(menuValue).bind(menu => getTriggeringItem(menuValue).bind(triggeringItemValue => getItemByValue(triggeringItemValue).map(triggeredItem => ({
7318 triggeredMenu: menu,
7319 triggeringItem: triggeredItem,
7320 triggeringPath: path
7322 const getTriggeringPath = (itemValue, getItemByValue) => {
7323 const extraPath = filter$2(lookupItem(itemValue).toArray(), menuValue => getPreparedMenu(menuValue).isSome());
7324 return get$g(paths.get(), itemValue).bind(path => {
7325 const revPath = reverse(extraPath.concat(path));
7326 const triggers = bind$3(revPath, (menuValue, menuIndex) => getTriggerData(menuValue, getItemByValue, revPath.slice(0, menuIndex + 1)).fold(() => is$1(primary.get(), menuValue) ? [] : [Optional.none()], data => [Optional.some(data)]));
7327 return sequence(triggers);
7330 const expand = itemValue => get$g(expansions.get(), itemValue).map(menu => {
7331 const current = get$g(paths.get(), itemValue).getOr([]);
7332 return [menu].concat(current);
7334 const collapse = itemValue => get$g(paths.get(), itemValue).bind(path => path.length > 1 ? Optional.some(path.slice(1)) : Optional.none());
7335 const refresh = itemValue => get$g(paths.get(), itemValue);
7336 const getPreparedMenu = menuValue => lookupMenu(menuValue).bind(extractPreparedMenu);
7337 const lookupMenu = menuValue => get$g(menus.get(), menuValue);
7338 const lookupItem = itemValue => get$g(expansions.get(), itemValue);
7339 const otherMenus = path => {
7340 const menuValues = directory.get();
7341 return difference(keys(menuValues), path);
7343 const getPrimary = () => primary.get().bind(getPreparedMenu);
7344 const getMenus = () => menus.get();
7361 const extractPreparedMenu = prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none();
7362 const LayeredState = {
7367 const onMenuItemHighlightedEvent = generate$6('tiered-menu-item-highlight');
7368 const onMenuItemDehighlightedEvent = generate$6('tiered-menu-item-dehighlight');
7370 var HighlightOnOpen;
7371 (function (HighlightOnOpen) {
7372 HighlightOnOpen[HighlightOnOpen['HighlightMenuAndItem'] = 0] = 'HighlightMenuAndItem';
7373 HighlightOnOpen[HighlightOnOpen['HighlightJustMenu'] = 1] = 'HighlightJustMenu';
7374 HighlightOnOpen[HighlightOnOpen['HighlightNone'] = 2] = 'HighlightNone';
7375 }(HighlightOnOpen || (HighlightOnOpen = {})));
7377 const make$6 = (detail, _rawUiSpec) => {
7378 const submenuParentItems = value$2();
7379 const buildMenus = (container, primaryName, menus) => map$1(menus, (spec, name) => {
7380 const makeSketch = () => Menu.sketch({
7383 markers: detail.markers,
7384 fakeFocus: detail.fakeFocus,
7385 onHighlight: (menuComp, itemComp) => {
7386 const highlightData = {
7390 emitWith(menuComp, onMenuItemHighlightedEvent, highlightData);
7392 onDehighlight: (menuComp, itemComp) => {
7393 const dehighlightData = {
7397 emitWith(menuComp, onMenuItemDehighlightedEvent, dehighlightData);
7399 focusManager: detail.fakeFocus ? highlights() : dom$2()
7401 return name === primaryName ? {
7403 menu: container.getSystem().build(makeSketch())
7409 const layeredState = LayeredState.init();
7410 const setup = container => {
7411 const componentMap = buildMenus(container, detail.data.primary, detail.data.menus);
7412 const directory = toDirectory();
7413 layeredState.setContents(detail.data.primary, componentMap, detail.data.expansions, directory);
7414 return layeredState.getPrimary();
7416 const getItemValue = item => Representing.getValue(item).value;
7417 const getItemByValue = (_container, menus, itemValue) => findMap(menus, menu => {
7418 if (!menu.getSystem().isConnected()) {
7419 return Optional.none();
7421 const candidates = Highlighting.getCandidates(menu);
7422 return find$5(candidates, c => getItemValue(c) === itemValue);
7424 const toDirectory = _container => map$1(detail.data.menus, (data, _menuName) => bind$3(data.items, item => item.type === 'separator' ? [] : [item.data.value]));
7425 const setActiveMenu = Highlighting.highlight;
7426 const setActiveMenuAndItem = (container, menu) => {
7427 setActiveMenu(container, menu);
7428 Highlighting.getHighlighted(menu).orThunk(() => Highlighting.getFirst(menu)).each(item => {
7429 if (detail.fakeFocus) {
7430 Highlighting.highlight(menu, item);
7432 dispatch(container, item.element, focusItem());
7436 const getMenus = (state, menuValues) => cat(map$2(menuValues, mv => state.lookupMenu(mv).bind(prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none())));
7437 const closeOthers = (container, state, path) => {
7438 const others = getMenus(state, state.otherMenus(path));
7439 each$1(others, o => {
7440 remove$1(o.element, [detail.markers.backgroundMenu]);
7441 if (!detail.stayInDom) {
7442 Replacing.remove(container, o);
7446 const getSubmenuParents = container => submenuParentItems.get().getOrThunk(() => {
7448 const items = descendants(container.element, `.${ detail.markers.item }`);
7449 const parentItems = filter$2(items, i => get$f(i, 'aria-haspopup') === 'true');
7450 each$1(parentItems, i => {
7451 container.getSystem().getByDom(i).each(itemComp => {
7452 const key = getItemValue(itemComp);
7456 submenuParentItems.set(r);
7459 const updateAriaExpansions = (container, path) => {
7460 const parentItems = getSubmenuParents(container);
7461 each(parentItems, (v, k) => {
7462 const expanded = contains$2(path, k);
7463 set$9(v.element, 'aria-expanded', expanded);
7466 const updateMenuPath = (container, state, path) => Optional.from(path[0]).bind(latestMenuName => state.lookupMenu(latestMenuName).bind(menuPrep => {
7467 if (menuPrep.type === 'notbuilt') {
7468 return Optional.none();
7470 const activeMenu = menuPrep.menu;
7471 const rest = getMenus(state, path.slice(1));
7473 add$2(r.element, detail.markers.backgroundMenu);
7475 if (!inBody(activeMenu.element)) {
7476 Replacing.append(container, premade(activeMenu));
7478 remove$1(activeMenu.element, [detail.markers.backgroundMenu]);
7479 setActiveMenuAndItem(container, activeMenu);
7480 closeOthers(container, state, path);
7481 return Optional.some(activeMenu);
7484 let ExpandHighlightDecision;
7485 (function (ExpandHighlightDecision) {
7486 ExpandHighlightDecision[ExpandHighlightDecision['HighlightSubmenu'] = 0] = 'HighlightSubmenu';
7487 ExpandHighlightDecision[ExpandHighlightDecision['HighlightParent'] = 1] = 'HighlightParent';
7488 }(ExpandHighlightDecision || (ExpandHighlightDecision = {})));
7489 const buildIfRequired = (container, menuName, menuPrep) => {
7490 if (menuPrep.type === 'notbuilt') {
7491 const menu = container.getSystem().build(menuPrep.nbMenu());
7492 layeredState.setMenuBuilt(menuName, menu);
7495 return menuPrep.menu;
7498 const expandRight = (container, item, decision = ExpandHighlightDecision.HighlightSubmenu) => {
7499 if (item.hasConfigured(Disabling) && Disabling.isDisabled(item)) {
7500 return Optional.some(item);
7502 const value = getItemValue(item);
7503 return layeredState.expand(value).bind(path => {
7504 updateAriaExpansions(container, path);
7505 return Optional.from(path[0]).bind(menuName => layeredState.lookupMenu(menuName).bind(activeMenuPrep => {
7506 const activeMenu = buildIfRequired(container, menuName, activeMenuPrep);
7507 if (!inBody(activeMenu.element)) {
7508 Replacing.append(container, premade(activeMenu));
7510 detail.onOpenSubmenu(container, item, activeMenu, reverse(path));
7511 if (decision === ExpandHighlightDecision.HighlightSubmenu) {
7512 Highlighting.highlightFirst(activeMenu);
7513 return updateMenuPath(container, layeredState, path);
7515 Highlighting.dehighlightAll(activeMenu);
7516 return Optional.some(item);
7522 const collapseLeft = (container, item) => {
7523 const value = getItemValue(item);
7524 return layeredState.collapse(value).bind(path => {
7525 updateAriaExpansions(container, path);
7526 return updateMenuPath(container, layeredState, path).map(activeMenu => {
7527 detail.onCollapseMenu(container, item, activeMenu);
7532 const updateView = (container, item) => {
7533 const value = getItemValue(item);
7534 return layeredState.refresh(value).bind(path => {
7535 updateAriaExpansions(container, path);
7536 return updateMenuPath(container, layeredState, path);
7539 const onRight = (container, item) => inside(item.element) ? Optional.none() : expandRight(container, item, ExpandHighlightDecision.HighlightSubmenu);
7540 const onLeft = (container, item) => inside(item.element) ? Optional.none() : collapseLeft(container, item);
7541 const onEscape = (container, item) => collapseLeft(container, item).orThunk(() => detail.onEscape(container, item).map(() => container));
7542 const keyOnItem = f => (container, simulatedEvent) => {
7543 return closest$1(simulatedEvent.getSource(), `.${ detail.markers.item }`).bind(target => container.getSystem().getByDom(target).toOptional().bind(item => f(container, item).map(always)));
7545 const events = derive$2([
7546 run$1(focus(), (tmenu, simulatedEvent) => {
7547 const item = simulatedEvent.event.item;
7548 layeredState.lookupItem(getItemValue(item)).each(() => {
7549 const menu = simulatedEvent.event.menu;
7550 Highlighting.highlight(tmenu, menu);
7551 const value = getItemValue(simulatedEvent.event.item);
7552 layeredState.refresh(value).each(path => closeOthers(tmenu, layeredState, path));
7555 runOnExecute$1((component, simulatedEvent) => {
7556 const target = simulatedEvent.event.target;
7557 component.getSystem().getByDom(target).each(item => {
7558 const itemValue = getItemValue(item);
7559 if (itemValue.indexOf('collapse-item') === 0) {
7560 collapseLeft(component, item);
7562 expandRight(component, item, ExpandHighlightDecision.HighlightSubmenu).fold(() => {
7563 detail.onExecute(component, item);
7567 runOnAttached((container, _simulatedEvent) => {
7568 setup(container).each(primary => {
7569 Replacing.append(container, premade(primary));
7570 detail.onOpenMenu(container, primary);
7571 if (detail.highlightOnOpen === HighlightOnOpen.HighlightMenuAndItem) {
7572 setActiveMenuAndItem(container, primary);
7573 } else if (detail.highlightOnOpen === HighlightOnOpen.HighlightJustMenu) {
7574 setActiveMenu(container, primary);
7578 run$1(onMenuItemHighlightedEvent, (tmenuComp, se) => {
7579 detail.onHighlightItem(tmenuComp, se.event.menuComp, se.event.itemComp);
7581 run$1(onMenuItemDehighlightedEvent, (tmenuComp, se) => {
7582 detail.onDehighlightItem(tmenuComp, se.event.menuComp, se.event.itemComp);
7584 ...detail.navigateOnHover ? [run$1(hover(), (tmenu, simulatedEvent) => {
7585 const item = simulatedEvent.event.item;
7586 updateView(tmenu, item);
7587 expandRight(tmenu, item, ExpandHighlightDecision.HighlightParent);
7588 detail.onHover(tmenu, item);
7591 const getActiveItem = container => Highlighting.getHighlighted(container).bind(Highlighting.getHighlighted);
7592 const collapseMenuApi = container => {
7593 getActiveItem(container).each(currentItem => {
7594 collapseLeft(container, currentItem);
7597 const highlightPrimary = container => {
7598 layeredState.getPrimary().each(primary => {
7599 setActiveMenuAndItem(container, primary);
7602 const extractMenuFromContainer = container => Optional.from(container.components()[0]).filter(comp => get$f(comp.element, 'role') === 'menu');
7603 const repositionMenus = container => {
7604 const maybeActivePrimary = layeredState.getPrimary().bind(primary => getActiveItem(container).bind(currentItem => {
7605 const itemValue = getItemValue(currentItem);
7606 const allMenus = values(layeredState.getMenus());
7607 const preparedMenus = cat(map$2(allMenus, LayeredState.extractPreparedMenu));
7608 return layeredState.getTriggeringPath(itemValue, v => getItemByValue(container, preparedMenus, v));
7609 }).map(triggeringPath => ({
7613 maybeActivePrimary.fold(() => {
7614 extractMenuFromContainer(container).each(primaryMenu => {
7615 detail.onRepositionMenu(container, primaryMenu, []);
7617 }, ({primary, triggeringPath}) => {
7618 detail.onRepositionMenu(container, primary, triggeringPath);
7622 collapseMenu: collapseMenuApi,
7629 markers: detail.markers,
7630 behaviours: augment(detail.tmenuBehaviours, [
7633 onRight: keyOnItem(onRight),
7634 onLeft: keyOnItem(onLeft),
7635 onEscape: keyOnItem(onEscape),
7636 focusIn: (container, _keyInfo) => {
7637 layeredState.getPrimary().each(primary => {
7638 dispatch(container, primary.element, focusItem());
7642 Highlighting.config({
7643 highlightClass: detail.markers.selectedMenu,
7644 itemClass: detail.markers.menu
7647 find: container => {
7648 return Highlighting.getHighlighted(container);
7651 Replacing.config({})
7653 eventOrder: detail.eventOrder,
7658 const collapseItem$1 = constant$1('collapse-item');
7660 const tieredData = (primary, menus, expansions) => ({
7665 const singleData = (name, menu) => ({
7667 menus: wrap$1(name, menu),
7670 const collapseItem = text => ({
7671 value: generate$6(collapseItem$1()),
7674 const tieredMenu = single({
7677 onStrictKeyboardHandler('onExecute'),
7678 onStrictKeyboardHandler('onEscape'),
7679 onStrictHandler('onOpenMenu'),
7680 onStrictHandler('onOpenSubmenu'),
7681 onHandler('onRepositionMenu'),
7682 onHandler('onCollapseMenu'),
7683 defaulted('highlightOnOpen', HighlightOnOpen.HighlightMenuAndItem),
7684 requiredObjOf('data', [
7685 required$1('primary'),
7686 required$1('menus'),
7687 required$1('expansions')
7689 defaulted('fakeFocus', false),
7690 onHandler('onHighlightItem'),
7691 onHandler('onDehighlightItem'),
7692 onHandler('onHover'),
7693 tieredMenuMarkers(),
7695 defaulted('navigateOnHover', true),
7696 defaulted('stayInDom', false),
7697 field('tmenuBehaviours', [
7703 defaulted('eventOrder', {})
7706 collapseMenu: (apis, tmenu) => {
7707 apis.collapseMenu(tmenu);
7709 highlightPrimary: (apis, tmenu) => {
7710 apis.highlightPrimary(tmenu);
7712 repositionMenus: (apis, tmenu) => {
7713 apis.repositionMenus(tmenu);
7724 const makeMenu = (detail, menuSandbox, placementSpec, menuSpec, getBounds) => {
7725 const lazySink = () => detail.lazySink(menuSandbox);
7726 const layouts = menuSpec.type === 'horizontal' ? {
7728 onLtr: () => belowOrAbove(),
7729 onRtl: () => belowOrAboveRtl()
7732 const isFirstTierSubmenu = triggeringPaths => triggeringPaths.length === 2;
7733 const getSubmenuLayouts = triggeringPaths => isFirstTierSubmenu(triggeringPaths) ? layouts : {};
7734 return tieredMenu.sketch({
7735 dom: { tag: 'div' },
7736 data: menuSpec.data,
7737 markers: menuSpec.menu.markers,
7738 highlightOnOpen: menuSpec.menu.highlightOnOpen,
7739 fakeFocus: menuSpec.menu.fakeFocus,
7741 Sandboxing.close(menuSandbox);
7742 detail.onEscape.map(handler => handler(menuSandbox));
7743 return Optional.some(true);
7746 return Optional.some(true);
7748 onOpenMenu: (tmenu, menu) => {
7749 Positioning.positionWithinBounds(lazySink().getOrDie(), menu, placementSpec, getBounds());
7751 onOpenSubmenu: (tmenu, item, submenu, triggeringPaths) => {
7752 const sink = lazySink().getOrDie();
7753 Positioning.position(sink, submenu, {
7757 ...getSubmenuLayouts(triggeringPaths)
7761 onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
7762 const sink = lazySink().getOrDie();
7763 Positioning.positionWithinBounds(sink, primaryMenu, placementSpec, getBounds());
7764 each$1(submenuTriggers, st => {
7765 const submenuLayouts = getSubmenuLayouts(st.triggeringPath);
7766 Positioning.position(sink, st.triggeredMenu, {
7769 item: st.triggeringItem,
7777 const factory$m = (detail, spec) => {
7778 const isPartOfRelated = (sandbox, queryElem) => {
7779 const related = detail.getRelated(sandbox);
7780 return related.exists(rel => isPartOf$1(rel, queryElem));
7782 const setContent = (sandbox, thing) => {
7783 Sandboxing.setContent(sandbox, thing);
7785 const showAt = (sandbox, thing, placementSpec) => {
7786 showWithin(sandbox, thing, placementSpec, Optional.none());
7788 const showWithin = (sandbox, thing, placementSpec, boxElement) => {
7789 showWithinBounds(sandbox, thing, placementSpec, () => boxElement.map(elem => box$1(elem)));
7791 const showWithinBounds = (sandbox, thing, placementSpec, getBounds) => {
7792 const sink = detail.lazySink(sandbox).getOrDie();
7793 Sandboxing.openWhileCloaked(sandbox, thing, () => Positioning.positionWithinBounds(sink, sandbox, placementSpec, getBounds()));
7794 Representing.setValue(sandbox, Optional.some({
7796 config: placementSpec,
7800 const showMenuAt = (sandbox, placementSpec, menuSpec) => {
7801 showMenuWithinBounds(sandbox, placementSpec, menuSpec, Optional.none);
7803 const showMenuWithinBounds = (sandbox, placementSpec, menuSpec, getBounds) => {
7804 const menu = makeMenu(detail, sandbox, placementSpec, menuSpec, getBounds);
7805 Sandboxing.open(sandbox, menu);
7806 Representing.setValue(sandbox, Optional.some({
7811 const hide = sandbox => {
7812 if (Sandboxing.isOpen(sandbox)) {
7813 Representing.setValue(sandbox, Optional.none());
7814 Sandboxing.close(sandbox);
7817 const getContent = sandbox => Sandboxing.getState(sandbox);
7818 const reposition = sandbox => {
7819 if (Sandboxing.isOpen(sandbox)) {
7820 Representing.getValue(sandbox).each(state => {
7821 switch (state.mode) {
7823 Sandboxing.getState(sandbox).each(tieredMenu.repositionMenus);
7826 const sink = detail.lazySink(sandbox).getOrDie();
7827 Positioning.positionWithinBounds(sink, sandbox, state.config, state.getBounds());
7839 showMenuWithinBounds,
7843 isOpen: Sandboxing.isOpen
7848 behaviours: augment(detail.inlineBehaviours, [
7850 isPartOf: (sandbox, data, queryElem) => {
7851 return isPartOf$1(data, queryElem) || isPartOfRelated(sandbox, queryElem);
7853 getAttachPoint: sandbox => {
7854 return detail.lazySink(sandbox).getOrDie();
7856 onOpen: sandbox => {
7857 detail.onShow(sandbox);
7859 onClose: sandbox => {
7860 detail.onHide(sandbox);
7863 Representing.config({
7866 initialValue: Optional.none()
7871 ...receivingChannel$1({
7872 isExtraPart: spec.isExtraPart,
7873 ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
7875 ...receivingChannel({
7876 ...detail.fireRepositionEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({}),
7877 doReposition: reposition
7882 eventOrder: detail.eventOrder,
7886 const InlineView = single({
7889 required$1('lazySink'),
7890 onHandler('onShow'),
7891 onHandler('onHide'),
7892 optionFunction('onEscape'),
7893 field('inlineBehaviours', [
7898 optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
7899 optionObjOf('fireRepositionEventInstead', [defaulted('event', repositionRequested())]),
7900 defaulted('getRelated', Optional.none),
7901 defaulted('isExtraPart', never),
7902 defaulted('eventOrder', Optional.none)
7906 showAt: (apis, component, anchor, thing) => {
7907 apis.showAt(component, anchor, thing);
7909 showWithin: (apis, component, anchor, thing, boxElement) => {
7910 apis.showWithin(component, anchor, thing, boxElement);
7912 showWithinBounds: (apis, component, anchor, thing, bounds) => {
7913 apis.showWithinBounds(component, anchor, thing, bounds);
7915 showMenuAt: (apis, component, anchor, menuSpec) => {
7916 apis.showMenuAt(component, anchor, menuSpec);
7918 showMenuWithinBounds: (apis, component, anchor, menuSpec, bounds) => {
7919 apis.showMenuWithinBounds(component, anchor, menuSpec, bounds);
7921 hide: (apis, component) => {
7922 apis.hide(component);
7924 isOpen: (apis, component) => apis.isOpen(component),
7925 getContent: (apis, component) => apis.getContent(component),
7926 setContent: (apis, component, thing) => {
7927 apis.setContent(component, thing);
7929 reposition: (apis, component) => {
7930 apis.reposition(component);
7935 var global$9 = tinymce.util.Tools.resolve('tinymce.util.Delay');
7937 const factory$l = detail => {
7938 const events = events$a(detail.action);
7939 const tag = detail.dom.tag;
7940 const lookupAttr = attr => get$g(detail.dom, 'attributes').bind(attrs => get$g(attrs, attr));
7941 const getModAttributes = () => {
7942 if (tag === 'button') {
7943 const type = lookupAttr('type').getOr('button');
7944 const roleAttrs = lookupAttr('role').map(role => ({ role })).getOr({});
7950 const role = lookupAttr('role').getOr('button');
7957 components: detail.components,
7959 behaviours: SketchBehaviours.augment(detail.buttonBehaviours, [
7960 Focusing.config({}),
7967 domModification: { attributes: getModAttributes() },
7968 eventOrder: detail.eventOrder
7971 const Button = single({
7975 defaulted('uid', undefined),
7977 defaulted('components', []),
7978 SketchBehaviours.field('buttonBehaviours', [
7984 defaulted('eventOrder', {})
7988 const record = spec => {
7989 const uid = isSketchSpec(spec) && hasNonNullableKey(spec, 'uid') ? spec.uid : generate$5('memento');
7990 const get = anyInSystem => anyInSystem.getSystem().getByUid(uid).getOrDie();
7991 const getOpt = anyInSystem => anyInSystem.getSystem().getByUid(uid).toOptional();
7992 const asSpec = () => ({
8003 var global$8 = tinymce.util.Tools.resolve('tinymce.util.I18n');
8005 const rtlTransform = {
8008 'table-insert-column-after': true,
8009 'table-insert-column-before': true,
8010 'paste-column-after': true,
8011 'paste-column-before': true,
8012 'unordered-list': true,
8013 'list-bull-circle': true,
8014 'list-bull-default': true,
8015 'list-bull-square': true
8017 const defaultIconName = 'temporary-placeholder';
8018 const defaultIcon = icons => () => get$g(icons, defaultIconName).getOr('!not found!');
8019 const getIconName = (name, icons) => {
8020 const lcName = name.toLowerCase();
8021 if (global$8.isRtl()) {
8022 const rtlName = ensureTrailing(lcName, '-rtl');
8023 return has$2(icons, rtlName) ? rtlName : lcName;
8028 const lookupIcon = (name, icons) => get$g(icons, getIconName(name, icons));
8029 const get$2 = (name, iconProvider) => {
8030 const icons = iconProvider();
8031 return lookupIcon(name, icons).getOrThunk(defaultIcon(icons));
8033 const getOr = (name, iconProvider, fallbackIcon) => {
8034 const icons = iconProvider();
8035 return lookupIcon(name, icons).or(fallbackIcon).getOrThunk(defaultIcon(icons));
8037 const needsRtlTransform = iconName => global$8.isRtl() ? has$2(rtlTransform, iconName) : false;
8038 const addFocusableBehaviour = () => config('add-focusable', [runOnAttached(comp => {
8039 child(comp.element, 'svg').each(svg => set$9(svg, 'focusable', 'false'));
8041 const renderIcon$2 = (spec, iconName, icons, fallbackIcon) => {
8042 const rtlIconClasses = needsRtlTransform(iconName) ? ['tox-icon--flip'] : [];
8043 const iconHtml = get$g(icons, getIconName(iconName, icons)).or(fallbackIcon).getOrThunk(defaultIcon(icons));
8047 attributes: spec.attributes ?? {},
8048 classes: spec.classes.concat(rtlIconClasses),
8051 behaviours: derive$1([
8052 ...spec.behaviours ?? [],
8053 addFocusableBehaviour()
8057 const render$3 = (iconName, spec, iconProvider, fallbackIcon = Optional.none()) => renderIcon$2(spec, iconName, iconProvider(), fallbackIcon);
8058 const renderFirst = (iconNames, spec, iconProvider) => {
8059 const icons = iconProvider();
8060 const iconName = find$5(iconNames, name => has$2(icons, getIconName(name, icons)));
8061 return renderIcon$2(spec, iconName.getOr(defaultIconName), icons, Optional.none());
8064 const notificationIconMap = {
8065 success: 'checkmark',
8072 const factory$k = detail => {
8073 const memBannerText = record({
8076 innerHtml: detail.translationProvider(detail.text)
8078 behaviours: derive$1([Replacing.config({})])
8080 const renderPercentBar = percent => ({
8083 classes: ['tox-bar'],
8084 styles: { width: `${ percent }%` }
8087 const renderPercentText = percent => ({
8090 classes: ['tox-text'],
8091 innerHtml: `${ percent }%`
8094 const memBannerProgress = record({
8097 classes: detail.progress ? [
8099 'tox-progress-indicator'
8100 ] : ['tox-progress-bar']
8106 classes: ['tox-bar-container']
8108 components: [renderPercentBar(0)]
8110 renderPercentText(0)
8112 behaviours: derive$1([Replacing.config({})])
8114 const updateProgress = (comp, percent) => {
8115 if (comp.getSystem().isConnected()) {
8116 memBannerProgress.getOpt(comp).each(progress => {
8117 Replacing.set(progress, [
8121 classes: ['tox-bar-container']
8123 components: [renderPercentBar(percent)]
8125 renderPercentText(percent)
8130 const updateText = (comp, text) => {
8131 if (comp.getSystem().isConnected()) {
8132 const banner = memBannerText.get(comp);
8133 Replacing.set(banner, [text$2(text)]);
8140 const iconChoices = flatten([
8141 detail.icon.toArray(),
8142 detail.level.toArray(),
8143 detail.level.bind(level => Optional.from(notificationIconMap[level])).toArray()
8145 const memButton = record(Button.sketch({
8149 'tox-notification__dismiss',
8151 'tox-button--naked',
8155 components: [render$3('close', {
8157 classes: ['tox-icon'],
8158 attributes: { 'aria-label': detail.translationProvider('Close') }
8159 }, detail.iconProvider)],
8161 detail.onAction(comp);
8164 const notificationIconSpec = renderFirst(iconChoices, {
8166 classes: ['tox-notification__icon']
8167 }, detail.iconProvider);
8168 const notificationBodySpec = {
8171 classes: ['tox-notification__body']
8173 components: [memBannerText.asSpec()],
8174 behaviours: derive$1([Replacing.config({})])
8176 const components = [
8177 notificationIconSpec,
8178 notificationBodySpec
8184 attributes: { role: 'alert' },
8185 classes: detail.level.map(level => [
8187 'tox-notification--in',
8188 `tox-notification--${ level }`
8191 'tox-notification--in'
8194 behaviours: derive$1([
8195 Focusing.config({}),
8196 config('notification-events', [run$1(focusin(), comp => {
8197 memButton.getOpt(comp).each(Focusing.focus);
8200 components: components.concat(detail.progress ? [memBannerProgress.asSpec()] : []).concat(!detail.closeButton ? [] : [memButton.asSpec()]),
8204 const Notification = single({
8205 name: 'Notification',
8209 required$1('progress'),
8211 required$1('onAction'),
8213 required$1('iconProvider'),
8214 required$1('translationProvider'),
8215 defaultedBoolean('closeButton', true)
8218 updateProgress: (apis, comp, percent) => {
8219 apis.updateProgress(comp, percent);
8221 updateText: (apis, comp, text) => {
8222 apis.updateText(comp, text);
8227 var NotificationManagerImpl = (editor, extras, uiMothership) => {
8228 const sharedBackstage = extras.backstage.shared;
8229 const getBounds = () => {
8230 const contentArea = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
8231 const win$1 = win();
8232 const x = clamp(win$1.x, contentArea.x, contentArea.right);
8233 const y = clamp(win$1.y, contentArea.y, contentArea.bottom);
8234 const right = Math.max(contentArea.right, win$1.right);
8235 const bottom = Math.max(contentArea.bottom, win$1.bottom);
8236 return Optional.some(bounds(x, y, right - x, bottom - y));
8238 const open = (settings, closeCallback) => {
8239 const close = () => {
8241 InlineView.hide(notificationWrapper);
8243 const notification = build$1(Notification.sketch({
8244 text: settings.text,
8251 ], settings.type) ? settings.type : undefined,
8252 progress: settings.progressBar === true,
8253 icon: settings.icon,
8254 closeButton: settings.closeButton,
8256 iconProvider: sharedBackstage.providers.icons,
8257 translationProvider: sharedBackstage.providers.translate
8259 const notificationWrapper = build$1(InlineView.sketch({
8262 classes: ['tox-notifications-container']
8264 lazySink: sharedBackstage.getSink,
8265 fireDismissalEventInstead: {},
8266 ...sharedBackstage.header.isPositionedAtTop() ? {} : { fireRepositionEventInstead: {} }
8268 uiMothership.add(notificationWrapper);
8269 if (isNumber(settings.timeout) && settings.timeout > 0) {
8270 global$9.setEditorTimeout(editor, () => {
8272 }, settings.timeout);
8274 const reposition = () => {
8275 const notificationSpec = premade(notification);
8276 const anchorOverrides = { maxHeightFunction: expandable$1() };
8277 const allNotifications = editor.notificationManager.getNotifications();
8278 if (allNotifications[0] === thisNotification) {
8280 ...sharedBackstage.anchors.banner(),
8281 overrides: anchorOverrides
8283 InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor }, getBounds);
8285 indexOf(allNotifications, thisNotification).each(idx => {
8286 const previousNotification = allNotifications[idx - 1].getEl();
8287 const nodeAnchor = {
8290 node: Optional.some(SugarElement.fromDom(previousNotification)),
8291 overrides: anchorOverrides,
8293 onRtl: () => [south$2],
8294 onLtr: () => [south$2]
8297 InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor: nodeAnchor }, getBounds);
8301 const thisNotification = {
8305 Notification.updateText(notification, nuText);
8308 getEl: () => notification.element.dom,
8311 Notification.updateProgress(notification, percent);
8315 return thisNotification;
8317 const close = notification => {
8318 notification.close();
8320 const getArgs = notification => {
8321 return notification.settings;
8330 var global$7 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
8332 var global$6 = tinymce.util.Tools.resolve('tinymce.EditorManager');
8334 var global$5 = tinymce.util.Tools.resolve('tinymce.Env');
8337 (function (ToolbarMode) {
8338 ToolbarMode['default'] = 'wrap';
8339 ToolbarMode['floating'] = 'floating';
8340 ToolbarMode['sliding'] = 'sliding';
8341 ToolbarMode['scrolling'] = 'scrolling';
8342 }(ToolbarMode$1 || (ToolbarMode$1 = {})));
8343 var ToolbarLocation$1;
8344 (function (ToolbarLocation) {
8345 ToolbarLocation['auto'] = 'auto';
8346 ToolbarLocation['top'] = 'top';
8347 ToolbarLocation['bottom'] = 'bottom';
8348 }(ToolbarLocation$1 || (ToolbarLocation$1 = {})));
8349 const option$2 = name => editor => editor.options.get(name);
8350 const wrapOptional = fn => editor => Optional.from(fn(editor));
8351 const register$e = editor => {
8352 const isPhone = global$5.deviceType.isPhone();
8353 const isMobile = global$5.deviceType.isTablet() || isPhone;
8354 const registerOption = editor.options.register;
8355 const stringOrFalseProcessor = value => isString(value) || value === false;
8356 const stringOrNumberProcessor = value => isString(value) || isNumber(value);
8357 registerOption('skin', {
8358 processor: value => isString(value) || value === false,
8361 registerOption('skin_url', { processor: 'string' });
8362 registerOption('height', {
8363 processor: stringOrNumberProcessor,
8364 default: Math.max(editor.getElement().offsetHeight, 400)
8366 registerOption('width', {
8367 processor: stringOrNumberProcessor,
8368 default: global$7.DOM.getStyle(editor.getElement(), 'width')
8370 registerOption('min_height', {
8371 processor: 'number',
8374 registerOption('min_width', { processor: 'number' });
8375 registerOption('max_height', { processor: 'number' });
8376 registerOption('max_width', { processor: 'number' });
8377 registerOption('style_formats', { processor: 'object[]' });
8378 registerOption('style_formats_merge', {
8379 processor: 'boolean',
8382 registerOption('style_formats_autohide', {
8383 processor: 'boolean',
8386 registerOption('line_height_formats', {
8387 processor: 'string',
8388 default: '1 1.1 1.2 1.3 1.4 1.5 2'
8390 registerOption('font_family_formats', {
8391 processor: 'string',
8392 default: 'Andale Mono=andale mono,monospace;' + 'Arial=arial,helvetica,sans-serif;' + 'Arial Black=arial black,sans-serif;' + 'Book Antiqua=book antiqua,palatino,serif;' + 'Comic Sans MS=comic sans ms,sans-serif;' + 'Courier New=courier new,courier,monospace;' + 'Georgia=georgia,palatino,serif;' + 'Helvetica=helvetica,arial,sans-serif;' + 'Impact=impact,sans-serif;' + 'Symbol=symbol;' + 'Tahoma=tahoma,arial,helvetica,sans-serif;' + 'Terminal=terminal,monaco,monospace;' + 'Times New Roman=times new roman,times,serif;' + 'Trebuchet MS=trebuchet ms,geneva,sans-serif;' + 'Verdana=verdana,geneva,sans-serif;' + 'Webdings=webdings;' + 'Wingdings=wingdings,zapf dingbats'
8394 registerOption('font_size_formats', {
8395 processor: 'string',
8396 default: '8pt 10pt 12pt 14pt 18pt 24pt 36pt'
8398 registerOption('block_formats', {
8399 processor: 'string',
8400 default: 'Paragraph=p;' + 'Heading 1=h1;' + 'Heading 2=h2;' + 'Heading 3=h3;' + 'Heading 4=h4;' + 'Heading 5=h5;' + 'Heading 6=h6;' + 'Preformatted=pre'
8402 registerOption('content_langs', { processor: 'object[]' });
8403 registerOption('removed_menuitems', {
8404 processor: 'string',
8407 registerOption('menubar', {
8408 processor: value => isString(value) || isBoolean(value),
8411 registerOption('menu', {
8412 processor: 'object',
8415 registerOption('toolbar', {
8416 processor: value => {
8417 if (isBoolean(value) || isString(value) || isArray(value)) {
8425 message: 'Must be a boolean, string or array.'
8432 registerOption('toolbar' + (num + 1), { processor: 'string' });
8434 registerOption('toolbar_mode', {
8435 processor: 'string',
8436 default: isMobile ? 'scrolling' : 'floating'
8438 registerOption('toolbar_groups', {
8439 processor: 'object',
8442 registerOption('toolbar_location', {
8443 processor: 'string',
8444 default: ToolbarLocation$1.auto
8446 registerOption('toolbar_persist', {
8447 processor: 'boolean',
8450 registerOption('toolbar_sticky', {
8451 processor: 'boolean',
8452 default: editor.inline
8454 registerOption('toolbar_sticky_offset', {
8455 processor: 'number',
8458 registerOption('fixed_toolbar_container', {
8459 processor: 'string',
8462 registerOption('fixed_toolbar_container_target', { processor: 'object' });
8463 registerOption('file_picker_callback', { processor: 'function' });
8464 registerOption('file_picker_validator_handler', { processor: 'function' });
8465 registerOption('file_picker_types', { processor: 'string' });
8466 registerOption('typeahead_urls', {
8467 processor: 'boolean',
8470 registerOption('anchor_top', {
8471 processor: stringOrFalseProcessor,
8474 registerOption('anchor_bottom', {
8475 processor: stringOrFalseProcessor,
8478 registerOption('draggable_modal', {
8479 processor: 'boolean',
8482 registerOption('statusbar', {
8483 processor: 'boolean',
8486 registerOption('elementpath', {
8487 processor: 'boolean',
8490 registerOption('branding', {
8491 processor: 'boolean',
8494 registerOption('promotion', {
8495 processor: 'boolean',
8498 registerOption('resize', {
8499 processor: value => value === 'both' || isBoolean(value),
8500 default: !global$5.deviceType.isTouch()
8502 registerOption('sidebar_show', { processor: 'string' });
8504 const isReadOnly = option$2('readonly');
8505 const getHeightOption = option$2('height');
8506 const getWidthOption = option$2('width');
8507 const getMinWidthOption = wrapOptional(option$2('min_width'));
8508 const getMinHeightOption = wrapOptional(option$2('min_height'));
8509 const getMaxWidthOption = wrapOptional(option$2('max_width'));
8510 const getMaxHeightOption = wrapOptional(option$2('max_height'));
8511 const getUserStyleFormats = wrapOptional(option$2('style_formats'));
8512 const shouldMergeStyleFormats = option$2('style_formats_merge');
8513 const shouldAutoHideStyleFormats = option$2('style_formats_autohide');
8514 const getContentLanguages = option$2('content_langs');
8515 const getRemovedMenuItems = option$2('removed_menuitems');
8516 const getToolbarMode = option$2('toolbar_mode');
8517 const getToolbarGroups = option$2('toolbar_groups');
8518 const getToolbarLocation = option$2('toolbar_location');
8519 const fixedContainerSelector = option$2('fixed_toolbar_container');
8520 const fixedToolbarContainerTarget = option$2('fixed_toolbar_container_target');
8521 const isToolbarPersist = option$2('toolbar_persist');
8522 const getStickyToolbarOffset = option$2('toolbar_sticky_offset');
8523 const getMenubar = option$2('menubar');
8524 const getToolbar = option$2('toolbar');
8525 const getFilePickerCallback = option$2('file_picker_callback');
8526 const getFilePickerValidatorHandler = option$2('file_picker_validator_handler');
8527 const getFilePickerTypes = option$2('file_picker_types');
8528 const useTypeaheadUrls = option$2('typeahead_urls');
8529 const getAnchorTop = option$2('anchor_top');
8530 const getAnchorBottom = option$2('anchor_bottom');
8531 const isDraggableModal$1 = option$2('draggable_modal');
8532 const useStatusBar = option$2('statusbar');
8533 const useElementPath = option$2('elementpath');
8534 const useBranding = option$2('branding');
8535 const getResize = option$2('resize');
8536 const getPasteAsText = option$2('paste_as_text');
8537 const getSidebarShow = option$2('sidebar_show');
8538 const promotionEnabled = option$2('promotion');
8539 const isSkinDisabled = editor => editor.options.get('skin') === false;
8540 const isMenubarEnabled = editor => editor.options.get('menubar') !== false;
8541 const getSkinUrl = editor => {
8542 const skinUrl = editor.options.get('skin_url');
8543 if (isSkinDisabled(editor)) {
8547 return editor.documentBaseURI.toAbsolute(skinUrl);
8549 const skin = editor.options.get('skin');
8550 return global$6.baseURL + '/skins/ui/' + skin;
8554 const getLineHeightFormats = editor => editor.options.get('line_height_formats').split(' ');
8555 const isToolbarEnabled = editor => {
8556 const toolbar = getToolbar(editor);
8557 const isToolbarString = isString(toolbar);
8558 const isToolbarObjectArray = isArray(toolbar) && toolbar.length > 0;
8559 return !isMultipleToolbars(editor) && (isToolbarObjectArray || isToolbarString || toolbar === true);
8561 const getMultipleToolbarsOption = editor => {
8562 const toolbars = range$2(9, num => editor.options.get('toolbar' + (num + 1)));
8563 const toolbarArray = filter$2(toolbars, isString);
8564 return someIf(toolbarArray.length > 0, toolbarArray);
8566 const isMultipleToolbars = editor => getMultipleToolbarsOption(editor).fold(() => {
8567 const toolbar = getToolbar(editor);
8568 return isArrayOf(toolbar, isString) && toolbar.length > 0;
8570 const isToolbarLocationBottom = editor => getToolbarLocation(editor) === ToolbarLocation$1.bottom;
8571 const fixedContainerTarget = editor => {
8572 if (!editor.inline) {
8573 return Optional.none();
8575 const selector = fixedContainerSelector(editor) ?? '';
8576 if (selector.length > 0) {
8577 return descendant(body(), selector);
8579 const element = fixedToolbarContainerTarget(editor);
8580 if (isNonNullable(element)) {
8581 return Optional.some(SugarElement.fromDom(element));
8583 return Optional.none();
8585 const useFixedContainer = editor => editor.inline && fixedContainerTarget(editor).isSome();
8586 const getUiContainer = editor => {
8587 const fixedContainer = fixedContainerTarget(editor);
8588 return fixedContainer.getOrThunk(() => getContentContainer(getRootNode(SugarElement.fromDom(editor.getElement()))));
8590 const isDistractionFree = editor => editor.inline && !isMenubarEnabled(editor) && !isToolbarEnabled(editor) && !isMultipleToolbars(editor);
8591 const isStickyToolbar = editor => {
8592 const isStickyToolbar = editor.options.get('toolbar_sticky');
8593 return (isStickyToolbar || editor.inline) && !useFixedContainer(editor) && !isDistractionFree(editor);
8595 const getMenus = editor => {
8596 const menu = editor.options.get('menu');
8597 return map$1(menu, menu => ({
8603 var Options = /*#__PURE__*/Object.freeze({
8605 get ToolbarMode () { return ToolbarMode$1; },
8606 get ToolbarLocation () { return ToolbarLocation$1; },
8607 register: register$e,
8608 getSkinUrl: getSkinUrl,
8609 isReadOnly: isReadOnly,
8610 isSkinDisabled: isSkinDisabled,
8611 getHeightOption: getHeightOption,
8612 getWidthOption: getWidthOption,
8613 getMinWidthOption: getMinWidthOption,
8614 getMinHeightOption: getMinHeightOption,
8615 getMaxWidthOption: getMaxWidthOption,
8616 getMaxHeightOption: getMaxHeightOption,
8617 getUserStyleFormats: getUserStyleFormats,
8618 shouldMergeStyleFormats: shouldMergeStyleFormats,
8619 shouldAutoHideStyleFormats: shouldAutoHideStyleFormats,
8620 getLineHeightFormats: getLineHeightFormats,
8621 getContentLanguages: getContentLanguages,
8622 getRemovedMenuItems: getRemovedMenuItems,
8623 isMenubarEnabled: isMenubarEnabled,
8624 isMultipleToolbars: isMultipleToolbars,
8625 isToolbarEnabled: isToolbarEnabled,
8626 isToolbarPersist: isToolbarPersist,
8627 getMultipleToolbarsOption: getMultipleToolbarsOption,
8628 getUiContainer: getUiContainer,
8629 useFixedContainer: useFixedContainer,
8630 getToolbarMode: getToolbarMode,
8631 isDraggableModal: isDraggableModal$1,
8632 isDistractionFree: isDistractionFree,
8633 isStickyToolbar: isStickyToolbar,
8634 getStickyToolbarOffset: getStickyToolbarOffset,
8635 getToolbarLocation: getToolbarLocation,
8636 isToolbarLocationBottom: isToolbarLocationBottom,
8637 getToolbarGroups: getToolbarGroups,
8639 getMenubar: getMenubar,
8640 getToolbar: getToolbar,
8641 getFilePickerCallback: getFilePickerCallback,
8642 getFilePickerTypes: getFilePickerTypes,
8643 useTypeaheadUrls: useTypeaheadUrls,
8644 getAnchorTop: getAnchorTop,
8645 getAnchorBottom: getAnchorBottom,
8646 getFilePickerValidatorHandler: getFilePickerValidatorHandler,
8647 useStatusBar: useStatusBar,
8648 useElementPath: useElementPath,
8649 promotionEnabled: promotionEnabled,
8650 useBranding: useBranding,
8651 getResize: getResize,
8652 getPasteAsText: getPasteAsText,
8653 getSidebarShow: getSidebarShow
8656 const autocompleteSelector = '[data-mce-autocompleter]';
8657 const detect = elm => closest$1(elm, autocompleteSelector);
8658 const findIn = elm => descendant(elm, autocompleteSelector);
8660 const setup$e = (api, editor) => {
8661 const redirectKeyToItem = (item, e) => {
8662 emitWith(item, keydown(), { raw: e });
8664 const getItem = () => api.getMenu().bind(Highlighting.getHighlighted);
8665 editor.on('keydown', e => {
8666 const keyCode = e.which;
8667 if (!api.isActive()) {
8670 if (api.isMenuOpen()) {
8671 if (keyCode === 13) {
8672 getItem().each(emitExecute);
8674 } else if (keyCode === 40) {
8675 getItem().fold(() => {
8676 api.getMenu().each(Highlighting.highlightFirst);
8678 redirectKeyToItem(item, e);
8681 e.stopImmediatePropagation();
8682 } else if (keyCode === 37 || keyCode === 38 || keyCode === 39) {
8683 getItem().each(item => {
8684 redirectKeyToItem(item, e);
8686 e.stopImmediatePropagation();
8690 if (keyCode === 13 || keyCode === 38 || keyCode === 40) {
8691 api.cancelIfNecessary();
8695 editor.on('NodeChange', e => {
8696 if (api.isActive() && !api.isProcessingAction() && detect(SugarElement.fromDom(e.element)).isNone()) {
8697 api.cancelIfNecessary();
8701 const AutocompleterEditorEvents = { setup: setup$e };
8704 (function (ItemResponse) {
8705 ItemResponse[ItemResponse['CLOSE_ON_EXECUTE'] = 0] = 'CLOSE_ON_EXECUTE';
8706 ItemResponse[ItemResponse['BUBBLE_TO_SANDBOX'] = 1] = 'BUBBLE_TO_SANDBOX';
8707 }(ItemResponse || (ItemResponse = {})));
8708 var ItemResponse$1 = ItemResponse;
8710 const navClass = 'tox-menu-nav__js';
8711 const selectableClass = 'tox-collection__item';
8712 const colorClass = 'tox-swatch';
8713 const presetClasses = {
8717 const tickedClass = 'tox-collection__item--enabled';
8718 const groupHeadingClass = 'tox-collection__group-heading';
8719 const iconClass = 'tox-collection__item-icon';
8720 const textClass = 'tox-collection__item-label';
8721 const accessoryClass = 'tox-collection__item-accessory';
8722 const caretClass = 'tox-collection__item-caret';
8723 const checkmarkClass = 'tox-collection__item-checkmark';
8724 const activeClass = 'tox-collection__item--active';
8725 const containerClass = 'tox-collection__item-container';
8726 const containerColumnClass = 'tox-collection__item-container--column';
8727 const containerRowClass = 'tox-collection__item-container--row';
8728 const containerAlignRightClass = 'tox-collection__item-container--align-right';
8729 const containerAlignLeftClass = 'tox-collection__item-container--align-left';
8730 const containerValignTopClass = 'tox-collection__item-container--valign-top';
8731 const containerValignMiddleClass = 'tox-collection__item-container--valign-middle';
8732 const containerValignBottomClass = 'tox-collection__item-container--valign-bottom';
8733 const classForPreset = presets => get$g(presetClasses, presets).getOr(navClass);
8735 const forMenu = presets => {
8736 if (presets === 'color') {
8737 return 'tox-swatches';
8742 const classes = presets => ({
8743 backgroundMenu: 'tox-background-menu',
8744 selectedMenu: 'tox-selected-menu',
8745 selectedItem: 'tox-collection__item--active',
8746 hasIcons: 'tox-menu--has-icons',
8747 menu: forMenu(presets),
8748 tieredMenu: 'tox-tiered-menu'
8751 const markers = presets => {
8752 const menuClasses = classes(presets);
8754 backgroundMenu: menuClasses.backgroundMenu,
8755 selectedMenu: menuClasses.selectedMenu,
8756 menu: menuClasses.menu,
8757 selectedItem: menuClasses.selectedItem,
8758 item: classForPreset(presets)
8761 const dom$1 = (hasIcons, columns, presets) => {
8762 const menuClasses = classes(presets);
8768 `tox-menu-${ columns }-column`
8770 hasIcons ? [menuClasses.hasIcons] : []
8774 const components = [Menu.parts.items({})];
8775 const part = (hasIcons, columns, presets) => {
8776 const menuClasses = classes(presets);
8779 classes: flatten([[menuClasses.tieredMenu]])
8783 markers: markers(presets)
8787 const schema$l = constant$1([
8789 defaulted('inputAttributes', {}),
8790 defaulted('inputStyles', {}),
8791 defaulted('tag', 'input'),
8792 defaulted('inputClasses', []),
8793 onHandler('onSetValue'),
8794 defaulted('styles', {}),
8795 defaulted('eventOrder', {}),
8796 field('inputBehaviours', [
8800 defaulted('selectOnFocus', true)
8802 const focusBehaviours = detail => derive$1([Focusing.config({
8803 onFocus: !detail.selectOnFocus ? noop : component => {
8804 const input = component.element;
8805 const value = get$6(input);
8806 input.dom.setSelectionRange(0, value.length);
8809 const behaviours = detail => ({
8810 ...focusBehaviours(detail),
8811 ...augment(detail.inputBehaviours, [Representing.config({
8814 ...detail.data.map(data => ({ initialValue: data })).getOr({}),
8815 getValue: input => {
8816 return get$6(input.element);
8818 setValue: (input, data) => {
8819 const current = get$6(input.element);
8820 if (current !== data) {
8821 set$5(input.element, data);
8825 onSetValue: detail.onSetValue
8828 const dom = detail => ({
8832 ...detail.inputAttributes
8834 styles: detail.inputStyles,
8835 classes: detail.inputClasses
8838 const factory$j = (detail, _spec) => ({
8842 behaviours: behaviours(detail),
8843 eventOrder: detail.eventOrder
8845 const Input = single({
8847 configFields: schema$l(),
8851 const refetchTriggerEvent = generate$6('refetch-trigger-event');
8852 const redirectMenuItemInteractionEvent = generate$6('redirect-menu-item-interaction');
8854 const menuSearcherClass = 'tox-menu__searcher';
8855 const findWithinSandbox = sandboxComp => {
8856 return descendant(sandboxComp.element, `.${ menuSearcherClass }`).bind(inputElem => sandboxComp.getSystem().getByDom(inputElem).toOptional());
8858 const findWithinMenu = findWithinSandbox;
8859 const restoreState = (inputComp, searcherState) => {
8860 Representing.setValue(inputComp, searcherState.fetchPattern);
8861 inputComp.element.dom.selectionStart = searcherState.selectionStart;
8862 inputComp.element.dom.selectionEnd = searcherState.selectionEnd;
8864 const saveState = inputComp => {
8865 const fetchPattern = Representing.getValue(inputComp);
8866 const selectionStart = inputComp.element.dom.selectionStart;
8867 const selectionEnd = inputComp.element.dom.selectionEnd;
8874 const setActiveDescendant = (inputComp, active) => {
8875 getOpt(active.element, 'id').each(id => set$9(inputComp.element, 'aria-activedescendant', id));
8877 const renderMenuSearcher = spec => {
8878 const handleByBrowser = (comp, se) => {
8880 return Optional.none();
8882 const handleByHighlightedItem = (comp, se) => {
8884 interactionEvent: se.event,
8885 eventType: se.event.raw.type
8887 emitWith(comp, redirectMenuItemInteractionEvent, eventData);
8888 return Optional.some(true);
8890 const customSearcherEventsName = 'searcher-events';
8894 classes: [selectableClass]
8896 components: [Input.sketch({
8902 ...spec.placeholder.map(placeholder => ({ placeholder: spec.i18n(placeholder) })).getOr({}),
8904 'aria-autocomplete': 'list'
8906 inputBehaviours: derive$1([
8907 config(customSearcherEventsName, [
8908 run$1(input(), inputComp => {
8909 emit(inputComp, refetchTriggerEvent);
8911 run$1(keydown(), (inputComp, se) => {
8912 if (se.event.raw.key === 'Escape') {
8919 onLeft: handleByBrowser,
8920 onRight: handleByBrowser,
8921 onSpace: handleByBrowser,
8922 onEnter: handleByHighlightedItem,
8923 onEscape: handleByHighlightedItem,
8924 onUp: handleByHighlightedItem,
8925 onDown: handleByHighlightedItem
8930 customSearcherEventsName,
8938 const searchResultsClass = 'tox-collection--results__js';
8939 const augmentWithAria = item => {
8946 ...item.dom.attributes ?? {},
8947 'id': generate$6('aria-item-search-result-id'),
8948 'aria-selected': 'false'
8957 const chunk = (rowDom, numColumns) => items => {
8958 const chunks = chunk$1(items, numColumns);
8959 return map$2(chunks, c => ({
8964 const forSwatch = columns => ({
8975 classes: ['tox-swatches']
8977 components: [Menu.parts.items({
8978 preprocess: columns !== 'auto' ? chunk({
8980 classes: ['tox-swatches__row']
8981 }, columns) : identity
8985 const forToolbar = columns => ({
8991 'tox-collection--toolbar',
8992 'tox-collection--toolbar-lg'
8995 components: [Menu.parts.items({
8998 classes: ['tox-collection__group']
9002 const preprocessCollection = (items, isSeparator) => {
9003 const allSplits = [];
9004 let currentSplit = [];
9005 each$1(items, (item, i) => {
9006 if (isSeparator(item, i)) {
9007 if (currentSplit.length > 0) {
9008 allSplits.push(currentSplit);
9011 if (has$2(item.dom, 'innerHtml') || item.components && item.components.length > 0) {
9012 currentSplit.push(item);
9015 currentSplit.push(item);
9018 if (currentSplit.length > 0) {
9019 allSplits.push(currentSplit);
9021 return map$2(allSplits, s => ({
9024 classes: ['tox-collection__group']
9029 const insertItemsPlaceholder = (columns, initItems, onItem) => {
9030 return Menu.parts.items({
9031 preprocess: rawItems => {
9032 const enrichedItems = map$2(rawItems, onItem);
9033 if (columns !== 'auto' && columns > 1) {
9036 classes: ['tox-collection__group']
9037 }, columns)(enrichedItems);
9039 return preprocessCollection(enrichedItems, (_item, i) => initItems[i].type === 'separator');
9044 const forCollection = (columns, initItems, _hasIcons = true) => ({
9050 ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'])
9052 components: [insertItemsPlaceholder(columns, initItems, identity)]
9054 const forCollectionWithSearchResults = (columns, initItems, _hasIcons = true) => {
9055 const ariaControlsSearchResults = generate$6('aria-controls-search-results');
9063 ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid']),
9064 attributes: { id: ariaControlsSearchResults }
9066 components: [insertItemsPlaceholder(columns, initItems, augmentWithAria)]
9069 const forCollectionWithSearchField = (columns, initItems, searchField) => {
9070 const ariaControlsSearchResults = generate$6('aria-controls-search-results');
9077 ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'])
9080 renderMenuSearcher({
9081 i18n: global$8.translate,
9082 placeholder: searchField.placeholder
9088 ...columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'],
9091 attributes: { id: ariaControlsSearchResults }
9093 components: [insertItemsPlaceholder(columns, initItems, augmentWithAria)]
9098 const forHorizontalCollection = (initItems, _hasIcons = true) => ({
9103 'tox-collection--horizontal'
9106 components: [Menu.parts.items({ preprocess: items => preprocessCollection(items, (_item, i) => initItems[i].type === 'separator') })]
9109 const menuHasIcons = xs => exists(xs, item => 'icon' in item && item.icon !== undefined);
9110 const handleError = error => {
9111 console.error(formatError(error));
9113 return Optional.none();
9115 const createHorizontalPartialMenuWithAlloyItems = (value, _hasIcons, items, _columns, _menuLayout) => {
9116 const structure = forHorizontalCollection(items);
9120 components: structure.components,
9124 const createPartialMenuWithAlloyItems = (value, hasIcons, items, columns, menuLayout) => {
9125 const getNormalStructure = () => {
9126 if (menuLayout.menuType !== 'searchable') {
9127 return forCollection(columns, items);
9129 return menuLayout.searchMode.searchMode === 'search-with-field' ? forCollectionWithSearchField(columns, items, menuLayout.searchMode) : forCollectionWithSearchResults(columns, items);
9132 if (menuLayout.menuType === 'color') {
9133 const structure = forSwatch(columns);
9137 components: structure.components,
9140 } else if (menuLayout.menuType === 'normal' && columns === 'auto') {
9141 const structure = forCollection(columns, items);
9145 components: structure.components,
9148 } else if (menuLayout.menuType === 'normal' || menuLayout.menuType === 'searchable') {
9149 const structure = getNormalStructure();
9153 components: structure.components,
9156 } else if (menuLayout.menuType === 'listpreview' && columns !== 'auto') {
9157 const structure = forToolbar(columns);
9161 components: structure.components,
9167 dom: dom$1(hasIcons, columns, menuLayout.menuType),
9168 components: components,
9174 const type = requiredString('type');
9175 const name$1 = requiredString('name');
9176 const label = requiredString('label');
9177 const text$1 = requiredString('text');
9178 const title = requiredString('title');
9179 const icon = requiredString('icon');
9180 const value$1 = requiredString('value');
9181 const fetch$1 = requiredFunction('fetch');
9182 const getSubmenuItems = requiredFunction('getSubmenuItems');
9183 const onAction = requiredFunction('onAction');
9184 const onItemAction = requiredFunction('onItemAction');
9185 const onSetup = defaultedFunction('onSetup', () => noop);
9186 const optionalName = optionString('name');
9187 const optionalText = optionString('text');
9188 const optionalIcon = optionString('icon');
9189 const optionalTooltip = optionString('tooltip');
9190 const optionalLabel = optionString('label');
9191 const optionalShortcut = optionString('shortcut');
9192 const optionalSelect = optionFunction('select');
9193 const active = defaultedBoolean('active', false);
9194 const borderless = defaultedBoolean('borderless', false);
9195 const enabled = defaultedBoolean('enabled', true);
9196 const primary = defaultedBoolean('primary', false);
9197 const defaultedColumns = num => defaulted('columns', num);
9198 const defaultedMeta = defaulted('meta', {});
9199 const defaultedOnAction = defaultedFunction('onAction', noop);
9200 const defaultedType = type => defaultedString('type', type);
9201 const generatedName = namePrefix => field$1('name', 'name', defaultedThunk(() => generate$6(`${ namePrefix }-name`)), string);
9202 const generatedValue = valuePrefix => field$1('value', 'value', defaultedThunk(() => generate$6(`${ valuePrefix }-value`)), anyValue());
9204 const separatorMenuItemSchema = objOf([
9208 const createSeparatorMenuItem = spec => asRaw('separatormenuitem', separatorMenuItemSchema, spec);
9210 const autocompleterItemSchema = objOf([
9211 defaultedType('autocompleteitem'),
9219 const createSeparatorItem = spec => asRaw('Autocompleter.Separator', separatorMenuItemSchema, spec);
9220 const createAutocompleterItem = spec => asRaw('Autocompleter.Item', autocompleterItemSchema, spec);
9222 const baseToolbarButtonFields = [
9229 const toolbarButtonSchema = objOf([
9232 ].concat(baseToolbarButtonFields));
9233 const createToolbarButton = spec => asRaw('toolbarbutton', toolbarButtonSchema, spec);
9235 const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
9236 const toggleButtonSchema = objOf(baseToolbarToggleButtonFields.concat([
9240 const createToggleButton = spec => asRaw('ToggleButton', toggleButtonSchema, spec);
9242 const contextBarFields = [
9243 defaultedFunction('predicate', never),
9244 defaultedStringEnum('scope', 'node', [
9248 defaultedStringEnum('position', 'selection', [
9255 const contextButtonFields = baseToolbarButtonFields.concat([
9256 defaultedType('contextformbutton'),
9259 customField('original', identity)
9261 const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
9262 defaultedType('contextformbutton'),
9265 customField('original', identity)
9267 const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
9268 const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
9269 const toggleOrNormal = choose$1('type', {
9270 contextformbutton: contextButtonFields,
9271 contextformtogglebutton: contextToggleButtonFields
9273 const contextFormSchema = objOf([
9274 defaultedType('contextform'),
9275 defaultedFunction('initValue', constant$1('')),
9277 requiredArrayOf('commands', toggleOrNormal),
9278 optionOf('launch', choose$1('type', {
9279 contextformbutton: launchButtonFields,
9280 contextformtogglebutton: launchToggleButtonFields
9282 ].concat(contextBarFields));
9283 const createContextForm = spec => asRaw('ContextForm', contextFormSchema, spec);
9285 const contextToolbarSchema = objOf([
9286 defaultedType('contexttoolbar'),
9287 requiredString('items')
9288 ].concat(contextBarFields));
9289 const createContextToolbar = spec => asRaw('ContextToolbar', contextToolbarSchema, spec);
9291 const cardImageFields = [
9293 requiredString('src'),
9294 optionString('alt'),
9295 defaultedArrayOf('classes', [], string)
9297 const cardImageSchema = objOf(cardImageFields);
9299 const cardTextFields = [
9303 defaultedArrayOf('classes', ['tox-collection__item-label'], string)
9305 const cardTextSchema = objOf(cardTextFields);
9307 const itemSchema$1 = valueThunk(() => choose$2('type', {
9308 cardimage: cardImageSchema,
9309 cardtext: cardTextSchema,
9310 cardcontainer: cardContainerSchema
9312 const cardContainerSchema = objOf([
9314 defaultedString('direction', 'horizontal'),
9315 defaultedString('align', 'left'),
9316 defaultedString('valign', 'middle'),
9317 requiredArrayOf('items', itemSchema$1)
9320 const commonMenuItemFields = [
9324 generatedValue('menuitem'),
9328 const cardMenuItemSchema = objOf([
9331 requiredArrayOf('items', itemSchema$1),
9334 ].concat(commonMenuItemFields));
9335 const createCardMenuItem = spec => asRaw('cardmenuitem', cardMenuItemSchema, spec);
9337 const choiceMenuItemSchema = objOf([
9341 ].concat(commonMenuItemFields));
9342 const createChoiceMenuItem = spec => asRaw('choicemenuitem', choiceMenuItemSchema, spec);
9344 const baseFields = [
9346 requiredString('fancytype'),
9349 const insertTableFields = [defaulted('initData', {})].concat(baseFields);
9350 const colorSwatchFields = [defaultedObjOf('initData', {}, [
9351 defaultedBoolean('allowCustomColors', true),
9352 optionArrayOf('colors', anyValue())
9353 ])].concat(baseFields);
9354 const fancyMenuItemSchema = choose$1('fancytype', {
9355 inserttable: insertTableFields,
9356 colorswatch: colorSwatchFields
9358 const createFancyMenuItem = spec => asRaw('fancymenuitem', fancyMenuItemSchema, spec);
9360 const menuItemSchema = objOf([
9365 ].concat(commonMenuItemFields));
9366 const createMenuItem = spec => asRaw('menuitem', menuItemSchema, spec);
9368 const nestedMenuItemSchema = objOf([
9373 ].concat(commonMenuItemFields));
9374 const createNestedMenuItem = spec => asRaw('nestedmenuitem', nestedMenuItemSchema, spec);
9376 const toggleMenuItemSchema = objOf([
9382 ].concat(commonMenuItemFields));
9383 const createToggleMenuItem = spec => asRaw('togglemenuitem', toggleMenuItemSchema, spec);
9385 const detectSize = (comp, margin, selectorClass) => {
9386 const descendants$1 = descendants(comp.element, '.' + selectorClass);
9387 if (descendants$1.length > 0) {
9388 const columnLength = findIndex$1(descendants$1, c => {
9389 const thisTop = c.dom.getBoundingClientRect().top;
9390 const cTop = descendants$1[0].dom.getBoundingClientRect().top;
9391 return Math.abs(thisTop - cTop) > margin;
9392 }).getOr(descendants$1.length);
9393 return Optional.some({
9394 numColumns: columnLength,
9395 numRows: Math.ceil(descendants$1.length / columnLength)
9398 return Optional.none();
9402 const namedEvents = (name, handlers) => derive$1([config(name, handlers)]);
9403 const unnamedEvents = handlers => namedEvents(generate$6('unnamed-events'), handlers);
9404 const SimpleBehaviours = {
9409 const ExclusivityChannel = generate$6('tooltip.exclusive');
9410 const ShowTooltipEvent = generate$6('tooltip.show');
9411 const HideTooltipEvent = generate$6('tooltip.hide');
9413 const hideAllExclusive = (component, _tConfig, _tState) => {
9414 component.getSystem().broadcastOn([ExclusivityChannel], {});
9416 const setComponents = (component, tConfig, tState, specs) => {
9417 tState.getTooltip().each(tooltip => {
9418 if (tooltip.getSystem().isConnected()) {
9419 Replacing.set(tooltip, specs);
9424 var TooltippingApis = /*#__PURE__*/Object.freeze({
9426 hideAllExclusive: hideAllExclusive,
9427 setComponents: setComponents
9430 const events$9 = (tooltipConfig, state) => {
9431 const hide = comp => {
9432 state.getTooltip().each(p => {
9434 tooltipConfig.onHide(comp, p);
9435 state.clearTooltip();
9439 const show = comp => {
9440 if (!state.isShowing()) {
9441 hideAllExclusive(comp);
9442 const sink = tooltipConfig.lazySink(comp).getOrDie();
9443 const popup = comp.getSystem().build({
9444 dom: tooltipConfig.tooltipDom,
9445 components: tooltipConfig.tooltipComponents,
9446 events: derive$2(tooltipConfig.mode === 'normal' ? [
9447 run$1(mouseover(), _ => {
9448 emit(comp, ShowTooltipEvent);
9450 run$1(mouseout(), _ => {
9451 emit(comp, HideTooltipEvent);
9454 behaviours: derive$1([Replacing.config({})])
9456 state.setTooltip(popup);
9457 attach(sink, popup);
9458 tooltipConfig.onShow(comp, popup);
9459 Positioning.position(sink, popup, { anchor: tooltipConfig.anchor(comp) });
9462 return derive$2(flatten([
9464 run$1(ShowTooltipEvent, comp => {
9465 state.resetTimer(() => {
9467 }, tooltipConfig.delay);
9469 run$1(HideTooltipEvent, comp => {
9470 state.resetTimer(() => {
9472 }, tooltipConfig.delay);
9474 run$1(receive(), (comp, message) => {
9475 const receivingData = message;
9476 if (!receivingData.universal) {
9477 if (contains$2(receivingData.channels, ExclusivityChannel)) {
9482 runOnDetached(comp => {
9486 tooltipConfig.mode === 'normal' ? [
9487 run$1(focusin(), comp => {
9488 emit(comp, ShowTooltipEvent);
9490 run$1(postBlur(), comp => {
9491 emit(comp, HideTooltipEvent);
9493 run$1(mouseover(), comp => {
9494 emit(comp, ShowTooltipEvent);
9496 run$1(mouseout(), comp => {
9497 emit(comp, HideTooltipEvent);
9500 run$1(highlight$1(), (comp, _se) => {
9501 emit(comp, ShowTooltipEvent);
9503 run$1(dehighlight$1(), comp => {
9504 emit(comp, HideTooltipEvent);
9510 var ActiveTooltipping = /*#__PURE__*/Object.freeze({
9515 var TooltippingSchema = [
9516 required$1('lazySink'),
9517 required$1('tooltipDom'),
9518 defaulted('exclusive', true),
9519 defaulted('tooltipComponents', []),
9520 defaulted('delay', 300),
9521 defaultedStringEnum('mode', 'normal', [
9525 defaulted('anchor', comp => ({
9547 onHandler('onHide'),
9551 const init$b = () => {
9552 const timer = value$2();
9553 const popup = value$2();
9554 const clearTimer = () => {
9555 timer.on(clearTimeout);
9557 const resetTimer = (f, delay) => {
9559 timer.set(setTimeout(f, delay));
9561 const readState = constant$1('not-implemented');
9563 getTooltip: popup.get,
9564 isShowing: popup.isSet,
9565 setTooltip: popup.set,
9566 clearTooltip: popup.clear,
9573 var TooltippingState = /*#__PURE__*/Object.freeze({
9578 const Tooltipping = create$4({
9579 fields: TooltippingSchema,
9580 name: 'tooltipping',
9581 active: ActiveTooltipping,
9582 state: TooltippingState,
9583 apis: TooltippingApis
9586 const escape = text => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
9588 const ReadOnlyChannel = 'silver.readonly';
9589 const ReadOnlyDataSchema = objOf([requiredBoolean('readonly')]);
9590 const broadcastReadonly = (uiComponents, readonly) => {
9591 const outerContainer = uiComponents.outerContainer;
9592 const target = outerContainer.element;
9594 uiComponents.mothership.broadcastOn([dismissPopups()], { target });
9595 uiComponents.uiMothership.broadcastOn([dismissPopups()], { target });
9597 uiComponents.mothership.broadcastOn([ReadOnlyChannel], { readonly });
9598 uiComponents.uiMothership.broadcastOn([ReadOnlyChannel], { readonly });
9600 const setupReadonlyModeSwitch = (editor, uiComponents) => {
9601 editor.on('init', () => {
9602 if (editor.mode.isReadOnly()) {
9603 broadcastReadonly(uiComponents, true);
9606 editor.on('SwitchMode', () => broadcastReadonly(uiComponents, editor.mode.isReadOnly()));
9607 if (isReadOnly(editor)) {
9608 editor.mode.set('readonly');
9611 const receivingConfig = () => Receiving.config({
9613 [ReadOnlyChannel]: {
9614 schema: ReadOnlyDataSchema,
9615 onReceive: (comp, data) => {
9616 Disabling.set(comp, data.readonly);
9622 const item = disabled => Disabling.config({
9624 disableClass: 'tox-collection__item--state-disabled'
9626 const button = disabled => Disabling.config({ disabled });
9627 const splitButton = disabled => Disabling.config({
9629 disableClass: 'tox-tbtn--disabled'
9631 const toolbarButton = disabled => Disabling.config({
9633 disableClass: 'tox-tbtn--disabled',
9636 const DisablingConfigs = {
9643 const runWithApi = (info, comp) => {
9644 const api = info.getApi(comp);
9649 const onControlAttached = (info, editorOffCell) => runOnAttached(comp => {
9650 const run = runWithApi(info, comp);
9652 const onDestroy = info.onSetup(api);
9653 if (isFunction(onDestroy)) {
9654 editorOffCell.set(onDestroy);
9658 const onControlDetached = (getApi, editorOffCell) => runOnDetached(comp => runWithApi(getApi, comp)(editorOffCell.get()));
9660 const onMenuItemExecute = (info, itemResponse) => runOnExecute$1((comp, simulatedEvent) => {
9661 runWithApi(info, comp)(info.onAction);
9662 if (!info.triggersSubmenu && itemResponse === ItemResponse$1.CLOSE_ON_EXECUTE) {
9663 if (comp.getSystem().isConnected()) {
9664 emit(comp, sandboxClose());
9666 simulatedEvent.stop();
9669 const menuItemEventOrder = {
9672 'alloy.base.behaviour',
9678 const componentRenderPipeline = cat;
9679 const renderCommonItem = (spec, structure, itemResponse, providersBackstage) => {
9680 const editorOffCell = Cell(noop);
9684 components: componentRenderPipeline(structure.optComponents),
9686 eventOrder: menuItemEventOrder,
9687 hasSubmenu: spec.triggersSubmenu,
9688 itemBehaviours: derive$1([
9689 config('item-events', [
9690 onMenuItemExecute(spec, itemResponse),
9691 onControlAttached(spec, editorOffCell),
9692 onControlDetached(spec, editorOffCell)
9694 DisablingConfigs.item(() => !spec.enabled || providersBackstage.isDisabled()),
9696 Replacing.config({})
9697 ].concat(spec.itemBehaviours))
9700 const buildData = source => ({
9701 value: source.value,
9703 text: source.text.getOr(''),
9708 const convertText = source => {
9709 const isMac = global$5.os.isMacOS() || global$5.os.isiOS();
9715 access: '\u2303\u2325'
9721 const replace = isMac ? mac : other;
9722 const shortcut = source.split('+');
9723 const updated = map$2(shortcut, segment => {
9724 const search = segment.toLowerCase().trim();
9725 return has$2(replace, search) ? replace[search] : segment;
9727 return isMac ? updated.join('') : updated.join('+');
9730 const renderIcon$1 = (name, icons, classes = [iconClass]) => render$3(name, {
9734 const renderText = text => ({
9737 classes: [textClass]
9739 components: [text$2(global$8.translate(text))]
9741 const renderHtml = (html, classes) => ({
9748 const renderStyledText = (style, text) => ({
9751 classes: [textClass]
9756 styles: style.styles
9758 components: [text$2(global$8.translate(text))]
9761 const renderShortcut = shortcut => ({
9764 classes: [accessoryClass]
9766 components: [text$2(convertText(shortcut))]
9768 const renderCheckmark = icons => renderIcon$1('checkmark', icons, [checkmarkClass]);
9769 const renderSubmenuCaret = icons => renderIcon$1('chevron-right', icons, [caretClass]);
9770 const renderDownwardsCaret = icons => renderIcon$1('chevron-down', icons, [caretClass]);
9771 const renderContainer = (container, components) => {
9772 const directionClass = container.direction === 'vertical' ? containerColumnClass : containerRowClass;
9773 const alignClass = container.align === 'left' ? containerAlignLeftClass : containerAlignRightClass;
9774 const getValignClass = () => {
9775 switch (container.valign) {
9777 return containerValignTopClass;
9779 return containerValignMiddleClass;
9781 return containerValignBottomClass;
9797 const renderImage = (src, classes, alt) => ({
9808 const renderColorStructure = (item, providerBackstage, fallbackIcon) => {
9809 const colorPickerCommand = 'custom';
9810 const removeColorCommand = 'remove';
9811 const itemText = item.ariaLabel;
9812 const itemValue = item.value;
9813 const iconSvg = item.iconContent.map(name => getOr(name, providerBackstage.icons, fallbackIcon));
9814 const getDom = () => {
9815 const common = colorClass;
9816 const icon = iconSvg.getOr('');
9817 const attributes = itemText.map(text => ({ title: providerBackstage.translate(text) })).getOr({});
9823 if (itemValue === colorPickerCommand) {
9829 'tox-swatches__picker-btn'
9833 } else if (itemValue === removeColorCommand) {
9838 'tox-swatch--remove'
9842 } else if (isNonNullable(itemValue)) {
9846 ...baseDom.attributes,
9847 'data-mce-color': itemValue
9849 styles: { 'background-color': itemValue }
9860 const renderItemDomStructure = ariaLabel => {
9861 const domTitle = ariaLabel.map(label => ({ attributes: { title: global$8.translate(label) } })).getOr({});
9871 const renderNormalItemStructure = (info, providersBackstage, renderIcons, fallbackIcon) => {
9874 classes: [iconClass]
9876 const renderIcon = iconName => render$3(iconName, iconSpec, providersBackstage.icons, fallbackIcon);
9877 const renderEmptyIcon = () => Optional.some({ dom: iconSpec });
9878 const leftIcon = renderIcons ? info.iconContent.map(renderIcon).orThunk(renderEmptyIcon) : Optional.none();
9879 const checkmark = info.checkMark;
9880 const textRender = Optional.from(info.meta).fold(() => renderText, meta => has$2(meta, 'style') ? curry(renderStyledText, meta.style) : renderText);
9881 const content = info.htmlContent.fold(() => info.textContent.map(textRender), html => Optional.some(renderHtml(html, [textClass])));
9883 dom: renderItemDomStructure(info.ariaLabel),
9887 info.shortcutContent.map(renderShortcut),
9894 const renderItemStructure = (info, providersBackstage, renderIcons, fallbackIcon = Optional.none()) => {
9895 if (info.presets === 'color') {
9896 return renderColorStructure(info, providersBackstage, fallbackIcon);
9898 return renderNormalItemStructure(info, providersBackstage, renderIcons, fallbackIcon);
9902 const tooltipBehaviour = (meta, sharedBackstage) => get$g(meta, 'tooltipWorker').map(tooltipWorker => [Tooltipping.config({
9903 lazySink: sharedBackstage.getSink,
9906 classes: ['tox-tooltip-worker-container']
9908 tooltipComponents: [],
9912 overrides: { maxHeightFunction: expandable$1 }
9914 mode: 'follow-highlight',
9915 onShow: (component, _tooltip) => {
9916 tooltipWorker(elm => {
9917 Tooltipping.setComponents(component, [external$1({ element: SugarElement.fromDom(elm) })]);
9921 const encodeText = text => global$7.DOM.encode(text);
9922 const replaceText = (text, matchText) => {
9923 const translated = global$8.translate(text);
9924 const encoded = encodeText(translated);
9925 if (matchText.length > 0) {
9926 const escapedMatchRegex = new RegExp(escape(matchText), 'gi');
9927 return encoded.replace(escapedMatchRegex, match => `<span class="tox-autocompleter-highlight">${ match }</span>`);
9932 const renderAutocompleteItem = (spec, matchText, useText, presets, onItemValueHandler, itemResponse, sharedBackstage, renderIcons = true) => {
9933 const structure = renderItemStructure({
9935 textContent: Optional.none(),
9936 htmlContent: useText ? spec.text.map(text => replaceText(text, matchText)) : Optional.none(),
9937 ariaLabel: spec.text,
9938 iconContent: spec.icon,
9939 shortcutContent: Optional.none(),
9940 checkMark: Optional.none(),
9941 caret: Optional.none(),
9943 }, sharedBackstage.providers, renderIcons, spec.icon);
9944 return renderCommonItem({
9945 data: buildData(spec),
9946 enabled: spec.enabled,
9947 getApi: constant$1({}),
9948 onAction: _api => onItemValueHandler(spec.value, spec.meta),
9949 onSetup: constant$1(noop),
9950 triggersSubmenu: false,
9951 itemBehaviours: tooltipBehaviour(spec.meta, sharedBackstage)
9952 }, structure, itemResponse, sharedBackstage.providers);
9955 const render$2 = (items, extras) => map$2(items, item => {
9956 switch (item.type) {
9957 case 'cardcontainer':
9958 return renderContainer(item, render$2(item.items, extras));
9960 return renderImage(item.src, item.classes, item.alt);
9962 const shouldHighlight = item.name.exists(name => contains$2(extras.cardText.highlightOn, name));
9963 const matchText = shouldHighlight ? Optional.from(extras.cardText.matchText).getOr('') : '';
9964 return renderHtml(replaceText(item.text, matchText), item.classes);
9967 const renderCardMenuItem = (spec, itemResponse, sharedBackstage, extras) => {
9968 const getApi = component => ({
9969 isEnabled: () => !Disabling.isDisabled(component),
9970 setEnabled: state => {
9971 Disabling.set(component, !state);
9972 each$1(descendants(component.element, '*'), elm => {
9973 component.getSystem().getByDom(elm).each(comp => {
9974 if (comp.hasConfigured(Disabling)) {
9975 Disabling.set(comp, !state);
9982 dom: renderItemDomStructure(spec.label),
9983 optComponents: [Optional.some({
9991 components: render$2(spec.items, extras)
9994 return renderCommonItem({
9996 text: Optional.none(),
9999 enabled: spec.enabled,
10001 onAction: spec.onAction,
10002 onSetup: spec.onSetup,
10003 triggersSubmenu: false,
10004 itemBehaviours: Optional.from(extras.itemBehaviours).getOr([])
10005 }, structure, itemResponse, sharedBackstage.providers);
10008 const renderChoiceItem = (spec, useText, presets, onItemValueHandler, isSelected, itemResponse, providersBackstage, renderIcons = true) => {
10009 const getApi = component => ({
10010 setActive: state => {
10011 Toggling.set(component, state);
10013 isActive: () => Toggling.isOn(component),
10014 isEnabled: () => !Disabling.isDisabled(component),
10015 setEnabled: state => Disabling.set(component, !state)
10017 const structure = renderItemStructure({
10019 textContent: useText ? spec.text : Optional.none(),
10020 htmlContent: Optional.none(),
10021 ariaLabel: spec.text,
10022 iconContent: spec.icon,
10023 shortcutContent: useText ? spec.shortcut : Optional.none(),
10024 checkMark: useText ? Optional.some(renderCheckmark(providersBackstage.icons)) : Optional.none(),
10025 caret: Optional.none(),
10027 }, providersBackstage, renderIcons);
10028 return deepMerge(renderCommonItem({
10029 data: buildData(spec),
10030 enabled: spec.enabled,
10032 onAction: _api => onItemValueHandler(spec.value),
10034 api.setActive(isSelected);
10037 triggersSubmenu: false,
10039 }, structure, itemResponse, providersBackstage), {
10041 toggleClass: tickedClass,
10042 toggleOnExecute: false,
10043 selected: spec.active,
10049 const parts$f = generate$3(owner$2(), parts$h());
10051 const hexColour = value => ({ value });
10052 const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
10053 const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
10054 const isHexString = hex => shorthandRegex.test(hex) || longformRegex.test(hex);
10055 const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
10056 const fromString$1 = hex => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
10057 const getLongForm = hex => {
10058 const hexString = hex.value.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
10059 return { value: hexString };
10061 const extractValues = hex => {
10062 const longForm = getLongForm(hex);
10063 const splitForm = longformRegex.exec(longForm.value);
10064 return splitForm === null ? [
10071 const toHex = component => {
10072 const hex = component.toString(16);
10073 return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
10075 const fromRgba = rgbaColour => {
10076 const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
10077 return hexColour(value);
10080 const min = Math.min;
10081 const max = Math.max;
10082 const round$1 = Math.round;
10083 const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
10084 const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
10085 const rgbaColour = (red, green, blue, alpha) => ({
10091 const isRgbaComponent = value => {
10092 const num = parseInt(value, 10);
10093 return num.toString() === value && num >= 0 && num <= 255;
10095 const fromHsv = hsv => {
10099 const hue = (hsv.hue || 0) % 360;
10100 let saturation = hsv.saturation / 100;
10101 let brightness = hsv.value / 100;
10102 saturation = max(0, min(saturation, 1));
10103 brightness = max(0, min(brightness, 1));
10104 if (saturation === 0) {
10105 r = g = b = round$1(255 * brightness);
10106 return rgbaColour(r, g, b, 1);
10108 const side = hue / 60;
10109 const chroma = brightness * saturation;
10110 const x = chroma * (1 - Math.abs(side % 2 - 1));
10111 const match = brightness - chroma;
10112 switch (Math.floor(side)) {
10146 r = round$1(255 * (r + match));
10147 g = round$1(255 * (g + match));
10148 b = round$1(255 * (b + match));
10149 return rgbaColour(r, g, b, 1);
10151 const fromHex = hexColour => {
10152 const result = extractValues(hexColour);
10153 const red = parseInt(result[1], 16);
10154 const green = parseInt(result[2], 16);
10155 const blue = parseInt(result[3], 16);
10156 return rgbaColour(red, green, blue, 1);
10158 const fromStringValues = (red, green, blue, alpha) => {
10159 const r = parseInt(red, 10);
10160 const g = parseInt(green, 10);
10161 const b = parseInt(blue, 10);
10162 const a = parseFloat(alpha);
10163 return rgbaColour(r, g, b, a);
10165 const fromString = rgbaString => {
10166 if (rgbaString === 'transparent') {
10167 return Optional.some(rgbaColour(0, 0, 0, 0));
10169 const rgbMatch = rgbRegex.exec(rgbaString);
10170 if (rgbMatch !== null) {
10171 return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
10173 const rgbaMatch = rgbaRegex.exec(rgbaString);
10174 if (rgbaMatch !== null) {
10175 return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
10177 return Optional.none();
10179 const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
10180 const red = rgbaColour(255, 0, 0, 1);
10182 const fireSkinLoaded$1 = editor => {
10183 editor.dispatch('SkinLoaded');
10185 const fireSkinLoadError$1 = (editor, error) => {
10186 editor.dispatch('SkinLoadError', error);
10188 const fireResizeEditor = editor => {
10189 editor.dispatch('ResizeEditor');
10191 const fireResizeContent = (editor, e) => {
10192 editor.dispatch('ResizeContent', e);
10194 const fireScrollContent = (editor, e) => {
10195 editor.dispatch('ScrollContent', e);
10197 const fireTextColorChange = (editor, data) => {
10198 editor.dispatch('TextColorChange', data);
10200 const fireAfterProgressState = (editor, state) => {
10201 editor.dispatch('AfterProgressState', { state });
10203 const fireResolveName = (editor, node) => editor.dispatch('ResolveName', {
10204 name: node.nodeName.toLowerCase(),
10208 const hsvColour = (hue, saturation, value) => ({
10213 const fromRgb = rgbaColour => {
10217 const r = rgbaColour.red / 255;
10218 const g = rgbaColour.green / 255;
10219 const b = rgbaColour.blue / 255;
10220 const minRGB = Math.min(r, Math.min(g, b));
10221 const maxRGB = Math.max(r, Math.max(g, b));
10222 if (minRGB === maxRGB) {
10224 return hsvColour(0, 0, v * 100);
10226 const d = r === minRGB ? g - b : b === minRGB ? r - g : b - r;
10227 h = r === minRGB ? 3 : b === minRGB ? 1 : 5;
10228 h = 60 * (h - d / (maxRGB - minRGB));
10229 s = (maxRGB - minRGB) / maxRGB;
10231 return hsvColour(Math.round(h), Math.round(s * 100), Math.round(v * 100));
10234 const hexToHsv = hex => fromRgb(fromHex(hex));
10235 const hsvToHex = hsv => fromRgba(fromHsv(hsv));
10236 const anyToHex = color => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
10237 const canvas = document.createElement('canvas');
10240 const canvasContext = canvas.getContext('2d');
10241 canvasContext.clearRect(0, 0, canvas.width, canvas.height);
10242 canvasContext.fillStyle = '#FFFFFF';
10243 canvasContext.fillStyle = color;
10244 canvasContext.fillRect(0, 0, 1, 1);
10245 const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
10250 return fromRgba(rgbaColour(r, g, b, a));
10253 var global$4 = tinymce.util.Tools.resolve('tinymce.util.LocalStorage');
10255 const storageName = 'tinymce-custom-colors';
10256 const ColorCache = (max = 10) => {
10257 const storageString = global$4.getItem(storageName);
10258 const localstorage = isString(storageString) ? JSON.parse(storageString) : [];
10259 const prune = list => {
10260 const diff = max - list.length;
10261 return diff < 0 ? list.slice(0, max) : list;
10263 const cache = prune(localstorage);
10264 const add = key => {
10265 indexOf(cache, key).each(remove);
10266 cache.unshift(key);
10267 if (cache.length > max) {
10270 global$4.setItem(storageName, JSON.stringify(cache));
10272 const remove = idx => {
10273 cache.splice(idx, 1);
10275 const state = () => cache.slice(0);
10282 const colorCache = ColorCache(10);
10283 const calcCols = colors => Math.max(5, Math.ceil(Math.sqrt(colors)));
10284 const mapColors = colorMap => {
10286 for (let i = 0; i < colorMap.length; i += 2) {
10288 text: colorMap[i + 1],
10289 value: '#' + anyToHex(colorMap[i]).value,
10295 const option$1 = name => editor => editor.options.get(name);
10296 const register$d = editor => {
10297 const registerOption = editor.options.register;
10298 registerOption('color_map', {
10299 processor: value => {
10300 if (isArrayOf(value, isString)) {
10302 value: mapColors(value),
10308 message: 'Must be an array of strings.'
10359 registerOption('color_cols', {
10360 processor: 'number',
10361 default: calcCols(getColors$2(editor).length)
10363 registerOption('custom_colors', {
10364 processor: 'boolean',
10368 const getColorCols$1 = option$1('color_cols');
10369 const hasCustomColors$1 = option$1('custom_colors');
10370 const getColors$2 = option$1('color_map');
10371 const getCurrentColors = () => map$2(colorCache.state(), color => ({
10372 type: 'choiceitem',
10376 const addColor = color => {
10377 colorCache.add(color);
10380 const fallbackColor = '#000000';
10381 const hasStyleApi = node => isNonNullable(node.style);
10382 const getCurrentColor = (editor, format) => {
10384 editor.dom.getParents(editor.selection.getStart(), elm => {
10385 const value = hasStyleApi(elm) ? elm.style[format === 'forecolor' ? 'color' : 'backgroundColor'] : null;
10387 color = color ? color : value;
10390 return Optional.from(color);
10392 const applyFormat = (editor, format, value) => {
10393 editor.undoManager.transact(() => {
10395 editor.formatter.apply(format, { value });
10396 editor.nodeChanged();
10399 const removeFormat = (editor, format) => {
10400 editor.undoManager.transact(() => {
10402 editor.formatter.remove(format, { value: null }, undefined, true);
10403 editor.nodeChanged();
10406 const registerCommands = editor => {
10407 editor.addCommand('mceApplyTextcolor', (format, value) => {
10408 applyFormat(editor, format, value);
10410 editor.addCommand('mceRemoveTextcolor', format => {
10411 removeFormat(editor, format);
10414 const getAdditionalColors = hasCustom => {
10415 const type = 'choiceitem';
10418 text: 'Remove color',
10419 icon: 'color-swatch-remove-color',
10424 text: 'Custom color',
10425 icon: 'color-picker',
10428 return hasCustom ? [
10433 const applyColor = (editor, format, value, onChoice) => {
10434 if (value === 'custom') {
10435 const dialog = colorPickerDialog(editor);
10436 dialog(colorOpt => {
10437 colorOpt.each(color => {
10439 editor.execCommand('mceApplyTextcolor', format, color);
10443 } else if (value === 'remove') {
10445 editor.execCommand('mceRemoveTextcolor', format);
10448 editor.execCommand('mceApplyTextcolor', format, value);
10451 const getColors$1 = (colors, hasCustom) => colors.concat(getCurrentColors().concat(getAdditionalColors(hasCustom)));
10452 const getFetch$1 = (colors, hasCustom) => callback => {
10453 callback(getColors$1(colors, hasCustom));
10455 const setIconColor = (splitButtonApi, name, newColor) => {
10456 const id = name === 'forecolor' ? 'tox-icon-text-color__color' : 'tox-icon-highlight-bg-color__color';
10457 splitButtonApi.setIconFill(id, newColor);
10459 const registerTextColorButton = (editor, name, format, tooltip, lastColor) => {
10460 editor.ui.registry.addSplitButton(name, {
10463 icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
10465 const optCurrentRgb = getCurrentColor(editor, format);
10466 return optCurrentRgb.bind(currentRgb => fromString(currentRgb).map(rgba => {
10467 const currentHex = fromRgba(rgba).value;
10468 return contains$1(value.toLowerCase(), currentHex);
10471 columns: getColorCols$1(editor),
10472 fetch: getFetch$1(getColors$2(editor), hasCustomColors$1(editor)),
10473 onAction: _splitButtonApi => {
10474 applyColor(editor, format, lastColor.get(), noop);
10476 onItemAction: (_splitButtonApi, value) => {
10477 applyColor(editor, format, value, newColor => {
10478 lastColor.set(newColor);
10479 fireTextColorChange(editor, {
10485 onSetup: splitButtonApi => {
10486 setIconColor(splitButtonApi, name, lastColor.get());
10487 const handler = e => {
10488 if (e.name === name) {
10489 setIconColor(splitButtonApi, e.name, e.color);
10492 editor.on('TextColorChange', handler);
10494 editor.off('TextColorChange', handler);
10499 const registerTextColorMenuItem = (editor, name, format, text) => {
10500 editor.ui.registry.addNestedMenuItem(name, {
10502 icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
10503 getSubmenuItems: () => [{
10504 type: 'fancymenuitem',
10505 fancytype: 'colorswatch',
10506 onAction: data => {
10507 applyColor(editor, format, data.value, noop);
10512 const colorPickerDialog = editor => (callback, value) => {
10513 let isValid = false;
10514 const onSubmit = api => {
10515 const data = api.getData();
10516 const hex = data.colorpicker;
10518 callback(Optional.from(hex));
10521 editor.windowManager.alert(editor.translate([
10522 'Invalid hex color code: {0}',
10527 const onAction = (_api, details) => {
10528 if (details.name === 'hex-valid') {
10529 isValid = details.value;
10532 const initialData = { colorpicker: value };
10533 editor.windowManager.open({
10534 title: 'Color Picker',
10539 type: 'colorpicker',
10540 name: 'colorpicker',
10562 callback(Optional.none());
10566 const register$c = editor => {
10567 registerCommands(editor);
10568 const lastForeColor = Cell(fallbackColor);
10569 const lastBackColor = Cell(fallbackColor);
10570 registerTextColorButton(editor, 'forecolor', 'forecolor', 'Text color', lastForeColor);
10571 registerTextColorButton(editor, 'backcolor', 'hilitecolor', 'Background color', lastBackColor);
10572 registerTextColorMenuItem(editor, 'forecolor', 'forecolor', 'Text color');
10573 registerTextColorMenuItem(editor, 'backcolor', 'hilitecolor', 'Background color');
10576 const createPartialChoiceMenu = (value, items, onItemValueHandler, columns, presets, itemResponse, select, providersBackstage) => {
10577 const hasIcons = menuHasIcons(items);
10578 const presetItemTypes = presets !== 'color' ? 'normal' : 'color';
10579 const alloyItems = createChoiceItems(items, onItemValueHandler, columns, presetItemTypes, itemResponse, select, providersBackstage);
10580 const menuLayout = { menuType: presets };
10581 return createPartialMenuWithAlloyItems(value, hasIcons, alloyItems, columns, menuLayout);
10583 const createChoiceItems = (items, onItemValueHandler, columns, itemPresets, itemResponse, select, providersBackstage) => cat(map$2(items, item => {
10584 if (item.type === 'choiceitem') {
10585 return createChoiceMenuItem(item).fold(handleError, d => Optional.some(renderChoiceItem(d, columns === 1, itemPresets, onItemValueHandler, select(d.value), itemResponse, providersBackstage, menuHasIcons(items))));
10587 return Optional.none();
10591 const deriveMenuMovement = (columns, presets) => {
10592 const menuMarkers = markers(presets);
10593 if (columns === 1) {
10598 } else if (columns === 'auto') {
10601 selector: '.' + menuMarkers.item,
10608 const rowClass = presets === 'color' ? 'tox-swatches__row' : 'tox-collection__group';
10611 rowSelector: '.' + rowClass
10615 const deriveCollectionMovement = (columns, presets) => {
10616 if (columns === 1) {
10620 selector: '.tox-collection__item'
10622 } else if (columns === 'auto') {
10625 selector: '.' + 'tox-collection__item',
10635 row: presets === 'color' ? '.tox-swatches__row' : '.tox-collection__group',
10636 cell: presets === 'color' ? `.${ colorClass }` : `.${ selectableClass }`
10642 const renderColorSwatchItem = (spec, backstage) => {
10643 const items = getColorItems(spec, backstage);
10644 const columns = backstage.colorinput.getColorCols();
10645 const presets = 'color';
10646 const menuSpec = createPartialChoiceMenu(generate$6('menu-value'), items, value => {
10647 spec.onAction({ value });
10648 }, columns, presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, backstage.shared.providers);
10649 const widgetSpec = {
10651 markers: markers(presets),
10652 movement: deriveMenuMovement(columns, presets)
10656 data: { value: generate$6('widget-id') },
10659 classes: ['tox-fancymenuitem']
10662 components: [parts$f.widget(Menu.sketch(widgetSpec))]
10665 const getColorItems = (spec, backstage) => {
10666 const useCustomColors = spec.initData.allowCustomColors && backstage.colorinput.hasCustomColors();
10667 return spec.initData.colors.fold(() => getColors$1(backstage.colorinput.getColors(), useCustomColors), colors => colors.concat(getAdditionalColors(useCustomColors)));
10670 const cellOverEvent = generate$6('cell-over');
10671 const cellExecuteEvent = generate$6('cell-execute');
10672 const makeCell = (row, col, labelId) => {
10673 const emitCellOver = c => emitWith(c, cellOverEvent, {
10677 const emitExecute = c => emitWith(c, cellExecuteEvent, {
10681 const onClick = (c, se) => {
10690 ['aria-labelledby']: labelId
10693 behaviours: derive$1([
10694 config('insert-table-picker-cell', [
10695 run$1(mouseover(), Focusing.focus),
10696 run$1(execute$5(), emitExecute),
10697 run$1(click(), onClick),
10698 run$1(tap(), onClick)
10701 toggleClass: 'tox-insert-table-picker__selected',
10702 toggleOnExecute: false
10704 Focusing.config({ onFocus: emitCellOver })
10708 const makeCells = (labelId, numRows, numCols) => {
10710 for (let i = 0; i < numRows; i++) {
10712 for (let j = 0; j < numCols; j++) {
10713 row.push(makeCell(i, j, labelId));
10719 const selectCells = (cells, selectedRow, selectedColumn, numRows, numColumns) => {
10720 for (let i = 0; i < numRows; i++) {
10721 for (let j = 0; j < numColumns; j++) {
10722 Toggling.set(cells[i][j], i <= selectedRow && j <= selectedColumn);
10726 const makeComponents = cells => bind$3(cells, cellRow => map$2(cellRow, premade));
10727 const makeLabelText = (row, col) => text$2(`${ col }x${ row }`);
10728 const renderInsertTableMenuItem = spec => {
10729 const numRows = 10;
10730 const numColumns = 10;
10731 const sizeLabelId = generate$6('size-label');
10732 const cells = makeCells(sizeLabelId, numRows, numColumns);
10733 const emptyLabelText = makeLabelText(0, 0);
10734 const memLabel = record({
10737 classes: ['tox-insert-table-picker__label'],
10738 attributes: { id: sizeLabelId }
10740 components: [emptyLabelText],
10741 behaviours: derive$1([Replacing.config({})])
10745 data: { value: generate$6('widget-id') },
10748 classes: ['tox-fancymenuitem']
10751 components: [parts$f.widget({
10754 classes: ['tox-insert-table-picker']
10756 components: makeComponents(cells).concat(memLabel.asSpec()),
10757 behaviours: derive$1([
10758 config('insert-table-picker', [
10759 runOnAttached(c => {
10760 Replacing.set(memLabel.get(c), [emptyLabelText]);
10762 runWithTarget(cellOverEvent, (c, t, e) => {
10763 const {row, col} = e.event;
10764 selectCells(cells, row, col, numRows, numColumns);
10765 Replacing.set(memLabel.get(c), [makeLabelText(row + 1, col + 1)]);
10767 runWithTarget(cellExecuteEvent, (c, _, e) => {
10768 const {row, col} = e.event;
10771 numColumns: col + 1
10773 emit(c, sandboxClose());
10782 selector: '[role="button"]'
10789 const fancyMenuItems = {
10790 inserttable: renderInsertTableMenuItem,
10791 colorswatch: renderColorSwatchItem
10793 const renderFancyMenuItem = (spec, backstage) => get$g(fancyMenuItems, spec.fancytype).map(render => render(spec, backstage));
10795 const renderNestedItem = (spec, itemResponse, providersBackstage, renderIcons = true, downwardsCaret = false) => {
10796 const caret = downwardsCaret ? renderDownwardsCaret(providersBackstage.icons) : renderSubmenuCaret(providersBackstage.icons);
10797 const getApi = component => ({
10798 isEnabled: () => !Disabling.isDisabled(component),
10799 setEnabled: state => Disabling.set(component, !state)
10801 const structure = renderItemStructure({
10803 iconContent: spec.icon,
10804 textContent: spec.text,
10805 htmlContent: Optional.none(),
10806 ariaLabel: spec.text,
10807 caret: Optional.some(caret),
10808 checkMark: Optional.none(),
10809 shortcutContent: spec.shortcut
10810 }, providersBackstage, renderIcons);
10811 return renderCommonItem({
10812 data: buildData(spec),
10814 enabled: spec.enabled,
10816 onSetup: spec.onSetup,
10817 triggersSubmenu: true,
10819 }, structure, itemResponse, providersBackstage);
10822 const renderNormalItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
10823 const getApi = component => ({
10824 isEnabled: () => !Disabling.isDisabled(component),
10825 setEnabled: state => Disabling.set(component, !state)
10827 const structure = renderItemStructure({
10829 iconContent: spec.icon,
10830 textContent: spec.text,
10831 htmlContent: Optional.none(),
10832 ariaLabel: spec.text,
10833 caret: Optional.none(),
10834 checkMark: Optional.none(),
10835 shortcutContent: spec.shortcut
10836 }, providersBackstage, renderIcons);
10837 return renderCommonItem({
10838 data: buildData(spec),
10840 enabled: spec.enabled,
10841 onAction: spec.onAction,
10842 onSetup: spec.onSetup,
10843 triggersSubmenu: false,
10845 }, structure, itemResponse, providersBackstage);
10848 const renderSeparatorItem = spec => ({
10857 components: spec.text.map(text$2).toArray()
10860 const renderToggleMenuItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
10861 const getApi = component => ({
10862 setActive: state => {
10863 Toggling.set(component, state);
10865 isActive: () => Toggling.isOn(component),
10866 isEnabled: () => !Disabling.isDisabled(component),
10867 setEnabled: state => Disabling.set(component, !state)
10869 const structure = renderItemStructure({
10870 iconContent: spec.icon,
10871 textContent: spec.text,
10872 htmlContent: Optional.none(),
10873 ariaLabel: spec.text,
10874 checkMark: Optional.some(renderCheckmark(providersBackstage.icons)),
10875 caret: Optional.none(),
10876 shortcutContent: spec.shortcut,
10879 }, providersBackstage, renderIcons);
10880 return deepMerge(renderCommonItem({
10881 data: buildData(spec),
10882 enabled: spec.enabled,
10884 onAction: spec.onAction,
10885 onSetup: spec.onSetup,
10886 triggersSubmenu: false,
10888 }, structure, itemResponse, providersBackstage), {
10890 toggleClass: tickedClass,
10891 toggleOnExecute: false,
10892 selected: spec.active
10897 const autocomplete = renderAutocompleteItem;
10898 const separator$3 = renderSeparatorItem;
10899 const normal = renderNormalItem;
10900 const nested = renderNestedItem;
10901 const toggle$1 = renderToggleMenuItem;
10902 const fancy = renderFancyMenuItem;
10903 const card = renderCardMenuItem;
10905 const getCoupled = (component, coupleConfig, coupleState, name) => coupleState.getOrCreate(component, coupleConfig, name);
10906 const getExistingCoupled = (component, coupleConfig, coupleState, name) => coupleState.getExisting(component, coupleConfig, name);
10908 var CouplingApis = /*#__PURE__*/Object.freeze({
10910 getCoupled: getCoupled,
10911 getExistingCoupled: getExistingCoupled
10914 var CouplingSchema = [requiredOf('others', setOf(Result.value, anyValue()))];
10916 const init$a = () => {
10917 const coupled = {};
10918 const lookupCoupled = (coupleConfig, coupledName) => {
10919 const available = keys(coupleConfig.others);
10920 if (available.length === 0) {
10921 throw new Error('Cannot find any known coupled components');
10923 return get$g(coupled, coupledName);
10926 const getOrCreate = (component, coupleConfig, name) => {
10927 return lookupCoupled(coupleConfig, name).getOrThunk(() => {
10928 const builder = get$g(coupleConfig.others, name).getOrDie('No information found for coupled component: ' + name);
10929 const spec = builder(component);
10930 const built = component.getSystem().build(spec);
10931 coupled[name] = built;
10935 const getExisting = (component, coupleConfig, name) => {
10936 return lookupCoupled(coupleConfig, name).orThunk(() => {
10937 get$g(coupleConfig.others, name).getOrDie('No information found for coupled component: ' + name);
10938 return Optional.none();
10941 const readState = constant$1({});
10949 var CouplingState = /*#__PURE__*/Object.freeze({
10954 const Coupling = create$4({
10955 fields: CouplingSchema,
10957 apis: CouplingApis,
10958 state: CouplingState
10961 const nu$3 = baseFn => {
10962 let data = Optional.none();
10963 let callbacks = [];
10964 const map = f => nu$3(nCallback => {
10966 nCallback(f(data));
10969 const get = nCallback => {
10973 callbacks.push(nCallback);
10978 data = Optional.some(x);
10983 const isReady = () => data.isSome();
10984 const run = cbs => {
10987 const call = cb => {
11001 const pure$1 = a => nu$3(callback => {
11004 const LazyValue = {
11009 const errorReporter = err => {
11014 const make$5 = run => {
11015 const get = callback => {
11016 run().then(callback, errorReporter);
11018 const map = fab => {
11019 return make$5(() => run().then(fab));
11021 const bind = aFutureB => {
11022 return make$5(() => run().then(v => aFutureB(v).toPromise()));
11024 const anonBind = futureB => {
11025 return make$5(() => run().then(() => futureB.toPromise()));
11027 const toLazy = () => {
11028 return LazyValue.nu(get);
11030 const toCached = () => {
11032 return make$5(() => {
11033 if (cache === null) {
11039 const toPromise = run;
11050 const nu$2 = baseFn => {
11051 return make$5(() => new Promise(baseFn));
11053 const pure = a => {
11054 return make$5(() => Promise.resolve(a));
11061 const suffix = constant$1('sink');
11062 const partType$1 = constant$1(optional({
11064 overrides: constant$1({
11065 dom: { tag: 'div' },
11066 behaviours: derive$1([Positioning.config({ useFixed: always })]),
11069 cutter(mousedown()),
11075 const getAnchor = (detail, component) => {
11076 const hotspot = detail.getHotspot(component).getOr(component);
11077 const type = 'hotspot';
11078 const overrides = detail.getAnchorOverrides();
11079 return detail.layouts.fold(() => ({
11090 const fetch = (detail, mapFetch, component) => {
11091 const fetcher = detail.fetch;
11092 return fetcher(component).map(mapFetch);
11094 const openF = (detail, mapFetch, anchor, component, sandbox, externals, highlightOnOpen) => {
11095 const futureData = fetch(detail, mapFetch, component);
11096 const getLazySink = getSink(component, detail);
11097 return futureData.map(tdata => tdata.bind(data => Optional.from(tieredMenu.sketch({
11098 ...externals.menu(),
11099 uid: generate$5(''),
11102 onOpenMenu: (tmenu, menu) => {
11103 const sink = getLazySink().getOrDie();
11104 Positioning.position(sink, menu, { anchor });
11105 Sandboxing.decloak(sandbox);
11107 onOpenSubmenu: (tmenu, item, submenu) => {
11108 const sink = getLazySink().getOrDie();
11109 Positioning.position(sink, submenu, {
11115 Sandboxing.decloak(sandbox);
11117 onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
11118 const sink = getLazySink().getOrDie();
11119 Positioning.position(sink, primaryMenu, { anchor });
11120 each$1(submenuTriggers, st => {
11121 Positioning.position(sink, st.triggeredMenu, {
11124 item: st.triggeringItem
11130 Focusing.focus(component);
11131 Sandboxing.close(sandbox);
11132 return Optional.some(true);
11136 const open = (detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen) => {
11137 const anchor = getAnchor(detail, hotspot);
11138 const processed = openF(detail, mapFetch, anchor, hotspot, sandbox, externals, highlightOnOpen);
11139 return processed.map(tdata => {
11141 if (Sandboxing.isOpen(sandbox)) {
11142 Sandboxing.close(sandbox);
11145 Sandboxing.cloak(sandbox);
11146 Sandboxing.open(sandbox, data);
11147 onOpenSync(sandbox);
11152 const close = (detail, mapFetch, component, sandbox, _externals, _onOpenSync, _highlightOnOpen) => {
11153 Sandboxing.close(sandbox);
11154 return Future.pure(sandbox);
11156 const togglePopup = (detail, mapFetch, hotspot, externals, onOpenSync, highlightOnOpen) => {
11157 const sandbox = Coupling.getCoupled(hotspot, 'sandbox');
11158 const showing = Sandboxing.isOpen(sandbox);
11159 const action = showing ? close : open;
11160 return action(detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen);
11162 const matchWidth = (hotspot, container, useMinWidth) => {
11163 const menu = Composing.getCurrent(container).getOr(container);
11164 const buttonWidth = get$c(hotspot.element);
11166 set$8(menu.element, 'min-width', buttonWidth + 'px');
11168 set$7(menu.element, buttonWidth);
11171 const getSink = (anyInSystem, sinkDetail) => anyInSystem.getSystem().getByUid(sinkDetail.uid + '-' + suffix()).map(internalSink => () => Result.value(internalSink)).getOrThunk(() => sinkDetail.lazySink.fold(() => () => Result.error(new Error('No internal sink is specified, nor could an external sink be found')), lazySinkFn => () => lazySinkFn(anyInSystem)));
11172 const doRepositionMenus = sandbox => {
11173 Sandboxing.getState(sandbox).each(tmenu => {
11174 tieredMenu.repositionMenus(tmenu);
11177 const makeSandbox$1 = (detail, hotspot, extras) => {
11178 const ariaControls = manager();
11179 const onOpen = (component, menu) => {
11180 const anchor = getAnchor(detail, hotspot);
11181 ariaControls.link(hotspot.element);
11182 if (detail.matchWidth) {
11183 matchWidth(anchor.hotspot, menu, detail.useMinWidth);
11185 detail.onOpen(anchor, component, menu);
11186 if (extras !== undefined && extras.onOpen !== undefined) {
11187 extras.onOpen(component, menu);
11190 const onClose = (component, menu) => {
11191 ariaControls.unlink(hotspot.element);
11192 if (extras !== undefined && extras.onClose !== undefined) {
11193 extras.onClose(component, menu);
11196 const lazySink = getSink(hotspot, detail);
11200 classes: detail.sandboxClasses,
11202 id: ariaControls.id,
11206 behaviours: SketchBehaviours.augment(detail.sandboxBehaviours, [
11207 Representing.config({
11210 initialValue: hotspot
11213 Sandboxing.config({
11216 isPartOf: (container, data, queryElem) => {
11217 return isPartOf$1(data, queryElem) || isPartOf$1(hotspot, queryElem);
11219 getAttachPoint: () => {
11220 return lazySink().getOrDie();
11225 return Sandboxing.getState(sandbox).bind(menu => Composing.getCurrent(menu));
11230 ...receivingChannel$1({ isExtraPart: never }),
11231 ...receivingChannel({ doReposition: doRepositionMenus })
11237 const repositionMenus = comp => {
11238 const sandbox = Coupling.getCoupled(comp, 'sandbox');
11239 doRepositionMenus(sandbox);
11242 const sandboxFields = () => [
11243 defaulted('sandboxClasses', []),
11244 SketchBehaviours.field('sandboxBehaviours', [
11252 const schema$k = constant$1([
11254 required$1('fetch'),
11255 onHandler('onOpen'),
11256 onKeyboardHandler('onExecute'),
11257 defaulted('getHotspot', Optional.some),
11258 defaulted('getAnchorOverrides', constant$1({})),
11260 field('dropdownBehaviours', [
11266 required$1('toggleClass'),
11267 defaulted('eventOrder', {}),
11268 option$3('lazySink'),
11269 defaulted('matchWidth', false),
11270 defaulted('useMinWidth', false),
11272 ].concat(sandboxFields()));
11273 const parts$e = constant$1([
11276 tieredMenuMarkers(),
11277 defaulted('fakeFocus', false)
11280 defaults: detail => {
11281 return { onExecute: detail.onExecute };
11287 const factory$i = (detail, components, _spec, externals) => {
11288 const lookupAttr = attr => get$g(detail.dom, 'attributes').bind(attrs => get$g(attrs, attr));
11289 const switchToMenu = sandbox => {
11290 Sandboxing.getState(sandbox).each(tmenu => {
11291 tieredMenu.highlightPrimary(tmenu);
11294 const togglePopup$1 = (dropdownComp, onOpenSync, highlightOnOpen) => {
11295 return togglePopup(detail, identity, dropdownComp, externals, onOpenSync, highlightOnOpen);
11297 const action = component => {
11298 const onOpenSync = switchToMenu;
11299 togglePopup$1(component, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
11303 if (!Toggling.isOn(comp)) {
11304 togglePopup$1(comp, noop, HighlightOnOpen.HighlightNone).get(noop);
11308 if (!Toggling.isOn(comp)) {
11309 togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).get(noop);
11313 const optSandbox = Coupling.getExistingCoupled(comp, 'sandbox');
11314 return optSandbox.fold(() => {
11315 return togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).map(noop);
11316 }, sandboxComp => {
11317 return open(detail, identity, comp, sandboxComp, externals, noop, HighlightOnOpen.HighlightMenuAndItem).map(noop);
11320 isOpen: Toggling.isOn,
11322 if (Toggling.isOn(comp)) {
11323 togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).get(noop);
11326 repositionMenus: comp => {
11327 if (Toggling.isOn(comp)) {
11328 repositionMenus(comp);
11332 const triggerExecute = (comp, _se) => {
11334 return Optional.some(true);
11340 behaviours: augment(detail.dropdownBehaviours, [
11342 toggleClass: detail.toggleClass,
11343 aria: { mode: 'expanded' }
11347 sandbox: hotspot => {
11348 return makeSandbox$1(detail, hotspot, {
11349 onOpen: () => Toggling.on(hotspot),
11350 onClose: () => Toggling.off(hotspot)
11357 onSpace: triggerExecute,
11358 onEnter: triggerExecute,
11359 onDown: (comp, _se) => {
11360 if (Dropdown.isOpen(comp)) {
11361 const sandbox = Coupling.getCoupled(comp, 'sandbox');
11362 switchToMenu(sandbox);
11364 Dropdown.open(comp);
11366 return Optional.some(true);
11368 onEscape: (comp, _se) => {
11369 if (Dropdown.isOpen(comp)) {
11370 Dropdown.close(comp);
11371 return Optional.some(true);
11373 return Optional.none();
11377 Focusing.config({})
11379 events: events$a(Optional.some(action)),
11381 ...detail.eventOrder,
11385 'alloy.base.behaviour'
11391 'aria-haspopup': 'true',
11392 ...detail.role.fold(() => ({}), role => ({ role })),
11393 ...detail.dom.tag === 'button' ? { type: lookupAttr('type').getOr('button') } : {}
11398 const Dropdown = composite({
11400 configFields: schema$k(),
11401 partFields: parts$e(),
11402 factory: factory$i,
11404 open: (apis, comp) => apis.open(comp),
11405 refetch: (apis, comp) => apis.refetch(comp),
11406 expand: (apis, comp) => apis.expand(comp),
11407 close: (apis, comp) => apis.close(comp),
11408 isOpen: (apis, comp) => apis.isOpen(comp),
11409 repositionMenus: (apis, comp) => apis.repositionMenus(comp)
11413 const identifyMenuLayout = searchMode => {
11414 switch (searchMode.searchMode) {
11415 case 'no-search': {
11416 return { menuType: 'normal' };
11420 menuType: 'searchable',
11426 const handleRefetchTrigger = originalSandboxComp => {
11427 const dropdown = Representing.getValue(originalSandboxComp);
11428 const optSearcherState = findWithinSandbox(originalSandboxComp).map(saveState);
11429 Dropdown.refetch(dropdown).get(() => {
11430 const newSandboxComp = Coupling.getCoupled(dropdown, 'sandbox');
11431 optSearcherState.each(searcherState => findWithinSandbox(newSandboxComp).each(inputComp => restoreState(inputComp, searcherState)));
11434 const handleRedirectToMenuItem = (sandboxComp, se) => {
11435 getActiveMenuItemFrom(sandboxComp).each(activeItem => {
11436 retargetAndDispatchWith(sandboxComp, activeItem.element, se.event.eventType, se.event.interactionEvent);
11439 const getActiveMenuItemFrom = sandboxComp => {
11440 return Sandboxing.getState(sandboxComp).bind(Highlighting.getHighlighted).bind(Highlighting.getHighlighted);
11442 const getSearchResults = activeMenuComp => {
11443 return has(activeMenuComp.element, searchResultsClass) ? Optional.some(activeMenuComp.element) : descendant(activeMenuComp.element, '.' + searchResultsClass);
11445 const updateAriaOnHighlight = (tmenuComp, menuComp, itemComp) => {
11446 findWithinMenu(tmenuComp).each(inputComp => {
11447 setActiveDescendant(inputComp, itemComp);
11448 const optActiveResults = getSearchResults(menuComp);
11449 optActiveResults.each(resultsElem => {
11450 getOpt(resultsElem, 'id').each(controlledId => set$9(inputComp.element, 'aria-controls', controlledId));
11453 set$9(itemComp.element, 'aria-selected', 'true');
11455 const updateAriaOnDehighlight = (tmenuComp, menuComp, itemComp) => {
11456 set$9(itemComp.element, 'aria-selected', 'false');
11458 const focusSearchField = tmenuComp => {
11459 findWithinMenu(tmenuComp).each(searcherComp => Focusing.focus(searcherComp));
11461 const getSearchPattern = dropdownComp => {
11462 const optSandboxComp = Coupling.getExistingCoupled(dropdownComp, 'sandbox');
11463 return optSandboxComp.bind(findWithinSandbox).map(saveState).map(state => state.fetchPattern).getOr('');
11467 (function (FocusMode) {
11468 FocusMode[FocusMode['ContentFocus'] = 0] = 'ContentFocus';
11469 FocusMode[FocusMode['UiFocus'] = 1] = 'UiFocus';
11470 }(FocusMode || (FocusMode = {})));
11471 const createMenuItemFromBridge = (item, itemResponse, backstage, menuHasIcons, isHorizontalMenu) => {
11472 const providersBackstage = backstage.shared.providers;
11473 const parseForHorizontalMenu = menuitem => !isHorizontalMenu ? menuitem : {
11475 shortcut: Optional.none(),
11476 icon: menuitem.text.isSome() ? Optional.none() : menuitem.icon
11478 switch (item.type) {
11480 return createMenuItem(item).fold(handleError, d => Optional.some(normal(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
11481 case 'nestedmenuitem':
11482 return createNestedMenuItem(item).fold(handleError, d => Optional.some(nested(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons, isHorizontalMenu)));
11483 case 'togglemenuitem':
11484 return createToggleMenuItem(item).fold(handleError, d => Optional.some(toggle$1(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
11486 return createSeparatorMenuItem(item).fold(handleError, d => Optional.some(separator$3(d)));
11487 case 'fancymenuitem':
11488 return createFancyMenuItem(item).fold(handleError, d => fancy(d, backstage));
11490 console.error('Unknown item in general menu', item);
11491 return Optional.none();
11495 const createAutocompleteItems = (items, matchText, onItemValueHandler, columns, itemResponse, sharedBackstage, highlightOn) => {
11496 const renderText = columns === 1;
11497 const renderIcons = !renderText || menuHasIcons(items);
11498 return cat(map$2(items, item => {
11499 switch (item.type) {
11501 return createSeparatorItem(item).fold(handleError, d => Optional.some(separator$3(d)));
11502 case 'cardmenuitem':
11503 return createCardMenuItem(item).fold(handleError, d => Optional.some(card({
11507 onItemValueHandler(d.value, d.meta);
11509 }, itemResponse, sharedBackstage, {
11510 itemBehaviours: tooltipBehaviour(d.meta, sharedBackstage),
11516 case 'autocompleteitem':
11518 return createAutocompleterItem(item).fold(handleError, d => Optional.some(autocomplete(d, matchText, renderText, 'normal', onItemValueHandler, itemResponse, sharedBackstage, renderIcons)));
11522 const createPartialMenu = (value, items, itemResponse, backstage, isHorizontalMenu, searchMode) => {
11523 const hasIcons = menuHasIcons(items);
11524 const alloyItems = cat(map$2(items, item => {
11525 const itemHasIcon = i => isHorizontalMenu ? !has$2(i, 'text') : hasIcons;
11526 const createItem = i => createMenuItemFromBridge(i, itemResponse, backstage, itemHasIcon(i), isHorizontalMenu);
11527 if (item.type === 'nestedmenuitem' && item.getSubmenuItems().length <= 0) {
11528 return createItem({
11533 return createItem(item);
11536 const menuLayout = identifyMenuLayout(searchMode);
11537 const createPartial = isHorizontalMenu ? createHorizontalPartialMenuWithAlloyItems : createPartialMenuWithAlloyItems;
11538 return createPartial(value, hasIcons, alloyItems, 1, menuLayout);
11540 const createTieredDataFrom = partialMenu => tieredMenu.singleData(partialMenu.value, partialMenu);
11541 const createInlineMenuFrom = (partialMenu, columns, focusMode, presets) => {
11542 const movement = deriveMenuMovement(columns, presets);
11543 const menuMarkers = markers(presets);
11545 data: createTieredDataFrom({
11548 menuBehaviours: SimpleBehaviours.unnamedEvents(columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
11549 detectSize(comp, 4, menuMarkers.item).each(({numColumns, numRows}) => {
11550 Keying.setGridSize(comp, numRows, numColumns);
11555 markers: markers(presets),
11556 fakeFocus: focusMode === FocusMode.ContentFocus
11561 const getAutocompleterRange = (dom, initRange) => {
11562 return detect(SugarElement.fromDom(initRange.startContainer)).map(elm => {
11563 const range = dom.createRng();
11564 range.selectNode(elm.dom);
11568 const register$b = (editor, sharedBackstage) => {
11569 const processingAction = Cell(false);
11570 const activeState = Cell(false);
11571 const autocompleter = build$1(InlineView.sketch({
11574 classes: ['tox-autocompleter']
11577 fireDismissalEventInstead: {},
11578 inlineBehaviours: derive$1([config('dismissAutocompleter', [run$1(dismissRequested(), () => cancelIfNecessary())])]),
11579 lazySink: sharedBackstage.getSink
11581 const isMenuOpen = () => InlineView.isOpen(autocompleter);
11582 const isActive = activeState.get;
11583 const hideIfNecessary = () => {
11584 if (isMenuOpen()) {
11585 InlineView.hide(autocompleter);
11588 const getMenu = () => InlineView.getContent(autocompleter).bind(tmenu => {
11589 return get$h(tmenu.components(), 0);
11591 const cancelIfNecessary = () => editor.execCommand('mceAutocompleterClose');
11592 const getCombinedItems = matches => {
11593 const columns = findMap(matches, m => Optional.from(m.columns)).getOr(1);
11594 return bind$3(matches, match => {
11595 const choices = match.items;
11596 return createAutocompleteItems(choices, match.matchText, (itemValue, itemMeta) => {
11597 const nr = editor.selection.getRng();
11598 getAutocompleterRange(editor.dom, nr).each(range => {
11599 const autocompleterApi = {
11600 hide: () => cancelIfNecessary(),
11601 reload: fetchOptions => {
11603 editor.execCommand('mceAutocompleterReload', false, { fetchOptions });
11606 processingAction.set(true);
11607 match.onAction(autocompleterApi, range, itemValue, itemMeta);
11608 processingAction.set(false);
11610 }, columns, ItemResponse$1.BUBBLE_TO_SANDBOX, sharedBackstage, match.highlightOn);
11613 const display = (lookupData, items) => {
11614 findIn(SugarElement.fromDom(editor.getBody())).each(element => {
11615 const columns = findMap(lookupData, ld => Optional.from(ld.columns)).getOr(1);
11616 InlineView.showMenuAt(autocompleter, {
11619 root: SugarElement.fromDom(editor.getBody()),
11620 node: Optional.from(element)
11622 }, createInlineMenuFrom(createPartialMenuWithAlloyItems('autocompleter-value', true, items, columns, { menuType: 'normal' }), columns, FocusMode.ContentFocus, 'normal'));
11624 getMenu().each(Highlighting.highlightFirst);
11626 const updateDisplay = lookupData => {
11627 const combinedItems = getCombinedItems(lookupData);
11628 if (combinedItems.length > 0) {
11629 display(lookupData, combinedItems);
11634 editor.on('AutocompleterStart', ({lookupData}) => {
11635 activeState.set(true);
11636 processingAction.set(false);
11637 updateDisplay(lookupData);
11639 editor.on('AutocompleterUpdate', ({lookupData}) => updateDisplay(lookupData));
11640 editor.on('AutocompleterEnd', () => {
11642 activeState.set(false);
11643 processingAction.set(false);
11645 const autocompleterUiApi = {
11649 isProcessingAction: processingAction.get,
11652 AutocompleterEditorEvents.setup(autocompleterUiApi, editor);
11654 const Autocompleter = { register: register$b };
11656 const closest = (scope, selector, isRoot) => closest$1(scope, selector, isRoot).isSome();
11658 const DelayedFunction = (fun, delay) => {
11660 const schedule = (...args) => {
11661 ref = setTimeout(() => {
11662 fun.apply(null, args);
11666 const cancel = () => {
11667 if (ref !== null) {
11678 const SIGNIFICANT_MOVE = 5;
11679 const LONGPRESS_DELAY = 400;
11680 const getTouch = event => {
11681 const raw = event.raw;
11682 if (raw.touches === undefined || raw.touches.length !== 1) {
11683 return Optional.none();
11685 return Optional.some(raw.touches[0]);
11687 const isFarEnough = (touch, data) => {
11688 const distX = Math.abs(touch.clientX - data.x);
11689 const distY = Math.abs(touch.clientY - data.y);
11690 return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
11692 const monitor = settings => {
11693 const startData = value$2();
11694 const longpressFired = Cell(false);
11695 const longpress$1 = DelayedFunction(event => {
11696 settings.triggerEvent(longpress(), event);
11697 longpressFired.set(true);
11698 }, LONGPRESS_DELAY);
11699 const handleTouchstart = event => {
11700 getTouch(event).each(touch => {
11701 longpress$1.cancel();
11705 target: event.target
11707 longpress$1.schedule(event);
11708 longpressFired.set(false);
11709 startData.set(data);
11711 return Optional.none();
11713 const handleTouchmove = event => {
11714 longpress$1.cancel();
11715 getTouch(event).each(touch => {
11716 startData.on(data => {
11717 if (isFarEnough(touch, data)) {
11722 return Optional.none();
11724 const handleTouchend = event => {
11725 longpress$1.cancel();
11726 const isSame = data => eq(data.target, event.target);
11727 return startData.get().filter(isSame).map(_data => {
11728 if (longpressFired.get()) {
11732 return settings.triggerEvent(tap(), event);
11736 const handlers = wrapAll([
11739 value: handleTouchstart
11743 value: handleTouchmove
11747 value: handleTouchend
11750 const fireIfReady = (event, type) => get$g(handlers, type).bind(handler => handler(event));
11751 return { fireIfReady };
11754 const isDangerous = event => {
11755 const keyEv = event.raw;
11756 return keyEv.which === BACKSPACE[0] && !contains$2([
11759 ], name$3(event.target)) && !closest(event.target, '[contenteditable="true"]');
11761 const setup$d = (container, rawSettings) => {
11763 stopBackspace: true,
11766 const pointerEvents = [
11779 const tapEvent = monitor(settings);
11780 const simpleEvents = map$2(pointerEvents.concat([
11786 'transitioncancel',
11795 ]), type => bind(container, type, event => {
11796 tapEvent.fireIfReady(event, type).each(tapStopped => {
11801 const stopped = settings.triggerEvent(type, event);
11806 const pasteTimeout = value$2();
11807 const onPaste = bind(container, 'paste', event => {
11808 tapEvent.fireIfReady(event, 'paste').each(tapStopped => {
11813 const stopped = settings.triggerEvent('paste', event);
11817 pasteTimeout.set(setTimeout(() => {
11818 settings.triggerEvent(postPaste(), event);
11821 const onKeydown = bind(container, 'keydown', event => {
11822 const stopped = settings.triggerEvent('keydown', event);
11825 } else if (settings.stopBackspace && isDangerous(event)) {
11829 const onFocusIn = bind(container, 'focusin', event => {
11830 const stopped = settings.triggerEvent('focusin', event);
11835 const focusoutTimeout = value$2();
11836 const onFocusOut = bind(container, 'focusout', event => {
11837 const stopped = settings.triggerEvent('focusout', event);
11841 focusoutTimeout.set(setTimeout(() => {
11842 settings.triggerEvent(postBlur(), event);
11845 const unbind = () => {
11846 each$1(simpleEvents, e => {
11849 onKeydown.unbind();
11850 onFocusIn.unbind();
11851 onFocusOut.unbind();
11853 pasteTimeout.on(clearTimeout);
11854 focusoutTimeout.on(clearTimeout);
11859 const derive = (rawEvent, rawTarget) => {
11860 const source = get$g(rawEvent, 'target').getOr(rawTarget);
11861 return Cell(source);
11864 const fromSource = (event, source) => {
11865 const stopper = Cell(false);
11866 const cutter = Cell(false);
11867 const stop = () => {
11870 const cut = () => {
11876 isStopped: stopper.get,
11879 setSource: source.set,
11880 getSource: source.get
11883 const fromExternal = event => {
11884 const stopper = Cell(false);
11885 const stop = () => {
11891 isStopped: stopper.get,
11894 setSource: die('Cannot set source of a broadcasted event'),
11895 getSource: die('Cannot get source of a broadcasted event')
11899 const adt$1 = Adt.generate([
11901 { resume: ['element'] },
11904 const doTriggerHandler = (lookup, eventType, rawEvent, target, source, logger) => {
11905 const handler = lookup(eventType, target);
11906 const simulatedEvent = fromSource(rawEvent, source);
11907 return handler.fold(() => {
11908 logger.logEventNoHandlers(eventType, target);
11909 return adt$1.complete();
11910 }, handlerInfo => {
11911 const descHandler = handlerInfo.descHandler;
11912 const eventHandler = getCurried(descHandler);
11913 eventHandler(simulatedEvent);
11914 if (simulatedEvent.isStopped()) {
11915 logger.logEventStopped(eventType, handlerInfo.element, descHandler.purpose);
11916 return adt$1.stopped();
11917 } else if (simulatedEvent.isCut()) {
11918 logger.logEventCut(eventType, handlerInfo.element, descHandler.purpose);
11919 return adt$1.complete();
11921 return parent(handlerInfo.element).fold(() => {
11922 logger.logNoParent(eventType, handlerInfo.element, descHandler.purpose);
11923 return adt$1.complete();
11925 logger.logEventResponse(eventType, handlerInfo.element, descHandler.purpose);
11926 return adt$1.resume(parent);
11931 const doTriggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, source, logger) => doTriggerHandler(lookup, eventType, rawEvent, rawTarget, source, logger).fold(always, parent => doTriggerOnUntilStopped(lookup, eventType, rawEvent, parent, source, logger), never);
11932 const triggerHandler = (lookup, eventType, rawEvent, target, logger) => {
11933 const source = derive(rawEvent, target);
11934 return doTriggerHandler(lookup, eventType, rawEvent, target, source, logger);
11936 const broadcast = (listeners, rawEvent, _logger) => {
11937 const simulatedEvent = fromExternal(rawEvent);
11938 each$1(listeners, listener => {
11939 const descHandler = listener.descHandler;
11940 const handler = getCurried(descHandler);
11941 handler(simulatedEvent);
11943 return simulatedEvent.isStopped();
11945 const triggerUntilStopped = (lookup, eventType, rawEvent, logger) => triggerOnUntilStopped(lookup, eventType, rawEvent, rawEvent.target, logger);
11946 const triggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, logger) => {
11947 const source = derive(rawEvent, rawTarget);
11948 return doTriggerOnUntilStopped(lookup, eventType, rawEvent, rawTarget, source, logger);
11951 const eventHandler = (element, descHandler) => ({
11955 const broadcastHandler = (id, handler) => ({
11957 descHandler: handler
11959 const EventRegistry = () => {
11960 const registry = {};
11961 const registerId = (extraArgs, id, events) => {
11962 each(events, (v, k) => {
11963 const handlers = registry[k] !== undefined ? registry[k] : {};
11964 handlers[id] = curryArgs(v, extraArgs);
11965 registry[k] = handlers;
11968 const findHandler = (handlers, elem) => read$1(elem).bind(id => get$g(handlers, id)).map(descHandler => eventHandler(elem, descHandler));
11969 const filterByType = type => get$g(registry, type).map(handlers => mapToArray(handlers, (f, id) => broadcastHandler(id, f))).getOr([]);
11970 const find = (isAboveRoot, type, target) => get$g(registry, type).bind(handlers => closest$4(target, elem => findHandler(handlers, elem), isAboveRoot));
11971 const unregisterId = id => {
11972 each(registry, (handlersById, _eventName) => {
11973 if (has$2(handlersById, id)) {
11974 delete handlersById[id];
11986 const Registry = () => {
11987 const events = EventRegistry();
11988 const components = {};
11989 const readOrTag = component => {
11990 const elem = component.element;
11991 return read$1(elem).getOrThunk(() => write('uid-', component.element));
11993 const failOnDuplicate = (component, tagId) => {
11994 const conflict = components[tagId];
11995 if (conflict === component) {
11996 unregister(component);
11998 throw new Error('The tagId "' + tagId + '" is already used by: ' + element(conflict.element) + '\nCannot use it for: ' + element(component.element) + '\n' + 'The conflicting element is' + (inBody(conflict.element) ? ' ' : ' not ') + 'already in the DOM');
12001 const register = component => {
12002 const tagId = readOrTag(component);
12003 if (hasNonNullableKey(components, tagId)) {
12004 failOnDuplicate(component, tagId);
12006 const extraArgs = [component];
12007 events.registerId(extraArgs, tagId, component.events);
12008 components[tagId] = component;
12010 const unregister = component => {
12011 read$1(component.element).each(tagId => {
12012 delete components[tagId];
12013 events.unregisterId(tagId);
12016 const filter = type => events.filterByType(type);
12017 const find = (isAboveRoot, type, target) => events.find(isAboveRoot, type, target);
12018 const getById = id => get$g(components, id);
12028 const factory$h = detail => {
12029 const {attributes, ...domWithoutAttributes} = detail.dom;
12035 role: 'presentation',
12038 ...domWithoutAttributes
12040 components: detail.components,
12041 behaviours: get$3(detail.containerBehaviours),
12042 events: detail.events,
12043 domModification: detail.domModification,
12044 eventOrder: detail.eventOrder
12047 const Container = single({
12049 factory: factory$h,
12051 defaulted('components', []),
12052 field('containerBehaviours', []),
12053 defaulted('events', {}),
12054 defaulted('domModification', {}),
12055 defaulted('eventOrder', {})
12059 const takeover = root => {
12060 const isAboveRoot = el => parent(root.element).fold(always, parent => eq(el, parent));
12061 const registry = Registry();
12062 const lookup = (eventName, target) => registry.find(isAboveRoot, eventName, target);
12063 const domEvents = setup$d(root.element, {
12064 triggerEvent: (eventName, event) => {
12065 return monitorEvent(eventName, event.target, logger => triggerUntilStopped(lookup, eventName, event, logger));
12068 const systemApi = {
12069 debugInfo: constant$1('real'),
12070 triggerEvent: (eventName, target, data) => {
12071 monitorEvent(eventName, target, logger => triggerOnUntilStopped(lookup, eventName, data, target, logger));
12073 triggerFocus: (target, originator) => {
12074 read$1(target).fold(() => {
12077 monitorEvent(focus$4(), target, logger => {
12078 triggerHandler(lookup, focus$4(), {
12083 }, target, logger);
12088 triggerEscape: (comp, simulatedEvent) => {
12089 systemApi.triggerEvent('keydown', comp.element, simulatedEvent.event);
12092 return getByUid(uid);
12094 getByDom: elem => {
12095 return getByDom(elem);
12098 buildOrPatch: buildOrPatch,
12102 removeFromGui: c => {
12108 removeFromWorld: c => {
12109 removeFromWorld(c);
12111 broadcast: message => {
12112 broadcast$1(message);
12114 broadcastOn: (channels, message) => {
12115 broadcastOn(channels, message);
12117 broadcastEvent: (eventName, event) => {
12118 broadcastEvent(eventName, event);
12120 isConnected: always
12122 const addToWorld = component => {
12123 component.connect(systemApi);
12124 if (!isText(component.element)) {
12125 registry.register(component);
12126 each$1(component.components(), addToWorld);
12127 systemApi.triggerEvent(systemInit(), component.element, { target: component.element });
12130 const removeFromWorld = component => {
12131 if (!isText(component.element)) {
12132 each$1(component.components(), removeFromWorld);
12133 registry.unregister(component);
12135 component.disconnect();
12137 const add = component => {
12138 attach(root, component);
12140 const remove = component => {
12143 const destroy = () => {
12144 domEvents.unbind();
12145 remove$5(root.element);
12147 const broadcastData = data => {
12148 const receivers = registry.filter(receive());
12149 each$1(receivers, receiver => {
12150 const descHandler = receiver.descHandler;
12151 const handler = getCurried(descHandler);
12155 const broadcast$1 = message => {
12161 const broadcastOn = (channels, message) => {
12168 const broadcastEvent = (eventName, event) => {
12169 const listeners = registry.filter(eventName);
12170 return broadcast(listeners, event);
12172 const getByUid = uid => registry.getById(uid).fold(() => Result.error(new Error('Could not find component with uid: "' + uid + '" in system.')), Result.value);
12173 const getByDom = elem => {
12174 const uid = read$1(elem).getOr('not found');
12175 return getByUid(uid);
12180 element: root.element,
12188 broadcast: broadcast$1,
12194 const renderBar = (spec, backstage) => ({
12199 'tox-form__controls-h-stack'
12202 components: map$2(spec.items, backstage.interpreter)
12205 const schema$j = constant$1([
12206 defaulted('prefix', 'form-field'),
12207 field('fieldBehaviours', [
12212 const parts$d = constant$1([
12214 schema: [required$1('dom')],
12224 styles: { display: 'none' },
12225 attributes: { 'aria-hidden': 'true' },
12226 innerHtml: spec.text
12231 schema: [required$1('text')],
12232 name: 'aria-descriptor'
12237 const excludeFactory = exclude(spec, ['factory']);
12238 return spec.factory.sketch(excludeFactory);
12241 schema: [required$1('factory')],
12246 const factory$g = (detail, components, _spec, _externals) => {
12247 const behaviours = augment(detail.fieldBehaviours, [
12249 find: container => {
12250 return getPart(container, detail, 'field');
12253 Representing.config({
12256 getValue: field => {
12257 return Composing.getCurrent(field).bind(Representing.getValue);
12259 setValue: (field, value) => {
12260 Composing.getCurrent(field).each(current => {
12261 Representing.setValue(current, value);
12267 const events = derive$2([runOnAttached((component, _simulatedEvent) => {
12268 const ps = getParts(component, detail, [
12273 ps.field().each(field => {
12274 const id = generate$6(detail.prefix);
12275 ps.label().each(label => {
12276 set$9(label.element, 'for', id);
12277 set$9(field.element, 'id', id);
12279 ps['aria-descriptor']().each(descriptor => {
12280 const descriptorId = generate$6(detail.prefix);
12281 set$9(descriptor.element, 'id', descriptorId);
12282 set$9(field.element, 'aria-describedby', descriptorId);
12287 getField: container => getPart(container, detail, 'field'),
12288 getLabel: container => getPart(container, detail, 'label')
12299 const FormField = composite({
12301 configFields: schema$j(),
12302 partFields: parts$d(),
12303 factory: factory$g,
12305 getField: (apis, comp) => apis.getField(comp),
12306 getLabel: (apis, comp) => apis.getLabel(comp)
12310 const exhibit$2 = (base, tabConfig) => nu$7({
12311 attributes: wrapAll([{
12312 key: tabConfig.tabAttr,
12317 var ActiveTabstopping = /*#__PURE__*/Object.freeze({
12322 var TabstopSchema = [defaulted('tabAttr', 'data-alloy-tabstop')];
12324 const Tabstopping = create$4({
12325 fields: TabstopSchema,
12326 name: 'tabstopping',
12327 active: ActiveTabstopping
12330 var global$3 = tinymce.util.Tools.resolve('tinymce.html.Entities');
12332 const renderFormFieldWith = (pLabel, pField, extraClasses, extraBehaviours) => {
12333 const spec = renderFormFieldSpecWith(pLabel, pField, extraClasses, extraBehaviours);
12334 return FormField.sketch(spec);
12336 const renderFormField = (pLabel, pField) => renderFormFieldWith(pLabel, pField, [], []);
12337 const renderFormFieldSpecWith = (pLabel, pField, extraClasses, extraBehaviours) => ({
12338 dom: renderFormFieldDomWith(extraClasses),
12339 components: pLabel.toArray().concat([pField]),
12340 fieldBehaviours: derive$1(extraBehaviours)
12342 const renderFormFieldDom = () => renderFormFieldDomWith([]);
12343 const renderFormFieldDomWith = extraClasses => ({
12345 classes: ['tox-form__group'].concat(extraClasses)
12347 const renderLabel$2 = (label, providersBackstage) => FormField.parts.label({
12350 classes: ['tox-label']
12352 components: [text$2(providersBackstage.translate(label))]
12355 const formChangeEvent = generate$6('form-component-change');
12356 const formCloseEvent = generate$6('form-close');
12357 const formCancelEvent = generate$6('form-cancel');
12358 const formActionEvent = generate$6('form-action');
12359 const formSubmitEvent = generate$6('form-submit');
12360 const formBlockEvent = generate$6('form-block');
12361 const formUnblockEvent = generate$6('form-unblock');
12362 const formTabChangeEvent = generate$6('form-tabchange');
12363 const formResizeEvent = generate$6('form-resize');
12365 const renderCollection = (spec, providersBackstage, initialData) => {
12366 const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
12367 const runOnItem = f => (comp, se) => {
12368 closest$1(se.event.target, '[data-collection-item-value]').each(target => {
12369 f(comp, se, target, get$f(target, 'data-collection-item-value'));
12372 const setContents = (comp, items) => {
12373 const htmlLines = map$2(items, item => {
12374 const itemText = global$8.translate(item.text);
12375 const textContent = spec.columns === 1 ? `<div class="tox-collection__item-label">${ itemText }</div>` : '';
12376 const iconContent = `<div class="tox-collection__item-icon">${ item.icon }</div>`;
12377 const mapItemName = {
12382 const ariaLabel = itemText.replace(/\_| \- |\-/g, match => mapItemName[match]);
12383 const disabledClass = providersBackstage.isDisabled() ? ' tox-collection__item--state-disabled' : '';
12384 return `<div class="tox-collection__item${ disabledClass }" tabindex="-1" data-collection-item-value="${ global$3.encodeAllRaw(item.value) }" title="${ ariaLabel }" aria-label="${ ariaLabel }">${ iconContent }${ textContent }</div>`;
12386 const chunks = spec.columns !== 'auto' && spec.columns > 1 ? chunk$1(htmlLines, spec.columns) : [htmlLines];
12387 const html = map$2(chunks, ch => `<div class="tox-collection__group">${ ch.join('') }</div>`);
12388 set$6(comp.element, html.join(''));
12390 const onClick = runOnItem((comp, se, tgt, itemValue) => {
12392 if (!providersBackstage.isDisabled()) {
12393 emitWith(comp, formActionEvent, {
12399 const collectionEvents = [
12400 run$1(mouseover(), runOnItem((comp, se, tgt) => {
12403 run$1(click(), onClick),
12404 run$1(tap(), onClick),
12405 run$1(focusin(), runOnItem((comp, se, tgt) => {
12406 descendant(comp.element, '.' + activeClass).each(currentActive => {
12407 remove$2(currentActive, activeClass);
12409 add$2(tgt, activeClass);
12411 run$1(focusout(), runOnItem(comp => {
12412 descendant(comp.element, '.' + activeClass).each(currentActive => {
12413 remove$2(currentActive, activeClass);
12416 runOnExecute$1(runOnItem((comp, se, tgt, itemValue) => {
12417 emitWith(comp, formActionEvent, {
12423 const iterCollectionItems = (comp, applyAttributes) => map$2(descendants(comp.element, '.tox-collection__item'), applyAttributes);
12424 const pField = FormField.parts.field({
12427 classes: ['tox-collection'].concat(spec.columns !== 1 ? ['tox-collection--grid'] : ['tox-collection--list'])
12430 factory: { sketch: identity },
12431 behaviours: derive$1([
12433 disabled: providersBackstage.isDisabled,
12434 onDisabled: comp => {
12435 iterCollectionItems(comp, childElm => {
12436 add$2(childElm, 'tox-collection__item--state-disabled');
12437 set$9(childElm, 'aria-disabled', true);
12440 onEnabled: comp => {
12441 iterCollectionItems(comp, childElm => {
12442 remove$2(childElm, 'tox-collection__item--state-disabled');
12443 remove$7(childElm, 'aria-disabled');
12448 Replacing.config({}),
12449 Representing.config({
12452 initialValue: initialData.getOr([])
12454 onSetValue: (comp, items) => {
12455 setContents(comp, items);
12456 if (spec.columns === 'auto') {
12457 detectSize(comp, 5, 'tox-collection__item').each(({numRows, numColumns}) => {
12458 Keying.setGridSize(comp, numRows, numColumns);
12461 emit(comp, formResizeEvent);
12464 Tabstopping.config({}),
12465 Keying.config(deriveCollectionMovement(spec.columns, 'normal')),
12466 config('collection-events', collectionEvents)
12471 'alloy.base.behaviour',
12472 'collection-events'
12476 const extraClasses = ['tox-form__group--collection'];
12477 return renderFormFieldWith(pLabel, pField, extraClasses, []);
12480 const ariaElements = [
12484 const isAriaElement = elem => {
12485 const name = name$3(elem);
12486 return contains$2(ariaElements, name);
12488 const markValid = (component, invalidConfig) => {
12489 const elem = invalidConfig.getRoot(component).getOr(component.element);
12490 remove$2(elem, invalidConfig.invalidClass);
12491 invalidConfig.notify.each(notifyInfo => {
12492 if (isAriaElement(component.element)) {
12493 set$9(component.element, 'aria-invalid', false);
12495 notifyInfo.getContainer(component).each(container => {
12496 set$6(container, notifyInfo.validHtml);
12498 notifyInfo.onValid(component);
12501 const markInvalid = (component, invalidConfig, invalidState, text) => {
12502 const elem = invalidConfig.getRoot(component).getOr(component.element);
12503 add$2(elem, invalidConfig.invalidClass);
12504 invalidConfig.notify.each(notifyInfo => {
12505 if (isAriaElement(component.element)) {
12506 set$9(component.element, 'aria-invalid', true);
12508 notifyInfo.getContainer(component).each(container => {
12509 set$6(container, text);
12511 notifyInfo.onInvalid(component, text);
12514 const query = (component, invalidConfig, _invalidState) => invalidConfig.validator.fold(() => Future.pure(Result.value(true)), validatorInfo => validatorInfo.validate(component));
12515 const run = (component, invalidConfig, invalidState) => {
12516 invalidConfig.notify.each(notifyInfo => {
12517 notifyInfo.onValidate(component);
12519 return query(component, invalidConfig).map(valid => {
12520 if (component.getSystem().isConnected()) {
12521 return valid.fold(err => {
12522 markInvalid(component, invalidConfig, invalidState, err);
12523 return Result.error(err);
12525 markValid(component, invalidConfig);
12526 return Result.value(v);
12529 return Result.error('No longer in system');
12533 const isInvalid = (component, invalidConfig) => {
12534 const elem = invalidConfig.getRoot(component).getOr(component.element);
12535 return has(elem, invalidConfig.invalidClass);
12538 var InvalidateApis = /*#__PURE__*/Object.freeze({
12540 markValid: markValid,
12541 markInvalid: markInvalid,
12544 isInvalid: isInvalid
12547 const events$8 = (invalidConfig, invalidState) => invalidConfig.validator.map(validatorInfo => derive$2([run$1(validatorInfo.onEvent, component => {
12548 run(component, invalidConfig, invalidState).get(identity);
12549 })].concat(validatorInfo.validateOnLoad ? [runOnAttached(component => {
12550 run(component, invalidConfig, invalidState).get(noop);
12551 })] : []))).getOr({});
12553 var ActiveInvalidate = /*#__PURE__*/Object.freeze({
12558 var InvalidateSchema = [
12559 required$1('invalidClass'),
12560 defaulted('getRoot', Optional.none),
12561 optionObjOf('notify', [
12562 defaulted('aria', 'alert'),
12563 defaulted('getContainer', Optional.none),
12564 defaulted('validHtml', ''),
12565 onHandler('onValid'),
12566 onHandler('onInvalid'),
12567 onHandler('onValidate')
12569 optionObjOf('validator', [
12570 required$1('validate'),
12571 defaulted('onEvent', 'input'),
12572 defaulted('validateOnLoad', true)
12576 const Invalidating = create$4({
12577 fields: InvalidateSchema,
12578 name: 'invalidating',
12579 active: ActiveInvalidate,
12580 apis: InvalidateApis,
12582 validation: validator => {
12583 return component => {
12584 const v = Representing.getValue(component);
12585 return Future.pure(validator(v));
12591 const exhibit$1 = () => nu$7({
12593 '-webkit-user-select': 'none',
12594 'user-select': 'none',
12595 '-ms-user-select': 'none',
12596 '-moz-user-select': '-moz-none'
12598 attributes: { unselectable: 'on' }
12600 const events$7 = () => derive$2([abort(selectstart(), always)]);
12602 var ActiveUnselecting = /*#__PURE__*/Object.freeze({
12608 const Unselecting = create$4({
12610 name: 'unselecting',
12611 active: ActiveUnselecting
12614 const renderPanelButton = (spec, sharedBackstage) => Dropdown.sketch({
12616 components: spec.components,
12617 toggleClass: 'mce-active',
12618 dropdownBehaviours: derive$1([
12619 DisablingConfigs.button(sharedBackstage.providers.isDisabled),
12621 Unselecting.config({}),
12622 Tabstopping.config({})
12624 layouts: spec.layouts,
12625 sandboxClasses: ['tox-dialog__popups'],
12626 lazySink: sharedBackstage.getSink,
12627 fetch: comp => Future.nu(callback => spec.fetch(callback)).map(items => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6('menu-value'), items, value => {
12628 spec.onItemAction(comp, value);
12629 }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, sharedBackstage.providers), { movement: deriveMenuMovement(spec.columns, spec.presets) })))),
12630 parts: { menu: part(false, 1, spec.presets) }
12633 const colorInputChangeEvent = generate$6('color-input-change');
12634 const colorSwatchChangeEvent = generate$6('color-swatch-change');
12635 const colorPickerCancelEvent = generate$6('color-picker-cancel');
12636 const renderColorInput = (spec, sharedBackstage, colorInputBackstage, initialData) => {
12637 const pField = FormField.parts.field({
12639 inputClasses: ['tox-textfield'],
12641 onSetValue: c => Invalidating.run(c).get(noop),
12642 inputBehaviours: derive$1([
12643 Disabling.config({ disabled: sharedBackstage.providers.isDisabled }),
12645 Tabstopping.config({}),
12646 Invalidating.config({
12647 invalidClass: 'tox-textbox-field-invalid',
12648 getRoot: comp => parentElement(comp.element),
12651 const val = Representing.getValue(comp);
12652 emitWith(comp, colorInputChangeEvent, { color: val });
12656 validateOnLoad: false,
12657 validate: input => {
12658 const inputValue = Representing.getValue(input);
12659 if (inputValue.length === 0) {
12660 return Future.pure(Result.value(true));
12662 const span = SugarElement.fromTag('span');
12663 set$8(span, 'background-color', inputValue);
12664 const res = getRaw(span, 'background-color').fold(() => Result.error('blah'), _ => Result.value(inputValue));
12665 return Future.pure(res);
12671 selectOnFocus: false
12673 const pLabel = spec.label.map(label => renderLabel$2(label, sharedBackstage.providers));
12674 const emitSwatchChange = (colorBit, value) => {
12675 emitWith(colorBit, colorSwatchChangeEvent, { value });
12677 const onItemAction = (comp, value) => {
12678 memColorButton.getOpt(comp).each(colorBit => {
12679 if (value === 'custom') {
12680 colorInputBackstage.colorPicker(valueOpt => {
12681 valueOpt.fold(() => emit(colorBit, colorPickerCancelEvent), value => {
12682 emitSwatchChange(colorBit, value);
12686 } else if (value === 'remove') {
12687 emitSwatchChange(colorBit, '');
12689 emitSwatchChange(colorBit, value);
12693 const memColorButton = record(renderPanelButton({
12696 attributes: { 'aria-label': sharedBackstage.providers.translate('Color swatch') }
12711 fetch: getFetch$1(colorInputBackstage.getColors(), colorInputBackstage.hasCustomColors()),
12712 columns: colorInputBackstage.getColorCols(),
12715 }, sharedBackstage));
12716 return FormField.sketch({
12719 classes: ['tox-form__group']
12721 components: pLabel.toArray().concat([{
12724 classes: ['tox-color-input']
12728 memColorButton.asSpec()
12731 fieldBehaviours: derive$1([config('form-field-events', [
12732 run$1(colorInputChangeEvent, (comp, se) => {
12733 memColorButton.getOpt(comp).each(colorButton => {
12734 set$8(colorButton.element, 'background-color', se.event.color);
12736 emitWith(comp, formChangeEvent, { name: spec.name });
12738 run$1(colorSwatchChangeEvent, (comp, se) => {
12739 FormField.getField(comp).each(field => {
12740 Representing.setValue(field, se.event.value);
12741 Composing.getCurrent(comp).each(Focusing.focus);
12744 run$1(colorPickerCancelEvent, (comp, _se) => {
12745 FormField.getField(comp).each(_field => {
12746 Composing.getCurrent(comp).each(Focusing.focus);
12753 const labelPart = optional({
12754 schema: [required$1('dom')],
12757 const edgePart = name => optional({
12758 name: '' + name + '-edge',
12759 overrides: detail => {
12760 const action = detail.model.manager.edgeActions[name];
12761 return action.fold(() => ({}), a => ({
12763 runActionExtra(touchstart(), (comp, se, d) => a(comp, d), [detail]),
12764 runActionExtra(mousedown(), (comp, se, d) => a(comp, d), [detail]),
12765 runActionExtra(mousemove(), (comp, se, det) => {
12766 if (det.mouseIsDown.get()) {
12774 const tlEdgePart = edgePart('top-left');
12775 const tedgePart = edgePart('top');
12776 const trEdgePart = edgePart('top-right');
12777 const redgePart = edgePart('right');
12778 const brEdgePart = edgePart('bottom-right');
12779 const bedgePart = edgePart('bottom');
12780 const blEdgePart = edgePart('bottom-left');
12781 const ledgePart = edgePart('left');
12782 const thumbPart = required({
12784 defaults: constant$1({ dom: { styles: { position: 'absolute' } } }),
12785 overrides: detail => {
12788 redirectToPart(touchstart(), detail, 'spectrum'),
12789 redirectToPart(touchmove(), detail, 'spectrum'),
12790 redirectToPart(touchend(), detail, 'spectrum'),
12791 redirectToPart(mousedown(), detail, 'spectrum'),
12792 redirectToPart(mousemove(), detail, 'spectrum'),
12793 redirectToPart(mouseup(), detail, 'spectrum')
12798 const spectrumPart = required({
12799 schema: [customField('mouseIsDown', () => Cell(false))],
12801 overrides: detail => {
12802 const modelDetail = detail.model;
12803 const model = modelDetail.manager;
12804 const setValueFrom = (component, simulatedEvent) => model.getValueFromEvent(simulatedEvent).map(value => model.setValueFrom(component, detail, value));
12806 behaviours: derive$1([
12809 onLeft: spectrum => model.onLeft(spectrum, detail),
12810 onRight: spectrum => model.onRight(spectrum, detail),
12811 onUp: spectrum => model.onUp(spectrum, detail),
12812 onDown: spectrum => model.onDown(spectrum, detail)
12814 Focusing.config({})
12817 run$1(touchstart(), setValueFrom),
12818 run$1(touchmove(), setValueFrom),
12819 run$1(mousedown(), setValueFrom),
12820 run$1(mousemove(), (spectrum, se) => {
12821 if (detail.mouseIsDown.get()) {
12822 setValueFrom(spectrum, se);
12829 var SliderParts = [
12843 const _sliderChangeEvent = 'slider.change.value';
12844 const sliderChangeEvent = constant$1(_sliderChangeEvent);
12845 const isTouchEvent$2 = evt => evt.type.indexOf('touch') !== -1;
12846 const getEventSource = simulatedEvent => {
12847 const evt = simulatedEvent.event.raw;
12848 if (isTouchEvent$2(evt)) {
12849 const touchEvent = evt;
12850 return touchEvent.touches !== undefined && touchEvent.touches.length === 1 ? Optional.some(touchEvent.touches[0]).map(t => SugarPosition(t.clientX, t.clientY)) : Optional.none();
12852 const mouseEvent = evt;
12853 return mouseEvent.clientX !== undefined ? Optional.some(mouseEvent).map(me => SugarPosition(me.clientX, me.clientY)) : Optional.none();
12857 const t = 'top', r = 'right', b = 'bottom', l = 'left';
12858 const minX = detail => detail.model.minX;
12859 const minY = detail => detail.model.minY;
12860 const min1X = detail => detail.model.minX - 1;
12861 const min1Y = detail => detail.model.minY - 1;
12862 const maxX = detail => detail.model.maxX;
12863 const maxY = detail => detail.model.maxY;
12864 const max1X = detail => detail.model.maxX + 1;
12865 const max1Y = detail => detail.model.maxY + 1;
12866 const range = (detail, max, min) => max(detail) - min(detail);
12867 const xRange = detail => range(detail, maxX, minX);
12868 const yRange = detail => range(detail, maxY, minY);
12869 const halfX = detail => xRange(detail) / 2;
12870 const halfY = detail => yRange(detail) / 2;
12871 const step = detail => detail.stepSize;
12872 const snap = detail => detail.snapToGrid;
12873 const snapStart = detail => detail.snapStart;
12874 const rounded = detail => detail.rounded;
12875 const hasEdge = (detail, edgeName) => detail[edgeName + '-edge'] !== undefined;
12876 const hasLEdge = detail => hasEdge(detail, l);
12877 const hasREdge = detail => hasEdge(detail, r);
12878 const hasTEdge = detail => hasEdge(detail, t);
12879 const hasBEdge = detail => hasEdge(detail, b);
12880 const currentValue = detail => detail.model.value.get();
12882 const xyValue = (x, y) => ({
12886 const fireSliderChange$3 = (component, value) => {
12887 emitWith(component, sliderChangeEvent(), { value });
12889 const setToTLEdgeXY = (edge, detail) => {
12890 fireSliderChange$3(edge, xyValue(min1X(detail), min1Y(detail)));
12892 const setToTEdge = (edge, detail) => {
12893 fireSliderChange$3(edge, min1Y(detail));
12895 const setToTEdgeXY = (edge, detail) => {
12896 fireSliderChange$3(edge, xyValue(halfX(detail), min1Y(detail)));
12898 const setToTREdgeXY = (edge, detail) => {
12899 fireSliderChange$3(edge, xyValue(max1X(detail), min1Y(detail)));
12901 const setToREdge = (edge, detail) => {
12902 fireSliderChange$3(edge, max1X(detail));
12904 const setToREdgeXY = (edge, detail) => {
12905 fireSliderChange$3(edge, xyValue(max1X(detail), halfY(detail)));
12907 const setToBREdgeXY = (edge, detail) => {
12908 fireSliderChange$3(edge, xyValue(max1X(detail), max1Y(detail)));
12910 const setToBEdge = (edge, detail) => {
12911 fireSliderChange$3(edge, max1Y(detail));
12913 const setToBEdgeXY = (edge, detail) => {
12914 fireSliderChange$3(edge, xyValue(halfX(detail), max1Y(detail)));
12916 const setToBLEdgeXY = (edge, detail) => {
12917 fireSliderChange$3(edge, xyValue(min1X(detail), max1Y(detail)));
12919 const setToLEdge = (edge, detail) => {
12920 fireSliderChange$3(edge, min1X(detail));
12922 const setToLEdgeXY = (edge, detail) => {
12923 fireSliderChange$3(edge, xyValue(min1X(detail), halfY(detail)));
12926 const reduceBy = (value, min, max, step) => {
12929 } else if (value > max) {
12931 } else if (value === min) {
12934 return Math.max(min, value - step);
12937 const increaseBy = (value, min, max, step) => {
12940 } else if (value < min) {
12942 } else if (value === max) {
12945 return Math.min(max, value + step);
12948 const capValue = (value, min, max) => Math.max(min, Math.min(max, value));
12949 const snapValueOf = (value, min, max, step, snapStart) => snapStart.fold(() => {
12950 const initValue = value - min;
12951 const extraValue = Math.round(initValue / step) * step;
12952 return capValue(min + extraValue, min - 1, max + 1);
12954 const remainder = (value - start) % step;
12955 const adjustment = Math.round(remainder / step);
12956 const rawSteps = Math.floor((value - start) / step);
12957 const maxSteps = Math.floor((max - start) / step);
12958 const numSteps = Math.min(maxSteps, rawSteps + adjustment);
12959 const r = start + numSteps * step;
12960 return Math.max(start, r);
12962 const findOffsetOf = (value, min, max) => Math.min(max, Math.max(value, min)) - min;
12963 const findValueOf = args => {
12964 const {min, max, range, value, step, snap, snapStart, rounded, hasMinEdge, hasMaxEdge, minBound, maxBound, screenRange} = args;
12965 const capMin = hasMinEdge ? min - 1 : min;
12966 const capMax = hasMaxEdge ? max + 1 : max;
12967 if (value < minBound) {
12969 } else if (value > maxBound) {
12972 const offset = findOffsetOf(value, minBound, maxBound);
12973 const newValue = capValue(offset / screenRange * range + min, capMin, capMax);
12974 if (snap && newValue >= min && newValue <= max) {
12975 return snapValueOf(newValue, min, max, step, snapStart);
12976 } else if (rounded) {
12977 return Math.round(newValue);
12983 const findOffsetOfValue$2 = args => {
12984 const {min, max, range, value, hasMinEdge, hasMaxEdge, maxBound, maxOffset, centerMinEdge, centerMaxEdge} = args;
12986 return hasMinEdge ? 0 : centerMinEdge;
12987 } else if (value > max) {
12988 return hasMaxEdge ? maxBound : centerMaxEdge;
12990 return (value - min) / range * maxOffset;
12994 const top = 'top', right = 'right', bottom = 'bottom', left = 'left', width = 'width', height = 'height';
12995 const getBounds = component => component.element.dom.getBoundingClientRect();
12996 const getBoundsProperty = (bounds, property) => bounds[property];
12997 const getMinXBounds = component => {
12998 const bounds = getBounds(component);
12999 return getBoundsProperty(bounds, left);
13001 const getMaxXBounds = component => {
13002 const bounds = getBounds(component);
13003 return getBoundsProperty(bounds, right);
13005 const getMinYBounds = component => {
13006 const bounds = getBounds(component);
13007 return getBoundsProperty(bounds, top);
13009 const getMaxYBounds = component => {
13010 const bounds = getBounds(component);
13011 return getBoundsProperty(bounds, bottom);
13013 const getXScreenRange = component => {
13014 const bounds = getBounds(component);
13015 return getBoundsProperty(bounds, width);
13017 const getYScreenRange = component => {
13018 const bounds = getBounds(component);
13019 return getBoundsProperty(bounds, height);
13021 const getCenterOffsetOf = (componentMinEdge, componentMaxEdge, spectrumMinEdge) => (componentMinEdge + componentMaxEdge) / 2 - spectrumMinEdge;
13022 const getXCenterOffSetOf = (component, spectrum) => {
13023 const componentBounds = getBounds(component);
13024 const spectrumBounds = getBounds(spectrum);
13025 const componentMinEdge = getBoundsProperty(componentBounds, left);
13026 const componentMaxEdge = getBoundsProperty(componentBounds, right);
13027 const spectrumMinEdge = getBoundsProperty(spectrumBounds, left);
13028 return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
13030 const getYCenterOffSetOf = (component, spectrum) => {
13031 const componentBounds = getBounds(component);
13032 const spectrumBounds = getBounds(spectrum);
13033 const componentMinEdge = getBoundsProperty(componentBounds, top);
13034 const componentMaxEdge = getBoundsProperty(componentBounds, bottom);
13035 const spectrumMinEdge = getBoundsProperty(spectrumBounds, top);
13036 return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
13039 const fireSliderChange$2 = (spectrum, value) => {
13040 emitWith(spectrum, sliderChangeEvent(), { value });
13042 const findValueOfOffset$1 = (spectrum, detail, left) => {
13046 range: xRange(detail),
13048 step: step(detail),
13049 snap: snap(detail),
13050 snapStart: snapStart(detail),
13051 rounded: rounded(detail),
13052 hasMinEdge: hasLEdge(detail),
13053 hasMaxEdge: hasREdge(detail),
13054 minBound: getMinXBounds(spectrum),
13055 maxBound: getMaxXBounds(spectrum),
13056 screenRange: getXScreenRange(spectrum)
13058 return findValueOf(args);
13060 const setValueFrom$2 = (spectrum, detail, value) => {
13061 const xValue = findValueOfOffset$1(spectrum, detail, value);
13062 const sliderVal = xValue;
13063 fireSliderChange$2(spectrum, sliderVal);
13066 const setToMin$2 = (spectrum, detail) => {
13067 const min = minX(detail);
13068 fireSliderChange$2(spectrum, min);
13070 const setToMax$2 = (spectrum, detail) => {
13071 const max = maxX(detail);
13072 fireSliderChange$2(spectrum, max);
13074 const moveBy$2 = (direction, spectrum, detail) => {
13075 const f = direction > 0 ? increaseBy : reduceBy;
13076 const xValue = f(currentValue(detail), minX(detail), maxX(detail), step(detail));
13077 fireSliderChange$2(spectrum, xValue);
13078 return Optional.some(xValue);
13080 const handleMovement$2 = direction => (spectrum, detail) => moveBy$2(direction, spectrum, detail).map(always);
13081 const getValueFromEvent$2 = simulatedEvent => {
13082 const pos = getEventSource(simulatedEvent);
13083 return pos.map(p => p.left);
13085 const findOffsetOfValue$1 = (spectrum, detail, value, minEdge, maxEdge) => {
13086 const minOffset = 0;
13087 const maxOffset = getXScreenRange(spectrum);
13088 const centerMinEdge = minEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(minOffset);
13089 const centerMaxEdge = maxEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
13093 range: xRange(detail),
13095 hasMinEdge: hasLEdge(detail),
13096 hasMaxEdge: hasREdge(detail),
13097 minBound: getMinXBounds(spectrum),
13099 maxBound: getMaxXBounds(spectrum),
13104 return findOffsetOfValue$2(args);
13106 const findPositionOfValue$1 = (slider, spectrum, value, minEdge, maxEdge, detail) => {
13107 const offset = findOffsetOfValue$1(spectrum, detail, value, minEdge, maxEdge);
13108 return getMinXBounds(spectrum) - getMinXBounds(slider) + offset;
13110 const setPositionFromValue$2 = (slider, thumb, detail, edges) => {
13111 const value = currentValue(detail);
13112 const pos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
13113 const thumbRadius = get$c(thumb.element) / 2;
13114 set$8(thumb.element, 'left', pos - thumbRadius + 'px');
13116 const onLeft$2 = handleMovement$2(-1);
13117 const onRight$2 = handleMovement$2(1);
13118 const onUp$2 = Optional.none;
13119 const onDown$2 = Optional.none;
13120 const edgeActions$2 = {
13121 'top-left': Optional.none(),
13122 'top': Optional.none(),
13123 'top-right': Optional.none(),
13124 'right': Optional.some(setToREdge),
13125 'bottom-right': Optional.none(),
13126 'bottom': Optional.none(),
13127 'bottom-left': Optional.none(),
13128 'left': Optional.some(setToLEdge)
13131 var HorizontalModel = /*#__PURE__*/Object.freeze({
13133 setValueFrom: setValueFrom$2,
13134 setToMin: setToMin$2,
13135 setToMax: setToMax$2,
13136 findValueOfOffset: findValueOfOffset$1,
13137 getValueFromEvent: getValueFromEvent$2,
13138 findPositionOfValue: findPositionOfValue$1,
13139 setPositionFromValue: setPositionFromValue$2,
13141 onRight: onRight$2,
13144 edgeActions: edgeActions$2
13147 const fireSliderChange$1 = (spectrum, value) => {
13148 emitWith(spectrum, sliderChangeEvent(), { value });
13150 const findValueOfOffset = (spectrum, detail, top) => {
13154 range: yRange(detail),
13156 step: step(detail),
13157 snap: snap(detail),
13158 snapStart: snapStart(detail),
13159 rounded: rounded(detail),
13160 hasMinEdge: hasTEdge(detail),
13161 hasMaxEdge: hasBEdge(detail),
13162 minBound: getMinYBounds(spectrum),
13163 maxBound: getMaxYBounds(spectrum),
13164 screenRange: getYScreenRange(spectrum)
13166 return findValueOf(args);
13168 const setValueFrom$1 = (spectrum, detail, value) => {
13169 const yValue = findValueOfOffset(spectrum, detail, value);
13170 const sliderVal = yValue;
13171 fireSliderChange$1(spectrum, sliderVal);
13174 const setToMin$1 = (spectrum, detail) => {
13175 const min = minY(detail);
13176 fireSliderChange$1(spectrum, min);
13178 const setToMax$1 = (spectrum, detail) => {
13179 const max = maxY(detail);
13180 fireSliderChange$1(spectrum, max);
13182 const moveBy$1 = (direction, spectrum, detail) => {
13183 const f = direction > 0 ? increaseBy : reduceBy;
13184 const yValue = f(currentValue(detail), minY(detail), maxY(detail), step(detail));
13185 fireSliderChange$1(spectrum, yValue);
13186 return Optional.some(yValue);
13188 const handleMovement$1 = direction => (spectrum, detail) => moveBy$1(direction, spectrum, detail).map(always);
13189 const getValueFromEvent$1 = simulatedEvent => {
13190 const pos = getEventSource(simulatedEvent);
13191 return pos.map(p => {
13195 const findOffsetOfValue = (spectrum, detail, value, minEdge, maxEdge) => {
13196 const minOffset = 0;
13197 const maxOffset = getYScreenRange(spectrum);
13198 const centerMinEdge = minEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(minOffset);
13199 const centerMaxEdge = maxEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
13203 range: yRange(detail),
13205 hasMinEdge: hasTEdge(detail),
13206 hasMaxEdge: hasBEdge(detail),
13207 minBound: getMinYBounds(spectrum),
13209 maxBound: getMaxYBounds(spectrum),
13214 return findOffsetOfValue$2(args);
13216 const findPositionOfValue = (slider, spectrum, value, minEdge, maxEdge, detail) => {
13217 const offset = findOffsetOfValue(spectrum, detail, value, minEdge, maxEdge);
13218 return getMinYBounds(spectrum) - getMinYBounds(slider) + offset;
13220 const setPositionFromValue$1 = (slider, thumb, detail, edges) => {
13221 const value = currentValue(detail);
13222 const pos = findPositionOfValue(slider, edges.getSpectrum(slider), value, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
13223 const thumbRadius = get$d(thumb.element) / 2;
13224 set$8(thumb.element, 'top', pos - thumbRadius + 'px');
13226 const onLeft$1 = Optional.none;
13227 const onRight$1 = Optional.none;
13228 const onUp$1 = handleMovement$1(-1);
13229 const onDown$1 = handleMovement$1(1);
13230 const edgeActions$1 = {
13231 'top-left': Optional.none(),
13232 'top': Optional.some(setToTEdge),
13233 'top-right': Optional.none(),
13234 'right': Optional.none(),
13235 'bottom-right': Optional.none(),
13236 'bottom': Optional.some(setToBEdge),
13237 'bottom-left': Optional.none(),
13238 'left': Optional.none()
13241 var VerticalModel = /*#__PURE__*/Object.freeze({
13243 setValueFrom: setValueFrom$1,
13244 setToMin: setToMin$1,
13245 setToMax: setToMax$1,
13246 findValueOfOffset: findValueOfOffset,
13247 getValueFromEvent: getValueFromEvent$1,
13248 findPositionOfValue: findPositionOfValue,
13249 setPositionFromValue: setPositionFromValue$1,
13251 onRight: onRight$1,
13254 edgeActions: edgeActions$1
13257 const fireSliderChange = (spectrum, value) => {
13258 emitWith(spectrum, sliderChangeEvent(), { value });
13260 const sliderValue = (x, y) => ({
13264 const setValueFrom = (spectrum, detail, value) => {
13265 const xValue = findValueOfOffset$1(spectrum, detail, value.left);
13266 const yValue = findValueOfOffset(spectrum, detail, value.top);
13267 const val = sliderValue(xValue, yValue);
13268 fireSliderChange(spectrum, val);
13271 const moveBy = (direction, isVerticalMovement, spectrum, detail) => {
13272 const f = direction > 0 ? increaseBy : reduceBy;
13273 const xValue = isVerticalMovement ? currentValue(detail).x : f(currentValue(detail).x, minX(detail), maxX(detail), step(detail));
13274 const yValue = !isVerticalMovement ? currentValue(detail).y : f(currentValue(detail).y, minY(detail), maxY(detail), step(detail));
13275 fireSliderChange(spectrum, sliderValue(xValue, yValue));
13276 return Optional.some(xValue);
13278 const handleMovement = (direction, isVerticalMovement) => (spectrum, detail) => moveBy(direction, isVerticalMovement, spectrum, detail).map(always);
13279 const setToMin = (spectrum, detail) => {
13280 const mX = minX(detail);
13281 const mY = minY(detail);
13282 fireSliderChange(spectrum, sliderValue(mX, mY));
13284 const setToMax = (spectrum, detail) => {
13285 const mX = maxX(detail);
13286 const mY = maxY(detail);
13287 fireSliderChange(spectrum, sliderValue(mX, mY));
13289 const getValueFromEvent = simulatedEvent => getEventSource(simulatedEvent);
13290 const setPositionFromValue = (slider, thumb, detail, edges) => {
13291 const value = currentValue(detail);
13292 const xPos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value.x, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
13293 const yPos = findPositionOfValue(slider, edges.getSpectrum(slider), value.y, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
13294 const thumbXRadius = get$c(thumb.element) / 2;
13295 const thumbYRadius = get$d(thumb.element) / 2;
13296 set$8(thumb.element, 'left', xPos - thumbXRadius + 'px');
13297 set$8(thumb.element, 'top', yPos - thumbYRadius + 'px');
13299 const onLeft = handleMovement(-1, false);
13300 const onRight = handleMovement(1, false);
13301 const onUp = handleMovement(-1, true);
13302 const onDown = handleMovement(1, true);
13303 const edgeActions = {
13304 'top-left': Optional.some(setToTLEdgeXY),
13305 'top': Optional.some(setToTEdgeXY),
13306 'top-right': Optional.some(setToTREdgeXY),
13307 'right': Optional.some(setToREdgeXY),
13308 'bottom-right': Optional.some(setToBREdgeXY),
13309 'bottom': Optional.some(setToBEdgeXY),
13310 'bottom-left': Optional.some(setToBLEdgeXY),
13311 'left': Optional.some(setToLEdgeXY)
13314 var TwoDModel = /*#__PURE__*/Object.freeze({
13316 setValueFrom: setValueFrom,
13317 setToMin: setToMin,
13318 setToMax: setToMax,
13319 getValueFromEvent: getValueFromEvent,
13320 setPositionFromValue: setPositionFromValue,
13325 edgeActions: edgeActions
13328 const SliderSchema = [
13329 defaulted('stepSize', 1),
13330 defaulted('onChange', noop),
13331 defaulted('onChoose', noop),
13332 defaulted('onInit', noop),
13333 defaulted('onDragStart', noop),
13334 defaulted('onDragEnd', noop),
13335 defaulted('snapToGrid', false),
13336 defaulted('rounded', true),
13337 option$3('snapStart'),
13338 requiredOf('model', choose$1('mode', {
13340 defaulted('minX', 0),
13341 defaulted('maxX', 100),
13342 customField('value', spec => Cell(spec.mode.minX)),
13343 required$1('getInitialValue'),
13344 output$1('manager', HorizontalModel)
13347 defaulted('minY', 0),
13348 defaulted('maxY', 100),
13349 customField('value', spec => Cell(spec.mode.minY)),
13350 required$1('getInitialValue'),
13351 output$1('manager', VerticalModel)
13354 defaulted('minX', 0),
13355 defaulted('maxX', 100),
13356 defaulted('minY', 0),
13357 defaulted('maxY', 100),
13358 customField('value', spec => Cell({
13362 required$1('getInitialValue'),
13363 output$1('manager', TwoDModel)
13366 field('sliderBehaviours', [
13370 customField('mouseIsDown', () => Cell(false))
13373 const sketch$2 = (detail, components, _spec, _externals) => {
13374 const getThumb = component => getPartOrDie(component, detail, 'thumb');
13375 const getSpectrum = component => getPartOrDie(component, detail, 'spectrum');
13376 const getLeftEdge = component => getPart(component, detail, 'left-edge');
13377 const getRightEdge = component => getPart(component, detail, 'right-edge');
13378 const getTopEdge = component => getPart(component, detail, 'top-edge');
13379 const getBottomEdge = component => getPart(component, detail, 'bottom-edge');
13380 const modelDetail = detail.model;
13381 const model = modelDetail.manager;
13382 const refresh = (slider, thumb) => {
13383 model.setPositionFromValue(slider, thumb, detail, {
13391 const setValue = (slider, newValue) => {
13392 modelDetail.value.set(newValue);
13393 const thumb = getThumb(slider);
13394 refresh(slider, thumb);
13396 const changeValue = (slider, newValue) => {
13397 setValue(slider, newValue);
13398 const thumb = getThumb(slider);
13399 detail.onChange(slider, thumb, newValue);
13400 return Optional.some(true);
13402 const resetToMin = slider => {
13403 model.setToMin(slider, detail);
13405 const resetToMax = slider => {
13406 model.setToMax(slider, detail);
13408 const choose = slider => {
13409 const fireOnChoose = () => {
13410 getPart(slider, detail, 'thumb').each(thumb => {
13411 const value = modelDetail.value.get();
13412 detail.onChoose(slider, thumb, value);
13415 const wasDown = detail.mouseIsDown.get();
13416 detail.mouseIsDown.set(false);
13421 const onDragStart = (slider, simulatedEvent) => {
13422 simulatedEvent.stop();
13423 detail.mouseIsDown.set(true);
13424 detail.onDragStart(slider, getThumb(slider));
13426 const onDragEnd = (slider, simulatedEvent) => {
13427 simulatedEvent.stop();
13428 detail.onDragEnd(slider, getThumb(slider));
13435 behaviours: augment(detail.sliderBehaviours, [
13438 focusIn: slider => {
13439 return getPart(slider, detail, 'spectrum').map(Keying.focusIn).map(always);
13442 Representing.config({
13446 return modelDetail.value.get();
13451 Receiving.config({ channels: { [mouseReleased()]: { onReceive: choose } } })
13454 run$1(sliderChangeEvent(), (slider, simulatedEvent) => {
13455 changeValue(slider, simulatedEvent.event.value);
13457 runOnAttached((slider, _simulatedEvent) => {
13458 const getInitial = modelDetail.getInitialValue();
13459 modelDetail.value.set(getInitial);
13460 const thumb = getThumb(slider);
13461 refresh(slider, thumb);
13462 const spectrum = getSpectrum(slider);
13463 detail.onInit(slider, thumb, spectrum, modelDetail.value.get());
13465 run$1(touchstart(), onDragStart),
13466 run$1(touchend(), onDragEnd),
13467 run$1(mousedown(), onDragStart),
13468 run$1(mouseup(), onDragEnd)
13476 domModification: { styles: { position: 'relative' } }
13480 const Slider = composite({
13482 configFields: SliderSchema,
13483 partFields: SliderParts,
13486 setValue: (apis, slider, value) => {
13487 apis.setValue(slider, value);
13489 resetToMin: (apis, slider) => {
13490 apis.resetToMin(slider);
13492 resetToMax: (apis, slider) => {
13493 apis.resetToMax(slider);
13495 refresh: (apis, slider) => {
13496 apis.refresh(slider);
13501 const fieldsUpdate = generate$6('rgb-hex-update');
13502 const sliderUpdate = generate$6('slider-update');
13503 const paletteUpdate = generate$6('palette-update');
13505 const sliderFactory = (translate, getClass) => {
13506 const spectrum = Slider.parts.spectrum({
13509 classes: [getClass('hue-slider-spectrum')],
13510 attributes: { role: 'presentation' }
13513 const thumb = Slider.parts.thumb({
13516 classes: [getClass('hue-slider-thumb')],
13517 attributes: { role: 'presentation' }
13520 return Slider.sketch({
13523 classes: [getClass('hue-slider')],
13524 attributes: { role: 'presentation' }
13529 getInitialValue: constant$1(0)
13535 sliderBehaviours: derive$1([Focusing.config({})]),
13536 onChange: (slider, _thumb, value) => {
13537 emitWith(slider, sliderUpdate, { value });
13542 const owner$1 = 'form';
13543 const schema$i = [field('formBehaviours', [Representing])];
13544 const getPartName$1 = name => '<alloy.field.' + name + '>';
13545 const sketch$1 = fSpec => {
13546 const parts = (() => {
13548 const field = (name, config) => {
13550 return generateOne$1(owner$1, getPartName$1(name), config);
13554 record: constant$1(record)
13557 const spec = fSpec(parts);
13558 const partNames = parts.record();
13559 const fieldParts = map$2(partNames, n => required({
13561 pname: getPartName$1(n)
13563 return composite$1(owner$1, schema$i, fieldParts, make$4, spec);
13565 const toResult = (o, e) => o.fold(() => Result.error(e), Result.value);
13566 const make$4 = (detail, components) => ({
13570 behaviours: augment(detail.formBehaviours, [Representing.config({
13573 getValue: form => {
13574 const resPs = getAllParts(form, detail);
13575 return map$1(resPs, (resPThunk, pName) => resPThunk().bind(v => {
13576 const opt = Composing.getCurrent(v);
13577 return toResult(opt, new Error(`Cannot find a current component to extract the value from for form part '${ pName }': ` + element(v.element)));
13578 }).map(Representing.getValue));
13580 setValue: (form, values) => {
13581 each(values, (newValue, key) => {
13582 getPart(form, detail, key).each(wrapper => {
13583 Composing.getCurrent(wrapper).each(field => {
13584 Representing.setValue(field, newValue);
13592 getField: (form, key) => {
13593 return getPart(form, detail, key).bind(Composing.getCurrent);
13598 getField: makeApi((apis, component, key) => apis.getField(component, key)),
13602 const validInput = generate$6('valid-input');
13603 const invalidInput = generate$6('invalid-input');
13604 const validatingInput = generate$6('validating-input');
13605 const translatePrefix = 'colorcustom.rgb.';
13606 const rgbFormFactory = (translate, getClass, onValidHexx, onInvalidHexx) => {
13607 const invalidation = (label, isValid) => Invalidating.config({
13608 invalidClass: getClass('invalid'),
13610 onValidate: comp => {
13611 emitWith(comp, validatingInput, { type: label });
13614 emitWith(comp, validInput, {
13616 value: Representing.getValue(comp)
13619 onInvalid: comp => {
13620 emitWith(comp, invalidInput, {
13622 value: Representing.getValue(comp)
13627 validate: comp => {
13628 const value = Representing.getValue(comp);
13629 const res = isValid(value) ? Result.value(true) : Result.error(translate('aria.input.invalid'));
13630 return Future.pure(res);
13632 validateOnLoad: false
13635 const renderTextField = (isValid, name, label, description, data) => {
13636 const helptext = translate(translatePrefix + 'range');
13637 const pLabel = FormField.parts.label({
13640 attributes: { 'aria-label': description }
13642 components: [text$2(label)]
13644 const pField = FormField.parts.field({
13649 ...name === 'hex' ? { 'aria-live': 'polite' } : {}
13651 inputClasses: [getClass('textfield')],
13652 inputBehaviours: derive$1([
13653 invalidation(name, isValid),
13654 Tabstopping.config({})
13656 onSetValue: input => {
13657 if (Invalidating.isInvalid(input)) {
13658 const run = Invalidating.run(input);
13667 const concats = name !== 'hex' ? [FormField.parts['aria-descriptor']({ text: helptext })] : [];
13668 const components = comps.concat(concats);
13672 attributes: { role: 'presentation' }
13677 const copyRgbToHex = (form, rgba) => {
13678 const hex = fromRgba(rgba);
13679 Form.getField(form, 'hex').each(hexField => {
13680 if (!Focusing.isFocused(hexField)) {
13681 Representing.setValue(form, { hex: hex.value });
13686 const copyRgbToForm = (form, rgb) => {
13687 const red = rgb.red;
13688 const green = rgb.green;
13689 const blue = rgb.blue;
13690 Representing.setValue(form, {
13696 const memPreview = record({
13699 classes: [getClass('rgba-preview')],
13700 styles: { 'background-color': 'white' },
13701 attributes: { role: 'presentation' }
13704 const updatePreview = (anyInSystem, hex) => {
13705 memPreview.getOpt(anyInSystem).each(preview => {
13706 set$8(preview.element, 'background-color', '#' + hex.value);
13709 const factory = () => {
13711 red: Cell(Optional.some(255)),
13712 green: Cell(Optional.some(255)),
13713 blue: Cell(Optional.some(255)),
13714 hex: Cell(Optional.some('ffffff'))
13716 const copyHexToRgb = (form, hex) => {
13717 const rgb = fromHex(hex);
13718 copyRgbToForm(form, rgb);
13721 const get = prop => state[prop].get();
13722 const set = (prop, value) => {
13723 state[prop].set(value);
13725 const getValueRgb = () => get('red').bind(red => get('green').bind(green => get('blue').map(blue => rgbaColour(red, green, blue, 1))));
13726 const setValueRgb = rgb => {
13727 const red = rgb.red;
13728 const green = rgb.green;
13729 const blue = rgb.blue;
13730 set('red', Optional.some(red));
13731 set('green', Optional.some(green));
13732 set('blue', Optional.some(blue));
13734 const onInvalidInput = (form, simulatedEvent) => {
13735 const data = simulatedEvent.event;
13736 if (data.type !== 'hex') {
13737 set(data.type, Optional.none());
13739 onInvalidHexx(form);
13742 const onValidHex = (form, value) => {
13744 const hex = hexColour(value);
13745 set('hex', Optional.some(value));
13746 const rgb = fromHex(hex);
13747 copyRgbToForm(form, rgb);
13749 emitWith(form, fieldsUpdate, { hex });
13750 updatePreview(form, hex);
13752 const onValidRgb = (form, prop, value) => {
13753 const val = parseInt(value, 10);
13754 set(prop, Optional.some(val));
13755 getValueRgb().each(rgb => {
13756 const hex = copyRgbToHex(form, rgb);
13757 emitWith(form, fieldsUpdate, { hex });
13758 updatePreview(form, hex);
13761 const isHexInputEvent = data => data.type === 'hex';
13762 const onValidInput = (form, simulatedEvent) => {
13763 const data = simulatedEvent.event;
13764 if (isHexInputEvent(data)) {
13765 onValidHex(form, data.value);
13767 onValidRgb(form, data.type, data.value);
13770 const formPartStrings = key => ({
13771 label: translate(translatePrefix + key + '.label'),
13772 description: translate(translatePrefix + key + '.description')
13774 const redStrings = formPartStrings('red');
13775 const greenStrings = formPartStrings('green');
13776 const blueStrings = formPartStrings('blue');
13777 const hexStrings = formPartStrings('hex');
13778 return deepMerge(Form.sketch(parts => ({
13781 classes: [getClass('rgb-form')],
13782 attributes: { 'aria-label': translate('aria.color.picker') }
13785 parts.field('red', FormField.sketch(renderTextField(isRgbaComponent, 'red', redStrings.label, redStrings.description, 255))),
13786 parts.field('green', FormField.sketch(renderTextField(isRgbaComponent, 'green', greenStrings.label, greenStrings.description, 255))),
13787 parts.field('blue', FormField.sketch(renderTextField(isRgbaComponent, 'blue', blueStrings.label, blueStrings.description, 255))),
13788 parts.field('hex', FormField.sketch(renderTextField(isHexString, 'hex', hexStrings.label, hexStrings.description, 'ffffff'))),
13789 memPreview.asSpec()
13791 formBehaviours: derive$1([
13792 Invalidating.config({ invalidClass: getClass('form-invalid') }),
13793 config('rgb-form-events', [
13794 run$1(validInput, onValidInput),
13795 run$1(invalidInput, onInvalidInput),
13796 run$1(validatingInput, onInvalidInput)
13801 updateHex: (form, hex) => {
13802 Representing.setValue(form, { hex: hex.value });
13803 copyHexToRgb(form, hex);
13804 updatePreview(form, hex);
13809 const rgbFormSketcher = single({
13814 updateHex: (apis, form, hex) => {
13815 apis.updateHex(form, hex);
13820 return rgbFormSketcher;
13823 const paletteFactory = (_translate, getClass) => {
13824 const spectrumPart = Slider.parts.spectrum({
13827 attributes: { role: 'presentation' },
13828 classes: [getClass('sv-palette-spectrum')]
13831 const thumbPart = Slider.parts.thumb({
13834 attributes: { role: 'presentation' },
13835 classes: [getClass('sv-palette-thumb')],
13836 innerHtml: `<div class=${ getClass('sv-palette-inner-thumb') } role="presentation"></div>`
13839 const setColour = (canvas, rgba) => {
13840 const {width, height} = canvas;
13841 const ctx = canvas.getContext('2d');
13842 if (ctx === null) {
13845 ctx.fillStyle = rgba;
13846 ctx.fillRect(0, 0, width, height);
13847 const grdWhite = ctx.createLinearGradient(0, 0, width, 0);
13848 grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
13849 grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
13850 ctx.fillStyle = grdWhite;
13851 ctx.fillRect(0, 0, width, height);
13852 const grdBlack = ctx.createLinearGradient(0, 0, 0, height);
13853 grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
13854 grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
13855 ctx.fillStyle = grdBlack;
13856 ctx.fillRect(0, 0, width, height);
13858 const setPaletteHue = (slider, hue) => {
13859 const canvas = slider.components()[0].element.dom;
13860 const hsv = hsvColour(hue, 100, 100);
13861 const rgba = fromHsv(hsv);
13862 setColour(canvas, toString(rgba));
13864 const setPaletteThumb = (slider, hex) => {
13865 const hsv = fromRgb(fromHex(hex));
13866 Slider.setValue(slider, {
13871 const factory = _detail => {
13872 const getInitialValue = constant$1({
13876 const onChange = (slider, _thumb, value) => {
13877 emitWith(slider, paletteUpdate, { value });
13879 const onInit = (_slider, _thumb, spectrum, _value) => {
13880 setColour(spectrum.element.dom, toString(red));
13882 const sliderBehaviours = derive$1([
13883 Composing.config({ find: Optional.some }),
13884 Focusing.config({})
13886 return Slider.sketch({
13889 attributes: { role: 'presentation' },
13890 classes: [getClass('sv-palette')]
13906 const saturationBrightnessPaletteSketcher = single({
13908 name: 'SaturationBrightnessPalette',
13911 setHue: (_apis, slider, hue) => {
13912 setPaletteHue(slider, hue);
13914 setThumb: (_apis, slider, hex) => {
13915 setPaletteThumb(slider, hex);
13920 return saturationBrightnessPaletteSketcher;
13923 const makeFactory = (translate, getClass) => {
13924 const factory = detail => {
13925 const rgbForm = rgbFormFactory(translate, getClass, detail.onValidHex, detail.onInvalidHex);
13926 const sbPalette = paletteFactory(translate, getClass);
13927 const hueSliderToDegrees = hue => (100 - hue) / 100 * 360;
13928 const hueDegreesToSlider = hue => 100 - hue / 360 * 100;
13930 paletteRgba: Cell(red),
13931 paletteHue: Cell(0)
13933 const memSlider = record(sliderFactory(translate, getClass));
13934 const memPalette = record(sbPalette.sketch({}));
13935 const memRgb = record(rgbForm.sketch({}));
13936 const updatePalette = (anyInSystem, _hex, hue) => {
13937 memPalette.getOpt(anyInSystem).each(palette => {
13938 sbPalette.setHue(palette, hue);
13941 const updateFields = (anyInSystem, hex) => {
13942 memRgb.getOpt(anyInSystem).each(form => {
13943 rgbForm.updateHex(form, hex);
13946 const updateSlider = (anyInSystem, _hex, hue) => {
13947 memSlider.getOpt(anyInSystem).each(slider => {
13948 Slider.setValue(slider, hueDegreesToSlider(hue));
13951 const updatePaletteThumb = (anyInSystem, hex) => {
13952 memPalette.getOpt(anyInSystem).each(palette => {
13953 sbPalette.setThumb(palette, hex);
13956 const updateState = (hex, hue) => {
13957 const rgba = fromHex(hex);
13958 state.paletteRgba.set(rgba);
13959 state.paletteHue.set(hue);
13961 const runUpdates = (anyInSystem, hex, hue, updates) => {
13962 updateState(hex, hue);
13963 each$1(updates, update => {
13964 update(anyInSystem, hex, hue);
13967 const onPaletteUpdate = () => {
13968 const updates = [updateFields];
13969 return (form, simulatedEvent) => {
13970 const value = simulatedEvent.event.value;
13971 const oldHue = state.paletteHue.get();
13972 const newHsv = hsvColour(oldHue, value.x, 100 - value.y);
13973 const newHex = hsvToHex(newHsv);
13974 runUpdates(form, newHex, oldHue, updates);
13977 const onSliderUpdate = () => {
13982 return (form, simulatedEvent) => {
13983 const hue = hueSliderToDegrees(simulatedEvent.event.value);
13984 const oldRgb = state.paletteRgba.get();
13985 const oldHsv = fromRgb(oldRgb);
13986 const newHsv = hsvColour(hue, oldHsv.saturation, oldHsv.value);
13987 const newHex = hsvToHex(newHsv);
13988 runUpdates(form, newHex, hue, updates);
13991 const onFieldsUpdate = () => {
13997 return (form, simulatedEvent) => {
13998 const hex = simulatedEvent.event.hex;
13999 const hsv = hexToHsv(hex);
14000 runUpdates(form, hex, hsv.hue, updates);
14007 memPalette.asSpec(),
14008 memSlider.asSpec(),
14011 behaviours: derive$1([
14012 config('colour-picker-events', [
14013 run$1(fieldsUpdate, onFieldsUpdate()),
14014 run$1(paletteUpdate, onPaletteUpdate()),
14015 run$1(sliderUpdate, onSliderUpdate())
14017 Composing.config({ find: comp => memRgb.getOpt(comp) }),
14018 Keying.config({ mode: 'acyclic' })
14022 const colourPickerSketcher = single({
14023 name: 'ColourPicker',
14026 defaulted('onValidHex', noop),
14027 defaulted('onInvalidHex', noop)
14031 return colourPickerSketcher;
14034 const self = () => Composing.config({ find: Optional.some });
14035 const memento$1 = mem => Composing.config({ find: mem.getOpt });
14036 const childAt = index => Composing.config({ find: comp => child$2(comp.element, index).bind(element => comp.getSystem().getByDom(element).toOptional()) });
14037 const ComposingConfigs = {
14039 memento: memento$1,
14043 const processors = objOf([
14044 defaulted('preprocess', identity),
14045 defaulted('postprocess', identity)
14047 const memento = (mem, rawProcessors) => {
14048 const ps = asRawOrDie$1('RepresentingConfigs.memento processors', processors, rawProcessors);
14049 return Representing.config({
14052 getValue: comp => {
14053 const other = mem.get(comp);
14054 const rawValue = Representing.getValue(other);
14055 return ps.postprocess(rawValue);
14057 setValue: (comp, rawValue) => {
14058 const newValue = ps.preprocess(rawValue);
14059 const other = mem.get(comp);
14060 Representing.setValue(other, newValue);
14065 const withComp = (optInitialValue, getter, setter) => Representing.config({
14068 ...optInitialValue.map(initialValue => ({ initialValue })).getOr({}),
14073 const withElement = (initialValue, getter, setter) => withComp(initialValue, c => getter(c.element), (c, v) => setter(c.element, v));
14074 const domValue = optInitialValue => withElement(optInitialValue, get$6, set$5);
14075 const domHtml = optInitialValue => withElement(optInitialValue, get$9, set$6);
14076 const memory = initialValue => Representing.config({
14082 const RepresentingConfigs = {
14092 'colorcustom.rgb.red.label': 'R',
14093 'colorcustom.rgb.red.description': 'Red component',
14094 'colorcustom.rgb.green.label': 'G',
14095 'colorcustom.rgb.green.description': 'Green component',
14096 'colorcustom.rgb.blue.label': 'B',
14097 'colorcustom.rgb.blue.description': 'Blue component',
14098 'colorcustom.rgb.hex.label': '#',
14099 'colorcustom.rgb.hex.description': 'Hex color code',
14100 'colorcustom.rgb.range': 'Range 0 to 255',
14101 'aria.color.picker': 'Color Picker',
14102 'aria.input.invalid': 'Invalid input'
14104 const translate$1 = providerBackstage => key => {
14105 return providerBackstage.translate(english[key]);
14107 const renderColorPicker = (_spec, providerBackstage, initialData) => {
14108 const getClass = key => 'tox-' + key;
14109 const colourPickerFactory = makeFactory(translate$1(providerBackstage), getClass);
14110 const onValidHex = form => {
14111 emitWith(form, formActionEvent, {
14116 const onInvalidHex = form => {
14117 emitWith(form, formActionEvent, {
14122 const memPicker = record(colourPickerFactory.sketch({
14125 classes: [getClass('color-picker-container')],
14126 attributes: { role: 'presentation' }
14132 dom: { tag: 'div' },
14133 components: [memPicker.asSpec()],
14134 behaviours: derive$1([
14135 RepresentingConfigs.withComp(initialData, comp => {
14136 const picker = memPicker.get(comp);
14137 const optRgbForm = Composing.getCurrent(picker);
14138 const optHex = optRgbForm.bind(rgbForm => {
14139 const formValues = Representing.getValue(rgbForm);
14140 return formValues.hex;
14142 return optHex.map(hex => '#' + hex).getOr('');
14143 }, (comp, newValue) => {
14144 const pattern = /^#([a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?)/;
14145 const valOpt = Optional.from(pattern.exec(newValue)).bind(matches => get$h(matches, 1));
14146 const picker = memPicker.get(comp);
14147 const optRgbForm = Composing.getCurrent(picker);
14148 optRgbForm.fold(() => {
14149 console.log('Can not find form');
14151 Representing.setValue(rgbForm, { hex: valOpt.getOr('') });
14152 Form.getField(rgbForm, 'hex').each(hexField => {
14153 emit(hexField, input());
14157 ComposingConfigs.self()
14162 var global$2 = tinymce.util.Tools.resolve('tinymce.Resource');
14164 const isOldCustomEditor = spec => has$2(spec, 'init');
14165 const renderCustomEditor = spec => {
14166 const editorApi = value$2();
14167 const memReplaced = record({ dom: { tag: spec.tag } });
14168 const initialValue = value$2();
14172 classes: ['tox-custom-editor']
14174 behaviours: derive$1([
14175 config('custom-editor-events', [runOnAttached(component => {
14176 memReplaced.getOpt(component).each(ta => {
14177 (isOldCustomEditor(spec) ? spec.init(ta.element.dom) : global$2.load(spec.scriptId, spec.scriptUrl).then(init => init(ta.element.dom, spec.settings))).then(ea => {
14178 initialValue.on(cvalue => {
14179 ea.setValue(cvalue);
14181 initialValue.clear();
14186 RepresentingConfigs.withComp(Optional.none(), () => editorApi.get().fold(() => initialValue.get().getOr(''), ed => ed.getValue()), (component, value) => {
14187 editorApi.get().fold(() => initialValue.set(value), ed => ed.setValue(value));
14189 ComposingConfigs.self()
14191 components: [memReplaced.asSpec()]
14195 var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
14197 const filterByExtension = (files, providersBackstage) => {
14198 const allowedImageFileTypes = global$1.explode(providersBackstage.getOption('images_file_types'));
14199 const isFileInAllowedTypes = file => exists(allowedImageFileTypes, type => endsWith(file.name.toLowerCase(), `.${ type.toLowerCase() }`));
14200 return filter$2(from(files), isFileInAllowedTypes);
14202 const renderDropZone = (spec, providersBackstage, initialData) => {
14203 const stopper = (_, se) => {
14206 const sequence = actions => (comp, se) => {
14207 each$1(actions, a => {
14211 const onDrop = (comp, se) => {
14212 if (!Disabling.isDisabled(comp)) {
14213 const transferEvent = se.event.raw;
14214 handleFiles(comp, transferEvent.dataTransfer?.files);
14217 const onSelect = (component, simulatedEvent) => {
14218 const input = simulatedEvent.event.raw.target;
14219 handleFiles(component, input.files);
14221 const handleFiles = (component, files) => {
14223 Representing.setValue(component, filterByExtension(files, providersBackstage));
14224 emitWith(component, formChangeEvent, { name: spec.name });
14227 const memInput = record({
14234 styles: { display: 'none' }
14236 behaviours: derive$1([config('input-file-events', [
14241 const renderField = s => ({
14245 classes: ['tox-dropzone-container']
14247 behaviours: derive$1([
14248 RepresentingConfigs.memory(initialData.getOr([])),
14249 ComposingConfigs.self(),
14250 Disabling.config({}),
14252 toggleClass: 'dragenter',
14253 toggleOnExecute: false
14255 config('dropzone-events', [
14256 run$1('dragenter', sequence([
14260 run$1('dragleave', sequence([
14264 run$1('dragover', stopper),
14265 run$1('drop', sequence([
14269 run$1(change(), onSelect)
14275 classes: ['tox-dropzone'],
14281 components: [text$2(providersBackstage.translate('Drop an image here'))]
14286 styles: { position: 'relative' },
14289 'tox-button--secondary'
14293 text$2(providersBackstage.translate('Browse for an image')),
14297 const inputComp = memInput.get(comp);
14298 inputComp.element.dom.click();
14300 buttonBehaviours: derive$1([
14301 Tabstopping.config({}),
14302 DisablingConfigs.button(providersBackstage.isDisabled),
14309 const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
14310 const pField = FormField.parts.field({ factory: { sketch: renderField } });
14311 return renderFormFieldWith(pLabel, pField, ['tox-form__group--stretched'], []);
14314 const renderGrid = (spec, backstage) => ({
14319 `tox-form__grid--${ spec.columns }col`
14322 components: map$2(spec.items, backstage.interpreter)
14325 const beforeObject = generate$6('alloy-fake-before-tabstop');
14326 const afterObject = generate$6('alloy-fake-after-tabstop');
14327 const craftWithClasses = classes => {
14336 attributes: { tabindex: '0' },
14339 behaviours: derive$1([
14340 Focusing.config({ ignore: true }),
14341 Tabstopping.config({})
14345 const craft = spec => {
14349 classes: ['tox-navobj']
14352 craftWithClasses([beforeObject]),
14354 craftWithClasses([afterObject])
14356 behaviours: derive$1([ComposingConfigs.childAt(1)])
14359 const triggerTab = (placeholder, shiftKey) => {
14360 emitWith(placeholder, keydown(), {
14367 const onFocus = (container, targetComp) => {
14368 const target = targetComp.element;
14369 if (has(target, beforeObject)) {
14370 triggerTab(container, true);
14371 } else if (has(target, afterObject)) {
14372 triggerTab(container, false);
14375 const isPseudoStop = element => {
14376 return closest(element, [
14377 '.' + beforeObject,
14379 ].join(','), never);
14382 const getDynamicSource = initialData => {
14383 const cachedValue = Cell(initialData.getOr(''));
14385 getValue: _frameComponent => cachedValue.get(),
14386 setValue: (frameComponent, html) => {
14387 if (cachedValue.get() !== html) {
14388 set$9(frameComponent.element, 'srcdoc', html);
14390 cachedValue.set(html);
14394 const renderIFrame = (spec, providersBackstage, initialData) => {
14395 const isSandbox = spec.sandboxed;
14396 const isTransparent = spec.transparent;
14397 const baseClass = 'tox-dialog__iframe';
14398 const attributes = {
14399 ...spec.label.map(title => ({ title })).getOr({}),
14400 ...initialData.map(html => ({ srcdoc: html })).getOr({}),
14401 ...isSandbox ? { sandbox: 'allow-scripts allow-same-origin' } : {}
14403 const sourcing = getDynamicSource(initialData);
14404 const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
14405 const factory = newSpec => craft({
14410 classes: isTransparent ? [baseClass] : [
14412 `${ baseClass }--opaque`
14415 behaviours: derive$1([
14416 Tabstopping.config({}),
14417 Focusing.config({}),
14418 RepresentingConfigs.withComp(initialData, sourcing.getValue, sourcing.setValue)
14421 const pField = FormField.parts.field({ factory: { sketch: factory } });
14422 return renderFormFieldWith(pLabel, pField, ['tox-form__group--stretched'], []);
14425 const image = image => new Promise((resolve, reject) => {
14426 const loaded = () => {
14430 const listeners = [
14431 bind(image, 'load', loaded),
14432 bind(image, 'error', () => {
14434 reject('Unable to load data from image: ' + image.dom.src);
14437 const destroy = () => each$1(listeners, l => l.unbind());
14438 if (image.dom.complete) {
14443 const calculateImagePosition = (panelWidth, panelHeight, imageWidth, imageHeight, zoom) => {
14444 const width = imageWidth * zoom;
14445 const height = imageHeight * zoom;
14446 const left = Math.max(0, panelWidth / 2 - width / 2);
14447 const top = Math.max(0, panelHeight / 2 - height / 2);
14449 left: left.toString() + 'px',
14450 top: top.toString() + 'px',
14451 width: width.toString() + 'px',
14452 height: height.toString() + 'px'
14455 const zoomToFit = (panel, width, height) => {
14456 const panelW = get$c(panel);
14457 const panelH = get$d(panel);
14458 return Math.min(panelW / width, panelH / height, 1);
14460 const renderImagePreview = (spec, initialData) => {
14461 const cachedData = Cell(initialData.getOr({ url: '' }));
14462 const memImage = record({
14465 classes: ['tox-imagepreview__image'],
14466 attributes: initialData.map(data => ({ src: data.url })).getOr({})
14469 const memContainer = record({
14472 classes: ['tox-imagepreview__container'],
14473 attributes: { role: 'presentation' }
14475 components: [memImage.asSpec()]
14477 const setValue = (frameComponent, data) => {
14478 const translatedData = { url: data.url };
14479 data.zoom.each(z => translatedData.zoom = z);
14480 data.cachedWidth.each(z => translatedData.cachedWidth = z);
14481 data.cachedHeight.each(z => translatedData.cachedHeight = z);
14482 cachedData.set(translatedData);
14483 const applyFramePositioning = () => {
14484 const {cachedWidth, cachedHeight, zoom} = translatedData;
14485 if (!isUndefined(cachedWidth) && !isUndefined(cachedHeight)) {
14486 if (isUndefined(zoom)) {
14487 const z = zoomToFit(frameComponent.element, cachedWidth, cachedHeight);
14488 translatedData.zoom = z;
14490 const position = calculateImagePosition(get$c(frameComponent.element), get$d(frameComponent.element), cachedWidth, cachedHeight, translatedData.zoom);
14491 memContainer.getOpt(frameComponent).each(container => {
14492 setAll(container.element, position);
14496 memImage.getOpt(frameComponent).each(imageComponent => {
14497 const img = imageComponent.element;
14498 if (data.url !== get$f(img, 'src')) {
14499 set$9(img, 'src', data.url);
14500 remove$2(frameComponent.element, 'tox-imagepreview__loaded');
14502 applyFramePositioning();
14503 image(img).then(img => {
14504 if (frameComponent.getSystem().isConnected()) {
14505 add$2(frameComponent.element, 'tox-imagepreview__loaded');
14506 translatedData.cachedWidth = img.dom.naturalWidth;
14507 translatedData.cachedHeight = img.dom.naturalHeight;
14508 applyFramePositioning();
14514 spec.height.each(h => styles.height = h);
14515 const fakeValidatedData = initialData.map(d => ({
14517 zoom: Optional.from(d.zoom),
14518 cachedWidth: Optional.from(d.cachedWidth),
14519 cachedHeight: Optional.from(d.cachedHeight)
14524 classes: ['tox-imagepreview'],
14526 attributes: { role: 'presentation' }
14528 components: [memContainer.asSpec()],
14529 behaviours: derive$1([
14530 ComposingConfigs.self(),
14531 RepresentingConfigs.withComp(fakeValidatedData, () => cachedData.get(), setValue)
14536 const renderLabel$1 = (spec, backstageShared) => {
14540 classes: ['tox-label']
14542 components: [text$2(backstageShared.providers.translate(spec.label))]
14544 const comps = map$2(spec.items, backstageShared.interpreter);
14548 classes: ['tox-form__group']
14554 behaviours: derive$1([
14555 ComposingConfigs.self(),
14556 Replacing.config({}),
14557 RepresentingConfigs.domHtml(Optional.none()),
14558 Keying.config({ mode: 'acyclic' })
14563 const internalToolbarButtonExecute = generate$6('toolbar.button.execute');
14564 const onToolbarButtonExecute = info => runOnExecute$1((comp, _simulatedEvent) => {
14565 runWithApi(info, comp)(itemApi => {
14566 emitWith(comp, internalToolbarButtonExecute, { buttonApi: itemApi });
14567 info.onAction(itemApi);
14570 const toolbarButtonEventOrder = {
14573 'alloy.base.behaviour',
14575 'toolbar-button-events'
14579 const renderIcon = (iconName, iconsProvider, behaviours) => render$3(iconName, {
14583 'tox-tbtn__icon-wrap'
14587 const renderIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, []);
14588 const renderReplaceableIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, [Replacing.config({})]);
14589 const renderLabel = (text, prefix, providersBackstage) => ({
14592 classes: [`${ prefix }__select-label`]
14594 components: [text$2(providersBackstage.translate(text))],
14595 behaviours: derive$1([Replacing.config({})])
14598 const updateMenuText = generate$6('update-menu-text');
14599 const updateMenuIcon = generate$6('update-menu-icon');
14600 const renderCommonDropdown = (spec, prefix, sharedBackstage) => {
14601 const editorOffCell = Cell(noop);
14602 const optMemDisplayText = spec.text.map(text => record(renderLabel(text, prefix, sharedBackstage.providers)));
14603 const optMemDisplayIcon = spec.icon.map(iconName => record(renderReplaceableIconFromPack(iconName, sharedBackstage.providers.icons)));
14604 const onLeftOrRightInMenu = (comp, se) => {
14605 const dropdown = Representing.getValue(comp);
14606 Focusing.focus(dropdown);
14607 emitWith(dropdown, 'keydown', { raw: se.event.raw });
14608 Dropdown.close(dropdown);
14609 return Optional.some(true);
14611 const role = spec.role.fold(() => ({}), role => ({ role }));
14612 const tooltipAttributes = spec.tooltip.fold(() => ({}), tooltip => {
14613 const translatedTooltip = sharedBackstage.providers.translate(tooltip);
14615 'title': translatedTooltip,
14616 'aria-label': translatedTooltip
14619 const iconSpec = render$3('chevron-down', {
14621 classes: [`${ prefix }__select-chevron`]
14622 }, sharedBackstage.providers.icons);
14623 const memDropdown = record(Dropdown.sketch({
14624 ...spec.uid ? { uid: spec.uid } : {},
14630 `${ prefix }--select`
14631 ].concat(map$2(spec.classes, c => `${ prefix }--${ c }`)),
14632 attributes: { ...tooltipAttributes }
14634 components: componentRenderPipeline([
14635 optMemDisplayIcon.map(mem => mem.asSpec()),
14636 optMemDisplayText.map(mem => mem.asSpec()),
14637 Optional.some(iconSpec)
14641 onOpen: (anchor, dropdownComp, tmenuComp) => {
14642 if (spec.searchable) {
14643 focusSearchField(tmenuComp);
14646 dropdownBehaviours: derive$1([
14647 ...spec.dropdownBehaviours,
14648 DisablingConfigs.button(() => spec.disabled || sharedBackstage.providers.isDisabled()),
14650 Unselecting.config({}),
14651 Replacing.config({}),
14652 config('dropdown-events', [
14653 onControlAttached(spec, editorOffCell),
14654 onControlDetached(spec, editorOffCell)
14656 config('menubutton-update-display-text', [
14657 run$1(updateMenuText, (comp, se) => {
14658 optMemDisplayText.bind(mem => mem.getOpt(comp)).each(displayText => {
14659 Replacing.set(displayText, [text$2(sharedBackstage.providers.translate(se.event.text))]);
14662 run$1(updateMenuIcon, (comp, se) => {
14663 optMemDisplayIcon.bind(mem => mem.getOpt(comp)).each(displayIcon => {
14664 Replacing.set(displayIcon, [renderReplaceableIconFromPack(se.event.icon, sharedBackstage.providers.icons)]);
14669 eventOrder: deepMerge(toolbarButtonEventOrder, {
14672 'alloy.base.behaviour',
14673 'item-type-events',
14674 'normal-dropdown-events'
14677 sandboxBehaviours: derive$1([
14680 onLeft: onLeftOrRightInMenu,
14681 onRight: onLeftOrRightInMenu
14683 config('dropdown-sandbox-events', [
14684 run$1(refetchTriggerEvent, (originalSandboxComp, se) => {
14685 handleRefetchTrigger(originalSandboxComp);
14688 run$1(redirectMenuItemInteractionEvent, (sandboxComp, se) => {
14689 handleRedirectToMenuItem(sandboxComp, se);
14694 lazySink: sharedBackstage.getSink,
14695 toggleClass: `${ prefix }--active`,
14698 ...part(false, spec.columns, spec.presets),
14699 fakeFocus: spec.searchable,
14700 onHighlightItem: updateAriaOnHighlight,
14701 onCollapseMenu: (tmenuComp, itemCompCausingCollapse, nowActiveMenuComp) => {
14702 Highlighting.getHighlighted(nowActiveMenuComp).each(itemComp => {
14703 updateAriaOnHighlight(tmenuComp, nowActiveMenuComp, itemComp);
14706 onDehighlightItem: updateAriaOnDehighlight
14709 fetch: comp => Future.nu(curry(spec.fetch, comp))
14711 return memDropdown.asSpec();
14714 const isMenuItemReference = item => isString(item);
14715 const isSeparator$2 = item => item.type === 'separator';
14716 const isExpandingMenuItem = item => has$2(item, 'getSubmenuItems');
14717 const separator$2 = { type: 'separator' };
14718 const unwrapReferences = (items, menuItems) => {
14719 const realItems = foldl(items, (acc, item) => {
14720 if (isMenuItemReference(item)) {
14723 } else if (item === '|') {
14724 return acc.length > 0 && !isSeparator$2(acc[acc.length - 1]) ? acc.concat([separator$2]) : acc;
14725 } else if (has$2(menuItems, item.toLowerCase())) {
14726 return acc.concat([menuItems[item.toLowerCase()]]);
14731 return acc.concat([item]);
14734 if (realItems.length > 0 && isSeparator$2(realItems[realItems.length - 1])) {
14739 const getFromExpandingItem = (item, menuItems) => {
14740 const submenuItems = item.getSubmenuItems();
14741 const rest = expand(submenuItems, menuItems);
14742 const newMenus = deepMerge(rest.menus, { [item.value]: rest.items });
14743 const newExpansions = deepMerge(rest.expansions, { [item.value]: item.value });
14747 expansions: newExpansions
14750 const generateValueIfRequired = item => {
14751 const itemValue = get$g(item, 'value').getOrThunk(() => generate$6('generated-menu-item'));
14752 return deepMerge({ value: itemValue }, item);
14754 const expand = (items, menuItems) => {
14755 const realItems = unwrapReferences(isString(items) ? items.split(' ') : items, menuItems);
14756 return foldr(realItems, (acc, item) => {
14757 if (isExpandingMenuItem(item)) {
14758 const itemWithValue = generateValueIfRequired(item);
14759 const newData = getFromExpandingItem(itemWithValue, menuItems);
14761 menus: deepMerge(acc.menus, newData.menus),
14766 expansions: deepMerge(acc.expansions, newData.expansions)
14784 const getSearchModeForField = settings => {
14785 return settings.search.fold(() => ({ searchMode: 'no-search' }), searchSettings => ({
14786 searchMode: 'search-with-field',
14787 placeholder: searchSettings.placeholder
14790 const getSearchModeForResults = settings => {
14791 return settings.search.fold(() => ({ searchMode: 'no-search' }), _ => ({ searchMode: 'search-with-results' }));
14793 const build = (items, itemResponse, backstage, settings) => {
14794 const primary = generate$6('primary-menu');
14795 const data = expand(items, backstage.shared.providers.menuItems());
14796 if (data.items.length === 0) {
14797 return Optional.none();
14799 const mainMenuSearchMode = getSearchModeForField(settings);
14800 const mainMenu = createPartialMenu(primary, data.items, itemResponse, backstage, settings.isHorizontalMenu, mainMenuSearchMode);
14801 const submenuSearchMode = getSearchModeForResults(settings);
14802 const submenus = map$1(data.menus, (menuItems, menuName) => createPartialMenu(menuName, menuItems, itemResponse, backstage, false, submenuSearchMode));
14803 const menus = deepMerge(submenus, wrap$1(primary, mainMenu));
14804 return Optional.from(tieredMenu.tieredData(primary, menus, data.expansions));
14807 const isSingleListItem = item => !has$2(item, 'items');
14808 const dataAttribute = 'data-value';
14809 const fetchItems = (dropdownComp, name, items, selectedValue) => map$2(items, item => {
14810 if (!isSingleListItem(item)) {
14812 type: 'nestedmenuitem',
14814 getSubmenuItems: () => fetchItems(dropdownComp, name, item.items, selectedValue)
14818 type: 'togglemenuitem',
14821 active: item.value === selectedValue,
14823 Representing.setValue(dropdownComp, item.value);
14824 emitWith(dropdownComp, formChangeEvent, { name });
14825 Focusing.focus(dropdownComp);
14830 const findItemByValue = (items, value) => findMap(items, item => {
14831 if (!isSingleListItem(item)) {
14832 return findItemByValue(item.items, value);
14834 return someIf(item.value === value, item);
14837 const renderListBox = (spec, backstage, initialData) => {
14838 const providersBackstage = backstage.shared.providers;
14839 const initialItem = initialData.bind(value => findItemByValue(spec.items, value)).orThunk(() => head(spec.items).filter(isSingleListItem));
14840 const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
14841 const pField = FormField.parts.field({
14844 sketch: sketchSpec => renderCommonDropdown({
14845 uid: sketchSpec.uid,
14846 text: initialItem.map(item => item.text),
14847 icon: Optional.none(),
14848 tooltip: spec.label,
14849 role: Optional.none(),
14850 fetch: (comp, callback) => {
14851 const items = fetchItems(comp, spec.name, spec.items, Representing.getValue(comp));
14852 callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
14853 isHorizontalMenu: false,
14854 search: Optional.none()
14857 onSetup: constant$1(noop),
14858 getApi: constant$1({}),
14862 dropdownBehaviours: [
14863 Tabstopping.config({}),
14864 RepresentingConfigs.withComp(initialItem.map(item => item.value), comp => get$f(comp.element, dataAttribute), (comp, data) => {
14865 findItemByValue(spec.items, data).each(item => {
14866 set$9(comp.element, dataAttribute, item.value);
14867 emitWith(comp, updateMenuText, { text: item.text });
14871 }, 'tox-listbox', backstage.shared)
14874 const listBoxWrap = {
14877 classes: ['tox-listboxfield']
14879 components: [pField]
14881 return FormField.sketch({
14884 classes: ['tox-form__group']
14886 components: flatten([
14890 fieldBehaviours: derive$1([Disabling.config({
14891 disabled: constant$1(!spec.enabled),
14892 onDisabled: comp => {
14893 FormField.getField(comp).each(Disabling.disable);
14895 onEnabled: comp => {
14896 FormField.getField(comp).each(Disabling.enable);
14902 const renderPanel = (spec, backstage) => ({
14905 classes: spec.classes
14907 components: map$2(spec.items, backstage.shared.interpreter)
14910 const factory$f = (detail, _spec) => {
14911 const options = map$2(detail.options, option => ({
14914 value: option.value,
14915 innerHtml: option.text
14918 const initialValues = detail.data.map(v => wrap$1('initialValue', v)).getOr({});
14923 classes: detail.selectClasses,
14924 attributes: detail.selectAttributes
14926 components: options,
14927 behaviours: augment(detail.selectBehaviours, [
14928 Focusing.config({}),
14929 Representing.config({
14932 getValue: select => {
14933 return get$6(select.element);
14935 setValue: (select, newValue) => {
14936 const found = find$5(detail.options, opt => opt.value === newValue);
14937 if (found.isSome()) {
14938 set$5(select.element, newValue);
14947 const HtmlSelect = single({
14948 name: 'HtmlSelect',
14950 required$1('options'),
14951 field('selectBehaviours', [
14955 defaulted('selectClasses', []),
14956 defaulted('selectAttributes', {}),
14962 const renderSelectBox = (spec, providersBackstage, initialData) => {
14963 const translatedOptions = map$2(spec.items, item => ({
14964 text: providersBackstage.translate(item.text),
14967 const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
14968 const pField = FormField.parts.field({
14970 ...initialData.map(data => ({ data })).getOr({}),
14971 selectAttributes: { size: spec.size },
14972 options: translatedOptions,
14973 factory: HtmlSelect,
14974 selectBehaviours: derive$1([
14975 Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
14976 Tabstopping.config({}),
14977 config('selectbox-change', [run$1(change(), (component, _) => {
14978 emitWith(component, formChangeEvent, { name: spec.name });
14982 const chevron = spec.size > 1 ? Optional.none() : Optional.some(render$3('chevron-down', {
14984 classes: ['tox-selectfield__icon-js']
14985 }, providersBackstage.icons));
14986 const selectWrap = {
14989 classes: ['tox-selectfield']
14991 components: flatten([
14996 return FormField.sketch({
14999 classes: ['tox-form__group']
15001 components: flatten([
15005 fieldBehaviours: derive$1([
15007 disabled: () => !spec.enabled || providersBackstage.isDisabled(),
15008 onDisabled: comp => {
15009 FormField.getField(comp).each(Disabling.disable);
15011 onEnabled: comp => {
15012 FormField.getField(comp).each(Disabling.enable);
15020 const schema$h = constant$1([
15021 defaulted('field1Name', 'field1'),
15022 defaulted('field2Name', 'field2'),
15023 onStrictHandler('onLockedChange'),
15024 markers$1(['lockClass']),
15025 defaulted('locked', false),
15026 SketchBehaviours.field('coupledFieldBehaviours', [
15031 const getField = (comp, detail, partName) => getPart(comp, detail, partName).bind(Composing.getCurrent);
15032 const coupledPart = (selfName, otherName) => required({
15033 factory: FormField,
15035 overrides: detail => {
15037 fieldBehaviours: derive$1([config('coupled-input-behaviour', [run$1(input(), me => {
15038 getField(me, detail, otherName).each(other => {
15039 getPart(me, detail, 'lock').each(lock => {
15040 if (Toggling.isOn(lock)) {
15041 detail.onLockedChange(me, other, lock);
15049 const parts$c = constant$1([
15050 coupledPart('field1', 'field2'),
15051 coupledPart('field2', 'field1'),
15054 schema: [required$1('dom')],
15056 overrides: detail => {
15058 buttonBehaviours: derive$1([Toggling.config({
15059 selected: detail.locked,
15060 toggleClass: detail.markers.lockClass,
15061 aria: { mode: 'pressed' }
15068 const factory$e = (detail, components, _spec, _externals) => ({
15072 behaviours: SketchBehaviours.augment(detail.coupledFieldBehaviours, [
15073 Composing.config({ find: Optional.some }),
15074 Representing.config({
15077 getValue: comp => {
15078 const parts = getPartsOrDie(comp, detail, [
15083 [detail.field1Name]: Representing.getValue(parts.field1()),
15084 [detail.field2Name]: Representing.getValue(parts.field2())
15087 setValue: (comp, value) => {
15088 const parts = getPartsOrDie(comp, detail, [
15092 if (hasNonNullableKey(value, detail.field1Name)) {
15093 Representing.setValue(parts.field1(), value[detail.field1Name]);
15095 if (hasNonNullableKey(value, detail.field2Name)) {
15096 Representing.setValue(parts.field2(), value[detail.field2Name]);
15103 getField1: component => getPart(component, detail, 'field1'),
15104 getField2: component => getPart(component, detail, 'field2'),
15105 getLock: component => getPart(component, detail, 'lock')
15108 const FormCoupledInputs = composite({
15109 name: 'FormCoupledInputs',
15110 configFields: schema$h(),
15111 partFields: parts$c(),
15112 factory: factory$e,
15114 getField1: (apis, component) => apis.getField1(component),
15115 getField2: (apis, component) => apis.getField2(component),
15116 getLock: (apis, component) => apis.getLock(component)
15120 const formatSize = size => {
15135 const maxDecimal = unit => unit in unitDec ? unitDec[unit] : 1;
15136 let numText = size.value.toFixed(maxDecimal(size.unit));
15137 if (numText.indexOf('.') !== -1) {
15138 numText = numText.replace(/\.?0*$/, '');
15140 return numText + size.unit;
15142 const parseSize = sizeText => {
15143 const numPattern = /^\s*(\d+(?:\.\d+)?)\s*(|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)\s*$/;
15144 const match = numPattern.exec(sizeText);
15145 if (match !== null) {
15146 const value = parseFloat(match[1]);
15147 const unit = match[2];
15148 return Result.value({
15153 return Result.error(sizeText);
15156 const convertUnit = (size, unit) => {
15166 const supported = u => has$2(inInch, u);
15167 if (size.unit === unit) {
15168 return Optional.some(size.value);
15169 } else if (supported(size.unit) && supported(unit)) {
15170 if (inInch[size.unit] === inInch[unit]) {
15171 return Optional.some(size.value);
15173 return Optional.some(size.value / inInch[size.unit] * inInch[unit]);
15176 return Optional.none();
15179 const noSizeConversion = _input => Optional.none();
15180 const ratioSizeConversion = (scale, unit) => size => convertUnit(size, unit).map(value => ({
15181 value: value * scale,
15184 const makeRatioConverter = (currentFieldText, otherFieldText) => {
15185 const cValue = parseSize(currentFieldText).toOptional();
15186 const oValue = parseSize(otherFieldText).toOptional();
15187 return lift2(cValue, oValue, (cSize, oSize) => convertUnit(cSize, oSize.unit).map(val => oSize.value / val).map(r => ratioSizeConversion(r, oSize.unit)).getOr(noSizeConversion)).getOr(noSizeConversion);
15190 const renderSizeInput = (spec, providersBackstage) => {
15191 let converter = noSizeConversion;
15192 const ratioEvent = generate$6('ratio-event');
15193 const makeIcon = iconName => render$3(iconName, {
15197 'tox-lock-icon__' + iconName
15199 }, providersBackstage.icons);
15200 const pLock = FormCoupledInputs.parts.lock({
15206 'tox-button--naked',
15209 attributes: { title: providersBackstage.translate(spec.label.getOr('Constrain proportions')) }
15215 buttonBehaviours: derive$1([
15216 Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
15218 Tabstopping.config({})
15221 const formGroup = components => ({
15224 classes: ['tox-form__group']
15228 const getFieldPart = isField1 => FormField.parts.field({
15230 inputClasses: ['tox-textfield'],
15231 inputBehaviours: derive$1([
15232 Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
15234 Tabstopping.config({}),
15235 config('size-input-events', [
15236 run$1(focusin(), (component, _simulatedEvent) => {
15237 emitWith(component, ratioEvent, { isField1 });
15239 run$1(change(), (component, _simulatedEvent) => {
15240 emitWith(component, formChangeEvent, { name: spec.name });
15244 selectOnFocus: false
15246 const getLabel = label => ({
15249 classes: ['tox-label']
15251 components: [text$2(providersBackstage.translate(label))]
15253 const widthField = FormCoupledInputs.parts.field1(formGroup([
15254 FormField.parts.label(getLabel('Width')),
15257 const heightField = FormCoupledInputs.parts.field2(formGroup([
15258 FormField.parts.label(getLabel('Height')),
15259 getFieldPart(false)
15261 return FormCoupledInputs.sketch({
15264 classes: ['tox-form__group']
15269 classes: ['tox-form__controls-h-stack']
15280 field1Name: 'width',
15281 field2Name: 'height',
15283 markers: { lockClass: 'tox-locked' },
15284 onLockedChange: (current, other, _lock) => {
15285 parseSize(Representing.getValue(current)).each(size => {
15286 converter(size).each(newSize => {
15287 Representing.setValue(other, formatSize(newSize));
15291 coupledFieldBehaviours: derive$1([
15293 disabled: () => !spec.enabled || providersBackstage.isDisabled(),
15294 onDisabled: comp => {
15295 FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.disable);
15296 FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.disable);
15297 FormCoupledInputs.getLock(comp).each(Disabling.disable);
15299 onEnabled: comp => {
15300 FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.enable);
15301 FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.enable);
15302 FormCoupledInputs.getLock(comp).each(Disabling.enable);
15306 config('size-input-events2', [run$1(ratioEvent, (component, simulatedEvent) => {
15307 const isField1 = simulatedEvent.event.isField1;
15308 const optCurrent = isField1 ? FormCoupledInputs.getField1(component) : FormCoupledInputs.getField2(component);
15309 const optOther = isField1 ? FormCoupledInputs.getField2(component) : FormCoupledInputs.getField1(component);
15310 const value1 = optCurrent.map(Representing.getValue).getOr('');
15311 const value2 = optOther.map(Representing.getValue).getOr('');
15312 converter = makeRatioConverter(value1, value2);
15318 const renderSlider = (spec, providerBackstage, initialData) => {
15319 const labelPart = Slider.parts.label({
15322 classes: ['tox-label']
15324 components: [text$2(providerBackstage.translate(spec.label))]
15326 const spectrum = Slider.parts.spectrum({
15329 classes: ['tox-slider__rail'],
15330 attributes: { role: 'presentation' }
15333 const thumb = Slider.parts.thumb({
15336 classes: ['tox-slider__handle'],
15337 attributes: { role: 'presentation' }
15340 return Slider.sketch({
15343 classes: ['tox-slider'],
15344 attributes: { role: 'presentation' }
15350 getInitialValue: constant$1(initialData.getOrThunk(() => (Math.abs(spec.max) - Math.abs(spec.min)) / 2))
15357 sliderBehaviours: derive$1([
15358 ComposingConfigs.self(),
15359 Focusing.config({})
15361 onChoose: (component, thumb, value) => {
15362 emitWith(component, formChangeEvent, {
15370 const renderTable = (spec, providersBackstage) => {
15371 const renderTh = text => ({
15374 innerHtml: providersBackstage.translate(text)
15377 const renderHeader = header => ({
15378 dom: { tag: 'thead' },
15380 dom: { tag: 'tr' },
15381 components: map$2(header, renderTh)
15384 const renderTd = text => ({
15387 innerHtml: providersBackstage.translate(text)
15390 const renderTr = row => ({
15391 dom: { tag: 'tr' },
15392 components: map$2(row, renderTd)
15394 const renderRows = rows => ({
15395 dom: { tag: 'tbody' },
15396 components: map$2(rows, renderTr)
15401 classes: ['tox-dialog__table']
15404 renderHeader(spec.header),
15405 renderRows(spec.cells)
15407 behaviours: derive$1([
15408 Tabstopping.config({}),
15409 Focusing.config({})
15414 const renderTextField = (spec, providersBackstage) => {
15415 const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
15416 const baseInputBehaviours = [
15417 Disabling.config({ disabled: () => spec.disabled || providersBackstage.isDisabled() }),
15421 useEnter: spec.multiline !== true,
15422 useControlEnter: spec.multiline === true,
15424 emit(comp, formSubmitEvent);
15425 return Optional.some(true);
15428 config('textfield-change', [
15429 run$1(input(), (component, _) => {
15430 emitWith(component, formChangeEvent, { name: spec.name });
15432 run$1(postPaste(), (component, _) => {
15433 emitWith(component, formChangeEvent, { name: spec.name });
15436 Tabstopping.config({})
15438 const validatingBehaviours = spec.validation.map(vl => Invalidating.config({
15439 getRoot: input => {
15440 return parentElement(input.element);
15442 invalidClass: 'tox-invalid',
15444 validate: input => {
15445 const v = Representing.getValue(input);
15446 const result = vl.validator(v);
15447 return Future.pure(result === true ? Result.value(v) : Result.error(result));
15449 validateOnLoad: vl.validateOnLoad
15452 const placeholder = spec.placeholder.fold(constant$1({}), p => ({ placeholder: providersBackstage.translate(p) }));
15453 const inputMode = spec.inputMode.fold(constant$1({}), mode => ({ inputmode: mode }));
15454 const inputAttributes = {
15458 const pField = FormField.parts.field({
15459 tag: spec.multiline === true ? 'textarea' : 'input',
15460 ...spec.data.map(data => ({ data })).getOr({}),
15462 inputClasses: [spec.classname],
15463 inputBehaviours: derive$1(flatten([
15464 baseInputBehaviours,
15465 validatingBehaviours
15467 selectOnFocus: false,
15470 const extraClasses = spec.flex ? ['tox-form__group--stretched'] : [];
15471 const extraClasses2 = extraClasses.concat(spec.maximized ? ['tox-form-group--maximize'] : []);
15472 const extraBehaviours = [
15474 disabled: () => spec.disabled || providersBackstage.isDisabled(),
15475 onDisabled: comp => {
15476 FormField.getField(comp).each(Disabling.disable);
15478 onEnabled: comp => {
15479 FormField.getField(comp).each(Disabling.enable);
15484 return renderFormFieldWith(pLabel, pField, extraClasses2, extraBehaviours);
15486 const renderInput = (spec, providersBackstage, initialData) => renderTextField({
15490 inputMode: spec.inputMode,
15491 placeholder: spec.placeholder,
15493 disabled: !spec.enabled,
15494 classname: 'tox-textfield',
15495 validation: Optional.none(),
15496 maximized: spec.maximized,
15498 }, providersBackstage);
15499 const renderTextarea = (spec, providersBackstage, initialData) => renderTextField({
15503 inputMode: Optional.none(),
15504 placeholder: spec.placeholder,
15506 disabled: !spec.enabled,
15507 classname: 'tox-textarea',
15508 validation: Optional.none(),
15509 maximized: spec.maximized,
15511 }, providersBackstage);
15513 const events$6 = (streamConfig, streamState) => {
15514 const streams = streamConfig.stream.streams;
15515 const processor = streams.setup(streamConfig, streamState);
15517 run$1(streamConfig.event, processor),
15518 runOnDetached(() => streamState.cancel())
15519 ].concat(streamConfig.cancelEvent.map(e => [run$1(e, () => streamState.cancel())]).getOr([])));
15522 var ActiveStreaming = /*#__PURE__*/Object.freeze({
15527 const first = (fn, rate) => {
15529 const cancel = () => {
15530 if (!isNull(timer)) {
15531 clearTimeout(timer);
15535 const throttle = (...args) => {
15536 if (isNull(timer)) {
15537 timer = setTimeout(() => {
15539 fn.apply(null, args);
15548 const last = (fn, rate) => {
15550 const cancel = () => {
15551 if (!isNull(timer)) {
15552 clearTimeout(timer);
15556 const throttle = (...args) => {
15558 timer = setTimeout(() => {
15560 fn.apply(null, args);
15569 const throttle = _config => {
15570 const state = Cell(null);
15571 const readState = () => ({ timer: state.get() !== null ? 'set' : 'unset' });
15572 const setTimer = t => {
15575 const cancel = () => {
15576 const t = state.get();
15587 const init$9 = spec => spec.stream.streams.state(spec);
15589 var StreamingState = /*#__PURE__*/Object.freeze({
15591 throttle: throttle,
15595 const setup$c = (streamInfo, streamState) => {
15596 const sInfo = streamInfo.stream;
15597 const throttler = last(streamInfo.onStream, sInfo.delay);
15598 streamState.setTimer(throttler);
15599 return (component, simulatedEvent) => {
15600 throttler.throttle(component, simulatedEvent);
15601 if (sInfo.stopEvent) {
15602 simulatedEvent.stop();
15606 var StreamingSchema = [
15607 requiredOf('stream', choose$1('mode', {
15609 required$1('delay'),
15610 defaulted('stopEvent', true),
15611 output$1('streams', {
15617 defaulted('event', 'input'),
15618 option$3('cancelEvent'),
15619 onStrictHandler('onStream')
15622 const Streaming = create$4({
15623 fields: StreamingSchema,
15625 active: ActiveStreaming,
15626 state: StreamingState
15629 const setValueFromItem = (model, input, item) => {
15630 const itemData = Representing.getValue(item);
15631 Representing.setValue(input, itemData);
15632 setCursorAtEnd(input);
15634 const setSelectionOn = (input, f) => {
15635 const el = input.element;
15636 const value = get$6(el);
15637 const node = el.dom;
15638 if (get$f(el, 'type') !== 'number') {
15642 const setCursorAtEnd = input => {
15643 setSelectionOn(input, (node, value) => node.setSelectionRange(value.length, value.length));
15645 const setSelectionToEnd = (input, startOffset) => {
15646 setSelectionOn(input, (node, value) => node.setSelectionRange(startOffset, value.length));
15648 const attemptSelectOver = (model, input, item) => {
15649 if (!model.selectsOver) {
15650 return Optional.none();
15652 const currentValue = Representing.getValue(input);
15653 const inputDisplay = model.getDisplayText(currentValue);
15654 const itemValue = Representing.getValue(item);
15655 const itemDisplay = model.getDisplayText(itemValue);
15656 return itemDisplay.indexOf(inputDisplay) === 0 ? Optional.some(() => {
15657 setValueFromItem(model, input, item);
15658 setSelectionToEnd(input, inputDisplay.length);
15659 }) : Optional.none();
15663 const itemExecute = constant$1('alloy.typeahead.itemexecute');
15665 const make$3 = (detail, components, spec, externals) => {
15666 const navigateList = (comp, simulatedEvent, highlighter) => {
15667 detail.previewing.set(false);
15668 const sandbox = Coupling.getCoupled(comp, 'sandbox');
15669 if (Sandboxing.isOpen(sandbox)) {
15670 Composing.getCurrent(sandbox).each(menu => {
15671 Highlighting.getHighlighted(menu).fold(() => {
15674 dispatchEvent(sandbox, menu.element, 'keydown', simulatedEvent);
15678 const onOpenSync = sandbox => {
15679 Composing.getCurrent(sandbox).each(highlighter);
15681 open(detail, mapFetch(comp), comp, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
15684 const focusBehaviours$1 = focusBehaviours(detail);
15685 const mapFetch = comp => tdata => tdata.map(data => {
15686 const menus = values(data.menus);
15687 const items = bind$3(menus, menu => filter$2(menu.items, item => item.type === 'item'));
15688 const repState = Representing.getState(comp);
15689 repState.update(map$2(items, item => item.data));
15692 const getActiveMenu = sandboxComp => Composing.getCurrent(sandboxComp);
15693 const typeaheadCustomEvents = 'typeaheadevents';
15694 const behaviours = [
15695 Focusing.config({}),
15696 Representing.config({
15697 onSetValue: detail.onSetValue,
15700 getDataKey: comp => get$6(comp.element),
15701 getFallbackEntry: itemString => ({
15705 setValue: (comp, data) => {
15706 set$5(comp.element, detail.model.getDisplayText(data));
15708 ...detail.initialData.map(d => wrap$1('initialValue', d)).getOr({})
15714 delay: detail.responseTime,
15717 onStream: (component, _simulatedEvent) => {
15718 const sandbox = Coupling.getCoupled(component, 'sandbox');
15719 const focusInInput = Focusing.isFocused(component);
15720 if (focusInInput) {
15721 if (get$6(component.element).length >= detail.minChars) {
15722 const previousValue = getActiveMenu(sandbox).bind(activeMenu => Highlighting.getHighlighted(activeMenu).map(Representing.getValue));
15723 detail.previewing.set(true);
15724 const onOpenSync = _sandbox => {
15725 getActiveMenu(sandbox).each(activeMenu => {
15726 previousValue.fold(() => {
15727 if (detail.model.selectsOver) {
15728 Highlighting.highlightFirst(activeMenu);
15731 Highlighting.highlightBy(activeMenu, item => {
15732 const itemData = Representing.getValue(item);
15733 return itemData.value === pv.value;
15735 Highlighting.getHighlighted(activeMenu).orThunk(() => {
15736 Highlighting.highlightFirst(activeMenu);
15737 return Optional.none();
15742 open(detail, mapFetch(component), component, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightJustMenu).get(noop);
15746 cancelEvent: typeaheadCancel()
15750 onDown: (comp, simulatedEvent) => {
15751 navigateList(comp, simulatedEvent, Highlighting.highlightFirst);
15752 return Optional.some(true);
15754 onEscape: comp => {
15755 const sandbox = Coupling.getCoupled(comp, 'sandbox');
15756 if (Sandboxing.isOpen(sandbox)) {
15757 Sandboxing.close(sandbox);
15758 return Optional.some(true);
15760 return Optional.none();
15762 onUp: (comp, simulatedEvent) => {
15763 navigateList(comp, simulatedEvent, Highlighting.highlightLast);
15764 return Optional.some(true);
15767 const sandbox = Coupling.getCoupled(comp, 'sandbox');
15768 const sandboxIsOpen = Sandboxing.isOpen(sandbox);
15769 if (sandboxIsOpen && !detail.previewing.get()) {
15770 return getActiveMenu(sandbox).bind(activeMenu => Highlighting.getHighlighted(activeMenu)).map(item => {
15771 emitWith(comp, itemExecute(), { item });
15775 const currentValue = Representing.getValue(comp);
15776 emit(comp, typeaheadCancel());
15777 detail.onExecute(sandbox, comp, currentValue);
15778 if (sandboxIsOpen) {
15779 Sandboxing.close(sandbox);
15781 return Optional.some(true);
15786 toggleClass: detail.markers.openClass,
15787 aria: { mode: 'expanded' }
15791 sandbox: hotspot => {
15792 return makeSandbox$1(detail, hotspot, {
15793 onOpen: () => Toggling.on(hotspot),
15794 onClose: () => Toggling.off(hotspot)
15799 config(typeaheadCustomEvents, [
15800 runOnAttached(typeaheadComp => {
15801 detail.lazyTypeaheadComp.set(Optional.some(typeaheadComp));
15803 runOnDetached(_typeaheadComp => {
15804 detail.lazyTypeaheadComp.set(Optional.none());
15806 runOnExecute$1(comp => {
15807 const onOpenSync = noop;
15808 togglePopup(detail, mapFetch(comp), comp, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
15810 run$1(itemExecute(), (comp, se) => {
15811 const sandbox = Coupling.getCoupled(comp, 'sandbox');
15812 setValueFromItem(detail.model, comp, se.event.item);
15813 emit(comp, typeaheadCancel());
15814 detail.onItemExecute(comp, sandbox, se.event.item, Representing.getValue(comp));
15815 Sandboxing.close(sandbox);
15816 setCursorAtEnd(comp);
15818 ].concat(detail.dismissOnBlur ? [run$1(postBlur(), typeahead => {
15819 const sandbox = Coupling.getCoupled(typeahead, 'sandbox');
15820 if (search(sandbox.element).isNone()) {
15821 Sandboxing.close(sandbox);
15825 const eventOrder = {
15826 [detachedFromDom()]: [
15827 Representing.name(),
15829 typeaheadCustomEvents
15831 ...detail.eventOrder
15835 dom: dom(deepMerge(detail, {
15837 'role': 'combobox',
15838 'aria-autocomplete': 'list',
15839 'aria-haspopup': 'true'
15843 ...focusBehaviours$1,
15844 ...augment(detail.typeaheadBehaviours, behaviours)
15850 const schema$g = constant$1([
15851 option$3('lazySink'),
15852 required$1('fetch'),
15853 defaulted('minChars', 5),
15854 defaulted('responseTime', 1000),
15855 onHandler('onOpen'),
15856 defaulted('getHotspot', Optional.some),
15857 defaulted('getAnchorOverrides', constant$1({})),
15858 defaulted('layouts', Optional.none()),
15859 defaulted('eventOrder', {}),
15860 defaultedObjOf('model', {}, [
15861 defaulted('getDisplayText', itemData => itemData.meta !== undefined && itemData.meta.text !== undefined ? itemData.meta.text : itemData.value),
15862 defaulted('selectsOver', true),
15863 defaulted('populateFromBrowse', true)
15865 onHandler('onSetValue'),
15866 onKeyboardHandler('onExecute'),
15867 onHandler('onItemExecute'),
15868 defaulted('inputClasses', []),
15869 defaulted('inputAttributes', {}),
15870 defaulted('inputStyles', {}),
15871 defaulted('matchWidth', true),
15872 defaulted('useMinWidth', false),
15873 defaulted('dismissOnBlur', true),
15874 markers$1(['openClass']),
15875 option$3('initialData'),
15876 field('typeaheadBehaviours', [
15884 customField('lazyTypeaheadComp', () => Cell(Optional.none)),
15885 customField('previewing', () => Cell(true))
15886 ].concat(schema$l()).concat(sandboxFields()));
15887 const parts$b = constant$1([external({
15888 schema: [tieredMenuMarkers()],
15890 overrides: detail => {
15893 onHighlightItem: (_tmenu, menu, item) => {
15894 if (!detail.previewing.get()) {
15895 detail.lazyTypeaheadComp.get().each(input => {
15896 if (detail.model.populateFromBrowse) {
15897 setValueFromItem(detail.model, input, item);
15901 detail.lazyTypeaheadComp.get().each(input => {
15902 attemptSelectOver(detail.model, input, item).fold(() => {
15903 if (detail.model.selectsOver) {
15904 Highlighting.dehighlight(menu, item);
15905 detail.previewing.set(true);
15907 detail.previewing.set(false);
15909 }, selectOverTextInInput => {
15910 selectOverTextInInput();
15911 detail.previewing.set(false);
15916 onExecute: (_menu, item) => {
15917 return detail.lazyTypeaheadComp.get().map(typeahead => {
15918 emitWith(typeahead, itemExecute(), { item });
15922 onHover: (menu, item) => {
15923 detail.previewing.set(false);
15924 detail.lazyTypeaheadComp.get().each(input => {
15925 if (detail.model.populateFromBrowse) {
15926 setValueFromItem(detail.model, input, item);
15934 const Typeahead = composite({
15936 configFields: schema$g(),
15937 partFields: parts$b(),
15941 const wrap = delegate => {
15942 const toCached = () => {
15943 return wrap(delegate.toCached());
15945 const bindFuture = f => {
15946 return wrap(delegate.bind(resA => resA.fold(err => Future.pure(Result.error(err)), a => f(a))));
15948 const bindResult = f => {
15949 return wrap(delegate.map(resA => resA.bind(f)));
15951 const mapResult = f => {
15952 return wrap(delegate.map(resA => resA.map(f)));
15954 const mapError = f => {
15955 return wrap(delegate.map(resA => resA.mapError(f)));
15957 const foldResult = (whenError, whenValue) => {
15958 return delegate.map(res => res.fold(whenError, whenValue));
15960 const withTimeout = (timeout, errorThunk) => {
15961 return wrap(Future.nu(callback => {
15962 let timedOut = false;
15963 const timer = setTimeout(() => {
15965 callback(Result.error(errorThunk()));
15967 delegate.get(result => {
15969 clearTimeout(timer);
15986 const nu$1 = worker => {
15987 return wrap(Future.nu(worker));
15989 const value = value => {
15990 return wrap(Future.pure(Result.value(value)));
15992 const error = error => {
15993 return wrap(Future.pure(Result.error(error)));
15995 const fromResult = result => {
15996 return wrap(Future.pure(result));
15998 const fromFuture = future => {
15999 return wrap(future.map(Result.value));
16001 const fromPromise = promise => {
16002 return nu$1(completer => {
16003 promise.then(value => {
16004 completer(Result.value(value));
16006 completer(Result.error(error));
16010 const FutureResult = {
16021 const getMenuButtonApi = component => ({
16022 isEnabled: () => !Disabling.isDisabled(component),
16023 setEnabled: state => Disabling.set(component, !state),
16024 setActive: state => {
16025 const elm = component.element;
16027 add$2(elm, 'tox-tbtn--enabled');
16028 set$9(elm, 'aria-pressed', true);
16030 remove$2(elm, 'tox-tbtn--enabled');
16031 remove$7(elm, 'aria-pressed');
16034 isActive: () => has(component.element, 'tox-tbtn--enabled')
16036 const renderMenuButton = (spec, prefix, backstage, role) => {
16037 return renderCommonDropdown({
16040 tooltip: spec.tooltip,
16041 searchable: spec.search.isSome(),
16043 fetch: (dropdownComp, callback) => {
16044 const fetchContext = { pattern: spec.search.isSome() ? getSearchPattern(dropdownComp) : '' };
16045 spec.fetch(items => {
16046 callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
16047 isHorizontalMenu: false,
16048 search: spec.search
16052 onSetup: spec.onSetup,
16053 getApi: getMenuButtonApi,
16057 dropdownBehaviours: [Tabstopping.config({})]
16058 }, prefix, backstage.shared);
16060 const getFetch = (items, getButton, backstage) => {
16061 const getMenuItemAction = item => api => {
16062 const newValue = !api.isActive();
16063 api.setActive(newValue);
16064 item.storage.set(newValue);
16065 backstage.shared.getSink().each(sink => {
16066 getButton().getOpt(sink).each(orig => {
16067 focus$3(orig.element);
16068 emitWith(orig, formActionEvent, {
16070 value: item.storage.get()
16075 const getMenuItemSetup = item => api => {
16076 api.setActive(item.storage.get());
16078 return success => {
16079 success(map$2(items, item => {
16080 const text = item.text.fold(() => ({}), text => ({ text }));
16085 onAction: getMenuItemAction(item),
16086 onSetup: getMenuItemSetup(item)
16092 const renderCommonSpec = (spec, actionOpt, extraBehaviours = [], dom, components, providersBackstage) => {
16093 const action = actionOpt.fold(() => ({}), action => ({ action }));
16095 buttonBehaviours: derive$1([
16096 DisablingConfigs.button(() => !spec.enabled || providersBackstage.isDisabled()),
16098 Tabstopping.config({}),
16099 config('button press', [
16100 preventDefault('click'),
16101 preventDefault('mousedown')
16103 ].concat(extraBehaviours)),
16107 'alloy.base.behaviour'
16111 'alloy.base.behaviour'
16116 const domFinal = deepMerge(common, { dom });
16117 return deepMerge(domFinal, { components });
16119 const renderIconButtonSpec = (spec, action, providersBackstage, extraBehaviours = []) => {
16120 const tooltipAttributes = spec.tooltip.map(tooltip => ({
16121 'aria-label': providersBackstage.translate(tooltip),
16122 'title': providersBackstage.translate(tooltip)
16126 classes: ['tox-tbtn'],
16127 attributes: tooltipAttributes
16129 const icon = spec.icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons));
16130 const components = componentRenderPipeline([icon]);
16131 return renderCommonSpec(spec, action, extraBehaviours, dom, components, providersBackstage);
16133 const calculateClassesFromButtonType = buttonType => {
16134 switch (buttonType) {
16136 return ['tox-button'];
16138 return ['tox-tbtn'];
16143 'tox-button--secondary'
16147 const renderButtonSpec = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
16148 const translatedText = providersBackstage.translate(spec.text);
16149 const icon = spec.icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons));
16150 const components = [icon.getOrThunk(() => text$2(translatedText))];
16151 const buttonType = spec.buttonType.getOr(!spec.primary && !spec.borderless ? 'secondary' : 'primary');
16152 const baseClasses = calculateClassesFromButtonType(buttonType);
16155 ...icon.isSome() ? ['tox-button--icon'] : [],
16156 ...spec.borderless ? ['tox-button--naked'] : [],
16162 attributes: { title: translatedText }
16164 return renderCommonSpec(spec, action, extraBehaviours, dom, components, providersBackstage);
16166 const renderButton = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
16167 const buttonSpec = renderButtonSpec(spec, Optional.some(action), providersBackstage, extraBehaviours, extraClasses);
16168 return Button.sketch(buttonSpec);
16170 const getAction = (name, buttonType) => comp => {
16171 if (buttonType === 'custom') {
16172 emitWith(comp, formActionEvent, {
16176 } else if (buttonType === 'submit') {
16177 emit(comp, formSubmitEvent);
16178 } else if (buttonType === 'cancel') {
16179 emit(comp, formCancelEvent);
16181 console.error('Unknown button type: ', buttonType);
16184 const isMenuFooterButtonSpec = (spec, buttonType) => buttonType === 'menu';
16185 const isNormalFooterButtonSpec = (spec, buttonType) => buttonType === 'custom' || buttonType === 'cancel' || buttonType === 'submit';
16186 const renderFooterButton = (spec, buttonType, backstage) => {
16187 if (isMenuFooterButtonSpec(spec, buttonType)) {
16188 const getButton = () => memButton;
16189 const menuButtonSpec = spec;
16190 const fixedSpec = {
16192 type: 'menubutton',
16193 search: Optional.none(),
16195 api.setEnabled(spec.enabled);
16198 fetch: getFetch(menuButtonSpec.items, getButton, backstage)
16200 const memButton = record(renderMenuButton(fixedSpec, 'tox-tbtn', backstage, Optional.none()));
16201 return memButton.asSpec();
16202 } else if (isNormalFooterButtonSpec(spec, buttonType)) {
16203 const action = getAction(spec.name, buttonType);
16204 const buttonSpec = {
16208 return renderButton(buttonSpec, action, backstage.shared.providers, []);
16210 console.error('Unknown footer button type: ', buttonType);
16211 throw new Error('Unknown footer button type');
16214 const renderDialogButton = (spec, providersBackstage) => {
16215 const action = getAction(spec.name, 'custom');
16216 return renderFormField(Optional.none(), FormField.parts.field({
16218 ...renderButtonSpec(spec, Optional.some(action), providersBackstage, [
16219 RepresentingConfigs.memory(''),
16220 ComposingConfigs.self()
16225 const separator$1 = { type: 'separator' };
16226 const toMenuItem = target => ({
16229 text: target.title,
16230 meta: { attach: target.attach },
16233 const staticMenuItem = (title, url) => ({
16237 meta: { attach: undefined },
16240 const toMenuItems = targets => map$2(targets, toMenuItem);
16241 const filterLinkTargets = (type, targets) => filter$2(targets, target => target.type === type);
16242 const filteredTargets = (type, targets) => toMenuItems(filterLinkTargets(type, targets));
16243 const headerTargets = linkInfo => filteredTargets('header', linkInfo.targets);
16244 const anchorTargets = linkInfo => filteredTargets('anchor', linkInfo.targets);
16245 const anchorTargetTop = linkInfo => Optional.from(linkInfo.anchorTop).map(url => staticMenuItem('<top>', url)).toArray();
16246 const anchorTargetBottom = linkInfo => Optional.from(linkInfo.anchorBottom).map(url => staticMenuItem('<bottom>', url)).toArray();
16247 const historyTargets = history => map$2(history, url => staticMenuItem(url, url));
16248 const joinMenuLists = items => {
16249 return foldl(items, (a, b) => {
16250 const bothEmpty = a.length === 0 || b.length === 0;
16251 return bothEmpty ? a.concat(b) : a.concat(separator$1, b);
16254 const filterByQuery = (term, menuItems) => {
16255 const lowerCaseTerm = term.toLowerCase();
16256 return filter$2(menuItems, item => {
16257 const text = item.meta !== undefined && item.meta.text !== undefined ? item.meta.text : item.text;
16258 const value = item.value ?? '';
16259 return contains$1(text.toLowerCase(), lowerCaseTerm) || contains$1(value.toLowerCase(), lowerCaseTerm);
16263 const getItems = (fileType, input, urlBackstage) => {
16264 const urlInputValue = Representing.getValue(input);
16265 const term = urlInputValue.meta.text !== undefined ? urlInputValue.meta.text : urlInputValue.value;
16266 const info = urlBackstage.getLinkInformation();
16267 return info.fold(() => [], linkInfo => {
16268 const history = filterByQuery(term, historyTargets(urlBackstage.getHistory(fileType)));
16269 return fileType === 'file' ? joinMenuLists([
16271 filterByQuery(term, headerTargets(linkInfo)),
16272 filterByQuery(term, flatten([
16273 anchorTargetTop(linkInfo),
16274 anchorTargets(linkInfo),
16275 anchorTargetBottom(linkInfo)
16280 const errorId = generate$6('aria-invalid');
16281 const renderUrlInput = (spec, backstage, urlBackstage, initialData) => {
16282 const providersBackstage = backstage.shared.providers;
16283 const updateHistory = component => {
16284 const urlEntry = Representing.getValue(component);
16285 urlBackstage.addToHistory(urlEntry.value, spec.filetype);
16287 const typeaheadSpec = {
16288 ...initialData.map(initialData => ({ initialData })).getOr({}),
16289 dismissOnBlur: true,
16290 inputClasses: ['tox-textfield'],
16291 sandboxClasses: ['tox-dialog__popups'],
16293 'aria-errormessage': errorId,
16299 const items = getItems(spec.filetype, input, urlBackstage);
16300 const tdata = build(items, ItemResponse$1.BUBBLE_TO_SANDBOX, backstage, {
16301 isHorizontalMenu: false,
16302 search: Optional.none()
16304 return Future.pure(tdata);
16306 getHotspot: comp => memUrlBox.getOpt(comp),
16307 onSetValue: (comp, _newValue) => {
16308 if (comp.hasConfigured(Invalidating)) {
16309 Invalidating.run(comp).get(noop);
16312 typeaheadBehaviours: derive$1([
16313 ...urlBackstage.getValidationHandler().map(handler => Invalidating.config({
16314 getRoot: comp => parentElement(comp.element),
16315 invalidClass: 'tox-control-wrap--status-invalid',
16317 onInvalid: (comp, err) => {
16318 memInvalidIcon.getOpt(comp).each(invalidComp => {
16319 set$9(invalidComp.element, 'title', providersBackstage.translate(err));
16324 validate: input => {
16325 const urlEntry = Representing.getValue(input);
16326 return FutureResult.nu(completer => {
16328 type: spec.filetype,
16329 url: urlEntry.value
16331 if (validation.status === 'invalid') {
16332 const err = Result.error(validation.message);
16335 const val = Result.value(validation.message);
16341 validateOnLoad: false
16344 Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
16345 Tabstopping.config({}),
16346 config('urlinput-events', [
16347 run$1(input(), comp => {
16348 const currentValue = get$6(comp.element);
16349 const trimmedValue = currentValue.trim();
16350 if (trimmedValue !== currentValue) {
16351 set$5(comp.element, trimmedValue);
16353 if (spec.filetype === 'file') {
16354 emitWith(comp, formChangeEvent, { name: spec.name });
16357 run$1(change(), comp => {
16358 emitWith(comp, formChangeEvent, { name: spec.name });
16359 updateHistory(comp);
16361 run$1(postPaste(), comp => {
16362 emitWith(comp, formChangeEvent, { name: spec.name });
16363 updateHistory(comp);
16375 getDisplayText: itemData => itemData.value,
16376 selectsOver: false,
16377 populateFromBrowse: false
16379 markers: { openClass: 'tox-textfield--popup-open' },
16380 lazySink: backstage.shared.getSink,
16381 parts: { menu: part(false, 1, 'normal') },
16382 onExecute: (_menu, component, _entry) => {
16383 emitWith(component, formSubmitEvent, {});
16385 onItemExecute: (typeahead, _sandbox, _item, _value) => {
16386 updateHistory(typeahead);
16387 emitWith(typeahead, formChangeEvent, { name: spec.name });
16390 const pField = FormField.parts.field({
16394 const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
16395 const makeIcon = (name, errId, icon = name, label = name) => render$3(icon, {
16399 'tox-control-wrap__status-icon-' + name
16402 'title': providersBackstage.translate(label),
16403 'aria-live': 'polite',
16404 ...errId.fold(() => ({}), id => ({ id }))
16406 }, providersBackstage.icons);
16407 const memInvalidIcon = record(makeIcon('invalid', Optional.some(errorId), 'warning'));
16408 const memStatus = record({
16411 classes: ['tox-control-wrap__status-icon-wrap']
16413 components: [memInvalidIcon.asSpec()]
16415 const optUrlPicker = urlBackstage.getUrlPicker(spec.filetype);
16416 const browseUrlEvent = generate$6('browser.url.event');
16417 const memUrlBox = record({
16420 classes: ['tox-control-wrap']
16426 behaviours: derive$1([Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() })])
16428 const memUrlPickerButton = record(renderButton({
16430 icon: Optional.some('browse'),
16431 text: spec.label.getOr(''),
16432 enabled: spec.enabled,
16434 buttonType: Optional.none(),
16436 }, component => emit(component, browseUrlEvent), providersBackstage, [], ['tox-browse-url']));
16437 const controlHWrapper = () => ({
16440 classes: ['tox-form__controls-h-stack']
16442 components: flatten([
16443 [memUrlBox.asSpec()],
16444 optUrlPicker.map(() => memUrlPickerButton.asSpec()).toArray()
16447 const openUrlPicker = comp => {
16448 Composing.getCurrent(comp).each(field => {
16449 const componentData = Representing.getValue(field);
16451 fieldname: spec.name,
16454 optUrlPicker.each(picker => {
16455 picker(urlData).get(chosenData => {
16456 Representing.setValue(field, chosenData);
16457 emitWith(comp, formChangeEvent, { name: spec.name });
16462 return FormField.sketch({
16463 dom: renderFormFieldDom(),
16464 components: pLabel.toArray().concat([controlHWrapper()]),
16465 fieldBehaviours: derive$1([
16467 disabled: () => !spec.enabled || providersBackstage.isDisabled(),
16468 onDisabled: comp => {
16469 FormField.getField(comp).each(Disabling.disable);
16470 memUrlPickerButton.getOpt(comp).each(Disabling.disable);
16472 onEnabled: comp => {
16473 FormField.getField(comp).each(Disabling.enable);
16474 memUrlPickerButton.getOpt(comp).each(Disabling.enable);
16478 config('url-input-events', [run$1(browseUrlEvent, openUrlPicker)])
16483 const renderAlertBanner = (spec, providersBackstage) => Container.sketch({
16486 attributes: { role: 'alert' },
16488 'tox-notification',
16489 'tox-notification--in',
16490 `tox-notification--${ spec.level }`
16497 classes: ['tox-notification__icon']
16499 components: [Button.sketch({
16504 'tox-button--naked',
16507 innerHtml: get$2(spec.icon, providersBackstage.icons),
16508 attributes: { title: providersBackstage.translate(spec.iconTooltip) }
16511 emitWith(comp, formActionEvent, {
16512 name: 'alert-banner',
16516 buttonBehaviours: derive$1([addFocusableBehaviour()])
16522 classes: ['tox-notification__body'],
16523 innerHtml: providersBackstage.translate(spec.text)
16529 const set$1 = (element, status) => {
16530 element.dom.checked = status;
16532 const get$1 = element => element.dom.checked;
16534 const renderCheckbox = (spec, providerBackstage, initialData) => {
16535 const toggleCheckboxHandler = comp => {
16536 comp.element.dom.click();
16537 return Optional.some(true);
16539 const pField = FormField.parts.field({
16540 factory: { sketch: identity },
16543 classes: ['tox-checkbox__input'],
16544 attributes: { type: 'checkbox' }
16546 behaviours: derive$1([
16547 ComposingConfigs.self(),
16548 Disabling.config({ disabled: () => !spec.enabled || providerBackstage.isDisabled() }),
16549 Tabstopping.config({}),
16550 Focusing.config({}),
16551 RepresentingConfigs.withElement(initialData, get$1, set$1),
16554 onEnter: toggleCheckboxHandler,
16555 onSpace: toggleCheckboxHandler,
16556 stopSpaceKeyup: true
16558 config('checkbox-events', [run$1(change(), (component, _) => {
16559 emitWith(component, formChangeEvent, { name: spec.name });
16563 const pLabel = FormField.parts.label({
16566 classes: ['tox-checkbox__label']
16568 components: [text$2(providerBackstage.translate(spec.label))],
16569 behaviours: derive$1([Unselecting.config({})])
16571 const makeIcon = className => {
16572 const iconName = className === 'checked' ? 'selected' : 'unselected';
16573 return render$3(iconName, {
16577 'tox-checkbox-icon__' + className
16579 }, providerBackstage.icons);
16581 const memIcons = record({
16584 classes: ['tox-checkbox__icons']
16587 makeIcon('checked'),
16588 makeIcon('unchecked')
16591 return FormField.sketch({
16594 classes: ['tox-checkbox']
16601 fieldBehaviours: derive$1([
16603 disabled: () => !spec.enabled || providerBackstage.isDisabled(),
16604 disableClass: 'tox-checkbox--disabled',
16605 onDisabled: comp => {
16606 FormField.getField(comp).each(Disabling.disable);
16608 onEnabled: comp => {
16609 FormField.getField(comp).each(Disabling.enable);
16617 const renderHtmlPanel = spec => {
16618 if (spec.presets === 'presentation') {
16619 return Container.sketch({
16622 classes: ['tox-form__group'],
16623 innerHtml: spec.html
16627 return Container.sketch({
16630 classes: ['tox-form__group'],
16631 innerHtml: spec.html,
16632 attributes: { role: 'document' }
16634 containerBehaviours: derive$1([
16635 Tabstopping.config({}),
16636 Focusing.config({})
16642 const make$2 = render => {
16643 return (parts, spec, dialogData, backstage) => get$g(spec, 'name').fold(() => render(spec, backstage, Optional.none()), fieldName => parts.field(fieldName, render(spec, backstage, get$g(dialogData, fieldName))));
16645 const makeIframe = render => (parts, spec, dialogData, backstage) => {
16646 const iframeSpec = deepMerge(spec, { source: 'dynamic' });
16647 return make$2(render)(parts, iframeSpec, dialogData, backstage);
16649 const factories = {
16650 bar: make$2((spec, backstage) => renderBar(spec, backstage.shared)),
16651 collection: make$2((spec, backstage, data) => renderCollection(spec, backstage.shared.providers, data)),
16652 alertbanner: make$2((spec, backstage) => renderAlertBanner(spec, backstage.shared.providers)),
16653 input: make$2((spec, backstage, data) => renderInput(spec, backstage.shared.providers, data)),
16654 textarea: make$2((spec, backstage, data) => renderTextarea(spec, backstage.shared.providers, data)),
16655 label: make$2((spec, backstage) => renderLabel$1(spec, backstage.shared)),
16656 iframe: makeIframe((spec, backstage, data) => renderIFrame(spec, backstage.shared.providers, data)),
16657 button: make$2((spec, backstage) => renderDialogButton(spec, backstage.shared.providers)),
16658 checkbox: make$2((spec, backstage, data) => renderCheckbox(spec, backstage.shared.providers, data)),
16659 colorinput: make$2((spec, backstage, data) => renderColorInput(spec, backstage.shared, backstage.colorinput, data)),
16660 colorpicker: make$2((spec, backstage, data) => renderColorPicker(spec, backstage.shared.providers, data)),
16661 dropzone: make$2((spec, backstage, data) => renderDropZone(spec, backstage.shared.providers, data)),
16662 grid: make$2((spec, backstage) => renderGrid(spec, backstage.shared)),
16663 listbox: make$2((spec, backstage, data) => renderListBox(spec, backstage, data)),
16664 selectbox: make$2((spec, backstage, data) => renderSelectBox(spec, backstage.shared.providers, data)),
16665 sizeinput: make$2((spec, backstage) => renderSizeInput(spec, backstage.shared.providers)),
16666 slider: make$2((spec, backstage, data) => renderSlider(spec, backstage.shared.providers, data)),
16667 urlinput: make$2((spec, backstage, data) => renderUrlInput(spec, backstage, backstage.urlinput, data)),
16668 customeditor: make$2(renderCustomEditor),
16669 htmlpanel: make$2(renderHtmlPanel),
16670 imagepreview: make$2((spec, _, data) => renderImagePreview(spec, data)),
16671 table: make$2((spec, backstage) => renderTable(spec, backstage.shared.providers)),
16672 panel: make$2((spec, backstage) => renderPanel(spec, backstage))
16674 const noFormParts = {
16675 field: (_name, spec) => spec,
16676 record: constant$1([])
16678 const interpretInForm = (parts, spec, dialogData, oldBackstage) => {
16679 const newBackstage = deepMerge(oldBackstage, { shared: { interpreter: childSpec => interpretParts(parts, childSpec, dialogData, newBackstage) } });
16680 return interpretParts(parts, spec, dialogData, newBackstage);
16682 const interpretParts = (parts, spec, dialogData, backstage) => get$g(factories, spec.type).fold(() => {
16683 console.error(`Unknown factory type "${ spec.type }", defaulting to container: `, spec);
16685 }, factory => factory(parts, spec, dialogData, backstage));
16686 const interpretWithoutForm = (spec, dialogData, backstage) => interpretParts(noFormParts, spec, dialogData, backstage);
16688 const labelPrefix = 'layout-inset';
16689 const westEdgeX = anchor => anchor.x;
16690 const middleX = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
16691 const eastEdgeX = (anchor, element) => anchor.x + anchor.width - element.width;
16692 const northY = anchor => anchor.y;
16693 const southY = (anchor, element) => anchor.y + anchor.height - element.height;
16694 const centreY = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
16695 const southwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), southY(anchor, element), bubbles.insetSouthwest(), northwest$3(), 'southwest', boundsRestriction(anchor, {
16699 const southeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), southY(anchor, element), bubbles.insetSoutheast(), northeast$3(), 'southeast', boundsRestriction(anchor, {
16703 const northwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), northY(anchor), bubbles.insetNorthwest(), southwest$3(), 'northwest', boundsRestriction(anchor, {
16707 const northeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), northY(anchor), bubbles.insetNortheast(), southeast$3(), 'northeast', boundsRestriction(anchor, {
16711 const north = (anchor, element, bubbles) => nu$6(middleX(anchor, element), northY(anchor), bubbles.insetNorth(), south$3(), 'north', boundsRestriction(anchor, { top: 2 }), labelPrefix);
16712 const south = (anchor, element, bubbles) => nu$6(middleX(anchor, element), southY(anchor, element), bubbles.insetSouth(), north$3(), 'south', boundsRestriction(anchor, { bottom: 3 }), labelPrefix);
16713 const east = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), centreY(anchor, element), bubbles.insetEast(), west$3(), 'east', boundsRestriction(anchor, { right: 0 }), labelPrefix);
16714 const west = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), centreY(anchor, element), bubbles.insetWest(), east$3(), 'west', boundsRestriction(anchor, { left: 1 }), labelPrefix);
16715 const lookupPreserveLayout = lastPlacement => {
16716 switch (lastPlacement) {
16735 const preserve = (anchor, element, bubbles, placee, bounds) => {
16736 const layout = getPlacement(placee).map(lookupPreserveLayout).getOr(north);
16737 return layout(anchor, element, bubbles, placee, bounds);
16739 const lookupFlippedLayout = lastPlacement => {
16740 switch (lastPlacement) {
16759 const flip = (anchor, element, bubbles, placee, bounds) => {
16760 const layout = getPlacement(placee).map(lookupFlippedLayout).getOr(north);
16761 return layout(anchor, element, bubbles, placee, bounds);
16764 const bubbleAlignments$2 = {
16774 const getInlineDialogAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
16775 const bubbleSize = 12;
16776 const overrides = { maxHeightFunction: expandable$1() };
16777 const editableAreaAnchor = () => ({
16779 root: getContentContainer(getRootNode(contentAreaElement())),
16780 node: Optional.from(contentAreaElement()),
16781 bubble: nu$5(bubbleSize, bubbleSize, bubbleAlignments$2),
16783 onRtl: () => [northeast],
16784 onLtr: () => [northwest]
16788 const standardAnchor = () => ({
16790 hotspot: lazyAnchorbar(),
16791 bubble: nu$5(-bubbleSize, bubbleSize, bubbleAlignments$2),
16793 onRtl: () => [southeast$2],
16794 onLtr: () => [southwest$2]
16798 return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
16800 const getBannerAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
16801 const editableAreaAnchor = () => ({
16803 root: getContentContainer(getRootNode(contentAreaElement())),
16804 node: Optional.from(contentAreaElement()),
16806 onRtl: () => [north],
16807 onLtr: () => [north]
16810 const standardAnchor = () => ({
16812 hotspot: lazyAnchorbar(),
16814 onRtl: () => [south$2],
16815 onLtr: () => [south$2]
16818 return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
16820 const getCursorAnchor = (editor, bodyElement) => () => ({
16822 root: bodyElement(),
16823 getSelection: () => {
16824 const rng = editor.selection.getRng();
16825 return Optional.some(SimSelection.range(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
16828 const getNodeAnchor$1 = bodyElement => element => ({
16830 root: bodyElement(),
16833 const getAnchors = (editor, lazyAnchorbar, isToolbarTop) => {
16834 const useFixedToolbarContainer = useFixedContainer(editor);
16835 const bodyElement = () => SugarElement.fromDom(editor.getBody());
16836 const contentAreaElement = () => SugarElement.fromDom(editor.getContentAreaContainer());
16837 const lazyUseEditableAreaAnchor = () => useFixedToolbarContainer || !isToolbarTop();
16839 inlineDialog: getInlineDialogAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
16840 banner: getBannerAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
16841 cursor: getCursorAnchor(editor, bodyElement),
16842 node: getNodeAnchor$1(bodyElement)
16846 const colorPicker = editor => (callback, value) => {
16847 const dialog = colorPickerDialog(editor);
16848 dialog(callback, value);
16850 const hasCustomColors = editor => () => hasCustomColors$1(editor);
16851 const getColors = editor => () => getColors$2(editor);
16852 const getColorCols = editor => () => getColorCols$1(editor);
16853 const ColorInputBackstage = editor => ({
16854 colorPicker: colorPicker(editor),
16855 hasCustomColors: hasCustomColors(editor),
16856 getColors: getColors(editor),
16857 getColorCols: getColorCols(editor)
16860 const isDraggableModal = editor => () => isDraggableModal$1(editor);
16861 const DialogBackstage = editor => ({ isDraggableModal: isDraggableModal(editor) });
16863 const HeaderBackstage = editor => {
16864 const mode = Cell(isToolbarLocationBottom(editor) ? 'bottom' : 'top');
16866 isPositionedAtTop: () => mode.get() === 'top',
16867 getDockingMode: mode.get,
16868 setDockingMode: mode.set
16872 const isNestedFormat = format => hasNonNullableKey(format, 'items');
16873 const isFormatReference = format => hasNonNullableKey(format, 'format');
16874 const defaultStyleFormats = [
16879 title: 'Heading 1',
16883 title: 'Heading 2',
16887 title: 'Heading 3',
16891 title: 'Heading 4',
16895 title: 'Heading 5',
16899 title: 'Heading 6',
16916 title: 'Underline',
16917 format: 'underline'
16920 title: 'Strikethrough',
16921 format: 'strikethrough'
16924 title: 'Superscript',
16925 format: 'superscript'
16928 title: 'Subscript',
16929 format: 'subscript'
16941 title: 'Paragraph',
16945 title: 'Blockquote',
16946 format: 'blockquote'
16963 format: 'alignleft'
16967 format: 'aligncenter'
16971 format: 'alignright'
16975 format: 'alignjustify'
16980 const isNestedFormats = format => has$2(format, 'items');
16981 const isBlockFormat = format => has$2(format, 'block');
16982 const isInlineFormat = format => has$2(format, 'inline');
16983 const isSelectorFormat = format => has$2(format, 'selector');
16984 const mapFormats = userFormats => foldl(userFormats, (acc, fmt) => {
16985 if (isNestedFormats(fmt)) {
16986 const result = mapFormats(fmt.items);
16988 customFormats: acc.customFormats.concat(result.customFormats),
16989 formats: acc.formats.concat([{
16991 items: result.formats
16994 } else if (isInlineFormat(fmt) || isBlockFormat(fmt) || isSelectorFormat(fmt)) {
16995 const formatName = isString(fmt.name) ? fmt.name : fmt.title.toLowerCase();
16996 const formatNameWithPrefix = `custom-${ formatName }`;
16998 customFormats: acc.customFormats.concat([{
16999 name: formatNameWithPrefix,
17002 formats: acc.formats.concat([{
17004 format: formatNameWithPrefix,
17011 formats: acc.formats.concat(fmt)
17018 const registerCustomFormats = (editor, userFormats) => {
17019 const result = mapFormats(userFormats);
17020 const registerFormats = customFormats => {
17021 each$1(customFormats, fmt => {
17022 if (!editor.formatter.has(fmt.name)) {
17023 editor.formatter.register(fmt.name, fmt.format);
17027 if (editor.formatter) {
17028 registerFormats(result.customFormats);
17030 editor.on('init', () => {
17031 registerFormats(result.customFormats);
17034 return result.formats;
17036 const getStyleFormats = editor => getUserStyleFormats(editor).map(userFormats => {
17037 const registeredUserFormats = registerCustomFormats(editor, userFormats);
17038 return shouldMergeStyleFormats(editor) ? defaultStyleFormats.concat(registeredUserFormats) : registeredUserFormats;
17039 }).getOr(defaultStyleFormats);
17041 const isSeparator$1 = format => {
17042 const keys$1 = keys(format);
17043 return keys$1.length === 1 && contains$2(keys$1, 'title');
17045 const processBasic = (item, isSelectedFor, getPreviewFor) => ({
17048 isSelected: isSelectedFor(item.format),
17049 getStylePreview: getPreviewFor(item.format)
17051 const register$a = (editor, formats, isSelectedFor, getPreviewFor) => {
17052 const enrichSupported = item => processBasic(item, isSelectedFor, getPreviewFor);
17053 const enrichMenu = item => {
17054 const newItems = doEnrich(item.items);
17058 getStyleItems: constant$1(newItems)
17061 const enrichCustom = item => {
17062 const formatName = isString(item.name) ? item.name : generate$6(item.title);
17063 const formatNameWithPrefix = `custom-${ formatName }`;
17067 format: formatNameWithPrefix,
17068 isSelected: isSelectedFor(formatNameWithPrefix),
17069 getStylePreview: getPreviewFor(formatNameWithPrefix)
17071 editor.formatter.register(formatName, newItem);
17074 const doEnrich = items => map$2(items, item => {
17075 if (isNestedFormat(item)) {
17076 return enrichMenu(item);
17077 } else if (isFormatReference(item)) {
17078 return enrichSupported(item);
17079 } else if (isSeparator$1(item)) {
17085 return enrichCustom(item);
17088 return doEnrich(formats);
17091 const init$8 = editor => {
17092 const isSelectedFor = format => () => editor.formatter.match(format);
17093 const getPreviewFor = format => () => {
17094 const fmt = editor.formatter.get(format);
17095 return fmt !== undefined ? Optional.some({
17096 tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
17097 styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
17098 }) : Optional.none();
17100 const settingsFormats = Cell([]);
17101 const eventsFormats = Cell([]);
17102 const replaceSettings = Cell(false);
17103 editor.on('PreInit', _e => {
17104 const formats = getStyleFormats(editor);
17105 const enriched = register$a(editor, formats, isSelectedFor, getPreviewFor);
17106 settingsFormats.set(enriched);
17108 editor.on('addStyleModifications', e => {
17109 const modifications = register$a(editor, e.items, isSelectedFor, getPreviewFor);
17110 eventsFormats.set(modifications);
17111 replaceSettings.set(e.replace);
17113 const getData = () => {
17114 const fromSettings = replaceSettings.get() ? [] : settingsFormats.get();
17115 const fromEvents = eventsFormats.get();
17116 return fromSettings.concat(fromEvents);
17118 return { getData };
17121 const isElement = node => isNonNullable(node) && node.nodeType === 1;
17122 const trim = global$1.trim;
17123 const hasContentEditableState = value => {
17125 if (isElement(node)) {
17126 if (node.contentEditable === value) {
17129 if (node.getAttribute('data-mce-contenteditable') === value) {
17136 const isContentEditableTrue = hasContentEditableState('true');
17137 const isContentEditableFalse = hasContentEditableState('false');
17138 const create$1 = (type, title, url, level, attach) => ({
17145 const isChildOfContentEditableTrue = node => {
17146 let tempNode = node;
17147 while (tempNode = tempNode.parentNode) {
17148 const value = tempNode.contentEditable;
17149 if (value && value !== 'inherit') {
17150 return isContentEditableTrue(tempNode);
17155 const select = (selector, root) => {
17156 return map$2(descendants(SugarElement.fromDom(root), selector), element => {
17157 return element.dom;
17160 const getElementText = elm => {
17161 return elm.innerText || elm.textContent;
17163 const getOrGenerateId = elm => {
17164 return elm.id ? elm.id : generate$6('h');
17166 const isAnchor = elm => {
17167 return elm && elm.nodeName === 'A' && (elm.id || elm.name) !== undefined;
17169 const isValidAnchor = elm => {
17170 return isAnchor(elm) && isEditable(elm);
17172 const isHeader = elm => {
17173 return elm && /^(H[1-6])$/.test(elm.nodeName);
17175 const isEditable = elm => {
17176 return isChildOfContentEditableTrue(elm) && !isContentEditableFalse(elm);
17178 const isValidHeader = elm => {
17179 return isHeader(elm) && isEditable(elm);
17181 const getLevel = elm => {
17182 return isHeader(elm) ? parseInt(elm.nodeName.substr(1), 10) : 0;
17184 const headerTarget = elm => {
17185 const headerId = getOrGenerateId(elm);
17186 const attach = () => {
17189 return create$1('header', getElementText(elm) ?? '', '#' + headerId, getLevel(elm), attach);
17191 const anchorTarget = elm => {
17192 const anchorId = elm.id || elm.name;
17193 const anchorText = getElementText(elm);
17194 return create$1('anchor', anchorText ? anchorText : '#' + anchorId, '#' + anchorId, 0, noop);
17196 const getHeaderTargets = elms => {
17197 return map$2(filter$2(elms, isValidHeader), headerTarget);
17199 const getAnchorTargets = elms => {
17200 return map$2(filter$2(elms, isValidAnchor), anchorTarget);
17202 const getTargetElements = elm => {
17203 const elms = select('h1,h2,h3,h4,h5,h6,a:not([href])', elm);
17206 const hasTitle = target => {
17207 return trim(target.title).length > 0;
17209 const find = elm => {
17210 const elms = getTargetElements(elm);
17211 return filter$2(getHeaderTargets(elms).concat(getAnchorTargets(elms)), hasTitle);
17213 const LinkTargets = { find };
17215 const STORAGE_KEY = 'tinymce-url-history';
17216 const HISTORY_LENGTH = 5;
17217 const isHttpUrl = url => isString(url) && /^https?/.test(url);
17218 const isArrayOfUrl = a => isArray(a) && a.length <= HISTORY_LENGTH && forall(a, isHttpUrl);
17219 const isRecordOfUrlArray = r => isObject(r) && find$4(r, value => !isArrayOfUrl(value)).isNone();
17220 const getAllHistory = () => {
17221 const unparsedHistory = global$4.getItem(STORAGE_KEY);
17222 if (unparsedHistory === null) {
17227 history = JSON.parse(unparsedHistory);
17229 if (e instanceof SyntaxError) {
17230 console.log('Local storage ' + STORAGE_KEY + ' was not valid JSON', e);
17235 if (!isRecordOfUrlArray(history)) {
17236 console.log('Local storage ' + STORAGE_KEY + ' was not valid format', history);
17241 const setAllHistory = history => {
17242 if (!isRecordOfUrlArray(history)) {
17243 throw new Error('Bad format for history:\n' + JSON.stringify(history));
17245 global$4.setItem(STORAGE_KEY, JSON.stringify(history));
17247 const getHistory = fileType => {
17248 const history = getAllHistory();
17249 return get$g(history, fileType).getOr([]);
17251 const addToHistory = (url, fileType) => {
17252 if (!isHttpUrl(url)) {
17255 const history = getAllHistory();
17256 const items = get$g(history, fileType).getOr([]);
17257 const itemsWithoutUrl = filter$2(items, item => item !== url);
17258 history[fileType] = [url].concat(itemsWithoutUrl).slice(0, HISTORY_LENGTH);
17259 setAllHistory(history);
17262 const isTruthy = value => !!value;
17263 const makeMap = value => map$1(global$1.makeMap(value, /[, ]/), isTruthy);
17264 const getPicker = editor => Optional.from(getFilePickerCallback(editor));
17265 const getPickerTypes = editor => {
17266 const optFileTypes = Optional.from(getFilePickerTypes(editor)).filter(isTruthy).map(makeMap);
17267 return getPicker(editor).fold(never, _picker => optFileTypes.fold(always, types => keys(types).length > 0 ? types : false));
17269 const getPickerSetting = (editor, filetype) => {
17270 const pickerTypes = getPickerTypes(editor);
17271 if (isBoolean(pickerTypes)) {
17272 return pickerTypes ? getPicker(editor) : Optional.none();
17274 return pickerTypes[filetype] ? getPicker(editor) : Optional.none();
17277 const getUrlPicker = (editor, filetype) => getPickerSetting(editor, filetype).map(picker => entry => Future.nu(completer => {
17278 const handler = (value, meta) => {
17279 if (!isString(value)) {
17280 throw new Error('Expected value to be string');
17282 if (meta !== undefined && !isObject(meta)) {
17283 throw new Error('Expected meta to be a object');
17293 fieldname: entry.fieldname,
17294 ...Optional.from(entry.meta).getOr({})
17296 picker.call(editor, handler, entry.value, meta);
17298 const getTextSetting = value => Optional.from(value).filter(isString).getOrUndefined();
17299 const getLinkInformation = editor => {
17300 if (!useTypeaheadUrls(editor)) {
17301 return Optional.none();
17303 return Optional.some({
17304 targets: LinkTargets.find(editor.getBody()),
17305 anchorTop: getTextSetting(getAnchorTop(editor)),
17306 anchorBottom: getTextSetting(getAnchorBottom(editor))
17309 const getValidationHandler = editor => Optional.from(getFilePickerValidatorHandler(editor));
17310 const UrlInputBackstage = editor => ({
17313 getLinkInformation: () => getLinkInformation(editor),
17314 getValidationHandler: () => getValidationHandler(editor),
17315 getUrlPicker: filetype => getUrlPicker(editor, filetype)
17318 const init$7 = (lazySink, editor, lazyAnchorbar) => {
17319 const contextMenuState = Cell(false);
17320 const toolbar = HeaderBackstage(editor);
17321 const backstage = {
17324 icons: () => editor.ui.registry.getAll().icons,
17325 menuItems: () => editor.ui.registry.getAll().menuItems,
17326 translate: global$8.translate,
17327 isDisabled: () => editor.mode.isReadOnly() || !editor.ui.isEnabled(),
17328 getOption: editor.options.get
17330 interpreter: s => interpretWithoutForm(s, {}, backstage),
17331 anchors: getAnchors(editor, lazyAnchorbar, toolbar.isPositionedAtTop),
17335 urlinput: UrlInputBackstage(editor),
17336 styles: init$8(editor),
17337 colorinput: ColorInputBackstage(editor),
17338 dialog: DialogBackstage(editor),
17339 isContextMenuOpen: () => contextMenuState.get(),
17340 setContextMenuState: state => contextMenuState.set(state)
17345 const setup$b = (editor, mothership, uiMothership) => {
17346 const broadcastEvent = (name, evt) => {
17351 ship.broadcastEvent(name, evt);
17354 const broadcastOn = (channel, message) => {
17359 ship.broadcastOn([channel], message);
17362 const fireDismissPopups = evt => broadcastOn(dismissPopups(), { target: evt.target });
17363 const doc = getDocument();
17364 const onTouchstart = bind(doc, 'touchstart', fireDismissPopups);
17365 const onTouchmove = bind(doc, 'touchmove', evt => broadcastEvent(documentTouchmove(), evt));
17366 const onTouchend = bind(doc, 'touchend', evt => broadcastEvent(documentTouchend(), evt));
17367 const onMousedown = bind(doc, 'mousedown', fireDismissPopups);
17368 const onMouseup = bind(doc, 'mouseup', evt => {
17369 if (evt.raw.button === 0) {
17370 broadcastOn(mouseReleased(), { target: evt.target });
17373 const onContentClick = raw => broadcastOn(dismissPopups(), { target: SugarElement.fromDom(raw.target) });
17374 const onContentMouseup = raw => {
17375 if (raw.button === 0) {
17376 broadcastOn(mouseReleased(), { target: SugarElement.fromDom(raw.target) });
17379 const onContentMousedown = () => {
17380 each$1(editor.editorManager.get(), loopEditor => {
17381 if (editor !== loopEditor) {
17382 loopEditor.dispatch('DismissPopups', { relatedTarget: editor });
17386 const onWindowScroll = evt => broadcastEvent(windowScroll(), fromRawEvent(evt));
17387 const onWindowResize = evt => {
17388 broadcastOn(repositionPopups(), {});
17389 broadcastEvent(windowResize(), fromRawEvent(evt));
17391 const onEditorResize = () => broadcastOn(repositionPopups(), {});
17392 const onEditorProgress = evt => {
17394 broadcastOn(dismissPopups(), { target: SugarElement.fromDom(editor.getContainer()) });
17397 const onDismissPopups = event => {
17398 broadcastOn(dismissPopups(), { target: SugarElement.fromDom(event.relatedTarget.getContainer()) });
17400 editor.on('PostRender', () => {
17401 editor.on('click', onContentClick);
17402 editor.on('tap', onContentClick);
17403 editor.on('mouseup', onContentMouseup);
17404 editor.on('mousedown', onContentMousedown);
17405 editor.on('ScrollWindow', onWindowScroll);
17406 editor.on('ResizeWindow', onWindowResize);
17407 editor.on('ResizeEditor', onEditorResize);
17408 editor.on('AfterProgressState', onEditorProgress);
17409 editor.on('DismissPopups', onDismissPopups);
17411 editor.on('remove', () => {
17412 editor.off('click', onContentClick);
17413 editor.off('tap', onContentClick);
17414 editor.off('mouseup', onContentMouseup);
17415 editor.off('mousedown', onContentMousedown);
17416 editor.off('ScrollWindow', onWindowScroll);
17417 editor.off('ResizeWindow', onWindowResize);
17418 editor.off('ResizeEditor', onEditorResize);
17419 editor.off('AfterProgressState', onEditorProgress);
17420 editor.off('DismissPopups', onDismissPopups);
17421 onMousedown.unbind();
17422 onTouchstart.unbind();
17423 onTouchmove.unbind();
17424 onTouchend.unbind();
17425 onMouseup.unbind();
17427 editor.on('detach', () => {
17428 detachSystem(mothership);
17429 detachSystem(uiMothership);
17430 mothership.destroy();
17431 uiMothership.destroy();
17435 const parts$a = AlloyParts;
17436 const partType = PartType;
17438 const schema$f = constant$1([
17439 defaulted('shell', false),
17440 required$1('makeItem'),
17441 defaulted('setupItem', noop),
17442 SketchBehaviours.field('listBehaviours', [Replacing])
17444 const customListDetail = () => ({ behaviours: derive$1([Replacing.config({})]) });
17445 const itemsPart = optional({
17447 overrides: customListDetail
17449 const parts$9 = constant$1([itemsPart]);
17450 const name = constant$1('CustomList');
17452 const factory$d = (detail, components, _spec, _external) => {
17453 const setItems = (list, items) => {
17454 getListContainer(list).fold(() => {
17455 console.error('Custom List was defined to not be a shell, but no item container was specified in components');
17456 throw new Error('Custom List was defined to not be a shell, but no item container was specified in components');
17458 const itemComps = Replacing.contents(container);
17459 const numListsRequired = items.length;
17460 const numListsToAdd = numListsRequired - itemComps.length;
17461 const itemsToAdd = numListsToAdd > 0 ? range$2(numListsToAdd, () => detail.makeItem()) : [];
17462 const itemsToRemove = itemComps.slice(numListsRequired);
17463 each$1(itemsToRemove, item => Replacing.remove(container, item));
17464 each$1(itemsToAdd, item => Replacing.append(container, item));
17465 const builtLists = Replacing.contents(container);
17466 each$1(builtLists, (item, i) => {
17467 detail.setupItem(list, item, items[i], i);
17471 const extra = detail.shell ? {
17472 behaviours: [Replacing.config({})],
17478 const getListContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'items');
17482 components: extra.components,
17483 behaviours: augment(detail.listBehaviours, extra.behaviours),
17487 const CustomList = composite({
17489 configFields: schema$f(),
17490 partFields: parts$9(),
17491 factory: factory$d,
17493 setItems: (apis, list, items) => {
17494 apis.setItems(list, items);
17499 const schema$e = constant$1([
17501 defaulted('shell', true),
17502 field('toolbarBehaviours', [Replacing])
17504 const enhanceGroups = () => ({ behaviours: derive$1([Replacing.config({})]) });
17505 const parts$8 = constant$1([optional({
17507 overrides: enhanceGroups
17510 const factory$c = (detail, components, _spec, _externals) => {
17511 const setGroups = (toolbar, groups) => {
17512 getGroupContainer(toolbar).fold(() => {
17513 console.error('Toolbar was defined to not be a shell, but no groups container was specified in components');
17514 throw new Error('Toolbar was defined to not be a shell, but no groups container was specified in components');
17516 Replacing.set(container, groups);
17519 const getGroupContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'groups');
17520 const extra = detail.shell ? {
17521 behaviours: [Replacing.config({})],
17530 components: extra.components,
17531 behaviours: augment(detail.toolbarBehaviours, extra.behaviours),
17532 apis: { setGroups },
17533 domModification: { attributes: { role: 'group' } }
17536 const Toolbar = composite({
17538 configFields: schema$e(),
17539 partFields: parts$8(),
17540 factory: factory$c,
17542 setGroups: (apis, toolbar, groups) => {
17543 apis.setGroups(toolbar, groups);
17548 const setup$a = noop;
17549 const isDocked$2 = never;
17550 const getBehaviours$1 = constant$1([]);
17552 var StaticHeader = /*#__PURE__*/Object.freeze({
17555 isDocked: isDocked$2,
17556 getBehaviours: getBehaviours$1
17559 const getOffsetParent = element => {
17560 const isFixed = is$1(getRaw(element, 'position'), 'fixed');
17561 const offsetParent$1 = isFixed ? Optional.none() : offsetParent(element);
17562 return offsetParent$1.orThunk(() => {
17563 const marker = SugarElement.fromTag('span');
17564 return parent(element).bind(parent => {
17565 append$2(parent, marker);
17566 const offsetParent$1 = offsetParent(marker);
17568 return offsetParent$1;
17572 const getOrigin = element => getOffsetParent(element).map(absolute$3).getOrThunk(() => SugarPosition(0, 0));
17574 const morphAdt = Adt.generate([
17576 { absolute: ['positionCss'] },
17577 { fixed: ['positionCss'] }
17579 const appear = (component, contextualInfo) => {
17580 const elem = component.element;
17581 add$2(elem, contextualInfo.transitionClass);
17582 remove$2(elem, contextualInfo.fadeOutClass);
17583 add$2(elem, contextualInfo.fadeInClass);
17584 contextualInfo.onShow(component);
17586 const disappear = (component, contextualInfo) => {
17587 const elem = component.element;
17588 add$2(elem, contextualInfo.transitionClass);
17589 remove$2(elem, contextualInfo.fadeInClass);
17590 add$2(elem, contextualInfo.fadeOutClass);
17591 contextualInfo.onHide(component);
17593 const isPartiallyVisible = (box, viewport) => box.y < viewport.bottom && box.bottom > viewport.y;
17594 const isTopCompletelyVisible = (box, viewport) => box.y >= viewport.y;
17595 const isBottomCompletelyVisible = (box, viewport) => box.bottom <= viewport.bottom;
17596 const isVisibleForModes = (modes, box, viewport) => forall(modes, mode => {
17599 return isBottomCompletelyVisible(box, viewport);
17601 return isTopCompletelyVisible(box, viewport);
17604 const getPrior = (elem, state) => state.getInitialPos().map(pos => bounds(pos.bounds.x, pos.bounds.y, get$c(elem), get$d(elem)));
17605 const storePrior = (elem, box, state) => {
17606 state.setInitialPos({
17607 style: getAllRaw(elem),
17608 position: get$e(elem, 'position') || 'static',
17612 const revertToOriginal = (elem, box, state) => state.getInitialPos().bind(position => {
17613 state.clearInitialPos();
17614 switch (position.position) {
17616 return Optional.some(morphAdt.static());
17618 const offsetBox = getOffsetParent(elem).map(box$1).getOrThunk(() => box$1(body()));
17619 return Optional.some(morphAdt.absolute(NuPositionCss('absolute', get$g(position.style, 'left').map(_left => box.x - offsetBox.x), get$g(position.style, 'top').map(_top => box.y - offsetBox.y), get$g(position.style, 'right').map(_right => offsetBox.right - box.right), get$g(position.style, 'bottom').map(_bottom => offsetBox.bottom - box.bottom))));
17621 return Optional.none();
17624 const morphToOriginal = (elem, viewport, state) => getPrior(elem, state).filter(box => isVisibleForModes(state.getModes(), box, viewport)).bind(box => revertToOriginal(elem, box, state));
17625 const morphToFixed = (elem, viewport, state) => {
17626 const box = box$1(elem);
17627 if (!isVisibleForModes(state.getModes(), box, viewport)) {
17628 storePrior(elem, box, state);
17629 const winBox = win();
17630 const left = box.x - winBox.x;
17631 const top = viewport.y - winBox.y;
17632 const bottom = winBox.bottom - viewport.bottom;
17633 const isTop = box.y <= viewport.y;
17634 return Optional.some(morphAdt.fixed(NuPositionCss('fixed', Optional.some(left), isTop ? Optional.some(top) : Optional.none(), Optional.none(), !isTop ? Optional.some(bottom) : Optional.none())));
17636 return Optional.none();
17639 const getMorph = (component, viewport, state) => {
17640 const elem = component.element;
17641 const isDocked = is$1(getRaw(elem, 'position'), 'fixed');
17642 return isDocked ? morphToOriginal(elem, viewport, state) : morphToFixed(elem, viewport, state);
17644 const getMorphToOriginal = (component, state) => {
17645 const elem = component.element;
17646 return getPrior(elem, state).bind(box => revertToOriginal(elem, box, state));
17649 const morphToStatic = (component, config, state) => {
17650 state.setDocked(false);
17657 ], prop => remove$6(component.element, prop));
17658 config.onUndocked(component);
17660 const morphToCoord = (component, config, state, position) => {
17661 const isDocked = position.position === 'fixed';
17662 state.setDocked(isDocked);
17663 applyPositionCss(component.element, position);
17664 const method = isDocked ? config.onDocked : config.onUndocked;
17667 const updateVisibility = (component, config, state, viewport, morphToDocked = false) => {
17668 config.contextual.each(contextInfo => {
17669 contextInfo.lazyContext(component).each(box => {
17670 const isVisible = isPartiallyVisible(box, viewport);
17671 if (isVisible !== state.isVisible()) {
17672 state.setVisible(isVisible);
17673 if (morphToDocked && !isVisible) {
17674 add$1(component.element, [contextInfo.fadeOutClass]);
17675 contextInfo.onHide(component);
17677 const method = isVisible ? appear : disappear;
17678 method(component, contextInfo);
17684 const refreshInternal = (component, config, state) => {
17685 const viewport = config.lazyViewport(component);
17686 const isDocked = state.isDocked();
17688 updateVisibility(component, config, state, viewport);
17690 getMorph(component, viewport, state).each(morph => {
17691 morph.fold(() => morphToStatic(component, config, state), position => morphToCoord(component, config, state, position), position => {
17692 updateVisibility(component, config, state, viewport, true);
17693 morphToCoord(component, config, state, position);
17697 const resetInternal = (component, config, state) => {
17698 const elem = component.element;
17699 state.setDocked(false);
17700 getMorphToOriginal(component, state).each(morph => {
17701 morph.fold(() => morphToStatic(component, config, state), position => morphToCoord(component, config, state, position), noop);
17703 state.setVisible(true);
17704 config.contextual.each(contextInfo => {
17706 contextInfo.fadeInClass,
17707 contextInfo.fadeOutClass,
17708 contextInfo.transitionClass
17710 contextInfo.onShow(component);
17712 refresh$4(component, config, state);
17714 const refresh$4 = (component, config, state) => {
17715 if (component.getSystem().isConnected()) {
17716 refreshInternal(component, config, state);
17719 const reset = (component, config, state) => {
17720 if (state.isDocked()) {
17721 resetInternal(component, config, state);
17724 const isDocked$1 = (component, config, state) => state.isDocked();
17725 const setModes = (component, config, state, modes) => state.setModes(modes);
17726 const getModes = (component, config, state) => state.getModes();
17728 var DockingApis = /*#__PURE__*/Object.freeze({
17730 refresh: refresh$4,
17732 isDocked: isDocked$1,
17733 getModes: getModes,
17737 const events$5 = (dockInfo, dockState) => derive$2([
17738 runOnSource(transitionend(), (component, simulatedEvent) => {
17739 dockInfo.contextual.each(contextInfo => {
17740 if (has(component.element, contextInfo.transitionClass)) {
17741 remove$1(component.element, [
17742 contextInfo.transitionClass,
17743 contextInfo.fadeInClass
17745 const notify = dockState.isVisible() ? contextInfo.onShown : contextInfo.onHidden;
17748 simulatedEvent.stop();
17751 run$1(windowScroll(), (component, _) => {
17752 refresh$4(component, dockInfo, dockState);
17754 run$1(windowResize(), (component, _) => {
17755 reset(component, dockInfo, dockState);
17759 var ActiveDocking = /*#__PURE__*/Object.freeze({
17764 var DockingSchema = [
17765 optionObjOf('contextual', [
17766 requiredString('fadeInClass'),
17767 requiredString('fadeOutClass'),
17768 requiredString('transitionClass'),
17769 requiredFunction('lazyContext'),
17770 onHandler('onShow'),
17771 onHandler('onShown'),
17772 onHandler('onHide'),
17773 onHandler('onHidden')
17775 defaultedFunction('lazyViewport', win),
17776 defaultedArrayOf('modes', [
17780 onHandler('onDocked'),
17781 onHandler('onUndocked')
17784 const init$6 = spec => {
17785 const docked = Cell(false);
17786 const visible = Cell(true);
17787 const initialBounds = value$2();
17788 const modes = Cell(spec.modes);
17789 const readState = () => `docked: ${ docked.get() }, visible: ${ visible.get() }, modes: ${ modes.get().join(',') }`;
17791 isDocked: docked.get,
17792 setDocked: docked.set,
17793 getInitialPos: initialBounds.get,
17794 setInitialPos: initialBounds.set,
17795 clearInitialPos: initialBounds.clear,
17796 isVisible: visible.get,
17797 setVisible: visible.set,
17798 getModes: modes.get,
17799 setModes: modes.set,
17804 var DockingState = /*#__PURE__*/Object.freeze({
17809 const Docking = create$4({
17810 fields: DockingSchema,
17812 active: ActiveDocking,
17814 state: DockingState
17817 const toolbarHeightChange = constant$1(generate$6('toolbar-height-change'));
17819 const visibility = {
17820 fadeInClass: 'tox-editor-dock-fadein',
17821 fadeOutClass: 'tox-editor-dock-fadeout',
17822 transitionClass: 'tox-editor-dock-transition'
17824 const editorStickyOnClass = 'tox-tinymce--toolbar-sticky-on';
17825 const editorStickyOffClass = 'tox-tinymce--toolbar-sticky-off';
17826 const scrollFromBehindHeader = (e, containerHeader) => {
17827 const doc = owner$4(containerHeader);
17828 const win = defaultView(containerHeader);
17829 const viewHeight = win.dom.innerHeight;
17830 const scrollPos = get$b(doc);
17831 const markerElement = SugarElement.fromDom(e.elm);
17832 const markerPos = absolute$2(markerElement);
17833 const markerHeight = get$d(markerElement);
17834 const markerTop = markerPos.y;
17835 const markerBottom = markerTop + markerHeight;
17836 const editorHeaderPos = absolute$3(containerHeader);
17837 const editorHeaderHeight = get$d(containerHeader);
17838 const editorHeaderTop = editorHeaderPos.top;
17839 const editorHeaderBottom = editorHeaderTop + editorHeaderHeight;
17840 const editorHeaderDockedAtTop = Math.abs(editorHeaderTop - scrollPos.top) < 2;
17841 const editorHeaderDockedAtBottom = Math.abs(editorHeaderBottom - (scrollPos.top + viewHeight)) < 2;
17842 if (editorHeaderDockedAtTop && markerTop < editorHeaderBottom) {
17843 to(scrollPos.left, markerTop - editorHeaderHeight, doc);
17844 } else if (editorHeaderDockedAtBottom && markerBottom > editorHeaderTop) {
17845 const y = markerTop - viewHeight + markerHeight + editorHeaderHeight;
17846 to(scrollPos.left, y, doc);
17849 const isDockedMode = (header, mode) => contains$2(Docking.getModes(header), mode);
17850 const updateIframeContentFlow = header => {
17851 const getOccupiedHeight = elm => getOuter$2(elm) + (parseInt(get$e(elm, 'margin-top'), 10) || 0) + (parseInt(get$e(elm, 'margin-bottom'), 10) || 0);
17852 const elm = header.element;
17853 parentElement(elm).each(parentElem => {
17854 const padding = 'padding-' + Docking.getModes(header)[0];
17855 if (Docking.isDocked(header)) {
17856 const parentWidth = get$c(parentElem);
17857 set$8(elm, 'width', parentWidth + 'px');
17858 set$8(parentElem, padding, getOccupiedHeight(elm) + 'px');
17860 remove$6(elm, 'width');
17861 remove$6(parentElem, padding);
17865 const updateSinkVisibility = (sinkElem, visible) => {
17867 remove$2(sinkElem, visibility.fadeOutClass);
17869 visibility.transitionClass,
17870 visibility.fadeInClass
17873 remove$2(sinkElem, visibility.fadeInClass);
17875 visibility.fadeOutClass,
17876 visibility.transitionClass
17880 const updateEditorClasses = (editor, docked) => {
17881 const editorContainer = SugarElement.fromDom(editor.getContainer());
17883 add$2(editorContainer, editorStickyOnClass);
17884 remove$2(editorContainer, editorStickyOffClass);
17886 add$2(editorContainer, editorStickyOffClass);
17887 remove$2(editorContainer, editorStickyOnClass);
17890 const restoreFocus = (headerElem, focusedElem) => {
17891 const ownerDoc = owner$4(focusedElem);
17892 active$1(ownerDoc).filter(activeElm => !eq(focusedElem, activeElm)).filter(activeElm => eq(activeElm, SugarElement.fromDom(ownerDoc.dom.body)) || contains(headerElem, activeElm)).each(() => focus$3(focusedElem));
17894 const findFocusedElem = (rootElm, lazySink) => search(rootElm).orThunk(() => lazySink().toOptional().bind(sink => search(sink.element)));
17895 const setup$9 = (editor, sharedBackstage, lazyHeader) => {
17896 if (!editor.inline) {
17897 if (!sharedBackstage.header.isPositionedAtTop()) {
17898 editor.on('ResizeEditor', () => {
17899 lazyHeader().each(Docking.reset);
17902 editor.on('ResizeWindow ResizeEditor', () => {
17903 lazyHeader().each(updateIframeContentFlow);
17905 editor.on('SkinLoaded', () => {
17906 lazyHeader().each(comp => {
17907 Docking.isDocked(comp) ? Docking.reset(comp) : Docking.refresh(comp);
17910 editor.on('FullscreenStateChanged', () => {
17911 lazyHeader().each(Docking.reset);
17914 editor.on('AfterScrollIntoView', e => {
17915 lazyHeader().each(header => {
17916 Docking.refresh(header);
17917 const headerElem = header.element;
17918 if (isVisible(headerElem)) {
17919 scrollFromBehindHeader(e, headerElem);
17923 editor.on('PostRender', () => {
17924 updateEditorClasses(editor, false);
17927 const isDocked = lazyHeader => lazyHeader().map(Docking.isDocked).getOr(false);
17928 const getIframeBehaviours = () => [Receiving.config({ channels: { [toolbarHeightChange()]: { onReceive: updateIframeContentFlow } } })];
17929 const getBehaviours = (editor, sharedBackstage) => {
17930 const focusedElm = value$2();
17931 const lazySink = sharedBackstage.getSink;
17932 const runOnSinkElement = f => {
17933 lazySink().each(sink => f(sink.element));
17935 const onDockingSwitch = comp => {
17936 if (!editor.inline) {
17937 updateIframeContentFlow(comp);
17939 updateEditorClasses(editor, Docking.isDocked(comp));
17940 comp.getSystem().broadcastOn([repositionPopups()], {});
17941 lazySink().each(sink => sink.getSystem().broadcastOn([repositionPopups()], {}));
17943 const additionalBehaviours = editor.inline ? [] : getIframeBehaviours();
17945 Focusing.config({}),
17948 lazyContext: comp => {
17949 const headerHeight = getOuter$2(comp.element);
17950 const container = editor.inline ? editor.getContentAreaContainer() : editor.getContainer();
17951 const box = box$1(SugarElement.fromDom(container));
17952 const boxHeight = box.height - headerHeight;
17953 const topBound = box.y + (isDockedMode(comp, 'top') ? 0 : headerHeight);
17954 return Optional.some(bounds(box.x, topBound, box.width, boxHeight));
17957 runOnSinkElement(elem => updateSinkVisibility(elem, true));
17960 runOnSinkElement(elem => remove$1(elem, [
17961 visibility.transitionClass,
17962 visibility.fadeInClass
17964 focusedElm.get().each(elem => {
17965 restoreFocus(comp.element, elem);
17966 focusedElm.clear();
17970 findFocusedElem(comp.element, lazySink).fold(focusedElm.clear, focusedElm.set);
17971 runOnSinkElement(elem => updateSinkVisibility(elem, false));
17974 runOnSinkElement(elem => remove$1(elem, [visibility.transitionClass]));
17978 lazyViewport: comp => {
17979 const win$1 = win();
17980 const offset = getStickyToolbarOffset(editor);
17981 const top = win$1.y + (isDockedMode(comp, 'top') ? offset : 0);
17982 const height = win$1.height - (isDockedMode(comp, 'bottom') ? offset : 0);
17983 return bounds(win$1.x, top, win$1.width, height);
17985 modes: [sharedBackstage.header.getDockingMode()],
17986 onDocked: onDockingSwitch,
17987 onUndocked: onDockingSwitch
17989 ...additionalBehaviours
17993 var StickyHeader = /*#__PURE__*/Object.freeze({
17996 isDocked: isDocked,
17997 getBehaviours: getBehaviours
18000 const renderHeader = spec => {
18001 const editor = spec.editor;
18002 const getBehaviours$2 = spec.sticky ? getBehaviours : getBehaviours$1;
18006 components: spec.components,
18007 behaviours: derive$1(getBehaviours$2(editor, spec.sharedBackstage))
18011 const groupToolbarButtonSchema = objOf([
18013 requiredOf('items', oneOf([
18016 requiredArrayOf('items', string)
18020 ].concat(baseToolbarButtonFields));
18021 const createGroupToolbarButton = spec => asRaw('GroupToolbarButton', groupToolbarButtonSchema, spec);
18023 const baseMenuButtonFields = [
18024 optionString('text'),
18025 optionString('tooltip'),
18026 optionString('icon'),
18027 defaultedOf('search', false, oneOf([
18029 objOf([optionString('placeholder')])
18031 if (isBoolean(x)) {
18032 return x ? Optional.some({ placeholder: Optional.none() }) : Optional.none();
18034 return Optional.some(x);
18037 requiredFunction('fetch'),
18038 defaultedFunction('onSetup', () => noop)
18041 const MenuButtonSchema = objOf([
18043 ...baseMenuButtonFields
18045 const createMenuButton = spec => asRaw('menubutton', MenuButtonSchema, spec);
18047 const splitButtonSchema = objOf([
18055 defaultedStringEnum('presets', 'normal', [
18060 defaultedColumns(1),
18064 const createSplitButton = spec => asRaw('SplitButton', splitButtonSchema, spec);
18066 const factory$b = (detail, spec) => {
18067 const setMenus = (comp, menus) => {
18068 const newMenus = map$2(menus, m => {
18069 const buttonSpec = {
18070 type: 'menubutton',
18072 fetch: callback => {
18073 callback(m.getItems());
18076 const internal = createMenuButton(buttonSpec).mapError(errInfo => formatError(errInfo)).getOrDie();
18077 return renderMenuButton(internal, 'tox-mbtn', spec.backstage, Optional.some('menuitem'));
18079 Replacing.set(comp, newMenus);
18082 focus: Keying.focusIn,
18089 behaviours: derive$1([
18090 Replacing.config({}),
18091 config('menubar-events', [
18092 runOnAttached(component => {
18093 detail.onSetup(component);
18095 run$1(mouseover(), (comp, se) => {
18096 descendant(comp.element, '.' + 'tox-mbtn--active').each(activeButton => {
18097 closest$1(se.event.target, '.' + 'tox-mbtn').each(hoveredButton => {
18098 if (!eq(activeButton, hoveredButton)) {
18099 comp.getSystem().getByDom(activeButton).each(activeComp => {
18100 comp.getSystem().getByDom(hoveredButton).each(hoveredComp => {
18101 Dropdown.expand(hoveredComp);
18102 Dropdown.close(activeComp);
18103 Focusing.focus(hoveredComp);
18110 run$1(focusShifted(), (comp, se) => {
18111 se.event.prevFocus.bind(prev => comp.getSystem().getByDom(prev).toOptional()).each(prev => {
18112 se.event.newFocus.bind(nu => comp.getSystem().getByDom(nu).toOptional()).each(nu => {
18113 if (Dropdown.isOpen(prev)) {
18114 Dropdown.expand(nu);
18115 Dropdown.close(prev);
18123 selector: '.' + 'tox-mbtn',
18124 onEscape: comp => {
18125 detail.onEscape(comp);
18126 return Optional.some(true);
18129 Tabstopping.config({})
18132 domModification: { attributes: { role: 'menubar' } }
18135 var SilverMenubar = single({
18136 factory: factory$b,
18137 name: 'silver.Menubar',
18141 required$1('onEscape'),
18142 required$1('backstage'),
18143 defaulted('onSetup', noop)
18146 focus: (apis, comp) => {
18149 setMenus: (apis, comp, menus) => {
18150 apis.setMenus(comp, menus);
18155 const promotionMessage = '\u26A1\ufe0fUpgrade';
18156 const promotionLink = 'https://www.tiny.cloud/tinymce-self-hosted-premium-features/?utm_source=TinyMCE&utm_medium=SPAP&utm_campaign=SPAP&utm_id=editorreferral';
18157 const renderPromotion = spec => {
18165 'href': promotionLink,
18167 'target': '_blank',
18168 'aria-hidden': 'true'
18170 classes: ['tox-promotion-link'],
18171 innerHtml: promotionMessage
18177 const getAnimationRoot = (component, slideConfig) => slideConfig.getAnimationRoot.fold(() => component.element, get => get(component));
18179 const getDimensionProperty = slideConfig => slideConfig.dimension.property;
18180 const getDimension = (slideConfig, elem) => slideConfig.dimension.getDimension(elem);
18181 const disableTransitions = (component, slideConfig) => {
18182 const root = getAnimationRoot(component, slideConfig);
18184 slideConfig.shrinkingClass,
18185 slideConfig.growingClass
18188 const setShrunk = (component, slideConfig) => {
18189 remove$2(component.element, slideConfig.openClass);
18190 add$2(component.element, slideConfig.closedClass);
18191 set$8(component.element, getDimensionProperty(slideConfig), '0px');
18192 reflow(component.element);
18194 const setGrown = (component, slideConfig) => {
18195 remove$2(component.element, slideConfig.closedClass);
18196 add$2(component.element, slideConfig.openClass);
18197 remove$6(component.element, getDimensionProperty(slideConfig));
18199 const doImmediateShrink = (component, slideConfig, slideState, _calculatedSize) => {
18200 slideState.setCollapsed();
18201 set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
18202 disableTransitions(component, slideConfig);
18203 setShrunk(component, slideConfig);
18204 slideConfig.onStartShrink(component);
18205 slideConfig.onShrunk(component);
18207 const doStartShrink = (component, slideConfig, slideState, calculatedSize) => {
18208 const size = calculatedSize.getOrThunk(() => getDimension(slideConfig, component.element));
18209 slideState.setCollapsed();
18210 set$8(component.element, getDimensionProperty(slideConfig), size);
18211 reflow(component.element);
18212 const root = getAnimationRoot(component, slideConfig);
18213 remove$2(root, slideConfig.growingClass);
18214 add$2(root, slideConfig.shrinkingClass);
18215 setShrunk(component, slideConfig);
18216 slideConfig.onStartShrink(component);
18218 const doStartSmartShrink = (component, slideConfig, slideState) => {
18219 const size = getDimension(slideConfig, component.element);
18220 const shrinker = size === '0px' ? doImmediateShrink : doStartShrink;
18221 shrinker(component, slideConfig, slideState, Optional.some(size));
18223 const doStartGrow = (component, slideConfig, slideState) => {
18224 const root = getAnimationRoot(component, slideConfig);
18225 const wasShrinking = has(root, slideConfig.shrinkingClass);
18226 const beforeSize = getDimension(slideConfig, component.element);
18227 setGrown(component, slideConfig);
18228 const fullSize = getDimension(slideConfig, component.element);
18229 const startPartialGrow = () => {
18230 set$8(component.element, getDimensionProperty(slideConfig), beforeSize);
18231 reflow(component.element);
18233 const startCompleteGrow = () => {
18234 setShrunk(component, slideConfig);
18236 const setStartSize = wasShrinking ? startPartialGrow : startCompleteGrow;
18238 remove$2(root, slideConfig.shrinkingClass);
18239 add$2(root, slideConfig.growingClass);
18240 setGrown(component, slideConfig);
18241 set$8(component.element, getDimensionProperty(slideConfig), fullSize);
18242 slideState.setExpanded();
18243 slideConfig.onStartGrow(component);
18245 const refresh$3 = (component, slideConfig, slideState) => {
18246 if (slideState.isExpanded()) {
18247 remove$6(component.element, getDimensionProperty(slideConfig));
18248 const fullSize = getDimension(slideConfig, component.element);
18249 set$8(component.element, getDimensionProperty(slideConfig), fullSize);
18252 const grow = (component, slideConfig, slideState) => {
18253 if (!slideState.isExpanded()) {
18254 doStartGrow(component, slideConfig, slideState);
18257 const shrink = (component, slideConfig, slideState) => {
18258 if (slideState.isExpanded()) {
18259 doStartSmartShrink(component, slideConfig, slideState);
18262 const immediateShrink = (component, slideConfig, slideState) => {
18263 if (slideState.isExpanded()) {
18264 doImmediateShrink(component, slideConfig, slideState);
18267 const hasGrown = (component, slideConfig, slideState) => slideState.isExpanded();
18268 const hasShrunk = (component, slideConfig, slideState) => slideState.isCollapsed();
18269 const isGrowing = (component, slideConfig, _slideState) => {
18270 const root = getAnimationRoot(component, slideConfig);
18271 return has(root, slideConfig.growingClass) === true;
18273 const isShrinking = (component, slideConfig, _slideState) => {
18274 const root = getAnimationRoot(component, slideConfig);
18275 return has(root, slideConfig.shrinkingClass) === true;
18277 const isTransitioning = (component, slideConfig, slideState) => isGrowing(component, slideConfig) || isShrinking(component, slideConfig);
18278 const toggleGrow = (component, slideConfig, slideState) => {
18279 const f = slideState.isExpanded() ? doStartSmartShrink : doStartGrow;
18280 f(component, slideConfig, slideState);
18282 const immediateGrow = (component, slideConfig, slideState) => {
18283 if (!slideState.isExpanded()) {
18284 setGrown(component, slideConfig);
18285 set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
18286 disableTransitions(component, slideConfig);
18287 slideState.setExpanded();
18288 slideConfig.onStartGrow(component);
18289 slideConfig.onGrown(component);
18293 var SlidingApis = /*#__PURE__*/Object.freeze({
18295 refresh: refresh$3,
18298 immediateShrink: immediateShrink,
18299 hasGrown: hasGrown,
18300 hasShrunk: hasShrunk,
18301 isGrowing: isGrowing,
18302 isShrinking: isShrinking,
18303 isTransitioning: isTransitioning,
18304 toggleGrow: toggleGrow,
18305 disableTransitions: disableTransitions,
18306 immediateGrow: immediateGrow
18309 const exhibit = (base, slideConfig, _slideState) => {
18310 const expanded = slideConfig.expanded;
18311 return expanded ? nu$7({
18312 classes: [slideConfig.openClass],
18315 classes: [slideConfig.closedClass],
18316 styles: wrap$1(slideConfig.dimension.property, '0px')
18319 const events$4 = (slideConfig, slideState) => derive$2([runOnSource(transitionend(), (component, simulatedEvent) => {
18320 const raw = simulatedEvent.event.raw;
18321 if (raw.propertyName === slideConfig.dimension.property) {
18322 disableTransitions(component, slideConfig);
18323 if (slideState.isExpanded()) {
18324 remove$6(component.element, slideConfig.dimension.property);
18326 const notify = slideState.isExpanded() ? slideConfig.onGrown : slideConfig.onShrunk;
18331 var ActiveSliding = /*#__PURE__*/Object.freeze({
18337 var SlidingSchema = [
18338 required$1('closedClass'),
18339 required$1('openClass'),
18340 required$1('shrinkingClass'),
18341 required$1('growingClass'),
18342 option$3('getAnimationRoot'),
18343 onHandler('onShrunk'),
18344 onHandler('onStartShrink'),
18345 onHandler('onGrown'),
18346 onHandler('onStartGrow'),
18347 defaulted('expanded', false),
18348 requiredOf('dimension', choose$1('property', {
18350 output$1('property', 'width'),
18351 output$1('getDimension', elem => get$c(elem) + 'px')
18354 output$1('property', 'height'),
18355 output$1('getDimension', elem => get$d(elem) + 'px')
18360 const init$5 = spec => {
18361 const state = Cell(spec.expanded);
18362 const readState = () => 'expanded: ' + state.get();
18364 isExpanded: () => state.get() === true,
18365 isCollapsed: () => state.get() === false,
18366 setCollapsed: curry(state.set, false),
18367 setExpanded: curry(state.set, true),
18372 var SlidingState = /*#__PURE__*/Object.freeze({
18377 const Sliding = create$4({
18378 fields: SlidingSchema,
18380 active: ActiveSliding,
18382 state: SlidingState
18385 const owner = 'container';
18386 const schema$d = [field('slotBehaviours', [])];
18387 const getPartName = name => '<alloy.field.' + name + '>';
18388 const sketch = sSpec => {
18389 const parts = (() => {
18391 const slot = (name, config) => {
18393 return generateOne$1(owner, getPartName(name), config);
18397 record: constant$1(record)
18400 const spec = sSpec(parts);
18401 const partNames = parts.record();
18402 const fieldParts = map$2(partNames, n => required({
18404 pname: getPartName(n)
18406 return composite$1(owner, schema$d, fieldParts, make$1, spec);
18408 const make$1 = (detail, components) => {
18409 const getSlotNames = _ => getAllPartNames(detail);
18410 const getSlot = (container, key) => getPart(container, detail, key);
18411 const onSlot = (f, def) => (container, key) => getPart(container, detail, key).map(slot => f(slot, key)).getOr(def);
18412 const onSlots = f => (container, keys) => {
18413 each$1(keys, key => f(container, key));
18415 const doShowing = (comp, _key) => get$f(comp.element, 'aria-hidden') !== 'true';
18416 const doShow = (comp, key) => {
18417 if (!doShowing(comp)) {
18418 const element = comp.element;
18419 remove$6(element, 'display');
18420 remove$7(element, 'aria-hidden');
18421 emitWith(comp, slotVisibility(), {
18427 const doHide = (comp, key) => {
18428 if (doShowing(comp)) {
18429 const element = comp.element;
18430 set$8(element, 'display', 'none');
18431 set$9(element, 'aria-hidden', 'true');
18432 emitWith(comp, slotVisibility(), {
18438 const isShowing = onSlot(doShowing, false);
18439 const hideSlot = onSlot(doHide);
18440 const hideSlots = onSlots(hideSlot);
18441 const hideAllSlots = container => hideSlots(container, getSlotNames());
18442 const showSlot = onSlot(doShow);
18455 behaviours: get$3(detail.slotBehaviours),
18459 const slotApis = map$1({
18460 getSlotNames: (apis, c) => apis.getSlotNames(c),
18461 getSlot: (apis, c, key) => apis.getSlot(c, key),
18462 isShowing: (apis, c, key) => apis.isShowing(c, key),
18463 hideSlot: (apis, c, key) => apis.hideSlot(c, key),
18464 hideAllSlots: (apis, c) => apis.hideAllSlots(c),
18465 showSlot: (apis, c, key) => apis.showSlot(c, key)
18466 }, value => makeApi(value));
18467 const SlotContainer = {
18472 const sidebarSchema = objOf([
18475 defaultedFunction('onShow', noop),
18476 defaultedFunction('onHide', noop),
18479 const createSidebar = spec => asRaw('sidebar', sidebarSchema, spec);
18481 const setup$8 = editor => {
18482 const {sidebars} = editor.ui.registry.getAll();
18483 each$1(keys(sidebars), name => {
18484 const spec = sidebars[name];
18485 const isActive = () => is$1(Optional.from(editor.queryCommandValue('ToggleSidebar')), name);
18486 editor.ui.registry.addToggleButton(name, {
18488 tooltip: spec.tooltip,
18489 onAction: buttonApi => {
18490 editor.execCommand('ToggleSidebar', false, name);
18491 buttonApi.setActive(isActive());
18493 onSetup: buttonApi => {
18494 buttonApi.setActive(isActive());
18495 const handleToggle = () => buttonApi.setActive(isActive());
18496 editor.on('ToggleSidebar', handleToggle);
18498 editor.off('ToggleSidebar', handleToggle);
18504 const getApi = comp => ({ element: () => comp.element.dom });
18505 const makePanels = (parts, panelConfigs) => {
18506 const specs = map$2(keys(panelConfigs), name => {
18507 const spec = panelConfigs[name];
18508 const bridged = getOrDie(createSidebar(spec));
18512 onSetup: bridged.onSetup,
18513 onShow: bridged.onShow,
18514 onHide: bridged.onHide
18517 return map$2(specs, spec => {
18518 const editorOffCell = Cell(noop);
18519 return parts.slot(spec.name, {
18522 classes: ['tox-sidebar__pane']
18524 behaviours: SimpleBehaviours.unnamedEvents([
18525 onControlAttached(spec, editorOffCell),
18526 onControlDetached(spec, editorOffCell),
18527 run$1(slotVisibility(), (sidepanel, se) => {
18528 const data = se.event;
18529 const optSidePanelSpec = find$5(specs, config => config.name === data.name);
18530 optSidePanelSpec.each(sidePanelSpec => {
18531 const handler = data.visible ? sidePanelSpec.onShow : sidePanelSpec.onHide;
18532 handler(sidePanelSpec.getApi(sidepanel));
18539 const makeSidebar = panelConfigs => SlotContainer.sketch(parts => ({
18542 classes: ['tox-sidebar__pane-container']
18544 components: makePanels(parts, panelConfigs),
18545 slotBehaviours: SimpleBehaviours.unnamedEvents([runOnAttached(slotContainer => SlotContainer.hideAllSlots(slotContainer))])
18547 const setSidebar = (sidebar, panelConfigs, showSidebar) => {
18548 const optSlider = Composing.getCurrent(sidebar);
18549 optSlider.each(slider => {
18550 Replacing.set(slider, [makeSidebar(panelConfigs)]);
18551 const configKey = showSidebar?.toLowerCase();
18552 if (isString(configKey) && has$2(panelConfigs, configKey)) {
18553 Composing.getCurrent(slider).each(slotContainer => {
18554 SlotContainer.showSlot(slotContainer, configKey);
18555 Sliding.immediateGrow(slider);
18556 remove$6(slider.element, 'width');
18561 const toggleSidebar = (sidebar, name) => {
18562 const optSlider = Composing.getCurrent(sidebar);
18563 optSlider.each(slider => {
18564 const optSlotContainer = Composing.getCurrent(slider);
18565 optSlotContainer.each(slotContainer => {
18566 if (Sliding.hasGrown(slider)) {
18567 if (SlotContainer.isShowing(slotContainer, name)) {
18568 Sliding.shrink(slider);
18570 SlotContainer.hideAllSlots(slotContainer);
18571 SlotContainer.showSlot(slotContainer, name);
18574 SlotContainer.hideAllSlots(slotContainer);
18575 SlotContainer.showSlot(slotContainer, name);
18576 Sliding.grow(slider);
18581 const whichSidebar = sidebar => {
18582 const optSlider = Composing.getCurrent(sidebar);
18583 return optSlider.bind(slider => {
18584 const sidebarOpen = Sliding.isGrowing(slider) || Sliding.hasGrown(slider);
18586 const optSlotContainer = Composing.getCurrent(slider);
18587 return optSlotContainer.bind(slotContainer => find$5(SlotContainer.getSlotNames(slotContainer), name => SlotContainer.isShowing(slotContainer, name)));
18589 return Optional.none();
18593 const fixSize = generate$6('FixSizeEvent');
18594 const autoSize = generate$6('AutoSizeEvent');
18595 const renderSidebar = spec => ({
18599 classes: ['tox-sidebar'],
18600 attributes: { role: 'complementary' }
18605 classes: ['tox-sidebar__slider']
18608 behaviours: derive$1([
18609 Tabstopping.config({}),
18610 Focusing.config({}),
18612 dimension: { property: 'width' },
18613 closedClass: 'tox-sidebar--sliding-closed',
18614 openClass: 'tox-sidebar--sliding-open',
18615 shrinkingClass: 'tox-sidebar--sliding-shrinking',
18616 growingClass: 'tox-sidebar--sliding-growing',
18617 onShrunk: slider => {
18618 const optSlotContainer = Composing.getCurrent(slider);
18619 optSlotContainer.each(SlotContainer.hideAllSlots);
18620 emit(slider, autoSize);
18622 onGrown: slider => {
18623 emit(slider, autoSize);
18625 onStartGrow: slider => {
18626 emitWith(slider, fixSize, { width: getRaw(slider.element, 'width').getOr('') });
18628 onStartShrink: slider => {
18629 emitWith(slider, fixSize, { width: get$c(slider.element) + 'px' });
18632 Replacing.config({}),
18635 const children = Replacing.contents(comp);
18636 return head(children);
18641 behaviours: derive$1([
18642 ComposingConfigs.childAt(0),
18643 config('sidebar-sliding-events', [
18644 run$1(fixSize, (comp, se) => {
18645 set$8(comp.element, 'width', se.event.width);
18647 run$1(autoSize, (comp, _se) => {
18648 remove$6(comp.element, 'width');
18654 const block = (component, config, state, getBusySpec) => {
18655 set$9(component.element, 'aria-busy', true);
18656 const root = config.getRoot(component).getOr(component);
18657 const blockerBehaviours = derive$1([
18660 onTab: () => Optional.some(true),
18661 onShiftTab: () => Optional.some(true)
18663 Focusing.config({})
18665 const blockSpec = getBusySpec(root, blockerBehaviours);
18666 const blocker = root.getSystem().build(blockSpec);
18667 Replacing.append(root, premade(blocker));
18668 if (blocker.hasConfigured(Keying) && config.focus) {
18669 Keying.focusIn(blocker);
18671 if (!state.isBlocked()) {
18672 config.onBlock(component);
18674 state.blockWith(() => Replacing.remove(root, blocker));
18676 const unblock = (component, config, state) => {
18677 remove$7(component.element, 'aria-busy');
18678 if (state.isBlocked()) {
18679 config.onUnblock(component);
18684 var BlockingApis = /*#__PURE__*/Object.freeze({
18690 var BlockingSchema = [
18691 defaultedFunction('getRoot', Optional.none),
18692 defaultedBoolean('focus', true),
18693 onHandler('onBlock'),
18694 onHandler('onUnblock')
18697 const init$4 = () => {
18698 const blocker = destroyable();
18699 const blockWith = destroy => {
18700 blocker.set({ destroy });
18703 readState: blocker.isSet,
18705 clear: blocker.clear,
18706 isBlocked: blocker.isSet
18710 var BlockingState = /*#__PURE__*/Object.freeze({
18715 const Blocking = create$4({
18716 fields: BlockingSchema,
18718 apis: BlockingApis,
18719 state: BlockingState
18722 const getAttrs = elem => {
18723 const attributes = elem.dom.attributes !== undefined ? elem.dom.attributes : [];
18724 return foldl(attributes, (b, attr) => {
18725 if (attr.name === 'class') {
18730 [attr.name]: attr.value
18735 const getClasses = elem => Array.prototype.slice.call(elem.dom.classList, 0);
18736 const fromHtml = html => {
18737 const elem = SugarElement.fromHtml(html);
18738 const children$1 = children(elem);
18739 const attrs = getAttrs(elem);
18740 const classes = getClasses(elem);
18741 const contents = children$1.length === 0 ? {} : { innerHtml: get$9(elem) };
18750 const getBusySpec$1 = providerBackstage => (_root, _behaviours) => ({
18754 'aria-label': providerBackstage.translate('Loading...'),
18757 classes: ['tox-throbber__busy-spinner']
18759 components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
18761 const focusBusyComponent = throbber => Composing.getCurrent(throbber).each(comp => focus$3(comp.element));
18762 const toggleEditorTabIndex = (editor, state) => {
18763 const tabIndexAttr = 'tabindex';
18764 const dataTabIndexAttr = `data-mce-${ tabIndexAttr }`;
18765 Optional.from(editor.iframeElement).map(SugarElement.fromDom).each(iframe => {
18767 getOpt(iframe, tabIndexAttr).each(tabIndex => set$9(iframe, dataTabIndexAttr, tabIndex));
18768 set$9(iframe, tabIndexAttr, -1);
18770 remove$7(iframe, tabIndexAttr);
18771 getOpt(iframe, dataTabIndexAttr).each(tabIndex => {
18772 set$9(iframe, tabIndexAttr, tabIndex);
18773 remove$7(iframe, dataTabIndexAttr);
18778 const toggleThrobber = (editor, comp, state, providerBackstage) => {
18779 const element = comp.element;
18780 toggleEditorTabIndex(editor, state);
18782 Blocking.block(comp, getBusySpec$1(providerBackstage));
18783 remove$6(element, 'display');
18784 remove$7(element, 'aria-hidden');
18785 if (editor.hasFocus()) {
18786 focusBusyComponent(comp);
18789 const throbberFocus = Composing.getCurrent(comp).exists(busyComp => hasFocus(busyComp.element));
18790 Blocking.unblock(comp);
18791 set$8(element, 'display', 'none');
18792 set$9(element, 'aria-hidden', 'true');
18793 if (throbberFocus) {
18798 const renderThrobber = spec => ({
18802 attributes: { 'aria-hidden': 'true' },
18803 classes: ['tox-throbber'],
18804 styles: { display: 'none' }
18806 behaviours: derive$1([
18807 Replacing.config({}),
18808 Blocking.config({ focus: false }),
18809 Composing.config({ find: comp => head(comp.components()) })
18813 const isFocusEvent = event => event.type === 'focusin';
18814 const isPasteBinTarget = event => {
18815 if (isFocusEvent(event)) {
18816 const node = event.composed ? head(event.composedPath()) : Optional.from(event.target);
18817 return node.map(SugarElement.fromDom).filter(isElement$1).exists(targetElm => has(targetElm, 'mce-pastebin'));
18822 const setup$7 = (editor, lazyThrobber, sharedBackstage) => {
18823 const throbberState = Cell(false);
18824 const timer = value$2();
18825 const stealFocus = e => {
18826 if (throbberState.get() && !isPasteBinTarget(e)) {
18827 e.preventDefault();
18828 focusBusyComponent(lazyThrobber());
18829 editor.editorManager.setActive(editor);
18832 if (!editor.inline) {
18833 editor.on('PreInit', () => {
18834 editor.dom.bind(editor.getWin(), 'focusin', stealFocus);
18835 editor.on('BeforeExecCommand', e => {
18836 if (e.command.toLowerCase() === 'mcefocus' && e.value !== true) {
18842 const toggle = state => {
18843 if (state !== throbberState.get()) {
18844 throbberState.set(state);
18845 toggleThrobber(editor, lazyThrobber(), state, sharedBackstage.providers);
18846 fireAfterProgressState(editor, state);
18849 editor.on('ProgressState', e => {
18850 timer.on(clearTimeout);
18851 if (isNumber(e.time)) {
18852 const timerId = global$9.setEditorTimeout(editor, () => toggle(e.state), e.time);
18853 timer.set(timerId);
18861 const generate$1 = (xs, f) => {
18866 const r = foldl(xs, (b, a) => {
18867 const value = f(a, b.len);
18868 return value.fold(constant$1(b), v => ({
18870 list: b.list.concat([v])
18876 const output = (within, extra, withinWidth) => ({
18881 const apportion = (units, total, len) => {
18882 const parray = generate$1(units, (unit, current) => {
18883 const width = len(unit);
18884 return Optional.some({
18887 finish: current + width,
18891 const within = filter$2(parray, unit => unit.finish <= total);
18892 const withinWidth = foldr(within, (acc, el) => acc + el.width, 0);
18893 const extra = parray.slice(within.length);
18900 const toUnit = parray => map$2(parray, unit => unit.element);
18901 const fitLast = (within, extra, withinWidth) => {
18902 const fits = toUnit(within.concat(extra));
18903 return output(fits, [], withinWidth);
18905 const overflow = (within, extra, overflower, withinWidth) => {
18906 const fits = toUnit(within).concat([overflower]);
18907 return output(fits, toUnit(extra), withinWidth);
18909 const fitAll = (within, extra, withinWidth) => output(toUnit(within), [], withinWidth);
18910 const tryFit = (total, units, len) => {
18911 const divide = apportion(units, total, len);
18912 return divide.extra.length === 0 ? Optional.some(divide) : Optional.none();
18914 const partition = (total, units, len, overflower) => {
18915 const divide = tryFit(total, units, len).getOrThunk(() => apportion(units, total - len(overflower), len));
18916 const within = divide.within;
18917 const extra = divide.extra;
18918 const withinWidth = divide.withinWidth;
18919 if (extra.length === 1 && extra[0].width <= len(overflower)) {
18920 return fitLast(within, extra, withinWidth);
18921 } else if (extra.length >= 1) {
18922 return overflow(within, extra, overflower, withinWidth);
18924 return fitAll(within, extra, withinWidth);
18928 const setGroups$1 = (toolbar, storedGroups) => {
18929 const bGroups = map$2(storedGroups, g => premade(g));
18930 Toolbar.setGroups(toolbar, bGroups);
18932 const findFocusedComp = comps => findMap(comps, comp => search(comp.element).bind(focusedElm => comp.getSystem().getByDom(focusedElm).toOptional()));
18933 const refresh$2 = (toolbar, detail, setOverflow) => {
18934 const builtGroups = detail.builtGroups.get();
18935 if (builtGroups.length === 0) {
18938 const primary = getPartOrDie(toolbar, detail, 'primary');
18939 const overflowGroup = Coupling.getCoupled(toolbar, 'overflowGroup');
18940 set$8(primary.element, 'visibility', 'hidden');
18941 const groups = builtGroups.concat([overflowGroup]);
18942 const focusedComp = findFocusedComp(groups);
18944 setGroups$1(primary, groups);
18945 const availableWidth = get$c(primary.element);
18946 const overflows = partition(availableWidth, detail.builtGroups.get(), comp => get$c(comp.element), overflowGroup);
18947 if (overflows.extra.length === 0) {
18948 Replacing.remove(primary, overflowGroup);
18951 setGroups$1(primary, overflows.within);
18952 setOverflow(overflows.extra);
18954 remove$6(primary.element, 'visibility');
18955 reflow(primary.element);
18956 focusedComp.each(Focusing.focus);
18959 const schema$c = constant$1([
18960 field('splitToolbarBehaviours', [Coupling]),
18961 customField('builtGroups', () => Cell([]))
18964 const schema$b = constant$1([
18965 markers$1(['overflowToggledClass']),
18966 optionFunction('getOverflowBounds'),
18967 required$1('lazySink'),
18968 customField('overflowGroups', () => Cell([]))
18969 ].concat(schema$c()));
18970 const parts$7 = constant$1([
18973 schema: schema$e(),
18977 schema: schema$e(),
18980 external({ name: 'overflow-button' }),
18981 external({ name: 'overflow-group' })
18984 const expandable = constant$1((element, available) => {
18985 setMax(element, Math.floor(available));
18988 const schema$a = constant$1([
18989 markers$1(['toggledClass']),
18990 required$1('lazySink'),
18991 requiredFunction('fetch'),
18992 optionFunction('getBounds'),
18993 optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
18996 const parts$6 = constant$1([
18999 overrides: detail => ({
19000 dom: { attributes: { 'aria-haspopup': 'true' } },
19001 buttonBehaviours: derive$1([Toggling.config({
19002 toggleClass: detail.markers.toggledClass,
19003 aria: { mode: 'expanded' },
19004 toggleOnExecute: false
19010 schema: schema$e(),
19012 overrides: detail => {
19014 toolbarBehaviours: derive$1([Keying.config({
19016 onEscape: comp => {
19017 getPart(comp, detail, 'button').each(Focusing.focus);
19018 return Optional.none();
19026 const toggle = (button, externals) => {
19027 const toolbarSandbox = Coupling.getCoupled(button, 'toolbarSandbox');
19028 if (Sandboxing.isOpen(toolbarSandbox)) {
19029 Sandboxing.close(toolbarSandbox);
19031 Sandboxing.open(toolbarSandbox, externals.toolbar());
19034 const position = (button, toolbar, detail, layouts) => {
19035 const bounds = detail.getBounds.map(bounder => bounder());
19036 const sink = detail.lazySink(button).getOrDie();
19037 Positioning.positionWithinBounds(sink, toolbar, {
19042 overrides: { maxWidthFunction: expandable() }
19046 const setGroups = (button, toolbar, detail, layouts, groups) => {
19047 Toolbar.setGroups(toolbar, groups);
19048 position(button, toolbar, detail, layouts);
19049 Toggling.on(button);
19051 const makeSandbox = (button, spec, detail) => {
19052 const ariaControls = manager();
19053 const onOpen = (sandbox, toolbar) => {
19054 detail.fetch().get(groups => {
19055 setGroups(button, toolbar, detail, spec.layouts, groups);
19056 ariaControls.link(button.element);
19057 Keying.focusIn(toolbar);
19060 const onClose = () => {
19061 Toggling.off(button);
19062 Focusing.focus(button);
19063 ariaControls.unlink(button.element);
19068 attributes: { id: ariaControls.id }
19070 behaviours: derive$1([
19073 onEscape: comp => {
19074 Sandboxing.close(comp);
19075 return Optional.some(true);
19078 Sandboxing.config({
19081 isPartOf: (container, data, queryElem) => {
19082 return isPartOf$1(data, queryElem) || isPartOf$1(button, queryElem);
19084 getAttachPoint: () => {
19085 return detail.lazySink(button).getOrDie();
19090 ...receivingChannel$1({
19091 isExtraPart: never,
19092 ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
19094 ...receivingChannel({
19095 doReposition: () => {
19096 Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
19097 position(button, toolbar, detail, spec.layouts);
19106 const factory$a = (detail, components, spec, externals) => ({
19108 ...externals.button(),
19109 action: button => {
19110 toggle(button, externals);
19112 buttonBehaviours: SketchBehaviours.augment({ dump: externals.button().buttonBehaviours }, [Coupling.config({
19114 toolbarSandbox: button => {
19115 return makeSandbox(button, spec, detail);
19121 setGroups: (button, groups) => {
19122 Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
19123 setGroups(button, toolbar, detail, spec.layouts, groups);
19126 reposition: button => {
19127 Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
19128 position(button, toolbar, detail, spec.layouts);
19131 toggle: button => {
19132 toggle(button, externals);
19134 getToolbar: button => {
19135 return Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox'));
19137 isOpen: button => {
19138 return Sandboxing.isOpen(Coupling.getCoupled(button, 'toolbarSandbox'));
19142 const FloatingToolbarButton = composite({
19143 name: 'FloatingToolbarButton',
19144 factory: factory$a,
19145 configFields: schema$a(),
19146 partFields: parts$6(),
19148 setGroups: (apis, button, groups) => {
19149 apis.setGroups(button, groups);
19151 reposition: (apis, button) => {
19152 apis.reposition(button);
19154 toggle: (apis, button) => {
19155 apis.toggle(button);
19157 getToolbar: (apis, button) => apis.getToolbar(button),
19158 isOpen: (apis, button) => apis.isOpen(button)
19162 const schema$9 = constant$1([
19163 required$1('items'),
19164 markers$1(['itemSelector']),
19165 field('tgroupBehaviours', [Keying])
19167 const parts$5 = constant$1([group({
19172 const factory$9 = (detail, components, _spec, _externals) => ({
19176 behaviours: augment(detail.tgroupBehaviours, [Keying.config({
19178 selector: detail.markers.itemSelector
19180 domModification: { attributes: { role: 'toolbar' } }
19182 const ToolbarGroup = composite({
19183 name: 'ToolbarGroup',
19184 configFields: schema$9(),
19185 partFields: parts$5(),
19189 const buildGroups = comps => map$2(comps, g => premade(g));
19190 const refresh$1 = (toolbar, memFloatingToolbarButton, detail) => {
19191 refresh$2(toolbar, detail, overflowGroups => {
19192 detail.overflowGroups.set(overflowGroups);
19193 memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
19194 FloatingToolbarButton.setGroups(floatingToolbarButton, buildGroups(overflowGroups));
19198 const factory$8 = (detail, components, spec, externals) => {
19199 const memFloatingToolbarButton = record(FloatingToolbarButton.sketch({
19200 fetch: () => Future.nu(resolve => {
19201 resolve(buildGroups(detail.overflowGroups.get()));
19212 onBottomLtr: () => [
19216 onBottomRtl: () => [
19221 getBounds: spec.getOverflowBounds,
19222 lazySink: detail.lazySink,
19223 fireDismissalEventInstead: {},
19224 markers: { toggledClass: detail.markers.overflowToggledClass },
19226 button: externals['overflow-button'](),
19227 toolbar: externals.overflow()
19234 behaviours: augment(detail.splitToolbarBehaviours, [Coupling.config({
19236 overflowGroup: () => {
19237 return ToolbarGroup.sketch({
19238 ...externals['overflow-group'](),
19239 items: [memFloatingToolbarButton.asSpec()]
19245 setGroups: (toolbar, groups) => {
19246 detail.builtGroups.set(map$2(groups, toolbar.getSystem().build));
19247 refresh$1(toolbar, memFloatingToolbarButton, detail);
19249 refresh: toolbar => refresh$1(toolbar, memFloatingToolbarButton, detail),
19250 toggle: toolbar => {
19251 memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
19252 FloatingToolbarButton.toggle(floatingToolbarButton);
19255 isOpen: toolbar => memFloatingToolbarButton.getOpt(toolbar).map(FloatingToolbarButton.isOpen).getOr(false),
19256 reposition: toolbar => {
19257 memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
19258 FloatingToolbarButton.reposition(floatingToolbarButton);
19261 getOverflow: toolbar => memFloatingToolbarButton.getOpt(toolbar).bind(FloatingToolbarButton.getToolbar)
19263 domModification: { attributes: { role: 'group' } }
19266 const SplitFloatingToolbar = composite({
19267 name: 'SplitFloatingToolbar',
19268 configFields: schema$b(),
19269 partFields: parts$7(),
19270 factory: factory$8,
19272 setGroups: (apis, toolbar, groups) => {
19273 apis.setGroups(toolbar, groups);
19275 refresh: (apis, toolbar) => {
19276 apis.refresh(toolbar);
19278 reposition: (apis, toolbar) => {
19279 apis.reposition(toolbar);
19281 toggle: (apis, toolbar) => {
19282 apis.toggle(toolbar);
19284 isOpen: (apis, toolbar) => apis.isOpen(toolbar),
19285 getOverflow: (apis, toolbar) => apis.getOverflow(toolbar)
19289 const schema$8 = constant$1([
19295 'overflowToggledClass'
19297 onHandler('onOpened'),
19298 onHandler('onClosed')
19299 ].concat(schema$c()));
19300 const parts$4 = constant$1([
19303 schema: schema$e(),
19308 schema: schema$e(),
19310 overrides: detail => {
19312 toolbarBehaviours: derive$1([
19314 dimension: { property: 'height' },
19315 closedClass: detail.markers.closedClass,
19316 openClass: detail.markers.openClass,
19317 shrinkingClass: detail.markers.shrinkingClass,
19318 growingClass: detail.markers.growingClass,
19319 onShrunk: comp => {
19320 getPart(comp, detail, 'overflow-button').each(button => {
19321 Toggling.off(button);
19322 Focusing.focus(button);
19324 detail.onClosed(comp);
19327 Keying.focusIn(comp);
19328 detail.onOpened(comp);
19330 onStartGrow: comp => {
19331 getPart(comp, detail, 'overflow-button').each(Toggling.on);
19336 onEscape: comp => {
19337 getPart(comp, detail, 'overflow-button').each(Focusing.focus);
19338 return Optional.some(true);
19346 name: 'overflow-button',
19347 overrides: detail => ({
19348 buttonBehaviours: derive$1([Toggling.config({
19349 toggleClass: detail.markers.overflowToggledClass,
19350 aria: { mode: 'pressed' },
19351 toggleOnExecute: false
19355 external({ name: 'overflow-group' })
19358 const isOpen = (toolbar, detail) => getPart(toolbar, detail, 'overflow').map(Sliding.hasGrown).getOr(false);
19359 const toggleToolbar = (toolbar, detail) => {
19360 getPart(toolbar, detail, 'overflow-button').bind(() => getPart(toolbar, detail, 'overflow')).each(overf => {
19361 refresh(toolbar, detail);
19362 Sliding.toggleGrow(overf);
19365 const refresh = (toolbar, detail) => {
19366 getPart(toolbar, detail, 'overflow').each(overflow => {
19367 refresh$2(toolbar, detail, groups => {
19368 const builtGroups = map$2(groups, g => premade(g));
19369 Toolbar.setGroups(overflow, builtGroups);
19371 getPart(toolbar, detail, 'overflow-button').each(button => {
19372 if (Sliding.hasGrown(overflow)) {
19373 Toggling.on(button);
19376 Sliding.refresh(overflow);
19379 const factory$7 = (detail, components, spec, externals) => {
19380 const toolbarToggleEvent = 'alloy.toolbar.toggle';
19381 const doSetGroups = (toolbar, groups) => {
19382 const built = map$2(groups, toolbar.getSystem().build);
19383 detail.builtGroups.set(built);
19389 behaviours: augment(detail.splitToolbarBehaviours, [
19392 overflowGroup: toolbar => {
19393 return ToolbarGroup.sketch({
19394 ...externals['overflow-group'](),
19395 items: [Button.sketch({
19396 ...externals['overflow-button'](),
19397 action: _button => {
19398 emit(toolbar, toolbarToggleEvent);
19405 config('toolbar-toggle-events', [run$1(toolbarToggleEvent, toolbar => {
19406 toggleToolbar(toolbar, detail);
19410 setGroups: (toolbar, groups) => {
19411 doSetGroups(toolbar, groups);
19412 refresh(toolbar, detail);
19414 refresh: toolbar => refresh(toolbar, detail),
19415 toggle: toolbar => toggleToolbar(toolbar, detail),
19416 isOpen: toolbar => isOpen(toolbar, detail)
19418 domModification: { attributes: { role: 'group' } }
19421 const SplitSlidingToolbar = composite({
19422 name: 'SplitSlidingToolbar',
19423 configFields: schema$8(),
19424 partFields: parts$4(),
19425 factory: factory$7,
19427 setGroups: (apis, toolbar, groups) => {
19428 apis.setGroups(toolbar, groups);
19430 refresh: (apis, toolbar) => {
19431 apis.refresh(toolbar);
19433 toggle: (apis, toolbar) => {
19434 apis.toggle(toolbar);
19436 isOpen: (apis, toolbar) => apis.isOpen(toolbar)
19440 const renderToolbarGroupCommon = toolbarGroup => {
19441 const attributes = toolbarGroup.title.fold(() => ({}), title => ({ attributes: { title } }));
19445 classes: ['tox-toolbar__group'],
19448 components: [ToolbarGroup.parts.items({})],
19449 items: toolbarGroup.items,
19450 markers: { itemSelector: '*:not(.tox-split-button) > .tox-tbtn:not([disabled]), ' + '.tox-split-button:not([disabled]), ' + '.tox-toolbar-nav-js:not([disabled])' },
19451 tgroupBehaviours: derive$1([
19452 Tabstopping.config({}),
19453 Focusing.config({})
19457 const renderToolbarGroup = toolbarGroup => ToolbarGroup.sketch(renderToolbarGroupCommon(toolbarGroup));
19458 const getToolbarBehaviours = (toolbarSpec, modeName) => {
19459 const onAttached = runOnAttached(component => {
19460 const groups = map$2(toolbarSpec.initGroups, renderToolbarGroup);
19461 Toolbar.setGroups(component, groups);
19464 DisablingConfigs.toolbarButton(toolbarSpec.providers.isDisabled),
19468 onEscape: toolbarSpec.onEscape,
19469 selector: '.tox-toolbar__group'
19471 config('toolbar-events', [onAttached])
19474 const renderMoreToolbarCommon = toolbarSpec => {
19475 const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
19477 uid: toolbarSpec.uid,
19480 classes: ['tox-toolbar-overlord']
19483 'overflow-group': renderToolbarGroupCommon({
19484 title: Optional.none(),
19487 'overflow-button': renderIconButtonSpec({
19489 icon: Optional.some('more-drawer'),
19491 tooltip: Optional.some('More...'),
19493 buttonType: Optional.none(),
19495 }, Optional.none(), toolbarSpec.providers)
19497 splitToolbarBehaviours: getToolbarBehaviours(toolbarSpec, modeName)
19500 const renderFloatingMoreToolbar = toolbarSpec => {
19501 const baseSpec = renderMoreToolbarCommon(toolbarSpec);
19502 const overflowXOffset = 4;
19503 const primary = SplitFloatingToolbar.parts.primary({
19506 classes: ['tox-toolbar__primary']
19509 return SplitFloatingToolbar.sketch({
19511 lazySink: toolbarSpec.getSink,
19512 getOverflowBounds: () => {
19513 const headerElem = toolbarSpec.moreDrawerData.lazyHeader().element;
19514 const headerBounds = absolute$2(headerElem);
19515 const docElem = documentElement(headerElem);
19516 const docBounds = absolute$2(docElem);
19517 const height = Math.max(docElem.dom.scrollHeight, docBounds.height);
19518 return bounds(headerBounds.x + overflowXOffset, docBounds.y, headerBounds.width - overflowXOffset * 2, height);
19525 classes: ['tox-toolbar__overflow'],
19526 attributes: toolbarSpec.attributes
19530 components: [primary],
19531 markers: { overflowToggledClass: 'tox-tbtn--enabled' }
19534 const renderSlidingMoreToolbar = toolbarSpec => {
19535 const primary = SplitSlidingToolbar.parts.primary({
19538 classes: ['tox-toolbar__primary']
19541 const overflow = SplitSlidingToolbar.parts.overflow({
19544 classes: ['tox-toolbar__overflow']
19547 const baseSpec = renderMoreToolbarCommon(toolbarSpec);
19548 return SplitSlidingToolbar.sketch({
19555 openClass: 'tox-toolbar__overflow--open',
19556 closedClass: 'tox-toolbar__overflow--closed',
19557 growingClass: 'tox-toolbar__overflow--growing',
19558 shrinkingClass: 'tox-toolbar__overflow--shrinking',
19559 overflowToggledClass: 'tox-tbtn--enabled'
19561 onOpened: comp => {
19562 comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'opened' });
19564 onClosed: comp => {
19565 comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'closed' });
19569 const renderToolbar = toolbarSpec => {
19570 const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
19571 return Toolbar.sketch({
19572 uid: toolbarSpec.uid,
19575 classes: ['tox-toolbar'].concat(toolbarSpec.type === ToolbarMode$1.scrolling ? ['tox-toolbar--scrolling'] : [])
19577 components: [Toolbar.parts.groups({})],
19578 toolbarBehaviours: getToolbarBehaviours(toolbarSpec, modeName)
19582 const factory$6 = (detail, components, _spec) => {
19584 getSocket: comp => {
19585 return parts$a.getPart(comp, detail, 'socket');
19587 setSidebar: (comp, panelConfigs, showSidebar) => {
19588 parts$a.getPart(comp, detail, 'sidebar').each(sidebar => setSidebar(sidebar, panelConfigs, showSidebar));
19590 toggleSidebar: (comp, name) => {
19591 parts$a.getPart(comp, detail, 'sidebar').each(sidebar => toggleSidebar(sidebar, name));
19593 whichSidebar: comp => {
19594 return parts$a.getPart(comp, detail, 'sidebar').bind(whichSidebar).getOrNull();
19596 getHeader: comp => {
19597 return parts$a.getPart(comp, detail, 'header');
19599 getToolbar: comp => {
19600 return parts$a.getPart(comp, detail, 'toolbar');
19602 setToolbar: (comp, groups) => {
19603 parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
19604 const renderedGroups = map$2(groups, renderToolbarGroup);
19605 toolbar.getApis().setGroups(toolbar, renderedGroups);
19608 setToolbars: (comp, toolbars) => {
19609 parts$a.getPart(comp, detail, 'multiple-toolbar').each(mToolbar => {
19610 const renderedToolbars = map$2(toolbars, g => map$2(g, renderToolbarGroup));
19611 CustomList.setItems(mToolbar, renderedToolbars);
19614 refreshToolbar: comp => {
19615 const toolbar = parts$a.getPart(comp, detail, 'toolbar');
19616 toolbar.each(toolbar => toolbar.getApis().refresh(toolbar));
19618 toggleToolbarDrawer: comp => {
19619 parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
19620 mapFrom(toolbar.getApis().toggle, toggle => toggle(toolbar));
19623 isToolbarDrawerToggled: comp => {
19624 return parts$a.getPart(comp, detail, 'toolbar').bind(toolbar => Optional.from(toolbar.getApis().isOpen).map(isOpen => isOpen(toolbar))).getOr(false);
19626 getThrobber: comp => {
19627 return parts$a.getPart(comp, detail, 'throbber');
19629 focusToolbar: comp => {
19630 const optToolbar = parts$a.getPart(comp, detail, 'toolbar').orThunk(() => parts$a.getPart(comp, detail, 'multiple-toolbar'));
19631 optToolbar.each(toolbar => {
19632 Keying.focusIn(toolbar);
19635 setMenubar: (comp, menus) => {
19636 parts$a.getPart(comp, detail, 'menubar').each(menubar => {
19637 SilverMenubar.setMenus(menubar, menus);
19640 focusMenubar: comp => {
19641 parts$a.getPart(comp, detail, 'menubar').each(menubar => {
19642 SilverMenubar.focus(menubar);
19651 behaviours: detail.behaviours
19654 const partMenubar = partType.optional({
19655 factory: SilverMenubar,
19657 schema: [required$1('backstage')]
19659 const toolbarFactory = spec => {
19660 if (spec.type === ToolbarMode$1.sliding) {
19661 return renderSlidingMoreToolbar;
19662 } else if (spec.type === ToolbarMode$1.floating) {
19663 return renderFloatingMoreToolbar;
19665 return renderToolbar;
19668 const partMultipleToolbar = partType.optional({
19670 sketch: spec => CustomList.sketch({
19673 listBehaviours: derive$1([Keying.config({
19675 selector: '.tox-toolbar'
19677 makeItem: () => renderToolbar({
19679 uid: generate$6('multiple-toolbar-item'),
19680 cyclicKeying: false,
19682 providers: spec.providers,
19685 return Optional.some(true);
19688 setupItem: (_mToolbar, tc, data, _index) => {
19689 Toolbar.setGroups(tc, data);
19694 name: 'multiple-toolbar',
19697 required$1('onEscape')
19700 const partToolbar = partType.optional({
19703 const renderer = toolbarFactory(spec);
19704 const toolbarSpec = {
19709 return Optional.some(true);
19711 cyclicKeying: false,
19713 getSink: spec.getSink,
19714 providers: spec.providers,
19716 lazyToolbar: spec.lazyToolbar,
19717 lazyMoreButton: spec.lazyMoreButton,
19718 lazyHeader: spec.lazyHeader
19720 attributes: spec.attributes
19722 return renderer(toolbarSpec);
19728 required$1('onEscape'),
19729 required$1('getSink')
19732 const partHeader = partType.optional({
19733 factory: { sketch: renderHeader },
19735 schema: [required$1('dom')]
19737 const partPromotion = partType.optional({
19738 factory: { sketch: renderPromotion },
19740 schema: [required$1('dom')]
19742 const partSocket = partType.optional({
19744 schema: [required$1('dom')]
19746 const partSidebar = partType.optional({
19747 factory: { sketch: renderSidebar },
19749 schema: [required$1('dom')]
19751 const partThrobber = partType.optional({
19752 factory: { sketch: renderThrobber },
19754 schema: [required$1('dom')]
19756 var OuterContainer = composite({
19757 name: 'OuterContainer',
19758 factory: factory$6,
19761 required$1('behaviours')
19767 partMultipleToolbar,
19774 getSocket: (apis, comp) => {
19775 return apis.getSocket(comp);
19777 setSidebar: (apis, comp, panelConfigs, showSidebar) => {
19778 apis.setSidebar(comp, panelConfigs, showSidebar);
19780 toggleSidebar: (apis, comp, name) => {
19781 apis.toggleSidebar(comp, name);
19783 whichSidebar: (apis, comp) => {
19784 return apis.whichSidebar(comp);
19786 getHeader: (apis, comp) => {
19787 return apis.getHeader(comp);
19789 getToolbar: (apis, comp) => {
19790 return apis.getToolbar(comp);
19792 setToolbar: (apis, comp, groups) => {
19793 apis.setToolbar(comp, groups);
19795 setToolbars: (apis, comp, toolbars) => {
19796 apis.setToolbars(comp, toolbars);
19798 refreshToolbar: (apis, comp) => {
19799 return apis.refreshToolbar(comp);
19801 toggleToolbarDrawer: (apis, comp) => {
19802 apis.toggleToolbarDrawer(comp);
19804 isToolbarDrawerToggled: (apis, comp) => {
19805 return apis.isToolbarDrawerToggled(comp);
19807 getThrobber: (apis, comp) => {
19808 return apis.getThrobber(comp);
19810 setMenubar: (apis, comp, menus) => {
19811 apis.setMenubar(comp, menus);
19813 focusMenubar: (apis, comp) => {
19814 apis.focusMenubar(comp);
19816 focusToolbar: (apis, comp) => {
19817 apis.focusToolbar(comp);
19822 const defaultMenubar = 'file edit view insert format tools table help';
19823 const defaultMenus = {
19826 items: 'newdocument restoredraft | preview | export print | deleteallconversations'
19830 items: 'undo redo | cut copy paste pastetext | selectall | searchreplace'
19834 items: 'code | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments'
19838 items: 'image link media addcomment pageembed template codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents footnotes | mergetags | insertdatetime'
19842 items: 'bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat'
19846 items: 'spellchecker spellcheckerlanguage | autocorrect capitalization | a11ycheck code wordcount'
19850 items: 'inserttable | cell row column | advtablesort | tableprops deletetable'
19857 const make = (menu, registry, editor) => {
19858 const removedMenuItems = getRemovedMenuItems(editor).split(/[ ,]/);
19861 getItems: () => bind$3(menu.items, i => {
19862 const itemName = i.toLowerCase();
19863 if (itemName.trim().length === 0) {
19865 } else if (exists(removedMenuItems, removedMenuItem => removedMenuItem === itemName)) {
19867 } else if (itemName === 'separator' || itemName === '|') {
19868 return [{ type: 'separator' }];
19869 } else if (registry.menuItems[itemName]) {
19870 return [registry.menuItems[itemName]];
19877 const parseItemsString = items => {
19878 return items.split(' ');
19880 const identifyMenus = (editor, registry) => {
19881 const rawMenuData = {
19885 const userDefinedMenus = keys(registry.menus).length > 0;
19886 const menubar = registry.menubar === undefined || registry.menubar === true ? parseItemsString(defaultMenubar) : parseItemsString(registry.menubar === false ? '' : registry.menubar);
19887 const validMenus = filter$2(menubar, menuName => {
19888 const isDefaultMenu = has$2(defaultMenus, menuName);
19889 if (userDefinedMenus) {
19890 return isDefaultMenu || get$g(registry.menus, menuName).exists(menu => has$2(menu, 'items'));
19892 return isDefaultMenu;
19895 const menus = map$2(validMenus, menuName => {
19896 const menuData = rawMenuData[menuName];
19898 title: menuData.title,
19899 items: parseItemsString(menuData.items)
19900 }, registry, editor);
19902 return filter$2(menus, menu => {
19903 const isNotSeparator = item => isString(item) || item.type !== 'separator';
19904 return menu.getItems().length > 0 && exists(menu.getItems(), isNotSeparator);
19908 const fireSkinLoaded = editor => {
19909 const done = () => {
19910 editor._skinLoaded = true;
19911 fireSkinLoaded$1(editor);
19914 if (editor.initialized) {
19917 editor.on('init', done);
19921 const fireSkinLoadError = (editor, err) => () => fireSkinLoadError$1(editor, { message: err });
19923 const loadStylesheet = (editor, stylesheetUrl, styleSheetLoader) => {
19924 editor.on('remove', () => styleSheetLoader.unload(stylesheetUrl));
19925 return styleSheetLoader.load(stylesheetUrl);
19927 const loadUiSkins = (editor, skinUrl) => {
19928 const skinUiCss = skinUrl + '/skin.min.css';
19929 return loadStylesheet(editor, skinUiCss, editor.ui.styleSheetLoader);
19931 const loadShadowDomUiSkins = (editor, skinUrl) => {
19932 const isInShadowRoot$1 = isInShadowRoot(SugarElement.fromDom(editor.getElement()));
19933 if (isInShadowRoot$1) {
19934 const shadowDomSkinCss = skinUrl + '/skin.shadowdom.min.css';
19935 return loadStylesheet(editor, shadowDomSkinCss, global$7.DOM.styleSheetLoader);
19937 return Promise.resolve();
19940 const loadSkin = (isInline, editor) => {
19941 const skinUrl = getSkinUrl(editor);
19943 editor.contentCSS.push(skinUrl + (isInline ? '/content.inline' : '/content') + '.min.css');
19945 if (!isSkinDisabled(editor) && isString(skinUrl)) {
19947 loadUiSkins(editor, skinUrl),
19948 loadShadowDomUiSkins(editor, skinUrl)
19949 ]).then(fireSkinLoaded(editor), fireSkinLoadError(editor, 'Skin could not be loaded'));
19951 fireSkinLoaded(editor)();
19954 const iframe = curry(loadSkin, false);
19955 const inline = curry(loadSkin, true);
19957 const onSetupFormatToggle = (editor, name) => api => {
19958 const boundCallback = unbindable();
19959 const init = () => {
19960 api.setActive(editor.formatter.match(name));
19961 const binding = editor.formatter.formatChanged(name, api.setActive);
19962 boundCallback.set(binding);
19964 editor.initialized ? init() : editor.once('init', init);
19966 editor.off('init', init);
19967 boundCallback.clear();
19970 const onSetupEvent = (editor, event, f) => api => {
19971 const handleEvent = () => f(api);
19972 const init = () => {
19974 editor.on(event, handleEvent);
19976 editor.initialized ? init() : editor.once('init', init);
19978 editor.off('init', init);
19979 editor.off(event, handleEvent);
19982 const onActionToggleFormat$1 = editor => rawItem => () => {
19983 editor.undoManager.transact(() => {
19985 editor.execCommand('mceToggleFormat', false, rawItem.format);
19988 const onActionExecCommand = (editor, command) => () => editor.execCommand(command);
19990 const generateSelectItems = (_editor, backstage, spec) => {
19991 const generateItem = (rawItem, response, invalid, value) => {
19992 const translatedText = backstage.shared.providers.translate(rawItem.title);
19993 if (rawItem.type === 'separator') {
19994 return Optional.some({
19996 text: translatedText
19998 } else if (rawItem.type === 'submenu') {
19999 const items = bind$3(rawItem.getStyleItems(), si => validate(si, response, value));
20000 if (response === 0 && items.length <= 0) {
20001 return Optional.none();
20003 return Optional.some({
20004 type: 'nestedmenuitem',
20005 text: translatedText,
20006 enabled: items.length > 0,
20007 getSubmenuItems: () => bind$3(rawItem.getStyleItems(), si => validate(si, response, value))
20011 return Optional.some({
20012 type: 'togglemenuitem',
20013 text: translatedText,
20014 icon: rawItem.icon,
20015 active: rawItem.isSelected(value),
20017 onAction: spec.onAction(rawItem),
20018 ...rawItem.getStylePreview().fold(() => ({}), preview => ({ meta: { style: preview } }))
20022 const validate = (item, response, value) => {
20023 const invalid = item.type === 'formatter' && spec.isInvalid(item);
20024 if (response === 0) {
20025 return invalid ? [] : generateItem(item, response, false, value).toArray();
20027 return generateItem(item, response, invalid, value).toArray();
20030 const validateItems = preItems => {
20031 const value = spec.getCurrentValue();
20032 const response = spec.shouldHide ? 0 : 1;
20033 return bind$3(preItems, item => validate(item, response, value));
20035 const getFetch = (backstage, getStyleItems) => (comp, callback) => {
20036 const preItems = getStyleItems();
20037 const items = validateItems(preItems);
20038 const menu = build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
20039 isHorizontalMenu: false,
20040 search: Optional.none()
20049 const createMenuItems = (editor, backstage, spec) => {
20050 const dataset = spec.dataset;
20051 const getStyleItems = dataset.type === 'basic' ? () => map$2(dataset.data, d => processBasic(d, spec.isSelectedFor, spec.getPreviewFor)) : dataset.getData;
20053 items: generateSelectItems(editor, backstage, spec),
20057 const createSelectButton = (editor, backstage, spec) => {
20058 const {items, getStyleItems} = createMenuItems(editor, backstage, spec);
20059 const getApi = comp => ({ getComponent: constant$1(comp) });
20060 const onSetup = onSetupEvent(editor, 'NodeChange', api => {
20061 const comp = api.getComponent();
20062 spec.updateText(comp);
20064 return renderCommonDropdown({
20065 text: spec.icon.isSome() ? Optional.none() : spec.text,
20067 tooltip: Optional.from(spec.tooltip),
20068 role: Optional.none(),
20069 fetch: items.getFetch(backstage, getStyleItems),
20074 classes: spec.icon.isSome() ? [] : ['bespoke'],
20075 dropdownBehaviours: []
20076 }, 'tox-tbtn', backstage.shared);
20079 const process = rawFormats => map$2(rawFormats, item => {
20080 let title = item, format = item;
20081 const values = item.split('=');
20082 if (values.length > 1) {
20084 format = values[1];
20091 const buildBasicStaticDataset = data => ({
20096 (function (Delimiter) {
20097 Delimiter[Delimiter['SemiColon'] = 0] = 'SemiColon';
20098 Delimiter[Delimiter['Space'] = 1] = 'Space';
20099 }(Delimiter || (Delimiter = {})));
20100 const split = (rawFormats, delimiter) => {
20101 if (delimiter === Delimiter.SemiColon) {
20102 return rawFormats.replace(/;$/, '').split(';');
20104 return rawFormats.split(' ');
20107 const buildBasicSettingsDataset = (editor, settingName, delimiter) => {
20108 const rawFormats = editor.options.get(settingName);
20109 const data = process(split(rawFormats, delimiter));
20116 const alignMenuItems = [
20119 icon: 'align-left',
20120 format: 'alignleft',
20121 command: 'JustifyLeft'
20125 icon: 'align-center',
20126 format: 'aligncenter',
20127 command: 'JustifyCenter'
20131 icon: 'align-right',
20132 format: 'alignright',
20133 command: 'JustifyRight'
20137 icon: 'align-justify',
20138 format: 'alignjustify',
20139 command: 'JustifyFull'
20142 const getSpec$4 = editor => {
20143 const getMatchingValue = () => find$5(alignMenuItems, item => editor.formatter.match(item.format));
20144 const isSelectedFor = format => () => editor.formatter.match(format);
20145 const getPreviewFor = _format => Optional.none;
20146 const updateSelectMenuIcon = comp => {
20147 const match = getMatchingValue();
20148 const alignment = match.fold(constant$1('left'), item => item.title.toLowerCase());
20149 emitWith(comp, updateMenuIcon, { icon: `align-${ alignment }` });
20151 const dataset = buildBasicStaticDataset(alignMenuItems);
20152 const onAction = rawItem => () => find$5(alignMenuItems, item => item.format === rawItem.format).each(item => editor.execCommand(item.command));
20155 text: Optional.none(),
20156 icon: Optional.some('align-left'),
20158 getCurrentValue: Optional.none,
20161 updateText: updateSelectMenuIcon,
20164 isInvalid: item => !editor.formatter.canApply(item.format)
20167 const createAlignButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$4(editor));
20168 const createAlignMenu = (editor, backstage) => {
20169 const menuItems = createMenuItems(editor, backstage, getSpec$4(editor));
20170 editor.ui.registry.addNestedMenuItem('align', {
20171 text: backstage.shared.providers.translate('Align'),
20172 getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
20176 const findNearest = (editor, getStyles) => {
20177 const styles = getStyles();
20178 const formats = map$2(styles, style => style.format);
20179 return Optional.from(editor.formatter.closest(formats)).bind(fmt => find$5(styles, data => data.format === fmt)).orThunk(() => someIf(editor.formatter.match('p'), {
20180 title: 'Paragraph',
20185 const getSpec$3 = editor => {
20186 const fallbackFormat = 'Paragraph';
20187 const isSelectedFor = format => () => editor.formatter.match(format);
20188 const getPreviewFor = format => () => {
20189 const fmt = editor.formatter.get(format);
20191 return Optional.some({
20192 tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
20193 styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
20196 return Optional.none();
20199 const updateSelectMenuText = comp => {
20200 const detectedFormat = findNearest(editor, () => dataset.data);
20201 const text = detectedFormat.fold(constant$1(fallbackFormat), fmt => fmt.title);
20202 emitWith(comp, updateMenuText, { text });
20204 const dataset = buildBasicSettingsDataset(editor, 'block_formats', Delimiter.SemiColon);
20207 text: Optional.some(fallbackFormat),
20208 icon: Optional.none(),
20210 getCurrentValue: Optional.none,
20212 onAction: onActionToggleFormat$1(editor),
20213 updateText: updateSelectMenuText,
20216 isInvalid: item => !editor.formatter.canApply(item.format)
20219 const createBlocksButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$3(editor));
20220 const createBlocksMenu = (editor, backstage) => {
20221 const menuItems = createMenuItems(editor, backstage, getSpec$3(editor));
20222 editor.ui.registry.addNestedMenuItem('blocks', {
20224 getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
20228 const systemStackFonts = [
20235 const splitFonts = fontFamily => {
20236 const fonts = fontFamily.split(/\s*,\s*/);
20237 return map$2(fonts, font => font.replace(/^['"]+|['"]+$/g, ''));
20239 const isSystemFontStack = fontFamily => {
20240 const matchesSystemStack = () => {
20241 const fonts = splitFonts(fontFamily.toLowerCase());
20242 return forall(systemStackFonts, font => fonts.indexOf(font.toLowerCase()) > -1);
20244 return fontFamily.indexOf('-apple-system') === 0 && matchesSystemStack();
20246 const getSpec$2 = editor => {
20247 const systemFont = 'System Font';
20248 const getMatchingValue = () => {
20249 const getFirstFont = fontFamily => fontFamily ? splitFonts(fontFamily)[0] : '';
20250 const fontFamily = editor.queryCommandValue('FontName');
20251 const items = dataset.data;
20252 const font = fontFamily ? fontFamily.toLowerCase() : '';
20253 const matchOpt = find$5(items, item => {
20254 const format = item.format;
20255 return format.toLowerCase() === font || getFirstFont(format).toLowerCase() === getFirstFont(font).toLowerCase();
20257 return someIf(isSystemFontStack(font), {
20267 const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
20268 const getCurrentValue = () => {
20269 const {matchOpt} = getMatchingValue();
20272 const getPreviewFor = item => () => Optional.some({
20274 styles: item.indexOf('dings') === -1 ? { 'font-family': item } : {}
20276 const onAction = rawItem => () => {
20277 editor.undoManager.transact(() => {
20279 editor.execCommand('FontName', false, rawItem.format);
20282 const updateSelectMenuText = comp => {
20283 const {matchOpt, font} = getMatchingValue();
20284 const text = matchOpt.fold(constant$1(font), item => item.title);
20285 emitWith(comp, updateMenuText, { text });
20287 const dataset = buildBasicSettingsDataset(editor, 'font_family_formats', Delimiter.SemiColon);
20290 text: Optional.some(systemFont),
20291 icon: Optional.none(),
20296 updateText: updateSelectMenuText,
20302 const createFontFamilyButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$2(editor));
20303 const createFontFamilyMenu = (editor, backstage) => {
20304 const menuItems = createMenuItems(editor, backstage, getSpec$2(editor));
20305 editor.ui.registry.addNestedMenuItem('fontfamily', {
20306 text: backstage.shared.providers.translate('Fonts'),
20307 getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
20311 const legacyFontSizes = {
20320 const keywordFontSizes = {
20329 const round = (number, precision) => {
20330 const factor = Math.pow(10, precision);
20331 return Math.round(number * factor) / factor;
20333 const toPt = (fontSize, precision) => {
20334 if (/[0-9.]+px$/.test(fontSize)) {
20335 return round(parseInt(fontSize, 10) * 72 / 96, precision || 0) + 'pt';
20337 return get$g(keywordFontSizes, fontSize).getOr(fontSize);
20340 const toLegacy = fontSize => get$g(legacyFontSizes, fontSize).getOr('');
20341 const getSpec$1 = editor => {
20342 const getMatchingValue = () => {
20343 let matchOpt = Optional.none();
20344 const items = dataset.data;
20345 const fontSize = editor.queryCommandValue('FontSize');
20347 for (let precision = 3; matchOpt.isNone() && precision >= 0; precision--) {
20348 const pt = toPt(fontSize, precision);
20349 const legacy = toLegacy(pt);
20350 matchOpt = find$5(items, item => item.format === fontSize || item.format === pt || item.format === legacy);
20358 const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
20359 const getCurrentValue = () => {
20360 const {matchOpt} = getMatchingValue();
20363 const getPreviewFor = constant$1(Optional.none);
20364 const onAction = rawItem => () => {
20365 editor.undoManager.transact(() => {
20367 editor.execCommand('FontSize', false, rawItem.format);
20370 const updateSelectMenuText = comp => {
20371 const {matchOpt, size} = getMatchingValue();
20372 const text = matchOpt.fold(constant$1(size), match => match.title);
20373 emitWith(comp, updateMenuText, { text });
20375 const dataset = buildBasicSettingsDataset(editor, 'font_size_formats', Delimiter.Space);
20377 tooltip: 'Font sizes',
20378 text: Optional.some('12pt'),
20379 icon: Optional.none(),
20384 updateText: updateSelectMenuText,
20390 const createFontSizeButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$1(editor));
20391 const createFontSizeMenu = (editor, backstage) => {
20392 const menuItems = createMenuItems(editor, backstage, getSpec$1(editor));
20393 editor.ui.registry.addNestedMenuItem('fontsize', {
20394 text: 'Font sizes',
20395 getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
20399 const getSpec = (editor, dataset) => {
20400 const fallbackFormat = 'Paragraph';
20401 const isSelectedFor = format => () => editor.formatter.match(format);
20402 const getPreviewFor = format => () => {
20403 const fmt = editor.formatter.get(format);
20404 return fmt !== undefined ? Optional.some({
20405 tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
20406 styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
20407 }) : Optional.none();
20409 const updateSelectMenuText = comp => {
20410 const getFormatItems = fmt => {
20411 if (isNestedFormat(fmt)) {
20412 return bind$3(fmt.items, getFormatItems);
20413 } else if (isFormatReference(fmt)) {
20422 const flattenedItems = bind$3(getStyleFormats(editor), getFormatItems);
20423 const detectedFormat = findNearest(editor, constant$1(flattenedItems));
20424 const text = detectedFormat.fold(constant$1(fallbackFormat), fmt => fmt.title);
20425 emitWith(comp, updateMenuText, { text });
20428 tooltip: 'Formats',
20429 text: Optional.some(fallbackFormat),
20430 icon: Optional.none(),
20432 getCurrentValue: Optional.none,
20434 onAction: onActionToggleFormat$1(editor),
20435 updateText: updateSelectMenuText,
20436 shouldHide: shouldAutoHideStyleFormats(editor),
20437 isInvalid: item => !editor.formatter.canApply(item.format),
20441 const createStylesButton = (editor, backstage) => {
20444 ...backstage.styles
20446 return createSelectButton(editor, backstage, getSpec(editor, dataset));
20448 const createStylesMenu = (editor, backstage) => {
20451 ...backstage.styles
20453 const menuItems = createMenuItems(editor, backstage, getSpec(editor, dataset));
20454 editor.ui.registry.addNestedMenuItem('styles', {
20456 getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
20460 const events$3 = (reflectingConfig, reflectingState) => {
20461 const update = (component, data) => {
20462 reflectingConfig.updateState.each(updateState => {
20463 const newState = updateState(component, data);
20464 reflectingState.set(newState);
20466 reflectingConfig.renderComponents.each(renderComponents => {
20467 const newComponents = renderComponents(data, reflectingState.get());
20468 const replacer = reflectingConfig.reuseDom ? withReuse : withoutReuse;
20469 replacer(component, newComponents);
20473 run$1(receive(), (component, message) => {
20474 const receivingData = message;
20475 if (!receivingData.universal) {
20476 const channel = reflectingConfig.channel;
20477 if (contains$2(receivingData.channels, channel)) {
20478 update(component, receivingData.data);
20482 runOnAttached((comp, _se) => {
20483 reflectingConfig.initialData.each(rawData => {
20484 update(comp, rawData);
20490 var ActiveReflecting = /*#__PURE__*/Object.freeze({
20495 const getState = (component, replaceConfig, reflectState) => reflectState;
20497 var ReflectingApis = /*#__PURE__*/Object.freeze({
20502 var ReflectingSchema = [
20503 required$1('channel'),
20504 option$3('renderComponents'),
20505 option$3('updateState'),
20506 option$3('initialData'),
20507 defaultedBoolean('reuseDom', true)
20510 const init$3 = () => {
20511 const cell = Cell(Optional.none());
20512 const clear = () => cell.set(Optional.none());
20513 const readState = () => cell.get().getOr('none');
20522 var ReflectingState = /*#__PURE__*/Object.freeze({
20527 const Reflecting = create$4({
20528 fields: ReflectingSchema,
20529 name: 'reflecting',
20530 active: ActiveReflecting,
20531 apis: ReflectingApis,
20532 state: ReflectingState
20535 const schema$7 = constant$1([
20536 required$1('toggleClass'),
20537 required$1('fetch'),
20538 onStrictHandler('onExecute'),
20539 defaulted('getHotspot', Optional.some),
20540 defaulted('getAnchorOverrides', constant$1({})),
20542 onStrictHandler('onItemExecute'),
20543 option$3('lazySink'),
20545 onHandler('onOpen'),
20546 field('splitDropdownBehaviours', [
20551 defaulted('matchWidth', false),
20552 defaulted('useMinWidth', false),
20553 defaulted('eventOrder', {}),
20555 ].concat(sandboxFields()));
20556 const arrowPart = required({
20558 schema: [required$1('dom')],
20561 return { buttonBehaviours: derive$1([Focusing.revoke()]) };
20563 overrides: detail => {
20567 attributes: { role: 'presentation' }
20570 arrow.getSystem().getByUid(detail.uid).each(emitExecute);
20572 buttonBehaviours: derive$1([Toggling.config({
20573 toggleOnExecute: false,
20574 toggleClass: detail.toggleClass
20579 const buttonPart = required({
20581 schema: [required$1('dom')],
20584 return { buttonBehaviours: derive$1([Focusing.revoke()]) };
20586 overrides: detail => {
20590 attributes: { role: 'presentation' }
20593 btn.getSystem().getByUid(detail.uid).each(splitDropdown => {
20594 detail.onExecute(splitDropdown, btn);
20600 const parts$3 = constant$1([
20610 styles: { display: 'none' },
20611 attributes: { 'aria-hidden': 'true' },
20612 innerHtml: spec.text
20617 schema: [required$1('text')],
20618 name: 'aria-descriptor'
20621 schema: [tieredMenuMarkers()],
20623 defaults: detail => {
20625 onExecute: (tmenu, item) => {
20626 tmenu.getSystem().getByUid(detail.uid).each(splitDropdown => {
20627 detail.onItemExecute(splitDropdown, tmenu, item);
20636 const factory$5 = (detail, components, spec, externals) => {
20637 const switchToMenu = sandbox => {
20638 Composing.getCurrent(sandbox).each(current => {
20639 Highlighting.highlightFirst(current);
20640 Keying.focusIn(current);
20643 const action = component => {
20644 const onOpenSync = switchToMenu;
20645 togglePopup(detail, identity, component, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
20647 const openMenu = comp => {
20649 return Optional.some(true);
20651 const executeOnButton = comp => {
20652 const button = getPartOrDie(comp, detail, 'button');
20653 emitExecute(button);
20654 return Optional.some(true);
20656 const buttonEvents = {
20657 ...derive$2([runOnAttached((component, _simulatedEvent) => {
20658 const ariaDescriptor = getPart(component, detail, 'aria-descriptor');
20659 ariaDescriptor.each(descriptor => {
20660 const descriptorId = generate$6('aria');
20661 set$9(descriptor.element, 'id', descriptorId);
20662 set$9(component.element, 'aria-describedby', descriptorId);
20665 ...events$a(Optional.some(action))
20668 repositionMenus: comp => {
20669 if (Toggling.isOn(comp)) {
20670 repositionMenus(comp);
20680 ...detail.eventOrder,
20684 'alloy.base.behaviour'
20687 events: buttonEvents,
20688 behaviours: augment(detail.splitDropdownBehaviours, [
20691 sandbox: hotspot => {
20692 const arrow = getPartOrDie(hotspot, detail, 'arrow');
20695 Toggling.on(arrow);
20696 Toggling.on(hotspot);
20699 Toggling.off(arrow);
20700 Toggling.off(hotspot);
20703 return makeSandbox$1(detail, hotspot, extras);
20709 onSpace: executeOnButton,
20710 onEnter: executeOnButton,
20713 Focusing.config({}),
20715 toggleOnExecute: false,
20716 aria: { mode: 'expanded' }
20721 'role': detail.role.getOr('button'),
20722 'aria-haspopup': true
20727 const SplitDropdown = composite({
20728 name: 'SplitDropdown',
20729 configFields: schema$7(),
20730 partFields: parts$3(),
20731 factory: factory$5,
20732 apis: { repositionMenus: (apis, comp) => apis.repositionMenus(comp) }
20735 const getButtonApi = component => ({
20736 isEnabled: () => !Disabling.isDisabled(component),
20737 setEnabled: state => Disabling.set(component, !state)
20739 const getToggleApi = component => ({
20740 setActive: state => {
20741 Toggling.set(component, state);
20743 isActive: () => Toggling.isOn(component),
20744 isEnabled: () => !Disabling.isDisabled(component),
20745 setEnabled: state => Disabling.set(component, !state)
20747 const getTooltipAttributes = (tooltip, providersBackstage) => tooltip.map(tooltip => ({
20748 'aria-label': providersBackstage.translate(tooltip),
20749 'title': providersBackstage.translate(tooltip)
20751 const focusButtonEvent = generate$6('focus-button');
20752 const renderCommonStructure = (icon, text, tooltip, receiver, behaviours, providersBackstage) => {
20756 classes: ['tox-tbtn'].concat(text.isSome() ? ['tox-tbtn--select'] : []),
20757 attributes: getTooltipAttributes(tooltip, providersBackstage)
20759 components: componentRenderPipeline([
20760 icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons)),
20761 text.map(text => renderLabel(text, 'tox-tbtn', providersBackstage))
20766 'alloy.base.behaviour',
20767 'common-button-display-events'
20770 buttonBehaviours: derive$1([
20771 DisablingConfigs.toolbarButton(providersBackstage.isDisabled),
20773 config('common-button-display-events', [run$1(mousedown(), (button, se) => {
20774 se.event.prevent();
20775 emit(button, focusButtonEvent);
20777 ].concat(receiver.map(r => Reflecting.config({
20783 renderComponents: (data, _state) => componentRenderPipeline([
20784 data.icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons)),
20785 data.text.map(text => renderLabel(text, 'tox-tbtn', providersBackstage))
20787 })).toArray()).concat(behaviours.getOr([])))
20790 const renderFloatingToolbarButton = (spec, backstage, identifyButtons, attributes) => {
20791 const sharedBackstage = backstage.shared;
20792 return FloatingToolbarButton.sketch({
20793 lazySink: sharedBackstage.getSink,
20794 fetch: () => Future.nu(resolve => {
20795 resolve(map$2(identifyButtons(spec.items), renderToolbarGroup));
20797 markers: { toggledClass: 'tox-tbtn--enabled' },
20799 button: renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), Optional.none(), sharedBackstage.providers),
20803 classes: ['tox-toolbar__overflow'],
20810 const renderCommonToolbarButton = (spec, specialisation, providersBackstage) => {
20811 const editorOffCell = Cell(noop);
20812 const structure = renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), Optional.none(), providersBackstage);
20813 return Button.sketch({
20814 dom: structure.dom,
20815 components: structure.components,
20816 eventOrder: toolbarButtonEventOrder,
20817 buttonBehaviours: derive$1([
20818 config('toolbar-button-events', [
20819 onToolbarButtonExecute({
20820 onAction: spec.onAction,
20821 getApi: specialisation.getApi
20823 onControlAttached(specialisation, editorOffCell),
20824 onControlDetached(specialisation, editorOffCell)
20826 DisablingConfigs.toolbarButton(() => !spec.enabled || providersBackstage.isDisabled()),
20828 ].concat(specialisation.toolbarButtonBehaviours))
20831 const renderToolbarButton = (spec, providersBackstage) => renderToolbarButtonWith(spec, providersBackstage, []);
20832 const renderToolbarButtonWith = (spec, providersBackstage, bonusEvents) => renderCommonToolbarButton(spec, {
20833 toolbarButtonBehaviours: bonusEvents.length > 0 ? [config('toolbarButtonWith', bonusEvents)] : [],
20834 getApi: getButtonApi,
20835 onSetup: spec.onSetup
20836 }, providersBackstage);
20837 const renderToolbarToggleButton = (spec, providersBackstage) => renderToolbarToggleButtonWith(spec, providersBackstage, []);
20838 const renderToolbarToggleButtonWith = (spec, providersBackstage, bonusEvents) => renderCommonToolbarButton(spec, {
20839 toolbarButtonBehaviours: [
20840 Replacing.config({}),
20842 toggleClass: 'tox-tbtn--enabled',
20843 aria: { mode: 'pressed' },
20844 toggleOnExecute: false
20846 ].concat(bonusEvents.length > 0 ? [config('toolbarToggleButtonWith', bonusEvents)] : []),
20847 getApi: getToggleApi,
20848 onSetup: spec.onSetup
20849 }, providersBackstage);
20850 const fetchChoices = (getApi, spec, providersBackstage) => comp => Future.nu(callback => spec.fetch(callback)).map(items => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6('menu-value'), items, value => {
20851 spec.onItemAction(getApi(comp), value);
20852 }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, spec.select.getOr(never), providersBackstage), {
20853 movement: deriveMenuMovement(spec.columns, spec.presets),
20854 menuBehaviours: SimpleBehaviours.unnamedEvents(spec.columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
20855 detectSize(comp, 4, classForPreset(spec.presets)).each(({numRows, numColumns}) => {
20856 Keying.setGridSize(comp, numRows, numColumns);
20860 const renderSplitButton = (spec, sharedBackstage) => {
20861 const displayChannel = generate$6('channel-update-split-dropdown-display');
20862 const getApi = comp => ({
20863 isEnabled: () => !Disabling.isDisabled(comp),
20864 setEnabled: state => Disabling.set(comp, !state),
20865 setIconFill: (id, value) => {
20866 descendant(comp.element, 'svg path[id="' + id + '"], rect[id="' + id + '"]').each(underlinePath => {
20867 set$9(underlinePath, 'fill', value);
20870 setActive: state => {
20871 set$9(comp.element, 'aria-pressed', state);
20872 descendant(comp.element, 'span').each(button => {
20873 comp.getSystem().getByDom(button).each(buttonComp => Toggling.set(buttonComp, state));
20876 isActive: () => descendant(comp.element, 'span').exists(button => comp.getSystem().getByDom(button).exists(Toggling.isOn))
20878 const editorOffCell = Cell(noop);
20879 const specialisation = {
20881 onSetup: spec.onSetup
20883 return SplitDropdown.sketch({
20886 classes: ['tox-split-button'],
20888 'aria-pressed': false,
20889 ...getTooltipAttributes(spec.tooltip, sharedBackstage.providers)
20892 onExecute: button => {
20893 spec.onAction(getApi(button));
20895 onItemExecute: (_a, _b, _c) => {
20897 splitDropdownBehaviours: derive$1([
20898 DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
20900 config('split-dropdown-events', [
20901 run$1(focusButtonEvent, Focusing.focus),
20902 onControlAttached(specialisation, editorOffCell),
20903 onControlDetached(specialisation, editorOffCell)
20905 Unselecting.config({})
20908 [attachedToDom()]: [
20909 'alloy.base.behaviour',
20910 'split-dropdown-events'
20913 toggleClass: 'tox-tbtn--enabled',
20914 lazySink: sharedBackstage.getSink,
20915 fetch: fetchChoices(getApi, spec, sharedBackstage.providers),
20916 parts: { menu: part(false, spec.columns, spec.presets) },
20918 SplitDropdown.parts.button(renderCommonStructure(spec.icon, spec.text, Optional.none(), Optional.some(displayChannel), Optional.some([Toggling.config({
20919 toggleClass: 'tox-tbtn--enabled',
20920 toggleOnExecute: false
20921 })]), sharedBackstage.providers)),
20922 SplitDropdown.parts.arrow({
20927 'tox-split-button__chevron'
20929 innerHtml: get$2('chevron-down', sharedBackstage.providers.icons)
20931 buttonBehaviours: derive$1([
20932 DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
20934 addFocusableBehaviour()
20937 SplitDropdown.parts['aria-descriptor']({ text: sharedBackstage.providers.translate('To open the popup, press Shift+Enter') })
20942 const defaultToolbar = [
20955 name: 'formatting',
20971 name: 'indentation',
20978 name: 'permanent pen',
20979 items: ['permanentpen']
20983 items: ['addcomment']
20986 const renderFromBridge = (bridgeBuilder, render) => (spec, backstage, editor) => {
20987 const internal = bridgeBuilder(spec).mapError(errInfo => formatError(errInfo)).getOrDie();
20988 return render(internal, backstage, editor);
20991 button: renderFromBridge(createToolbarButton, (s, backstage) => renderToolbarButton(s, backstage.shared.providers)),
20992 togglebutton: renderFromBridge(createToggleButton, (s, backstage) => renderToolbarToggleButton(s, backstage.shared.providers)),
20993 menubutton: renderFromBridge(createMenuButton, (s, backstage) => renderMenuButton(s, 'tox-tbtn', backstage, Optional.none())),
20994 splitbutton: renderFromBridge(createSplitButton, (s, backstage) => renderSplitButton(s, backstage.shared)),
20995 grouptoolbarbutton: renderFromBridge(createGroupToolbarButton, (s, backstage, editor) => {
20996 const buttons = editor.ui.registry.getAll().buttons;
20997 const identify = toolbar => identifyButtons(editor, {
21000 allowToolbarGroups: false
21001 }, backstage, Optional.none());
21002 const attributes = { [Attribute]: backstage.shared.header.isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop };
21003 switch (getToolbarMode(editor)) {
21004 case ToolbarMode$1.floating:
21005 return renderFloatingToolbarButton(s, backstage, identify, attributes);
21007 throw new Error('Toolbar groups are only supported when using floating toolbar mode');
21011 const extractFrom = (spec, backstage, editor) => get$g(types, spec.type).fold(() => {
21012 console.error('skipping button defined by', spec);
21013 return Optional.none();
21014 }, render => Optional.some(render(spec, backstage, editor)));
21015 const bespokeButtons = {
21016 styles: createStylesButton,
21017 fontsize: createFontSizeButton,
21018 fontfamily: createFontFamilyButton,
21019 blocks: createBlocksButton,
21020 align: createAlignButton
21022 const removeUnusedDefaults = buttons => {
21023 const filteredItemGroups = map$2(defaultToolbar, group => {
21024 const items = filter$2(group.items, subItem => has$2(buttons, subItem) || has$2(bespokeButtons, subItem));
21030 return filter$2(filteredItemGroups, group => group.items.length > 0);
21032 const convertStringToolbar = strToolbar => {
21033 const groupsStrings = strToolbar.split('|');
21034 return map$2(groupsStrings, g => ({ items: g.trim().split(' ') }));
21036 const isToolbarGroupSettingArray = toolbar => isArrayOf(toolbar, t => has$2(t, 'name') && has$2(t, 'items'));
21037 const createToolbar = toolbarConfig => {
21038 const toolbar = toolbarConfig.toolbar;
21039 const buttons = toolbarConfig.buttons;
21040 if (toolbar === false) {
21042 } else if (toolbar === undefined || toolbar === true) {
21043 return removeUnusedDefaults(buttons);
21044 } else if (isString(toolbar)) {
21045 return convertStringToolbar(toolbar);
21046 } else if (isToolbarGroupSettingArray(toolbar)) {
21049 console.error('Toolbar type should be string, string[], boolean or ToolbarGroup[]');
21053 const lookupButton = (editor, buttons, toolbarItem, allowToolbarGroups, backstage, prefixes) => get$g(buttons, toolbarItem.toLowerCase()).orThunk(() => prefixes.bind(ps => findMap(ps, prefix => get$g(buttons, prefix + toolbarItem.toLowerCase())))).fold(() => get$g(bespokeButtons, toolbarItem.toLowerCase()).map(r => r(editor, backstage)), spec => {
21054 if (spec.type === 'grouptoolbarbutton' && !allowToolbarGroups) {
21055 console.warn(`Ignoring the '${ toolbarItem }' toolbar button. Group toolbar buttons are only supported when using floating toolbar mode and cannot be nested.`);
21056 return Optional.none();
21058 return extractFrom(spec, backstage, editor);
21061 const identifyButtons = (editor, toolbarConfig, backstage, prefixes) => {
21062 const toolbarGroups = createToolbar(toolbarConfig);
21063 const groups = map$2(toolbarGroups, group => {
21064 const items = bind$3(group.items, toolbarItem => {
21065 return toolbarItem.trim().length === 0 ? [] : lookupButton(editor, toolbarConfig.buttons, toolbarItem, toolbarConfig.allowToolbarGroups, backstage, prefixes).toArray();
21068 title: Optional.from(editor.translate(group.name)),
21072 return filter$2(groups, group => group.items.length > 0);
21075 const setToolbar = (editor, uiComponents, rawUiConfig, backstage) => {
21076 const comp = uiComponents.outerContainer;
21077 const toolbarConfig = rawUiConfig.toolbar;
21078 const toolbarButtonsConfig = rawUiConfig.buttons;
21079 if (isArrayOf(toolbarConfig, isString)) {
21080 const toolbars = toolbarConfig.map(t => {
21083 buttons: toolbarButtonsConfig,
21084 allowToolbarGroups: rawUiConfig.allowToolbarGroups
21086 return identifyButtons(editor, config, backstage, Optional.none());
21088 OuterContainer.setToolbars(comp, toolbars);
21090 OuterContainer.setToolbar(comp, identifyButtons(editor, rawUiConfig, backstage, Optional.none()));
21094 const detection = detect$1();
21095 const isiOS12 = detection.os.isiOS() && detection.os.version.major <= 12;
21096 const setupEvents$1 = (editor, uiComponents) => {
21097 const dom = editor.dom;
21098 let contentWindow = editor.getWin();
21099 const initialDocEle = editor.getDoc().documentElement;
21100 const lastWindowDimensions = Cell(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
21101 const lastDocumentDimensions = Cell(SugarPosition(initialDocEle.offsetWidth, initialDocEle.offsetHeight));
21102 const resizeWindow = () => {
21103 const outer = lastWindowDimensions.get();
21104 if (outer.left !== contentWindow.innerWidth || outer.top !== contentWindow.innerHeight) {
21105 lastWindowDimensions.set(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
21106 fireResizeContent(editor);
21109 const resizeDocument = () => {
21110 const docEle = editor.getDoc().documentElement;
21111 const inner = lastDocumentDimensions.get();
21112 if (inner.left !== docEle.offsetWidth || inner.top !== docEle.offsetHeight) {
21113 lastDocumentDimensions.set(SugarPosition(docEle.offsetWidth, docEle.offsetHeight));
21114 fireResizeContent(editor);
21117 const scroll = e => {
21118 fireScrollContent(editor, e);
21120 dom.bind(contentWindow, 'resize', resizeWindow);
21121 dom.bind(contentWindow, 'scroll', scroll);
21122 const elementLoad = capture(SugarElement.fromDom(editor.getBody()), 'load', resizeDocument);
21123 const mothership = uiComponents.uiMothership.element;
21124 editor.on('hide', () => {
21125 set$8(mothership, 'display', 'none');
21127 editor.on('show', () => {
21128 remove$6(mothership, 'display');
21130 editor.on('NodeChange', resizeDocument);
21131 editor.on('remove', () => {
21132 elementLoad.unbind();
21133 dom.unbind(contentWindow, 'resize', resizeWindow);
21134 dom.unbind(contentWindow, 'scroll', scroll);
21135 contentWindow = null;
21138 const render$1 = (editor, uiComponents, rawUiConfig, backstage, args) => {
21139 const lastToolbarWidth = Cell(0);
21140 const outerContainer = uiComponents.outerContainer;
21142 const eTargetNode = SugarElement.fromDom(args.targetNode);
21143 const uiRoot = getContentContainer(getRootNode(eTargetNode));
21144 attachSystemAfter(eTargetNode, uiComponents.mothership);
21145 attachSystem(uiRoot, uiComponents.uiMothership);
21146 editor.on('PostRender', () => {
21147 OuterContainer.setSidebar(outerContainer, rawUiConfig.sidebar, getSidebarShow(editor));
21148 setToolbar(editor, uiComponents, rawUiConfig, backstage);
21149 lastToolbarWidth.set(editor.getWin().innerWidth);
21150 OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
21151 setupEvents$1(editor, uiComponents);
21153 const socket = OuterContainer.getSocket(outerContainer).getOrDie('Could not find expected socket element');
21155 setAll(socket.element, {
21156 'overflow': 'scroll',
21157 '-webkit-overflow-scrolling': 'touch'
21159 const limit = first(() => {
21160 editor.dispatch('ScrollContent');
21162 const unbinder = bind(socket.element, 'scroll', limit.throttle);
21163 editor.on('remove', unbinder.unbind);
21165 setupReadonlyModeSwitch(editor, uiComponents);
21166 editor.addCommand('ToggleSidebar', (_ui, value) => {
21167 OuterContainer.toggleSidebar(outerContainer, value);
21168 editor.dispatch('ToggleSidebar');
21170 editor.addQueryValueHandler('ToggleSidebar', () => OuterContainer.whichSidebar(outerContainer) ?? '');
21171 const toolbarMode = getToolbarMode(editor);
21172 const refreshDrawer = () => {
21173 OuterContainer.refreshToolbar(uiComponents.outerContainer);
21175 if (toolbarMode === ToolbarMode$1.sliding || toolbarMode === ToolbarMode$1.floating) {
21176 editor.on('ResizeWindow ResizeEditor ResizeContent', () => {
21177 const width = editor.getWin().innerWidth;
21178 if (width !== lastToolbarWidth.get()) {
21180 lastToolbarWidth.set(width);
21185 setEnabled: state => {
21186 broadcastReadonly(uiComponents, !state);
21188 isEnabled: () => !Disabling.isDisabled(outerContainer)
21191 iframeContainer: socket.element.dom,
21192 editorContainer: outerContainer.element.dom,
21197 var Iframe = /*#__PURE__*/Object.freeze({
21202 const parseToInt = val => {
21203 const re = /^[0-9\.]+(|px)$/i;
21204 if (re.test('' + val)) {
21205 return Optional.some(parseInt('' + val, 10));
21207 return Optional.none();
21209 const numToPx = val => isNumber(val) ? val + 'px' : val;
21210 const calcCappedSize = (size, minSize, maxSize) => {
21211 const minOverride = minSize.filter(min => size < min);
21212 const maxOverride = maxSize.filter(max => size > max);
21213 return minOverride.or(maxOverride).getOr(size);
21216 const getHeight = editor => {
21217 const baseHeight = getHeightOption(editor);
21218 const minHeight = getMinHeightOption(editor);
21219 const maxHeight = getMaxHeightOption(editor);
21220 return parseToInt(baseHeight).map(height => calcCappedSize(height, minHeight, maxHeight));
21222 const getHeightWithFallback = editor => {
21223 const height = getHeight(editor);
21224 return height.getOr(getHeightOption(editor));
21226 const getWidth = editor => {
21227 const baseWidth = getWidthOption(editor);
21228 const minWidth = getMinWidthOption(editor);
21229 const maxWidth = getMaxWidthOption(editor);
21230 return parseToInt(baseWidth).map(width => calcCappedSize(width, minWidth, maxWidth));
21232 const getWidthWithFallback = editor => {
21233 const width = getWidth(editor);
21234 return width.getOr(getWidthOption(editor));
21237 const {ToolbarLocation, ToolbarMode} = Options;
21238 const InlineHeader = (editor, targetElm, uiComponents, backstage, floatContainer) => {
21239 const {uiMothership, outerContainer} = uiComponents;
21240 const DOM = global$7.DOM;
21241 const useFixedToolbarContainer = useFixedContainer(editor);
21242 const isSticky = isStickyToolbar(editor);
21243 const editorMaxWidthOpt = getMaxWidthOption(editor).or(getWidth(editor));
21244 const headerBackstage = backstage.shared.header;
21245 const isPositionedAtTop = headerBackstage.isPositionedAtTop;
21246 const toolbarMode = getToolbarMode(editor);
21247 const isSplitToolbar = toolbarMode === ToolbarMode.sliding || toolbarMode === ToolbarMode.floating;
21248 const visible = Cell(false);
21249 const isVisible = () => visible.get() && !editor.removed;
21250 const calcToolbarOffset = toolbar => isSplitToolbar ? toolbar.fold(constant$1(0), tbar => tbar.components().length > 1 ? get$d(tbar.components()[1].element) : 0) : 0;
21251 const calcMode = container => {
21252 switch (getToolbarLocation(editor)) {
21253 case ToolbarLocation.auto:
21254 const toolbar = OuterContainer.getToolbar(outerContainer);
21255 const offset = calcToolbarOffset(toolbar);
21256 const toolbarHeight = get$d(container.element) - offset;
21257 const targetBounds = box$1(targetElm);
21258 const roomAtTop = targetBounds.y > toolbarHeight;
21262 const doc = documentElement(targetElm);
21263 const docHeight = Math.max(doc.dom.scrollHeight, get$d(doc));
21264 const roomAtBottom = targetBounds.bottom < docHeight - toolbarHeight;
21265 if (roomAtBottom) {
21268 const winBounds = win();
21269 const isRoomAtBottomViewport = winBounds.bottom < targetBounds.bottom - toolbarHeight;
21270 return isRoomAtBottomViewport ? 'bottom' : 'top';
21273 case ToolbarLocation.bottom:
21275 case ToolbarLocation.top:
21280 const setupMode = mode => {
21281 floatContainer.on(container => {
21282 Docking.setModes(container, [mode]);
21283 headerBackstage.setDockingMode(mode);
21284 const verticalDir = isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop;
21285 set$9(container.element, Attribute, verticalDir);
21288 const updateChromeWidth = () => {
21289 floatContainer.on(container => {
21290 const maxWidth = editorMaxWidthOpt.getOrThunk(() => {
21291 const bodyMargin = parseToInt(get$e(body(), 'margin-left')).getOr(0);
21292 return get$c(body()) - absolute$3(targetElm).left + bodyMargin;
21294 set$8(container.element, 'max-width', maxWidth + 'px');
21297 const updateChromePosition = () => {
21298 floatContainer.on(container => {
21299 const toolbar = OuterContainer.getToolbar(outerContainer);
21300 const offset = calcToolbarOffset(toolbar);
21301 const targetBounds = box$1(targetElm);
21302 const top = isPositionedAtTop() ? Math.max(targetBounds.y - get$d(container.element) + offset, 0) : targetBounds.bottom;
21303 setAll(outerContainer.element, {
21304 position: 'absolute',
21305 top: Math.round(top) + 'px',
21306 left: Math.round(targetBounds.x) + 'px'
21310 const repositionPopups$1 = () => {
21311 uiMothership.broadcastOn([repositionPopups()], {});
21313 const updateChromeUi = (resetDocking = false) => {
21314 if (!isVisible()) {
21317 if (!useFixedToolbarContainer) {
21318 updateChromeWidth();
21320 if (isSplitToolbar) {
21321 OuterContainer.refreshToolbar(outerContainer);
21323 if (!useFixedToolbarContainer) {
21324 updateChromePosition();
21327 const action = resetDocking ? Docking.reset : Docking.refresh;
21328 floatContainer.on(action);
21330 repositionPopups$1();
21332 const updateMode = (updateUi = true) => {
21333 if (useFixedToolbarContainer || !isSticky || !isVisible()) {
21336 floatContainer.on(container => {
21337 const currentMode = headerBackstage.getDockingMode();
21338 const newMode = calcMode(container);
21339 if (newMode !== currentMode) {
21340 setupMode(newMode);
21342 updateChromeUi(true);
21347 const show = () => {
21349 set$8(outerContainer.element, 'display', 'flex');
21350 DOM.addClass(editor.getBody(), 'mce-edit-focus');
21351 remove$6(uiMothership.element, 'display');
21355 const hide = () => {
21356 visible.set(false);
21357 if (uiComponents.outerContainer) {
21358 set$8(outerContainer.element, 'display', 'none');
21359 DOM.removeClass(editor.getBody(), 'mce-edit-focus');
21361 set$8(uiMothership.element, 'display', 'none');
21368 update: updateChromeUi,
21370 repositionPopups: repositionPopups$1
21374 const getTargetPosAndBounds = (targetElm, isToolbarTop) => {
21375 const bounds = box$1(targetElm);
21377 pos: isToolbarTop ? bounds.y : bounds.bottom,
21381 const setupEvents = (editor, targetElm, ui, toolbarPersist) => {
21382 const prevPosAndBounds = Cell(getTargetPosAndBounds(targetElm, ui.isPositionedAtTop()));
21383 const resizeContent = e => {
21384 const {pos, bounds} = getTargetPosAndBounds(targetElm, ui.isPositionedAtTop());
21388 } = prevPosAndBounds.get();
21389 const hasResized = bounds.height !== prevBounds.height || bounds.width !== prevBounds.width;
21390 prevPosAndBounds.set({
21395 fireResizeContent(editor, e);
21397 if (ui.isVisible()) {
21398 if (prevPos !== pos) {
21400 } else if (hasResized) {
21402 ui.repositionPopups();
21406 if (!toolbarPersist) {
21407 editor.on('activate', ui.show);
21408 editor.on('deactivate', ui.hide);
21410 editor.on('SkinLoaded ResizeWindow', () => ui.update(true));
21411 editor.on('NodeChange keydown', e => {
21412 requestAnimationFrame(() => resizeContent(e));
21414 editor.on('ScrollWindow', () => ui.updateMode());
21415 const elementLoad = unbindable();
21416 elementLoad.set(capture(SugarElement.fromDom(editor.getBody()), 'load', e => resizeContent(e.raw)));
21417 editor.on('remove', () => {
21418 elementLoad.clear();
21421 const render = (editor, uiComponents, rawUiConfig, backstage, args) => {
21422 const {mothership, uiMothership, outerContainer} = uiComponents;
21423 const floatContainer = value$2();
21424 const targetElm = SugarElement.fromDom(args.targetNode);
21425 const ui = InlineHeader(editor, targetElm, uiComponents, backstage, floatContainer);
21426 const toolbarPersist = isToolbarPersist(editor);
21428 const render = () => {
21429 if (floatContainer.isSet()) {
21433 floatContainer.set(OuterContainer.getHeader(outerContainer).getOrDie());
21434 const uiContainer = getUiContainer(editor);
21435 attachSystem(uiContainer, mothership);
21436 attachSystem(uiContainer, uiMothership);
21437 setToolbar(editor, uiComponents, rawUiConfig, backstage);
21438 OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
21440 setupEvents(editor, targetElm, ui, toolbarPersist);
21441 editor.nodeChanged();
21443 editor.on('show', render);
21444 editor.on('hide', ui.hide);
21445 if (!toolbarPersist) {
21446 editor.on('focus', render);
21447 editor.on('blur', ui.hide);
21449 editor.on('init', () => {
21450 if (editor.hasFocus() || toolbarPersist) {
21454 setupReadonlyModeSwitch(editor, uiComponents);
21458 setEnabled: state => {
21459 broadcastReadonly(uiComponents, !state);
21461 isEnabled: () => !Disabling.isDisabled(outerContainer)
21464 editorContainer: outerContainer.element.dom,
21469 var Inline = /*#__PURE__*/Object.freeze({
21474 const showContextToolbarEvent = 'contexttoolbar-show';
21475 const hideContextToolbarEvent = 'contexttoolbar-hide';
21477 const getFormApi = input => ({
21478 hide: () => emit(input, sandboxClose()),
21479 getValue: () => Representing.getValue(input)
21481 const runOnExecute = (memInput, original) => run$1(internalToolbarButtonExecute, (comp, se) => {
21482 const input = memInput.get(comp);
21483 const formApi = getFormApi(input);
21484 original.onAction(formApi, se.event.buttonApi);
21486 const renderContextButton = (memInput, button, providers) => {
21487 const {primary, ...rest} = button.original;
21488 const bridged = getOrDie(createToolbarButton({
21493 return renderToolbarButtonWith(bridged, providers, [runOnExecute(memInput, button)]);
21495 const renderContextToggleButton = (memInput, button, providers) => {
21496 const {primary, ...rest} = button.original;
21497 const bridged = getOrDie(createToggleButton({
21499 type: 'togglebutton',
21502 return renderToolbarToggleButtonWith(bridged, providers, [runOnExecute(memInput, button)]);
21504 const isToggleButton = button => button.type === 'contextformtogglebutton';
21505 const generateOne = (memInput, button, providersBackstage) => {
21506 if (isToggleButton(button)) {
21507 return renderContextToggleButton(memInput, button, providersBackstage);
21509 return renderContextButton(memInput, button, providersBackstage);
21512 const generate = (memInput, buttons, providersBackstage) => {
21513 const mementos = map$2(buttons, button => record(generateOne(memInput, button, providersBackstage)));
21514 const asSpecs = () => map$2(mementos, mem => mem.asSpec());
21515 const findPrimary = compInSystem => findMap(buttons, (button, i) => {
21516 if (button.primary) {
21517 return Optional.from(mementos[i]).bind(mem => mem.getOpt(compInSystem)).filter(not(Disabling.isDisabled));
21519 return Optional.none();
21528 const buildInitGroups = (ctx, providers) => {
21529 const inputAttributes = ctx.label.fold(() => ({}), label => ({ 'aria-label': label }));
21530 const memInput = record(Input.sketch({
21532 'tox-toolbar-textfield',
21533 'tox-toolbar-nav-js'
21535 data: ctx.initValue(),
21537 selectOnFocus: true,
21538 inputBehaviours: derive$1([Keying.config({
21540 onEnter: input => commands.findPrimary(input).map(primary => {
21541 emitExecute(primary);
21544 onLeft: (comp, se) => {
21546 return Optional.none();
21548 onRight: (comp, se) => {
21550 return Optional.none();
21554 const commands = generate(memInput, ctx.commands, providers);
21557 title: Optional.none(),
21558 items: [memInput.asSpec()]
21561 title: Optional.none(),
21562 items: commands.asSpecs()
21566 const renderContextForm = (toolbarType, ctx, providers) => renderToolbar({
21568 uid: generate$6('context-toolbar'),
21569 initGroups: buildInitGroups(ctx, providers),
21570 onEscape: Optional.none,
21571 cyclicKeying: true,
21574 const ContextForm = {
21579 const isVerticalOverlap = (a, b, threshold = 0.01) => b.bottom - a.y >= threshold && a.bottom - b.y >= threshold;
21580 const getRangeRect = rng => {
21581 const rect = rng.getBoundingClientRect();
21582 if (rect.height <= 0 && rect.width <= 0) {
21583 const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset).element;
21584 const elm = isText(leaf$1) ? parent(leaf$1) : Optional.some(leaf$1);
21585 return elm.filter(isElement$1).map(e => e.dom.getBoundingClientRect()).getOr(rect);
21590 const getSelectionBounds = editor => {
21591 const rng = editor.selection.getRng();
21592 const rect = getRangeRect(rng);
21593 if (editor.inline) {
21594 const scroll = get$b();
21595 return bounds(scroll.left + rect.left, scroll.top + rect.top, rect.width, rect.height);
21597 const bodyPos = absolute$2(SugarElement.fromDom(editor.getBody()));
21598 return bounds(bodyPos.x + rect.left, bodyPos.y + rect.top, rect.width, rect.height);
21601 const getAnchorElementBounds = (editor, lastElement) => lastElement.filter(elem => inBody(elem) && isHTMLElement(elem)).map(absolute$2).getOrThunk(() => getSelectionBounds(editor));
21602 const getHorizontalBounds = (contentAreaBox, viewportBounds, margin) => {
21603 const x = Math.max(contentAreaBox.x + margin, viewportBounds.x);
21604 const right = Math.min(contentAreaBox.right - margin, viewportBounds.right);
21610 const getVerticalBounds = (editor, contentAreaBox, viewportBounds, isToolbarLocationTop, toolbarType, margin) => {
21611 const container = SugarElement.fromDom(editor.getContainer());
21612 const header = descendant(container, '.tox-editor-header').getOr(container);
21613 const headerBox = box$1(header);
21614 const isToolbarBelowContentArea = headerBox.y >= contentAreaBox.bottom;
21615 const isToolbarAbove = isToolbarLocationTop && !isToolbarBelowContentArea;
21616 if (editor.inline && isToolbarAbove) {
21618 y: Math.max(headerBox.bottom + margin, viewportBounds.y),
21619 bottom: viewportBounds.bottom
21622 if (editor.inline && !isToolbarAbove) {
21624 y: viewportBounds.y,
21625 bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
21628 const containerBounds = toolbarType === 'line' ? box$1(container) : contentAreaBox;
21629 if (isToolbarAbove) {
21631 y: Math.max(headerBox.bottom + margin, viewportBounds.y),
21632 bottom: Math.min(containerBounds.bottom - margin, viewportBounds.bottom)
21636 y: Math.max(containerBounds.y + margin, viewportBounds.y),
21637 bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
21640 const getContextToolbarBounds = (editor, sharedBackstage, toolbarType, margin = 0) => {
21641 const viewportBounds = getBounds$3(window);
21642 const contentAreaBox = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
21643 const toolbarOrMenubarEnabled = isMenubarEnabled(editor) || isToolbarEnabled(editor) || isMultipleToolbars(editor);
21644 const {x, width} = getHorizontalBounds(contentAreaBox, viewportBounds, margin);
21645 if (editor.inline && !toolbarOrMenubarEnabled) {
21646 return bounds(x, viewportBounds.y, width, viewportBounds.height);
21648 const isToolbarTop = sharedBackstage.header.isPositionedAtTop();
21649 const {y, bottom} = getVerticalBounds(editor, contentAreaBox, viewportBounds, isToolbarTop, toolbarType, margin);
21650 return bounds(x, y, width, bottom - y);
21654 const bubbleSize$1 = 12;
21655 const bubbleAlignments$1 = {
21658 alignLeft: ['tox-pop--align-left'],
21659 alignRight: ['tox-pop--align-right'],
21660 right: ['tox-pop--right'],
21661 left: ['tox-pop--left'],
21662 bottom: ['tox-pop--bottom'],
21663 top: ['tox-pop--top'],
21664 inset: ['tox-pop--inset']
21666 const anchorOverrides = {
21667 maxHeightFunction: expandable$1(),
21668 maxWidthFunction: expandable()
21670 const isEntireElementSelected = (editor, elem) => {
21671 const rng = editor.selection.getRng();
21672 const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset);
21673 return rng.startContainer === rng.endContainer && rng.startOffset === rng.endOffset - 1 && eq(leaf$1.element, elem);
21675 const preservePosition = (elem, position, f) => {
21676 const currentPosition = getRaw(elem, 'position');
21677 set$8(elem, 'position', position);
21678 const result = f(elem);
21679 currentPosition.each(pos => set$8(elem, 'position', pos));
21682 const shouldUseInsetLayouts = position => position === 'node';
21683 const determineInsetLayout = (editor, contextbar, elem, data, bounds) => {
21684 const selectionBounds = getSelectionBounds(editor);
21685 const isSameAnchorElement = data.lastElement().exists(prev => eq(elem, prev));
21686 if (isEntireElementSelected(editor, elem)) {
21687 return isSameAnchorElement ? preserve : north;
21688 } else if (isSameAnchorElement) {
21689 return preservePosition(contextbar, data.getMode(), () => {
21690 const isOverlapping = isVerticalOverlap(selectionBounds, box$1(contextbar));
21691 return isOverlapping && !data.isReposition() ? flip : preserve;
21694 const yBounds = data.getMode() === 'fixed' ? bounds.y + get$b().top : bounds.y;
21695 const contextbarHeight = get$d(contextbar) + bubbleSize$1;
21696 return yBounds + contextbarHeight <= selectionBounds.y ? north : south;
21699 const getAnchorSpec$2 = (editor, mobile, data, position) => {
21700 const smartInsetLayout = elem => (anchor, element, bubbles, placee, bounds) => {
21701 const layout = determineInsetLayout(editor, placee, elem, data, bounds);
21702 const newAnchor = {
21705 height: bounds.height
21708 ...layout(newAnchor, element, bubbles, placee, bounds),
21712 const getInsetLayouts = elem => shouldUseInsetLayouts(position) ? [smartInsetLayout(elem)] : [];
21713 const desktopAnchorSpecLayouts = {
21721 ].concat(getInsetLayouts(elem)),
21729 ].concat(getInsetLayouts(elem))
21731 const mobileAnchorSpecLayouts = {
21739 ].concat(getInsetLayouts(elem)),
21747 ].concat(getInsetLayouts(elem))
21749 return mobile ? mobileAnchorSpecLayouts : desktopAnchorSpecLayouts;
21751 const getAnchorLayout = (editor, position, isTouch, data) => {
21752 if (position === 'line') {
21754 bubble: nu$5(bubbleSize$1, 0, bubbleAlignments$1),
21756 onLtr: () => [east$2],
21757 onRtl: () => [west$2]
21759 overrides: anchorOverrides
21763 bubble: nu$5(0, bubbleSize$1, bubbleAlignments$1, 1 / bubbleSize$1),
21764 layouts: getAnchorSpec$2(editor, isTouch, data, position),
21765 overrides: anchorOverrides
21770 const matchTargetWith = (elem, candidates) => {
21771 const ctxs = filter$2(candidates, toolbarApi => toolbarApi.predicate(elem.dom));
21772 const {pass, fail} = partition$3(ctxs, t => t.type === 'contexttoolbar');
21774 contextToolbars: pass,
21778 const filterByPositionForStartNode = toolbars => {
21779 if (toolbars.length <= 1) {
21782 const doesPositionExist = value => exists(toolbars, t => t.position === value);
21783 const filterToolbarsByPosition = value => filter$2(toolbars, t => t.position === value);
21784 const hasSelectionToolbars = doesPositionExist('selection');
21785 const hasNodeToolbars = doesPositionExist('node');
21786 if (hasSelectionToolbars || hasNodeToolbars) {
21787 if (hasNodeToolbars && hasSelectionToolbars) {
21788 const nodeToolbars = filterToolbarsByPosition('node');
21789 const selectionToolbars = map$2(filterToolbarsByPosition('selection'), t => ({
21793 return nodeToolbars.concat(selectionToolbars);
21795 return hasSelectionToolbars ? filterToolbarsByPosition('selection') : filterToolbarsByPosition('node');
21798 return filterToolbarsByPosition('line');
21802 const filterByPositionForAncestorNode = toolbars => {
21803 if (toolbars.length <= 1) {
21806 const findPosition = value => find$5(toolbars, t => t.position === value);
21807 const basePosition = findPosition('selection').orThunk(() => findPosition('node')).orThunk(() => findPosition('line')).map(t => t.position);
21808 return basePosition.fold(() => [], pos => filter$2(toolbars, t => t.position === pos));
21811 const matchStartNode = (elem, nodeCandidates, editorCandidates) => {
21812 const nodeMatches = matchTargetWith(elem, nodeCandidates);
21813 if (nodeMatches.contextForms.length > 0) {
21814 return Optional.some({
21816 toolbars: [nodeMatches.contextForms[0]]
21819 const editorMatches = matchTargetWith(elem, editorCandidates);
21820 if (editorMatches.contextForms.length > 0) {
21821 return Optional.some({
21823 toolbars: [editorMatches.contextForms[0]]
21825 } else if (nodeMatches.contextToolbars.length > 0 || editorMatches.contextToolbars.length > 0) {
21826 const toolbars = filterByPositionForStartNode(nodeMatches.contextToolbars.concat(editorMatches.contextToolbars));
21827 return Optional.some({
21832 return Optional.none();
21836 const matchAncestor = (isRoot, startNode, scopes) => {
21837 if (isRoot(startNode)) {
21838 return Optional.none();
21840 return ancestor$2(startNode, ancestorElem => {
21841 if (isElement$1(ancestorElem)) {
21842 const {contextToolbars, contextForms} = matchTargetWith(ancestorElem, scopes.inNodeScope);
21843 const toolbars = contextForms.length > 0 ? contextForms : filterByPositionForAncestorNode(contextToolbars);
21844 return toolbars.length > 0 ? Optional.some({
21845 elem: ancestorElem,
21847 }) : Optional.none();
21849 return Optional.none();
21854 const lookup$1 = (scopes, editor) => {
21855 const rootElem = SugarElement.fromDom(editor.getBody());
21856 const isRoot = elem => eq(elem, rootElem);
21857 const isOutsideRoot = startNode => !isRoot(startNode) && !contains(rootElem, startNode);
21858 const startNode = SugarElement.fromDom(editor.selection.getNode());
21859 if (isOutsideRoot(startNode)) {
21860 return Optional.none();
21862 return matchStartNode(startNode, scopes.inNodeScope, scopes.inEditorScope).orThunk(() => matchAncestor(isRoot, startNode, scopes));
21865 const categorise = (contextToolbars, navigate) => {
21867 const inNodeScope = [];
21868 const inEditorScope = [];
21869 const formNavigators = {};
21870 const lookupTable = {};
21871 const registerForm = (key, toolbarSpec) => {
21872 const contextForm = getOrDie(createContextForm(toolbarSpec));
21873 forms[key] = contextForm;
21874 contextForm.launch.map(launch => {
21875 formNavigators['form:' + key + ''] = {
21876 ...toolbarSpec.launch,
21877 type: launch.type === 'contextformtogglebutton' ? 'togglebutton' : 'button',
21879 navigate(contextForm);
21883 if (contextForm.scope === 'editor') {
21884 inEditorScope.push(contextForm);
21886 inNodeScope.push(contextForm);
21888 lookupTable[key] = contextForm;
21890 const registerToolbar = (key, toolbarSpec) => {
21891 createContextToolbar(toolbarSpec).each(contextToolbar => {
21892 if (toolbarSpec.scope === 'editor') {
21893 inEditorScope.push(contextToolbar);
21895 inNodeScope.push(contextToolbar);
21897 lookupTable[key] = contextToolbar;
21900 const keys$1 = keys(contextToolbars);
21901 each$1(keys$1, key => {
21902 const toolbarApi = contextToolbars[key];
21903 if (toolbarApi.type === 'contextform') {
21904 registerForm(key, toolbarApi);
21905 } else if (toolbarApi.type === 'contexttoolbar') {
21906 registerToolbar(key, toolbarApi);
21918 const forwardSlideEvent = generate$6('forward-slide');
21919 const backSlideEvent = generate$6('backward-slide');
21920 const changeSlideEvent = generate$6('change-slide-event');
21921 const resizingClass = 'tox-pop--resizing';
21922 const renderContextToolbar = spec => {
21923 const stack = Cell([]);
21924 return InlineView.sketch({
21927 classes: ['tox-pop']
21929 fireDismissalEventInstead: { event: 'doNotDismissYet' },
21932 InlineView.getContent(comp).each(c => {
21933 remove$6(c.element, 'visibility');
21935 remove$2(comp.element, resizingClass);
21936 remove$6(comp.element, 'width');
21938 inlineBehaviours: derive$1([
21939 config('context-toolbar-events', [
21940 runOnSource(transitionend(), (comp, se) => {
21941 if (se.event.raw.propertyName === 'width') {
21942 remove$2(comp.element, resizingClass);
21943 remove$6(comp.element, 'width');
21946 run$1(changeSlideEvent, (comp, se) => {
21947 const elem = comp.element;
21948 remove$6(elem, 'width');
21949 const currentWidth = get$c(elem);
21950 InlineView.setContent(comp, se.event.contents);
21951 add$2(elem, resizingClass);
21952 const newWidth = get$c(elem);
21953 set$8(elem, 'width', currentWidth + 'px');
21954 InlineView.getContent(comp).each(newContents => {
21955 se.event.focus.bind(f => {
21957 return search(elem);
21959 Keying.focusIn(newContents);
21960 return active$1(getRootNode(elem));
21964 set$8(comp.element, 'width', newWidth + 'px');
21967 run$1(forwardSlideEvent, (comp, se) => {
21968 InlineView.getContent(comp).each(oldContents => {
21969 stack.set(stack.get().concat([{
21971 focus: active$1(getRootNode(comp.element))
21974 emitWith(comp, changeSlideEvent, {
21975 contents: se.event.forwardContents,
21976 focus: Optional.none()
21979 run$1(backSlideEvent, (comp, _se) => {
21980 last$1(stack.get()).each(last => {
21981 stack.set(stack.get().slice(0, stack.get().length - 1));
21982 emitWith(comp, changeSlideEvent, {
21983 contents: premade(last.bar),
21991 onEscape: comp => last$1(stack.get()).fold(() => spec.onEscape(), _ => {
21992 emit(comp, backSlideEvent);
21993 return Optional.some(true);
21997 lazySink: () => Result.value(spec.sink)
22001 const transitionClass = 'tox-pop--transition';
22002 const register$9 = (editor, registryContextToolbars, sink, extras) => {
22003 const backstage = extras.backstage;
22004 const sharedBackstage = backstage.shared;
22005 const isTouch = detect$1().deviceType.isTouch;
22006 const lastElement = value$2();
22007 const lastTrigger = value$2();
22008 const lastContextPosition = value$2();
22009 const contextbar = build$1(renderContextToolbar({
22013 return Optional.some(true);
22016 const getBounds = () => {
22017 const position = lastContextPosition.get().getOr('node');
22018 const margin = shouldUseInsetLayouts(position) ? 1 : 0;
22019 return getContextToolbarBounds(editor, sharedBackstage, position, margin);
22021 const canLaunchToolbar = () => {
22022 return !editor.removed && !(isTouch() && backstage.isContextMenuOpen());
22024 const isSameLaunchElement = elem => is$1(lift2(elem, lastElement.get(), eq), true);
22025 const shouldContextToolbarHide = () => {
22026 if (!canLaunchToolbar()) {
22029 const contextToolbarBounds = getBounds();
22030 const anchorBounds = is$1(lastContextPosition.get(), 'node') ? getAnchorElementBounds(editor, lastElement.get()) : getSelectionBounds(editor);
22031 return contextToolbarBounds.height <= 0 || !isVerticalOverlap(anchorBounds, contextToolbarBounds);
22034 const close = () => {
22035 lastElement.clear();
22036 lastTrigger.clear();
22037 lastContextPosition.clear();
22038 InlineView.hide(contextbar);
22040 const hideOrRepositionIfNecessary = () => {
22041 if (InlineView.isOpen(contextbar)) {
22042 const contextBarEle = contextbar.element;
22043 remove$6(contextBarEle, 'display');
22044 if (shouldContextToolbarHide()) {
22045 set$8(contextBarEle, 'display', 'none');
22047 lastTrigger.set(0);
22048 InlineView.reposition(contextbar);
22052 const wrapInPopDialog = toolbarSpec => ({
22055 classes: ['tox-pop__dialog']
22057 components: [toolbarSpec],
22058 behaviours: derive$1([
22059 Keying.config({ mode: 'acyclic' }),
22060 config('pop-dialog-wrap-events', [
22061 runOnAttached(comp => {
22062 editor.shortcuts.add('ctrl+F9', 'focus statusbar', () => Keying.focusIn(comp));
22064 runOnDetached(_comp => {
22065 editor.shortcuts.remove('ctrl+F9');
22070 const getScopes = cached(() => categorise(registryContextToolbars, toolbarApi => {
22071 const alloySpec = buildToolbar([toolbarApi]);
22072 emitWith(contextbar, forwardSlideEvent, { forwardContents: wrapInPopDialog(alloySpec) });
22074 const buildContextToolbarGroups = (allButtons, ctx) => identifyButtons(editor, {
22075 buttons: allButtons,
22076 toolbar: ctx.items,
22077 allowToolbarGroups: false
22078 }, extras.backstage, Optional.some(['form:']));
22079 const buildContextFormGroups = (ctx, providers) => ContextForm.buildInitGroups(ctx, providers);
22080 const buildToolbar = toolbars => {
22081 const {buttons} = editor.ui.registry.getAll();
22082 const scopes = getScopes();
22083 const allButtons = {
22085 ...scopes.formNavigators
22087 const toolbarType = getToolbarMode(editor) === ToolbarMode$1.scrolling ? ToolbarMode$1.scrolling : ToolbarMode$1.default;
22088 const initGroups = flatten(map$2(toolbars, ctx => ctx.type === 'contexttoolbar' ? buildContextToolbarGroups(allButtons, ctx) : buildContextFormGroups(ctx, sharedBackstage.providers)));
22089 return renderToolbar({
22091 uid: generate$6('context-toolbar'),
22093 onEscape: Optional.none,
22094 cyclicKeying: true,
22095 providers: sharedBackstage.providers
22098 const getAnchor = (position, element) => {
22099 const anchorage = position === 'node' ? sharedBackstage.anchors.node(element) : sharedBackstage.anchors.cursor();
22100 const anchorLayout = getAnchorLayout(editor, position, isTouch(), {
22101 lastElement: lastElement.get,
22102 isReposition: () => is$1(lastTrigger.get(), 0),
22103 getMode: () => Positioning.getMode(sink)
22105 return deepMerge(anchorage, anchorLayout);
22107 const launchContext = (toolbarApi, elem) => {
22108 launchContextToolbar.cancel();
22109 if (!canLaunchToolbar()) {
22112 const toolbarSpec = buildToolbar(toolbarApi);
22113 const position = toolbarApi[0].position;
22114 const anchor = getAnchor(position, elem);
22115 lastContextPosition.set(position);
22116 lastTrigger.set(1);
22117 const contextBarEle = contextbar.element;
22118 remove$6(contextBarEle, 'display');
22119 if (!isSameLaunchElement(elem)) {
22120 remove$2(contextBarEle, transitionClass);
22121 Positioning.reset(sink, contextbar);
22123 InlineView.showWithinBounds(contextbar, wrapInPopDialog(toolbarSpec), {
22126 classes: [transitionClass],
22129 }, () => Optional.some(getBounds()));
22130 elem.fold(lastElement.clear, lastElement.set);
22131 if (shouldContextToolbarHide()) {
22132 set$8(contextBarEle, 'display', 'none');
22135 const launchContextToolbar = last(() => {
22136 if (!editor.hasFocus() || editor.removed) {
22139 if (has(contextbar.element, transitionClass)) {
22140 launchContextToolbar.throttle();
22142 const scopes = getScopes();
22143 lookup$1(scopes, editor).fold(close, info => {
22144 launchContext(info.toolbars, Optional.some(info.elem));
22148 editor.on('init', () => {
22149 editor.on('remove', close);
22150 editor.on('ScrollContent ScrollWindow ObjectResized ResizeEditor longpress', hideOrRepositionIfNecessary);
22151 editor.on('click keyup focus SetContent', launchContextToolbar.throttle);
22152 editor.on(hideContextToolbarEvent, close);
22153 editor.on(showContextToolbarEvent, e => {
22154 const scopes = getScopes();
22155 get$g(scopes.lookupTable, e.toolbarKey).each(ctx => {
22156 launchContext([ctx], someIf(e.target !== editor, e.target));
22157 InlineView.getContent(contextbar).each(Keying.focusIn);
22160 editor.on('focusout', _e => {
22161 global$9.setEditorTimeout(editor, () => {
22162 if (search(sink.element).isNone() && search(contextbar.element).isNone()) {
22167 editor.on('SwitchMode', () => {
22168 if (editor.mode.isReadOnly()) {
22172 editor.on('AfterProgressState', event => {
22175 } else if (editor.hasFocus()) {
22176 launchContextToolbar.throttle();
22179 editor.on('NodeChange', _e => {
22180 search(contextbar.element).fold(launchContextToolbar.throttle, noop);
22185 const register$8 = editor => {
22186 const alignToolbarButtons = [
22189 text: 'Align left',
22190 cmd: 'JustifyLeft',
22194 name: 'aligncenter',
22195 text: 'Align center',
22196 cmd: 'JustifyCenter',
22197 icon: 'align-center'
22200 name: 'alignright',
22201 text: 'Align right',
22202 cmd: 'JustifyRight',
22203 icon: 'align-right'
22206 name: 'alignjustify',
22208 cmd: 'JustifyFull',
22209 icon: 'align-justify'
22212 each$1(alignToolbarButtons, item => {
22213 editor.ui.registry.addToggleButton(item.name, {
22214 tooltip: item.text,
22216 onAction: onActionExecCommand(editor, item.cmd),
22217 onSetup: onSetupFormatToggle(editor, item.name)
22220 editor.ui.registry.addButton('alignnone', {
22221 tooltip: 'No alignment',
22222 icon: 'align-none',
22223 onAction: onActionExecCommand(editor, 'JustifyNone')
22228 unsupportedLength: [
22258 const pattern = (() => {
22259 const decimalDigits = '[0-9]+';
22260 const signedInteger = '[+-]?' + decimalDigits;
22261 const exponentPart = '[eE]' + signedInteger;
22263 const opt = input => `(?:${ input })?`;
22264 const unsignedDecimalLiteral = [
22266 decimalDigits + dot + opt(decimalDigits) + opt(exponentPart),
22267 dot + decimalDigits + opt(exponentPart),
22268 decimalDigits + opt(exponentPart)
22270 const float = `[+-]?(?:${ unsignedDecimalLiteral })`;
22271 return new RegExp(`^(${ float })(.*)$`);
22273 const isUnit = (unit, accepted) => exists(accepted, acc => exists(units[acc], check => unit === check));
22274 const parse = (input, accepted) => {
22275 const match = Optional.from(pattern.exec(input));
22276 return match.bind(array => {
22277 const value = Number(array[1]);
22278 const unitRaw = array[2];
22279 if (isUnit(unitRaw, accepted)) {
22280 return Optional.some({
22285 return Optional.none();
22289 const normalise = (input, accepted) => parse(input, accepted).map(({value, unit}) => value + unit);
22291 const registerController = (editor, spec) => {
22292 const getMenuItems = () => {
22293 const options = spec.getOptions(editor);
22294 const initial = spec.getCurrent(editor).map(spec.hash);
22295 const current = value$2();
22296 return map$2(options, value => ({
22297 type: 'togglemenuitem',
22298 text: spec.display(value),
22300 const setActive = active => {
22302 current.on(oldApi => oldApi.setActive(false));
22305 api.setActive(active);
22307 setActive(is$1(initial, spec.hash(value)));
22308 const unbindWatcher = spec.watcher(editor, value, setActive);
22314 onAction: () => spec.setCurrent(editor, value)
22317 editor.ui.registry.addMenuButton(spec.name, {
22318 tooltip: spec.text,
22320 fetch: callback => callback(getMenuItems()),
22321 onSetup: spec.onToolbarSetup
22323 editor.ui.registry.addNestedMenuItem(spec.name, {
22324 type: 'nestedmenuitem',
22326 getSubmenuItems: getMenuItems,
22327 onSetup: spec.onMenuSetup
22330 const lineHeightSpec = {
22331 name: 'lineheight',
22332 text: 'Line height',
22333 icon: 'line-height',
22334 getOptions: getLineHeightFormats,
22335 hash: input => normalise(input, [
22341 watcher: (editor, value, callback) => editor.formatter.formatChanged('lineheight', callback, false, { value }).unbind,
22342 getCurrent: editor => Optional.from(editor.queryCommandValue('LineHeight')),
22343 setCurrent: (editor, value) => editor.execCommand('LineHeight', false, value)
22345 const languageSpec = editor => {
22346 const settingsOpt = Optional.from(getContentLanguages(editor));
22347 return settingsOpt.map(settings => ({
22351 getOptions: constant$1(settings),
22352 hash: input => isUndefined(input.customCode) ? input.code : `${ input.code }/${ input.customCode }`,
22353 display: input => input.title,
22354 watcher: (editor, value, callback) => editor.formatter.formatChanged('lang', callback, false, {
22356 customValue: value.customCode ?? null
22358 getCurrent: editor => {
22359 const node = SugarElement.fromDom(editor.selection.getNode());
22360 return closest$4(node, n => Optional.some(n).filter(isElement$1).bind(ele => {
22361 const codeOpt = getOpt(ele, 'lang');
22362 return codeOpt.map(code => {
22363 const customCode = getOpt(ele, 'data-mce-lang').getOrUndefined();
22372 setCurrent: (editor, lang) => editor.execCommand('Lang', false, lang),
22373 onToolbarSetup: api => {
22374 const unbinder = unbindable();
22375 api.setActive(editor.formatter.match('lang', {}, undefined, true));
22376 unbinder.set(editor.formatter.formatChanged('lang', api.setActive, true));
22377 return unbinder.clear;
22381 const register$7 = editor => {
22382 registerController(editor, lineHeightSpec);
22383 languageSpec(editor).each(spec => registerController(editor, spec));
22386 const register$6 = (editor, backstage) => {
22387 createAlignMenu(editor, backstage);
22388 createFontFamilyMenu(editor, backstage);
22389 createStylesMenu(editor, backstage);
22390 createBlocksMenu(editor, backstage);
22391 createFontSizeMenu(editor, backstage);
22394 const onSetupOutdentState = editor => onSetupEvent(editor, 'NodeChange', api => {
22395 api.setEnabled(editor.queryCommandState('outdent'));
22397 const registerButtons$2 = editor => {
22398 editor.ui.registry.addButton('outdent', {
22399 tooltip: 'Decrease indent',
22401 onSetup: onSetupOutdentState(editor),
22402 onAction: onActionExecCommand(editor, 'outdent')
22404 editor.ui.registry.addButton('indent', {
22405 tooltip: 'Increase indent',
22407 onAction: onActionExecCommand(editor, 'indent')
22410 const register$5 = editor => {
22411 registerButtons$2(editor);
22414 const makeSetupHandler = (editor, pasteAsText) => api => {
22415 api.setActive(pasteAsText.get());
22416 const pastePlainTextToggleHandler = e => {
22417 pasteAsText.set(e.state);
22418 api.setActive(e.state);
22420 editor.on('PastePlainTextToggle', pastePlainTextToggleHandler);
22421 return () => editor.off('PastePlainTextToggle', pastePlainTextToggleHandler);
22423 const register$4 = editor => {
22424 const pasteAsText = Cell(getPasteAsText(editor));
22425 const onAction = () => editor.execCommand('mceTogglePlainTextPaste');
22426 editor.ui.registry.addToggleButton('pastetext', {
22428 icon: 'paste-text',
22429 tooltip: 'Paste as text',
22431 onSetup: makeSetupHandler(editor, pasteAsText)
22433 editor.ui.registry.addToggleMenuItem('pastetext', {
22434 text: 'Paste as text',
22435 icon: 'paste-text',
22437 onSetup: makeSetupHandler(editor, pasteAsText)
22441 const onActionToggleFormat = (editor, fmt) => () => {
22442 editor.execCommand('mceToggleFormat', false, fmt);
22444 const registerFormatButtons = editor => {
22462 name: 'strikethrough',
22463 text: 'Strikethrough',
22464 icon: 'strike-through'
22472 name: 'superscript',
22473 text: 'Superscript',
22474 icon: 'superscript'
22476 ], (btn, _idx) => {
22477 editor.ui.registry.addToggleButton(btn.name, {
22480 onSetup: onSetupFormatToggle(editor, btn.name),
22481 onAction: onActionToggleFormat(editor, btn.name)
22484 for (let i = 1; i <= 6; i++) {
22485 const name = 'h' + i;
22486 editor.ui.registry.addToggleButton(name, {
22487 text: name.toUpperCase(),
22488 tooltip: 'Heading ' + i,
22489 onSetup: onSetupFormatToggle(editor, name),
22490 onAction: onActionToggleFormat(editor, name)
22494 const registerCommandButtons = editor => {
22522 text: 'Select all',
22523 action: 'SelectAll',
22527 name: 'newdocument',
22528 text: 'New document',
22529 action: 'mceNewDocument',
22530 icon: 'new-document'
22533 name: 'removeformat',
22534 text: 'Clear formatting',
22535 action: 'RemoveFormat',
22536 icon: 'remove-formatting'
22547 action: 'mcePrint',
22552 text: 'Horizontal line',
22553 action: 'InsertHorizontalRule',
22554 icon: 'horizontal-rule'
22557 editor.ui.registry.addButton(btn.name, {
22560 onAction: onActionExecCommand(editor, btn.action)
22564 const registerCommandToggleButtons = editor => {
22566 name: 'blockquote',
22567 text: 'Blockquote',
22568 action: 'mceBlockQuote',
22571 editor.ui.registry.addToggleButton(btn.name, {
22574 onAction: onActionExecCommand(editor, btn.action),
22575 onSetup: onSetupFormatToggle(editor, btn.name)
22579 const registerButtons$1 = editor => {
22580 registerFormatButtons(editor);
22581 registerCommandButtons(editor);
22582 registerCommandToggleButtons(editor);
22584 const registerMenuItems$2 = editor => {
22603 action: 'Underline',
22608 name: 'strikethrough',
22609 text: 'Strikethrough',
22610 action: 'Strikethrough',
22611 icon: 'strike-through'
22616 action: 'Subscript',
22620 name: 'superscript',
22621 text: 'Superscript',
22622 action: 'Superscript',
22623 icon: 'superscript'
22626 name: 'removeformat',
22627 text: 'Clear formatting',
22628 action: 'RemoveFormat',
22629 icon: 'remove-formatting'
22632 name: 'newdocument',
22633 text: 'New document',
22634 action: 'mceNewDocument',
22635 icon: 'new-document'
22660 text: 'Select all',
22661 action: 'SelectAll',
22662 icon: 'select-all',
22668 action: 'mcePrint',
22674 text: 'Horizontal line',
22675 action: 'InsertHorizontalRule',
22676 icon: 'horizontal-rule'
22679 editor.ui.registry.addMenuItem(menuitem.name, {
22680 text: menuitem.text,
22681 icon: menuitem.icon,
22682 shortcut: menuitem.shortcut,
22683 onAction: onActionExecCommand(editor, menuitem.action)
22686 editor.ui.registry.addMenuItem('codeformat', {
22688 icon: 'sourcecode',
22689 onAction: onActionToggleFormat(editor, 'code')
22692 const register$3 = editor => {
22693 registerButtons$1(editor);
22694 registerMenuItems$2(editor);
22697 const onSetupUndoRedoState = (editor, type) => onSetupEvent(editor, 'Undo Redo AddUndo TypingUndo ClearUndos SwitchMode', api => {
22698 api.setEnabled(!editor.mode.isReadOnly() && editor.undoManager[type]());
22700 const registerMenuItems$1 = editor => {
22701 editor.ui.registry.addMenuItem('undo', {
22704 shortcut: 'Meta+Z',
22705 onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
22706 onAction: onActionExecCommand(editor, 'undo')
22708 editor.ui.registry.addMenuItem('redo', {
22711 shortcut: 'Meta+Y',
22712 onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
22713 onAction: onActionExecCommand(editor, 'redo')
22716 const registerButtons = editor => {
22717 editor.ui.registry.addButton('undo', {
22721 onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
22722 onAction: onActionExecCommand(editor, 'undo')
22724 editor.ui.registry.addButton('redo', {
22728 onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
22729 onAction: onActionExecCommand(editor, 'redo')
22732 const register$2 = editor => {
22733 registerMenuItems$1(editor);
22734 registerButtons(editor);
22737 const onSetupVisualAidState = editor => onSetupEvent(editor, 'VisualAid', api => {
22738 api.setActive(editor.hasVisual);
22740 const registerMenuItems = editor => {
22741 editor.ui.registry.addToggleMenuItem('visualaid', {
22742 text: 'Visual aids',
22743 onSetup: onSetupVisualAidState(editor),
22744 onAction: onActionExecCommand(editor, 'mceToggleVisualAid')
22747 const registerToolbarButton = editor => {
22748 editor.ui.registry.addButton('visualaid', {
22749 tooltip: 'Visual aids',
22750 text: 'Visual aids',
22751 onAction: onActionExecCommand(editor, 'mceToggleVisualAid')
22754 const register$1 = editor => {
22755 registerToolbarButton(editor);
22756 registerMenuItems(editor);
22759 const setup$6 = (editor, backstage) => {
22760 register$8(editor);
22761 register$3(editor);
22762 register$6(editor, backstage);
22763 register$2(editor);
22764 register$c(editor);
22765 register$1(editor);
22766 register$5(editor);
22767 register$7(editor);
22768 register$4(editor);
22771 const patchPipeConfig = config => isString(config) ? config.split(/[ ,]/) : config;
22772 const option = name => editor => editor.options.get(name);
22773 const register = editor => {
22774 const registerOption = editor.options.register;
22775 registerOption('contextmenu_avoid_overlap', {
22776 processor: 'string',
22779 registerOption('contextmenu_never_use_native', {
22780 processor: 'boolean',
22783 registerOption('contextmenu', {
22784 processor: value => {
22785 if (value === false) {
22790 } else if (isString(value) || isArrayOf(value, isString)) {
22792 value: patchPipeConfig(value),
22798 message: 'Must be false or a string.'
22802 default: 'link linkchecker image editimage table spellchecker configurepermanentpen'
22805 const shouldNeverUseNative = option('contextmenu_never_use_native');
22806 const getAvoidOverlapSelector = option('contextmenu_avoid_overlap');
22807 const isContextMenuDisabled = editor => getContextMenu(editor).length === 0;
22808 const getContextMenu = editor => {
22809 const contextMenus = editor.ui.registry.getAll().contextMenus;
22810 const contextMenu = editor.options.get('contextmenu');
22811 if (editor.options.isSet('contextmenu')) {
22812 return contextMenu;
22814 return filter$2(contextMenu, item => has$2(contextMenus, item));
22818 const nu = (x, y) => ({
22823 const transpose = (pos, dx, dy) => {
22824 return nu(pos.x + dx, pos.y + dy);
22826 const isTouchEvent$1 = e => e.type === 'longpress' || e.type.indexOf('touch') === 0;
22827 const fromPageXY = e => {
22828 if (isTouchEvent$1(e)) {
22829 const touch = e.touches[0];
22830 return nu(touch.pageX, touch.pageY);
22832 return nu(e.pageX, e.pageY);
22835 const fromClientXY = e => {
22836 if (isTouchEvent$1(e)) {
22837 const touch = e.touches[0];
22838 return nu(touch.clientX, touch.clientY);
22840 return nu(e.clientX, e.clientY);
22843 const transposeContentAreaContainer = (element, pos) => {
22844 const containerPos = global$7.DOM.getPos(element);
22845 return transpose(pos, containerPos.x, containerPos.y);
22847 const getPointAnchor = (editor, e) => {
22848 if (e.type === 'contextmenu' || e.type === 'longpress') {
22849 if (editor.inline) {
22850 return fromPageXY(e);
22852 return transposeContentAreaContainer(editor.getContentAreaContainer(), fromClientXY(e));
22855 return getSelectionAnchor(editor);
22858 const getSelectionAnchor = editor => {
22861 root: SugarElement.fromDom(editor.selection.getNode())
22864 const getNodeAnchor = editor => ({
22866 node: Optional.some(SugarElement.fromDom(editor.selection.getNode())),
22867 root: SugarElement.fromDom(editor.getBody())
22869 const getAnchorSpec$1 = (editor, e, anchorType) => {
22870 switch (anchorType) {
22872 return getNodeAnchor(editor);
22874 return getPointAnchor(editor, e);
22876 return getSelectionAnchor(editor);
22880 const initAndShow$1 = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
22881 const items = buildMenu();
22882 const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
22883 build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
22884 isHorizontalMenu: false,
22885 search: Optional.none()
22886 }).map(menuData => {
22887 e.preventDefault();
22888 InlineView.showMenuAt(contextmenu, { anchor: anchorSpec }, {
22889 menu: { markers: markers('normal') },
22925 const bubbleSize = 12;
22926 const bubbleAlignments = {
22929 alignLeft: ['tox-pop--align-left'],
22930 alignRight: ['tox-pop--align-right'],
22931 right: ['tox-pop--right'],
22932 left: ['tox-pop--left'],
22933 bottom: ['tox-pop--bottom'],
22934 top: ['tox-pop--top']
22936 const isTouchWithinSelection = (editor, e) => {
22937 const selection = editor.selection;
22938 if (selection.isCollapsed() || e.touches.length < 1) {
22941 const touch = e.touches[0];
22942 const rng = selection.getRng();
22943 const rngRectOpt = getFirstRect(editor.getWin(), SimSelection.domRange(rng));
22944 return rngRectOpt.exists(rngRect => rngRect.left <= touch.clientX && rngRect.right >= touch.clientX && rngRect.top <= touch.clientY && rngRect.bottom >= touch.clientY);
22947 const setupiOSOverrides = editor => {
22948 const originalSelection = editor.selection.getRng();
22949 const selectionReset = () => {
22950 global$9.setEditorTimeout(editor, () => {
22951 editor.selection.setRng(originalSelection);
22953 unbindEventListeners();
22955 editor.once('touchend', selectionReset);
22956 const preventMousedown = e => {
22957 e.preventDefault();
22958 e.stopImmediatePropagation();
22960 editor.on('mousedown', preventMousedown, true);
22961 const clearSelectionReset = () => unbindEventListeners();
22962 editor.once('longpresscancel', clearSelectionReset);
22963 const unbindEventListeners = () => {
22964 editor.off('touchend', selectionReset);
22965 editor.off('longpresscancel', clearSelectionReset);
22966 editor.off('mousedown', preventMousedown);
22969 const getAnchorSpec = (editor, e, anchorType) => {
22970 const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
22971 const bubbleYOffset = anchorType === 'point' ? bubbleSize : 0;
22973 bubble: nu$5(0, bubbleYOffset, bubbleAlignments),
22976 maxWidthFunction: expandable(),
22977 maxHeightFunction: expandable$1()
22982 const show = (editor, e, items, backstage, contextmenu, anchorType, highlightImmediately) => {
22983 const anchorSpec = getAnchorSpec(editor, e, anchorType);
22984 build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
22985 isHorizontalMenu: true,
22986 search: Optional.none()
22987 }).map(menuData => {
22988 e.preventDefault();
22989 const highlightOnOpen = highlightImmediately ? HighlightOnOpen.HighlightMenuAndItem : HighlightOnOpen.HighlightNone;
22990 InlineView.showMenuWithinBounds(contextmenu, { anchor: anchorSpec }, {
22992 markers: markers('normal'),
22997 }, () => Optional.some(getContextToolbarBounds(editor, backstage.shared, anchorType === 'node' ? 'node' : 'selection')));
22998 editor.dispatch(hideContextToolbarEvent);
23001 const initAndShow = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
23002 const detection = detect$1();
23003 const isiOS = detection.os.isiOS();
23004 const isMacOS = detection.os.isMacOS();
23005 const isAndroid = detection.os.isAndroid();
23006 const isTouch = detection.deviceType.isTouch();
23007 const shouldHighlightImmediately = () => !(isAndroid || isiOS || isMacOS && isTouch);
23008 const open = () => {
23009 const items = buildMenu();
23010 show(editor, e, items, backstage, contextmenu, anchorType, shouldHighlightImmediately());
23012 if ((isMacOS || isiOS) && anchorType !== 'node') {
23013 const openiOS = () => {
23014 setupiOSOverrides(editor);
23017 if (isTouchWithinSelection(editor, e)) {
23020 editor.once('selectionchange', openiOS);
23021 editor.once('touchend', () => editor.off('selectionchange', openiOS));
23028 const isSeparator = item => isString(item) ? item === '|' : item.type === 'separator';
23029 const separator = { type: 'separator' };
23030 const makeContextItem = item => {
23031 const commonMenuItem = item => ({
23034 enabled: item.enabled,
23035 shortcut: item.shortcut
23037 if (isString(item)) {
23040 switch (item.type) {
23045 type: 'nestedmenuitem',
23046 ...commonMenuItem(item),
23047 getSubmenuItems: () => {
23048 const items = item.getSubmenuItems();
23049 if (isString(items)) {
23052 return map$2(items, makeContextItem);
23057 const commonItem = item;
23060 ...commonMenuItem(commonItem),
23061 onAction: noarg(commonItem.onAction)
23066 const addContextMenuGroup = (xs, groupItems) => {
23067 if (groupItems.length === 0) {
23070 const lastMenuItem = last$1(xs).filter(item => !isSeparator(item));
23071 const before = lastMenuItem.fold(() => [], _ => [separator]);
23072 return xs.concat(before).concat(groupItems).concat([separator]);
23074 const generateContextMenu = (contextMenus, menuConfig, selectedElement) => {
23075 const sections = foldl(menuConfig, (acc, name) => {
23076 return get$g(contextMenus, name.toLowerCase()).map(menu => {
23077 const items = menu.update(selectedElement);
23078 if (isString(items)) {
23079 return addContextMenuGroup(acc, items.split(' '));
23080 } else if (items.length > 0) {
23081 const allItems = map$2(items, makeContextItem);
23082 return addContextMenuGroup(acc, allItems);
23086 }).getOrThunk(() => acc.concat([name]));
23088 if (sections.length > 0 && isSeparator(sections[sections.length - 1])) {
23093 const isNativeOverrideKeyEvent = (editor, e) => e.ctrlKey && !shouldNeverUseNative(editor);
23094 const isTouchEvent = e => e.type === 'longpress' || has$2(e, 'touches');
23095 const isTriggeredByKeyboard = (editor, e) => !isTouchEvent(e) && (e.button !== 2 || e.target === editor.getBody() && e.pointerType === '');
23096 const getSelectedElement = (editor, e) => isTriggeredByKeyboard(editor, e) ? editor.selection.getStart(true) : e.target;
23097 const getAnchorType = (editor, e) => {
23098 const selector = getAvoidOverlapSelector(editor);
23099 const anchorType = isTriggeredByKeyboard(editor, e) ? 'selection' : 'point';
23100 if (isNotEmpty(selector)) {
23101 const target = getSelectedElement(editor, e);
23102 const selectorExists = closest(SugarElement.fromDom(target), selector);
23103 return selectorExists ? 'node' : anchorType;
23108 const setup$5 = (editor, lazySink, backstage) => {
23109 const detection = detect$1();
23110 const isTouch = detection.deviceType.isTouch;
23111 const contextmenu = build$1(InlineView.sketch({
23112 dom: { tag: 'div' },
23114 onEscape: () => editor.focus(),
23115 onShow: () => backstage.setContextMenuState(true),
23116 onHide: () => backstage.setContextMenuState(false),
23117 fireDismissalEventInstead: {},
23118 inlineBehaviours: derive$1([config('dismissContextMenu', [run$1(dismissRequested(), (comp, _se) => {
23119 Sandboxing.close(comp);
23123 const hideContextMenu = () => InlineView.hide(contextmenu);
23124 const showContextMenu = e => {
23125 if (shouldNeverUseNative(editor)) {
23126 e.preventDefault();
23128 if (isNativeOverrideKeyEvent(editor, e) || isContextMenuDisabled(editor)) {
23131 const anchorType = getAnchorType(editor, e);
23132 const buildMenu = () => {
23133 const selectedElement = getSelectedElement(editor, e);
23134 const registry = editor.ui.registry.getAll();
23135 const menuConfig = getContextMenu(editor);
23136 return generateContextMenu(registry.contextMenus, menuConfig, selectedElement);
23138 const initAndShow$2 = isTouch() ? initAndShow : initAndShow$1;
23139 initAndShow$2(editor, e, buildMenu, backstage, contextmenu, anchorType);
23141 editor.on('init', () => {
23142 const hideEvents = 'ResizeEditor ScrollContent ScrollWindow longpresscancel' + (isTouch() ? '' : ' ResizeWindow');
23143 editor.on(hideEvents, hideContextMenu);
23144 editor.on('longpress contextmenu', showContextMenu);
23148 const adt = Adt.generate([
23168 const subtract = change => point => point.translate(-change.left, -change.top);
23169 const add = change => point => point.translate(change.left, change.top);
23170 const transform = changes => (x, y) => foldl(changes, (rest, f) => f(rest), SugarPosition(x, y));
23171 const asFixed = (coord, scroll, origin) => coord.fold(transform([
23174 ]), transform([subtract(scroll)]), transform([]));
23175 const asAbsolute = (coord, scroll, origin) => coord.fold(transform([add(origin)]), transform([]), transform([add(scroll)]));
23176 const asOffset = (coord, scroll, origin) => coord.fold(transform([]), transform([subtract(origin)]), transform([
23180 const withinRange = (coord1, coord2, xRange, yRange, scroll, origin) => {
23181 const a1 = asAbsolute(coord1, scroll, origin);
23182 const a2 = asAbsolute(coord2, scroll, origin);
23183 return Math.abs(a1.left - a2.left) <= xRange && Math.abs(a1.top - a2.top) <= yRange;
23185 const getDeltas = (coord1, coord2, xRange, yRange, scroll, origin) => {
23186 const a1 = asAbsolute(coord1, scroll, origin);
23187 const a2 = asAbsolute(coord2, scroll, origin);
23188 const left = Math.abs(a1.left - a2.left);
23189 const top = Math.abs(a1.top - a2.top);
23190 return SugarPosition(left, top);
23192 const toStyles = (coord, scroll, origin) => {
23193 const stylesOpt = coord.fold((x, y) => ({
23194 position: Optional.some('absolute'),
23195 left: Optional.some(x + 'px'),
23196 top: Optional.some(y + 'px')
23198 position: Optional.some('absolute'),
23199 left: Optional.some(x - origin.left + 'px'),
23200 top: Optional.some(y - origin.top + 'px')
23202 position: Optional.some('fixed'),
23203 left: Optional.some(x + 'px'),
23204 top: Optional.some(y + 'px')
23207 right: Optional.none(),
23208 bottom: Optional.none(),
23212 const translate = (coord, deltaX, deltaY) => coord.fold((x, y) => offset(x + deltaX, y + deltaY), (x, y) => absolute(x + deltaX, y + deltaY), (x, y) => fixed(x + deltaX, y + deltaY));
23213 const absorb = (partialCoord, originalCoord, scroll, origin) => {
23214 const absorbOne = (stencil, nu) => (optX, optY) => {
23215 const original = stencil(originalCoord, scroll, origin);
23216 return nu(optX.getOr(original.left), optY.getOr(original.top));
23218 return partialCoord.fold(absorbOne(asOffset, offset), absorbOne(asAbsolute, absolute), absorbOne(asFixed, fixed));
23220 const offset = adt.offset;
23221 const absolute = adt.absolute;
23222 const fixed = adt.fixed;
23224 const parseAttrToInt = (element, name) => {
23225 const value = get$f(element, name);
23226 return isUndefined(value) ? NaN : parseInt(value, 10);
23228 const get = (component, snapsInfo) => {
23229 const element = component.element;
23230 const x = parseAttrToInt(element, snapsInfo.leftAttr);
23231 const y = parseAttrToInt(element, snapsInfo.topAttr);
23232 return isNaN(x) || isNaN(y) ? Optional.none() : Optional.some(SugarPosition(x, y));
23234 const set = (component, snapsInfo, pt) => {
23235 const element = component.element;
23236 set$9(element, snapsInfo.leftAttr, pt.left + 'px');
23237 set$9(element, snapsInfo.topAttr, pt.top + 'px');
23239 const clear = (component, snapsInfo) => {
23240 const element = component.element;
23241 remove$7(element, snapsInfo.leftAttr);
23242 remove$7(element, snapsInfo.topAttr);
23245 const getCoords = (component, snapInfo, coord, delta) => get(component, snapInfo).fold(() => coord, fixed$1 => fixed(fixed$1.left + delta.left, fixed$1.top + delta.top));
23246 const moveOrSnap = (component, snapInfo, coord, delta, scroll, origin) => {
23247 const newCoord = getCoords(component, snapInfo, coord, delta);
23248 const snap = snapInfo.mustSnap ? findClosestSnap(component, snapInfo, newCoord, scroll, origin) : findSnap(component, snapInfo, newCoord, scroll, origin);
23249 const fixedCoord = asFixed(newCoord, scroll, origin);
23250 set(component, snapInfo, fixedCoord);
23251 return snap.fold(() => ({
23252 coord: fixed(fixedCoord.left, fixedCoord.top),
23253 extra: Optional.none()
23255 coord: spanned.output,
23256 extra: spanned.extra
23259 const stopDrag = (component, snapInfo) => {
23260 clear(component, snapInfo);
23262 const findMatchingSnap = (snaps, newCoord, scroll, origin) => findMap(snaps, snap => {
23263 const sensor = snap.sensor;
23264 const inRange = withinRange(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
23265 return inRange ? Optional.some({
23266 output: absorb(snap.output, newCoord, scroll, origin),
23268 }) : Optional.none();
23270 const findClosestSnap = (component, snapInfo, newCoord, scroll, origin) => {
23271 const snaps = snapInfo.getSnapPoints(component);
23272 const matchSnap = findMatchingSnap(snaps, newCoord, scroll, origin);
23273 return matchSnap.orThunk(() => {
23274 const bestSnap = foldl(snaps, (acc, snap) => {
23275 const sensor = snap.sensor;
23276 const deltas = getDeltas(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
23277 return acc.deltas.fold(() => ({
23278 deltas: Optional.some(deltas),
23279 snap: Optional.some(snap)
23280 }), bestDeltas => {
23281 const currAvg = (deltas.left + deltas.top) / 2;
23282 const bestAvg = (bestDeltas.left + bestDeltas.top) / 2;
23283 if (currAvg <= bestAvg) {
23285 deltas: Optional.some(deltas),
23286 snap: Optional.some(snap)
23293 deltas: Optional.none(),
23294 snap: Optional.none()
23296 return bestSnap.snap.map(snap => ({
23297 output: absorb(snap.output, newCoord, scroll, origin),
23302 const findSnap = (component, snapInfo, newCoord, scroll, origin) => {
23303 const snaps = snapInfo.getSnapPoints(component);
23304 return findMatchingSnap(snaps, newCoord, scroll, origin);
23306 const snapTo$1 = (snap, scroll, origin) => ({
23307 coord: absorb(snap.output, snap.output, scroll, origin),
23311 const snapTo = (component, dragConfig, _state, snap) => {
23312 const target = dragConfig.getTarget(component.element);
23313 if (dragConfig.repositionTarget) {
23314 const doc = owner$4(component.element);
23315 const scroll = get$b(doc);
23316 const origin = getOrigin(target);
23317 const snapPin = snapTo$1(snap, scroll, origin);
23318 const styles = toStyles(snapPin.coord, scroll, origin);
23319 setOptions(target, styles);
23323 var DraggingApis = /*#__PURE__*/Object.freeze({
23328 const initialAttribute = 'data-initial-z-index';
23329 const resetZIndex = blocker => {
23330 parent(blocker.element).filter(isElement$1).each(root => {
23331 getOpt(root, initialAttribute).fold(() => remove$6(root, 'z-index'), zIndex => set$8(root, 'z-index', zIndex));
23332 remove$7(root, initialAttribute);
23335 const changeZIndex = blocker => {
23336 parent(blocker.element).filter(isElement$1).each(root => {
23337 getRaw(root, 'z-index').each(zindex => {
23338 set$9(root, initialAttribute, zindex);
23340 set$8(root, 'z-index', get$e(blocker.element, 'z-index'));
23343 const instigate = (anyComponent, blocker) => {
23344 anyComponent.getSystem().addToGui(blocker);
23345 changeZIndex(blocker);
23347 const discard = blocker => {
23348 resetZIndex(blocker);
23349 blocker.getSystem().removeFromGui(blocker);
23351 const createComponent = (component, blockerClass, blockerEvents) => component.getSystem().build(Container.sketch({
23358 'position': 'fixed',
23359 'z-index': '1000000000000000'
23361 classes: [blockerClass]
23363 events: blockerEvents
23366 var SnapSchema = optionObjOf('snaps', [
23367 required$1('getSnapPoints'),
23368 onHandler('onSensor'),
23369 required$1('leftAttr'),
23370 required$1('topAttr'),
23371 defaulted('lazyViewport', win),
23372 defaulted('mustSnap', false)
23376 defaulted('useFixed', never),
23377 required$1('blockerClass'),
23378 defaulted('getTarget', identity),
23379 defaulted('onDrag', noop),
23380 defaulted('repositionTarget', true),
23381 defaulted('onDrop', noop),
23382 defaultedFunction('getBounds', win),
23386 const getCurrentCoord = target => lift3(getRaw(target, 'left'), getRaw(target, 'top'), getRaw(target, 'position'), (left, top, position) => {
23387 const nu = position === 'fixed' ? fixed : offset;
23388 return nu(parseInt(left, 10), parseInt(top, 10));
23389 }).getOrThunk(() => {
23390 const location = absolute$3(target);
23391 return absolute(location.left, location.top);
23393 const clampCoords = (component, coords, scroll, origin, startData) => {
23394 const bounds = startData.bounds;
23395 const absoluteCoord = asAbsolute(coords, scroll, origin);
23396 const newX = clamp(absoluteCoord.left, bounds.x, bounds.x + bounds.width - startData.width);
23397 const newY = clamp(absoluteCoord.top, bounds.y, bounds.y + bounds.height - startData.height);
23398 const newCoords = absolute(newX, newY);
23399 return coords.fold(() => {
23400 const offset$1 = asOffset(newCoords, scroll, origin);
23401 return offset(offset$1.left, offset$1.top);
23402 }, constant$1(newCoords), () => {
23403 const fixed$1 = asFixed(newCoords, scroll, origin);
23404 return fixed(fixed$1.left, fixed$1.top);
23407 const calcNewCoord = (component, optSnaps, currentCoord, scroll, origin, delta, startData) => {
23408 const newCoord = optSnaps.fold(() => {
23409 const translated = translate(currentCoord, delta.left, delta.top);
23410 const fixedCoord = asFixed(translated, scroll, origin);
23411 return fixed(fixedCoord.left, fixedCoord.top);
23413 const snapping = moveOrSnap(component, snapInfo, currentCoord, delta, scroll, origin);
23414 snapping.extra.each(extra => {
23415 snapInfo.onSensor(component, extra);
23417 return snapping.coord;
23419 return clampCoords(component, newCoord, scroll, origin, startData);
23421 const dragBy = (component, dragConfig, startData, delta) => {
23422 const target = dragConfig.getTarget(component.element);
23423 if (dragConfig.repositionTarget) {
23424 const doc = owner$4(component.element);
23425 const scroll = get$b(doc);
23426 const origin = getOrigin(target);
23427 const currentCoord = getCurrentCoord(target);
23428 const newCoord = calcNewCoord(component, dragConfig.snaps, currentCoord, scroll, origin, delta, startData);
23429 const styles = toStyles(newCoord, scroll, origin);
23430 setOptions(target, styles);
23432 dragConfig.onDrag(component, target, delta);
23435 const calcStartData = (dragConfig, comp) => ({
23436 bounds: dragConfig.getBounds(),
23437 height: getOuter$2(comp.element),
23438 width: getOuter$1(comp.element)
23440 const move = (component, dragConfig, dragState, dragMode, event) => {
23441 const delta = dragState.update(dragMode, event);
23442 const dragStartData = dragState.getStartData().getOrThunk(() => calcStartData(dragConfig, component));
23443 delta.each(dlt => {
23444 dragBy(component, dragConfig, dragStartData, dlt);
23447 const stop = (component, blocker, dragConfig, dragState) => {
23448 blocker.each(discard);
23449 dragConfig.snaps.each(snapInfo => {
23450 stopDrag(component, snapInfo);
23452 const target = dragConfig.getTarget(component.element);
23454 dragConfig.onDrop(component, target);
23456 const handlers = events => (dragConfig, dragState) => {
23457 const updateStartState = comp => {
23458 dragState.setStartData(calcStartData(dragConfig, comp));
23461 run$1(windowScroll(), comp => {
23462 dragState.getStartData().each(() => updateStartState(comp));
23464 ...events(dragConfig, dragState, updateStartState)
23468 const init$2 = dragApi => derive$2([
23469 run$1(mousedown(), dragApi.forceDrop),
23470 run$1(mouseup(), dragApi.drop),
23471 run$1(mousemove(), (comp, simulatedEvent) => {
23472 dragApi.move(simulatedEvent.event);
23474 run$1(mouseout(), dragApi.delayDrop)
23477 const getData$1 = event => Optional.from(SugarPosition(event.x, event.y));
23478 const getDelta$1 = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
23480 var MouseData = /*#__PURE__*/Object.freeze({
23482 getData: getData$1,
23483 getDelta: getDelta$1
23486 const events$2 = (dragConfig, dragState, updateStartState) => [run$1(mousedown(), (component, simulatedEvent) => {
23487 const raw = simulatedEvent.event.raw;
23488 if (raw.button !== 0) {
23491 simulatedEvent.stop();
23492 const stop$1 = () => stop(component, Optional.some(blocker), dragConfig, dragState);
23493 const delayDrop = DelayedFunction(stop$1, 200);
23496 delayDrop: delayDrop.schedule,
23499 delayDrop.cancel();
23500 move(component, dragConfig, dragState, MouseData, event);
23503 const blocker = createComponent(component, dragConfig.blockerClass, init$2(dragApi));
23504 const start = () => {
23505 updateStartState(component);
23506 instigate(component, blocker);
23512 output$1('dragger', { handlers: handlers(events$2) })
23515 const init$1 = dragApi => derive$2([
23516 run$1(touchstart(), dragApi.forceDrop),
23517 run$1(touchend(), dragApi.drop),
23518 run$1(touchcancel(), dragApi.drop),
23519 run$1(touchmove(), (comp, simulatedEvent) => {
23520 dragApi.move(simulatedEvent.event);
23524 const getDataFrom = touches => {
23525 const touch = touches[0];
23526 return Optional.some(SugarPosition(touch.clientX, touch.clientY));
23528 const getData = event => {
23529 const raw = event.raw;
23530 const touches = raw.touches;
23531 return touches.length === 1 ? getDataFrom(touches) : Optional.none();
23533 const getDelta = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
23535 var TouchData = /*#__PURE__*/Object.freeze({
23541 const events$1 = (dragConfig, dragState, updateStartState) => {
23542 const blockerSingleton = value$2();
23543 const stopBlocking = component => {
23544 stop(component, blockerSingleton.get(), dragConfig, dragState);
23545 blockerSingleton.clear();
23548 run$1(touchstart(), (component, simulatedEvent) => {
23549 simulatedEvent.stop();
23550 const stop = () => stopBlocking(component);
23556 move(component, dragConfig, dragState, TouchData, event);
23559 const blocker = createComponent(component, dragConfig.blockerClass, init$1(dragApi));
23560 blockerSingleton.set(blocker);
23561 const start = () => {
23562 updateStartState(component);
23563 instigate(component, blocker);
23567 run$1(touchmove(), (component, simulatedEvent) => {
23568 simulatedEvent.stop();
23569 move(component, dragConfig, dragState, TouchData, simulatedEvent.event);
23571 run$1(touchend(), (component, simulatedEvent) => {
23572 simulatedEvent.stop();
23573 stopBlocking(component);
23575 run$1(touchcancel(), stopBlocking)
23580 output$1('dragger', { handlers: handlers(events$1) })
23583 const events = (dragConfig, dragState, updateStartState) => [
23584 ...events$2(dragConfig, dragState, updateStartState),
23585 ...events$1(dragConfig, dragState, updateStartState)
23589 output$1('dragger', { handlers: handlers(events) })
23592 const mouse = schema$5;
23593 const touch = schema$4;
23594 const mouseOrTouch = schema$3;
23596 var DraggingBranches = /*#__PURE__*/Object.freeze({
23600 mouseOrTouch: mouseOrTouch
23603 const init = () => {
23604 let previous = Optional.none();
23605 let startData = Optional.none();
23606 const reset = () => {
23607 previous = Optional.none();
23608 startData = Optional.none();
23610 const calculateDelta = (mode, nu) => {
23611 const result = previous.map(old => mode.getDelta(old, nu));
23612 previous = Optional.some(nu);
23615 const update = (mode, dragEvent) => mode.getData(dragEvent).bind(nuData => calculateDelta(mode, nuData));
23616 const setStartData = data => {
23617 startData = Optional.some(data);
23619 const getStartData = () => startData;
23620 const readState = constant$1({});
23630 var DragState = /*#__PURE__*/Object.freeze({
23635 const Dragging = createModes({
23637 branches: DraggingBranches,
23640 events: (dragConfig, dragState) => {
23641 const dragger = dragConfig.dragger;
23642 return dragger.handlers(dragConfig, dragState);
23646 snap: sConfig => ({
23647 sensor: sConfig.sensor,
23648 range: sConfig.range,
23649 output: sConfig.output,
23650 extra: Optional.from(sConfig.extra)
23657 const snapWidth = 40;
23658 const snapOffset = snapWidth / 2;
23659 const calcSnap = (selectorOpt, td, x, y, width, height) => selectorOpt.fold(() => Dragging.snap({
23660 sensor: absolute(x - snapOffset, y - snapOffset),
23661 range: SugarPosition(width, height),
23662 output: absolute(Optional.some(x), Optional.some(y)),
23664 }), selectorHandle => {
23665 const sensorLeft = x - snapOffset;
23666 const sensorTop = y - snapOffset;
23667 const sensorWidth = snapWidth;
23668 const sensorHeight = snapWidth;
23669 const rect = selectorHandle.element.dom.getBoundingClientRect();
23670 return Dragging.snap({
23671 sensor: absolute(sensorLeft, sensorTop),
23672 range: SugarPosition(sensorWidth, sensorHeight),
23673 output: absolute(Optional.some(x - rect.width / 2), Optional.some(y - rect.height / 2)),
23677 const getSnapsConfig = (getSnapPoints, cell, onChange) => {
23678 const isSameCell = (cellOpt, td) => cellOpt.exists(currentTd => eq(currentTd, td));
23681 leftAttr: 'data-drag-left',
23682 topAttr: 'data-drag-top',
23683 onSensor: (component, extra) => {
23684 const td = extra.td;
23685 if (!isSameCell(cell.get(), td)) {
23693 const createSelector = snaps => record(Button.sketch({
23696 classes: ['tox-selector']
23698 buttonBehaviours: derive$1([
23700 mode: 'mouseOrTouch',
23701 blockerClass: 'blocker',
23704 Unselecting.config({})
23709 'alloy.base.behaviour'
23713 'alloy.base.behaviour'
23717 const setup$4 = (editor, sink) => {
23718 const tlTds = Cell([]);
23719 const brTds = Cell([]);
23720 const isVisible = Cell(false);
23721 const startCell = value$2();
23722 const finishCell = value$2();
23723 const getTopLeftSnap = td => {
23724 const box = absolute$2(td);
23725 return calcSnap(memTopLeft.getOpt(sink), td, box.x, box.y, box.width, box.height);
23727 const getTopLeftSnaps = () => map$2(tlTds.get(), td => getTopLeftSnap(td));
23728 const getBottomRightSnap = td => {
23729 const box = absolute$2(td);
23730 return calcSnap(memBottomRight.getOpt(sink), td, box.right, box.bottom, box.width, box.height);
23732 const getBottomRightSnaps = () => map$2(brTds.get(), td => getBottomRightSnap(td));
23733 const topLeftSnaps = getSnapsConfig(getTopLeftSnaps, startCell, start => {
23734 finishCell.get().each(finish => {
23735 editor.dispatch('TableSelectorChange', {
23741 const bottomRightSnaps = getSnapsConfig(getBottomRightSnaps, finishCell, finish => {
23742 startCell.get().each(start => {
23743 editor.dispatch('TableSelectorChange', {
23749 const memTopLeft = createSelector(topLeftSnaps);
23750 const memBottomRight = createSelector(bottomRightSnaps);
23751 const topLeft = build$1(memTopLeft.asSpec());
23752 const bottomRight = build$1(memBottomRight.asSpec());
23753 const showOrHideHandle = (selector, cell, isAbove, isBelow) => {
23754 const cellRect = cell.dom.getBoundingClientRect();
23755 remove$6(selector.element, 'display');
23756 const viewportHeight = defaultView(SugarElement.fromDom(editor.getBody())).dom.innerHeight;
23757 const aboveViewport = isAbove(cellRect);
23758 const belowViewport = isBelow(cellRect, viewportHeight);
23759 if (aboveViewport || belowViewport) {
23760 set$8(selector.element, 'display', 'none');
23763 const snapTo = (selector, cell, getSnapConfig, pos) => {
23764 const snap = getSnapConfig(cell);
23765 Dragging.snapTo(selector, snap);
23766 const isAbove = rect => rect[pos] < 0;
23767 const isBelow = (rect, viewportHeight) => rect[pos] > viewportHeight;
23768 showOrHideHandle(selector, cell, isAbove, isBelow);
23770 const snapTopLeft = cell => snapTo(topLeft, cell, getTopLeftSnap, 'top');
23771 const snapLastTopLeft = () => startCell.get().each(snapTopLeft);
23772 const snapBottomRight = cell => snapTo(bottomRight, cell, getBottomRightSnap, 'bottom');
23773 const snapLastBottomRight = () => finishCell.get().each(snapBottomRight);
23774 if (detect$1().deviceType.isTouch()) {
23775 editor.on('TableSelectionChange', e => {
23776 if (!isVisible.get()) {
23777 attach(sink, topLeft);
23778 attach(sink, bottomRight);
23779 isVisible.set(true);
23781 startCell.set(e.start);
23782 finishCell.set(e.finish);
23783 e.otherCells.each(otherCells => {
23784 tlTds.set(otherCells.upOrLeftCells);
23785 brTds.set(otherCells.downOrRightCells);
23786 snapTopLeft(e.start);
23787 snapBottomRight(e.finish);
23790 editor.on('ResizeEditor ResizeWindow ScrollContent', () => {
23792 snapLastBottomRight();
23794 editor.on('TableSelectionClear', () => {
23795 if (isVisible.get()) {
23797 detach(bottomRight);
23798 isVisible.set(false);
23801 finishCell.clear();
23806 var Logo = "<svg width=\"50px\" height=\"16px\" viewBox=\"0 0 50 16\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.143 0c2.608.015 5.186 2.178 5.186 5.331 0 0 .077 3.812-.084 4.87-.361 2.41-2.164 4.074-4.65 4.496-1.453.284-2.523.49-3.212.623-.373.071-.634.122-.785.152-.184.038-.997.145-1.35.145-2.732 0-5.21-2.04-5.248-5.33 0 0 0-3.514.03-4.442.093-2.4 1.758-4.342 4.926-4.963 0 0 3.875-.752 4.036-.782.368-.07.775-.1 1.15-.1Zm1.826 2.8L5.83 3.989v2.393l-2.455.475v5.968l6.137-1.189V9.243l2.456-.476V2.8ZM5.83 6.382l3.682-.713v3.574l-3.682.713V6.382Zm27.173-1.64-.084-1.066h-2.226v9.132h2.456V7.743c-.008-1.151.998-2.064 2.149-2.072 1.15-.008 1.987.92 1.995 2.072v5.065h2.455V7.359c-.015-2.18-1.657-3.929-3.837-3.913a3.993 3.993 0 0 0-2.908 1.296Zm-6.3-4.266L29.16 0v2.387l-2.456.475V.476Zm0 3.2v9.132h2.456V3.676h-2.456Zm18.179 11.787L49.11 3.676H46.58l-1.612 4.527-.46 1.382-.384-1.382-1.611-4.527H39.98l3.3 9.132L42.15 16l2.732-.537ZM22.867 9.738c0 .752.568 1.075.921 1.075.353 0 .668-.047.998-.154l.537 1.765c-.23.154-.92.537-2.225.537-1.305 0-2.655-.997-2.686-2.686a136.877 136.877 0 0 1 0-4.374H18.8V3.676h1.612v-1.98l2.455-.476v2.456h2.302V5.9h-2.302v3.837Z\"/>\n</svg>\n";
23808 const isHidden = elm => elm.nodeName === 'BR' || !!elm.getAttribute('data-mce-bogus') || elm.getAttribute('data-mce-type') === 'bookmark';
23809 const renderElementPath = (editor, settings, providersBackstage) => {
23810 const delimiter = settings.delimiter ?? '\u203A';
23811 const renderElement = (name, element, index) => Button.sketch({
23814 classes: ['tox-statusbar__path-item'],
23816 'data-index': index,
23817 'aria-level': index + 1
23820 components: [text$2(name)],
23823 editor.selection.select(element);
23824 editor.nodeChanged();
23826 buttonBehaviours: derive$1([
23827 DisablingConfigs.button(providersBackstage.isDisabled),
23831 const renderDivider = () => ({
23834 classes: ['tox-statusbar__path-divider'],
23835 attributes: { 'aria-hidden': true }
23837 components: [text$2(` ${ delimiter } `)]
23839 const renderPathData = data => foldl(data, (acc, path, index) => {
23840 const element = renderElement(path.name, path.element, index);
23842 return acc.concat([element]);
23844 return acc.concat([
23850 const updatePath = parents => {
23851 const newPath = [];
23852 let i = parents.length;
23854 const parent = parents[i];
23855 if (parent.nodeType === 1 && !isHidden(parent)) {
23856 const args = fireResolveName(editor, parent);
23857 if (!args.isDefaultPrevented()) {
23863 if (args.isPropagationStopped()) {
23873 classes: ['tox-statusbar__path'],
23874 attributes: { role: 'navigation' }
23876 behaviours: derive$1([
23879 selector: 'div[role=button]'
23881 Disabling.config({ disabled: providersBackstage.isDisabled }),
23883 Tabstopping.config({}),
23884 Replacing.config({}),
23885 config('elementPathEvents', [runOnAttached((comp, _e) => {
23886 editor.shortcuts.add('alt+F11', 'focus statusbar elementpath', () => Keying.focusIn(comp));
23887 editor.on('NodeChange', e => {
23888 const newPath = updatePath(e.parents);
23889 const newChildren = newPath.length > 0 ? renderPathData(newPath) : [];
23890 Replacing.set(comp, newChildren);
23899 (function (ResizeTypes) {
23900 ResizeTypes[ResizeTypes['None'] = 0] = 'None';
23901 ResizeTypes[ResizeTypes['Both'] = 1] = 'Both';
23902 ResizeTypes[ResizeTypes['Vertical'] = 2] = 'Vertical';
23903 }(ResizeTypes || (ResizeTypes = {})));
23904 const getDimensions = (editor, deltas, resizeType, originalHeight, originalWidth) => {
23905 const dimensions = { height: calcCappedSize(originalHeight + deltas.top, getMinHeightOption(editor), getMaxHeightOption(editor)) };
23906 if (resizeType === ResizeTypes.Both) {
23907 dimensions.width = calcCappedSize(originalWidth + deltas.left, getMinWidthOption(editor), getMaxWidthOption(editor));
23911 const resize = (editor, deltas, resizeType) => {
23912 const container = SugarElement.fromDom(editor.getContainer());
23913 const dimensions = getDimensions(editor, deltas, resizeType, get$d(container), get$c(container));
23914 each(dimensions, (val, dim) => {
23915 if (isNumber(val)) {
23916 set$8(container, dim, numToPx(val));
23919 fireResizeEditor(editor);
23922 const getResizeType = editor => {
23923 const resize = getResize(editor);
23924 if (resize === false) {
23925 return ResizeTypes.None;
23926 } else if (resize === 'both') {
23927 return ResizeTypes.Both;
23929 return ResizeTypes.Vertical;
23932 const keyboardHandler = (editor, resizeType, x, y) => {
23934 const delta = SugarPosition(x * scale, y * scale);
23935 resize(editor, delta, resizeType);
23936 return Optional.some(true);
23938 const renderResizeHandler = (editor, providersBackstage) => {
23939 const resizeType = getResizeType(editor);
23940 if (resizeType === ResizeTypes.None) {
23941 return Optional.none();
23943 return Optional.some(render$3('resize-handle', {
23945 classes: ['tox-statusbar__resize-handle'],
23946 attributes: { title: providersBackstage.translate('Resize') },
23950 repositionTarget: false,
23951 onDrag: (_comp, _target, delta) => resize(editor, delta, resizeType),
23952 blockerClass: 'tox-blocker'
23956 onLeft: () => keyboardHandler(editor, resizeType, -1, 0),
23957 onRight: () => keyboardHandler(editor, resizeType, 1, 0),
23958 onUp: () => keyboardHandler(editor, resizeType, 0, -1),
23959 onDown: () => keyboardHandler(editor, resizeType, 0, 1)
23961 Tabstopping.config({}),
23962 Focusing.config({})
23964 }, providersBackstage.icons));
23967 const renderWordCount = (editor, providersBackstage) => {
23968 const replaceCountText = (comp, count, mode) => Replacing.set(comp, [text$2(providersBackstage.translate([
23972 return Button.sketch({
23975 classes: ['tox-statusbar__wordcount']
23978 buttonBehaviours: derive$1([
23979 DisablingConfigs.button(providersBackstage.isDisabled),
23981 Tabstopping.config({}),
23982 Replacing.config({}),
23983 Representing.config({
23995 config('wordcount-events', [
23996 runOnExecute$1(comp => {
23997 const currentVal = Representing.getValue(comp);
23998 const newMode = currentVal.mode === 'words' ? 'characters' : 'words';
23999 Representing.setValue(comp, {
24001 count: currentVal.count
24003 replaceCountText(comp, currentVal.count, newMode);
24005 runOnAttached(comp => {
24006 editor.on('wordCountUpdate', e => {
24007 const {mode} = Representing.getValue(comp);
24008 Representing.setValue(comp, {
24012 replaceCountText(comp, e.wordCount, mode);
24020 'alloy.base.behaviour',
24027 const renderStatusbar = (editor, providersBackstage) => {
24028 const renderBranding = () => {
24032 classes: ['tox-statusbar__branding']
24038 'href': 'https://www.tiny.cloud/powered-by-tiny?utm_campaign=editor_referral&utm_medium=poweredby&utm_source=tinymce&utm_content=v6',
24040 'target': '_blank',
24041 'aria-label': global$8.translate([
24046 innerHtml: Logo.trim()
24048 behaviours: derive$1([Focusing.config({})])
24052 const getTextComponents = () => {
24053 const components = [];
24054 if (useElementPath(editor)) {
24055 components.push(renderElementPath(editor, {}, providersBackstage));
24057 if (editor.hasPlugin('wordcount')) {
24058 components.push(renderWordCount(editor, providersBackstage));
24060 if (useBranding(editor)) {
24061 components.push(renderBranding());
24063 if (components.length > 0) {
24067 classes: ['tox-statusbar__text-container']
24074 const getComponents = () => {
24075 const components = getTextComponents();
24076 const resizeHandler = renderResizeHandler(editor, providersBackstage);
24077 return components.concat(resizeHandler.toArray());
24082 classes: ['tox-statusbar']
24084 components: getComponents()
24088 const getLazyMothership = singleton => singleton.get().getOrDie('UI has not been rendered');
24089 const setup$3 = editor => {
24090 const isInline = editor.inline;
24091 const mode = isInline ? Inline : Iframe;
24092 const header = isStickyToolbar(editor) ? StickyHeader : StaticHeader;
24093 const lazySink = value$2();
24094 const lazyOuterContainer = value$2();
24095 const lazyMothership = value$2();
24096 const lazyUiMothership = value$2();
24097 const platform = detect$1();
24098 const isTouch = platform.deviceType.isTouch();
24099 const touchPlatformClass = 'tox-platform-touch';
24100 const deviceClasses = isTouch ? [touchPlatformClass] : [];
24101 const isToolbarBottom = isToolbarLocationBottom(editor);
24102 const toolbarMode = getToolbarMode(editor);
24103 const memAnchorBar = record({
24106 classes: ['tox-anchorbar']
24109 const lazyHeader = () => lazyOuterContainer.get().bind(OuterContainer.getHeader);
24110 const lazySinkResult = () => Result.fromOption(lazySink.get(), 'UI has not been rendered');
24111 const lazyAnchorBar = () => lazyOuterContainer.get().bind(container => memAnchorBar.getOpt(container)).getOrDie('Could not find a anchor bar element');
24112 const lazyToolbar = () => lazyOuterContainer.get().bind(container => OuterContainer.getToolbar(container)).getOrDie('Could not find more toolbar element');
24113 const lazyThrobber = () => lazyOuterContainer.get().bind(container => OuterContainer.getThrobber(container)).getOrDie('Could not find throbber element');
24114 const backstage = init$7(lazySinkResult, editor, lazyAnchorBar);
24115 const makeHeaderPart = () => {
24116 const verticalDirAttributes = { attributes: { [Attribute]: isToolbarBottom ? AttributeValue.BottomToTop : AttributeValue.TopToBottom } };
24117 const partMenubar = OuterContainer.parts.menubar({
24120 classes: ['tox-menubar']
24127 const partToolbar = OuterContainer.parts.toolbar({
24130 classes: ['tox-toolbar']
24132 getSink: lazySinkResult,
24133 providers: backstage.shared.providers,
24139 lazyHeader: () => lazyHeader().getOrDie('Could not find header element'),
24140 ...verticalDirAttributes
24142 const partMultipleToolbar = OuterContainer.parts['multiple-toolbar']({
24145 classes: ['tox-toolbar-overlord']
24147 providers: backstage.shared.providers,
24153 const hasMultipleToolbar = isMultipleToolbars(editor);
24154 const hasToolbar = isToolbarEnabled(editor);
24155 const hasMenubar = isMenubarEnabled(editor);
24156 const shouldHavePromotion = promotionEnabled(editor);
24157 const partPromotion = makePromotion();
24158 const getPartToolbar = () => {
24159 if (hasMultipleToolbar) {
24160 return [partMultipleToolbar];
24161 } else if (hasToolbar) {
24162 return [partToolbar];
24167 const menubarCollection = shouldHavePromotion ? [
24171 return OuterContainer.parts.header({
24174 classes: ['tox-editor-header'],
24175 ...verticalDirAttributes
24177 components: flatten([
24178 hasMenubar ? menubarCollection : [],
24180 useFixedContainer(editor) ? [] : [memAnchorBar.asSpec()]
24182 sticky: isStickyToolbar(editor),
24184 sharedBackstage: backstage.shared
24187 const makePromotion = () => {
24188 return OuterContainer.parts.promotion({
24191 classes: ['tox-promotion']
24195 const makeSidebarDefinition = () => {
24196 const partSocket = OuterContainer.parts.socket({
24199 classes: ['tox-edit-area']
24202 const partSidebar = OuterContainer.parts.sidebar({
24205 classes: ['tox-sidebar']
24211 classes: ['tox-sidebar-wrap']
24219 const renderSink = () => {
24220 const uiContainer = getUiContainer(editor);
24221 const isGridUiContainer = eq(body(), uiContainer) && get$e(uiContainer, 'display') === 'grid';
24229 ].concat(deviceClasses),
24230 attributes: { ...global$8.isRtl() ? { dir: 'rtl' } : {} }
24232 behaviours: derive$1([Positioning.config({ useFixed: () => header.isDocked(lazyHeader) })])
24234 const reactiveWidthSpec = {
24235 dom: { styles: { width: document.body.clientWidth + 'px' } },
24236 events: derive$2([run$1(windowResize(), comp => {
24237 set$8(comp.element, 'width', document.body.clientWidth + 'px');
24240 const sink = build$1(deepMerge(sinkSpec, isGridUiContainer ? reactiveWidthSpec : {}));
24241 const uiMothership = takeover(sink);
24242 lazySink.set(sink);
24243 lazyUiMothership.set(uiMothership);
24249 const renderContainer = () => {
24250 const partHeader = makeHeaderPart();
24251 const sidebarContainer = makeSidebarDefinition();
24252 const partThrobber = OuterContainer.parts.throbber({
24255 classes: ['tox-throbber']
24259 const statusbar = useStatusBar(editor) && !isInline ? Optional.some(renderStatusbar(editor, backstage.shared.providers)) : Optional.none();
24260 const editorComponents = flatten([
24261 isToolbarBottom ? [] : [partHeader],
24262 isInline ? [] : [sidebarContainer],
24263 isToolbarBottom ? [partHeader] : []
24265 const editorContainer = {
24268 classes: ['tox-editor-container']
24270 components: editorComponents
24272 const containerComponents = flatten([
24274 isInline ? [] : statusbar.toArray(),
24277 const isHidden = isDistractionFree(editor);
24278 const attributes = {
24279 role: 'application',
24280 ...global$8.isRtl() ? { dir: 'rtl' } : {},
24281 ...isHidden ? { 'aria-hidden': 'true' } : {}
24283 const outerContainer = build$1(OuterContainer.sketch({
24289 ].concat(isInline ? ['tox-tinymce-inline'] : []).concat(isToolbarBottom ? ['tox-tinymce--toolbar-bottom'] : []).concat(deviceClasses),
24291 visibility: 'hidden',
24299 components: containerComponents,
24300 behaviours: derive$1([
24302 Disabling.config({ disableClass: 'tox-tinymce--disabled' }),
24305 selector: '.tox-menubar, .tox-toolbar, .tox-toolbar__primary, .tox-toolbar__overflow--open, .tox-sidebar__overflow--open, .tox-statusbar__path, .tox-statusbar__wordcount, .tox-statusbar__branding a, .tox-statusbar__resize-handle'
24309 const mothership = takeover(outerContainer);
24310 lazyOuterContainer.set(outerContainer);
24311 lazyMothership.set(mothership);
24317 const setEditorSize = outerContainer => {
24318 const parsedHeight = numToPx(getHeightWithFallback(editor));
24319 const parsedWidth = numToPx(getWidthWithFallback(editor));
24320 if (!editor.inline) {
24321 if (isValidValue('div', 'width', parsedWidth)) {
24322 set$8(outerContainer.element, 'width', parsedWidth);
24324 if (isValidValue('div', 'height', parsedHeight)) {
24325 set$8(outerContainer.element, 'height', parsedHeight);
24327 set$8(outerContainer.element, 'height', '400px');
24330 return parsedHeight;
24332 const setupShortcutsAndCommands = outerContainer => {
24333 editor.addShortcut('alt+F9', 'focus menubar', () => {
24334 OuterContainer.focusMenubar(outerContainer);
24336 editor.addShortcut('alt+F10', 'focus toolbar', () => {
24337 OuterContainer.focusToolbar(outerContainer);
24339 editor.addCommand('ToggleToolbarDrawer', () => {
24340 OuterContainer.toggleToolbarDrawer(outerContainer);
24342 editor.addQueryStateHandler('ToggleToolbarDrawer', () => OuterContainer.isToolbarDrawerToggled(outerContainer));
24344 const renderUI = () => {
24345 const {mothership, outerContainer} = renderContainer();
24346 const {uiMothership, sink} = renderSink();
24347 map$1(getToolbarGroups(editor), (toolbarGroupButtonConfig, name) => {
24348 editor.ui.registry.addGroupToolbarButton(name, toolbarGroupButtonConfig);
24350 const {buttons, menuItems, contextToolbars, sidebars} = editor.ui.registry.getAll();
24351 const toolbarOpt = getMultipleToolbarsOption(editor);
24352 const rawUiConfig = {
24354 menus: getMenus(editor),
24355 menubar: getMenubar(editor),
24356 toolbar: toolbarOpt.getOrThunk(() => getToolbar(editor)),
24357 allowToolbarGroups: toolbarMode === ToolbarMode$1.floating,
24361 setupShortcutsAndCommands(outerContainer);
24362 setup$b(editor, mothership, uiMothership);
24363 header.setup(editor, backstage.shared, lazyHeader);
24364 setup$6(editor, backstage);
24365 setup$5(editor, lazySinkResult, backstage);
24367 setup$7(editor, lazyThrobber, backstage.shared);
24368 register$9(editor, contextToolbars, sink, { backstage });
24369 setup$4(editor, sink);
24370 const elm = editor.getElement();
24371 const height = setEditorSize(outerContainer);
24372 const uiComponents = {
24382 return mode.render(editor, uiComponents, rawUiConfig, backstage, args);
24384 const getMothership = () => getLazyMothership(lazyMothership);
24385 const getUiMothership = () => getLazyMothership(lazyUiMothership);
24394 const describedBy = (describedElement, describeElement) => {
24395 const describeId = Optional.from(get$f(describedElement, 'id')).fold(() => {
24396 const id = generate$6('dialog-describe');
24397 set$9(describeElement, 'id', id);
24400 set$9(describedElement, 'aria-describedby', describeId);
24403 const labelledBy = (labelledElement, labelElement) => {
24404 const labelId = getOpt(labelledElement, 'id').fold(() => {
24405 const id = generate$6('dialog-label');
24406 set$9(labelElement, 'id', id);
24409 set$9(labelledElement, 'aria-labelledby', labelId);
24412 const schema$2 = constant$1([
24413 required$1('lazySink'),
24414 option$3('dragBlockClass'),
24415 defaultedFunction('getBounds', win),
24416 defaulted('useTabstopAt', always),
24417 defaulted('eventOrder', {}),
24418 field('modalBehaviours', [Keying]),
24419 onKeyboardHandler('onExecute'),
24420 onStrictKeyboardHandler('onEscape')
24422 const basic = { sketch: identity };
24423 const parts$2 = constant$1([
24425 name: 'draghandle',
24426 overrides: (detail, spec) => {
24428 behaviours: derive$1([Dragging.config({
24430 getTarget: handle => {
24431 return ancestor(handle, '[role="dialog"]').getOr(handle);
24433 blockerClass: detail.dragBlockClass.getOrDie(new Error('The drag blocker class was not specified for a dialog with a drag handle: \n' + JSON.stringify(spec, null, 2)).message),
24434 getBounds: detail.getDragBounds
24440 schema: [required$1('dom')],
24445 schema: [required$1('dom')],
24450 schema: [required$1('dom')],
24455 schema: [required$1('dom')],
24460 sketch: (spec, detail) => ({
24463 components: detail.components
24477 defaulted('components', [])
24483 const factory$4 = (detail, components, spec, externals) => {
24484 const dialogComp = value$2();
24485 const showDialog = dialog => {
24486 dialogComp.set(dialog);
24487 const sink = detail.lazySink(dialog).getOrDie();
24488 const externalBlocker = externals.blocker();
24489 const blocker = sink.getSystem().build({
24490 ...externalBlocker,
24491 components: externalBlocker.components.concat([premade(dialog)]),
24492 behaviours: derive$1([
24493 Focusing.config({}),
24494 config('dialog-blocker-events', [runOnSource(focusin(), () => {
24495 Keying.focusIn(dialog);
24499 attach(sink, blocker);
24500 Keying.focusIn(dialog);
24502 const hideDialog = dialog => {
24503 dialogComp.clear();
24504 parent(dialog.element).each(blockerDom => {
24505 dialog.getSystem().getByDom(blockerDom).each(blocker => {
24510 const getDialogBody = dialog => getPartOrDie(dialog, detail, 'body');
24511 const getDialogFooter = dialog => getPartOrDie(dialog, detail, 'footer');
24512 const setBusy = (dialog, getBusySpec) => {
24513 Blocking.block(dialog, getBusySpec);
24515 const setIdle = dialog => {
24516 Blocking.unblock(dialog);
24518 const modalEventsId = generate$6('modal-events');
24519 const eventOrder = {
24520 ...detail.eventOrder,
24521 [attachedToDom()]: [modalEventsId].concat(detail.eventOrder['alloy.system.attached'] || [])
24530 getBody: getDialogBody,
24531 getFooter: getDialogFooter,
24539 'aria-modal': 'true'
24542 behaviours: augment(detail.modalBehaviours, [
24543 Replacing.config({}),
24546 onEnter: detail.onExecute,
24547 onEscape: detail.onEscape,
24548 useTabstopAt: detail.useTabstopAt
24550 Blocking.config({ getRoot: dialogComp.get }),
24551 config(modalEventsId, [runOnAttached(c => {
24552 labelledBy(c.element, getPartOrDie(c, detail, 'title').element);
24553 describedBy(c.element, getPartOrDie(c, detail, 'body').element);
24558 const ModalDialog = composite({
24559 name: 'ModalDialog',
24560 configFields: schema$2(),
24561 partFields: parts$2(),
24562 factory: factory$4,
24564 show: (apis, dialog) => {
24567 hide: (apis, dialog) => {
24570 getBody: (apis, dialog) => apis.getBody(dialog),
24571 getFooter: (apis, dialog) => apis.getFooter(dialog),
24572 setBusy: (apis, dialog, getBusySpec) => {
24573 apis.setBusy(dialog, getBusySpec);
24575 setIdle: (apis, dialog) => {
24576 apis.setIdle(dialog);
24581 const dialogToggleMenuItemSchema = objOf([
24584 ].concat(commonMenuItemFields));
24585 const dialogToggleMenuItemDataProcessor = boolean;
24587 const baseFooterButtonFields = [
24588 generatedName('button'),
24590 defaultedStringEnum('align', 'end', [
24596 optionStringEnum('buttonType', [
24601 const dialogFooterButtonFields = [
24602 ...baseFooterButtonFields,
24605 const normalFooterButtonFields = [
24606 requiredStringEnum('type', [
24611 ...dialogFooterButtonFields
24613 const menuFooterButtonFields = [
24614 requiredStringEnum('type', ['menu']),
24618 requiredArrayOf('items', dialogToggleMenuItemSchema),
24619 ...baseFooterButtonFields
24621 const dialogFooterButtonSchema = choose$1('type', {
24622 submit: normalFooterButtonFields,
24623 cancel: normalFooterButtonFields,
24624 custom: normalFooterButtonFields,
24625 menu: menuFooterButtonFields
24628 const alertBannerFields = [
24631 requiredStringEnum('level', [
24638 defaulted('url', '')
24640 const alertBannerSchema = objOf(alertBannerFields);
24642 const createBarFields = itemsField => [
24647 const buttonFields = [
24651 generatedName('button'),
24654 optionStringEnum('buttonType', [
24661 const buttonSchema = objOf(buttonFields);
24663 const formComponentFields = [
24667 const formComponentWithLabelFields = formComponentFields.concat([optionalLabel]);
24669 const checkboxFields = formComponentFields.concat([
24673 const checkboxSchema = objOf(checkboxFields);
24674 const checkboxDataProcessor = boolean;
24676 const collectionFields = formComponentWithLabelFields.concat([defaultedColumns('auto')]);
24677 const collectionSchema = objOf(collectionFields);
24678 const collectionDataProcessor = arrOfObj([
24684 const colorInputFields = formComponentWithLabelFields;
24685 const colorInputSchema = objOf(colorInputFields);
24686 const colorInputDataProcessor = string;
24688 const colorPickerFields = formComponentWithLabelFields;
24689 const colorPickerSchema = objOf(colorPickerFields);
24690 const colorPickerDataProcessor = string;
24692 const customEditorFields = formComponentFields.concat([
24693 defaultedString('tag', 'textarea'),
24694 requiredString('scriptId'),
24695 requiredString('scriptUrl'),
24696 defaultedPostMsg('settings', undefined)
24698 const customEditorFieldsOld = formComponentFields.concat([
24699 defaultedString('tag', 'textarea'),
24700 requiredFunction('init')
24702 const customEditorSchema = valueOf(v => asRaw('customeditor.old', objOfOnly(customEditorFieldsOld), v).orThunk(() => asRaw('customeditor.new', objOfOnly(customEditorFields), v)));
24703 const customEditorDataProcessor = string;
24705 const dropZoneFields = formComponentWithLabelFields;
24706 const dropZoneSchema = objOf(dropZoneFields);
24707 const dropZoneDataProcessor = arrOfVal();
24709 const createGridFields = itemsField => [
24711 requiredNumber('columns'),
24715 const htmlPanelFields = [
24717 requiredString('html'),
24718 defaultedStringEnum('presets', 'presentation', [
24723 const htmlPanelSchema = objOf(htmlPanelFields);
24725 const iframeFields = formComponentWithLabelFields.concat([
24726 defaultedBoolean('sandboxed', true),
24727 defaultedBoolean('transparent', true)
24729 const iframeSchema = objOf(iframeFields);
24730 const iframeDataProcessor = string;
24732 const imagePreviewSchema = objOf(formComponentFields.concat([optionString('height')]));
24733 const imagePreviewDataProcessor = objOf([
24734 requiredString('url'),
24735 optionNumber('zoom'),
24736 optionNumber('cachedWidth'),
24737 optionNumber('cachedHeight')
24740 const inputFields = formComponentWithLabelFields.concat([
24741 optionString('inputMode'),
24742 optionString('placeholder'),
24743 defaultedBoolean('maximized', false),
24746 const inputSchema = objOf(inputFields);
24747 const inputDataProcessor = string;
24749 const createLabelFields = itemsField => [
24755 const listBoxSingleItemFields = [
24759 const listBoxNestedItemFields = [
24761 requiredArrayOf('items', thunkOf('items', () => listBoxItemSchema))
24763 const listBoxItemSchema = oneOf([
24764 objOf(listBoxSingleItemFields),
24765 objOf(listBoxNestedItemFields)
24767 const listBoxFields = formComponentWithLabelFields.concat([
24768 requiredArrayOf('items', listBoxItemSchema),
24771 const listBoxSchema = objOf(listBoxFields);
24772 const listBoxDataProcessor = string;
24774 const selectBoxFields = formComponentWithLabelFields.concat([
24775 requiredArrayOfObj('items', [
24779 defaultedNumber('size', 1),
24782 const selectBoxSchema = objOf(selectBoxFields);
24783 const selectBoxDataProcessor = string;
24785 const sizeInputFields = formComponentWithLabelFields.concat([
24786 defaultedBoolean('constrain', true),
24789 const sizeInputSchema = objOf(sizeInputFields);
24790 const sizeInputDataProcessor = objOf([
24791 requiredString('width'),
24792 requiredString('height')
24795 const sliderFields = formComponentFields.concat([
24797 defaultedNumber('min', 0),
24798 defaultedNumber('max', 0)
24800 const sliderSchema = objOf(sliderFields);
24801 const sliderInputDataProcessor = number;
24803 const tableFields = [
24805 requiredArrayOf('header', string),
24806 requiredArrayOf('cells', arrOf(string))
24808 const tableSchema = objOf(tableFields);
24810 const textAreaFields = formComponentWithLabelFields.concat([
24811 optionString('placeholder'),
24812 defaultedBoolean('maximized', false),
24815 const textAreaSchema = objOf(textAreaFields);
24816 const textAreaDataProcessor = string;
24818 const urlInputFields = formComponentWithLabelFields.concat([
24819 defaultedStringEnum('filetype', 'file', [
24826 const urlInputSchema = objOf(urlInputFields);
24827 const urlInputDataProcessor = objOf([
24832 const createItemsField = name => field$1('items', 'items', required$2(), arrOf(valueOf(v => asRaw(`Checking item of ${ name }`, itemSchema, v).fold(sErr => Result.error(formatError(sErr)), passValue => Result.value(passValue)))));
24833 const itemSchema = valueThunk(() => choose$2('type', {
24834 alertbanner: alertBannerSchema,
24835 bar: objOf(createBarFields(createItemsField('bar'))),
24836 button: buttonSchema,
24837 checkbox: checkboxSchema,
24838 colorinput: colorInputSchema,
24839 colorpicker: colorPickerSchema,
24840 dropzone: dropZoneSchema,
24841 grid: objOf(createGridFields(createItemsField('grid'))),
24842 iframe: iframeSchema,
24843 input: inputSchema,
24844 listbox: listBoxSchema,
24845 selectbox: selectBoxSchema,
24846 sizeinput: sizeInputSchema,
24847 slider: sliderSchema,
24848 textarea: textAreaSchema,
24849 urlinput: urlInputSchema,
24850 customeditor: customEditorSchema,
24851 htmlpanel: htmlPanelSchema,
24852 imagepreview: imagePreviewSchema,
24853 collection: collectionSchema,
24854 label: objOf(createLabelFields(createItemsField('label'))),
24855 table: tableSchema,
24858 const panelFields = [
24860 defaulted('classes', []),
24861 requiredArrayOf('items', itemSchema)
24863 const panelSchema = objOf(panelFields);
24865 const tabFields = [
24866 generatedName('tab'),
24868 requiredArrayOf('items', itemSchema)
24870 const tabPanelFields = [
24872 requiredArrayOfObj('tabs', tabFields)
24874 const tabPanelSchema = objOf(tabPanelFields);
24876 const dialogButtonFields = dialogFooterButtonFields;
24877 const dialogButtonSchema = dialogFooterButtonSchema;
24878 const dialogSchema = objOf([
24879 requiredString('title'),
24880 requiredOf('body', choose$2('type', {
24881 panel: panelSchema,
24882 tabpanel: tabPanelSchema
24884 defaultedString('size', 'normal'),
24885 requiredArrayOf('buttons', dialogButtonSchema),
24886 defaulted('initialData', {}),
24887 defaultedFunction('onAction', noop),
24888 defaultedFunction('onChange', noop),
24889 defaultedFunction('onSubmit', noop),
24890 defaultedFunction('onClose', noop),
24891 defaultedFunction('onCancel', noop),
24892 defaultedFunction('onTabChange', noop)
24894 const createDialog = spec => asRaw('dialog', dialogSchema, spec);
24896 const urlDialogButtonSchema = objOf([
24897 requiredStringEnum('type', [
24901 ...dialogButtonFields
24903 const urlDialogSchema = objOf([
24904 requiredString('title'),
24905 requiredString('url'),
24906 optionNumber('height'),
24907 optionNumber('width'),
24908 optionArrayOf('buttons', urlDialogButtonSchema),
24909 defaultedFunction('onAction', noop),
24910 defaultedFunction('onCancel', noop),
24911 defaultedFunction('onClose', noop),
24912 defaultedFunction('onMessage', noop)
24914 const createUrlDialog = spec => asRaw('dialog', urlDialogSchema, spec);
24916 const getAllObjects = obj => {
24917 if (isObject(obj)) {
24918 return [obj].concat(bind$3(values(obj), getAllObjects));
24919 } else if (isArray(obj)) {
24920 return bind$3(obj, getAllObjects);
24926 const isNamedItem = obj => isString(obj.type) && isString(obj.name);
24927 const dataProcessors = {
24928 checkbox: checkboxDataProcessor,
24929 colorinput: colorInputDataProcessor,
24930 colorpicker: colorPickerDataProcessor,
24931 dropzone: dropZoneDataProcessor,
24932 input: inputDataProcessor,
24933 iframe: iframeDataProcessor,
24934 imagepreview: imagePreviewDataProcessor,
24935 selectbox: selectBoxDataProcessor,
24936 sizeinput: sizeInputDataProcessor,
24937 slider: sliderInputDataProcessor,
24938 listbox: listBoxDataProcessor,
24939 size: sizeInputDataProcessor,
24940 textarea: textAreaDataProcessor,
24941 urlinput: urlInputDataProcessor,
24942 customeditor: customEditorDataProcessor,
24943 collection: collectionDataProcessor,
24944 togglemenuitem: dialogToggleMenuItemDataProcessor
24946 const getDataProcessor = item => Optional.from(dataProcessors[item.type]);
24947 const getNamedItems = structure => filter$2(getAllObjects(structure), isNamedItem);
24949 const createDataValidator = structure => {
24950 const namedItems = getNamedItems(structure);
24951 const fields = bind$3(namedItems, item => getDataProcessor(item).fold(() => [], schema => [requiredOf(item.name, schema)]));
24952 return objOf(fields);
24955 const extract = structure => {
24956 const internalDialog = getOrDie(createDialog(structure));
24957 const dataValidator = createDataValidator(structure);
24958 const initialData = structure.initialData ?? {};
24965 const DialogManager = {
24966 open: (factory, structure) => {
24967 const extraction = extract(structure);
24968 return factory(extraction.internalDialog, extraction.initialData, extraction.dataValidator);
24970 openUrl: (factory, structure) => {
24971 const internalDialog = getOrDie(createUrlDialog(structure));
24972 return factory(internalDialog);
24974 redial: structure => extract(structure)
24977 const toValidValues = values => {
24980 each(values, (value, name) => {
24987 return errors.length > 0 ? Result.error(errors) : Result.value(result);
24990 const renderBodyPanel = (spec, dialogData, backstage) => {
24991 const memForm = record(Form.sketch(parts => ({
24994 classes: ['tox-form'].concat(spec.classes)
24996 components: map$2(spec.items, item => interpretInForm(parts, item, dialogData, backstage))
25001 classes: ['tox-dialog__body']
25006 classes: ['tox-dialog__body-content']
25008 components: [memForm.asSpec()]
25010 behaviours: derive$1([
25013 useTabstopAt: not(isPseudoStop)
25015 ComposingConfigs.memento(memForm),
25016 RepresentingConfigs.memento(memForm, {
25017 postprocess: formValue => toValidValues(formValue).fold(err => {
25018 console.error(err);
25026 const factory$3 = (detail, _spec) => ({
25029 components: detail.components,
25030 events: events$a(detail.action),
25031 behaviours: augment(detail.tabButtonBehaviours, [
25032 Focusing.config({}),
25038 Representing.config({
25041 initialValue: detail.value
25045 domModification: detail.domModification
25047 const TabButton = single({
25050 defaulted('uid', undefined),
25051 required$1('value'),
25052 field$1('dom', 'dom', mergeWithThunk(() => ({
25055 'id': generate$6('aria'),
25056 'aria-selected': 'false'
25059 option$3('action'),
25060 defaulted('domModification', {}),
25061 field('tabButtonBehaviours', [
25071 const schema$1 = constant$1([
25072 required$1('tabs'),
25074 defaulted('clickToDismiss', false),
25075 field('tabbarBehaviours', [
25084 const tabsPart = group({
25085 factory: TabButton,
25088 overrides: barDetail => {
25089 const dismissTab$1 = (tabbar, button) => {
25090 Highlighting.dehighlight(tabbar, button);
25091 emitWith(tabbar, dismissTab(), {
25096 const changeTab$1 = (tabbar, button) => {
25097 Highlighting.highlight(tabbar, button);
25098 emitWith(tabbar, changeTab(), {
25104 action: button => {
25105 const tabbar = button.getSystem().getByUid(barDetail.uid).getOrDie();
25106 const activeButton = Highlighting.isHighlighted(tabbar, button);
25107 const response = (() => {
25108 if (activeButton && barDetail.clickToDismiss) {
25109 return dismissTab$1;
25110 } else if (!activeButton) {
25111 return changeTab$1;
25116 response(tabbar, button);
25118 domModification: { classes: [barDetail.markers.tabClass] }
25122 const parts$1 = constant$1([tabsPart]);
25124 const factory$2 = (detail, components, _spec, _externals) => ({
25128 'debug.sketcher': 'Tabbar',
25129 'domModification': { attributes: { role: 'tablist' } },
25130 'behaviours': augment(detail.tabbarBehaviours, [
25131 Highlighting.config({
25132 highlightClass: detail.markers.selectedClass,
25133 itemClass: detail.markers.tabClass,
25134 onHighlight: (tabbar, tab) => {
25135 set$9(tab.element, 'aria-selected', 'true');
25137 onDehighlight: (tabbar, tab) => {
25138 set$9(tab.element, 'aria-selected', 'false');
25143 getInitial: tabbar => {
25144 return Highlighting.getHighlighted(tabbar).map(tab => tab.element);
25146 selector: '.' + detail.markers.tabClass,
25147 executeOnMove: true
25151 const Tabbar = composite({
25153 configFields: schema$1(),
25154 partFields: parts$1(),
25158 const factory$1 = (detail, _spec) => ({
25161 behaviours: augment(detail.tabviewBehaviours, [Replacing.config({})]),
25162 domModification: { attributes: { role: 'tabpanel' } }
25164 const Tabview = single({
25166 configFields: [field('tabviewBehaviours', [Replacing])],
25170 const schema = constant$1([
25171 defaulted('selectFirst', true),
25172 onHandler('onChangeTab'),
25173 onHandler('onDismissTab'),
25174 defaulted('tabs', []),
25175 field('tabSectionBehaviours', [])
25177 const barPart = required({
25181 requiredObjOf('markers', [
25182 required$1('tabClass'),
25183 required$1('selectedClass')
25187 defaults: detail => {
25188 return { tabs: detail.tabs };
25191 const viewPart = required({
25195 const parts = constant$1([
25200 const factory = (detail, components, _spec, _externals) => {
25201 const changeTab$1 = button => {
25202 const tabValue = Representing.getValue(button);
25203 getPart(button, detail, 'tabview').each(tabview => {
25204 const tabWithValue = find$5(detail.tabs, t => t.value === tabValue);
25205 tabWithValue.each(tabData => {
25206 const panel = tabData.view();
25207 getOpt(button.element, 'id').each(id => {
25208 set$9(tabview.element, 'aria-labelledby', id);
25210 Replacing.set(tabview, panel);
25211 detail.onChangeTab(tabview, button, panel);
25215 const changeTabBy = (section, byPred) => {
25216 getPart(section, detail, 'tabbar').each(tabbar => {
25217 byPred(tabbar).each(emitExecute);
25224 behaviours: get$3(detail.tabSectionBehaviours),
25225 events: derive$2(flatten([
25226 detail.selectFirst ? [runOnAttached((section, _simulatedEvent) => {
25227 changeTabBy(section, Highlighting.getFirst);
25230 run$1(changeTab(), (section, simulatedEvent) => {
25231 const button = simulatedEvent.event.button;
25232 changeTab$1(button);
25234 run$1(dismissTab(), (section, simulatedEvent) => {
25235 const button = simulatedEvent.event.button;
25236 detail.onDismissTab(section, button);
25241 getViewItems: section => {
25242 return getPart(section, detail, 'tabview').map(tabview => Replacing.contents(tabview)).getOr([]);
25244 showTab: (section, tabKey) => {
25245 const getTabIfNotActive = tabbar => {
25246 const candidates = Highlighting.getCandidates(tabbar);
25247 const optTab = find$5(candidates, c => Representing.getValue(c) === tabKey);
25248 return optTab.filter(tab => !Highlighting.isHighlighted(tabbar, tab));
25250 changeTabBy(section, getTabIfNotActive);
25255 const TabSection = composite({
25256 name: 'TabSection',
25257 configFields: schema(),
25258 partFields: parts(),
25261 getViewItems: (apis, component) => apis.getViewItems(component),
25262 showTab: (apis, component, tabKey) => {
25263 apis.showTab(component, tabKey);
25268 const measureHeights = (allTabs, tabview, tabviewComp) => map$2(allTabs, (_tab, i) => {
25269 Replacing.set(tabviewComp, allTabs[i].view());
25270 const rect = tabview.dom.getBoundingClientRect();
25271 Replacing.set(tabviewComp, []);
25272 return rect.height;
25274 const getMaxHeight = heights => head(sort(heights, (a, b) => {
25277 } else if (a < b) {
25283 const getMaxTabviewHeight = (dialog, tabview, tablist) => {
25284 const documentElement$1 = documentElement(dialog).dom;
25285 const rootElm = ancestor(dialog, '.tox-dialog-wrap').getOr(dialog);
25286 const isFixed = get$e(rootElm, 'position') === 'fixed';
25289 maxHeight = Math.max(documentElement$1.clientHeight, window.innerHeight);
25291 maxHeight = Math.max(documentElement$1.offsetHeight, documentElement$1.scrollHeight);
25293 const tabviewHeight = get$d(tabview);
25294 const isTabListBeside = tabview.dom.offsetLeft >= tablist.dom.offsetLeft + get$c(tablist);
25295 const currentTabHeight = isTabListBeside ? Math.max(get$d(tablist), tabviewHeight) : tabviewHeight;
25296 const dialogTopMargin = parseInt(get$e(dialog, 'margin-top'), 10) || 0;
25297 const dialogBottomMargin = parseInt(get$e(dialog, 'margin-bottom'), 10) || 0;
25298 const dialogHeight = get$d(dialog) + dialogTopMargin + dialogBottomMargin;
25299 const chromeHeight = dialogHeight - currentTabHeight;
25300 return maxHeight - chromeHeight;
25302 const showTab = (allTabs, comp) => {
25303 head(allTabs).each(tab => TabSection.showTab(comp, tab.value));
25305 const setTabviewHeight = (tabview, height) => {
25306 set$8(tabview, 'height', height + 'px');
25307 set$8(tabview, 'flex-basis', height + 'px');
25309 const updateTabviewHeight = (dialogBody, tabview, maxTabHeight) => {
25310 ancestor(dialogBody, '[role="dialog"]').each(dialog => {
25311 descendant(dialog, '[role="tablist"]').each(tablist => {
25312 maxTabHeight.get().map(height => {
25313 set$8(tabview, 'height', '0');
25314 set$8(tabview, 'flex-basis', '0');
25315 return Math.min(height, getMaxTabviewHeight(dialog, tabview, tablist));
25316 }).each(height => {
25317 setTabviewHeight(tabview, height);
25322 const getTabview = dialog => descendant(dialog, '[role="tabpanel"]');
25323 const smartMode = allTabs => {
25324 const maxTabHeight = value$2();
25325 const extraEvents = [
25326 runOnAttached(comp => {
25327 const dialog = comp.element;
25328 getTabview(dialog).each(tabview => {
25329 set$8(tabview, 'visibility', 'hidden');
25330 comp.getSystem().getByDom(tabview).toOptional().each(tabviewComp => {
25331 const heights = measureHeights(allTabs, tabview, tabviewComp);
25332 const maxTabHeightOpt = getMaxHeight(heights);
25333 maxTabHeightOpt.fold(maxTabHeight.clear, maxTabHeight.set);
25335 updateTabviewHeight(dialog, tabview, maxTabHeight);
25336 remove$6(tabview, 'visibility');
25337 showTab(allTabs, comp);
25338 requestAnimationFrame(() => {
25339 updateTabviewHeight(dialog, tabview, maxTabHeight);
25343 run$1(windowResize(), comp => {
25344 const dialog = comp.element;
25345 getTabview(dialog).each(tabview => {
25346 updateTabviewHeight(dialog, tabview, maxTabHeight);
25349 run$1(formResizeEvent, (comp, _se) => {
25350 const dialog = comp.element;
25351 getTabview(dialog).each(tabview => {
25352 const oldFocus = active$1(getRootNode(tabview));
25353 set$8(tabview, 'visibility', 'hidden');
25354 const oldHeight = getRaw(tabview, 'height').map(h => parseInt(h, 10));
25355 remove$6(tabview, 'height');
25356 remove$6(tabview, 'flex-basis');
25357 const newHeight = tabview.dom.getBoundingClientRect().height;
25358 const hasGrown = oldHeight.forall(h => newHeight > h);
25360 maxTabHeight.set(newHeight);
25361 updateTabviewHeight(dialog, tabview, maxTabHeight);
25363 oldHeight.each(h => {
25364 setTabviewHeight(tabview, h);
25367 remove$6(tabview, 'visibility');
25368 oldFocus.each(focus$3);
25372 const selectFirst = false;
25379 const SendDataToSectionChannel = 'send-data-to-section';
25380 const SendDataToViewChannel = 'send-data-to-view';
25381 const renderTabPanel = (spec, dialogData, backstage) => {
25382 const storedValue = Cell({});
25383 const updateDataWithForm = form => {
25384 const formData = Representing.getValue(form);
25385 const validData = toValidValues(formData).getOr({});
25386 const currentData = storedValue.get();
25387 const newData = deepMerge(currentData, validData);
25388 storedValue.set(newData);
25390 const setDataOnForm = form => {
25391 const tabData = storedValue.get();
25392 Representing.setValue(form, tabData);
25394 const oldTab = Cell(null);
25395 const allTabs = map$2(spec.tabs, tab => {
25400 classes: ['tox-dialog__body-nav-item']
25402 components: [text$2(backstage.shared.providers.translate(tab.title))],
25404 return [Form.sketch(parts => ({
25407 classes: ['tox-form']
25409 components: map$2(tab.items, item => interpretInForm(parts, item, dialogData, backstage)),
25410 formBehaviours: derive$1([
25413 useTabstopAt: not(isPseudoStop)
25415 config('TabView.form.events', [
25416 runOnAttached(setDataOnForm),
25417 runOnDetached(updateDataWithForm)
25420 channels: wrapAll([
25422 key: SendDataToSectionChannel,
25423 value: { onReceive: updateDataWithForm }
25426 key: SendDataToViewChannel,
25427 value: { onReceive: setDataOnForm }
25436 const tabMode = smartMode(allTabs);
25437 return TabSection.sketch({
25440 classes: ['tox-dialog__body']
25442 onChangeTab: (section, button, _viewItems) => {
25443 const name = Representing.getValue(button);
25444 emitWith(section, formTabChangeEvent, {
25446 oldName: oldTab.get()
25452 TabSection.parts.tabbar({
25455 classes: ['tox-dialog__body-nav']
25457 components: [Tabbar.parts.tabs({})],
25459 tabClass: 'tox-tab',
25460 selectedClass: 'tox-dialog__body-nav-item--active'
25462 tabbarBehaviours: derive$1([Tabstopping.config({})])
25464 TabSection.parts.tabview({
25467 classes: ['tox-dialog__body-content']
25471 selectFirst: tabMode.selectFirst,
25472 tabSectionBehaviours: derive$1([
25473 config('tabpanel', tabMode.extraEvents),
25474 Keying.config({ mode: 'acyclic' }),
25475 Composing.config({ find: comp => head(TabSection.getViewItems(comp)) }),
25476 RepresentingConfigs.withComp(Optional.none(), tsection => {
25477 tsection.getSystem().broadcastOn([SendDataToSectionChannel], {});
25478 return storedValue.get();
25479 }, (tsection, value) => {
25480 storedValue.set(value);
25481 tsection.getSystem().broadcastOn([SendDataToViewChannel], {});
25487 const dialogChannel = generate$6('update-dialog');
25488 const titleChannel = generate$6('update-title');
25489 const bodyChannel = generate$6('update-body');
25490 const footerChannel = generate$6('update-footer');
25491 const bodySendMessageChannel = generate$6('body-send-message');
25493 const renderBody = (spec, dialogId, contentId, backstage, ariaAttrs) => {
25494 const renderComponents = incoming => {
25495 const body = incoming.body;
25496 switch (body.type) {
25498 return [renderTabPanel(body, incoming.initialData, backstage)];
25501 return [renderBodyPanel(body, incoming.initialData, backstage)];
25505 const updateState = (_comp, incoming) => Optional.some({ isTabPanel: () => incoming.body.type === 'tabpanel' });
25506 const ariaAttributes = { 'aria-live': 'polite' };
25510 classes: ['tox-dialog__content-js'],
25512 ...contentId.map(x => ({ id: x })).getOr({}),
25513 ...ariaAttrs ? ariaAttributes : {}
25517 behaviours: derive$1([
25518 ComposingConfigs.childAt(0),
25519 Reflecting.config({
25520 channel: `${ bodyChannel }-${ dialogId }`,
25528 const renderInlineBody = (spec, dialogId, contentId, backstage, ariaAttrs) => renderBody(spec, dialogId, Optional.some(contentId), backstage, ariaAttrs);
25529 const renderModalBody = (spec, dialogId, backstage) => {
25530 const bodySpec = renderBody(spec, dialogId, Optional.none(), backstage, false);
25531 return ModalDialog.parts.body(bodySpec);
25533 const renderIframeBody = spec => {
25537 classes: ['tox-dialog__content-js']
25542 classes: ['tox-dialog__body-iframe']
25544 components: [craft({
25547 attributes: { src: spec.url }
25549 behaviours: derive$1([
25550 Tabstopping.config({}),
25551 Focusing.config({})
25555 behaviours: derive$1([Keying.config({
25557 useTabstopAt: not(isPseudoStop)
25560 return ModalDialog.parts.body(bodySpec);
25563 function _typeof(obj) {
25564 '@babel/helpers - typeof';
25565 return _typeof = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (obj) {
25567 } : function (obj) {
25568 return obj && 'function' == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? 'symbol' : typeof obj;
25571 function _setPrototypeOf(o, p) {
25572 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
25576 return _setPrototypeOf(o, p);
25578 function _isNativeReflectConstruct() {
25579 if (typeof Reflect === 'undefined' || !Reflect.construct)
25581 if (Reflect.construct.sham)
25583 if (typeof Proxy === 'function')
25586 Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {
25593 function _construct(Parent, args, Class) {
25594 if (_isNativeReflectConstruct()) {
25595 _construct = Reflect.construct;
25597 _construct = function _construct(Parent, args, Class) {
25599 a.push.apply(a, args);
25600 var Constructor = Function.bind.apply(Parent, a);
25601 var instance = new Constructor();
25603 _setPrototypeOf(instance, Class.prototype);
25607 return _construct.apply(null, arguments);
25609 function _toConsumableArray(arr) {
25610 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
25612 function _arrayWithoutHoles(arr) {
25613 if (Array.isArray(arr))
25614 return _arrayLikeToArray(arr);
25616 function _iterableToArray(iter) {
25617 if (typeof Symbol !== 'undefined' && iter[Symbol.iterator] != null || iter['@@iterator'] != null)
25618 return Array.from(iter);
25620 function _unsupportedIterableToArray(o, minLen) {
25623 if (typeof o === 'string')
25624 return _arrayLikeToArray(o, minLen);
25625 var n = Object.prototype.toString.call(o).slice(8, -1);
25626 if (n === 'Object' && o.constructor)
25627 n = o.constructor.name;
25628 if (n === 'Map' || n === 'Set')
25629 return Array.from(o);
25630 if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
25631 return _arrayLikeToArray(o, minLen);
25633 function _arrayLikeToArray(arr, len) {
25634 if (len == null || len > arr.length)
25636 for (var i = 0, arr2 = new Array(len); i < len; i++)
25640 function _nonIterableSpread() {
25641 throw new TypeError('Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.');
25643 var hasOwnProperty = Object.hasOwnProperty, setPrototypeOf = Object.setPrototypeOf, isFrozen = Object.isFrozen, getPrototypeOf = Object.getPrototypeOf, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
25644 var freeze = Object.freeze, seal = Object.seal, create = Object.create;
25645 var _ref = typeof Reflect !== 'undefined' && Reflect, apply = _ref.apply, construct = _ref.construct;
25647 apply = function apply(fun, thisValue, args) {
25648 return fun.apply(thisValue, args);
25652 freeze = function freeze(x) {
25657 seal = function seal(x) {
25662 construct = function construct(Func, args) {
25663 return _construct(Func, _toConsumableArray(args));
25666 var arrayForEach = unapply(Array.prototype.forEach);
25667 var arrayPop = unapply(Array.prototype.pop);
25668 var arrayPush = unapply(Array.prototype.push);
25669 var stringToLowerCase = unapply(String.prototype.toLowerCase);
25670 var stringMatch = unapply(String.prototype.match);
25671 var stringReplace = unapply(String.prototype.replace);
25672 var stringIndexOf = unapply(String.prototype.indexOf);
25673 var stringTrim = unapply(String.prototype.trim);
25674 var regExpTest = unapply(RegExp.prototype.test);
25675 var typeErrorCreate = unconstruct(TypeError);
25676 function unapply(func) {
25677 return function (thisArg) {
25678 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
25679 args[_key - 1] = arguments[_key];
25681 return apply(func, thisArg, args);
25684 function unconstruct(func) {
25685 return function () {
25686 for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
25687 args[_key2] = arguments[_key2];
25689 return construct(func, args);
25692 function addToSet(set, array) {
25693 if (setPrototypeOf) {
25694 setPrototypeOf(set, null);
25696 var l = array.length;
25698 var element = array[l];
25699 if (typeof element === 'string') {
25700 var lcElement = stringToLowerCase(element);
25701 if (lcElement !== element) {
25702 if (!isFrozen(array)) {
25703 array[l] = lcElement;
25705 element = lcElement;
25708 set[element] = true;
25712 function clone(object) {
25713 var newObject = create(null);
25715 for (property in object) {
25716 if (apply(hasOwnProperty, object, [property])) {
25717 newObject[property] = object[property];
25722 function lookupGetter(object, prop) {
25723 while (object !== null) {
25724 var desc = getOwnPropertyDescriptor(object, prop);
25727 return unapply(desc.get);
25729 if (typeof desc.value === 'function') {
25730 return unapply(desc.value);
25733 object = getPrototypeOf(object);
25735 function fallbackValue(element) {
25736 console.warn('fallback value for', element);
25739 return fallbackValue;
25741 var html$1 = freeze([
25860 var svg$1 = freeze([
25868 'animatetransform',
25905 var svgFilters = freeze([
25908 'feComponentTransfer',
25910 'feConvolveMatrix',
25911 'feDiffuseLighting',
25912 'feDisplacementMap',
25926 'feSpecularLighting',
25931 var svgDisallowed = freeze([
25938 'font-face-format',
25956 var mathMl$1 = freeze([
25987 var mathMlDisallowed = freeze([
26004 var text = freeze(['#text']);
26005 var html = freeze([
26012 'autopictureinpicture',
26036 'disablepictureinpicture',
26037 'disableremoteplayback',
26120 'alignment-baseline',
26136 'color-interpolation',
26137 'color-interpolation-filters',
26162 'font-size-adjust',
26174 'gradienttransform',
26194 'kernelunitlength',
26203 'maskcontentunits',
26224 'patterncontentunits',
26225 'patterntransform',
26229 'preserveaspectratio',
26245 'specularconstant',
26246 'specularexponent',
26253 'stroke-dasharray',
26254 'stroke-dashoffset',
26257 'stroke-miterlimit',
26268 'transform-origin',
26288 'xchannelselector',
26289 'ychannelselector',
26300 var mathMl = freeze([
26343 'scriptsizemultiplier',
26362 var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
26363 var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
26364 var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
26365 var ARIA_ATTR = seal(/^aria-[\-\w]+$/);
26366 var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
26367 var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
26368 var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
26369 var DOCTYPE_NAME = seal(/^html$/i);
26370 var getGlobal = function getGlobal() {
26371 return typeof window === 'undefined' ? null : window;
26373 var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
26374 if (_typeof(trustedTypes) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
26378 var ATTR_NAME = 'data-tt-policy-suffix';
26379 if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
26380 suffix = document.currentScript.getAttribute(ATTR_NAME);
26382 var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
26384 return trustedTypes.createPolicy(policyName, {
26385 createHTML: function createHTML(html) {
26390 console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
26394 function createDOMPurify() {
26395 var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
26396 var DOMPurify = function DOMPurify(root) {
26397 return createDOMPurify(root);
26399 DOMPurify.version = '2.3.8';
26400 DOMPurify.removed = [];
26401 if (!window || !window.document || window.document.nodeType !== 9) {
26402 DOMPurify.isSupported = false;
26405 var originalDocument = window.document;
26406 var document = window.document;
26407 var DocumentFragment = window.DocumentFragment, HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter, _window$NamedNodeMap = window.NamedNodeMap, NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, HTMLFormElement = window.HTMLFormElement, DOMParser = window.DOMParser, trustedTypes = window.trustedTypes;
26408 var ElementPrototype = Element.prototype;
26409 var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
26410 var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
26411 var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
26412 var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
26413 if (typeof HTMLTemplateElement === 'function') {
26414 var template = document.createElement('template');
26415 if (template.content && template.content.ownerDocument) {
26416 document = template.content.ownerDocument;
26419 var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
26420 var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
26421 var _document = document, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName;
26422 var importNode = originalDocument.importNode;
26423 var documentMode = {};
26425 documentMode = clone(document).documentMode ? document.documentMode : {};
26429 DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
26430 var MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE;
26431 var IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
26432 var ALLOWED_TAGS = null;
26433 var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text)));
26434 var ALLOWED_ATTR = null;
26435 var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml)));
26436 var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
26439 configurable: false,
26443 attributeNameCheck: {
26445 configurable: false,
26449 allowCustomizedBuiltInElements: {
26451 configurable: false,
26456 var FORBID_TAGS = null;
26457 var FORBID_ATTR = null;
26458 var ALLOW_ARIA_ATTR = true;
26459 var ALLOW_DATA_ATTR = true;
26460 var ALLOW_UNKNOWN_PROTOCOLS = false;
26461 var SAFE_FOR_TEMPLATES = false;
26462 var WHOLE_DOCUMENT = false;
26463 var SET_CONFIG = false;
26464 var FORCE_BODY = false;
26465 var RETURN_DOM = false;
26466 var RETURN_DOM_FRAGMENT = false;
26467 var RETURN_TRUSTED_TYPE = false;
26468 var SANITIZE_DOM = true;
26469 var KEEP_CONTENT = true;
26470 var IN_PLACE = false;
26471 var USE_PROFILES = {};
26472 var FORBID_CONTENTS = null;
26473 var DEFAULT_FORBID_CONTENTS = addToSet({}, [
26500 var DATA_URI_TAGS = null;
26501 var DEFAULT_DATA_URI_TAGS = addToSet({}, [
26509 var URI_SAFE_ATTRIBUTES = null;
26510 var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
26526 var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
26527 var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
26528 var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
26529 var NAMESPACE = HTML_NAMESPACE;
26530 var IS_EMPTY_INPUT = false;
26531 var PARSER_MEDIA_TYPE;
26532 var SUPPORTED_PARSER_MEDIA_TYPES = [
26533 'application/xhtml+xml',
26536 var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
26537 var transformCaseFunc;
26539 var formElement = document.createElement('form');
26540 var isRegexOrFunction = function isRegexOrFunction(testValue) {
26541 return testValue instanceof RegExp || testValue instanceof Function;
26543 var _parseConfig = function _parseConfig(cfg) {
26544 if (CONFIG && CONFIG === cfg) {
26547 if (!cfg || _typeof(cfg) !== 'object') {
26551 ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
26552 ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
26553 URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
26554 DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
26555 FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
26556 FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
26557 FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
26558 USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
26559 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
26560 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
26561 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
26562 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
26563 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
26564 RETURN_DOM = cfg.RETURN_DOM || false;
26565 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
26566 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
26567 FORCE_BODY = cfg.FORCE_BODY || false;
26568 SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
26569 KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
26570 IN_PLACE = cfg.IN_PLACE || false;
26571 IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
26572 NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
26573 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
26574 CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
26576 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
26577 CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
26579 if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
26580 CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
26582 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;
26583 transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
26585 } : stringToLowerCase;
26586 if (SAFE_FOR_TEMPLATES) {
26587 ALLOW_DATA_ATTR = false;
26589 if (RETURN_DOM_FRAGMENT) {
26592 if (USE_PROFILES) {
26593 ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
26595 if (USE_PROFILES.html === true) {
26596 addToSet(ALLOWED_TAGS, html$1);
26597 addToSet(ALLOWED_ATTR, html);
26599 if (USE_PROFILES.svg === true) {
26600 addToSet(ALLOWED_TAGS, svg$1);
26601 addToSet(ALLOWED_ATTR, svg);
26602 addToSet(ALLOWED_ATTR, xml);
26604 if (USE_PROFILES.svgFilters === true) {
26605 addToSet(ALLOWED_TAGS, svgFilters);
26606 addToSet(ALLOWED_ATTR, svg);
26607 addToSet(ALLOWED_ATTR, xml);
26609 if (USE_PROFILES.mathMl === true) {
26610 addToSet(ALLOWED_TAGS, mathMl$1);
26611 addToSet(ALLOWED_ATTR, mathMl);
26612 addToSet(ALLOWED_ATTR, xml);
26615 if (cfg.ADD_TAGS) {
26616 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
26617 ALLOWED_TAGS = clone(ALLOWED_TAGS);
26619 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
26621 if (cfg.ADD_ATTR) {
26622 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
26623 ALLOWED_ATTR = clone(ALLOWED_ATTR);
26625 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
26627 if (cfg.ADD_URI_SAFE_ATTR) {
26628 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
26630 if (cfg.FORBID_CONTENTS) {
26631 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
26632 FORBID_CONTENTS = clone(FORBID_CONTENTS);
26634 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
26636 if (KEEP_CONTENT) {
26637 ALLOWED_TAGS['#text'] = true;
26639 if (WHOLE_DOCUMENT) {
26640 addToSet(ALLOWED_TAGS, [
26646 if (ALLOWED_TAGS.table) {
26647 addToSet(ALLOWED_TAGS, ['tbody']);
26648 delete FORBID_TAGS.tbody;
26655 var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
26662 var HTML_INTEGRATION_POINTS = addToSet({}, [
26668 var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
26675 var ALL_SVG_TAGS = addToSet({}, svg$1);
26676 addToSet(ALL_SVG_TAGS, svgFilters);
26677 addToSet(ALL_SVG_TAGS, svgDisallowed);
26678 var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
26679 addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
26680 var _checkValidNamespace = function _checkValidNamespace(element) {
26681 var parent = getParentNode(element);
26682 if (!parent || !parent.tagName) {
26684 namespaceURI: HTML_NAMESPACE,
26685 tagName: 'template'
26688 var tagName = stringToLowerCase(element.tagName);
26689 var parentTagName = stringToLowerCase(parent.tagName);
26690 if (element.namespaceURI === SVG_NAMESPACE) {
26691 if (parent.namespaceURI === HTML_NAMESPACE) {
26692 return tagName === 'svg';
26694 if (parent.namespaceURI === MATHML_NAMESPACE) {
26695 return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
26697 return Boolean(ALL_SVG_TAGS[tagName]);
26699 if (element.namespaceURI === MATHML_NAMESPACE) {
26700 if (parent.namespaceURI === HTML_NAMESPACE) {
26701 return tagName === 'math';
26703 if (parent.namespaceURI === SVG_NAMESPACE) {
26704 return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
26706 return Boolean(ALL_MATHML_TAGS[tagName]);
26708 if (element.namespaceURI === HTML_NAMESPACE) {
26709 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
26712 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
26715 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
26719 var _forceRemove = function _forceRemove(node) {
26720 arrayPush(DOMPurify.removed, { element: node });
26722 node.parentNode.removeChild(node);
26725 node.outerHTML = emptyHTML;
26731 var _removeAttribute = function _removeAttribute(name, node) {
26733 arrayPush(DOMPurify.removed, {
26734 attribute: node.getAttributeNode(name),
26738 arrayPush(DOMPurify.removed, {
26743 node.removeAttribute(name);
26744 if (name === 'is' && !ALLOWED_ATTR[name]) {
26745 if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
26747 _forceRemove(node);
26752 node.setAttribute(name, '');
26758 var _initDocument = function _initDocument(dirty) {
26760 var leadingWhitespace;
26762 dirty = '<remove></remove>' + dirty;
26764 var matches = stringMatch(dirty, /^[\r\n\t ]+/);
26765 leadingWhitespace = matches && matches[0];
26767 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml') {
26768 dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
26770 var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
26771 if (NAMESPACE === HTML_NAMESPACE) {
26773 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
26777 if (!doc || !doc.documentElement) {
26778 doc = implementation.createDocument(NAMESPACE, 'template', null);
26780 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
26784 var body = doc.body || doc.documentElement;
26785 if (dirty && leadingWhitespace) {
26786 body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
26788 if (NAMESPACE === HTML_NAMESPACE) {
26789 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
26791 return WHOLE_DOCUMENT ? doc.documentElement : body;
26793 var _createIterator = function _createIterator(root) {
26794 return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
26796 var _isClobbered = function _isClobbered(elm) {
26797 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');
26799 var _isNode = function _isNode(object) {
26800 return _typeof(Node) === 'object' ? object instanceof Node : object && _typeof(object) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
26802 var _executeHook = function _executeHook(entryPoint, currentNode, data) {
26803 if (!hooks[entryPoint]) {
26806 arrayForEach(hooks[entryPoint], function (hook) {
26807 hook.call(DOMPurify, currentNode, data, CONFIG);
26810 var _sanitizeElements = function _sanitizeElements(currentNode) {
26812 _executeHook('beforeSanitizeElements', currentNode, null);
26813 if (_isClobbered(currentNode)) {
26814 _forceRemove(currentNode);
26817 if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
26818 _forceRemove(currentNode);
26821 var tagName = transformCaseFunc(currentNode.nodeName);
26822 _executeHook('uponSanitizeElement', currentNode, {
26824 allowedTags: ALLOWED_TAGS
26826 if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
26827 _forceRemove(currentNode);
26830 if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
26831 _forceRemove(currentNode);
26834 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
26835 if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
26836 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName))
26838 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName))
26841 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
26842 var parentNode = getParentNode(currentNode) || currentNode.parentNode;
26843 var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
26844 if (childNodes && parentNode) {
26845 var childCount = childNodes.length;
26846 for (var i = childCount - 1; i >= 0; --i) {
26847 parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
26851 _forceRemove(currentNode);
26854 if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
26855 _forceRemove(currentNode);
26858 if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
26859 _forceRemove(currentNode);
26862 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
26863 content = currentNode.textContent;
26864 content = stringReplace(content, MUSTACHE_EXPR$1, ' ');
26865 content = stringReplace(content, ERB_EXPR$1, ' ');
26866 if (currentNode.textContent !== content) {
26867 arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
26868 currentNode.textContent = content;
26871 _executeHook('afterSanitizeElements', currentNode, null);
26874 var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
26875 if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
26878 if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName));
26879 else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName));
26880 else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
26881 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)));
26885 } else if (URI_SAFE_ATTRIBUTES[lcName]);
26886 else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, '')));
26887 else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]);
26888 else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, '')));
26895 var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
26896 return tagName.indexOf('-') > 0;
26898 var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
26903 _executeHook('beforeSanitizeAttributes', currentNode, null);
26904 var attributes = currentNode.attributes;
26912 allowedAttributes: ALLOWED_ATTR
26914 l = attributes.length;
26916 attr = attributes[l];
26917 var _attr = attr, name = _attr.name, namespaceURI = _attr.namespaceURI;
26918 value = name === 'value' ? attr.value : stringTrim(attr.value);
26919 lcName = transformCaseFunc(name);
26920 var initValue = value;
26921 hookEvent.attrName = lcName;
26922 hookEvent.attrValue = value;
26923 hookEvent.keepAttr = true;
26924 hookEvent.forceKeepAttr = undefined;
26925 _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
26926 value = hookEvent.attrValue;
26927 if (hookEvent.forceKeepAttr) {
26930 if (!hookEvent.keepAttr) {
26931 _removeAttribute(name, currentNode);
26934 if (regExpTest(/\/>/i, value)) {
26935 _removeAttribute(name, currentNode);
26938 if (SAFE_FOR_TEMPLATES) {
26939 value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
26940 value = stringReplace(value, ERB_EXPR$1, ' ');
26942 var lcTag = transformCaseFunc(currentNode.nodeName);
26943 if (!_isValidAttribute(lcTag, lcName, value)) {
26944 _removeAttribute(name, currentNode);
26947 if (value !== initValue) {
26949 if (namespaceURI) {
26950 currentNode.setAttributeNS(namespaceURI, name, value);
26952 currentNode.setAttribute(name, value);
26955 _removeAttribute(name, currentNode);
26959 _executeHook('afterSanitizeAttributes', currentNode, null);
26961 var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
26963 var shadowIterator = _createIterator(fragment);
26964 _executeHook('beforeSanitizeShadowDOM', fragment, null);
26965 while (shadowNode = shadowIterator.nextNode()) {
26966 _executeHook('uponSanitizeShadowNode', shadowNode, null);
26967 if (_sanitizeElements(shadowNode)) {
26970 if (shadowNode.content instanceof DocumentFragment) {
26971 _sanitizeShadowDOM(shadowNode.content);
26973 _sanitizeAttributes(shadowNode);
26975 _executeHook('afterSanitizeShadowDOM', fragment, null);
26977 DOMPurify.sanitize = function (dirty, cfg) {
26983 IS_EMPTY_INPUT = !dirty;
26984 if (IS_EMPTY_INPUT) {
26987 if (typeof dirty !== 'string' && !_isNode(dirty)) {
26988 if (typeof dirty.toString !== 'function') {
26989 throw typeErrorCreate('toString is not a function');
26991 dirty = dirty.toString();
26992 if (typeof dirty !== 'string') {
26993 throw typeErrorCreate('dirty is not a string, aborting');
26997 if (!DOMPurify.isSupported) {
26998 if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
26999 if (typeof dirty === 'string') {
27000 return window.toStaticHTML(dirty);
27002 if (_isNode(dirty)) {
27003 return window.toStaticHTML(dirty.outerHTML);
27011 DOMPurify.removed = [];
27012 if (typeof dirty === 'string') {
27016 if (dirty.nodeName) {
27017 var tagName = transformCaseFunc(dirty.nodeName);
27018 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
27019 throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
27022 } else if (dirty instanceof Node) {
27023 body = _initDocument('<!---->');
27024 importedNode = body.ownerDocument.importNode(dirty, true);
27025 if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
27026 body = importedNode;
27027 } else if (importedNode.nodeName === 'HTML') {
27028 body = importedNode;
27030 body.appendChild(importedNode);
27033 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
27034 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
27036 body = _initDocument(dirty);
27038 return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
27041 if (body && FORCE_BODY) {
27042 _forceRemove(body.firstChild);
27044 var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
27045 while (currentNode = nodeIterator.nextNode()) {
27046 if (currentNode.nodeType === 3 && currentNode === oldNode) {
27049 if (_sanitizeElements(currentNode)) {
27052 if (currentNode.content instanceof DocumentFragment) {
27053 _sanitizeShadowDOM(currentNode.content);
27055 _sanitizeAttributes(currentNode);
27056 oldNode = currentNode;
27063 if (RETURN_DOM_FRAGMENT) {
27064 returnNode = createDocumentFragment.call(body.ownerDocument);
27065 while (body.firstChild) {
27066 returnNode.appendChild(body.firstChild);
27071 if (ALLOWED_ATTR.shadowroot) {
27072 returnNode = importNode.call(originalDocument, returnNode, true);
27076 var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
27077 if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
27078 serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
27080 if (SAFE_FOR_TEMPLATES) {
27081 serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
27082 serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
27084 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
27086 DOMPurify.setConfig = function (cfg) {
27090 DOMPurify.clearConfig = function () {
27092 SET_CONFIG = false;
27094 DOMPurify.isValidAttribute = function (tag, attr, value) {
27098 var lcTag = transformCaseFunc(tag);
27099 var lcName = transformCaseFunc(attr);
27100 return _isValidAttribute(lcTag, lcName, value);
27102 DOMPurify.addHook = function (entryPoint, hookFunction) {
27103 if (typeof hookFunction !== 'function') {
27106 hooks[entryPoint] = hooks[entryPoint] || [];
27107 arrayPush(hooks[entryPoint], hookFunction);
27109 DOMPurify.removeHook = function (entryPoint) {
27110 if (hooks[entryPoint]) {
27111 return arrayPop(hooks[entryPoint]);
27114 DOMPurify.removeHooks = function (entryPoint) {
27115 if (hooks[entryPoint]) {
27116 hooks[entryPoint] = [];
27119 DOMPurify.removeAllHooks = function () {
27124 var purify = createDOMPurify();
27126 const sanitizeHtmlString = html => purify().sanitize(html);
27128 const isTouch = global$5.deviceType.isTouch();
27129 const hiddenHeader = (title, close) => ({
27132 styles: { display: 'none' },
27133 classes: ['tox-dialog__header']
27140 const pClose = (onClose, providersBackstage) => ModalDialog.parts.close(Button.sketch({
27145 'tox-button--icon',
27146 'tox-button--naked'
27150 'aria-label': providersBackstage.translate('Close')
27154 buttonBehaviours: derive$1([Tabstopping.config({})])
27156 const pUntitled = () => ModalDialog.parts.title({
27159 classes: ['tox-dialog__title'],
27161 styles: { display: 'none' }
27164 const pBodyMessage = (message, providersBackstage) => ModalDialog.parts.body({
27167 classes: ['tox-dialog__body']
27172 classes: ['tox-dialog__body-content']
27174 components: [{ dom: fromHtml(`<p>${ sanitizeHtmlString(providersBackstage.translate(message)) }</p>`) }]
27177 const pFooter = buttons => ModalDialog.parts.footer({
27180 classes: ['tox-dialog__footer']
27182 components: buttons
27184 const pFooterGroup = (startButtons, endButtons) => [
27188 classes: ['tox-dialog__footer-start']
27190 components: startButtons
27195 classes: ['tox-dialog__footer-end']
27197 components: endButtons
27200 const renderDialog$1 = spec => {
27201 const dialogClass = 'tox-dialog';
27202 const blockerClass = dialogClass + '-wrap';
27203 const blockerBackdropClass = blockerClass + '__backdrop';
27204 const scrollLockClass = dialogClass + '__disable-scroll';
27205 return ModalDialog.sketch({
27206 lazySink: spec.lazySink,
27207 onEscape: comp => {
27208 spec.onEscape(comp);
27209 return Optional.some(true);
27211 useTabstopAt: elem => !isPseudoStop(elem),
27214 classes: [dialogClass].concat(spec.extraClasses),
27216 position: 'relative',
27217 ...spec.extraStyles
27223 ...spec.footer.toArray()
27227 dom: fromHtml(`<div class="${ blockerClass }"></div>`),
27231 classes: isTouch ? [
27232 blockerBackdropClass,
27233 blockerBackdropClass + '--opaque'
27234 ] : [blockerBackdropClass]
27239 dragBlockClass: blockerClass,
27240 modalBehaviours: derive$1([
27241 Focusing.config({}),
27242 config('dialog-events', spec.dialogEvents.concat([runOnSource(focusin(), (comp, _se) => {
27243 Keying.focusIn(comp);
27245 config('scroll-lock', [
27246 runOnAttached(() => {
27247 add$2(body(), scrollLockClass);
27249 runOnDetached(() => {
27250 remove$2(body(), scrollLockClass);
27253 ...spec.extraBehaviours
27256 [execute$5()]: ['dialog-events'],
27257 [attachedToDom()]: [
27260 'alloy.base.behaviour'
27262 [detachedFromDom()]: [
27263 'alloy.base.behaviour',
27272 const renderClose = providersBackstage => Button.sketch({
27277 'tox-button--icon',
27278 'tox-button--naked'
27282 'aria-label': providersBackstage.translate('Close'),
27283 'title': providersBackstage.translate('Close')
27286 components: [render$3('close', {
27288 classes: ['tox-icon']
27289 }, providersBackstage.icons)],
27291 emit(comp, formCancelEvent);
27294 const renderTitle = (spec, dialogId, titleId, providersBackstage) => {
27295 const renderComponents = data => [text$2(providersBackstage.translate(data.title))];
27299 classes: ['tox-dialog__title'],
27300 attributes: { ...titleId.map(x => ({ id: x })).getOr({}) }
27303 behaviours: derive$1([Reflecting.config({
27304 channel: `${ titleChannel }-${ dialogId }`,
27310 const renderDragHandle = () => ({ dom: fromHtml('<div class="tox-dialog__draghandle"></div>') });
27311 const renderInlineHeader = (spec, dialogId, titleId, providersBackstage) => Container.sketch({
27312 dom: fromHtml('<div class="tox-dialog__header"></div>'),
27314 renderTitle(spec, dialogId, Optional.some(titleId), providersBackstage),
27315 renderDragHandle(),
27316 renderClose(providersBackstage)
27318 containerBehaviours: derive$1([Dragging.config({
27320 blockerClass: 'blocker',
27321 getTarget: handle => {
27322 return closest$1(handle, '[role="dialog"]').getOrDie();
27325 getSnapPoints: () => [],
27326 leftAttr: 'data-drag-left',
27327 topAttr: 'data-drag-top'
27331 const renderModalHeader = (spec, dialogId, providersBackstage) => {
27332 const pTitle = ModalDialog.parts.title(renderTitle(spec, dialogId, Optional.none(), providersBackstage));
27333 const pHandle = ModalDialog.parts.draghandle(renderDragHandle());
27334 const pClose = ModalDialog.parts.close(renderClose(providersBackstage));
27335 const components = [pTitle].concat(spec.draggable ? [pHandle] : []).concat([pClose]);
27336 return Container.sketch({
27337 dom: fromHtml('<div class="tox-dialog__header"></div>'),
27342 const getHeader = (title, dialogId, backstage) => renderModalHeader({
27343 title: backstage.shared.providers.translate(title),
27344 draggable: backstage.dialog.isDraggableModal()
27345 }, dialogId, backstage.shared.providers);
27346 const getBusySpec = (message, bs, providers) => ({
27349 classes: ['tox-dialog__busy-spinner'],
27350 attributes: { 'aria-label': providers.translate(message) },
27356 position: 'absolute'
27360 components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
27362 const getEventExtras = (lazyDialog, providers, extra) => ({
27363 onClose: () => extra.closeWindow(),
27364 onBlock: blockEvent => {
27365 ModalDialog.setBusy(lazyDialog(), (_comp, bs) => getBusySpec(blockEvent.message, bs, providers));
27368 ModalDialog.setIdle(lazyDialog());
27371 const renderModalDialog = (spec, initialData, dialogEvents, backstage) => {
27372 const updateState = (_comp, incoming) => Optional.some(incoming);
27373 return build$1(renderDialog$1({
27375 lazySink: backstage.shared.getSink,
27377 Reflecting.config({
27378 channel: `${ dialogChannel }-${ spec.id }`,
27382 RepresentingConfigs.memory({}),
27383 ...spec.extraBehaviours
27385 onEscape: comp => {
27386 emit(comp, formCancelEvent);
27394 [attachedToDom()]: [
27399 'alloy.base.behaviour'
27401 [detachedFromDom()]: [
27402 'alloy.base.behaviour',
27411 const mapMenuButtons = buttons => {
27412 const mapItems = button => {
27413 const items = map$2(button.items, item => {
27414 const cell = Cell(false);
27425 return map$2(buttons, button => {
27426 return button.type === 'menu' ? mapItems(button) : button;
27429 const extractCellsToObject = buttons => foldl(buttons, (acc, button) => {
27430 if (button.type === 'menu') {
27431 const menuButton = button;
27432 return foldl(menuButton.items, (innerAcc, item) => {
27433 innerAcc[item.name] = item.storage;
27440 const initCommonEvents = (fireApiEvent, extras) => [
27441 runWithTarget(focusin(), onFocus),
27442 fireApiEvent(formCloseEvent, (_api, spec) => {
27446 fireApiEvent(formCancelEvent, (api, spec, _event, self) => {
27447 spec.onCancel(api);
27448 emit(self, formCloseEvent);
27450 run$1(formUnblockEvent, (_c, _se) => extras.onUnblock()),
27451 run$1(formBlockEvent, (_c, se) => extras.onBlock(se.event))
27453 const initUrlDialog = (getInstanceApi, extras) => {
27454 const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
27455 withSpec(c, (spec, _c) => {
27456 f(getInstanceApi(), spec, se.event, c);
27459 const withSpec = (c, f) => {
27460 Reflecting.getState(c).get().each(currentDialog => {
27461 f(currentDialog, c);
27465 ...initCommonEvents(fireApiEvent, extras),
27466 fireApiEvent(formActionEvent, (api, spec, event) => {
27467 spec.onAction(api, { name: event.name });
27471 const initDialog = (getInstanceApi, extras, getSink) => {
27472 const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
27473 withSpec(c, (spec, _c) => {
27474 f(getInstanceApi(), spec, se.event, c);
27477 const withSpec = (c, f) => {
27478 Reflecting.getState(c).get().each(currentDialogInit => {
27479 f(currentDialogInit.internalDialog, c);
27483 ...initCommonEvents(fireApiEvent, extras),
27484 fireApiEvent(formSubmitEvent, (api, spec) => spec.onSubmit(api)),
27485 fireApiEvent(formChangeEvent, (api, spec, event) => {
27486 spec.onChange(api, { name: event.name });
27488 fireApiEvent(formActionEvent, (api, spec, event, component) => {
27489 const focusIn = () => Keying.focusIn(component);
27490 const isDisabled = focused => has$1(focused, 'disabled') || getOpt(focused, 'aria-disabled').exists(val => val === 'true');
27491 const rootNode = getRootNode(component.element);
27492 const current = active$1(rootNode);
27493 spec.onAction(api, {
27497 active$1(rootNode).fold(focusIn, focused => {
27498 if (isDisabled(focused)) {
27500 } else if (current.exists(cur => contains(focused, cur) && isDisabled(cur))) {
27503 getSink().toOptional().filter(sink => !contains(sink.element, focused)).each(focusIn);
27507 fireApiEvent(formTabChangeEvent, (api, spec, event) => {
27508 spec.onTabChange(api, {
27509 newTabName: event.name,
27510 oldTabName: event.oldName
27513 runOnDetached(component => {
27514 const api = getInstanceApi();
27515 Representing.setValue(component, api.getData());
27519 const SilverDialogEvents = {
27524 const makeButton = (button, backstage) => renderFooterButton(button, button.type, backstage);
27525 const lookup = (compInSystem, footerButtons, buttonName) => find$5(footerButtons, button => button.name === buttonName).bind(memButton => memButton.memento.getOpt(compInSystem));
27526 const renderComponents = (_data, state) => {
27527 const footerButtons = state.map(s => s.footerButtons).getOr([]);
27528 const buttonGroups = partition$3(footerButtons, button => button.align === 'start');
27529 const makeGroup = (edge, buttons) => Container.sketch({
27532 classes: [`tox-dialog__footer-${ edge }`]
27534 components: map$2(buttons, button => button.memento.asSpec())
27536 const startButtons = makeGroup('start', buttonGroups.pass);
27537 const endButtons = makeGroup('end', buttonGroups.fail);
27543 const renderFooter = (initSpec, dialogId, backstage) => {
27544 const updateState = (comp, data) => {
27545 const footerButtons = map$2(data.buttons, button => {
27546 const memButton = record(makeButton(button, backstage));
27549 align: button.align,
27553 const lookupByName = buttonName => lookup(comp, footerButtons, buttonName);
27554 return Optional.some({
27560 dom: fromHtml('<div class="tox-dialog__footer"></div>'),
27562 behaviours: derive$1([Reflecting.config({
27563 channel: `${ footerChannel }-${ dialogId }`,
27564 initialData: initSpec,
27570 const renderInlineFooter = (initSpec, dialogId, backstage) => renderFooter(initSpec, dialogId, backstage);
27571 const renderModalFooter = (initSpec, dialogId, backstage) => ModalDialog.parts.footer(renderFooter(initSpec, dialogId, backstage));
27573 const getCompByName = (access, name) => {
27574 const root = access.getRoot();
27575 if (root.getSystem().isConnected()) {
27576 const form = Composing.getCurrent(access.getFormWrapper()).getOr(access.getFormWrapper());
27577 return Form.getField(form, name).orThunk(() => {
27578 const footer = access.getFooter();
27579 const footerState = Reflecting.getState(footer).get();
27580 return footerState.bind(f => f.lookupByName(name));
27583 return Optional.none();
27586 const validateData$1 = (access, data) => {
27587 const root = access.getRoot();
27588 return Reflecting.getState(root).get().map(dialogState => getOrDie(asRaw('data', dialogState.dataValidator, data))).getOr(data);
27590 const getDialogApi = (access, doRedial, menuItemStates) => {
27591 const withRoot = f => {
27592 const root = access.getRoot();
27593 if (root.getSystem().isConnected()) {
27597 const getData = () => {
27598 const root = access.getRoot();
27599 const valueComp = root.getSystem().isConnected() ? access.getFormWrapper() : root;
27600 const representedValues = Representing.getValue(valueComp);
27601 const menuItemCurrentState = map$1(menuItemStates, cell => cell.get());
27603 ...representedValues,
27604 ...menuItemCurrentState
27607 const setData = newData => {
27609 const prevData = instanceApi.getData();
27610 const mergedData = deepMerge(prevData, newData);
27611 const newInternalData = validateData$1(access, mergedData);
27612 const form = access.getFormWrapper();
27613 Representing.setValue(form, newInternalData);
27614 each(menuItemStates, (v, k) => {
27615 if (has$2(mergedData, k)) {
27616 v.set(mergedData[k]);
27621 const setEnabled = (name, state) => {
27622 getCompByName(access, name).each(state ? Disabling.enable : Disabling.disable);
27624 const focus = name => {
27625 getCompByName(access, name).each(Focusing.focus);
27627 const block = message => {
27628 if (!isString(message)) {
27629 throw new Error('The dialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
27632 emitWith(root, formBlockEvent, { message });
27635 const unblock = () => {
27637 emit(root, formUnblockEvent);
27640 const showTab = name => {
27642 const body = access.getBody();
27643 const bodyState = Reflecting.getState(body);
27644 if (bodyState.get().exists(b => b.isTabPanel())) {
27645 Composing.getCurrent(body).each(tabSection => {
27646 TabSection.showTab(tabSection, name);
27651 const redial = d => {
27653 const id = access.getId();
27654 const dialogInit = doRedial(d);
27655 root.getSystem().broadcastOn([`${ dialogChannel }-${ id }`], dialogInit);
27656 root.getSystem().broadcastOn([`${ titleChannel }-${ id }`], dialogInit.internalDialog);
27657 root.getSystem().broadcastOn([`${ bodyChannel }-${ id }`], dialogInit.internalDialog);
27658 root.getSystem().broadcastOn([`${ footerChannel }-${ id }`], dialogInit.internalDialog);
27659 instanceApi.setData(dialogInit.initialData);
27662 const close = () => {
27664 emit(root, formCloseEvent);
27667 const instanceApi = {
27678 return instanceApi;
27681 const getDialogSizeClasses = size => {
27684 return ['tox-dialog--width-lg'];
27686 return ['tox-dialog--width-md'];
27691 const renderDialog = (dialogInit, extra, backstage) => {
27692 const dialogId = generate$6('dialog');
27693 const internalDialog = dialogInit.internalDialog;
27694 const header = getHeader(internalDialog.title, dialogId, backstage);
27695 const body = renderModalBody({
27696 body: internalDialog.body,
27697 initialData: internalDialog.initialData
27698 }, dialogId, backstage);
27699 const storedMenuButtons = mapMenuButtons(internalDialog.buttons);
27700 const objOfCells = extractCellsToObject(storedMenuButtons);
27701 const footer = renderModalFooter({ buttons: storedMenuButtons }, dialogId, backstage);
27702 const dialogEvents = SilverDialogEvents.initDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra), backstage.shared.getSink);
27703 const dialogSize = getDialogSizeClasses(internalDialog.size);
27708 footer: Optional.some(footer),
27709 extraClasses: dialogSize,
27710 extraBehaviours: [],
27713 const dialog = renderModalDialog(spec, dialogInit, dialogEvents, backstage);
27714 const modalAccess = (() => {
27715 const getForm = () => {
27716 const outerForm = ModalDialog.getBody(dialog);
27717 return Composing.getCurrent(outerForm).getOr(outerForm);
27720 getId: constant$1(dialogId),
27721 getRoot: constant$1(dialog),
27722 getBody: () => ModalDialog.getBody(dialog),
27723 getFooter: () => ModalDialog.getFooter(dialog),
27724 getFormWrapper: getForm
27727 const instanceApi = getDialogApi(modalAccess, extra.redial, objOfCells);
27734 const renderInlineDialog = (dialogInit, extra, backstage, ariaAttrs) => {
27735 const dialogId = generate$6('dialog');
27736 const dialogLabelId = generate$6('dialog-label');
27737 const dialogContentId = generate$6('dialog-content');
27738 const internalDialog = dialogInit.internalDialog;
27739 const updateState = (_comp, incoming) => Optional.some(incoming);
27740 const memHeader = record(renderInlineHeader({
27741 title: internalDialog.title,
27743 }, dialogId, dialogLabelId, backstage.shared.providers));
27744 const memBody = record(renderInlineBody({
27745 body: internalDialog.body,
27746 initialData: internalDialog.initialData
27747 }, dialogId, dialogContentId, backstage, ariaAttrs));
27748 const storagedMenuButtons = mapMenuButtons(internalDialog.buttons);
27749 const objOfCells = extractCellsToObject(storagedMenuButtons);
27750 const memFooter = record(renderInlineFooter({ buttons: storagedMenuButtons }, dialogId, backstage));
27751 const dialogEvents = SilverDialogEvents.initDialog(() => instanceApi, {
27752 onBlock: event => {
27753 Blocking.block(dialog, (_comp, bs) => getBusySpec(event.message, bs, backstage.shared.providers));
27756 Blocking.unblock(dialog);
27758 onClose: () => extra.closeWindow()
27759 }, backstage.shared.getSink);
27760 const dialog = build$1({
27765 'tox-dialog-inline'
27769 ['aria-labelledby']: dialogLabelId,
27770 ['aria-describedby']: dialogContentId
27778 [execute$5()]: ['execute-on-form'],
27779 [attachedToDom()]: [
27784 behaviours: derive$1([
27788 emit(c, formCloseEvent);
27789 return Optional.some(true);
27791 useTabstopAt: elem => !isPseudoStop(elem) && (name$3(elem) !== 'button' || get$f(elem, 'disabled') !== 'disabled')
27793 Reflecting.config({
27794 channel: `${ dialogChannel }-${ dialogId }`,
27796 initialData: dialogInit
27798 Focusing.config({}),
27799 config('execute-on-form', dialogEvents.concat([runOnSource(focusin(), (comp, _se) => {
27800 Keying.focusIn(comp);
27802 Blocking.config({ getRoot: () => Optional.some(dialog) }),
27803 Replacing.config({}),
27804 RepresentingConfigs.memory({})
27807 memHeader.asSpec(),
27812 const instanceApi = getDialogApi({
27813 getId: constant$1(dialogId),
27814 getRoot: constant$1(dialog),
27815 getFooter: () => memFooter.get(dialog),
27816 getBody: () => memBody.get(dialog),
27817 getFormWrapper: () => {
27818 const body = memBody.get(dialog);
27819 return Composing.getCurrent(body).getOr(body);
27821 }, extra.redial, objOfCells);
27828 var global = tinymce.util.Tools.resolve('tinymce.util.URI');
27830 const getUrlDialogApi = root => {
27831 const withRoot = f => {
27832 if (root.getSystem().isConnected()) {
27836 const block = message => {
27837 if (!isString(message)) {
27838 throw new Error('The urlDialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
27841 emitWith(root, formBlockEvent, { message });
27844 const unblock = () => {
27846 emit(root, formUnblockEvent);
27849 const close = () => {
27851 emit(root, formCloseEvent);
27854 const sendMessage = data => {
27856 root.getSystem().broadcastOn([bodySendMessageChannel], data);
27867 const SUPPORTED_MESSAGE_ACTIONS = [
27875 const isSupportedMessage = data => isObject(data) && SUPPORTED_MESSAGE_ACTIONS.indexOf(data.mceAction) !== -1;
27876 const isCustomMessage = data => !isSupportedMessage(data) && isObject(data) && has$2(data, 'mceAction');
27877 const handleMessage = (editor, api, data) => {
27878 switch (data.mceAction) {
27879 case 'insertContent':
27880 editor.insertContent(data.content);
27883 editor.setContent(data.content);
27885 case 'execCommand':
27886 const ui = isBoolean(data.ui) ? data.ui : false;
27887 editor.execCommand(data.cmd, ui, data.value);
27893 api.block(data.message);
27900 const renderUrlDialog = (internalDialog, extra, editor, backstage) => {
27901 const dialogId = generate$6('dialog');
27902 const header = getHeader(internalDialog.title, dialogId, backstage);
27903 const body = renderIframeBody(internalDialog);
27904 const footer = internalDialog.buttons.bind(buttons => {
27905 if (buttons.length === 0) {
27906 return Optional.none();
27908 return Optional.some(renderModalFooter({ buttons }, dialogId, backstage));
27911 const dialogEvents = SilverDialogEvents.initUrlDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra));
27913 ...internalDialog.height.fold(() => ({}), height => ({
27914 'height': height + 'px',
27915 'max-height': height + 'px'
27917 ...internalDialog.width.fold(() => ({}), width => ({
27918 'width': width + 'px',
27919 'max-width': width + 'px'
27922 const classes = internalDialog.width.isNone() && internalDialog.height.isNone() ? ['tox-dialog--width-lg'] : [];
27923 const iframeUri = new global(internalDialog.url, { base_uri: new global(window.location.href) });
27924 const iframeDomain = `${ iframeUri.protocol }://${ iframeUri.host }${ iframeUri.port ? ':' + iframeUri.port : '' }`;
27925 const messageHandlerUnbinder = unbindable();
27926 const extraBehaviours = [
27927 config('messages', [
27928 runOnAttached(() => {
27929 const unbind = bind(SugarElement.fromDom(window), 'message', e => {
27930 if (iframeUri.isSameOrigin(new global(e.raw.origin))) {
27931 const data = e.raw.data;
27932 if (isSupportedMessage(data)) {
27933 handleMessage(editor, instanceApi, data);
27934 } else if (isCustomMessage(data)) {
27935 internalDialog.onMessage(instanceApi, data);
27939 messageHandlerUnbinder.set(unbind);
27941 runOnDetached(messageHandlerUnbinder.clear)
27945 [bodySendMessageChannel]: {
27946 onReceive: (comp, data) => {
27947 descendant(comp.element, 'iframe').each(iframeEle => {
27948 const iframeWin = iframeEle.dom.contentWindow;
27949 if (isNonNullable(iframeWin)) {
27950 iframeWin.postMessage(data, iframeDomain);
27963 extraClasses: classes,
27965 extraStyles: styles
27967 const dialog = renderModalDialog(spec, internalDialog, dialogEvents, backstage);
27968 const instanceApi = getUrlDialogApi(dialog);
27975 const setup$2 = backstage => {
27976 const sharedBackstage = backstage.shared;
27977 const open = (message, callback) => {
27978 const closeDialog = () => {
27979 ModalDialog.hide(alertDialog);
27982 const memFooterClose = record(renderFooterButton({
27983 name: 'close-alert',
27986 buttonType: Optional.some('primary'),
27989 icon: Optional.none()
27990 }, 'cancel', backstage));
27991 const titleSpec = pUntitled();
27992 const closeSpec = pClose(closeDialog, sharedBackstage.providers);
27993 const alertDialog = build$1(renderDialog$1({
27994 lazySink: () => sharedBackstage.getSink(),
27995 header: hiddenHeader(titleSpec, closeSpec),
27996 body: pBodyMessage(message, sharedBackstage.providers),
27997 footer: Optional.some(pFooter(pFooterGroup([], [memFooterClose.asSpec()]))),
27998 onEscape: closeDialog,
27999 extraClasses: ['tox-alert-dialog'],
28000 extraBehaviours: [],
28002 dialogEvents: [run$1(formCancelEvent, closeDialog)],
28005 ModalDialog.show(alertDialog);
28006 const footerCloseButton = memFooterClose.get(alertDialog);
28007 Focusing.focus(footerCloseButton);
28012 const setup$1 = backstage => {
28013 const sharedBackstage = backstage.shared;
28014 const open = (message, callback) => {
28015 const closeDialog = state => {
28016 ModalDialog.hide(confirmDialog);
28019 const memFooterYes = record(renderFooterButton({
28023 buttonType: Optional.some('primary'),
28026 icon: Optional.none()
28027 }, 'submit', backstage));
28028 const footerNo = renderFooterButton({
28032 buttonType: Optional.some('secondary'),
28035 icon: Optional.none()
28036 }, 'cancel', backstage);
28037 const titleSpec = pUntitled();
28038 const closeSpec = pClose(() => closeDialog(false), sharedBackstage.providers);
28039 const confirmDialog = build$1(renderDialog$1({
28040 lazySink: () => sharedBackstage.getSink(),
28041 header: hiddenHeader(titleSpec, closeSpec),
28042 body: pBodyMessage(message, sharedBackstage.providers),
28043 footer: Optional.some(pFooter(pFooterGroup([], [
28045 memFooterYes.asSpec()
28047 onEscape: () => closeDialog(false),
28048 extraClasses: ['tox-confirm-dialog'],
28049 extraBehaviours: [],
28052 run$1(formCancelEvent, () => closeDialog(false)),
28053 run$1(formSubmitEvent, () => closeDialog(true))
28057 ModalDialog.show(confirmDialog);
28058 const footerYesButton = memFooterYes.get(confirmDialog);
28059 Focusing.focus(footerYesButton);
28064 const validateData = (data, validator) => getOrDie(asRaw('data', validator, data));
28065 const isAlertOrConfirmDialog = target => closest(target, '.tox-alert-dialog') || closest(target, '.tox-confirm-dialog');
28066 const inlineAdditionalBehaviours = (editor, isStickyToolbar, isToolbarLocationTop) => {
28067 if (isStickyToolbar && isToolbarLocationTop) {
28070 return [Docking.config({
28072 lazyContext: () => Optional.some(box$1(SugarElement.fromDom(editor.getContentAreaContainer()))),
28073 fadeInClass: 'tox-dialog-dock-fadein',
28074 fadeOutClass: 'tox-dialog-dock-fadeout',
28075 transitionClass: 'tox-dialog-dock-transition'
28081 const setup = extras => {
28082 const backstage = extras.backstage;
28083 const editor = extras.editor;
28084 const isStickyToolbar$1 = isStickyToolbar(editor);
28085 const alertDialog = setup$2(backstage);
28086 const confirmDialog = setup$1(backstage);
28087 const open = (config, params, closeWindow) => {
28088 if (params !== undefined && params.inline === 'toolbar') {
28089 return openInlineDialog(config, backstage.shared.anchors.inlineDialog(), closeWindow, params.ariaAttrs);
28090 } else if (params !== undefined && params.inline === 'cursor') {
28091 return openInlineDialog(config, backstage.shared.anchors.cursor(), closeWindow, params.ariaAttrs);
28093 return openModalDialog(config, closeWindow);
28096 const openUrl = (config, closeWindow) => openModalUrlDialog(config, closeWindow);
28097 const openModalUrlDialog = (config, closeWindow) => {
28098 const factory = contents => {
28099 const dialog = renderUrlDialog(contents, {
28100 closeWindow: () => {
28101 ModalDialog.hide(dialog.dialog);
28102 closeWindow(dialog.instanceApi);
28104 }, editor, backstage);
28105 ModalDialog.show(dialog.dialog);
28106 return dialog.instanceApi;
28108 return DialogManager.openUrl(factory, config);
28110 const openModalDialog = (config, closeWindow) => {
28111 const factory = (contents, internalInitialData, dataValidator) => {
28112 const initialData = internalInitialData;
28113 const dialogInit = {
28116 internalDialog: contents
28118 const dialog = renderDialog(dialogInit, {
28119 redial: DialogManager.redial,
28120 closeWindow: () => {
28121 ModalDialog.hide(dialog.dialog);
28122 closeWindow(dialog.instanceApi);
28125 ModalDialog.show(dialog.dialog);
28126 dialog.instanceApi.setData(initialData);
28127 return dialog.instanceApi;
28129 return DialogManager.open(factory, config);
28131 const openInlineDialog = (config$1, anchor, closeWindow, ariaAttrs = false) => {
28132 const factory = (contents, internalInitialData, dataValidator) => {
28133 const initialData = validateData(internalInitialData, dataValidator);
28134 const inlineDialog = value$2();
28135 const isToolbarLocationTop = backstage.shared.header.isPositionedAtTop();
28136 const dialogInit = {
28139 internalDialog: contents
28141 const refreshDocking = () => inlineDialog.on(dialog => {
28142 InlineView.reposition(dialog);
28143 Docking.refresh(dialog);
28145 const dialogUi = renderInlineDialog(dialogInit, {
28146 redial: DialogManager.redial,
28147 closeWindow: () => {
28148 inlineDialog.on(InlineView.hide);
28149 editor.off('ResizeEditor', refreshDocking);
28150 inlineDialog.clear();
28151 closeWindow(dialogUi.instanceApi);
28153 }, backstage, ariaAttrs);
28154 const inlineDialogComp = build$1(InlineView.sketch({
28155 lazySink: backstage.shared.getSink,
28160 fireDismissalEventInstead: {},
28161 ...isToolbarLocationTop ? {} : { fireRepositionEventInstead: {} },
28162 inlineBehaviours: derive$1([
28163 config('window-manager-inline-events', [run$1(dismissRequested(), (_comp, _se) => {
28164 emit(dialogUi.dialog, formCancelEvent);
28166 ...inlineAdditionalBehaviours(editor, isStickyToolbar$1, isToolbarLocationTop)
28168 isExtraPart: (_comp, target) => isAlertOrConfirmDialog(target)
28170 inlineDialog.set(inlineDialogComp);
28171 InlineView.showWithin(inlineDialogComp, premade(dialogUi.dialog), { anchor }, Optional.some(body()));
28172 if (!isStickyToolbar$1 || !isToolbarLocationTop) {
28173 Docking.refresh(inlineDialogComp);
28174 editor.on('ResizeEditor', refreshDocking);
28176 dialogUi.instanceApi.setData(initialData);
28177 Keying.focusIn(dialogUi.dialog);
28178 return dialogUi.instanceApi;
28180 return DialogManager.open(factory, config$1);
28182 const confirm = (message, callback) => {
28183 confirmDialog.open(message, callback);
28185 const alert = (message, callback) => {
28186 alertDialog.open(message, callback);
28188 const close = instanceApi => {
28189 instanceApi.close();
28200 const registerOptions = editor => {
28201 register$e(editor);
28202 register$d(editor);
28205 var Theme = () => {
28206 global$a.add('silver', editor => {
28207 registerOptions(editor);
28208 const {getUiMothership, backstage, renderUI} = setup$3(editor);
28209 Autocompleter.register(editor, backstage.shared);
28210 const windowMgr = setup({
28216 getWindowManagerImpl: constant$1(windowMgr),
28217 getNotificationManagerImpl: () => NotificationManagerImpl(editor, { backstage }, getUiMothership())