diff --git a/README.md b/README.md index c7a296b..ff0f6ac 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,7 @@ tinymce: | Bundle version | TinyMCE version | TinyMCE Web Component version | |----------------|-----------------|-------------------------------| +| **3.3** | 7.9.1 | 2.3.2 | | **3.2** | 7.7.2 | 2.1.0 | | **3.1** | 7.6.1 | 2.1.0 | | **3.0** | 7.5.1 | 2.1.0 | diff --git a/package-lock.json b/package-lock.json index 6509714..e25aa6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,6 +59,94 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@ephox/agar": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@ephox/agar/-/agar-8.0.1.tgz", + "integrity": "sha512-2LR/u0oos9GadRoLFDVE6NRDV8Tl9+DYQyouVYn0+7afAYdouyw+nXaoTVG5nnvMG+ofsmldKOC82nJWu0a4kQ==", + "dependencies": { + "@ephox/bedrock-client": "11 || 12 || 13", + "@ephox/bedrock-common": "11 || 12 || 13", + "@ephox/jax": "^7.0.10", + "@ephox/sand": "^6.0.10", + "@ephox/sugar": "^9.3.1", + "@types/sizzle": "^2.3.3", + "fast-check": "^2.0.0", + "sizzle": "^2.3.4" + } + }, + "node_modules/@ephox/bedrock-client": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@ephox/bedrock-client/-/bedrock-client-13.0.0.tgz", + "integrity": "sha512-Zah4+o7wFmYO6x3AHiQ1fIYdWIKMAlgszFqKp+JYrmkmqQG9h25wk2izPvTvJ+UGrORU6W90PrDWuksE1XhcUw==", + "dependencies": { + "@ephox/bedrock-common": "^13.0.0", + "@ephox/dispute": "^1.0.3" + } + }, + "node_modules/@ephox/bedrock-common": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@ephox/bedrock-common/-/bedrock-common-13.0.0.tgz", + "integrity": "sha512-aJ3gtezZ0duGJAniT/+uWi0fFCJRqNdJjumxhCwOVTc2MSsXcyqn70s6FIlrp/Fw2QuyiEqxgormgrmBUbWNWA==", + "dependencies": { + "diff": "^5.0.0" + } + }, + "node_modules/@ephox/dispute": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@ephox/dispute/-/dispute-1.0.16.tgz", + "integrity": "sha512-qHy0c+TX4FZx6xI2EBoBqOjGlbtGqQlvK7uWMNCVkfXveJ/dWhjFKfxRR2fsIN/xOYDQ7uJ/GcD+oDpryxl1dA==", + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/@ephox/jax": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@ephox/jax/-/jax-7.0.10.tgz", + "integrity": "sha512-iDqR2M45ketsSdfQmrjy8xyqVGPiLUTs/FOYBmwUdbBNYifQx9sT2eKQrOmsVYuH6voZaoiXdA0EK8aqHcKGQg==", + "dependencies": { + "@ephox/katamari": "^9.1.6" + } + }, + "node_modules/@ephox/katamari": { + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@ephox/katamari/-/katamari-9.1.6.tgz", + "integrity": "sha512-7R7hcpiIWaDk4t731ppdr3X/hjLZkHTDjJCEgGgTS3ylddodGKtSMS91tISicYjKQXnB06GT+gJoOk3/McazIg==", + "dependencies": { + "@ephox/dispute": "^1.0.3" + } + }, + "node_modules/@ephox/mcagar": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@ephox/mcagar/-/mcagar-9.0.1.tgz", + "integrity": "sha512-iNMP8mkz8AtgiRceU4TAnstQje3RG8yxM/QoWKkriCeh6n5fe1sSfexFRVW3fwZ0bUrjTlyawSqoH0yhESqJjQ==", + "dependencies": { + "@ephox/agar": "^8.0.1", + "@ephox/katamari": "^9.1.6", + "@ephox/sand": "^6.0.10", + "@ephox/sugar": "^9.3.1", + "fast-check": "^2.0.0" + }, + "peerDependencies": { + "tinymce": ">=4.0.0" + } + }, + "node_modules/@ephox/sand": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@ephox/sand/-/sand-6.0.10.tgz", + "integrity": "sha512-q/2Xcjl1O5c9/HHxQiEKGZkGsC68WUjVP5ciDNKqrZd1s1BhA3VWbaubQxxBRt3SwKyBCukfS5gL53qkqTfbkg==", + "dependencies": { + "@ephox/katamari": "^9.1.6" + } + }, + "node_modules/@ephox/sugar": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@ephox/sugar/-/sugar-9.3.1.tgz", + "integrity": "sha512-NQMqDN0zC+IZGuhBuz/7RxncfJsmTBhCHgaqkHOJ5d1E0CIL9afIizBYQ0JSHS3osAb9woGGtwPobjCx3/Srpw==", + "dependencies": { + "@ephox/katamari": "^9.1.6", + "@ephox/sand": "^6.0.10" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", @@ -202,10 +290,24 @@ "node": ">=18" } }, + "node_modules/@tinymce/miniature": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@tinymce/miniature/-/miniature-6.0.0.tgz", + "integrity": "sha512-bLpaTTgbyMHP3V8bucSxvCTVTUjRRk05zDgnlD5Hj2eo6hEyHT1FCqpuhdVLHx9mbCydrlAIhhsY8Ex6Hp8Qqg==", + "dependencies": { + "@ephox/agar": "^8.0.0", + "@ephox/katamari": "^9.1.5", + "@ephox/mcagar": "^9.0.0", + "@ephox/sugar": "^9.3.0" + } + }, "node_modules/@tinymce/tinymce-webcomponent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@tinymce/tinymce-webcomponent/-/tinymce-webcomponent-2.1.0.tgz", - "integrity": "sha512-71pMNHqk2iDEagrrBH+zuUAtgrHaDGDIlgnJsLfA3nHlk8FyhM6eCtPAEwUQtFh0sgPRrx1VNuz/JRawQUdL/g==" + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@tinymce/tinymce-webcomponent/-/tinymce-webcomponent-2.3.2.tgz", + "integrity": "sha512-hDI8Xyc9HxM6eWasg3D7l0aJJHdD6ZWn3axWMLYX6zgAZZDKeeCRa88EAi/s2Cd+/r8cuztpJgnqXUt4Y87PqA==", + "dependencies": { + "@tinymce/miniature": "^6.0.0" + } }, "node_modules/@types/minimist": { "version": "1.2.5", @@ -225,6 +327,11 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "dev": true }, + "node_modules/@types/sizzle": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==" + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -542,6 +649,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -821,6 +936,21 @@ "node": ">=0.10.0" } }, + "node_modules/fast-check": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-2.25.0.tgz", + "integrity": "sha512-wRUT2KD2lAmT75WNIJIHECawoUUMHM0I5jrlLXGtGeqmPL8jl/EldUDjY1VCp6fDY8yflyfUeIOsOBrIbIiArg==", + "dependencies": { + "pure-rand": "^5.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1909,6 +2039,21 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2203,6 +2348,11 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/sizzle": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-kPGev+SiByuzi/YPDTqCwdKLWCaN9+14ve86yH0gP6Efue04xjLYWJrcLC6y1buFyIVXkwHNXPsOTEd1MYVPbQ==" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -2506,9 +2656,9 @@ "dev": true }, "node_modules/tinymce": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-7.7.2.tgz", - "integrity": "sha512-GX7Jd0ac9ph3QM2yei4uOoxytKX096CyG6VkkgQNikY39T6cDldoNgaqzHHlcm62WtdBMCd7Ch+PYaRnQo+NLA==" + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-7.9.1.tgz", + "integrity": "sha512-zaOHwmiP1EqTeLRXAvVriDb00JYnfEjWGPdKEuac7MiZJ5aiDMZ4Unc98Gmajn+PBljOmO1GKV6G0KwWn3+k8A==" }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -2531,6 +2681,11 @@ "node": ">=8" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/public/ext/tinymce-webcomponent.js b/public/ext/tinymce-webcomponent.js index cc1c7da..394b545 100644 --- a/public/ext/tinymce-webcomponent.js +++ b/public/ext/tinymce-webcomponent.js @@ -85,6 +85,49 @@ }; const ScriptLoader = CreateScriptLoader(); + const toInt = str => parseInt(str, 10); + const cmp = (a, b) => { + const delta = a - b; + if (delta === 0) { + return 0; + } + return delta > 0 ? 1 : -1; + }; + const nu = (major, minor, patch) => ({ + major, + minor, + patch + }); + const parse = versionString => { + const parts = /([0-9]+)\.([0-9]+)\.([0-9]+)(?:(\-.+)?)/.exec(versionString); + return parts ? nu(toInt(parts[1]), toInt(parts[2]), toInt(parts[3])) : nu(0, 0, 0); + }; + const compare = (version1, version2) => { + const cmp1 = cmp(version1.major, version2.major); + if (cmp1 !== 0) { + return cmp1; + } + const cmp2 = cmp(version1.minor, version2.minor); + if (cmp2 !== 0) { + return cmp2; + } + const cmp3 = cmp(version1.patch, version2.patch); + if (cmp3 !== 0) { + return cmp3; + } + return 0; + }; + + const createSemVer = tinymce => { + const semver = [ + tinymce.majorVersion, + tinymce.minorVersion + ].join('.'); + return semver.split('.').slice(0, 3).join('.'); + }; + const getVersion = tinymce => parse(createSemVer(tinymce)); + const isLessThan = (tinymce, version) => !tinymce ? false : compare(getVersion(tinymce), parse(version)) === -1; + var Status; (function (Status) { Status[Status['Raw'] = 0] = 'Raw'; @@ -106,10 +149,10 @@ const lookup = values => key => isLookupKey(values, key) ? values[key] : key; const parseGlobal = resolve; const parseString = identity; - const parseFalseOrString = lookup({ 'false': false }); + const parseFalseOrString = lookup({ false: false }); const parseBooleanOrString = lookup({ - 'true': true, - 'false': false + true: true, + false: false }); const parseNumberOrString = value => /^\d+$/.test(value) ? Number.parseInt(value, 10) : value; const configAttributes = { @@ -142,6 +185,7 @@ promotion: parseBooleanOrString }; const configRenames = {}; + const isDisabledOptionSupported = tinymce => !isLessThan(tinymce, '7.6.0'); class TinyMceEditor extends HTMLElement { static get formAssociated() { return true; @@ -217,7 +261,8 @@ 'form', 'readonly', 'autofocus', - 'placeholder' + 'placeholder', + 'disabled' ].concat(nativeEvents).concat(tinyEvents); } constructor() { @@ -302,6 +347,9 @@ if (this.readonly) { config.readonly = true; } + if (this.disabled) { + config.disabled = true; + } if (this.autofocus) { config.auto_focus = true; } @@ -339,7 +387,10 @@ } this._shadowDom.appendChild(target); const baseConfig = this._getConfig(); - const conf = Object.assign(Object.assign({}, baseConfig), { + const conf = Object.assign(Object.assign(Object.assign({}, baseConfig), { + disabled: this.hasAttribute('disabled'), + readonly: this.hasAttribute('readonly') + }), { target, setup: editor => { this._editor = editor; @@ -349,6 +400,9 @@ editor.on('SwitchMode', _e => { this.readonly = this.readonly; }); + editor.on('DisabledStateChange', _e => { + this.disabled = this.disabled; + }); each(this._eventHandlers, (handler, event) => { if (handler !== undefined) { editor.on(event, handler); @@ -359,7 +413,9 @@ } } }); - this._getTinymce().init(conf); + this._getTinymce().init(conf).catch(err => { + console.error('TinyMCE init failed', err); + }); } _getTinymceSrc() { var _a; @@ -367,7 +423,7 @@ if (src) { return src; } - const channel = (_a = this.getAttribute('channel')) !== null && _a !== void 0 ? _a : '6'; + const channel = (_a = this.getAttribute('channel')) !== null && _a !== void 0 ? _a : '8'; const apiKey = this.hasAttribute('api-key') ? this.getAttribute('api-key') : 'no-api-key'; return `https://cdn.tiny.cloud/1/${ apiKey }/tinymce/${ channel }/tinymce.min.js`; } @@ -382,6 +438,8 @@ if (oldValue !== newValue) { if (attribute === 'form') { this._updateForm(); + } else if (attribute === 'disabled') { + this.disabled = newValue !== null; } else if (attribute === 'readonly') { this.readonly = newValue !== null; } else if (attribute === 'autofocus') { @@ -408,6 +466,9 @@ disconnectedCallback() { this._mutationObserver.disconnect(); this._updateForm(); + if (this._editor) { + this._getTinymce().remove(this._editor); + } } get value() { var _a, _b; @@ -443,6 +504,22 @@ } } } + get disabled() { + return this._editor ? this._editor.options.get('disabled') : this.hasAttribute('disabled'); + } + set disabled(value) { + var _a; + const tinymce = (_a = this._getTinymce) === null || _a === void 0 ? void 0 : _a.call(this); + const isVersionNewer = tinymce ? isDisabledOptionSupported(tinymce) : true; + if (this._editor && this._status === Status.Ready && isVersionNewer) { + this._editor.options.set('disabled', value); + } + if (value && !this.hasAttribute('disabled')) { + this.setAttribute('disabled', ''); + } else if (!value && this.hasAttribute('disabled')) { + this.removeAttribute('disabled'); + } + } get placeholder() { return this.getAttribute('placeholder'); } diff --git a/public/ext/tinymce/CHANGELOG.md b/public/ext/tinymce/CHANGELOG.md index 3779d39..4793dd0 100644 --- a/public/ext/tinymce/CHANGELOG.md +++ b/public/ext/tinymce/CHANGELOG.md @@ -5,6 +5,53 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), and is generated by [Changie](https://github.com/miniscruff/changie). +## 7.9.1 - 2025-05-29 + +### Improved +- Update `Notices` file and minified notices. #TINY-12091 + +## 7.9.0 - 2025-05-15 + +### Added +- Added new `disc` style option for unordered lists. #TINY-12015 + +### Improved +- The resize cursor now points in the correct direction for each resize mode. Patch contributed by daniloff200. ##GH-10189 +- If `style_formats` is empty, the button is now disabled. #TINY-12005 +- Inline dialog dropdowns reposition when the dialog is dragged or the window is scrolled. #TINY-11368 +- Bullet list icons were have been updated to better represent the default styles. #TINY-12014 + +### Changed +- The ContextFormSizeInput lock button is now centered instead of aligned to the end. #TINY-11916 +- Changed the default value of `advlist_bullet_styles` option to `default,disc,circle,square`. #TINY-12083 + +### Fixed +- Autolink no longer overrides already existing links when autolinking. #TINY-11836 +- Removed the deprecated CSS media selector `-ms-high-contrast`. #TINY-11876 +- The `mceInsertContent` command no longer deletes the parent block element when an anchor is selected. #TINY-11953 +- Table resizers are now visible when inline editor has a z-index property. #TINY-11981 +- Tabbing inside a `figcaption` element no longer displays two text insertion carets. #TINY-11997 +- Pressing Enter before a floating image no longer duplicates the image. #TINY-11676 +- Editor did not scroll into viewport on receiving focus on Chrome and Safari. #TINY-12017 +- Select UI elements was not properly styled on Chrome version 136. #TINY-12131 + +## 7.8.0 - 2025-04-09 + +### Added +- New subtoolbar support for context toolbars. #TINY-11748 +- New `extended_mathml_attributes` and `extended_mathml_elements` options. #TINY-11756 +- New `onboarding` option. #TINY-11931 + +### Improved +- Focus outline was misaligned with comment card border on saving an edit. #TINY-11329 +- The `editor.selection.scrollIntoView()` method now pads the target scroll area with a small margin, ensuring content doesn't sit at the very edge of the viewport. #TINY-11786 + +### Changed +- Changed promotional text and link. #TINY-11905 + +### Fixed +- Setting editor height to a `pt` or `em` value was ignoring min/max height settings. #TINY-11108 + ## 7.7.2 - 2025-03-19 ### Fixed diff --git a/public/ext/tinymce/composer.json b/public/ext/tinymce/composer.json index 78ecf5e..ab901e5 100644 --- a/public/ext/tinymce/composer.json +++ b/public/ext/tinymce/composer.json @@ -1,6 +1,6 @@ { "name": "tinymce/tinymce", - "version": "7.7.2", + "version": "7.9.1", "description": "Web based JavaScript HTML WYSIWYG editor control.", "license": [ "GPL-2.0-or-later" diff --git a/public/ext/tinymce/icons/default/icons.js b/public/ext/tinymce/icons/default/icons.js index ec26071..1bfa16e 100644 --- a/public/ext/tinymce/icons/default/icons.js +++ b/public/ext/tinymce/icons/default/icons.js @@ -19,7 +19,7 @@ tinymce.IconManager.add('default', { 'bookmark': '', 'border-style': '', 'border-width': '', - 'brightness': '', + 'brightness': '', 'browse': '', 'cancel': '', 'cell-background-color': '', @@ -37,11 +37,11 @@ tinymce.IconManager.add('default', { 'code-sample': '', 'color-levels': '', 'color-picker': '', - 'color-swatch-remove-color': '', + 'color-swatch-remove-color': '', 'color-swatch': '', 'comment-add': '', 'comment': '', - 'contrast': '', + 'contrast': '', 'copy': '', 'crop': '', 'cut-column': '', @@ -67,7 +67,7 @@ tinymce.IconManager.add('default', { 'format': '', 'fullscreen': '', 'gallery': '', - 'gamma': '', + 'gamma': '', 'help': '', 'highlight-bg-color': '', 'home': '', @@ -78,15 +78,16 @@ tinymce.IconManager.add('default', { 'info': '', 'insert-character': '', 'insert-time': '', - 'invert': '', + 'invert': '', 'italic': '', 'language': '', 'line-height': '', 'line': '', 'link': '', - 'list-bull-circle': '', - 'list-bull-default': '', - 'list-bull-square': '', + 'list-bull-circle': '', + 'list-bull-default': '', + 'list-bull-disc': '', + 'list-bull-square': '', 'list-num-default-rtl': '', 'list-num-default': '', 'list-num-lower-alpha-rtl': '', @@ -147,7 +148,7 @@ tinymce.IconManager.add('default', { 'selected': '', 'send': '', 'settings': '', - 'sharpen': '', + 'sharpen': '', 'sourcecode': '', 'spell-check': '', 'strike-through': '', @@ -193,6 +194,7 @@ tinymce.IconManager.add('default', { 'add-file': '', 'adjustments': '', 'alt-text': '', + 'auto-image-enhancement': '', 'blur': '', 'box': '', 'camera': '', @@ -205,16 +207,17 @@ tinymce.IconManager.add('default', { 'folder': '', 'google-drive': '', 'google-photos': '', - 'grayscale': '', + 'grayscale': '', 'huddle': '', 'image-decorative': '', 'image-enhancements': '', 'instagram': '', 'onedrive': '', + 'photo-filter': '', 'revert-changes': '', - 'saturation': '', + 'saturation': '', 'transform-image': '', - 'vibrance': '', + 'vibrance': '', 'vk': '', 'warmth': '', 'user': '', diff --git a/public/ext/tinymce/icons/default/icons.min.js b/public/ext/tinymce/icons/default/icons.min.js index 7cfec79..e177f1f 100644 --- a/public/ext/tinymce/icons/default/icons.min.js +++ b/public/ext/tinymce/icons/default/icons.min.js @@ -1 +1 @@ -tinymce.IconManager.add("default",{icons:{"accessibility-check":'',"accordion-toggle":'',accordion:'',"action-next":'',"action-prev":'',addtag:'',"ai-prompt":'',ai:'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',footnote:'',"format-code":'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',"math-equation":'',mentions:'',minus:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"export-pdf":'',"export-word":'',"import-word":'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"permanent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"revision-history":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',send:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',"template-add":'',template:'',"temporary-placeholder":'',"text-color":'',"text-size-decrease":'',"text-size-increase":'',toc:'',translate:'',typography:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',"add-file":'',adjustments:'',"alt-text":'',blur:'',box:'',camera:'',caption:'',dropbox:'',evernote:'',exposure:'',fb:'',flickr:'',folder:'',"google-drive":'',"google-photos":'',grayscale:'',huddle:'',"image-decorative":'',"image-enhancements":'',instagram:'',onedrive:'',"revert-changes":'',saturation:'',"transform-image":'',vibrance:'',vk:'',warmth:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}}); \ No newline at end of file +tinymce.IconManager.add("default",{icons:{"accessibility-check":'',"accordion-toggle":'',accordion:'',"action-next":'',"action-prev":'',addtag:'',"ai-prompt":'',ai:'',"align-center":'',"align-justify":'',"align-left":'',"align-none":'',"align-right":'',"arrow-left":'',"arrow-right":'',bold:'',bookmark:'',"border-style":'',"border-width":'',brightness:'',browse:'',cancel:'',"cell-background-color":'',"cell-border-color":'',"change-case":'',"character-count":'',"checklist-rtl":'',checklist:'',checkmark:'',"chevron-down":'',"chevron-left":'',"chevron-right":'',"chevron-up":'',close:'',"code-sample":'',"color-levels":'',"color-picker":'',"color-swatch-remove-color":'',"color-swatch":'',"comment-add":'',comment:'',contrast:'',copy:'',crop:'',"cut-column":'',"cut-row":'',cut:'',"document-properties":'',drag:'',"duplicate-column":'',"duplicate-row":'',duplicate:'',"edit-block":'',"edit-image":'',"embed-page":'',embed:'',emoji:'',export:'',fill:'',"flip-horizontally":'',"flip-vertically":'',footnote:'',"format-code":'',"format-painter":'',format:'',fullscreen:'',gallery:'',gamma:'',help:'',"highlight-bg-color":'',home:'',"horizontal-rule":'',"image-options":'',image:'',indent:'',info:'',"insert-character":'',"insert-time":'',invert:'',italic:'',language:'',"line-height":'',line:'',link:'',"list-bull-circle":'',"list-bull-default":'',"list-bull-disc":'',"list-bull-square":'',"list-num-default-rtl":'',"list-num-default":'',"list-num-lower-alpha-rtl":'',"list-num-lower-alpha":'',"list-num-lower-greek-rtl":'',"list-num-lower-greek":'',"list-num-lower-roman-rtl":'',"list-num-lower-roman":'',"list-num-upper-alpha-rtl":'',"list-num-upper-alpha":'',"list-num-upper-roman-rtl":'',"list-num-upper-roman":'',lock:'',ltr:'',"math-equation":'',mentions:'',minus:'',"more-drawer":'',"new-document":'',"new-tab":'',"non-breaking":'',notice:'',"ordered-list-rtl":'',"ordered-list":'',orientation:'',outdent:'',"export-pdf":'',"export-word":'',"import-word":'',"page-break":'',paragraph:'',"paste-column-after":'',"paste-column-before":'',"paste-row-after":'',"paste-row-before":'',"paste-text":'',paste:'',"permanent-pen":'',plus:'',preferences:'',preview:'',print:'',quote:'',redo:'',reload:'',"remove-formatting":'',remove:'',"resize-handle":'',resize:'',"restore-draft":'',"revision-history":'',"rotate-left":'',"rotate-right":'',rtl:'',save:'',search:'',"select-all":'',selected:'',send:'',settings:'',sharpen:'',sourcecode:'',"spell-check":'',"strike-through":'',subscript:'',superscript:'',"table-caption":'',"table-cell-classes":'',"table-cell-properties":'',"table-cell-select-all":'',"table-cell-select-inner":'',"table-classes":'',"table-delete-column":'',"table-delete-row":'',"table-delete-table":'',"table-insert-column-after":'',"table-insert-column-before":'',"table-insert-row-above":'',"table-insert-row-after":'',"table-left-header":'',"table-merge-cells":'',"table-row-numbering-rtl":'',"table-row-numbering":'',"table-row-properties":'',"table-split-cells":'',"table-top-header":'',table:'',"template-add":'',template:'',"temporary-placeholder":'',"text-color":'',"text-size-decrease":'',"text-size-increase":'',toc:'',translate:'',typography:'',underline:'',undo:'',unlink:'',unlock:'',"unordered-list":'',unselected:'',upload:'',"add-file":'',adjustments:'',"alt-text":'',"auto-image-enhancement":'',blur:'',box:'',camera:'',caption:'',dropbox:'',evernote:'',exposure:'',fb:'',flickr:'',folder:'',"google-drive":'',"google-photos":'',grayscale:'',huddle:'',"image-decorative":'',"image-enhancements":'',instagram:'',onedrive:'',"photo-filter":'',"revert-changes":'',saturation:'',"transform-image":'',vibrance:'',vk:'',warmth:'',user:'',"vertical-align":'',visualblocks:'',visualchars:'',warning:'',"zoom-in":'',"zoom-out":''}}); \ No newline at end of file diff --git a/public/ext/tinymce/models/dom/model.js b/public/ext/tinymce/models/dom/model.js index e5c21d8..156ae2c 100644 --- a/public/ext/tinymce/models/dom/model.js +++ b/public/ext/tinymce/models/dom/model.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -7,1270 +7,1484 @@ var global$1 = tinymce.util.Tools.resolve('tinymce.ModelManager'); + /* eslint-disable @typescript-eslint/no-wrapper-object-types */ const hasProto = (v, constructor, predicate) => { - var _a; - if (predicate(v, constructor.prototype)) { - return true; - } else { - return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; - } - }; - const typeOf = x => { - const t = typeof x; - if (x === null) { - return 'null'; - } else if (t === 'object' && Array.isArray(x)) { - return 'array'; - } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { - return 'string'; - } else { - return t; - } + var _a; + if (predicate(v, constructor.prototype)) { + return true; + } + else { + // String-based fallback time + return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; + } + }; + const typeOf = (x) => { + const t = typeof x; + if (x === null) { + return 'null'; + } + else if (t === 'object' && Array.isArray(x)) { + return 'array'; + } + else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { + return 'string'; + } + else { + return t; + } }; - const isType$1 = type => value => typeOf(value) === type; - const isSimpleType = type => value => typeof value === type; - const eq$2 = t => a => t === a; + const isType$1 = (type) => (value) => typeOf(value) === type; + const isSimpleType = (type) => (value) => typeof value === type; + const eq$2 = (t) => (a) => t === a; const isString = isType$1('string'); const isObject = isType$1('object'); const isArray = isType$1('array'); const isNull = eq$2(null); const isBoolean = isSimpleType('boolean'); const isUndefined = eq$2(undefined); - const isNullable = a => a === null || a === undefined; - const isNonNullable = a => !isNullable(a); + const isNullable = (a) => a === null || a === undefined; + const isNonNullable = (a) => !isNullable(a); const isFunction = isSimpleType('function'); const isNumber = isSimpleType('number'); - const noop = () => { - }; + const noop = () => { }; + /** Compose a unary function with an n-ary function */ const compose = (fa, fb) => { - return (...args) => { - return fa(fb.apply(null, args)); - }; + return (...args) => { + return fa(fb.apply(null, args)); + }; }; - const compose1 = (fbc, fab) => a => fbc(fab(a)); - const constant = value => { - return () => { - return value; - }; + /** Compose two unary functions. Similar to compose, but avoids using Function.prototype.apply. */ + const compose1 = (fbc, fab) => (a) => fbc(fab(a)); + const constant = (value) => { + return () => { + return value; + }; }; - const identity = x => { - return x; + const identity = (x) => { + return x; }; const tripleEquals = (a, b) => { - return a === b; + return a === b; }; + // eslint-disable-next-line prefer-arrow/prefer-arrow-functions function curry(fn, ...initialArgs) { - return (...restArgs) => { - const all = initialArgs.concat(restArgs); - return fn.apply(null, all); - }; + return (...restArgs) => { + const all = initialArgs.concat(restArgs); + return fn.apply(null, all); + }; } - const not = f => t => !f(t); - const die = msg => { - return () => { - throw new Error(msg); - }; + const not = (f) => (t) => !f(t); + const die = (msg) => { + return () => { + throw new Error(msg); + }; }; - const apply = f => { - return f(); + const apply = (f) => { + return f(); }; const never = constant(false); const always = constant(true); + /** + * The `Optional` type represents a value (of any type) that potentially does + * not exist. Any `Optional` can either be a `Some` (in which case the + * value does exist) or a `None` (in which case the value does not exist). This + * module defines a whole lot of FP-inspired utility functions for dealing with + * `Optional` objects. + * + * Comparison with null or undefined: + * - We don't get fancy null coalescing operators with `Optional` + * - We do get fancy helper functions with `Optional` + * - `Optional` support nesting, and allow for the type to still be nullable (or + * another `Optional`) + * - There is no option to turn off strict-optional-checks like there is for + * strict-null-checks + */ class Optional { - constructor(tag, value) { - this.tag = tag; - this.value = value; - } - static some(value) { - return new Optional(true, value); - } - static none() { - return Optional.singletonNone; - } - fold(onNone, onSome) { - if (this.tag) { - return onSome(this.value); - } else { - return onNone(); - } - } - isSome() { - return this.tag; - } - isNone() { - return !this.tag; - } - map(mapper) { - if (this.tag) { - return Optional.some(mapper(this.value)); - } else { - return Optional.none(); - } - } - bind(binder) { - if (this.tag) { - return binder(this.value); - } else { - return Optional.none(); - } - } - exists(predicate) { - return this.tag && predicate(this.value); - } - forall(predicate) { - return !this.tag || predicate(this.value); - } - filter(predicate) { - if (!this.tag || predicate(this.value)) { - return this; - } else { - return Optional.none(); - } - } - getOr(replacement) { - return this.tag ? this.value : replacement; - } - or(replacement) { - return this.tag ? this : replacement; - } - getOrThunk(thunk) { - return this.tag ? this.value : thunk(); - } - orThunk(thunk) { - return this.tag ? this : thunk(); - } - getOrDie(message) { - if (!this.tag) { - throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); - } else { - return this.value; - } - } - static from(value) { - return isNonNullable(value) ? Optional.some(value) : Optional.none(); - } - getOrNull() { - return this.tag ? this.value : null; - } - getOrUndefined() { - return this.value; - } - each(worker) { - if (this.tag) { - worker(this.value); - } - } - toArray() { - return this.tag ? [this.value] : []; - } - toString() { - return this.tag ? `some(${ this.value })` : 'none()'; - } + // The internal representation has a `tag` and a `value`, but both are + // private: able to be console.logged, but not able to be accessed by code + constructor(tag, value) { + this.tag = tag; + this.value = value; + } + // --- Identities --- + /** + * Creates a new `Optional` that **does** contain a value. + */ + static some(value) { + return new Optional(true, value); + } + /** + * Create a new `Optional` that **does not** contain a value. `T` can be + * any type because we don't actually have a `T`. + */ + static none() { + return Optional.singletonNone; + } + /** + * Perform a transform on an `Optional` type. Regardless of whether this + * `Optional` contains a value or not, `fold` will return a value of type `U`. + * If this `Optional` does not contain a value, the `U` will be created by + * calling `onNone`. If this `Optional` does contain a value, the `U` will be + * created by calling `onSome`. + * + * For the FP enthusiasts in the room, this function: + * 1. Could be used to implement all of the functions below + * 2. Forms a catamorphism + */ + fold(onNone, onSome) { + if (this.tag) { + return onSome(this.value); + } + else { + return onNone(); + } + } + /** + * Determine if this `Optional` object contains a value. + */ + isSome() { + return this.tag; + } + /** + * Determine if this `Optional` object **does not** contain a value. + */ + isNone() { + return !this.tag; + } + // --- Functor (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. If + * you provide a function to turn a T into a U, this is the function you use + * to turn an `Optional` into an `Optional`. If this **does** contain + * a value then the output will also contain a value (that value being the + * output of `mapper(this.value)`), and if this **does not** contain a value + * then neither will the output. + */ + map(mapper) { + if (this.tag) { + return Optional.some(mapper(this.value)); + } + else { + return Optional.none(); + } + } + // --- Monad (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. + * Unlike `map`, here the transform itself also returns an `Optional`. + */ + bind(binder) { + if (this.tag) { + return binder(this.value); + } + else { + return Optional.none(); + } + } + // --- Traversable (name stolen from Haskell / maths) --- + /** + * For a given predicate, this function finds out if there **exists** a value + * inside this `Optional` object that meets the predicate. In practice, this + * means that for `Optional`s that do not contain a value it returns false (as + * no predicate-meeting value exists). + */ + exists(predicate) { + return this.tag && predicate(this.value); + } + /** + * For a given predicate, this function finds out if **all** the values inside + * this `Optional` object meet the predicate. In practice, this means that + * for `Optional`s that do not contain a value it returns true (as all 0 + * objects do meet the predicate). + */ + forall(predicate) { + return !this.tag || predicate(this.value); + } + filter(predicate) { + if (!this.tag || predicate(this.value)) { + return this; + } + else { + return Optional.none(); + } + } + // --- Getters --- + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. + */ + getOr(replacement) { + return this.tag ? this.value : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` object is also + * `Optional` - meaning that this method will always return an `Optional`. + */ + or(replacement) { + return this.tag ? this : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` value is + * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you + * pass a function which (if called) will **return** the `value` you want to + * use. + */ + getOrThunk(thunk) { + return this.tag ? this.value : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided Optional object does not contain a + * value. + * + * Unlike `or`, in this method the `replacement` value is "thunked" - that is + * to say that you don't pass a value to `orThunk`, you pass a function which + * (if called) will **return** the `value` you want to use. + * + * Unlike `getOrThunk`, in this method the `replacement` value is also + * `Optional`, meaning that this method will always return an `Optional`. + */ + orThunk(thunk) { + return this.tag ? this : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, throwing an + * exception if the provided `Optional` object does not contain a value. + * + * WARNING: + * You should only be using this function if you know that the `Optional` + * object **is not** empty (otherwise you're throwing exceptions in production + * code, which is bad). + * + * In tests this is more acceptable. + * + * Prefer other methods to this, such as `.each`. + */ + getOrDie(message) { + if (!this.tag) { + throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); + } + else { + return this.value; + } + } + // --- Interop with null and undefined --- + /** + * Creates an `Optional` value from a nullable (or undefined-able) input. + * Null, or undefined, is converted to `None`, and anything else is converted + * to `Some`. + */ + static from(value) { + return isNonNullable(value) ? Optional.some(value) : Optional.none(); + } + /** + * Converts an `Optional` to a nullable type, by getting the value if it + * exists, or returning `null` if it does not. + */ + getOrNull() { + return this.tag ? this.value : null; + } + /** + * Converts an `Optional` to an undefined-able type, by getting the value if + * it exists, or returning `undefined` if it does not. + */ + getOrUndefined() { + return this.value; + } + // --- Utilities --- + /** + * If the `Optional` contains a value, perform an action on that value. + * Unlike the rest of the methods on this type, `.each` has side-effects. If + * you want to transform an `Optional` **into** something, then this is not + * the method for you. If you want to use an `Optional` to **do** + * something, then this is the method for you - provided you're okay with not + * doing anything in the case where the `Optional` doesn't have a value inside + * it. If you're not sure whether your use-case fits into transforming + * **into** something or **doing** something, check whether it has a return + * value. If it does, you should be performing a transform. + */ + each(worker) { + if (this.tag) { + worker(this.value); + } + } + /** + * Turn the `Optional` object into an array that contains all of the values + * stored inside the `Optional`. In practice, this means the output will have + * either 0 or 1 elements. + */ + toArray() { + return this.tag ? [this.value] : []; + } + /** + * Turn the `Optional` object into a string for debugging or printing. Not + * recommended for production code, but good for debugging. Also note that + * these days an `Optional` object can be logged to the console directly, and + * its inner value (if it exists) will be visible. + */ + toString() { + return this.tag ? `some(${this.value})` : 'none()'; + } } + // Sneaky optimisation: every instance of Optional.none is identical, so just + // reuse the same object Optional.singletonNone = new Optional(false); + /* eslint-disable @typescript-eslint/unbound-method */ const nativeSlice = Array.prototype.slice; const nativeIndexOf = Array.prototype.indexOf; const nativePush = Array.prototype.push; + /* eslint-enable */ const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t); const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1; const exists = (xs, pred) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - if (pred(x, i)) { - return true; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + if (pred(x, i)) { + return true; + } } - } - return false; + return false; }; const range$1 = (num, f) => { - const r = []; - for (let i = 0; i < num; i++) { - r.push(f(i)); - } - return r; + const r = []; + for (let i = 0; i < num; i++) { + r.push(f(i)); + } + return r; }; const map$1 = (xs, f) => { - const len = xs.length; - const r = new Array(len); - for (let i = 0; i < len; i++) { - const x = xs[i]; - r[i] = f(x, i); - } - return r; + // pre-allocating array size when it's guaranteed to be known + // http://jsperf.com/push-allocated-vs-dynamic/22 + const len = xs.length; + const r = new Array(len); + for (let i = 0; i < len; i++) { + const x = xs[i]; + r[i] = f(x, i); + } + return r; }; + // Unwound implementing other functions in terms of each. + // The code size is roughly the same, and it should allow for better optimisation. + // const each = function(xs: T[], f: (x: T, i?: number, xs?: T[]) => void): void { const each$2 = (xs, f) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - f(x, i); - } + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + f(x, i); + } }; const eachr = (xs, f) => { - for (let i = xs.length - 1; i >= 0; i--) { - const x = xs[i]; - f(x, i); - } + for (let i = xs.length - 1; i >= 0; i--) { + const x = xs[i]; + f(x, i); + } }; const partition = (xs, pred) => { - const pass = []; - const fail = []; - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - const arr = pred(x, i) ? pass : fail; - arr.push(x); - } - return { - pass, - fail - }; + const pass = []; + const fail = []; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + const arr = pred(x, i) ? pass : fail; + arr.push(x); + } + return { pass, fail }; }; const filter$2 = (xs, pred) => { - const r = []; - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - if (pred(x, i)) { - r.push(x); + const r = []; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + if (pred(x, i)) { + r.push(x); + } } - } - return r; + return r; }; const foldr = (xs, f, acc) => { - eachr(xs, (x, i) => { - acc = f(acc, x, i); - }); - return acc; + eachr(xs, (x, i) => { + acc = f(acc, x, i); + }); + return acc; }; const foldl = (xs, f, acc) => { - each$2(xs, (x, i) => { - acc = f(acc, x, i); - }); - return acc; + each$2(xs, (x, i) => { + acc = f(acc, x, i); + }); + return acc; }; const findUntil = (xs, pred, until) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - if (pred(x, i)) { - return Optional.some(x); - } else if (until(x, i)) { - break; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + if (pred(x, i)) { + return Optional.some(x); + } + else if (until(x, i)) { + break; + } } - } - return Optional.none(); + return Optional.none(); }; const find$1 = (xs, pred) => { - return findUntil(xs, pred, never); + return findUntil(xs, pred, never); }; const findIndex = (xs, pred) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - if (pred(x, i)) { - return Optional.some(i); + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + if (pred(x, i)) { + return Optional.some(i); + } } - } - return Optional.none(); + return Optional.none(); }; - const flatten = xs => { - const r = []; - for (let i = 0, len = xs.length; i < len; ++i) { - if (!isArray(xs[i])) { - throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs); + const flatten = (xs) => { + // Note, this is possible because push supports multiple arguments: + // http://jsperf.com/concat-push/6 + // Note that in the past, concat() would silently work (very slowly) for array-like objects. + // With this change it will throw an error. + const r = []; + for (let i = 0, len = xs.length; i < len; ++i) { + // Ensure that each value is an array itself + if (!isArray(xs[i])) { + throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs); + } + nativePush.apply(r, xs[i]); } - nativePush.apply(r, xs[i]); - } - return r; + return r; }; const bind$2 = (xs, f) => flatten(map$1(xs, f)); const forall = (xs, pred) => { - for (let i = 0, len = xs.length; i < len; ++i) { - const x = xs[i]; - if (pred(x, i) !== true) { - return false; + for (let i = 0, len = xs.length; i < len; ++i) { + const x = xs[i]; + if (pred(x, i) !== true) { + return false; + } } - } - return true; + return true; }; - const reverse = xs => { - const r = nativeSlice.call(xs, 0); - r.reverse(); - return r; + const reverse = (xs) => { + const r = nativeSlice.call(xs, 0); + r.reverse(); + return r; }; const mapToObject = (xs, f) => { - const r = {}; - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - r[String(x)] = f(x, i); - } - return r; + const r = {}; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + r[String(x)] = f(x, i); + } + return r; }; const sort$1 = (xs, comparator) => { - const copy = nativeSlice.call(xs, 0); - copy.sort(comparator); - return copy; + const copy = nativeSlice.call(xs, 0); + copy.sort(comparator); + return copy; }; const get$d = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none(); - const head = xs => get$d(xs, 0); - const last$2 = xs => get$d(xs, xs.length - 1); + const head = (xs) => get$d(xs, 0); + const last$2 = (xs) => get$d(xs, xs.length - 1); const findMap = (arr, f) => { - for (let i = 0; i < arr.length; i++) { - const r = f(arr[i], i); - if (r.isSome()) { - return r; + for (let i = 0; i < arr.length; i++) { + const r = f(arr[i], i); + if (r.isSome()) { + return r; + } } - } - return Optional.none(); + return Optional.none(); }; + // There are many variations of Object iteration that are faster than the 'for-in' style: + // http://jsperf.com/object-keys-iteration/107 + // + // Use the native keys if it is available (IE9+), otherwise fall back to manually filtering const keys = Object.keys; + // eslint-disable-next-line @typescript-eslint/unbound-method const hasOwnProperty = Object.hasOwnProperty; const each$1 = (obj, f) => { - const props = keys(obj); - for (let k = 0, len = props.length; k < len; k++) { - const i = props[k]; - const x = obj[i]; - f(x, i); - } + const props = keys(obj); + for (let k = 0, len = props.length; k < len; k++) { + const i = props[k]; + const x = obj[i]; + f(x, i); + } }; const map = (obj, f) => { - return tupleMap(obj, (x, i) => ({ - k: i, - v: f(x, i) - })); + return tupleMap(obj, (x, i) => ({ + k: i, + v: f(x, i) + })); }; const tupleMap = (obj, f) => { - const r = {}; - each$1(obj, (x, i) => { - const tuple = f(x, i); - r[tuple.k] = tuple.v; - }); - return r; + const r = {}; + each$1(obj, (x, i) => { + const tuple = f(x, i); + r[tuple.k] = tuple.v; + }); + return r; }; - const objAcc = r => (x, i) => { - r[i] = x; + const objAcc = (r) => (x, i) => { + r[i] = x; }; const internalFilter = (obj, pred, onTrue, onFalse) => { - each$1(obj, (x, i) => { - (pred(x, i) ? onTrue : onFalse)(x, i); - }); + each$1(obj, (x, i) => { + (pred(x, i) ? onTrue : onFalse)(x, i); + }); }; const filter$1 = (obj, pred) => { - const t = {}; - internalFilter(obj, pred, objAcc(t), noop); - return t; + const t = {}; + internalFilter(obj, pred, objAcc(t), noop); + return t; }; const mapToArray = (obj, f) => { - const r = []; - each$1(obj, (value, name) => { - r.push(f(value, name)); - }); - return r; + const r = []; + each$1(obj, (value, name) => { + r.push(f(value, name)); + }); + return r; }; - const values = obj => { - return mapToArray(obj, identity); + const values = (obj) => { + return mapToArray(obj, identity); }; const get$c = (obj, key) => { - return has$1(obj, key) ? Optional.from(obj[key]) : Optional.none(); + return has$1(obj, key) ? Optional.from(obj[key]) : Optional.none(); }; const has$1 = (obj, key) => hasOwnProperty.call(obj, key); const hasNonNullableKey = (obj, key) => has$1(obj, key) && obj[key] !== undefined && obj[key] !== null; - const isEmpty = r => { - for (const x in r) { - if (hasOwnProperty.call(r, x)) { - return false; + const isEmpty = (r) => { + for (const x in r) { + if (hasOwnProperty.call(r, x)) { + return false; + } } - } - return true; + return true; }; - const Global = typeof window !== 'undefined' ? window : Function('return this;')(); - - const path = (parts, scope) => { - let o = scope !== undefined && scope !== null ? scope : Global; - for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) { - o = o[parts[i]]; - } - return o; + /* + * Generates a church encoded ADT (https://en.wikipedia.org/wiki/Church_encoding) + * For syntax and use, look at the test code. + */ + const generate$1 = (cases) => { + // validation + if (!isArray(cases)) { + throw new Error('cases must be an array'); + } + if (cases.length === 0) { + throw new Error('there must be at least one case'); + } + const constructors = []; + // adt is mutated to add the individual cases + const adt = {}; + each$2(cases, (acase, count) => { + const keys$1 = keys(acase); + // validation + if (keys$1.length !== 1) { + throw new Error('one and only one name per case'); + } + const key = keys$1[0]; + const value = acase[key]; + // validation + if (adt[key] !== undefined) { + throw new Error('duplicate key detected:' + key); + } + else if (key === 'cata') { + throw new Error('cannot have a case named cata (sorry)'); + } + else if (!isArray(value)) { + // this implicitly checks if acase is an object + throw new Error('case arguments must be an array'); + } + constructors.push(key); + // + // constructor for key + // + adt[key] = (...args) => { + const argLength = args.length; + // validation + if (argLength !== value.length) { + throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength); + } + const match = (branches) => { + const branchKeys = keys(branches); + if (constructors.length !== branchKeys.length) { + throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(',')); + } + const allReqd = forall(constructors, (reqKey) => { + return contains$2(branchKeys, reqKey); + }); + if (!allReqd) { + throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', ')); + } + return branches[key].apply(null, args); + }; + // + // the fold function for key + // + return { + fold: (...foldArgs) => { + // runtime validation + if (foldArgs.length !== cases.length) { + throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length); + } + const target = foldArgs[count]; + return target.apply(null, args); + }, + match, + // NOTE: Only for debugging. + log: (label) => { + // eslint-disable-next-line no-console + console.log(label, { + constructors, + constructor: key, + params: args + }); + } + }; + }; + }); + return adt; }; - const resolve$2 = (p, scope) => { - const parts = p.split('.'); - return path(parts, scope); + const Adt = { + generate: generate$1 }; - const unsafe = (name, scope) => { - return resolve$2(name, scope); - }; - const getOrDie = (name, scope) => { - const actual = unsafe(name, scope); - if (actual === undefined || actual === null) { - throw new Error(name + ' not available on this browser'); - } - return actual; + const Cell = (initial) => { + let value = initial; + const get = () => { + return value; + }; + const set = (v) => { + value = v; + }; + return { + get, + set + }; }; - const getPrototypeOf = Object.getPrototypeOf; - const sandHTMLElement = scope => { - return getOrDie('HTMLElement', scope); + const sort = (arr) => { + return arr.slice(0).sort(); }; - const isPrototypeOf = x => { - const scope = resolve$2('ownerDocument.defaultView', x); - return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf(x).constructor.name)); + const reqMessage = (required, keys) => { + throw new Error('All required keys (' + sort(required).join(', ') + ') were not specified. Specified keys were: ' + sort(keys).join(', ') + '.'); }; - - const COMMENT = 8; - const DOCUMENT = 9; - const DOCUMENT_FRAGMENT = 11; - const ELEMENT = 1; - const TEXT = 3; - - const name = element => { - const r = element.dom.nodeName; - return r.toLowerCase(); + const unsuppMessage = (unsupported) => { + throw new Error('Unsupported keys for object: ' + sort(unsupported).join(', ')); }; - const type = element => element.dom.nodeType; - const isType = t => element => type(element) === t; - const isComment = element => type(element) === COMMENT || name(element) === '#comment'; - const isHTMLElement = element => isElement(element) && isPrototypeOf(element.dom); - const isElement = isType(ELEMENT); - const isText = isType(TEXT); - const isDocument = isType(DOCUMENT); - const isDocumentFragment = isType(DOCUMENT_FRAGMENT); - const isTag = tag => e => isElement(e) && name(e) === tag; - - const rawSet = (dom, key, value) => { - if (isString(value) || isBoolean(value) || isNumber(value)) { - dom.setAttribute(key, value + ''); - } else { - console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom); - throw new Error('Attribute value was not simple'); - } + const validateStrArr = (label, array) => { + if (!isArray(array)) { + throw new Error('The ' + label + ' fields must be an array. Was: ' + array + '.'); + } + each$2(array, (a) => { + if (!isString(a)) { + throw new Error('The value ' + a + ' in the ' + label + ' fields was not a string.'); + } + }); }; - const set$2 = (element, key, value) => { - rawSet(element.dom, key, value); + const invalidTypeMessage = (incorrect, type) => { + throw new Error('All values need to be of type: ' + type + '. Keys (' + sort(incorrect).join(', ') + ') were not.'); }; - const setAll$1 = (element, attrs) => { - const dom = element.dom; - each$1(attrs, (v, k) => { - rawSet(dom, k, v); - }); + const checkDupes = (everything) => { + const sorted = sort(everything); + const dupe = find$1(sorted, (s, i) => { + return i < sorted.length - 1 && s === sorted[i + 1]; + }); + dupe.each((d) => { + throw new Error('The field: ' + d + ' occurs more than once in the combined fields: [' + sorted.join(', ') + '].'); + }); }; - const setOptions = (element, attrs) => { - each$1(attrs, (v, k) => { - v.fold(() => { - remove$7(element, k); - }, value => { - rawSet(element.dom, k, value); + + // Ensure that the object has all required fields. They must be functions. + const base = (handleUnsupported, required) => { + return baseWith(handleUnsupported, required, { + validate: isFunction, + label: 'function' }); - }); }; - const get$b = (element, key) => { - const v = element.dom.getAttribute(key); - return v === null ? undefined : v; + // Ensure that the object has all required fields. They must satisy predicates. + const baseWith = (handleUnsupported, required, pred) => { + if (required.length === 0) { + throw new Error('You must specify at least one required field.'); + } + validateStrArr('required', required); + checkDupes(required); + return (obj) => { + const keys$1 = keys(obj); + // Ensure all required keys are present. + const allReqd = forall(required, (req) => { + return contains$2(keys$1, req); + }); + if (!allReqd) { + reqMessage(required, keys$1); + } + handleUnsupported(required, keys$1); + const invalidKeys = filter$2(required, (key) => { + return !pred.validate(obj[key], key); + }); + if (invalidKeys.length > 0) { + invalidTypeMessage(invalidKeys, pred.label); + } + return obj; + }; }; - const getOpt = (element, key) => Optional.from(get$b(element, key)); - const remove$7 = (element, key) => { - element.dom.removeAttribute(key); + const handleExact = (required, keys) => { + const unsupported = filter$2(keys, (key) => { + return !contains$2(required, key); + }); + if (unsupported.length > 0) { + unsuppMessage(unsupported); + } }; - const clone$2 = element => foldl(element.dom.attributes, (acc, attr) => { - acc[attr.name] = attr.value; - return acc; - }, {}); - - const fromHtml$1 = (html, scope) => { - const doc = scope || document; - const div = doc.createElement('div'); - div.innerHTML = html; - if (!div.hasChildNodes() || div.childNodes.length > 1) { - const message = 'HTML does not have a single root node'; - console.error(message, html); - throw new Error(message); - } - return fromDom$1(div.childNodes[0]); + const exactly = (required) => base(handleExact, required); + + /** + * Creates a new `Result` that **does** contain a value. + */ + const value$1 = (value) => { + const applyHelper = (fn) => fn(value); + const constHelper = constant(value); + const outputHelper = () => output; + const output = { + // Debug info + tag: true, + inner: value, + // Actual Result methods + fold: (_onError, onValue) => onValue(value), + isValue: always, + isError: never, + map: (mapper) => Result.value(mapper(value)), + mapError: outputHelper, + bind: applyHelper, + exists: applyHelper, + forall: applyHelper, + getOr: constHelper, + or: outputHelper, + getOrThunk: constHelper, + orThunk: outputHelper, + getOrDie: constHelper, + each: (fn) => { + // Can't write the function inline because we don't want to return something by mistake + fn(value); + }, + toOptional: () => Optional.some(value), + }; + return output; + }; + /** + * Creates a new `Result` that **does not** contain a value, and therefore + * contains an error. + */ + const error = (error) => { + const outputHelper = () => output; + const output = { + // Debug info + tag: false, + inner: error, + // Actual Result methods + fold: (onError, _onValue) => onError(error), + isValue: never, + isError: always, + map: outputHelper, + mapError: (mapper) => Result.error(mapper(error)), + bind: outputHelper, + exists: never, + forall: always, + getOr: identity, + or: identity, + getOrThunk: apply, + orThunk: apply, + getOrDie: die(String(error)), + each: noop, + toOptional: Optional.none, + }; + return output; + }; + /** + * Creates a new `Result` from an `Optional` and an `E`. If the + * `Optional` contains a value, so will the outputted `Result`. If it does not, + * the outputted `Result` will contain an error (and that error will be the + * error passed in). + */ + const fromOption = (optional, err) => optional.fold(() => error(err), value$1); + const Result = { + value: value$1, + error, + fromOption }; - const fromTag = (tag, scope) => { - const doc = scope || document; - const node = doc.createElement(tag); - return fromDom$1(node); + + // Use window object as the global if it's available since CSP will block script evals + // eslint-disable-next-line @typescript-eslint/no-implied-eval + const Global = typeof window !== 'undefined' ? window : Function('return this;')(); + + // This API is intended to give the capability to return namespaced strings. + // For CSS, since dots are not valid class names, the dots are turned into dashes. + const css = (namespace) => { + const dashNamespace = namespace.replace(/\./g, '-'); + const resolve = (str) => { + return dashNamespace + '-' + str; + }; + return { + resolve + }; }; - const fromText = (text, scope) => { - const doc = scope || document; - const node = doc.createTextNode(text); - return fromDom$1(node); + + /** + * **Is** the value stored inside this Optional object equal to `rhs`? + */ + const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs)); + const cat = (arr) => { + const r = []; + const push = (x) => { + r.push(x); + }; + for (let i = 0; i < arr.length; i++) { + arr[i].each(push); + } + return r; }; - const fromDom$1 = node => { - if (node === null || node === undefined) { - throw new Error('Node cannot be null or undefined'); - } - return { dom: node }; + const bindFrom = (a, f) => (a !== undefined && a !== null) ? f(a) : Optional.none(); + // This can help with type inference, by specifying the type param on the none case, so the caller doesn't have to. + const someIf = (b, a) => b ? Optional.some(a) : Optional.none(); + + /** path :: ([String], JsObj?) -> JsObj */ + const path = (parts, scope) => { + let o = scope !== undefined && scope !== null ? scope : Global; + for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) { + o = o[parts[i]]; + } + return o; }; - const fromPoint$1 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1); - const SugarElement = { - fromHtml: fromHtml$1, - fromTag, - fromText, - fromDom: fromDom$1, - fromPoint: fromPoint$1 + /** resolve :: (String, JsObj?) -> JsObj */ + const resolve$2 = (p, scope) => { + const parts = p.split('.'); + return path(parts, scope); }; - const is$2 = (element, selector) => { - const dom = element.dom; - if (dom.nodeType !== ELEMENT) { - return false; - } else { - const elem = dom; - if (elem.matches !== undefined) { - return elem.matches(selector); - } else if (elem.msMatchesSelector !== undefined) { - return elem.msMatchesSelector(selector); - } else if (elem.webkitMatchesSelector !== undefined) { - return elem.webkitMatchesSelector(selector); - } else if (elem.mozMatchesSelector !== undefined) { - return elem.mozMatchesSelector(selector); - } else { - throw new Error('Browser lacks native selectors'); - } - } - }; - const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0; - const all$1 = (selector, scope) => { - const base = scope === undefined ? document : scope.dom; - return bypassSelector(base) ? [] : map$1(base.querySelectorAll(selector), SugarElement.fromDom); + const singleton = (doRevoke) => { + const subject = Cell(Optional.none()); + const revoke = () => subject.get().each(doRevoke); + const clear = () => { + revoke(); + subject.set(Optional.none()); + }; + const isSet = () => subject.get().isSome(); + const get = () => subject.get(); + const set = (s) => { + revoke(); + subject.set(Optional.some(s)); + }; + return { + clear, + isSet, + get, + set + }; }; - const one = (selector, scope) => { - const base = scope === undefined ? document : scope.dom; - return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom); + const value = () => { + const subject = singleton(noop); + const on = (f) => subject.get().each(f); + return { + ...subject, + on + }; }; - const eq$1 = (e1, e2) => e1.dom === e2.dom; - const contains$1 = (e1, e2) => { - const d1 = e1.dom; - const d2 = e2.dom; - return d1 === d2 ? false : d1.contains(d2); - }; - const is$1 = is$2; - - const owner = element => SugarElement.fromDom(element.dom.ownerDocument); - const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos); - const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement); - const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView); - const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom); - const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom); - const parents = (element, isRoot) => { - const stop = isFunction(isRoot) ? isRoot : never; - let dom = element.dom; - const ret = []; - while (dom.parentNode !== null && dom.parentNode !== undefined) { - const rawParent = dom.parentNode; - const p = SugarElement.fromDom(rawParent); - ret.push(p); - if (stop(p) === true) { - break; - } else { - dom = rawParent; - } - } - return ret; - }; - const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom); - const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom); - const children$2 = element => map$1(element.dom.childNodes, SugarElement.fromDom); - const child$2 = (element, index) => { - const cs = element.dom.childNodes; - return Optional.from(cs[index]).map(SugarElement.fromDom); + const removeFromStart = (str, numChars) => { + return str.substring(numChars); }; - const firstChild = element => child$2(element, 0); - const before$3 = (marker, element) => { - const parent$1 = parent(marker); - parent$1.each(v => { - v.dom.insertBefore(element.dom, marker.dom); - }); - }; - const after$5 = (marker, element) => { - const sibling = nextSibling(marker); - sibling.fold(() => { - const parent$1 = parent(marker); - parent$1.each(v => { - append$1(v, element); - }); - }, v => { - before$3(v, element); - }); + const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr; + const removeLeading = (str, prefix) => { + return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str; }; - const prepend = (parent, element) => { - const firstChild$1 = firstChild(parent); - firstChild$1.fold(() => { - append$1(parent, element); - }, v => { - parent.dom.insertBefore(element.dom, v.dom); - }); + const contains$1 = (str, substr, start = 0, end) => { + const idx = str.indexOf(substr, start); + if (idx !== -1) { + return isUndefined(end) ? true : idx + substr.length <= end; + } + else { + return false; + } }; - const append$1 = (parent, element) => { - parent.dom.appendChild(element.dom); + /** Does 'str' start with 'prefix'? + * Note: all strings start with the empty string. + * More formally, for all strings x, startsWith(x, ""). + * This is so that for all strings x and y, startsWith(y + x, y) + */ + const startsWith = (str, prefix) => { + return checkRange(str, prefix, 0); }; - const appendAt = (parent, element, index) => { - child$2(parent, index).fold(() => { - append$1(parent, element); - }, v => { - before$3(v, element); - }); + /** Does 'str' end with 'suffix'? + * Note: all strings end with the empty string. + * More formally, for all strings x, endsWith(x, ""). + * This is so that for all strings x and y, endsWith(x + y, y) + */ + const endsWith = (str, suffix) => { + return checkRange(str, suffix, str.length - suffix.length); }; - const wrap = (element, wrapper) => { - before$3(element, wrapper); - append$1(wrapper, element); + const blank = (r) => (s) => s.replace(r, ''); + /** removes all leading and trailing spaces */ + const trim = blank(/^\s+|\s+$/g); + const isNotEmpty = (s) => s.length > 0; + const toFloat = (value) => { + const num = parseFloat(value); + return isNaN(num) ? Optional.none() : Optional.some(num); + }; + + // Run a function fn after rate ms. If another invocation occurs + // during the time it is waiting, reschedule the function again + // with the new arguments. + const last$1 = (fn, rate) => { + let timer = null; + const cancel = () => { + if (!isNull(timer)) { + clearTimeout(timer); + timer = null; + } + }; + const throttle = (...args) => { + cancel(); + timer = setTimeout(() => { + timer = null; + fn.apply(null, args); + }, rate); + }; + return { + cancel, + throttle + }; }; - const after$4 = (marker, elements) => { - each$2(elements, (x, i) => { - const e = i === 0 ? marker : elements[i - 1]; - after$5(e, x); - }); - }; - const append = (parent, elements) => { - each$2(elements, x => { - append$1(parent, x); - }); - }; - - const empty = element => { - element.dom.textContent = ''; - each$2(children$2(element), rogue => { - remove$6(rogue); - }); - }; - const remove$6 = element => { - const dom = element.dom; - if (dom.parentNode !== null) { - dom.parentNode.removeChild(dom); - } - }; - const unwrap = wrapper => { - const children = children$2(wrapper); - if (children.length > 0) { - after$4(wrapper, children); - } - remove$6(wrapper); - }; - - const clone$1 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep)); - const shallow = original => clone$1(original, false); - const deep = original => clone$1(original, true); - const shallowAs = (original, tag) => { - const nu = SugarElement.fromTag(tag); - const attributes = clone$2(original); - setAll$1(nu, attributes); - return nu; - }; - const copy$2 = (original, tag) => { - const nu = shallowAs(original, tag); - const cloneChildren = children$2(deep(original)); - append(nu, cloneChildren); - return nu; + const cached = (f) => { + let called = false; + let r; + return (...args) => { + if (!called) { + called = true; + r = f.apply(null, args); + } + return r; + }; }; - const mutate$1 = (original, tag) => { - const nu = shallowAs(original, tag); - after$5(original, nu); - const children = children$2(original); - append(nu, children); - remove$6(original); - return nu; - }; - - const validSectionList = [ - 'tfoot', - 'thead', - 'tbody', - 'colgroup' - ]; - const isValidSection = parentName => contains$2(validSectionList, parentName); + + const nbsp = '\u00A0'; + + const validSectionList = ['tfoot', 'thead', 'tbody', 'colgroup']; + const isValidSection = (parentName) => contains$2(validSectionList, parentName); const grid = (rows, columns) => ({ - rows, - columns + rows, + columns }); const address = (row, column) => ({ - row, - column + row, + column }); const detail = (element, rowspan, colspan) => ({ - element, - rowspan, - colspan + element, + rowspan, + colspan }); const detailnew = (element, rowspan, colspan, isNew) => ({ - element, - rowspan, - colspan, - isNew + element, + rowspan, + colspan, + isNew }); const extended = (element, rowspan, colspan, row, column, isLocked) => ({ - element, - rowspan, - colspan, - row, - column, - isLocked + element, + rowspan, + colspan, + row, + column, + isLocked }); const rowdetail = (element, cells, section) => ({ - element, - cells, - section + element, + cells, + section }); const rowdetailnew = (element, cells, section, isNew) => ({ - element, - cells, - section, - isNew + element, + cells, + section, + isNew }); const elementnew = (element, isNew, isLocked) => ({ - element, - isNew, - isLocked + element, + isNew, + isLocked }); const rowcells = (element, cells, section, isNew) => ({ - element, - cells, - section, - isNew + element, + cells, + section, + isNew }); const bounds = (startRow, startCol, finishRow, finishCol) => ({ - startRow, - startCol, - finishRow, - finishCol + startRow, + startCol, + finishRow, + finishCol }); const columnext = (element, colspan, column) => ({ - element, - colspan, - column + element, + colspan, + column }); const colgroup = (element, columns) => ({ - element, - columns + element, + columns }); - const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host); - const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode()); - const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body); - const getShadowRoot = e => { - const r = getRootNode(e); - return isShadowRoot(r) ? Optional.some(r) : Optional.none(); - }; - const getShadowHost = e => SugarElement.fromDom(e.dom.host); - const getOriginalEventTarget = event => { - if (isNonNullable(event.target)) { - const el = SugarElement.fromDom(event.target); - if (isElement(el) && isOpenShadowHost(el)) { - if (event.composed && event.composedPath) { - const composedPath = event.composedPath(); - if (composedPath) { - return head(composedPath); - } - } - } - } - return Optional.from(event.target); + const addCells = (gridRow, index, cells) => { + const existingCells = gridRow.cells; + const before = existingCells.slice(0, index); + const after = existingCells.slice(index); + const newCells = before.concat(cells).concat(after); + return setCells(gridRow, newCells); }; - const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot); - - const inBody = element => { - const dom = isText(element) ? element.dom.parentNode : element.dom; - if (dom === undefined || dom === null || dom.ownerDocument === null) { - return false; - } - const doc = dom.ownerDocument; - return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost)); + const addCell = (gridRow, index, cell) => addCells(gridRow, index, [cell]); + const mutateCell = (gridRow, index, cell) => { + const cells = gridRow.cells; + cells[index] = cell; + }; + const setCells = (gridRow, cells) => rowcells(gridRow.element, cells, gridRow.section, gridRow.isNew); + const mapCells = (gridRow, f) => { + const cells = gridRow.cells; + const r = map$1(cells, f); + return rowcells(gridRow.element, r, gridRow.section, gridRow.isNew); + }; + const getCell = (gridRow, index) => gridRow.cells[index]; + const getCellElement = (gridRow, index) => getCell(gridRow, index).element; + const cellLength = (gridRow) => gridRow.cells.length; + const extractGridDetails = (grid) => { + const result = partition(grid, (row) => row.section === 'colgroup'); + return { + rows: result.fail, + cols: result.pass + }; }; - const body$1 = () => getBody$1(SugarElement.fromDom(document)); - const getBody$1 = doc => { - const b = doc.dom.body; - if (b === null || b === undefined) { - throw new Error('Body is not available yet'); - } - return SugarElement.fromDom(b); + const clone$2 = (gridRow, cloneRow, cloneCell) => { + const newCells = map$1(gridRow.cells, cloneCell); + return rowcells(cloneRow(gridRow.element), newCells, gridRow.section, true); }; - const ancestors$4 = (scope, predicate, isRoot) => filter$2(parents(scope, isRoot), predicate); - const children$1 = (scope, predicate) => filter$2(children$2(scope), predicate); - const descendants$1 = (scope, predicate) => { - let result = []; - each$2(children$2(scope), x => { - if (predicate(x)) { - result = result.concat([x]); + const fromHtml$1 = (html, scope) => { + const doc = scope || document; + const div = doc.createElement('div'); + div.innerHTML = html; + if (!div.hasChildNodes() || div.childNodes.length > 1) { + const message = 'HTML does not have a single root node'; + // eslint-disable-next-line no-console + console.error(message, html); + throw new Error(message); } - result = result.concat(descendants$1(x, predicate)); - }); - return result; - }; - - const ancestors$3 = (scope, selector, isRoot) => ancestors$4(scope, e => is$2(e, selector), isRoot); - const children = (scope, selector) => children$1(scope, e => is$2(e, selector)); - const descendants = (scope, selector) => all$1(selector, scope); - - var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => { - if (is(scope, a)) { - return Optional.some(scope); - } else if (isFunction(isRoot) && isRoot(scope)) { - return Optional.none(); - } else { - return ancestor(scope, a, isRoot); - } + return fromDom$1(div.childNodes[0]); }; - - const ancestor$2 = (scope, predicate, isRoot) => { - let element = scope.dom; - const stop = isFunction(isRoot) ? isRoot : never; - while (element.parentNode) { - element = element.parentNode; - const el = SugarElement.fromDom(element); - if (predicate(el)) { - return Optional.some(el); - } else if (stop(el)) { - break; - } - } - return Optional.none(); - }; - const closest$2 = (scope, predicate, isRoot) => { - const is = (s, test) => test(s); - return ClosestOrAncestor(is, ancestor$2, scope, predicate, isRoot); - }; - const child$1 = (scope, predicate) => { - const pred = node => predicate(SugarElement.fromDom(node)); - const result = find$1(scope.dom.childNodes, pred); - return result.map(SugarElement.fromDom); + const fromTag = (tag, scope) => { + const doc = scope || document; + const node = doc.createElement(tag); + return fromDom$1(node); }; - const descendant$1 = (scope, predicate) => { - const descend = node => { - for (let i = 0; i < node.childNodes.length; i++) { - const child = SugarElement.fromDom(node.childNodes[i]); - if (predicate(child)) { - return Optional.some(child); - } - const res = descend(node.childNodes[i]); - if (res.isSome()) { - return res; - } + const fromText = (text, scope) => { + const doc = scope || document; + const node = doc.createTextNode(text); + return fromDom$1(node); + }; + const fromDom$1 = (node) => { + // TODO: Consider removing this check, but left atm for safety + if (node === null || node === undefined) { + throw new Error('Node cannot be null or undefined'); } - return Optional.none(); - }; - return descend(scope.dom); + return { + dom: node + }; }; - - const ancestor$1 = (scope, selector, isRoot) => ancestor$2(scope, e => is$2(e, selector), isRoot); - const child = (scope, selector) => child$1(scope, e => is$2(e, selector)); - const descendant = (scope, selector) => one(selector, scope); - const closest$1 = (scope, selector, isRoot) => { - const is = (element, selector) => is$2(element, selector); - return ClosestOrAncestor(is, ancestor$1, scope, selector, isRoot); - }; - - const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs)); - const cat = arr => { - const r = []; - const push = x => { - r.push(x); - }; - for (let i = 0; i < arr.length; i++) { - arr[i].each(push); - } - return r; - }; - const bindFrom = (a, f) => a !== undefined && a !== null ? f(a) : Optional.none(); - const someIf = (b, a) => b ? Optional.some(a) : Optional.none(); - - const removeFromStart = (str, numChars) => { - return str.substring(numChars); + const fromPoint$1 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1); + // tslint:disable-next-line:variable-name + const SugarElement = { + fromHtml: fromHtml$1, + fromTag, + fromText, + fromDom: fromDom$1, + fromPoint: fromPoint$1 }; - const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr; - const removeLeading = (str, prefix) => { - return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str; - }; - const contains = (str, substr, start = 0, end) => { - const idx = str.indexOf(substr, start); - if (idx !== -1) { - return isUndefined(end) ? true : idx + substr.length <= end; - } else { - return false; - } - }; - const startsWith = (str, prefix) => { - return checkRange(str, prefix, 0); - }; - const endsWith = (str, suffix) => { - return checkRange(str, suffix, str.length - suffix.length); - }; - const blank = r => s => s.replace(r, ''); - const trim = blank(/^\s+|\s+$/g); - const isNotEmpty = s => s.length > 0; - const toFloat = value => { - const num = parseFloat(value); - return isNaN(num) ? Optional.none() : Optional.some(num); + const selectNode = (win, element) => { + const rng = win.document.createRange(); + rng.selectNode(element.dom); + return rng; }; - - const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue); - - const internalSet = (dom, property, value) => { - if (!isString(value)) { - console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom); - throw new Error('CSS value must be a string: ' + value); - } - if (isSupported(dom)) { - dom.style.setProperty(property, value); - } + const selectNodeContents = (win, element) => { + const rng = win.document.createRange(); + selectNodeContentsUsing(rng, element); + return rng; }; - const internalRemove = (dom, property) => { - if (isSupported(dom)) { - dom.style.removeProperty(property); - } + const selectNodeContentsUsing = (rng, element) => rng.selectNodeContents(element.dom); + // NOTE: Mutates the range. + const setStart = (rng, situ) => { + situ.fold((e) => { + rng.setStartBefore(e.dom); + }, (e, o) => { + rng.setStart(e.dom, o); + }, (e) => { + rng.setStartAfter(e.dom); + }); }; - const set$1 = (element, property, value) => { - const dom = element.dom; - internalSet(dom, property, value); + const setFinish = (rng, situ) => { + situ.fold((e) => { + rng.setEndBefore(e.dom); + }, (e, o) => { + rng.setEnd(e.dom, o); + }, (e) => { + rng.setEndAfter(e.dom); + }); }; - const setAll = (element, css) => { - const dom = element.dom; - each$1(css, (v, k) => { - internalSet(dom, k, v); - }); + const relativeToNative = (win, startSitu, finishSitu) => { + const range = win.document.createRange(); + setStart(range, startSitu); + setFinish(range, finishSitu); + return range; }; - const get$a = (element, property) => { - const dom = element.dom; - const styles = window.getComputedStyle(dom); - const r = styles.getPropertyValue(property); - return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r; + const exactToNative = (win, start, soffset, finish, foffset) => { + const rng = win.document.createRange(); + rng.setStart(start.dom, soffset); + rng.setEnd(finish.dom, foffset); + return rng; + }; + const toRect = (rect) => ({ + left: rect.left, + top: rect.top, + right: rect.right, + bottom: rect.bottom, + width: rect.width, + height: rect.height + }); + const getFirstRect$1 = (rng) => { + const rects = rng.getClientRects(); + // ASSUMPTION: The first rectangle is the start of the selection + const rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect(); + return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none(); }; - const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : ''; - const getRaw$2 = (element, property) => { - const dom = element.dom; - const raw = getUnsafeProperty(dom, property); - return Optional.from(raw).filter(r => r.length > 0); + + const adt$6 = Adt.generate([ + { ltr: ['start', 'soffset', 'finish', 'foffset'] }, + { rtl: ['start', 'soffset', 'finish', 'foffset'] } + ]); + const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset); + const getRanges = (win, selection) => selection.match({ + domRange: (rng) => { + return { + ltr: constant(rng), + rtl: Optional.none + }; + }, + relative: (startSitu, finishSitu) => { + return { + ltr: cached(() => relativeToNative(win, startSitu, finishSitu)), + rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu))) + }; + }, + exact: (start, soffset, finish, foffset) => { + return { + ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)), + rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset))) + }; + } + }); + const doDiagnose = (win, ranges) => { + // If we cannot create a ranged selection from start > finish, it could be RTL + const rng = ranges.ltr(); + if (rng.collapsed) { + // Let's check if it's RTL ... if it is, then reversing the direction will not be collapsed + const reversed = ranges.rtl().filter((rev) => rev.collapsed === false); + return reversed.map((rev) => + // We need to use "reversed" here, because the original only has one point (collapsed) + adt$6.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$6.ltr, rng)); + } + else { + return fromRange(win, adt$6.ltr, rng); + } }; - const remove$5 = (element, property) => { - const dom = element.dom; - internalRemove(dom, property); - if (is(getOpt(element, 'style').map(trim), '')) { - remove$7(element, 'style'); - } + const diagnose = (win, selection) => { + const ranges = getRanges(win, selection); + return doDiagnose(win, ranges); }; - const copy$1 = (source, target) => { - const sourceDom = source.dom; - const targetDom = target.dom; - if (isSupported(sourceDom) && isSupported(targetDom)) { - targetDom.style.cssText = sourceDom.style.cssText; - } + const asLtrRange = (win, selection) => { + const diagnosis = diagnose(win, selection); + return diagnosis.match({ + ltr: (start, soffset, finish, foffset) => { + const rng = win.document.createRange(); + rng.setStart(start.dom, soffset); + rng.setEnd(finish.dom, foffset); + return rng; + }, + rtl: (start, soffset, finish, foffset) => { + // NOTE: Reversing start and finish + const rng = win.document.createRange(); + rng.setStart(finish.dom, foffset); + rng.setEnd(start.dom, soffset); + return rng; + } + }); }; + adt$6.ltr; + adt$6.rtl; - const getAttrValue = (cell, name, fallback = 0) => getOpt(cell, name).map(value => parseInt(value, 10)).getOr(fallback); - const getSpan = (cell, type) => getAttrValue(cell, type, 1); - const hasColspan = cellOrCol => { - if (isTag('col')(cellOrCol)) { - return getAttrValue(cellOrCol, 'span', 1) > 1; - } else { - return getSpan(cellOrCol, 'colspan') > 1; - } - }; - const hasRowspan = cell => getSpan(cell, 'rowspan') > 1; - const getCssValue = (element, property) => parseInt(get$a(element, property), 10); - const minWidth = constant(10); - const minHeight = constant(10); + const COMMENT = 8; + const DOCUMENT = 9; + const DOCUMENT_FRAGMENT = 11; + const ELEMENT = 1; + const TEXT = 3; - const firstLayer = (scope, selector) => { - return filterFirstLayer(scope, selector, always); - }; - const filterFirstLayer = (scope, selector, predicate) => { - return bind$2(children$2(scope), x => { - if (is$2(x, selector)) { - return predicate(x) ? [x] : []; - } else { - return filterFirstLayer(x, selector, predicate); + const is$1 = (element, selector) => { + const dom = element.dom; + if (dom.nodeType !== ELEMENT) { + return false; + } + else { + const elem = dom; + if (elem.matches !== undefined) { + return elem.matches(selector); + } + else if (elem.msMatchesSelector !== undefined) { + return elem.msMatchesSelector(selector); + } + else if (elem.webkitMatchesSelector !== undefined) { + return elem.webkitMatchesSelector(selector); + } + else if (elem.mozMatchesSelector !== undefined) { + // cast to any as mozMatchesSelector doesn't exist in TS DOM lib + return elem.mozMatchesSelector(selector); + } + else { + throw new Error('Browser lacks native selectors'); + } // unfortunately we can't throw this on startup :( } - }); }; - - const lookup = (tags, element, isRoot = never) => { - if (isRoot(element)) { - return Optional.none(); - } - if (contains$2(tags, name(element))) { - return Optional.some(element); - } - const isRootOrUpperTable = elm => is$2(elm, 'table') || isRoot(elm); - return ancestor$1(element, tags.join(','), isRootOrUpperTable); - }; - const cell = (element, isRoot) => lookup([ - 'td', - 'th' - ], element, isRoot); - const cells$1 = ancestor => firstLayer(ancestor, 'th,td'); - const columns$1 = ancestor => { - if (is$2(ancestor, 'colgroup')) { - return children(ancestor, 'col'); - } else { - return bind$2(columnGroups(ancestor), columnGroup => children(columnGroup, 'col')); - } + const bypassSelector = (dom) => + // Only elements, documents and shadow roots support querySelector + // shadow root element type is DOCUMENT_FRAGMENT + dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || + // IE fix for complex queries on empty nodes: http://jsfiddle.net/spyder/fv9ptr5L/ + dom.childElementCount === 0; + const all$1 = (selector, scope) => { + const base = scope === undefined ? document : scope.dom; + return bypassSelector(base) ? [] : map$1(base.querySelectorAll(selector), SugarElement.fromDom); }; - const table = (element, isRoot) => closest$1(element, 'table', isRoot); - const rows$1 = ancestor => firstLayer(ancestor, 'tr'); - const columnGroups = ancestor => table(ancestor).fold(constant([]), table => children(table, 'colgroup')); - - const fromRowsOrColGroups = (elems, getSection) => map$1(elems, row => { - if (name(row) === 'colgroup') { - const cells = map$1(columns$1(row), column => { - const colspan = getAttrValue(column, 'span', 1); - return detail(column, 1, colspan); - }); - return rowdetail(row, cells, 'colgroup'); - } else { - const cells = map$1(cells$1(row), cell => { - const rowspan = getAttrValue(cell, 'rowspan', 1); - const colspan = getAttrValue(cell, 'colspan', 1); - return detail(cell, rowspan, colspan); - }); - return rowdetail(row, cells, getSection(row)); - } - }); - const getParentSection = group => parent(group).map(parent => { - const parentName = name(parent); - return isValidSection(parentName) ? parentName : 'tbody'; - }).getOr('tbody'); - const fromTable$1 = table => { - const rows = rows$1(table); - const columnGroups$1 = columnGroups(table); - const elems = [ - ...columnGroups$1, - ...rows - ]; - return fromRowsOrColGroups(elems, getParentSection); + const one = (selector, scope) => { + const base = scope === undefined ? document : scope.dom; + return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom); }; - const fromPastedRows = (elems, section) => fromRowsOrColGroups(elems, () => section); - const cached = f => { - let called = false; - let r; - return (...args) => { - if (!called) { - called = true; - r = f.apply(null, args); - } - return r; - }; + const eq$1 = (e1, e2) => e1.dom === e2.dom; + // Returns: true if node e1 contains e2, otherwise false. + // (returns false if e1===e2: A node does not contain itself). + const contains = (e1, e2) => { + const d1 = e1.dom; + const d2 = e2.dom; + return d1 === d2 ? false : d1.contains(d2); }; + const is = is$1; const DeviceType = (os, browser, userAgent, mediaMatch) => { - const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true; - const isiPhone = os.isiOS() && !isiPad; - const isMobile = os.isiOS() || os.isAndroid(); - const isTouch = isMobile || mediaMatch('(pointer:coarse)'); - const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)'); - const isPhone = isiPhone || isMobile && !isTablet; - const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false; - const isDesktop = !isPhone && !isTablet && !iOSwebview; - return { - isiPad: constant(isiPad), - isiPhone: constant(isiPhone), - isTablet: constant(isTablet), - isPhone: constant(isPhone), - isTouch: constant(isTouch), - isAndroid: os.isAndroid, - isiOS: os.isiOS, - isWebView: constant(iOSwebview), - isDesktop: constant(isDesktop) - }; + const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true; + const isiPhone = os.isiOS() && !isiPad; + const isMobile = os.isiOS() || os.isAndroid(); + const isTouch = isMobile || mediaMatch('(pointer:coarse)'); + const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)'); + const isPhone = isiPhone || isMobile && !isTablet; + const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false; + const isDesktop = !isPhone && !isTablet && !iOSwebview; + return { + isiPad: constant(isiPad), + isiPhone: constant(isiPhone), + isTablet: constant(isTablet), + isPhone: constant(isPhone), + isTouch: constant(isTouch), + isAndroid: os.isAndroid, + isiOS: os.isiOS, + isWebView: constant(iOSwebview), + isDesktop: constant(isDesktop) + }; }; const firstMatch = (regexes, s) => { - for (let i = 0; i < regexes.length; i++) { - const x = regexes[i]; - if (x.test(s)) { - return x; + for (let i = 0; i < regexes.length; i++) { + const x = regexes[i]; + if (x.test(s)) { + return x; + } } - } - return undefined; + return undefined; }; const find = (regexes, agent) => { - const r = firstMatch(regexes, agent); - if (!r) { - return { - major: 0, - minor: 0 + const r = firstMatch(regexes, agent); + if (!r) { + return { major: 0, minor: 0 }; + } + const group = (i) => { + return Number(agent.replace(r, '$' + i)); }; - } - const group = i => { - return Number(agent.replace(r, '$' + i)); - }; - return nu$2(group(1), group(2)); + return nu$2(group(1), group(2)); }; const detect$5 = (versionRegexes, agent) => { - const cleanedAgent = String(agent).toLowerCase(); - if (versionRegexes.length === 0) { - return unknown$2(); - } - return find(versionRegexes, cleanedAgent); + const cleanedAgent = String(agent).toLowerCase(); + if (versionRegexes.length === 0) { + return unknown$2(); + } + return find(versionRegexes, cleanedAgent); }; const unknown$2 = () => { - return nu$2(0, 0); + return nu$2(0, 0); }; const nu$2 = (major, minor) => { - return { - major, - minor - }; + return { major, minor }; }; const Version = { - nu: nu$2, - detect: detect$5, - unknown: unknown$2 + nu: nu$2, + detect: detect$5, + unknown: unknown$2 }; const detectBrowser$1 = (browsers, userAgentData) => { - return findMap(userAgentData.brands, uaBrand => { - const lcBrand = uaBrand.brand.toLowerCase(); - return find$1(browsers, browser => { - var _a; - return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase()); - }).map(info => ({ - current: info.name, - version: Version.nu(parseInt(uaBrand.version, 10), 0) - })); - }); + return findMap(userAgentData.brands, (uaBrand) => { + const lcBrand = uaBrand.brand.toLowerCase(); + return find$1(browsers, (browser) => { var _a; return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase()); }) + .map((info) => ({ + current: info.name, + version: Version.nu(parseInt(uaBrand.version, 10), 0) + })); + }); }; const detect$4 = (candidates, userAgent) => { - const agent = String(userAgent).toLowerCase(); - return find$1(candidates, candidate => { - return candidate.search(agent); - }); + const agent = String(userAgent).toLowerCase(); + return find$1(candidates, (candidate) => { + return candidate.search(agent); + }); }; + // They (browser and os) are the same at the moment, but they might + // not stay that way. const detectBrowser = (browsers, userAgent) => { - return detect$4(browsers, userAgent).map(browser => { - const version = Version.detect(browser.versionRegexes, userAgent); - return { - current: browser.name, - version - }; - }); + return detect$4(browsers, userAgent).map((browser) => { + const version = Version.detect(browser.versionRegexes, userAgent); + return { + current: browser.name, + version + }; + }); }; const detectOs = (oses, userAgent) => { - return detect$4(oses, userAgent).map(os => { - const version = Version.detect(os.versionRegexes, userAgent); - return { - current: os.name, - version - }; - }); + return detect$4(oses, userAgent).map((os) => { + const version = Version.detect(os.versionRegexes, userAgent); + return { + current: os.name, + version + }; + }); }; const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/; - const checkContains = target => { - return uastring => { - return contains(uastring, target); - }; + const checkContains = (target) => { + return (uastring) => { + return contains$1(uastring, target); + }; }; const browsers = [ - { - name: 'Edge', - versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/], - search: uastring => { - return contains(uastring, 'edge/') && contains(uastring, 'chrome') && contains(uastring, 'safari') && contains(uastring, 'applewebkit'); - } - }, - { - name: 'Chromium', - brand: 'Chromium', - versionRegexes: [ - /.*?chrome\/([0-9]+)\.([0-9]+).*/, - normalVersionRegex - ], - search: uastring => { - return contains(uastring, 'chrome') && !contains(uastring, 'chromeframe'); - } - }, - { - name: 'IE', - versionRegexes: [ - /.*?msie\ ?([0-9]+)\.([0-9]+).*/, - /.*?rv:([0-9]+)\.([0-9]+).*/ - ], - search: uastring => { - return contains(uastring, 'msie') || contains(uastring, 'trident'); - } - }, - { - name: 'Opera', - versionRegexes: [ - normalVersionRegex, - /.*?opera\/([0-9]+)\.([0-9]+).*/ - ], - search: checkContains('opera') - }, - { - name: 'Firefox', - versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/], - search: checkContains('firefox') - }, - { - name: 'Safari', - versionRegexes: [ - normalVersionRegex, - /.*?cpu os ([0-9]+)_([0-9]+).*/ - ], - search: uastring => { - return (contains(uastring, 'safari') || contains(uastring, 'mobile/')) && contains(uastring, 'applewebkit'); + // This is legacy Edge + { + name: 'Edge', + versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/], + search: (uastring) => { + return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit'); + } + }, + // This is Google Chrome and Chromium Edge + { + name: 'Chromium', + brand: 'Chromium', + versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/, normalVersionRegex], + search: (uastring) => { + return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe'); + } + }, + { + name: 'IE', + versionRegexes: [/.*?msie\ ?([0-9]+)\.([0-9]+).*/, /.*?rv:([0-9]+)\.([0-9]+).*/], + search: (uastring) => { + return contains$1(uastring, 'msie') || contains$1(uastring, 'trident'); + } + }, + // INVESTIGATE: Is this still the Opera user agent? + { + name: 'Opera', + versionRegexes: [normalVersionRegex, /.*?opera\/([0-9]+)\.([0-9]+).*/], + search: checkContains('opera') + }, + { + name: 'Firefox', + versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/], + search: checkContains('firefox') + }, + { + name: 'Safari', + versionRegexes: [normalVersionRegex, /.*?cpu os ([0-9]+)_([0-9]+).*/], + search: (uastring) => { + return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit'); + } } - } ]; const oses = [ - { - name: 'Windows', - search: checkContains('win'), - versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/] - }, - { - name: 'iOS', - search: uastring => { - return contains(uastring, 'iphone') || contains(uastring, 'ipad'); + { + name: 'Windows', + search: checkContains('win'), + versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/] }, - versionRegexes: [ - /.*?version\/\ ?([0-9]+)\.([0-9]+).*/, - /.*cpu os ([0-9]+)_([0-9]+).*/, - /.*cpu iphone os ([0-9]+)_([0-9]+).*/ - ] - }, - { - name: 'Android', - search: checkContains('android'), - versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/] - }, - { - name: 'macOS', - search: checkContains('mac os x'), - versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/] - }, - { - name: 'Linux', - search: checkContains('linux'), - versionRegexes: [] - }, - { - name: 'Solaris', - search: checkContains('sunos'), - versionRegexes: [] - }, - { - name: 'FreeBSD', - search: checkContains('freebsd'), - versionRegexes: [] - }, - { - name: 'ChromeOS', - search: checkContains('cros'), - versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/] - } + { + name: 'iOS', + search: (uastring) => { + return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad'); + }, + versionRegexes: [/.*?version\/\ ?([0-9]+)\.([0-9]+).*/, /.*cpu os ([0-9]+)_([0-9]+).*/, /.*cpu iphone os ([0-9]+)_([0-9]+).*/] + }, + { + name: 'Android', + search: checkContains('android'), + versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/] + }, + { + name: 'macOS', + search: checkContains('mac os x'), + versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/] + }, + { + name: 'Linux', + search: checkContains('linux'), + versionRegexes: [] + }, + { name: 'Solaris', + search: checkContains('sunos'), + versionRegexes: [] + }, + { + name: 'FreeBSD', + search: checkContains('freebsd'), + versionRegexes: [] + }, + { + name: 'ChromeOS', + search: checkContains('cros'), + versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/] + } ]; const PlatformInfo = { - browsers: constant(browsers), - oses: constant(oses) + browsers: constant(browsers), + oses: constant(oses) }; const edge = 'Edge'; @@ -1280,35 +1494,36 @@ const firefox = 'Firefox'; const safari = 'Safari'; const unknown$1 = () => { - return nu$1({ - current: undefined, - version: Version.unknown() - }); - }; - const nu$1 = info => { - const current = info.current; - const version = info.version; - const isBrowser = name => () => current === name; - return { - current, - version, - isEdge: isBrowser(edge), - isChromium: isBrowser(chromium), - isIE: isBrowser(ie), - isOpera: isBrowser(opera), - isFirefox: isBrowser(firefox), - isSafari: isBrowser(safari) - }; + return nu$1({ + current: undefined, + version: Version.unknown() + }); + }; + const nu$1 = (info) => { + const current = info.current; + const version = info.version; + const isBrowser = (name) => () => current === name; + return { + current, + version, + isEdge: isBrowser(edge), + isChromium: isBrowser(chromium), + // NOTE: isIe just looks too weird + isIE: isBrowser(ie), + isOpera: isBrowser(opera), + isFirefox: isBrowser(firefox), + isSafari: isBrowser(safari) + }; }; const Browser = { - unknown: unknown$1, - nu: nu$1, - edge: constant(edge), - chromium: constant(chromium), - ie: constant(ie), - opera: constant(opera), - firefox: constant(firefox), - safari: constant(safari) + unknown: unknown$1, + nu: nu$1, + edge: constant(edge), + chromium: constant(chromium), + ie: constant(ie), + opera: constant(opera), + firefox: constant(firefox), + safari: constant(safari) }; const windows = 'Windows'; @@ -1319,6824 +1534,7461 @@ const solaris = 'Solaris'; const freebsd = 'FreeBSD'; const chromeos = 'ChromeOS'; + // Though there is a bit of dupe with this and Browser, trying to + // reuse code makes it much harder to follow and change. const unknown = () => { - return nu({ - current: undefined, - version: Version.unknown() - }); - }; - const nu = info => { - const current = info.current; - const version = info.version; - const isOS = name => () => current === name; - return { - current, - version, - isWindows: isOS(windows), - isiOS: isOS(ios), - isAndroid: isOS(android), - isMacOS: isOS(macos), - isLinux: isOS(linux), - isSolaris: isOS(solaris), - isFreeBSD: isOS(freebsd), - isChromeOS: isOS(chromeos) - }; + return nu({ + current: undefined, + version: Version.unknown() + }); + }; + const nu = (info) => { + const current = info.current; + const version = info.version; + const isOS = (name) => () => current === name; + return { + current, + version, + isWindows: isOS(windows), + // TODO: Fix capitalisation + isiOS: isOS(ios), + isAndroid: isOS(android), + isMacOS: isOS(macos), + isLinux: isOS(linux), + isSolaris: isOS(solaris), + isFreeBSD: isOS(freebsd), + isChromeOS: isOS(chromeos) + }; }; const OperatingSystem = { - unknown, - nu, - windows: constant(windows), - ios: constant(ios), - android: constant(android), - linux: constant(linux), - macos: constant(macos), - solaris: constant(solaris), - freebsd: constant(freebsd), - chromeos: constant(chromeos) + unknown, + nu, + windows: constant(windows), + ios: constant(ios), + android: constant(android), + linux: constant(linux), + macos: constant(macos), + solaris: constant(solaris), + freebsd: constant(freebsd), + chromeos: constant(chromeos) }; const detect$3 = (userAgent, userAgentDataOpt, mediaMatch) => { - const browsers = PlatformInfo.browsers(); - const oses = PlatformInfo.oses(); - const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu); - const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu); - const deviceType = DeviceType(os, browser, userAgent, mediaMatch); - return { - browser, - os, - deviceType - }; - }; - const PlatformDetection = { detect: detect$3 }; - - const mediaMatch = query => window.matchMedia(query).matches; - let platform = cached(() => PlatformDetection.detect(window.navigator.userAgent, Optional.from(window.navigator.userAgentData), mediaMatch)); + const browsers = PlatformInfo.browsers(); + const oses = PlatformInfo.oses(); + const browser = userAgentDataOpt.bind((userAgentData) => detectBrowser$1(browsers, userAgentData)) + .orThunk(() => detectBrowser(browsers, userAgent)) + .fold(Browser.unknown, Browser.nu); + const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu); + const deviceType = DeviceType(os, browser, userAgent, mediaMatch); + return { + browser, + os, + deviceType + }; + }; + const PlatformDetection = { + detect: detect$3 + }; + + const mediaMatch = (query) => window.matchMedia(query).matches; + // IMPORTANT: Must be in a thunk, otherwise rollup thinks calling this immediately + // causes side effects and won't tree shake this away + // Note: navigator.userAgentData is not part of the native typescript types yet + let platform = cached(() => PlatformDetection.detect(window.navigator.userAgent, Optional.from((window.navigator.userAgentData)), mediaMatch)); const detect$2 = () => platform(); - const Dimension = (name, getOffset) => { - const set = (element, h) => { - if (!isNumber(h) && !h.match(/^[0-9]+$/)) { - throw new Error(name + '.set accepts only positive integer values. Value was ' + h); - } - const dom = element.dom; - if (isSupported(dom)) { - dom.style[name] = h + 'px'; - } - }; - const get = element => { - const r = getOffset(element); - if (r <= 0 || r === null) { - const css = get$a(element, name); - return parseFloat(css) || 0; + const unsafe = (name, scope) => { + return resolve$2(name, scope); + }; + const getOrDie = (name, scope) => { + const actual = unsafe(name, scope); + if (actual === undefined || actual === null) { + throw new Error(name + ' not available on this browser'); } - return r; - }; - const getOuter = get; - const aggregate = (element, properties) => foldl(properties, (acc, property) => { - const val = get$a(element, property); - const value = val === undefined ? 0 : parseInt(val, 10); - return isNaN(value) ? acc : acc + value; - }, 0); - const max = (element, value, properties) => { - const cumulativeInclusions = aggregate(element, properties); - const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0; - return absoluteMax; - }; - return { - set, - get, - getOuter, - aggregate, - max - }; + return actual; }; - const toNumber = (px, fallback) => toFloat(px).getOr(fallback); - const getProp = (element, name, fallback) => toNumber(get$a(element, name), fallback); - const calcContentBoxSize = (element, size, upper, lower) => { - const paddingUpper = getProp(element, `padding-${ upper }`, 0); - const paddingLower = getProp(element, `padding-${ lower }`, 0); - const borderUpper = getProp(element, `border-${ upper }-width`, 0); - const borderLower = getProp(element, `border-${ lower }-width`, 0); - return size - paddingUpper - paddingLower - borderUpper - borderLower; + const getPrototypeOf = Object.getPrototypeOf; + /* + * IE9 and above + * + * MDN no use on this one, but here's the link anyway: + * https://developer.mozilla.org/en/docs/Web/API/HTMLElement + */ + const sandHTMLElement = (scope) => { + return getOrDie('HTMLElement', scope); + }; + const isPrototypeOf = (x) => { + // use Resolve to get the window object for x and just return undefined if it can't find it. + // undefined scope later triggers using the global window. + const scope = resolve$2('ownerDocument.defaultView', x); + // TINY-7374: We can't rely on looking at the owner window HTMLElement as the element may have + // been constructed in a different window and then appended to the current window document. + return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf(x).constructor.name)); + }; + + const name = (element) => { + const r = element.dom.nodeName; + return r.toLowerCase(); + }; + const type = (element) => element.dom.nodeType; + const isType = (t) => (element) => type(element) === t; + const isComment = (element) => type(element) === COMMENT || name(element) === '#comment'; + const isHTMLElement = (element) => isElement(element) && isPrototypeOf(element.dom); + const isElement = isType(ELEMENT); + const isText = isType(TEXT); + const isDocument = isType(DOCUMENT); + const isDocumentFragment = isType(DOCUMENT_FRAGMENT); + const isTag = (tag) => (e) => isElement(e) && name(e) === tag; + + /** + * The document associated with the current element + * NOTE: this will throw if the owner is null. + */ + const owner = (element) => SugarElement.fromDom(element.dom.ownerDocument); + /** + * If the element is a document, return it. Otherwise, return its ownerDocument. + * @param dos + */ + const documentOrOwner = (dos) => isDocument(dos) ? dos : owner(dos); + const documentElement = (element) => SugarElement.fromDom(documentOrOwner(element).dom.documentElement); + /** + * The window element associated with the element + * NOTE: this will throw if the defaultView is null. + */ + const defaultView = (element) => SugarElement.fromDom(documentOrOwner(element).dom.defaultView); + const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom); + const parentElement = (element) => Optional.from(element.dom.parentElement).map(SugarElement.fromDom); + const parents = (element, isRoot) => { + const stop = isFunction(isRoot) ? isRoot : never; + // This is used a *lot* so it needs to be performant, not recursive + let dom = element.dom; + const ret = []; + while (dom.parentNode !== null && dom.parentNode !== undefined) { + const rawParent = dom.parentNode; + const p = SugarElement.fromDom(rawParent); + ret.push(p); + if (stop(p) === true) { + break; + } + else { + dom = rawParent; + } + } + return ret; }; - const getCalculatedWidth = (element, boxSizing) => { - const dom = element.dom; - const width = dom.getBoundingClientRect().width || dom.offsetWidth; - return boxSizing === 'border-box' ? width : calcContentBoxSize(element, width, 'left', 'right'); + const prevSibling = (element) => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom); + const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom); + const children$2 = (element) => map$1(element.dom.childNodes, SugarElement.fromDom); + const child$2 = (element, index) => { + const cs = element.dom.childNodes; + return Optional.from(cs[index]).map(SugarElement.fromDom); }; - const getHeight$1 = element => getProp(element, 'height', element.dom.offsetHeight); - const getWidth = element => getProp(element, 'width', element.dom.offsetWidth); - const getInnerWidth = element => getCalculatedWidth(element, 'content-box'); + const firstChild = (element) => child$2(element, 0); - const api$2 = Dimension('width', element => element.dom.offsetWidth); - const get$9 = element => api$2.get(element); - const getOuter$2 = element => api$2.getOuter(element); - const getInner = getInnerWidth; - const getRuntime$1 = getWidth; + const makeRange = (start, soffset, finish, foffset) => { + const doc = owner(start); + // TODO: We need to think about a better place to put native range creation code. Does it even belong in sugar? + // Could the `Compare` checks (node.compareDocumentPosition) handle these situations better? + const rng = doc.dom.createRange(); + rng.setStart(start.dom, soffset); + rng.setEnd(finish.dom, foffset); + return rng; + }; + const after$5 = (start, soffset, finish, foffset) => { + const r = makeRange(start, soffset, finish, foffset); + const same = eq$1(start, finish) && soffset === foffset; + return r.collapsed && !same; + }; + + /** + * Is the element a ShadowRoot? + * + * Note: this is insufficient to test if any element is a shadow root, but it is sufficient to differentiate between + * a Document and a ShadowRoot. + */ + const isShadowRoot = (dos) => isDocumentFragment(dos) && isNonNullable(dos.dom.host); + const getRootNode = (e) => SugarElement.fromDom(e.dom.getRootNode()); + /** Where content needs to go. ShadowRoot or document body */ + const getContentContainer = (dos) => + // Can't use SugarBody.body without causing a circular module reference (since SugarBody.inBody uses SugarShadowDom) + isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body); + /** If this element is in a ShadowRoot, return it. */ + const getShadowRoot = (e) => { + const r = getRootNode(e); + return isShadowRoot(r) ? Optional.some(r) : Optional.none(); + }; + /** Return the host of a ShadowRoot. + * + * This function will throw if Shadow DOM is unsupported in the browser, or if the host is null. + * If you actually have a ShadowRoot, this shouldn't happen. + */ + const getShadowHost = (e) => SugarElement.fromDom(e.dom.host); + /** + * When Events bubble up through a ShadowRoot, the browser changes the target to be the shadow host. + * This function gets the "original" event target if possible. + * This only works if the shadow tree is open - if the shadow tree is closed, event.target is returned. + * See: https://developers.google.com/web/fundamentals/web-components/shadowdom#events + */ + const getOriginalEventTarget = (event) => { + if (isNonNullable(event.target)) { + const el = SugarElement.fromDom(event.target); + if (isElement(el) && isOpenShadowHost(el)) { + // When target element is inside Shadow DOM we need to take first element from composedPath + // otherwise we'll get Shadow Root parent, not actual target element. + if (event.composed && event.composedPath) { + const composedPath = event.composedPath(); + if (composedPath) { + return head(composedPath); + } + } + } + } + return Optional.from(event.target); + }; + /** Return true if the element is a host of an open shadow root. + * Return false if the element is a host of a closed shadow root, or if the element is not a host. + */ + const isOpenShadowHost = (element) => isNonNullable(element.dom.shadowRoot); - const addCells = (gridRow, index, cells) => { - const existingCells = gridRow.cells; - const before = existingCells.slice(0, index); - const after = existingCells.slice(index); - const newCells = before.concat(cells).concat(after); - return setCells(gridRow, newCells); + const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({ + target, + x, + y, + stop, + prevent, + kill, + raw + }); + /** Wraps an Event in an EventArgs structure. + * The returned EventArgs structure has its target set to the "original" target if possible. + * See SugarShadowDom.getOriginalEventTarget + */ + const fromRawEvent$1 = (rawEvent) => { + const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target)); + const stop = () => rawEvent.stopPropagation(); + const prevent = () => rawEvent.preventDefault(); + const kill = compose(prevent, stop); // more of a sequence than a compose, but same effect + // FIX: Don't just expose the raw event. Need to identify what needs standardisation. + return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent); + }; + const handle$1 = (filter, handler) => (rawEvent) => { + if (filter(rawEvent)) { + handler(fromRawEvent$1(rawEvent)); + } }; - const addCell = (gridRow, index, cell) => addCells(gridRow, index, [cell]); - const mutateCell = (gridRow, index, cell) => { - const cells = gridRow.cells; - cells[index] = cell; + const binder = (element, event, filter, handler, useCapture) => { + const wrapped = handle$1(filter, handler); + // IE9 minimum + element.dom.addEventListener(event, wrapped, useCapture); + return { + unbind: curry(unbind, element, event, wrapped, useCapture) + }; }; - const setCells = (gridRow, cells) => rowcells(gridRow.element, cells, gridRow.section, gridRow.isNew); - const mapCells = (gridRow, f) => { - const cells = gridRow.cells; - const r = map$1(cells, f); - return rowcells(gridRow.element, r, gridRow.section, gridRow.isNew); + const bind$1 = (element, event, filter, handler) => binder(element, event, filter, handler, false); + const unbind = (element, event, handler, useCapture) => { + // IE9 minimum + element.dom.removeEventListener(event, handler, useCapture); }; - const getCell = (gridRow, index) => gridRow.cells[index]; - const getCellElement = (gridRow, index) => getCell(gridRow, index).element; - const cellLength = gridRow => gridRow.cells.length; - const extractGridDetails = grid => { - const result = partition(grid, row => row.section === 'colgroup'); - return { - rows: result.fail, - cols: result.pass - }; + + const filter = always; // no filter on plain DomEvents + const bind = (element, event, handler) => bind$1(element, event, filter, handler); + const fromRawEvent = fromRawEvent$1; + + const before$3 = (marker, element) => { + const parent$1 = parent(marker); + parent$1.each((v) => { + v.dom.insertBefore(element.dom, marker.dom); + }); }; - const clone = (gridRow, cloneRow, cloneCell) => { - const newCells = map$1(gridRow.cells, cloneCell); - return rowcells(cloneRow(gridRow.element), newCells, gridRow.section, true); + const after$4 = (marker, element) => { + const sibling = nextSibling(marker); + sibling.fold(() => { + const parent$1 = parent(marker); + parent$1.each((v) => { + append$1(v, element); + }); + }, (v) => { + before$3(v, element); + }); }; - - const LOCKED_COL_ATTR = 'data-snooker-locked-cols'; - const getLockedColumnsFromTable = table => getOpt(table, LOCKED_COL_ATTR).bind(lockedColStr => Optional.from(lockedColStr.match(/\d+/g))).map(lockedCols => mapToObject(lockedCols, always)); - const getLockedColumnsFromGrid = grid => { - const locked = foldl(extractGridDetails(grid).rows, (acc, row) => { - each$2(row.cells, (cell, idx) => { - if (cell.isLocked) { - acc[idx] = true; - } + const prepend = (parent, element) => { + const firstChild$1 = firstChild(parent); + firstChild$1.fold(() => { + append$1(parent, element); + }, (v) => { + parent.dom.insertBefore(element.dom, v.dom); }); - return acc; - }, {}); - const lockedArr = mapToArray(locked, (_val, key) => parseInt(key, 10)); - return sort$1(lockedArr); }; - - const key = (row, column) => { - return row + ',' + column; + const append$1 = (parent, element) => { + parent.dom.appendChild(element.dom); }; - const getAt = (warehouse, row, column) => Optional.from(warehouse.access[key(row, column)]); - const findItem = (warehouse, item, comparator) => { - const filtered = filterItems(warehouse, detail => { - return comparator(item, detail.element); - }); - return filtered.length > 0 ? Optional.some(filtered[0]) : Optional.none(); + const appendAt = (parent, element, index) => { + child$2(parent, index).fold(() => { + append$1(parent, element); + }, (v) => { + before$3(v, element); + }); }; - const filterItems = (warehouse, predicate) => { - const all = bind$2(warehouse.all, r => { - return r.cells; - }); - return filter$2(all, predicate); - }; - const generateColumns = rowData => { - const columnsGroup = {}; - let index = 0; - each$2(rowData.cells, column => { - const colspan = column.colspan; - range$1(colspan, columnIndex => { - const colIndex = index + columnIndex; - columnsGroup[colIndex] = columnext(column.element, colspan, colIndex); - }); - index += colspan; - }); - return columnsGroup; - }; - const generate$2 = list => { - const access = {}; - const cells = []; - const tableOpt = head(list).map(rowData => rowData.element).bind(table); - const lockedColumns = tableOpt.bind(getLockedColumnsFromTable).getOr({}); - let maxRows = 0; - let maxColumns = 0; - let rowCount = 0; - const { - pass: colgroupRows, - fail: rows - } = partition(list, rowData => rowData.section === 'colgroup'); - each$2(rows, rowData => { - const currentRow = []; - each$2(rowData.cells, rowCell => { - let start = 0; - while (access[key(rowCount, start)] !== undefined) { - start++; - } - const isLocked = hasNonNullableKey(lockedColumns, start.toString()); - const current = extended(rowCell.element, rowCell.rowspan, rowCell.colspan, rowCount, start, isLocked); - for (let occupiedColumnPosition = 0; occupiedColumnPosition < rowCell.colspan; occupiedColumnPosition++) { - for (let occupiedRowPosition = 0; occupiedRowPosition < rowCell.rowspan; occupiedRowPosition++) { - const rowPosition = rowCount + occupiedRowPosition; - const columnPosition = start + occupiedColumnPosition; - const newpos = key(rowPosition, columnPosition); - access[newpos] = current; - maxColumns = Math.max(maxColumns, columnPosition + 1); - } - } - currentRow.push(current); - }); - maxRows++; - cells.push(rowdetail(rowData.element, currentRow, rowData.section)); - rowCount++; - }); - const {columns, colgroups} = last$2(colgroupRows).map(rowData => { - const columns = generateColumns(rowData); - const colgroup$1 = colgroup(rowData.element, values(columns)); - return { - colgroups: [colgroup$1], - columns - }; - }).getOrThunk(() => ({ - colgroups: [], - columns: {} - })); - const grid$1 = grid(maxRows, maxColumns); - return { - grid: grid$1, - access, - all: cells, - columns, - colgroups - }; - }; - const fromTable = table => { - const list = fromTable$1(table); - return generate$2(list); - }; - const justCells = warehouse => bind$2(warehouse.all, w => w.cells); - const justColumns = warehouse => values(warehouse.columns); - const hasColumns = warehouse => keys(warehouse.columns).length > 0; - const getColumnAt = (warehouse, columnIndex) => Optional.from(warehouse.columns[columnIndex]); - const Warehouse = { - fromTable, - generate: generate$2, - getAt, - findItem, - filterItems, - justCells, - justColumns, - hasColumns, - getColumnAt + const wrap = (element, wrapper) => { + before$3(element, wrapper); + append$1(wrapper, element); }; - const columns = (warehouse, isValidCell = always) => { - const grid = warehouse.grid; - const cols = range$1(grid.columns, identity); - const rowsArr = range$1(grid.rows, identity); - return map$1(cols, col => { - const getBlock = () => bind$2(rowsArr, r => Warehouse.getAt(warehouse, r, col).filter(detail => detail.column === col).toArray()); - const isValid = detail => detail.colspan === 1 && isValidCell(detail.element); - const getFallback = () => Warehouse.getAt(warehouse, 0, col); - return decide(getBlock, isValid, getFallback); - }); + const after$3 = (marker, elements) => { + each$2(elements, (x, i) => { + const e = i === 0 ? marker : elements[i - 1]; + after$4(e, x); + }); }; - const decide = (getBlock, isValid, getFallback) => { - const inBlock = getBlock(); - const validInBlock = find$1(inBlock, isValid); - const detailOption = validInBlock.orThunk(() => Optional.from(inBlock[0]).orThunk(getFallback)); - return detailOption.map(detail => detail.element); - }; - const rows = warehouse => { - const grid = warehouse.grid; - const rowsArr = range$1(grid.rows, identity); - const cols = range$1(grid.columns, identity); - return map$1(rowsArr, row => { - const getBlock = () => bind$2(cols, c => Warehouse.getAt(warehouse, row, c).filter(detail => detail.row === row).fold(constant([]), detail => [detail])); - const isSingle = detail => detail.rowspan === 1; - const getFallback = () => Warehouse.getAt(warehouse, row, 0); - return decide(getBlock, isSingle, getFallback); - }); + const append = (parent, elements) => { + each$2(elements, (x) => { + append$1(parent, x); + }); }; - const deduce = (xs, index) => { - if (index < 0 || index >= xs.length - 1) { - return Optional.none(); - } - const current = xs[index].fold(() => { - const rest = reverse(xs.slice(0, index)); - return findMap(rest, (a, i) => a.map(aa => ({ - value: aa, - delta: i + 1 - }))); - }, c => Optional.some({ - value: c, - delta: 0 - })); - const next = xs[index + 1].fold(() => { - const rest = xs.slice(index + 1); - return findMap(rest, (a, i) => a.map(aa => ({ - value: aa, - delta: i + 1 - }))); - }, n => Optional.some({ - value: n, - delta: 1 - })); - return current.bind(c => next.map(n => { - const extras = n.delta + c.delta; - return Math.abs(n.value - c.value) / extras; - })); - }; - - const onDirection = (isLtr, isRtl) => element => getDirection(element) === 'rtl' ? isRtl : isLtr; - const getDirection = element => get$a(element, 'direction') === 'rtl' ? 'rtl' : 'ltr'; - - const api$1 = Dimension('height', element => { - const dom = element.dom; - return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight; - }); - const get$8 = element => api$1.get(element); - const getOuter$1 = element => api$1.getOuter(element); - const getRuntime = getHeight$1; - - const r = (left, top) => { - const translate = (x, y) => r(left + x, top + y); - return { - left, - top, - translate - }; + const rawSet = (dom, key, value) => { + /* + * JQuery coerced everything to a string, and silently did nothing on text node/null/undefined. + * + * We fail on those invalid cases, only allowing numbers and booleans. + */ + if (isString(value) || isBoolean(value) || isNumber(value)) { + dom.setAttribute(key, value + ''); + } + else { + // eslint-disable-next-line no-console + console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom); + throw new Error('Attribute value was not simple'); + } }; - const SugarPosition = r; - - const boxPosition = dom => { - const box = dom.getBoundingClientRect(); - return SugarPosition(box.left, box.top); - }; - const firstDefinedOrZero = (a, b) => { - if (a !== undefined) { - return a; - } else { - return b !== undefined ? b : 0; - } - }; - const absolute = element => { - const doc = element.dom.ownerDocument; - const body = doc.body; - const win = doc.defaultView; - const html = doc.documentElement; - if (body === element.dom) { - return SugarPosition(body.offsetLeft, body.offsetTop); - } - const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop); - const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft); - const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop); - const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft); - return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop); - }; - const viewport = element => { - const dom = element.dom; - const doc = dom.ownerDocument; - const body = doc.body; - if (body === dom) { - return SugarPosition(body.offsetLeft, body.offsetTop); - } - if (!inBody(element)) { - return SugarPosition(0, 0); - } - return boxPosition(dom); - }; - - const rowInfo = (row, y) => ({ - row, - y - }); - const colInfo = (col, x) => ({ - col, - x - }); - const rtlEdge = cell => { - const pos = absolute(cell); - return pos.left + getOuter$2(cell); - }; - const ltrEdge = cell => { - return absolute(cell).left; - }; - const getLeftEdge = (index, cell) => { - return colInfo(index, ltrEdge(cell)); + const set$2 = (element, key, value) => { + rawSet(element.dom, key, value); }; - const getRightEdge = (index, cell) => { - return colInfo(index, rtlEdge(cell)); + const setAll$1 = (element, attrs) => { + const dom = element.dom; + each$1(attrs, (v, k) => { + rawSet(dom, k, v); + }); }; - const getTop$1 = cell => { - return absolute(cell).top; + const setOptions = (element, attrs) => { + each$1(attrs, (v, k) => { + v.fold(() => { + remove$6(element, k); + }, (value) => { + rawSet(element.dom, k, value); + }); + }); }; - const getTopEdge = (index, cell) => { - return rowInfo(index, getTop$1(cell)); + const get$b = (element, key) => { + const v = element.dom.getAttribute(key); + // undefined is the more appropriate value for JS, and this matches JQuery + return v === null ? undefined : v; }; - const getBottomEdge = (index, cell) => { - return rowInfo(index, getTop$1(cell) + getOuter$1(cell)); + const getOpt = (element, key) => Optional.from(get$b(element, key)); + const remove$6 = (element, key) => { + element.dom.removeAttribute(key); }; - const findPositions = (getInnerEdge, getOuterEdge, array) => { - if (array.length === 0) { - return []; - } - const lines = map$1(array.slice(1), (cellOption, index) => { - return cellOption.map(cell => { - return getInnerEdge(index, cell); - }); - }); - const lastLine = array[array.length - 1].map(cell => { - return getOuterEdge(array.length - 1, cell); - }); - return lines.concat([lastLine]); - }; - const negate = step => { - return -step; + const clone$1 = (element) => foldl(element.dom.attributes, (acc, attr) => { + acc[attr.name] = attr.value; + return acc; + }, {}); + + const empty = (element) => { + // shortcut "empty node" trick. Requires IE 9. + element.dom.textContent = ''; + // If the contents was a single empty text node, the above doesn't remove it. But, it's still faster in general + // than removing every child node manually. + // The following is (probably) safe for performance as 99.9% of the time the trick works and + // Traverse.children will return an empty array. + each$2(children$2(element), (rogue) => { + remove$5(rogue); + }); }; - const height = { - delta: identity, - positions: optElements => findPositions(getTopEdge, getBottomEdge, optElements), - edge: getTop$1 + const remove$5 = (element) => { + const dom = element.dom; + if (dom.parentNode !== null) { + dom.parentNode.removeChild(dom); + } }; - const ltr$1 = { - delta: identity, - edge: ltrEdge, - positions: optElements => findPositions(getLeftEdge, getRightEdge, optElements) + const unwrap = (wrapper) => { + const children = children$2(wrapper); + if (children.length > 0) { + after$3(wrapper, children); + } + remove$5(wrapper); }; - const rtl$1 = { - delta: negate, - edge: rtlEdge, - positions: optElements => findPositions(getRightEdge, getLeftEdge, optElements) + + const clone = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep)); + /** Shallow clone - just the tag, no children */ + const shallow = (original) => clone(original, false); + /** Deep clone - everything copied including children */ + const deep = (original) => clone(original, true); + /** Shallow clone, with a new tag */ + const shallowAs = (original, tag) => { + const nu = SugarElement.fromTag(tag); + const attributes = clone$1(original); + setAll$1(nu, attributes); + return nu; }; - const detect$1 = onDirection(ltr$1, rtl$1); - const width = { - delta: (amount, table) => detect$1(table).delta(amount, table), - positions: (cols, table) => detect$1(table).positions(cols, table), - edge: cell => detect$1(cell).edge(cell) + /** Deep clone, with a new tag */ + const copy$2 = (original, tag) => { + const nu = shallowAs(original, tag); + // NOTE + // previously this used serialisation: + // nu.dom.innerHTML = original.dom.innerHTML; + // + // Clone should be equivalent (and faster), but if TD <-> TH toggle breaks, put it back. + const cloneChildren = children$2(deep(original)); + append(nu, cloneChildren); + return nu; + }; + /** Change the tag name, but keep all children */ + const mutate$1 = (original, tag) => { + const nu = shallowAs(original, tag); + after$4(original, nu); + const children = children$2(original); + append(nu, children); + remove$5(original); + return nu; }; - const units = { - unsupportedLength: [ - 'em', - 'ex', - 'cap', - 'ch', - 'ic', - 'rem', - 'lh', - 'rlh', - 'vw', - 'vh', - 'vi', - 'vb', - 'vmin', - 'vmax', - 'cm', - 'mm', - 'Q', - 'in', - 'pc', - 'pt', - 'px' - ], - fixed: [ - 'px', - 'pt' - ], - relative: ['%'], - empty: [''] + const fromHtml = (html, scope) => { + const doc = scope || document; + const div = doc.createElement('div'); + div.innerHTML = html; + return children$2(SugarElement.fromDom(div)); + }; + const fromDom = (nodes) => map$1(nodes, SugarElement.fromDom); + + const get$a = (element) => element.dom.innerHTML; + const getOuter$2 = (element) => { + const container = SugarElement.fromTag('div'); + const clone = SugarElement.fromDom(element.dom.cloneNode(true)); + append$1(container, clone); + return get$a(container); + }; + + // some elements, such as mathml, don't have style attributes + // others, such as angular elements, have style attributes that aren't a CSSStyleDeclaration + const isSupported = (dom) => + // eslint-disable-next-line @typescript-eslint/unbound-method + dom.style !== undefined && isFunction(dom.style.getPropertyValue); + + // Node.contains() is very, very, very good performance + // http://jsperf.com/closest-vs-contains/5 + const inBody = (element) => { + // Technically this is only required on IE, where contains() returns false for text nodes. + // But it's cheap enough to run everywhere and Sugar doesn't have platform detection (yet). + const dom = isText(element) ? element.dom.parentNode : element.dom; + // use ownerDocument.body to ensure this works inside iframes. + // Normally contains is bad because an element "contains" itself, but here we want that. + if (dom === undefined || dom === null || dom.ownerDocument === null) { + return false; + } + const doc = dom.ownerDocument; + return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost)); }; - const pattern = (() => { - const decimalDigits = '[0-9]+'; - const signedInteger = '[+-]?' + decimalDigits; - const exponentPart = '[eE]' + signedInteger; - const dot = '\\.'; - const opt = input => `(?:${ input })?`; - const unsignedDecimalLiteral = [ - 'Infinity', - decimalDigits + dot + opt(decimalDigits) + opt(exponentPart), - dot + decimalDigits + opt(exponentPart), - decimalDigits + opt(exponentPart) - ].join('|'); - const float = `[+-]?(?:${ unsignedDecimalLiteral })`; - return new RegExp(`^(${ float })(.*)$`); - })(); - const isUnit = (unit, accepted) => exists(accepted, acc => exists(units[acc], check => unit === check)); - const parse = (input, accepted) => { - const match = Optional.from(pattern.exec(input)); - return match.bind(array => { - const value = Number(array[1]); - const unitRaw = array[2]; - if (isUnit(unitRaw, accepted)) { - return Optional.some({ - value, - unit: unitRaw - }); - } else { - return Optional.none(); + const getBody$1 = (doc) => { + const b = doc.dom.body; + if (b === null || b === undefined) { + throw new Error('Body is not available yet'); } - }); + return SugarElement.fromDom(b); }; - const rPercentageBasedSizeRegex = /(\d+(\.\d+)?)%/; - const rPixelBasedSizeRegex = /(\d+(\.\d+)?)px|em/; - const isCol$2 = isTag('col'); - const isRow$2 = isTag('tr'); - const getPercentSize = (elm, outerGetter, innerGetter) => { - const relativeParent = parentElement(elm).getOrThunk(() => getBody$1(owner(elm))); - return outerGetter(elm) / innerGetter(relativeParent) * 100; + const internalSet = (dom, property, value) => { + // This is going to hurt. Apologies. + // JQuery coerces numbers to pixels for certain property names, and other times lets numbers through. + // we're going to be explicit; strings only. + if (!isString(value)) { + // eslint-disable-next-line no-console + console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom); + throw new Error('CSS value must be a string: ' + value); + } + // removed: support for dom().style[property] where prop is camel case instead of normal property name + if (isSupported(dom)) { + dom.style.setProperty(property, value); + } }; - const setPixelWidth = (cell, amount) => { - set$1(cell, 'width', amount + 'px'); + const internalRemove = (dom, property) => { + /* + * IE9 and above - MDN doesn't have details, but here's a couple of random internet claims + * + * http://help.dottoro.com/ljopsjck.php + * http://stackoverflow.com/a/7901886/7546 + */ + if (isSupported(dom)) { + dom.style.removeProperty(property); + } }; - const setPercentageWidth = (cell, amount) => { - set$1(cell, 'width', amount + '%'); + const set$1 = (element, property, value) => { + const dom = element.dom; + internalSet(dom, property, value); }; - const setHeight = (cell, amount) => { - set$1(cell, 'height', amount + 'px'); + const setAll = (element, css) => { + const dom = element.dom; + each$1(css, (v, k) => { + internalSet(dom, k, v); + }); }; - const removeHeight = cell => { - remove$5(cell, 'height'); + /* + * NOTE: For certain properties, this returns the "used value" which is subtly different to the "computed value" (despite calling getComputedStyle). + * Blame CSS 2.0. + * + * https://developer.mozilla.org/en-US/docs/Web/CSS/used_value + */ + const get$9 = (element, property) => { + const dom = element.dom; + /* + * IE9 and above per + * https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle + * + * Not in numerosity, because it doesn't memoize and looking this up dynamically in performance critical code would be horrendous. + * + * JQuery has some magic here for IE popups, but we don't really need that. + * It also uses element.ownerDocument.defaultView to handle iframes but that hasn't been required since FF 3.6. + */ + const styles = window.getComputedStyle(dom); + const r = styles.getPropertyValue(property); + // jquery-ism: If r is an empty string, check that the element is not in a document. If it isn't, return the raw value. + // Turns out we do this a lot. + return (r === '' && !inBody(element)) ? getUnsafeProperty(dom, property) : r; + }; + // removed: support for dom().style[property] where prop is camel case instead of normal property name + // empty string is what the browsers (IE11 and Chrome) return when the propertyValue doesn't exists. + const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : ''; + /* + * Gets the raw value from the style attribute. Useful for retrieving "used values" from the DOM: + * https://developer.mozilla.org/en-US/docs/Web/CSS/used_value + * + * Returns NONE if the property isn't set, or the value is an empty string. + */ + const getRaw$2 = (element, property) => { + const dom = element.dom; + const raw = getUnsafeProperty(dom, property); + return Optional.from(raw).filter((r) => r.length > 0); }; - const getHeightValue = cell => getRuntime(cell) + 'px'; - const convert = (cell, number, getter, setter) => { - const newSize = table(cell).map(table => { - const total = getter(table); - return Math.floor(number / 100 * total); - }).getOr(number); - setter(cell, newSize); - return newSize; + const remove$4 = (element, property) => { + const dom = element.dom; + internalRemove(dom, property); + if (is$2(getOpt(element, 'style').map(trim), '')) { + // No more styles left, remove the style attribute as well + remove$6(element, 'style'); + } }; - const normalizePixelSize = (value, cell, getter, setter) => { - const number = parseFloat(value); - return endsWith(value, '%') && name(cell) !== 'table' ? convert(cell, number, getter, setter) : number; - }; - const getTotalHeight = cell => { - const value = getHeightValue(cell); - if (!value) { - return get$8(cell); - } - return normalizePixelSize(value, cell, get$8, setHeight); - }; - const get$7 = (cell, type, f) => { - const v = f(cell); - const span = getSpan(cell, type); - return v / span; - }; - const getRaw$1 = (element, prop) => { - return getRaw$2(element, prop).orThunk(() => { - return getOpt(element, prop).map(val => val + 'px'); - }); - }; - const getRawWidth$1 = element => getRaw$1(element, 'width'); - const getRawHeight$1 = element => getRaw$1(element, 'height'); - const getPercentageWidth = cell => getPercentSize(cell, get$9, getInner); - const getPixelWidth$1 = cell => isCol$2(cell) ? get$9(cell) : getRuntime$1(cell); - const getHeight = cell => { - return isRow$2(cell) ? get$8(cell) : get$7(cell, 'rowspan', getTotalHeight); - }; - const getGenericWidth = cell => { - const width = getRawWidth$1(cell); - return width.bind(w => parse(w, [ - 'fixed', - 'relative', - 'empty' - ])); + const copy$1 = (source, target) => { + const sourceDom = source.dom; + const targetDom = target.dom; + if (isSupported(sourceDom) && isSupported(targetDom)) { + targetDom.style.cssText = sourceDom.style.cssText; + } }; - const setGenericWidth = (cell, amount, unit) => { - set$1(cell, 'width', amount + unit); - }; - const getPixelTableWidth = table => get$9(table) + 'px'; - const getPixelTableHeight = table => get$8(table) + 'px'; - const getPercentTableWidth = table => getPercentSize(table, get$9, getInner) + '%'; - const isPercentSizing$1 = table => getRawWidth$1(table).exists(size => rPercentageBasedSizeRegex.test(size)); - const isPixelSizing$1 = table => getRawWidth$1(table).exists(size => rPixelBasedSizeRegex.test(size)); - const isNoneSizing$1 = table => getRawWidth$1(table).isNone(); - const percentageBasedSizeRegex = constant(rPercentageBasedSizeRegex); - const isCol$1 = isTag('col'); - const getRawW = cell => { - return getRawWidth$1(cell).getOrThunk(() => getPixelWidth$1(cell) + 'px'); - }; - const getRawH = cell => { - return getRawHeight$1(cell).getOrThunk(() => getHeight(cell) + 'px'); - }; - const justCols = warehouse => map$1(Warehouse.justColumns(warehouse), column => Optional.from(column.element)); - const isValidColumn = cell => { - const browser = detect$2().browser; - const supportsColWidths = browser.isChromium() || browser.isFirefox(); - return isCol$1(cell) ? supportsColWidths : true; - }; - const getDimension = (cellOpt, index, backups, filter, getter, fallback) => cellOpt.filter(filter).fold(() => fallback(deduce(backups, index)), cell => getter(cell)); - const getWidthFrom = (warehouse, table, getWidth, fallback) => { - const columnCells = columns(warehouse); - const columns$1 = Warehouse.hasColumns(warehouse) ? justCols(warehouse) : columnCells; - const backups = [Optional.some(width.edge(table))].concat(map$1(width.positions(columnCells, table), pos => pos.map(p => p.x))); - const colFilter = not(hasColspan); - return map$1(columns$1, (cellOption, c) => { - return getDimension(cellOption, c, backups, colFilter, column => { - if (isValidColumn(column)) { - return getWidth(column); - } else { - const cell = bindFrom(columnCells[c], identity); - return getDimension(cell, c, backups, colFilter, cell => fallback(Optional.some(get$9(cell))), fallback); + const Dimension = (name, getOffset) => { + const set = (element, h) => { + if (!isNumber(h) && !h.match(/^[0-9]+$/)) { + throw new Error(name + '.set accepts only positive integer values. Value was ' + h); + } + const dom = element.dom; + if (isSupported(dom)) { + dom.style[name] = h + 'px'; + } + }; + /* + * jQuery supports querying width and height on the document and window objects. + * + * TBIO doesn't do this, so the code is removed to save space, but left here just in case. + */ + /* + var getDocumentWidth = (element) => { + var dom = element.dom; + if (Node.isDocument(element)) { + var body = dom.body; + var doc = dom.documentElement; + return Math.max( + body.scrollHeight, + doc.scrollHeight, + body.offsetHeight, + doc.offsetHeight, + doc.clientHeight + ); } - }, fallback); - }); - }; - const getDeduced = deduced => { - return deduced.map(d => { - return d + 'px'; - }).getOr(''); - }; - const getRawWidths = (warehouse, table) => { - return getWidthFrom(warehouse, table, getRawW, getDeduced); - }; - const getPercentageWidths = (warehouse, table, tableSize) => { - return getWidthFrom(warehouse, table, getPercentageWidth, deduced => { - return deduced.fold(() => { - return tableSize.minCellWidth(); - }, cellWidth => { - return cellWidth / tableSize.pixelWidth() * 100; - }); - }); - }; - const getPixelWidths = (warehouse, table, tableSize) => { - return getWidthFrom(warehouse, table, getPixelWidth$1, deduced => { - return deduced.getOrThunk(tableSize.minCellWidth); - }); - }; - const getHeightFrom = (warehouse, table, getHeight, fallback) => { - const rowCells = rows(warehouse); - const rows$1 = map$1(warehouse.all, r => Optional.some(r.element)); - const backups = [Optional.some(height.edge(table))].concat(map$1(height.positions(rowCells, table), pos => pos.map(p => p.y))); - return map$1(rows$1, (row, i) => getDimension(row, i, backups, always, getHeight, fallback)); - }; - const getPixelHeights = (warehouse, table) => { - return getHeightFrom(warehouse, table, getHeight, deduced => { - return deduced.getOrThunk(minHeight); - }); - }; - const getRawHeights = (warehouse, table) => { - return getHeightFrom(warehouse, table, getRawH, getDeduced); + }; + + var getWindowWidth = (element) => { + var dom = element.dom; + if (dom.window === dom) { + // There is no offsetHeight on a window, so use the clientHeight of the document + return dom.document.documentElement.clientHeight; + } + }; + */ + const get = (element) => { + const r = getOffset(element); + // zero or null means non-standard or disconnected, fall back to CSS + if (r <= 0 || r === null) { + const css = get$9(element, name); + // ugh this feels dirty, but it saves cycles + return parseFloat(css) || 0; + } + return r; + }; + // in jQuery, getOuter replicates (or uses) box-sizing: border-box calculations + // although these calculations only seem relevant for quirks mode, and edge cases TBIO doesn't rely on + const getOuter = get; + const aggregate = (element, properties) => foldl(properties, (acc, property) => { + const val = get$9(element, property); + const value = val === undefined ? 0 : parseInt(val, 10); + return isNaN(value) ? acc : acc + value; + }, 0); + const max = (element, value, properties) => { + const cumulativeInclusions = aggregate(element, properties); + // if max-height is 100px and your cumulativeInclusions is 150px, there is no way max-height can be 100px, so we return 0. + const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0; + return absoluteMax; + }; + return { + set, + get, + getOuter, + aggregate, + max + }; }; - const widthLookup = (table, getter) => () => { - if (inBody(table)) { - return getter(table); - } else { - return parseFloat(getRaw$2(table, 'width').getOr('0')); - } - }; - const noneSize = table => { - const getWidth = widthLookup(table, get$9); - const zero = constant(0); - const getWidths = (warehouse, tableSize) => getPixelWidths(warehouse, table, tableSize); - return { - width: getWidth, - pixelWidth: getWidth, - getWidths, - getCellDelta: zero, - singleColumnWidth: constant([0]), - minCellWidth: zero, - setElementWidth: noop, - adjustTableWidth: noop, - isRelative: true, - label: 'none' - }; - }; - const percentageSize = table => { - const getFloatWidth = widthLookup(table, elem => parseFloat(getPercentTableWidth(elem))); - const getWidth = widthLookup(table, get$9); - const getCellDelta = delta => delta / getWidth() * 100; - const singleColumnWidth = (w, _delta) => [100 - w]; - const minCellWidth = () => minWidth() / getWidth() * 100; - const adjustTableWidth = delta => { - const currentWidth = getFloatWidth(); - const change = delta / 100 * currentWidth; - const newWidth = currentWidth + change; - setPercentageWidth(table, newWidth); - }; - const getWidths = (warehouse, tableSize) => getPercentageWidths(warehouse, table, tableSize); - return { - width: getFloatWidth, - pixelWidth: getWidth, - getWidths, - getCellDelta, - singleColumnWidth, - minCellWidth, - setElementWidth: setPercentageWidth, - adjustTableWidth, - isRelative: true, - label: 'percent' - }; - }; - const pixelSize = table => { - const getWidth = widthLookup(table, get$9); - const getCellDelta = identity; - const singleColumnWidth = (w, delta) => { - const newNext = Math.max(minWidth(), w + delta); - return [newNext - w]; - }; - const adjustTableWidth = delta => { - const newWidth = getWidth() + delta; - setPixelWidth(table, newWidth); - }; - const getWidths = (warehouse, tableSize) => getPixelWidths(warehouse, table, tableSize); - return { - width: getWidth, - pixelWidth: getWidth, - getWidths, - getCellDelta, - singleColumnWidth, - minCellWidth: minWidth, - setElementWidth: setPixelWidth, - adjustTableWidth, - isRelative: false, - label: 'pixel' - }; - }; - const chooseSize = (element, width) => { - const percentMatch = percentageBasedSizeRegex().exec(width); - if (percentMatch !== null) { - return percentageSize(element); - } else { - return pixelSize(element); - } - }; - const getTableSize = table => { - const width = getRawWidth$1(table); - return width.fold(() => noneSize(table), w => chooseSize(table, w)); + const toNumber = (px, fallback) => toFloat(px).getOr(fallback); + const getProp = (element, name, fallback) => toNumber(get$9(element, name), fallback); + const calcContentBoxSize = (element, size, upper, lower) => { + const paddingUpper = getProp(element, `padding-${upper}`, 0); + const paddingLower = getProp(element, `padding-${lower}`, 0); + const borderUpper = getProp(element, `border-${upper}-width`, 0); + const borderLower = getProp(element, `border-${lower}-width`, 0); + return size - paddingUpper - paddingLower - borderUpper - borderLower; }; - const TableSize = { - getTableSize, - pixelSize, - percentageSize, - noneSize + const getCalculatedWidth = (element, boxSizing) => { + const dom = element.dom; + const width = dom.getBoundingClientRect().width || dom.offsetWidth; + return boxSizing === 'border-box' ? width : calcContentBoxSize(element, width, 'left', 'right'); }; + const getHeight$1 = (element) => getProp(element, 'height', element.dom.offsetHeight); + const getWidth = (element) => getProp(element, 'width', element.dom.offsetWidth); + const getInnerWidth = (element) => getCalculatedWidth(element, 'content-box'); - const statsStruct = (minRow, minCol, maxRow, maxCol, allCells, selectedCells) => ({ - minRow, - minCol, - maxRow, - maxCol, - allCells, - selectedCells + const api$2 = Dimension('height', (element) => { + // getBoundingClientRect gives better results than offsetHeight for tables with captions on Firefox + const dom = element.dom; + return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight; }); - const findSelectedStats = (house, isSelected) => { - const totalColumns = house.grid.columns; - const totalRows = house.grid.rows; - let minRow = totalRows; - let minCol = totalColumns; - let maxRow = 0; - let maxCol = 0; - const allCells = []; - const selectedCells = []; - each$1(house.access, detail => { - allCells.push(detail); - if (isSelected(detail)) { - selectedCells.push(detail); - const startRow = detail.row; - const endRow = startRow + detail.rowspan - 1; - const startCol = detail.column; - const endCol = startCol + detail.colspan - 1; - if (startRow < minRow) { - minRow = startRow; - } else if (endRow > maxRow) { - maxRow = endRow; - } - if (startCol < minCol) { - minCol = startCol; - } else if (endCol > maxCol) { - maxCol = endCol; - } + const get$8 = (element) => api$2.get(element); + const getOuter$1 = (element) => api$2.getOuter(element); + const getRuntime$1 = getHeight$1; + + const api$1 = Dimension('width', (element) => + // IMO passing this function is better than using dom['offset' + 'width'] + element.dom.offsetWidth); + Dimension('width', (element) => { + const dom = element.dom; + return inBody(element) ? dom.getBoundingClientRect().width : dom.offsetWidth; + }); + const get$7 = (element) => api$1.get(element); + const getOuter = (element) => api$1.getOuter(element); + const getInner = getInnerWidth; + const getRuntime = getWidth; + + const r = (left, top) => { + const translate = (x, y) => r(left + x, top + y); + return { + left, + top, + translate + }; + }; + // tslint:disable-next-line:variable-name + const SugarPosition = r; + + const boxPosition = (dom) => { + const box = dom.getBoundingClientRect(); + return SugarPosition(box.left, box.top); + }; + // Avoids falsy false fallthrough + const firstDefinedOrZero = (a, b) => { + if (a !== undefined) { + return a; + } + else { + return b !== undefined ? b : 0; } - }); - return statsStruct(minRow, minCol, maxRow, maxCol, allCells, selectedCells); }; - const makeCell = (list, seenSelected, rowIndex) => { - const row = list[rowIndex].element; - const td = SugarElement.fromTag('td'); - append$1(td, SugarElement.fromTag('br')); - const f = seenSelected ? append$1 : prepend; - f(row, td); + const absolute = (element) => { + const doc = element.dom.ownerDocument; + const body = doc.body; + const win = doc.defaultView; + const html = doc.documentElement; + if (body === element.dom) { + return SugarPosition(body.offsetLeft, body.offsetTop); + } + const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop); + const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft); + const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop); + const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft); + return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop); }; - const fillInGaps = (list, house, stats, isSelected) => { - const rows = filter$2(list, row => row.section !== 'colgroup'); - const totalColumns = house.grid.columns; - const totalRows = house.grid.rows; - for (let i = 0; i < totalRows; i++) { - let seenSelected = false; - for (let j = 0; j < totalColumns; j++) { - if (!(i < stats.minRow || i > stats.maxRow || j < stats.minCol || j > stats.maxCol)) { - const needCell = Warehouse.getAt(house, i, j).filter(isSelected).isNone(); - if (needCell) { - makeCell(rows, seenSelected, i); - } else { - seenSelected = true; - } - } + const viewport = (element) => { + const dom = element.dom; + const doc = dom.ownerDocument; + const body = doc.body; + if (body === dom) { + return SugarPosition(body.offsetLeft, body.offsetTop); + } + if (!inBody(element)) { + return SugarPosition(0, 0); } - } + return boxPosition(dom); }; - const clean = (replica, stats, house, widthDelta) => { - each$1(house.columns, col => { - if (col.column < stats.minCol || col.column > stats.maxCol) { - remove$6(col.element); - } - }); - const emptyRows = filter$2(firstLayer(replica, 'tr'), row => row.dom.childElementCount === 0); - each$2(emptyRows, remove$6); - if (stats.minCol === stats.maxCol || stats.minRow === stats.maxRow) { - each$2(firstLayer(replica, 'th,td'), cell => { - remove$7(cell, 'rowspan'); - remove$7(cell, 'colspan'); - }); - } - remove$7(replica, LOCKED_COL_ATTR); - remove$7(replica, 'data-snooker-col-series'); - const tableSize = TableSize.getTableSize(replica); - tableSize.adjustTableWidth(widthDelta); + + // get scroll position (x,y) relative to document _doc (or global if not supplied) + const get$6 = (_DOC) => { + const doc = _DOC !== undefined ? _DOC.dom : document; + // ASSUMPTION: This is for cross-browser support, body works for Safari & EDGE, and when we have an iframe body scroller + const x = doc.body.scrollLeft || doc.documentElement.scrollLeft; + const y = doc.body.scrollTop || doc.documentElement.scrollTop; + return SugarPosition(x, y); }; - const getTableWidthDelta = (table, warehouse, tableSize, stats) => { - if (stats.minCol === 0 && warehouse.grid.columns === stats.maxCol + 1) { - return 0; - } - const colWidths = getPixelWidths(warehouse, table, tableSize); - const allColsWidth = foldl(colWidths, (acc, width) => acc + width, 0); - const selectedColsWidth = foldl(colWidths.slice(stats.minCol, stats.maxCol + 1), (acc, width) => acc + width, 0); - const newWidth = selectedColsWidth / allColsWidth * tableSize.pixelWidth(); - const delta = newWidth - tableSize.pixelWidth(); - return tableSize.getCellDelta(delta); + // Scroll content by (x,y) relative to document _doc (or global if not supplied) + const by = (x, y, _DOC) => { + const doc = _DOC !== undefined ? _DOC.dom : document; + const win = doc.defaultView; + if (win) { + win.scrollBy(x, y); + } }; - const extract$1 = (table, selectedSelector) => { - const isSelected = detail => is$2(detail.element, selectedSelector); - const replica = deep(table); - const list = fromTable$1(replica); - const tableSize = TableSize.getTableSize(table); - const replicaHouse = Warehouse.generate(list); - const replicaStats = findSelectedStats(replicaHouse, isSelected); - const selector = 'th:not(' + selectedSelector + ')' + ',td:not(' + selectedSelector + ')'; - const unselectedCells = filterFirstLayer(replica, 'th,td', cell => is$2(cell, selector)); - each$2(unselectedCells, remove$6); - fillInGaps(list, replicaHouse, replicaStats, isSelected); - const house = Warehouse.fromTable(table); - const widthDelta = getTableWidthDelta(table, house, tableSize, replicaStats); - clean(replica, replicaStats, replicaHouse, widthDelta); - return replica; - }; - - const nbsp = '\xA0'; const NodeValue = (is, name) => { - const get = element => { - if (!is(element)) { - throw new Error('Can only get ' + name + ' value of a ' + name + ' node'); - } - return getOption(element).getOr(''); - }; - const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none(); - const set = (element, value) => { - if (!is(element)) { - throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node'); - } - element.dom.nodeValue = value; - }; - return { - get, - getOption, - set - }; + const get = (element) => { + if (!is(element)) { + throw new Error('Can only get ' + name + ' value of a ' + name + ' node'); + } + return getOption(element).getOr(''); + }; + const getOption = (element) => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none(); + const set = (element, value) => { + if (!is(element)) { + throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node'); + } + element.dom.nodeValue = value; + }; + return { + get, + getOption, + set + }; }; const api = NodeValue(isText, 'text'); - const get$6 = element => api.get(element); - const getOption = element => api.getOption(element); + const get$5 = (element) => api.get(element); + const getOption = (element) => api.getOption(element); const set = (element, value) => api.set(element, value); - const getEnd = element => name(element) === 'img' ? 1 : getOption(element).fold(() => children$2(element).length, v => v.length); - const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome(); - const isContentEditableFalse = elem => isHTMLElement(elem) && get$b(elem, 'contenteditable') === 'false'; - const elementsWithCursorPosition = [ - 'img', - 'br' - ]; - const isCursorPosition = elem => { - const hasCursorPosition = isTextNodeWithCursorPosition(elem); - return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse(elem); - }; - - const first = element => descendant$1(element, isCursorPosition); - const last$1 = element => descendantRtl(element, isCursorPosition); - const descendantRtl = (scope, predicate) => { - const descend = element => { - const children = children$2(element); - for (let i = children.length - 1; i >= 0; i--) { - const child = children[i]; - if (predicate(child)) { - return Optional.some(child); - } - const res = descend(child); - if (res.isSome()) { - return res; - } - } - return Optional.none(); - }; - return descend(scope); - }; + const onDirection = (isLtr, isRtl) => (element) => getDirection(element) === 'rtl' ? isRtl : isLtr; + const getDirection = (element) => get$9(element, 'direction') === 'rtl' ? 'rtl' : 'ltr'; - const transferableAttributes = { - scope: [ - 'row', - 'col' - ] - }; - const createCell = doc => () => { - const td = SugarElement.fromTag('td', doc.dom); - append$1(td, SugarElement.fromTag('br', doc.dom)); - return td; - }; - const createCol = doc => () => { - return SugarElement.fromTag('col', doc.dom); - }; - const createColgroup = doc => () => { - return SugarElement.fromTag('colgroup', doc.dom); + // Methods for handling attributes that contain a list of values
+ const read = (element, attr) => { + const value = get$b(element, attr); + return value === undefined || value === '' ? [] : value.split(' '); }; - const createRow$1 = doc => () => { - return SugarElement.fromTag('tr', doc.dom); + const add$3 = (element, attr, id) => { + const old = read(element, attr); + const nu = old.concat([id]); + set$2(element, attr, nu.join(' ')); + return true; }; - const replace$1 = (cell, tag, attrs) => { - const replica = copy$2(cell, tag); - each$1(attrs, (v, k) => { - if (v === null) { - remove$7(replica, k); - } else { - set$2(replica, k, v); + const remove$3 = (element, attr, id) => { + const nu = filter$2(read(element, attr), (v) => v !== id); + if (nu.length > 0) { + set$2(element, attr, nu.join(' ')); } - }); - return replica; - }; - const pasteReplace = cell => { - return cell; - }; - const cloneFormats = (oldCell, newCell, formats) => { - const first$1 = first(oldCell); - return first$1.map(firstText => { - const formatSelector = formats.join(','); - const parents = ancestors$3(firstText, formatSelector, element => { - return eq$1(element, oldCell); - }); - return foldr(parents, (last, parent) => { - const clonedFormat = shallow(parent); - append$1(last, clonedFormat); - return clonedFormat; - }, newCell); - }).getOr(newCell); - }; - const cloneAppropriateAttributes = (original, clone) => { - each$1(transferableAttributes, (validAttributes, attributeName) => getOpt(original, attributeName).filter(attribute => contains$2(validAttributes, attribute)).each(attribute => set$2(clone, attributeName, attribute))); - }; - const cellOperations = (mutate, doc, formatsToClone) => { - const cloneCss = (prev, clone) => { - copy$1(prev.element, clone); - remove$5(clone, 'height'); - if (prev.colspan !== 1) { - remove$5(clone, 'width'); - } - }; - const newCell = prev => { - const td = SugarElement.fromTag(name(prev.element), doc.dom); - const formats = formatsToClone.getOr([ - 'strong', - 'em', - 'b', - 'i', - 'span', - 'font', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'p', - 'div' - ]); - const lastNode = formats.length > 0 ? cloneFormats(prev.element, td, formats) : td; - append$1(lastNode, SugarElement.fromTag('br')); - cloneCss(prev, td); - cloneAppropriateAttributes(prev.element, td); - mutate(prev.element, td); - return td; - }; - const newCol = prev => { - const col = SugarElement.fromTag(name(prev.element), doc.dom); - cloneCss(prev, col); - mutate(prev.element, col); - return col; - }; - return { - col: newCol, - colgroup: createColgroup(doc), - row: createRow$1(doc), - cell: newCell, - replace: replace$1, - colGap: createCol(doc), - gap: createCell(doc) - }; - }; - const paste$1 = doc => { - return { - col: createCol(doc), - colgroup: createColgroup(doc), - row: createRow$1(doc), - cell: createCell(doc), - replace: pasteReplace, - colGap: createCol(doc), - gap: createCell(doc) - }; + else { + remove$6(element, attr); + } + return false; }; - const fromHtml = (html, scope) => { - const doc = scope || document; - const div = doc.createElement('div'); - div.innerHTML = html; - return children$2(SugarElement.fromDom(div)); + var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => { + if (is(scope, a)) { + return Optional.some(scope); + } + else if (isFunction(isRoot) && isRoot(scope)) { + return Optional.none(); + } + else { + return ancestor(scope, a, isRoot); + } }; - const fromDom = nodes => map$1(nodes, SugarElement.fromDom); - const option = name => editor => editor.options.get(name); - const defaultWidth = '100%'; - const getPixelForcedWidth = editor => { - var _a; - const dom = editor.dom; - const parentBlock = (_a = dom.getParent(editor.selection.getStart(), dom.isBlock)) !== null && _a !== void 0 ? _a : editor.getBody(); - return getInner(SugarElement.fromDom(parentBlock)) + 'px'; - }; - const determineDefaultTableStyles = (editor, defaultStyles) => { - if (isTableResponsiveForced(editor) || !shouldStyleWithCss(editor)) { - return defaultStyles; - } else if (isTablePixelsForced(editor)) { - return { - ...defaultStyles, - width: getPixelForcedWidth(editor) - }; - } else { - return { - ...defaultStyles, - width: defaultWidth - }; - } - }; - const determineDefaultTableAttributes = (editor, defaultAttributes) => { - if (isTableResponsiveForced(editor) || shouldStyleWithCss(editor)) { - return defaultAttributes; - } else if (isTablePixelsForced(editor)) { - return { - ...defaultAttributes, - width: getPixelForcedWidth(editor) - }; - } else { - return { - ...defaultAttributes, - width: defaultWidth - }; - } - }; - const register = editor => { - const registerOption = editor.options.register; - registerOption('table_clone_elements', { processor: 'string[]' }); - registerOption('table_use_colgroups', { - processor: 'boolean', - default: true - }); - registerOption('table_header_type', { - processor: value => { - const valid = contains$2([ - 'section', - 'cells', - 'sectionCells', - 'auto' - ], value); - return valid ? { - value, - valid - } : { - valid: false, - message: 'Must be one of: section, cells, sectionCells or auto.' - }; - }, - default: 'section' - }); - registerOption('table_sizing_mode', { - processor: 'string', - default: 'auto' - }); - registerOption('table_default_attributes', { - processor: 'object', - default: { border: '1' } - }); - registerOption('table_default_styles', { - processor: 'object', - default: { 'border-collapse': 'collapse' } - }); - registerOption('table_column_resizing', { - processor: value => { - const valid = contains$2([ - 'preservetable', - 'resizetable' - ], value); - return valid ? { - value, - valid - } : { - valid: false, - message: 'Must be preservetable, or resizetable.' - }; - }, - default: 'preservetable' - }); - registerOption('table_resize_bars', { - processor: 'boolean', - default: true - }); - registerOption('table_style_by_css', { - processor: 'boolean', - default: true - }); - registerOption('table_merge_content_on_paste', { - processor: 'boolean', - default: true - }); - }; - const getTableCloneElements = editor => { - return Optional.from(editor.options.get('table_clone_elements')); - }; - const hasTableObjectResizing = editor => { - const objectResizing = editor.options.get('object_resizing'); - return contains$2(objectResizing.split(','), 'table'); + const ancestor$2 = (scope, predicate, isRoot) => { + let element = scope.dom; + const stop = isFunction(isRoot) ? isRoot : never; + while (element.parentNode) { + element = element.parentNode; + const el = SugarElement.fromDom(element); + if (predicate(el)) { + return Optional.some(el); + } + else if (stop(el)) { + break; + } + } + return Optional.none(); }; - const getTableHeaderType = option('table_header_type'); - const getTableColumnResizingBehaviour = option('table_column_resizing'); - const isPreserveTableColumnResizing = editor => getTableColumnResizingBehaviour(editor) === 'preservetable'; - const isResizeTableColumnResizing = editor => getTableColumnResizingBehaviour(editor) === 'resizetable'; - const getTableSizingMode = option('table_sizing_mode'); - const isTablePercentagesForced = editor => getTableSizingMode(editor) === 'relative'; - const isTablePixelsForced = editor => getTableSizingMode(editor) === 'fixed'; - const isTableResponsiveForced = editor => getTableSizingMode(editor) === 'responsive'; - const hasTableResizeBars = option('table_resize_bars'); - const shouldStyleWithCss = option('table_style_by_css'); - const shouldMergeContentOnPaste = option('table_merge_content_on_paste'); - const getTableDefaultAttributes = editor => { - const options = editor.options; - const defaultAttributes = options.get('table_default_attributes'); - return options.isSet('table_default_attributes') ? defaultAttributes : determineDefaultTableAttributes(editor, defaultAttributes); + const closest$2 = (scope, predicate, isRoot) => { + // This is required to avoid ClosestOrAncestor passing the predicate to itself + const is = (s, test) => test(s); + return ClosestOrAncestor(is, ancestor$2, scope, predicate, isRoot); }; - const getTableDefaultStyles = editor => { - const options = editor.options; - const defaultStyles = options.get('table_default_styles'); - return options.isSet('table_default_styles') ? defaultStyles : determineDefaultTableStyles(editor, defaultStyles); + const child$1 = (scope, predicate) => { + const pred = (node) => predicate(SugarElement.fromDom(node)); + const result = find$1(scope.dom.childNodes, pred); + return result.map(SugarElement.fromDom); }; - const tableUseColumnGroup = option('table_use_colgroups'); - const fixedContainerSelector = option('fixed_toolbar_container'); - const fixedToolbarContainerTarget = option('fixed_toolbar_container_target'); - const fixedContainerTarget = editor => { - var _a; - if (!editor.inline) { - return Optional.none(); - } - const selector = (_a = fixedContainerSelector(editor)) !== null && _a !== void 0 ? _a : ''; - if (selector.length > 0) { - return descendant(body$1(), selector); - } - const element = fixedToolbarContainerTarget(editor); - if (isNonNullable(element)) { - return Optional.some(SugarElement.fromDom(element)); - } - return Optional.none(); - }; - const useFixedContainer = editor => editor.inline && fixedContainerTarget(editor).isSome(); - const getUiMode = option('ui_mode'); - const isSplitUiMode = editor => !useFixedContainer(editor) && getUiMode(editor) === 'split'; - - const closest = target => closest$1(target, '[contenteditable]'); - const isEditable$1 = (element, assumeEditable = false) => { - if (inBody(element)) { - return element.dom.isContentEditable; - } else { - return closest(element).fold(constant(assumeEditable), editable => getRaw(editable) === 'true'); - } - }; - const getRaw = element => element.dom.contentEditable; - - const getBody = editor => SugarElement.fromDom(editor.getBody()); - const getIsRoot = editor => element => eq$1(element, getBody(editor)); - const removeDataStyle = table => { - remove$7(table, 'data-mce-style'); - const removeStyleAttribute = element => remove$7(element, 'data-mce-style'); - each$2(cells$1(table), removeStyleAttribute); - each$2(columns$1(table), removeStyleAttribute); - each$2(rows$1(table), removeStyleAttribute); - }; - const getSelectionStart = editor => SugarElement.fromDom(editor.selection.getStart()); - const getPixelWidth = elm => elm.getBoundingClientRect().width; - const getPixelHeight = elm => elm.getBoundingClientRect().height; - const getRawValue = prop => (editor, elm) => { - const raw = editor.dom.getStyle(elm, prop) || editor.dom.getAttrib(elm, prop); - return Optional.from(raw).filter(isNotEmpty); + const descendant$1 = (scope, predicate) => { + const descend = (node) => { + // tslint:disable-next-line:prefer-for-of + for (let i = 0; i < node.childNodes.length; i++) { + const child = SugarElement.fromDom(node.childNodes[i]); + if (predicate(child)) { + return Optional.some(child); + } + const res = descend(node.childNodes[i]); + if (res.isSome()) { + return res; + } + } + return Optional.none(); + }; + return descend(scope.dom); }; - const getRawWidth = getRawValue('width'); - const getRawHeight = getRawValue('height'); - const isPercentage$1 = value => /^(\d+(\.\d+)?)%$/.test(value); - const isPixel = value => /^(\d+(\.\d+)?)px$/.test(value); - const isInEditableContext$1 = cell => closest$2(cell, isTag('table')).exists(isEditable$1); - const inSelection = (bounds, detail) => { - const leftEdge = detail.column; - const rightEdge = detail.column + detail.colspan - 1; - const topEdge = detail.row; - const bottomEdge = detail.row + detail.rowspan - 1; - return leftEdge <= bounds.finishCol && rightEdge >= bounds.startCol && (topEdge <= bounds.finishRow && bottomEdge >= bounds.startRow); + const ancestor$1 = (scope, selector, isRoot) => ancestor$2(scope, (e) => is$1(e, selector), isRoot); + const child = (scope, selector) => child$1(scope, (e) => is$1(e, selector)); + const descendant = (scope, selector) => one(selector, scope); + // Returns Some(closest ancestor element (sugared)) matching 'selector' up to isRoot, or None() otherwise + const closest$1 = (scope, selector, isRoot) => { + const is = (element, selector) => is$1(element, selector); + return ClosestOrAncestor(is, ancestor$1, scope, selector, isRoot); + }; + + // IE11 Can return undefined for a classList on elements such as math, so we make sure it's not undefined before attempting to use it. + const supports = (element) => element.dom.classList !== undefined; + const get$4 = (element) => read(element, 'class'); + const add$2 = (element, clazz) => add$3(element, 'class', clazz); + const remove$2 = (element, clazz) => remove$3(element, 'class', clazz); + + /* + * ClassList is IE10 minimum: + * https://developer.mozilla.org/en-US/docs/Web/API/Element.classList + * + * Note that IE doesn't support the second argument to toggle (at all). + * If it did, the toggler could be better. + */ + const add$1 = (element, clazz) => { + if (supports(element)) { + element.dom.classList.add(clazz); + } + else { + add$2(element, clazz); + } }; - const isWithin = (bounds, detail) => { - return detail.column >= bounds.startCol && detail.column + detail.colspan - 1 <= bounds.finishCol && detail.row >= bounds.startRow && detail.row + detail.rowspan - 1 <= bounds.finishRow; + const cleanClass = (element) => { + const classList = supports(element) ? element.dom.classList : get$4(element); + // classList is a "live list", so this is up to date already + if (classList.length === 0) { + // No more classes left, remove the class attribute as well + remove$6(element, 'class'); + } }; - const isRectangular = (warehouse, bounds) => { - let isRect = true; - const detailIsWithin = curry(isWithin, bounds); - for (let i = bounds.startRow; i <= bounds.finishRow; i++) { - for (let j = bounds.startCol; j <= bounds.finishCol; j++) { - isRect = isRect && Warehouse.getAt(warehouse, i, j).exists(detailIsWithin); + const remove$1 = (element, clazz) => { + if (supports(element)) { + const classList = element.dom.classList; + classList.remove(clazz); + } + else { + remove$2(element, clazz); } - } - return isRect ? Optional.some(bounds) : Optional.none(); + cleanClass(element); }; + const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz); - const getBounds = (detailA, detailB) => { - return bounds(Math.min(detailA.row, detailB.row), Math.min(detailA.column, detailB.column), Math.max(detailA.row + detailA.rowspan - 1, detailB.row + detailB.rowspan - 1), Math.max(detailA.column + detailA.colspan - 1, detailB.column + detailB.colspan - 1)); - }; - const getAnyBox = (warehouse, startCell, finishCell) => { - const startCoords = Warehouse.findItem(warehouse, startCell, eq$1); - const finishCoords = Warehouse.findItem(warehouse, finishCell, eq$1); - return startCoords.bind(sc => { - return finishCoords.map(fc => { - return getBounds(sc, fc); + const remove = (element, classes) => { + each$2(classes, (x) => { + remove$1(element, x); }); - }); - }; - const getBox$1 = (warehouse, startCell, finishCell) => { - return getAnyBox(warehouse, startCell, finishCell).bind(bounds => { - return isRectangular(warehouse, bounds); - }); }; - const moveBy$1 = (warehouse, cell, row, column) => { - return Warehouse.findItem(warehouse, cell, eq$1).bind(detail => { - const startRow = row > 0 ? detail.row + detail.rowspan - 1 : detail.row; - const startCol = column > 0 ? detail.column + detail.colspan - 1 : detail.column; - const dest = Warehouse.getAt(warehouse, startRow + row, startCol + column); - return dest.map(d => { - return d.element; - }); - }); - }; - const intercepts$1 = (warehouse, start, finish) => { - return getAnyBox(warehouse, start, finish).map(bounds => { - const inside = Warehouse.filterItems(warehouse, curry(inSelection, bounds)); - return map$1(inside, detail => { - return detail.element; - }); - }); - }; - const parentCell = (warehouse, innerCell) => { - const isContainedBy = (c1, c2) => { - return contains$1(c2, c1); - }; - return Warehouse.findItem(warehouse, innerCell, isContainedBy).map(detail => { - return detail.element; - }); + const closest = (target) => closest$1(target, '[contenteditable]'); + const isEditable$1 = (element, assumeEditable = false) => { + if (inBody(element)) { + return element.dom.isContentEditable; + } + else { + // Find the closest contenteditable element and check if it's editable + return closest(element).fold(constant(assumeEditable), (editable) => getRaw$1(editable) === 'true'); + } }; + const getRaw$1 = (element) => element.dom.contentEditable; - const moveBy = (cell, deltaRow, deltaColumn) => { - return table(cell).bind(table => { - const warehouse = getWarehouse(table); - return moveBy$1(warehouse, cell, deltaRow, deltaColumn); - }); + const addClass = (clazz) => (element) => { + add$1(element, clazz); }; - const intercepts = (table, first, last) => { - const warehouse = getWarehouse(table); - return intercepts$1(warehouse, first, last); + const removeClasses = (classes) => (element) => { + remove(element, classes); }; - const nestedIntercepts = (table, first, firstTable, last, lastTable) => { - const warehouse = getWarehouse(table); - const optStartCell = eq$1(table, firstTable) ? Optional.some(first) : parentCell(warehouse, first); - const optLastCell = eq$1(table, lastTable) ? Optional.some(last) : parentCell(warehouse, last); - return optStartCell.bind(startCell => optLastCell.bind(lastCell => intercepts$1(warehouse, startCell, lastCell))); - }; - const getBox = (table, first, last) => { - const warehouse = getWarehouse(table); - return getBox$1(warehouse, first, last); + + const ancestors$4 = (scope, predicate, isRoot) => filter$2(parents(scope, isRoot), predicate); + const children$1 = (scope, predicate) => filter$2(children$2(scope), predicate); + const descendants$1 = (scope, predicate) => { + let result = []; + // Recurse.toArray() might help here + each$2(children$2(scope), (x) => { + if (predicate(x)) { + result = result.concat([x]); + } + result = result.concat(descendants$1(x, predicate)); + }); + return result; }; - const getWarehouse = Warehouse.fromTable; - var TagBoundaries = [ - 'body', - 'p', - 'div', - 'article', - 'aside', - 'figcaption', - 'figure', - 'footer', - 'header', - 'nav', - 'section', - 'ol', - 'ul', - 'li', - 'table', - 'thead', - 'tbody', - 'tfoot', - 'caption', - 'tr', - 'td', - 'th', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'blockquote', - 'pre', - 'address' - ]; + // For all of the following: + // + // jQuery does siblings of firstChild. IE9+ supports scope.dom.children (similar to Traverse.children but elements only). + // Traverse should also do this (but probably not by default). + // + const ancestors$3 = (scope, selector, isRoot) => + // It may surprise you to learn this is exactly what JQuery does + // TODO: Avoid all this wrapping and unwrapping + ancestors$4(scope, (e) => is$1(e, selector), isRoot); + const children = (scope, selector) => + // It may surprise you to learn this is exactly what JQuery does + // TODO: Avoid all the wrapping and unwrapping + children$1(scope, (e) => is$1(e, selector)); + const descendants = (scope, selector) => all$1(selector, scope); - var DomUniverse = () => { - const clone = element => { - return SugarElement.fromDom(element.dom.cloneNode(false)); - }; - const document = element => documentOrOwner(element).dom; - const isBoundary = element => { - if (!isElement(element)) { - return false; - } - if (name(element) === 'body') { - return true; - } - return contains$2(TagBoundaries, name(element)); - }; - const isEmptyTag = element => { - if (!isElement(element)) { - return false; - } - return contains$2([ - 'br', - 'img', - 'hr', - 'input' - ], name(element)); - }; - const isNonEditable = element => isElement(element) && get$b(element, 'contenteditable') === 'false'; - const comparePosition = (element, other) => { - return element.dom.compareDocumentPosition(other.dom); - }; - const copyAttributesTo = (source, destination) => { - const as = clone$2(source); - setAll$1(destination, as); - }; - const isSpecial = element => { - const tag = name(element); - return contains$2([ - 'script', - 'noscript', - 'iframe', - 'noframes', - 'noembed', - 'title', - 'style', - 'textarea', - 'xmp' - ], tag); - }; - const getLanguage = element => isElement(element) ? getOpt(element, 'lang') : Optional.none(); - return { - up: constant({ - selector: ancestor$1, - closest: closest$1, - predicate: ancestor$2, - all: parents - }), - down: constant({ - selector: descendants, - predicate: descendants$1 - }), - styles: constant({ - get: get$a, - getRaw: getRaw$2, - set: set$1, - remove: remove$5 - }), - attrs: constant({ - get: get$b, - set: set$2, - remove: remove$7, - copyTo: copyAttributesTo - }), - insert: constant({ - before: before$3, - after: after$5, - afterAll: after$4, - append: append$1, - appendAll: append, - prepend: prepend, - wrap: wrap - }), - remove: constant({ - unwrap: unwrap, - remove: remove$6 - }), - create: constant({ - nu: SugarElement.fromTag, - clone, - text: SugarElement.fromText - }), - query: constant({ - comparePosition, - prevSibling: prevSibling, - nextSibling: nextSibling - }), - property: constant({ - children: children$2, - name: name, - parent: parent, - document, - isText: isText, - isComment: isComment, - isElement: isElement, - isSpecial, - getLanguage, - getText: get$6, - setText: set, - isBoundary, - isEmptyTag, - isNonEditable - }), - eq: eq$1, - is: is$1 - }; - }; + const inParent = (parent, children, element, index) => ({ + parent, + children, + element, + index + }); + const indexInParent = (element) => parent(element).bind((parent) => { + const children = children$2(parent); + return indexOf(children, element).map((index) => inParent(parent, children, element, index)); + }); + const indexOf = (elements, element) => findIndex(elements, curry(eq$1, element)); - const all = (universe, look, elements, f) => { - const head = elements[0]; - const tail = elements.slice(1); - return f(universe, look, head, tail); - }; - const oneAll = (universe, look, elements) => { - return elements.length > 0 ? all(universe, look, elements, unsafeOne) : Optional.none(); - }; - const unsafeOne = (universe, look, head, tail) => { - const start = look(universe, head); - return foldr(tail, (b, a) => { - const current = look(universe, a); - return commonElement(universe, b, current); - }, start); - }; - const commonElement = (universe, start, end) => { - return start.bind(s => { - return end.filter(curry(universe.eq, s)); - }); - }; + const ancestor = (scope, predicate, isRoot) => ancestor$2(scope, predicate, isRoot).isSome(); - const eq = (universe, item) => { - return curry(universe.eq, item); - }; - const ancestors$2 = (universe, start, end, isRoot = never) => { - const ps1 = [start].concat(universe.up().all(start)); - const ps2 = [end].concat(universe.up().all(end)); - const prune = path => { - const index = findIndex(path, isRoot); - return index.fold(() => { - return path; - }, ind => { - return path.slice(0, ind + 1); - }); - }; - const pruned1 = prune(ps1); - const pruned2 = prune(ps2); - const shared = find$1(pruned1, x => { - return exists(pruned2, eq(universe, x)); - }); - return { - firstpath: pruned1, - secondpath: pruned2, - shared - }; + const getEnd = (element) => name(element) === 'img' ? 1 : getOption(element).fold(() => children$2(element).length, (v) => v.length); + const isTextNodeWithCursorPosition = (el) => getOption(el).filter((text) => + // For the purposes of finding cursor positions only allow text nodes with content, + // but trim removes   and that's allowed + text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome(); + const isContentEditableFalse = (elem) => isHTMLElement(elem) && (get$b(elem, 'contenteditable') === 'false'); + const elementsWithCursorPosition = ['img', 'br']; + const isCursorPosition = (elem) => { + const hasCursorPosition = isTextNodeWithCursorPosition(elem); + return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem)) || isContentEditableFalse(elem); + }; + + const first = (element) => descendant$1(element, isCursorPosition); + const last = (element) => descendantRtl(element, isCursorPosition); + // Note, sugar probably needs some RTL traversals. + const descendantRtl = (scope, predicate) => { + const descend = (element) => { + const children = children$2(element); + for (let i = children.length - 1; i >= 0; i--) { + const child = children[i]; + if (predicate(child)) { + return Optional.some(child); + } + const res = descend(child); + if (res.isSome()) { + return res; + } + } + return Optional.none(); + }; + return descend(scope); }; - const sharedOne$1 = oneAll; - const ancestors$1 = ancestors$2; - - const universe$3 = DomUniverse(); - const sharedOne = (look, elements) => { - return sharedOne$1(universe$3, (_universe, element) => { - return look(element); - }, elements); + const create$4 = (start, soffset, finish, foffset) => ({ + start, + soffset, + finish, + foffset + }); + // tslint:disable-next-line:variable-name + const SimRange = { + create: create$4 }; - const ancestors = (start, finish, isRoot) => { - return ancestors$1(universe$3, start, finish, isRoot); + + const adt$5 = Adt.generate([ + { before: ['element'] }, + { on: ['element', 'offset'] }, + { after: ['element'] } + ]); + // Probably don't need this given that we now have "match" + const cata$1 = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter); + const getStart$1 = (situ) => situ.fold(identity, identity, identity); + const before$2 = adt$5.before; + const on = adt$5.on; + const after$2 = adt$5.after; + // tslint:disable-next-line:variable-name + const Situ = { + before: before$2, + on, + after: after$2, + cata: cata$1, + getStart: getStart$1 }; - const lookupTable = container => { - return ancestor$1(container, 'table'); + // Consider adding a type for "element" + const adt$4 = Adt.generate([ + { domRange: ['rng'] }, + { relative: ['startSitu', 'finishSitu'] }, + { exact: ['start', 'soffset', 'finish', 'foffset'] } + ]); + const exactFromRange = (simRange) => adt$4.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset); + const getStart = (selection) => selection.match({ + domRange: (rng) => SugarElement.fromDom(rng.startContainer), + relative: (startSitu, _finishSitu) => Situ.getStart(startSitu), + exact: (start, _soffset, _finish, _foffset) => start + }); + const domRange = adt$4.domRange; + const relative = adt$4.relative; + const exact = adt$4.exact; + const getWin = (selection) => { + const start = getStart(selection); + return defaultView(start); + }; + // This is out of place but it's API so I can't remove it + const range = SimRange.create; + // tslint:disable-next-line:variable-name + const SimSelection = { + domRange, + relative, + exact, + exactFromRange, + getWin, + range }; - const identify = (start, finish, isRoot) => { - const getIsRoot = rootTable => { - return element => { - return isRoot !== undefined && isRoot(element) || eq$1(element, rootTable); - }; - }; - if (eq$1(start, finish)) { - return Optional.some({ - boxes: Optional.some([start]), - start, - finish - }); - } else { - return lookupTable(start).bind(startTable => { - return lookupTable(finish).bind(finishTable => { - if (eq$1(startTable, finishTable)) { - return Optional.some({ - boxes: intercepts(startTable, start, finish), - start, - finish - }); - } else if (contains$1(startTable, finishTable)) { - const ancestorCells = ancestors$3(finish, 'td,th', getIsRoot(startTable)); - const finishCell = ancestorCells.length > 0 ? ancestorCells[ancestorCells.length - 1] : finish; - return Optional.some({ - boxes: nestedIntercepts(startTable, start, startTable, finish, finishTable), - start, - finish: finishCell - }); - } else if (contains$1(finishTable, startTable)) { - const ancestorCells = ancestors$3(start, 'td,th', getIsRoot(finishTable)); - const startCell = ancestorCells.length > 0 ? ancestorCells[ancestorCells.length - 1] : start; - return Optional.some({ - boxes: nestedIntercepts(finishTable, start, startTable, finish, finishTable), - start, - finish: startCell - }); - } else { - return ancestors(start, finish).shared.bind(lca => { - return closest$1(lca, 'table', isRoot).bind(lcaTable => { - const finishAncestorCells = ancestors$3(finish, 'td,th', getIsRoot(lcaTable)); - const finishCell = finishAncestorCells.length > 0 ? finishAncestorCells[finishAncestorCells.length - 1] : finish; - const startAncestorCells = ancestors$3(start, 'td,th', getIsRoot(lcaTable)); - const startCell = startAncestorCells.length > 0 ? startAncestorCells[startAncestorCells.length - 1] : start; - return Optional.some({ - boxes: nestedIntercepts(lcaTable, start, startTable, finish, finishTable), - start: startCell, - finish: finishCell - }); - }); - }); + + const caretPositionFromPoint = (doc, x, y) => { + var _a; + return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)) + .bind((pos) => { + // It turns out that Firefox can return null for pos.offsetNode + if (pos.offsetNode === null) { + return Optional.none(); } - }); + const r = doc.createRange(); + r.setStart(pos.offsetNode, pos.offset); + r.collapse(); + return Optional.some(r); }); - } }; - const retrieve$1 = (container, selector) => { - const sels = descendants(container, selector); - return sels.length > 0 ? Optional.some(sels) : Optional.none(); + const caretRangeFromPoint = (doc, x, y) => { var _a; return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)); }; + const availableSearch = (doc, x, y) => { + if (doc.caretPositionFromPoint) { + return caretPositionFromPoint(doc, x, y); // defined standard, firefox only + } + else if (doc.caretRangeFromPoint) { + return caretRangeFromPoint(doc, x, y); // webkit/blink implementation + } + else { + return Optional.none(); // unsupported browser + } }; - const getLast = (boxes, lastSelectedSelector) => { - return find$1(boxes, box => { - return is$2(box, lastSelectedSelector); - }); + const fromPoint = (win, x, y) => { + const doc = win.document; + return availableSearch(doc, x, y).map((rng) => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset)); }; - const getEdges = (container, firstSelectedSelector, lastSelectedSelector) => { - return descendant(container, firstSelectedSelector).bind(first => { - return descendant(container, lastSelectedSelector).bind(last => { - return sharedOne(lookupTable, [ - first, - last - ]).map(table => { - return { - first, - last, - table - }; - }); - }); - }); + + const beforeSpecial = (element, offset) => { + // From memory, we don't want to use
directly on Firefox because it locks the keyboard input. + // It turns out that directly on IE locks the keyboard as well. + // If the offset is 0, use before. If the offset is 1, use after. + // TBIO-3889: Firefox Situ.on results in a child of the ; Situ.before results in platform inconsistencies + const name$1 = name(element); + if ('input' === name$1) { + return Situ.after(element); + } + else if (!contains$2(['br', 'img'], name$1)) { + return Situ.on(element, offset); + } + else { + return offset === 0 ? Situ.before(element) : Situ.after(element); + } }; - const expandTo = (finish, firstSelectedSelector) => { - return ancestor$1(finish, 'table').bind(table => { - return descendant(table, firstSelectedSelector).bind(start => { - return identify(start, finish).bind(identified => { - return identified.boxes.map(boxes => { - return { - boxes, - start: identified.start, - finish: identified.finish - }; - }); - }); - }); - }); + const preprocessRelative = (startSitu, finishSitu) => { + const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after); + const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after); + return SimSelection.relative(start, finish); }; - const shiftSelection = (boxes, deltaRow, deltaColumn, firstSelectedSelector, lastSelectedSelector) => { - return getLast(boxes, lastSelectedSelector).bind(last => { - return moveBy(last, deltaRow, deltaColumn).bind(finish => { - return expandTo(finish, firstSelectedSelector); - }); - }); + const preprocessExact = (start, soffset, finish, foffset) => { + const startSitu = beforeSpecial(start, soffset); + const finishSitu = beforeSpecial(finish, foffset); + return SimSelection.relative(startSitu, finishSitu); }; - const retrieve = (container, selector) => { - return retrieve$1(container, selector); - }; - const retrieveBox = (container, firstSelectedSelector, lastSelectedSelector) => { - return getEdges(container, firstSelectedSelector, lastSelectedSelector).bind(edges => { - const isRoot = ancestor => { - return eq$1(container, ancestor); - }; - const sectionSelector = 'thead,tfoot,tbody,table'; - const firstAncestor = ancestor$1(edges.first, sectionSelector, isRoot); - const lastAncestor = ancestor$1(edges.last, sectionSelector, isRoot); - return firstAncestor.bind(fA => { - return lastAncestor.bind(lA => { - return eq$1(fA, lA) ? getBox(edges.table, edges.first, edges.last) : Optional.none(); - }); + const getNativeSelection = (win) => Optional.from(win.getSelection()); + const doSetNativeRange = (win, rng) => { + getNativeSelection(win).each((selection) => { + selection.removeAllRanges(); + selection.addRange(rng); }); - }); - }; - - const selection = identity; - const unmergable = selectedCells => { - const hasSpan = (elem, type) => getOpt(elem, type).exists(span => parseInt(span, 10) > 1); - const hasRowOrColSpan = elem => hasSpan(elem, 'rowspan') || hasSpan(elem, 'colspan'); - return selectedCells.length > 0 && forall(selectedCells, hasRowOrColSpan) ? Optional.some(selectedCells) : Optional.none(); }; - const mergable = (table, selectedCells, ephemera) => { - if (selectedCells.length <= 1) { - return Optional.none(); - } else { - return retrieveBox(table, ephemera.firstSelectedSelector, ephemera.lastSelectedSelector).map(bounds => ({ - bounds, - cells: selectedCells - })); - } + const doSetRange = (win, start, soffset, finish, foffset) => { + const rng = exactToNative(win, start, soffset, finish, foffset); + doSetNativeRange(win, rng); }; - - const strSelected = 'data-mce-selected'; - const strSelectedSelector = 'td[' + strSelected + '],th[' + strSelected + ']'; - const strAttributeSelector = '[' + strSelected + ']'; - const strFirstSelected = 'data-mce-first-selected'; - const strFirstSelectedSelector = 'td[' + strFirstSelected + '],th[' + strFirstSelected + ']'; - const strLastSelected = 'data-mce-last-selected'; - const strLastSelectedSelector = 'td[' + strLastSelected + '],th[' + strLastSelected + ']'; - const attributeSelector = strAttributeSelector; - const ephemera = { - selected: strSelected, - selectedSelector: strSelectedSelector, - firstSelected: strFirstSelected, - firstSelectedSelector: strFirstSelectedSelector, - lastSelected: strLastSelected, - lastSelectedSelector: strLastSelectedSelector + const setLegacyRtlRange = (win, selection, start, soffset, finish, foffset) => { + selection.collapse(start.dom, soffset); + selection.extend(finish.dom, foffset); }; - - const forMenu = (selectedCells, table, cell) => ({ - element: cell, - mergable: mergable(table, selectedCells, ephemera), - unmergable: unmergable(selectedCells), - selection: selection(selectedCells) - }); - const paste = (element, clipboard, generators) => ({ - element, - clipboard, - generators - }); - const pasteRows = (selectedCells, _cell, clipboard, generators) => ({ - selection: selection(selectedCells), - clipboard, - generators + const setRangeFromRelative = (win, relative) => diagnose(win, relative).match({ + ltr: (start, soffset, finish, foffset) => { + doSetRange(win, start, soffset, finish, foffset); + }, + rtl: (start, soffset, finish, foffset) => { + getNativeSelection(win).each((selection) => { + // If this selection is backwards, then we need to use extend. + if (selection.setBaseAndExtent) { + selection.setBaseAndExtent(start.dom, soffset, finish.dom, foffset); + } + else if (selection.extend) { + // This try catch is for older browsers (Firefox 52) as they're sometimes unable to handle setting backwards selections using selection.extend and error out. + try { + setLegacyRtlRange(win, selection, start, soffset, finish, foffset); + } + catch (_a) { + // If it does fail, try again with ltr. + doSetRange(win, finish, foffset, start, soffset); + } + } + else { + doSetRange(win, finish, foffset, start, soffset); + } + }); + } }); - - const getSelectionCellFallback = element => table(element).bind(table => retrieve(table, ephemera.firstSelectedSelector)).fold(constant(element), cells => cells[0]); - const getSelectionFromSelector = selector => (initCell, isRoot) => { - const cellName = name(initCell); - const cell = cellName === 'col' || cellName === 'colgroup' ? getSelectionCellFallback(initCell) : initCell; - return closest$1(cell, selector, isRoot); - }; - const getSelectionCellOrCaption = getSelectionFromSelector('th,td,caption'); - const getSelectionCell = getSelectionFromSelector('th,td'); - const getCellsFromSelection = editor => fromDom(editor.model.table.getSelectedCells()); - const getCellsFromFakeSelection = editor => filter$2(getCellsFromSelection(editor), cell => is$2(cell, ephemera.selectedSelector)); - - const extractSelected = cells => { - return table(cells[0]).map(table => { - const replica = extract$1(table, attributeSelector); - removeDataStyle(replica); - return [replica]; - }); - }; - const serializeElements = (editor, elements) => map$1(elements, elm => editor.selection.serializer.serialize(elm.dom, {})).join(''); - const getTextContent = (editor, replicaElements) => { - const doc = editor.getDoc(); - const dos = getRootNode(SugarElement.fromDom(editor.getBody())); - const offscreenDiv = SugarElement.fromTag('div', doc); - set$2(offscreenDiv, 'data-mce-bogus', 'all'); - setAll(offscreenDiv, { - position: 'fixed', - left: '-9999999px', - top: '0', - overflow: 'hidden', - opacity: '0' - }); - const root = getContentContainer(dos); - append(offscreenDiv, replicaElements); - append$1(root, offscreenDiv); - const textContent = offscreenDiv.dom.innerText; - remove$6(offscreenDiv); - return textContent; + const setExact = (win, start, soffset, finish, foffset) => { + const relative = preprocessExact(start, soffset, finish, foffset); + setRangeFromRelative(win, relative); }; - const registerEvents = (editor, actions) => { - editor.on('BeforeGetContent', e => { - const multiCellContext = cells => { - e.preventDefault(); - extractSelected(cells).each(replicaElements => { - const content = e.format === 'text' ? getTextContent(editor, replicaElements) : serializeElements(editor, replicaElements); - e.content = content; - }); - }; - if (e.selection === true) { - const cells = getCellsFromFakeSelection(editor); - if (cells.length >= 1) { - multiCellContext(cells); - } + const setRelative = (win, startSitu, finishSitu) => { + const relative = preprocessRelative(startSitu, finishSitu); + setRangeFromRelative(win, relative); + }; + // NOTE: We are still reading the range because it gives subtly different behaviour + // than using the anchorNode and focusNode. I'm not sure if this behaviour is any + // better or worse; it's just different. + const readRange = (selection) => { + if (selection.rangeCount > 0) { + const firstRng = selection.getRangeAt(0); + const lastRng = selection.getRangeAt(selection.rangeCount - 1); + return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset)); } - }); - editor.on('BeforeSetContent', e => { - if (e.selection === true && e.paste === true) { - const selectedCells = getCellsFromSelection(editor); - head(selectedCells).each(cell => { - table(cell).each(table => { - const elements = filter$2(fromHtml(e.content), content => { - return name(content) !== 'meta'; - }); - const isTable = isTag('table'); - if (shouldMergeContentOnPaste(editor) && elements.length === 1 && isTable(elements[0])) { - e.preventDefault(); - const doc = SugarElement.fromDom(editor.getDoc()); - const generators = paste$1(doc); - const targets = paste(cell, elements[0], generators); - actions.pasteCells(table, targets).each(() => { - editor.focus(); - }); - } - }); - }); + else { + return Optional.none(); } - }); }; - - const point = (element, offset) => ({ - element, - offset - }); - - const scan$1 = (universe, element, direction) => { - if (universe.property().isText(element) && universe.property().getText(element).trim().length === 0 || universe.property().isComment(element)) { - return direction(element).bind(elem => { - return scan$1(universe, elem, direction).orThunk(() => { - return Optional.some(elem); - }); - }); - } else { - return Optional.none(); - } + const doGetExact = (selection) => { + if (selection.anchorNode === null || selection.focusNode === null) { + return readRange(selection); + } + else { + const anchor = SugarElement.fromDom(selection.anchorNode); + const focus = SugarElement.fromDom(selection.focusNode); + // if this returns true anchor is _after_ focus, so we need a custom selection object to maintain the RTL selection + return after$5(anchor, selection.anchorOffset, focus, selection.focusOffset) ? Optional.some(SimRange.create(anchor, selection.anchorOffset, focus, selection.focusOffset)) : readRange(selection); + } }; - const toEnd = (universe, element) => { - if (universe.property().isText(element)) { - return universe.property().getText(element).length; - } - const children = universe.property().children(element); - return children.length; + const setToElement = (win, element, selectNodeContents$1 = true) => { + const rngGetter = selectNodeContents$1 ? selectNodeContents : selectNode; + const rng = rngGetter(win, element); + doSetNativeRange(win, rng); + }; + const getExact = (win) => + // We want to retrieve the selection as it is. + getNativeSelection(win) + .filter((sel) => sel.rangeCount > 0) + .bind(doGetExact); + // TODO: Test this. + const get$3 = (win) => getExact(win).map((range) => SimSelection.exact(range.start, range.soffset, range.finish, range.foffset)); + const getFirstRect = (win, selection) => { + const rng = asLtrRange(win, selection); + return getFirstRect$1(rng); }; - const freefallRtl$2 = (universe, element) => { - const candidate = scan$1(universe, element, universe.query().prevSibling).getOr(element); - if (universe.property().isText(candidate)) { - return point(candidate, toEnd(universe, candidate)); - } - const children = universe.property().children(candidate); - return children.length > 0 ? freefallRtl$2(universe, children[children.length - 1]) : point(candidate, toEnd(universe, candidate)); + const getAtPoint = (win, x, y) => fromPoint(win, x, y); + const clear = (win) => { + getNativeSelection(win).each((selection) => selection.removeAllRanges()); }; - const freefallRtl$1 = freefallRtl$2; - - const universe$2 = DomUniverse(); - const freefallRtl = element => { - return freefallRtl$1(universe$2, element); + const units = { + // we don't really support all of these different ways to express a length + unsupportedLength: [ + 'em', + 'ex', + 'cap', + 'ch', + 'ic', + 'rem', + 'lh', + 'rlh', + 'vw', + 'vh', + 'vi', + 'vb', + 'vmin', + 'vmax', + 'cm', + 'mm', + 'Q', + 'in', + 'pc', + 'pt', + 'px' + ], + // these are the length values we do support + fixed: ['px', 'pt'], + relative: ['%'], + empty: [''] }; - - const halve = (main, other) => { - if (!hasColspan(main)) { - const width = getGenericWidth(main); - width.each(w => { - const newWidth = w.value / 2; - setGenericWidth(main, newWidth, w.unit); - setGenericWidth(other, newWidth, w.unit); + // Built from https://tc39.es/ecma262/#prod-StrDecimalLiteral + // Matches a float followed by a trailing set of characters + const pattern = (() => { + const decimalDigits = '[0-9]+'; + const signedInteger = '[+-]?' + decimalDigits; + const exponentPart = '[eE]' + signedInteger; + const dot = '\\.'; + const opt = (input) => `(?:${input})?`; + const unsignedDecimalLiteral = [ + 'Infinity', + decimalDigits + dot + opt(decimalDigits) + opt(exponentPart), + dot + decimalDigits + opt(exponentPart), + decimalDigits + opt(exponentPart) + ].join('|'); + const float = `[+-]?(?:${unsignedDecimalLiteral})`; + return new RegExp(`^(${float})(.*)$`); + })(); + const isUnit = (unit, accepted) => exists(accepted, (acc) => exists(units[acc], (check) => unit === check)); + const parse = (input, accepted) => { + const match = Optional.from(pattern.exec(input)); + return match.bind((array) => { + const value = Number(array[1]); + const unitRaw = array[2]; + if (isUnit(unitRaw, accepted)) { + return Optional.some({ + value, + unit: unitRaw + }); + } + else { + return Optional.none(); + } }); - } }; - const zero = array => map$1(array, constant(0)); + const zero = (array) => map$1(array, constant(0)); const surround = (sizes, startIndex, endIndex, results, f) => f(sizes.slice(0, startIndex)).concat(results).concat(f(sizes.slice(endIndex))); - const clampDeltaHelper = predicate => (sizes, index, delta, minCellSize) => { - if (!predicate(delta)) { - return delta; - } else { - const newSize = Math.max(minCellSize, sizes[index] - Math.abs(delta)); - const diff = Math.abs(newSize - sizes[index]); - return delta >= 0 ? diff : -diff; - } - }; - const clampNegativeDelta = clampDeltaHelper(delta => delta < 0); + // Clamp positive or negative delta so that a column/row cannot be reduced past its min size + const clampDeltaHelper = (predicate) => (sizes, index, delta, minCellSize) => { + if (!predicate(delta)) { + return delta; + } + else { + const newSize = Math.max(minCellSize, sizes[index] - Math.abs(delta)); + const diff = Math.abs(newSize - sizes[index]); + return delta >= 0 ? diff : -diff; + } + }; + const clampNegativeDelta = clampDeltaHelper((delta) => delta < 0); const clampDelta = clampDeltaHelper(always); + // Preserve the size of the columns/rows and adjust the table size const resizeTable = () => { - const calcFixedDeltas = (sizes, index, next, delta, minCellSize) => { - const clampedDelta = clampNegativeDelta(sizes, index, delta, minCellSize); - return surround(sizes, index, next + 1, [ - clampedDelta, - 0 - ], zero); - }; - const calcRelativeDeltas = (sizes, index, delta, minCellSize) => { - const ratio = (100 + delta) / 100; - const newThis = Math.max(minCellSize, (sizes[index] + delta) / ratio); - return map$1(sizes, (size, idx) => { - const newSize = idx === index ? newThis : size / ratio; - return newSize - size; - }); - }; - const calcLeftEdgeDeltas = (sizes, index, next, delta, minCellSize, isRelative) => { - if (isRelative) { - return calcRelativeDeltas(sizes, index, delta, minCellSize); - } else { - return calcFixedDeltas(sizes, index, next, delta, minCellSize); - } - }; - const calcMiddleDeltas = (sizes, _prev, index, next, delta, minCellSize, isRelative) => calcLeftEdgeDeltas(sizes, index, next, delta, minCellSize, isRelative); - const resizeTable = (resizer, delta) => resizer(delta); - const calcRightEdgeDeltas = (sizes, _prev, index, delta, minCellSize, isRelative) => { - if (isRelative) { - return calcRelativeDeltas(sizes, index, delta, minCellSize); - } else { - const clampedDelta = clampNegativeDelta(sizes, index, delta, minCellSize); - return zero(sizes.slice(0, index)).concat([clampedDelta]); - } - }; - const calcRedestributedWidths = (sizes, totalWidth, pixelDelta, isRelative) => { - if (isRelative) { - const tableWidth = totalWidth + pixelDelta; - const ratio = tableWidth / totalWidth; - const newSizes = map$1(sizes, size => size / ratio); - return { - delta: ratio * 100 - 100, - newSizes - }; - } else { - return { - delta: pixelDelta, - newSizes: sizes - }; - } - }; - return { - resizeTable, - clampTableDelta: clampNegativeDelta, - calcLeftEdgeDeltas, - calcMiddleDeltas, - calcRightEdgeDeltas, - calcRedestributedWidths - }; + const calcFixedDeltas = (sizes, index, next, delta, minCellSize) => { + const clampedDelta = clampNegativeDelta(sizes, index, delta, minCellSize); + return surround(sizes, index, next + 1, [clampedDelta, 0], zero); + }; + // Calculate delta for adjusted column + // Also need to calculate deltas for all other columns/rows to ensure they stay at the same visual width/height + // when the table width/height is adjusted + const calcRelativeDeltas = (sizes, index, delta, minCellSize) => { + // ASSUMPTION: The delta will be a percentage. This may not be correct if other relative sizing is added, so we probably + // need a better way to calc the ratio. + const ratio = (100 + delta) / 100; + const newThis = Math.max(minCellSize, (sizes[index] + delta) / ratio); + return map$1(sizes, (size, idx) => { + const newSize = idx === index ? newThis : size / ratio; + return newSize - size; + }); + }; + // Calculations for the inner columns/rows + const calcLeftEdgeDeltas = (sizes, index, next, delta, minCellSize, isRelative) => { + if (isRelative) { + return calcRelativeDeltas(sizes, index, delta, minCellSize); + } + else { + return calcFixedDeltas(sizes, index, next, delta, minCellSize); + } + }; + const calcMiddleDeltas = (sizes, _prev, index, next, delta, minCellSize, isRelative) => calcLeftEdgeDeltas(sizes, index, next, delta, minCellSize, isRelative); + const resizeTable = (resizer, delta) => resizer(delta); + // Calculations for the last column/row resizer + const calcRightEdgeDeltas = (sizes, _prev, index, delta, minCellSize, isRelative) => { + if (isRelative) { + return calcRelativeDeltas(sizes, index, delta, minCellSize); + } + else { + const clampedDelta = clampNegativeDelta(sizes, index, delta, minCellSize); + return zero(sizes.slice(0, index)).concat([clampedDelta]); + } + }; + const calcRedestributedWidths = (sizes, totalWidth, pixelDelta, isRelative) => { + if (isRelative) { + const tableWidth = totalWidth + pixelDelta; + const ratio = tableWidth / totalWidth; + const newSizes = map$1(sizes, (size) => size / ratio); + return { + delta: (ratio * 100) - 100, + newSizes, + }; + } + else { + return { + delta: pixelDelta, + newSizes: sizes, + }; + } + }; + return { + resizeTable, + clampTableDelta: clampNegativeDelta, + calcLeftEdgeDeltas, + calcMiddleDeltas, + calcRightEdgeDeltas, + calcRedestributedWidths, + }; }; + // Distribute the column/rows and try to preserve the table size const preserveTable = () => { - const calcLeftEdgeDeltas = (sizes, index, next, delta, minCellSize) => { - const idx = delta >= 0 ? next : index; - const clampedDelta = clampDelta(sizes, idx, delta, minCellSize); - return surround(sizes, index, next + 1, [ - clampedDelta, - -clampedDelta - ], zero); - }; - const calcMiddleDeltas = (sizes, _prev, index, next, delta, minCellSize) => calcLeftEdgeDeltas(sizes, index, next, delta, minCellSize); - const resizeTable = (resizer, delta, isLastColumn) => { - if (isLastColumn) { - resizer(delta); - } - }; - const calcRightEdgeDeltas = (sizes, _prev, _index, delta, _minCellSize, isRelative) => { - if (isRelative) { - return zero(sizes); - } else { - const diff = delta / sizes.length; - return map$1(sizes, constant(diff)); - } - }; - const clampTableDelta = (sizes, index, delta, minCellSize, isLastColumn) => { - if (isLastColumn) { - if (delta >= 0) { - return delta; - } else { - const maxDelta = foldl(sizes, (a, b) => a + b - minCellSize, 0); - return Math.max(-maxDelta, delta); - } - } else { - return clampNegativeDelta(sizes, index, delta, minCellSize); - } - }; - const calcRedestributedWidths = (sizes, _totalWidth, _pixelDelta, _isRelative) => ({ - delta: 0, - newSizes: sizes - }); - return { - resizeTable, - clampTableDelta, - calcLeftEdgeDeltas, - calcMiddleDeltas, - calcRightEdgeDeltas, - calcRedestributedWidths - }; + // Calculations for the inner columns/rows + const calcLeftEdgeDeltas = (sizes, index, next, delta, minCellSize) => { + const idx = delta >= 0 ? next : index; + const clampedDelta = clampDelta(sizes, idx, delta, minCellSize); + // negative delta -> deltas becomes [ neg, pos ], positive delta -> deltas becomes [ pos, neg ] + return surround(sizes, index, next + 1, [clampedDelta, -clampedDelta], zero); + }; + const calcMiddleDeltas = (sizes, _prev, index, next, delta, minCellSize) => calcLeftEdgeDeltas(sizes, index, next, delta, minCellSize); + const resizeTable = (resizer, delta, isLastColumn) => { + if (isLastColumn) { + resizer(delta); + } + }; + // Calculations for the last column/row resizer + const calcRightEdgeDeltas = (sizes, _prev, _index, delta, _minCellSize, isRelative) => { + if (isRelative) { + return zero(sizes); + } + else { + // Distribute the delta amongst all of the columns/rows + const diff = delta / sizes.length; + return map$1(sizes, constant(diff)); + } + }; + const clampTableDelta = (sizes, index, delta, minCellSize, isLastColumn) => { + // Don't clamp the last resizer using normal methods + // Need to allow table width to be reduced past the last column position to allow for distributive resizing + if (isLastColumn) { + if (delta >= 0) { + return delta; + } + else { + // Clamp delta so that none of the columns/rows can reduce below their min size + const maxDelta = foldl(sizes, (a, b) => a + b - minCellSize, 0); + return Math.max(-maxDelta, delta); + } + } + else { + return clampNegativeDelta(sizes, index, delta, minCellSize); + } + }; + const calcRedestributedWidths = (sizes, _totalWidth, _pixelDelta, _isRelative) => ({ + delta: 0, + newSizes: sizes, + }); + return { + resizeTable, + clampTableDelta, + calcLeftEdgeDeltas, + calcMiddleDeltas, + calcRightEdgeDeltas, + calcRedestributedWidths + }; }; - const getGridSize = table => { - const warehouse = Warehouse.fromTable(table); - return warehouse.grid; + const getAttrValue = (cell, name, fallback = 0) => getOpt(cell, name).map((value) => parseInt(value, 10)).getOr(fallback); + const getSpan = (cell, type) => getAttrValue(cell, type, 1); + const hasColspan = (cellOrCol) => { + if (isTag('col')(cellOrCol)) { + return getAttrValue(cellOrCol, 'span', 1) > 1; + } + else { + return getSpan(cellOrCol, 'colspan') > 1; + } }; + const hasRowspan = (cell) => getSpan(cell, 'rowspan') > 1; + const getCssValue = (element, property) => parseInt(get$9(element, property), 10); + const minWidth = constant(10); + const minHeight = constant(10); - const isHeaderCell = isTag('th'); - const isHeaderCells = cells => forall(cells, cell => isHeaderCell(cell.element)); - const getRowHeaderType = (isHeaderRow, isHeaderCells) => { - if (isHeaderRow && isHeaderCells) { - return 'sectionCells'; - } else if (isHeaderRow) { - return 'section'; - } else { - return 'cells'; - } - }; - const getRowType = row => { - const isHeaderRow = row.section === 'thead'; - const isHeaderCells = is(findCommonCellType(row.cells), 'th'); - if (row.section === 'tfoot') { - return { type: 'footer' }; - } else if (isHeaderRow || isHeaderCells) { - return { - type: 'header', - subType: getRowHeaderType(isHeaderRow, isHeaderCells) - }; - } else { - return { type: 'body' }; - } - }; - const findCommonCellType = cells => { - const headerCells = filter$2(cells, cell => isHeaderCell(cell.element)); - if (headerCells.length === 0) { - return Optional.some('td'); - } else if (headerCells.length === cells.length) { - return Optional.some('th'); - } else { - return Optional.none(); - } - }; - const findCommonRowType = rows => { - const rowTypes = map$1(rows, row => getRowType(row).type); - const hasHeader = contains$2(rowTypes, 'header'); - const hasFooter = contains$2(rowTypes, 'footer'); - if (!hasHeader && !hasFooter) { - return Optional.some('body'); - } else { - const hasBody = contains$2(rowTypes, 'body'); - if (hasHeader && !hasBody && !hasFooter) { - return Optional.some('header'); - } else if (!hasHeader && !hasBody && hasFooter) { - return Optional.some('footer'); - } else { - return Optional.none(); - } - } - }; - const findTableRowHeaderType = warehouse => findMap(warehouse.all, row => { - const rowType = getRowType(row); - return rowType.type === 'header' ? Optional.from(rowType.subType) : Optional.none(); - }); - - const transformCell = (cell, comparator, substitution) => elementnew(substitution(cell.element, comparator), true, cell.isLocked); - const transformRow = (row, section) => row.section !== section ? rowcells(row.element, row.cells, section, row.isNew) : row; - const section = () => ({ - transformRow, - transformCell: (cell, comparator, substitution) => { - const newCell = substitution(cell.element, comparator); - const fixedCell = name(newCell) !== 'td' ? mutate$1(newCell, 'td') : newCell; - return elementnew(fixedCell, cell.isNew, cell.isLocked); - } - }); - const sectionCells = () => ({ - transformRow, - transformCell - }); - const cells = () => ({ - transformRow: (row, section) => { - const newSection = section === 'thead' ? 'tbody' : section; - return transformRow(row, newSection); - }, - transformCell - }); - const fallback = () => ({ - transformRow: identity, - transformCell - }); - const getTableSectionType = (table, fallback) => { - const warehouse = Warehouse.fromTable(table); - const type = findTableRowHeaderType(warehouse).getOr(fallback); - switch (type) { - case 'section': - return section(); - case 'sectionCells': - return sectionCells(); - case 'cells': - return cells(); - } + const firstLayer = (scope, selector) => { + return filterFirstLayer(scope, selector, always); }; - const TableSection = { - getTableSectionType, - section, - sectionCells, - cells, - fallback + const filterFirstLayer = (scope, selector, predicate) => { + return bind$2(children$2(scope), (x) => { + if (is$1(x, selector)) { + return predicate(x) ? [x] : []; + } + else { + return filterFirstLayer(x, selector, predicate); + } + }); }; - const setIfNot = (element, property, value, ignore) => { - if (value === ignore) { - remove$7(element, property); - } else { - set$2(element, property, value); - } - }; - const insert$1 = (table, selector, element) => { - last$2(children(table, selector)).fold(() => prepend(table, element), child => after$5(child, element)); - }; - const generateSection = (table, sectionName) => { - const section = child(table, sectionName).getOrThunk(() => { - const newSection = SugarElement.fromTag(sectionName, owner(table).dom); - if (sectionName === 'thead') { - insert$1(table, 'caption,colgroup', newSection); - } else if (sectionName === 'colgroup') { - insert$1(table, 'caption', newSection); - } else { - append$1(table, newSection); - } - return newSection; - }); - empty(section); - return section; + // lookup inside this table + const lookup = (tags, element, isRoot = never) => { + // If the element we're inspecting is the root, we definitely don't want it. + if (isRoot(element)) { + return Optional.none(); + } + // This looks a lot like SelectorFind.closest, with one big exception - the isRoot check. + // The code here will look for parents if passed a table, SelectorFind.closest with that specific isRoot check won't. + if (contains$2(tags, name(element))) { + return Optional.some(element); + } + const isRootOrUpperTable = (elm) => is$1(elm, 'table') || isRoot(elm); + return ancestor$1(element, tags.join(','), isRootOrUpperTable); + }; + /* + * Identify the optional cell that element represents. + */ + const cell = (element, isRoot) => lookup(['td', 'th'], element, isRoot); + const cells$1 = (ancestor) => firstLayer(ancestor, 'th,td'); + const columns$1 = (ancestor) => { + if (is$1(ancestor, 'colgroup')) { + return children(ancestor, 'col'); + } + else { + return bind$2(columnGroups(ancestor), (columnGroup) => children(columnGroup, 'col')); + } }; - const render$1 = (table, grid) => { - const newRows = []; - const newCells = []; - const syncRows = gridSection => map$1(gridSection, row => { - if (row.isNew) { - newRows.push(row.element); - } - const tr = row.element; - empty(tr); - each$2(row.cells, cell => { - if (cell.isNew) { - newCells.push(cell.element); - } - setIfNot(cell.element, 'colspan', cell.colspan, 1); - setIfNot(cell.element, 'rowspan', cell.rowspan, 1); - append$1(tr, cell.element); - }); - return tr; - }); - const syncColGroup = gridSection => bind$2(gridSection, colGroup => map$1(colGroup.cells, col => { - setIfNot(col.element, 'span', col.colspan, 1); - return col.element; - })); - const renderSection = (gridSection, sectionName) => { - const section = generateSection(table, sectionName); - const sync = sectionName === 'colgroup' ? syncColGroup : syncRows; - const sectionElems = sync(gridSection); - append(section, sectionElems); - }; - const removeSection = sectionName => { - child(table, sectionName).each(remove$6); - }; - const renderOrRemoveSection = (gridSection, sectionName) => { - if (gridSection.length > 0) { - renderSection(gridSection, sectionName); - } else { - removeSection(sectionName); - } - }; - const headSection = []; - const bodySection = []; - const footSection = []; - const columnGroupsSection = []; - each$2(grid, row => { - switch (row.section) { - case 'thead': - headSection.push(row); - break; - case 'tbody': - bodySection.push(row); - break; - case 'tfoot': - footSection.push(row); - break; - case 'colgroup': - columnGroupsSection.push(row); - break; - } - }); - renderOrRemoveSection(columnGroupsSection, 'colgroup'); - renderOrRemoveSection(headSection, 'thead'); - renderOrRemoveSection(bodySection, 'tbody'); - renderOrRemoveSection(footSection, 'tfoot'); - return { - newRows, - newCells - }; - }; - const copy = grid => map$1(grid, row => { - const tr = shallow(row.element); - each$2(row.cells, cell => { - const clonedCell = deep(cell.element); - setIfNot(clonedCell, 'colspan', cell.colspan, 1); - setIfNot(clonedCell, 'rowspan', cell.rowspan, 1); - append$1(tr, clonedCell); - }); - return tr; - }); + const table = (element, isRoot) => closest$1(element, 'table', isRoot); + const rows$1 = (ancestor) => firstLayer(ancestor, 'tr'); + const columnGroups = (ancestor) => table(ancestor).fold(constant([]), (table) => children(table, 'colgroup')); - const getColumn = (grid, index) => { - return map$1(grid, row => { - return getCell(row, index); - }); + const isHeaderCell = isTag('th'); + const isHeaderCells = (cells) => forall(cells, (cell) => isHeaderCell(cell.element)); + const getRowHeaderType = (isHeaderRow, isHeaderCells) => { + if (isHeaderRow && isHeaderCells) { + return 'sectionCells'; + } + else if (isHeaderRow) { + return 'section'; + } + else { + return 'cells'; + } }; - const getRow = (grid, index) => { - return grid[index]; - }; - const findDiff = (xs, comp) => { - if (xs.length === 0) { - return 0; - } - const first = xs[0]; - const index = findIndex(xs, x => { - return !comp(first.element, x.element); - }); - return index.getOr(xs.length); - }; - const subgrid = (grid, row, column, comparator) => { - const gridRow = getRow(grid, row); - const isColRow = gridRow.section === 'colgroup'; - const colspan = findDiff(gridRow.cells.slice(column), comparator); - const rowspan = isColRow ? 1 : findDiff(getColumn(grid.slice(row), column), comparator); - return { - colspan, - rowspan - }; + const getRowType = (row) => { + // Header rows can use a combination of theads and ths - want to detect the different combinations + const isHeaderRow = row.section === 'thead'; + const isHeaderCells = is$2(findCommonCellType(row.cells), 'th'); + if (row.section === 'tfoot') { + return { type: 'footer' }; + } + else if (isHeaderRow || isHeaderCells) { + return { type: 'header', subType: getRowHeaderType(isHeaderRow, isHeaderCells) }; + } + else { + return { type: 'body' }; + } }; - - const toDetails = (grid, comparator) => { - const seen = map$1(grid, row => map$1(row.cells, never)); - const updateSeen = (rowIndex, columnIndex, rowspan, colspan) => { - for (let row = rowIndex; row < rowIndex + rowspan; row++) { - for (let column = columnIndex; column < columnIndex + colspan; column++) { - seen[row][column] = true; - } + const findCommonCellType = (cells) => { + const headerCells = filter$2(cells, (cell) => isHeaderCell(cell.element)); + if (headerCells.length === 0) { + return Optional.some('td'); + } + else if (headerCells.length === cells.length) { + return Optional.some('th'); + } + else { + return Optional.none(); } - }; - return map$1(grid, (row, rowIndex) => { - const details = bind$2(row.cells, (cell, columnIndex) => { - if (seen[rowIndex][columnIndex] === false) { - const result = subgrid(grid, rowIndex, columnIndex, comparator); - updateSeen(rowIndex, columnIndex, result.rowspan, result.colspan); - return [detailnew(cell.element, result.rowspan, result.colspan, cell.isNew)]; - } else { - return []; - } - }); - return rowdetailnew(row.element, details, row.section, row.isNew); - }); }; - const toGrid = (warehouse, generators, isNew) => { - const grid = []; - each$2(warehouse.colgroups, colgroup => { - const colgroupCols = []; - for (let columnIndex = 0; columnIndex < warehouse.grid.columns; columnIndex++) { - const element = Warehouse.getColumnAt(warehouse, columnIndex).map(column => elementnew(column.element, isNew, false)).getOrThunk(() => elementnew(generators.colGap(), true, false)); - colgroupCols.push(element); - } - grid.push(rowcells(colgroup.element, colgroupCols, 'colgroup', isNew)); - }); - for (let rowIndex = 0; rowIndex < warehouse.grid.rows; rowIndex++) { - const rowCells = []; - for (let columnIndex = 0; columnIndex < warehouse.grid.columns; columnIndex++) { - const element = Warehouse.getAt(warehouse, rowIndex, columnIndex).map(item => elementnew(item.element, isNew, item.isLocked)).getOrThunk(() => elementnew(generators.gap(), true, false)); - rowCells.push(element); - } - const rowDetail = warehouse.all[rowIndex]; - const row = rowcells(rowDetail.element, rowCells, rowDetail.section, isNew); - grid.push(row); - } - return grid; + const findCommonRowType = (rows) => { + const rowTypes = map$1(rows, (row) => getRowType(row).type); + const hasHeader = contains$2(rowTypes, 'header'); + const hasFooter = contains$2(rowTypes, 'footer'); + if (!hasHeader && !hasFooter) { + return Optional.some('body'); + } + else { + const hasBody = contains$2(rowTypes, 'body'); + if (hasHeader && !hasBody && !hasFooter) { + return Optional.some('header'); + } + else if (!hasHeader && !hasBody && hasFooter) { + return Optional.some('footer'); + } + else { + return Optional.none(); + } + } }; + const findTableRowHeaderType = (warehouse) => findMap(warehouse.all, (row) => { + const rowType = getRowType(row); + return rowType.type === 'header' ? Optional.from(rowType.subType) : Optional.none(); + }); - const fromWarehouse = (warehouse, generators) => toGrid(warehouse, generators, false); - const toDetailList = grid => toDetails(grid, eq$1); - const findInWarehouse = (warehouse, element) => findMap(warehouse.all, r => find$1(r.cells, e => eq$1(element, e.element))); - const extractCells = (warehouse, target, predicate) => { - const details = map$1(target.selection, cell$1 => { - return cell(cell$1).bind(lc => findInWarehouse(warehouse, lc)).filter(predicate); - }); - const cells = cat(details); - return someIf(cells.length > 0, cells); - }; - const run = (operation, extract, adjustment, postAction, genWrappers) => (table, target, generators, behaviours) => { - const warehouse = Warehouse.fromTable(table); - const tableSection = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.section).getOrThunk(TableSection.fallback); - const output = extract(warehouse, target).map(info => { - const model = fromWarehouse(warehouse, generators); - const result = operation(model, info, eq$1, genWrappers(generators), tableSection); - const lockedColumns = getLockedColumnsFromGrid(result.grid); - const grid = toDetailList(result.grid); - return { - info, - grid, - cursor: result.cursor, - lockedColumns - }; - }); - return output.bind(out => { - const newElements = render$1(table, out.grid); - const tableSizing = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.sizing).getOrThunk(() => TableSize.getTableSize(table)); - const resizing = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.resize).getOrThunk(preserveTable); - adjustment(table, out.grid, out.info, { - sizing: tableSizing, - resize: resizing, - section: tableSection - }); - postAction(table); - remove$7(table, LOCKED_COL_ATTR); - if (out.lockedColumns.length > 0) { - set$2(table, LOCKED_COL_ATTR, out.lockedColumns.join(',')); - } - return Optional.some({ - cursor: out.cursor, - newRows: newElements.newRows, - newCells: newElements.newCells - }); - }); - }; - const onPaste = (warehouse, target) => cell(target.element).bind(cell => findInWarehouse(warehouse, cell).map(details => { - const value = { - ...details, - generators: target.generators, - clipboard: target.clipboard - }; - return value; - })); - const onPasteByEditor = (warehouse, target) => extractCells(warehouse, target, always).map(cells => ({ - cells, - generators: target.generators, - clipboard: target.clipboard - })); - const onMergable = (_warehouse, target) => target.mergable; - const onUnmergable = (_warehouse, target) => target.unmergable; - const onCells = (warehouse, target) => extractCells(warehouse, target, always); - const onUnlockedCells = (warehouse, target) => extractCells(warehouse, target, detail => !detail.isLocked); - const isUnlockedTableCell = (warehouse, cell) => findInWarehouse(warehouse, cell).exists(detail => !detail.isLocked); - const allUnlocked = (warehouse, cells) => forall(cells, cell => isUnlockedTableCell(warehouse, cell)); - const onUnlockedMergable = (warehouse, target) => onMergable(warehouse, target).filter(mergeable => allUnlocked(warehouse, mergeable.cells)); - const onUnlockedUnmergable = (warehouse, target) => onUnmergable(warehouse, target).filter(cells => allUnlocked(warehouse, cells)); - - const merge$2 = (grid, bounds, comparator, substitution) => { - const rows = extractGridDetails(grid).rows; - if (rows.length === 0) { - return grid; - } - for (let i = bounds.startRow; i <= bounds.finishRow; i++) { - for (let j = bounds.startCol; j <= bounds.finishCol; j++) { - const row = rows[i]; - const isLocked = getCell(row, j).isLocked; - mutateCell(row, j, elementnew(substitution(), false, isLocked)); + const fromRowsOrColGroups = (elems, getSection) => map$1(elems, (row) => { + if (name(row) === 'colgroup') { + const cells = map$1(columns$1(row), (column) => { + const colspan = getAttrValue(column, 'span', 1); + return detail(column, 1, colspan); + }); + return rowdetail(row, cells, 'colgroup'); } - } - return grid; - }; - const unmerge = (grid, target, comparator, substitution) => { - const rows = extractGridDetails(grid).rows; - let first = true; - for (let i = 0; i < rows.length; i++) { - for (let j = 0; j < cellLength(rows[0]); j++) { - const row = rows[i]; - const currentCell = getCell(row, j); - const currentCellElm = currentCell.element; - const isToReplace = comparator(currentCellElm, target); - if (isToReplace && !first) { - mutateCell(row, j, elementnew(substitution(), true, currentCell.isLocked)); - } else if (isToReplace) { - first = false; - } + else { + const cells = map$1(cells$1(row), (cell) => { + const rowspan = getAttrValue(cell, 'rowspan', 1); + const colspan = getAttrValue(cell, 'colspan', 1); + return detail(cell, rowspan, colspan); + }); + return rowdetail(row, cells, getSection(row)); } - } - return grid; + }); + const getParentSection = (group) => parent(group).map((parent) => { + const parentName = name(parent); + return isValidSection(parentName) ? parentName : 'tbody'; + }).getOr('tbody'); + /* + * Takes a DOM table and returns a list of list of: + element: row element + cells: (id, rowspan, colspan) structs + */ + const fromTable$1 = (table) => { + const rows = rows$1(table); + const columnGroups$1 = columnGroups(table); + const elems = [...columnGroups$1, ...rows]; + return fromRowsOrColGroups(elems, getParentSection); }; - const uniqueCells = (row, comparator) => { - return foldl(row, (rest, cell) => { - return exists(rest, currentCell => { - return comparator(currentCell.element, cell.element); - }) ? rest : rest.concat([cell]); - }, []); + const fromPastedRows = (elems, section) => fromRowsOrColGroups(elems, () => section); + + const LOCKED_COL_ATTR = 'data-snooker-locked-cols'; + const getLockedColumnsFromTable = (table) => getOpt(table, LOCKED_COL_ATTR) + .bind((lockedColStr) => Optional.from(lockedColStr.match(/\d+/g))) + .map((lockedCols) => mapToObject(lockedCols, always)); + // Need to check all of the cells to determine which columns are locked - reasoning is because rowspan and colspan cells where the same cell is used by multiple columns + const getLockedColumnsFromGrid = (grid) => { + const locked = foldl(extractGridDetails(grid).rows, (acc, row) => { + each$2(row.cells, (cell, idx) => { + if (cell.isLocked) { + acc[idx] = true; + } + }); + return acc; + }, {}); + const lockedArr = mapToArray(locked, (_val, key) => parseInt(key, 10)); + return sort$1(lockedArr); }; - const splitCols = (grid, index, comparator, substitution) => { - if (index > 0 && index < grid[0].cells.length) { - each$2(grid, row => { - const prevCell = row.cells[index - 1]; - let offset = 0; - const substitute = substitution(); - while (row.cells.length > index + offset && comparator(prevCell.element, row.cells[index + offset].element)) { - mutateCell(row, index + offset, elementnew(substitute, true, row.cells[index + offset].isLocked)); - offset++; - } + + const key = (row, column) => { + return row + ',' + column; + }; + const getAt = (warehouse, row, column) => Optional.from(warehouse.access[key(row, column)]); + const findItem = (warehouse, item, comparator) => { + const filtered = filterItems(warehouse, (detail) => { + return comparator(item, detail.element); }); - } - return grid; + return filtered.length > 0 ? Optional.some(filtered[0]) : Optional.none(); }; - const splitRows = (grid, index, comparator, substitution) => { - const rows = extractGridDetails(grid).rows; - if (index > 0 && index < rows.length) { - const rowPrevCells = rows[index - 1].cells; - const cells = uniqueCells(rowPrevCells, comparator); - each$2(cells, cell => { - let replacement = Optional.none(); - for (let i = index; i < rows.length; i++) { - for (let j = 0; j < cellLength(rows[0]); j++) { - const row = rows[i]; - const current = getCell(row, j); - const isToReplace = comparator(current.element, cell.element); - if (isToReplace) { - if (replacement.isNone()) { - replacement = Optional.some(substitution()); + const filterItems = (warehouse, predicate) => { + const all = bind$2(warehouse.all, (r) => { + return r.cells; + }); + return filter$2(all, predicate); + }; + const generateColumns = (rowData) => { + const columnsGroup = {}; + let index = 0; + each$2(rowData.cells, (column) => { + const colspan = column.colspan; + range$1(colspan, (columnIndex) => { + const colIndex = index + columnIndex; + columnsGroup[colIndex] = columnext(column.element, colspan, colIndex); + }); + index += colspan; + }); + return columnsGroup; + }; + /* + * From a list of list of Detail, generate three pieces of information: + * 1. the grid size + * 2. a data structure which can efficiently identify which cell is in which row,column position + * 3. a list of all cells in order left-to-right, top-to-bottom + */ + const generate = (list) => { + // list is an array of objects, made by cells and elements + // elements: is the TR + // cells: is an array of objects representing the cells in the row. + // It is made of: + // colspan (merge cell) + // element + // rowspan (merge cols) + const access = {}; + const cells = []; + const tableOpt = head(list).map((rowData) => rowData.element).bind(table); + const lockedColumns = tableOpt.bind(getLockedColumnsFromTable).getOr({}); + let maxRows = 0; + let maxColumns = 0; + let rowCount = 0; + const { pass: colgroupRows, fail: rows } = partition(list, (rowData) => rowData.section === 'colgroup'); + // Handle rows first + each$2(rows, (rowData) => { + const currentRow = []; + each$2(rowData.cells, (rowCell) => { + let start = 0; + // If this spot has been taken by a previous rowspan, skip it. + while (access[key(rowCount, start)] !== undefined) { + start++; } - replacement.each(sub => { - mutateCell(row, j, elementnew(sub, true, current.isLocked)); - }); - } - } - } + const isLocked = hasNonNullableKey(lockedColumns, start.toString()); + const current = extended(rowCell.element, rowCell.rowspan, rowCell.colspan, rowCount, start, isLocked); + // Occupy all the (row, column) positions that this cell spans for. + for (let occupiedColumnPosition = 0; occupiedColumnPosition < rowCell.colspan; occupiedColumnPosition++) { + for (let occupiedRowPosition = 0; occupiedRowPosition < rowCell.rowspan; occupiedRowPosition++) { + const rowPosition = rowCount + occupiedRowPosition; + const columnPosition = start + occupiedColumnPosition; + const newpos = key(rowPosition, columnPosition); + access[newpos] = current; + maxColumns = Math.max(maxColumns, columnPosition + 1); + } + } + currentRow.push(current); + }); + maxRows++; + cells.push(rowdetail(rowData.element, currentRow, rowData.section)); + rowCount++; }); - } - return grid; - }; - - const value$1 = value => { - const applyHelper = fn => fn(value); - const constHelper = constant(value); - const outputHelper = () => output; - const output = { - tag: true, - inner: value, - fold: (_onError, onValue) => onValue(value), - isValue: always, - isError: never, - map: mapper => Result.value(mapper(value)), - mapError: outputHelper, - bind: applyHelper, - exists: applyHelper, - forall: applyHelper, - getOr: constHelper, - or: outputHelper, - getOrThunk: constHelper, - orThunk: outputHelper, - getOrDie: constHelper, - each: fn => { - fn(value); - }, - toOptional: () => Optional.some(value) - }; - return output; - }; - const error = error => { - const outputHelper = () => output; - const output = { - tag: false, - inner: error, - fold: (onError, _onValue) => onError(error), - isValue: never, - isError: always, - map: outputHelper, - mapError: mapper => Result.error(mapper(error)), - bind: outputHelper, - exists: never, - forall: always, - getOr: identity, - or: identity, - getOrThunk: apply, - orThunk: apply, - getOrDie: die(String(error)), - each: noop, - toOptional: Optional.none - }; - return output; - }; - const fromOption = (optional, err) => optional.fold(() => error(err), value$1); - const Result = { - value: value$1, - error, - fromOption - }; - - const measure = (startAddress, gridA, gridB) => { - if (startAddress.row >= gridA.length || startAddress.column > cellLength(gridA[0])) { - return Result.error('invalid start address out of table bounds, row: ' + startAddress.row + ', column: ' + startAddress.column); - } - const rowRemainder = gridA.slice(startAddress.row); - const colRemainder = rowRemainder[0].cells.slice(startAddress.column); - const colRequired = cellLength(gridB[0]); - const rowRequired = gridB.length; - return Result.value({ - rowDelta: rowRemainder.length - rowRequired, - colDelta: colRemainder.length - colRequired - }); - }; - const measureWidth = (gridA, gridB) => { - const colLengthA = cellLength(gridA[0]); - const colLengthB = cellLength(gridB[0]); - return { - rowDelta: 0, - colDelta: colLengthA - colLengthB - }; + // Handle colgroups + // Note: Currently only a single colgroup is supported so just use the last one + const { columns, colgroups } = last$2(colgroupRows).map((rowData) => { + const columns = generateColumns(rowData); + const colgroup$1 = colgroup(rowData.element, values(columns)); + return { + colgroups: [colgroup$1], + columns + }; + }).getOrThunk(() => ({ + colgroups: [], + columns: {} + })); + const grid$1 = grid(maxRows, maxColumns); + return { + grid: grid$1, + access, + all: cells, + columns, + colgroups + }; }; - const measureHeight = (gridA, gridB) => { - const rowLengthA = gridA.length; - const rowLengthB = gridB.length; - return { - rowDelta: rowLengthA - rowLengthB, - colDelta: 0 - }; + const fromTable = (table) => { + const list = fromTable$1(table); + return generate(list); }; - const generateElements = (amount, row, generators, isLocked) => { - const generator = row.section === 'colgroup' ? generators.col : generators.cell; - return range$1(amount, idx => elementnew(generator(), true, isLocked(idx))); + const justCells = (warehouse) => bind$2(warehouse.all, (w) => w.cells); + const justColumns = (warehouse) => values(warehouse.columns); + const hasColumns = (warehouse) => keys(warehouse.columns).length > 0; + const getColumnAt = (warehouse, columnIndex) => Optional.from(warehouse.columns[columnIndex]); + const Warehouse = { + fromTable, + generate, + getAt, + findItem, + filterItems, + justCells, + justColumns, + hasColumns, + getColumnAt }; - const rowFill = (grid, amount, generators, lockedColumns) => { - const exampleRow = grid[grid.length - 1]; - return grid.concat(range$1(amount, () => { - const generator = exampleRow.section === 'colgroup' ? generators.colgroup : generators.row; - const row = clone(exampleRow, generator, identity); - const elements = generateElements(row.cells.length, row, generators, idx => has$1(lockedColumns, idx.toString())); - return setCells(row, elements); - })); - }; - const colFill = (grid, amount, generators, startIndex) => map$1(grid, row => { - const newChildren = generateElements(amount, row, generators, never); - return addCells(row, startIndex, newChildren); + + const transformCell = (cell, comparator, substitution) => elementnew(substitution(cell.element, comparator), true, cell.isLocked); + const transformRow = (row, section) => row.section !== section ? rowcells(row.element, row.cells, section, row.isNew) : row; + const section = () => ({ + transformRow, + transformCell: (cell, comparator, substitution) => { + const newCell = substitution(cell.element, comparator); + // Convert the cell to a td element as "section" should always use td element + const fixedCell = name(newCell) !== 'td' ? mutate$1(newCell, 'td') : newCell; + return elementnew(fixedCell, cell.isNew, cell.isLocked); + } + }); + const sectionCells = () => ({ + transformRow, + transformCell }); - const lockedColFill = (grid, generators, lockedColumns) => map$1(grid, row => { - return foldl(lockedColumns, (acc, colNum) => { - const newChild = generateElements(1, row, generators, always)[0]; - return addCell(acc, colNum, newChild); - }, row); + const cells = () => ({ + transformRow: (row, section) => { + // Ensure that cells are always within the tbody for headers + const newSection = section === 'thead' ? 'tbody' : section; + return transformRow(row, newSection); + }, + transformCell }); - const tailor = (gridA, delta, generators) => { - const fillCols = delta.colDelta < 0 ? colFill : identity; - const fillRows = delta.rowDelta < 0 ? rowFill : identity; - const lockedColumns = getLockedColumnsFromGrid(gridA); - const gridWidth = cellLength(gridA[0]); - const isLastColLocked = exists(lockedColumns, locked => locked === gridWidth - 1); - const modifiedCols = fillCols(gridA, Math.abs(delta.colDelta), generators, isLastColLocked ? gridWidth - 1 : gridWidth); - const newLockedColumns = getLockedColumnsFromGrid(modifiedCols); - return fillRows(modifiedCols, Math.abs(delta.rowDelta), generators, mapToObject(newLockedColumns, always)); + // A fallback legacy type that won't adjust the row/section type + // and instead will only modify cells + const fallback = () => ({ + transformRow: identity, + transformCell + }); + const getTableSectionType = (table, fallback) => { + const warehouse = Warehouse.fromTable(table); + const type = findTableRowHeaderType(warehouse).getOr(fallback); + switch (type) { + case 'section': + return section(); + case 'sectionCells': + return sectionCells(); + case 'cells': + return cells(); + } + }; + const TableSection = { + getTableSectionType, + section, + sectionCells, + cells, + fallback }; - const isSpanning = (grid, row, col, comparator) => { - const candidate = getCell(grid[row], col); - const matching = curry(comparator, candidate.element); - const currentRow = grid[row]; - return grid.length > 1 && cellLength(currentRow) > 1 && (col > 0 && matching(getCellElement(currentRow, col - 1)) || col < currentRow.cells.length - 1 && matching(getCellElement(currentRow, col + 1)) || row > 0 && matching(getCellElement(grid[row - 1], col)) || row < grid.length - 1 && matching(getCellElement(grid[row + 1], col))); + /* + * Identify for each column, a cell that has colspan 1. Note, this + * may actually fail, and future work will be to calculate column + * sizes that are only available through the difference of two + * spanning columns. + */ + const columns = (warehouse, isValidCell = always) => { + const grid = warehouse.grid; + const cols = range$1(grid.columns, identity); + const rowsArr = range$1(grid.rows, identity); + return map$1(cols, (col) => { + const getBlock = () => bind$2(rowsArr, (r) => Warehouse.getAt(warehouse, r, col) + .filter((detail) => detail.column === col) + .toArray()); + const isValid = (detail) => detail.colspan === 1 && isValidCell(detail.element); + const getFallback = () => Warehouse.getAt(warehouse, 0, col); + return decide(getBlock, isValid, getFallback); + }); }; - const mergeTables = (startAddress, gridA, gridBRows, generator, comparator, lockedColumns) => { - const startRow = startAddress.row; - const startCol = startAddress.column; - const mergeHeight = gridBRows.length; - const mergeWidth = cellLength(gridBRows[0]); - const endRow = startRow + mergeHeight; - const endCol = startCol + mergeWidth + lockedColumns.length; - const lockedColumnObj = mapToObject(lockedColumns, always); - for (let r = startRow; r < endRow; r++) { - let skippedCol = 0; - for (let c = startCol; c < endCol; c++) { - if (lockedColumnObj[c]) { - skippedCol++; - continue; - } - if (isSpanning(gridA, r, c, comparator)) { - unmerge(gridA, getCellElement(gridA[r], c), comparator, generator.cell); - } - const gridBColIndex = c - startCol - skippedCol; - const newCell = getCell(gridBRows[r - startRow], gridBColIndex); - const newCellElm = newCell.element; - const replacement = generator.replace(newCellElm); - mutateCell(gridA[r], c, elementnew(replacement, true, newCell.isLocked)); + const decide = (getBlock, isValid, getFallback) => { + const inBlock = getBlock(); + const validInBlock = find$1(inBlock, isValid); + const detailOption = validInBlock.orThunk(() => Optional.from(inBlock[0]).orThunk(getFallback)); + return detailOption.map((detail) => detail.element); + }; + const rows = (warehouse) => { + const grid = warehouse.grid; + const rowsArr = range$1(grid.rows, identity); + const cols = range$1(grid.columns, identity); + return map$1(rowsArr, (row) => { + const getBlock = () => bind$2(cols, (c) => Warehouse.getAt(warehouse, row, c) + .filter((detail) => detail.row === row) + .fold(constant([]), (detail) => [detail])); + const isSingle = (detail) => detail.rowspan === 1; + const getFallback = () => Warehouse.getAt(warehouse, row, 0); + return decide(getBlock, isSingle, getFallback); + }); + }; + + const deduce = (xs, index) => { + if (index < 0 || index >= xs.length - 1) { + return Optional.none(); } - } - return gridA; + const current = xs[index].fold(() => { + const rest = reverse(xs.slice(0, index)); + return findMap(rest, (a, i) => a.map((aa) => ({ value: aa, delta: i + 1 }))); + }, (c) => Optional.some({ value: c, delta: 0 })); + const next = xs[index + 1].fold(() => { + const rest = xs.slice(index + 1); + return findMap(rest, (a, i) => a.map((aa) => ({ value: aa, delta: i + 1 }))); + }, (n) => Optional.some({ value: n, delta: 1 })); + return current.bind((c) => next.map((n) => { + const extras = n.delta + c.delta; + return Math.abs(n.value - c.value) / extras; + })); }; - const getValidStartAddress = (currentStartAddress, grid, lockedColumns) => { - const gridColLength = cellLength(grid[0]); - const adjustedRowAddress = extractGridDetails(grid).cols.length + currentStartAddress.row; - const possibleColAddresses = range$1(gridColLength - currentStartAddress.column, num => num + currentStartAddress.column); - const validColAddress = find$1(possibleColAddresses, num => forall(lockedColumns, col => col !== num)).getOr(gridColLength - 1); - return { - row: adjustedRowAddress, - column: validColAddress - }; - }; - const getLockedColumnsWithinBounds = (startAddress, rows, lockedColumns) => filter$2(lockedColumns, colNum => colNum >= startAddress.column && colNum <= cellLength(rows[0]) + startAddress.column); - const merge$1 = (startAddress, gridA, gridB, generator, comparator) => { - const lockedColumns = getLockedColumnsFromGrid(gridA); - const validStartAddress = getValidStartAddress(startAddress, gridA, lockedColumns); - const gridBRows = extractGridDetails(gridB).rows; - const lockedColumnsWithinBounds = getLockedColumnsWithinBounds(validStartAddress, gridBRows, lockedColumns); - const result = measure(validStartAddress, gridA, gridBRows); - return result.map(diff => { - const delta = { - ...diff, - colDelta: diff.colDelta - lockedColumnsWithinBounds.length - }; - const fittedGrid = tailor(gridA, delta, generator); - const newLockedColumns = getLockedColumnsFromGrid(fittedGrid); - const newLockedColumnsWithinBounds = getLockedColumnsWithinBounds(validStartAddress, gridBRows, newLockedColumns); - return mergeTables(validStartAddress, fittedGrid, gridBRows, generator, comparator, newLockedColumnsWithinBounds); - }); + + const rowInfo = (row, y) => ({ + row, + y + }); + const colInfo = (col, x) => ({ + col, + x + }); + const rtlEdge = (cell) => { + const pos = absolute(cell); + return pos.left + getOuter(cell); }; - const insertCols = (index, gridA, gridB, generator, comparator) => { - splitCols(gridA, index, comparator, generator.cell); - const delta = measureHeight(gridB, gridA); - const fittedNewGrid = tailor(gridB, delta, generator); - const secondDelta = measureHeight(gridA, fittedNewGrid); - const fittedOldGrid = tailor(gridA, secondDelta, generator); - return map$1(fittedOldGrid, (gridRow, i) => { - return addCells(gridRow, index, fittedNewGrid[i].cells); - }); + const ltrEdge = (cell) => { + return absolute(cell).left; }; - const insertRows = (index, gridA, gridB, generator, comparator) => { - splitRows(gridA, index, comparator, generator.cell); - const locked = getLockedColumnsFromGrid(gridA); - const diff = measureWidth(gridA, gridB); - const delta = { - ...diff, - colDelta: diff.colDelta - locked.length - }; - const fittedOldGrid = tailor(gridA, delta, generator); - const { - cols: oldCols, - rows: oldRows - } = extractGridDetails(fittedOldGrid); - const newLocked = getLockedColumnsFromGrid(fittedOldGrid); - const secondDiff = measureWidth(gridB, gridA); - const secondDelta = { - ...secondDiff, - colDelta: secondDiff.colDelta + newLocked.length - }; - const fittedGridB = lockedColFill(gridB, generator, newLocked); - const fittedNewGrid = tailor(fittedGridB, secondDelta, generator); - return [ - ...oldCols, - ...oldRows.slice(0, index), - ...fittedNewGrid, - ...oldRows.slice(index, oldRows.length) - ]; - }; - - const cloneRow = (row, cloneCell, comparator, substitution) => clone(row, elem => substitution(elem, comparator), cloneCell); - const insertRowAt = (grid, index, example, comparator, substitution) => { - const {rows, cols} = extractGridDetails(grid); - const before = rows.slice(0, index); - const after = rows.slice(index); - const newRow = cloneRow(rows[example], (ex, c) => { - const withinSpan = index > 0 && index < rows.length && comparator(getCellElement(rows[index - 1], c), getCellElement(rows[index], c)); - const ret = withinSpan ? getCell(rows[index], c) : elementnew(substitution(ex.element, comparator), true, ex.isLocked); - return ret; - }, comparator, substitution); - return [ - ...cols, - ...before, - newRow, - ...after - ]; + const getLeftEdge = (index, cell) => { + return colInfo(index, ltrEdge(cell)); }; - const getElementFor = (row, column, section, withinSpan, example, comparator, substitution) => { - if (section === 'colgroup' || !withinSpan) { - const cell = getCell(row, example); - return elementnew(substitution(cell.element, comparator), true, false); - } else { - return getCell(row, column); - } - }; - const insertColumnAt = (grid, index, example, comparator, substitution) => map$1(grid, row => { - const withinSpan = index > 0 && index < cellLength(row) && comparator(getCellElement(row, index - 1), getCellElement(row, index)); - const sub = getElementFor(row, index, row.section, withinSpan, example, comparator, substitution); - return addCell(row, index, sub); - }); - const deleteColumnsAt = (grid, columns) => bind$2(grid, row => { - const existingCells = row.cells; - const cells = foldr(columns, (acc, column) => column >= 0 && column < acc.length ? acc.slice(0, column).concat(acc.slice(column + 1)) : acc, existingCells); - return cells.length > 0 ? [rowcells(row.element, cells, row.section, row.isNew)] : []; - }); - const deleteRowsAt = (grid, start, finish) => { - const {rows, cols} = extractGridDetails(grid); - return [ - ...cols, - ...rows.slice(0, start), - ...rows.slice(finish + 1) - ]; + const getRightEdge = (index, cell) => { + return colInfo(index, rtlEdge(cell)); }; - - const notInStartRow = (grid, rowIndex, colIndex, comparator) => getCellElement(grid[rowIndex], colIndex) !== undefined && (rowIndex > 0 && comparator(getCellElement(grid[rowIndex - 1], colIndex), getCellElement(grid[rowIndex], colIndex))); - const notInStartColumn = (row, index, comparator) => index > 0 && comparator(getCellElement(row, index - 1), getCellElement(row, index)); - const isDuplicatedCell = (grid, rowIndex, colIndex, comparator) => notInStartRow(grid, rowIndex, colIndex, comparator) || notInStartColumn(grid[rowIndex], colIndex, comparator); - const rowReplacerPredicate = (targetRow, columnHeaders) => { - const entireTableIsHeader = forall(columnHeaders, identity) && isHeaderCells(targetRow.cells); - return entireTableIsHeader ? always : (cell, _rowIndex, colIndex) => { - const type = name(cell.element); - return !(type === 'th' && columnHeaders[colIndex]); - }; + const getTop$1 = (cell) => { + return absolute(cell).top; }; - const columnReplacePredicate = (targetColumn, rowHeaders) => { - const entireTableIsHeader = forall(rowHeaders, identity) && isHeaderCells(targetColumn); - return entireTableIsHeader ? always : (cell, rowIndex, _colIndex) => { - const type = name(cell.element); - return !(type === 'th' && rowHeaders[rowIndex]); - }; + const getTopEdge = (index, cell) => { + return rowInfo(index, getTop$1(cell)); }; - const determineScope = (applyScope, cell, newScope, isInHeader) => { - const hasSpan = scope => scope === 'row' ? hasRowspan(cell) : hasColspan(cell); - const getScope = scope => hasSpan(scope) ? `${ scope }group` : scope; - if (applyScope) { - return isHeaderCell(cell) ? getScope(newScope) : null; - } else if (isInHeader && isHeaderCell(cell)) { - const oppositeScope = newScope === 'row' ? 'col' : 'row'; - return getScope(oppositeScope); - } else { - return null; - } + const getBottomEdge = (index, cell) => { + return rowInfo(index, getTop$1(cell) + getOuter$1(cell)); }; - const rowScopeGenerator = (applyScope, columnHeaders) => (cell, rowIndex, columnIndex) => Optional.some(determineScope(applyScope, cell.element, 'col', columnHeaders[columnIndex])); - const columnScopeGenerator = (applyScope, rowHeaders) => (cell, rowIndex) => Optional.some(determineScope(applyScope, cell.element, 'row', rowHeaders[rowIndex])); - const replace = (cell, comparator, substitute) => elementnew(substitute(cell.element, comparator), true, cell.isLocked); - const replaceIn = (grid, targets, comparator, substitute, replacer, genScope, shouldReplace) => { - const isTarget = cell => { - return exists(targets, target => { - return comparator(cell.element, target.element); - }); - }; - return map$1(grid, (row, rowIndex) => { - return mapCells(row, (cell, colIndex) => { - if (isTarget(cell)) { - const newCell = shouldReplace(cell, rowIndex, colIndex) ? replacer(cell, comparator, substitute) : cell; - genScope(newCell, rowIndex, colIndex).each(scope => { - setOptions(newCell.element, { scope: Optional.from(scope) }); + const findPositions = (getInnerEdge, getOuterEdge, array) => { + if (array.length === 0) { + return []; + } + const lines = map$1(array.slice(1), (cellOption, index) => { + return cellOption.map((cell) => { + return getInnerEdge(index, cell); }); - return newCell; - } else { - return cell; - } }); - }); + const lastLine = array[array.length - 1].map((cell) => { + return getOuterEdge(array.length - 1, cell); + }); + return lines.concat([lastLine]); }; - const getColumnCells = (rows, columnIndex, comparator) => bind$2(rows, (row, i) => { - return isDuplicatedCell(rows, i, columnIndex, comparator) ? [] : [getCell(row, columnIndex)]; - }); - const getRowCells = (rows, rowIndex, comparator) => { - const targetRow = rows[rowIndex]; - return bind$2(targetRow.cells, (item, i) => { - return isDuplicatedCell(rows, rowIndex, i, comparator) ? [] : [item]; - }); + const negate = (step) => { + return -step; }; - const replaceColumns = (grid, indexes, applyScope, comparator, substitution) => { - const rows = extractGridDetails(grid).rows; - const targets = bind$2(indexes, index => getColumnCells(rows, index, comparator)); - const rowHeaders = map$1(rows, row => isHeaderCells(row.cells)); - const shouldReplaceCell = columnReplacePredicate(targets, rowHeaders); - const scopeGenerator = columnScopeGenerator(applyScope, rowHeaders); - return replaceIn(grid, targets, comparator, substitution, replace, scopeGenerator, shouldReplaceCell); + const height = { + delta: identity, + positions: (optElements) => findPositions(getTopEdge, getBottomEdge, optElements), + edge: getTop$1 }; - const replaceRows = (grid, indexes, section, applyScope, comparator, substitution, tableSection) => { - const {cols, rows} = extractGridDetails(grid); - const targetRow = rows[indexes[0]]; - const targets = bind$2(indexes, index => getRowCells(rows, index, comparator)); - const columnHeaders = map$1(targetRow.cells, (_cell, index) => isHeaderCells(getColumnCells(rows, index, comparator))); - const newRows = [...rows]; - each$2(indexes, index => { - newRows[index] = tableSection.transformRow(rows[index], section); - }); - const newGrid = [ - ...cols, - ...newRows - ]; - const shouldReplaceCell = rowReplacerPredicate(targetRow, columnHeaders); - const scopeGenerator = rowScopeGenerator(applyScope, columnHeaders); - return replaceIn(newGrid, targets, comparator, substitution, tableSection.transformCell, scopeGenerator, shouldReplaceCell); + const ltr$1 = { + delta: identity, + edge: ltrEdge, + positions: (optElements) => findPositions(getLeftEdge, getRightEdge, optElements) }; - const replaceCells = (grid, details, comparator, substitution) => { - const rows = extractGridDetails(grid).rows; - const targetCells = map$1(details, detail => getCell(rows[detail.row], detail.column)); - return replaceIn(grid, targetCells, comparator, substitution, replace, Optional.none, always); - }; - - const generate$1 = cases => { - if (!isArray(cases)) { - throw new Error('cases must be an array'); - } - if (cases.length === 0) { - throw new Error('there must be at least one case'); - } - const constructors = []; - const adt = {}; - each$2(cases, (acase, count) => { - const keys$1 = keys(acase); - if (keys$1.length !== 1) { - throw new Error('one and only one name per case'); - } - const key = keys$1[0]; - const value = acase[key]; - if (adt[key] !== undefined) { - throw new Error('duplicate key detected:' + key); - } else if (key === 'cata') { - throw new Error('cannot have a case named cata (sorry)'); - } else if (!isArray(value)) { - throw new Error('case arguments must be an array'); - } - constructors.push(key); - adt[key] = (...args) => { - const argLength = args.length; - if (argLength !== value.length) { - throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength); - } - const match = branches => { - const branchKeys = keys(branches); - if (constructors.length !== branchKeys.length) { - throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(',')); - } - const allReqd = forall(constructors, reqKey => { - return contains$2(branchKeys, reqKey); - }); - if (!allReqd) { - throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', ')); - } - return branches[key].apply(null, args); - }; - return { - fold: (...foldArgs) => { - if (foldArgs.length !== cases.length) { - throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length); - } - const target = foldArgs[count]; - return target.apply(null, args); - }, - match, - log: label => { - console.log(label, { - constructors, - constructor: key, - params: args - }); - } - }; - }; - }); - return adt; + const rtl$1 = { + delta: negate, + edge: rtlEdge, + positions: (optElements) => findPositions(getRightEdge, getLeftEdge, optElements) + }; + const detect$1 = onDirection(ltr$1, rtl$1); + const width = { + delta: (amount, table) => detect$1(table).delta(amount, table), + positions: (cols, table) => detect$1(table).positions(cols, table), + edge: (cell) => detect$1(cell).edge(cell) }; - const Adt = { generate: generate$1 }; - - const adt$6 = Adt.generate([ - { none: [] }, - { only: ['index'] }, - { - left: [ - 'index', - 'next' - ] - }, - { - middle: [ - 'prev', - 'index', - 'next' - ] - }, - { - right: [ - 'prev', - 'index' - ] - } - ]); - const ColumnContext = { ...adt$6 }; - const neighbours = (input, index) => { - if (input.length === 0) { - return ColumnContext.none(); - } - if (input.length === 1) { - return ColumnContext.only(0); - } - if (index === 0) { - return ColumnContext.left(0, 1); - } - if (index === input.length - 1) { - return ColumnContext.right(index - 1, index); - } - if (index > 0 && index < input.length - 1) { - return ColumnContext.middle(index - 1, index, index + 1); - } - return ColumnContext.none(); + const rPercentageBasedSizeRegex = /(\d+(\.\d+)?)%/; + const rPixelBasedSizeRegex = /(\d+(\.\d+)?)px|em/; + const isCol$2 = isTag('col'); + const isRow$2 = isTag('tr'); + const getPercentSize = (elm, outerGetter, innerGetter) => { + const relativeParent = parentElement(elm).getOrThunk(() => getBody$1(owner(elm))); + return outerGetter(elm) / innerGetter(relativeParent) * 100; }; - const determine = (input, column, step, tableSize, resize) => { - const result = input.slice(0); - const context = neighbours(input, column); - const onNone = constant(map$1(result, constant(0))); - const onOnly = index => tableSize.singleColumnWidth(result[index], step); - const onLeft = (index, next) => resize.calcLeftEdgeDeltas(result, index, next, step, tableSize.minCellWidth(), tableSize.isRelative); - const onMiddle = (prev, index, next) => resize.calcMiddleDeltas(result, prev, index, next, step, tableSize.minCellWidth(), tableSize.isRelative); - const onRight = (prev, index) => resize.calcRightEdgeDeltas(result, prev, index, step, tableSize.minCellWidth(), tableSize.isRelative); - return context.fold(onNone, onOnly, onLeft, onMiddle, onRight); + const setPixelWidth = (cell, amount) => { + set$1(cell, 'width', amount + 'px'); }; - - const total = (start, end, measures) => { - let r = 0; - for (let i = start; i < end; i++) { - r += measures[i] !== undefined ? measures[i] : 0; - } - return r; + const setPercentageWidth = (cell, amount) => { + set$1(cell, 'width', amount + '%'); }; - const recalculateWidthForCells = (warehouse, widths) => { - const all = Warehouse.justCells(warehouse); - return map$1(all, cell => { - const width = total(cell.column, cell.column + cell.colspan, widths); - return { - element: cell.element, - width, - colspan: cell.colspan - }; - }); + const setHeight = (cell, amount) => { + set$1(cell, 'height', amount + 'px'); }; - const recalculateWidthForColumns = (warehouse, widths) => { - const groups = Warehouse.justColumns(warehouse); - return map$1(groups, (column, index) => ({ - element: column.element, - width: widths[index], - colspan: column.colspan - })); + const removeHeight = (cell) => { + remove$4(cell, 'height'); }; - const matchRowHeight = (warehouse, heights) => { - return map$1(warehouse.all, (row, i) => { - return { - element: row.element, - height: heights[i] - }; - }); + const getHeightValue = (cell) => getRuntime$1(cell) + 'px'; + const convert = (cell, number, getter, setter) => { + const newSize = table(cell).map((table) => { + const total = getter(table); + return Math.floor((number / 100.0) * total); + }).getOr(number); + setter(cell, newSize); + return newSize; }; - - const sumUp = newSize => foldr(newSize, (b, a) => b + a, 0); - const recalculate = (warehouse, widths) => { - if (Warehouse.hasColumns(warehouse)) { - return recalculateWidthForColumns(warehouse, widths); - } else { - return recalculateWidthForCells(warehouse, widths); - } + const normalizePixelSize = (value, cell, getter, setter) => { + const number = parseFloat(value); + return endsWith(value, '%') && name(cell) !== 'table' ? convert(cell, number, getter, setter) : number; }; - const recalculateAndApply = (warehouse, widths, tableSize) => { - const newSizes = recalculate(warehouse, widths); - each$2(newSizes, cell => { - tableSize.setElementWidth(cell.element, cell.width); - }); + const getTotalHeight = (cell) => { + const value = getHeightValue(cell); + if (!value) { + return get$8(cell); + } + return normalizePixelSize(value, cell, get$8, setHeight); }; - const adjustWidth = (table, delta, index, resizing, tableSize) => { - const warehouse = Warehouse.fromTable(table); - const step = tableSize.getCellDelta(delta); - const widths = tableSize.getWidths(warehouse, tableSize); - const isLastColumn = index === warehouse.grid.columns - 1; - const clampedStep = resizing.clampTableDelta(widths, index, step, tableSize.minCellWidth(), isLastColumn); - const deltas = determine(widths, index, clampedStep, tableSize, resizing); - const newWidths = map$1(deltas, (dx, i) => dx + widths[i]); - recalculateAndApply(warehouse, newWidths, tableSize); - resizing.resizeTable(tableSize.adjustTableWidth, clampedStep, isLastColumn); + const get$2 = (cell, type, f) => { + const v = f(cell); + const span = getSpan(cell, type); + return v / span; }; - const adjustHeight = (table, delta, index) => { - const warehouse = Warehouse.fromTable(table); - const heights = getPixelHeights(warehouse, table); - const newHeights = map$1(heights, (dy, i) => index === i ? Math.max(delta + dy, minHeight()) : dy); - const newRowSizes = matchRowHeight(warehouse, newHeights); - each$2(newRowSizes, row => { - setHeight(row.element, row.height); - }); - each$2(Warehouse.justCells(warehouse), cell => { - removeHeight(cell.element); - }); - const total = sumUp(newHeights); - setHeight(table, total); + const getRaw = (element, prop) => { + // Try to use the style first, otherwise attempt to get the value from an attribute + return getRaw$2(element, prop).orThunk(() => { + return getOpt(element, prop).map((val) => val + 'px'); + }); }; - const adjustAndRedistributeWidths$1 = (_table, list, details, tableSize, resizeBehaviour) => { - const warehouse = Warehouse.generate(list); - const sizes = tableSize.getWidths(warehouse, tableSize); - const tablePixelWidth = tableSize.pixelWidth(); - const {newSizes, delta} = resizeBehaviour.calcRedestributedWidths(sizes, tablePixelWidth, details.pixelDelta, tableSize.isRelative); - recalculateAndApply(warehouse, newSizes, tableSize); - tableSize.adjustTableWidth(delta); + const getRawWidth$1 = (element) => getRaw(element, 'width'); + const getRawHeight$1 = (element) => getRaw(element, 'height'); + // Get a percentage size for a percentage parent table + const getPercentageWidth = (cell) => getPercentSize(cell, get$7, getInner); + const getPixelWidth$1 = (cell) => + // For col elements use the computed width as col elements aren't affected by borders, padding, etc... + isCol$2(cell) ? get$7(cell) : getRuntime(cell); + const getHeight = (cell) => { + return isRow$2(cell) ? get$8(cell) : get$2(cell, 'rowspan', getTotalHeight); }; - const adjustWidthTo = (_table, list, _info, tableSize) => { - const warehouse = Warehouse.generate(list); - const widths = tableSize.getWidths(warehouse, tableSize); - recalculateAndApply(warehouse, widths, tableSize); + const getGenericWidth = (cell) => { + const width = getRawWidth$1(cell); + return width.bind((w) => parse(w, ['fixed', 'relative', 'empty'])); }; + const setGenericWidth = (cell, amount, unit) => { + set$1(cell, 'width', amount + unit); + }; + const getPixelTableWidth = (table) => get$7(table) + 'px'; + const getPixelTableHeight = (table) => get$8(table) + 'px'; + const getPercentTableWidth = (table) => getPercentSize(table, get$7, getInner) + '%'; + const isPercentSizing$1 = (table) => getRawWidth$1(table).exists((size) => rPercentageBasedSizeRegex.test(size)); + const isPixelSizing$1 = (table) => getRawWidth$1(table).exists((size) => rPixelBasedSizeRegex.test(size)); + const isNoneSizing$1 = (table) => getRawWidth$1(table).isNone(); + const percentageBasedSizeRegex = constant(rPercentageBasedSizeRegex); - const uniqueColumns = details => { - const uniqueCheck = (rest, detail) => { - const columnExists = exists(rest, currentDetail => currentDetail.column === detail.column); - return columnExists ? rest : rest.concat([detail]); - }; - return foldl(details, uniqueCheck, []).sort((detailA, detailB) => detailA.column - detailB.column); + const isCol$1 = isTag('col'); + const getRawW = (cell) => { + return getRawWidth$1(cell).getOrThunk(() => getPixelWidth$1(cell) + 'px'); + }; + const getRawH = (cell) => { + return getRawHeight$1(cell).getOrThunk(() => getHeight(cell) + 'px'); + }; + const justCols = (warehouse) => map$1(Warehouse.justColumns(warehouse), (column) => Optional.from(column.element)); + // Col elements don't have valid computed widths/positions in all browsers, so treat them as invalid in that case + const isValidColumn = (cell) => { + const browser = detect$2().browser; + const supportsColWidths = browser.isChromium() || browser.isFirefox(); + return isCol$1(cell) ? supportsColWidths : true; + }; + const getDimension = (cellOpt, index, backups, filter, getter, fallback) => cellOpt.filter(filter).fold( + // Can't just read the width of a cell, so calculate. + () => fallback(deduce(backups, index)), (cell) => getter(cell)); + const getWidthFrom = (warehouse, table, getWidth, fallback) => { + // Only treat a cell as being valid for a column representation if it has a raw width, otherwise we won't be able to calculate the expected width. + // This is needed as one cell may have a width but others may not, so we need to try and use one with a specified width first. + const columnCells = columns(warehouse); + const columns$1 = Warehouse.hasColumns(warehouse) ? justCols(warehouse) : columnCells; + const backups = [Optional.some(width.edge(table))].concat(map$1(width.positions(columnCells, table), (pos) => pos.map((p) => p.x))); + // Only use the width of cells that have no column span (or colspan 1) + const colFilter = not(hasColspan); + return map$1(columns$1, (cellOption, c) => { + return getDimension(cellOption, c, backups, colFilter, (column) => { + if (isValidColumn(column)) { + return getWidth(column); + } + else { + // Invalid column so fallback to trying to get the computed width from the cell + const cell = bindFrom(columnCells[c], identity); + return getDimension(cell, c, backups, colFilter, (cell) => fallback(Optional.some(get$7(cell))), fallback); + } + }, fallback); + }); }; - - const isCol = isTag('col'); - const isColgroup = isTag('colgroup'); - const isRow$1 = element => name(element) === 'tr' || isColgroup(element); - const elementToData = element => { - const colspan = getAttrValue(element, 'colspan', 1); - const rowspan = getAttrValue(element, 'rowspan', 1); - return { - element, - colspan, - rowspan - }; + const getDeduced = (deduced) => { + return deduced.map((d) => { + return d + 'px'; + }).getOr(''); }; - const modification = (generators, toData = elementToData) => { - const nuCell = data => isCol(data.element) ? generators.col(data) : generators.cell(data); - const nuRow = data => isColgroup(data.element) ? generators.colgroup(data) : generators.row(data); - const add = element => { - if (isRow$1(element)) { - return nuRow({ element }); - } else { - const cell = element; - const replacement = nuCell(toData(cell)); - recent = Optional.some({ - item: cell, - replacement - }); - return replacement; - } - }; - let recent = Optional.none(); - const getOrInit = (element, comparator) => { - return recent.fold(() => { - return add(element); - }, p => { - return comparator(element, p.item) ? p.replacement : add(element); - }); - }; - return { getOrInit }; - }; - const transform$1 = tag => { - return generators => { - const list = []; - const find = (element, comparator) => { - return find$1(list, x => { - return comparator(x.item, element); - }); - }; - const makeNew = element => { - const attrs = tag === 'td' ? { scope: null } : {}; - const cell = generators.replace(element, tag, attrs); - list.push({ - item: element, - sub: cell - }); - return cell; - }; - const replaceOrInit = (element, comparator) => { - if (isRow$1(element) || isCol(element)) { - return element; - } else { - const cell = element; - return find(cell, comparator).fold(() => { - return makeNew(cell); - }, p => { - return comparator(element, p.item) ? p.sub : makeNew(cell); - }); - } - }; - return { replaceOrInit }; - }; + const getRawWidths = (warehouse, table) => { + return getWidthFrom(warehouse, table, getRawW, getDeduced); }; - const getScopeAttribute = cell => getOpt(cell, 'scope').map(attribute => attribute.substr(0, 3)); - const merging = generators => { - const unmerge = cell => { - const scope = getScopeAttribute(cell); - scope.each(attribute => set$2(cell, 'scope', attribute)); - return () => { - const raw = generators.cell({ - element: cell, - colspan: 1, - rowspan: 1 - }); - remove$5(raw, 'width'); - remove$5(cell, 'width'); - scope.each(attribute => set$2(raw, 'scope', attribute)); - return raw; - }; - }; - const merge = cells => { - const getScopeProperty = () => { - const stringAttributes = cat(map$1(cells, getScopeAttribute)); - if (stringAttributes.length === 0) { - return Optional.none(); - } else { - const baseScope = stringAttributes[0]; - const scopes = [ - 'row', - 'col' - ]; - const isMixed = exists(stringAttributes, attribute => { - return attribute !== baseScope && contains$2(scopes, attribute); + const getPercentageWidths = (warehouse, table, tableSize) => { + return getWidthFrom(warehouse, table, getPercentageWidth, (deduced) => { + return deduced.fold(() => { + return tableSize.minCellWidth(); + }, (cellWidth) => { + return cellWidth / tableSize.pixelWidth() * 100; }); - return isMixed ? Optional.none() : Optional.from(baseScope); - } - }; - remove$5(cells[0], 'width'); - getScopeProperty().fold(() => remove$7(cells[0], 'scope'), attribute => set$2(cells[0], 'scope', attribute + 'group')); - return constant(cells[0]); - }; - return { - unmerge, - merge - }; + }); }; - const Generators = { - modification, - transform: transform$1, - merging + const getPixelWidths = (warehouse, table, tableSize) => { + return getWidthFrom(warehouse, table, getPixelWidth$1, (deduced) => { + // Minimum cell width when all else fails. + return deduced.getOrThunk(tableSize.minCellWidth); + }); }; - - const blockList = [ - 'body', - 'p', - 'div', - 'article', - 'aside', - 'figcaption', - 'figure', - 'footer', - 'header', - 'nav', - 'section', - 'ol', - 'ul', - 'table', - 'thead', - 'tfoot', - 'tbody', - 'caption', - 'tr', - 'td', - 'th', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'blockquote', - 'pre', - 'address' - ]; - const isList$1 = (universe, item) => { - const tagName = universe.property().name(item); - return contains$2([ - 'ol', - 'ul' - ], tagName); + const getHeightFrom = (warehouse, table, getHeight, fallback) => { + const rowCells = rows(warehouse); + const rows$1 = map$1(warehouse.all, (r) => Optional.some(r.element)); + const backups = [Optional.some(height.edge(table))].concat(map$1(height.positions(rowCells, table), (pos) => pos.map((p) => p.y))); + return map$1(rows$1, (row, i) => getDimension(row, i, backups, always, getHeight, fallback)); }; - const isBlock$1 = (universe, item) => { - const tagName = universe.property().name(item); - return contains$2(blockList, tagName); + const getPixelHeights = (warehouse, table) => { + return getHeightFrom(warehouse, table, getHeight, (deduced) => { + return deduced.getOrThunk(minHeight); + }); }; - const isEmptyTag$1 = (universe, item) => { - return contains$2([ - 'br', - 'img', - 'hr', - 'input' - ], universe.property().name(item)); + const getRawHeights = (warehouse, table) => { + return getHeightFrom(warehouse, table, getRawH, getDeduced); }; - const universe$1 = DomUniverse(); - const isBlock = element => { - return isBlock$1(universe$1, element); + const widthLookup = (table, getter) => () => { + // Use the actual width if attached, otherwise fallback to the raw width + if (inBody(table)) { + return getter(table); + } + else { + return parseFloat(getRaw$2(table, 'width').getOr('0')); + } }; - const isList = element => { - return isList$1(universe$1, element); + const noneSize = (table) => { + const getWidth = widthLookup(table, get$7); + const zero = constant(0); + const getWidths = (warehouse, tableSize) => getPixelWidths(warehouse, table, tableSize); + // Note: The 3 delta functions below return 0 to signify a change shouldn't be made + // however this is currently not used, so may need changing if ever used + return { + width: getWidth, + pixelWidth: getWidth, + getWidths, + getCellDelta: zero, + singleColumnWidth: constant([0]), + minCellWidth: zero, + setElementWidth: noop, + adjustTableWidth: noop, + isRelative: true, + label: 'none' + }; }; - const isEmptyTag = element => { - return isEmptyTag$1(universe$1, element); + const percentageSize = (table) => { + const getFloatWidth = widthLookup(table, (elem) => parseFloat(getPercentTableWidth(elem))); + const getWidth = widthLookup(table, get$7); + const getCellDelta = (delta) => delta / getWidth() * 100; + // If we have one column in a percent based table, that column should be 100% of the width of the table. + const singleColumnWidth = (w, _delta) => [100 - w]; + // Get the width of a 10 pixel wide cell over the width of the table as a percentage + const minCellWidth = () => minWidth() / getWidth() * 100; + const adjustTableWidth = (delta) => { + const currentWidth = getFloatWidth(); + const change = delta / 100 * currentWidth; + const newWidth = currentWidth + change; + setPercentageWidth(table, newWidth); + }; + const getWidths = (warehouse, tableSize) => getPercentageWidths(warehouse, table, tableSize); + return { + width: getFloatWidth, + pixelWidth: getWidth, + getWidths, + getCellDelta, + singleColumnWidth, + minCellWidth, + setElementWidth: setPercentageWidth, + adjustTableWidth, + isRelative: true, + label: 'percent' + }; }; - - const merge = cells => { - const isBr = isTag('br'); - const advancedBr = children => { - return forall(children, c => { - return isBr(c) || isText(c) && get$6(c).trim().length === 0; - }); - }; - const isListItem = el => { - return name(el) === 'li' || ancestor$2(el, isList).isSome(); - }; - const siblingIsBlock = el => { - return nextSibling(el).map(rightSibling => { - if (isBlock(rightSibling)) { - return true; - } - if (isEmptyTag(rightSibling)) { - return name(rightSibling) === 'img' ? false : true; - } - return false; - }).getOr(false); - }; - const markCell = cell => { - return last$1(cell).bind(rightEdge => { - const rightSiblingIsBlock = siblingIsBlock(rightEdge); - return parent(rightEdge).map(parent => { - return rightSiblingIsBlock === true || isListItem(parent) || isBr(rightEdge) || isBlock(parent) && !eq$1(cell, parent) ? [] : [SugarElement.fromTag('br')]; - }); - }).getOr([]); - }; - const markContent = () => { - const content = bind$2(cells, cell => { - const children = children$2(cell); - return advancedBr(children) ? [] : children.concat(markCell(cell)); - }); - return content.length === 0 ? [SugarElement.fromTag('br')] : content; - }; - const contents = markContent(); - empty(cells[0]); - append(cells[0], contents); - }; - - const isEditable = elem => isEditable$1(elem, true); - const prune = table => { - const cells = cells$1(table); - if (cells.length === 0) { - remove$6(table); - } - }; - const outcome = (grid, cursor) => ({ - grid, - cursor - }); - const findEditableCursorPosition = rows => findMap(rows, row => findMap(row.cells, cell => { - const elem = cell.element; - return someIf(isEditable(elem), elem); - })); - const elementFromGrid = (grid, row, column) => { - var _a, _b; - const rows = extractGridDetails(grid).rows; - return Optional.from((_b = (_a = rows[row]) === null || _a === void 0 ? void 0 : _a.cells[column]) === null || _b === void 0 ? void 0 : _b.element).filter(isEditable).orThunk(() => findEditableCursorPosition(rows)); - }; - const bundle = (grid, row, column) => { - const cursorElement = elementFromGrid(grid, row, column); - return outcome(grid, cursorElement); - }; - const uniqueRows = details => { - const rowCompilation = (rest, detail) => { - const rowExists = exists(rest, currentDetail => currentDetail.row === detail.row); - return rowExists ? rest : rest.concat([detail]); - }; - return foldl(details, rowCompilation, []).sort((detailA, detailB) => detailA.row - detailB.row); - }; - const opInsertRowsBefore = (grid, details, comparator, genWrappers) => { - const targetIndex = details[0].row; - const rows = uniqueRows(details); - const newGrid = foldr(rows, (acc, row) => { - const newG = insertRowAt(acc.grid, targetIndex, row.row + acc.delta, comparator, genWrappers.getOrInit); - return { - grid: newG, - delta: acc.delta + 1 + const pixelSize = (table) => { + const getWidth = widthLookup(table, get$7); + const getCellDelta = identity; + const singleColumnWidth = (w, delta) => { + const newNext = Math.max(minWidth(), w + delta); + return [newNext - w]; }; - }, { - grid, - delta: 0 - }).grid; - return bundle(newGrid, targetIndex, details[0].column); - }; - const opInsertRowsAfter = (grid, details, comparator, genWrappers) => { - const rows = uniqueRows(details); - const target = rows[rows.length - 1]; - const targetIndex = target.row + target.rowspan; - const newGrid = foldr(rows, (newG, row) => { - return insertRowAt(newG, targetIndex, row.row, comparator, genWrappers.getOrInit); - }, grid); - return bundle(newGrid, targetIndex, details[0].column); - }; - const opInsertColumnsBefore = (grid, extractDetail, comparator, genWrappers) => { - const details = extractDetail.details; - const columns = uniqueColumns(details); - const targetIndex = columns[0].column; - const newGrid = foldr(columns, (acc, col) => { - const newG = insertColumnAt(acc.grid, targetIndex, col.column + acc.delta, comparator, genWrappers.getOrInit); + const adjustTableWidth = (delta) => { + const newWidth = getWidth() + delta; + setPixelWidth(table, newWidth); + }; + const getWidths = (warehouse, tableSize) => getPixelWidths(warehouse, table, tableSize); return { - grid: newG, - delta: acc.delta + 1 + width: getWidth, + pixelWidth: getWidth, + getWidths, + getCellDelta, + singleColumnWidth, + minCellWidth: minWidth, + setElementWidth: setPixelWidth, + adjustTableWidth, + isRelative: false, + label: 'pixel' }; - }, { - grid, - delta: 0 - }).grid; - return bundle(newGrid, details[0].row, targetIndex); - }; - const opInsertColumnsAfter = (grid, extractDetail, comparator, genWrappers) => { - const details = extractDetail.details; - const target = details[details.length - 1]; - const targetIndex = target.column + target.colspan; - const columns = uniqueColumns(details); - const newGrid = foldr(columns, (newG, col) => { - return insertColumnAt(newG, targetIndex, col.column, comparator, genWrappers.getOrInit); - }, grid); - return bundle(newGrid, details[0].row, targetIndex); - }; - const opMakeColumnsHeader = (initialGrid, details, comparator, genWrappers) => { - const columns = uniqueColumns(details); - const columnIndexes = map$1(columns, detail => detail.column); - const newGrid = replaceColumns(initialGrid, columnIndexes, true, comparator, genWrappers.replaceOrInit); - return bundle(newGrid, details[0].row, details[0].column); - }; - const opMakeCellsHeader = (initialGrid, details, comparator, genWrappers) => { - const newGrid = replaceCells(initialGrid, details, comparator, genWrappers.replaceOrInit); - return bundle(newGrid, details[0].row, details[0].column); - }; - const opUnmakeColumnsHeader = (initialGrid, details, comparator, genWrappers) => { - const columns = uniqueColumns(details); - const columnIndexes = map$1(columns, detail => detail.column); - const newGrid = replaceColumns(initialGrid, columnIndexes, false, comparator, genWrappers.replaceOrInit); - return bundle(newGrid, details[0].row, details[0].column); - }; - const opUnmakeCellsHeader = (initialGrid, details, comparator, genWrappers) => { - const newGrid = replaceCells(initialGrid, details, comparator, genWrappers.replaceOrInit); - return bundle(newGrid, details[0].row, details[0].column); }; - const makeRowsSection = (section, applyScope) => (initialGrid, details, comparator, genWrappers, tableSection) => { - const rows = uniqueRows(details); - const rowIndexes = map$1(rows, detail => detail.row); - const newGrid = replaceRows(initialGrid, rowIndexes, section, applyScope, comparator, genWrappers.replaceOrInit, tableSection); - return bundle(newGrid, details[0].row, details[0].column); + const chooseSize = (element, width) => { + const percentMatch = percentageBasedSizeRegex().exec(width); + if (percentMatch !== null) { + return percentageSize(element); + } + else { + return pixelSize(element); + } }; - const opMakeRowsHeader = makeRowsSection('thead', true); - const opMakeRowsBody = makeRowsSection('tbody', false); - const opMakeRowsFooter = makeRowsSection('tfoot', false); - const opEraseColumns = (grid, extractDetail, _comparator, _genWrappers) => { - const columns = uniqueColumns(extractDetail.details); - const newGrid = deleteColumnsAt(grid, map$1(columns, column => column.column)); - const maxColIndex = newGrid.length > 0 ? newGrid[0].cells.length - 1 : 0; - return bundle(newGrid, columns[0].row, Math.min(columns[0].column, maxColIndex)); + const getTableSize = (table) => { + const width = getRawWidth$1(table); + return width.fold(() => noneSize(table), (w) => chooseSize(table, w)); }; - const opEraseRows = (grid, details, _comparator, _genWrappers) => { - const rows = uniqueRows(details); - const newGrid = deleteRowsAt(grid, rows[0].row, rows[rows.length - 1].row); - const maxRowIndex = Math.max(extractGridDetails(newGrid).rows.length - 1, 0); - return bundle(newGrid, Math.min(details[0].row, maxRowIndex), details[0].column); + const TableSize = { + getTableSize, + pixelSize, + percentageSize, + noneSize }; - const opMergeCells = (grid, mergable, comparator, genWrappers) => { - const cells = mergable.cells; - merge(cells); - const newGrid = merge$2(grid, mergable.bounds, comparator, genWrappers.merge(cells)); - return outcome(newGrid, Optional.from(cells[0])); + + const setIfNot = (element, property, value, ignore) => { + if (value === ignore) { + remove$6(element, property); + } + else { + set$2(element, property, value); + } }; - const opUnmergeCells = (grid, unmergable, comparator, genWrappers) => { - const unmerge$1 = (b, cell) => unmerge(b, cell, comparator, genWrappers.unmerge(cell)); - const newGrid = foldr(unmergable, unmerge$1, grid); - return outcome(newGrid, Optional.from(unmergable[0])); + const insert$1 = (table, selector, element) => { + last$2(children(table, selector)).fold(() => prepend(table, element), (child) => after$4(child, element)); }; - const opPasteCells = (grid, pasteDetails, comparator, _genWrappers) => { - const gridify = (table, generators) => { - const wh = Warehouse.fromTable(table); - return toGrid(wh, generators, true); - }; - const gridB = gridify(pasteDetails.clipboard, pasteDetails.generators); - const startAddress = address(pasteDetails.row, pasteDetails.column); - const mergedGrid = merge$1(startAddress, grid, gridB, pasteDetails.generators, comparator); - return mergedGrid.fold(() => outcome(grid, Optional.some(pasteDetails.element)), newGrid => { - return bundle(newGrid, pasteDetails.row, pasteDetails.column); - }); + const generateSection = (table, sectionName) => { + const section = child(table, sectionName).getOrThunk(() => { + const newSection = SugarElement.fromTag(sectionName, owner(table).dom); + if (sectionName === 'thead') { + insert$1(table, 'caption,colgroup', newSection); + } + else if (sectionName === 'colgroup') { + insert$1(table, 'caption', newSection); + } + else { + append$1(table, newSection); + } + return newSection; + }); + empty(section); + return section; }; - const gridifyRows = (rows, generators, context) => { - const pasteDetails = fromPastedRows(rows, context.section); - const wh = Warehouse.generate(pasteDetails); - return toGrid(wh, generators, true); + const render$1 = (table, grid) => { + const newRows = []; + const newCells = []; + const syncRows = (gridSection) => map$1(gridSection, (row) => { + if (row.isNew) { + newRows.push(row.element); + } + const tr = row.element; + empty(tr); + each$2(row.cells, (cell) => { + if (cell.isNew) { + newCells.push(cell.element); + } + setIfNot(cell.element, 'colspan', cell.colspan, 1); + setIfNot(cell.element, 'rowspan', cell.rowspan, 1); + append$1(tr, cell.element); + }); + return tr; + }); + // Assumption we should only ever have 1 colgroup. The spec allows for multiple, however it's currently unsupported + const syncColGroup = (gridSection) => bind$2(gridSection, (colGroup) => map$1(colGroup.cells, (col) => { + setIfNot(col.element, 'span', col.colspan, 1); + return col.element; + })); + const renderSection = (gridSection, sectionName) => { + const section = generateSection(table, sectionName); + const sync = sectionName === 'colgroup' ? syncColGroup : syncRows; + const sectionElems = sync(gridSection); + append(section, sectionElems); + }; + const removeSection = (sectionName) => { + child(table, sectionName).each(remove$5); + }; + const renderOrRemoveSection = (gridSection, sectionName) => { + if (gridSection.length > 0) { + renderSection(gridSection, sectionName); + } + else { + removeSection(sectionName); + } + }; + const headSection = []; + const bodySection = []; + const footSection = []; + const columnGroupsSection = []; + each$2(grid, (row) => { + switch (row.section) { + case 'thead': + headSection.push(row); + break; + case 'tbody': + bodySection.push(row); + break; + case 'tfoot': + footSection.push(row); + break; + case 'colgroup': + columnGroupsSection.push(row); + break; + } + }); + renderOrRemoveSection(columnGroupsSection, 'colgroup'); + renderOrRemoveSection(headSection, 'thead'); + renderOrRemoveSection(bodySection, 'tbody'); + renderOrRemoveSection(footSection, 'tfoot'); + return { + newRows, + newCells + }; }; - const opPasteColsBefore = (grid, pasteDetails, comparator, _genWrappers) => { - const rows = extractGridDetails(grid).rows; - const index = pasteDetails.cells[0].column; - const context = rows[pasteDetails.cells[0].row]; - const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); - const mergedGrid = insertCols(index, grid, gridB, pasteDetails.generators, comparator); - return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column); + const copy = (grid) => map$1(grid, (row) => { + // Shallow copy the row element + const tr = shallow(row.element); + each$2(row.cells, (cell) => { + const clonedCell = deep(cell.element); + setIfNot(clonedCell, 'colspan', cell.colspan, 1); + setIfNot(clonedCell, 'rowspan', cell.rowspan, 1); + append$1(tr, clonedCell); + }); + return tr; + }); + + const getColumn = (grid, index) => { + return map$1(grid, (row) => { + return getCell(row, index); + }); }; - const opPasteColsAfter = (grid, pasteDetails, comparator, _genWrappers) => { - const rows = extractGridDetails(grid).rows; - const index = pasteDetails.cells[pasteDetails.cells.length - 1].column + pasteDetails.cells[pasteDetails.cells.length - 1].colspan; - const context = rows[pasteDetails.cells[0].row]; - const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); - const mergedGrid = insertCols(index, grid, gridB, pasteDetails.generators, comparator); - return bundle(mergedGrid, pasteDetails.cells[0].row, index); + const getRow = (grid, index) => { + return grid[index]; }; - const opPasteRowsBefore = (grid, pasteDetails, comparator, _genWrappers) => { - const rows = extractGridDetails(grid).rows; - const index = pasteDetails.cells[0].row; - const context = rows[index]; - const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); - const mergedGrid = insertRows(index, grid, gridB, pasteDetails.generators, comparator); - return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column); + const findDiff = (xs, comp) => { + if (xs.length === 0) { + return 0; + } + const first = xs[0]; + const index = findIndex(xs, (x) => { + return !comp(first.element, x.element); + }); + return index.getOr(xs.length); + }; + /* + * grid is the grid + * row is the row index into the grid + * column in the column index into the grid + * + * Return + * colspan: column span of the cell at (row, column) + * rowspan: row span of the cell at (row, column) + */ + const subgrid = (grid, row, column, comparator) => { + const gridRow = getRow(grid, row); + const isColRow = gridRow.section === 'colgroup'; + const colspan = findDiff(gridRow.cells.slice(column), comparator); + const rowspan = isColRow ? 1 : findDiff(getColumn(grid.slice(row), column), comparator); + return { + colspan, + rowspan + }; }; - const opPasteRowsAfter = (grid, pasteDetails, comparator, _genWrappers) => { - const rows = extractGridDetails(grid).rows; - const index = pasteDetails.cells[pasteDetails.cells.length - 1].row + pasteDetails.cells[pasteDetails.cells.length - 1].rowspan; - const context = rows[pasteDetails.cells[0].row]; - const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); - const mergedGrid = insertRows(index, grid, gridB, pasteDetails.generators, comparator); - return bundle(mergedGrid, index, pasteDetails.cells[0].column); + + const toDetails = (grid, comparator) => { + const seen = map$1(grid, (row) => map$1(row.cells, never)); + const updateSeen = (rowIndex, columnIndex, rowspan, colspan) => { + for (let row = rowIndex; row < rowIndex + rowspan; row++) { + for (let column = columnIndex; column < columnIndex + colspan; column++) { + seen[row][column] = true; + } + } + }; + return map$1(grid, (row, rowIndex) => { + const details = bind$2(row.cells, (cell, columnIndex) => { + // if we have seen this one, then skip it. + if (seen[rowIndex][columnIndex] === false) { + const result = subgrid(grid, rowIndex, columnIndex, comparator); + updateSeen(rowIndex, columnIndex, result.rowspan, result.colspan); + return [detailnew(cell.element, result.rowspan, result.colspan, cell.isNew)]; + } + else { + return []; + } + }); + return rowdetailnew(row.element, details, row.section, row.isNew); + }); }; - const opGetColumnsType = (table, target) => { - const house = Warehouse.fromTable(table); - const details = onCells(house, target); - return details.bind(selectedCells => { - const lastSelectedCell = selectedCells[selectedCells.length - 1]; - const minColRange = selectedCells[0].column; - const maxColRange = lastSelectedCell.column + lastSelectedCell.colspan; - const selectedColumnCells = flatten(map$1(house.all, row => filter$2(row.cells, cell => cell.column >= minColRange && cell.column < maxColRange))); - return findCommonCellType(selectedColumnCells); - }).getOr(''); + const toGrid = (warehouse, generators, isNew) => { + const grid = []; + each$2(warehouse.colgroups, (colgroup) => { + const colgroupCols = []; + // This will add missing cols as well as clamp the number of cols to the max number of actual columns + // Note: Spans on cols are unsupported so clamping cols may result in a span on a col element being incorrect + for (let columnIndex = 0; columnIndex < warehouse.grid.columns; columnIndex++) { + const element = Warehouse.getColumnAt(warehouse, columnIndex) + .map((column) => elementnew(column.element, isNew, false)) + .getOrThunk(() => elementnew(generators.colGap(), true, false)); + colgroupCols.push(element); + } + grid.push(rowcells(colgroup.element, colgroupCols, 'colgroup', isNew)); + }); + for (let rowIndex = 0; rowIndex < warehouse.grid.rows; rowIndex++) { + const rowCells = []; + for (let columnIndex = 0; columnIndex < warehouse.grid.columns; columnIndex++) { + // The element is going to be the element at that position, or a newly generated gap. + const element = Warehouse.getAt(warehouse, rowIndex, columnIndex).map((item) => elementnew(item.element, isNew, item.isLocked)).getOrThunk(() => elementnew(generators.gap(), true, false)); + rowCells.push(element); + } + const rowDetail = warehouse.all[rowIndex]; + const row = rowcells(rowDetail.element, rowCells, rowDetail.section, isNew); + grid.push(row); + } + return grid; }; - const opGetCellsType = (table, target) => { - const house = Warehouse.fromTable(table); - const details = onCells(house, target); - return details.bind(findCommonCellType).getOr(''); + + const fromWarehouse = (warehouse, generators) => toGrid(warehouse, generators, false); + const toDetailList = (grid) => toDetails(grid, eq$1); + const findInWarehouse = (warehouse, element) => findMap(warehouse.all, (r) => find$1(r.cells, (e) => eq$1(element, e.element))); + const extractCells = (warehouse, target, predicate) => { + const details = map$1(target.selection, (cell$1) => { + return cell(cell$1) + .bind((lc) => findInWarehouse(warehouse, lc)) + .filter(predicate); + }); + const cells = cat(details); + return someIf(cells.length > 0, cells); }; - const opGetRowsType = (table, target) => { - const house = Warehouse.fromTable(table); - const details = onCells(house, target); - return details.bind(selectedCells => { - const lastSelectedCell = selectedCells[selectedCells.length - 1]; - const minRowRange = selectedCells[0].row; - const maxRowRange = lastSelectedCell.row + lastSelectedCell.rowspan; - const selectedRows = house.all.slice(minRowRange, maxRowRange); - return findCommonRowType(selectedRows); - }).getOr(''); + const run = (operation, extract, adjustment, postAction, genWrappers, table, target, generators, behaviours) => { + const warehouse = Warehouse.fromTable(table); + const tableSection = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.section).getOrThunk(TableSection.fallback); + const output = extract(warehouse, target).map((info) => { + const model = fromWarehouse(warehouse, generators); + const result = operation(model, info, eq$1, genWrappers(generators), tableSection); + const lockedColumns = getLockedColumnsFromGrid(result.grid); + const grid = toDetailList(result.grid); + return { + info, + grid, + cursor: result.cursor, + lockedColumns + }; + }); + return output.bind((out) => { + const newElements = render$1(table, out.grid); + const tableSizing = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.sizing).getOrThunk(() => TableSize.getTableSize(table)); + const resizing = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.resize).getOrThunk(preserveTable); + adjustment(table, out.grid, out.info, { sizing: tableSizing, resize: resizing, section: tableSection }); + postAction(table); + // Update locked cols attribute + remove$6(table, LOCKED_COL_ATTR); + if (out.lockedColumns.length > 0) { + set$2(table, LOCKED_COL_ATTR, out.lockedColumns.join(',')); + } + return Optional.some({ + cursor: out.cursor, + newRows: newElements.newRows, + newCells: newElements.newCells + }); + }); }; - const resize = (table, list, details, behaviours) => adjustWidthTo(table, list, details, behaviours.sizing); - const adjustAndRedistributeWidths = (table, list, details, behaviours) => adjustAndRedistributeWidths$1(table, list, details, behaviours.sizing, behaviours.resize); - const firstColumnIsLocked = (_warehouse, details) => exists(details, detail => detail.column === 0 && detail.isLocked); - const lastColumnIsLocked = (warehouse, details) => exists(details, detail => detail.column + detail.colspan >= warehouse.grid.columns && detail.isLocked); - const getColumnsWidth = (warehouse, details) => { - const columns$1 = columns(warehouse); - const uniqueCols = uniqueColumns(details); - return foldl(uniqueCols, (acc, detail) => { - const column = columns$1[detail.column]; - const colWidth = column.map(getOuter$2).getOr(0); - return acc + colWidth; - }, 0); - }; - const insertColumnsExtractor = before => (warehouse, target) => onCells(warehouse, target).filter(details => { - const checkLocked = before ? firstColumnIsLocked : lastColumnIsLocked; - return !checkLocked(warehouse, details); - }).map(details => ({ - details, - pixelDelta: getColumnsWidth(warehouse, details) + const onPaste = (warehouse, target) => cell(target.element).bind((cell) => findInWarehouse(warehouse, cell).map((details) => { + const value = { + ...details, + generators: target.generators, + clipboard: target.clipboard + }; + return value; })); - const eraseColumnsExtractor = (warehouse, target) => onUnlockedCells(warehouse, target).map(details => ({ - details, - pixelDelta: -getColumnsWidth(warehouse, details) + const onPasteByEditor = (warehouse, target) => extractCells(warehouse, target, always).map((cells) => ({ + cells, + generators: target.generators, + clipboard: target.clipboard })); - const pasteColumnsExtractor = before => (warehouse, target) => onPasteByEditor(warehouse, target).filter(details => { - const checkLocked = before ? firstColumnIsLocked : lastColumnIsLocked; - return !checkLocked(warehouse, details.cells); - }); - const headerCellGenerator = Generators.transform('th'); - const bodyCellGenerator = Generators.transform('td'); - const insertRowsBefore = run(opInsertRowsBefore, onCells, noop, noop, Generators.modification); - const insertRowsAfter = run(opInsertRowsAfter, onCells, noop, noop, Generators.modification); - const insertColumnsBefore = run(opInsertColumnsBefore, insertColumnsExtractor(true), adjustAndRedistributeWidths, noop, Generators.modification); - const insertColumnsAfter = run(opInsertColumnsAfter, insertColumnsExtractor(false), adjustAndRedistributeWidths, noop, Generators.modification); - const eraseColumns = run(opEraseColumns, eraseColumnsExtractor, adjustAndRedistributeWidths, prune, Generators.modification); - const eraseRows = run(opEraseRows, onCells, noop, prune, Generators.modification); - const makeColumnsHeader = run(opMakeColumnsHeader, onUnlockedCells, noop, noop, headerCellGenerator); - const unmakeColumnsHeader = run(opUnmakeColumnsHeader, onUnlockedCells, noop, noop, bodyCellGenerator); - const makeRowsHeader = run(opMakeRowsHeader, onCells, noop, noop, headerCellGenerator); - const makeRowsBody = run(opMakeRowsBody, onCells, noop, noop, bodyCellGenerator); - const makeRowsFooter = run(opMakeRowsFooter, onCells, noop, noop, bodyCellGenerator); - const makeCellsHeader = run(opMakeCellsHeader, onUnlockedCells, noop, noop, headerCellGenerator); - const unmakeCellsHeader = run(opUnmakeCellsHeader, onUnlockedCells, noop, noop, bodyCellGenerator); - const mergeCells = run(opMergeCells, onUnlockedMergable, resize, noop, Generators.merging); - const unmergeCells = run(opUnmergeCells, onUnlockedUnmergable, resize, noop, Generators.merging); - const pasteCells = run(opPasteCells, onPaste, resize, noop, Generators.modification); - const pasteColsBefore = run(opPasteColsBefore, pasteColumnsExtractor(true), noop, noop, Generators.modification); - const pasteColsAfter = run(opPasteColsAfter, pasteColumnsExtractor(false), noop, noop, Generators.modification); - const pasteRowsBefore = run(opPasteRowsBefore, onPasteByEditor, noop, noop, Generators.modification); - const pasteRowsAfter = run(opPasteRowsAfter, onPasteByEditor, noop, noop, Generators.modification); - const getColumnsType = opGetColumnsType; - const getCellsType = opGetCellsType; - const getRowsType = opGetRowsType; + const onMergable = (_warehouse, target) => target.mergable; + const onUnmergable = (_warehouse, target) => target.unmergable; + const onCells = (warehouse, target) => extractCells(warehouse, target, always); + const onUnlockedCells = (warehouse, target) => extractCells(warehouse, target, (detail) => !detail.isLocked); + const isUnlockedTableCell = (warehouse, cell) => findInWarehouse(warehouse, cell).exists((detail) => !detail.isLocked); + const allUnlocked = (warehouse, cells) => forall(cells, (cell) => isUnlockedTableCell(warehouse, cell)); + // If any locked columns are present in the selection, then don't want to be able to merge + const onUnlockedMergable = (warehouse, target) => onMergable(warehouse, target).filter((mergeable) => allUnlocked(warehouse, mergeable.cells)); + // If any locked columns are present in the selection, then don't want to be able to unmerge + const onUnlockedUnmergable = (warehouse, target) => onUnmergable(warehouse, target).filter((cells) => allUnlocked(warehouse, cells)); - const fireNewRow = (editor, row) => editor.dispatch('NewRow', { node: row }); - const fireNewCell = (editor, cell) => editor.dispatch('NewCell', { node: cell }); - const fireTableModified = (editor, table, data) => { - editor.dispatch('TableModified', { - ...data, - table - }); + const adt$3 = Adt.generate([ + { none: [] }, + { only: ['index'] }, + { left: ['index', 'next'] }, + { middle: ['prev', 'index', 'next'] }, + { right: ['prev', 'index'] } + ]); + const ColumnContext = { + ...adt$3 }; - const fireTableSelectionChange = (editor, cells, start, finish, otherCells) => { - editor.dispatch('TableSelectionChange', { - cells, - start, - finish, - otherCells - }); + + /* + * Based on the column index, identify the context + */ + const neighbours = (input, index) => { + if (input.length === 0) { + return ColumnContext.none(); + } + if (input.length === 1) { + return ColumnContext.only(0); + } + if (index === 0) { + return ColumnContext.left(0, 1); + } + if (index === input.length - 1) { + return ColumnContext.right(index - 1, index); + } + if (index > 0 && index < input.length - 1) { + return ColumnContext.middle(index - 1, index, index + 1); + } + return ColumnContext.none(); }; - const fireTableSelectionClear = editor => { - editor.dispatch('TableSelectionClear'); + /* + * Calculate the offsets to apply to each column width (not the absolute widths themselves) + * based on a resize at column: column of step: step + */ + const determine = (input, column, step, tableSize, resize) => { + const result = input.slice(0); + const context = neighbours(input, column); + const onNone = constant(map$1(result, constant(0))); + const onOnly = (index) => tableSize.singleColumnWidth(result[index], step); + const onLeft = (index, next) => resize.calcLeftEdgeDeltas(result, index, next, step, tableSize.minCellWidth(), tableSize.isRelative); + const onMiddle = (prev, index, next) => resize.calcMiddleDeltas(result, prev, index, next, step, tableSize.minCellWidth(), tableSize.isRelative); + // Applies to the last column bar + const onRight = (prev, index) => resize.calcRightEdgeDeltas(result, prev, index, step, tableSize.minCellWidth(), tableSize.isRelative); + return context.fold(onNone, onOnly, onLeft, onMiddle, onRight); + }; + + // Returns the sum of elements of measures in the half-open range [start, end) + // Measures is in pixels, treated as an array of integers or integers in string format. + // NOTE: beware of accumulated rounding errors over multiple columns - could result in noticeable table width changes + const total = (start, end, measures) => { + let r = 0; + for (let i = start; i < end; i++) { + r += measures[i] !== undefined ? measures[i] : 0; + } + return r; }; - const fireObjectResizeStart = (editor, target, width, height, origin) => { - editor.dispatch('ObjectResizeStart', { - target, - width, - height, - origin - }); + // Returns an array of all cells in warehouse with updated cell-widths, using + // the array 'widths' of the representative widths of each column of the table 'warehouse' + const recalculateWidthForCells = (warehouse, widths) => { + const all = Warehouse.justCells(warehouse); + return map$1(all, (cell) => { + // width of a spanning cell is sum of widths of representative columns it spans + const width = total(cell.column, cell.column + cell.colspan, widths); + return { + element: cell.element, + width, + colspan: cell.colspan + }; + }); }; - const fireObjectResized = (editor, target, width, height, origin) => { - editor.dispatch('ObjectResized', { - target, - width, - height, - origin - }); + const recalculateWidthForColumns = (warehouse, widths) => { + const groups = Warehouse.justColumns(warehouse); + return map$1(groups, (column, index) => ({ + element: column.element, + width: widths[index], + colspan: column.colspan + })); + }; + const matchRowHeight = (warehouse, heights) => { + return map$1(warehouse.all, (row, i) => { + return { + element: row.element, + height: heights[i] + }; + }); + }; + + const sumUp = (newSize) => foldr(newSize, (b, a) => b + a, 0); + const recalculate = (warehouse, widths) => { + if (Warehouse.hasColumns(warehouse)) { + return recalculateWidthForColumns(warehouse, widths); + } + else { + return recalculateWidthForCells(warehouse, widths); + } }; - const styleModified = { - structure: false, - style: true + const recalculateAndApply = (warehouse, widths, tableSize) => { + // Set the width of each cell based on the column widths + const newSizes = recalculate(warehouse, widths); + each$2(newSizes, (cell) => { + tableSize.setElementWidth(cell.element, cell.width); + }); }; - const structureModified = { - structure: true, - style: false + const adjustWidth = (table, delta, index, resizing, tableSize) => { + const warehouse = Warehouse.fromTable(table); + const step = tableSize.getCellDelta(delta); + const widths = tableSize.getWidths(warehouse, tableSize); + const isLastColumn = index === warehouse.grid.columns - 1; + const clampedStep = resizing.clampTableDelta(widths, index, step, tableSize.minCellWidth(), isLastColumn); + // Calculate all of the new widths for columns + const deltas = determine(widths, index, clampedStep, tableSize, resizing); + const newWidths = map$1(deltas, (dx, i) => dx + widths[i]); + recalculateAndApply(warehouse, newWidths, tableSize); + resizing.resizeTable(tableSize.adjustTableWidth, clampedStep, isLastColumn); }; - const styleAndStructureModified = { - structure: true, - style: true + const adjustHeight = (table, delta, index) => { + const warehouse = Warehouse.fromTable(table); + const heights = getPixelHeights(warehouse, table); + const newHeights = map$1(heights, (dy, i) => index === i ? Math.max(delta + dy, minHeight()) : dy); + const newRowSizes = matchRowHeight(warehouse, newHeights); + each$2(newRowSizes, (row) => { + setHeight(row.element, row.height); + }); + each$2(Warehouse.justCells(warehouse), (cell) => { + removeHeight(cell.element); + }); + const total = sumUp(newHeights); + setHeight(table, total); }; - - const get$5 = (editor, table) => { - if (isTablePercentagesForced(editor)) { - return TableSize.percentageSize(table); - } else if (isTablePixelsForced(editor)) { - return TableSize.pixelSize(table); - } else { - return TableSize.getTableSize(table); - } + // Using the width of the added/removed columns gathered on extraction (pixelDelta), get and apply the new column sizes and overall table width delta + const adjustAndRedistributeWidths$1 = (_table, list, details, tableSize, resizeBehaviour) => { + const warehouse = Warehouse.generate(list); + const sizes = tableSize.getWidths(warehouse, tableSize); + const tablePixelWidth = tableSize.pixelWidth(); + const { newSizes, delta } = resizeBehaviour.calcRedestributedWidths(sizes, tablePixelWidth, details.pixelDelta, tableSize.isRelative); + recalculateAndApply(warehouse, newSizes, tableSize); + tableSize.adjustTableWidth(delta); + }; + // Ensure that the width of table cells match the passed in table information. + const adjustWidthTo = (_table, list, _info, tableSize) => { + const warehouse = Warehouse.generate(list); + const widths = tableSize.getWidths(warehouse, tableSize); + recalculateAndApply(warehouse, widths, tableSize); }; - const TableActions = (editor, resizeHandler, cellSelectionHandler) => { - const isTableBody = editor => name(getBody(editor)) === 'table'; - const lastRowGuard = table => !isTableBody(editor) || getGridSize(table).rows > 1; - const lastColumnGuard = table => !isTableBody(editor) || getGridSize(table).columns > 1; - const cloneFormats = getTableCloneElements(editor); - const colMutationOp = isResizeTableColumnResizing(editor) ? noop : halve; - const getTableSectionType = table => { - switch (getTableHeaderType(editor)) { - case 'section': - return TableSection.section(); - case 'sectionCells': - return TableSection.sectionCells(); - case 'cells': - return TableSection.cells(); - default: - return TableSection.getTableSectionType(table, 'section'); - } - }; - const setSelectionFromAction = (table, result) => result.cursor.fold(() => { - const cells = cells$1(table); - return head(cells).filter(inBody).map(firstCell => { - cellSelectionHandler.clearSelectedCells(table.dom); - const rng = editor.dom.createRng(); - rng.selectNode(firstCell.dom); - editor.selection.setRng(rng); - set$2(firstCell, 'data-mce-selected', '1'); - return rng; - }); - }, cell => { - const des = freefallRtl(cell); - const rng = editor.dom.createRng(); - rng.setStart(des.element.dom, des.offset); - rng.setEnd(des.element.dom, des.offset); - editor.selection.setRng(rng); - cellSelectionHandler.clearSelectedCells(table.dom); - return Optional.some(rng); - }); - const execute = (operation, guard, mutate, effect) => (table, target, noEvents = false) => { - removeDataStyle(table); - const doc = SugarElement.fromDom(editor.getDoc()); - const generators = cellOperations(mutate, doc, cloneFormats); - const behaviours = { - sizing: get$5(editor, table), - resize: isResizeTableColumnResizing(editor) ? resizeTable() : preserveTable(), - section: getTableSectionType(table) - }; - return guard(table) ? operation(table, target, generators, behaviours).bind(result => { - resizeHandler.refresh(table.dom); - each$2(result.newRows, row => { - fireNewRow(editor, row.dom); - }); - each$2(result.newCells, cell => { - fireNewCell(editor, cell.dom); - }); - const range = setSelectionFromAction(table, result); - if (inBody(table)) { - removeDataStyle(table); - if (!noEvents) { - fireTableModified(editor, table.dom, effect); - } - } - return range.map(rng => ({ - rng, - effect - })); - }) : Optional.none(); - }; - const deleteRow = execute(eraseRows, lastRowGuard, noop, structureModified); - const deleteColumn = execute(eraseColumns, lastColumnGuard, noop, structureModified); - const insertRowsBefore$1 = execute(insertRowsBefore, always, noop, structureModified); - const insertRowsAfter$1 = execute(insertRowsAfter, always, noop, structureModified); - const insertColumnsBefore$1 = execute(insertColumnsBefore, always, colMutationOp, structureModified); - const insertColumnsAfter$1 = execute(insertColumnsAfter, always, colMutationOp, structureModified); - const mergeCells$1 = execute(mergeCells, always, noop, structureModified); - const unmergeCells$1 = execute(unmergeCells, always, noop, structureModified); - const pasteColsBefore$1 = execute(pasteColsBefore, always, noop, structureModified); - const pasteColsAfter$1 = execute(pasteColsAfter, always, noop, structureModified); - const pasteRowsBefore$1 = execute(pasteRowsBefore, always, noop, structureModified); - const pasteRowsAfter$1 = execute(pasteRowsAfter, always, noop, structureModified); - const pasteCells$1 = execute(pasteCells, always, noop, styleAndStructureModified); - const makeCellsHeader$1 = execute(makeCellsHeader, always, noop, structureModified); - const unmakeCellsHeader$1 = execute(unmakeCellsHeader, always, noop, structureModified); - const makeColumnsHeader$1 = execute(makeColumnsHeader, always, noop, structureModified); - const unmakeColumnsHeader$1 = execute(unmakeColumnsHeader, always, noop, structureModified); - const makeRowsHeader$1 = execute(makeRowsHeader, always, noop, structureModified); - const makeRowsBody$1 = execute(makeRowsBody, always, noop, structureModified); - const makeRowsFooter$1 = execute(makeRowsFooter, always, noop, structureModified); - const getTableCellType = getCellsType; - const getTableColType = getColumnsType; - const getTableRowType = getRowsType; - return { - deleteRow, - deleteColumn, - insertRowsBefore: insertRowsBefore$1, - insertRowsAfter: insertRowsAfter$1, - insertColumnsBefore: insertColumnsBefore$1, - insertColumnsAfter: insertColumnsAfter$1, - mergeCells: mergeCells$1, - unmergeCells: unmergeCells$1, - pasteColsBefore: pasteColsBefore$1, - pasteColsAfter: pasteColsAfter$1, - pasteRowsBefore: pasteRowsBefore$1, - pasteRowsAfter: pasteRowsAfter$1, - pasteCells: pasteCells$1, - makeCellsHeader: makeCellsHeader$1, - unmakeCellsHeader: unmakeCellsHeader$1, - makeColumnsHeader: makeColumnsHeader$1, - unmakeColumnsHeader: unmakeColumnsHeader$1, - makeRowsHeader: makeRowsHeader$1, - makeRowsBody: makeRowsBody$1, - makeRowsFooter: makeRowsFooter$1, - getTableRowType, - getTableCellType, - getTableColType - }; + const halve = (main, other) => { + // Only set width on the new cell if we have a colspan of 1 (or no colspan) as we can only safely do that for cells + // that are a single column, since we don't know the individual column widths for a cell with a colspan. + // Instead, we'll rely on the adjustments/postAction logic to set the widths based on other cells in the column + if (!hasColspan(main)) { + const width = getGenericWidth(main); + width.each((w) => { + const newWidth = w.value / 2; + setGenericWidth(main, newWidth, w.unit); + setGenericWidth(other, newWidth, w.unit); + }); + } }; const constrainSpan = (element, property, value) => { - const currentColspan = getAttrValue(element, property, 1); - if (value === 1 || currentColspan <= 1) { - remove$7(element, property); - } else { - set$2(element, property, Math.min(value, currentColspan)); - } - }; - const isColInRange = (minColRange, maxColRange) => cell => { - const endCol = cell.column + cell.colspan - 1; - const startCol = cell.column; - return endCol >= minColRange && startCol < maxColRange; + const currentColspan = getAttrValue(element, property, 1); + if (value === 1 || currentColspan <= 1) { + remove$6(element, property); + } + else { + set$2(element, property, Math.min(value, currentColspan)); + } + }; + const isColInRange = (minColRange, maxColRange) => (cell) => { + const endCol = cell.column + cell.colspan - 1; + const startCol = cell.column; + return endCol >= minColRange && startCol < maxColRange; }; const generateColGroup = (house, minColRange, maxColRange) => { - if (Warehouse.hasColumns(house)) { - const colsToCopy = filter$2(Warehouse.justColumns(house), isColInRange(minColRange, maxColRange)); - const copiedCols = map$1(colsToCopy, c => { - const clonedCol = deep(c.element); - constrainSpan(clonedCol, 'span', maxColRange - minColRange); - return clonedCol; - }); - const fakeColgroup = SugarElement.fromTag('colgroup'); - append(fakeColgroup, copiedCols); - return [fakeColgroup]; - } else { - return []; - } - }; - const generateRows = (house, minColRange, maxColRange) => map$1(house.all, row => { - const cellsToCopy = filter$2(row.cells, isColInRange(minColRange, maxColRange)); - const copiedCells = map$1(cellsToCopy, cell => { - const clonedCell = deep(cell.element); - constrainSpan(clonedCell, 'colspan', maxColRange - minColRange); - return clonedCell; - }); - const fakeTR = SugarElement.fromTag('tr'); - append(fakeTR, copiedCells); - return fakeTR; + if (Warehouse.hasColumns(house)) { + const colsToCopy = filter$2(Warehouse.justColumns(house), isColInRange(minColRange, maxColRange)); + const copiedCols = map$1(colsToCopy, (c) => { + const clonedCol = deep(c.element); + constrainSpan(clonedCol, 'span', maxColRange - minColRange); + return clonedCol; + }); + const fakeColgroup = SugarElement.fromTag('colgroup'); + append(fakeColgroup, copiedCols); + return [fakeColgroup]; + } + else { + return []; + } + }; + const generateRows = (house, minColRange, maxColRange) => map$1(house.all, (row) => { + const cellsToCopy = filter$2(row.cells, isColInRange(minColRange, maxColRange)); + const copiedCells = map$1(cellsToCopy, (cell) => { + const clonedCell = deep(cell.element); + constrainSpan(clonedCell, 'colspan', maxColRange - minColRange); + return clonedCell; + }); + const fakeTR = SugarElement.fromTag('tr'); + append(fakeTR, copiedCells); + return fakeTR; }); const copyCols = (table, target) => { - const house = Warehouse.fromTable(table); - const details = onUnlockedCells(house, target); - return details.map(selectedCells => { - const lastSelectedCell = selectedCells[selectedCells.length - 1]; - const minColRange = selectedCells[0].column; - const maxColRange = lastSelectedCell.column + lastSelectedCell.colspan; - const fakeColGroups = generateColGroup(house, minColRange, maxColRange); - const fakeRows = generateRows(house, minColRange, maxColRange); - return [ - ...fakeColGroups, - ...fakeRows - ]; - }); - }; - - const copyRows = (table, target, generators) => { - const warehouse = Warehouse.fromTable(table); - const details = onCells(warehouse, target); - return details.bind(selectedCells => { - const grid = toGrid(warehouse, generators, false); - const rows = extractGridDetails(grid).rows; - const slicedGrid = rows.slice(selectedCells[0].row, selectedCells[selectedCells.length - 1].row + selectedCells[selectedCells.length - 1].rowspan); - const filteredGrid = bind$2(slicedGrid, row => { - const newCells = filter$2(row.cells, cell => !cell.isLocked); - return newCells.length > 0 ? [{ - ...row, - cells: newCells - }] : []; + const house = Warehouse.fromTable(table); + const details = onUnlockedCells(house, target); + return details.map((selectedCells) => { + const lastSelectedCell = selectedCells[selectedCells.length - 1]; + const minColRange = selectedCells[0].column; + const maxColRange = lastSelectedCell.column + lastSelectedCell.colspan; + const fakeColGroups = generateColGroup(house, minColRange, maxColRange); + const fakeRows = generateRows(house, minColRange, maxColRange); + return [...fakeColGroups, ...fakeRows]; }); - const slicedDetails = toDetailList(filteredGrid); - return someIf(slicedDetails.length > 0, slicedDetails); - }).map(slicedDetails => copy(slicedDetails)); }; - const adt$5 = Adt.generate([ - { invalid: ['raw'] }, - { pixels: ['value'] }, - { percent: ['value'] } - ]); - const validateFor = (suffix, type, value) => { - const rawAmount = value.substring(0, value.length - suffix.length); - const amount = parseFloat(rawAmount); - return rawAmount === amount.toString() ? type(amount) : adt$5.invalid(value); - }; - const from = value => { - if (endsWith(value, '%')) { - return validateFor('%', adt$5.percent, value); - } - if (endsWith(value, 'px')) { - return validateFor('px', adt$5.pixels, value); - } - return adt$5.invalid(value); - }; - const Size = { - ...adt$5, - from + const copyRows = (table, target, generators) => { + const warehouse = Warehouse.fromTable(table); + // Cannot use onUnlockedCells like extractor here as if only cells in a locked column are selected, then this will be Optional.none and + // there is now no way of knowing which rows are selected + const details = onCells(warehouse, target); + return details.bind((selectedCells) => { + const grid = toGrid(warehouse, generators, false); + const rows = extractGridDetails(grid).rows; + const slicedGrid = rows.slice(selectedCells[0].row, selectedCells[selectedCells.length - 1].row + selectedCells[selectedCells.length - 1].rowspan); + // Remove any locked cells from the copied grid rows + const filteredGrid = bind$2(slicedGrid, (row) => { + const newCells = filter$2(row.cells, (cell) => !cell.isLocked); + return newCells.length > 0 ? [{ ...row, cells: newCells }] : []; + }); + const slicedDetails = toDetailList(filteredGrid); + return someIf(slicedDetails.length > 0, slicedDetails); + }).map((slicedDetails) => copy(slicedDetails)); }; - const redistributeToPercent = (widths, totalWidth) => { - return map$1(widths, w => { - const colType = Size.from(w); - return colType.fold(() => { - return w; - }, px => { - const ratio = px / totalWidth * 100; - return ratio + '%'; - }, pc => { - return pc + '%'; - }); - }); + const statsStruct = (minRow, minCol, maxRow, maxCol, allCells, selectedCells) => ({ + minRow, + minCol, + maxRow, + maxCol, + allCells, + selectedCells, + }); + const findSelectedStats = (house, isSelected) => { + const totalColumns = house.grid.columns; + const totalRows = house.grid.rows; + /* Refactor into a method returning a struct to hide the mutation */ + let minRow = totalRows; + let minCol = totalColumns; + let maxRow = 0; + let maxCol = 0; + const allCells = []; + const selectedCells = []; + each$1(house.access, (detail) => { + allCells.push(detail); + if (isSelected(detail)) { + selectedCells.push(detail); + const startRow = detail.row; + const endRow = startRow + detail.rowspan - 1; + const startCol = detail.column; + const endCol = startCol + detail.colspan - 1; + if (startRow < minRow) { + minRow = startRow; + } + else if (endRow > maxRow) { + maxRow = endRow; + } + if (startCol < minCol) { + minCol = startCol; + } + else if (endCol > maxCol) { + maxCol = endCol; + } + } + }); + return statsStruct(minRow, minCol, maxRow, maxCol, allCells, selectedCells); }; - const redistributeToPx = (widths, totalWidth, newTotalWidth) => { - const scale = newTotalWidth / totalWidth; - return map$1(widths, w => { - const colType = Size.from(w); - return colType.fold(() => { - return w; - }, px => { - return px * scale + 'px'; - }, pc => { - return pc / 100 * newTotalWidth + 'px'; - }); - }); + const makeCell = (list, seenSelected, rowIndex) => { + // no need to check bounds, as anything outside this index is removed in the nested for loop + const row = list[rowIndex].element; + const td = SugarElement.fromTag('td'); + append$1(td, SugarElement.fromTag('br')); + const f = seenSelected ? append$1 : prepend; + f(row, td); }; - const redistributeEmpty = (newWidthType, columns) => { - const f = newWidthType.fold(() => constant(''), pixels => { - const num = pixels / columns; - return constant(num + 'px'); - }, () => { - const num = 100 / columns; - return constant(num + '%'); - }); - return range$1(columns, f); + const fillInGaps = (list, house, stats, isSelected) => { + const rows = filter$2(list, (row) => row.section !== 'colgroup'); + const totalColumns = house.grid.columns; + const totalRows = house.grid.rows; + // unselected cells have been deleted, now fill in the gaps in the model + for (let i = 0; i < totalRows; i++) { + let seenSelected = false; + for (let j = 0; j < totalColumns; j++) { + if (!(i < stats.minRow || i > stats.maxRow || j < stats.minCol || j > stats.maxCol)) { + // if there is a hole in the table itself, or it's an unselected position, we need a cell + const needCell = Warehouse.getAt(house, i, j).filter(isSelected).isNone(); + if (needCell) { + makeCell(rows, seenSelected, i); + } + else { + seenSelected = true; + } + } + } + } }; - const redistributeValues = (newWidthType, widths, totalWidth) => { - return newWidthType.fold(() => { - return widths; - }, px => { - return redistributeToPx(widths, totalWidth, px); - }, _pc => { - return redistributeToPercent(widths, totalWidth); - }); + const clean = (replica, stats, house, widthDelta) => { + // remove columns that are not in the new table + each$1(house.columns, (col) => { + if (col.column < stats.minCol || col.column > stats.maxCol) { + remove$5(col.element); + } + }); + // can't use :empty selector as that will not include TRs made up of whitespace + const emptyRows = filter$2(firstLayer(replica, 'tr'), (row) => + // there is no sugar method for this, and Traverse.children() does too much processing + row.dom.childElementCount === 0); + each$2(emptyRows, remove$5); + // If there is only one column, or only one row, delete all the colspan/rowspan + if (stats.minCol === stats.maxCol || stats.minRow === stats.maxRow) { + each$2(firstLayer(replica, 'th,td'), (cell) => { + remove$6(cell, 'rowspan'); + remove$6(cell, 'colspan'); + }); + } + // Remove any attributes that should not be in the replicated table + remove$6(replica, LOCKED_COL_ATTR); + // TODO: TINY-6944 - need to figure out a better way of handling this + remove$6(replica, 'data-snooker-col-series'); // For advtable series column feature + const tableSize = TableSize.getTableSize(replica); + tableSize.adjustTableWidth(widthDelta); + // TODO TINY-6863: If using relative widths, ensure cell and column widths are redistributed }; - const redistribute$1 = (widths, totalWidth, newWidth) => { - const newType = Size.from(newWidth); - const floats = forall(widths, s => { - return s === '0px'; - }) ? redistributeEmpty(newType, widths.length) : redistributeValues(newType, widths, totalWidth); - return normalize(floats); + const getTableWidthDelta = (table, warehouse, tableSize, stats) => { + // short circuit entire table selected + if (stats.minCol === 0 && warehouse.grid.columns === stats.maxCol + 1) { + return 0; + } + const colWidths = getPixelWidths(warehouse, table, tableSize); + const allColsWidth = foldl(colWidths, (acc, width) => acc + width, 0); + const selectedColsWidth = foldl(colWidths.slice(stats.minCol, stats.maxCol + 1), (acc, width) => acc + width, 0); + const newWidth = (selectedColsWidth / allColsWidth) * tableSize.pixelWidth(); + const delta = newWidth - tableSize.pixelWidth(); + return tableSize.getCellDelta(delta); }; - const sum = (values, fallback) => { - if (values.length === 0) { - return fallback; - } - return foldr(values, (rest, v) => { - return Size.from(v).fold(constant(0), identity, identity) + rest; - }, 0); + const extract$1 = (table, selectedSelector) => { + const isSelected = (detail) => is$1(detail.element, selectedSelector); + const replica = deep(table); + const list = fromTable$1(replica); + const tableSize = TableSize.getTableSize(table); + const replicaHouse = Warehouse.generate(list); + const replicaStats = findSelectedStats(replicaHouse, isSelected); + // remove unselected cells + const selector = 'th:not(' + selectedSelector + ')' + ',td:not(' + selectedSelector + ')'; + const unselectedCells = filterFirstLayer(replica, 'th,td', (cell) => is$1(cell, selector)); + each$2(unselectedCells, remove$5); + fillInGaps(list, replicaHouse, replicaStats, isSelected); + const house = Warehouse.fromTable(table); + const widthDelta = getTableWidthDelta(table, house, tableSize, replicaStats); + clean(replica, replicaStats, replicaHouse, widthDelta); + return replica; }; - const roundDown = (num, unit) => { - const floored = Math.floor(num); - return { - value: floored + unit, - remainder: num - floored - }; - }; - const add$3 = (value, amount) => { - return Size.from(value).fold(constant(value), px => { - return px + amount + 'px'; - }, pc => { - return pc + amount + '%'; - }); - }; - const normalize = values => { - if (values.length === 0) { - return values; - } - const scan = foldr(values, (rest, value) => { - const info = Size.from(value).fold(() => ({ - value, - remainder: 0 - }), num => roundDown(num, 'px'), num => ({ - value: num + '%', - remainder: 0 - })); + + const isCol = isTag('col'); + const isColgroup = isTag('colgroup'); + const isRow$1 = (element) => name(element) === 'tr' || isColgroup(element); + const elementToData = (element) => { + const colspan = getAttrValue(element, 'colspan', 1); + const rowspan = getAttrValue(element, 'rowspan', 1); return { - output: [info.value].concat(rest.output), - remainder: rest.remainder + info.remainder + element, + colspan, + rowspan }; - }, { - output: [], - remainder: 0 - }); - const r = scan.output; - return r.slice(0, r.length - 1).concat([add$3(r[r.length - 1], Math.round(scan.remainder))]); }; - const validate = Size.from; - - const redistributeToW = (newWidths, cells, unit) => { - each$2(cells, cell => { - const widths = newWidths.slice(cell.column, cell.colspan + cell.column); - const w = sum(widths, minWidth()); - set$1(cell.element, 'width', w + unit); - }); - }; - const redistributeToColumns = (newWidths, columns, unit) => { - each$2(columns, (column, index) => { - const width = sum([newWidths[index]], minWidth()); - set$1(column.element, 'width', width + unit); - }); + // note that `toData` seems to be only for testing + const modification = (generators, toData = elementToData) => { + const nuCell = (data) => isCol(data.element) ? generators.col(data) : generators.cell(data); + const nuRow = (data) => isColgroup(data.element) ? generators.colgroup(data) : generators.row(data); + const add = (element) => { + if (isRow$1(element)) { + return nuRow({ element }); + } + else { + const cell = element; + const replacement = nuCell(toData(cell)); + recent = Optional.some({ item: cell, replacement }); + return replacement; + } + }; + let recent = Optional.none(); + const getOrInit = (element, comparator) => { + return recent.fold(() => { + return add(element); + }, (p) => { + return comparator(element, p.item) ? p.replacement : add(element); + }); + }; + return { + getOrInit + }; }; - const redistributeToH = (newHeights, rows, cells) => { - each$2(cells, cell => { - remove$5(cell.element, 'height'); - }); - each$2(rows, (row, i) => { - set$1(row.element, 'height', newHeights[i]); - }); + const transform$1 = (tag) => { + return (generators) => { + const list = []; + const find = (element, comparator) => { + return find$1(list, (x) => { + return comparator(x.item, element); + }); + }; + const makeNew = (element) => { + // Ensure scope is never set on a td element as it's a deprecated attribute + const attrs = tag === 'td' ? { scope: null } : {}; + const cell = generators.replace(element, tag, attrs); + list.push({ + item: element, + sub: cell + }); + return cell; + }; + const replaceOrInit = (element, comparator) => { + if (isRow$1(element) || isCol(element)) { + return element; + } + else { + const cell = element; + return find(cell, comparator).fold(() => { + return makeNew(cell); + }, (p) => { + return comparator(element, p.item) ? p.sub : makeNew(cell); + }); + } + }; + return { + replaceOrInit + }; + }; }; - const getUnit = newSize => { - return validate(newSize).fold(constant('px'), constant('px'), constant('%')); + const getScopeAttribute = (cell) => getOpt(cell, 'scope').map( + // Attribute can be col, colgroup, row, and rowgroup. + // As col and colgroup are to be treated as if they are the same, lob off everything after the first three characters and there is no difference. + (attribute) => attribute.substr(0, 3)); + const merging = (generators) => { + const unmerge = (cell) => { + const scope = getScopeAttribute(cell); + scope.each((attribute) => set$2(cell, 'scope', attribute)); + return () => { + const raw = generators.cell({ + element: cell, + colspan: 1, + rowspan: 1 + }); + // Remove any width calculations because they are no longer relevant. + remove$4(raw, 'width'); + remove$4(cell, 'width'); + scope.each((attribute) => set$2(raw, 'scope', attribute)); + return raw; + }; + }; + const merge = (cells) => { + const getScopeProperty = () => { + const stringAttributes = cat(map$1(cells, getScopeAttribute)); + if (stringAttributes.length === 0) { + return Optional.none(); + } + else { + const baseScope = stringAttributes[0]; + const scopes = ['row', 'col']; + const isMixed = exists(stringAttributes, (attribute) => { + return attribute !== baseScope && contains$2(scopes, attribute); + }); + return isMixed ? Optional.none() : Optional.from(baseScope); + } + }; + remove$4(cells[0], 'width'); + getScopeProperty().fold(() => remove$6(cells[0], 'scope'), (attribute) => set$2(cells[0], 'scope', attribute + 'group')); + return constant(cells[0]); + }; + return { + unmerge, + merge + }; }; - const redistribute = (table, optWidth, optHeight) => { - const warehouse = Warehouse.fromTable(table); - const rows = warehouse.all; - const cells = Warehouse.justCells(warehouse); - const columns = Warehouse.justColumns(warehouse); - optWidth.each(newWidth => { - const widthUnit = getUnit(newWidth); - const totalWidth = get$9(table); - const oldWidths = getRawWidths(warehouse, table); - const nuWidths = redistribute$1(oldWidths, totalWidth, newWidth); - if (Warehouse.hasColumns(warehouse)) { - redistributeToColumns(nuWidths, columns, widthUnit); - } else { - redistributeToW(nuWidths, cells, widthUnit); - } - set$1(table, 'width', newWidth); - }); - optHeight.each(newHeight => { - const totalHeight = get$8(table); - const oldHeights = getRawHeights(warehouse, table); - const nuHeights = redistribute$1(oldHeights, totalHeight, newHeight); - redistributeToH(nuHeights, rows, cells); - set$1(table, 'height', newHeight); - }); + const Generators = { + modification, + transform: transform$1, + merging }; - const isPercentSizing = isPercentSizing$1; - const isPixelSizing = isPixelSizing$1; - const isNoneSizing = isNoneSizing$1; - const cleanupLegacyAttributes = element => { - remove$7(element, 'width'); - remove$7(element, 'height'); + const getUpOrLeftCells = (grid, selectedCells) => { + // Get rows up or at the row of the bottom right cell + const upGrid = grid.slice(0, selectedCells[selectedCells.length - 1].row + 1); + const upDetails = toDetailList(upGrid); + // Get an array of the cells up or to the left of the bottom right cell + return bind$2(upDetails, (detail) => { + const slicedCells = detail.cells.slice(0, selectedCells[selectedCells.length - 1].column + 1); + return map$1(slicedCells, (cell) => cell.element); + }); + }; + const getDownOrRightCells = (grid, selectedCells) => { + // Get rows down or at the row of the top left cell (including rowspans) + const downGrid = grid.slice(selectedCells[0].row + selectedCells[0].rowspan - 1, grid.length); + const downDetails = toDetailList(downGrid); + // Get an array of the cells down or to the right of the bottom right cell + return bind$2(downDetails, (detail) => { + const slicedCells = detail.cells.slice(selectedCells[0].column + selectedCells[0].colspan - 1, detail.cells.length); + return map$1(slicedCells, (cell) => cell.element); + }); + }; + const getOtherCells = (table, target, generators) => { + const warehouse = Warehouse.fromTable(table); + const details = onCells(warehouse, target); + return details.map((selectedCells) => { + const grid = toGrid(warehouse, generators, false); + const { rows } = extractGridDetails(grid); + const upOrLeftCells = getUpOrLeftCells(rows, selectedCells); + const downOrRightCells = getDownOrRightCells(rows, selectedCells); + return { + upOrLeftCells, + downOrRightCells + }; + }); }; - const convertToPercentSizeWidth = table => { - const newWidth = getPercentTableWidth(table); - redistribute(table, Optional.some(newWidth), Optional.none()); - cleanupLegacyAttributes(table); + + const only = (element, isResizable) => { + // If element is a 'document', use the document element ('HTML' tag) for appending. + const parent = isDocument(element) ? documentElement(element) : element; + return { + parent: constant(parent), + view: constant(element), + dragContainer: constant(parent), + origin: constant(SugarPosition(0, 0)), + isResizable + }; }; - const convertToPixelSizeWidth = table => { - const newWidth = getPixelTableWidth(table); - redistribute(table, Optional.some(newWidth), Optional.none()); - cleanupLegacyAttributes(table); + const detached = (editable, chrome, isResizable) => { + const origin = () => absolute(chrome); + return { + parent: constant(chrome), + view: constant(editable), + dragContainer: constant(chrome), + origin, + isResizable + }; }; - const convertToPixelSizeHeight = table => { - const newHeight = getPixelTableHeight(table); - redistribute(table, Optional.none(), Optional.some(newHeight)); - cleanupLegacyAttributes(table); + const body = (editable, isResizable) => { + return { + parent: constant(editable), + view: constant(editable), + dragContainer: constant(editable), + origin: () => absolute(editable), + isResizable + }; }; - const convertToNoneSizeWidth = table => { - remove$5(table, 'width'); - const columns = columns$1(table); - const rowElements = columns.length > 0 ? columns : cells$1(table); - each$2(rowElements, cell => { - remove$5(cell, 'width'); - cleanupLegacyAttributes(cell); - }); - cleanupLegacyAttributes(table); + const ResizeWire = { + only, + detached, + body }; - const DefaultRenderOptions = { - styles: { - 'border-collapse': 'collapse', - 'width': '100%' - }, - attributes: { border: '1' }, - colGroups: false + const adt$2 = Adt.generate([ + { invalid: ['raw'] }, + { pixels: ['value'] }, + { percent: ['value'] } + ]); + const validateFor = (suffix, type, value) => { + const rawAmount = value.substring(0, value.length - suffix.length); + const amount = parseFloat(rawAmount); + return rawAmount === amount.toString() ? type(amount) : adt$2.invalid(value); }; - const tableHeaderCell = () => SugarElement.fromTag('th'); - const tableCell = () => SugarElement.fromTag('td'); - const tableColumn = () => SugarElement.fromTag('col'); - const createRow = (columns, rowHeaders, columnHeaders, rowIndex) => { - const tr = SugarElement.fromTag('tr'); - for (let j = 0; j < columns; j++) { - const td = rowIndex < rowHeaders || j < columnHeaders ? tableHeaderCell() : tableCell(); - if (j < columnHeaders) { - set$2(td, 'scope', 'row'); + const from = (value) => { + if (endsWith(value, '%')) { + return validateFor('%', adt$2.percent, value); } - if (rowIndex < rowHeaders) { - set$2(td, 'scope', 'col'); + if (endsWith(value, 'px')) { + return validateFor('px', adt$2.pixels, value); } - append$1(td, SugarElement.fromTag('br')); - append$1(tr, td); - } - return tr; + return adt$2.invalid(value); }; - const createGroupRow = columns => { - const columnGroup = SugarElement.fromTag('colgroup'); - range$1(columns, () => append$1(columnGroup, tableColumn())); - return columnGroup; - }; - const createRows = (rows, columns, rowHeaders, columnHeaders) => range$1(rows, r => createRow(columns, rowHeaders, columnHeaders, r)); - const render = (rows, columns, rowHeaders, columnHeaders, headerType, renderOpts = DefaultRenderOptions) => { - const table = SugarElement.fromTag('table'); - const rowHeadersGoInThead = headerType !== 'cells'; - setAll(table, renderOpts.styles); - setAll$1(table, renderOpts.attributes); - if (renderOpts.colGroups) { - append$1(table, createGroupRow(columns)); - } - const actualRowHeaders = Math.min(rows, rowHeaders); - if (rowHeadersGoInThead && rowHeaders > 0) { - const thead = SugarElement.fromTag('thead'); - append$1(table, thead); - const theadRowHeaders = headerType === 'sectionCells' ? actualRowHeaders : 0; - const theadRows = createRows(rowHeaders, columns, theadRowHeaders, columnHeaders); - append(thead, theadRows); - } - const tbody = SugarElement.fromTag('tbody'); - append$1(table, tbody); - const numRows = rowHeadersGoInThead ? rows - actualRowHeaders : rows; - const numRowHeaders = rowHeadersGoInThead ? 0 : rowHeaders; - const tbodyRows = createRows(numRows, columns, numRowHeaders, columnHeaders); - append(tbody, tbodyRows); - return table; - }; - - const get$4 = element => element.dom.innerHTML; - const getOuter = element => { - const container = SugarElement.fromTag('div'); - const clone = SugarElement.fromDom(element.dom.cloneNode(true)); - append$1(container, clone); - return get$4(container); + const Size = { + ...adt$2, + from }; - const placeCaretInCell = (editor, cell) => { - editor.selection.select(cell.dom, true); - editor.selection.collapse(true); + // Convert all column widths to percent. + const redistributeToPercent = (widths, totalWidth) => { + return map$1(widths, (w) => { + const colType = Size.from(w); + return colType.fold(() => { + return w; + }, (px) => { + const ratio = px / totalWidth * 100; + return ratio + '%'; + }, (pc) => { + return pc + '%'; + }); + }); }; - const selectFirstCellInTable = (editor, tableElm) => { - descendant(tableElm, 'td,th').each(curry(placeCaretInCell, editor)); + const redistributeToPx = (widths, totalWidth, newTotalWidth) => { + const scale = newTotalWidth / totalWidth; + return map$1(widths, (w) => { + const colType = Size.from(w); + return colType.fold(() => { + return w; + }, (px) => { + return (px * scale) + 'px'; + }, (pc) => { + return (pc / 100 * newTotalWidth) + 'px'; + }); + }); }; - const fireEvents = (editor, table) => { - each$2(descendants(table, 'tr'), row => { - fireNewRow(editor, row.dom); - each$2(descendants(row, 'th,td'), cell => { - fireNewCell(editor, cell.dom); + const redistributeEmpty = (newWidthType, columns) => { + const f = newWidthType.fold(() => constant(''), (pixels) => { + const num = pixels / columns; + return constant(num + 'px'); + }, () => { + const num = 100 / columns; + return constant(num + '%'); }); - }); + return range$1(columns, f); }; - const isPercentage = width => isString(width) && width.indexOf('%') !== -1; - const insert = (editor, columns, rows, colHeaders, rowHeaders) => { - const defaultStyles = getTableDefaultStyles(editor); - const options = { - styles: defaultStyles, - attributes: getTableDefaultAttributes(editor), - colGroups: tableUseColumnGroup(editor) - }; - editor.undoManager.ignore(() => { - const table = render(rows, columns, rowHeaders, colHeaders, getTableHeaderType(editor), options); - set$2(table, 'data-mce-id', '__mce'); - const html = getOuter(table); - editor.insertContent(html); - editor.addVisual(); - }); - return descendant(getBody(editor), 'table[data-mce-id="__mce"]').map(table => { - if (isTablePixelsForced(editor)) { - convertToPixelSizeWidth(table); - } else if (isTableResponsiveForced(editor)) { - convertToNoneSizeWidth(table); - } else if (isTablePercentagesForced(editor) || isPercentage(defaultStyles.width)) { - convertToPercentSizeWidth(table); - } - removeDataStyle(table); - remove$7(table, 'data-mce-id'); - fireEvents(editor, table); - selectFirstCellInTable(editor, table); - return table.dom; - }).getOrNull(); + const redistributeValues = (newWidthType, widths, totalWidth) => { + return newWidthType.fold(() => { + return widths; + }, (px) => { + return redistributeToPx(widths, totalWidth, px); + }, (_pc) => { + return redistributeToPercent(widths, totalWidth); + }); }; - const insertTable = (editor, rows, columns, options = {}) => { - const checkInput = val => isNumber(val) && val > 0; - if (checkInput(rows) && checkInput(columns)) { - const headerRows = options.headerRows || 0; - const headerColumns = options.headerColumns || 0; - return insert(editor, columns, rows, headerColumns, headerRows); - } else { - console.error('Invalid values for mceInsertTable - rows and columns values are required to insert a table.'); - return null; - } + const redistribute$1 = (widths, totalWidth, newWidth) => { + const newType = Size.from(newWidth); + const floats = forall(widths, (s) => { + return s === '0px'; + }) ? redistributeEmpty(newType, widths.length) : redistributeValues(newType, widths, totalWidth); + return normalize(floats); }; - - var global = tinymce.util.Tools.resolve('tinymce.FakeClipboard'); - - const tableTypeBase = 'x-tinymce/dom-table-'; - const tableTypeRow = tableTypeBase + 'rows'; - const tableTypeColumn = tableTypeBase + 'columns'; - const setData = items => { - const fakeClipboardItem = global.FakeClipboardItem(items); - global.write([fakeClipboardItem]); + const sum = (values, fallback) => { + if (values.length === 0) { + return fallback; + } + return foldr(values, (rest, v) => { + return Size.from(v).fold(constant(0), identity, identity) + rest; + }, 0); }; - const getData = type => { - var _a; - const items = (_a = global.read()) !== null && _a !== void 0 ? _a : []; - return findMap(items, item => Optional.from(item.getType(type))); + const roundDown = (num, unit) => { + const floored = Math.floor(num); + return { value: floored + unit, remainder: num - floored }; + }; + const add = (value, amount) => { + return Size.from(value).fold(constant(value), (px) => { + return (px + amount) + 'px'; + }, (pc) => { + return (pc + amount) + '%'; + }); }; - const clearData = type => { - if (getData(type).isSome()) { - global.clear(); - } + const normalize = (values) => { + if (values.length === 0) { + return values; + } + const scan = foldr(values, (rest, value) => { + const info = Size.from(value).fold(() => ({ value, remainder: 0 }), (num) => roundDown(num, 'px'), (num) => ({ value: num + '%', remainder: 0 })); + return { + output: [info.value].concat(rest.output), + remainder: rest.remainder + info.remainder + }; + }, { output: [], remainder: 0 }); + const r = scan.output; + return r.slice(0, r.length - 1).concat([add(r[r.length - 1], Math.round(scan.remainder))]); }; - const setRows = rowsOpt => { - rowsOpt.fold(clearRows, rows => setData({ [tableTypeRow]: rows })); + const validate = Size.from; + + const redistributeToW = (newWidths, cells, unit) => { + each$2(cells, (cell) => { + const widths = newWidths.slice(cell.column, cell.colspan + cell.column); + const w = sum(widths, minWidth()); + set$1(cell.element, 'width', w + unit); + }); }; - const getRows = () => getData(tableTypeRow); - const clearRows = () => clearData(tableTypeRow); - const setColumns = columnsOpt => { - columnsOpt.fold(clearColumns, columns => setData({ [tableTypeColumn]: columns })); + const redistributeToColumns = (newWidths, columns, unit) => { + each$2(columns, (column, index) => { + const width = sum([newWidths[index]], minWidth()); + set$1(column.element, 'width', width + unit); + }); }; - const getColumns = () => getData(tableTypeColumn); - const clearColumns = () => clearData(tableTypeColumn); - - const getSelectionStartCellOrCaption = editor => getSelectionCellOrCaption(getSelectionStart(editor), getIsRoot(editor)).filter(isInEditableContext$1); - const getSelectionStartCell = editor => getSelectionCell(getSelectionStart(editor), getIsRoot(editor)).filter(isInEditableContext$1); - const registerCommands = (editor, actions) => { - const isRoot = getIsRoot(editor); - const eraseTable = () => getSelectionStartCellOrCaption(editor).each(cellOrCaption => { - table(cellOrCaption, isRoot).filter(not(isRoot)).each(table => { - const cursor = SugarElement.fromText(''); - after$5(table, cursor); - remove$6(table); - if (editor.dom.isEmpty(editor.getBody())) { - editor.setContent(''); - editor.selection.setCursorLocation(); - } else { - const rng = editor.dom.createRng(); - rng.setStart(cursor.dom, 0); - rng.setEnd(cursor.dom, 0); - editor.selection.setRng(rng); - editor.nodeChanged(); - } + const redistributeToH = (newHeights, rows, cells) => { + each$2(cells, (cell) => { + remove$4(cell.element, 'height'); }); - }); - const setSizingMode = sizing => getSelectionStartCellOrCaption(editor).each(cellOrCaption => { - const isForcedSizing = isTableResponsiveForced(editor) || isTablePixelsForced(editor) || isTablePercentagesForced(editor); - if (!isForcedSizing) { - table(cellOrCaption, isRoot).each(table => { - if (sizing === 'relative' && !isPercentSizing(table)) { - convertToPercentSizeWidth(table); - } else if (sizing === 'fixed' && !isPixelSizing(table)) { - convertToPixelSizeWidth(table); - } else if (sizing === 'responsive' && !isNoneSizing(table)) { - convertToNoneSizeWidth(table); - } - removeDataStyle(table); - fireTableModified(editor, table.dom, structureModified); - }); - } - }); - const getTableFromCell = cell => table(cell, isRoot); - const performActionOnSelection = action => getSelectionStartCell(editor).bind(cell => getTableFromCell(cell).map(table => action(table, cell))); - const toggleTableClass = (_ui, clazz) => { - performActionOnSelection(table => { - editor.formatter.toggle('tableclass', { value: clazz }, table.dom); - fireTableModified(editor, table.dom, styleModified); - }); - }; - const toggleTableCellClass = (_ui, clazz) => { - performActionOnSelection(table => { - const selectedCells = getCellsFromSelection(editor); - const allHaveClass = forall(selectedCells, cell => editor.formatter.match('tablecellclass', { value: clazz }, cell.dom)); - const formatterAction = allHaveClass ? editor.formatter.remove : editor.formatter.apply; - each$2(selectedCells, cell => formatterAction('tablecellclass', { value: clazz }, cell.dom)); - fireTableModified(editor, table.dom, styleModified); - }); - }; - const toggleCaption = () => { - getSelectionStartCellOrCaption(editor).each(cellOrCaption => { - table(cellOrCaption, isRoot).each(table => { - child(table, 'caption').fold(() => { - const caption = SugarElement.fromTag('caption'); - append$1(caption, SugarElement.fromText('Caption')); - appendAt(table, caption, 0); - editor.selection.setCursorLocation(caption.dom, 0); - }, caption => { - if (isTag('caption')(cellOrCaption)) { - one('td', table).each(td => editor.selection.setCursorLocation(td.dom, 0)); - } - remove$6(caption); - }); - fireTableModified(editor, table.dom, structureModified); - }); - }); - }; - const postExecute = _data => { - editor.focus(); - }; - const actOnSelection = (execute, noEvents = false) => performActionOnSelection((table, startCell) => { - const targets = forMenu(getCellsFromSelection(editor), table, startCell); - execute(table, targets, noEvents).each(postExecute); - }); - const copyRowSelection = () => performActionOnSelection((table, startCell) => { - const targets = forMenu(getCellsFromSelection(editor), table, startCell); - const generators = cellOperations(noop, SugarElement.fromDom(editor.getDoc()), Optional.none()); - return copyRows(table, targets, generators); - }); - const copyColSelection = () => performActionOnSelection((table, startCell) => { - const targets = forMenu(getCellsFromSelection(editor), table, startCell); - return copyCols(table, targets); - }); - const pasteOnSelection = (execute, getRows) => getRows().each(rows => { - const clonedRows = map$1(rows, row => deep(row)); - performActionOnSelection((table, startCell) => { - const generators = paste$1(SugarElement.fromDom(editor.getDoc())); - const targets = pasteRows(getCellsFromSelection(editor), startCell, clonedRows, generators); - execute(table, targets).each(postExecute); - }); - }); - const actOnType = getAction => (_ui, args) => get$c(args, 'type').each(type => { - actOnSelection(getAction(type), args.no_events); - }); - each$1({ - mceTableSplitCells: () => actOnSelection(actions.unmergeCells), - mceTableMergeCells: () => actOnSelection(actions.mergeCells), - mceTableInsertRowBefore: () => actOnSelection(actions.insertRowsBefore), - mceTableInsertRowAfter: () => actOnSelection(actions.insertRowsAfter), - mceTableInsertColBefore: () => actOnSelection(actions.insertColumnsBefore), - mceTableInsertColAfter: () => actOnSelection(actions.insertColumnsAfter), - mceTableDeleteCol: () => actOnSelection(actions.deleteColumn), - mceTableDeleteRow: () => actOnSelection(actions.deleteRow), - mceTableCutCol: () => copyColSelection().each(selection => { - setColumns(selection); - actOnSelection(actions.deleteColumn); - }), - mceTableCutRow: () => copyRowSelection().each(selection => { - setRows(selection); - actOnSelection(actions.deleteRow); - }), - mceTableCopyCol: () => copyColSelection().each(selection => setColumns(selection)), - mceTableCopyRow: () => copyRowSelection().each(selection => setRows(selection)), - mceTablePasteColBefore: () => pasteOnSelection(actions.pasteColsBefore, getColumns), - mceTablePasteColAfter: () => pasteOnSelection(actions.pasteColsAfter, getColumns), - mceTablePasteRowBefore: () => pasteOnSelection(actions.pasteRowsBefore, getRows), - mceTablePasteRowAfter: () => pasteOnSelection(actions.pasteRowsAfter, getRows), - mceTableDelete: eraseTable, - mceTableCellToggleClass: toggleTableCellClass, - mceTableToggleClass: toggleTableClass, - mceTableToggleCaption: toggleCaption, - mceTableSizingMode: (_ui, sizing) => setSizingMode(sizing), - mceTableCellType: actOnType(type => type === 'th' ? actions.makeCellsHeader : actions.unmakeCellsHeader), - mceTableColType: actOnType(type => type === 'th' ? actions.makeColumnsHeader : actions.unmakeColumnsHeader), - mceTableRowType: actOnType(type => { - switch (type) { - case 'header': - return actions.makeRowsHeader; - case 'footer': - return actions.makeRowsFooter; - default: - return actions.makeRowsBody; - } - }) - }, (func, name) => editor.addCommand(name, func)); - editor.addCommand('mceInsertTable', (_ui, args) => { - insertTable(editor, args.rows, args.columns, args.options); - }); - editor.addCommand('mceTableApplyCellStyle', (_ui, args) => { - const getFormatName = style => 'tablecell' + style.toLowerCase().replace('-', ''); - if (!isObject(args)) { - return; - } - const cells = filter$2(getCellsFromSelection(editor), isInEditableContext$1); - if (cells.length === 0) { - return; - } - const validArgs = filter$1(args, (value, style) => editor.formatter.has(getFormatName(style)) && isString(value)); - if (isEmpty(validArgs)) { - return; - } - each$1(validArgs, (value, style) => { - const formatName = getFormatName(style); - each$2(cells, cell => { - if (value === '') { - editor.formatter.remove(formatName, { value: null }, cell.dom, true); - } else { - editor.formatter.apply(formatName, { value }, cell.dom); - } - }); + each$2(rows, (row, i) => { + set$1(row.element, 'height', newHeights[i]); }); - getTableFromCell(cells[0]).each(table => fireTableModified(editor, table.dom, styleModified)); - }); }; - - const registerQueryCommands = (editor, actions) => { - const isRoot = getIsRoot(editor); - const lookupOnSelection = action => getSelectionCell(getSelectionStart(editor)).bind(cell => table(cell, isRoot).map(table => { - const targets = forMenu(getCellsFromSelection(editor), table, cell); - return action(table, targets); - })).getOr(''); - each$1({ - mceTableRowType: () => lookupOnSelection(actions.getTableRowType), - mceTableCellType: () => lookupOnSelection(actions.getTableCellType), - mceTableColType: () => lookupOnSelection(actions.getTableColType) - }, (func, name) => editor.addQueryValueHandler(name, func)); + const getUnit = (newSize) => { + return validate(newSize).fold(constant('px'), constant('px'), constant('%')); }; - - const adt$4 = Adt.generate([ - { before: ['element'] }, - { - on: [ - 'element', - 'offset' - ] - }, - { after: ['element'] } - ]); - const cata$1 = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter); - const getStart$1 = situ => situ.fold(identity, identity, identity); - const before$2 = adt$4.before; - const on = adt$4.on; - const after$3 = adt$4.after; - const Situ = { - before: before$2, - on, - after: after$3, - cata: cata$1, - getStart: getStart$1 + // Procedure to resize table dimensions to optWidth x optHeight and redistribute cell and row dimensions. + // Updates CSS of the table, rows, and cells. + const redistribute = (table, optWidth, optHeight) => { + const warehouse = Warehouse.fromTable(table); + const rows = warehouse.all; + const cells = Warehouse.justCells(warehouse); + const columns = Warehouse.justColumns(warehouse); + optWidth.each((newWidth) => { + const widthUnit = getUnit(newWidth); + const totalWidth = get$7(table); + const oldWidths = getRawWidths(warehouse, table); + const nuWidths = redistribute$1(oldWidths, totalWidth, newWidth); + if (Warehouse.hasColumns(warehouse)) { + redistributeToColumns(nuWidths, columns, widthUnit); + } + else { + redistributeToW(nuWidths, cells, widthUnit); + } + set$1(table, 'width', newWidth); + }); + optHeight.each((newHeight) => { + const totalHeight = get$8(table); + const oldHeights = getRawHeights(warehouse, table); + const nuHeights = redistribute$1(oldHeights, totalHeight, newHeight); + redistributeToH(nuHeights, rows, cells); + set$1(table, 'height', newHeight); + }); }; + const isPercentSizing = isPercentSizing$1; + const isPixelSizing = isPixelSizing$1; + const isNoneSizing = isNoneSizing$1; - const create$4 = (selection, kill) => ({ - selection, - kill - }); - const Response = { create: create$4 }; - - const selectNode = (win, element) => { - const rng = win.document.createRange(); - rng.selectNode(element.dom); - return rng; - }; - const selectNodeContents = (win, element) => { - const rng = win.document.createRange(); - selectNodeContentsUsing(rng, element); - return rng; - }; - const selectNodeContentsUsing = (rng, element) => rng.selectNodeContents(element.dom); - const setStart = (rng, situ) => { - situ.fold(e => { - rng.setStartBefore(e.dom); - }, (e, o) => { - rng.setStart(e.dom, o); - }, e => { - rng.setStartAfter(e.dom); - }); - }; - const setFinish = (rng, situ) => { - situ.fold(e => { - rng.setEndBefore(e.dom); - }, (e, o) => { - rng.setEnd(e.dom, o); - }, e => { - rng.setEndAfter(e.dom); - }); - }; - const relativeToNative = (win, startSitu, finishSitu) => { - const range = win.document.createRange(); - setStart(range, startSitu); - setFinish(range, finishSitu); - return range; - }; - const exactToNative = (win, start, soffset, finish, foffset) => { - const rng = win.document.createRange(); - rng.setStart(start.dom, soffset); - rng.setEnd(finish.dom, foffset); - return rng; - }; - const toRect = rect => ({ - left: rect.left, - top: rect.top, - right: rect.right, - bottom: rect.bottom, - width: rect.width, - height: rect.height - }); - const getFirstRect$1 = rng => { - const rects = rng.getClientRects(); - const rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect(); - return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none(); - }; + var TagBoundaries = [ + 'body', + 'p', + 'div', + 'article', + 'aside', + 'figcaption', + 'figure', + 'footer', + 'header', + 'nav', + 'section', + 'ol', + 'ul', + 'li', + 'table', + 'thead', + 'tbody', + 'tfoot', + 'caption', + 'tr', + 'td', + 'th', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'blockquote', + 'pre', + 'address' + ]; - const adt$3 = Adt.generate([ - { - ltr: [ - 'start', - 'soffset', - 'finish', - 'foffset' - ] - }, - { - rtl: [ - 'start', - 'soffset', - 'finish', - 'foffset' - ] - } - ]); - const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset); - const getRanges = (win, selection) => selection.match({ - domRange: rng => { - return { - ltr: constant(rng), - rtl: Optional.none + var DomUniverse = () => { + const clone = (element) => { + return SugarElement.fromDom(element.dom.cloneNode(false)); }; - }, - relative: (startSitu, finishSitu) => { - return { - ltr: cached(() => relativeToNative(win, startSitu, finishSitu)), - rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu))) + const document = (element) => documentOrOwner(element).dom; + const isBoundary = (element) => { + if (!isElement(element)) { + return false; + } + if (name(element) === 'body') { + return true; + } + return contains$2(TagBoundaries, name(element)); + }; + const isEmptyTag = (element) => { + if (!isElement(element)) { + return false; + } + return contains$2(['br', 'img', 'hr', 'input'], name(element)); + }; + const isNonEditable = (element) => isElement(element) && get$b(element, 'contenteditable') === 'false'; + const comparePosition = (element, other) => { + return element.dom.compareDocumentPosition(other.dom); + }; + const copyAttributesTo = (source, destination) => { + const as = clone$1(source); + setAll$1(destination, as); + }; + const isSpecial = (element) => { + const tag = name(element); + return contains$2([ + 'script', 'noscript', 'iframe', 'noframes', 'noembed', 'title', 'style', 'textarea', 'xmp' + ], tag); }; - }, - exact: (start, soffset, finish, foffset) => { + const getLanguage = (element) => isElement(element) ? getOpt(element, 'lang') : Optional.none(); return { - ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)), - rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset))) + up: constant({ + selector: ancestor$1, + closest: closest$1, + predicate: ancestor$2, + all: parents + }), + down: constant({ + selector: descendants, + predicate: descendants$1 + }), + styles: constant({ + get: get$9, + getRaw: getRaw$2, + set: set$1, + remove: remove$4 + }), + attrs: constant({ + get: get$b, + set: set$2, + remove: remove$6, + copyTo: copyAttributesTo + }), + insert: constant({ + before: before$3, + after: after$4, + afterAll: after$3, + append: append$1, + appendAll: append, + prepend: prepend, + wrap: wrap + }), + remove: constant({ + unwrap: unwrap, + remove: remove$5 + }), + create: constant({ + nu: SugarElement.fromTag, + clone, + text: SugarElement.fromText + }), + query: constant({ + comparePosition, + prevSibling: prevSibling, + nextSibling: nextSibling + }), + property: constant({ + children: children$2, + name: name, + parent: parent, + document, + isText: isText, + isComment: isComment, + isElement: isElement, + isSpecial, + getLanguage, + getText: get$5, + setText: set, + isBoundary, + isEmptyTag, + isNonEditable + }), + eq: eq$1, + is: is }; - } - }); - const doDiagnose = (win, ranges) => { - const rng = ranges.ltr(); - if (rng.collapsed) { - const reversed = ranges.rtl().filter(rev => rev.collapsed === false); - return reversed.map(rev => adt$3.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$3.ltr, rng)); - } else { - return fromRange(win, adt$3.ltr, rng); - } - }; - const diagnose = (win, selection) => { - const ranges = getRanges(win, selection); - return doDiagnose(win, ranges); - }; - const asLtrRange = (win, selection) => { - const diagnosis = diagnose(win, selection); - return diagnosis.match({ - ltr: (start, soffset, finish, foffset) => { - const rng = win.document.createRange(); - rng.setStart(start.dom, soffset); - rng.setEnd(finish.dom, foffset); - return rng; - }, - rtl: (start, soffset, finish, foffset) => { - const rng = win.document.createRange(); - rng.setStart(finish.dom, foffset); - rng.setEnd(start.dom, soffset); - return rng; - } - }); - }; - adt$3.ltr; - adt$3.rtl; - - const create$3 = (start, soffset, finish, foffset) => ({ - start, - soffset, - finish, - foffset - }); - const SimRange = { create: create$3 }; - - const create$2 = (start, soffset, finish, foffset) => { - return { - start: Situ.on(start, soffset), - finish: Situ.on(finish, foffset) - }; - }; - const Situs = { create: create$2 }; - - const convertToRange = (win, selection) => { - const rng = asLtrRange(win, selection); - return SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset); - }; - const makeSitus = Situs.create; - - const sync = (container, isRoot, start, soffset, finish, foffset, selectRange) => { - if (!(eq$1(start, finish) && soffset === foffset)) { - return closest$1(start, 'td,th', isRoot).bind(s => { - return closest$1(finish, 'td,th', isRoot).bind(f => { - return detect(container, isRoot, s, f, selectRange); - }); - }); - } else { - return Optional.none(); - } - }; - const detect = (container, isRoot, start, finish, selectRange) => { - if (!eq$1(start, finish)) { - return identify(start, finish, isRoot).bind(cellSel => { - const boxes = cellSel.boxes.getOr([]); - if (boxes.length > 1) { - selectRange(container, boxes, cellSel.start, cellSel.finish); - return Optional.some(Response.create(Optional.some(makeSitus(start, 0, start, getEnd(start))), true)); - } else { - return Optional.none(); - } - }); - } else { - return Optional.none(); - } - }; - const update = (rows, columns, container, selected, annotations) => { - const updateSelection = newSels => { - annotations.clearBeforeUpdate(container); - annotations.selectRange(container, newSels.boxes, newSels.start, newSels.finish); - return newSels.boxes; - }; - return shiftSelection(selected, rows, columns, annotations.firstSelectedSelector, annotations.lastSelectedSelector).map(updateSelection); }; const traverse = (item, mode) => ({ - item, - mode + item, + mode }); const backtrack = (universe, item, _direction, transition = sidestep) => { - return universe.property().parent(item).map(p => { - return traverse(p, transition); - }); + return universe.property().parent(item).map((p) => { + return traverse(p, transition); + }); }; const sidestep = (universe, item, direction, transition = advance) => { - return direction.sibling(universe, item).map(p => { - return traverse(p, transition); - }); + return direction.sibling(universe, item).map((p) => { + return traverse(p, transition); + }); }; const advance = (universe, item, direction, transition = advance) => { - const children = universe.property().children(item); - const result = direction.first(children); - return result.map(r => { - return traverse(r, transition); - }); + const children = universe.property().children(item); + const result = direction.first(children); + return result.map((r) => { + return traverse(r, transition); + }); }; + /* + * Rule breakdown: + * + * current: the traversal that we are applying. + * next: the next traversal to apply if the current traversal succeeds (e.g. advance after sidestepping) + * fallback: the traversal to fallback to when the current traversal does not find a node + */ const successors = [ - { - current: backtrack, - next: sidestep, - fallback: Optional.none() - }, - { - current: sidestep, - next: advance, - fallback: Optional.some(backtrack) - }, - { - current: advance, - next: advance, - fallback: Optional.some(sidestep) - } + { current: backtrack, next: sidestep, fallback: Optional.none() }, + { current: sidestep, next: advance, fallback: Optional.some(backtrack) }, + { current: advance, next: advance, fallback: Optional.some(sidestep) } ]; const go = (universe, item, mode, direction, rules = successors) => { - const ruleOpt = find$1(rules, succ => { - return succ.current === mode; - }); - return ruleOpt.bind(rule => { - return rule.current(universe, item, direction, rule.next).orThunk(() => { - return rule.fallback.bind(fb => { - return go(universe, item, fb, direction); - }); + // INVESTIGATE: Find a way which doesn't require an array search first to identify the current mode. + const ruleOpt = find$1(rules, (succ) => { + return succ.current === mode; + }); + return ruleOpt.bind((rule) => { + // Attempt the current mode. If not, use the fallback and try again. + return rule.current(universe, item, direction, rule.next).orThunk(() => { + return rule.fallback.bind((fb) => { + return go(universe, item, fb, direction); + }); + }); }); - }); }; const left$1 = () => { - const sibling = (universe, item) => { - return universe.query().prevSibling(item); - }; - const first = children => { - return children.length > 0 ? Optional.some(children[children.length - 1]) : Optional.none(); - }; - return { - sibling, - first - }; + const sibling = (universe, item) => { + return universe.query().prevSibling(item); + }; + const first = (children) => { + return children.length > 0 ? Optional.some(children[children.length - 1]) : Optional.none(); + }; + return { + sibling, + first + }; }; const right$1 = () => { - const sibling = (universe, item) => { - return universe.query().nextSibling(item); - }; - const first = children => { - return children.length > 0 ? Optional.some(children[0]) : Optional.none(); - }; - return { - sibling, - first - }; + const sibling = (universe, item) => { + return universe.query().nextSibling(item); + }; + const first = (children) => { + return children.length > 0 ? Optional.some(children[0]) : Optional.none(); + }; + return { + sibling, + first + }; }; const Walkers = { - left: left$1, - right: right$1 + left: left$1, + right: right$1 }; const hone = (universe, item, predicate, mode, direction, isRoot) => { - const next = go(universe, item, mode, direction); - return next.bind(n => { - if (isRoot(n.item)) { - return Optional.none(); - } else { - return predicate(n.item) ? Optional.some(n.item) : hone(universe, n.item, predicate, n.mode, direction, isRoot); - } - }); + const next = go(universe, item, mode, direction); + return next.bind((n) => { + if (isRoot(n.item)) { + return Optional.none(); + } + else { + return predicate(n.item) ? Optional.some(n.item) : hone(universe, n.item, predicate, n.mode, direction, isRoot); + } + }); }; const left = (universe, item, predicate, isRoot) => { - return hone(universe, item, predicate, sidestep, Walkers.left(), isRoot); + return hone(universe, item, predicate, sidestep, Walkers.left(), isRoot); }; const right = (universe, item, predicate, isRoot) => { - return hone(universe, item, predicate, sidestep, Walkers.right(), isRoot); + return hone(universe, item, predicate, sidestep, Walkers.right(), isRoot); + }; + + const point = (element, offset) => ({ + element, + offset + }); + + const scan$1 = (universe, element, direction) => { + // if a comment or zero-length text, scan the siblings + if ((universe.property().isText(element) && universe.property().getText(element).trim().length === 0) + || universe.property().isComment(element)) { + return direction(element).bind((elem) => { + return scan$1(universe, elem, direction).orThunk(() => { + return Optional.some(elem); + }); + }); + } + else { + return Optional.none(); + } + }; + const toEnd = (universe, element) => { + if (universe.property().isText(element)) { + return universe.property().getText(element).length; + } + const children = universe.property().children(element); + return children.length; + }; + const freefallRtl$2 = (universe, element) => { + const candidate = scan$1(universe, element, universe.query().prevSibling).getOr(element); + if (universe.property().isText(candidate)) { + return point(candidate, toEnd(universe, candidate)); + } + const children = universe.property().children(candidate); + return children.length > 0 ? freefallRtl$2(universe, children[children.length - 1]) : point(candidate, toEnd(universe, candidate)); + }; + + const freefallRtl$1 = freefallRtl$2; + + const universe$3 = DomUniverse(); + const freefallRtl = (element) => { + return freefallRtl$1(universe$3, element); }; - const isLeaf = universe => element => universe.property().children(element).length === 0; + const isLeaf = (universe) => (element) => universe.property().children(element).length === 0; const before$1 = (universe, item, isRoot) => { - return seekLeft$1(universe, item, isLeaf(universe), isRoot); + return seekLeft$1(universe, item, isLeaf(universe), isRoot); }; - const after$2 = (universe, item, isRoot) => { - return seekRight$1(universe, item, isLeaf(universe), isRoot); + const after$1 = (universe, item, isRoot) => { + return seekRight$1(universe, item, isLeaf(universe), isRoot); }; const seekLeft$1 = left; const seekRight$1 = right; + go; - const universe = DomUniverse(); + const universe$2 = DomUniverse(); const before = (element, isRoot) => { - return before$1(universe, element, isRoot); + return before$1(universe$2, element, isRoot); }; - const after$1 = (element, isRoot) => { - return after$2(universe, element, isRoot); + const after = (element, isRoot) => { + return after$1(universe$2, element, isRoot); }; const seekLeft = (element, predicate, isRoot) => { - return seekLeft$1(universe, element, predicate, isRoot); + return seekLeft$1(universe$2, element, predicate, isRoot); }; const seekRight = (element, predicate, isRoot) => { - return seekRight$1(universe, element, predicate, isRoot); + return seekRight$1(universe$2, element, predicate, isRoot); }; - const ancestor = (scope, predicate, isRoot) => ancestor$2(scope, predicate, isRoot).isSome(); - - const adt$2 = Adt.generate([ - { none: ['message'] }, - { success: [] }, - { failedUp: ['cell'] }, - { failedDown: ['cell'] } - ]); - const isOverlapping = (bridge, before, after) => { - const beforeBounds = bridge.getRect(before); - const afterBounds = bridge.getRect(after); - return afterBounds.right > beforeBounds.left && afterBounds.left < beforeBounds.right; - }; - const isRow = elem => { - return closest$1(elem, 'tr'); - }; - const verify = (bridge, before, beforeOffset, after, afterOffset, failure, isRoot) => { - return closest$1(after, 'td,th', isRoot).bind(afterCell => { - return closest$1(before, 'td,th', isRoot).map(beforeCell => { - if (!eq$1(afterCell, beforeCell)) { - return sharedOne(isRow, [ - afterCell, - beforeCell - ]).fold(() => { - return isOverlapping(bridge, beforeCell, afterCell) ? adt$2.success() : failure(beforeCell); - }, _sharedRow => { - return failure(beforeCell); - }); - } else { - return eq$1(after, afterCell) && getEnd(afterCell) === afterOffset ? failure(beforeCell) : adt$2.none('in same cell'); - } - }); - }).getOr(adt$2.none('default')); + const blockList = [ + 'body', + 'p', + 'div', + 'article', + 'aside', + 'figcaption', + 'figure', + 'footer', + 'header', + 'nav', + 'section', + 'ol', + 'ul', + // --- NOTE, TagBoundaries has li here. That means universe.isBoundary => true for li tags. + 'table', + 'thead', + 'tfoot', + 'tbody', + 'caption', + 'tr', + 'td', + 'th', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'blockquote', + 'pre', + 'address' + ]; + const isList$1 = (universe, item) => { + const tagName = universe.property().name(item); + return contains$2(['ol', 'ul'], tagName); }; - const cata = (subject, onNone, onSuccess, onFailedUp, onFailedDown) => { - return subject.fold(onNone, onSuccess, onFailedUp, onFailedDown); + const isBlock$1 = (universe, item) => { + const tagName = universe.property().name(item); + return contains$2(blockList, tagName); }; - const BeforeAfter = { - ...adt$2, - verify, - cata + const isEmptyTag$1 = (universe, item) => { + return contains$2(['br', 'img', 'hr', 'input'], universe.property().name(item)); }; - const inParent = (parent, children, element, index) => ({ - parent, - children, - element, - index + const leftRight = (left, right) => ({ + left, + right }); - const indexInParent = element => parent(element).bind(parent => { - const children = children$2(parent); - return indexOf(children, element).map(index => inParent(parent, children, element, index)); + const brokenPath = (first, second, splits) => ({ + first, + second, + splits }); - const indexOf = (elements, element) => findIndex(elements, curry(eq$1, element)); - - const isBr = isTag('br'); - const gatherer = (cand, gather, isRoot) => { - return gather(cand, isRoot).bind(target => { - return isText(target) && get$6(target).trim().length === 0 ? gatherer(target, gather, isRoot) : Optional.some(target); - }); - }; - const handleBr = (isRoot, element, direction) => { - return direction.traverse(element).orThunk(() => { - return gatherer(element, direction.gather, isRoot); - }).map(direction.relative); + const bisect = (universe, parent, child) => { + const children = universe.property().children(parent); + const index = findIndex(children, curry(universe.eq, child)); + return index.map((ind) => { + return { + before: children.slice(0, ind), + after: children.slice(ind + 1) + }; + }); }; - const findBr = (element, offset) => { - return child$2(element, offset).filter(isBr).orThunk(() => { - return child$2(element, offset - 1).filter(isBr); - }); + /** + * Clone parent to the RIGHT and move everything after child in the parent element into + * a clone of the parent (placed after parent). + */ + const breakToRight = (universe, parent, child) => { + return bisect(universe, parent, child).map((parts) => { + const second = universe.create().clone(parent); + universe.insert().appendAll(second, parts.after); + universe.insert().after(parent, second); + return leftRight(parent, second); + }); }; - const handleParent = (isRoot, element, offset, direction) => { - return findBr(element, offset).bind(br => { - return direction.traverse(br).fold(() => { - return gatherer(br, direction.gather, isRoot).map(direction.relative); - }, adjacent => { - return indexInParent(adjacent).map(info => { - return Situ.on(info.parent, info.index); - }); + /** + * Clone parent to the LEFT and move everything before and including child into + * the a clone of the parent (placed before parent) + */ + const breakToLeft = (universe, parent, child) => { + return bisect(universe, parent, child).map((parts) => { + const prior = universe.create().clone(parent); + universe.insert().appendAll(prior, parts.before.concat([child])); + universe.insert().appendAll(parent, parts.after); + universe.insert().before(parent, prior); + return leftRight(prior, parent); }); - }); }; - const tryBr = (isRoot, element, offset, direction) => { - const target = isBr(element) ? handleBr(isRoot, element, direction) : handleParent(isRoot, element, offset, direction); - return target.map(tgt => { - return { - start: tgt, - finish: tgt + /* + * Using the breaker, break from the child up to the top element defined by the predicate. + * It returns three values: + * first: the top level element that completed the break + * second: the optional element representing second part of the top-level split if the breaking completed successfully to the top + * splits: a list of (Element, Element) pairs that represent the splits that have occurred on the way to the top. + */ + const breakPath = (universe, item, isTop, breaker) => { + const next = (child, group, splits) => { + const fallback = brokenPath(child, Optional.none(), splits); + // Found the top, so stop. + if (isTop(child)) { + return brokenPath(child, group, splits); + } + else { + // Split the child at parent, and keep going + return universe.property().parent(child).bind((parent) => { + return breaker(universe, parent, child).map((breakage) => { + const extra = [{ first: breakage.left, second: breakage.right }]; + // Our isTop is based on the left-side parent, so keep it regardless of split. + const nextChild = isTop(parent) ? parent : breakage.left; + return next(nextChild, Optional.some(breakage.right), splits.concat(extra)); + }); + }).getOr(fallback); + } }; - }); - }; - const process = analysis => { - return BeforeAfter.cata(analysis, _message => { - return Optional.none(); - }, () => { - return Optional.none(); - }, cell => { - return Optional.some(point(cell, 0)); - }, cell => { - return Optional.some(point(cell, getEnd(cell))); - }); + return next(item, Optional.none(), []); }; - const moveDown = (caret, amount) => { - return { - left: caret.left, - top: caret.top + amount, - right: caret.right, - bottom: caret.bottom + amount - }; - }; - const moveUp = (caret, amount) => { - return { - left: caret.left, - top: caret.top - amount, - right: caret.right, - bottom: caret.bottom - amount - }; + const all = (universe, look, elements, f) => { + const head = elements[0]; + const tail = elements.slice(1); + return f(universe, look, head, tail); }; - const translate = (caret, xDelta, yDelta) => { - return { - left: caret.left + xDelta, - top: caret.top + yDelta, - right: caret.right + xDelta, - bottom: caret.bottom + yDelta - }; + /** + * Check if look returns the same element for all elements, and return it if it exists. + */ + const oneAll = (universe, look, elements) => { + return elements.length > 0 ? + all(universe, look, elements, unsafeOne) : + Optional.none(); }; - const getTop = caret => { - return caret.top; + const unsafeOne = (universe, look, head, tail) => { + const start = look(universe, head); + return foldr(tail, (b, a) => { + const current = look(universe, a); + return commonElement(universe, b, current); + }, start); }; - const getBottom = caret => { - return caret.bottom; + const commonElement = (universe, start, end) => { + return start.bind((s) => { + return end.filter(curry(universe.eq, s)); + }); }; - const getPartialBox = (bridge, element, offset) => { - if (offset >= 0 && offset < getEnd(element)) { - return bridge.getRangedRect(element, offset, element, offset + 1); - } else if (offset > 0) { - return bridge.getRangedRect(element, offset - 1, element, offset); - } - return Optional.none(); - }; - const toCaret = rect => ({ - left: rect.left, - top: rect.top, - right: rect.right, - bottom: rect.bottom - }); - const getElemBox = (bridge, element) => { - return Optional.some(bridge.getRect(element)); - }; - const getBoxAt = (bridge, element, offset) => { - if (isElement(element)) { - return getElemBox(bridge, element).map(toCaret); - } else if (isText(element)) { - return getPartialBox(bridge, element, offset).map(toCaret); - } else { - return Optional.none(); - } + const eq = (universe, item) => { + return curry(universe.eq, item); }; - const getEntireBox = (bridge, element) => { - if (isElement(element)) { - return getElemBox(bridge, element).map(toCaret); - } else if (isText(element)) { - return bridge.getRangedRect(element, 0, element, getEnd(element)).map(toCaret); - } else { - return Optional.none(); - } + // Note: this can be exported if it is required in the future. + const ancestors$2 = (universe, start, end, isRoot = never) => { + // Inefficient if no isRoot is supplied. + // TODO: Andy knows there is a graph-based algorithm to find a common parent, but can't remember it + // This also includes something to get the subset after finding the common parent + const ps1 = [start].concat(universe.up().all(start)); + const ps2 = [end].concat(universe.up().all(end)); + const prune = (path) => { + const index = findIndex(path, isRoot); + return index.fold(() => { + return path; + }, (ind) => { + return path.slice(0, ind + 1); + }); + }; + const pruned1 = prune(ps1); + const pruned2 = prune(ps2); + const shared = find$1(pruned1, (x) => { + return exists(pruned2, eq(universe, x)); + }); + return { + firstpath: pruned1, + secondpath: pruned2, + shared + }; }; - const JUMP_SIZE = 5; - const NUM_RETRIES = 100; - const adt$1 = Adt.generate([ - { none: [] }, - { retry: ['caret'] } - ]); - const isOutside = (caret, box) => { - return caret.left < box.left || Math.abs(box.right - caret.left) < 1 || caret.left > box.right; - }; - const inOutsideBlock = (bridge, element, caret) => { - return closest$2(element, isBlock).fold(never, cell => { - return getEntireBox(bridge, cell).exists(box => { - return isOutside(caret, box); - }); - }); + const sharedOne$1 = oneAll; + const ancestors$1 = ancestors$2; + breakToLeft; + breakToRight; + breakPath; + + const universe$1 = DomUniverse(); + const sharedOne = (look, elements) => { + return sharedOne$1(universe$1, (_universe, element) => { + return look(element); + }, elements); }; - const adjustDown = (bridge, element, guessBox, original, caret) => { - const lowerCaret = moveDown(caret, JUMP_SIZE); - if (Math.abs(guessBox.bottom - original.bottom) < 1) { - return adt$1.retry(lowerCaret); - } else if (guessBox.top > caret.bottom) { - return adt$1.retry(lowerCaret); - } else if (guessBox.top === caret.bottom) { - return adt$1.retry(moveDown(caret, 1)); - } else { - return inOutsideBlock(bridge, element, caret) ? adt$1.retry(translate(lowerCaret, JUMP_SIZE, 0)) : adt$1.none(); - } + const ancestors = (start, finish, isRoot) => { + return ancestors$1(universe$1, start, finish, isRoot); }; - const adjustUp = (bridge, element, guessBox, original, caret) => { - const higherCaret = moveUp(caret, JUMP_SIZE); - if (Math.abs(guessBox.top - original.top) < 1) { - return adt$1.retry(higherCaret); - } else if (guessBox.bottom < caret.top) { - return adt$1.retry(higherCaret); - } else if (guessBox.bottom === caret.top) { - return adt$1.retry(moveUp(caret, 1)); - } else { - return inOutsideBlock(bridge, element, caret) ? adt$1.retry(translate(higherCaret, JUMP_SIZE, 0)) : adt$1.none(); - } + + const universe = DomUniverse(); + const isBlock = (element) => { + return isBlock$1(universe, element); }; - const upMovement = { - point: getTop, - adjuster: adjustUp, - move: moveUp, - gather: before + const isList = (element) => { + return isList$1(universe, element); }; - const downMovement = { - point: getBottom, - adjuster: adjustDown, - move: moveDown, - gather: after$1 + const isEmptyTag = (element) => { + return isEmptyTag$1(universe, element); }; - const isAtTable = (bridge, x, y) => { - return bridge.elementFromPoint(x, y).filter(elm => { - return name(elm) === 'table'; - }).isSome(); + + const merge$2 = (cells) => { + const isBr = isTag('br'); + const advancedBr = (children) => { + return forall(children, (c) => { + return isBr(c) || (isText(c) && get$5(c).trim().length === 0); + }); + }; + const isListItem = (el) => { + return name(el) === 'li' || ancestor$2(el, isList).isSome(); + }; + const siblingIsBlock = (el) => { + return nextSibling(el).map((rightSibling) => { + if (isBlock(rightSibling)) { + return true; + } + if (isEmptyTag(rightSibling)) { + return name(rightSibling) === 'img' ? false : true; + } + return false; + }).getOr(false); + }; + const markCell = (cell) => { + return last(cell).bind((rightEdge) => { + const rightSiblingIsBlock = siblingIsBlock(rightEdge); + return parent(rightEdge).map((parent) => { + return rightSiblingIsBlock === true || isListItem(parent) || isBr(rightEdge) || (isBlock(parent) && !eq$1(cell, parent)) ? [] : [SugarElement.fromTag('br')]; + }); + }).getOr([]); + }; + const markContent = () => { + const content = bind$2(cells, (cell) => { + const children = children$2(cell); + return advancedBr(children) ? [] : children.concat(markCell(cell)); + }); + return content.length === 0 ? [SugarElement.fromTag('br')] : content; + }; + const contents = markContent(); + empty(cells[0]); + append(cells[0], contents); + }; + + // Remove legacy sizing attributes such as "width" + const cleanupLegacyAttributes = (element) => { + remove$6(element, 'width'); + remove$6(element, 'height'); + }; + const convertToPercentSizeWidth = (table) => { + const newWidth = getPercentTableWidth(table); + redistribute(table, Optional.some(newWidth), Optional.none()); + cleanupLegacyAttributes(table); + }; + const convertToPixelSizeWidth = (table) => { + const newWidth = getPixelTableWidth(table); + redistribute(table, Optional.some(newWidth), Optional.none()); + cleanupLegacyAttributes(table); + }; + const convertToPixelSizeHeight = (table) => { + const newHeight = getPixelTableHeight(table); + redistribute(table, Optional.none(), Optional.some(newHeight)); + cleanupLegacyAttributes(table); + }; + const convertToNoneSizeWidth = (table) => { + remove$4(table, 'width'); + const columns = columns$1(table); + const rowElements = columns.length > 0 ? columns : cells$1(table); + each$2(rowElements, (cell) => { + remove$4(cell, 'width'); + cleanupLegacyAttributes(cell); + }); + cleanupLegacyAttributes(table); }; - const adjustForTable = (bridge, movement, original, caret, numRetries) => { - return adjustTil(bridge, movement, original, movement.move(caret, JUMP_SIZE), numRetries); + + const transferableAttributes = { + scope: [ + 'row', + 'col' + ] }; - const adjustTil = (bridge, movement, original, caret, numRetries) => { - if (numRetries === 0) { - return Optional.some(caret); - } - if (isAtTable(bridge, caret.left, movement.point(caret))) { - return adjustForTable(bridge, movement, original, caret, numRetries - 1); - } - return bridge.situsFromPoint(caret.left, movement.point(caret)).bind(guess => { - return guess.start.fold(Optional.none, element => { - return getEntireBox(bridge, element).bind(guessBox => { - return movement.adjuster(bridge, element, guessBox, original, caret).fold(Optional.none, newCaret => { - return adjustTil(bridge, movement, original, newCaret, numRetries - 1); - }); - }).orThunk(() => { - return Optional.some(caret); - }); - }, Optional.none); - }); + // NOTE: This may create a td instead of a th, but it is for irregular table handling. + const createCell = (doc) => () => { + const td = SugarElement.fromTag('td', doc.dom); + append$1(td, SugarElement.fromTag('br', doc.dom)); + return td; }; - const checkScroll = (movement, adjusted, bridge) => { - if (movement.point(adjusted) > bridge.getInnerHeight()) { - return Optional.some(movement.point(adjusted) - bridge.getInnerHeight()); - } else if (movement.point(adjusted) < 0) { - return Optional.some(-movement.point(adjusted)); - } else { - return Optional.none(); - } + const createCol = (doc) => () => { + return SugarElement.fromTag('col', doc.dom); }; - const retry = (movement, bridge, caret) => { - const moved = movement.move(caret, JUMP_SIZE); - const adjusted = adjustTil(bridge, movement, caret, moved, NUM_RETRIES).getOr(moved); - return checkScroll(movement, adjusted, bridge).fold(() => { - return bridge.situsFromPoint(adjusted.left, movement.point(adjusted)); - }, delta => { - bridge.scrollBy(0, delta); - return bridge.situsFromPoint(adjusted.left, movement.point(adjusted) - delta); - }); + const createColgroup = (doc) => () => { + return SugarElement.fromTag('colgroup', doc.dom); }; - const Retries = { - tryUp: curry(retry, upMovement), - tryDown: curry(retry, downMovement), - getJumpSize: constant(JUMP_SIZE) + const createRow$1 = (doc) => () => { + return SugarElement.fromTag('tr', doc.dom); }; - - const MAX_RETRIES = 20; - const findSpot = (bridge, isRoot, direction) => { - return bridge.getSelection().bind(sel => { - return tryBr(isRoot, sel.finish, sel.foffset, direction).fold(() => { - return Optional.some(point(sel.finish, sel.foffset)); - }, brNeighbour => { - const range = bridge.fromSitus(brNeighbour); - const analysis = BeforeAfter.verify(bridge, sel.finish, sel.foffset, range.finish, range.foffset, direction.failure, isRoot); - return process(analysis); + const replace$1 = (cell, tag, attrs) => { + const replica = copy$2(cell, tag); + // TODO: Snooker passes null to indicate 'remove attribute' + each$1(attrs, (v, k) => { + if (v === null) { + remove$6(replica, k); + } + else { + set$2(replica, k, v); + } }); - }); + return replica; }; - const scan = (bridge, isRoot, element, offset, direction, numRetries) => { - if (numRetries === 0) { - return Optional.none(); - } - return tryCursor(bridge, isRoot, element, offset, direction).bind(situs => { - const range = bridge.fromSitus(situs); - const analysis = BeforeAfter.verify(bridge, element, offset, range.finish, range.foffset, direction.failure, isRoot); - return BeforeAfter.cata(analysis, () => { - return Optional.none(); - }, () => { - return Optional.some(situs); - }, cell => { - if (eq$1(element, cell) && offset === 0) { - return tryAgain(bridge, element, offset, moveUp, direction); - } else { - return scan(bridge, isRoot, cell, 0, direction, numRetries - 1); - } - }, cell => { - if (eq$1(element, cell) && offset === getEnd(cell)) { - return tryAgain(bridge, element, offset, moveDown, direction); - } else { - return scan(bridge, isRoot, cell, getEnd(cell), direction, numRetries - 1); - } - }); - }); + // eslint-disable-next-line @tinymce/prefer-fun + const pasteReplace = (cell) => { + // TODO: check for empty content and don't return anything + return cell; }; - const tryAgain = (bridge, element, offset, move, direction) => { - return getBoxAt(bridge, element, offset).bind(box => { - return tryAt(bridge, direction, move(box, Retries.getJumpSize())); - }); + const cloneFormats = (oldCell, newCell, formats) => { + const first$1 = first(oldCell); + return first$1.map((firstText) => { + const formatSelector = formats.join(','); + // Find the ancestors of the first text node that match the given formats. + const parents = ancestors$3(firstText, formatSelector, (element) => { + return eq$1(element, oldCell); + }); + // Add the matched ancestors to the new cell, then return the new cell. + return foldr(parents, (last, parent) => { + const clonedFormat = shallow(parent); + append$1(last, clonedFormat); + return clonedFormat; + }, newCell); + }).getOr(newCell); }; - const tryAt = (bridge, direction, box) => { - const browser = detect$2().browser; - if (browser.isChromium() || browser.isSafari() || browser.isFirefox()) { - return direction.retry(bridge, box); - } else { - return Optional.none(); - } + const cloneAppropriateAttributes = (original, clone) => { + each$1(transferableAttributes, (validAttributes, attributeName) => getOpt(original, attributeName) + .filter((attribute) => contains$2(validAttributes, attribute)) + .each((attribute) => set$2(clone, attributeName, attribute))); }; - const tryCursor = (bridge, isRoot, element, offset, direction) => { - return getBoxAt(bridge, element, offset).bind(box => { - return tryAt(bridge, direction, box); - }); + const cellOperations = (mutate, doc, formatsToClone) => { + const cloneCss = (prev, clone) => { + // inherit the style and width, dont inherit the row height + copy$1(prev.element, clone); + remove$4(clone, 'height'); + // dont inherit the width of spanning columns + if (prev.colspan !== 1) { + remove$4(clone, 'width'); + } + }; + const newCell = (prev) => { + const td = SugarElement.fromTag(name(prev.element), doc.dom); + const formats = formatsToClone.getOr(['strong', 'em', 'b', 'i', 'span', 'font', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div']); + // If we aren't cloning the child formatting, we can just give back the new td immediately. + const lastNode = formats.length > 0 ? cloneFormats(prev.element, td, formats) : td; + append$1(lastNode, SugarElement.fromTag('br')); + cloneCss(prev, td); + cloneAppropriateAttributes(prev.element, td); + mutate(prev.element, td); + return td; + }; + const newCol = (prev) => { + const col = SugarElement.fromTag(name(prev.element), doc.dom); + cloneCss(prev, col); + mutate(prev.element, col); + return col; + }; + return { + col: newCol, + colgroup: createColgroup(doc), + row: createRow$1(doc), + cell: newCell, + replace: replace$1, + colGap: createCol(doc), + gap: createCell(doc) + }; }; - const handle$1 = (bridge, isRoot, direction) => { - return findSpot(bridge, isRoot, direction).bind(spot => { - return scan(bridge, isRoot, spot.element, spot.offset, direction, MAX_RETRIES).map(bridge.fromSitus); - }); + const paste$1 = (doc) => { + return { + col: createCol(doc), + colgroup: createColgroup(doc), + row: createRow$1(doc), + cell: createCell(doc), + replace: pasteReplace, + colGap: createCol(doc), + gap: createCell(doc) + }; }; - const inSameTable = (elem, table) => { - return ancestor(elem, e => { - return parent(e).exists(p => { - return eq$1(p, table); - }); - }); + const getGridSize = (table) => { + const warehouse = Warehouse.fromTable(table); + return warehouse.grid; }; - const simulate = (bridge, isRoot, direction, initial, anchor) => { - return closest$1(initial, 'td,th', isRoot).bind(start => { - return closest$1(start, 'table', isRoot).bind(table => { - if (!inSameTable(anchor, table)) { - return Optional.none(); - } - return handle$1(bridge, isRoot, direction).bind(range => { - return closest$1(range.finish, 'td,th', isRoot).map(finish => { - return { - start, - finish, - range - }; - }); - }); - }); - }); + + // substitution: () -> item + const merge$1 = (grid, bounds, comparator, substitution) => { + const rows = extractGridDetails(grid).rows; + // Mutating. Do we care about the efficiency gain? + if (rows.length === 0) { + return grid; + } + for (let i = bounds.startRow; i <= bounds.finishRow; i++) { + for (let j = bounds.startCol; j <= bounds.finishCol; j++) { + // We can probably simplify this again now that we aren't reusing merge. + const row = rows[i]; + const isLocked = getCell(row, j).isLocked; + mutateCell(row, j, elementnew(substitution(), false, isLocked)); + } + } + return grid; }; - const navigate = (bridge, isRoot, direction, initial, anchor, precheck) => { - return precheck(initial, isRoot).orThunk(() => { - return simulate(bridge, isRoot, direction, initial, anchor).map(info => { - const range = info.range; - return Response.create(Optional.some(makeSitus(range.start, range.soffset, range.finish, range.foffset)), true); - }); - }); + // substitution: () -> item + const unmerge = (grid, target, comparator, substitution) => { + const rows = extractGridDetails(grid).rows; + // Mutating. Do we care about the efficiency gain? + let first = true; + // tslint:disable-next-line:prefer-for-of + for (let i = 0; i < rows.length; i++) { + for (let j = 0; j < cellLength(rows[0]); j++) { + const row = rows[i]; + const currentCell = getCell(row, j); + const currentCellElm = currentCell.element; + const isToReplace = comparator(currentCellElm, target); + if (isToReplace && !first) { + mutateCell(row, j, elementnew(substitution(), true, currentCell.isLocked)); + } + else if (isToReplace) { + first = false; + } + } + } + return grid; }; - const firstUpCheck = (initial, isRoot) => { - return closest$1(initial, 'tr', isRoot).bind(startRow => { - return closest$1(startRow, 'table', isRoot).bind(table => { - const rows = descendants(table, 'tr'); - if (eq$1(startRow, rows[0])) { - return seekLeft(table, element => { - return last$1(element).isSome(); - }, isRoot).map(last => { - const lastOffset = getEnd(last); - return Response.create(Optional.some(makeSitus(last, lastOffset, last, lastOffset)), true); - }); - } else { - return Optional.none(); - } - }); - }); + const uniqueCells = (row, comparator) => { + return foldl(row, (rest, cell) => { + return exists(rest, (currentCell) => { + return comparator(currentCell.element, cell.element); + }) ? rest : rest.concat([cell]); + }, []); }; - const lastDownCheck = (initial, isRoot) => { - return closest$1(initial, 'tr', isRoot).bind(startRow => { - return closest$1(startRow, 'table', isRoot).bind(table => { - const rows = descendants(table, 'tr'); - if (eq$1(startRow, rows[rows.length - 1])) { - return seekRight(table, element => { - return first(element).isSome(); - }, isRoot).map(first => { - return Response.create(Optional.some(makeSitus(first, 0, first, 0)), true); + const splitCols = (grid, index, comparator, substitution) => { + // We don't need to split rows if we're inserting at the first or last row of the old table + if (index > 0 && index < grid[0].cells.length) { + each$2(grid, (row) => { + const prevCell = row.cells[index - 1]; + let offset = 0; + const substitute = substitution(); + while (row.cells.length > index + offset && comparator(prevCell.element, row.cells[index + offset].element)) { + mutateCell(row, index + offset, elementnew(substitute, true, row.cells[index + offset].isLocked)); + offset++; + } }); - } else { - return Optional.none(); - } - }); - }); - }; - const select = (bridge, container, isRoot, direction, initial, anchor, selectRange) => { - return simulate(bridge, isRoot, direction, initial, anchor).bind(info => { - return detect(container, isRoot, info.start, info.finish, selectRange); - }); - }; - - const Cell = initial => { - let value = initial; - const get = () => { - return value; - }; - const set = v => { - value = v; - }; - return { - get, - set - }; - }; - - const singleton = doRevoke => { - const subject = Cell(Optional.none()); - const revoke = () => subject.get().each(doRevoke); - const clear = () => { - revoke(); - subject.set(Optional.none()); - }; - const isSet = () => subject.get().isSome(); - const get = () => subject.get(); - const set = s => { - revoke(); - subject.set(Optional.some(s)); - }; - return { - clear, - isSet, - get, - set - }; - }; - const value = () => { - const subject = singleton(noop); - const on = f => subject.get().each(f); - return { - ...subject, - on - }; + } + return grid; }; - - const findCell = (target, isRoot) => closest$1(target, 'td,th', isRoot); - const isInEditableContext = cell => parentElement(cell).exists(isEditable$1); - const MouseSelection = (bridge, container, isRoot, annotations) => { - const cursor = value(); - const clearstate = cursor.clear; - const applySelection = event => { - cursor.on(start => { - annotations.clearBeforeUpdate(container); - findCell(event.target, isRoot).each(finish => { - identify(start, finish, isRoot).each(cellSel => { - const boxes = cellSel.boxes.getOr([]); - if (boxes.length === 1) { - const singleCell = boxes[0]; - const isNonEditableCell = getRaw(singleCell) === 'false'; - const isCellClosestContentEditable = is(closest(event.target), singleCell, eq$1); - if (isNonEditableCell && isCellClosestContentEditable) { - annotations.selectRange(container, boxes, singleCell, singleCell); + const splitRows = (grid, index, comparator, substitution) => { + // We don't need to split rows if we're inserting at the first or last row of the old table + const rows = extractGridDetails(grid).rows; + if (index > 0 && index < rows.length) { + const rowPrevCells = rows[index - 1].cells; + const cells = uniqueCells(rowPrevCells, comparator); + each$2(cells, (cell) => { + // only make a sub when we have to + let replacement = Optional.none(); + for (let i = index; i < rows.length; i++) { + for (let j = 0; j < cellLength(rows[0]); j++) { + const row = rows[i]; + const current = getCell(row, j); + const isToReplace = comparator(current.element, cell.element); + if (isToReplace) { + if (replacement.isNone()) { + replacement = Optional.some(substitution()); + } + replacement.each((sub) => { + mutateCell(row, j, elementnew(sub, true, current.isLocked)); + }); + } + } } - } else if (boxes.length > 1) { - annotations.selectRange(container, boxes, cellSel.start, cellSel.finish); - bridge.selectContents(finish); - } }); - }); - }); - }; - const mousedown = event => { - annotations.clear(container); - findCell(event.target, isRoot).filter(isInEditableContext).each(cursor.set); - }; - const mouseover = event => { - applySelection(event); - }; - const mouseup = event => { - applySelection(event); - clearstate(); - }; - return { - clearstate, - mousedown, - mouseover, - mouseup - }; + } + return grid; }; - const down = { - traverse: nextSibling, - gather: after$1, - relative: Situ.before, - retry: Retries.tryDown, - failure: BeforeAfter.failedDown - }; - const up = { - traverse: prevSibling, - gather: before, - relative: Situ.before, - retry: Retries.tryUp, - failure: BeforeAfter.failedUp - }; + /* + Fitment, is a module used to ensure that the Inserted table (gridB) can fit squareley within the Host table (gridA). + - measure returns a delta of rows and cols, eg: + - col: 3 means gridB can fit with 3 spaces to spare + - row: -5 means gridB can needs 5 more rows to completely fit into gridA + - col: 0, row: 0 depics perfect fitment - const isKey = key => { - return keycode => { - return keycode === key; - }; - }; - const isUp = isKey(38); - const isDown = isKey(40); - const isNavigation = keycode => { - return keycode >= 37 && keycode <= 40; + - tailor, requires a delta and returns grid that is built to match the delta, tailored to fit. + eg: 3x3 gridA, with a delta col: -3, row: 2 returns a new grid 3 rows x 6 cols + + - assumptions: All grids used by this module should be rectangular + */ + const measure = (startAddress, gridA, gridB) => { + if (startAddress.row >= gridA.length || startAddress.column > cellLength(gridA[0])) { + return Result.error('invalid start address out of table bounds, row: ' + startAddress.row + ', column: ' + startAddress.column); + } + const rowRemainder = gridA.slice(startAddress.row); + const colRemainder = rowRemainder[0].cells.slice(startAddress.column); + const colRequired = cellLength(gridB[0]); + const rowRequired = gridB.length; + return Result.value({ + rowDelta: rowRemainder.length - rowRequired, + colDelta: colRemainder.length - colRequired + }); }; - const ltr = { - isBackward: isKey(37), - isForward: isKey(39) + const measureWidth = (gridA, gridB) => { + const colLengthA = cellLength(gridA[0]); + const colLengthB = cellLength(gridB[0]); + return { + rowDelta: 0, + colDelta: colLengthA - colLengthB + }; }; - const rtl = { - isBackward: isKey(39), - isForward: isKey(37) + const measureHeight = (gridA, gridB) => { + const rowLengthA = gridA.length; + const rowLengthB = gridB.length; + return { + rowDelta: rowLengthA - rowLengthB, + colDelta: 0 + }; }; - - const get$3 = _DOC => { - const doc = _DOC !== undefined ? _DOC.dom : document; - const x = doc.body.scrollLeft || doc.documentElement.scrollLeft; - const y = doc.body.scrollTop || doc.documentElement.scrollTop; - return SugarPosition(x, y); + const generateElements = (amount, row, generators, isLocked) => { + const generator = row.section === 'colgroup' ? generators.col : generators.cell; + return range$1(amount, (idx) => elementnew(generator(), true, isLocked(idx))); }; - const by = (x, y, _DOC) => { - const doc = _DOC !== undefined ? _DOC.dom : document; - const win = doc.defaultView; - if (win) { - win.scrollBy(x, y); - } + const rowFill = (grid, amount, generators, lockedColumns) => { + const exampleRow = grid[grid.length - 1]; + return grid.concat(range$1(amount, () => { + const generator = exampleRow.section === 'colgroup' ? generators.colgroup : generators.row; + const row = clone$2(exampleRow, generator, identity); + const elements = generateElements(row.cells.length, row, generators, (idx) => has$1(lockedColumns, idx.toString())); + return setCells(row, elements); + })); }; - - const adt = Adt.generate([ - { domRange: ['rng'] }, - { - relative: [ - 'startSitu', - 'finishSitu' - ] - }, - { - exact: [ - 'start', - 'soffset', - 'finish', - 'foffset' - ] - } - ]); - const exactFromRange = simRange => adt.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset); - const getStart = selection => selection.match({ - domRange: rng => SugarElement.fromDom(rng.startContainer), - relative: (startSitu, _finishSitu) => Situ.getStart(startSitu), - exact: (start, _soffset, _finish, _foffset) => start + const colFill = (grid, amount, generators, startIndex) => map$1(grid, (row) => { + const newChildren = generateElements(amount, row, generators, never); + return addCells(row, startIndex, newChildren); }); - const domRange = adt.domRange; - const relative = adt.relative; - const exact = adt.exact; - const getWin = selection => { - const start = getStart(selection); - return defaultView(start); - }; - const range = SimRange.create; - const SimSelection = { - domRange, - relative, - exact, - exactFromRange, - getWin, - range + const lockedColFill = (grid, generators, lockedColumns) => map$1(grid, (row) => { + return foldl(lockedColumns, (acc, colNum) => { + const newChild = generateElements(1, row, generators, always)[0]; + return addCell(acc, colNum, newChild); + }, row); + }); + const tailor = (gridA, delta, generators) => { + const fillCols = delta.colDelta < 0 ? colFill : identity; + const fillRows = delta.rowDelta < 0 ? rowFill : identity; + const lockedColumns = getLockedColumnsFromGrid(gridA); + const gridWidth = cellLength(gridA[0]); + const isLastColLocked = exists(lockedColumns, (locked) => locked === gridWidth - 1); + const modifiedCols = fillCols(gridA, Math.abs(delta.colDelta), generators, isLastColLocked ? gridWidth - 1 : gridWidth); + // Need to recalculate locked column positions + const newLockedColumns = getLockedColumnsFromGrid(modifiedCols); + return fillRows(modifiedCols, Math.abs(delta.rowDelta), generators, mapToObject(newLockedColumns, always)); }; - const caretPositionFromPoint = (doc, x, y) => { - var _a; - return Optional.from((_a = doc.caretPositionFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)).bind(pos => { - if (pos.offsetNode === null) { - return Optional.none(); - } - const r = doc.createRange(); - r.setStart(pos.offsetNode, pos.offset); - r.collapse(); - return Optional.some(r); - }); - }; - const caretRangeFromPoint = (doc, x, y) => { - var _a; - return Optional.from((_a = doc.caretRangeFromPoint) === null || _a === void 0 ? void 0 : _a.call(doc, x, y)); + const isSpanning = (grid, row, col, comparator) => { + const candidate = getCell(grid[row], col); + const matching = curry(comparator, candidate.element); + const currentRow = grid[row]; + // sanity check, 1x1 has no spans + return grid.length > 1 && cellLength(currentRow) > 1 && + ( + // search left, if we're not on the left edge + // search down, if we're not on the bottom edge + (col > 0 && matching(getCellElement(currentRow, col - 1))) || + // search right, if we're not on the right edge + (col < currentRow.cells.length - 1 && matching(getCellElement(currentRow, col + 1))) || + // search up, if we're not on the top edge + (row > 0 && matching(getCellElement(grid[row - 1], col))) || + (row < grid.length - 1 && matching(getCellElement(grid[row + 1], col)))); }; - const availableSearch = (doc, x, y) => { - if (doc.caretPositionFromPoint) { - return caretPositionFromPoint(doc, x, y); - } else if (doc.caretRangeFromPoint) { - return caretRangeFromPoint(doc, x, y); - } else { - return Optional.none(); - } + const mergeTables = (startAddress, gridA, gridBRows, generator, comparator, lockedColumns) => { + // Assumes + // - gridA is square and gridB is square + const startRow = startAddress.row; + const startCol = startAddress.column; + const mergeHeight = gridBRows.length; + const mergeWidth = cellLength(gridBRows[0]); + const endRow = startRow + mergeHeight; + const endCol = startCol + mergeWidth + lockedColumns.length; + const lockedColumnObj = mapToObject(lockedColumns, always); + // embrace the mutation - I think this is easier to follow? To discuss. + for (let r = startRow; r < endRow; r++) { + let skippedCol = 0; + for (let c = startCol; c < endCol; c++) { + if (lockedColumnObj[c]) { + skippedCol++; + continue; + } + if (isSpanning(gridA, r, c, comparator)) { + // mutation within mutation, it's mutatception + unmerge(gridA, getCellElement(gridA[r], c), comparator, generator.cell); + } + const gridBColIndex = c - startCol - skippedCol; + const newCell = getCell(gridBRows[r - startRow], gridBColIndex); + // This can't be a col element at this point so we can cast it to a cell + const newCellElm = newCell.element; + const replacement = generator.replace(newCellElm); + mutateCell(gridA[r], c, elementnew(replacement, true, newCell.isLocked)); + } + } + return gridA; }; - const fromPoint = (win, x, y) => { - const doc = win.document; - return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset)); + const getValidStartAddress = (currentStartAddress, grid, lockedColumns) => { + const gridColLength = cellLength(grid[0]); + /* + When we paste from a table without colgroups to a table that has them, we need to ensure we are inserting them at + the correct row index (the `col`s are treated as cells in the Structs.RowCells array). + + To do this, we get the number of `col`s in the destination table and add that to the startAddress row. + */ + const adjustedRowAddress = extractGridDetails(grid).cols.length + currentStartAddress.row; + const possibleColAddresses = range$1(gridColLength - currentStartAddress.column, (num) => num + currentStartAddress.column); + // Find a starting column address that isn't a locked column + const validColAddress = find$1(possibleColAddresses, (num) => forall(lockedColumns, (col) => col !== num)).getOr(gridColLength - 1); + return { + row: adjustedRowAddress, + column: validColAddress + }; }; - - const beforeSpecial = (element, offset) => { - const name$1 = name(element); - if ('input' === name$1) { - return Situ.after(element); - } else if (!contains$2([ - 'br', - 'img' - ], name$1)) { - return Situ.on(element, offset); - } else { - return offset === 0 ? Situ.before(element) : Situ.after(element); - } + const getLockedColumnsWithinBounds = (startAddress, rows, lockedColumns) => filter$2(lockedColumns, (colNum) => colNum >= startAddress.column && colNum <= cellLength(rows[0]) + startAddress.column); + const merge = (startAddress, gridA, gridB, generator, comparator) => { + const lockedColumns = getLockedColumnsFromGrid(gridA); + const validStartAddress = getValidStartAddress(startAddress, gridA, lockedColumns); + /* + We always remove the cols (extract the rows) from the table being pasted. This ensures that if we are pasting from a table with colgroups into a table + without them, we don't insert the `col` elements as if they were `td`s + */ + const gridBRows = extractGridDetails(gridB).rows; + const lockedColumnsWithinBounds = getLockedColumnsWithinBounds(validStartAddress, gridBRows, lockedColumns); + const result = measure(validStartAddress, gridA, gridBRows); + /* + Need to subtract extra delta for locked columns between startAddress and the startAddress + gridB column count as + locked column cells cannot be merged into. Therefore, extra column cells need to be added to gridA to allow gridB cells to be merged + */ + return result.map((diff) => { + const delta = { + ...diff, + colDelta: diff.colDelta - lockedColumnsWithinBounds.length + }; + const fittedGrid = tailor(gridA, delta, generator); + // Need to recalculate lockedColumnsWithinBounds as tailoring may have inserted columns before last locked column which changes the locked index + const newLockedColumns = getLockedColumnsFromGrid(fittedGrid); + const newLockedColumnsWithinBounds = getLockedColumnsWithinBounds(validStartAddress, gridBRows, newLockedColumns); + return mergeTables(validStartAddress, fittedGrid, gridBRows, generator, comparator, newLockedColumnsWithinBounds); + }); }; - const preprocessRelative = (startSitu, finishSitu) => { - const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after); - const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after); - return SimSelection.relative(start, finish); + const insertCols = (index, gridA, gridB, generator, comparator) => { + splitCols(gridA, index, comparator, generator.cell); + const delta = measureHeight(gridB, gridA); + const fittedNewGrid = tailor(gridB, delta, generator); + const secondDelta = measureHeight(gridA, fittedNewGrid); + const fittedOldGrid = tailor(gridA, secondDelta, generator); + return map$1(fittedOldGrid, (gridRow, i) => { + return addCells(gridRow, index, fittedNewGrid[i].cells); + }); }; - const preprocessExact = (start, soffset, finish, foffset) => { - const startSitu = beforeSpecial(start, soffset); - const finishSitu = beforeSpecial(finish, foffset); - return SimSelection.relative(startSitu, finishSitu); + /* + Inserting rows with locked columns + - Tailor gridA first (this needs to be done first as the position of the locked columns may change when tailoring gridA and the location of the locked columns needs to be stable before tailoring gridB) + - measure delta between gridA and gridB (pasted rows) - if negative colDelta, gridA needs extra columns added to match gridB + - need to calculate how many columns in gridB cannot be directly inserted into gridA - this is how many extra columns need to be added to gridA (this consideres the fact locked column cannot be inserted into) + - nonLockedGridA + lockedGridA - gridB = colDelta (By subtracting locked column count, can get required diff) + - tailor gridA by adding the required extra columns if necessary either at the end of gridA or before the last column depending on whether it is locked + - Recalculate where the locked columns are in gridA after tailoring + - Measure and determine if extra columns need to be added to gridB (locked columns should not count towards the delta as colFilling (adding extra columns) for locked columns is handled separately) + - Do a lockedColFill on gridB + - Tailor gridB by adding extra columns to end of gridB if required + */ + const insertRows = (index, gridA, gridB, generator, comparator) => { + splitRows(gridA, index, comparator, generator.cell); + const locked = getLockedColumnsFromGrid(gridA); + const diff = measureWidth(gridA, gridB); + const delta = { + ...diff, + colDelta: diff.colDelta - locked.length + }; + const fittedOldGrid = tailor(gridA, delta, generator); + const { cols: oldCols, rows: oldRows } = extractGridDetails(fittedOldGrid); + const newLocked = getLockedColumnsFromGrid(fittedOldGrid); + const secondDiff = measureWidth(gridB, gridA); + // Don't want the locked columns to count towards to the colDelta as column filling for locked columns is handled separately + const secondDelta = { + ...secondDiff, + colDelta: secondDiff.colDelta + newLocked.length + }; + const fittedGridB = lockedColFill(gridB, generator, newLocked); + const fittedNewGrid = tailor(fittedGridB, secondDelta, generator); + return [ + ...oldCols, + ...oldRows.slice(0, index), + ...fittedNewGrid, + ...oldRows.slice(index, oldRows.length) + ]; }; - const makeRange = (start, soffset, finish, foffset) => { - const doc = owner(start); - const rng = doc.dom.createRange(); - rng.setStart(start.dom, soffset); - rng.setEnd(finish.dom, foffset); - return rng; + const cloneRow = (row, cloneCell, comparator, substitution) => clone$2(row, (elem) => substitution(elem, comparator), cloneCell); + // substitution :: (item, comparator) -> item + // example is the location of the cursor (the row index) + // index is the insert position (at - or after - example) (the row index) + const insertRowAt = (grid, index, example, comparator, substitution) => { + const { rows, cols } = extractGridDetails(grid); + const before = rows.slice(0, index); + const after = rows.slice(index); + const newRow = cloneRow(rows[example], (ex, c) => { + const withinSpan = index > 0 && index < rows.length && comparator(getCellElement(rows[index - 1], c), getCellElement(rows[index], c)); + const ret = withinSpan ? getCell(rows[index], c) : elementnew(substitution(ex.element, comparator), true, ex.isLocked); + return ret; + }, comparator, substitution); + return [ + ...cols, + ...before, + newRow, + ...after + ]; }; - const after = (start, soffset, finish, foffset) => { - const r = makeRange(start, soffset, finish, foffset); - const same = eq$1(start, finish) && soffset === foffset; - return r.collapsed && !same; + const getElementFor = (row, column, section, withinSpan, example, comparator, substitution) => { + if (section === 'colgroup' || !withinSpan) { + const cell = getCell(row, example); + // locked is explicitly set to false so the newly inserted column doesn't inherit example column locked state + return elementnew(substitution(cell.element, comparator), true, false); + } + else { + return getCell(row, column); + } }; - - const getNativeSelection = win => Optional.from(win.getSelection()); - const doSetNativeRange = (win, rng) => { - getNativeSelection(win).each(selection => { - selection.removeAllRanges(); - selection.addRange(rng); - }); - }; - const doSetRange = (win, start, soffset, finish, foffset) => { - const rng = exactToNative(win, start, soffset, finish, foffset); - doSetNativeRange(win, rng); - }; - const setLegacyRtlRange = (win, selection, start, soffset, finish, foffset) => { - selection.collapse(start.dom, soffset); - selection.extend(finish.dom, foffset); - }; - const setRangeFromRelative = (win, relative) => diagnose(win, relative).match({ - ltr: (start, soffset, finish, foffset) => { - doSetRange(win, start, soffset, finish, foffset); - }, - rtl: (start, soffset, finish, foffset) => { - getNativeSelection(win).each(selection => { - if (selection.setBaseAndExtent) { - selection.setBaseAndExtent(start.dom, soffset, finish.dom, foffset); - } else if (selection.extend) { - try { - setLegacyRtlRange(win, selection, start, soffset, finish, foffset); - } catch (_a) { - doSetRange(win, finish, foffset, start, soffset); - } - } else { - doSetRange(win, finish, foffset, start, soffset); - } - }); - } + // substitution :: (item, comparator) -> item + // example is the location of the cursor (the column index) + // index is the insert position (at - or after - example) (the column index) + const insertColumnAt = (grid, index, example, comparator, substitution) => map$1(grid, (row) => { + const withinSpan = index > 0 && index < cellLength(row) && comparator(getCellElement(row, index - 1), getCellElement(row, index)); + const sub = getElementFor(row, index, row.section, withinSpan, example, comparator, substitution); + return addCell(row, index, sub); }); - const setExact = (win, start, soffset, finish, foffset) => { - const relative = preprocessExact(start, soffset, finish, foffset); - setRangeFromRelative(win, relative); + const deleteColumnsAt = (grid, columns) => bind$2(grid, (row) => { + const existingCells = row.cells; + const cells = foldr(columns, (acc, column) => column >= 0 && column < acc.length ? acc.slice(0, column).concat(acc.slice(column + 1)) : acc, existingCells); + return cells.length > 0 ? [rowcells(row.element, cells, row.section, row.isNew)] : []; + }); + const deleteRowsAt = (grid, start, finish) => { + const { rows, cols } = extractGridDetails(grid); + return [ + ...cols, + ...rows.slice(0, start), + ...rows.slice(finish + 1) + ]; }; - const setRelative = (win, startSitu, finishSitu) => { - const relative = preprocessRelative(startSitu, finishSitu); - setRangeFromRelative(win, relative); - }; - const readRange = selection => { - if (selection.rangeCount > 0) { - const firstRng = selection.getRangeAt(0); - const lastRng = selection.getRangeAt(selection.rangeCount - 1); - return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset)); - } else { - return Optional.none(); - } + + const notInStartRow = (grid, rowIndex, colIndex, comparator) => getCellElement(grid[rowIndex], colIndex) !== undefined && (rowIndex > 0 && comparator(getCellElement(grid[rowIndex - 1], colIndex), getCellElement(grid[rowIndex], colIndex))); + const notInStartColumn = (row, index, comparator) => index > 0 && comparator(getCellElement(row, index - 1), getCellElement(row, index)); + // This checks for cells that aren't in the "start" position as the model will create duplicate element references for + // each column/row that the cell spans. As an example, for a merged cell with rowspan="2", the cell in the second row is a duplicate + // of the cell in the first row. + const isDuplicatedCell = (grid, rowIndex, colIndex, comparator) => notInStartRow(grid, rowIndex, colIndex, comparator) || notInStartColumn(grid[rowIndex], colIndex, comparator); + const rowReplacerPredicate = (targetRow, columnHeaders) => { + const entireTableIsHeader = forall(columnHeaders, identity) && isHeaderCells(targetRow.cells); + return entireTableIsHeader ? always : (cell, _rowIndex, colIndex) => { + const type = name(cell.element); + return !(type === 'th' && columnHeaders[colIndex]); + }; }; - const doGetExact = selection => { - if (selection.anchorNode === null || selection.focusNode === null) { - return readRange(selection); - } else { - const anchor = SugarElement.fromDom(selection.anchorNode); - const focus = SugarElement.fromDom(selection.focusNode); - return after(anchor, selection.anchorOffset, focus, selection.focusOffset) ? Optional.some(SimRange.create(anchor, selection.anchorOffset, focus, selection.focusOffset)) : readRange(selection); - } + const columnReplacePredicate = (targetColumn, rowHeaders) => { + const entireTableIsHeader = forall(rowHeaders, identity) && isHeaderCells(targetColumn); + return entireTableIsHeader ? always : (cell, rowIndex, _colIndex) => { + const type = name(cell.element); + return !(type === 'th' && rowHeaders[rowIndex]); + }; }; - const setToElement = (win, element, selectNodeContents$1 = true) => { - const rngGetter = selectNodeContents$1 ? selectNodeContents : selectNode; - const rng = rngGetter(win, element); - doSetNativeRange(win, rng); + const determineScope = (applyScope, cell, newScope, isInHeader) => { + const hasSpan = (scope) => scope === 'row' ? hasRowspan(cell) : hasColspan(cell); + const getScope = (scope) => hasSpan(scope) ? `${scope}group` : scope; + if (applyScope) { + return isHeaderCell(cell) ? getScope(newScope) : null; + } + else if (isInHeader && isHeaderCell(cell)) { + // The cell is still in a header row/column so ensure the right scope is reverted to + const oppositeScope = newScope === 'row' ? 'col' : 'row'; + return getScope(oppositeScope); + } + else { + // No longer a header so ensure the scope is removed + return null; + } }; - const getExact = win => getNativeSelection(win).filter(sel => sel.rangeCount > 0).bind(doGetExact); - const get$2 = win => getExact(win).map(range => SimSelection.exact(range.start, range.soffset, range.finish, range.foffset)); - const getFirstRect = (win, selection) => { - const rng = asLtrRange(win, selection); - return getFirstRect$1(rng); + const rowScopeGenerator = (applyScope, columnHeaders) => (cell, rowIndex, columnIndex) => Optional.some(determineScope(applyScope, cell.element, 'col', columnHeaders[columnIndex])); + const columnScopeGenerator = (applyScope, rowHeaders) => (cell, rowIndex) => Optional.some(determineScope(applyScope, cell.element, 'row', rowHeaders[rowIndex])); + const replace = (cell, comparator, substitute) => elementnew(substitute(cell.element, comparator), true, cell.isLocked); + const replaceIn = (grid, targets, comparator, substitute, replacer, genScope, shouldReplace) => { + const isTarget = (cell) => { + return exists(targets, (target) => { + return comparator(cell.element, target.element); + }); + }; + return map$1(grid, (row, rowIndex) => { + return mapCells(row, (cell, colIndex) => { + if (isTarget(cell)) { + const newCell = shouldReplace(cell, rowIndex, colIndex) ? replacer(cell, comparator, substitute) : cell; + // Update the scope + genScope(newCell, rowIndex, colIndex).each((scope) => { + setOptions(newCell.element, { scope: Optional.from(scope) }); + }); + return newCell; + } + else { + return cell; + } + }); + }); }; - const getAtPoint = (win, x, y) => fromPoint(win, x, y); - const clear = win => { - getNativeSelection(win).each(selection => selection.removeAllRanges()); - }; - - const WindowBridge = win => { - const elementFromPoint = (x, y) => { - return SugarElement.fromPoint(SugarElement.fromDom(win.document), x, y); - }; - const getRect = element => { - return element.dom.getBoundingClientRect(); - }; - const getRangedRect = (start, soffset, finish, foffset) => { - const sel = SimSelection.exact(start, soffset, finish, foffset); - return getFirstRect(win, sel); - }; - const getSelection = () => { - return get$2(win).map(exactAdt => { - return convertToRange(win, exactAdt); - }); - }; - const fromSitus = situs => { - const relative = SimSelection.relative(situs.start, situs.finish); - return convertToRange(win, relative); - }; - const situsFromPoint = (x, y) => { - return getAtPoint(win, x, y).map(exact => { - return Situs.create(exact.start, exact.soffset, exact.finish, exact.foffset); - }); - }; - const clearSelection = () => { - clear(win); - }; - const collapseSelection = (toStart = false) => { - get$2(win).each(sel => sel.fold(rng => rng.collapse(toStart), (startSitu, finishSitu) => { - const situ = toStart ? startSitu : finishSitu; - setRelative(win, situ, situ); - }, (start, soffset, finish, foffset) => { - const node = toStart ? start : finish; - const offset = toStart ? soffset : foffset; - setExact(win, node, offset, node, offset); - })); - }; - const selectNode = element => { - setToElement(win, element, false); - }; - const selectContents = element => { - setToElement(win, element); - }; - const setSelection = sel => { - setExact(win, sel.start, sel.soffset, sel.finish, sel.foffset); - }; - const setRelativeSelection = (start, finish) => { - setRelative(win, start, finish); - }; - const getInnerHeight = () => { - return win.innerHeight; - }; - const getScrollY = () => { - const pos = get$3(SugarElement.fromDom(win.document)); - return pos.top; - }; - const scrollBy = (x, y) => { - by(x, y, SugarElement.fromDom(win.document)); - }; - return { - elementFromPoint, - getRect, - getRangedRect, - getSelection, - fromSitus, - situsFromPoint, - clearSelection, - collapseSelection, - setSelection, - setRelativeSelection, - selectNode, - selectContents, - getInnerHeight, - getScrollY, - scrollBy - }; - }; - - const rc = (rows, cols) => ({ - rows, - cols + const getColumnCells = (rows, columnIndex, comparator) => bind$2(rows, (row, i) => { + // check if already added. + return isDuplicatedCell(rows, i, columnIndex, comparator) ? [] : [getCell(row, columnIndex)]; }); - const mouse = (win, container, isRoot, annotations) => { - const bridge = WindowBridge(win); - const handlers = MouseSelection(bridge, container, isRoot, annotations); - return { - clearstate: handlers.clearstate, - mousedown: handlers.mousedown, - mouseover: handlers.mouseover, - mouseup: handlers.mouseup - }; - }; - const isEditableNode = node => closest$2(node, isHTMLElement).exists(isEditable$1); - const isEditableSelection = (start, finish) => isEditableNode(start) || isEditableNode(finish); - const keyboard = (win, container, isRoot, annotations) => { - const bridge = WindowBridge(win); - const clearToNavigate = () => { - annotations.clear(container); - return Optional.none(); - }; - const keydown = (event, start, soffset, finish, foffset, direction) => { - const realEvent = event.raw; - const keycode = realEvent.which; - const shiftKey = realEvent.shiftKey === true; - const handler = retrieve$1(container, annotations.selectedSelector).fold(() => { - if (isNavigation(keycode) && !shiftKey) { - annotations.clearBeforeUpdate(container); - } - if (isNavigation(keycode) && shiftKey && !isEditableSelection(start, finish)) { - return Optional.none; - } else if (isDown(keycode) && shiftKey) { - return curry(select, bridge, container, isRoot, down, finish, start, annotations.selectRange); - } else if (isUp(keycode) && shiftKey) { - return curry(select, bridge, container, isRoot, up, finish, start, annotations.selectRange); - } else if (isDown(keycode)) { - return curry(navigate, bridge, isRoot, down, finish, start, lastDownCheck); - } else if (isUp(keycode)) { - return curry(navigate, bridge, isRoot, up, finish, start, firstUpCheck); - } else { - return Optional.none; - } - }, selected => { - const update$1 = attempts => { - return () => { - const navigation = findMap(attempts, delta => { - return update(delta.rows, delta.cols, container, selected, annotations); - }); - return navigation.fold(() => { - return getEdges(container, annotations.firstSelectedSelector, annotations.lastSelectedSelector).map(edges => { - const relative = isDown(keycode) || direction.isForward(keycode) ? Situ.after : Situ.before; - bridge.setRelativeSelection(Situ.on(edges.first, 0), relative(edges.table)); - annotations.clear(container); - return Response.create(Optional.none(), true); - }); - }, _ => { - return Optional.some(Response.create(Optional.none(), true)); - }); - }; - }; - if (isNavigation(keycode) && shiftKey && !isEditableSelection(start, finish)) { - return Optional.none; - } else if (isDown(keycode) && shiftKey) { - return update$1([rc(+1, 0)]); - } else if (isUp(keycode) && shiftKey) { - return update$1([rc(-1, 0)]); - } else if (direction.isBackward(keycode) && shiftKey) { - return update$1([ - rc(0, -1), - rc(-1, 0) - ]); - } else if (direction.isForward(keycode) && shiftKey) { - return update$1([ - rc(0, +1), - rc(+1, 0) - ]); - } else if (isNavigation(keycode) && !shiftKey) { - return clearToNavigate; - } else { - return Optional.none; - } + const getRowCells = (rows, rowIndex, comparator) => { + const targetRow = rows[rowIndex]; + return bind$2(targetRow.cells, (item, i) => { + // Check that we haven't already added this one. + return isDuplicatedCell(rows, rowIndex, i, comparator) ? [] : [item]; }); - return handler(); - }; - const keyup = (event, start, soffset, finish, foffset) => { - return retrieve$1(container, annotations.selectedSelector).fold(() => { - const realEvent = event.raw; - const keycode = realEvent.which; - const shiftKey = realEvent.shiftKey === true; - if (!shiftKey) { - return Optional.none(); - } - if (isNavigation(keycode) && isEditableSelection(start, finish)) { - return sync(container, isRoot, start, soffset, finish, foffset, annotations.selectRange); - } else { - return Optional.none(); - } - }, Optional.none); - }; - return { - keydown, - keyup - }; }; - const external = (win, container, isRoot, annotations) => { - const bridge = WindowBridge(win); - return (start, finish) => { - annotations.clearBeforeUpdate(container); - identify(start, finish, isRoot).each(cellSel => { - const boxes = cellSel.boxes.getOr([]); - annotations.selectRange(container, boxes, cellSel.start, cellSel.finish); - bridge.selectContents(finish); - bridge.collapseSelection(); + const replaceColumns = (grid, indexes, applyScope, comparator, substitution) => { + // Make this efficient later. + const rows = extractGridDetails(grid).rows; + const targets = bind$2(indexes, (index) => getColumnCells(rows, index, comparator)); + const rowHeaders = map$1(rows, (row) => isHeaderCells(row.cells)); + const shouldReplaceCell = columnReplacePredicate(targets, rowHeaders); + const scopeGenerator = columnScopeGenerator(applyScope, rowHeaders); + return replaceIn(grid, targets, comparator, substitution, replace, scopeGenerator, shouldReplaceCell); + }; + const replaceRows = (grid, indexes, section, applyScope, comparator, substitution, tableSection) => { + const { cols, rows } = extractGridDetails(grid); + const targetRow = rows[indexes[0]]; + const targets = bind$2(indexes, (index) => getRowCells(rows, index, comparator)); + const columnHeaders = map$1(targetRow.cells, (_cell, index) => isHeaderCells(getColumnCells(rows, index, comparator))); + // Transform and replace the target row + // TODO: TINY-7776: This doesn't deal with rowspans which can break the layout when moving to a new section + const newRows = [...rows]; + each$2(indexes, (index) => { + newRows[index] = tableSection.transformRow(rows[index], section); }); - }; + const newGrid = [...cols, ...newRows]; + const shouldReplaceCell = rowReplacerPredicate(targetRow, columnHeaders); + const scopeGenerator = rowScopeGenerator(applyScope, columnHeaders); + return replaceIn(newGrid, targets, comparator, substitution, tableSection.transformCell, scopeGenerator, shouldReplaceCell); }; - - const read = (element, attr) => { - const value = get$b(element, attr); - return value === undefined || value === '' ? [] : value.split(' '); - }; - const add$2 = (element, attr, id) => { - const old = read(element, attr); - const nu = old.concat([id]); - set$2(element, attr, nu.join(' ')); - return true; - }; - const remove$4 = (element, attr, id) => { - const nu = filter$2(read(element, attr), v => v !== id); - if (nu.length > 0) { - set$2(element, attr, nu.join(' ')); - } else { - remove$7(element, attr); - } - return false; + const replaceCells = (grid, details, comparator, substitution) => { + const rows = extractGridDetails(grid).rows; + const targetCells = map$1(details, (detail) => getCell(rows[detail.row], detail.column)); + return replaceIn(grid, targetCells, comparator, substitution, replace, Optional.none, always); }; - const supports = element => element.dom.classList !== undefined; - const get$1 = element => read(element, 'class'); - const add$1 = (element, clazz) => add$2(element, 'class', clazz); - const remove$3 = (element, clazz) => remove$4(element, 'class', clazz); - - const add = (element, clazz) => { - if (supports(element)) { - element.dom.classList.add(clazz); - } else { - add$1(element, clazz); - } - }; - const cleanClass = element => { - const classList = supports(element) ? element.dom.classList : get$1(element); - if (classList.length === 0) { - remove$7(element, 'class'); - } - }; - const remove$2 = (element, clazz) => { - if (supports(element)) { - const classList = element.dom.classList; - classList.remove(clazz); - } else { - remove$3(element, clazz); - } - cleanClass(element); + const uniqueColumns = (details) => { + const uniqueCheck = (rest, detail) => { + const columnExists = exists(rest, (currentDetail) => currentDetail.column === detail.column); + return columnExists ? rest : rest.concat([detail]); + }; + return foldl(details, uniqueCheck, []).sort((detailA, detailB) => detailA.column - detailB.column); }; - const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz); - const remove$1 = (element, classes) => { - each$2(classes, x => { - remove$2(element, x); - }); - }; - - const addClass = clazz => element => { - add(element, clazz); - }; - const removeClasses = classes => element => { - remove$1(element, classes); - }; - - const byClass = ephemera => { - const addSelectionClass = addClass(ephemera.selected); - const removeSelectionClasses = removeClasses([ - ephemera.selected, - ephemera.lastSelected, - ephemera.firstSelected - ]); - const clear = container => { - const sels = descendants(container, ephemera.selectedSelector); - each$2(sels, removeSelectionClasses); - }; - const selectRange = (container, cells, start, finish) => { - clear(container); - each$2(cells, addSelectionClass); - add(start, ephemera.firstSelected); - add(finish, ephemera.lastSelected); - }; - return { - clearBeforeUpdate: clear, - clear, - selectRange, - selectedSelector: ephemera.selectedSelector, - firstSelectedSelector: ephemera.firstSelectedSelector, - lastSelectedSelector: ephemera.lastSelectedSelector - }; - }; - const byAttr = (ephemera, onSelection, onClear) => { - const removeSelectionAttributes = element => { - remove$7(element, ephemera.selected); - remove$7(element, ephemera.firstSelected); - remove$7(element, ephemera.lastSelected); - }; - const addSelectionAttribute = element => { - set$2(element, ephemera.selected, '1'); - }; - const clear = container => { - clearBeforeUpdate(container); - onClear(); - }; - const clearBeforeUpdate = container => { - const sels = descendants(container, `${ ephemera.selectedSelector },${ ephemera.firstSelectedSelector },${ ephemera.lastSelectedSelector }`); - each$2(sels, removeSelectionAttributes); - }; - const selectRange = (container, cells, start, finish) => { - clear(container); - each$2(cells, addSelectionAttribute); - set$2(start, ephemera.firstSelected, '1'); - set$2(finish, ephemera.lastSelected, '1'); - onSelection(cells, start, finish); - }; - return { - clearBeforeUpdate, - clear, - selectRange, - selectedSelector: ephemera.selectedSelector, - firstSelectedSelector: ephemera.firstSelectedSelector, - lastSelectedSelector: ephemera.lastSelectedSelector - }; - }; - const SelectionAnnotation = { - byClass, - byAttr + // This uses a slight variation to the default `ContentEditable.isEditable` behaviour, + // as when the element is detached we assume it is editable because it is a new cell. + const isEditable = (elem) => isEditable$1(elem, true); + const prune = (table) => { + const cells = cells$1(table); + if (cells.length === 0) { + remove$5(table); + } }; - - const fold = (subject, onNone, onMultiple, onSingle) => { - switch (subject.tag) { - case 'none': - return onNone(); - case 'single': - return onSingle(subject.element); - case 'multiple': - return onMultiple(subject.elements); - } - }; - const none = () => ({ tag: 'none' }); - const multiple = elements => ({ - tag: 'multiple', - elements - }); - const single = element => ({ - tag: 'single', - element + const outcome = (grid, cursor) => ({ + grid, + cursor }); - - const Selections = (lazyRoot, getStart, selectedSelector) => { - const get = () => retrieve(lazyRoot(), selectedSelector).fold(() => getStart().fold(none, single), multiple); - return { get }; - }; - - const getUpOrLeftCells = (grid, selectedCells) => { - const upGrid = grid.slice(0, selectedCells[selectedCells.length - 1].row + 1); - const upDetails = toDetailList(upGrid); - return bind$2(upDetails, detail => { - const slicedCells = detail.cells.slice(0, selectedCells[selectedCells.length - 1].column + 1); - return map$1(slicedCells, cell => cell.element); - }); + const findEditableCursorPosition = (rows) => findMap(rows, (row) => findMap(row.cells, (cell) => { + const elem = cell.element; + return someIf(isEditable(elem), elem); + })); + const elementFromGrid = (grid, row, column) => { + var _a, _b; + const rows = extractGridDetails(grid).rows; + return Optional.from((_b = (_a = rows[row]) === null || _a === void 0 ? void 0 : _a.cells[column]) === null || _b === void 0 ? void 0 : _b.element) + .filter(isEditable) + // Fallback to the first valid position in the table + .orThunk(() => findEditableCursorPosition(rows)); }; - const getDownOrRightCells = (grid, selectedCells) => { - const downGrid = grid.slice(selectedCells[0].row + selectedCells[0].rowspan - 1, grid.length); - const downDetails = toDetailList(downGrid); - return bind$2(downDetails, detail => { - const slicedCells = detail.cells.slice(selectedCells[0].column + selectedCells[0].colspan - 1, detail.cells.length); - return map$1(slicedCells, cell => cell.element); - }); + const bundle = (grid, row, column) => { + const cursorElement = elementFromGrid(grid, row, column); + return outcome(grid, cursorElement); }; - const getOtherCells = (table, target, generators) => { - const warehouse = Warehouse.fromTable(table); - const details = onCells(warehouse, target); - return details.map(selectedCells => { - const grid = toGrid(warehouse, generators, false); - const {rows} = extractGridDetails(grid); - const upOrLeftCells = getUpOrLeftCells(rows, selectedCells); - const downOrRightCells = getDownOrRightCells(rows, selectedCells); - return { - upOrLeftCells, - downOrRightCells + const uniqueRows = (details) => { + const rowCompilation = (rest, detail) => { + const rowExists = exists(rest, (currentDetail) => currentDetail.row === detail.row); + return rowExists ? rest : rest.concat([detail]); }; - }); - }; - - const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({ - target, - x, - y, - stop, - prevent, - kill, - raw - }); - const fromRawEvent$1 = rawEvent => { - const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target)); - const stop = () => rawEvent.stopPropagation(); - const prevent = () => rawEvent.preventDefault(); - const kill = compose(prevent, stop); - return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent); - }; - const handle = (filter, handler) => rawEvent => { - if (filter(rawEvent)) { - handler(fromRawEvent$1(rawEvent)); - } - }; - const binder = (element, event, filter, handler, useCapture) => { - const wrapped = handle(filter, handler); - element.dom.addEventListener(event, wrapped, useCapture); - return { unbind: curry(unbind, element, event, wrapped, useCapture) }; + return foldl(details, rowCompilation, []).sort((detailA, detailB) => detailA.row - detailB.row); }; - const bind$1 = (element, event, filter, handler) => binder(element, event, filter, handler, false); - const unbind = (element, event, handler, useCapture) => { - element.dom.removeEventListener(event, handler, useCapture); + const opInsertRowsBefore = (grid, details, comparator, genWrappers) => { + const targetIndex = details[0].row; + const rows = uniqueRows(details); + const newGrid = foldr(rows, (acc, row) => { + const newG = insertRowAt(acc.grid, targetIndex, row.row + acc.delta, comparator, genWrappers.getOrInit); + return { grid: newG, delta: acc.delta + 1 }; + }, { grid, delta: 0 }).grid; + return bundle(newGrid, targetIndex, details[0].column); }; - - const filter = always; - const bind = (element, event, handler) => bind$1(element, event, filter, handler); - const fromRawEvent = fromRawEvent$1; - - const hasInternalTarget = e => !has(SugarElement.fromDom(e.target), 'ephox-snooker-resizer-bar'); - const TableCellSelectionHandler = (editor, resizeHandler) => { - const cellSelection = Selections(() => SugarElement.fromDom(editor.getBody()), () => getSelectionCell(getSelectionStart(editor), getIsRoot(editor)), ephemera.selectedSelector); - const onSelection = (cells, start, finish) => { - const tableOpt = table(start); - tableOpt.each(table => { - const cellsDom = map$1(cells, cell => cell.dom); - const cloneFormats = getTableCloneElements(editor); - const generators = cellOperations(noop, SugarElement.fromDom(editor.getDoc()), cloneFormats); - const selectedCells = getCellsFromSelection(editor); - const otherCellsDom = getOtherCells(table, { selection: selectedCells }, generators).map(otherCells => map(otherCells, cellArr => map$1(cellArr, cell => cell.dom))).getOrUndefined(); - fireTableSelectionChange(editor, cellsDom, start.dom, finish.dom, otherCellsDom); - }); - }; - const onClear = () => fireTableSelectionClear(editor); - const annotations = SelectionAnnotation.byAttr(ephemera, onSelection, onClear); - editor.on('init', _e => { - const win = editor.getWin(); - const body = getBody(editor); - const isRoot = getIsRoot(editor); - const syncSelection = () => { - const sel = editor.selection; - const start = SugarElement.fromDom(sel.getStart()); - const end = SugarElement.fromDom(sel.getEnd()); - const shared = sharedOne(table, [ - start, - end - ]); - shared.fold(() => annotations.clear(body), noop); - }; - const mouseHandlers = mouse(win, body, isRoot, annotations); - const keyHandlers = keyboard(win, body, isRoot, annotations); - const external$1 = external(win, body, isRoot, annotations); - const hasShiftKey = event => event.raw.shiftKey === true; - editor.on('TableSelectorChange', e => external$1(e.start, e.finish)); - const handleResponse = (event, response) => { - if (!hasShiftKey(event)) { - return; - } - if (response.kill) { - event.kill(); - } - response.selection.each(ns => { - const relative = SimSelection.relative(ns.start, ns.finish); - const rng = asLtrRange(win, relative); - editor.selection.setRng(rng); - }); - }; - const keyup = event => { - const wrappedEvent = fromRawEvent(event); - if (wrappedEvent.raw.shiftKey && isNavigation(wrappedEvent.raw.which)) { - const rng = editor.selection.getRng(); - const start = SugarElement.fromDom(rng.startContainer); - const end = SugarElement.fromDom(rng.endContainer); - keyHandlers.keyup(wrappedEvent, start, rng.startOffset, end, rng.endOffset).each(response => { - handleResponse(wrappedEvent, response); - }); - } - }; - const keydown = event => { - const wrappedEvent = fromRawEvent(event); - resizeHandler.hide(); - const rng = editor.selection.getRng(); - const start = SugarElement.fromDom(rng.startContainer); - const end = SugarElement.fromDom(rng.endContainer); - const direction = onDirection(ltr, rtl)(SugarElement.fromDom(editor.selection.getStart())); - keyHandlers.keydown(wrappedEvent, start, rng.startOffset, end, rng.endOffset, direction).each(response => { - handleResponse(wrappedEvent, response); - }); - resizeHandler.show(); - }; - const isLeftMouse = raw => raw.button === 0; - const isLeftButtonPressed = raw => { - if (raw.buttons === undefined) { - return true; - } - return (raw.buttons & 1) !== 0; - }; - const dragStart = _e => { - mouseHandlers.clearstate(); - }; - const mouseDown = e => { - if (isLeftMouse(e) && hasInternalTarget(e)) { - mouseHandlers.mousedown(fromRawEvent(e)); - } - }; - const mouseOver = e => { - if (isLeftButtonPressed(e) && hasInternalTarget(e)) { - mouseHandlers.mouseover(fromRawEvent(e)); - } - }; - const mouseUp = e => { - if (isLeftMouse(e) && hasInternalTarget(e)) { - mouseHandlers.mouseup(fromRawEvent(e)); - } - }; - const getDoubleTap = () => { - const lastTarget = Cell(SugarElement.fromDom(body)); - const lastTimeStamp = Cell(0); - const touchEnd = t => { - const target = SugarElement.fromDom(t.target); - if (isTag('td')(target) || isTag('th')(target)) { - const lT = lastTarget.get(); - const lTS = lastTimeStamp.get(); - if (eq$1(lT, target) && t.timeStamp - lTS < 300) { - t.preventDefault(); - external$1(target, target); - } - } - lastTarget.set(target); - lastTimeStamp.set(t.timeStamp); - }; - return { touchEnd }; - }; - const doubleTap = getDoubleTap(); - editor.on('dragstart', dragStart); - editor.on('mousedown', mouseDown); - editor.on('mouseover', mouseOver); - editor.on('mouseup', mouseUp); - editor.on('touchend', doubleTap.touchEnd); - editor.on('keyup', keyup); - editor.on('keydown', keydown); - editor.on('NodeChange', syncSelection); - }); - editor.on('PreInit', () => { - editor.serializer.addTempAttr(ephemera.firstSelected); - editor.serializer.addTempAttr(ephemera.lastSelected); - }); - const clearSelectedCells = container => annotations.clear(SugarElement.fromDom(container)); - const getSelectedCells = () => fold(cellSelection.get(), constant([]), cells => { - return map$1(cells, cell => cell.dom); - }, cell => [cell.dom]); - return { - getSelectedCells, - clearSelectedCells - }; - }; - - const Event = fields => { - let handlers = []; - const bind = handler => { - if (handler === undefined) { - throw new Error('Event bind error: undefined handler'); - } - handlers.push(handler); - }; - const unbind = handler => { - handlers = filter$2(handlers, h => { - return h !== handler; - }); - }; - const trigger = (...args) => { - const event = {}; - each$2(fields, (name, i) => { - event[name] = args[i]; - }); - each$2(handlers, handler => { - handler(event); - }); - }; - return { - bind, - unbind, - trigger - }; - }; - - const create$1 = typeDefs => { - const registry = map(typeDefs, event => { - return { - bind: event.bind, - unbind: event.unbind - }; - }); - const trigger = map(typeDefs, event => { - return event.trigger; - }); - return { - registry, - trigger - }; - }; - - const last = (fn, rate) => { - let timer = null; - const cancel = () => { - if (!isNull(timer)) { - clearTimeout(timer); - timer = null; - } - }; - const throttle = (...args) => { - cancel(); - timer = setTimeout(() => { - timer = null; - fn.apply(null, args); - }, rate); - }; - return { - cancel, - throttle - }; - }; - - const sort = arr => { - return arr.slice(0).sort(); + const opInsertRowsAfter = (grid, details, comparator, genWrappers) => { + const rows = uniqueRows(details); + const target = rows[rows.length - 1]; + const targetIndex = target.row + target.rowspan; + const newGrid = foldr(rows, (newG, row) => { + return insertRowAt(newG, targetIndex, row.row, comparator, genWrappers.getOrInit); + }, grid); + return bundle(newGrid, targetIndex, details[0].column); }; - const reqMessage = (required, keys) => { - throw new Error('All required keys (' + sort(required).join(', ') + ') were not specified. Specified keys were: ' + sort(keys).join(', ') + '.'); + const opInsertColumnsBefore = (grid, extractDetail, comparator, genWrappers) => { + const details = extractDetail.details; + const columns = uniqueColumns(details); + const targetIndex = columns[0].column; + const newGrid = foldr(columns, (acc, col) => { + const newG = insertColumnAt(acc.grid, targetIndex, col.column + acc.delta, comparator, genWrappers.getOrInit); + return { grid: newG, delta: acc.delta + 1 }; + }, { grid, delta: 0 }).grid; + return bundle(newGrid, details[0].row, targetIndex); }; - const unsuppMessage = unsupported => { - throw new Error('Unsupported keys for object: ' + sort(unsupported).join(', ')); + const opInsertColumnsAfter = (grid, extractDetail, comparator, genWrappers) => { + const details = extractDetail.details; + const target = details[details.length - 1]; + const targetIndex = target.column + target.colspan; + const columns = uniqueColumns(details); + const newGrid = foldr(columns, (newG, col) => { + return insertColumnAt(newG, targetIndex, col.column, comparator, genWrappers.getOrInit); + }, grid); + return bundle(newGrid, details[0].row, targetIndex); }; - const validateStrArr = (label, array) => { - if (!isArray(array)) { - throw new Error('The ' + label + ' fields must be an array. Was: ' + array + '.'); - } - each$2(array, a => { - if (!isString(a)) { - throw new Error('The value ' + a + ' in the ' + label + ' fields was not a string.'); - } - }); + const opMakeColumnsHeader = (initialGrid, details, comparator, genWrappers) => { + const columns = uniqueColumns(details); + const columnIndexes = map$1(columns, (detail) => detail.column); + const newGrid = replaceColumns(initialGrid, columnIndexes, true, comparator, genWrappers.replaceOrInit); + return bundle(newGrid, details[0].row, details[0].column); }; - const invalidTypeMessage = (incorrect, type) => { - throw new Error('All values need to be of type: ' + type + '. Keys (' + sort(incorrect).join(', ') + ') were not.'); + const opMakeCellsHeader = (initialGrid, details, comparator, genWrappers) => { + const newGrid = replaceCells(initialGrid, details, comparator, genWrappers.replaceOrInit); + return bundle(newGrid, details[0].row, details[0].column); }; - const checkDupes = everything => { - const sorted = sort(everything); - const dupe = find$1(sorted, (s, i) => { - return i < sorted.length - 1 && s === sorted[i + 1]; - }); - dupe.each(d => { - throw new Error('The field: ' + d + ' occurs more than once in the combined fields: [' + sorted.join(', ') + '].'); - }); + const opUnmakeColumnsHeader = (initialGrid, details, comparator, genWrappers) => { + const columns = uniqueColumns(details); + const columnIndexes = map$1(columns, (detail) => detail.column); + const newGrid = replaceColumns(initialGrid, columnIndexes, false, comparator, genWrappers.replaceOrInit); + return bundle(newGrid, details[0].row, details[0].column); }; - - const base = (handleUnsupported, required) => { - return baseWith(handleUnsupported, required, { - validate: isFunction, - label: 'function' - }); + const opUnmakeCellsHeader = (initialGrid, details, comparator, genWrappers) => { + const newGrid = replaceCells(initialGrid, details, comparator, genWrappers.replaceOrInit); + return bundle(newGrid, details[0].row, details[0].column); }; - const baseWith = (handleUnsupported, required, pred) => { - if (required.length === 0) { - throw new Error('You must specify at least one required field.'); - } - validateStrArr('required', required); - checkDupes(required); - return obj => { - const keys$1 = keys(obj); - const allReqd = forall(required, req => { - return contains$2(keys$1, req); - }); - if (!allReqd) { - reqMessage(required, keys$1); - } - handleUnsupported(required, keys$1); - const invalidKeys = filter$2(required, key => { - return !pred.validate(obj[key], key); - }); - if (invalidKeys.length > 0) { - invalidTypeMessage(invalidKeys, pred.label); - } - return obj; - }; + const makeRowsSection = (section, applyScope) => (initialGrid, details, comparator, genWrappers, tableSection) => { + const rows = uniqueRows(details); + const rowIndexes = map$1(rows, (detail) => detail.row); + const newGrid = replaceRows(initialGrid, rowIndexes, section, applyScope, comparator, genWrappers.replaceOrInit, tableSection); + return bundle(newGrid, details[0].row, details[0].column); }; - const handleExact = (required, keys) => { - const unsupported = filter$2(keys, key => { - return !contains$2(required, key); - }); - if (unsupported.length > 0) { - unsuppMessage(unsupported); - } + const opMakeRowsHeader = makeRowsSection('thead', true); + const opMakeRowsBody = makeRowsSection('tbody', false); + const opMakeRowsFooter = makeRowsSection('tfoot', false); + const opEraseColumns = (grid, extractDetail, _comparator, _genWrappers) => { + const columns = uniqueColumns(extractDetail.details); + const newGrid = deleteColumnsAt(grid, map$1(columns, (column) => column.column)); + const maxColIndex = newGrid.length > 0 ? newGrid[0].cells.length - 1 : 0; + return bundle(newGrid, columns[0].row, Math.min(columns[0].column, maxColIndex)); }; - const exactly = required => base(handleExact, required); - - const DragMode = exactly([ - 'compare', - 'extract', - 'mutate', - 'sink' - ]); - const DragSink = exactly([ - 'element', - 'start', - 'stop', - 'destroy' - ]); - const DragApi = exactly([ - 'forceDrop', - 'drop', - 'move', - 'delayDrop' - ]); - - const InDrag = () => { - let previous = Optional.none(); - const reset = () => { - previous = Optional.none(); - }; - const update = (mode, nu) => { - const result = previous.map(old => { - return mode.compare(old, nu); - }); - previous = Optional.some(nu); - return result; - }; - const onEvent = (event, mode) => { - const dataOption = mode.extract(event); - dataOption.each(data => { - const offset = update(mode, data); - offset.each(d => { - events.trigger.move(d); - }); - }); - }; - const events = create$1({ move: Event(['info']) }); - return { - onEvent, - reset, - events: events.registry - }; + const opEraseRows = (grid, details, _comparator, _genWrappers) => { + const rows = uniqueRows(details); + const newGrid = deleteRowsAt(grid, rows[0].row, rows[rows.length - 1].row); + const maxRowIndex = Math.max(extractGridDetails(newGrid).rows.length - 1, 0); + return bundle(newGrid, Math.min(details[0].row, maxRowIndex), details[0].column); }; - - const NoDrag = () => { - const events = create$1({ move: Event(['info']) }); - return { - onEvent: noop, - reset: noop, - events: events.registry - }; + const opMergeCells = (grid, mergable, comparator, genWrappers) => { + const cells = mergable.cells; + merge$2(cells); + const newGrid = merge$1(grid, mergable.bounds, comparator, genWrappers.merge(cells)); + return outcome(newGrid, Optional.from(cells[0])); }; - - const Movement = () => { - const noDragState = NoDrag(); - const inDragState = InDrag(); - let dragState = noDragState; - const on = () => { - dragState.reset(); - dragState = inDragState; - }; - const off = () => { - dragState.reset(); - dragState = noDragState; - }; - const onEvent = (event, mode) => { - dragState.onEvent(event, mode); - }; - const isOn = () => { - return dragState === inDragState; - }; - return { - on, - off, - isOn, - onEvent, - events: inDragState.events - }; + const opUnmergeCells = (grid, unmergable, comparator, genWrappers) => { + const unmerge$1 = (b, cell) => unmerge(b, cell, comparator, genWrappers.unmerge(cell)); + const newGrid = foldr(unmergable, unmerge$1, grid); + return outcome(newGrid, Optional.from(unmergable[0])); }; - - const setup = (mutation, mode, settings) => { - let active = false; - const events = create$1({ - start: Event([]), - stop: Event([]) - }); - const movement = Movement(); - const drop = () => { - sink.stop(); - if (movement.isOn()) { - movement.off(); - events.trigger.stop(); - } - }; - const throttledDrop = last(drop, 200); - const go = parent => { - sink.start(parent); - movement.on(); - events.trigger.start(); - }; - const mousemove = event => { - throttledDrop.cancel(); - movement.onEvent(event, mode); - }; - movement.events.move.bind(event => { - mode.mutate(mutation, event.info); - }); - const on = () => { - active = true; - }; - const off = () => { - active = false; - }; - const isActive = () => active; - const runIfActive = f => { - return (...args) => { - if (active) { - f.apply(null, args); - } + const opPasteCells = (grid, pasteDetails, comparator, _genWrappers) => { + const gridify = (table, generators) => { + const wh = Warehouse.fromTable(table); + return toGrid(wh, generators, true); }; - }; - const sink = mode.sink(DragApi({ - forceDrop: drop, - drop: runIfActive(drop), - move: runIfActive(mousemove), - delayDrop: runIfActive(throttledDrop.throttle) - }), settings); - const destroy = () => { - sink.destroy(); - }; - return { - element: sink.element, - go, - on, - off, - isActive, - destroy, - events: events.registry - }; + const gridB = gridify(pasteDetails.clipboard, pasteDetails.generators); + const startAddress = address(pasteDetails.row, pasteDetails.column); + const mergedGrid = merge(startAddress, grid, gridB, pasteDetails.generators, comparator); + return mergedGrid.fold(() => outcome(grid, Optional.some(pasteDetails.element)), (newGrid) => { + return bundle(newGrid, pasteDetails.row, pasteDetails.column); + }); }; - - const css = namespace => { - const dashNamespace = namespace.replace(/\./g, '-'); - const resolve = str => { - return dashNamespace + '-' + str; - }; - return { resolve }; + const gridifyRows = (rows, generators, context) => { + const pasteDetails = fromPastedRows(rows, context.section); + const wh = Warehouse.generate(pasteDetails); + return toGrid(wh, generators, true); }; - - const styles$1 = css('ephox-dragster'); - const resolve$1 = styles$1.resolve; - - const Blocker = options => { - const settings = { - layerClass: resolve$1('blocker'), - ...options - }; - const div = SugarElement.fromTag('div'); - set$2(div, 'role', 'presentation'); - setAll(div, { - position: 'fixed', - left: '0px', - top: '0px', - width: '100%', - height: '100%' - }); - add(div, resolve$1('blocker')); - add(div, settings.layerClass); - const element = constant(div); - const destroy = () => { - remove$6(div); - }; - return { - element, - destroy - }; + const opPasteColsBefore = (grid, pasteDetails, comparator, _genWrappers) => { + const rows = extractGridDetails(grid).rows; + const index = pasteDetails.cells[0].column; + const context = rows[pasteDetails.cells[0].row]; + const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); + const mergedGrid = insertCols(index, grid, gridB, pasteDetails.generators, comparator); + return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column); }; - - const compare = (old, nu) => { - return SugarPosition(nu.left - old.left, nu.top - old.top); + const opPasteColsAfter = (grid, pasteDetails, comparator, _genWrappers) => { + const rows = extractGridDetails(grid).rows; + const index = pasteDetails.cells[pasteDetails.cells.length - 1].column + pasteDetails.cells[pasteDetails.cells.length - 1].colspan; + const context = rows[pasteDetails.cells[0].row]; + const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); + const mergedGrid = insertCols(index, grid, gridB, pasteDetails.generators, comparator); + return bundle(mergedGrid, pasteDetails.cells[0].row, index); }; - const extract = event => { - return Optional.some(SugarPosition(event.x, event.y)); + const opPasteRowsBefore = (grid, pasteDetails, comparator, _genWrappers) => { + const rows = extractGridDetails(grid).rows; + const index = pasteDetails.cells[0].row; + const context = rows[index]; + const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); + const mergedGrid = insertRows(index, grid, gridB, pasteDetails.generators, comparator); + return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column); }; - const mutate = (mutation, info) => { - mutation.mutate(info.left, info.top); + const opPasteRowsAfter = (grid, pasteDetails, comparator, _genWrappers) => { + const rows = extractGridDetails(grid).rows; + const index = pasteDetails.cells[pasteDetails.cells.length - 1].row + pasteDetails.cells[pasteDetails.cells.length - 1].rowspan; + const context = rows[pasteDetails.cells[0].row]; + const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context); + const mergedGrid = insertRows(index, grid, gridB, pasteDetails.generators, comparator); + return bundle(mergedGrid, index, pasteDetails.cells[0].column); }; - const sink = (dragApi, settings) => { - const blocker = Blocker(settings); - const mdown = bind(blocker.element(), 'mousedown', dragApi.forceDrop); - const mup = bind(blocker.element(), 'mouseup', dragApi.drop); - const mmove = bind(blocker.element(), 'mousemove', dragApi.move); - const mout = bind(blocker.element(), 'mouseout', dragApi.delayDrop); - const destroy = () => { - blocker.destroy(); - mup.unbind(); - mmove.unbind(); - mout.unbind(); - mdown.unbind(); - }; - const start = parent => { - append$1(parent, blocker.element()); - }; - const stop = () => { - remove$6(blocker.element()); - }; - return DragSink({ - element: blocker.element, - start, - stop, - destroy - }); + const opGetColumnsType = (table, target) => { + const house = Warehouse.fromTable(table); + const details = onCells(house, target); + return details.bind((selectedCells) => { + const lastSelectedCell = selectedCells[selectedCells.length - 1]; + const minColRange = selectedCells[0].column; + const maxColRange = lastSelectedCell.column + lastSelectedCell.colspan; + const selectedColumnCells = flatten(map$1(house.all, (row) => filter$2(row.cells, (cell) => cell.column >= minColRange && cell.column < maxColRange))); + return findCommonCellType(selectedColumnCells); + }).getOr(''); }; - var MouseDrag = DragMode({ - compare, - extract, - sink, - mutate + const opGetCellsType = (table, target) => { + const house = Warehouse.fromTable(table); + const details = onCells(house, target); + return details.bind(findCommonCellType).getOr(''); + }; + const opGetRowsType = (table, target) => { + const house = Warehouse.fromTable(table); + const details = onCells(house, target); + return details.bind((selectedCells) => { + const lastSelectedCell = selectedCells[selectedCells.length - 1]; + const minRowRange = selectedCells[0].row; + const maxRowRange = lastSelectedCell.row + lastSelectedCell.rowspan; + const selectedRows = house.all.slice(minRowRange, maxRowRange); + return findCommonRowType(selectedRows); + }).getOr(''); + }; + // Only column modifications force a resizing. Everything else just tries to preserve the table as is. + const resize = (table, list, details, behaviours) => adjustWidthTo(table, list, details, behaviours.sizing); + const adjustAndRedistributeWidths = (table, list, details, behaviours) => adjustAndRedistributeWidths$1(table, list, details, behaviours.sizing, behaviours.resize); + // Custom selection extractors + const firstColumnIsLocked = (_warehouse, details) => exists(details, (detail) => detail.column === 0 && detail.isLocked); + // TODO: Maybe have an Arr.existsR which would be more efficient for most cases below + const lastColumnIsLocked = (warehouse, details) => exists(details, (detail) => detail.column + detail.colspan >= warehouse.grid.columns && detail.isLocked); + const getColumnsWidth = (warehouse, details) => { + const columns$1 = columns(warehouse); + const uniqueCols = uniqueColumns(details); + return foldl(uniqueCols, (acc, detail) => { + const column = columns$1[detail.column]; + const colWidth = column.map(getOuter).getOr(0); + return acc + colWidth; + }, 0); + }; + const insertColumnsExtractor = (before) => (warehouse, target) => onCells(warehouse, target).filter((details) => { + const checkLocked = before ? firstColumnIsLocked : lastColumnIsLocked; + return !checkLocked(warehouse, details); + }).map((details) => ({ + details, + pixelDelta: getColumnsWidth(warehouse, details), + })); + const eraseColumnsExtractor = (warehouse, target) => onUnlockedCells(warehouse, target).map((details) => ({ + details, + pixelDelta: -getColumnsWidth(warehouse, details), // needs to be negative as we are removing columns + })); + const pasteColumnsExtractor = (before) => (warehouse, target) => onPasteByEditor(warehouse, target).filter((details) => { + const checkLocked = before ? firstColumnIsLocked : lastColumnIsLocked; + return !checkLocked(warehouse, details.cells); }); + const headerCellGenerator = Generators.transform('th'); + const bodyCellGenerator = Generators.transform('td'); + const insertRowsBefore = (table, target, generators, behaviours) => run(opInsertRowsBefore, onCells, noop, noop, Generators.modification, table, target, generators, behaviours); + const insertRowsAfter = (table, target, generators, behaviours) => run(opInsertRowsAfter, onCells, noop, noop, Generators.modification, table, target, generators, behaviours); + const insertColumnsBefore = (table, target, generators, behaviours) => run(opInsertColumnsBefore, insertColumnsExtractor(true), adjustAndRedistributeWidths, noop, Generators.modification, table, target, generators, behaviours); + const insertColumnsAfter = (table, target, generators, behaviours) => run(opInsertColumnsAfter, insertColumnsExtractor(false), adjustAndRedistributeWidths, noop, Generators.modification, table, target, generators, behaviours); + const eraseColumns = (table, target, generators, behaviours) => run(opEraseColumns, eraseColumnsExtractor, adjustAndRedistributeWidths, prune, Generators.modification, table, target, generators, behaviours); + const eraseRows = (table, target, generators, behaviours) => run(opEraseRows, onCells, noop, prune, Generators.modification, table, target, generators, behaviours); + const makeColumnsHeader = (table, target, generators, behaviours) => run(opMakeColumnsHeader, onUnlockedCells, noop, noop, headerCellGenerator, table, target, generators, behaviours); + const unmakeColumnsHeader = (table, target, generators, behaviours) => run(opUnmakeColumnsHeader, onUnlockedCells, noop, noop, bodyCellGenerator, table, target, generators, behaviours); + const makeRowsHeader = (table, target, generators, behaviours) => run(opMakeRowsHeader, onCells, noop, noop, headerCellGenerator, table, target, generators, behaviours); + const makeRowsBody = (table, target, generators, behaviours) => run(opMakeRowsBody, onCells, noop, noop, bodyCellGenerator, table, target, generators, behaviours); + const makeRowsFooter = (table, target, generators, behaviours) => run(opMakeRowsFooter, onCells, noop, noop, bodyCellGenerator, table, target, generators, behaviours); + const makeCellsHeader = (table, target, generators, behaviours) => run(opMakeCellsHeader, onUnlockedCells, noop, noop, headerCellGenerator, table, target, generators, behaviours); + const unmakeCellsHeader = (table, target, generators, behaviours) => run(opUnmakeCellsHeader, onUnlockedCells, noop, noop, bodyCellGenerator, table, target, generators, behaviours); + const mergeCells = (table, target, generators, behaviours) => run(opMergeCells, onUnlockedMergable, resize, noop, Generators.merging, table, target, generators, behaviours); + const unmergeCells = (table, target, generators, behaviours) => run(opUnmergeCells, onUnlockedUnmergable, resize, noop, Generators.merging, table, target, generators, behaviours); + const pasteCells = (table, target, generators, behaviours) => run(opPasteCells, onPaste, resize, noop, Generators.modification, table, target, generators, behaviours); + const pasteColsBefore = (table, target, generators, behaviours) => run(opPasteColsBefore, pasteColumnsExtractor(true), noop, noop, Generators.modification, table, target, generators, behaviours); + const pasteColsAfter = (table, target, generators, behaviours) => run(opPasteColsAfter, pasteColumnsExtractor(false), noop, noop, Generators.modification, table, target, generators, behaviours); + const pasteRowsBefore = (table, target, generators, behaviours) => run(opPasteRowsBefore, onPasteByEditor, noop, noop, Generators.modification, table, target, generators, behaviours); + const pasteRowsAfter = (table, target, generators, behaviours) => run(opPasteRowsAfter, onPasteByEditor, noop, noop, Generators.modification, table, target, generators, behaviours); + const getColumnsType = opGetColumnsType; + const getCellsType = opGetCellsType; + const getRowsType = opGetRowsType; - const transform = (mutation, settings = {}) => { - var _a; - const mode = (_a = settings.mode) !== null && _a !== void 0 ? _a : MouseDrag; - return setup(mutation, mode, settings); + const inSelection = (bounds, detail) => { + const leftEdge = detail.column; + const rightEdge = detail.column + detail.colspan - 1; + const topEdge = detail.row; + const bottomEdge = detail.row + detail.rowspan - 1; + return (leftEdge <= bounds.finishCol && rightEdge >= bounds.startCol) && (topEdge <= bounds.finishRow && bottomEdge >= bounds.startRow); }; - - const styles = css('ephox-snooker'); - const resolve = styles.resolve; - - const Mutation = () => { - const events = create$1({ - drag: Event([ - 'xDelta', - 'yDelta' - ]) - }); - const mutate = (x, y) => { - events.trigger.drag(x, y); - }; - return { - mutate, - events: events.registry - }; + // Note, something is *within* if it is completely contained within the bounds. + const isWithin = (bounds, detail) => { + return (detail.column >= bounds.startCol && + (detail.column + detail.colspan - 1) <= bounds.finishCol && + detail.row >= bounds.startRow && + (detail.row + detail.rowspan - 1) <= bounds.finishRow); }; - - const BarMutation = () => { - const events = create$1({ - drag: Event([ - 'xDelta', - 'yDelta', - 'target' - ]) - }); - let target = Optional.none(); - const delegate = Mutation(); - delegate.events.drag.bind(event => { - target.each(t => { - events.trigger.drag(event.xDelta, event.yDelta, t); - }); - }); - const assign = t => { - target = Optional.some(t); - }; - const get = () => { - return target; - }; - return { - assign, - get, - mutate: delegate.mutate, - events: events.registry - }; + const isRectangular = (warehouse, bounds) => { + let isRect = true; + const detailIsWithin = curry(isWithin, bounds); + for (let i = bounds.startRow; i <= bounds.finishRow; i++) { + for (let j = bounds.startCol; j <= bounds.finishCol; j++) { + isRect = isRect && Warehouse.getAt(warehouse, i, j).exists(detailIsWithin); + } + } + return isRect ? Optional.some(bounds) : Optional.none(); }; - const col = (column, x, y, w, h) => { - const bar = SugarElement.fromTag('div'); - setAll(bar, { - position: 'absolute', - left: x - w / 2 + 'px', - top: y + 'px', - height: h + 'px', - width: w + 'px' - }); - setAll$1(bar, { - 'data-column': column, - 'role': 'presentation' - }); - return bar; + const getBounds = (detailA, detailB) => { + return bounds(Math.min(detailA.row, detailB.row), Math.min(detailA.column, detailB.column), Math.max(detailA.row + detailA.rowspan - 1, detailB.row + detailB.rowspan - 1), Math.max(detailA.column + detailA.colspan - 1, detailB.column + detailB.colspan - 1)); }; - const row = (r, x, y, w, h) => { - const bar = SugarElement.fromTag('div'); - setAll(bar, { - position: 'absolute', - left: x + 'px', - top: y - h / 2 + 'px', - height: h + 'px', - width: w + 'px' - }); - setAll$1(bar, { - 'data-row': r, - 'role': 'presentation' - }); - return bar; + const getAnyBox = (warehouse, startCell, finishCell) => { + const startCoords = Warehouse.findItem(warehouse, startCell, eq$1); + const finishCoords = Warehouse.findItem(warehouse, finishCell, eq$1); + return startCoords.bind((sc) => { + return finishCoords.map((fc) => { + return getBounds(sc, fc); + }); + }); + }; + const getBox$1 = (warehouse, startCell, finishCell) => { + return getAnyBox(warehouse, startCell, finishCell).bind((bounds) => { + return isRectangular(warehouse, bounds); + }); }; - const resizeBar = resolve('resizer-bar'); - const resizeRowBar = resolve('resizer-rows'); - const resizeColBar = resolve('resizer-cols'); - const BAR_THICKNESS = 7; - const resizableRows = (warehouse, isResizable) => bind$2(warehouse.all, (row, i) => isResizable(row.element) ? [i] : []); - const resizableColumns = (warehouse, isResizable) => { - const resizableCols = []; - range$1(warehouse.grid.columns, index => { - const colElmOpt = Warehouse.getColumnAt(warehouse, index).map(col => col.element); - if (colElmOpt.forall(isResizable)) { - resizableCols.push(index); - } - }); - return filter$2(resizableCols, colIndex => { - const columnCells = Warehouse.filterItems(warehouse, cell => cell.column === colIndex); - return forall(columnCells, cell => isResizable(cell.element)); - }); - }; - const destroy = wire => { - const previous = descendants(wire.parent(), '.' + resizeBar); - each$2(previous, remove$6); + const moveBy$1 = (warehouse, cell, row, column) => { + return Warehouse.findItem(warehouse, cell, eq$1).bind((detail) => { + const startRow = row > 0 ? detail.row + detail.rowspan - 1 : detail.row; + const startCol = column > 0 ? detail.column + detail.colspan - 1 : detail.column; + const dest = Warehouse.getAt(warehouse, startRow + row, startCol + column); + return dest.map((d) => { + return d.element; + }); + }); }; - const drawBar = (wire, positions, create) => { - const origin = wire.origin(); - each$2(positions, cpOption => { - cpOption.each(cp => { - const bar = create(origin, cp); - add(bar, resizeBar); - append$1(wire.parent(), bar); + const intercepts$1 = (warehouse, start, finish) => { + return getAnyBox(warehouse, start, finish).map((bounds) => { + const inside = Warehouse.filterItems(warehouse, curry(inSelection, bounds)); + return map$1(inside, (detail) => { + return detail.element; + }); }); - }); }; - const refreshCol = (wire, colPositions, position, tableHeight) => { - drawBar(wire, colPositions, (origin, cp) => { - const colBar = col(cp.col, cp.x - origin.left, position.top - origin.top, BAR_THICKNESS, tableHeight); - add(colBar, resizeColBar); - return colBar; - }); + const parentCell = (warehouse, innerCell) => { + const isContainedBy = (c1, c2) => { + return contains(c2, c1); + }; + return Warehouse.findItem(warehouse, innerCell, isContainedBy).map((detail) => { + return detail.element; + }); }; - const refreshRow = (wire, rowPositions, position, tableWidth) => { - drawBar(wire, rowPositions, (origin, cp) => { - const rowBar = row(cp.row, position.left - origin.left, cp.y - origin.top, tableWidth, BAR_THICKNESS); - add(rowBar, resizeRowBar); - return rowBar; - }); + + const moveBy = (cell, deltaRow, deltaColumn) => { + return table(cell).bind((table) => { + const warehouse = getWarehouse(table); + return moveBy$1(warehouse, cell, deltaRow, deltaColumn); + }); + }; + const intercepts = (table, first, last) => { + const warehouse = getWarehouse(table); + return intercepts$1(warehouse, first, last); + }; + const nestedIntercepts = (table, first, firstTable, last, lastTable) => { + const warehouse = getWarehouse(table); + const optStartCell = eq$1(table, firstTable) ? Optional.some(first) : parentCell(warehouse, first); + const optLastCell = eq$1(table, lastTable) ? Optional.some(last) : parentCell(warehouse, last); + return optStartCell.bind((startCell) => optLastCell.bind((lastCell) => intercepts$1(warehouse, startCell, lastCell))); + }; + const getBox = (table, first, last) => { + const warehouse = getWarehouse(table); + return getBox$1(warehouse, first, last); + }; + // Private method ... keep warehouse in snooker, please. + const getWarehouse = Warehouse.fromTable; + + const DefaultRenderOptions = { + styles: { + 'border-collapse': 'collapse', + 'width': '100%' + }, + attributes: { + border: '1' + }, + colGroups: false + }; + const tableHeaderCell = () => SugarElement.fromTag('th'); + const tableCell = () => SugarElement.fromTag('td'); + const tableColumn = () => SugarElement.fromTag('col'); + const createRow = (columns, rowHeaders, columnHeaders, rowIndex) => { + const tr = SugarElement.fromTag('tr'); + for (let j = 0; j < columns; j++) { + const td = rowIndex < rowHeaders || j < columnHeaders ? tableHeaderCell() : tableCell(); + if (j < columnHeaders) { + set$2(td, 'scope', 'row'); + } + if (rowIndex < rowHeaders) { + set$2(td, 'scope', 'col'); + } + // Note, this is a placeholder so that the cells have height. The unicode character didn't work in IE10. + append$1(td, SugarElement.fromTag('br')); + append$1(tr, td); + } + return tr; + }; + const createGroupRow = (columns) => { + const columnGroup = SugarElement.fromTag('colgroup'); + range$1(columns, () => append$1(columnGroup, tableColumn())); + return columnGroup; + }; + const createRows = (rows, columns, rowHeaders, columnHeaders) => range$1(rows, (r) => createRow(columns, rowHeaders, columnHeaders, r)); + const render = (rows, columns, rowHeaders, columnHeaders, headerType, renderOpts = DefaultRenderOptions) => { + const table = SugarElement.fromTag('table'); + const rowHeadersGoInThead = headerType !== 'cells'; + setAll(table, renderOpts.styles); + setAll$1(table, renderOpts.attributes); + if (renderOpts.colGroups) { + append$1(table, createGroupRow(columns)); + } + const actualRowHeaders = Math.min(rows, rowHeaders); + if (rowHeadersGoInThead && rowHeaders > 0) { + const thead = SugarElement.fromTag('thead'); + append$1(table, thead); + const theadRowHeaders = headerType === 'sectionCells' ? actualRowHeaders : 0; + const theadRows = createRows(rowHeaders, columns, theadRowHeaders, columnHeaders); + append(thead, theadRows); + } + const tbody = SugarElement.fromTag('tbody'); + append$1(table, tbody); + const numRows = rowHeadersGoInThead ? rows - actualRowHeaders : rows; + const numRowHeaders = rowHeadersGoInThead ? 0 : rowHeaders; + const tbodyRows = createRows(numRows, columns, numRowHeaders, columnHeaders); + append(tbody, tbodyRows); + return table; + }; + + const Event = (fields) => { + let handlers = []; + const bind = (handler) => { + if (handler === undefined) { + throw new Error('Event bind error: undefined handler'); + } + handlers.push(handler); + }; + const unbind = (handler) => { + // This is quite a bit slower than handlers.splice() but we hate mutation. + // Unbind isn't used very often so it should be ok. + handlers = filter$2(handlers, (h) => { + return h !== handler; + }); + }; + const trigger = (...args) => { + const event = {}; + each$2(fields, (name, i) => { + event[name] = args[i]; + }); + each$2(handlers, (handler) => { + handler(event); + }); + }; + return { + bind, + unbind, + trigger + }; + }; + + /** :: {name : Event} -> Events */ + const create$3 = (typeDefs) => { + const registry = map(typeDefs, (event) => { + return { + bind: event.bind, + unbind: event.unbind + }; + }); + const trigger = map(typeDefs, (event) => { + return event.trigger; + }); + return { + registry, + trigger + }; + }; + + const DragMode = exactly([ + 'compare', + 'extract', + 'mutate', + 'sink' + ]); + const DragSink = exactly([ + 'element', + 'start', + 'stop', + 'destroy' + ]); + const DragApi = exactly([ + 'forceDrop', + 'drop', + 'move', + 'delayDrop' + ]); + + const InDrag = () => { + let previous = Optional.none(); + const reset = () => { + previous = Optional.none(); + }; + // Return position delta between previous position and nu position, + // or None if this is the first. Set the previous position to nu. + const update = (mode, nu) => { + const result = previous.map((old) => { + return mode.compare(old, nu); + }); + previous = Optional.some(nu); + return result; + }; + const onEvent = (event, mode) => { + const dataOption = mode.extract(event); + // Dragster move events require a position delta. The moveevent is only triggered + // on the second and subsequent dragster move events. The first is dropped. + dataOption.each((data) => { + const offset = update(mode, data); + offset.each((d) => { + events.trigger.move(d); + }); + }); + }; + const events = create$3({ + move: Event(['info']) + }); + return { + onEvent, + reset, + events: events.registry + }; + }; + + const NoDrag = () => { + const events = create$3({ + move: Event(['info']) + }); + return { + onEvent: noop, + reset: noop, + events: events.registry + }; + }; + + const Movement = () => { + const noDragState = NoDrag(); + const inDragState = InDrag(); + let dragState = noDragState; + const on = () => { + dragState.reset(); + dragState = inDragState; + }; + const off = () => { + dragState.reset(); + dragState = noDragState; + }; + const onEvent = (event, mode) => { + dragState.onEvent(event, mode); + }; + const isOn = () => { + return dragState === inDragState; + }; + return { + on, + off, + isOn, + onEvent, + events: inDragState.events + }; + }; + + const setup = (mutation, mode, settings) => { + let active = false; + const events = create$3({ + start: Event([]), + stop: Event([]) + }); + const movement = Movement(); + const drop = () => { + sink.stop(); + if (movement.isOn()) { + movement.off(); + events.trigger.stop(); + } + }; + const throttledDrop = last$1(drop, 200); + const go = (parent) => { + sink.start(parent); + movement.on(); + events.trigger.start(); + }; + const mousemove = (event) => { + throttledDrop.cancel(); + movement.onEvent(event, mode); + }; + movement.events.move.bind((event) => { + mode.mutate(mutation, event.info); + }); + const on = () => { + active = true; + }; + const off = () => { + active = false; + // acivate some events here? + }; + const isActive = () => active; + const runIfActive = (f) => { + return (...args) => { + if (active) { + f.apply(null, args); + } + }; + }; + const sink = mode.sink(DragApi({ + // ASSUMPTION: runIfActive is not needed for mousedown. This is pretty much a safety measure for + // inconsistent situations so that we don't block input. + forceDrop: drop, + drop: runIfActive(drop), + move: runIfActive(mousemove), + delayDrop: runIfActive(throttledDrop.throttle) + }), settings); + const destroy = () => { + sink.destroy(); + }; + return { + element: sink.element, + go, + on, + off, + isActive, + destroy, + events: events.registry + }; + }; + + const styles$1 = css('ephox-dragster'); + const resolve$1 = styles$1.resolve; + + const Blocker = (options) => { + const settings = { + layerClass: resolve$1('blocker'), + ...options + }; + const div = SugarElement.fromTag('div'); + set$2(div, 'role', 'presentation'); + setAll(div, { + position: 'fixed', + left: '0px', + top: '0px', + width: '100%', + height: '100%' + }); + add$1(div, resolve$1('blocker')); + add$1(div, settings.layerClass); + const element = constant(div); + const destroy = () => { + remove$5(div); + }; + return { + element, + destroy + }; + }; + + const compare = (old, nu) => { + return SugarPosition(nu.left - old.left, nu.top - old.top); + }; + const extract = (event) => { + return Optional.some(SugarPosition(event.x, event.y)); + }; + const mutate = (mutation, info) => { + mutation.mutate(info.left, info.top); + }; + const sink = (dragApi, settings) => { + const blocker = Blocker(settings); + // Included for safety. If the blocker has stayed on the screen, get rid of it on a click. + const mdown = bind(blocker.element(), 'mousedown', dragApi.forceDrop); + const mup = bind(blocker.element(), 'mouseup', dragApi.drop); + const mmove = bind(blocker.element(), 'mousemove', dragApi.move); + const mout = bind(blocker.element(), 'mouseout', dragApi.delayDrop); + const destroy = () => { + blocker.destroy(); + mup.unbind(); + mmove.unbind(); + mout.unbind(); + mdown.unbind(); + }; + const start = (parent) => { + append$1(parent, blocker.element()); + }; + const stop = () => { + remove$5(blocker.element()); + }; + return DragSink({ + element: blocker.element, + start, + stop, + destroy + }); + }; + var MouseDrag = DragMode({ + compare, + extract, + sink, + mutate + }); + + const transform = (mutation, settings = {}) => { + var _a; + const mode = (_a = settings.mode) !== null && _a !== void 0 ? _a : MouseDrag; + return setup(mutation, mode, settings); + }; + + const styles = css('ephox-snooker'); + const resolve = styles.resolve; + + const Mutation = () => { + const events = create$3({ + drag: Event(['xDelta', 'yDelta']) + }); + const mutate = (x, y) => { + events.trigger.drag(x, y); + }; + return { + mutate, + events: events.registry + }; + }; + + const BarMutation = () => { + const events = create$3({ + drag: Event(['xDelta', 'yDelta', 'target']) + }); + let target = Optional.none(); + const delegate = Mutation(); + delegate.events.drag.bind((event) => { + target.each((t) => { + // There is always going to be this padding / border collapse / margin problem with widths. I'll have to resolve that. + events.trigger.drag(event.xDelta, event.yDelta, t); + }); + }); + const assign = (t) => { + target = Optional.some(t); + }; + const get = () => { + return target; + }; + return { + assign, + get, + mutate: delegate.mutate, + events: events.registry + }; + }; + + const col = (column, x, y, w, h) => { + const bar = SugarElement.fromTag('div'); + setAll(bar, { + position: 'absolute', + left: x - w / 2 + 'px', + top: y + 'px', + height: h + 'px', + width: w + 'px' + }); + setAll$1(bar, { 'data-mce-bogus': 'all', 'data-column': column, 'role': 'presentation' }); + return bar; + }; + const row = (r, x, y, w, h) => { + const bar = SugarElement.fromTag('div'); + setAll(bar, { + position: 'absolute', + left: x + 'px', + top: y - h / 2 + 'px', + height: h + 'px', + width: w + 'px' + }); + setAll$1(bar, { 'data-mce-bogus': 'all', 'data-row': r, 'role': 'presentation' }); + return bar; + }; + + const resizeBar = resolve('resizer-bar'); + const resizeRowBar = resolve('resizer-rows'); + const resizeColBar = resolve('resizer-cols'); + const BAR_THICKNESS = 7; + const resizableRows = (warehouse, isResizable) => bind$2(warehouse.all, (row, i) => isResizable(row.element) ? [i] : []); + const resizableColumns = (warehouse, isResizable) => { + const resizableCols = []; + // Check col elements and see if they are resizable + range$1(warehouse.grid.columns, (index) => { + // With use of forall, index will be included if col doesn't exist meaning the column cells will be checked below + const colElmOpt = Warehouse.getColumnAt(warehouse, index).map((col) => col.element); + if (colElmOpt.forall(isResizable)) { + resizableCols.push(index); + } + }); + // Check cells of the resizable columns and make sure they are resizable + return filter$2(resizableCols, (colIndex) => { + const columnCells = Warehouse.filterItems(warehouse, (cell) => cell.column === colIndex); + return forall(columnCells, (cell) => isResizable(cell.element)); + }); + }; + const destroy = (wire) => { + const previous = descendants(wire.parent(), '.' + resizeBar); + each$2(previous, remove$5); + }; + const drawBar = (wire, positions, create) => { + const origin = wire.origin(); + each$2(positions, (cpOption) => { + cpOption.each((cp) => { + const bar = create(origin, cp); + add$1(bar, resizeBar); + append$1(wire.parent(), bar); + }); + }); + }; + const refreshCol = (wire, colPositions, position, tableHeight) => { + drawBar(wire, colPositions, (origin, cp) => { + const colBar = col(cp.col, cp.x - origin.left, position.top - origin.top, BAR_THICKNESS, tableHeight); + add$1(colBar, resizeColBar); + return colBar; + }); + }; + const refreshRow = (wire, rowPositions, position, tableWidth) => { + drawBar(wire, rowPositions, (origin, cp) => { + const rowBar = row(cp.row, position.left - origin.left, cp.y - origin.top, tableWidth, BAR_THICKNESS); + add$1(rowBar, resizeRowBar); + return rowBar; + }); }; const refreshGrid = (warhouse, wire, table, rows, cols) => { - const position = absolute(table); - const isResizable = wire.isResizable; - const rowPositions = rows.length > 0 ? height.positions(rows, table) : []; - const resizableRowBars = rowPositions.length > 0 ? resizableRows(warhouse, isResizable) : []; - const resizableRowPositions = filter$2(rowPositions, (_pos, i) => exists(resizableRowBars, barIndex => i === barIndex)); - refreshRow(wire, resizableRowPositions, position, getOuter$2(table)); - const colPositions = cols.length > 0 ? width.positions(cols, table) : []; - const resizableColBars = colPositions.length > 0 ? resizableColumns(warhouse, isResizable) : []; - const resizableColPositions = filter$2(colPositions, (_pos, i) => exists(resizableColBars, barIndex => i === barIndex)); - refreshCol(wire, resizableColPositions, position, getOuter$1(table)); + const position = absolute(table); + const isResizable = wire.isResizable; + const rowPositions = rows.length > 0 ? height.positions(rows, table) : []; + const resizableRowBars = rowPositions.length > 0 ? resizableRows(warhouse, isResizable) : []; + const resizableRowPositions = filter$2(rowPositions, (_pos, i) => exists(resizableRowBars, (barIndex) => i === barIndex)); + refreshRow(wire, resizableRowPositions, position, getOuter(table)); + const colPositions = cols.length > 0 ? width.positions(cols, table) : []; + const resizableColBars = colPositions.length > 0 ? resizableColumns(warhouse, isResizable) : []; + const resizableColPositions = filter$2(colPositions, (_pos, i) => exists(resizableColBars, (barIndex) => i === barIndex)); + refreshCol(wire, resizableColPositions, position, getOuter$1(table)); }; const refresh = (wire, table) => { - destroy(wire); - if (wire.isResizable(table)) { - const warehouse = Warehouse.fromTable(table); - const rows$1 = rows(warehouse); - const cols = columns(warehouse); - refreshGrid(warehouse, wire, table, rows$1, cols); - } + destroy(wire); + if (wire.isResizable(table)) { + const warehouse = Warehouse.fromTable(table); + const rows$1 = rows(warehouse); + const cols = columns(warehouse); + refreshGrid(warehouse, wire, table, rows$1, cols); + } }; const each = (wire, f) => { - const bars = descendants(wire.parent(), '.' + resizeBar); - each$2(bars, f); + const bars = descendants(wire.parent(), '.' + resizeBar); + each$2(bars, f); }; - const hide = wire => { - each(wire, bar => { - set$1(bar, 'display', 'none'); - }); + const hide = (wire) => { + each(wire, (bar) => { + set$1(bar, 'display', 'none'); + }); }; - const show = wire => { - each(wire, bar => { - set$1(bar, 'display', 'block'); - }); + const show = (wire) => { + each(wire, (bar) => { + set$1(bar, 'display', 'block'); + }); }; - const isRowBar = element => { - return has(element, resizeRowBar); + const isRowBar = (element) => { + return has(element, resizeRowBar); }; - const isColBar = element => { - return has(element, resizeColBar); + const isColBar = (element) => { + return has(element, resizeColBar); }; const resizeBarDragging = resolve('resizer-bar-dragging'); - const BarManager = wire => { - const mutation = BarMutation(); - const resizing = transform(mutation, {}); - let hoverTable = Optional.none(); - const getResizer = (element, type) => { - return Optional.from(get$b(element, type)); - }; - mutation.events.drag.bind(event => { - getResizer(event.target, 'data-row').each(_dataRow => { - const currentRow = getCssValue(event.target, 'top'); - set$1(event.target, 'top', currentRow + event.yDelta + 'px'); - }); - getResizer(event.target, 'data-column').each(_dataCol => { - const currentCol = getCssValue(event.target, 'left'); - set$1(event.target, 'left', currentCol + event.xDelta + 'px'); - }); - }); - const getDelta = (target, dir) => { - const newX = getCssValue(target, dir); - const oldX = getAttrValue(target, 'data-initial-' + dir, 0); - return newX - oldX; - }; - resizing.events.stop.bind(() => { - mutation.get().each(target => { - hoverTable.each(table => { - getResizer(target, 'data-row').each(row => { - const delta = getDelta(target, 'top'); - remove$7(target, 'data-initial-top'); - events.trigger.adjustHeight(table, delta, parseInt(row, 10)); + const BarManager = (wire) => { + const mutation = BarMutation(); + const resizing = transform(mutation, {}); + let hoverTable = Optional.none(); + const getResizer = (element, type) => { + return Optional.from(get$b(element, type)); + }; + /* Reposition the bar as the user drags */ + mutation.events.drag.bind((event) => { + getResizer(event.target, 'data-row').each((_dataRow) => { + const currentRow = getCssValue(event.target, 'top'); + set$1(event.target, 'top', currentRow + event.yDelta + 'px'); + }); + getResizer(event.target, 'data-column').each((_dataCol) => { + const currentCol = getCssValue(event.target, 'left'); + set$1(event.target, 'left', currentCol + event.xDelta + 'px'); }); - getResizer(target, 'data-column').each(column => { - const delta = getDelta(target, 'left'); - remove$7(target, 'data-initial-left'); - events.trigger.adjustWidth(table, delta, parseInt(column, 10)); + }); + const getDelta = (target, dir) => { + const newX = getCssValue(target, dir); + const oldX = getAttrValue(target, 'data-initial-' + dir, 0); + return newX - oldX; + }; + /* Resize the column once the user releases the mouse */ + resizing.events.stop.bind(() => { + mutation.get().each((target) => { + hoverTable.each((table) => { + getResizer(target, 'data-row').each((row) => { + const delta = getDelta(target, 'top'); + remove$6(target, 'data-initial-top'); + events.trigger.adjustHeight(table, delta, parseInt(row, 10)); + }); + getResizer(target, 'data-column').each((column) => { + const delta = getDelta(target, 'left'); + remove$6(target, 'data-initial-left'); + events.trigger.adjustWidth(table, delta, parseInt(column, 10)); + }); + refresh(wire, table); + }); + }); + }); + const handler = (target, dir) => { + events.trigger.startAdjust(); + mutation.assign(target); + set$2(target, 'data-initial-' + dir, getCssValue(target, dir)); + add$1(target, resizeBarDragging); + set$1(target, 'opacity', '0.2'); + resizing.go(wire.dragContainer()); + }; + /* mousedown on resize bar: start dragging when the bar is clicked, storing the initial position. */ + const mousedown = bind(wire.parent(), 'mousedown', (event) => { + if (isRowBar(event.target)) { + handler(event.target, 'top'); + } + if (isColBar(event.target)) { + handler(event.target, 'left'); + } + }); + const isRoot = (e) => { + return eq$1(e, wire.view()); + }; + const findClosestEditableTable = (target) => closest$1(target, 'table', isRoot).filter(isEditable$1); + const isResizer = (target) => has(target, 'ephox-snooker-resizer-bar') || has(target, 'ephox-dragster-blocker'); + /* mouseover on table: When the mouse moves within the CONTENT AREA (NOT THE TABLE), refresh the bars. */ + const mouseover = bind(wire.view(), 'mouseover', (event) => { + findClosestEditableTable(event.target).fold(() => { + /* + * mouseout is not reliable within ContentEditable, so for all other mouseover events we clear bars. + * This is fairly safe to do frequently; it's a single querySelectorAll() on the content and Arr.map on the result. + * If we _really_ need to optimise it further, we can start caching the bar references in the wire somehow. + * + * Because the resizers were moved into the editor for inline mode, we need to check if the event target is not a resizer. + */ + if (inBody(event.target) && !isResizer(event.target)) { + destroy(wire); + } + }, (table) => { + if (resizing.isActive()) { + hoverTable = Optional.some(table); + refresh(wire, table); + } }); - refresh(wire, table); - }); - }); - }); - const handler = (target, dir) => { - events.trigger.startAdjust(); - mutation.assign(target); - set$2(target, 'data-initial-' + dir, getCssValue(target, dir)); - add(target, resizeBarDragging); - set$1(target, 'opacity', '0.2'); - resizing.go(wire.dragContainer()); - }; - const mousedown = bind(wire.parent(), 'mousedown', event => { - if (isRowBar(event.target)) { - handler(event.target, 'top'); - } - if (isColBar(event.target)) { - handler(event.target, 'left'); - } - }); - const isRoot = e => { - return eq$1(e, wire.view()); - }; - const findClosestEditableTable = target => closest$1(target, 'table', isRoot).filter(isEditable$1); - const mouseover = bind(wire.view(), 'mouseover', event => { - findClosestEditableTable(event.target).fold(() => { - if (inBody(event.target)) { + }); + const destroy$1 = () => { + mousedown.unbind(); + mouseover.unbind(); + resizing.destroy(); destroy(wire); - } - }, table => { - if (resizing.isActive()) { - hoverTable = Optional.some(table); - refresh(wire, table); - } + }; + const refresh$1 = (tbl) => { + refresh(wire, tbl); + }; + const events = create$3({ + adjustHeight: Event(['table', 'delta', 'row']), + adjustWidth: Event(['table', 'delta', 'column']), + startAdjust: Event([]) }); - }); - const destroy$1 = () => { - mousedown.unbind(); - mouseover.unbind(); - resizing.destroy(); - destroy(wire); - }; - const refresh$1 = tbl => { - refresh(wire, tbl); - }; - const events = create$1({ - adjustHeight: Event([ - 'table', - 'delta', - 'row' - ]), - adjustWidth: Event([ - 'table', - 'delta', - 'column' - ]), - startAdjust: Event([]) - }); - return { - destroy: destroy$1, - refresh: refresh$1, - on: resizing.on, - off: resizing.off, - hideBars: curry(hide, wire), - showBars: curry(show, wire), - events: events.registry - }; - }; - - const create = (wire, resizing, lazySizing) => { - const hdirection = height; - const vdirection = width; - const manager = BarManager(wire); - const events = create$1({ - beforeResize: Event([ - 'table', - 'type' - ]), - afterResize: Event([ - 'table', - 'type' - ]), - startDrag: Event([]) - }); - manager.events.adjustHeight.bind(event => { - const table = event.table; - events.trigger.beforeResize(table, 'row'); - const delta = hdirection.delta(event.delta, table); - adjustHeight(table, delta, event.row); - events.trigger.afterResize(table, 'row'); - }); - manager.events.startAdjust.bind(_event => { - events.trigger.startDrag(); - }); - manager.events.adjustWidth.bind(event => { - const table = event.table; - events.trigger.beforeResize(table, 'col'); - const delta = vdirection.delta(event.delta, table); - const tableSize = lazySizing(table); - adjustWidth(table, delta, event.column, resizing, tableSize); - events.trigger.afterResize(table, 'col'); - }); - return { - on: manager.on, - off: manager.off, - refreshBars: manager.refresh, - hideBars: manager.hideBars, - showBars: manager.showBars, - destroy: manager.destroy, - events: events.registry - }; - }; - const TableResize = { create }; - - const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295; - - let unique = 0; - const generate = prefix => { - const date = new Date(); - const time = date.getTime(); - const random$1 = Math.floor(random() * 1000000000); - unique++; - return prefix + '_' + random$1 + unique + String(time); + return { + destroy: destroy$1, + refresh: refresh$1, + on: resizing.on, + off: resizing.off, + hideBars: curry(hide, wire), + showBars: curry(show, wire), + events: events.registry + }; }; - const only = (element, isResizable) => { - const parent = isDocument(element) ? documentElement(element) : element; - return { - parent: constant(parent), - view: constant(element), - dragContainer: constant(parent), - origin: constant(SugarPosition(0, 0)), - isResizable - }; + const create$2 = (wire, resizing, lazySizing) => { + const hdirection = height; + const vdirection = width; + const manager = BarManager(wire); + const events = create$3({ + beforeResize: Event(['table', 'type']), + afterResize: Event(['table', 'type']), + startDrag: Event([]), + }); + manager.events.adjustHeight.bind((event) => { + const table = event.table; + events.trigger.beforeResize(table, 'row'); + const delta = hdirection.delta(event.delta, table); + // TODO: Use the resizing behaviour for heights as well + adjustHeight(table, delta, event.row); + events.trigger.afterResize(table, 'row'); + }); + manager.events.startAdjust.bind((_event) => { + events.trigger.startDrag(); + }); + manager.events.adjustWidth.bind((event) => { + const table = event.table; + events.trigger.beforeResize(table, 'col'); + const delta = vdirection.delta(event.delta, table); + const tableSize = lazySizing(table); + adjustWidth(table, delta, event.column, resizing, tableSize); + events.trigger.afterResize(table, 'col'); + }); + return { + on: manager.on, + off: manager.off, + refreshBars: manager.refresh, + hideBars: manager.hideBars, + showBars: manager.showBars, + destroy: manager.destroy, + events: events.registry + }; }; - const detached = (editable, chrome, isResizable) => { - const origin = () => absolute(chrome); - return { - parent: constant(chrome), - view: constant(editable), - dragContainer: constant(chrome), - origin, - isResizable - }; - }; - const body = (editable, chrome, isResizable) => { - return { - parent: constant(chrome), - view: constant(editable), - dragContainer: constant(chrome), - origin: constant(SugarPosition(0, 0)), - isResizable - }; - }; - const scrollable = (editable, chrome, dragContainer, isResizable) => { - return { - parent: constant(chrome), - view: constant(editable), - dragContainer: constant(dragContainer), - origin: () => absolute(chrome), - isResizable - }; + const TableResize = { + create: create$2 }; - const ResizeWire = { - only, - detached, - body, - scrollable - }; - - const createContainer = position => { - const id = generate('resizer-container'); - const container = SugarElement.fromTag('div'); - set$2(container, 'id', id); - setAll(container, { - position, - height: '0', - width: '0', - padding: '0', - margin: '0', - border: '0' - }); - return container; - }; - const getInlineResizeWire = (editor, isResizable) => { - const isSplitUiMode$1 = isSplitUiMode(editor); - const editorBody = SugarElement.fromDom(editor.getBody()); - const container = createContainer(isSplitUiMode$1 ? 'relative' : 'static'); - const body = body$1(); - if (isSplitUiMode$1) { - after$5(editorBody, container); - return ResizeWire.scrollable(editorBody, container, body, isResizable); - } - append$1(body, container); - return ResizeWire.body(editorBody, container, isResizable); + + const option = (name) => (editor) => editor.options.get(name); + // Note: This is also contained in the table plugin Options.ts file + const defaultWidth = '100%'; + const getPixelForcedWidth = (editor) => { + var _a; + // Determine the inner size of the parent block element where the table will be inserted + const dom = editor.dom; + const parentBlock = (_a = dom.getParent(editor.selection.getStart(), dom.isBlock)) !== null && _a !== void 0 ? _a : editor.getBody(); + return getInner(SugarElement.fromDom(parentBlock)) + 'px'; + }; + // Note: This is also contained in the table plugin Options.ts file + const determineDefaultTableStyles = (editor, defaultStyles) => { + if (isTableResponsiveForced(editor) || !shouldStyleWithCss(editor)) { + return defaultStyles; + } + else if (isTablePixelsForced(editor)) { + return { ...defaultStyles, width: getPixelForcedWidth(editor) }; + } + else { + return { ...defaultStyles, width: defaultWidth }; + } }; - const get = (editor, isResizable) => { - if (editor.inline) { - return getInlineResizeWire(editor, isResizable); - } - return ResizeWire.only(SugarElement.fromDom(editor.getDoc()), isResizable); + // Note: This is also contained in the table plugin Options.ts file + const determineDefaultTableAttributes = (editor, defaultAttributes) => { + if (isTableResponsiveForced(editor) || shouldStyleWithCss(editor)) { + return defaultAttributes; + } + else if (isTablePixelsForced(editor)) { + return { ...defaultAttributes, width: getPixelForcedWidth(editor) }; + } + else { + return { ...defaultAttributes, width: defaultWidth }; + } + }; + const register = (editor) => { + const registerOption = editor.options.register; + registerOption('table_clone_elements', { + processor: 'string[]' + }); + registerOption('table_use_colgroups', { + processor: 'boolean', + default: true + }); + registerOption('table_header_type', { + processor: (value) => { + const valid = contains$2(['section', 'cells', 'sectionCells', 'auto'], value); + return valid ? { value, valid } : { valid: false, message: 'Must be one of: section, cells, sectionCells or auto.' }; + }, + default: 'section' + }); + registerOption('table_sizing_mode', { + processor: 'string', + default: 'auto' + }); + registerOption('table_default_attributes', { + processor: 'object', + default: { + border: '1' + } + }); + registerOption('table_default_styles', { + processor: 'object', + default: { + 'border-collapse': 'collapse', + } + }); + registerOption('table_column_resizing', { + processor: (value) => { + const valid = contains$2(['preservetable', 'resizetable'], value); + return valid ? { value, valid } : { valid: false, message: 'Must be preservetable, or resizetable.' }; + }, + default: 'preservetable' + }); + registerOption('table_resize_bars', { + processor: 'boolean', + default: true + }); + registerOption('table_style_by_css', { + processor: 'boolean', + default: true + }); + registerOption('table_merge_content_on_paste', { + processor: 'boolean', + default: true + }); + }; + const getTableCloneElements = (editor) => { + return Optional.from(editor.options.get('table_clone_elements')); }; - const remove = (editor, wire) => { - if (editor.inline) { - remove$6(wire.parent()); - } + const hasTableObjectResizing = (editor) => { + const objectResizing = editor.options.get('object_resizing'); + return contains$2(objectResizing.split(','), 'table'); + }; + const getTableHeaderType = option('table_header_type'); + const getTableColumnResizingBehaviour = option('table_column_resizing'); + const isPreserveTableColumnResizing = (editor) => getTableColumnResizingBehaviour(editor) === 'preservetable'; + const isResizeTableColumnResizing = (editor) => getTableColumnResizingBehaviour(editor) === 'resizetable'; + const getTableSizingMode = option('table_sizing_mode'); + const isTablePercentagesForced = (editor) => getTableSizingMode(editor) === 'relative'; + const isTablePixelsForced = (editor) => getTableSizingMode(editor) === 'fixed'; + const isTableResponsiveForced = (editor) => getTableSizingMode(editor) === 'responsive'; + const hasTableResizeBars = option('table_resize_bars'); + const shouldStyleWithCss = option('table_style_by_css'); + const shouldMergeContentOnPaste = option('table_merge_content_on_paste'); + const getTableDefaultAttributes = (editor) => { + // Note: The we don't rely on the default here as we need to dynamically lookup the widths based on the current editor state + const options = editor.options; + const defaultAttributes = options.get('table_default_attributes'); + return options.isSet('table_default_attributes') ? defaultAttributes : determineDefaultTableAttributes(editor, defaultAttributes); + }; + const getTableDefaultStyles = (editor) => { + // Note: The we don't rely on the default here as we need to dynamically lookup the widths based on the current editor state + const options = editor.options; + const defaultStyles = options.get('table_default_styles'); + return options.isSet('table_default_styles') ? defaultStyles : determineDefaultTableStyles(editor, defaultStyles); }; + const tableUseColumnGroup = option('table_use_colgroups'); - const isTable = node => isNonNullable(node) && node.nodeName === 'TABLE'; - const barResizerPrefix = 'bar-'; - const isResizable = elm => get$b(elm, 'data-mce-resize') !== 'false'; - const syncTableCellPixels = table => { - const warehouse = Warehouse.fromTable(table); - if (!Warehouse.hasColumns(warehouse)) { - each$2(cells$1(table), cell => { - const computedWidth = get$a(cell, 'width'); - set$1(cell, 'width', computedWidth); - remove$7(cell, 'width'); - }); - } - }; - const isCornerResize = origin => startsWith(origin, 'corner-'); - const getCornerLocation = origin => removeLeading(origin, 'corner-'); - const TableResizeHandler = editor => { - const selectionRng = value(); - const tableResize = value(); - const resizeWire = value(); - let startW; - let startRawW; - let startH; - let startRawH; - const lazySizing = table => get$5(editor, table); - const lazyResizingBehaviour = () => isPreserveTableColumnResizing(editor) ? preserveTable() : resizeTable(); - const getNumColumns = table => getGridSize(table).columns; - const getNumRows = table => getGridSize(table).rows; - const afterCornerResize = (table, origin, width, height) => { - const location = getCornerLocation(origin); - const isRightEdgeResize = endsWith(location, 'e'); - const isNorthEdgeResize = startsWith(location, 'n'); - if (startRawW === '') { - convertToPercentSizeWidth(table); - } - if (startRawH === '') { - convertToPixelSizeHeight(table); - } - if (width !== startW && startRawW !== '') { - set$1(table, 'width', startRawW); - const resizing = lazyResizingBehaviour(); - const tableSize = lazySizing(table); - const col = isPreserveTableColumnResizing(editor) || isRightEdgeResize ? getNumColumns(table) - 1 : 0; - adjustWidth(table, width - startW, col, resizing, tableSize); - } else if (isPercentage$1(startRawW)) { - const percentW = parseFloat(startRawW.replace('%', '')); - const targetPercentW = width * percentW / startW; - set$1(table, 'width', targetPercentW + '%'); - } - if (isPixel(startRawW)) { - syncTableCellPixels(table); - } - if (height !== startH && startRawH !== '') { - set$1(table, 'height', startRawH); - const idx = isNorthEdgeResize ? 0 : getNumRows(table) - 1; - adjustHeight(table, height - startH, idx); - } - }; - const destroy = () => { - tableResize.on(sz => { - sz.destroy(); - }); - resizeWire.on(w => { - remove(editor, w); - }); - }; - editor.on('init', () => { - const rawWire = get(editor, isResizable); - resizeWire.set(rawWire); - if (hasTableObjectResizing(editor) && hasTableResizeBars(editor)) { - const resizing = lazyResizingBehaviour(); - const sz = TableResize.create(rawWire, resizing, lazySizing); - if (!editor.mode.isReadOnly()) { - sz.on(); - } - sz.events.startDrag.bind(_event => { - selectionRng.set(editor.selection.getRng()); - }); - sz.events.beforeResize.bind(event => { - const rawTable = event.table.dom; - fireObjectResizeStart(editor, rawTable, getPixelWidth(rawTable), getPixelHeight(rawTable), barResizerPrefix + event.type); - }); - sz.events.afterResize.bind(event => { - const table = event.table; - const rawTable = table.dom; - removeDataStyle(table); - selectionRng.on(rng => { - editor.selection.setRng(rng); - editor.focus(); - }); - fireObjectResized(editor, rawTable, getPixelWidth(rawTable), getPixelHeight(rawTable), barResizerPrefix + event.type); - editor.undoManager.add(); - }); - tableResize.set(sz); - } - }); - editor.on('ObjectResizeStart', e => { - const targetElm = e.target; - if (isTable(targetElm) && !editor.mode.isReadOnly()) { - const table = SugarElement.fromDom(targetElm); - each$2(editor.dom.select('.mce-clonedresizable'), clone => { - editor.dom.addClass(clone, 'mce-' + getTableColumnResizingBehaviour(editor) + '-columns'); - }); - if (!isPixelSizing(table) && isTablePixelsForced(editor)) { - convertToPixelSizeWidth(table); - } else if (!isPercentSizing(table) && isTablePercentagesForced(editor)) { - convertToPercentSizeWidth(table); - } - if (isNoneSizing(table) && startsWith(e.origin, barResizerPrefix)) { - convertToPercentSizeWidth(table); - } - startW = e.width; - startRawW = isTableResponsiveForced(editor) ? '' : getRawWidth(editor, targetElm).getOr(''); - startH = e.height; - startRawH = getRawHeight(editor, targetElm).getOr(''); - } - }); - editor.on('ObjectResized', e => { - const targetElm = e.target; - if (isTable(targetElm)) { - const table = SugarElement.fromDom(targetElm); - const origin = e.origin; - if (isCornerResize(origin)) { - afterCornerResize(table, origin, e.width, e.height); - } - removeDataStyle(table); - fireTableModified(editor, table.dom, styleModified); - } - }); - const showResizeBars = () => { - tableResize.on(resize => { - resize.on(); - resize.showBars(); - }); - }; - const hideResizeBars = () => { - tableResize.on(resize => { - resize.off(); - resize.hideBars(); - }); - }; - editor.on('DisabledStateChange', e => { - e.state ? hideResizeBars() : showResizeBars(); - }); - editor.on('SwitchMode', () => { - editor.mode.isReadOnly() ? hideResizeBars() : showResizeBars(); - }); - editor.on('dragstart dragend', e => { - e.type === 'dragstart' ? hideResizeBars() : showResizeBars(); - }); - editor.on('remove', () => { - destroy(); - }); - const refresh = table => { - tableResize.on(resize => resize.refreshBars(SugarElement.fromDom(table))); - }; - const hide = () => { - tableResize.on(resize => resize.hideBars()); - }; - const show = () => { - tableResize.on(resize => resize.showBars()); - }; - return { - refresh, - hide, - show - }; - }; - - const setupTable = editor => { - register(editor); - const resizeHandler = TableResizeHandler(editor); - const cellSelectionHandler = TableCellSelectionHandler(editor, resizeHandler); - const actions = TableActions(editor, resizeHandler, cellSelectionHandler); - registerCommands(editor, actions); - registerQueryCommands(editor, actions); - registerEvents(editor, actions); - return { - getSelectedCells: cellSelectionHandler.getSelectedCells, - clearSelectedCells: cellSelectionHandler.clearSelectedCells - }; - }; - - const DomModel = editor => { - const table = setupTable(editor); - return { table }; + /* + NOTE: This file is partially duplicated in the following locations: + - plugins/table/core/Utils.ts + - advtable + Make sure that if making changes to this file, the other files are updated as well + */ + const getBody = (editor) => SugarElement.fromDom(editor.getBody()); + const getIsRoot = (editor) => (element) => eq$1(element, getBody(editor)); + const removeDataStyle = (table) => { + remove$6(table, 'data-mce-style'); + const removeStyleAttribute = (element) => remove$6(element, 'data-mce-style'); + each$2(cells$1(table), removeStyleAttribute); + each$2(columns$1(table), removeStyleAttribute); + each$2(rows$1(table), removeStyleAttribute); + }; + const getSelectionStart = (editor) => SugarElement.fromDom(editor.selection.getStart()); + const getPixelWidth = (elm) => elm.getBoundingClientRect().width; + const getPixelHeight = (elm) => elm.getBoundingClientRect().height; + const getRawValue = (prop) => (editor, elm) => { + const raw = editor.dom.getStyle(elm, prop) || editor.dom.getAttrib(elm, prop); + return Optional.from(raw).filter(isNotEmpty); + }; + const getRawWidth = getRawValue('width'); + const getRawHeight = getRawValue('height'); + const isPercentage$1 = (value) => /^(\d+(\.\d+)?)%$/.test(value); + const isPixel = (value) => /^(\d+(\.\d+)?)px$/.test(value); + const isInEditableContext$1 = (cell) => closest$2(cell, isTag('table')).exists(isEditable$1); + + const lookupTable = (container) => { + return ancestor$1(container, 'table'); + }; + const identify = (start, finish, isRoot) => { + const getIsRoot = (rootTable) => { + return (element) => { + return (isRoot !== undefined && isRoot(element)) || eq$1(element, rootTable); + }; + }; + // Optimisation: If the cells are equal, it's a single cell array + if (eq$1(start, finish)) { + return Optional.some({ + boxes: Optional.some([start]), + start, + finish + }); + } + else { + return lookupTable(start).bind((startTable) => { + return lookupTable(finish).bind((finishTable) => { + if (eq$1(startTable, finishTable)) { // Selecting from within the same table. + return Optional.some({ + boxes: intercepts(startTable, start, finish), + start, + finish + }); + } + else if (contains(startTable, finishTable)) { // Selecting from the parent table to the nested table. + const ancestorCells = ancestors$3(finish, 'td,th', getIsRoot(startTable)); + const finishCell = ancestorCells.length > 0 ? ancestorCells[ancestorCells.length - 1] : finish; + return Optional.some({ + boxes: nestedIntercepts(startTable, start, startTable, finish, finishTable), + start, + finish: finishCell + }); + } + else if (contains(finishTable, startTable)) { // Selecting from the nested table to the parent table. + const ancestorCells = ancestors$3(start, 'td,th', getIsRoot(finishTable)); + const startCell = ancestorCells.length > 0 ? ancestorCells[ancestorCells.length - 1] : start; + return Optional.some({ + boxes: nestedIntercepts(finishTable, start, startTable, finish, finishTable), + start, + finish: startCell + }); + } + else { // Selecting from a nested table to a different nested table. + return ancestors(start, finish).shared.bind((lca) => { + return closest$1(lca, 'table', isRoot).bind((lcaTable) => { + const finishAncestorCells = ancestors$3(finish, 'td,th', getIsRoot(lcaTable)); + const finishCell = finishAncestorCells.length > 0 ? finishAncestorCells[finishAncestorCells.length - 1] : finish; + const startAncestorCells = ancestors$3(start, 'td,th', getIsRoot(lcaTable)); + const startCell = startAncestorCells.length > 0 ? startAncestorCells[startAncestorCells.length - 1] : start; + return Optional.some({ + boxes: nestedIntercepts(lcaTable, start, startTable, finish, finishTable), + start: startCell, + finish: finishCell + }); + }); + }); + } + }); + }); + } + }; + const retrieve$1 = (container, selector) => { + const sels = descendants(container, selector); + return sels.length > 0 ? Optional.some(sels) : Optional.none(); + }; + const getLast = (boxes, lastSelectedSelector) => { + return find$1(boxes, (box) => { + return is$1(box, lastSelectedSelector); + }); + }; + const getEdges = (container, firstSelectedSelector, lastSelectedSelector) => { + return descendant(container, firstSelectedSelector).bind((first) => { + return descendant(container, lastSelectedSelector).bind((last) => { + return sharedOne(lookupTable, [first, last]).map((table) => { + return { + first, + last, + table + }; + }); + }); + }); + }; + const expandTo = (finish, firstSelectedSelector) => { + return ancestor$1(finish, 'table').bind((table) => { + return descendant(table, firstSelectedSelector).bind((start) => { + return identify(start, finish).bind((identified) => { + return identified.boxes.map((boxes) => { + return { + boxes, + start: identified.start, + finish: identified.finish + }; + }); + }); + }); + }); + }; + const shiftSelection = (boxes, deltaRow, deltaColumn, firstSelectedSelector, lastSelectedSelector) => { + return getLast(boxes, lastSelectedSelector).bind((last) => { + return moveBy(last, deltaRow, deltaColumn).bind((finish) => { + return expandTo(finish, firstSelectedSelector); + }); + }); + }; + + // Explicitly calling CellSelection.retrieve so that we can see the API signature. + const retrieve = (container, selector) => { + return retrieve$1(container, selector); + }; + const retrieveBox = (container, firstSelectedSelector, lastSelectedSelector) => { + return getEdges(container, firstSelectedSelector, lastSelectedSelector).bind((edges) => { + const isRoot = (ancestor) => { + return eq$1(container, ancestor); + }; + const sectionSelector = 'thead,tfoot,tbody,table'; + const firstAncestor = ancestor$1(edges.first, sectionSelector, isRoot); + const lastAncestor = ancestor$1(edges.last, sectionSelector, isRoot); + return firstAncestor.bind((fA) => { + return lastAncestor.bind((lA) => { + return eq$1(fA, lA) ? getBox(edges.table, edges.first, edges.last) : Optional.none(); + }); + }); + }); + }; + + const selection = identity; + const unmergable = (selectedCells) => { + const hasSpan = (elem, type) => getOpt(elem, type).exists((span) => parseInt(span, 10) > 1); + const hasRowOrColSpan = (elem) => hasSpan(elem, 'rowspan') || hasSpan(elem, 'colspan'); + return selectedCells.length > 0 && forall(selectedCells, hasRowOrColSpan) ? Optional.some(selectedCells) : Optional.none(); + }; + const mergable = (table, selectedCells, ephemera) => { + if (selectedCells.length <= 1) { + return Optional.none(); + } + else { + return retrieveBox(table, ephemera.firstSelectedSelector, ephemera.lastSelectedSelector) + .map((bounds) => ({ bounds, cells: selectedCells })); + } + }; + + const create$1 = (selection, kill) => ({ + selection, + kill + }); + const Response = { + create: create$1 + }; + + const fold = (subject, onNone, onMultiple, onSingle) => { + switch (subject.tag) { + case "none" /* SelectionTypeTag.None */: + return onNone(); + case "single" /* SelectionTypeTag.Single */: + return onSingle(subject.element); + case "multiple" /* SelectionTypeTag.Multiple */: + return onMultiple(subject.elements); + } + }; + const none = () => ({ tag: "none" /* SelectionTypeTag.None */ }); + const multiple = (elements) => ({ tag: "multiple" /* SelectionTypeTag.Multiple */, elements }); + const single = (element) => ({ tag: "single" /* SelectionTypeTag.Single */, element }); + + const Selections = (lazyRoot, getStart, selectedSelector) => { + const get = () => retrieve(lazyRoot(), selectedSelector).fold(() => getStart().fold(none, single), multiple); + return { + get + }; + }; + + const create = (start, soffset, finish, foffset) => { + return { + start: Situ.on(start, soffset), + finish: Situ.on(finish, foffset) + }; + }; + const Situs = { + create + }; + + const convertToRange = (win, selection) => { + // TODO: Use API packages of sugar + const rng = asLtrRange(win, selection); + return SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset); + }; + const makeSitus = Situs.create; + + // Based on a start and finish, select the appropriate box of cells + const sync = (container, isRoot, start, soffset, finish, foffset, selectRange) => { + if (!(eq$1(start, finish) && soffset === foffset)) { + return closest$1(start, 'td,th', isRoot).bind((s) => { + return closest$1(finish, 'td,th', isRoot).bind((f) => { + return detect(container, isRoot, s, f, selectRange); + }); + }); + } + else { + return Optional.none(); + } + }; + // If the cells are different, and there is a rectangle to connect them, select the cells. + const detect = (container, isRoot, start, finish, selectRange) => { + if (!eq$1(start, finish)) { + return identify(start, finish, isRoot).bind((cellSel) => { + const boxes = cellSel.boxes.getOr([]); + if (boxes.length > 1) { + selectRange(container, boxes, cellSel.start, cellSel.finish); + return Optional.some(Response.create(Optional.some(makeSitus(start, 0, start, getEnd(start))), true)); + } + else { + return Optional.none(); + } + }); + } + else { + return Optional.none(); + } + }; + const update = (rows, columns, container, selected, annotations) => { + const updateSelection = (newSels) => { + annotations.clearBeforeUpdate(container); + annotations.selectRange(container, newSels.boxes, newSels.start, newSels.finish); + return newSels.boxes; + }; + return shiftSelection(selected, rows, columns, annotations.firstSelectedSelector, annotations.lastSelectedSelector).map(updateSelection); + }; + + const adt$1 = Adt.generate([ + { none: ['message'] }, + { success: [] }, + { failedUp: ['cell'] }, + { failedDown: ['cell'] } + ]); + // Let's get some bounding rects, and see if they overlap (x-wise) + const isOverlapping = (bridge, before, after) => { + const beforeBounds = bridge.getRect(before); + const afterBounds = bridge.getRect(after); + return afterBounds.right > beforeBounds.left && afterBounds.left < beforeBounds.right; + }; + const isRow = (elem) => { + return closest$1(elem, 'tr'); + }; + const verify = (bridge, before, beforeOffset, after, afterOffset, failure, isRoot) => { + // Identify the cells that the before and after are in. + return closest$1(after, 'td,th', isRoot).bind((afterCell) => { + return closest$1(before, 'td,th', isRoot).map((beforeCell) => { + // If they are not in the same cell + if (!eq$1(afterCell, beforeCell)) { + return sharedOne(isRow, [afterCell, beforeCell]).fold(() => { + // No shared row, and they overlap x-wise -> success, otherwise: failed + return isOverlapping(bridge, beforeCell, afterCell) ? adt$1.success() : failure(beforeCell); + }, (_sharedRow) => { + // In the same row, so it failed. + return failure(beforeCell); + }); + } + else { + return eq$1(after, afterCell) && getEnd(afterCell) === afterOffset ? failure(beforeCell) : adt$1.none('in same cell'); + } + }); + }).getOr(adt$1.none('default')); + }; + const cata = (subject, onNone, onSuccess, onFailedUp, onFailedDown) => { + return subject.fold(onNone, onSuccess, onFailedUp, onFailedDown); + }; + const BeforeAfter = { + ...adt$1, + verify, + cata + }; + + const isBr = isTag('br'); + const gatherer = (cand, gather, isRoot) => { + return gather(cand, isRoot).bind((target) => { + return isText(target) && get$5(target).trim().length === 0 ? gatherer(target, gather, isRoot) : Optional.some(target); + }); + }; + const handleBr = (isRoot, element, direction) => { + // 1. Has a neighbouring sibling ... position relative to neighbouring element + // 2. Has no neighbouring sibling ... position relative to gathered element + return direction.traverse(element).orThunk(() => { + return gatherer(element, direction.gather, isRoot); + }).map(direction.relative); + }; + const findBr = (element, offset) => { + return child$2(element, offset).filter(isBr).orThunk(() => { + // Can be either side of the br, and still be a br. + return child$2(element, offset - 1).filter(isBr); + }); + }; + const handleParent = (isRoot, element, offset, direction) => { + // 1. Has no neighbouring sibling, position relative to gathered element + // 2. Has a neighbouring sibling, position at the neighbouring sibling with respect to parent + return findBr(element, offset).bind((br) => { + return direction.traverse(br).fold(() => { + return gatherer(br, direction.gather, isRoot).map(direction.relative); + }, (adjacent) => { + return indexInParent(adjacent).map((info) => { + return Situ.on(info.parent, info.index); + }); + }); + }); + }; + const tryBr = (isRoot, element, offset, direction) => { + // Three different situations + // 1. the br is the child, and it has a previous sibling. Use parent, index-1) + // 2. the br is the child and it has no previous sibling, set to before the previous gather result + // 3. the br is the element and it has a previous sibling, use parent index-1) + // 4. the br is the element and it has no previous sibling, set to before the previous gather result. + // 2. the element is the br itself, + const target = isBr(element) ? handleBr(isRoot, element, direction) : handleParent(isRoot, element, offset, direction); + return target.map((tgt) => { + return { + start: tgt, + finish: tgt + }; + }); + }; + const process = (analysis) => { + return BeforeAfter.cata(analysis, (_message) => { + return Optional.none(); + }, () => { + return Optional.none(); + }, (cell) => { + return Optional.some(point(cell, 0)); + }, (cell) => { + return Optional.some(point(cell, getEnd(cell))); + }); + }; + + const moveDown = (caret, amount) => { + return { + left: caret.left, + top: caret.top + amount, + right: caret.right, + bottom: caret.bottom + amount + }; + }; + const moveUp = (caret, amount) => { + return { + left: caret.left, + top: caret.top - amount, + right: caret.right, + bottom: caret.bottom - amount + }; + }; + const translate = (caret, xDelta, yDelta) => { + return { + left: caret.left + xDelta, + top: caret.top + yDelta, + right: caret.right + xDelta, + bottom: caret.bottom + yDelta + }; + }; + const getTop = (caret) => { + return caret.top; + }; + const getBottom = (caret) => { + return caret.bottom; + }; + + const getPartialBox = (bridge, element, offset) => { + if (offset >= 0 && offset < getEnd(element)) { + return bridge.getRangedRect(element, offset, element, offset + 1); + } + else if (offset > 0) { + return bridge.getRangedRect(element, offset - 1, element, offset); + } + return Optional.none(); + }; + const toCaret = (rect) => ({ + left: rect.left, + top: rect.top, + right: rect.right, + bottom: rect.bottom + }); + const getElemBox = (bridge, element) => { + return Optional.some(bridge.getRect(element)); + }; + const getBoxAt = (bridge, element, offset) => { + // Note, we might need to consider this offset and descend. + if (isElement(element)) { + return getElemBox(bridge, element).map(toCaret); + } + else if (isText(element)) { + return getPartialBox(bridge, element, offset).map(toCaret); + } + else { + return Optional.none(); + } + }; + const getEntireBox = (bridge, element) => { + if (isElement(element)) { + return getElemBox(bridge, element).map(toCaret); + } + else if (isText(element)) { + return bridge.getRangedRect(element, 0, element, getEnd(element)).map(toCaret); + } + else { + return Optional.none(); + } + }; + + const JUMP_SIZE = 5; + const NUM_RETRIES = 100; + const adt = Adt.generate([ + { none: [] }, + { retry: ['caret'] } + ]); + const isOutside = (caret, box) => { + return caret.left < box.left || Math.abs(box.right - caret.left) < 1 || caret.left > box.right; + }; + // Find the block and determine whether or not that block is outside. If it is outside, move up/down and right. + const inOutsideBlock = (bridge, element, caret) => { + return closest$2(element, isBlock).fold(never, (cell) => { + return getEntireBox(bridge, cell).exists((box) => { + return isOutside(caret, box); + }); + }); + }; + /* + * The approach is as follows. + * + * The browser APIs for caret ranges return elements that are the closest text elements to your (x, y) position, even if those + * closest elements are miles away. This causes problems when you are trying to identify what is immediately above or below + * a cell, because often the closest text is in a cell that is in a completely different column. Therefore, the approach needs + * to keep moving down until the thing that we are hitting is likely to be a true positive. + * + * Steps: + * + * 1. If the y position of the next guess is not different from the original, keep going. + * 2a. If the guess box doesn't actually include the position looked for, then the browser has returned a node that does not have + * a rectangle which truly intercepts the point. So, keep going. Note, we used to jump straight away here, but that means that + * we might skip over something that wasn't considered close enough but was a better guess than just making the y value skip. + * 2b. If the guess box exactly aligns with the caret, then adjust by 1 and go again. This is to get a more accurate offset. + * 3. if the guess box does include the caret, but the guess box's parent cell does not *really* contain the caret, try again shifting + * only the x value. If the guess box's parent cell does *really* contain the caret (i.e. it is horizontally-aligned), then stop + * because the guess is GOOD. + */ + const adjustDown = (bridge, element, guessBox, original, caret) => { + const lowerCaret = moveDown(caret, JUMP_SIZE); + if (Math.abs(guessBox.bottom - original.bottom) < 1) { + return adt.retry(lowerCaret); + } + else if (guessBox.top > caret.bottom) { + return adt.retry(lowerCaret); + } + else if (guessBox.top === caret.bottom) { + return adt.retry(moveDown(caret, 1)); + } + else { + return inOutsideBlock(bridge, element, caret) ? adt.retry(translate(lowerCaret, JUMP_SIZE, 0)) : adt.none(); + } + }; + const adjustUp = (bridge, element, guessBox, original, caret) => { + const higherCaret = moveUp(caret, JUMP_SIZE); + if (Math.abs(guessBox.top - original.top) < 1) { + return adt.retry(higherCaret); + } + else if (guessBox.bottom < caret.top) { + return adt.retry(higherCaret); + } + else if (guessBox.bottom === caret.top) { + return adt.retry(moveUp(caret, 1)); + } + else { + return inOutsideBlock(bridge, element, caret) ? adt.retry(translate(higherCaret, JUMP_SIZE, 0)) : adt.none(); + } + }; + const upMovement = { + point: getTop, + adjuster: adjustUp, + move: moveUp, + gather: before + }; + const downMovement = { + point: getBottom, + adjuster: adjustDown, + move: moveDown, + gather: after + }; + const isAtTable = (bridge, x, y) => { + return bridge.elementFromPoint(x, y).filter((elm) => { + return name(elm) === 'table'; + }).isSome(); + }; + const adjustForTable = (bridge, movement, original, caret, numRetries) => { + return adjustTil(bridge, movement, original, movement.move(caret, JUMP_SIZE), numRetries); + }; + const adjustTil = (bridge, movement, original, caret, numRetries) => { + if (numRetries === 0) { + return Optional.some(caret); + } + if (isAtTable(bridge, caret.left, movement.point(caret))) { + return adjustForTable(bridge, movement, original, caret, numRetries - 1); + } + return bridge.situsFromPoint(caret.left, movement.point(caret)).bind((guess) => { + return guess.start.fold(Optional.none, (element) => { + return getEntireBox(bridge, element).bind((guessBox) => { + return movement.adjuster(bridge, element, guessBox, original, caret).fold(Optional.none, (newCaret) => { + return adjustTil(bridge, movement, original, newCaret, numRetries - 1); + }); + }).orThunk(() => { + return Optional.some(caret); + }); + }, Optional.none); + }); + }; + const checkScroll = (movement, adjusted, bridge) => { + // I'm not convinced that this is right. Let's re-examine it later. + if (movement.point(adjusted) > bridge.getInnerHeight()) { + return Optional.some(movement.point(adjusted) - bridge.getInnerHeight()); + } + else if (movement.point(adjusted) < 0) { + return Optional.some(-movement.point(adjusted)); + } + else { + return Optional.none(); + } + }; + const retry = (movement, bridge, caret) => { + const moved = movement.move(caret, JUMP_SIZE); + const adjusted = adjustTil(bridge, movement, caret, moved, NUM_RETRIES).getOr(moved); + return checkScroll(movement, adjusted, bridge).fold(() => { + return bridge.situsFromPoint(adjusted.left, movement.point(adjusted)); + }, (delta) => { + bridge.scrollBy(0, delta); + return bridge.situsFromPoint(adjusted.left, movement.point(adjusted) - delta); + }); + }; + const Retries = { + tryUp: curry(retry, upMovement), + tryDown: curry(retry, downMovement), + getJumpSize: constant(JUMP_SIZE) + }; + + const MAX_RETRIES = 20; + const findSpot = (bridge, isRoot, direction) => { + return bridge.getSelection().bind((sel) => { + return tryBr(isRoot, sel.finish, sel.foffset, direction).fold(() => { + return Optional.some(point(sel.finish, sel.foffset)); + }, (brNeighbour) => { + const range = bridge.fromSitus(brNeighbour); + const analysis = BeforeAfter.verify(bridge, sel.finish, sel.foffset, range.finish, range.foffset, direction.failure, isRoot); + return process(analysis); + }); + }); + }; + const scan = (bridge, isRoot, element, offset, direction, numRetries) => { + if (numRetries === 0) { + return Optional.none(); + } + // Firstly, move the (x, y) and see what element we end up on. + return tryCursor(bridge, isRoot, element, offset, direction).bind((situs) => { + const range = bridge.fromSitus(situs); + // Now, check to see if the element is a new cell. + const analysis = BeforeAfter.verify(bridge, element, offset, range.finish, range.foffset, direction.failure, isRoot); + return BeforeAfter.cata(analysis, () => { + return Optional.none(); + }, () => { + // We have a new cell, so we stop looking. + return Optional.some(situs); + }, (cell) => { + if (eq$1(element, cell) && offset === 0) { + return tryAgain(bridge, element, offset, moveUp, direction); + } + else { // We need to look again from the start of our current cell + return scan(bridge, isRoot, cell, 0, direction, numRetries - 1); + } + }, (cell) => { + // If we were here last time, move and try again. + if (eq$1(element, cell) && offset === getEnd(cell)) { + return tryAgain(bridge, element, offset, moveDown, direction); + } + else { // We need to look again from the end of our current cell + return scan(bridge, isRoot, cell, getEnd(cell), direction, numRetries - 1); + } + }); + }); + }; + const tryAgain = (bridge, element, offset, move, direction) => { + return getBoxAt(bridge, element, offset).bind((box) => { + return tryAt(bridge, direction, move(box, Retries.getJumpSize())); + }); + }; + const tryAt = (bridge, direction, box) => { + const browser = detect$2().browser; + // NOTE: As we attempt to take over selection everywhere, we'll probably need to separate these again. + if (browser.isChromium() || browser.isSafari() || browser.isFirefox()) { + return direction.retry(bridge, box); + } + else { + return Optional.none(); + } + }; + const tryCursor = (bridge, isRoot, element, offset, direction) => { + return getBoxAt(bridge, element, offset).bind((box) => { + return tryAt(bridge, direction, box); + }); + }; + const handle = (bridge, isRoot, direction) => { + return findSpot(bridge, isRoot, direction).bind((spot) => { + // There is a point to start doing box-hitting from + return scan(bridge, isRoot, spot.element, spot.offset, direction, MAX_RETRIES).map(bridge.fromSitus); + }); + }; + + const inSameTable = (elem, table) => { + return ancestor(elem, (e) => { + return parent(e).exists((p) => { + return eq$1(p, table); + }); + }); + }; + // Note: initial is the finishing element, because that's where the cursor starts from + // Anchor is the starting element, and is only used to work out if we are in the same table + const simulate = (bridge, isRoot, direction, initial, anchor) => { + return closest$1(initial, 'td,th', isRoot).bind((start) => { + return closest$1(start, 'table', isRoot).bind((table) => { + if (!inSameTable(anchor, table)) { + return Optional.none(); + } + return handle(bridge, isRoot, direction).bind((range) => { + return closest$1(range.finish, 'td,th', isRoot).map((finish) => { + return { + start, + finish, + range + }; + }); + }); + }); + }); + }; + const navigate = (bridge, isRoot, direction, initial, anchor, precheck) => { + return precheck(initial, isRoot).orThunk(() => { + return simulate(bridge, isRoot, direction, initial, anchor).map((info) => { + const range = info.range; + return Response.create(Optional.some(makeSitus(range.start, range.soffset, range.finish, range.foffset)), true); + }); + }); + }; + const firstUpCheck = (initial, isRoot) => { + return closest$1(initial, 'tr', isRoot).bind((startRow) => { + return closest$1(startRow, 'table', isRoot).bind((table) => { + const rows = descendants(table, 'tr'); + if (eq$1(startRow, rows[0])) { + return seekLeft(table, (element) => { + return last(element).isSome(); + }, isRoot).map((last) => { + const lastOffset = getEnd(last); + return Response.create(Optional.some(makeSitus(last, lastOffset, last, lastOffset)), true); + }); + } + else { + return Optional.none(); + } + }); + }); + }; + const lastDownCheck = (initial, isRoot) => { + return closest$1(initial, 'tr', isRoot).bind((startRow) => { + return closest$1(startRow, 'table', isRoot).bind((table) => { + const rows = descendants(table, 'tr'); + if (eq$1(startRow, rows[rows.length - 1])) { + return seekRight(table, (element) => { + return first(element).isSome(); + }, isRoot).map((first) => { + return Response.create(Optional.some(makeSitus(first, 0, first, 0)), true); + }); + } + else { + return Optional.none(); + } + }); + }); + }; + const select = (bridge, container, isRoot, direction, initial, anchor, selectRange) => { + return simulate(bridge, isRoot, direction, initial, anchor).bind((info) => { + return detect(container, isRoot, info.start, info.finish, selectRange); + }); + }; + + const findCell = (target, isRoot) => closest$1(target, 'td,th', isRoot); + const isInEditableContext = (cell) => parentElement(cell).exists(isEditable$1); + const MouseSelection = (bridge, container, isRoot, annotations) => { + const cursor = value(); + const clearstate = cursor.clear; + const applySelection = (event) => { + cursor.on((start) => { + annotations.clearBeforeUpdate(container); + findCell(event.target, isRoot).each((finish) => { + identify(start, finish, isRoot).each((cellSel) => { + const boxes = cellSel.boxes.getOr([]); + if (boxes.length === 1) { + // If a single noneditable cell is selected and the actual selection target within the cell + // is also noneditable, make sure it is annotated + const singleCell = boxes[0]; + const isNonEditableCell = getRaw$1(singleCell) === 'false'; + const isCellClosestContentEditable = is$2(closest(event.target), singleCell, eq$1); + if (isNonEditableCell && isCellClosestContentEditable) { + // Not selecting the contents or the node of the actual cell as shown below, keeping the selection on the offscreen element. + annotations.selectRange(container, boxes, singleCell, singleCell); + } + } + else if (boxes.length > 1) { + // Wait until we have more than one, otherwise you can't do text selection inside a cell. + annotations.selectRange(container, boxes, cellSel.start, cellSel.finish); + // stop the browser from creating a big text selection, select the cell where the cursor is + bridge.selectContents(finish); + } + }); + }); + }); + }; + /* Keep this as lightweight as possible when we're not in a table selection, it runs constantly */ + const mousedown = (event) => { + annotations.clear(container); + findCell(event.target, isRoot).filter(isInEditableContext).each(cursor.set); + }; + /* Keep this as lightweight as possible when we're not in a table selection, it runs constantly */ + const mouseover = (event) => { + applySelection(event); + }; + /* Keep this as lightweight as possible when we're not in a table selection, it runs constantly */ + const mouseup = (event) => { + // Needed as Firefox will change the selection between the mouseover and mouseup when selecting + // just 2 cells as Firefox supports multiple selection ranges + applySelection(event); + clearstate(); + }; + return { + clearstate, + mousedown, + mouseover, + mouseup + }; + }; + + const down = { + traverse: nextSibling, + gather: after, + relative: Situ.before, + retry: Retries.tryDown, + failure: BeforeAfter.failedDown + }; + const up = { + traverse: prevSibling, + gather: before, + relative: Situ.before, + retry: Retries.tryUp, + failure: BeforeAfter.failedUp + }; + + const isKey = (key) => { + return (keycode) => { + return keycode === key; + }; + }; + const isUp = isKey(38); + const isDown = isKey(40); + const isNavigation = (keycode) => { + return keycode >= 37 && keycode <= 40; + }; + const ltr = { + // We need to move KEYS out of keytar and into something much more low-level. + isBackward: isKey(37), + isForward: isKey(39) + }; + const rtl = { + isBackward: isKey(39), + isForward: isKey(37) + }; + + const WindowBridge = (win) => { + const elementFromPoint = (x, y) => { + return SugarElement.fromPoint(SugarElement.fromDom(win.document), x, y); + }; + const getRect = (element) => { + return element.dom.getBoundingClientRect(); + }; + const getRangedRect = (start, soffset, finish, foffset) => { + const sel = SimSelection.exact(start, soffset, finish, foffset); + return getFirstRect(win, sel); + }; + const getSelection = () => { + return get$3(win).map((exactAdt) => { + return convertToRange(win, exactAdt); + }); + }; + const fromSitus = (situs) => { + const relative = SimSelection.relative(situs.start, situs.finish); + return convertToRange(win, relative); + }; + const situsFromPoint = (x, y) => { + return getAtPoint(win, x, y).map((exact) => { + return Situs.create(exact.start, exact.soffset, exact.finish, exact.foffset); + }); + }; + const clearSelection = () => { + clear(win); + }; + const collapseSelection = (toStart = false) => { + get$3(win).each((sel) => sel.fold((rng) => rng.collapse(toStart), (startSitu, finishSitu) => { + const situ = toStart ? startSitu : finishSitu; + setRelative(win, situ, situ); + }, (start, soffset, finish, foffset) => { + const node = toStart ? start : finish; + const offset = toStart ? soffset : foffset; + setExact(win, node, offset, node, offset); + })); + }; + const selectNode = (element) => { + setToElement(win, element, false); + }; + const selectContents = (element) => { + setToElement(win, element); + }; + const setSelection = (sel) => { + setExact(win, sel.start, sel.soffset, sel.finish, sel.foffset); + }; + const setRelativeSelection = (start, finish) => { + setRelative(win, start, finish); + }; + const getInnerHeight = () => { + return win.innerHeight; + }; + const getScrollY = () => { + const pos = get$6(SugarElement.fromDom(win.document)); + return pos.top; + }; + const scrollBy = (x, y) => { + by(x, y, SugarElement.fromDom(win.document)); + }; + return { + elementFromPoint, + getRect, + getRangedRect, + getSelection, + fromSitus, + situsFromPoint, + clearSelection, + collapseSelection, + setSelection, + setRelativeSelection, + selectNode, + selectContents, + getInnerHeight, + getScrollY, + scrollBy + }; + }; + + const rc = (rows, cols) => ({ rows, cols }); + const mouse = (win, container, isRoot, annotations) => { + const bridge = WindowBridge(win); + const handlers = MouseSelection(bridge, container, isRoot, annotations); + return { + clearstate: handlers.clearstate, + mousedown: handlers.mousedown, + mouseover: handlers.mouseover, + mouseup: handlers.mouseup + }; + }; + const isEditableNode = (node) => closest$2(node, isHTMLElement).exists(isEditable$1); + const isEditableSelection = (start, finish) => isEditableNode(start) || isEditableNode(finish); + const keyboard = (win, container, isRoot, annotations) => { + const bridge = WindowBridge(win); + const clearToNavigate = () => { + annotations.clear(container); + return Optional.none(); + }; + const keydown = (event, start, soffset, finish, foffset, direction) => { + const realEvent = event.raw; + const keycode = realEvent.which; + const shiftKey = realEvent.shiftKey === true; + const handler = retrieve$1(container, annotations.selectedSelector).fold(() => { + // Make sure any possible lingering annotations are cleared + if (isNavigation(keycode) && !shiftKey) { + annotations.clearBeforeUpdate(container); + } + // Shift down should predict the movement and set the selection. + if (isNavigation(keycode) && shiftKey && !isEditableSelection(start, finish)) { + return Optional.none; + } + else if (isDown(keycode) && shiftKey) { + return curry(select, bridge, container, isRoot, down, finish, start, annotations.selectRange); + } + else if (isUp(keycode) && shiftKey) { // Shift up should predict the movement and set the selection. + return curry(select, bridge, container, isRoot, up, finish, start, annotations.selectRange); + } + else if (isDown(keycode)) { // Down should predict the movement and set the cursor + return curry(navigate, bridge, isRoot, down, finish, start, lastDownCheck); + } + else if (isUp(keycode)) { // Up should predict the movement and set the cursor + return curry(navigate, bridge, isRoot, up, finish, start, firstUpCheck); + } + else { + return Optional.none; + } + }, (selected) => { + const update$1 = (attempts) => { + return () => { + const navigation = findMap(attempts, (delta) => { + return update(delta.rows, delta.cols, container, selected, annotations); + }); + // Shift the selected rows and update the selection. + return navigation.fold(() => { + // The cell selection went outside the table, so clear it and bridge from the first box to before/after + // the table + return getEdges(container, annotations.firstSelectedSelector, annotations.lastSelectedSelector).map((edges) => { + const relative = isDown(keycode) || direction.isForward(keycode) ? Situ.after : Situ.before; + bridge.setRelativeSelection(Situ.on(edges.first, 0), relative(edges.table)); + annotations.clear(container); + return Response.create(Optional.none(), true); + }); + }, (_) => { + return Optional.some(Response.create(Optional.none(), true)); + }); + }; + }; + if (isNavigation(keycode) && shiftKey && !isEditableSelection(start, finish)) { + return Optional.none; + } + else if (isDown(keycode) && shiftKey) { + return update$1([rc(+1, 0)]); + } + else if (isUp(keycode) && shiftKey) { + return update$1([rc(-1, 0)]); + } + else if (direction.isBackward(keycode) && shiftKey) { // Left and right should try up/down respectively if they fail. + return update$1([rc(0, -1), rc(-1, 0)]); + } + else if (direction.isForward(keycode) && shiftKey) { + return update$1([rc(0, +1), rc(+1, 0)]); + } + else if (isNavigation(keycode) && !shiftKey) { // Clear the selection on normal arrow keys. + return clearToNavigate; + } + else { + return Optional.none; + } + }); + return handler(); + }; + const keyup = (event, start, soffset, finish, foffset) => { + return retrieve$1(container, annotations.selectedSelector).fold(() => { + const realEvent = event.raw; + const keycode = realEvent.which; + const shiftKey = realEvent.shiftKey === true; + if (!shiftKey) { + return Optional.none(); + } + if (isNavigation(keycode) && isEditableSelection(start, finish)) { + return sync(container, isRoot, start, soffset, finish, foffset, annotations.selectRange); + } + else { + return Optional.none(); + } + }, Optional.none); + }; + return { + keydown, + keyup + }; + }; + const external = (win, container, isRoot, annotations) => { + const bridge = WindowBridge(win); + return (start, finish) => { + annotations.clearBeforeUpdate(container); + identify(start, finish, isRoot).each((cellSel) => { + const boxes = cellSel.boxes.getOr([]); + annotations.selectRange(container, boxes, cellSel.start, cellSel.finish); + // stop the browser from creating a big text selection, place the selection at the end of the cell where the cursor is + bridge.selectContents(finish); + bridge.collapseSelection(); + }); + }; + }; + + const byClass = (ephemera) => { + const addSelectionClass = addClass(ephemera.selected); + const removeSelectionClasses = removeClasses([ephemera.selected, ephemera.lastSelected, ephemera.firstSelected]); + const clear = (container) => { + const sels = descendants(container, ephemera.selectedSelector); + each$2(sels, removeSelectionClasses); + }; + const selectRange = (container, cells, start, finish) => { + clear(container); + each$2(cells, addSelectionClass); + add$1(start, ephemera.firstSelected); + add$1(finish, ephemera.lastSelected); + }; + return { + clearBeforeUpdate: clear, + clear, + selectRange, + selectedSelector: ephemera.selectedSelector, + firstSelectedSelector: ephemera.firstSelectedSelector, + lastSelectedSelector: ephemera.lastSelectedSelector + }; + }; + const byAttr = (ephemera, onSelection, onClear) => { + const removeSelectionAttributes = (element) => { + remove$6(element, ephemera.selected); + remove$6(element, ephemera.firstSelected); + remove$6(element, ephemera.lastSelected); + }; + const addSelectionAttribute = (element) => { + set$2(element, ephemera.selected, '1'); + }; + const clear = (container) => { + clearBeforeUpdate(container); + onClear(); + }; + const clearBeforeUpdate = (container) => { + const sels = descendants(container, `${ephemera.selectedSelector},${ephemera.firstSelectedSelector},${ephemera.lastSelectedSelector}`); + each$2(sels, removeSelectionAttributes); + }; + const selectRange = (container, cells, start, finish) => { + clear(container); + each$2(cells, addSelectionAttribute); + set$2(start, ephemera.firstSelected, '1'); + set$2(finish, ephemera.lastSelected, '1'); + onSelection(cells, start, finish); + }; + return { + clearBeforeUpdate, + clear, + selectRange, + selectedSelector: ephemera.selectedSelector, + firstSelectedSelector: ephemera.firstSelectedSelector, + lastSelectedSelector: ephemera.lastSelectedSelector + }; + }; + const SelectionAnnotation = { + byClass, + byAttr + }; + + /* + NOTE: This file is duplicated in the following locations: + - plugins/table/selection/Ephemera.ts + - advtable + Make sure that if making changes to this file, the other files are updated as well + */ + const strSelected = 'data-mce-selected'; + const strSelectedSelector = 'td[' + strSelected + '],th[' + strSelected + ']'; + // used with not selectors + const strAttributeSelector = '[' + strSelected + ']'; + const strFirstSelected = 'data-mce-first-selected'; + const strFirstSelectedSelector = 'td[' + strFirstSelected + '],th[' + strFirstSelected + ']'; + const strLastSelected = 'data-mce-last-selected'; + const strLastSelectedSelector = 'td[' + strLastSelected + '],th[' + strLastSelected + ']'; + const attributeSelector = strAttributeSelector; + const ephemera = { + selected: strSelected, + selectedSelector: strSelectedSelector, + firstSelected: strFirstSelected, + firstSelectedSelector: strFirstSelectedSelector, + lastSelected: strLastSelected, + lastSelectedSelector: strLastSelectedSelector + }; + + /* + NOTE: This file is partially duplicated in the following locations: + - plugins/table/queries/TableTargets.ts + - advtable + Make sure that if making changes to this file, the other files are updated as well + */ + const forMenu = (selectedCells, table, cell) => ({ + element: cell, + mergable: mergable(table, selectedCells, ephemera), + unmergable: unmergable(selectedCells), + selection: selection(selectedCells) + }); + const paste = (element, clipboard, generators) => ({ + element, + clipboard, + generators + }); + const pasteRows = (selectedCells, _cell, clipboard, generators) => ({ + selection: selection(selectedCells), + clipboard, + generators + }); + + /* + NOTE: This file is partially duplicated in the following locations: + - plugins/table/selection/TableSelection.ts + - advtable + Make sure that if making changes to this file, the other files are updated as well + */ + const getSelectionCellFallback = (element) => table(element).bind((table) => retrieve(table, ephemera.firstSelectedSelector)).fold(constant(element), (cells) => cells[0]); + const getSelectionFromSelector = (selector) => (initCell, isRoot) => { + const cellName = name(initCell); + const cell = cellName === 'col' || cellName === 'colgroup' ? getSelectionCellFallback(initCell) : initCell; + return closest$1(cell, selector, isRoot); + }; + const getSelectionCellOrCaption = getSelectionFromSelector('th,td,caption'); + const getSelectionCell = getSelectionFromSelector('th,td'); + // Note: Includes single cell if the start of the selection whether collapsed or ranged is within a table cell + const getCellsFromSelection = (editor) => fromDom(editor.model.table.getSelectedCells()); + const getCellsFromFakeSelection = (editor) => filter$2(getCellsFromSelection(editor), (cell) => is$1(cell, ephemera.selectedSelector)); + + const extractSelected = (cells) => { + // Assume for now that we only have one table (also handles the case where we multi select outside a table) + return table(cells[0]).map((table) => { + const replica = extract$1(table, attributeSelector); + removeDataStyle(replica); + return [replica]; + }); + }; + const serializeElements = (editor, elements) => map$1(elements, (elm) => editor.selection.serializer.serialize(elm.dom, {})).join(''); + const getTextContent = (editor, replicaElements) => { + const doc = editor.getDoc(); + const dos = getRootNode(SugarElement.fromDom(editor.getBody())); + // Set up offscreen div so that the extracted table element can be inserted into the DOM + // TINY-10847: If the table element is detached from the DOM, calling innerText is equivalent to calling + // textContent which does not include '\n' and '\t' characters to separate rows and cells respectively + const offscreenDiv = SugarElement.fromTag('div', doc); + set$2(offscreenDiv, 'data-mce-bogus', 'all'); + setAll(offscreenDiv, { + position: 'fixed', + left: '-9999999px', + top: '0', + overflow: 'hidden', + opacity: '0' + }); + const root = getContentContainer(dos); + append(offscreenDiv, replicaElements); + append$1(root, offscreenDiv); + const textContent = offscreenDiv.dom.innerText; + remove$5(offscreenDiv); + return textContent; + }; + const registerEvents = (editor, actions) => { + editor.on('BeforeGetContent', (e) => { + const multiCellContext = (cells) => { + e.preventDefault(); + extractSelected(cells).each((replicaElements) => { + const content = e.format === 'text' ? getTextContent(editor, replicaElements) : serializeElements(editor, replicaElements); + e.content = content; + }); + }; + if (e.selection === true) { + const cells = getCellsFromFakeSelection(editor); + if (cells.length >= 1) { + multiCellContext(cells); + } + } + }); + editor.on('BeforeSetContent', (e) => { + if (e.selection === true && e.paste === true) { + const selectedCells = getCellsFromSelection(editor); + head(selectedCells).each((cell) => { + table(cell).each((table) => { + const elements = filter$2(fromHtml(e.content), (content) => { + return name(content) !== 'meta'; + }); + const isTable = isTag('table'); + if (shouldMergeContentOnPaste(editor) && elements.length === 1 && isTable(elements[0])) { + e.preventDefault(); + const doc = SugarElement.fromDom(editor.getDoc()); + const generators = paste$1(doc); + const targets = paste(cell, elements[0], generators); + actions.pasteCells(table, targets).each(() => { + editor.focus(); + }); + } + }); + }); + } + }); + }; + + /* + NOTE: This file is duplicated in the following locations: + - core/api/TableEvents.ts + - plugins/table/api/Events.ts + - advtable + Make sure that if making changes to this file, the other files are updated as well + */ + const fireNewRow = (editor, row) => editor.dispatch('NewRow', { node: row }); + const fireNewCell = (editor, cell) => editor.dispatch('NewCell', { node: cell }); + const fireTableModified = (editor, table, data) => { + editor.dispatch('TableModified', { ...data, table }); + }; + const fireTableSelectionChange = (editor, cells, start, finish, otherCells) => { + editor.dispatch('TableSelectionChange', { + cells, + start, + finish, + otherCells + }); + }; + const fireTableSelectionClear = (editor) => { + editor.dispatch('TableSelectionClear'); + }; + const fireObjectResizeStart = (editor, target, width, height, origin) => { + editor.dispatch('ObjectResizeStart', { target, width, height, origin }); + }; + const fireObjectResized = (editor, target, width, height, origin) => { + editor.dispatch('ObjectResized', { target, width, height, origin }); + }; + const styleModified = { structure: false, style: true }; + const structureModified = { structure: true, style: false }; + const styleAndStructureModified = { structure: true, style: true }; + + const get$1 = (editor, table) => { + // Note: We can't enforce none (responsive), as if someone manually resizes a table + // then it must switch to either pixel (fixed) or percentage (relative) sizing + if (isTablePercentagesForced(editor)) { + return TableSize.percentageSize(table); + } + else if (isTablePixelsForced(editor)) { + return TableSize.pixelSize(table); + } + else { + // Detect based on the table width + return TableSize.getTableSize(table); + } + }; + + const TableActions = (editor, resizeHandler, cellSelectionHandler) => { + const isTableBody = (editor) => name(getBody(editor)) === 'table'; + const lastRowGuard = (table) => !isTableBody(editor) || getGridSize(table).rows > 1; + const lastColumnGuard = (table) => !isTableBody(editor) || getGridSize(table).columns > 1; + // Optional.none gives the default cloneFormats. + const cloneFormats = getTableCloneElements(editor); + const colMutationOp = isResizeTableColumnResizing(editor) ? noop : halve; + const getTableSectionType = (table) => { + switch (getTableHeaderType(editor)) { + case 'section': + return TableSection.section(); + case 'sectionCells': + return TableSection.sectionCells(); + case 'cells': + return TableSection.cells(); + default: + // Attempt to automatically find the type. If a type can't be found + // then fallback to "section" to maintain backwards compatibility. + return TableSection.getTableSectionType(table, 'section'); + } + }; + const setSelectionFromAction = (table, result) => result.cursor.fold(() => { + // Snooker has reported we don't have a good cursor position. However, we may have a locked column + // with noneditable cells, so lets check if we have a noneditable cell and if so place the selection + const cells = cells$1(table); + return head(cells).filter(inBody).map((firstCell) => { + cellSelectionHandler.clearSelectedCells(table.dom); + const rng = editor.dom.createRng(); + rng.selectNode(firstCell.dom); + editor.selection.setRng(rng); + set$2(firstCell, 'data-mce-selected', '1'); + return rng; + }); + }, (cell) => { + const des = freefallRtl(cell); + const rng = editor.dom.createRng(); + rng.setStart(des.element.dom, des.offset); + rng.setEnd(des.element.dom, des.offset); + editor.selection.setRng(rng); + cellSelectionHandler.clearSelectedCells(table.dom); + return Optional.some(rng); + }); + const execute = (operation, guard, mutate, effect) => (table, target, noEvents = false) => { + removeDataStyle(table); + const doc = SugarElement.fromDom(editor.getDoc()); + const generators = cellOperations(mutate, doc, cloneFormats); + const behaviours = { + sizing: get$1(editor, table), + resize: isResizeTableColumnResizing(editor) ? resizeTable() : preserveTable(), + section: getTableSectionType(table) + }; + return guard(table) ? operation(table, target, generators, behaviours).bind((result) => { + // Update the resize bars after the table operation + resizeHandler.refresh(table.dom); + // INVESTIGATE: Should "noEvents" prevent these from firing as well? + each$2(result.newRows, (row) => { + fireNewRow(editor, row.dom); + }); + each$2(result.newCells, (cell) => { + fireNewCell(editor, cell.dom); + }); + const range = setSelectionFromAction(table, result); + if (inBody(table)) { + removeDataStyle(table); + if (!noEvents) { + fireTableModified(editor, table.dom, effect); + } + } + return range.map((rng) => ({ + rng, + effect + })); + }) : Optional.none(); + }; + const deleteRow = execute(eraseRows, lastRowGuard, noop, structureModified); + const deleteColumn = execute(eraseColumns, lastColumnGuard, noop, structureModified); + const insertRowsBefore$1 = execute(insertRowsBefore, always, noop, structureModified); + const insertRowsAfter$1 = execute(insertRowsAfter, always, noop, structureModified); + const insertColumnsBefore$1 = execute(insertColumnsBefore, always, colMutationOp, structureModified); + const insertColumnsAfter$1 = execute(insertColumnsAfter, always, colMutationOp, structureModified); + const mergeCells$1 = execute(mergeCells, always, noop, structureModified); + const unmergeCells$1 = execute(unmergeCells, always, noop, structureModified); + const pasteColsBefore$1 = execute(pasteColsBefore, always, noop, structureModified); + const pasteColsAfter$1 = execute(pasteColsAfter, always, noop, structureModified); + const pasteRowsBefore$1 = execute(pasteRowsBefore, always, noop, structureModified); + const pasteRowsAfter$1 = execute(pasteRowsAfter, always, noop, structureModified); + const pasteCells$1 = execute(pasteCells, always, noop, styleAndStructureModified); + const makeCellsHeader$1 = execute(makeCellsHeader, always, noop, structureModified); + const unmakeCellsHeader$1 = execute(unmakeCellsHeader, always, noop, structureModified); + const makeColumnsHeader$1 = execute(makeColumnsHeader, always, noop, structureModified); + const unmakeColumnsHeader$1 = execute(unmakeColumnsHeader, always, noop, structureModified); + const makeRowsHeader$1 = execute(makeRowsHeader, always, noop, structureModified); + const makeRowsBody$1 = execute(makeRowsBody, always, noop, structureModified); + const makeRowsFooter$1 = execute(makeRowsFooter, always, noop, structureModified); + const getTableCellType = getCellsType; + const getTableColType = getColumnsType; + const getTableRowType = getRowsType; + return { + deleteRow, + deleteColumn, + insertRowsBefore: insertRowsBefore$1, + insertRowsAfter: insertRowsAfter$1, + insertColumnsBefore: insertColumnsBefore$1, + insertColumnsAfter: insertColumnsAfter$1, + mergeCells: mergeCells$1, + unmergeCells: unmergeCells$1, + pasteColsBefore: pasteColsBefore$1, + pasteColsAfter: pasteColsAfter$1, + pasteRowsBefore: pasteRowsBefore$1, + pasteRowsAfter: pasteRowsAfter$1, + pasteCells: pasteCells$1, + makeCellsHeader: makeCellsHeader$1, + unmakeCellsHeader: unmakeCellsHeader$1, + makeColumnsHeader: makeColumnsHeader$1, + unmakeColumnsHeader: unmakeColumnsHeader$1, + makeRowsHeader: makeRowsHeader$1, + makeRowsBody: makeRowsBody$1, + makeRowsFooter: makeRowsFooter$1, + getTableRowType, + getTableCellType, + getTableColType + }; + }; + + const placeCaretInCell = (editor, cell) => { + editor.selection.select(cell.dom, true); + editor.selection.collapse(true); + }; + const selectFirstCellInTable = (editor, tableElm) => { + descendant(tableElm, 'td,th').each(curry(placeCaretInCell, editor)); + }; + const fireEvents = (editor, table) => { + each$2(descendants(table, 'tr'), (row) => { + fireNewRow(editor, row.dom); + each$2(descendants(row, 'th,td'), (cell) => { + fireNewCell(editor, cell.dom); + }); + }); + }; + const isPercentage = (width) => isString(width) && width.indexOf('%') !== -1; + const insert = (editor, columns, rows, colHeaders, rowHeaders) => { + const defaultStyles = getTableDefaultStyles(editor); + const options = { + styles: defaultStyles, + attributes: getTableDefaultAttributes(editor), + colGroups: tableUseColumnGroup(editor) + }; + // Don't create an undo level when inserting the base table HTML otherwise we can end up with 2 undo levels + editor.undoManager.ignore(() => { + const table = render(rows, columns, rowHeaders, colHeaders, getTableHeaderType(editor), options); + set$2(table, 'data-mce-id', '__mce'); + const html = getOuter$2(table); + editor.insertContent(html); + editor.addVisual(); + }); + // Enforce the sizing mode of the table + return descendant(getBody(editor), 'table[data-mce-id="__mce"]').map((table) => { + if (isTablePixelsForced(editor)) { + convertToPixelSizeWidth(table); + } + else if (isTableResponsiveForced(editor)) { + convertToNoneSizeWidth(table); + } + else if (isTablePercentagesForced(editor) || isPercentage(defaultStyles.width)) { + convertToPercentSizeWidth(table); + } + removeDataStyle(table); + remove$6(table, 'data-mce-id'); + fireEvents(editor, table); + selectFirstCellInTable(editor, table); + return table.dom; + }).getOrNull(); + }; + const insertTable = (editor, rows, columns, options = {}) => { + const checkInput = (val) => isNumber(val) && val > 0; + if (checkInput(rows) && checkInput(columns)) { + const headerRows = options.headerRows || 0; + const headerColumns = options.headerColumns || 0; + return insert(editor, columns, rows, headerColumns, headerRows); + } + else { + // eslint-disable-next-line no-console + console.error('Invalid values for mceInsertTable - rows and columns values are required to insert a table.'); + return null; + } + }; + + var global = tinymce.util.Tools.resolve('tinymce.FakeClipboard'); + + /* + NOTE: This file is duplicated in the following locations: + - plugins/table/api/Clipboard.ts + Make sure that if making changes to this file, the other files are updated as well + */ + const tableTypeBase = 'x-tinymce/dom-table-'; + const tableTypeRow = tableTypeBase + 'rows'; + const tableTypeColumn = tableTypeBase + 'columns'; + const setData = (items) => { + const fakeClipboardItem = global.FakeClipboardItem(items); + global.write([fakeClipboardItem]); + }; + const getData = (type) => { + var _a; + const items = (_a = global.read()) !== null && _a !== void 0 ? _a : []; + return findMap(items, (item) => Optional.from(item.getType(type))); + }; + const clearData = (type) => { + if (getData(type).isSome()) { + global.clear(); + } + }; + const setRows = (rowsOpt) => { + rowsOpt.fold(clearRows, (rows) => setData({ [tableTypeRow]: rows })); + }; + const getRows = () => getData(tableTypeRow); + const clearRows = () => clearData(tableTypeRow); + const setColumns = (columnsOpt) => { + columnsOpt.fold(clearColumns, (columns) => setData({ [tableTypeColumn]: columns })); + }; + const getColumns = () => getData(tableTypeColumn); + const clearColumns = () => clearData(tableTypeColumn); + + const getSelectionStartCellOrCaption = (editor) => getSelectionCellOrCaption(getSelectionStart(editor), getIsRoot(editor)).filter(isInEditableContext$1); + const getSelectionStartCell = (editor) => getSelectionCell(getSelectionStart(editor), getIsRoot(editor)).filter(isInEditableContext$1); + const registerCommands = (editor, actions) => { + const isRoot = getIsRoot(editor); + const eraseTable = () => getSelectionStartCellOrCaption(editor).each((cellOrCaption) => { + table(cellOrCaption, isRoot).filter(not(isRoot)).each((table) => { + const cursor = SugarElement.fromText(''); + after$4(table, cursor); + remove$5(table); + if (editor.dom.isEmpty(editor.getBody())) { + editor.setContent(''); + editor.selection.setCursorLocation(); + } + else { + const rng = editor.dom.createRng(); + rng.setStart(cursor.dom, 0); + rng.setEnd(cursor.dom, 0); + editor.selection.setRng(rng); + editor.nodeChanged(); + } + }); + }); + const setSizingMode = (sizing) => getSelectionStartCellOrCaption(editor).each((cellOrCaption) => { + // Do nothing if tables are forced to use a specific sizing mode + const isForcedSizing = isTableResponsiveForced(editor) || isTablePixelsForced(editor) || isTablePercentagesForced(editor); + if (!isForcedSizing) { + table(cellOrCaption, isRoot).each((table) => { + if (sizing === 'relative' && !isPercentSizing(table)) { + convertToPercentSizeWidth(table); + } + else if (sizing === 'fixed' && !isPixelSizing(table)) { + convertToPixelSizeWidth(table); + } + else if (sizing === 'responsive' && !isNoneSizing(table)) { + convertToNoneSizeWidth(table); + } + removeDataStyle(table); + fireTableModified(editor, table.dom, structureModified); + }); + } + }); + const getTableFromCell = (cell) => table(cell, isRoot); + const performActionOnSelection = (action) => getSelectionStartCell(editor).bind((cell) => getTableFromCell(cell).map((table) => action(table, cell))); + const toggleTableClass = (_ui, clazz) => { + performActionOnSelection((table) => { + editor.formatter.toggle('tableclass', { value: clazz }, table.dom); + fireTableModified(editor, table.dom, styleModified); + }); + }; + const toggleTableCellClass = (_ui, clazz) => { + performActionOnSelection((table) => { + const selectedCells = getCellsFromSelection(editor); + const allHaveClass = forall(selectedCells, (cell) => editor.formatter.match('tablecellclass', { value: clazz }, cell.dom)); + const formatterAction = allHaveClass ? editor.formatter.remove : editor.formatter.apply; + each$2(selectedCells, (cell) => formatterAction('tablecellclass', { value: clazz }, cell.dom)); + fireTableModified(editor, table.dom, styleModified); + }); + }; + const toggleCaption = () => { + getSelectionStartCellOrCaption(editor).each((cellOrCaption) => { + table(cellOrCaption, isRoot).each((table) => { + child(table, 'caption').fold(() => { + const caption = SugarElement.fromTag('caption'); + append$1(caption, SugarElement.fromText('Caption')); + appendAt(table, caption, 0); + editor.selection.setCursorLocation(caption.dom, 0); + }, (caption) => { + if (isTag('caption')(cellOrCaption)) { + one('td', table).each((td) => editor.selection.setCursorLocation(td.dom, 0)); + } + remove$5(caption); + }); + fireTableModified(editor, table.dom, structureModified); + }); + }); + }; + const postExecute = (_data) => { + editor.focus(); + }; + const actOnSelection = (execute, noEvents = false) => performActionOnSelection((table, startCell) => { + const targets = forMenu(getCellsFromSelection(editor), table, startCell); + execute(table, targets, noEvents).each(postExecute); + }); + const copyRowSelection = () => performActionOnSelection((table, startCell) => { + const targets = forMenu(getCellsFromSelection(editor), table, startCell); + const generators = cellOperations(noop, SugarElement.fromDom(editor.getDoc()), Optional.none()); + return copyRows(table, targets, generators); + }); + const copyColSelection = () => performActionOnSelection((table, startCell) => { + const targets = forMenu(getCellsFromSelection(editor), table, startCell); + return copyCols(table, targets); + }); + const pasteOnSelection = (execute, getRows) => + // If we have FakeClipboard rows to paste + getRows().each((rows) => { + const clonedRows = map$1(rows, (row) => deep(row)); + performActionOnSelection((table, startCell) => { + const generators = paste$1(SugarElement.fromDom(editor.getDoc())); + const targets = pasteRows(getCellsFromSelection(editor), startCell, clonedRows, generators); + execute(table, targets).each(postExecute); + }); + }); + const actOnType = (getAction) => (_ui, args) => get$c(args, 'type').each((type) => { + actOnSelection(getAction(type), args.no_events); + }); + // Register action commands + each$1({ + mceTableSplitCells: () => actOnSelection(actions.unmergeCells), + mceTableMergeCells: () => actOnSelection(actions.mergeCells), + mceTableInsertRowBefore: () => actOnSelection(actions.insertRowsBefore), + mceTableInsertRowAfter: () => actOnSelection(actions.insertRowsAfter), + mceTableInsertColBefore: () => actOnSelection(actions.insertColumnsBefore), + mceTableInsertColAfter: () => actOnSelection(actions.insertColumnsAfter), + mceTableDeleteCol: () => actOnSelection(actions.deleteColumn), + mceTableDeleteRow: () => actOnSelection(actions.deleteRow), + mceTableCutCol: () => copyColSelection().each((selection) => { + setColumns(selection); + actOnSelection(actions.deleteColumn); + }), + mceTableCutRow: () => copyRowSelection().each((selection) => { + setRows(selection); + actOnSelection(actions.deleteRow); + }), + mceTableCopyCol: () => copyColSelection().each((selection) => setColumns(selection)), + mceTableCopyRow: () => copyRowSelection().each((selection) => setRows(selection)), + mceTablePasteColBefore: () => pasteOnSelection(actions.pasteColsBefore, getColumns), + mceTablePasteColAfter: () => pasteOnSelection(actions.pasteColsAfter, getColumns), + mceTablePasteRowBefore: () => pasteOnSelection(actions.pasteRowsBefore, getRows), + mceTablePasteRowAfter: () => pasteOnSelection(actions.pasteRowsAfter, getRows), + mceTableDelete: eraseTable, + mceTableCellToggleClass: toggleTableCellClass, + mceTableToggleClass: toggleTableClass, + mceTableToggleCaption: toggleCaption, + mceTableSizingMode: (_ui, sizing) => setSizingMode(sizing), + mceTableCellType: actOnType((type) => type === 'th' ? actions.makeCellsHeader : actions.unmakeCellsHeader), + mceTableColType: actOnType((type) => type === 'th' ? actions.makeColumnsHeader : actions.unmakeColumnsHeader), + mceTableRowType: actOnType((type) => { + switch (type) { + case 'header': + return actions.makeRowsHeader; + case 'footer': + return actions.makeRowsFooter; + default: + return actions.makeRowsBody; + } + }) + }, (func, name) => editor.addCommand(name, func)); + editor.addCommand('mceInsertTable', (_ui, args) => { + insertTable(editor, args.rows, args.columns, args.options); + }); + // Apply cell style using command (background color, border color, border style and border width) + // tinyMCE.activeEditor.execCommand('mceTableApplyCellStyle', false, { backgroundColor: 'red', borderColor: 'blue' }) + // Remove cell style using command (an empty string indicates to remove the style) + // tinyMCE.activeEditor.execCommand('mceTableApplyCellStyle', false, { backgroundColor: '' }) + editor.addCommand('mceTableApplyCellStyle', (_ui, args) => { + const getFormatName = (style) => 'tablecell' + style.toLowerCase().replace('-', ''); + if (!isObject(args)) { + return; + } + const cells = filter$2(getCellsFromSelection(editor), isInEditableContext$1); + if (cells.length === 0) { + return; + } + const validArgs = filter$1(args, (value, style) => editor.formatter.has(getFormatName(style)) && isString(value)); + if (isEmpty(validArgs)) { + return; + } + each$1(validArgs, (value, style) => { + const formatName = getFormatName(style); + each$2(cells, (cell) => { + if (value === '') { + editor.formatter.remove(formatName, { value: null }, cell.dom, true); + } + else { + editor.formatter.apply(formatName, { value }, cell.dom); + } + }); + }); + /* + Use the first cell in the selection to get the table and fire the TableModified event. + If this command is applied over multiple tables, only the first table selected + will have a TableModified event thrown. + */ + getTableFromCell(cells[0]).each((table) => fireTableModified(editor, table.dom, styleModified)); + }); + }; + + const registerQueryCommands = (editor, actions) => { + const isRoot = getIsRoot(editor); + const lookupOnSelection = (action) => getSelectionCell(getSelectionStart(editor)).bind((cell) => table(cell, isRoot).map((table) => { + const targets = forMenu(getCellsFromSelection(editor), table, cell); + return action(table, targets); + })).getOr(''); + each$1({ + mceTableRowType: () => lookupOnSelection(actions.getTableRowType), + mceTableCellType: () => lookupOnSelection(actions.getTableCellType), + mceTableColType: () => lookupOnSelection(actions.getTableColType) + }, (func, name) => editor.addQueryValueHandler(name, func)); + }; + + const hasInternalTarget = (e) => !has(SugarElement.fromDom(e.target), 'ephox-snooker-resizer-bar'); + const TableCellSelectionHandler = (editor, resizeHandler) => { + const cellSelection = Selections(() => SugarElement.fromDom(editor.getBody()), () => getSelectionCell(getSelectionStart(editor), getIsRoot(editor)), ephemera.selectedSelector); + const onSelection = (cells, start, finish) => { + const tableOpt = table(start); + tableOpt.each((table) => { + const cellsDom = map$1(cells, (cell) => cell.dom); + const cloneFormats = getTableCloneElements(editor); + const generators = cellOperations(noop, SugarElement.fromDom(editor.getDoc()), cloneFormats); + const selectedCells = getCellsFromSelection(editor); + const otherCellsDom = getOtherCells(table, { selection: selectedCells }, generators) + .map((otherCells) => map(otherCells, (cellArr) => map$1(cellArr, (cell) => cell.dom))) + .getOrUndefined(); + fireTableSelectionChange(editor, cellsDom, start.dom, finish.dom, otherCellsDom); + }); + }; + const onClear = () => fireTableSelectionClear(editor); + const annotations = SelectionAnnotation.byAttr(ephemera, onSelection, onClear); + editor.on('init', (_e) => { + const win = editor.getWin(); + const body = getBody(editor); + const isRoot = getIsRoot(editor); + // When the selection changes through either the mouse or keyboard, and the selection is no longer within the table. + // Remove the selection. + const syncSelection = () => { + const sel = editor.selection; + const start = SugarElement.fromDom(sel.getStart()); + const end = SugarElement.fromDom(sel.getEnd()); + const shared = sharedOne(table, [start, end]); + shared.fold(() => annotations.clear(body), noop); + }; + const mouseHandlers = mouse(win, body, isRoot, annotations); + const keyHandlers = keyboard(win, body, isRoot, annotations); + const external$1 = external(win, body, isRoot, annotations); + const hasShiftKey = (event) => event.raw.shiftKey === true; + editor.on('TableSelectorChange', (e) => external$1(e.start, e.finish)); + const handleResponse = (event, response) => { + // Only handle shift key non shiftkey cell navigation is handled by core + if (!hasShiftKey(event)) { + return; + } + if (response.kill) { + event.kill(); + } + response.selection.each((ns) => { + const relative = SimSelection.relative(ns.start, ns.finish); + const rng = asLtrRange(win, relative); + editor.selection.setRng(rng); + }); + }; + const keyup = (event) => { + const wrappedEvent = fromRawEvent(event); + // Note, this is an optimisation. + if (wrappedEvent.raw.shiftKey && isNavigation(wrappedEvent.raw.which)) { + const rng = editor.selection.getRng(); + const start = SugarElement.fromDom(rng.startContainer); + const end = SugarElement.fromDom(rng.endContainer); + keyHandlers.keyup(wrappedEvent, start, rng.startOffset, end, rng.endOffset).each((response) => { + handleResponse(wrappedEvent, response); + }); + } + }; + const keydown = (event) => { + const wrappedEvent = fromRawEvent(event); + resizeHandler.hide(); + const rng = editor.selection.getRng(); + const start = SugarElement.fromDom(rng.startContainer); + const end = SugarElement.fromDom(rng.endContainer); + const direction = onDirection(ltr, rtl)(SugarElement.fromDom(editor.selection.getStart())); + keyHandlers.keydown(wrappedEvent, start, rng.startOffset, end, rng.endOffset, direction).each((response) => { + handleResponse(wrappedEvent, response); + }); + resizeHandler.show(); + }; + const isLeftMouse = (raw) => raw.button === 0; + // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons + const isLeftButtonPressed = (raw) => { + // Only added by Chrome/Firefox in June 2015. + // This is only to fix a 1px bug (TBIO-2836) so return true if we're on an older browser + if (raw.buttons === undefined) { + return true; + } + // use bitwise & for optimal comparison + // eslint-disable-next-line no-bitwise + return (raw.buttons & 1) !== 0; + }; + const dragStart = (_e) => { + mouseHandlers.clearstate(); + }; + const mouseDown = (e) => { + if (isLeftMouse(e) && hasInternalTarget(e)) { + mouseHandlers.mousedown(fromRawEvent(e)); + } + }; + const mouseOver = (e) => { + if (isLeftButtonPressed(e) && hasInternalTarget(e)) { + mouseHandlers.mouseover(fromRawEvent(e)); + } + }; + const mouseUp = (e) => { + if (isLeftMouse(e) && hasInternalTarget(e)) { + mouseHandlers.mouseup(fromRawEvent(e)); + } + }; + const getDoubleTap = () => { + const lastTarget = Cell(SugarElement.fromDom(body)); + const lastTimeStamp = Cell(0); + const touchEnd = (t) => { + const target = SugarElement.fromDom(t.target); + if (isTag('td')(target) || isTag('th')(target)) { + const lT = lastTarget.get(); + const lTS = lastTimeStamp.get(); + if (eq$1(lT, target) && (t.timeStamp - lTS) < 300) { + t.preventDefault(); + external$1(target, target); + } + } + lastTarget.set(target); + lastTimeStamp.set(t.timeStamp); + }; + return { + touchEnd + }; + }; + const doubleTap = getDoubleTap(); + editor.on('dragstart', dragStart); + editor.on('mousedown', mouseDown); + editor.on('mouseover', mouseOver); + editor.on('mouseup', mouseUp); + editor.on('touchend', doubleTap.touchEnd); + editor.on('keyup', keyup); + editor.on('keydown', keydown); + editor.on('NodeChange', syncSelection); + }); + editor.on('PreInit', () => { + editor.serializer.addTempAttr(ephemera.firstSelected); + editor.serializer.addTempAttr(ephemera.lastSelected); + }); + const clearSelectedCells = (container) => annotations.clear(SugarElement.fromDom(container)); + const getSelectedCells = () => fold(cellSelection.get(), + // No fake selected cells + constant([]), + // This path is taken whenever there is fake cell selection even for just a single selected cell + (cells) => { + return map$1(cells, (cell) => cell.dom); + }, + // For this path, the start of the selection whether collapsed or ranged is within a table cell + (cell) => [cell.dom]); + return { + getSelectedCells, + clearSelectedCells + }; + }; + + const get = (editor, isResizable) => { + const editorBody = SugarElement.fromDom(editor.getBody()); + return ResizeWire.body(editorBody, isResizable); + }; + + const isTable = (node) => isNonNullable(node) && node.nodeName === 'TABLE'; + const barResizerPrefix = 'bar-'; + const isResizable = (elm) => get$b(elm, 'data-mce-resize') !== 'false'; + const syncTableCellPixels = (table) => { + const warehouse = Warehouse.fromTable(table); + if (!Warehouse.hasColumns(warehouse)) { + // Ensure the specified width matches the actual cell width + each$2(cells$1(table), (cell) => { + const computedWidth = get$9(cell, 'width'); + set$1(cell, 'width', computedWidth); + remove$6(cell, 'width'); + }); + } + }; + const isCornerResize = (origin) => startsWith(origin, 'corner-'); + const getCornerLocation = (origin) => removeLeading(origin, 'corner-'); + const TableResizeHandler = (editor) => { + const selectionRng = value(); + const tableResize = value(); + const resizeWire = value(); + let startW; + let startRawW; + let startH; + let startRawH; + const lazySizing = (table) => get$1(editor, table); + const lazyResizingBehaviour = () => isPreserveTableColumnResizing(editor) ? preserveTable() : resizeTable(); + const getNumColumns = (table) => getGridSize(table).columns; + const getNumRows = (table) => getGridSize(table).rows; + const afterCornerResize = (table, origin, width, height) => { + // Origin will tell us which handle was clicked, eg corner-se or corner-nw + // so check to see if it ends with `e` (eg east edge) + const location = getCornerLocation(origin); + const isRightEdgeResize = endsWith(location, 'e'); + const isNorthEdgeResize = startsWith(location, 'n'); + // Responsive tables don't have a width so we need to convert it to a relative/percent + // table instead, as that's closer to responsive sizing than fixed sizing + if (startRawW === '') { + convertToPercentSizeWidth(table); + } + // Responsive tables don't have a height so we need to convert it to a fixed value to be able to resize the table height + if (startRawH === '') { + convertToPixelSizeHeight(table); + } + // Adjust the column sizes and update the table width to use the right sizing, if the table changed size. + // This is needed as core will always use pixels when setting the width. + if (width !== startW && startRawW !== '') { + // Restore the original size and then let snooker resize appropriately + set$1(table, 'width', startRawW); + const resizing = lazyResizingBehaviour(); + const tableSize = lazySizing(table); + // For preserve table we want to always resize the entire table. So pretend the last column is being resized + const col = isPreserveTableColumnResizing(editor) || isRightEdgeResize ? getNumColumns(table) - 1 : 0; + adjustWidth(table, width - startW, col, resizing, tableSize); + // Handle the edge case where someone might fire this event without resizing. + // If so then we need to ensure the table is still using percent + } + else if (isPercentage$1(startRawW)) { + const percentW = parseFloat(startRawW.replace('%', '')); + const targetPercentW = width * percentW / startW; + set$1(table, 'width', targetPercentW + '%'); + } + // Sync the cell sizes, as the core resizing logic doesn't update them, but snooker does + if (isPixel(startRawW)) { + syncTableCellPixels(table); + } + // NOTE: This will only change the height of the first or last tr + if (height !== startH && startRawH !== '') { + // Restore the original size and then let snooker resize appropriately + set$1(table, 'height', startRawH); + const idx = isNorthEdgeResize ? 0 : getNumRows(table) - 1; + adjustHeight(table, height - startH, idx); + } + }; + const destroy = () => { + tableResize.on((sz) => { + sz.destroy(); + }); + }; + editor.on('init', () => { + const rawWire = get(editor, isResizable); + resizeWire.set(rawWire); + if (hasTableObjectResizing(editor) && hasTableResizeBars(editor)) { + const resizing = lazyResizingBehaviour(); + const sz = TableResize.create(rawWire, resizing, lazySizing); + if (!editor.mode.isReadOnly()) { + sz.on(); + } + sz.events.startDrag.bind((_event) => { + selectionRng.set(editor.selection.getRng()); + }); + sz.events.beforeResize.bind((event) => { + const rawTable = event.table.dom; + fireObjectResizeStart(editor, rawTable, getPixelWidth(rawTable), getPixelHeight(rawTable), barResizerPrefix + event.type); + }); + sz.events.afterResize.bind((event) => { + const table = event.table; + const rawTable = table.dom; + removeDataStyle(table); + selectionRng.on((rng) => { + editor.selection.setRng(rng); + editor.focus(); + }); + fireObjectResized(editor, rawTable, getPixelWidth(rawTable), getPixelHeight(rawTable), barResizerPrefix + event.type); + editor.undoManager.add(); + }); + tableResize.set(sz); + } + }); + // If we're updating the table width via the old mechanic, we need to update the constituent cells' widths/heights too. + editor.on('ObjectResizeStart', (e) => { + const targetElm = e.target; + if (isTable(targetElm) && !editor.mode.isReadOnly()) { + const table = SugarElement.fromDom(targetElm); + // Add a class based on the resizing mode + each$2(editor.dom.select('.mce-clonedresizable'), (clone) => { + editor.dom.addClass(clone, 'mce-' + getTableColumnResizingBehaviour(editor) + '-columns'); + }); + if (!isPixelSizing(table) && isTablePixelsForced(editor)) { + convertToPixelSizeWidth(table); + } + else if (!isPercentSizing(table) && isTablePercentagesForced(editor)) { + convertToPercentSizeWidth(table); + } + // TINY-6601: If resizing using a bar, then snooker will base the resizing on the initial size. So + // when using a responsive table we need to ensure we convert to a relative table before resizing + if (isNoneSizing(table) && startsWith(e.origin, barResizerPrefix)) { + convertToPercentSizeWidth(table); + } + startW = e.width; + startRawW = isTableResponsiveForced(editor) ? '' : getRawWidth(editor, targetElm).getOr(''); + startH = e.height; + startRawH = getRawHeight(editor, targetElm).getOr(''); + } + }); + editor.on('ObjectResized', (e) => { + const targetElm = e.target; + if (isTable(targetElm)) { + const table = SugarElement.fromDom(targetElm); + // Resize based on the snooker logic to adjust the individual col/rows if resized from a corner + const origin = e.origin; + if (isCornerResize(origin)) { + afterCornerResize(table, origin, e.width, e.height); + } + removeDataStyle(table); + fireTableModified(editor, table.dom, styleModified); + } + }); + const showResizeBars = () => { + tableResize.on((resize) => { + resize.on(); + resize.showBars(); + }); + }; + const hideResizeBars = () => { + tableResize.on((resize) => { + resize.off(); + resize.hideBars(); + }); + }; + editor.on('DisabledStateChange', (e) => { + e.state ? hideResizeBars() : showResizeBars(); + }); + editor.on('SwitchMode', () => { + editor.mode.isReadOnly() ? hideResizeBars() : showResizeBars(); + }); + editor.on('dragstart dragend', (e) => { + e.type === 'dragstart' ? hideResizeBars() : showResizeBars(); + }); + editor.on('remove', () => { + destroy(); + }); + const refresh = (table) => { + tableResize.on((resize) => resize.refreshBars(SugarElement.fromDom(table))); + }; + const hide = () => { + tableResize.on((resize) => resize.hideBars()); + }; + const show = () => { + tableResize.on((resize) => resize.showBars()); + }; + return { + refresh, + hide, + show + }; + }; + + const setupTable = (editor) => { + register(editor); + const resizeHandler = TableResizeHandler(editor); + const cellSelectionHandler = TableCellSelectionHandler(editor, resizeHandler); + const actions = TableActions(editor, resizeHandler, cellSelectionHandler); + registerCommands(editor, actions); + registerQueryCommands(editor, actions); + // TODO: TINY-8385 Maybe move to core. Although, will need RTC to have that working first + registerEvents(editor, actions); + return { + getSelectedCells: cellSelectionHandler.getSelectedCells, + clearSelectedCells: cellSelectionHandler.clearSelectedCells + }; + }; + + const DomModel = (editor) => { + const table = setupTable(editor); + return { + table + }; }; var Model = () => { - global$1.add('dom', DomModel); + global$1.add('dom', DomModel); }; Model(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/models/dom/model.min.js b/public/ext/tinymce/models/dom/model.min.js index 51e88d1..32bb9a3 100644 --- a/public/ext/tinymce/models/dom/model.min.js +++ b/public/ext/tinymce/models/dom/model.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.ModelManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(t)===e,o=e=>t=>typeof t===e,n=e=>t=>e===t,r=t("string"),s=t("object"),l=t("array"),a=n(null),c=o("boolean"),i=n(void 0),m=e=>!(e=>null==e)(e),d=o("function"),u=o("number"),f=()=>{},g=e=>()=>e,h=e=>e,p=(e,t)=>e===t;function b(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const w=e=>t=>!e(t),v=e=>e(),y=g(!1),x=g(!0);class C{constructor(e,t){this.tag=e,this.value=t}static some(e){return new C(!0,e)}static none(){return C.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?C.some(e(this.value)):C.none()}bind(e){return this.tag?e(this.value):C.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:C.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return m(e)?C.some(e):C.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}C.singletonNone=new C(!1);const S=Array.prototype.slice,T=Array.prototype.indexOf,R=Array.prototype.push,D=(e,t)=>{return o=e,n=t,T.call(o,n)>-1;var o,n},O=(e,t)=>{for(let o=0,n=e.length;o{const o=[];for(let n=0;n{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;o{const o=[],n=[];for(let r=0,s=e.length;r{const o=[];for(let n=0,r=e.length;n(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),A=(e,t,o)=>(N(e,((e,n)=>{o=t(o,e,n)})),o),L=(e,t)=>((e,t,o)=>{for(let n=0,r=e.length;n{for(let o=0,n=e.length;o{const t=[];for(let o=0,n=e.length;oM(E(e,t)),P=(e,t)=>{for(let o=0,n=e.length;o{const o={};for(let n=0,r=e.length;nt>=0&&tF(e,0),$=e=>F(e,e.length-1),V=(e,t)=>{for(let o=0;o{const o=q(e);for(let n=0,r=o.length;nY(e,((e,o)=>({k:o,v:t(e,o)}))),Y=(e,t)=>{const o={};return G(e,((e,n)=>{const r=t(e,n);o[r.k]=r.v})),o},J=(e,t)=>{const o=[];return G(e,((e,n)=>{o.push(t(e,n))})),o},Q=e=>J(e,h),X=(e,t)=>U.call(e,t),Z="undefined"!=typeof window?window:Function("return this;")(),ee=(e,t)=>((e,t)=>{let o=null!=t?t:Z;for(let t=0;t{const t=ee("ownerDocument.defaultView",e);return s(e)&&((e=>((e,t)=>{const o=((e,t)=>ee(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(te(e).constructor.name))},ne=e=>e.dom.nodeName.toLowerCase(),re=e=>e.dom.nodeType,se=e=>t=>re(t)===e,le=e=>8===re(e)||"#comment"===ne(e),ae=e=>ce(e)&&oe(e.dom),ce=se(1),ie=se(3),me=se(9),de=se(11),ue=e=>t=>ce(t)&&ne(t)===e,fe=(e,t,o)=>{if(!(r(o)||c(o)||u(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},ge=(e,t,o)=>{fe(e.dom,t,o)},he=(e,t)=>{const o=e.dom;G(t,((e,t)=>{fe(o,t,e)}))},pe=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},be=(e,t)=>C.from(pe(e,t)),we=(e,t)=>{e.dom.removeAttribute(t)},ve=e=>A(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),ye=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},xe={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return ye(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return ye(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return ye(o)},fromDom:ye,fromPoint:(e,t,o)=>C.from(e.dom.elementFromPoint(t,o)).map(ye)},Ce=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},Se=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Te=(e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?C.none():C.from(o.querySelector(e)).map(xe.fromDom)},Re=(e,t)=>e.dom===t.dom,De=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},Oe=Ce,ke=e=>xe.fromDom(e.dom.ownerDocument),Ee=e=>me(e)?e:ke(e),Ne=e=>C.from(e.dom.parentNode).map(xe.fromDom),_e=e=>C.from(e.dom.parentElement).map(xe.fromDom),Be=(e,t)=>{const o=d(t)?t:y;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=xe.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r},ze=e=>C.from(e.dom.previousSibling).map(xe.fromDom),Ae=e=>C.from(e.dom.nextSibling).map(xe.fromDom),Le=e=>E(e.dom.childNodes,xe.fromDom),We=(e,t)=>{const o=e.dom.childNodes;return C.from(o[t]).map(xe.fromDom)},Me=(e,t)=>{Ne(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},je=(e,t)=>{Ae(e).fold((()=>{Ne(e).each((e=>{Ie(e,t)}))}),(e=>{Me(e,t)}))},Pe=(e,t)=>{const o=(e=>We(e,0))(e);o.fold((()=>{Ie(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},Ie=(e,t)=>{e.dom.appendChild(t.dom)},Fe=(e,t)=>{Me(e,t),Ie(t,e)},He=(e,t)=>{N(t,((o,n)=>{const r=0===n?e:t[n-1];je(r,o)}))},$e=(e,t)=>{N(t,(t=>{Ie(e,t)}))},Ve=e=>{e.dom.textContent="",N(Le(e),(e=>{qe(e)}))},qe=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Ue=e=>{const t=Le(e);t.length>0&&He(e,t),qe(e)},Ge=(e,t)=>xe.fromDom(e.dom.cloneNode(t)),Ke=e=>Ge(e,!1),Ye=e=>Ge(e,!0),Je=(e,t)=>{const o=xe.fromTag(t),n=ve(e);return he(o,n),o},Qe=["tfoot","thead","tbody","colgroup"],Xe=(e,t,o)=>({element:e,rowspan:t,colspan:o}),Ze=(e,t,o)=>({element:e,cells:t,section:o}),et=(e,t,o)=>({element:e,isNew:t,isLocked:o}),tt=(e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}),ot=e=>de(e)&&m(e.dom.host),nt=e=>xe.fromDom(e.dom.getRootNode()),rt=e=>xe.fromDom(e.dom.host),st=e=>{const t=ie(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=nt(e);return ot(t)?C.some(t):C.none()})(xe.fromDom(t)).fold((()=>o.body.contains(t)),(n=st,r=rt,e=>n(r(e))));var n,r},lt=()=>at(xe.fromDom(document)),at=e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return xe.fromDom(t)},ct=(e,t)=>{let o=[];return N(Le(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(ct(e,t))})),o},it=(e,t,o)=>((e,o,n)=>B(Be(e,n),(e=>Ce(e,t))))(e,0,o),mt=(e,t)=>(e=>B(Le(e),(e=>Ce(e,t))))(e),dt=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?[]:E(o.querySelectorAll(e),xe.fromDom)})(t,e);var ut=(e,t,o,n,r)=>e(o,n)?C.some(o):d(r)&&r(o)?C.none():t(o,n,r);const ft=(e,t,o)=>{let n=e.dom;const r=d(o)?o:y;for(;n.parentNode;){n=n.parentNode;const e=xe.fromDom(n);if(t(e))return C.some(e);if(r(e))break}return C.none()},gt=(e,t,o)=>ut(((e,t)=>t(e)),ft,e,t,o),ht=(e,t,o)=>ft(e,(e=>Ce(e,t)),o),pt=(e,t)=>(e=>L(e.dom.childNodes,(e=>{return o=xe.fromDom(e),Ce(o,t);var o})).map(xe.fromDom))(e),bt=(e,t)=>Te(t,e),wt=(e,t,o)=>ut(((e,t)=>Ce(e,t)),ht,e,t,o),vt=(e,t,o=p)=>e.exists((e=>o(e,t))),yt=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;te?C.some(t):C.none(),Ct=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,St=(e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!i(n)||r+t.length<=n)},Tt=(e,t)=>Ct(e,t,0),Rt=(e,t)=>Ct(e,t,e.length-t.length),Dt=(e=>t=>t.replace(e,""))(/^\s+|\s+$/g),Ot=e=>e.length>0,kt=e=>void 0!==e.style&&d(e.style.getPropertyValue),Et=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);kt(e)&&e.style.setProperty(t,o)},Nt=(e,t,o)=>{const n=e.dom;Et(n,t,o)},_t=(e,t)=>{const o=e.dom;G(t,((e,t)=>{Et(o,t,e)}))},Bt=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||st(e)?n:zt(o,t)},zt=(e,t)=>kt(e)?e.style.getPropertyValue(t):"",At=(e,t)=>{const o=e.dom,n=zt(o,t);return C.from(n).filter((e=>e.length>0))},Lt=(e,t)=>{((e,t)=>{kt(e)&&e.style.removeProperty(t)})(e.dom,t),vt(be(e,"style").map(Dt),"")&&we(e,"style")},Wt=(e,t,o=0)=>be(e,t).map((e=>parseInt(e,10))).getOr(o),Mt=(e,t)=>Wt(e,t,1),jt=e=>ue("col")(e)?Wt(e,"span",1)>1:Mt(e,"colspan")>1,Pt=(e,t)=>parseInt(Bt(e,t),10),It=g(10),Ft=g(10),Ht=(e,t)=>$t(e,t,x),$t=(e,t,o)=>j(Le(e),(e=>Ce(e,t)?o(e)?[e]:[]:$t(e,t,o))),Vt=(e,t)=>((e,t,o=y)=>o(t)?C.none():D(e,ne(t))?C.some(t):ht(t,e.join(","),(e=>Ce(e,"table")||o(e))))(["td","th"],e,t),qt=e=>Ht(e,"th,td"),Ut=e=>Ce(e,"colgroup")?mt(e,"col"):j(Yt(e),(e=>mt(e,"col"))),Gt=(e,t)=>wt(e,"table",t),Kt=e=>Ht(e,"tr"),Yt=e=>Gt(e).fold(g([]),(e=>mt(e,"colgroup"))),Jt=(e,t)=>E(e,(e=>{if("colgroup"===ne(e)){const t=E(Ut(e),(e=>{const t=Wt(e,"span",1);return Xe(e,1,t)}));return Ze(e,t,"colgroup")}{const o=E(qt(e),(e=>{const t=Wt(e,"rowspan",1),o=Wt(e,"colspan",1);return Xe(e,t,o)}));return Ze(e,o,t(e))}})),Qt=e=>Ne(e).map((e=>{const t=ne(e);return(e=>D(Qe,e))(t)?t:"tbody"})).getOr("tbody"),Xt=e=>{const t=Kt(e),o=[...Yt(e),...t];return Jt(o,Qt)},Zt=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},eo=()=>to(0,0),to=(e,t)=>({major:e,minor:t}),oo={nu:to,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?eo():((e,t)=>{const o=((e,t)=>{for(let o=0;oNumber(t.replace(o,"$"+e));return to(n(1),n(2))})(e,o)},unknown:eo},no=(e,t)=>{const o=String(t).toLowerCase();return L(e,(e=>e.search(o)))},ro=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,so=e=>t=>St(t,e),lo=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>St(e,"edge/")&&St(e,"chrome")&&St(e,"safari")&&St(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,ro],search:e=>St(e,"chrome")&&!St(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>St(e,"msie")||St(e,"trident")},{name:"Opera",versionRegexes:[ro,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:so("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:so("firefox")},{name:"Safari",versionRegexes:[ro,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(St(e,"safari")||St(e,"mobile/"))&&St(e,"applewebkit")}],ao=[{name:"Windows",search:so("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>St(e,"iphone")||St(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:so("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:so("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:so("linux"),versionRegexes:[]},{name:"Solaris",search:so("sunos"),versionRegexes:[]},{name:"FreeBSD",search:so("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:so("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],co={browsers:g(lo),oses:g(ao)},io="Edge",mo="Chromium",uo="Opera",fo="Firefox",go="Safari",ho=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(io),isChromium:n(mo),isIE:n("IE"),isOpera:n(uo),isFirefox:n(fo),isSafari:n(go)}},po=()=>ho({current:void 0,version:oo.unknown()}),bo=ho,wo=(g(io),g(mo),g("IE"),g(uo),g(fo),g(go),"Windows"),vo="Android",yo="Linux",xo="macOS",Co="Solaris",So="FreeBSD",To="ChromeOS",Ro=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(wo),isiOS:n("iOS"),isAndroid:n(vo),isMacOS:n(xo),isLinux:n(yo),isSolaris:n(Co),isFreeBSD:n(So),isChromeOS:n(To)}},Do=()=>Ro({current:void 0,version:oo.unknown()}),Oo=Ro,ko=(g(wo),g("iOS"),g(vo),g(yo),g(xo),g(Co),g(So),g(To),e=>window.matchMedia(e).matches);let Eo=Zt((()=>((e,t,o)=>{const n=co.browsers(),r=co.oses(),s=t.bind((e=>((e,t)=>V(t.brands,(t=>{const o=t.brand.toLowerCase();return L(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:oo.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>no(e,t).map((e=>{const o=oo.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(po,bo),l=((e,t)=>no(e,t).map((e=>{const o=oo.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(r,e).fold(Do,Oo),a=((e,t,o,n)=>{const r=e.isiOS()&&!0===/ipad/i.test(o),s=e.isiOS()&&!r,l=e.isiOS()||e.isAndroid(),a=l||n("(pointer:coarse)"),c=r||!s&&l&&n("(min-device-width:768px)"),i=s||l&&!c,m=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),d=!i&&!c&&!m;return{isiPad:g(r),isiPhone:g(s),isTablet:g(c),isPhone:g(i),isTouch:g(a),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(m),isDesktop:g(d)}})(l,s,e,o);return{browser:s,os:l,deviceType:a}})(window.navigator.userAgent,C.from(window.navigator.userAgentData),ko)));const No=()=>Eo(),_o=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=Bt(o,e);return parseFloat(t)||0}return n},n=(e,t)=>A(t,((t,o)=>{const n=Bt(e,o),r=void 0===n?0:parseInt(n,10);return isNaN(r)?t:t+r}),0);return{set:(t,o)=>{if(!u(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;kt(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const r=n(e,o);return t>r?t-r:0}}},Bo=(e,t,o)=>((e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?C.none():C.some(t)})(e).getOr(t))(Bt(e,t),o),zo=_o("width",(e=>e.dom.offsetWidth)),Ao=e=>zo.get(e),Lo=e=>zo.getOuter(e),Wo=e=>((e,t)=>{const o=e.dom,n=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?n:((e,t,o,n)=>t-Bo(e,`padding-${o}`,0)-Bo(e,`padding-${n}`,0)-Bo(e,`border-${o}-width`,0)-Bo(e,`border-${n}-width`,0))(e,n,"left","right")})(e,"content-box"),Mo=(e,t,o)=>{const n=e.cells,r=n.slice(0,t),s=n.slice(t),l=r.concat(o).concat(s);return Io(e,l)},jo=(e,t,o)=>Mo(e,t,[o]),Po=(e,t,o)=>{e.cells[t]=o},Io=(e,t)=>tt(e.element,t,e.section,e.isNew),Fo=(e,t)=>e.cells[t],Ho=(e,t)=>Fo(e,t).element,$o=e=>e.cells.length,Vo=e=>{const t=_(e,(e=>"colgroup"===e.section));return{rows:t.fail,cols:t.pass}},qo=(e,t,o)=>{const n=E(e.cells,o);return tt(t(e.element),n,e.section,!0)},Uo="data-snooker-locked-cols",Go=e=>be(e,Uo).bind((e=>C.from(e.match(/\d+/g)))).map((e=>I(e,x))),Ko=e=>{const t=A(Vo(e).rows,((e,t)=>(N(t.cells,((t,o)=>{t.isLocked&&(e[o]=!0)})),e)),{}),o=J(t,((e,t)=>parseInt(t,10)));return(e=>{const t=S.call(e,0);return t.sort(void 0),t})(o)},Yo=(e,t)=>e+","+t,Jo=(e,t)=>{const o=j(e.all,(e=>e.cells));return B(o,t)},Qo=e=>{const t={},o=[],n=H(e).map((e=>e.element)).bind(Gt).bind(Go).getOr({});let r=0,s=0,l=0;const{pass:a,fail:c}=_(e,(e=>"colgroup"===e.section));N(c,(e=>{const a=[];N(e.cells,(e=>{let o=0;for(;void 0!==t[Yo(l,o)];)o++;const r=((e,t)=>X(e,t)&&void 0!==e[t]&&null!==e[t])(n,o.toString()),c=((e,t,o,n,r,s)=>({element:e,rowspan:t,colspan:o,row:n,column:r,isLocked:s}))(e.element,e.rowspan,e.colspan,l,o,r);for(let n=0;n{const t=(e=>{const t={};let o=0;return N(e.cells,(e=>{const n=e.colspan;k(n,(r=>{const s=o+r;t[s]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,n,s)})),o+=n})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,Q(t));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),d=((e,t)=>({rows:e,columns:t}))(r,s);return{grid:d,access:t,all:o,columns:i,colgroups:m}},Xo=e=>{const t=Xt(e);return Qo(t)},Zo=Qo,en=(e,t,o)=>C.from(e.access[Yo(t,o)]),tn=(e,t,o)=>{const n=Jo(e,(e=>o(t,e.element)));return n.length>0?C.some(n[0]):C.none()},on=Jo,nn=e=>j(e.all,(e=>e.cells)),rn=e=>Q(e.columns),sn=e=>q(e.columns).length>0,ln=(e,t)=>C.from(e.columns[t]),an=(e,t=x)=>{const o=e.grid,n=k(o.columns,h),r=k(o.rows,h);return E(n,(o=>cn((()=>j(r,(t=>en(e,t,o).filter((e=>e.column===o)).toArray()))),(e=>1===e.colspan&&t(e.element)),(()=>en(e,0,o)))))},cn=(e,t,o)=>{const n=e();return L(n,t).orThunk((()=>C.from(n[0]).orThunk(o))).map((e=>e.element))},mn=e=>{const t=e.grid,o=k(t.rows,h),n=k(t.columns,h);return E(o,(t=>cn((()=>j(n,(o=>en(e,t,o).filter((e=>e.row===t)).fold(g([]),(e=>[e]))))),(e=>1===e.rowspan),(()=>en(e,t,0)))))},dn=(e,t)=>o=>"rtl"===un(o)?t:e,un=e=>"rtl"===Bt(e,"direction")?"rtl":"ltr",fn=_o("height",(e=>{const t=e.dom;return st(e)?t.getBoundingClientRect().height:t.offsetHeight})),gn=e=>fn.get(e),hn=e=>fn.getOuter(e),pn=(e,t)=>({left:e,top:t,translate:(o,n)=>pn(e+o,t+n)}),bn=pn,wn=(e,t)=>void 0!==e?e:void 0!==t?t:0,vn=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,r=t.documentElement;if(o===e.dom)return bn(o.offsetLeft,o.offsetTop);const s=wn(null==n?void 0:n.pageYOffset,r.scrollTop),l=wn(null==n?void 0:n.pageXOffset,r.scrollLeft),a=wn(r.clientTop,o.clientTop),c=wn(r.clientLeft,o.clientLeft);return yn(e).translate(l-c,s-a)},yn=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?bn(o.offsetLeft,o.offsetTop):st(e)?(e=>{const t=e.getBoundingClientRect();return bn(t.left,t.top)})(t):bn(0,0)},xn=(e,t)=>({row:e,y:t}),Cn=(e,t)=>({col:e,x:t}),Sn=e=>vn(e).left+Lo(e),Tn=e=>vn(e).left,Rn=(e,t)=>Cn(e,Tn(t)),Dn=(e,t)=>Cn(e,Sn(t)),On=e=>vn(e).top,kn=(e,t)=>xn(e,On(t)),En=(e,t)=>xn(e,On(t)+hn(t)),Nn=(e,t,o)=>{if(0===o.length)return[];const n=E(o.slice(1),((t,o)=>t.map((t=>e(o,t))))),r=o[o.length-1].map((e=>t(o.length-1,e)));return n.concat([r])},_n={delta:h,positions:e=>Nn(kn,En,e),edge:On},Bn=dn({delta:h,edge:Tn,positions:e=>Nn(Rn,Dn,e)},{delta:e=>-e,edge:Sn,positions:e=>Nn(Dn,Rn,e)}),zn={delta:(e,t)=>Bn(t).delta(e,t),positions:(e,t)=>Bn(t).positions(e,t),edge:e=>Bn(e).edge(e)},An={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},Ln=(()=>{const e="[0-9]+",t="[eE][+-]?"+e,o=e=>`(?:${e})?`,n=["Infinity",e+"\\."+o(e)+o(t),"\\."+e+o(t),e+o(t)].join("|");return new RegExp(`^([+-]?(?:${n}))(.*)$`)})(),Wn=/(\d+(\.\d+)?)%/,Mn=/(\d+(\.\d+)?)px|em/,jn=ue("col"),Pn=ue("tr"),In=(e,t,o)=>{const n=_e(e).getOrThunk((()=>at(ke(e))));return t(e)/o(n)*100},Fn=(e,t)=>{Nt(e,"width",t+"px")},Hn=(e,t)=>{Nt(e,"width",t+"%")},$n=(e,t)=>{Nt(e,"height",t+"px")},Vn=e=>{const t=(e=>{return Bo(t=e,"height",t.dom.offsetHeight)+"px";var t})(e);return t?((e,t,o,n)=>{const r=parseFloat(e);return Rt(e,"%")&&"table"!==ne(t)?((e,t,o,n)=>{const r=Gt(e).map((e=>{const n=o(e);return Math.floor(t/100*n)})).getOr(t);return n(e,r),r})(t,r,o,n):r})(t,e,gn,$n):gn(e)},qn=(e,t)=>At(e,t).orThunk((()=>be(e,t).map((e=>e+"px")))),Un=e=>qn(e,"width"),Gn=e=>In(e,Ao,Wo),Kn=e=>{return jn(e)?Ao(e):Bo(t=e,"width",t.dom.offsetWidth);var t},Yn=e=>Pn(e)?gn(e):((e,t,o)=>o(e)/Mt(e,"rowspan"))(e,0,Vn),Jn=(e,t,o)=>{Nt(e,"width",t+o)},Qn=e=>In(e,Ao,Wo)+"%",Xn=g(Wn),Zn=ue("col"),er=e=>Un(e).getOrThunk((()=>Kn(e)+"px")),tr=e=>{return(t=e,qn(t,"height")).getOrThunk((()=>Yn(e)+"px"));var t},or=(e,t,o,n,r,s)=>e.filter(n).fold((()=>s(((e,t)=>{if(t<0||t>=e.length-1)return C.none();const o=e[t].fold((()=>{const o=(e=>{const t=S.call(e,0);return t.reverse(),t})(e.slice(0,t));return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:0}))),n=e[t+1].fold((()=>{const o=e.slice(t+1);return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:1})));return o.bind((e=>n.map((t=>{const o=t.delta+e.delta;return Math.abs(t.value-e.value)/o}))))})(o,t))),(e=>r(e))),nr=(e,t,o,n)=>{const r=an(e),s=sn(e)?(e=>E(rn(e),(e=>C.from(e.element))))(e):r,l=[C.some(zn.edge(t))].concat(E(zn.positions(r,t),(e=>e.map((e=>e.x))))),a=w(jt);return E(s,((e,t)=>or(e,t,l,a,(e=>{if((e=>{const t=No().browser,o=t.isChromium()||t.isFirefox();return!Zn(e)||o})(e))return o(e);{const e=null!=(s=r[t])?h(s):C.none();return or(e,t,l,a,(e=>n(C.some(Ao(e)))),n)}var s}),n)))},rr=e=>e.map((e=>e+"px")).getOr(""),sr=(e,t,o)=>nr(e,t,Kn,(e=>e.getOrThunk(o.minCellWidth))),lr=(e,t,o,n)=>{const r=mn(e),s=E(e.all,(e=>C.some(e.element))),l=[C.some(_n.edge(t))].concat(E(_n.positions(r,t),(e=>e.map((e=>e.y)))));return E(s,((e,t)=>or(e,t,l,x,o,n)))},ar=(e,t)=>()=>st(e)?t(e):parseFloat(At(e,"width").getOr("0")),cr=e=>{const t=ar(e,(e=>parseFloat(Qn(e)))),o=ar(e,Ao);return{width:t,pixelWidth:o,getWidths:(t,o)=>((e,t,o)=>nr(e,t,Gn,(e=>e.fold((()=>o.minCellWidth()),(e=>e/o.pixelWidth()*100)))))(t,e,o),getCellDelta:e=>e/o()*100,singleColumnWidth:(e,t)=>[100-e],minCellWidth:()=>It()/o()*100,setElementWidth:Hn,adjustTableWidth:o=>{const n=t();Hn(e,n+o/100*n)},isRelative:!0,label:"percent"}},ir=e=>{const t=ar(e,Ao);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:h,singleColumnWidth:(e,t)=>[Math.max(It(),e+t)-e],minCellWidth:It,setElementWidth:Fn,adjustTableWidth:o=>{const n=t()+o;Fn(e,n)},isRelative:!1,label:"pixel"}},mr=e=>Un(e).fold((()=>(e=>{const t=ar(e,Ao),o=g(0);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:o,singleColumnWidth:g([0]),minCellWidth:o,setElementWidth:f,adjustTableWidth:f,isRelative:!0,label:"none"}})(e)),(t=>((e,t)=>null!==Xn().exec(t)?cr(e):ir(e))(e,t))),dr=ir,ur=cr,fr=(e,t,o)=>{const n=e[o].element,r=xe.fromTag("td");Ie(r,xe.fromTag("br")),(t?Ie:Pe)(n,r)},gr=(e=>{const t=t=>e(t)?C.from(t.dom.nodeValue):C.none();return{get:o=>{if(!e(o))throw new Error("Can only get text value of a text node");return t(o).getOr("")},getOption:t,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(ie),hr=e=>gr.get(e),pr=e=>gr.getOption(e),br=(e,t)=>gr.set(e,t),wr=e=>"img"===ne(e)?1:pr(e).fold((()=>Le(e).length),(e=>e.length)),vr=["img","br"],yr=e=>pr(e).filter((e=>0!==e.trim().length||e.indexOf("\xa0")>-1)).isSome()||D(vr,ne(e))||(e=>ae(e)&&"false"===pe(e,"contenteditable"))(e),xr=e=>((e,t)=>{const o=e=>{for(let n=0;nSr(e,yr),Sr=(e,t)=>{const o=e=>{const n=Le(e);for(let e=n.length-1;e>=0;e--){const r=n[e];if(t(r))return C.some(r);const s=o(r);if(s.isSome())return s}return C.none()};return o(e)},Tr={scope:["row","col"]},Rr=e=>()=>{const t=xe.fromTag("td",e.dom);return Ie(t,xe.fromTag("br",e.dom)),t},Dr=e=>()=>xe.fromTag("col",e.dom),Or=e=>()=>xe.fromTag("colgroup",e.dom),kr=e=>()=>xe.fromTag("tr",e.dom),Er=(e,t,o)=>{const n=((e,t)=>{const o=Je(e,t),n=Le(Ye(e));return $e(o,n),o})(e,t);return G(o,((e,t)=>{null===e?we(n,t):ge(n,t,e)})),n},Nr=e=>e,_r=(e,t,o)=>{const n=(e,t)=>{((e,t)=>{const o=e.dom,n=t.dom;kt(o)&&kt(n)&&(n.style.cssText=o.style.cssText)})(e.element,t),Lt(t,"height"),1!==e.colspan&&Lt(t,"width")};return{col:o=>{const r=xe.fromTag(ne(o.element),t.dom);return n(o,r),e(o.element,r),r},colgroup:Or(t),row:kr(t),cell:r=>{const s=xe.fromTag(ne(r.element),t.dom),l=o.getOr(["strong","em","b","i","span","font","h1","h2","h3","h4","h5","h6","p","div"]),a=l.length>0?((e,t,o)=>xr(e).map((n=>{const r=o.join(","),s=it(n,r,(t=>Re(t,e)));return z(s,((e,t)=>{const o=Ke(t);return Ie(e,o),o}),t)})).getOr(t))(r.element,s,l):s;return Ie(a,xe.fromTag("br")),n(r,s),((e,t)=>{G(Tr,((o,n)=>be(e,n).filter((e=>D(o,e))).each((e=>ge(t,n,e)))))})(r.element,s),e(r.element,s),s},replace:Er,colGap:Dr(t),gap:Rr(t)}},Br=e=>({col:Dr(e),colgroup:Or(e),row:kr(e),cell:Rr(e),replace:Nr,colGap:Dr(e),gap:Rr(e)}),zr=e=>t=>t.options.get(e),Ar="100%",Lr=e=>{var t;const o=e.dom,n=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return Wo(xe.fromDom(n))+"px"},Wr=e=>C.from(e.options.get("table_clone_elements")),Mr=zr("table_header_type"),jr=zr("table_column_resizing"),Pr=e=>"preservetable"===jr(e),Ir=e=>"resizetable"===jr(e),Fr=zr("table_sizing_mode"),Hr=e=>"relative"===Fr(e),$r=e=>"fixed"===Fr(e),Vr=e=>"responsive"===Fr(e),qr=zr("table_resize_bars"),Ur=zr("table_style_by_css"),Gr=zr("table_merge_content_on_paste"),Kr=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>Vr(e)||Ur(e)?t:$r(e)?{...t,width:Lr(e)}:{...t,width:Ar})(e,o)},Yr=zr("table_use_colgroups"),Jr=zr("fixed_toolbar_container"),Qr=zr("fixed_toolbar_container_target"),Xr=zr("ui_mode"),Zr=e=>wt(e,"[contenteditable]"),es=(e,t=!1)=>st(e)?e.dom.isContentEditable:Zr(e).fold(g(t),(e=>"true"===ts(e))),ts=e=>e.dom.contentEditable,os=e=>xe.fromDom(e.getBody()),ns=e=>t=>Re(t,os(e)),rs=e=>{we(e,"data-mce-style");const t=e=>we(e,"data-mce-style");N(qt(e),t),N(Ut(e),t),N(Kt(e),t)},ss=e=>xe.fromDom(e.selection.getStart()),ls=e=>e.getBoundingClientRect().width,as=e=>e.getBoundingClientRect().height,cs=e=>(t,o)=>{const n=t.dom.getStyle(o,e)||t.dom.getAttrib(o,e);return C.from(n).filter(Ot)},is=cs("width"),ms=cs("height"),ds=e=>gt(e,ue("table")).exists(es),us=(e,t)=>{const o=t.column,n=t.column+t.colspan-1,r=t.row,s=t.row+t.rowspan-1;return o<=e.finishCol&&n>=e.startCol&&r<=e.finishRow&&s>=e.startRow},fs=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,gs=(e,t,o)=>{const n=tn(e,t,Re),r=tn(e,o,Re);return n.bind((e=>r.map((t=>{return o=e,n=t,{startRow:Math.min(o.row,n.row),startCol:Math.min(o.column,n.column),finishRow:Math.max(o.row+o.rowspan-1,n.row+n.rowspan-1),finishCol:Math.max(o.column+o.colspan-1,n.column+n.colspan-1)};var o,n}))))},hs=(e,t,o)=>gs(e,t,o).map((t=>{const o=on(e,b(us,t));return E(o,(e=>e.element))})),ps=(e,t)=>tn(e,t,((e,t)=>De(t,e))).map((e=>e.element)),bs=(e,t,o)=>{const n=vs(e);return hs(n,t,o)},ws=(e,t,o,n,r)=>{const s=vs(e),l=Re(e,o)?C.some(t):ps(s,t),a=Re(e,r)?C.some(n):ps(s,n);return l.bind((e=>a.bind((t=>hs(s,e,t)))))},vs=Xo;var ys=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],xs=()=>({up:g({selector:ht,closest:wt,predicate:ft,all:Be}),down:g({selector:dt,predicate:ct}),styles:g({get:Bt,getRaw:At,set:Nt,remove:Lt}),attrs:g({get:pe,set:ge,remove:we,copyTo:(e,t)=>{const o=ve(e);he(t,o)}}),insert:g({before:Me,after:je,afterAll:He,append:Ie,appendAll:$e,prepend:Pe,wrap:Fe}),remove:g({unwrap:Ue,remove:qe}),create:g({nu:xe.fromTag,clone:e=>xe.fromDom(e.dom.cloneNode(!1)),text:xe.fromText}),query:g({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:ze,nextSibling:Ae}),property:g({children:Le,name:ne,parent:Ne,document:e=>Ee(e).dom,isText:ie,isComment:le,isElement:ce,isSpecial:e=>{const t=ne(e);return D(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>ce(e)?be(e,"lang"):C.none(),getText:hr,setText:br,isBoundary:e=>!!ce(e)&&("body"===ne(e)||D(ys,ne(e))),isEmptyTag:e=>!!ce(e)&&D(["br","img","hr","input"],ne(e)),isNonEditable:e=>ce(e)&&"false"===pe(e,"contenteditable")}),eq:Re,is:Oe});const Cs=(e,t,o,n)=>{const r=t(e,o);return z(n,((o,n)=>{const r=t(e,n);return Ss(e,o,r)}),r)},Ss=(e,t,o)=>t.bind((t=>o.filter(b(e.eq,t)))),Ts=xs(),Rs=(e,t)=>((e,t,o)=>o.length>0?((e,t,o,n)=>n(e,t,o[0],o.slice(1)))(e,t,o,Cs):C.none())(Ts,((t,o)=>e(o)),t),Ds=e=>ht(e,"table"),Os=(e,t,o)=>{const n=e=>t=>void 0!==o&&o(t)||Re(t,e);return Re(e,t)?C.some({boxes:C.some([e]),start:e,finish:t}):Ds(e).bind((r=>Ds(t).bind((s=>{if(Re(r,s))return C.some({boxes:bs(r,e,t),start:e,finish:t});if(De(r,s)){const o=it(t,"td,th",n(r)),l=o.length>0?o[o.length-1]:t;return C.some({boxes:ws(r,e,r,t,s),start:e,finish:l})}if(De(s,r)){const o=it(e,"td,th",n(s)),l=o.length>0?o[o.length-1]:e;return C.some({boxes:ws(s,e,r,t,s),start:e,finish:l})}return((e,t)=>((e,t,o,n=y)=>{const r=[t].concat(e.up().all(t)),s=[o].concat(e.up().all(o)),l=e=>W(e,n).fold((()=>e),(t=>e.slice(0,t+1))),a=l(r),c=l(s),i=L(a,(t=>O(c,((e,t)=>b(e.eq,t))(e,t))));return{firstpath:a,secondpath:c,shared:i}})(Ts,e,t,void 0))(e,t).shared.bind((l=>wt(l,"table",o).bind((o=>{const l=it(t,"td,th",n(o)),a=l.length>0?l[l.length-1]:t,c=it(e,"td,th",n(o)),i=c.length>0?c[c.length-1]:e;return C.some({boxes:ws(o,e,r,t,s),start:i,finish:a})}))))}))))},ks=(e,t)=>{const o=dt(e,t);return o.length>0?C.some(o):C.none()},Es=(e,t,o)=>bt(e,t).bind((t=>bt(e,o).bind((e=>Rs(Ds,[t,e]).map((o=>({first:t,last:e,table:o}))))))),Ns=(e,t,o,n,r)=>((e,t)=>L(e,(e=>Ce(e,t))))(e,r).bind((e=>((e,t,o)=>Gt(e).bind((n=>((e,t,o,n)=>tn(e,t,Re).bind((t=>{const r=o>0?t.row+t.rowspan-1:t.row,s=n>0?t.column+t.colspan-1:t.column;return en(e,r+o,s+n).map((e=>e.element))})))(vs(n),e,t,o))))(e,t,o).bind((e=>((e,t)=>ht(e,"table").bind((o=>bt(o,t).bind((t=>Os(t,e).bind((e=>e.boxes.map((t=>({boxes:t,start:e.start,finish:e.finish}))))))))))(e,n))))),_s=(e,t)=>ks(e,t),Bs=(e,t,o)=>Es(e,t,o).bind((t=>{const o=t=>Re(e,t),n="thead,tfoot,tbody,table",r=ht(t.first,n,o),s=ht(t.last,n,o);return r.bind((e=>s.bind((o=>Re(e,o)?((e,t,o)=>((e,t,o)=>gs(e,t,o).bind((t=>((e,t)=>{let o=!0;const n=b(fs,t);for(let r=t.startRow;r<=t.finishRow;r++)for(let s=t.startCol;s<=t.finishCol;s++)o=o&&en(e,r,s).exists(n);return o?C.some(t):C.none()})(e,t))))(vs(e),t,o))(t.table,t.first,t.last):C.none()))))})),zs=h,As=e=>{const t=(e,t)=>be(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&P(e,(e=>t(e,"rowspan")||t(e,"colspan")))?C.some(e):C.none()},Ls=(e,t,o)=>t.length<=1?C.none():Bs(e,o.firstSelectedSelector,o.lastSelectedSelector).map((e=>({bounds:e,cells:t}))),Ws="data-mce-selected",Ms="data-mce-first-selected",js="data-mce-last-selected",Ps="["+Ws+"]",Is={selected:Ws,selectedSelector:"td["+Ws+"],th["+Ws+"]",firstSelected:Ms,firstSelectedSelector:"td["+Ms+"],th["+Ms+"]",lastSelected:js,lastSelectedSelector:"td["+js+"],th["+js+"]"},Fs=(e,t,o)=>({element:o,mergable:Ls(t,e,Is),unmergable:As(e),selection:zs(e)}),Hs=e=>(t,o)=>{const n=ne(t),r="col"===n||"colgroup"===n?Gt(s=t).bind((e=>_s(e,Is.firstSelectedSelector))).fold(g(s),(e=>e[0])):t;var s;return wt(r,e,o)},$s=Hs("th,td,caption"),Vs=Hs("th,td"),qs=e=>{return t=e.model.table.getSelectedCells(),E(t,xe.fromDom);var t},Us=(e,t)=>{e.on("BeforeGetContent",(t=>{const o=o=>{t.preventDefault(),(e=>Gt(e[0]).map((e=>{const t=((e,t)=>{const o=e=>Ce(e.element,t),n=Ye(e),r=Xt(n),s=mr(e),l=Zo(r),a=((e,t)=>{const o=e.grid.columns;let n=e.grid.rows,r=o,s=0,l=0;const a=[],c=[];return G(e.access,(e=>{if(a.push(e),t(e)){c.push(e);const t=e.row,o=t+e.rowspan-1,a=e.column,i=a+e.colspan-1;ts&&(s=o),al&&(l=i)}})),((e,t,o,n,r,s)=>({minRow:e,minCol:t,maxRow:o,maxCol:n,allCells:r,selectedCells:s}))(n,r,s,l,a,c)})(l,o),c="th:not("+t+"),td:not("+t+")",i=$t(n,"th,td",(e=>Ce(e,c)));N(i,qe),((e,t,o,n)=>{const r=B(e,(e=>"colgroup"!==e.section)),s=t.grid.columns,l=t.grid.rows;for(let e=0;eo.maxRow||ao.maxCol||(en(t,e,a).filter(n).isNone()?fr(r,l,e):l=!0)}})(r,l,a,o);const m=((e,t,o,n)=>{if(0===n.minCol&&t.grid.columns===n.maxCol+1)return 0;const r=sr(t,e,o),s=A(r,((e,t)=>e+t),0),l=A(r.slice(n.minCol,n.maxCol+1),((e,t)=>e+t),0),a=l/s*o.pixelWidth()-o.pixelWidth();return o.getCellDelta(a)})(e,Xo(e),s,a);return((e,t,o,n)=>{G(o.columns,(e=>{(e.columnt.maxCol)&&qe(e.element)}));const r=B(Ht(e,"tr"),(e=>0===e.dom.childElementCount));N(r,qe),t.minCol!==t.maxCol&&t.minRow!==t.maxRow||N(Ht(e,"th,td"),(e=>{we(e,"rowspan"),we(e,"colspan")})),we(e,Uo),we(e,"data-snooker-col-series"),mr(e).adjustTableWidth(n)})(n,a,l,m),n})(e,Ps);return rs(t),[t]})))(o).each((o=>{const n="text"===t.format?((e,t)=>{const o=e.getDoc(),n=nt(xe.fromDom(e.getBody())),r=xe.fromTag("div",o);ge(r,"data-mce-bogus","all"),_t(r,{position:"fixed",left:"-9999999px",top:"0",overflow:"hidden",opacity:"0"});const s=(e=>ot(e)?e:xe.fromDom(Ee(e).dom.body))(n);$e(r,t),Ie(s,r);const l=r.dom.innerText;return qe(r),l})(e,o):((e,t)=>E(t,(t=>e.selection.serializer.serialize(t.dom,{}))).join(""))(e,o);t.content=n}))};if(!0===t.selection){const t=(e=>B(qs(e),(e=>Ce(e,Is.selectedSelector))))(e);t.length>=1&&o(t)}})),e.on("BeforeSetContent",(o=>{if(!0===o.selection&&!0===o.paste){const n=qs(e);H(n).each((n=>{Gt(n).each((r=>{const s=B((e=>{const t=document.createElement("div");return t.innerHTML=e,Le(xe.fromDom(t))})(o.content),(e=>"meta"!==ne(e))),l=ue("table");if(Gr(e)&&1===s.length&&l(s[0])){o.preventDefault();const l=xe.fromDom(e.getDoc()),a=Br(l),c=((e,t,o)=>({element:e,clipboard:t,generators:o}))(n,s[0],a);t.pasteCells(r,c).each((()=>{e.focus()}))}}))}))}}))},Gs=(e,t)=>({element:e,offset:t}),Ks=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>Ks(e,t,o).orThunk((()=>C.some(t))))):C.none(),Ys=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,Js=(e,t)=>{const o=Ks(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return Gs(o,Ys(e,o));const n=e.property().children(o);return n.length>0?Js(e,n[n.length-1]):Gs(o,Ys(e,o))},Qs=Js,Xs=xs(),Zs=(e,t)=>{if(!jt(e)){const o=(e=>Un(e).bind((e=>{return t=e,o=["fixed","relative","empty"],C.from(Ln.exec(t)).bind((e=>{const t=Number(e[1]),n=e[2];return((e,t)=>O(t,(t=>O(An[t],(t=>e===t)))))(n,o)?C.some({value:t,unit:n}):C.none()}));var t,o})))(e);o.each((o=>{const n=o.value/2;Jn(e,n,o.unit),Jn(t,n,o.unit)}))}},el=e=>E(e,g(0)),tl=(e,t,o,n,r)=>r(e.slice(0,t)).concat(n).concat(r(e.slice(o))),ol=e=>(t,o,n,r)=>{if(e(n)){const e=Math.max(r,t[o]-Math.abs(n)),s=Math.abs(e-t[o]);return n>=0?s:-s}return n},nl=ol((e=>e<0)),rl=ol(x),sl=()=>{const e=(e,t,o,n)=>{const r=(100+o)/100,s=Math.max(n,(e[t]+o)/r);return E(e,((e,o)=>(o===t?s:e/r)-e))},t=(t,o,n,r,s,l)=>l?e(t,o,r,s):((e,t,o,n,r)=>{const s=nl(e,t,n,r);return tl(e,t,o+1,[s,0],el)})(t,o,n,r,s);return{resizeTable:(e,t)=>e(t),clampTableDelta:nl,calcLeftEdgeDeltas:t,calcMiddleDeltas:(e,o,n,r,s,l,a)=>t(e,n,r,s,l,a),calcRightEdgeDeltas:(t,o,n,r,s,l)=>{if(l)return e(t,n,r,s);{const e=nl(t,n,r,s);return el(t.slice(0,n)).concat([e])}},calcRedestributedWidths:(e,t,o,n)=>{if(n){const n=(t+o)/t,r=E(e,(e=>e/n));return{delta:100*n-100,newSizes:r}}return{delta:o,newSizes:e}}}},ll=()=>{const e=(e,t,o,n,r)=>{const s=rl(e,n>=0?o:t,n,r);return tl(e,t,o+1,[s,-s],el)};return{resizeTable:(e,t,o)=>{o&&e(t)},clampTableDelta:(e,t,o,n,r)=>{if(r){if(o>=0)return o;{const t=A(e,((e,t)=>e+t-n),0);return Math.max(-t,o)}}return nl(e,t,o,n)},calcLeftEdgeDeltas:e,calcMiddleDeltas:(t,o,n,r,s,l)=>e(t,n,r,s,l),calcRightEdgeDeltas:(e,t,o,n,r,s)=>{if(s)return el(e);{const t=n/e.length;return E(e,g(t))}},calcRedestributedWidths:(e,t,o,n)=>({delta:0,newSizes:e})}},al=e=>Xo(e).grid,cl=ue("th"),il=e=>P(e,(e=>cl(e.element))),ml=(e,t)=>e&&t?"sectionCells":e?"section":"cells",dl=e=>{const t="thead"===e.section,o=vt(ul(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:ml(t,o)}:{type:"body"}},ul=e=>{const t=B(e,(e=>cl(e.element)));return 0===t.length?C.some("td"):t.length===e.length?C.some("th"):C.none()},fl=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),gl=(e,t)=>e.section!==t?tt(e.element,e.cells,t,e.isNew):e,hl=()=>({transformRow:gl,transformCell:(e,t,o)=>{const n=o(e.element,t),r="td"!==ne(n)?(e=>{const t=Je(e,"td");je(e,t);const o=Le(e);return $e(t,o),qe(e),t})(n):n;return et(r,e.isNew,e.isLocked)}}),pl=()=>({transformRow:gl,transformCell:fl}),bl=()=>({transformRow:(e,t)=>gl(e,"thead"===t?"tbody":t),transformCell:fl}),wl=hl,vl=pl,yl=bl,xl=()=>({transformRow:h,transformCell:fl}),Cl=(e,t,o,n)=>{o===n?we(e,t):ge(e,t,o)},Sl=(e,t,o)=>{$(mt(e,t)).fold((()=>Pe(e,o)),(e=>je(e,o)))},Tl=(e,t)=>{const o=[],n=[],r=e=>E(e,(e=>{e.isNew&&o.push(e.element);const t=e.element;return Ve(t),N(e.cells,(e=>{e.isNew&&n.push(e.element),Cl(e.element,"colspan",e.colspan,1),Cl(e.element,"rowspan",e.rowspan,1),Ie(t,e.element)})),t})),s=e=>j(e,(e=>E(e.cells,(e=>(Cl(e.element,"span",e.colspan,1),e.element))))),l=(t,o)=>{const n=((e,t)=>{const o=pt(e,t).getOrThunk((()=>{const o=xe.fromTag(t,ke(e).dom);return"thead"===t?Sl(e,"caption,colgroup",o):"colgroup"===t?Sl(e,"caption",o):Ie(e,o),o}));return Ve(o),o})(e,o),l=("colgroup"===o?s:r)(t);$e(n,l)},a=(t,o)=>{t.length>0?l(t,o):(t=>{pt(e,t).each(qe)})(o)},c=[],i=[],m=[],d=[];return N(t,(e=>{switch(e.section){case"thead":c.push(e);break;case"tbody":i.push(e);break;case"tfoot":m.push(e);break;case"colgroup":d.push(e)}})),a(d,"colgroup"),a(c,"thead"),a(i,"tbody"),a(m,"tfoot"),{newRows:o,newCells:n}},Rl=(e,t)=>{if(0===e.length)return 0;const o=e[0];return W(e,(e=>!t(o.element,e.element))).getOr(e.length)},Dl=(e,t)=>{const o=E(e,(e=>E(e.cells,y)));return E(e,((n,r)=>{const s=j(n.cells,((n,s)=>{if(!1===o[r][s]){const m=((e,t,o,n)=>{const r=((e,t)=>e[t])(e,t),s="colgroup"===r.section,l=Rl(r.cells.slice(o),n),a=s?1:Rl(((e,t)=>E(e,(e=>Fo(e,t))))(e.slice(t),o),n);return{colspan:l,rowspan:a}})(e,r,s,t);return((e,t,n,r)=>{for(let s=e;s({element:e,cells:t,section:o,isNew:n}))(n.element,s,n.section,n.isNew)}))},Ol=(e,t,o)=>{const n=[];N(e.colgroups,(r=>{const s=[];for(let n=0;net(e.element,o,!1))).getOrThunk((()=>et(t.colGap(),!0,!1)));s.push(r)}n.push(tt(r.element,s,"colgroup",o))}));for(let r=0;ret(e.element,o,e.isLocked))).getOrThunk((()=>et(t.gap(),!0,!1)));s.push(l)}const l=e.all[r],a=tt(l.element,s,l.section,o);n.push(a)}return n},kl=e=>Dl(e,Re),El=(e,t)=>V(e.all,(e=>L(e.cells,(e=>Re(t,e.element))))),Nl=(e,t,o)=>{const n=E(t.selection,(t=>Vt(t).bind((t=>El(e,t))).filter(o))),r=yt(n);return xt(r.length>0,r)},_l=(e,t,o,n,r)=>(s,l,a,c)=>{const i=Xo(s),m=C.from(null==c?void 0:c.section).getOrThunk(xl);return t(i,l).map((t=>{const o=((e,t)=>Ol(e,t,!1))(i,a),n=e(o,t,Re,r(a),m),s=Ko(n.grid);return{info:t,grid:kl(n.grid),cursor:n.cursor,lockedColumns:s}})).bind((e=>{const t=Tl(s,e.grid),r=C.from(null==c?void 0:c.sizing).getOrThunk((()=>mr(s))),l=C.from(null==c?void 0:c.resize).getOrThunk(ll);return o(s,e.grid,e.info,{sizing:r,resize:l,section:m}),n(s),we(s,Uo),e.lockedColumns.length>0&&ge(s,Uo,e.lockedColumns.join(",")),C.some({cursor:e.cursor,newRows:t.newRows,newCells:t.newCells})}))},Bl=(e,t)=>Nl(e,t,x).map((e=>({cells:e,generators:t.generators,clipboard:t.clipboard}))),zl=(e,t)=>Nl(e,t,x),Al=(e,t)=>Nl(e,t,(e=>!e.isLocked)),Ll=(e,t)=>P(t,(t=>((e,t)=>El(e,t).exists((e=>!e.isLocked)))(e,t))),Wl=(e,t,o,n)=>{const r=Vo(e).rows;let s=!0;for(let e=0;e{const t=t=>t(e),o=g(e),n=()=>r,r={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:x,isError:y,map:t=>Pl.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>C.some(e)};return r},jl=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:y,isError:x,map:t,mapError:t=>Pl.error(t(e)),bind:t,exists:y,forall:x,getOr:h,or:h,getOrThunk:v,orThunk:v,getOrDie:(n=String(e),()=>{throw new Error(n)}),each:f,toOptional:C.none};var n;return o},Pl={value:Ml,error:jl,fromOption:(e,t)=>e.fold((()=>jl(t)),Ml)},Il=(e,t)=>({rowDelta:0,colDelta:$o(e[0])-$o(t[0])}),Fl=(e,t)=>({rowDelta:e.length-t.length,colDelta:0}),Hl=(e,t,o,n)=>{const r="colgroup"===t.section?o.col:o.cell;return k(e,(e=>et(r(),!0,n(e))))},$l=(e,t,o,n)=>{const r=e[e.length-1];return e.concat(k(t,(()=>{const e="colgroup"===r.section?o.colgroup:o.row,t=qo(r,e,h),s=Hl(t.cells.length,t,o,(e=>X(n,e.toString())));return Io(t,s)})))},Vl=(e,t,o,n)=>E(e,(e=>{const r=Hl(t,e,o,y);return Mo(e,n,r)})),ql=(e,t,o)=>{const n=t.colDelta<0?Vl:h,r=t.rowDelta<0?$l:h,s=Ko(e),l=$o(e[0]),a=O(s,(e=>e===l-1)),c=n(e,Math.abs(t.colDelta),o,a?l-1:l),i=Ko(c);return r(c,Math.abs(t.rowDelta),o,I(i,x))},Ul=(e,t,o,n)=>{const r=b(n,Fo(e[t],o).element),s=e[t];return e.length>1&&$o(s)>1&&(o>0&&r(Ho(s,o-1))||o0&&r(Ho(e[t-1],o))||tB(o,(o=>o>=e.column&&o<=$o(t[0])+e.column)),Kl=(e,t,o,n,r)=>{((e,t,o,n)=>{t>0&&t{const r=e.cells[t-1];let s=0;const l=n();for(;e.cells.length>t+s&&o(r.element,e.cells[t+s].element);)Po(e,t+s,et(l,!0,e.cells[t+s].isLocked)),s++}))})(t,e,r,n.cell);const s=Fl(o,t),l=ql(o,s,n),a=Fl(t,l),c=ql(t,a,n);return E(c,((t,o)=>Mo(t,e,l[o].cells)))},Yl=(e,t,o,n,r)=>{((e,t,o,n)=>{const r=Vo(e).rows;if(t>0&&tA(e,((e,o)=>O(e,(e=>t(e.element,o.element)))?e:e.concat([o])),[]))(r[t-1].cells,o);N(e,(e=>{let s=C.none();for(let l=t;l{Po(a,t,et(e,!0,c.isLocked))})))}}))}})(t,e,r,n.cell);const s=Ko(t),l=Il(t,o),a={...l,colDelta:l.colDelta-s.length},c=ql(t,a,n),{cols:i,rows:m}=Vo(c),d=Ko(c),u=Il(o,t),f={...u,colDelta:u.colDelta+d.length},g=(p=n,b=d,E(o,(e=>A(b,((t,o)=>{const n=Hl(1,e,p,x)[0];return jo(t,o,n)}),e)))),h=ql(g,f,n);var p,b;return[...i,...m.slice(0,e),...h,...m.slice(e,m.length)]},Jl=(e,t,o,n,r)=>{const{rows:s,cols:l}=Vo(e),a=s.slice(0,t),c=s.slice(t);return[...l,...a,((e,t,o,n)=>qo(e,(e=>n(e,o)),t))(s[o],((e,o)=>t>0&&tE(e,(e=>{const s=t>0&&t<$o(e)&&n(Ho(e,t-1),Ho(e,t)),l=((e,t,o,n,r,s,l)=>{if("colgroup"!==o&&n)return Fo(e,t);{const t=Fo(e,r);return et(l(t.element,s),!0,!1)}})(e,t,e.section,s,o,n,r);return jo(e,t,l)})),Xl=(e,t,o,n)=>((e,t,o,n)=>void 0!==Ho(e[t],o)&&t>0&&n(Ho(e[t-1],o),Ho(e[t],o)))(e,t,o,n)||((e,t,o)=>t>0&&o(Ho(e,t-1),Ho(e,t)))(e[t],o,n),Zl=(e,t,o,n)=>{const r=e=>(e=>"row"===e?(e=>Mt(e,"rowspan")>1)(t):jt(t))(e)?`${e}group`:e;return e?cl(t)?r(o):null:n&&cl(t)?r("row"===o?"col":"row"):null},ea=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),ta=(e,t,o,n,r,s,l)=>E(e,((e,a)=>(e=>{const c=e.cells,i=E(c,((e,c)=>{if((e=>O(t,(t=>o(e.element,t.element))))(e)){const t=l(e,a,c)?r(e,o,n):e;return s(t,a,c).each((e=>{var o,n;o=t.element,n={scope:C.from(e)},G(n,((e,t)=>{e.fold((()=>{we(o,t)}),(e=>{fe(o.dom,t,e)}))}))})),t}return e}));return tt(e.element,i,e.section,e.isNew)})(e))),oa=(e,t,o)=>j(e,((n,r)=>Xl(e,r,t,o)?[]:[Fo(n,t)])),na=(e,t,o,n,r)=>{const s=Vo(e).rows,l=j(t,(e=>oa(s,e,n))),a=E(s,(e=>il(e.cells))),c=((e,t)=>P(t,h)&&il(e)?x:(e,o,n)=>!("th"===ne(e.element)&&t[o]))(l,a),i=((e,t)=>(o,n)=>C.some(Zl(e,o.element,"row",t[n])))(o,a);return ta(e,l,n,r,ea,i,c)},ra=(e,t,o,n)=>{const r=Vo(e).rows,s=E(t,(e=>Fo(r[e.row],e.column)));return ta(e,s,o,n,ea,C.none,x)},sa=e=>{if(!l(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return N(e,((n,r)=>{const s=q(n);if(1!==s.length)throw new Error("one and only one name per case");const a=s[0],c=n[a];if(void 0!==o[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!l(c))throw new Error("case arguments must be an array");t.push(a),o[a]=(...o)=>{const n=o.length;if(n!==c.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+c.length+" ("+c+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const n=q(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!P(t,(e=>D(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:a,params:o})}}}})),o},la={...sa([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}])},aa=(e,t,o)=>{const n=((e,t)=>sn(e)?((e,t)=>{const o=rn(e);return E(o,((e,o)=>({element:e.element,width:t[o],colspan:e.colspan})))})(e,t):((e,t)=>{const o=nn(e);return E(o,(e=>{const o=((e,t,o)=>{let n=0;for(let r=e;r{o.setElementWidth(e.element,e.width)}))},ca=(e,t,o,n,r)=>{const s=Xo(e),l=r.getCellDelta(t),a=r.getWidths(s,r),c=o===s.grid.columns-1,i=n.clampTableDelta(a,o,l,r.minCellWidth(),c),m=((e,t,o,n,r)=>{const s=e.slice(0),l=((e,t)=>0===e.length?la.none():1===e.length?la.only(0):0===t?la.left(0,1):t===e.length-1?la.right(t-1,t):t>0&&tn.singleColumnWidth(s[e],o)),((e,t)=>r.calcLeftEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)),((e,t,l)=>r.calcMiddleDeltas(s,e,t,l,o,n.minCellWidth(),n.isRelative)),((e,t)=>r.calcRightEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)))})(a,o,i,r,n),d=E(m,((e,t)=>e+a[t]));aa(s,d,r),n.resizeTable(r.adjustTableWidth,i,c)},ia=(e,t,o)=>{const n=Xo(e),r=((e,t)=>lr(e,t,Yn,(e=>e.getOrThunk(Ft))))(n,e),s=E(r,((e,n)=>o===n?Math.max(t+e,Ft()):e)),l=((e,t)=>E(e.all,((e,o)=>({element:e.element,height:t[o]}))))(n,s);N(l,(e=>{$n(e.element,e.height)})),N(nn(n),(e=>{(e=>{Lt(e,"height")})(e.element)}));const a=z(s,((e,t)=>e+t),0);$n(e,a)},ma=e=>A(e,((e,t)=>O(e,(e=>e.column===t.column))?e:e.concat([t])),[]).sort(((e,t)=>e.column-t.column)),da=ue("col"),ua=ue("colgroup"),fa=e=>"tr"===ne(e)||ua(e),ga=e=>({element:e,colspan:Wt(e,"colspan",1),rowspan:Wt(e,"rowspan",1)}),ha=e=>be(e,"scope").map((e=>e.substr(0,3))),pa=(e,t=ga)=>{const o=o=>{if(fa(o))return ua((r={element:o}).element)?e.colgroup(r):e.row(r);{const r=o,s=(t=>da(t.element)?e.col(t):e.cell(t))(t(r));return n=C.some({item:r,replacement:s}),s}var r};let n=C.none();return{getOrInit:(e,t)=>n.fold((()=>o(e)),(n=>t(e,n.item)?n.replacement:o(e)))}},ba=e=>t=>{const o=[],n=n=>{const r="td"===e?{scope:null}:{},s=t.replace(n,e,r);return o.push({item:n,sub:s}),s};return{replaceOrInit:(e,t)=>{if(fa(e)||da(e))return e;{const r=e;return((e,t)=>L(o,(o=>t(o.item,e))))(r,t).fold((()=>n(r)),(o=>t(e,o.item)?o.sub:n(r)))}}}},wa=e=>({unmerge:t=>{const o=ha(t);return o.each((e=>ge(t,"scope",e))),()=>{const n=e.cell({element:t,colspan:1,rowspan:1});return Lt(n,"width"),Lt(t,"width"),o.each((e=>ge(n,"scope",e))),n}},merge:e=>(Lt(e[0],"width"),(()=>{const t=yt(E(e,ha));if(0===t.length)return C.none();{const e=t[0],o=["row","col"];return O(t,(t=>t!==e&&D(o,t)))?C.none():C.from(e)}})().fold((()=>we(e[0],"scope")),(t=>ge(e[0],"scope",t+"group"))),g(e[0]))}),va=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","table","thead","tfoot","tbody","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],ya=xs(),xa=e=>((e,t)=>{const o=e.property().name(t);return D(va,o)})(ya,e),Ca=e=>((e,t)=>{const o=e.property().name(t);return D(["ol","ul"],o)})(ya,e),Sa=e=>{const t=ue("br"),o=e=>Cr(e).bind((o=>{const n=Ae(o).map((e=>!!xa(e)||!!((e,t)=>D(["br","img","hr","input"],e.property().name(t)))(ya,e)&&"img"!==ne(e))).getOr(!1);return Ne(o).map((r=>{return!0===n||("li"===ne(s=r)||ft(s,Ca).isSome())||t(o)||xa(r)&&!Re(e,r)?[]:[xe.fromTag("br")];var s}))})).getOr([]),n=(()=>{const n=j(e,(e=>{const n=Le(e);return(e=>P(e,(e=>t(e)||ie(e)&&0===hr(e).trim().length)))(n)?[]:n.concat(o(e))}));return 0===n.length?[xe.fromTag("br")]:n})();Ve(e[0]),$e(e[0],n)},Ta=e=>es(e,!0),Ra=e=>{0===qt(e).length&&qe(e)},Da=(e,t)=>({grid:e,cursor:t}),Oa=(e,t,o)=>{const n=((e,t,o)=>{var n,r;const s=Vo(e).rows;return C.from(null===(r=null===(n=s[t])||void 0===n?void 0:n.cells[o])||void 0===r?void 0:r.element).filter(Ta).orThunk((()=>(e=>V(e,(e=>V(e.cells,(e=>{const t=e.element;return xt(Ta(t),t)})))))(s)))})(e,t,o);return Da(e,n)},ka=e=>A(e,((e,t)=>O(e,(e=>e.row===t.row))?e:e.concat([t])),[]).sort(((e,t)=>e.row-t.row)),Ea=(e,t)=>(o,n,r,s,l)=>{const a=ka(n),c=E(a,(e=>e.row)),i=((e,t,o,n,r,s,l)=>{const{cols:a,rows:c}=Vo(e),i=c[t[0]],m=j(t,(e=>((e,t,o)=>{const n=e[t];return j(n.cells,((n,r)=>Xl(e,t,r,o)?[]:[n]))})(c,e,r))),d=E(i.cells,((e,t)=>il(oa(c,t,r)))),u=[...c];N(t,(e=>{u[e]=l.transformRow(c[e],o)}));const f=[...a,...u],g=((e,t)=>P(t,h)&&il(e.cells)?x:(e,o,n)=>!("th"===ne(e.element)&&t[n]))(i,d),p=((e,t)=>(o,n,r)=>C.some(Zl(e,o.element,"col",t[r])))(n,d);return ta(f,m,r,s,l.transformCell,p,g)})(o,c,e,t,r,s.replaceOrInit,l);return Oa(i,n[0].row,n[0].column)},Na=Ea("thead",!0),_a=Ea("tbody",!1),Ba=Ea("tfoot",!1),za=(e,t,o)=>{const n=((e,t)=>Jt(e,(()=>t)))(e,o.section),r=Zo(n);return Ol(r,t,!0)},Aa=(e,t,o,n)=>((e,t,o,n)=>{const r=Zo(t),s=n.getWidths(r,n);aa(r,s,n)})(0,t,0,n.sizing),La=(e,t,o,n)=>((e,t,o,n,r)=>{const s=Zo(t),l=n.getWidths(s,n),a=n.pixelWidth(),{newSizes:c,delta:i}=r.calcRedestributedWidths(l,a,o.pixelDelta,n.isRelative);aa(s,c,n),n.adjustTableWidth(i)})(0,t,o,n.sizing,n.resize),Wa=(e,t)=>O(t,(e=>0===e.column&&e.isLocked)),Ma=(e,t)=>O(t,(t=>t.column+t.colspan>=e.grid.columns&&t.isLocked)),ja=(e,t)=>{const o=an(e),n=ma(t);return A(n,((e,t)=>e+o[t.column].map(Lo).getOr(0)),0)},Pa=e=>(t,o)=>zl(t,o).filter((o=>!(e?Wa:Ma)(t,o))).map((e=>({details:e,pixelDelta:ja(t,e)}))),Ia=e=>(t,o)=>Bl(t,o).filter((o=>!(e?Wa:Ma)(t,o.cells))),Fa=ba("th"),Ha=ba("td"),$a=_l(((e,t,o,n)=>{const r=t[0].row,s=ka(t),l=z(s,((e,t)=>({grid:Jl(e.grid,r,t.row+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Oa(l,r,t[0].column)}),zl,f,f,pa),Va=_l(((e,t,o,n)=>{const r=ka(t),s=r[r.length-1],l=s.row+s.rowspan,a=z(r,((e,t)=>Jl(e,l,t.row,o,n.getOrInit)),e);return Oa(a,l,t[0].column)}),zl,f,f,pa),qa=_l(((e,t,o,n)=>{const r=t.details,s=ma(r),l=s[0].column,a=z(s,((e,t)=>({grid:Ql(e.grid,l,t.column+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Oa(a,r[0].row,l)}),Pa(!0),La,f,pa),Ua=_l(((e,t,o,n)=>{const r=t.details,s=r[r.length-1],l=s.column+s.colspan,a=ma(r),c=z(a,((e,t)=>Ql(e,l,t.column,o,n.getOrInit)),e);return Oa(c,r[0].row,l)}),Pa(!1),La,f,pa),Ga=_l(((e,t,o,n)=>{const r=ma(t.details),s=((e,t)=>j(e,(e=>{const o=e.cells,n=z(t,((e,t)=>t>=0&&t0?[tt(e.element,n,e.section,e.isNew)]:[]})))(e,E(r,(e=>e.column))),l=s.length>0?s[0].cells.length-1:0;return Oa(s,r[0].row,Math.min(r[0].column,l))}),((e,t)=>Al(e,t).map((t=>({details:t,pixelDelta:-ja(e,t)})))),La,Ra,pa),Ka=_l(((e,t,o,n)=>{const r=ka(t),s=((e,t,o)=>{const{rows:n,cols:r}=Vo(e);return[...r,...n.slice(0,t),...n.slice(o+1)]})(e,r[0].row,r[r.length-1].row),l=Math.max(Vo(s).rows.length-1,0);return Oa(s,Math.min(t[0].row,l),t[0].column)}),zl,f,Ra,pa),Ya=_l(((e,t,o,n)=>{const r=ma(t),s=E(r,(e=>e.column)),l=na(e,s,!0,o,n.replaceOrInit);return Oa(l,t[0].row,t[0].column)}),Al,f,f,Fa),Ja=_l(((e,t,o,n)=>{const r=ma(t),s=E(r,(e=>e.column)),l=na(e,s,!1,o,n.replaceOrInit);return Oa(l,t[0].row,t[0].column)}),Al,f,f,Ha),Qa=_l(Na,zl,f,f,Fa),Xa=_l(_a,zl,f,f,Ha),Za=_l(Ba,zl,f,f,Ha),ec=_l(((e,t,o,n)=>{const r=ra(e,t,o,n.replaceOrInit);return Oa(r,t[0].row,t[0].column)}),Al,f,f,Fa),tc=_l(((e,t,o,n)=>{const r=ra(e,t,o,n.replaceOrInit);return Oa(r,t[0].row,t[0].column)}),Al,f,f,Ha),oc=_l(((e,t,o,n)=>{const r=t.cells;Sa(r);const s=((e,t,o,n)=>{const r=Vo(e).rows;if(0===r.length)return e;for(let e=t.startRow;e<=t.finishRow;e++)for(let o=t.startCol;o<=t.finishCol;o++){const t=r[e],s=Fo(t,o).isLocked;Po(t,o,et(n(),!1,s))}return e})(e,t.bounds,0,n.merge(r));return Da(s,C.from(r[0]))}),((e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>Ll(e,t.cells)))),Aa,f,wa),nc=_l(((e,t,o,n)=>{const r=z(t,((e,t)=>Wl(e,t,o,n.unmerge(t))),e);return Da(r,C.from(t[0]))}),((e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>Ll(e,t)))),Aa,f,wa),rc=_l(((e,t,o,n)=>{const r=((e,t)=>{const o=Xo(e);return Ol(o,t,!0)})(t.clipboard,t.generators);var s,l;return((e,t,o,n,r)=>{const s=Ko(t),l=((e,t,o)=>{const n=$o(t[0]),r=Vo(t).cols.length+e.row,s=k(n-e.column,(t=>t+e.column));return{row:r,column:L(s,(e=>P(o,(t=>t!==e)))).getOr(n-1)}})(e,t,s),a=Vo(o).rows,c=Gl(l,a,s),i=((e,t,o)=>{if(e.row>=t.length||e.column>$o(t[0]))return Pl.error("invalid start address out of table bounds, row: "+e.row+", column: "+e.column);const n=t.slice(e.row),r=n[0].cells.slice(e.column),s=$o(o[0]),l=o.length;return Pl.value({rowDelta:n.length-l,colDelta:r.length-s})})(l,t,a);return i.map((e=>{const o={...e,colDelta:e.colDelta-c.length},s=ql(t,o,n),i=Ko(s),m=Gl(l,a,i);return((e,t,o,n,r,s)=>{const l=e.row,a=e.column,c=l+o.length,i=a+$o(o[0])+s.length,m=I(s,x);for(let e=l;eDa(e,C.some(t.element))),(e=>Oa(e,t.row,t.column)))}),((e,t)=>Vt(t.element).bind((o=>El(e,o).map((e=>({...e,generators:t.generators,clipboard:t.clipboard})))))),Aa,f,pa),sc=_l(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[0].column,l=r[t.cells[0].row],a=za(t.clipboard,t.generators,l),c=Kl(s,e,a,t.generators,o);return Oa(c,t.cells[0].row,t.cells[0].column)}),Ia(!0),f,f,pa),lc=_l(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[t.cells.length-1].column+t.cells[t.cells.length-1].colspan,l=r[t.cells[0].row],a=za(t.clipboard,t.generators,l),c=Kl(s,e,a,t.generators,o);return Oa(c,t.cells[0].row,s)}),Ia(!1),f,f,pa),ac=_l(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[0].row,l=r[s],a=za(t.clipboard,t.generators,l),c=Yl(s,e,a,t.generators,o);return Oa(c,t.cells[0].row,t.cells[0].column)}),Bl,f,f,pa),cc=_l(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[t.cells.length-1].row+t.cells[t.cells.length-1].rowspan,l=r[t.cells[0].row],a=za(t.clipboard,t.generators,l),c=Yl(s,e,a,t.generators,o);return Oa(c,s,t.cells[0].column)}),Bl,f,f,pa),ic=(e,t)=>{const o=Xo(e);return zl(o,t).bind((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=M(E(o.all,(e=>B(e.cells,(e=>e.column>=n&&e.column{const o=Xo(e);return zl(o,t).bind(ul).getOr("")},dc=(e,t)=>{const o=Xo(e);return zl(o,t).bind((e=>{const t=e[e.length-1],n=e[0].row,r=t.row+t.rowspan;return(e=>{const t=E(e,(e=>dl(e).type)),o=D(t,"header"),n=D(t,"footer");if(o||n){const e=D(t,"body");return!o||e||n?o||e||!n?C.none():C.some("footer"):C.some("header")}return C.some("body")})(o.all.slice(n,r))})).getOr("")},uc=(e,t)=>e.dispatch("NewRow",{node:t}),fc=(e,t)=>e.dispatch("NewCell",{node:t}),gc=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},hc={structure:!1,style:!0},pc={structure:!0,style:!1},bc={structure:!0,style:!0},wc=(e,t)=>Hr(e)?ur(t):$r(e)?dr(t):mr(t),vc=(e,t,o)=>{const n=e=>"table"===ne(os(e)),r=Wr(e),s=Ir(e)?f:Zs,l=t=>{switch(Mr(e)){case"section":return wl();case"sectionCells":return vl();case"cells":return yl();default:return((e,t)=>{var o;switch((o=Xo(e),V(o.all,(e=>{const t=dl(e);return"header"===t.type?C.from(t.subType):C.none()}))).getOr(t)){case"section":return hl();case"sectionCells":return pl();case"cells":return bl()}})(t,"section")}},a=(n,s,a,c)=>(i,m,d=!1)=>{rs(i);const u=xe.fromDom(e.getDoc()),f=_r(a,u,r),g={sizing:wc(e,i),resize:Ir(e)?sl():ll(),section:l(i)};return s(i)?n(i,m,f,g).bind((n=>{t.refresh(i.dom),N(n.newRows,(t=>{uc(e,t.dom)})),N(n.newCells,(t=>{fc(e,t.dom)}));const r=((t,n)=>n.cursor.fold((()=>{const n=qt(t);return H(n).filter(st).map((n=>{o.clearSelectedCells(t.dom);const r=e.dom.createRng();return r.selectNode(n.dom),e.selection.setRng(r),ge(n,"data-mce-selected","1"),r}))}),(n=>{const r=Qs(Xs,n),s=e.dom.createRng();return s.setStart(r.element.dom,r.offset),s.setEnd(r.element.dom,r.offset),e.selection.setRng(s),o.clearSelectedCells(t.dom),C.some(s)})))(i,n);return st(i)&&(rs(i),d||gc(e,i.dom,c)),r.map((e=>({rng:e,effect:c})))})):C.none()},c=a(Ka,(t=>!n(e)||al(t).rows>1),f,pc),i=a(Ga,(t=>!n(e)||al(t).columns>1),f,pc);return{deleteRow:c,deleteColumn:i,insertRowsBefore:a($a,x,f,pc),insertRowsAfter:a(Va,x,f,pc),insertColumnsBefore:a(qa,x,s,pc),insertColumnsAfter:a(Ua,x,s,pc),mergeCells:a(oc,x,f,pc),unmergeCells:a(nc,x,f,pc),pasteColsBefore:a(sc,x,f,pc),pasteColsAfter:a(lc,x,f,pc),pasteRowsBefore:a(ac,x,f,pc),pasteRowsAfter:a(cc,x,f,pc),pasteCells:a(rc,x,f,bc),makeCellsHeader:a(ec,x,f,pc),unmakeCellsHeader:a(tc,x,f,pc),makeColumnsHeader:a(Ya,x,f,pc),unmakeColumnsHeader:a(Ja,x,f,pc),makeRowsHeader:a(Qa,x,f,pc),makeRowsBody:a(Xa,x,f,pc),makeRowsFooter:a(Za,x,f,pc),getTableRowType:dc,getTableCellType:mc,getTableColType:ic}},yc=(e,t,o)=>{const n=Wt(e,t,1);1===o||n<=1?we(e,t):ge(e,t,Math.min(o,n))},xc=(e,t)=>o=>{const n=o.column+o.colspan-1,r=o.column;return n>=e&&r{const n=o.substring(0,o.length-e.length),r=parseFloat(n);return n===r.toString()?t(r):Cc.invalid(o)},Tc={...Cc,from:e=>Rt(e,"%")?Sc("%",Cc.percent,e):Rt(e,"px")?Sc("px",Cc.pixels,e):Cc.invalid(e)},Rc=(e,t,o)=>{const n=Tc.from(o),r=P(e,(e=>"0px"===e))?((e,t)=>{const o=e.fold((()=>g("")),(e=>g(e/t+"px")),(()=>g(100/t+"%")));return k(t,o)})(n,e.length):((e,t,o)=>e.fold((()=>t),(e=>((e,t,o)=>{const n=o/t;return E(e,(e=>Tc.from(e).fold((()=>e),(e=>e*n+"px"),(e=>e/100*o+"px"))))})(t,o,e)),(e=>((e,t)=>E(e,(e=>Tc.from(e).fold((()=>e),(e=>e/t*100+"%"),(e=>e+"%")))))(t,o))))(n,e,t);return kc(r)},Dc=(e,t)=>0===e.length?t:z(e,((e,t)=>Tc.from(t).fold(g(0),h,h)+e),0),Oc=(e,t)=>Tc.from(e).fold(g(e),(e=>e+t+"px"),(e=>e+t+"%")),kc=e=>{if(0===e.length)return e;const t=z(e,((e,t)=>{const o=Tc.from(t).fold((()=>({value:t,remainder:0})),(e=>(e=>{const t=Math.floor(e);return{value:t+"px",remainder:e-t}})(e)),(e=>({value:e+"%",remainder:0})));return{output:[o.value].concat(e.output),remainder:e.remainder+o.remainder}}),{output:[],remainder:0}),o=t.output;return o.slice(0,o.length-1).concat([Oc(o[o.length-1],Math.round(t.remainder))])},Ec=Tc.from,Nc=(e,t,o)=>{const n=Xo(e),r=n.all,s=nn(n),l=rn(n);t.each((t=>{const o=Ec(t).fold(g("px"),g("px"),g("%")),r=Ao(e),a=((e,t)=>nr(e,t,er,rr))(n,e),c=Rc(a,r,t);sn(n)?((e,t,o)=>{N(t,((t,n)=>{const r=Dc([e[n]],It());Nt(t.element,"width",r+o)}))})(c,l,o):((e,t,o)=>{N(t,(t=>{const n=e.slice(t.column,t.colspan+t.column),r=Dc(n,It());Nt(t.element,"width",r+o)}))})(c,s,o),Nt(e,"width",t)})),o.each((t=>{const o=gn(e),l=((e,t)=>lr(e,t,tr,rr))(n,e);((e,t,o)=>{N(o,(e=>{Lt(e.element,"height")})),N(t,((t,o)=>{Nt(t.element,"height",e[o])}))})(Rc(l,o,t),r,s),Nt(e,"height",t)}))},_c=e=>Un(e).exists((e=>Wn.test(e))),Bc=e=>Un(e).exists((e=>Mn.test(e))),zc=e=>Un(e).isNone(),Ac=e=>{we(e,"width"),we(e,"height")},Lc=e=>{const t=Qn(e);Nc(e,C.some(t),C.none()),Ac(e)},Wc=e=>{const t=(e=>Ao(e)+"px")(e);Nc(e,C.some(t),C.none()),Ac(e)},Mc=e=>{Lt(e,"width");const t=Ut(e),o=t.length>0?t:qt(e);N(o,(e=>{Lt(e,"width"),Ac(e)})),Ac(e)},jc={styles:{"border-collapse":"collapse",width:"100%"},attributes:{border:"1"},colGroups:!1},Pc=(e,t,o,n)=>k(e,(e=>((e,t,o,n)=>{const r=xe.fromTag("tr");for(let s=0;s{e.selection.select(t.dom,!0),e.selection.collapse(!0)},Fc=(e,t,o,n,s)=>{const l=(e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>Vr(e)||!Ur(e)?t:$r(e)?{...t,width:Lr(e)}:{...t,width:Ar})(e,o)})(e),a={styles:l,attributes:Kr(e),colGroups:Yr(e)};return e.undoManager.ignore((()=>{const r=((e,t,o,n,r,s=jc)=>{const l=xe.fromTag("table"),a="cells"!==r;_t(l,s.styles),he(l,s.attributes),s.colGroups&&Ie(l,(e=>{const t=xe.fromTag("colgroup");return k(e,(()=>Ie(t,xe.fromTag("col")))),t})(t));const c=Math.min(e,o);if(a&&o>0){const e=xe.fromTag("thead");Ie(l,e);const s=Pc(o,t,"sectionCells"===r?c:0,n);$e(e,s)}const i=xe.fromTag("tbody");Ie(l,i);const m=Pc(a?e-c:e,t,a?0:o,n);return $e(i,m),l})(o,t,s,n,Mr(e),a);ge(r,"data-mce-id","__mce");const l=(e=>{const t=xe.fromTag("div"),o=xe.fromDom(e.dom.cloneNode(!0));return Ie(t,o),(e=>e.dom.innerHTML)(t)})(r);e.insertContent(l),e.addVisual()})),bt(os(e),'table[data-mce-id="__mce"]').map((t=>($r(e)?Wc(t):Vr(e)?Mc(t):(Hr(e)||(e=>r(e)&&-1!==e.indexOf("%"))(l.width))&&Lc(t),rs(t),we(t,"data-mce-id"),((e,t)=>{N(dt(t,"tr"),(t=>{uc(e,t.dom),N(dt(t,"th,td"),(t=>{fc(e,t.dom)}))}))})(e,t),((e,t)=>{bt(t,"td,th").each(b(Ic,e))})(e,t),t.dom))).getOrNull()};var Hc=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const $c="x-tinymce/dom-table-",Vc=$c+"rows",qc=$c+"columns",Uc=e=>{const t=Hc.FakeClipboardItem(e);Hc.write([t])},Gc=e=>{var t;const o=null!==(t=Hc.read())&&void 0!==t?t:[];return V(o,(t=>C.from(t.getType(e))))},Kc=e=>{Gc(e).isSome()&&Hc.clear()},Yc=e=>{e.fold(Qc,(e=>Uc({[Vc]:e})))},Jc=()=>Gc(Vc),Qc=()=>Kc(Vc),Xc=e=>{e.fold(ei,(e=>Uc({[qc]:e})))},Zc=()=>Gc(qc),ei=()=>Kc(qc),ti=e=>$s(ss(e),ns(e)).filter(ds),oi=(e,t)=>{const o=ns(e),n=e=>Gt(e,o),l=t=>(e=>Vs(ss(e),ns(e)).filter(ds))(e).bind((e=>n(e).map((o=>t(o,e))))),a=t=>{e.focus()},c=(t,o=!1)=>l(((n,r)=>{const s=Fs(qs(e),n,r);t(n,s,o).each(a)})),i=()=>l(((t,o)=>((e,t,o)=>{const n=Xo(e);return zl(n,t).bind((e=>{const t=Ol(n,o,!1),r=Vo(t).rows.slice(e[0].row,e[e.length-1].row+e[e.length-1].rowspan),s=j(r,(e=>{const t=B(e.cells,(e=>!e.isLocked));return t.length>0?[{...e,cells:t}]:[]})),l=kl(s);return xt(l.length>0,l)})).map((e=>E(e,(e=>{const t=Ke(e.element);return N(e.cells,(e=>{const o=Ye(e.element);Cl(o,"colspan",e.colspan,1),Cl(o,"rowspan",e.rowspan,1),Ie(t,o)})),t}))))})(t,Fs(qs(e),t,o),_r(f,xe.fromDom(e.getDoc()),C.none())))),m=()=>l(((t,o)=>((e,t)=>{const o=Xo(e);return Al(o,t).map((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=((e,t,o)=>{if(sn(e)){const n=B(rn(e),xc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return yc(n,"span",o-t),n})),s=xe.fromTag("colgroup");return $e(s,r),[s]}return[]})(o,n,r),l=((e,t,o)=>E(e.all,(e=>{const n=B(e.cells,xc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return yc(n,"colspan",o-t),n})),s=xe.fromTag("tr");return $e(s,r),s})))(o,n,r);return[...s,...l]}))})(t,Fs(qs(e),t,o)))),d=(t,o)=>o().each((o=>{const n=E(o,(e=>Ye(e)));l(((o,r)=>{const s=Br(xe.fromDom(e.getDoc())),l=((e,t,o,n)=>({selection:zs(e),clipboard:o,generators:n}))(qs(e),0,n,s);t(o,l).each(a)}))})),g=e=>(t,o)=>((e,t)=>X(e,t)?C.from(e[t]):C.none())(o,"type").each((t=>{c(e(t),o.no_events)}));G({mceTableSplitCells:()=>c(t.unmergeCells),mceTableMergeCells:()=>c(t.mergeCells),mceTableInsertRowBefore:()=>c(t.insertRowsBefore),mceTableInsertRowAfter:()=>c(t.insertRowsAfter),mceTableInsertColBefore:()=>c(t.insertColumnsBefore),mceTableInsertColAfter:()=>c(t.insertColumnsAfter),mceTableDeleteCol:()=>c(t.deleteColumn),mceTableDeleteRow:()=>c(t.deleteRow),mceTableCutCol:()=>m().each((e=>{Xc(e),c(t.deleteColumn)})),mceTableCutRow:()=>i().each((e=>{Yc(e),c(t.deleteRow)})),mceTableCopyCol:()=>m().each((e=>Xc(e))),mceTableCopyRow:()=>i().each((e=>Yc(e))),mceTablePasteColBefore:()=>d(t.pasteColsBefore,Zc),mceTablePasteColAfter:()=>d(t.pasteColsAfter,Zc),mceTablePasteRowBefore:()=>d(t.pasteRowsBefore,Jc),mceTablePasteRowAfter:()=>d(t.pasteRowsAfter,Jc),mceTableDelete:()=>ti(e).each((t=>{Gt(t,o).filter(w(o)).each((t=>{const o=xe.fromText("");if(je(t,o),qe(t),e.dom.isEmpty(e.getBody()))e.setContent(""),e.selection.setCursorLocation();else{const t=e.dom.createRng();t.setStart(o.dom,0),t.setEnd(o.dom,0),e.selection.setRng(t),e.nodeChanged()}}))})),mceTableCellToggleClass:(t,o)=>{l((t=>{const n=qs(e),r=P(n,(t=>e.formatter.match("tablecellclass",{value:o},t.dom))),s=r?e.formatter.remove:e.formatter.apply;N(n,(e=>s("tablecellclass",{value:o},e.dom))),gc(e,t.dom,hc)}))},mceTableToggleClass:(t,o)=>{l((t=>{e.formatter.toggle("tableclass",{value:o},t.dom),gc(e,t.dom,hc)}))},mceTableToggleCaption:()=>{ti(e).each((t=>{Gt(t,o).each((o=>{pt(o,"caption").fold((()=>{const t=xe.fromTag("caption");Ie(t,xe.fromText("Caption")),((e,t)=>{We(e,0).fold((()=>{Ie(e,t)}),(e=>{Me(e,t)}))})(o,t),e.selection.setCursorLocation(t.dom,0)}),(n=>{ue("caption")(t)&&Te("td",o).each((t=>e.selection.setCursorLocation(t.dom,0))),qe(n)})),gc(e,o.dom,pc)}))}))},mceTableSizingMode:(t,n)=>(t=>ti(e).each((n=>{Vr(e)||$r(e)||Hr(e)||Gt(n,o).each((o=>{"relative"!==t||_c(o)?"fixed"!==t||Bc(o)?"responsive"!==t||zc(o)||Mc(o):Wc(o):Lc(o),rs(o),gc(e,o.dom,pc)}))})))(n),mceTableCellType:g((e=>"th"===e?t.makeCellsHeader:t.unmakeCellsHeader)),mceTableColType:g((e=>"th"===e?t.makeColumnsHeader:t.unmakeColumnsHeader)),mceTableRowType:g((e=>{switch(e){case"header":return t.makeRowsHeader;case"footer":return t.makeRowsFooter;default:return t.makeRowsBody}}))},((t,o)=>e.addCommand(o,t))),e.addCommand("mceInsertTable",((t,o)=>{((e,t,o,n={})=>{const r=e=>u(e)&&e>0;if(r(t)&&r(o)){const r=n.headerRows||0,s=n.headerColumns||0;return Fc(e,o,t,s,r)}console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.")})(e,o.rows,o.columns,o.options)})),e.addCommand("mceTableApplyCellStyle",((t,o)=>{const l=e=>"tablecell"+e.toLowerCase().replace("-","");if(!s(o))return;const a=B(qs(e),ds);if(0===a.length)return;const c=((e,t)=>{const o={};return((e,t,o,n)=>{G(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(e=>(t,o)=>{e[o]=t})(o),f),o})(o,((t,o)=>e.formatter.has(l(o))&&r(t)));(e=>{for(const t in e)if(U.call(e,t))return!1;return!0})(c)||(G(c,((t,o)=>{const n=l(o);N(a,(o=>{""===t?e.formatter.remove(n,{value:null},o.dom,!0):e.formatter.apply(n,{value:t},o.dom)}))})),n(a[0]).each((t=>gc(e,t.dom,hc))))}))},ni=sa([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),ri={before:ni.before,on:ni.on,after:ni.after,cata:(e,t,o,n)=>e.fold(t,o,n),getStart:e=>e.fold(h,h,h)},si=(e,t)=>({selection:e,kill:t}),li=(e,t)=>{const o=e.document.createRange();return o.selectNode(t.dom),o},ai=(e,t)=>{const o=e.document.createRange();return ci(o,t),o},ci=(e,t)=>e.selectNodeContents(t.dom),ii=(e,t,o)=>{const n=e.document.createRange();var r;return r=n,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},mi=(e,t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},di=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),ui=sa([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),fi=(e,t,o)=>t(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset),gi=(e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:g(e),rtl:C.none}),relative:(t,o)=>({ltr:Zt((()=>ii(e,t,o))),rtl:Zt((()=>C.some(ii(e,o,t))))}),exact:(t,o,n,r)=>({ltr:Zt((()=>mi(e,t,o,n,r))),rtl:Zt((()=>C.some(mi(e,n,r,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();return o.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>ui.rtl(xe.fromDom(e.endContainer),e.endOffset,xe.fromDom(e.startContainer),e.startOffset))).getOrThunk((()=>fi(0,ui.ltr,o))):fi(0,ui.ltr,o)})(0,o)},hi=(e,t)=>gi(e,t).match({ltr:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},rtl:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(n.dom,r),s.setEnd(t.dom,o),s}});ui.ltr,ui.rtl;const pi=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),bi=(e,t,o,n)=>({start:ri.on(e,t),finish:ri.on(o,n)}),wi=(e,t)=>{const o=hi(e,t);return pi(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset)},vi=bi,yi=(e,t,o,n,r)=>Re(o,n)?C.none():Os(o,n,t).bind((t=>{const n=t.boxes.getOr([]);return n.length>1?(r(e,n,t.start,t.finish),C.some(si(C.some(vi(o,0,o,wr(o))),!0))):C.none()})),xi=(e,t)=>({item:e,mode:t}),Ci=(e,t,o,n=Si)=>e.property().parent(t).map((e=>xi(e,n))),Si=(e,t,o,n=Ti)=>o.sibling(e,t).map((e=>xi(e,n))),Ti=(e,t,o,n=Ti)=>{const r=e.property().children(t);return o.first(r).map((e=>xi(e,n)))},Ri=[{current:Ci,next:Si,fallback:C.none()},{current:Si,next:Ti,fallback:C.some(Ci)},{current:Ti,next:Ti,fallback:C.some(Si)}],Di=(e,t,o,n,r=Ri)=>L(r,(e=>e.current===o)).bind((o=>o.current(e,t,n,o.next).orThunk((()=>o.fallback.bind((o=>Di(e,t,o,n))))))),Oi=(e,t,o,n,r,s)=>Di(e,t,n,r).bind((t=>s(t.item)?C.none():o(t.item)?C.some(t.item):Oi(e,t.item,o,t.mode,r,s))),ki=e=>t=>0===e.property().children(t).length,Ei=(e,t,o,n)=>Oi(e,t,o,Si,{sibling:(e,t)=>e.query().prevSibling(t),first:e=>e.length>0?C.some(e[e.length-1]):C.none()},n),Ni=(e,t,o,n)=>Oi(e,t,o,Si,{sibling:(e,t)=>e.query().nextSibling(t),first:e=>e.length>0?C.some(e[0]):C.none()},n),_i=xs(),Bi=(e,t)=>((e,t,o)=>Ei(e,t,ki(e),o))(_i,e,t),zi=(e,t)=>((e,t,o)=>Ni(e,t,ki(e),o))(_i,e,t),Ai=sa([{none:["message"]},{success:[]},{failedUp:["cell"]},{failedDown:["cell"]}]),Li=e=>wt(e,"tr"),Wi={...Ai,verify:(e,t,o,n,r,s,l)=>wt(n,"td,th",l).bind((o=>wt(t,"td,th",l).map((t=>Re(o,t)?Re(n,o)&&wr(o)===r?s(t):Ai.none("in same cell"):Rs(Li,[o,t]).fold((()=>((e,t,o)=>{const n=e.getRect(t),r=e.getRect(o);return r.right>n.left&&r.lefts(t))))))).getOr(Ai.none("default")),cata:(e,t,o,n,r)=>e.fold(t,o,n,r)},Mi=ue("br"),ji=(e,t,o)=>t(e,o).bind((e=>ie(e)&&0===hr(e).trim().length?ji(e,t,o):C.some(e))),Pi=(e,t,o,n)=>((e,t)=>We(e,t).filter(Mi).orThunk((()=>We(e,t-1).filter(Mi))))(t,o).bind((t=>n.traverse(t).fold((()=>ji(t,n.gather,e).map(n.relative)),(e=>(e=>Ne(e).bind((t=>{const o=Le(t);return((e,t)=>W(e,b(Re,t)))(o,e).map((n=>((e,t,o,n)=>({parent:e,children:t,element:o,index:n}))(t,o,e,n)))})))(e).map((e=>ri.on(e.parent,e.index))))))),Ii=(e,t)=>({left:e.left,top:e.top+t,right:e.right,bottom:e.bottom+t}),Fi=(e,t)=>({left:e.left,top:e.top-t,right:e.right,bottom:e.bottom-t}),Hi=(e,t,o)=>({left:e.left+t,top:e.top+o,right:e.right+t,bottom:e.bottom+o}),$i=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom}),Vi=(e,t)=>C.some(e.getRect(t)),qi=(e,t,o)=>ce(t)?Vi(e,t).map($i):ie(t)?((e,t,o)=>o>=0&&o0?e.getRangedRect(t,o-1,t,o):C.none())(e,t,o).map($i):C.none(),Ui=(e,t)=>ce(t)?Vi(e,t).map($i):ie(t)?e.getRangedRect(t,0,t,wr(t)).map($i):C.none(),Gi=sa([{none:[]},{retry:["caret"]}]),Ki=(e,t,o)=>gt(t,xa).fold(y,(t=>Ui(e,t).exists((e=>((e,t)=>e.leftt.right)(o,e))))),Yi={point:e=>e.bottom,adjuster:(e,t,o,n,r)=>{const s=Ii(r,5);return Math.abs(o.bottom-n.bottom)<1||o.top>r.bottom?Gi.retry(s):o.top===r.bottom?Gi.retry(Ii(r,1)):Ki(e,t,r)?Gi.retry(Hi(s,5,0)):Gi.none()},move:Ii,gather:zi},Ji=(e,t,o,n,r)=>0===r?C.some(n):((e,t,o)=>e.elementFromPoint(t,o).filter((e=>"table"===ne(e))).isSome())(e,n.left,t.point(n))?((e,t,o,n,r)=>Ji(e,t,o,t.move(n,5),r))(e,t,o,n,r-1):e.situsFromPoint(n.left,t.point(n)).bind((s=>s.start.fold(C.none,(s=>Ui(e,s).bind((l=>t.adjuster(e,s,l,o,n).fold(C.none,(n=>Ji(e,t,o,n,r-1))))).orThunk((()=>C.some(n)))),C.none))),Qi=(e,t,o)=>{const n=e.move(o,5),r=Ji(t,e,o,n,100).getOr(n);return((e,t,o)=>e.point(t)>o.getInnerHeight()?C.some(e.point(t)-o.getInnerHeight()):e.point(t)<0?C.some(-e.point(t)):C.none())(e,r,t).fold((()=>t.situsFromPoint(r.left,e.point(r))),(o=>(t.scrollBy(0,o),t.situsFromPoint(r.left,e.point(r)-o))))},Xi={tryUp:b(Qi,{point:e=>e.top,adjuster:(e,t,o,n,r)=>{const s=Fi(r,5);return Math.abs(o.top-n.top)<1||o.bottome.getSelection().bind((n=>((e,t,o,n)=>{const r=Mi(t)?((e,t,o)=>o.traverse(t).orThunk((()=>ji(t,o.gather,e))).map(o.relative))(e,t,n):Pi(e,t,o,n);return r.map((e=>({start:e,finish:e})))})(t,n.finish,n.foffset,o).fold((()=>C.some(Gs(n.finish,n.foffset))),(r=>{const s=e.fromSitus(r);return l=Wi.verify(e,n.finish,n.foffset,s.finish,s.foffset,o.failure,t),Wi.cata(l,(e=>C.none()),(()=>C.none()),(e=>C.some(Gs(e,0))),(e=>C.some(Gs(e,wr(e)))));var l})))),em=(e,t,o,n,r,s)=>0===s?C.none():nm(e,t,o,n,r).bind((l=>{const a=e.fromSitus(l),c=Wi.verify(e,o,n,a.finish,a.foffset,r.failure,t);return Wi.cata(c,(()=>C.none()),(()=>C.some(l)),(l=>Re(o,l)&&0===n?tm(e,o,n,Fi,r):em(e,t,l,0,r,s-1)),(l=>Re(o,l)&&n===wr(l)?tm(e,o,n,Ii,r):em(e,t,l,wr(l),r,s-1)))})),tm=(e,t,o,n,r)=>qi(e,t,o).bind((t=>om(e,r,n(t,Xi.getJumpSize())))),om=(e,t,o)=>{const n=No().browser;return n.isChromium()||n.isSafari()||n.isFirefox()?t.retry(e,o):C.none()},nm=(e,t,o,n,r)=>qi(e,o,n).bind((t=>om(e,r,t))),rm=(e,t,o,n,r)=>wt(n,"td,th",t).bind((n=>wt(n,"table",t).bind((s=>((e,t)=>ft(e,(e=>Ne(e).exists((e=>Re(e,t)))),void 0).isSome())(r,s)?((e,t,o)=>Zi(e,t,o).bind((n=>em(e,t,n.element,n.offset,o,20).map(e.fromSitus))))(e,t,o).bind((e=>wt(e.finish,"td,th",t).map((t=>({start:n,finish:t,range:e}))))):C.none())))),sm=(e,t,o,n,r,s)=>s(n,t).orThunk((()=>rm(e,t,o,n,r).map((e=>{const t=e.range;return si(C.some(vi(t.start,t.soffset,t.finish,t.foffset)),!0)})))),lm=(e,t)=>wt(e,"tr",t).bind((e=>wt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[0])?((e,t,o)=>Ei(_i,e,(e=>Cr(e).isSome()),o))(o,0,t).map((e=>{const t=wr(e);return si(C.some(vi(e,t,e,t)),!0)})):C.none()})))),am=(e,t)=>wt(e,"tr",t).bind((e=>wt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[n.length-1])?((e,t,o)=>Ni(_i,e,(e=>xr(e).isSome()),o))(o,0,t).map((e=>si(C.some(vi(e,0,e,0)),!0))):C.none()})))),cm=(e,t,o,n,r,s,l)=>rm(e,o,n,r,s).bind((e=>yi(t,o,e.start,e.finish,l))),im=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},mm=()=>{const e=(e=>{const t=im(C.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(C.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(C.some(e))}}})(f);return{...e,on:t=>e.get().each(t)}},dm=(e,t)=>wt(e,"td,th",t),um=e=>_e(e).exists(es),fm={traverse:Ae,gather:zi,relative:ri.before,retry:Xi.tryDown,failure:Wi.failedDown},gm={traverse:ze,gather:Bi,relative:ri.before,retry:Xi.tryUp,failure:Wi.failedUp},hm=e=>t=>t===e,pm=hm(38),bm=hm(40),wm=e=>e>=37&&e<=40,vm={isBackward:hm(37),isForward:hm(39)},ym={isBackward:hm(39),isForward:hm(37)},xm=sa([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),Cm={domRange:xm.domRange,relative:xm.relative,exact:xm.exact,exactFromRange:e=>xm.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>xe.fromDom(e.startContainer),relative:(e,t)=>ri.getStart(e),exact:(e,t,o,n)=>e}))(e);return xe.fromDom(Ee(t).dom.defaultView)},range:pi},Sm=(e,t)=>{const o=ne(e);return"input"===o?ri.after(e):D(["br","img"],o)?0===t?ri.before(e):ri.after(e):ri.on(e,t)},Tm=e=>C.from(e.getSelection()),Rm=(e,t)=>{Tm(e).each((e=>{e.removeAllRanges(),e.addRange(t)}))},Dm=(e,t,o,n,r)=>{const s=mi(e,t,o,n,r);Rm(e,s)},Om=(e,t)=>gi(e,t).match({ltr:(t,o,n,r)=>{Dm(e,t,o,n,r)},rtl:(t,o,n,r)=>{Tm(e).each((s=>{if(s.setBaseAndExtent)s.setBaseAndExtent(t.dom,o,n.dom,r);else if(s.extend)try{((e,t,o,n,r,s)=>{t.collapse(o.dom,n),t.extend(r.dom,s)})(0,s,t,o,n,r)}catch(s){Dm(e,n,r,t,o)}else Dm(e,n,r,t,o)}))}}),km=(e,t,o,n,r)=>{const s=((e,t,o,n)=>{const r=Sm(e,t),s=Sm(o,n);return Cm.relative(r,s)})(t,o,n,r);Om(e,s)},Em=(e,t,o)=>{const n=((e,t)=>{const o=e.fold(ri.before,Sm,ri.after),n=t.fold(ri.before,Sm,ri.after);return Cm.relative(o,n)})(t,o);Om(e,n)},Nm=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return C.some(pi(xe.fromDom(t.startContainer),t.startOffset,xe.fromDom(o.endContainer),o.endOffset))}return C.none()},_m=e=>{if(null===e.anchorNode||null===e.focusNode)return Nm(e);{const t=xe.fromDom(e.anchorNode),o=xe.fromDom(e.focusNode);return((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=ke(e).dom.createRange();return r.setStart(e.dom,t),r.setEnd(o.dom,n),r})(e,t,o,n),s=Re(e,o)&&t===n;return r.collapsed&&!s})(t,e.anchorOffset,o,e.focusOffset)?C.some(pi(t,e.anchorOffset,o,e.focusOffset)):Nm(e)}},Bm=(e,t,o=!0)=>{const n=(o?ai:li)(e,t);Rm(e,n)},zm=e=>(e=>Tm(e).filter((e=>e.rangeCount>0)).bind(_m))(e).map((e=>Cm.exact(e.start,e.soffset,e.finish,e.foffset))),Am=(e,t,o)=>((e,t,o)=>((e,t,o)=>e.caretPositionFromPoint?((e,t,o)=>{var n;return C.from(null===(n=e.caretPositionFromPoint)||void 0===n?void 0:n.call(e,t,o)).bind((t=>{if(null===t.offsetNode)return C.none();const o=e.createRange();return o.setStart(t.offsetNode,t.offset),o.collapse(),C.some(o)}))})(e,t,o):e.caretRangeFromPoint?((e,t,o)=>{var n;return C.from(null===(n=e.caretRangeFromPoint)||void 0===n?void 0:n.call(e,t,o))})(e,t,o):C.none())(e.document,t,o).map((e=>pi(xe.fromDom(e.startContainer),e.startOffset,xe.fromDom(e.endContainer),e.endOffset))))(e,t,o),Lm=e=>({elementFromPoint:(t,o)=>xe.fromPoint(xe.fromDom(e.document),t,o),getRect:e=>e.dom.getBoundingClientRect(),getRangedRect:(t,o,n,r)=>{const s=Cm.exact(t,o,n,r);return((e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?C.some(o).map(di):C.none()})(hi(e,t)))(e,s)},getSelection:()=>zm(e).map((t=>wi(e,t))),fromSitus:t=>{const o=Cm.relative(t.start,t.finish);return wi(e,o)},situsFromPoint:(t,o)=>Am(e,t,o).map((e=>bi(e.start,e.soffset,e.finish,e.foffset))),clearSelection:()=>{(e=>{Tm(e).each((e=>e.removeAllRanges()))})(e)},collapseSelection:(t=!1)=>{zm(e).each((o=>o.fold((e=>e.collapse(t)),((o,n)=>{const r=t?o:n;Em(e,r,r)}),((o,n,r,s)=>{const l=t?o:r,a=t?n:s;km(e,l,a,l,a)}))))},setSelection:t=>{km(e,t.start,t.soffset,t.finish,t.foffset)},setRelativeSelection:(t,o)=>{Em(e,t,o)},selectNode:t=>{Bm(e,t,!1)},selectContents:t=>{Bm(e,t)},getInnerHeight:()=>e.innerHeight,getScrollY:()=>(e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return bn(o,n)})(xe.fromDom(e.document)).top,scrollBy:(t,o)=>{((e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollBy(e,t)})(t,o,xe.fromDom(e.document))}}),Wm=(e,t)=>({rows:e,cols:t}),Mm=e=>gt(e,ae).exists(es),jm=(e,t)=>Mm(e)||Mm(t),Pm=e=>void 0!==e.dom.classList,Im=(e,t)=>((e,t,o)=>{const n=((e,t)=>{const o=pe(e,t);return void 0===o||""===o?[]:o.split(" ")})(e,t).concat([o]);return ge(e,t,n.join(" ")),!0})(e,"class",t),Fm=(e,t)=>{Pm(e)?e.dom.classList.add(t):Im(e,t)},Hm=(e,t)=>Pm(e)&&e.dom.classList.contains(t),$m=()=>({tag:"none"}),Vm=e=>({tag:"multiple",elements:e}),qm=e=>({tag:"single",element:e}),Um=e=>{const t=xe.fromDom((e=>{if(m(e.target)){const t=xe.fromDom(e.target);if(ce(t)&&m(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return H(t)}}return C.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),r=(s=n,l=o,(...e)=>s(l.apply(null,e)));var s,l;return((e,t,o,n,r,s,l)=>({target:e,x:t,y:o,stop:n,prevent:r,kill:s,raw:l}))(t,e.clientX,e.clientY,o,n,r,e)},Gm=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},Km=x,Ym=(e,t,o)=>((e,t,o,n)=>((e,t,o,n,r)=>{const s=((e,t)=>o=>{e(o)&&t(Um(o))})(o,n);return e.dom.addEventListener(t,s,r),{unbind:b(Gm,e,t,s,r)}})(e,t,o,n,!1))(e,t,Km,o),Jm=Um,Qm=e=>!Hm(xe.fromDom(e.target),"ephox-snooker-resizer-bar"),Xm=(e,t)=>{const o=(r=Is.selectedSelector,{get:()=>_s(xe.fromDom(e.getBody()),r).fold((()=>Vs(ss(e),ns(e)).fold($m,qm)),Vm)}),n=((e,t,o)=>{const n=t=>{we(t,e.selected),we(t,e.firstSelected),we(t,e.lastSelected)},r=t=>{ge(t,e.selected,"1")},s=e=>{l(e),o()},l=t=>{const o=dt(t,`${e.selectedSelector},${e.firstSelectedSelector},${e.lastSelectedSelector}`);N(o,n)};return{clearBeforeUpdate:l,clear:s,selectRange:(o,n,l,a)=>{s(o),N(n,r),ge(l,e.firstSelected,"1"),ge(a,e.lastSelected,"1"),t(n,l,a)},selectedSelector:e.selectedSelector,firstSelectedSelector:e.firstSelectedSelector,lastSelectedSelector:e.lastSelectedSelector}})(Is,((t,o,n)=>{Gt(o).each((r=>{const s=E(t,(e=>e.dom)),l=Wr(e),a=_r(f,xe.fromDom(e.getDoc()),l),c=((e,t,o)=>{const n=Xo(e);return zl(n,t).map((e=>{const t=Ol(n,o,!1),{rows:r}=Vo(t),s=((e,t)=>{const o=e.slice(0,t[t.length-1].row+1),n=kl(o);return j(n,(e=>{const o=e.cells.slice(0,t[t.length-1].column+1);return E(o,(e=>e.element))}))})(r,e),l=((e,t)=>{const o=e.slice(t[0].row+t[0].rowspan-1,e.length),n=kl(o);return j(n,(e=>{const o=e.cells.slice(t[0].column+t[0].colspan-1,e.cells.length);return E(o,(e=>e.element))}))})(r,e);return{upOrLeftCells:s,downOrRightCells:l}}))})(r,{selection:qs(e)},a).map((e=>K(e,(e=>E(e,(e=>e.dom)))))).getOrUndefined();((e,t,o,n,r)=>{e.dispatch("TableSelectionChange",{cells:t,start:o,finish:n,otherCells:r})})(e,s,o.dom,n.dom,c)}))}),(()=>(e=>{e.dispatch("TableSelectionClear")})(e)));var r;return e.on("init",(o=>{const r=e.getWin(),s=os(e),l=ns(e),a=((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=mm(),s=r.clear,l=s=>{r.on((r=>{n.clearBeforeUpdate(t),dm(s.target,o).each((l=>{Os(r,l,o).each((o=>{const r=o.boxes.getOr([]);if(1===r.length){const e=r[0],o="false"===ts(e),l=vt(Zr(s.target),e,Re);o&&l&&n.selectRange(t,r,e,e)}else r.length>1&&(n.selectRange(t,r,o.start,o.finish),e.selectContents(l))}))}))}))};return{clearstate:s,mousedown:e=>{n.clear(t),dm(e.target,o).filter(um).each(r.set)},mouseover:e=>{l(e)},mouseup:e=>{l(e),s()}}})(Lm(e),t,o,n);return{clearstate:r.clearstate,mousedown:r.mousedown,mouseover:r.mouseover,mouseup:r.mouseup}})(r,s,l,n),c=((e,t,o,n)=>{const r=Lm(e),s=()=>(n.clear(t),C.none());return{keydown:(e,l,a,c,i,m)=>{const d=e.raw,u=d.which,f=!0===d.shiftKey,g=ks(t,n.selectedSelector).fold((()=>(wm(u)&&!f&&n.clearBeforeUpdate(t),wm(u)&&f&&!jm(l,c)?C.none:bm(u)&&f?b(cm,r,t,o,fm,c,l,n.selectRange):pm(u)&&f?b(cm,r,t,o,gm,c,l,n.selectRange):bm(u)?b(sm,r,o,fm,c,l,am):pm(u)?b(sm,r,o,gm,c,l,lm):C.none)),(e=>{const o=o=>()=>{const s=V(o,(o=>((e,t,o,n,r)=>Ns(n,e,t,r.firstSelectedSelector,r.lastSelectedSelector).map((e=>(r.clearBeforeUpdate(o),r.selectRange(o,e.boxes,e.start,e.finish),e.boxes))))(o.rows,o.cols,t,e,n)));return s.fold((()=>Es(t,n.firstSelectedSelector,n.lastSelectedSelector).map((e=>{const o=bm(u)||m.isForward(u)?ri.after:ri.before;return r.setRelativeSelection(ri.on(e.first,0),o(e.table)),n.clear(t),si(C.none(),!0)}))),(e=>C.some(si(C.none(),!0))))};return wm(u)&&f&&!jm(l,c)?C.none:bm(u)&&f?o([Wm(1,0)]):pm(u)&&f?o([Wm(-1,0)]):m.isBackward(u)&&f?o([Wm(0,-1),Wm(-1,0)]):m.isForward(u)&&f?o([Wm(0,1),Wm(1,0)]):wm(u)&&!f?s:C.none}));return g()},keyup:(e,r,s,l,a)=>ks(t,n.selectedSelector).fold((()=>{const c=e.raw,i=c.which;return!0===c.shiftKey&&wm(i)&&jm(r,l)?((e,t,o,n,r,s,l)=>Re(o,r)&&n===s?C.none():wt(o,"td,th",t).bind((o=>wt(r,"td,th",t).bind((n=>yi(e,t,o,n,l))))))(t,o,r,s,l,a,n.selectRange):C.none()}),C.none)}})(r,s,l,n),i=((e,t,o,n)=>{const r=Lm(e);return(e,s)=>{n.clearBeforeUpdate(t),Os(e,s,o).each((e=>{const o=e.boxes.getOr([]);n.selectRange(t,o,e.start,e.finish),r.selectContents(s),r.collapseSelection()}))}})(r,s,l,n);e.on("TableSelectorChange",(e=>i(e.start,e.finish)));const m=(t,o)=>{(e=>!0===e.raw.shiftKey)(t)&&(o.kill&&t.kill(),o.selection.each((t=>{const o=Cm.relative(t.start,t.finish),n=hi(r,o);e.selection.setRng(n)})))},d=e=>0===e.button,u=(()=>{const e=im(xe.fromDom(s)),t=im(0);return{touchEnd:o=>{const n=xe.fromDom(o.target);if(ue("td")(n)||ue("th")(n)){const r=e.get(),s=t.get();Re(r,n)&&o.timeStamp-s<300&&(o.preventDefault(),i(n,n))}e.set(n),t.set(o.timeStamp)}}})();e.on("dragstart",(e=>{a.clearstate()})),e.on("mousedown",(e=>{d(e)&&Qm(e)&&a.mousedown(Jm(e))})),e.on("mouseover",(e=>{var t;(void 0===(t=e).buttons||1&t.buttons)&&Qm(e)&&a.mouseover(Jm(e))})),e.on("mouseup",(e=>{d(e)&&Qm(e)&&a.mouseup(Jm(e))})),e.on("touchend",u.touchEnd),e.on("keyup",(t=>{const o=Jm(t);if(o.raw.shiftKey&&wm(o.raw.which)){const t=e.selection.getRng(),n=xe.fromDom(t.startContainer),r=xe.fromDom(t.endContainer);c.keyup(o,n,t.startOffset,r,t.endOffset).each((e=>{m(o,e)}))}})),e.on("keydown",(o=>{const n=Jm(o);t.hide();const r=e.selection.getRng(),s=xe.fromDom(r.startContainer),l=xe.fromDom(r.endContainer),a=dn(vm,ym)(xe.fromDom(e.selection.getStart()));c.keydown(n,s,r.startOffset,l,r.endOffset,a).each((e=>{m(n,e)})),t.show()})),e.on("NodeChange",(()=>{const t=e.selection,o=xe.fromDom(t.getStart()),r=xe.fromDom(t.getEnd());Rs(Gt,[o,r]).fold((()=>n.clear(s)),f)}))})),e.on("PreInit",(()=>{e.serializer.addTempAttr(Is.firstSelected),e.serializer.addTempAttr(Is.lastSelected)})),{getSelectedCells:()=>((e,t)=>{switch(e.tag){case"none":return t();case"single":return(e=>[e.dom])(e.element);case"multiple":return(e=>E(e,(e=>e.dom)))(e.elements)}})(o.get(),g([])),clearSelectedCells:e=>n.clear(xe.fromDom(e))}},Zm=e=>{let t=[];return{bind:e=>{if(void 0===e)throw new Error("Event bind error: undefined handler");t.push(e)},unbind:e=>{t=B(t,(t=>t!==e))},trigger:(...o)=>{const n={};N(e,((e,t)=>{n[e]=o[t]})),N(t,(e=>{e(n)}))}}},ed=e=>({registry:K(e,(e=>({bind:e.bind,unbind:e.unbind}))),trigger:K(e,(e=>e.trigger))}),td=e=>e.slice(0).sort(),od=(e,t)=>{const o=B(t,(t=>!D(e,t)));o.length>0&&(e=>{throw new Error("Unsupported keys for object: "+td(e).join(", "))})(o)},nd=e=>((e,t)=>((e,t,o)=>{if(0===t.length)throw new Error("You must specify at least one required field.");return((e,t)=>{if(!l(t))throw new Error("The "+e+" fields must be an array. Was: "+t+".");N(t,(t=>{if(!r(t))throw new Error("The value "+t+" in the "+e+" fields was not a string.")}))})("required",t),(e=>{const t=td(e);L(t,((e,o)=>o{throw new Error("The field: "+e+" occurs more than once in the combined fields: ["+t.join(", ")+"].")}))})(t),n=>{const r=q(n);P(t,(e=>D(r,e)))||((e,t)=>{throw new Error("All required keys ("+td(e).join(", ")+") were not specified. Specified keys were: "+td(t).join(", ")+".")})(t,r),e(t,r);const s=B(t,(e=>!o.validate(n[e],e)));return s.length>0&&((e,t)=>{throw new Error("All values need to be of type: "+t+". Keys ("+td(e).join(", ")+") were not.")})(s,o.label),n}})(e,t,{validate:d,label:"function"}))(od,e),rd=nd(["compare","extract","mutate","sink"]),sd=nd(["element","start","stop","destroy"]),ld=nd(["forceDrop","drop","move","delayDrop"]),ad=()=>{const e=(()=>{const e=ed({move:Zm(["info"])});return{onEvent:f,reset:f,events:e.registry}})(),t=(()=>{let e=C.none();const t=ed({move:Zm(["info"])});return{onEvent:(o,n)=>{n.extract(o).each((o=>{const r=((t,o)=>{const n=e.map((e=>t.compare(e,o)));return e=C.some(o),n})(n,o);r.each((e=>{t.trigger.move(e)}))}))},reset:()=>{e=C.none()},events:t.registry}})();let o=e;return{on:()=>{o.reset(),o=t},off:()=>{o.reset(),o=e},isOn:()=>o===t,onEvent:(e,t)=>{o.onEvent(e,t)},events:t.events}},cd=e=>{const t=e.replace(/\./g,"-");return{resolve:e=>t+"-"+e}},id=cd("ephox-dragster").resolve;var md=rd({compare:(e,t)=>bn(t.left-e.left,t.top-e.top),extract:e=>C.some(bn(e.x,e.y)),sink:(e,t)=>{const o=(e=>{const t={layerClass:id("blocker"),...e},o=xe.fromTag("div");return ge(o,"role","presentation"),_t(o,{position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),Fm(o,id("blocker")),Fm(o,t.layerClass),{element:g(o),destroy:()=>{qe(o)}}})(t),n=Ym(o.element(),"mousedown",e.forceDrop),r=Ym(o.element(),"mouseup",e.drop),s=Ym(o.element(),"mousemove",e.move),l=Ym(o.element(),"mouseout",e.delayDrop);return sd({element:o.element,start:e=>{Ie(e,o.element())},stop:()=>{qe(o.element())},destroy:()=>{o.destroy(),r.unbind(),s.unbind(),l.unbind(),n.unbind()}})},mutate:(e,t)=>{e.mutate(t.left,t.top)}});const dd=cd("ephox-snooker").resolve,ud=dd("resizer-bar"),fd=dd("resizer-rows"),gd=dd("resizer-cols"),hd=e=>{const t=dt(e.parent(),"."+ud);N(t,qe)},pd=(e,t,o)=>{const n=e.origin();N(t,(t=>{t.each((t=>{const r=o(n,t);Fm(r,ud),Ie(e.parent(),r)}))}))},bd=(e,t,o,n,r)=>{const s=vn(o),l=t.isResizable,a=n.length>0?_n.positions(n,o):[],c=a.length>0?((e,t)=>j(e.all,((e,o)=>t(e.element)?[o]:[])))(e,l):[];((e,t,o,n)=>{pd(e,t,((e,t)=>{const r=((e,t,o,n)=>{const r=xe.fromTag("div");return _t(r,{position:"absolute",left:t+"px",top:o-3.5+"px",height:"7px",width:n+"px"}),he(r,{"data-row":e,role:"presentation"}),r})(t.row,o.left-e.left,t.y-e.top,n);return Fm(r,fd),r}))})(t,B(a,((e,t)=>O(c,(e=>t===e)))),s,Lo(o));const i=r.length>0?zn.positions(r,o):[],m=i.length>0?((e,t)=>{const o=[];return k(e.grid.columns,(n=>{ln(e,n).map((e=>e.element)).forall(t)&&o.push(n)})),B(o,(o=>{const n=on(e,(e=>e.column===o));return P(n,(e=>t(e.element)))}))})(e,l):[];((e,t,o,n)=>{pd(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return _t(s,{position:"absolute",left:t-3.5+"px",top:o+"px",height:r+"px",width:"7px"}),he(s,{"data-column":e,role:"presentation"}),s})(t.col,t.x-e.left,o.top-e.top,0,n);return Fm(r,gd),r}))})(t,B(i,((e,t)=>O(m,(e=>t===e)))),s,hn(o))},wd=(e,t)=>{if(hd(e),e.isResizable(t)){const o=Xo(t),n=mn(o),r=an(o);bd(o,e,t,n,r)}},vd=(e,t)=>{const o=dt(e.parent(),"."+ud);N(o,t)},yd=e=>{vd(e,(e=>{Nt(e,"display","none")}))},xd=e=>{vd(e,(e=>{Nt(e,"display","block")}))},Cd=dd("resizer-bar-dragging"),Sd=e=>{const t=(()=>{const e=ed({drag:Zm(["xDelta","yDelta","target"])});let t=C.none();const o=(()=>{const e=ed({drag:Zm(["xDelta","yDelta"])});return{mutate:(t,o)=>{e.trigger.drag(t,o)},events:e.registry}})();return o.events.drag.bind((o=>{t.each((t=>{e.trigger.drag(o.xDelta,o.yDelta,t)}))})),{assign:e=>{t=C.some(e)},get:()=>t,mutate:o.mutate,events:e.registry}})(),o=((e,t={})=>{var o;return((e,t,o)=>{let n=!1;const r=ed({start:Zm([]),stop:Zm([])}),s=ad(),l=()=>{m.stop(),s.isOn()&&(s.off(),r.trigger.stop())},c=(e=>{let t=null;const o=()=>{a(t)||(clearTimeout(t),t=null)};return{cancel:o,throttle:(...n)=>{o(),t=setTimeout((()=>{t=null,e.apply(null,n)}),200)}}})(l);s.events.move.bind((o=>{t.mutate(e,o.info)}));const i=e=>(...t)=>{n&&e.apply(null,t)},m=t.sink(ld({forceDrop:l,drop:i(l),move:i((e=>{c.cancel(),s.onEvent(e,t)})),delayDrop:i(c.throttle)}),o);return{element:m.element,go:e=>{m.start(e),s.on(),r.trigger.start()},on:()=>{n=!0},off:()=>{n=!1},isActive:()=>n,destroy:()=>{m.destroy()},events:r.registry}})(e,null!==(o=t.mode)&&void 0!==o?o:md,t)})(t,{});let n=C.none();const r=(e,t)=>C.from(pe(e,t));t.events.drag.bind((e=>{r(e.target,"data-row").each((t=>{const o=Pt(e.target,"top");Nt(e.target,"top",o+e.yDelta+"px")})),r(e.target,"data-column").each((t=>{const o=Pt(e.target,"left");Nt(e.target,"left",o+e.xDelta+"px")}))}));const s=(e,t)=>Pt(e,t)-Wt(e,"data-initial-"+t,0);o.events.stop.bind((()=>{t.get().each((t=>{n.each((o=>{r(t,"data-row").each((e=>{const n=s(t,"top");we(t,"data-initial-top"),d.trigger.adjustHeight(o,n,parseInt(e,10))})),r(t,"data-column").each((e=>{const n=s(t,"left");we(t,"data-initial-left"),d.trigger.adjustWidth(o,n,parseInt(e,10))})),wd(e,o)}))}))}));const l=(n,r)=>{d.trigger.startAdjust(),t.assign(n),ge(n,"data-initial-"+r,Pt(n,r)),Fm(n,Cd),Nt(n,"opacity","0.2"),o.go(e.dragContainer())},c=Ym(e.parent(),"mousedown",(e=>{var t;t=e.target,Hm(t,fd)&&l(e.target,"top"),(e=>Hm(e,gd))(e.target)&&l(e.target,"left")})),i=t=>Re(t,e.view()),m=Ym(e.view(),"mouseover",(t=>{var r;(r=t.target,wt(r,"table",i).filter(es)).fold((()=>{st(t.target)&&hd(e)}),(t=>{o.isActive()&&(n=C.some(t),wd(e,t))}))})),d=ed({adjustHeight:Zm(["table","delta","row"]),adjustWidth:Zm(["table","delta","column"]),startAdjust:Zm([])});return{destroy:()=>{c.unbind(),m.unbind(),o.destroy(),hd(e)},refresh:t=>{wd(e,t)},on:o.on,off:o.off,hideBars:b(yd,e),showBars:b(xd,e),events:d.registry}};let Td=0;const Rd=(e,t)=>{const o=(e=>!(e=>e.inline&&(e=>{var t;if(!e.inline)return C.none();const o=null!==(t=Jr(e))&&void 0!==t?t:"";if(o.length>0)return bt(lt(),o);const n=Qr(e);return m(n)?C.some(xe.fromDom(n)):C.none()})(e).isSome())(e)&&"split"===Xr(e))(e),n=xe.fromDom(e.getBody()),r=(e=>{const t=(e=>{const t=(new Date).getTime(),o=Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295*1e9);return Td++,e+"_"+o+Td+String(t)})("resizer-container"),o=xe.fromTag("div");return ge(o,"id",t),_t(o,{position:e,height:"0",width:"0",padding:"0",margin:"0",border:"0"}),o})(o?"relative":"static"),s=lt();return o?(je(n,r),((e,t,o,n)=>({parent:g(t),view:g(e),dragContainer:g(o),origin:()=>vn(t),isResizable:n}))(n,r,s,t)):(Ie(s,r),((e,t,o)=>({parent:g(t),view:g(e),dragContainer:g(t),origin:g(bn(0,0)),isResizable:o}))(n,r,t))},Dd=e=>m(e)&&"TABLE"===e.nodeName,Od="bar-",kd=e=>"false"!==pe(e,"data-mce-resize"),Ed=e=>{const t=mm(),o=mm(),n=mm();let r,s,l,a;const c=t=>wc(e,t),i=()=>Pr(e)?ll():sl(),m=(t,o,n,m)=>{const d=(e=>{return Tt(t=e,"corner-")?(e=>e.substring(7))(t):t;var t})(o),u=Rt(d,"e"),f=Tt(d,"n");if(""===s&&Lc(t),""===a&&(e=>{const t=(e=>gn(e)+"px")(e);Nc(e,C.none(),C.some(t)),Ac(e)})(t),n!==r&&""!==s){Nt(t,"width",s);const o=i(),l=c(t),a=Pr(e)||u?(e=>al(e).columns)(t)-1:0;ca(t,n-r,a,o,l)}else if((e=>/^(\d+(\.\d+)?)%$/.test(e))(s)){const e=parseFloat(s.replace("%",""));Nt(t,"width",n*e/r+"%")}if((e=>/^(\d+(\.\d+)?)px$/.test(e))(s)&&(e=>{const t=Xo(e);sn(t)||N(qt(e),(e=>{const t=Bt(e,"width");Nt(e,"width",t),we(e,"width")}))})(t),m!==l&&""!==a){Nt(t,"height",a);const e=f?0:(e=>al(e).rows)(t)-1;ia(t,m-l,e)}};e.on("init",(()=>{const r=((e,t)=>e.inline?Rd(e,t):((e,t)=>{const o=me(e)?(e=>xe.fromDom(Ee(e).dom.documentElement))(e):e;return{parent:g(o),view:g(e),dragContainer:g(o),origin:g(bn(0,0)),isResizable:t}})(xe.fromDom(e.getDoc()),t))(e,kd);if(n.set(r),(e=>{const t=e.options.get("object_resizing");return D(t.split(","),"table")})(e)&&qr(e)){const n=((e,t,o)=>{const n=_n,r=zn,s=Sd(e),l=ed({beforeResize:Zm(["table","type"]),afterResize:Zm(["table","type"]),startDrag:Zm([])});return s.events.adjustHeight.bind((e=>{const t=e.table;l.trigger.beforeResize(t,"row");const o=n.delta(e.delta,t);ia(t,o,e.row),l.trigger.afterResize(t,"row")})),s.events.startAdjust.bind((e=>{l.trigger.startDrag()})),s.events.adjustWidth.bind((e=>{const n=e.table;l.trigger.beforeResize(n,"col");const s=r.delta(e.delta,n),a=o(n);ca(n,s,e.column,t,a),l.trigger.afterResize(n,"col")})),{on:s.on,off:s.off,refreshBars:s.refresh,hideBars:s.hideBars,showBars:s.showBars,destroy:s.destroy,events:l.registry}})(r,i(),c);e.mode.isReadOnly()||n.on(),n.events.startDrag.bind((o=>{t.set(e.selection.getRng())})),n.events.beforeResize.bind((t=>{const o=t.table.dom;((e,t,o,n,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:o,height:n,origin:r})})(e,o,ls(o),as(o),Od+t.type)})),n.events.afterResize.bind((o=>{const n=o.table,r=n.dom;rs(n),t.on((t=>{e.selection.setRng(t),e.focus()})),((e,t,o,n,r)=>{e.dispatch("ObjectResized",{target:t,width:o,height:n,origin:r})})(e,r,ls(r),as(r),Od+o.type),e.undoManager.add()})),o.set(n)}})),e.on("ObjectResizeStart",(t=>{const o=t.target;if(Dd(o)&&!e.mode.isReadOnly()){const n=xe.fromDom(o);N(e.dom.select(".mce-clonedresizable"),(t=>{e.dom.addClass(t,"mce-"+jr(e)+"-columns")})),!Bc(n)&&$r(e)?Wc(n):!_c(n)&&Hr(e)&&Lc(n),zc(n)&&Tt(t.origin,Od)&&Lc(n),r=t.width,s=Vr(e)?"":is(e,o).getOr(""),l=t.height,a=ms(e,o).getOr("")}})),e.on("ObjectResized",(t=>{const o=t.target;if(Dd(o)){const n=xe.fromDom(o),r=t.origin;(e=>Tt(e,"corner-"))(r)&&m(n,r,t.width,t.height),rs(n),gc(e,n.dom,hc)}}));const d=()=>{o.on((e=>{e.on(),e.showBars()}))},u=()=>{o.on((e=>{e.off(),e.hideBars()}))};return e.on("DisabledStateChange",(e=>{e.state?u():d()})),e.on("SwitchMode",(()=>{e.mode.isReadOnly()?u():d()})),e.on("dragstart dragend",(e=>{"dragstart"===e.type?u():d()})),e.on("remove",(()=>{o.on((e=>{e.destroy()})),n.on((t=>{((e,t)=>{e.inline&&qe(t.parent())})(e,t)}))})),{refresh:e=>{o.on((t=>t.refreshBars(xe.fromDom(e))))},hide:()=>{o.on((e=>e.hideBars()))},show:()=>{o.on((e=>e.showBars()))}}},Nd=e=>{(e=>{const t=e.options.register;t("table_clone_elements",{processor:"string[]"}),t("table_use_colgroups",{processor:"boolean",default:!0}),t("table_header_type",{processor:e=>{const t=D(["section","cells","sectionCells","auto"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: section, cells, sectionCells or auto."}},default:"section"}),t("table_sizing_mode",{processor:"string",default:"auto"}),t("table_default_attributes",{processor:"object",default:{border:"1"}}),t("table_default_styles",{processor:"object",default:{"border-collapse":"collapse"}}),t("table_column_resizing",{processor:e=>{const t=D(["preservetable","resizetable"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be preservetable, or resizetable."}},default:"preservetable"}),t("table_resize_bars",{processor:"boolean",default:!0}),t("table_style_by_css",{processor:"boolean",default:!0}),t("table_merge_content_on_paste",{processor:"boolean",default:!0})})(e);const t=Ed(e),o=Xm(e,t),n=vc(e,t,o);return oi(e,n),((e,t)=>{const o=ns(e),n=t=>Vs(ss(e)).bind((n=>Gt(n,o).map((o=>{const r=Fs(qs(e),o,n);return t(o,r)})))).getOr("");G({mceTableRowType:()=>n(t.getTableRowType),mceTableCellType:()=>n(t.getTableCellType),mceTableColType:()=>n(t.getTableColType)},((t,o)=>e.addQueryValueHandler(o,t)))})(e,n),Us(e,n),{getSelectedCells:o.getSelectedCells,clearSelectedCells:o.clearSelectedCells}};e.add("dom",(e=>({table:Nd(e)})))}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.ModelManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(t)===e,o=e=>t=>typeof t===e,n=e=>t=>e===t,r=t("string"),s=t("object"),l=t("array"),a=n(null),c=o("boolean"),i=n(void 0),m=e=>!(e=>null==e)(e),d=o("function"),u=o("number"),f=()=>{},g=e=>()=>e,h=e=>e,p=(e,t)=>e===t;function b(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const w=e=>t=>!e(t),v=e=>e(),y=g(!1),x=g(!0);class C{constructor(e,t){this.tag=e,this.value=t}static some(e){return new C(!0,e)}static none(){return C.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?C.some(e(this.value)):C.none()}bind(e){return this.tag?e(this.value):C.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:C.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return m(e)?C.some(e):C.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}C.singletonNone=new C(!1);const S=Array.prototype.slice,T=Array.prototype.indexOf,R=Array.prototype.push,D=(e,t)=>{return o=e,n=t,T.call(o,n)>-1;var o,n},O=(e,t)=>{for(let o=0,n=e.length;o{const o=[];for(let n=0;n{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;o{const o=[],n=[];for(let r=0,s=e.length;r{const o=[];for(let n=0,r=e.length;n(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),A=(e,t,o)=>(N(e,((e,n)=>{o=t(o,e,n)})),o),W=(e,t)=>((e,t,o)=>{for(let n=0,r=e.length;n{for(let o=0,n=e.length;o{const t=[];for(let o=0,n=e.length;oM(E(e,t)),P=(e,t)=>{for(let o=0,n=e.length;o{const o={};for(let n=0,r=e.length;nt>=0&&tF(e,0),$=e=>F(e,e.length-1),V=(e,t)=>{for(let o=0;o{const o=q(e);for(let n=0,r=o.length;nY(e,((e,o)=>({k:o,v:t(e,o)}))),Y=(e,t)=>{const o={};return G(e,((e,n)=>{const r=t(e,n);o[r.k]=r.v})),o},J=(e,t)=>{const o=[];return G(e,((e,n)=>{o.push(t(e,n))})),o},Q=e=>J(e,h),X=(e,t)=>U.call(e,t),Z=e=>{if(!l(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return N(e,((n,r)=>{const s=q(n);if(1!==s.length)throw new Error("one and only one name per case");const a=s[0],c=n[a];if(void 0!==o[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!l(c))throw new Error("case arguments must be an array");t.push(a),o[a]=(...o)=>{const n=o.length;if(n!==c.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+c.length+" ("+c+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const n=q(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!P(t,(e=>D(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:a,params:o})}}}})),o},ee=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},te=e=>e.slice(0).sort(),oe=(e,t)=>{const o=_(t,(t=>!D(e,t)));o.length>0&&(e=>{throw new Error("Unsupported keys for object: "+te(e).join(", "))})(o)},ne=e=>((e,t)=>((e,t,o)=>{if(0===t.length)throw new Error("You must specify at least one required field.");return((e,t)=>{if(!l(t))throw new Error("The "+e+" fields must be an array. Was: "+t+".");N(t,(t=>{if(!r(t))throw new Error("The value "+t+" in the "+e+" fields was not a string.")}))})("required",t),(e=>{const t=te(e);W(t,((e,o)=>o{throw new Error("The field: "+e+" occurs more than once in the combined fields: ["+t.join(", ")+"].")}))})(t),n=>{const r=q(n);P(t,(e=>D(r,e)))||((e,t)=>{throw new Error("All required keys ("+te(e).join(", ")+") were not specified. Specified keys were: "+te(t).join(", ")+".")})(t,r),e(t,r);const s=_(t,(e=>!o.validate(n[e],e)));return s.length>0&&((e,t)=>{throw new Error("All values need to be of type: "+t+". Keys ("+te(e).join(", ")+") were not.")})(s,o.label),n}})(e,t,{validate:d,label:"function"}))(oe,e),re=e=>{const t=t=>t(e),o=g(e),n=()=>r,r={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:x,isError:y,map:t=>le.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>C.some(e)};return r},se=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:y,isError:x,map:t,mapError:t=>le.error(t(e)),bind:t,exists:y,forall:x,getOr:h,or:h,getOrThunk:v,orThunk:v,getOrDie:(n=String(e),()=>{throw new Error(n)}),each:f,toOptional:C.none};var n;return o},le={value:re,error:se,fromOption:(e,t)=>e.fold((()=>se(t)),re)},ae="undefined"!=typeof window?window:Function("return this;")(),ce=e=>{const t=e.replace(/\./g,"-");return{resolve:e=>t+"-"+e}},ie=(e,t,o=p)=>e.exists((e=>o(e,t))),me=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;te?C.some(t):C.none(),ue=(e,t)=>((e,t)=>{let o=null!=t?t:ae;for(let t=0;t{const e=(e=>{const t=ee(C.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(C.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(C.some(e))}}})(f);return{...e,on:t=>e.get().each(t)}},ge=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,he=(e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!i(n)||r+t.length<=n)},pe=(e,t)=>ge(e,t,0),be=(e,t)=>ge(e,t,e.length-t.length),we=(e=>t=>t.replace(e,""))(/^\s+|\s+$/g),ve=e=>e.length>0,ye=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},xe=["tfoot","thead","tbody","colgroup"],Ce=(e,t,o)=>({element:e,rowspan:t,colspan:o}),Se=(e,t,o)=>({element:e,cells:t,section:o}),Te=(e,t,o)=>({element:e,isNew:t,isLocked:o}),Re=(e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}),De=(e,t,o)=>{const n=e.cells,r=n.slice(0,t),s=n.slice(t),l=r.concat(o).concat(s);return Ee(e,l)},Oe=(e,t,o)=>De(e,t,[o]),ke=(e,t,o)=>{e.cells[t]=o},Ee=(e,t)=>Re(e.element,t,e.section,e.isNew),Ne=(e,t)=>e.cells[t],Be=(e,t)=>Ne(e,t).element,_e=e=>e.cells.length,ze=e=>{const t=B(e,(e=>"colgroup"===e.section));return{rows:t.fail,cols:t.pass}},Ae=(e,t,o)=>{const n=E(e.cells,o);return Re(t(e.element),n,e.section,!0)},We=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},Le={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return We(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return We(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return We(o)},fromDom:We,fromPoint:(e,t,o)=>C.from(e.dom.elementFromPoint(t,o)).map(We)},Me=(e,t)=>{const o=e.document.createRange();return o.selectNode(t.dom),o},je=(e,t)=>{const o=e.document.createRange();return Pe(o,t),o},Pe=(e,t)=>e.selectNodeContents(t.dom),Ie=(e,t,o)=>{const n=e.document.createRange();var r;return r=n,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},Fe=(e,t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},He=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),$e=Z([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),Ve=(e,t,o)=>t(Le.fromDom(o.startContainer),o.startOffset,Le.fromDom(o.endContainer),o.endOffset),qe=(e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:g(e),rtl:C.none}),relative:(t,o)=>({ltr:ye((()=>Ie(e,t,o))),rtl:ye((()=>C.some(Ie(e,o,t))))}),exact:(t,o,n,r)=>({ltr:ye((()=>Fe(e,t,o,n,r))),rtl:ye((()=>C.some(Fe(e,n,r,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();return o.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>$e.rtl(Le.fromDom(e.endContainer),e.endOffset,Le.fromDom(e.startContainer),e.startOffset))).getOrThunk((()=>Ve(0,$e.ltr,o))):Ve(0,$e.ltr,o)})(0,o)},Ue=(e,t)=>qe(e,t).match({ltr:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},rtl:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(n.dom,r),s.setEnd(t.dom,o),s}});$e.ltr,$e.rtl;const Ge=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},Ke=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Ye=(e,t)=>{const o=void 0===t?document:t.dom;return Ke(o)?C.none():C.from(o.querySelector(e)).map(Le.fromDom)},Je=(e,t)=>e.dom===t.dom,Qe=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},Xe=Ge,Ze=()=>et(0,0),et=(e,t)=>({major:e,minor:t}),tt={nu:et,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?Ze():((e,t)=>{const o=((e,t)=>{for(let o=0;oNumber(t.replace(o,"$"+e));return et(n(1),n(2))})(e,o)},unknown:Ze},ot=(e,t)=>{const o=String(t).toLowerCase();return W(e,(e=>e.search(o)))},nt=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,rt=e=>t=>he(t,e),st=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>he(e,"edge/")&&he(e,"chrome")&&he(e,"safari")&&he(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,nt],search:e=>he(e,"chrome")&&!he(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>he(e,"msie")||he(e,"trident")},{name:"Opera",versionRegexes:[nt,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:rt("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:rt("firefox")},{name:"Safari",versionRegexes:[nt,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(he(e,"safari")||he(e,"mobile/"))&&he(e,"applewebkit")}],lt=[{name:"Windows",search:rt("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>he(e,"iphone")||he(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:rt("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:rt("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:rt("linux"),versionRegexes:[]},{name:"Solaris",search:rt("sunos"),versionRegexes:[]},{name:"FreeBSD",search:rt("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:rt("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],at={browsers:g(st),oses:g(lt)},ct="Edge",it="Chromium",mt="Opera",dt="Firefox",ut="Safari",ft=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(ct),isChromium:n(it),isIE:n("IE"),isOpera:n(mt),isFirefox:n(dt),isSafari:n(ut)}},gt=()=>ft({current:void 0,version:tt.unknown()}),ht=ft,pt=(g(ct),g(it),g("IE"),g(mt),g(dt),g(ut),"Windows"),bt="Android",wt="Linux",vt="macOS",yt="Solaris",xt="FreeBSD",Ct="ChromeOS",St=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(pt),isiOS:n("iOS"),isAndroid:n(bt),isMacOS:n(vt),isLinux:n(wt),isSolaris:n(yt),isFreeBSD:n(xt),isChromeOS:n(Ct)}},Tt=()=>St({current:void 0,version:tt.unknown()}),Rt=St,Dt=(g(pt),g("iOS"),g(bt),g(wt),g(vt),g(yt),g(xt),g(Ct),e=>window.matchMedia(e).matches);let Ot=ye((()=>((e,t,o)=>{const n=at.browsers(),r=at.oses(),s=t.bind((e=>((e,t)=>V(t.brands,(t=>{const o=t.brand.toLowerCase();return W(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:tt.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>ot(e,t).map((e=>{const o=tt.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(gt,ht),l=((e,t)=>ot(e,t).map((e=>{const o=tt.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(r,e).fold(Tt,Rt),a=((e,t,o,n)=>{const r=e.isiOS()&&!0===/ipad/i.test(o),s=e.isiOS()&&!r,l=e.isiOS()||e.isAndroid(),a=l||n("(pointer:coarse)"),c=r||!s&&l&&n("(min-device-width:768px)"),i=s||l&&!c,m=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),d=!i&&!c&&!m;return{isiPad:g(r),isiPhone:g(s),isTablet:g(c),isPhone:g(i),isTouch:g(a),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(m),isDesktop:g(d)}})(l,s,e,o);return{browser:s,os:l,deviceType:a}})(window.navigator.userAgent,C.from(window.navigator.userAgentData),Dt)));const kt=()=>Ot(),Et=Object.getPrototypeOf,Nt=e=>{const t=ue("ownerDocument.defaultView",e);return s(e)&&((e=>((e,t)=>{const o=((e,t)=>ue(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(Et(e).constructor.name))},Bt=e=>e.dom.nodeName.toLowerCase(),_t=e=>e.dom.nodeType,zt=e=>t=>_t(t)===e,At=e=>8===_t(e)||"#comment"===Bt(e),Wt=e=>Lt(e)&&Nt(e.dom),Lt=zt(1),Mt=zt(3),jt=zt(9),Pt=zt(11),It=e=>t=>Lt(t)&&Bt(t)===e,Ft=e=>Le.fromDom(e.dom.ownerDocument),Ht=e=>jt(e)?e:Ft(e),$t=e=>C.from(e.dom.parentNode).map(Le.fromDom),Vt=e=>C.from(e.dom.parentElement).map(Le.fromDom),qt=(e,t)=>{const o=d(t)?t:y;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=Le.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r},Ut=e=>C.from(e.dom.previousSibling).map(Le.fromDom),Gt=e=>C.from(e.dom.nextSibling).map(Le.fromDom),Kt=e=>E(e.dom.childNodes,Le.fromDom),Yt=(e,t)=>{const o=e.dom.childNodes;return C.from(o[t]).map(Le.fromDom)},Jt=e=>Pt(e)&&m(e.dom.host),Qt=e=>Le.fromDom(e.dom.getRootNode()),Xt=e=>Le.fromDom(e.dom.host),Zt=e=>{const t=Le.fromDom((e=>{if(m(e.target)){const t=Le.fromDom(e.target);if(Lt(t)&&m(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return H(t)}}return C.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),r=(s=n,l=o,(...e)=>s(l.apply(null,e)));var s,l;return((e,t,o,n,r,s,l)=>({target:e,x:t,y:o,stop:n,prevent:r,kill:s,raw:l}))(t,e.clientX,e.clientY,o,n,r,e)},eo=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},to=x,oo=(e,t,o)=>((e,t,o,n)=>((e,t,o,n,r)=>{const s=((e,t)=>o=>{e(o)&&t(Zt(o))})(o,n);return e.dom.addEventListener(t,s,r),{unbind:b(eo,e,t,s,r)}})(e,t,o,n,!1))(e,t,to,o),no=Zt,ro=(e,t)=>{$t(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},so=(e,t)=>{Gt(e).fold((()=>{$t(e).each((e=>{ao(e,t)}))}),(e=>{ro(e,t)}))},lo=(e,t)=>{const o=(e=>Yt(e,0))(e);o.fold((()=>{ao(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},ao=(e,t)=>{e.dom.appendChild(t.dom)},co=(e,t)=>{ro(e,t),ao(t,e)},io=(e,t)=>{N(t,((o,n)=>{const r=0===n?e:t[n-1];so(r,o)}))},mo=(e,t)=>{N(t,(t=>{ao(e,t)}))},uo=(e,t,o)=>{if(!(r(o)||c(o)||u(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},fo=(e,t,o)=>{uo(e.dom,t,o)},go=(e,t)=>{const o=e.dom;G(t,((e,t)=>{uo(o,t,e)}))},ho=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},po=(e,t)=>C.from(ho(e,t)),bo=(e,t)=>{e.dom.removeAttribute(t)},wo=e=>A(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),vo=e=>{e.dom.textContent="",N(Kt(e),(e=>{yo(e)}))},yo=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},xo=e=>{const t=Kt(e);t.length>0&&io(e,t),yo(e)},Co=(e,t)=>Le.fromDom(e.dom.cloneNode(t)),So=e=>Co(e,!1),To=e=>Co(e,!0),Ro=(e,t)=>{const o=Le.fromTag(t),n=wo(e);return go(o,n),o},Do=e=>void 0!==e.style&&d(e.style.getPropertyValue),Oo=e=>{const t=Mt(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=Qt(e);return Jt(t)?C.some(t):C.none()})(Le.fromDom(t)).fold((()=>o.body.contains(t)),(n=Oo,r=Xt,e=>n(r(e))));var n,r},ko=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);Do(e)&&e.style.setProperty(t,o)},Eo=(e,t,o)=>{const n=e.dom;ko(n,t,o)},No=(e,t)=>{const o=e.dom;G(t,((e,t)=>{ko(o,t,e)}))},Bo=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||Oo(e)?n:_o(o,t)},_o=(e,t)=>Do(e)?e.style.getPropertyValue(t):"",zo=(e,t)=>{const o=e.dom,n=_o(o,t);return C.from(n).filter((e=>e.length>0))},Ao=(e,t)=>{((e,t)=>{Do(e)&&e.style.removeProperty(t)})(e.dom,t),ie(po(e,"style").map(we),"")&&bo(e,"style")},Wo=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=Bo(o,e);return parseFloat(t)||0}return n},n=(e,t)=>A(t,((t,o)=>{const n=Bo(e,o),r=void 0===n?0:parseInt(n,10);return isNaN(r)?t:t+r}),0);return{set:(t,o)=>{if(!u(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;Do(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const r=n(e,o);return t>r?t-r:0}}},Lo=(e,t,o)=>((e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?C.none():C.some(t)})(e).getOr(t))(Bo(e,t),o),Mo=Wo("height",(e=>{const t=e.dom;return Oo(e)?t.getBoundingClientRect().height:t.offsetHeight})),jo=e=>Mo.get(e),Po=e=>Mo.getOuter(e),Io=Wo("width",(e=>e.dom.offsetWidth));Wo("width",(e=>{const t=e.dom;return Oo(e)?t.getBoundingClientRect().width:t.offsetWidth}));const Fo=e=>Io.get(e),Ho=e=>Io.getOuter(e),$o=e=>((e,t)=>{const o=e.dom,n=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?n:((e,t,o,n)=>t-Lo(e,`padding-${o}`,0)-Lo(e,`padding-${n}`,0)-Lo(e,`border-${o}-width`,0)-Lo(e,`border-${n}-width`,0))(e,n,"left","right")})(e,"content-box"),Vo=(e,t)=>({left:e,top:t,translate:(o,n)=>Vo(e+o,t+n)}),qo=Vo,Uo=(e,t)=>void 0!==e?e:void 0!==t?t:0,Go=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,r=t.documentElement;if(o===e.dom)return qo(o.offsetLeft,o.offsetTop);const s=Uo(null==n?void 0:n.pageYOffset,r.scrollTop),l=Uo(null==n?void 0:n.pageXOffset,r.scrollLeft),a=Uo(r.clientTop,o.clientTop),c=Uo(r.clientLeft,o.clientLeft);return Ko(e).translate(l-c,s-a)},Ko=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?qo(o.offsetLeft,o.offsetTop):Oo(e)?(e=>{const t=e.getBoundingClientRect();return qo(t.left,t.top)})(t):qo(0,0)},Yo=(e=>{const t=t=>e(t)?C.from(t.dom.nodeValue):C.none();return{get:o=>{if(!e(o))throw new Error("Can only get text value of a text node");return t(o).getOr("")},getOption:t,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(Mt),Jo=e=>Yo.get(e),Qo=e=>Yo.getOption(e),Xo=(e,t)=>Yo.set(e,t),Zo=(e,t)=>o=>"rtl"===en(o)?t:e,en=e=>"rtl"===Bo(e,"direction")?"rtl":"ltr";var tn=(e,t,o,n,r)=>e(o,n)?C.some(o):d(r)&&r(o)?C.none():t(o,n,r);const on=(e,t,o)=>{let n=e.dom;const r=d(o)?o:y;for(;n.parentNode;){n=n.parentNode;const e=Le.fromDom(n);if(t(e))return C.some(e);if(r(e))break}return C.none()},nn=(e,t,o)=>tn(((e,t)=>t(e)),on,e,t,o),rn=(e,t,o)=>on(e,(e=>Ge(e,t)),o),sn=(e,t)=>(e=>W(e.dom.childNodes,(e=>{return o=Le.fromDom(e),Ge(o,t);var o})).map(Le.fromDom))(e),ln=(e,t)=>Ye(t,e),an=(e,t,o)=>tn(((e,t)=>Ge(e,t)),rn,e,t,o),cn=e=>void 0!==e.dom.classList,mn=(e,t)=>((e,t,o)=>{const n=((e,t)=>{const o=ho(e,t);return void 0===o||""===o?[]:o.split(" ")})(e,t).concat([o]);return fo(e,t,n.join(" ")),!0})(e,"class",t),dn=(e,t)=>{cn(e)?e.dom.classList.add(t):mn(e,t)},un=(e,t)=>cn(e)&&e.dom.classList.contains(t),fn=e=>an(e,"[contenteditable]"),gn=(e,t=!1)=>Oo(e)?e.dom.isContentEditable:fn(e).fold(g(t),(e=>"true"===hn(e))),hn=e=>e.dom.contentEditable,pn=(e,t)=>{let o=[];return N(Kt(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(pn(e,t))})),o},bn=(e,t,o)=>((e,o,n)=>_(qt(e,n),(e=>Ge(e,t))))(e,0,o),wn=(e,t)=>(e=>_(Kt(e),(e=>Ge(e,t))))(e),vn=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return Ke(o)?[]:E(o.querySelectorAll(e),Le.fromDom)})(t,e),yn=e=>"img"===Bt(e)?1:Qo(e).fold((()=>Kt(e).length),(e=>e.length)),xn=["img","br"],Cn=e=>Qo(e).filter((e=>0!==e.trim().length||e.indexOf("\xa0")>-1)).isSome()||D(xn,Bt(e))||(e=>Wt(e)&&"false"===ho(e,"contenteditable"))(e),Sn=e=>((e,t)=>{const o=e=>{for(let n=0;nRn(e,Cn),Rn=(e,t)=>{const o=e=>{const n=Kt(e);for(let e=n.length-1;e>=0;e--){const r=n[e];if(t(r))return C.some(r);const s=o(r);if(s.isSome())return s}return C.none()};return o(e)},Dn=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),On=Z([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),kn={before:On.before,on:On.on,after:On.after,cata:(e,t,o,n)=>e.fold(t,o,n),getStart:e=>e.fold(h,h,h)},En=Z([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),Nn={domRange:En.domRange,relative:En.relative,exact:En.exact,exactFromRange:e=>En.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>Le.fromDom(e.startContainer),relative:(e,t)=>kn.getStart(e),exact:(e,t,o,n)=>e}))(e);return Le.fromDom(Ht(t).dom.defaultView)},range:Dn},Bn=(e,t)=>{const o=Bt(e);return"input"===o?kn.after(e):D(["br","img"],o)?0===t?kn.before(e):kn.after(e):kn.on(e,t)},_n=e=>C.from(e.getSelection()),zn=(e,t)=>{_n(e).each((e=>{e.removeAllRanges(),e.addRange(t)}))},An=(e,t,o,n,r)=>{const s=Fe(e,t,o,n,r);zn(e,s)},Wn=(e,t)=>qe(e,t).match({ltr:(t,o,n,r)=>{An(e,t,o,n,r)},rtl:(t,o,n,r)=>{_n(e).each((s=>{if(s.setBaseAndExtent)s.setBaseAndExtent(t.dom,o,n.dom,r);else if(s.extend)try{((e,t,o,n,r,s)=>{t.collapse(o.dom,n),t.extend(r.dom,s)})(0,s,t,o,n,r)}catch(s){An(e,n,r,t,o)}else An(e,n,r,t,o)}))}}),Ln=(e,t,o,n,r)=>{const s=((e,t,o,n)=>{const r=Bn(e,t),s=Bn(o,n);return Nn.relative(r,s)})(t,o,n,r);Wn(e,s)},Mn=(e,t,o)=>{const n=((e,t)=>{const o=e.fold(kn.before,Bn,kn.after),n=t.fold(kn.before,Bn,kn.after);return Nn.relative(o,n)})(t,o);Wn(e,n)},jn=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return C.some(Dn(Le.fromDom(t.startContainer),t.startOffset,Le.fromDom(o.endContainer),o.endOffset))}return C.none()},Pn=e=>{if(null===e.anchorNode||null===e.focusNode)return jn(e);{const t=Le.fromDom(e.anchorNode),o=Le.fromDom(e.focusNode);return((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=Ft(e).dom.createRange();return r.setStart(e.dom,t),r.setEnd(o.dom,n),r})(e,t,o,n),s=Je(e,o)&&t===n;return r.collapsed&&!s})(t,e.anchorOffset,o,e.focusOffset)?C.some(Dn(t,e.anchorOffset,o,e.focusOffset)):jn(e)}},In=(e,t,o=!0)=>{const n=(o?je:Me)(e,t);zn(e,n)},Fn=e=>(e=>_n(e).filter((e=>e.rangeCount>0)).bind(Pn))(e).map((e=>Nn.exact(e.start,e.soffset,e.finish,e.foffset))),Hn=(e,t,o)=>((e,t,o)=>((e,t,o)=>e.caretPositionFromPoint?((e,t,o)=>{var n;return C.from(null===(n=e.caretPositionFromPoint)||void 0===n?void 0:n.call(e,t,o)).bind((t=>{if(null===t.offsetNode)return C.none();const o=e.createRange();return o.setStart(t.offsetNode,t.offset),o.collapse(),C.some(o)}))})(e,t,o):e.caretRangeFromPoint?((e,t,o)=>{var n;return C.from(null===(n=e.caretRangeFromPoint)||void 0===n?void 0:n.call(e,t,o))})(e,t,o):C.none())(e.document,t,o).map((e=>Dn(Le.fromDom(e.startContainer),e.startOffset,Le.fromDom(e.endContainer),e.endOffset))))(e,t,o),$n={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},Vn=(()=>{const e="[0-9]+",t="[eE][+-]?"+e,o=e=>`(?:${e})?`,n=["Infinity",e+"\\."+o(e)+o(t),"\\."+e+o(t),e+o(t)].join("|");return new RegExp(`^([+-]?(?:${n}))(.*)$`)})(),qn=e=>E(e,g(0)),Un=(e,t,o,n,r)=>r(e.slice(0,t)).concat(n).concat(r(e.slice(o))),Gn=e=>(t,o,n,r)=>{if(e(n)){const e=Math.max(r,t[o]-Math.abs(n)),s=Math.abs(e-t[o]);return n>=0?s:-s}return n},Kn=Gn((e=>e<0)),Yn=Gn(x),Jn=()=>{const e=(e,t,o,n)=>{const r=(100+o)/100,s=Math.max(n,(e[t]+o)/r);return E(e,((e,o)=>(o===t?s:e/r)-e))},t=(t,o,n,r,s,l)=>l?e(t,o,r,s):((e,t,o,n,r)=>{const s=Kn(e,t,n,r);return Un(e,t,o+1,[s,0],qn)})(t,o,n,r,s);return{resizeTable:(e,t)=>e(t),clampTableDelta:Kn,calcLeftEdgeDeltas:t,calcMiddleDeltas:(e,o,n,r,s,l,a)=>t(e,n,r,s,l,a),calcRightEdgeDeltas:(t,o,n,r,s,l)=>{if(l)return e(t,n,r,s);{const e=Kn(t,n,r,s);return qn(t.slice(0,n)).concat([e])}},calcRedestributedWidths:(e,t,o,n)=>{if(n){const n=(t+o)/t,r=E(e,(e=>e/n));return{delta:100*n-100,newSizes:r}}return{delta:o,newSizes:e}}}},Qn=()=>{const e=(e,t,o,n,r)=>{const s=Yn(e,n>=0?o:t,n,r);return Un(e,t,o+1,[s,-s],qn)};return{resizeTable:(e,t,o)=>{o&&e(t)},clampTableDelta:(e,t,o,n,r)=>{if(r){if(o>=0)return o;{const t=A(e,((e,t)=>e+t-n),0);return Math.max(-t,o)}}return Kn(e,t,o,n)},calcLeftEdgeDeltas:e,calcMiddleDeltas:(t,o,n,r,s,l)=>e(t,n,r,s,l),calcRightEdgeDeltas:(e,t,o,n,r,s)=>{if(s)return qn(e);{const t=n/e.length;return E(e,g(t))}},calcRedestributedWidths:(e,t,o,n)=>({delta:0,newSizes:e})}},Xn=(e,t,o=0)=>po(e,t).map((e=>parseInt(e,10))).getOr(o),Zn=(e,t)=>Xn(e,t,1),er=e=>It("col")(e)?Xn(e,"span",1)>1:Zn(e,"colspan")>1,tr=(e,t)=>parseInt(Bo(e,t),10),or=g(10),nr=g(10),rr=(e,t)=>sr(e,t,x),sr=(e,t,o)=>j(Kt(e),(e=>Ge(e,t)?o(e)?[e]:[]:sr(e,t,o))),lr=(e,t)=>((e,t,o=y)=>o(t)?C.none():D(e,Bt(t))?C.some(t):rn(t,e.join(","),(e=>Ge(e,"table")||o(e))))(["td","th"],e,t),ar=e=>rr(e,"th,td"),cr=e=>Ge(e,"colgroup")?wn(e,"col"):j(dr(e),(e=>wn(e,"col"))),ir=(e,t)=>an(e,"table",t),mr=e=>rr(e,"tr"),dr=e=>ir(e).fold(g([]),(e=>wn(e,"colgroup"))),ur=It("th"),fr=e=>P(e,(e=>ur(e.element))),gr=(e,t)=>e&&t?"sectionCells":e?"section":"cells",hr=e=>{const t="thead"===e.section,o=ie(pr(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:gr(t,o)}:{type:"body"}},pr=e=>{const t=_(e,(e=>ur(e.element)));return 0===t.length?C.some("td"):t.length===e.length?C.some("th"):C.none()},br=(e,t)=>E(e,(e=>{if("colgroup"===Bt(e)){const t=E(cr(e),(e=>{const t=Xn(e,"span",1);return Ce(e,1,t)}));return Se(e,t,"colgroup")}{const o=E(ar(e),(e=>{const t=Xn(e,"rowspan",1),o=Xn(e,"colspan",1);return Ce(e,t,o)}));return Se(e,o,t(e))}})),wr=e=>$t(e).map((e=>{const t=Bt(e);return(e=>D(xe,e))(t)?t:"tbody"})).getOr("tbody"),vr=e=>{const t=mr(e),o=[...dr(e),...t];return br(o,wr)},yr="data-snooker-locked-cols",xr=e=>po(e,yr).bind((e=>C.from(e.match(/\d+/g)))).map((e=>I(e,x))),Cr=e=>{const t=A(ze(e).rows,((e,t)=>(N(t.cells,((t,o)=>{t.isLocked&&(e[o]=!0)})),e)),{}),o=J(t,((e,t)=>parseInt(t,10)));return(e=>{const t=S.call(e,0);return t.sort(void 0),t})(o)},Sr=(e,t)=>e+","+t,Tr=(e,t)=>{const o=j(e.all,(e=>e.cells));return _(o,t)},Rr=e=>{const t={},o=[],n=H(e).map((e=>e.element)).bind(ir).bind(xr).getOr({});let r=0,s=0,l=0;const{pass:a,fail:c}=B(e,(e=>"colgroup"===e.section));N(c,(e=>{const a=[];N(e.cells,(e=>{let o=0;for(;void 0!==t[Sr(l,o)];)o++;const r=((e,t)=>X(e,t)&&void 0!==e[t]&&null!==e[t])(n,o.toString()),c=((e,t,o,n,r,s)=>({element:e,rowspan:t,colspan:o,row:n,column:r,isLocked:s}))(e.element,e.rowspan,e.colspan,l,o,r);for(let n=0;n{const t=(e=>{const t={};let o=0;return N(e.cells,(e=>{const n=e.colspan;k(n,(r=>{const s=o+r;t[s]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,n,s)})),o+=n})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,Q(t));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),d=((e,t)=>({rows:e,columns:t}))(r,s);return{grid:d,access:t,all:o,columns:i,colgroups:m}},Dr=e=>{const t=vr(e);return Rr(t)},Or=Rr,kr=(e,t,o)=>C.from(e.access[Sr(t,o)]),Er=(e,t,o)=>{const n=Tr(e,(e=>o(t,e.element)));return n.length>0?C.some(n[0]):C.none()},Nr=Tr,Br=e=>j(e.all,(e=>e.cells)),_r=e=>Q(e.columns),zr=e=>q(e.columns).length>0,Ar=(e,t)=>C.from(e.columns[t]),Wr=(e,t,o)=>Te(o(e.element,t),!0,e.isLocked),Lr=(e,t)=>e.section!==t?Re(e.element,e.cells,t,e.isNew):e,Mr=()=>({transformRow:Lr,transformCell:(e,t,o)=>{const n=o(e.element,t),r="td"!==Bt(n)?(e=>{const t=Ro(e,"td");so(e,t);const o=Kt(e);return mo(t,o),yo(e),t})(n):n;return Te(r,e.isNew,e.isLocked)}}),jr=()=>({transformRow:Lr,transformCell:Wr}),Pr=()=>({transformRow:(e,t)=>Lr(e,"thead"===t?"tbody":t),transformCell:Wr}),Ir=Mr,Fr=jr,Hr=Pr,$r=()=>({transformRow:h,transformCell:Wr}),Vr=(e,t=x)=>{const o=e.grid,n=k(o.columns,h),r=k(o.rows,h);return E(n,(o=>qr((()=>j(r,(t=>kr(e,t,o).filter((e=>e.column===o)).toArray()))),(e=>1===e.colspan&&t(e.element)),(()=>kr(e,0,o)))))},qr=(e,t,o)=>{const n=e();return W(n,t).orThunk((()=>C.from(n[0]).orThunk(o))).map((e=>e.element))},Ur=e=>{const t=e.grid,o=k(t.rows,h),n=k(t.columns,h);return E(o,(t=>qr((()=>j(n,(o=>kr(e,t,o).filter((e=>e.row===t)).fold(g([]),(e=>[e]))))),(e=>1===e.rowspan),(()=>kr(e,t,0)))))},Gr=(e,t)=>({row:e,y:t}),Kr=(e,t)=>({col:e,x:t}),Yr=e=>Go(e).left+Ho(e),Jr=e=>Go(e).left,Qr=(e,t)=>Kr(e,Jr(t)),Xr=(e,t)=>Kr(e,Yr(t)),Zr=e=>Go(e).top,es=(e,t)=>Gr(e,Zr(t)),ts=(e,t)=>Gr(e,Zr(t)+Po(t)),os=(e,t,o)=>{if(0===o.length)return[];const n=E(o.slice(1),((t,o)=>t.map((t=>e(o,t))))),r=o[o.length-1].map((e=>t(o.length-1,e)));return n.concat([r])},ns={delta:h,positions:e=>os(es,ts,e),edge:Zr},rs=Zo({delta:h,edge:Jr,positions:e=>os(Qr,Xr,e)},{delta:e=>-e,edge:Yr,positions:e=>os(Xr,Qr,e)}),ss={delta:(e,t)=>rs(t).delta(e,t),positions:(e,t)=>rs(t).positions(e,t),edge:e=>rs(e).edge(e)},ls=/(\d+(\.\d+)?)%/,as=/(\d+(\.\d+)?)px|em/,cs=It("col"),is=It("tr"),ms=(e,t,o)=>{const n=Vt(e).getOrThunk((()=>(e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return Le.fromDom(t)})(Ft(e))));return t(e)/o(n)*100},ds=(e,t)=>{Eo(e,"width",t+"px")},us=(e,t)=>{Eo(e,"width",t+"%")},fs=(e,t)=>{Eo(e,"height",t+"px")},gs=e=>{const t=(e=>{return Lo(t=e,"height",t.dom.offsetHeight)+"px";var t})(e);return t?((e,t,o,n)=>{const r=parseFloat(e);return be(e,"%")&&"table"!==Bt(t)?((e,t,o,n)=>{const r=ir(e).map((e=>{const n=o(e);return Math.floor(t/100*n)})).getOr(t);return n(e,r),r})(t,r,o,n):r})(t,e,jo,fs):jo(e)},hs=(e,t)=>zo(e,t).orThunk((()=>po(e,t).map((e=>e+"px")))),ps=e=>hs(e,"width"),bs=e=>ms(e,Fo,$o),ws=e=>{return cs(e)?Fo(e):Lo(t=e,"width",t.dom.offsetWidth);var t},vs=e=>is(e)?jo(e):((e,t,o)=>o(e)/Zn(e,"rowspan"))(e,0,gs),ys=(e,t,o)=>{Eo(e,"width",t+o)},xs=e=>ms(e,Fo,$o)+"%",Cs=g(ls),Ss=It("col"),Ts=e=>ps(e).getOrThunk((()=>ws(e)+"px")),Rs=e=>{return(t=e,hs(t,"height")).getOrThunk((()=>vs(e)+"px"));var t},Ds=(e,t,o,n,r,s)=>e.filter(n).fold((()=>s(((e,t)=>{if(t<0||t>=e.length-1)return C.none();const o=e[t].fold((()=>{const o=(e=>{const t=S.call(e,0);return t.reverse(),t})(e.slice(0,t));return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:0}))),n=e[t+1].fold((()=>{const o=e.slice(t+1);return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:1})));return o.bind((e=>n.map((t=>{const o=t.delta+e.delta;return Math.abs(t.value-e.value)/o}))))})(o,t))),(e=>r(e))),Os=(e,t,o,n)=>{const r=Vr(e),s=zr(e)?(e=>E(_r(e),(e=>C.from(e.element))))(e):r,l=[C.some(ss.edge(t))].concat(E(ss.positions(r,t),(e=>e.map((e=>e.x))))),a=w(er);return E(s,((e,t)=>Ds(e,t,l,a,(e=>{if((e=>{const t=kt().browser,o=t.isChromium()||t.isFirefox();return!Ss(e)||o})(e))return o(e);{const e=null!=(s=r[t])?h(s):C.none();return Ds(e,t,l,a,(e=>n(C.some(Fo(e)))),n)}var s}),n)))},ks=e=>e.map((e=>e+"px")).getOr(""),Es=(e,t,o)=>Os(e,t,ws,(e=>e.getOrThunk(o.minCellWidth))),Ns=(e,t,o,n)=>{const r=Ur(e),s=E(e.all,(e=>C.some(e.element))),l=[C.some(ns.edge(t))].concat(E(ns.positions(r,t),(e=>e.map((e=>e.y)))));return E(s,((e,t)=>Ds(e,t,l,x,o,n)))},Bs=(e,t)=>()=>Oo(e)?t(e):parseFloat(zo(e,"width").getOr("0")),_s=e=>{const t=Bs(e,(e=>parseFloat(xs(e)))),o=Bs(e,Fo);return{width:t,pixelWidth:o,getWidths:(t,o)=>((e,t,o)=>Os(e,t,bs,(e=>e.fold((()=>o.minCellWidth()),(e=>e/o.pixelWidth()*100)))))(t,e,o),getCellDelta:e=>e/o()*100,singleColumnWidth:(e,t)=>[100-e],minCellWidth:()=>or()/o()*100,setElementWidth:us,adjustTableWidth:o=>{const n=t();us(e,n+o/100*n)},isRelative:!0,label:"percent"}},zs=e=>{const t=Bs(e,Fo);return{width:t,pixelWidth:t,getWidths:(t,o)=>Es(t,e,o),getCellDelta:h,singleColumnWidth:(e,t)=>[Math.max(or(),e+t)-e],minCellWidth:or,setElementWidth:ds,adjustTableWidth:o=>{const n=t()+o;ds(e,n)},isRelative:!1,label:"pixel"}},As=e=>ps(e).fold((()=>(e=>{const t=Bs(e,Fo),o=g(0);return{width:t,pixelWidth:t,getWidths:(t,o)=>Es(t,e,o),getCellDelta:o,singleColumnWidth:g([0]),minCellWidth:o,setElementWidth:f,adjustTableWidth:f,isRelative:!0,label:"none"}})(e)),(t=>((e,t)=>null!==Cs().exec(t)?_s(e):zs(e))(e,t))),Ws=zs,Ls=_s,Ms=(e,t,o,n)=>{o===n?bo(e,t):fo(e,t,o)},js=(e,t,o)=>{$(wn(e,t)).fold((()=>lo(e,o)),(e=>so(e,o)))},Ps=(e,t)=>{const o=[],n=[],r=e=>E(e,(e=>{e.isNew&&o.push(e.element);const t=e.element;return vo(t),N(e.cells,(e=>{e.isNew&&n.push(e.element),Ms(e.element,"colspan",e.colspan,1),Ms(e.element,"rowspan",e.rowspan,1),ao(t,e.element)})),t})),s=e=>j(e,(e=>E(e.cells,(e=>(Ms(e.element,"span",e.colspan,1),e.element))))),l=(t,o)=>{const n=((e,t)=>{const o=sn(e,t).getOrThunk((()=>{const o=Le.fromTag(t,Ft(e).dom);return"thead"===t?js(e,"caption,colgroup",o):"colgroup"===t?js(e,"caption",o):ao(e,o),o}));return vo(o),o})(e,o),l=("colgroup"===o?s:r)(t);mo(n,l)},a=(t,o)=>{t.length>0?l(t,o):(t=>{sn(e,t).each(yo)})(o)},c=[],i=[],m=[],d=[];return N(t,(e=>{switch(e.section){case"thead":c.push(e);break;case"tbody":i.push(e);break;case"tfoot":m.push(e);break;case"colgroup":d.push(e)}})),a(d,"colgroup"),a(c,"thead"),a(i,"tbody"),a(m,"tfoot"),{newRows:o,newCells:n}},Is=(e,t)=>{if(0===e.length)return 0;const o=e[0];return L(e,(e=>!t(o.element,e.element))).getOr(e.length)},Fs=(e,t)=>{const o=E(e,(e=>E(e.cells,y)));return E(e,((n,r)=>{const s=j(n.cells,((n,s)=>{if(!1===o[r][s]){const m=((e,t,o,n)=>{const r=((e,t)=>e[t])(e,t),s="colgroup"===r.section,l=Is(r.cells.slice(o),n),a=s?1:Is(((e,t)=>E(e,(e=>Ne(e,t))))(e.slice(t),o),n);return{colspan:l,rowspan:a}})(e,r,s,t);return((e,t,n,r)=>{for(let s=e;s({element:e,cells:t,section:o,isNew:n}))(n.element,s,n.section,n.isNew)}))},Hs=(e,t,o)=>{const n=[];N(e.colgroups,(r=>{const s=[];for(let n=0;nTe(e.element,o,!1))).getOrThunk((()=>Te(t.colGap(),!0,!1)));s.push(r)}n.push(Re(r.element,s,"colgroup",o))}));for(let r=0;rTe(e.element,o,e.isLocked))).getOrThunk((()=>Te(t.gap(),!0,!1)));s.push(l)}const l=e.all[r],a=Re(l.element,s,l.section,o);n.push(a)}return n},$s=e=>Fs(e,Je),Vs=(e,t)=>V(e.all,(e=>W(e.cells,(e=>Je(t,e.element))))),qs=(e,t,o)=>{const n=E(t.selection,(t=>lr(t).bind((t=>Vs(e,t))).filter(o))),r=me(n);return de(r.length>0,r)},Us=(e,t,o,n,r,s,l,a,c)=>{const i=Dr(s),m=C.from(null==c?void 0:c.section).getOrThunk($r);return t(i,l).map((t=>{const o=((e,t)=>Hs(e,t,!1))(i,a),n=e(o,t,Je,r(a),m),s=Cr(n.grid);return{info:t,grid:$s(n.grid),cursor:n.cursor,lockedColumns:s}})).bind((e=>{const t=Ps(s,e.grid),r=C.from(null==c?void 0:c.sizing).getOrThunk((()=>As(s))),l=C.from(null==c?void 0:c.resize).getOrThunk(Qn);return o(s,e.grid,e.info,{sizing:r,resize:l,section:m}),n(s),bo(s,yr),e.lockedColumns.length>0&&fo(s,yr,e.lockedColumns.join(",")),C.some({cursor:e.cursor,newRows:t.newRows,newCells:t.newCells})}))},Gs=(e,t)=>lr(t.element).bind((o=>Vs(e,o).map((e=>({...e,generators:t.generators,clipboard:t.clipboard}))))),Ks=(e,t)=>qs(e,t,x).map((e=>({cells:e,generators:t.generators,clipboard:t.clipboard}))),Ys=(e,t)=>qs(e,t,x),Js=(e,t)=>qs(e,t,(e=>!e.isLocked)),Qs=(e,t)=>P(t,(t=>((e,t)=>Vs(e,t).exists((e=>!e.isLocked)))(e,t))),Xs=(e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>Qs(e,t.cells))),Zs=(e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>Qs(e,t))),el={...Z([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}])},tl=(e,t,o)=>{const n=((e,t)=>zr(e)?((e,t)=>{const o=_r(e);return E(o,((e,o)=>({element:e.element,width:t[o],colspan:e.colspan})))})(e,t):((e,t)=>{const o=Br(e);return E(o,(e=>{const o=((e,t,o)=>{let n=0;for(let r=e;r{o.setElementWidth(e.element,e.width)}))},ol=(e,t,o,n,r)=>{const s=Dr(e),l=r.getCellDelta(t),a=r.getWidths(s,r),c=o===s.grid.columns-1,i=n.clampTableDelta(a,o,l,r.minCellWidth(),c),m=((e,t,o,n,r)=>{const s=e.slice(0),l=((e,t)=>0===e.length?el.none():1===e.length?el.only(0):0===t?el.left(0,1):t===e.length-1?el.right(t-1,t):t>0&&tn.singleColumnWidth(s[e],o)),((e,t)=>r.calcLeftEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)),((e,t,l)=>r.calcMiddleDeltas(s,e,t,l,o,n.minCellWidth(),n.isRelative)),((e,t)=>r.calcRightEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)))})(a,o,i,r,n),d=E(m,((e,t)=>e+a[t]));tl(s,d,r),n.resizeTable(r.adjustTableWidth,i,c)},nl=(e,t,o)=>{const n=Dr(e),r=((e,t)=>Ns(e,t,vs,(e=>e.getOrThunk(nr))))(n,e),s=E(r,((e,n)=>o===n?Math.max(t+e,nr()):e)),l=((e,t)=>E(e.all,((e,o)=>({element:e.element,height:t[o]}))))(n,s);N(l,(e=>{fs(e.element,e.height)})),N(Br(n),(e=>{(e=>{Ao(e,"height")})(e.element)}));const a=z(s,((e,t)=>e+t),0);fs(e,a)},rl=(e,t)=>{if(!er(e)){const o=(e=>ps(e).bind((e=>{return t=e,o=["fixed","relative","empty"],C.from(Vn.exec(t)).bind((e=>{const t=Number(e[1]),n=e[2];return((e,t)=>O(t,(t=>O($n[t],(t=>e===t)))))(n,o)?C.some({value:t,unit:n}):C.none()}));var t,o})))(e);o.each((o=>{const n=o.value/2;ys(e,n,o.unit),ys(t,n,o.unit)}))}},sl=(e,t,o)=>{const n=Xn(e,t,1);1===o||n<=1?bo(e,t):fo(e,t,Math.min(o,n))},ll=(e,t)=>o=>{const n=o.column+o.colspan-1,r=o.column;return n>=e&&r{const n=e[o].element,r=Le.fromTag("td");ao(r,Le.fromTag("br")),(t?ao:lo)(n,r)},cl=It("col"),il=It("colgroup"),ml=e=>"tr"===Bt(e)||il(e),dl=e=>({element:e,colspan:Xn(e,"colspan",1),rowspan:Xn(e,"rowspan",1)}),ul=e=>po(e,"scope").map((e=>e.substr(0,3))),fl=(e,t=dl)=>{const o=o=>{if(ml(o))return il((r={element:o}).element)?e.colgroup(r):e.row(r);{const r=o,s=(t=>cl(t.element)?e.col(t):e.cell(t))(t(r));return n=C.some({item:r,replacement:s}),s}var r};let n=C.none();return{getOrInit:(e,t)=>n.fold((()=>o(e)),(n=>t(e,n.item)?n.replacement:o(e)))}},gl=e=>t=>{const o=[],n=n=>{const r="td"===e?{scope:null}:{},s=t.replace(n,e,r);return o.push({item:n,sub:s}),s};return{replaceOrInit:(e,t)=>{if(ml(e)||cl(e))return e;{const r=e;return((e,t)=>W(o,(o=>t(o.item,e))))(r,t).fold((()=>n(r)),(o=>t(e,o.item)?o.sub:n(r)))}}}},hl=e=>({unmerge:t=>{const o=ul(t);return o.each((e=>fo(t,"scope",e))),()=>{const n=e.cell({element:t,colspan:1,rowspan:1});return Ao(n,"width"),Ao(t,"width"),o.each((e=>fo(n,"scope",e))),n}},merge:e=>(Ao(e[0],"width"),(()=>{const t=me(E(e,ul));if(0===t.length)return C.none();{const e=t[0],o=["row","col"];return O(t,(t=>t!==e&&D(o,t)))?C.none():C.from(e)}})().fold((()=>bo(e[0],"scope")),(t=>fo(e[0],"scope",t+"group"))),g(e[0]))}),pl=Z([{invalid:["raw"]},{pixels:["value"]},{percent:["value"]}]),bl=(e,t,o)=>{const n=o.substring(0,o.length-e.length),r=parseFloat(n);return n===r.toString()?t(r):pl.invalid(o)},wl={...pl,from:e=>be(e,"%")?bl("%",pl.percent,e):be(e,"px")?bl("px",pl.pixels,e):pl.invalid(e)},vl=(e,t,o)=>{const n=wl.from(o),r=P(e,(e=>"0px"===e))?((e,t)=>{const o=e.fold((()=>g("")),(e=>g(e/t+"px")),(()=>g(100/t+"%")));return k(t,o)})(n,e.length):((e,t,o)=>e.fold((()=>t),(e=>((e,t,o)=>{const n=o/t;return E(e,(e=>wl.from(e).fold((()=>e),(e=>e*n+"px"),(e=>e/100*o+"px"))))})(t,o,e)),(e=>((e,t)=>E(e,(e=>wl.from(e).fold((()=>e),(e=>e/t*100+"%"),(e=>e+"%")))))(t,o))))(n,e,t);return Cl(r)},yl=(e,t)=>0===e.length?t:z(e,((e,t)=>wl.from(t).fold(g(0),h,h)+e),0),xl=(e,t)=>wl.from(e).fold(g(e),(e=>e+t+"px"),(e=>e+t+"%")),Cl=e=>{if(0===e.length)return e;const t=z(e,((e,t)=>{const o=wl.from(t).fold((()=>({value:t,remainder:0})),(e=>(e=>{const t=Math.floor(e);return{value:t+"px",remainder:e-t}})(e)),(e=>({value:e+"%",remainder:0})));return{output:[o.value].concat(e.output),remainder:e.remainder+o.remainder}}),{output:[],remainder:0}),o=t.output;return o.slice(0,o.length-1).concat([xl(o[o.length-1],Math.round(t.remainder))])},Sl=wl.from,Tl=(e,t,o)=>{const n=Dr(e),r=n.all,s=Br(n),l=_r(n);t.each((t=>{const o=Sl(t).fold(g("px"),g("px"),g("%")),r=Fo(e),a=((e,t)=>Os(e,t,Ts,ks))(n,e),c=vl(a,r,t);zr(n)?((e,t,o)=>{N(t,((t,n)=>{const r=yl([e[n]],or());Eo(t.element,"width",r+o)}))})(c,l,o):((e,t,o)=>{N(t,(t=>{const n=e.slice(t.column,t.colspan+t.column),r=yl(n,or());Eo(t.element,"width",r+o)}))})(c,s,o),Eo(e,"width",t)})),o.each((t=>{const o=jo(e),l=((e,t)=>Ns(e,t,Rs,ks))(n,e);((e,t,o)=>{N(o,(e=>{Ao(e.element,"height")})),N(t,((t,o)=>{Eo(t.element,"height",e[o])}))})(vl(l,o,t),r,s),Eo(e,"height",t)}))},Rl=e=>ps(e).exists((e=>ls.test(e))),Dl=e=>ps(e).exists((e=>as.test(e))),Ol=e=>ps(e).isNone();var kl=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],El=()=>({up:g({selector:rn,closest:an,predicate:on,all:qt}),down:g({selector:vn,predicate:pn}),styles:g({get:Bo,getRaw:zo,set:Eo,remove:Ao}),attrs:g({get:ho,set:fo,remove:bo,copyTo:(e,t)=>{const o=wo(e);go(t,o)}}),insert:g({before:ro,after:so,afterAll:io,append:ao,appendAll:mo,prepend:lo,wrap:co}),remove:g({unwrap:xo,remove:yo}),create:g({nu:Le.fromTag,clone:e=>Le.fromDom(e.dom.cloneNode(!1)),text:Le.fromText}),query:g({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:Ut,nextSibling:Gt}),property:g({children:Kt,name:Bt,parent:$t,document:e=>Ht(e).dom,isText:Mt,isComment:At,isElement:Lt,isSpecial:e=>{const t=Bt(e);return D(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>Lt(e)?po(e,"lang"):C.none(),getText:Jo,setText:Xo,isBoundary:e=>!!Lt(e)&&("body"===Bt(e)||D(kl,Bt(e))),isEmptyTag:e=>!!Lt(e)&&D(["br","img","hr","input"],Bt(e)),isNonEditable:e=>Lt(e)&&"false"===ho(e,"contenteditable")}),eq:Je,is:Xe});const Nl=(e,t)=>({item:e,mode:t}),Bl=(e,t,o,n=_l)=>e.property().parent(t).map((e=>Nl(e,n))),_l=(e,t,o,n=zl)=>o.sibling(e,t).map((e=>Nl(e,n))),zl=(e,t,o,n=zl)=>{const r=e.property().children(t);return o.first(r).map((e=>Nl(e,n)))},Al=[{current:Bl,next:_l,fallback:C.none()},{current:_l,next:zl,fallback:C.some(Bl)},{current:zl,next:zl,fallback:C.some(_l)}],Wl=(e,t,o,n,r=Al)=>W(r,(e=>e.current===o)).bind((o=>o.current(e,t,n,o.next).orThunk((()=>o.fallback.bind((o=>Wl(e,t,o,n))))))),Ll=(e,t,o,n,r,s)=>Wl(e,t,n,r).bind((t=>s(t.item)?C.none():o(t.item)?C.some(t.item):Ll(e,t.item,o,t.mode,r,s))),Ml=(e,t)=>({element:e,offset:t}),jl=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>jl(e,t,o).orThunk((()=>C.some(t))))):C.none(),Pl=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,Il=(e,t)=>{const o=jl(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return Ml(o,Pl(e,o));const n=e.property().children(o);return n.length>0?Il(e,n[n.length-1]):Ml(o,Pl(e,o))},Fl=Il,Hl=El(),$l=e=>t=>0===e.property().children(t).length,Vl=(e,t,o,n)=>Ll(e,t,o,_l,{sibling:(e,t)=>e.query().prevSibling(t),first:e=>e.length>0?C.some(e[e.length-1]):C.none()},n),ql=(e,t,o,n)=>Ll(e,t,o,_l,{sibling:(e,t)=>e.query().nextSibling(t),first:e=>e.length>0?C.some(e[0]):C.none()},n),Ul=El(),Gl=(e,t)=>((e,t,o)=>Vl(e,t,$l(e),o))(Ul,e,t),Kl=(e,t)=>((e,t,o)=>ql(e,t,$l(e),o))(Ul,e,t),Yl=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","table","thead","tfoot","tbody","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],Jl=(e,t,o,n)=>{const r=t(e,o);return z(n,((o,n)=>{const r=t(e,n);return Ql(e,o,r)}),r)},Ql=(e,t,o)=>t.bind((t=>o.filter(b(e.eq,t)))),Xl=El(),Zl=(e,t)=>((e,t,o)=>o.length>0?((e,t,o,n)=>n(e,t,o[0],o.slice(1)))(e,t,o,Jl):C.none())(Xl,((t,o)=>e(o)),t),ea=El(),ta=e=>((e,t)=>{const o=e.property().name(t);return D(Yl,o)})(ea,e),oa=e=>((e,t)=>{const o=e.property().name(t);return D(["ol","ul"],o)})(ea,e),na=e=>{const t=It("br"),o=e=>Tn(e).bind((o=>{const n=Gt(o).map((e=>!!ta(e)||!!((e,t)=>D(["br","img","hr","input"],e.property().name(t)))(ea,e)&&"img"!==Bt(e))).getOr(!1);return $t(o).map((r=>{return!0===n||("li"===Bt(s=r)||on(s,oa).isSome())||t(o)||ta(r)&&!Je(e,r)?[]:[Le.fromTag("br")];var s}))})).getOr([]),n=(()=>{const n=j(e,(e=>{const n=Kt(e);return(e=>P(e,(e=>t(e)||Mt(e)&&0===Jo(e).trim().length)))(n)?[]:n.concat(o(e))}));return 0===n.length?[Le.fromTag("br")]:n})();vo(e[0]),mo(e[0],n)},ra=e=>{bo(e,"width"),bo(e,"height")},sa=e=>{const t=xs(e);Tl(e,C.some(t),C.none()),ra(e)},la=e=>{const t=(e=>Fo(e)+"px")(e);Tl(e,C.some(t),C.none()),ra(e)},aa=e=>{Ao(e,"width");const t=cr(e),o=t.length>0?t:ar(e);N(o,(e=>{Ao(e,"width"),ra(e)})),ra(e)},ca={scope:["row","col"]},ia=e=>()=>{const t=Le.fromTag("td",e.dom);return ao(t,Le.fromTag("br",e.dom)),t},ma=e=>()=>Le.fromTag("col",e.dom),da=e=>()=>Le.fromTag("colgroup",e.dom),ua=e=>()=>Le.fromTag("tr",e.dom),fa=(e,t,o)=>{const n=((e,t)=>{const o=Ro(e,t),n=Kt(To(e));return mo(o,n),o})(e,t);return G(o,((e,t)=>{null===e?bo(n,t):fo(n,t,e)})),n},ga=e=>e,ha=(e,t,o)=>{const n=(e,t)=>{((e,t)=>{const o=e.dom,n=t.dom;Do(o)&&Do(n)&&(n.style.cssText=o.style.cssText)})(e.element,t),Ao(t,"height"),1!==e.colspan&&Ao(t,"width")};return{col:o=>{const r=Le.fromTag(Bt(o.element),t.dom);return n(o,r),e(o.element,r),r},colgroup:da(t),row:ua(t),cell:r=>{const s=Le.fromTag(Bt(r.element),t.dom),l=o.getOr(["strong","em","b","i","span","font","h1","h2","h3","h4","h5","h6","p","div"]),a=l.length>0?((e,t,o)=>Sn(e).map((n=>{const r=o.join(","),s=bn(n,r,(t=>Je(t,e)));return z(s,((e,t)=>{const o=So(t);return ao(e,o),o}),t)})).getOr(t))(r.element,s,l):s;return ao(a,Le.fromTag("br")),n(r,s),((e,t)=>{G(ca,((o,n)=>po(e,n).filter((e=>D(o,e))).each((e=>fo(t,n,e)))))})(r.element,s),e(r.element,s),s},replace:fa,colGap:ma(t),gap:ia(t)}},pa=e=>({col:ma(e),colgroup:da(e),row:ua(e),cell:ia(e),replace:ga,colGap:ma(e),gap:ia(e)}),ba=e=>Dr(e).grid,wa=(e,t,o,n)=>{const r=ze(e).rows;let s=!0;for(let e=0;e({rowDelta:0,colDelta:_e(e[0])-_e(t[0])}),ya=(e,t)=>({rowDelta:e.length-t.length,colDelta:0}),xa=(e,t,o,n)=>{const r="colgroup"===t.section?o.col:o.cell;return k(e,(e=>Te(r(),!0,n(e))))},Ca=(e,t,o,n)=>{const r=e[e.length-1];return e.concat(k(t,(()=>{const e="colgroup"===r.section?o.colgroup:o.row,t=Ae(r,e,h),s=xa(t.cells.length,t,o,(e=>X(n,e.toString())));return Ee(t,s)})))},Sa=(e,t,o,n)=>E(e,(e=>{const r=xa(t,e,o,y);return De(e,n,r)})),Ta=(e,t,o)=>{const n=t.colDelta<0?Sa:h,r=t.rowDelta<0?Ca:h,s=Cr(e),l=_e(e[0]),a=O(s,(e=>e===l-1)),c=n(e,Math.abs(t.colDelta),o,a?l-1:l),i=Cr(c);return r(c,Math.abs(t.rowDelta),o,I(i,x))},Ra=(e,t,o,n)=>{const r=b(n,Ne(e[t],o).element),s=e[t];return e.length>1&&_e(s)>1&&(o>0&&r(Be(s,o-1))||o0&&r(Be(e[t-1],o))||t_(o,(o=>o>=e.column&&o<=_e(t[0])+e.column)),Oa=(e,t,o,n,r)=>{((e,t,o,n)=>{t>0&&t{const r=e.cells[t-1];let s=0;const l=n();for(;e.cells.length>t+s&&o(r.element,e.cells[t+s].element);)ke(e,t+s,Te(l,!0,e.cells[t+s].isLocked)),s++}))})(t,e,r,n.cell);const s=ya(o,t),l=Ta(o,s,n),a=ya(t,l),c=Ta(t,a,n);return E(c,((t,o)=>De(t,e,l[o].cells)))},ka=(e,t,o,n,r)=>{((e,t,o,n)=>{const r=ze(e).rows;if(t>0&&tA(e,((e,o)=>O(e,(e=>t(e.element,o.element)))?e:e.concat([o])),[]))(r[t-1].cells,o);N(e,(e=>{let s=C.none();for(let l=t;l{ke(a,t,Te(e,!0,c.isLocked))})))}}))}})(t,e,r,n.cell);const s=Cr(t),l=va(t,o),a={...l,colDelta:l.colDelta-s.length},c=Ta(t,a,n),{cols:i,rows:m}=ze(c),d=Cr(c),u=va(o,t),f={...u,colDelta:u.colDelta+d.length},g=(p=n,b=d,E(o,(e=>A(b,((t,o)=>{const n=xa(1,e,p,x)[0];return Oe(t,o,n)}),e)))),h=Ta(g,f,n);var p,b;return[...i,...m.slice(0,e),...h,...m.slice(e,m.length)]},Ea=(e,t,o,n,r)=>{const{rows:s,cols:l}=ze(e),a=s.slice(0,t),c=s.slice(t);return[...l,...a,((e,t,o,n)=>Ae(e,(e=>n(e,o)),t))(s[o],((e,o)=>t>0&&tE(e,(e=>{const s=t>0&&t<_e(e)&&n(Be(e,t-1),Be(e,t)),l=((e,t,o,n,r,s,l)=>{if("colgroup"!==o&&n)return Ne(e,t);{const t=Ne(e,r);return Te(l(t.element,s),!0,!1)}})(e,t,e.section,s,o,n,r);return Oe(e,t,l)})),Ba=(e,t,o,n)=>((e,t,o,n)=>void 0!==Be(e[t],o)&&t>0&&n(Be(e[t-1],o),Be(e[t],o)))(e,t,o,n)||((e,t,o)=>t>0&&o(Be(e,t-1),Be(e,t)))(e[t],o,n),_a=(e,t,o,n)=>{const r=e=>(e=>"row"===e?(e=>Zn(e,"rowspan")>1)(t):er(t))(e)?`${e}group`:e;return e?ur(t)?r(o):null:n&&ur(t)?r("row"===o?"col":"row"):null},za=(e,t,o)=>Te(o(e.element,t),!0,e.isLocked),Aa=(e,t,o,n,r,s,l)=>E(e,((e,a)=>(e=>{const c=e.cells,i=E(c,((e,c)=>{if((e=>O(t,(t=>o(e.element,t.element))))(e)){const t=l(e,a,c)?r(e,o,n):e;return s(t,a,c).each((e=>{var o,n;o=t.element,n={scope:C.from(e)},G(n,((e,t)=>{e.fold((()=>{bo(o,t)}),(e=>{uo(o.dom,t,e)}))}))})),t}return e}));return Re(e.element,i,e.section,e.isNew)})(e))),Wa=(e,t,o)=>j(e,((n,r)=>Ba(e,r,t,o)?[]:[Ne(n,t)])),La=(e,t,o,n,r)=>{const s=ze(e).rows,l=j(t,(e=>Wa(s,e,n))),a=E(s,(e=>fr(e.cells))),c=((e,t)=>P(t,h)&&fr(e)?x:(e,o,n)=>!("th"===Bt(e.element)&&t[o]))(l,a),i=((e,t)=>(o,n)=>C.some(_a(e,o.element,"row",t[n])))(o,a);return Aa(e,l,n,r,za,i,c)},Ma=(e,t,o,n)=>{const r=ze(e).rows,s=E(t,(e=>Ne(r[e.row],e.column)));return Aa(e,s,o,n,za,C.none,x)},ja=e=>A(e,((e,t)=>O(e,(e=>e.column===t.column))?e:e.concat([t])),[]).sort(((e,t)=>e.column-t.column)),Pa=e=>gn(e,!0),Ia=e=>{0===ar(e).length&&yo(e)},Fa=(e,t)=>({grid:e,cursor:t}),Ha=(e,t,o)=>{const n=((e,t,o)=>{var n,r;const s=ze(e).rows;return C.from(null===(r=null===(n=s[t])||void 0===n?void 0:n.cells[o])||void 0===r?void 0:r.element).filter(Pa).orThunk((()=>(e=>V(e,(e=>V(e.cells,(e=>{const t=e.element;return de(Pa(t),t)})))))(s)))})(e,t,o);return Fa(e,n)},$a=e=>A(e,((e,t)=>O(e,(e=>e.row===t.row))?e:e.concat([t])),[]).sort(((e,t)=>e.row-t.row)),Va=(e,t,o,n)=>{const r=t[0].row,s=$a(t),l=z(s,((e,t)=>({grid:Ea(e.grid,r,t.row+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Ha(l,r,t[0].column)},qa=(e,t,o,n)=>{const r=$a(t),s=r[r.length-1],l=s.row+s.rowspan,a=z(r,((e,t)=>Ea(e,l,t.row,o,n.getOrInit)),e);return Ha(a,l,t[0].column)},Ua=(e,t,o,n)=>{const r=t.details,s=ja(r),l=s[0].column,a=z(s,((e,t)=>({grid:Na(e.grid,l,t.column+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Ha(a,r[0].row,l)},Ga=(e,t,o,n)=>{const r=t.details,s=r[r.length-1],l=s.column+s.colspan,a=ja(r),c=z(a,((e,t)=>Na(e,l,t.column,o,n.getOrInit)),e);return Ha(c,r[0].row,l)},Ka=(e,t,o,n)=>{const r=ja(t),s=E(r,(e=>e.column)),l=La(e,s,!0,o,n.replaceOrInit);return Ha(l,t[0].row,t[0].column)},Ya=(e,t,o,n)=>{const r=Ma(e,t,o,n.replaceOrInit);return Ha(r,t[0].row,t[0].column)},Ja=(e,t,o,n)=>{const r=ja(t),s=E(r,(e=>e.column)),l=La(e,s,!1,o,n.replaceOrInit);return Ha(l,t[0].row,t[0].column)},Qa=(e,t,o,n)=>{const r=Ma(e,t,o,n.replaceOrInit);return Ha(r,t[0].row,t[0].column)},Xa=(e,t)=>(o,n,r,s,l)=>{const a=$a(n),c=E(a,(e=>e.row)),i=((e,t,o,n,r,s,l)=>{const{cols:a,rows:c}=ze(e),i=c[t[0]],m=j(t,(e=>((e,t,o)=>{const n=e[t];return j(n.cells,((n,r)=>Ba(e,t,r,o)?[]:[n]))})(c,e,r))),d=E(i.cells,((e,t)=>fr(Wa(c,t,r)))),u=[...c];N(t,(e=>{u[e]=l.transformRow(c[e],o)}));const f=[...a,...u],g=((e,t)=>P(t,h)&&fr(e.cells)?x:(e,o,n)=>!("th"===Bt(e.element)&&t[n]))(i,d),p=((e,t)=>(o,n,r)=>C.some(_a(e,o.element,"col",t[r])))(n,d);return Aa(f,m,r,s,l.transformCell,p,g)})(o,c,e,t,r,s.replaceOrInit,l);return Ha(i,n[0].row,n[0].column)},Za=Xa("thead",!0),ec=Xa("tbody",!1),tc=Xa("tfoot",!1),oc=(e,t,o,n)=>{const r=ja(t.details),s=((e,t)=>j(e,(e=>{const o=e.cells,n=z(t,((e,t)=>t>=0&&t0?[Re(e.element,n,e.section,e.isNew)]:[]})))(e,E(r,(e=>e.column))),l=s.length>0?s[0].cells.length-1:0;return Ha(s,r[0].row,Math.min(r[0].column,l))},nc=(e,t,o,n)=>{const r=$a(t),s=((e,t,o)=>{const{rows:n,cols:r}=ze(e);return[...r,...n.slice(0,t),...n.slice(o+1)]})(e,r[0].row,r[r.length-1].row),l=Math.max(ze(s).rows.length-1,0);return Ha(s,Math.min(t[0].row,l),t[0].column)},rc=(e,t,o,n)=>{const r=t.cells;na(r);const s=((e,t,o,n)=>{const r=ze(e).rows;if(0===r.length)return e;for(let e=t.startRow;e<=t.finishRow;e++)for(let o=t.startCol;o<=t.finishCol;o++){const t=r[e],s=Ne(t,o).isLocked;ke(t,o,Te(n(),!1,s))}return e})(e,t.bounds,0,n.merge(r));return Fa(s,C.from(r[0]))},sc=(e,t,o,n)=>{const r=z(t,((e,t)=>wa(e,t,o,n.unmerge(t))),e);return Fa(r,C.from(t[0]))},lc=(e,t,o,n)=>{const r=((e,t)=>{const o=Dr(e);return Hs(o,t,!0)})(t.clipboard,t.generators);var s,l;return((e,t,o,n,r)=>{const s=Cr(t),l=((e,t,o)=>{const n=_e(t[0]),r=ze(t).cols.length+e.row,s=k(n-e.column,(t=>t+e.column));return{row:r,column:W(s,(e=>P(o,(t=>t!==e)))).getOr(n-1)}})(e,t,s),a=ze(o).rows,c=Da(l,a,s),i=((e,t,o)=>{if(e.row>=t.length||e.column>_e(t[0]))return le.error("invalid start address out of table bounds, row: "+e.row+", column: "+e.column);const n=t.slice(e.row),r=n[0].cells.slice(e.column),s=_e(o[0]),l=o.length;return le.value({rowDelta:n.length-l,colDelta:r.length-s})})(l,t,a);return i.map((e=>{const o={...e,colDelta:e.colDelta-c.length},s=Ta(t,o,n),i=Cr(s),m=Da(l,a,i);return((e,t,o,n,r,s)=>{const l=e.row,a=e.column,c=l+o.length,i=a+_e(o[0])+s.length,m=I(s,x);for(let e=l;eFa(e,C.some(t.element))),(e=>Ha(e,t.row,t.column)))},ac=(e,t,o)=>{const n=((e,t)=>br(e,(()=>t)))(e,o.section),r=Or(n);return Hs(r,t,!0)},cc=(e,t,o,n)=>{const r=ze(e).rows,s=t.cells[0].column,l=r[t.cells[0].row],a=ac(t.clipboard,t.generators,l),c=Oa(s,e,a,t.generators,o);return Ha(c,t.cells[0].row,t.cells[0].column)},ic=(e,t,o,n)=>{const r=ze(e).rows,s=t.cells[t.cells.length-1].column+t.cells[t.cells.length-1].colspan,l=r[t.cells[0].row],a=ac(t.clipboard,t.generators,l),c=Oa(s,e,a,t.generators,o);return Ha(c,t.cells[0].row,s)},mc=(e,t,o,n)=>{const r=ze(e).rows,s=t.cells[0].row,l=r[s],a=ac(t.clipboard,t.generators,l),c=ka(s,e,a,t.generators,o);return Ha(c,t.cells[0].row,t.cells[0].column)},dc=(e,t,o,n)=>{const r=ze(e).rows,s=t.cells[t.cells.length-1].row+t.cells[t.cells.length-1].rowspan,l=r[t.cells[0].row],a=ac(t.clipboard,t.generators,l),c=ka(s,e,a,t.generators,o);return Ha(c,s,t.cells[0].column)},uc=(e,t,o,n)=>((e,t,o,n)=>{const r=Or(t),s=n.getWidths(r,n);tl(r,s,n)})(0,t,0,n.sizing),fc=(e,t,o,n)=>((e,t,o,n,r)=>{const s=Or(t),l=n.getWidths(s,n),a=n.pixelWidth(),{newSizes:c,delta:i}=r.calcRedestributedWidths(l,a,o.pixelDelta,n.isRelative);tl(s,c,n),n.adjustTableWidth(i)})(0,t,o,n.sizing,n.resize),gc=(e,t)=>O(t,(e=>0===e.column&&e.isLocked)),hc=(e,t)=>O(t,(t=>t.column+t.colspan>=e.grid.columns&&t.isLocked)),pc=(e,t)=>{const o=Vr(e),n=ja(t);return A(n,((e,t)=>e+o[t.column].map(Ho).getOr(0)),0)},bc=e=>(t,o)=>Ys(t,o).filter((o=>!(e?gc:hc)(t,o))).map((e=>({details:e,pixelDelta:pc(t,e)}))),wc=(e,t)=>Js(e,t).map((t=>({details:t,pixelDelta:-pc(e,t)}))),vc=e=>(t,o)=>Ks(t,o).filter((o=>!(e?gc:hc)(t,o.cells))),yc=gl("th"),xc=gl("td"),Cc=(e,t,o,n)=>Us(Va,Ys,f,f,fl,e,t,o,n),Sc=(e,t,o,n)=>Us(qa,Ys,f,f,fl,e,t,o,n),Tc=(e,t,o,n)=>Us(Ua,bc(!0),fc,f,fl,e,t,o,n),Rc=(e,t,o,n)=>Us(Ga,bc(!1),fc,f,fl,e,t,o,n),Dc=(e,t,o,n)=>Us(oc,wc,fc,Ia,fl,e,t,o,n),Oc=(e,t,o,n)=>Us(nc,Ys,f,Ia,fl,e,t,o,n),kc=(e,t,o,n)=>Us(Ka,Js,f,f,yc,e,t,o,n),Ec=(e,t,o,n)=>Us(Ja,Js,f,f,xc,e,t,o,n),Nc=(e,t,o,n)=>Us(Za,Ys,f,f,yc,e,t,o,n),Bc=(e,t,o,n)=>Us(ec,Ys,f,f,xc,e,t,o,n),_c=(e,t,o,n)=>Us(tc,Ys,f,f,xc,e,t,o,n),zc=(e,t,o,n)=>Us(Ya,Js,f,f,yc,e,t,o,n),Ac=(e,t,o,n)=>Us(Qa,Js,f,f,xc,e,t,o,n),Wc=(e,t,o,n)=>Us(rc,Xs,uc,f,hl,e,t,o,n),Lc=(e,t,o,n)=>Us(sc,Zs,uc,f,hl,e,t,o,n),Mc=(e,t,o,n)=>Us(lc,Gs,uc,f,fl,e,t,o,n),jc=(e,t,o,n)=>Us(cc,vc(!0),f,f,fl,e,t,o,n),Pc=(e,t,o,n)=>Us(ic,vc(!1),f,f,fl,e,t,o,n),Ic=(e,t,o,n)=>Us(mc,Ks,f,f,fl,e,t,o,n),Fc=(e,t,o,n)=>Us(dc,Ks,f,f,fl,e,t,o,n),Hc=(e,t)=>{const o=Dr(e);return Ys(o,t).bind((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=M(E(o.all,(e=>_(e.cells,(e=>e.column>=n&&e.column{const o=Dr(e);return Ys(o,t).bind(pr).getOr("")},Vc=(e,t)=>{const o=Dr(e);return Ys(o,t).bind((e=>{const t=e[e.length-1],n=e[0].row,r=t.row+t.rowspan;return(e=>{const t=E(e,(e=>hr(e).type)),o=D(t,"header"),n=D(t,"footer");if(o||n){const e=D(t,"body");return!o||e||n?o||e||!n?C.none():C.some("footer"):C.some("header")}return C.some("body")})(o.all.slice(n,r))})).getOr("")},qc=(e,t)=>{const o=t.column,n=t.column+t.colspan-1,r=t.row,s=t.row+t.rowspan-1;return o<=e.finishCol&&n>=e.startCol&&r<=e.finishRow&&s>=e.startRow},Uc=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,Gc=(e,t,o)=>{const n=Er(e,t,Je),r=Er(e,o,Je);return n.bind((e=>r.map((t=>{return o=e,n=t,{startRow:Math.min(o.row,n.row),startCol:Math.min(o.column,n.column),finishRow:Math.max(o.row+o.rowspan-1,n.row+n.rowspan-1),finishCol:Math.max(o.column+o.colspan-1,n.column+n.colspan-1)};var o,n}))))},Kc=(e,t,o)=>Gc(e,t,o).map((t=>{const o=Nr(e,b(qc,t));return E(o,(e=>e.element))})),Yc=(e,t)=>Er(e,t,((e,t)=>Qe(t,e))).map((e=>e.element)),Jc=(e,t,o)=>{const n=Xc(e);return Kc(n,t,o)},Qc=(e,t,o,n,r)=>{const s=Xc(e),l=Je(e,o)?C.some(t):Yc(s,t),a=Je(e,r)?C.some(n):Yc(s,n);return l.bind((e=>a.bind((t=>Kc(s,e,t)))))},Xc=Dr,Zc={styles:{"border-collapse":"collapse",width:"100%"},attributes:{border:"1"},colGroups:!1},ei=(e,t,o,n)=>k(e,(e=>((e,t,o,n)=>{const r=Le.fromTag("tr");for(let s=0;s{let t=[];return{bind:e=>{if(void 0===e)throw new Error("Event bind error: undefined handler");t.push(e)},unbind:e=>{t=_(t,(t=>t!==e))},trigger:(...o)=>{const n={};N(e,((e,t)=>{n[e]=o[t]})),N(t,(e=>{e(n)}))}}},oi=e=>({registry:K(e,(e=>({bind:e.bind,unbind:e.unbind}))),trigger:K(e,(e=>e.trigger))}),ni=ne(["compare","extract","mutate","sink"]),ri=ne(["element","start","stop","destroy"]),si=ne(["forceDrop","drop","move","delayDrop"]),li=()=>{const e=(()=>{const e=oi({move:ti(["info"])});return{onEvent:f,reset:f,events:e.registry}})(),t=(()=>{let e=C.none();const t=oi({move:ti(["info"])});return{onEvent:(o,n)=>{n.extract(o).each((o=>{const r=((t,o)=>{const n=e.map((e=>t.compare(e,o)));return e=C.some(o),n})(n,o);r.each((e=>{t.trigger.move(e)}))}))},reset:()=>{e=C.none()},events:t.registry}})();let o=e;return{on:()=>{o.reset(),o=t},off:()=>{o.reset(),o=e},isOn:()=>o===t,onEvent:(e,t)=>{o.onEvent(e,t)},events:t.events}},ai=ce("ephox-dragster").resolve;var ci=ni({compare:(e,t)=>qo(t.left-e.left,t.top-e.top),extract:e=>C.some(qo(e.x,e.y)),sink:(e,t)=>{const o=(e=>{const t={layerClass:ai("blocker"),...e},o=Le.fromTag("div");return fo(o,"role","presentation"),No(o,{position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),dn(o,ai("blocker")),dn(o,t.layerClass),{element:g(o),destroy:()=>{yo(o)}}})(t),n=oo(o.element(),"mousedown",e.forceDrop),r=oo(o.element(),"mouseup",e.drop),s=oo(o.element(),"mousemove",e.move),l=oo(o.element(),"mouseout",e.delayDrop);return ri({element:o.element,start:e=>{ao(e,o.element())},stop:()=>{yo(o.element())},destroy:()=>{o.destroy(),r.unbind(),s.unbind(),l.unbind(),n.unbind()}})},mutate:(e,t)=>{e.mutate(t.left,t.top)}});const ii=ce("ephox-snooker").resolve,mi=ii("resizer-bar"),di=ii("resizer-rows"),ui=ii("resizer-cols"),fi=e=>{const t=vn(e.parent(),"."+mi);N(t,yo)},gi=(e,t,o)=>{const n=e.origin();N(t,(t=>{t.each((t=>{const r=o(n,t);dn(r,mi),ao(e.parent(),r)}))}))},hi=(e,t,o,n,r)=>{const s=Go(o),l=t.isResizable,a=n.length>0?ns.positions(n,o):[],c=a.length>0?((e,t)=>j(e.all,((e,o)=>t(e.element)?[o]:[])))(e,l):[];((e,t,o,n)=>{gi(e,t,((e,t)=>{const r=((e,t,o,n)=>{const r=Le.fromTag("div");return No(r,{position:"absolute",left:t+"px",top:o-3.5+"px",height:"7px",width:n+"px"}),go(r,{"data-mce-bogus":"all","data-row":e,role:"presentation"}),r})(t.row,o.left-e.left,t.y-e.top,n);return dn(r,di),r}))})(t,_(a,((e,t)=>O(c,(e=>t===e)))),s,Ho(o));const i=r.length>0?ss.positions(r,o):[],m=i.length>0?((e,t)=>{const o=[];return k(e.grid.columns,(n=>{Ar(e,n).map((e=>e.element)).forall(t)&&o.push(n)})),_(o,(o=>{const n=Nr(e,(e=>e.column===o));return P(n,(e=>t(e.element)))}))})(e,l):[];((e,t,o,n)=>{gi(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=Le.fromTag("div");return No(s,{position:"absolute",left:t-3.5+"px",top:o+"px",height:r+"px",width:"7px"}),go(s,{"data-mce-bogus":"all","data-column":e,role:"presentation"}),s})(t.col,t.x-e.left,o.top-e.top,0,n);return dn(r,ui),r}))})(t,_(i,((e,t)=>O(m,(e=>t===e)))),s,Po(o))},pi=(e,t)=>{if(fi(e),e.isResizable(t)){const o=Dr(t),n=Ur(o),r=Vr(o);hi(o,e,t,n,r)}},bi=(e,t)=>{const o=vn(e.parent(),"."+mi);N(o,t)},wi=e=>{bi(e,(e=>{Eo(e,"display","none")}))},vi=e=>{bi(e,(e=>{Eo(e,"display","block")}))},yi=ii("resizer-bar-dragging"),xi=e=>{const t=(()=>{const e=oi({drag:ti(["xDelta","yDelta","target"])});let t=C.none();const o=(()=>{const e=oi({drag:ti(["xDelta","yDelta"])});return{mutate:(t,o)=>{e.trigger.drag(t,o)},events:e.registry}})();return o.events.drag.bind((o=>{t.each((t=>{e.trigger.drag(o.xDelta,o.yDelta,t)}))})),{assign:e=>{t=C.some(e)},get:()=>t,mutate:o.mutate,events:e.registry}})(),o=((e,t={})=>{var o;return((e,t,o)=>{let n=!1;const r=oi({start:ti([]),stop:ti([])}),s=li(),l=()=>{m.stop(),s.isOn()&&(s.off(),r.trigger.stop())},c=(e=>{let t=null;const o=()=>{a(t)||(clearTimeout(t),t=null)};return{cancel:o,throttle:(...n)=>{o(),t=setTimeout((()=>{t=null,e.apply(null,n)}),200)}}})(l);s.events.move.bind((o=>{t.mutate(e,o.info)}));const i=e=>(...t)=>{n&&e.apply(null,t)},m=t.sink(si({forceDrop:l,drop:i(l),move:i((e=>{c.cancel(),s.onEvent(e,t)})),delayDrop:i(c.throttle)}),o);return{element:m.element,go:e=>{m.start(e),s.on(),r.trigger.start()},on:()=>{n=!0},off:()=>{n=!1},isActive:()=>n,destroy:()=>{m.destroy()},events:r.registry}})(e,null!==(o=t.mode)&&void 0!==o?o:ci,t)})(t,{});let n=C.none();const r=(e,t)=>C.from(ho(e,t));t.events.drag.bind((e=>{r(e.target,"data-row").each((t=>{const o=tr(e.target,"top");Eo(e.target,"top",o+e.yDelta+"px")})),r(e.target,"data-column").each((t=>{const o=tr(e.target,"left");Eo(e.target,"left",o+e.xDelta+"px")}))}));const s=(e,t)=>tr(e,t)-Xn(e,"data-initial-"+t,0);o.events.stop.bind((()=>{t.get().each((t=>{n.each((o=>{r(t,"data-row").each((e=>{const n=s(t,"top");bo(t,"data-initial-top"),d.trigger.adjustHeight(o,n,parseInt(e,10))})),r(t,"data-column").each((e=>{const n=s(t,"left");bo(t,"data-initial-left"),d.trigger.adjustWidth(o,n,parseInt(e,10))})),pi(e,o)}))}))}));const l=(n,r)=>{d.trigger.startAdjust(),t.assign(n),fo(n,"data-initial-"+r,tr(n,r)),dn(n,yi),Eo(n,"opacity","0.2"),o.go(e.dragContainer())},c=oo(e.parent(),"mousedown",(e=>{var t;t=e.target,un(t,di)&&l(e.target,"top"),(e=>un(e,ui))(e.target)&&l(e.target,"left")})),i=t=>Je(t,e.view()),m=oo(e.view(),"mouseover",(t=>{var r;(r=t.target,an(r,"table",i).filter(gn)).fold((()=>{Oo(t.target)&&!(e=>un(e,"ephox-snooker-resizer-bar")||un(e,"ephox-dragster-blocker"))(t.target)&&fi(e)}),(t=>{o.isActive()&&(n=C.some(t),pi(e,t))}))})),d=oi({adjustHeight:ti(["table","delta","row"]),adjustWidth:ti(["table","delta","column"]),startAdjust:ti([])});return{destroy:()=>{c.unbind(),m.unbind(),o.destroy(),fi(e)},refresh:t=>{pi(e,t)},on:o.on,off:o.off,hideBars:b(wi,e),showBars:b(vi,e),events:d.registry}},Ci=e=>t=>t.options.get(e),Si="100%",Ti=e=>{var t;const o=e.dom,n=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return $o(Le.fromDom(n))+"px"},Ri=e=>C.from(e.options.get("table_clone_elements")),Di=Ci("table_header_type"),Oi=Ci("table_column_resizing"),ki=e=>"preservetable"===Oi(e),Ei=e=>"resizetable"===Oi(e),Ni=Ci("table_sizing_mode"),Bi=e=>"relative"===Ni(e),_i=e=>"fixed"===Ni(e),zi=e=>"responsive"===Ni(e),Ai=Ci("table_resize_bars"),Wi=Ci("table_style_by_css"),Li=Ci("table_merge_content_on_paste"),Mi=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>zi(e)||Wi(e)?t:_i(e)?{...t,width:Ti(e)}:{...t,width:Si})(e,o)},ji=Ci("table_use_colgroups"),Pi=e=>Le.fromDom(e.getBody()),Ii=e=>t=>Je(t,Pi(e)),Fi=e=>{bo(e,"data-mce-style");const t=e=>bo(e,"data-mce-style");N(ar(e),t),N(cr(e),t),N(mr(e),t)},Hi=e=>Le.fromDom(e.selection.getStart()),$i=e=>e.getBoundingClientRect().width,Vi=e=>e.getBoundingClientRect().height,qi=e=>(t,o)=>{const n=t.dom.getStyle(o,e)||t.dom.getAttrib(o,e);return C.from(n).filter(ve)},Ui=qi("width"),Gi=qi("height"),Ki=e=>nn(e,It("table")).exists(gn),Yi=e=>rn(e,"table"),Ji=(e,t,o)=>{const n=e=>t=>void 0!==o&&o(t)||Je(t,e);return Je(e,t)?C.some({boxes:C.some([e]),start:e,finish:t}):Yi(e).bind((r=>Yi(t).bind((s=>{if(Je(r,s))return C.some({boxes:Jc(r,e,t),start:e,finish:t});if(Qe(r,s)){const o=bn(t,"td,th",n(r)),l=o.length>0?o[o.length-1]:t;return C.some({boxes:Qc(r,e,r,t,s),start:e,finish:l})}if(Qe(s,r)){const o=bn(e,"td,th",n(s)),l=o.length>0?o[o.length-1]:e;return C.some({boxes:Qc(s,e,r,t,s),start:e,finish:l})}return((e,t)=>((e,t,o,n=y)=>{const r=[t].concat(e.up().all(t)),s=[o].concat(e.up().all(o)),l=e=>L(e,n).fold((()=>e),(t=>e.slice(0,t+1))),a=l(r),c=l(s),i=W(a,(t=>O(c,((e,t)=>b(e.eq,t))(e,t))));return{firstpath:a,secondpath:c,shared:i}})(Xl,e,t,void 0))(e,t).shared.bind((l=>an(l,"table",o).bind((o=>{const l=bn(t,"td,th",n(o)),a=l.length>0?l[l.length-1]:t,c=bn(e,"td,th",n(o)),i=c.length>0?c[c.length-1]:e;return C.some({boxes:Qc(o,e,r,t,s),start:i,finish:a})}))))}))))},Qi=(e,t)=>{const o=vn(e,t);return o.length>0?C.some(o):C.none()},Xi=(e,t,o)=>ln(e,t).bind((t=>ln(e,o).bind((e=>Zl(Yi,[t,e]).map((o=>({first:t,last:e,table:o}))))))),Zi=(e,t,o,n,r)=>((e,t)=>W(e,(e=>Ge(e,t))))(e,r).bind((e=>((e,t,o)=>ir(e).bind((n=>((e,t,o,n)=>Er(e,t,Je).bind((t=>{const r=o>0?t.row+t.rowspan-1:t.row,s=n>0?t.column+t.colspan-1:t.column;return kr(e,r+o,s+n).map((e=>e.element))})))(Xc(n),e,t,o))))(e,t,o).bind((e=>((e,t)=>rn(e,"table").bind((o=>ln(o,t).bind((t=>Ji(t,e).bind((e=>e.boxes.map((t=>({boxes:t,start:e.start,finish:e.finish}))))))))))(e,n))))),em=(e,t)=>Qi(e,t),tm=(e,t,o)=>Xi(e,t,o).bind((t=>{const o=t=>Je(e,t),n="thead,tfoot,tbody,table",r=rn(t.first,n,o),s=rn(t.last,n,o);return r.bind((e=>s.bind((o=>Je(e,o)?((e,t,o)=>((e,t,o)=>Gc(e,t,o).bind((t=>((e,t)=>{let o=!0;const n=b(Uc,t);for(let r=t.startRow;r<=t.finishRow;r++)for(let s=t.startCol;s<=t.finishCol;s++)o=o&&kr(e,r,s).exists(n);return o?C.some(t):C.none()})(e,t))))(Xc(e),t,o))(t.table,t.first,t.last):C.none()))))})),om=h,nm=e=>{const t=(e,t)=>po(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&P(e,(e=>t(e,"rowspan")||t(e,"colspan")))?C.some(e):C.none()},rm=(e,t,o)=>t.length<=1?C.none():tm(e,o.firstSelectedSelector,o.lastSelectedSelector).map((e=>({bounds:e,cells:t}))),sm=(e,t)=>({selection:e,kill:t}),lm=()=>({tag:"none"}),am=e=>({tag:"multiple",elements:e}),cm=e=>({tag:"single",element:e}),im=(e,t,o,n)=>({start:kn.on(e,t),finish:kn.on(o,n)}),mm=(e,t)=>{const o=Ue(e,t);return Dn(Le.fromDom(o.startContainer),o.startOffset,Le.fromDom(o.endContainer),o.endOffset)},dm=im,um=(e,t,o,n,r)=>Je(o,n)?C.none():Ji(o,n,t).bind((t=>{const n=t.boxes.getOr([]);return n.length>1?(r(e,n,t.start,t.finish),C.some(sm(C.some(dm(o,0,o,yn(o))),!0))):C.none()})),fm=Z([{none:["message"]},{success:[]},{failedUp:["cell"]},{failedDown:["cell"]}]),gm=e=>an(e,"tr"),hm={...fm,verify:(e,t,o,n,r,s,l)=>an(n,"td,th",l).bind((o=>an(t,"td,th",l).map((t=>Je(o,t)?Je(n,o)&&yn(o)===r?s(t):fm.none("in same cell"):Zl(gm,[o,t]).fold((()=>((e,t,o)=>{const n=e.getRect(t),r=e.getRect(o);return r.right>n.left&&r.lefts(t))))))).getOr(fm.none("default")),cata:(e,t,o,n,r)=>e.fold(t,o,n,r)},pm=It("br"),bm=(e,t,o)=>t(e,o).bind((e=>Mt(e)&&0===Jo(e).trim().length?bm(e,t,o):C.some(e))),wm=(e,t,o,n)=>((e,t)=>Yt(e,t).filter(pm).orThunk((()=>Yt(e,t-1).filter(pm))))(t,o).bind((t=>n.traverse(t).fold((()=>bm(t,n.gather,e).map(n.relative)),(e=>(e=>$t(e).bind((t=>{const o=Kt(t);return((e,t)=>L(e,b(Je,t)))(o,e).map((n=>((e,t,o,n)=>({parent:e,children:t,element:o,index:n}))(t,o,e,n)))})))(e).map((e=>kn.on(e.parent,e.index))))))),vm=(e,t)=>({left:e.left,top:e.top+t,right:e.right,bottom:e.bottom+t}),ym=(e,t)=>({left:e.left,top:e.top-t,right:e.right,bottom:e.bottom-t}),xm=(e,t,o)=>({left:e.left+t,top:e.top+o,right:e.right+t,bottom:e.bottom+o}),Cm=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom}),Sm=(e,t)=>C.some(e.getRect(t)),Tm=(e,t,o)=>Lt(t)?Sm(e,t).map(Cm):Mt(t)?((e,t,o)=>o>=0&&o0?e.getRangedRect(t,o-1,t,o):C.none())(e,t,o).map(Cm):C.none(),Rm=(e,t)=>Lt(t)?Sm(e,t).map(Cm):Mt(t)?e.getRangedRect(t,0,t,yn(t)).map(Cm):C.none(),Dm=Z([{none:[]},{retry:["caret"]}]),Om=(e,t,o)=>nn(t,ta).fold(y,(t=>Rm(e,t).exists((e=>((e,t)=>e.leftt.right)(o,e))))),km={point:e=>e.bottom,adjuster:(e,t,o,n,r)=>{const s=vm(r,5);return Math.abs(o.bottom-n.bottom)<1||o.top>r.bottom?Dm.retry(s):o.top===r.bottom?Dm.retry(vm(r,1)):Om(e,t,r)?Dm.retry(xm(s,5,0)):Dm.none()},move:vm,gather:Kl},Em=(e,t,o,n,r)=>0===r?C.some(n):((e,t,o)=>e.elementFromPoint(t,o).filter((e=>"table"===Bt(e))).isSome())(e,n.left,t.point(n))?((e,t,o,n,r)=>Em(e,t,o,t.move(n,5),r))(e,t,o,n,r-1):e.situsFromPoint(n.left,t.point(n)).bind((s=>s.start.fold(C.none,(s=>Rm(e,s).bind((l=>t.adjuster(e,s,l,o,n).fold(C.none,(n=>Em(e,t,o,n,r-1))))).orThunk((()=>C.some(n)))),C.none))),Nm=(e,t,o)=>{const n=e.move(o,5),r=Em(t,e,o,n,100).getOr(n);return((e,t,o)=>e.point(t)>o.getInnerHeight()?C.some(e.point(t)-o.getInnerHeight()):e.point(t)<0?C.some(-e.point(t)):C.none())(e,r,t).fold((()=>t.situsFromPoint(r.left,e.point(r))),(o=>(t.scrollBy(0,o),t.situsFromPoint(r.left,e.point(r)-o))))},Bm={tryUp:b(Nm,{point:e=>e.top,adjuster:(e,t,o,n,r)=>{const s=ym(r,5);return Math.abs(o.top-n.top)<1||o.bottome.getSelection().bind((n=>((e,t,o,n)=>{const r=pm(t)?((e,t,o)=>o.traverse(t).orThunk((()=>bm(t,o.gather,e))).map(o.relative))(e,t,n):wm(e,t,o,n);return r.map((e=>({start:e,finish:e})))})(t,n.finish,n.foffset,o).fold((()=>C.some(Ml(n.finish,n.foffset))),(r=>{const s=e.fromSitus(r);return l=hm.verify(e,n.finish,n.foffset,s.finish,s.foffset,o.failure,t),hm.cata(l,(e=>C.none()),(()=>C.none()),(e=>C.some(Ml(e,0))),(e=>C.some(Ml(e,yn(e)))));var l})))),zm=(e,t,o,n,r,s)=>0===s?C.none():Lm(e,t,o,n,r).bind((l=>{const a=e.fromSitus(l),c=hm.verify(e,o,n,a.finish,a.foffset,r.failure,t);return hm.cata(c,(()=>C.none()),(()=>C.some(l)),(l=>Je(o,l)&&0===n?Am(e,o,n,ym,r):zm(e,t,l,0,r,s-1)),(l=>Je(o,l)&&n===yn(l)?Am(e,o,n,vm,r):zm(e,t,l,yn(l),r,s-1)))})),Am=(e,t,o,n,r)=>Tm(e,t,o).bind((t=>Wm(e,r,n(t,Bm.getJumpSize())))),Wm=(e,t,o)=>{const n=kt().browser;return n.isChromium()||n.isSafari()||n.isFirefox()?t.retry(e,o):C.none()},Lm=(e,t,o,n,r)=>Tm(e,o,n).bind((t=>Wm(e,r,t))),Mm=(e,t,o,n,r)=>an(n,"td,th",t).bind((n=>an(n,"table",t).bind((s=>((e,t)=>on(e,(e=>$t(e).exists((e=>Je(e,t)))),void 0).isSome())(r,s)?((e,t,o)=>_m(e,t,o).bind((n=>zm(e,t,n.element,n.offset,o,20).map(e.fromSitus))))(e,t,o).bind((e=>an(e.finish,"td,th",t).map((t=>({start:n,finish:t,range:e}))))):C.none())))),jm=(e,t,o,n,r,s)=>s(n,t).orThunk((()=>Mm(e,t,o,n,r).map((e=>{const t=e.range;return sm(C.some(dm(t.start,t.soffset,t.finish,t.foffset)),!0)})))),Pm=(e,t)=>an(e,"tr",t).bind((e=>an(e,"table",t).bind((o=>{const n=vn(o,"tr");return Je(e,n[0])?((e,t,o)=>Vl(Ul,e,(e=>Tn(e).isSome()),o))(o,0,t).map((e=>{const t=yn(e);return sm(C.some(dm(e,t,e,t)),!0)})):C.none()})))),Im=(e,t)=>an(e,"tr",t).bind((e=>an(e,"table",t).bind((o=>{const n=vn(o,"tr");return Je(e,n[n.length-1])?((e,t,o)=>ql(Ul,e,(e=>Sn(e).isSome()),o))(o,0,t).map((e=>sm(C.some(dm(e,0,e,0)),!0))):C.none()})))),Fm=(e,t,o,n,r,s,l)=>Mm(e,o,n,r,s).bind((e=>um(t,o,e.start,e.finish,l))),Hm=(e,t)=>an(e,"td,th",t),$m=e=>Vt(e).exists(gn),Vm={traverse:Gt,gather:Kl,relative:kn.before,retry:Bm.tryDown,failure:hm.failedDown},qm={traverse:Ut,gather:Gl,relative:kn.before,retry:Bm.tryUp,failure:hm.failedUp},Um=e=>t=>t===e,Gm=Um(38),Km=Um(40),Ym=e=>e>=37&&e<=40,Jm={isBackward:Um(37),isForward:Um(39)},Qm={isBackward:Um(39),isForward:Um(37)},Xm=e=>({elementFromPoint:(t,o)=>Le.fromPoint(Le.fromDom(e.document),t,o),getRect:e=>e.dom.getBoundingClientRect(),getRangedRect:(t,o,n,r)=>{const s=Nn.exact(t,o,n,r);return((e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?C.some(o).map(He):C.none()})(Ue(e,t)))(e,s)},getSelection:()=>Fn(e).map((t=>mm(e,t))),fromSitus:t=>{const o=Nn.relative(t.start,t.finish);return mm(e,o)},situsFromPoint:(t,o)=>Hn(e,t,o).map((e=>im(e.start,e.soffset,e.finish,e.foffset))),clearSelection:()=>{(e=>{_n(e).each((e=>e.removeAllRanges()))})(e)},collapseSelection:(t=!1)=>{Fn(e).each((o=>o.fold((e=>e.collapse(t)),((o,n)=>{const r=t?o:n;Mn(e,r,r)}),((o,n,r,s)=>{const l=t?o:r,a=t?n:s;Ln(e,l,a,l,a)}))))},setSelection:t=>{Ln(e,t.start,t.soffset,t.finish,t.foffset)},setRelativeSelection:(t,o)=>{Mn(e,t,o)},selectNode:t=>{In(e,t,!1)},selectContents:t=>{In(e,t)},getInnerHeight:()=>e.innerHeight,getScrollY:()=>(e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return qo(o,n)})(Le.fromDom(e.document)).top,scrollBy:(t,o)=>{((e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollBy(e,t)})(t,o,Le.fromDom(e.document))}}),Zm=(e,t)=>({rows:e,cols:t}),ed=e=>nn(e,Wt).exists(gn),td=(e,t)=>ed(e)||ed(t),od="data-mce-selected",nd="data-mce-first-selected",rd="data-mce-last-selected",sd="["+od+"]",ld={selected:od,selectedSelector:"td["+od+"],th["+od+"]",firstSelected:nd,firstSelectedSelector:"td["+nd+"],th["+nd+"]",lastSelected:rd,lastSelectedSelector:"td["+rd+"],th["+rd+"]"},ad=(e,t,o)=>({element:o,mergable:rm(t,e,ld),unmergable:nm(e),selection:om(e)}),cd=e=>(t,o)=>{const n=Bt(t),r="col"===n||"colgroup"===n?ir(s=t).bind((e=>em(e,ld.firstSelectedSelector))).fold(g(s),(e=>e[0])):t;var s;return an(r,e,o)},id=cd("th,td,caption"),md=cd("th,td"),dd=e=>{return t=e.model.table.getSelectedCells(),E(t,Le.fromDom);var t},ud=(e,t)=>{e.on("BeforeGetContent",(t=>{const o=o=>{t.preventDefault(),(e=>ir(e[0]).map((e=>{const t=((e,t)=>{const o=e=>Ge(e.element,t),n=To(e),r=vr(n),s=As(e),l=Or(r),a=((e,t)=>{const o=e.grid.columns;let n=e.grid.rows,r=o,s=0,l=0;const a=[],c=[];return G(e.access,(e=>{if(a.push(e),t(e)){c.push(e);const t=e.row,o=t+e.rowspan-1,a=e.column,i=a+e.colspan-1;ts&&(s=o),al&&(l=i)}})),((e,t,o,n,r,s)=>({minRow:e,minCol:t,maxRow:o,maxCol:n,allCells:r,selectedCells:s}))(n,r,s,l,a,c)})(l,o),c="th:not("+t+"),td:not("+t+")",i=sr(n,"th,td",(e=>Ge(e,c)));N(i,yo),((e,t,o,n)=>{const r=_(e,(e=>"colgroup"!==e.section)),s=t.grid.columns,l=t.grid.rows;for(let e=0;eo.maxRow||ao.maxCol||(kr(t,e,a).filter(n).isNone()?al(r,l,e):l=!0)}})(r,l,a,o);const m=((e,t,o,n)=>{if(0===n.minCol&&t.grid.columns===n.maxCol+1)return 0;const r=Es(t,e,o),s=A(r,((e,t)=>e+t),0),l=A(r.slice(n.minCol,n.maxCol+1),((e,t)=>e+t),0),a=l/s*o.pixelWidth()-o.pixelWidth();return o.getCellDelta(a)})(e,Dr(e),s,a);return((e,t,o,n)=>{G(o.columns,(e=>{(e.columnt.maxCol)&&yo(e.element)}));const r=_(rr(e,"tr"),(e=>0===e.dom.childElementCount));N(r,yo),t.minCol!==t.maxCol&&t.minRow!==t.maxRow||N(rr(e,"th,td"),(e=>{bo(e,"rowspan"),bo(e,"colspan")})),bo(e,yr),bo(e,"data-snooker-col-series"),As(e).adjustTableWidth(n)})(n,a,l,m),n})(e,sd);return Fi(t),[t]})))(o).each((o=>{const n="text"===t.format?((e,t)=>{const o=e.getDoc(),n=Qt(Le.fromDom(e.getBody())),r=Le.fromTag("div",o);fo(r,"data-mce-bogus","all"),No(r,{position:"fixed",left:"-9999999px",top:"0",overflow:"hidden",opacity:"0"});const s=(e=>Jt(e)?e:Le.fromDom(Ht(e).dom.body))(n);mo(r,t),ao(s,r);const l=r.dom.innerText;return yo(r),l})(e,o):((e,t)=>E(t,(t=>e.selection.serializer.serialize(t.dom,{}))).join(""))(e,o);t.content=n}))};if(!0===t.selection){const t=(e=>_(dd(e),(e=>Ge(e,ld.selectedSelector))))(e);t.length>=1&&o(t)}})),e.on("BeforeSetContent",(o=>{if(!0===o.selection&&!0===o.paste){const n=dd(e);H(n).each((n=>{ir(n).each((r=>{const s=_((e=>{const t=document.createElement("div");return t.innerHTML=e,Kt(Le.fromDom(t))})(o.content),(e=>"meta"!==Bt(e))),l=It("table");if(Li(e)&&1===s.length&&l(s[0])){o.preventDefault();const l=Le.fromDom(e.getDoc()),a=pa(l),c=((e,t,o)=>({element:e,clipboard:t,generators:o}))(n,s[0],a);t.pasteCells(r,c).each((()=>{e.focus()}))}}))}))}}))},fd=(e,t)=>e.dispatch("NewRow",{node:t}),gd=(e,t)=>e.dispatch("NewCell",{node:t}),hd=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},pd={structure:!1,style:!0},bd={structure:!0,style:!1},wd={structure:!0,style:!0},vd=(e,t)=>Bi(e)?Ls(t):_i(e)?Ws(t):As(t),yd=(e,t,o)=>{const n=e=>"table"===Bt(Pi(e)),r=Ri(e),s=Ei(e)?f:rl,l=t=>{switch(Di(e)){case"section":return Ir();case"sectionCells":return Fr();case"cells":return Hr();default:return((e,t)=>{var o;switch((o=Dr(e),V(o.all,(e=>{const t=hr(e);return"header"===t.type?C.from(t.subType):C.none()}))).getOr(t)){case"section":return Mr();case"sectionCells":return jr();case"cells":return Pr()}})(t,"section")}},a=(n,s,a,c)=>(i,m,d=!1)=>{Fi(i);const u=Le.fromDom(e.getDoc()),f=ha(a,u,r),g={sizing:vd(e,i),resize:Ei(e)?Jn():Qn(),section:l(i)};return s(i)?n(i,m,f,g).bind((n=>{t.refresh(i.dom),N(n.newRows,(t=>{fd(e,t.dom)})),N(n.newCells,(t=>{gd(e,t.dom)}));const r=((t,n)=>n.cursor.fold((()=>{const n=ar(t);return H(n).filter(Oo).map((n=>{o.clearSelectedCells(t.dom);const r=e.dom.createRng();return r.selectNode(n.dom),e.selection.setRng(r),fo(n,"data-mce-selected","1"),r}))}),(n=>{const r=Fl(Hl,n),s=e.dom.createRng();return s.setStart(r.element.dom,r.offset),s.setEnd(r.element.dom,r.offset),e.selection.setRng(s),o.clearSelectedCells(t.dom),C.some(s)})))(i,n);return Oo(i)&&(Fi(i),d||hd(e,i.dom,c)),r.map((e=>({rng:e,effect:c})))})):C.none()},c=a(Oc,(t=>!n(e)||ba(t).rows>1),f,bd),i=a(Dc,(t=>!n(e)||ba(t).columns>1),f,bd);return{deleteRow:c,deleteColumn:i,insertRowsBefore:a(Cc,x,f,bd),insertRowsAfter:a(Sc,x,f,bd),insertColumnsBefore:a(Tc,x,s,bd),insertColumnsAfter:a(Rc,x,s,bd),mergeCells:a(Wc,x,f,bd),unmergeCells:a(Lc,x,f,bd),pasteColsBefore:a(jc,x,f,bd),pasteColsAfter:a(Pc,x,f,bd),pasteRowsBefore:a(Ic,x,f,bd),pasteRowsAfter:a(Fc,x,f,bd),pasteCells:a(Mc,x,f,wd),makeCellsHeader:a(zc,x,f,bd),unmakeCellsHeader:a(Ac,x,f,bd),makeColumnsHeader:a(kc,x,f,bd),unmakeColumnsHeader:a(Ec,x,f,bd),makeRowsHeader:a(Nc,x,f,bd),makeRowsBody:a(Bc,x,f,bd),makeRowsFooter:a(_c,x,f,bd),getTableRowType:Vc,getTableCellType:$c,getTableColType:Hc}},xd=(e,t)=>{e.selection.select(t.dom,!0),e.selection.collapse(!0)},Cd=(e,t,o,n,s)=>{const l=(e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>zi(e)||!Wi(e)?t:_i(e)?{...t,width:Ti(e)}:{...t,width:Si})(e,o)})(e),a={styles:l,attributes:Mi(e),colGroups:ji(e)};return e.undoManager.ignore((()=>{const r=((e,t,o,n,r,s=Zc)=>{const l=Le.fromTag("table"),a="cells"!==r;No(l,s.styles),go(l,s.attributes),s.colGroups&&ao(l,(e=>{const t=Le.fromTag("colgroup");return k(e,(()=>ao(t,Le.fromTag("col")))),t})(t));const c=Math.min(e,o);if(a&&o>0){const e=Le.fromTag("thead");ao(l,e);const s=ei(o,t,"sectionCells"===r?c:0,n);mo(e,s)}const i=Le.fromTag("tbody");ao(l,i);const m=ei(a?e-c:e,t,a?0:o,n);return mo(i,m),l})(o,t,s,n,Di(e),a);fo(r,"data-mce-id","__mce");const l=(e=>{const t=Le.fromTag("div"),o=Le.fromDom(e.dom.cloneNode(!0));return ao(t,o),(e=>e.dom.innerHTML)(t)})(r);e.insertContent(l),e.addVisual()})),ln(Pi(e),'table[data-mce-id="__mce"]').map((t=>(_i(e)?la(t):zi(e)?aa(t):(Bi(e)||(e=>r(e)&&-1!==e.indexOf("%"))(l.width))&&sa(t),Fi(t),bo(t,"data-mce-id"),((e,t)=>{N(vn(t,"tr"),(t=>{fd(e,t.dom),N(vn(t,"th,td"),(t=>{gd(e,t.dom)}))}))})(e,t),((e,t)=>{ln(t,"td,th").each(b(xd,e))})(e,t),t.dom))).getOrNull()};var Sd=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const Td="x-tinymce/dom-table-",Rd=Td+"rows",Dd=Td+"columns",Od=e=>{const t=Sd.FakeClipboardItem(e);Sd.write([t])},kd=e=>{var t;const o=null!==(t=Sd.read())&&void 0!==t?t:[];return V(o,(t=>C.from(t.getType(e))))},Ed=e=>{kd(e).isSome()&&Sd.clear()},Nd=e=>{e.fold(_d,(e=>Od({[Rd]:e})))},Bd=()=>kd(Rd),_d=()=>Ed(Rd),zd=e=>{e.fold(Wd,(e=>Od({[Dd]:e})))},Ad=()=>kd(Dd),Wd=()=>Ed(Dd),Ld=e=>id(Hi(e),Ii(e)).filter(Ki),Md=(e,t)=>{const o=Ii(e),n=e=>ir(e,o),l=t=>(e=>md(Hi(e),Ii(e)).filter(Ki))(e).bind((e=>n(e).map((o=>t(o,e))))),a=t=>{e.focus()},c=(t,o=!1)=>l(((n,r)=>{const s=ad(dd(e),n,r);t(n,s,o).each(a)})),i=()=>l(((t,o)=>((e,t,o)=>{const n=Dr(e);return Ys(n,t).bind((e=>{const t=Hs(n,o,!1),r=ze(t).rows.slice(e[0].row,e[e.length-1].row+e[e.length-1].rowspan),s=j(r,(e=>{const t=_(e.cells,(e=>!e.isLocked));return t.length>0?[{...e,cells:t}]:[]})),l=$s(s);return de(l.length>0,l)})).map((e=>E(e,(e=>{const t=So(e.element);return N(e.cells,(e=>{const o=To(e.element);Ms(o,"colspan",e.colspan,1),Ms(o,"rowspan",e.rowspan,1),ao(t,o)})),t}))))})(t,ad(dd(e),t,o),ha(f,Le.fromDom(e.getDoc()),C.none())))),m=()=>l(((t,o)=>((e,t)=>{const o=Dr(e);return Js(o,t).map((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=((e,t,o)=>{if(zr(e)){const n=_(_r(e),ll(t,o)),r=E(n,(e=>{const n=To(e.element);return sl(n,"span",o-t),n})),s=Le.fromTag("colgroup");return mo(s,r),[s]}return[]})(o,n,r),l=((e,t,o)=>E(e.all,(e=>{const n=_(e.cells,ll(t,o)),r=E(n,(e=>{const n=To(e.element);return sl(n,"colspan",o-t),n})),s=Le.fromTag("tr");return mo(s,r),s})))(o,n,r);return[...s,...l]}))})(t,ad(dd(e),t,o)))),d=(t,o)=>o().each((o=>{const n=E(o,(e=>To(e)));l(((o,r)=>{const s=pa(Le.fromDom(e.getDoc())),l=((e,t,o,n)=>({selection:om(e),clipboard:o,generators:n}))(dd(e),0,n,s);t(o,l).each(a)}))})),g=e=>(t,o)=>((e,t)=>X(e,t)?C.from(e[t]):C.none())(o,"type").each((t=>{c(e(t),o.no_events)}));G({mceTableSplitCells:()=>c(t.unmergeCells),mceTableMergeCells:()=>c(t.mergeCells),mceTableInsertRowBefore:()=>c(t.insertRowsBefore),mceTableInsertRowAfter:()=>c(t.insertRowsAfter),mceTableInsertColBefore:()=>c(t.insertColumnsBefore),mceTableInsertColAfter:()=>c(t.insertColumnsAfter),mceTableDeleteCol:()=>c(t.deleteColumn),mceTableDeleteRow:()=>c(t.deleteRow),mceTableCutCol:()=>m().each((e=>{zd(e),c(t.deleteColumn)})),mceTableCutRow:()=>i().each((e=>{Nd(e),c(t.deleteRow)})),mceTableCopyCol:()=>m().each((e=>zd(e))),mceTableCopyRow:()=>i().each((e=>Nd(e))),mceTablePasteColBefore:()=>d(t.pasteColsBefore,Ad),mceTablePasteColAfter:()=>d(t.pasteColsAfter,Ad),mceTablePasteRowBefore:()=>d(t.pasteRowsBefore,Bd),mceTablePasteRowAfter:()=>d(t.pasteRowsAfter,Bd),mceTableDelete:()=>Ld(e).each((t=>{ir(t,o).filter(w(o)).each((t=>{const o=Le.fromText("");if(so(t,o),yo(t),e.dom.isEmpty(e.getBody()))e.setContent(""),e.selection.setCursorLocation();else{const t=e.dom.createRng();t.setStart(o.dom,0),t.setEnd(o.dom,0),e.selection.setRng(t),e.nodeChanged()}}))})),mceTableCellToggleClass:(t,o)=>{l((t=>{const n=dd(e),r=P(n,(t=>e.formatter.match("tablecellclass",{value:o},t.dom))),s=r?e.formatter.remove:e.formatter.apply;N(n,(e=>s("tablecellclass",{value:o},e.dom))),hd(e,t.dom,pd)}))},mceTableToggleClass:(t,o)=>{l((t=>{e.formatter.toggle("tableclass",{value:o},t.dom),hd(e,t.dom,pd)}))},mceTableToggleCaption:()=>{Ld(e).each((t=>{ir(t,o).each((o=>{sn(o,"caption").fold((()=>{const t=Le.fromTag("caption");ao(t,Le.fromText("Caption")),((e,t)=>{Yt(e,0).fold((()=>{ao(e,t)}),(e=>{ro(e,t)}))})(o,t),e.selection.setCursorLocation(t.dom,0)}),(n=>{It("caption")(t)&&Ye("td",o).each((t=>e.selection.setCursorLocation(t.dom,0))),yo(n)})),hd(e,o.dom,bd)}))}))},mceTableSizingMode:(t,n)=>(t=>Ld(e).each((n=>{zi(e)||_i(e)||Bi(e)||ir(n,o).each((o=>{"relative"!==t||Rl(o)?"fixed"!==t||Dl(o)?"responsive"!==t||Ol(o)||aa(o):la(o):sa(o),Fi(o),hd(e,o.dom,bd)}))})))(n),mceTableCellType:g((e=>"th"===e?t.makeCellsHeader:t.unmakeCellsHeader)),mceTableColType:g((e=>"th"===e?t.makeColumnsHeader:t.unmakeColumnsHeader)),mceTableRowType:g((e=>{switch(e){case"header":return t.makeRowsHeader;case"footer":return t.makeRowsFooter;default:return t.makeRowsBody}}))},((t,o)=>e.addCommand(o,t))),e.addCommand("mceInsertTable",((t,o)=>{((e,t,o,n={})=>{const r=e=>u(e)&&e>0;if(r(t)&&r(o)){const r=n.headerRows||0,s=n.headerColumns||0;return Cd(e,o,t,s,r)}console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.")})(e,o.rows,o.columns,o.options)})),e.addCommand("mceTableApplyCellStyle",((t,o)=>{const l=e=>"tablecell"+e.toLowerCase().replace("-","");if(!s(o))return;const a=_(dd(e),Ki);if(0===a.length)return;const c=((e,t)=>{const o={};return((e,t,o,n)=>{G(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(e=>(t,o)=>{e[o]=t})(o),f),o})(o,((t,o)=>e.formatter.has(l(o))&&r(t)));(e=>{for(const t in e)if(U.call(e,t))return!1;return!0})(c)||(G(c,((t,o)=>{const n=l(o);N(a,(o=>{""===t?e.formatter.remove(n,{value:null},o.dom,!0):e.formatter.apply(n,{value:t},o.dom)}))})),n(a[0]).each((t=>hd(e,t.dom,pd))))}))},jd=e=>!un(Le.fromDom(e.target),"ephox-snooker-resizer-bar"),Pd=(e,t)=>{const o=(r=ld.selectedSelector,{get:()=>em(Le.fromDom(e.getBody()),r).fold((()=>md(Hi(e),Ii(e)).fold(lm,cm)),am)}),n=((e,t,o)=>{const n=t=>{bo(t,e.selected),bo(t,e.firstSelected),bo(t,e.lastSelected)},r=t=>{fo(t,e.selected,"1")},s=e=>{l(e),o()},l=t=>{const o=vn(t,`${e.selectedSelector},${e.firstSelectedSelector},${e.lastSelectedSelector}`);N(o,n)};return{clearBeforeUpdate:l,clear:s,selectRange:(o,n,l,a)=>{s(o),N(n,r),fo(l,e.firstSelected,"1"),fo(a,e.lastSelected,"1"),t(n,l,a)},selectedSelector:e.selectedSelector,firstSelectedSelector:e.firstSelectedSelector,lastSelectedSelector:e.lastSelectedSelector}})(ld,((t,o,n)=>{ir(o).each((r=>{const s=E(t,(e=>e.dom)),l=Ri(e),a=ha(f,Le.fromDom(e.getDoc()),l),c=((e,t,o)=>{const n=Dr(e);return Ys(n,t).map((e=>{const t=Hs(n,o,!1),{rows:r}=ze(t),s=((e,t)=>{const o=e.slice(0,t[t.length-1].row+1),n=$s(o);return j(n,(e=>{const o=e.cells.slice(0,t[t.length-1].column+1);return E(o,(e=>e.element))}))})(r,e),l=((e,t)=>{const o=e.slice(t[0].row+t[0].rowspan-1,e.length),n=$s(o);return j(n,(e=>{const o=e.cells.slice(t[0].column+t[0].colspan-1,e.cells.length);return E(o,(e=>e.element))}))})(r,e);return{upOrLeftCells:s,downOrRightCells:l}}))})(r,{selection:dd(e)},a).map((e=>K(e,(e=>E(e,(e=>e.dom)))))).getOrUndefined();((e,t,o,n,r)=>{e.dispatch("TableSelectionChange",{cells:t,start:o,finish:n,otherCells:r})})(e,s,o.dom,n.dom,c)}))}),(()=>(e=>{e.dispatch("TableSelectionClear")})(e)));var r;return e.on("init",(o=>{const r=e.getWin(),s=Pi(e),l=Ii(e),a=((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=fe(),s=r.clear,l=s=>{r.on((r=>{n.clearBeforeUpdate(t),Hm(s.target,o).each((l=>{Ji(r,l,o).each((o=>{const r=o.boxes.getOr([]);if(1===r.length){const e=r[0],o="false"===hn(e),l=ie(fn(s.target),e,Je);o&&l&&n.selectRange(t,r,e,e)}else r.length>1&&(n.selectRange(t,r,o.start,o.finish),e.selectContents(l))}))}))}))};return{clearstate:s,mousedown:e=>{n.clear(t),Hm(e.target,o).filter($m).each(r.set)},mouseover:e=>{l(e)},mouseup:e=>{l(e),s()}}})(Xm(e),t,o,n);return{clearstate:r.clearstate,mousedown:r.mousedown,mouseover:r.mouseover,mouseup:r.mouseup}})(r,s,l,n),c=((e,t,o,n)=>{const r=Xm(e),s=()=>(n.clear(t),C.none());return{keydown:(e,l,a,c,i,m)=>{const d=e.raw,u=d.which,f=!0===d.shiftKey,g=Qi(t,n.selectedSelector).fold((()=>(Ym(u)&&!f&&n.clearBeforeUpdate(t),Ym(u)&&f&&!td(l,c)?C.none:Km(u)&&f?b(Fm,r,t,o,Vm,c,l,n.selectRange):Gm(u)&&f?b(Fm,r,t,o,qm,c,l,n.selectRange):Km(u)?b(jm,r,o,Vm,c,l,Im):Gm(u)?b(jm,r,o,qm,c,l,Pm):C.none)),(e=>{const o=o=>()=>{const s=V(o,(o=>((e,t,o,n,r)=>Zi(n,e,t,r.firstSelectedSelector,r.lastSelectedSelector).map((e=>(r.clearBeforeUpdate(o),r.selectRange(o,e.boxes,e.start,e.finish),e.boxes))))(o.rows,o.cols,t,e,n)));return s.fold((()=>Xi(t,n.firstSelectedSelector,n.lastSelectedSelector).map((e=>{const o=Km(u)||m.isForward(u)?kn.after:kn.before;return r.setRelativeSelection(kn.on(e.first,0),o(e.table)),n.clear(t),sm(C.none(),!0)}))),(e=>C.some(sm(C.none(),!0))))};return Ym(u)&&f&&!td(l,c)?C.none:Km(u)&&f?o([Zm(1,0)]):Gm(u)&&f?o([Zm(-1,0)]):m.isBackward(u)&&f?o([Zm(0,-1),Zm(-1,0)]):m.isForward(u)&&f?o([Zm(0,1),Zm(1,0)]):Ym(u)&&!f?s:C.none}));return g()},keyup:(e,r,s,l,a)=>Qi(t,n.selectedSelector).fold((()=>{const c=e.raw,i=c.which;return!0===c.shiftKey&&Ym(i)&&td(r,l)?((e,t,o,n,r,s,l)=>Je(o,r)&&n===s?C.none():an(o,"td,th",t).bind((o=>an(r,"td,th",t).bind((n=>um(e,t,o,n,l))))))(t,o,r,s,l,a,n.selectRange):C.none()}),C.none)}})(r,s,l,n),i=((e,t,o,n)=>{const r=Xm(e);return(e,s)=>{n.clearBeforeUpdate(t),Ji(e,s,o).each((e=>{const o=e.boxes.getOr([]);n.selectRange(t,o,e.start,e.finish),r.selectContents(s),r.collapseSelection()}))}})(r,s,l,n);e.on("TableSelectorChange",(e=>i(e.start,e.finish)));const m=(t,o)=>{(e=>!0===e.raw.shiftKey)(t)&&(o.kill&&t.kill(),o.selection.each((t=>{const o=Nn.relative(t.start,t.finish),n=Ue(r,o);e.selection.setRng(n)})))},d=e=>0===e.button,u=(()=>{const e=ee(Le.fromDom(s)),t=ee(0);return{touchEnd:o=>{const n=Le.fromDom(o.target);if(It("td")(n)||It("th")(n)){const r=e.get(),s=t.get();Je(r,n)&&o.timeStamp-s<300&&(o.preventDefault(),i(n,n))}e.set(n),t.set(o.timeStamp)}}})();e.on("dragstart",(e=>{a.clearstate()})),e.on("mousedown",(e=>{d(e)&&jd(e)&&a.mousedown(no(e))})),e.on("mouseover",(e=>{var t;(void 0===(t=e).buttons||1&t.buttons)&&jd(e)&&a.mouseover(no(e))})),e.on("mouseup",(e=>{d(e)&&jd(e)&&a.mouseup(no(e))})),e.on("touchend",u.touchEnd),e.on("keyup",(t=>{const o=no(t);if(o.raw.shiftKey&&Ym(o.raw.which)){const t=e.selection.getRng(),n=Le.fromDom(t.startContainer),r=Le.fromDom(t.endContainer);c.keyup(o,n,t.startOffset,r,t.endOffset).each((e=>{m(o,e)}))}})),e.on("keydown",(o=>{const n=no(o);t.hide();const r=e.selection.getRng(),s=Le.fromDom(r.startContainer),l=Le.fromDom(r.endContainer),a=Zo(Jm,Qm)(Le.fromDom(e.selection.getStart()));c.keydown(n,s,r.startOffset,l,r.endOffset,a).each((e=>{m(n,e)})),t.show()})),e.on("NodeChange",(()=>{const t=e.selection,o=Le.fromDom(t.getStart()),r=Le.fromDom(t.getEnd());Zl(ir,[o,r]).fold((()=>n.clear(s)),f)}))})),e.on("PreInit",(()=>{e.serializer.addTempAttr(ld.firstSelected),e.serializer.addTempAttr(ld.lastSelected)})),{getSelectedCells:()=>((e,t)=>{switch(e.tag){case"none":return t();case"single":return(e=>[e.dom])(e.element);case"multiple":return(e=>E(e,(e=>e.dom)))(e.elements)}})(o.get(),g([])),clearSelectedCells:e=>n.clear(Le.fromDom(e))}},Id=e=>m(e)&&"TABLE"===e.nodeName,Fd="bar-",Hd=e=>"false"!==ho(e,"data-mce-resize"),$d=e=>{const t=fe(),o=fe(),n=fe();let r,s,l,a;const c=t=>vd(e,t),i=()=>ki(e)?Qn():Jn(),m=(t,o,n,m)=>{const d=(e=>{return pe(t=e,"corner-")?(e=>e.substring(7))(t):t;var t})(o),u=be(d,"e"),f=pe(d,"n");if(""===s&&sa(t),""===a&&(e=>{const t=(e=>jo(e)+"px")(e);Tl(e,C.none(),C.some(t)),ra(e)})(t),n!==r&&""!==s){Eo(t,"width",s);const o=i(),l=c(t),a=ki(e)||u?(e=>ba(e).columns)(t)-1:0;ol(t,n-r,a,o,l)}else if((e=>/^(\d+(\.\d+)?)%$/.test(e))(s)){const e=parseFloat(s.replace("%",""));Eo(t,"width",n*e/r+"%")}if((e=>/^(\d+(\.\d+)?)px$/.test(e))(s)&&(e=>{const t=Dr(e);zr(t)||N(ar(e),(e=>{const t=Bo(e,"width");Eo(e,"width",t),bo(e,"width")}))})(t),m!==l&&""!==a){Eo(t,"height",a);const e=f?0:(e=>ba(e).rows)(t)-1;nl(t,m-l,e)}};e.on("init",(()=>{const r=((e,t)=>((e,t)=>({parent:g(e),view:g(e),dragContainer:g(e),origin:()=>Go(e),isResizable:t}))(Le.fromDom(e.getBody()),t))(e,Hd);if(n.set(r),(e=>{const t=e.options.get("object_resizing");return D(t.split(","),"table")})(e)&&Ai(e)){const n=((e,t,o)=>{const n=ns,r=ss,s=xi(e),l=oi({beforeResize:ti(["table","type"]),afterResize:ti(["table","type"]),startDrag:ti([])});return s.events.adjustHeight.bind((e=>{const t=e.table;l.trigger.beforeResize(t,"row");const o=n.delta(e.delta,t);nl(t,o,e.row),l.trigger.afterResize(t,"row")})),s.events.startAdjust.bind((e=>{l.trigger.startDrag()})),s.events.adjustWidth.bind((e=>{const n=e.table;l.trigger.beforeResize(n,"col");const s=r.delta(e.delta,n),a=o(n);ol(n,s,e.column,t,a),l.trigger.afterResize(n,"col")})),{on:s.on,off:s.off,refreshBars:s.refresh,hideBars:s.hideBars,showBars:s.showBars,destroy:s.destroy,events:l.registry}})(r,i(),c);e.mode.isReadOnly()||n.on(),n.events.startDrag.bind((o=>{t.set(e.selection.getRng())})),n.events.beforeResize.bind((t=>{const o=t.table.dom;((e,t,o,n,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:o,height:n,origin:r})})(e,o,$i(o),Vi(o),Fd+t.type)})),n.events.afterResize.bind((o=>{const n=o.table,r=n.dom;Fi(n),t.on((t=>{e.selection.setRng(t),e.focus()})),((e,t,o,n,r)=>{e.dispatch("ObjectResized",{target:t,width:o,height:n,origin:r})})(e,r,$i(r),Vi(r),Fd+o.type),e.undoManager.add()})),o.set(n)}})),e.on("ObjectResizeStart",(t=>{const o=t.target;if(Id(o)&&!e.mode.isReadOnly()){const n=Le.fromDom(o);N(e.dom.select(".mce-clonedresizable"),(t=>{e.dom.addClass(t,"mce-"+Oi(e)+"-columns")})),!Dl(n)&&_i(e)?la(n):!Rl(n)&&Bi(e)&&sa(n),Ol(n)&&pe(t.origin,Fd)&&sa(n),r=t.width,s=zi(e)?"":Ui(e,o).getOr(""),l=t.height,a=Gi(e,o).getOr("")}})),e.on("ObjectResized",(t=>{const o=t.target;if(Id(o)){const n=Le.fromDom(o),r=t.origin;(e=>pe(e,"corner-"))(r)&&m(n,r,t.width,t.height),Fi(n),hd(e,n.dom,pd)}}));const d=()=>{o.on((e=>{e.on(),e.showBars()}))},u=()=>{o.on((e=>{e.off(),e.hideBars()}))};return e.on("DisabledStateChange",(e=>{e.state?u():d()})),e.on("SwitchMode",(()=>{e.mode.isReadOnly()?u():d()})),e.on("dragstart dragend",(e=>{"dragstart"===e.type?u():d()})),e.on("remove",(()=>{o.on((e=>{e.destroy()}))})),{refresh:e=>{o.on((t=>t.refreshBars(Le.fromDom(e))))},hide:()=>{o.on((e=>e.hideBars()))},show:()=>{o.on((e=>e.showBars()))}}},Vd=e=>{(e=>{const t=e.options.register;t("table_clone_elements",{processor:"string[]"}),t("table_use_colgroups",{processor:"boolean",default:!0}),t("table_header_type",{processor:e=>{const t=D(["section","cells","sectionCells","auto"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: section, cells, sectionCells or auto."}},default:"section"}),t("table_sizing_mode",{processor:"string",default:"auto"}),t("table_default_attributes",{processor:"object",default:{border:"1"}}),t("table_default_styles",{processor:"object",default:{"border-collapse":"collapse"}}),t("table_column_resizing",{processor:e=>{const t=D(["preservetable","resizetable"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be preservetable, or resizetable."}},default:"preservetable"}),t("table_resize_bars",{processor:"boolean",default:!0}),t("table_style_by_css",{processor:"boolean",default:!0}),t("table_merge_content_on_paste",{processor:"boolean",default:!0})})(e);const t=$d(e),o=Pd(e,t),n=yd(e,t,o);return Md(e,n),((e,t)=>{const o=Ii(e),n=t=>md(Hi(e)).bind((n=>ir(n,o).map((o=>{const r=ad(dd(e),o,n);return t(o,r)})))).getOr("");G({mceTableRowType:()=>n(t.getTableRowType),mceTableCellType:()=>n(t.getTableCellType),mceTableColType:()=>n(t.getTableColType)},((t,o)=>e.addQueryValueHandler(o,t)))})(e,n),ud(e,n),{getSelectedCells:o.getSelectedCells,clearSelectedCells:o.clearSelectedCells}};e.add("dom",(e=>({table:Vd(e)})))}(); \ No newline at end of file diff --git a/public/ext/tinymce/notices.txt b/public/ext/tinymce/notices.txt new file mode 100644 index 0000000..44a9c74 --- /dev/null +++ b/public/ext/tinymce/notices.txt @@ -0,0 +1,21 @@ +Below is a list of third party libraries that this software uses: +---------------------------------------------------------------- + +dompurify - Patched by Tiny +owner: Mario Heiderich +repo: https://github.com/cure53/DOMPurify +version: 3.2.4 +license: MPL-2.0 OR Apache-2.0 + +prismjs +owner: Lea Verou +repo: https://github.com/PrismJS/prism +version: 1.25.0 +license: MIT + + +prism-themes +owner: Lea Verou +repo: https://github.com/PrismJS/prism-themes +version: 1.9.0 +license: MIT diff --git a/public/ext/tinymce/package.json b/public/ext/tinymce/package.json index 065da1b..4ece366 100644 --- a/public/ext/tinymce/package.json +++ b/public/ext/tinymce/package.json @@ -1,6 +1,6 @@ { "name": "tinymce", - "version": "7.7.2", + "version": "7.9.1", "repository": { "type": "git", "url": "https://github.com/tinymce/tinymce.git", diff --git a/public/ext/tinymce/plugins/accordion/plugin.js b/public/ext/tinymce/plugins/accordion/plugin.js index 702d6f0..1cfadff 100644 --- a/public/ext/tinymce/plugins/accordion/plugin.js +++ b/public/ext/tinymce/plugins/accordion/plugin.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -7,728 +7,1004 @@ var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager'); - const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295; - - let unique = 0; - const generate = prefix => { - const date = new Date(); - const time = date.getTime(); - const random$1 = Math.floor(random() * 1000000000); - unique++; - return prefix + '_' + random$1 + unique + String(time); - }; - + /* eslint-disable @typescript-eslint/no-wrapper-object-types */ const hasProto = (v, constructor, predicate) => { - var _a; - if (predicate(v, constructor.prototype)) { - return true; - } else { - return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; - } - }; - const typeOf = x => { - const t = typeof x; - if (x === null) { - return 'null'; - } else if (t === 'object' && Array.isArray(x)) { - return 'array'; - } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { - return 'string'; - } else { - return t; - } - }; - const isType$1 = type => value => typeOf(value) === type; - const isSimpleType = type => value => typeof value === type; + var _a; + if (predicate(v, constructor.prototype)) { + return true; + } + else { + // String-based fallback time + return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; + } + }; + const typeOf = (x) => { + const t = typeof x; + if (x === null) { + return 'null'; + } + else if (t === 'object' && Array.isArray(x)) { + return 'array'; + } + else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { + return 'string'; + } + else { + return t; + } + }; + const isType$1 = (type) => (value) => typeOf(value) === type; + const isSimpleType = (type) => (value) => typeof value === type; const isString = isType$1('string'); const isBoolean = isSimpleType('boolean'); - const isNullable = a => a === null || a === undefined; - const isNonNullable = a => !isNullable(a); + const isNullable = (a) => a === null || a === undefined; + const isNonNullable = (a) => !isNullable(a); const isFunction = isSimpleType('function'); const isNumber = isSimpleType('number'); - const compose1 = (fbc, fab) => a => fbc(fab(a)); - const constant = value => { - return () => { - return value; - }; + /** Compose two unary functions. Similar to compose, but avoids using Function.prototype.apply. */ + const compose1 = (fbc, fab) => (a) => fbc(fab(a)); + const constant = (value) => { + return () => { + return value; + }; }; const tripleEquals = (a, b) => { - return a === b; + return a === b; }; const never = constant(false); + /** + * The `Optional` type represents a value (of any type) that potentially does + * not exist. Any `Optional` can either be a `Some` (in which case the + * value does exist) or a `None` (in which case the value does not exist). This + * module defines a whole lot of FP-inspired utility functions for dealing with + * `Optional` objects. + * + * Comparison with null or undefined: + * - We don't get fancy null coalescing operators with `Optional` + * - We do get fancy helper functions with `Optional` + * - `Optional` support nesting, and allow for the type to still be nullable (or + * another `Optional`) + * - There is no option to turn off strict-optional-checks like there is for + * strict-null-checks + */ class Optional { - constructor(tag, value) { - this.tag = tag; - this.value = value; - } - static some(value) { - return new Optional(true, value); - } - static none() { - return Optional.singletonNone; - } - fold(onNone, onSome) { - if (this.tag) { - return onSome(this.value); - } else { - return onNone(); - } - } - isSome() { - return this.tag; - } - isNone() { - return !this.tag; - } - map(mapper) { - if (this.tag) { - return Optional.some(mapper(this.value)); - } else { - return Optional.none(); - } - } - bind(binder) { - if (this.tag) { - return binder(this.value); - } else { - return Optional.none(); - } - } - exists(predicate) { - return this.tag && predicate(this.value); - } - forall(predicate) { - return !this.tag || predicate(this.value); - } - filter(predicate) { - if (!this.tag || predicate(this.value)) { - return this; - } else { - return Optional.none(); - } - } - getOr(replacement) { - return this.tag ? this.value : replacement; - } - or(replacement) { - return this.tag ? this : replacement; - } - getOrThunk(thunk) { - return this.tag ? this.value : thunk(); - } - orThunk(thunk) { - return this.tag ? this : thunk(); - } - getOrDie(message) { - if (!this.tag) { - throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); - } else { - return this.value; - } - } - static from(value) { - return isNonNullable(value) ? Optional.some(value) : Optional.none(); - } - getOrNull() { - return this.tag ? this.value : null; - } - getOrUndefined() { - return this.value; - } - each(worker) { - if (this.tag) { - worker(this.value); - } - } - toArray() { - return this.tag ? [this.value] : []; - } - toString() { - return this.tag ? `some(${ this.value })` : 'none()'; - } + // The internal representation has a `tag` and a `value`, but both are + // private: able to be console.logged, but not able to be accessed by code + constructor(tag, value) { + this.tag = tag; + this.value = value; + } + // --- Identities --- + /** + * Creates a new `Optional` that **does** contain a value. + */ + static some(value) { + return new Optional(true, value); + } + /** + * Create a new `Optional` that **does not** contain a value. `T` can be + * any type because we don't actually have a `T`. + */ + static none() { + return Optional.singletonNone; + } + /** + * Perform a transform on an `Optional` type. Regardless of whether this + * `Optional` contains a value or not, `fold` will return a value of type `U`. + * If this `Optional` does not contain a value, the `U` will be created by + * calling `onNone`. If this `Optional` does contain a value, the `U` will be + * created by calling `onSome`. + * + * For the FP enthusiasts in the room, this function: + * 1. Could be used to implement all of the functions below + * 2. Forms a catamorphism + */ + fold(onNone, onSome) { + if (this.tag) { + return onSome(this.value); + } + else { + return onNone(); + } + } + /** + * Determine if this `Optional` object contains a value. + */ + isSome() { + return this.tag; + } + /** + * Determine if this `Optional` object **does not** contain a value. + */ + isNone() { + return !this.tag; + } + // --- Functor (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. If + * you provide a function to turn a T into a U, this is the function you use + * to turn an `Optional` into an `Optional`. If this **does** contain + * a value then the output will also contain a value (that value being the + * output of `mapper(this.value)`), and if this **does not** contain a value + * then neither will the output. + */ + map(mapper) { + if (this.tag) { + return Optional.some(mapper(this.value)); + } + else { + return Optional.none(); + } + } + // --- Monad (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. + * Unlike `map`, here the transform itself also returns an `Optional`. + */ + bind(binder) { + if (this.tag) { + return binder(this.value); + } + else { + return Optional.none(); + } + } + // --- Traversable (name stolen from Haskell / maths) --- + /** + * For a given predicate, this function finds out if there **exists** a value + * inside this `Optional` object that meets the predicate. In practice, this + * means that for `Optional`s that do not contain a value it returns false (as + * no predicate-meeting value exists). + */ + exists(predicate) { + return this.tag && predicate(this.value); + } + /** + * For a given predicate, this function finds out if **all** the values inside + * this `Optional` object meet the predicate. In practice, this means that + * for `Optional`s that do not contain a value it returns true (as all 0 + * objects do meet the predicate). + */ + forall(predicate) { + return !this.tag || predicate(this.value); + } + filter(predicate) { + if (!this.tag || predicate(this.value)) { + return this; + } + else { + return Optional.none(); + } + } + // --- Getters --- + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. + */ + getOr(replacement) { + return this.tag ? this.value : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` object is also + * `Optional` - meaning that this method will always return an `Optional`. + */ + or(replacement) { + return this.tag ? this : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` value is + * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you + * pass a function which (if called) will **return** the `value` you want to + * use. + */ + getOrThunk(thunk) { + return this.tag ? this.value : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided Optional object does not contain a + * value. + * + * Unlike `or`, in this method the `replacement` value is "thunked" - that is + * to say that you don't pass a value to `orThunk`, you pass a function which + * (if called) will **return** the `value` you want to use. + * + * Unlike `getOrThunk`, in this method the `replacement` value is also + * `Optional`, meaning that this method will always return an `Optional`. + */ + orThunk(thunk) { + return this.tag ? this : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, throwing an + * exception if the provided `Optional` object does not contain a value. + * + * WARNING: + * You should only be using this function if you know that the `Optional` + * object **is not** empty (otherwise you're throwing exceptions in production + * code, which is bad). + * + * In tests this is more acceptable. + * + * Prefer other methods to this, such as `.each`. + */ + getOrDie(message) { + if (!this.tag) { + throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); + } + else { + return this.value; + } + } + // --- Interop with null and undefined --- + /** + * Creates an `Optional` value from a nullable (or undefined-able) input. + * Null, or undefined, is converted to `None`, and anything else is converted + * to `Some`. + */ + static from(value) { + return isNonNullable(value) ? Optional.some(value) : Optional.none(); + } + /** + * Converts an `Optional` to a nullable type, by getting the value if it + * exists, or returning `null` if it does not. + */ + getOrNull() { + return this.tag ? this.value : null; + } + /** + * Converts an `Optional` to an undefined-able type, by getting the value if + * it exists, or returning `undefined` if it does not. + */ + getOrUndefined() { + return this.value; + } + // --- Utilities --- + /** + * If the `Optional` contains a value, perform an action on that value. + * Unlike the rest of the methods on this type, `.each` has side-effects. If + * you want to transform an `Optional` **into** something, then this is not + * the method for you. If you want to use an `Optional` to **do** + * something, then this is the method for you - provided you're okay with not + * doing anything in the case where the `Optional` doesn't have a value inside + * it. If you're not sure whether your use-case fits into transforming + * **into** something or **doing** something, check whether it has a return + * value. If it does, you should be performing a transform. + */ + each(worker) { + if (this.tag) { + worker(this.value); + } + } + /** + * Turn the `Optional` object into an array that contains all of the values + * stored inside the `Optional`. In practice, this means the output will have + * either 0 or 1 elements. + */ + toArray() { + return this.tag ? [this.value] : []; + } + /** + * Turn the `Optional` object into a string for debugging or printing. Not + * recommended for production code, but good for debugging. Also note that + * these days an `Optional` object can be logged to the console directly, and + * its inner value (if it exists) will be visible. + */ + toString() { + return this.tag ? `some(${this.value})` : 'none()'; + } } + // Sneaky optimisation: every instance of Optional.none is identical, so just + // reuse the same object Optional.singletonNone = new Optional(false); const nativeIndexOf = Array.prototype.indexOf; + /* eslint-enable */ const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t); const contains = (xs, x) => rawIndexOf(xs, x) > -1; const map = (xs, f) => { - const len = xs.length; - const r = new Array(len); - for (let i = 0; i < len; i++) { - const x = xs[i]; - r[i] = f(x, i); - } - return r; + // pre-allocating array size when it's guaranteed to be known + // http://jsperf.com/push-allocated-vs-dynamic/22 + const len = xs.length; + const r = new Array(len); + for (let i = 0; i < len; i++) { + const x = xs[i]; + r[i] = f(x, i); + } + return r; }; + // Unwound implementing other functions in terms of each. + // The code size is roughly the same, and it should allow for better optimisation. + // const each = function(xs: T[], f: (x: T, i?: number, xs?: T[]) => void): void { const each$1 = (xs, f) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - f(x, i); - } + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + f(x, i); + } }; const filter = (xs, pred) => { - const r = []; - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - if (pred(x, i)) { - r.push(x); + const r = []; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + if (pred(x, i)) { + r.push(x); + } } - } - return r; + return r; }; const foldl = (xs, f, acc) => { - each$1(xs, (x, i) => { - acc = f(acc, x, i); - }); - return acc; + each$1(xs, (x, i) => { + acc = f(acc, x, i); + }); + return acc; }; + // There are many variations of Object iteration that are faster than the 'for-in' style: + // http://jsperf.com/object-keys-iteration/107 + // + // Use the native keys if it is available (IE9+), otherwise fall back to manually filtering const keys = Object.keys; const each = (obj, f) => { - const props = keys(obj); - for (let k = 0, len = props.length; k < len; k++) { - const i = props[k]; - const x = obj[i]; - f(x, i); - } + const props = keys(obj); + for (let k = 0, len = props.length; k < len; k++) { + const i = props[k]; + const x = obj[i]; + f(x, i); + } }; - typeof window !== 'undefined' ? window : Function('return this;')(); - - const COMMENT = 8; - const DOCUMENT = 9; - const DOCUMENT_FRAGMENT = 11; - const ELEMENT = 1; - const TEXT = 3; + /** + * Adds two numbers, and wrap to a range. + * If the result overflows to the right, snap to the left. + * If the result overflows to the left, snap to the right. + */ + // the division is meant to get a number between 0 and 1 for more information check this discussion: https://stackoverflow.com/questions/58285941/how-to-replace-math-random-with-crypto-getrandomvalues-and-keep-same-result + const random = () => window.crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295; - const name = element => { - const r = element.dom.nodeName; - return r.toLowerCase(); + /** + * Generate a unique identifier. + * + * The unique portion of the identifier only contains an underscore + * and digits, so that it may safely be used within HTML attributes. + * + * The chance of generating a non-unique identifier has been minimized + * by combining the current time, a random number and a one-up counter. + * + * generate :: String -> String + */ + let unique = 0; + const generate = (prefix) => { + const date = new Date(); + const time = date.getTime(); + const random$1 = Math.floor(random() * 1000000000); + unique++; + return prefix + '_' + random$1 + unique + String(time); }; - const type = element => element.dom.nodeType; - const isType = t => element => type(element) === t; - const isComment = element => type(element) === COMMENT || name(element) === '#comment'; - const isElement = isType(ELEMENT); - const isText = isType(TEXT); - const isDocument = isType(DOCUMENT); - const isDocumentFragment = isType(DOCUMENT_FRAGMENT); - const rawSet = (dom, key, value) => { - if (isString(value) || isBoolean(value) || isNumber(value)) { - dom.setAttribute(key, value + ''); - } else { - console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom); - throw new Error('Attribute value was not simple'); - } - }; - const set$2 = (element, key, value) => { - rawSet(element.dom, key, value); - }; - const setAll = (element, attrs) => { - const dom = element.dom; - each(attrs, (v, k) => { - rawSet(dom, k, v); - }); - }; - const get$2 = (element, key) => { - const v = element.dom.getAttribute(key); - return v === null ? undefined : v; - }; - const getOpt = (element, key) => Optional.from(get$2(element, key)); - const remove$2 = (element, key) => { - element.dom.removeAttribute(key); - }; - const clone = element => foldl(element.dom.attributes, (acc, attr) => { - acc[attr.name] = attr.value; - return acc; - }, {}); + /** + * **Is** the value stored inside this Optional object equal to `rhs`? + */ + const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs)); + + const blank = (r) => (s) => s.replace(r, ''); + /** removes all leading and trailing spaces */ + const trim = blank(/^\s+|\s+$/g); + + const point = (element, offset) => ({ + element, + offset + }); const fromHtml = (html, scope) => { - const doc = scope || document; - const div = doc.createElement('div'); - div.innerHTML = html; - if (!div.hasChildNodes() || div.childNodes.length > 1) { - const message = 'HTML does not have a single root node'; - console.error(message, html); - throw new Error(message); - } - return fromDom(div.childNodes[0]); + const doc = scope || document; + const div = doc.createElement('div'); + div.innerHTML = html; + if (!div.hasChildNodes() || div.childNodes.length > 1) { + const message = 'HTML does not have a single root node'; + // eslint-disable-next-line no-console + console.error(message, html); + throw new Error(message); + } + return fromDom(div.childNodes[0]); }; const fromTag = (tag, scope) => { - const doc = scope || document; - const node = doc.createElement(tag); - return fromDom(node); + const doc = scope || document; + const node = doc.createElement(tag); + return fromDom(node); }; const fromText = (text, scope) => { - const doc = scope || document; - const node = doc.createTextNode(text); - return fromDom(node); - }; - const fromDom = node => { - if (node === null || node === undefined) { - throw new Error('Node cannot be null or undefined'); - } - return { dom: node }; + const doc = scope || document; + const node = doc.createTextNode(text); + return fromDom(node); + }; + const fromDom = (node) => { + // TODO: Consider removing this check, but left atm for safety + if (node === null || node === undefined) { + throw new Error('Node cannot be null or undefined'); + } + return { + dom: node + }; }; const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom); + // tslint:disable-next-line:variable-name const SugarElement = { - fromHtml, - fromTag, - fromText, - fromDom, - fromPoint + fromHtml, + fromTag, + fromText, + fromDom, + fromPoint }; - const is$2 = (element, selector) => { - const dom = element.dom; - if (dom.nodeType !== ELEMENT) { - return false; - } else { - const elem = dom; - if (elem.matches !== undefined) { - return elem.matches(selector); - } else if (elem.msMatchesSelector !== undefined) { - return elem.msMatchesSelector(selector); - } else if (elem.webkitMatchesSelector !== undefined) { - return elem.webkitMatchesSelector(selector); - } else if (elem.mozMatchesSelector !== undefined) { - return elem.mozMatchesSelector(selector); - } else { - throw new Error('Browser lacks native selectors'); - } - } - }; - const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0; + const COMMENT = 8; + const DOCUMENT = 9; + const DOCUMENT_FRAGMENT = 11; + const ELEMENT = 1; + const TEXT = 3; + + const is$1 = (element, selector) => { + const dom = element.dom; + if (dom.nodeType !== ELEMENT) { + return false; + } + else { + const elem = dom; + if (elem.matches !== undefined) { + return elem.matches(selector); + } + else if (elem.msMatchesSelector !== undefined) { + return elem.msMatchesSelector(selector); + } + else if (elem.webkitMatchesSelector !== undefined) { + return elem.webkitMatchesSelector(selector); + } + else if (elem.mozMatchesSelector !== undefined) { + // cast to any as mozMatchesSelector doesn't exist in TS DOM lib + return elem.mozMatchesSelector(selector); + } + else { + throw new Error('Browser lacks native selectors'); + } // unfortunately we can't throw this on startup :( + } + }; + const bypassSelector = (dom) => + // Only elements, documents and shadow roots support querySelector + // shadow root element type is DOCUMENT_FRAGMENT + dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || + // IE fix for complex queries on empty nodes: http://jsfiddle.net/spyder/fv9ptr5L/ + dom.childElementCount === 0; const all = (selector, scope) => { - const base = scope === undefined ? document : scope.dom; - return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom); + const base = scope === undefined ? document : scope.dom; + return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom); }; const one = (selector, scope) => { - const base = scope === undefined ? document : scope.dom; - return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom); + const base = scope === undefined ? document : scope.dom; + return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom); }; const eq = (e1, e2) => e1.dom === e2.dom; - const is$1 = is$2; + const is = is$1; - const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs)); - - const blank = r => s => s.replace(r, ''); - const trim = blank(/^\s+|\s+$/g); - - const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue); + const name = (element) => { + const r = element.dom.nodeName; + return r.toLowerCase(); + }; + const type = (element) => element.dom.nodeType; + const isType = (t) => (element) => type(element) === t; + const isComment = (element) => type(element) === COMMENT || name(element) === '#comment'; + const isElement = isType(ELEMENT); + const isText = isType(TEXT); + const isDocument = isType(DOCUMENT); + const isDocumentFragment = isType(DOCUMENT_FRAGMENT); - const owner = element => SugarElement.fromDom(element.dom.ownerDocument); - const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos); - const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom); + /** + * The document associated with the current element + * NOTE: this will throw if the owner is null. + */ + const owner = (element) => SugarElement.fromDom(element.dom.ownerDocument); + /** + * If the element is a document, return it. Otherwise, return its ownerDocument. + * @param dos + */ + const documentOrOwner = (dos) => isDocument(dos) ? dos : owner(dos); + const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom); const parents = (element, isRoot) => { - const stop = isFunction(isRoot) ? isRoot : never; - let dom = element.dom; - const ret = []; - while (dom.parentNode !== null && dom.parentNode !== undefined) { - const rawParent = dom.parentNode; - const p = SugarElement.fromDom(rawParent); - ret.push(p); - if (stop(p) === true) { - break; - } else { - dom = rawParent; - } - } - return ret; - }; - const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom); - const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom); - const children = element => map(element.dom.childNodes, SugarElement.fromDom); - const child = (element, index) => { - const cs = element.dom.childNodes; - return Optional.from(cs[index]).map(SugarElement.fromDom); + const stop = isFunction(isRoot) ? isRoot : never; + // This is used a *lot* so it needs to be performant, not recursive + let dom = element.dom; + const ret = []; + while (dom.parentNode !== null && dom.parentNode !== undefined) { + const rawParent = dom.parentNode; + const p = SugarElement.fromDom(rawParent); + ret.push(p); + if (stop(p) === true) { + break; + } + else { + dom = rawParent; + } + } + return ret; }; - const firstChild = element => child(element, 0); - - const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host); - const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode()); - const getShadowRoot = e => { - const r = getRootNode(e); - return isShadowRoot(r) ? Optional.some(r) : Optional.none(); + const prevSibling = (element) => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom); + const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom); + const children = (element) => map(element.dom.childNodes, SugarElement.fromDom); + const child = (element, index) => { + const cs = element.dom.childNodes; + return Optional.from(cs[index]).map(SugarElement.fromDom); }; - const getShadowHost = e => SugarElement.fromDom(e.dom.host); + const firstChild = (element) => child(element, 0); - const inBody = element => { - const dom = isText(element) ? element.dom.parentNode : element.dom; - if (dom === undefined || dom === null || dom.ownerDocument === null) { - return false; - } - const doc = dom.ownerDocument; - return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost)); - }; - - const internalSet = (dom, property, value) => { - if (!isString(value)) { - console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom); - throw new Error('CSS value must be a string: ' + value); - } - if (isSupported(dom)) { - dom.style.setProperty(property, value); - } - }; - const internalRemove = (dom, property) => { - if (isSupported(dom)) { - dom.style.removeProperty(property); - } - }; - const set$1 = (element, property, value) => { - const dom = element.dom; - internalSet(dom, property, value); - }; - const get$1 = (element, property) => { - const dom = element.dom; - const styles = window.getComputedStyle(dom); - const r = styles.getPropertyValue(property); - return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r; - }; - const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : ''; - const getRaw = (element, property) => { - const dom = element.dom; - const raw = getUnsafeProperty(dom, property); - return Optional.from(raw).filter(r => r.length > 0); - }; - const remove$1 = (element, property) => { - const dom = element.dom; - internalRemove(dom, property); - if (is(getOpt(element, 'style').map(trim), '')) { - remove$2(element, 'style'); - } - }; + /** + * Is the element a ShadowRoot? + * + * Note: this is insufficient to test if any element is a shadow root, but it is sufficient to differentiate between + * a Document and a ShadowRoot. + */ + const isShadowRoot = (dos) => isDocumentFragment(dos) && isNonNullable(dos.dom.host); + const getRootNode = (e) => SugarElement.fromDom(e.dom.getRootNode()); + /** If this element is in a ShadowRoot, return it. */ + const getShadowRoot = (e) => { + const r = getRootNode(e); + return isShadowRoot(r) ? Optional.some(r) : Optional.none(); + }; + /** Return the host of a ShadowRoot. + * + * This function will throw if Shadow DOM is unsupported in the browser, or if the host is null. + * If you actually have a ShadowRoot, this shouldn't happen. + */ + const getShadowHost = (e) => SugarElement.fromDom(e.dom.host); const before = (marker, element) => { - const parent$1 = parent(marker); - parent$1.each(v => { - v.dom.insertBefore(element.dom, marker.dom); - }); + const parent$1 = parent(marker); + parent$1.each((v) => { + v.dom.insertBefore(element.dom, marker.dom); + }); }; const after$1 = (marker, element) => { - const sibling = nextSibling(marker); - sibling.fold(() => { - const parent$1 = parent(marker); - parent$1.each(v => { - append$1(v, element); + const sibling = nextSibling(marker); + sibling.fold(() => { + const parent$1 = parent(marker); + parent$1.each((v) => { + append$1(v, element); + }); + }, (v) => { + before(v, element); }); - }, v => { - before(v, element); - }); }; const prepend = (parent, element) => { - const firstChild$1 = firstChild(parent); - firstChild$1.fold(() => { - append$1(parent, element); - }, v => { - parent.dom.insertBefore(element.dom, v.dom); - }); + const firstChild$1 = firstChild(parent); + firstChild$1.fold(() => { + append$1(parent, element); + }, (v) => { + parent.dom.insertBefore(element.dom, v.dom); + }); }; const append$1 = (parent, element) => { - parent.dom.appendChild(element.dom); + parent.dom.appendChild(element.dom); }; const wrap = (element, wrapper) => { - before(element, wrapper); - append$1(wrapper, element); + before(element, wrapper); + append$1(wrapper, element); }; const after = (marker, elements) => { - each$1(elements, (x, i) => { - const e = i === 0 ? marker : elements[i - 1]; - after$1(e, x); - }); + each$1(elements, (x, i) => { + const e = i === 0 ? marker : elements[i - 1]; + after$1(e, x); + }); }; const append = (parent, elements) => { - each$1(elements, x => { - append$1(parent, x); - }); + each$1(elements, (x) => { + append$1(parent, x); + }); }; - const descendants$1 = (scope, predicate) => { - let result = []; - each$1(children(scope), x => { - if (predicate(x)) { - result = result.concat([x]); + const rawSet = (dom, key, value) => { + /* + * JQuery coerced everything to a string, and silently did nothing on text node/null/undefined. + * + * We fail on those invalid cases, only allowing numbers and booleans. + */ + if (isString(value) || isBoolean(value) || isNumber(value)) { + dom.setAttribute(key, value + ''); } - result = result.concat(descendants$1(x, predicate)); - }); - return result; + else { + // eslint-disable-next-line no-console + console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom); + throw new Error('Attribute value was not simple'); + } + }; + const set$2 = (element, key, value) => { + rawSet(element.dom, key, value); + }; + const setAll = (element, attrs) => { + const dom = element.dom; + each(attrs, (v, k) => { + rawSet(dom, k, v); + }); }; + const get$2 = (element, key) => { + const v = element.dom.getAttribute(key); + // undefined is the more appropriate value for JS, and this matches JQuery + return v === null ? undefined : v; + }; + const getOpt = (element, key) => Optional.from(get$2(element, key)); + const remove$2 = (element, key) => { + element.dom.removeAttribute(key); + }; + const clone = (element) => foldl(element.dom.attributes, (acc, attr) => { + acc[attr.name] = attr.value; + return acc; + }, {}); - var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => { - if (is(scope, a)) { - return Optional.some(scope); - } else if (isFunction(isRoot) && isRoot(scope)) { - return Optional.none(); - } else { - return ancestor(scope, a, isRoot); - } + const remove$1 = (element) => { + const dom = element.dom; + if (dom.parentNode !== null) { + dom.parentNode.removeChild(dom); + } + }; + const unwrap = (wrapper) => { + const children$1 = children(wrapper); + if (children$1.length > 0) { + after(wrapper, children$1); + } + remove$1(wrapper); }; - const ancestor$1 = (scope, predicate, isRoot) => { - let element = scope.dom; - const stop = isFunction(isRoot) ? isRoot : never; - while (element.parentNode) { - element = element.parentNode; - const el = SugarElement.fromDom(element); - if (predicate(el)) { - return Optional.some(el); - } else if (stop(el)) { - break; - } - } - return Optional.none(); + // some elements, such as mathml, don't have style attributes + // others, such as angular elements, have style attributes that aren't a CSSStyleDeclaration + const isSupported = (dom) => + // eslint-disable-next-line @typescript-eslint/unbound-method + dom.style !== undefined && isFunction(dom.style.getPropertyValue); + + // Node.contains() is very, very, very good performance + // http://jsperf.com/closest-vs-contains/5 + const inBody = (element) => { + // Technically this is only required on IE, where contains() returns false for text nodes. + // But it's cheap enough to run everywhere and Sugar doesn't have platform detection (yet). + const dom = isText(element) ? element.dom.parentNode : element.dom; + // use ownerDocument.body to ensure this works inside iframes. + // Normally contains is bad because an element "contains" itself, but here we want that. + if (dom === undefined || dom === null || dom.ownerDocument === null) { + return false; + } + const doc = dom.ownerDocument; + return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost)); }; - const remove = element => { - const dom = element.dom; - if (dom.parentNode !== null) { - dom.parentNode.removeChild(dom); - } - }; - const unwrap = wrapper => { - const children$1 = children(wrapper); - if (children$1.length > 0) { - after(wrapper, children$1); - } - remove(wrapper); + const internalSet = (dom, property, value) => { + // This is going to hurt. Apologies. + // JQuery coerces numbers to pixels for certain property names, and other times lets numbers through. + // we're going to be explicit; strings only. + if (!isString(value)) { + // eslint-disable-next-line no-console + console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom); + throw new Error('CSS value must be a string: ' + value); + } + // removed: support for dom().style[property] where prop is camel case instead of normal property name + if (isSupported(dom)) { + dom.style.setProperty(property, value); + } + }; + const internalRemove = (dom, property) => { + /* + * IE9 and above - MDN doesn't have details, but here's a couple of random internet claims + * + * http://help.dottoro.com/ljopsjck.php + * http://stackoverflow.com/a/7901886/7546 + */ + if (isSupported(dom)) { + dom.style.removeProperty(property); + } + }; + const set$1 = (element, property, value) => { + const dom = element.dom; + internalSet(dom, property, value); + }; + /* + * NOTE: For certain properties, this returns the "used value" which is subtly different to the "computed value" (despite calling getComputedStyle). + * Blame CSS 2.0. + * + * https://developer.mozilla.org/en-US/docs/Web/CSS/used_value + */ + const get$1 = (element, property) => { + const dom = element.dom; + /* + * IE9 and above per + * https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle + * + * Not in numerosity, because it doesn't memoize and looking this up dynamically in performance critical code would be horrendous. + * + * JQuery has some magic here for IE popups, but we don't really need that. + * It also uses element.ownerDocument.defaultView to handle iframes but that hasn't been required since FF 3.6. + */ + const styles = window.getComputedStyle(dom); + const r = styles.getPropertyValue(property); + // jquery-ism: If r is an empty string, check that the element is not in a document. If it isn't, return the raw value. + // Turns out we do this a lot. + return (r === '' && !inBody(element)) ? getUnsafeProperty(dom, property) : r; + }; + // removed: support for dom().style[property] where prop is camel case instead of normal property name + // empty string is what the browsers (IE11 and Chrome) return when the propertyValue doesn't exists. + const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : ''; + /* + * Gets the raw value from the style attribute. Useful for retrieving "used values" from the DOM: + * https://developer.mozilla.org/en-US/docs/Web/CSS/used_value + * + * Returns NONE if the property isn't set, or the value is an empty string. + */ + const getRaw = (element, property) => { + const dom = element.dom; + const raw = getUnsafeProperty(dom, property); + return Optional.from(raw).filter((r) => r.length > 0); + }; + const remove = (element, property) => { + const dom = element.dom; + internalRemove(dom, property); + if (is$2(getOpt(element, 'style').map(trim), '')) { + // No more styles left, remove the style attribute as well + remove$2(element, 'style'); + } }; - const descendants = (scope, selector) => all(selector, scope); + const NodeValue = (is, name) => { + const get = (element) => { + if (!is(element)) { + throw new Error('Can only get ' + name + ' value of a ' + name + ' node'); + } + return getOption(element).getOr(''); + }; + const getOption = (element) => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none(); + const set = (element, value) => { + if (!is(element)) { + throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node'); + } + element.dom.nodeValue = value; + }; + return { + get, + getOption, + set + }; + }; + + const api = NodeValue(isText, 'text'); + const get = (element) => api.get(element); + const set = (element, value) => api.set(element, value); - const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is$2(e, selector), isRoot); + var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => { + if (is(scope, a)) { + return Optional.some(scope); + } + else if (isFunction(isRoot) && isRoot(scope)) { + return Optional.none(); + } + else { + return ancestor(scope, a, isRoot); + } + }; + + const ancestor$1 = (scope, predicate, isRoot) => { + let element = scope.dom; + const stop = isFunction(isRoot) ? isRoot : never; + while (element.parentNode) { + element = element.parentNode; + const el = SugarElement.fromDom(element); + if (predicate(el)) { + return Optional.some(el); + } + else if (stop(el)) { + break; + } + } + return Optional.none(); + }; + + const ancestor = (scope, selector, isRoot) => ancestor$1(scope, (e) => is$1(e, selector), isRoot); const descendant = (scope, selector) => one(selector, scope); + // Returns Some(closest ancestor element (sugared)) matching 'selector' up to isRoot, or None() otherwise const closest = (scope, selector, isRoot) => { - const is = (element, selector) => is$2(element, selector); - return ClosestOrAncestor(is, ancestor, scope, selector, isRoot); + const is = (element, selector) => is$1(element, selector); + return ClosestOrAncestor(is, ancestor, scope, selector, isRoot); }; - const NodeValue = (is, name) => { - const get = element => { - if (!is(element)) { - throw new Error('Can only get ' + name + ' value of a ' + name + ' node'); - } - return getOption(element).getOr(''); - }; - const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none(); - const set = (element, value) => { - if (!is(element)) { - throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node'); - } - element.dom.nodeValue = value; - }; - return { - get, - getOption, - set - }; + const descendants$1 = (scope, predicate) => { + let result = []; + // Recurse.toArray() might help here + each$1(children(scope), (x) => { + if (predicate(x)) { + result = result.concat([x]); + } + result = result.concat(descendants$1(x, predicate)); + }); + return result; }; - const api = NodeValue(isText, 'text'); - const get = element => api.get(element); - const set = (element, value) => api.set(element, value); + const descendants = (scope, selector) => all(selector, scope); var TagBoundaries = [ - 'body', - 'p', - 'div', - 'article', - 'aside', - 'figcaption', - 'figure', - 'footer', - 'header', - 'nav', - 'section', - 'ol', - 'ul', - 'li', - 'table', - 'thead', - 'tbody', - 'tfoot', - 'caption', - 'tr', - 'td', - 'th', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'blockquote', - 'pre', - 'address' + 'body', + 'p', + 'div', + 'article', + 'aside', + 'figcaption', + 'figure', + 'footer', + 'header', + 'nav', + 'section', + 'ol', + 'ul', + 'li', + 'table', + 'thead', + 'tbody', + 'tfoot', + 'caption', + 'tr', + 'td', + 'th', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'blockquote', + 'pre', + 'address' ]; var DomUniverse = () => { - const clone$1 = element => { - return SugarElement.fromDom(element.dom.cloneNode(false)); - }; - const document = element => documentOrOwner(element).dom; - const isBoundary = element => { - if (!isElement(element)) { - return false; - } - if (name(element) === 'body') { - return true; - } - return contains(TagBoundaries, name(element)); - }; - const isEmptyTag = element => { - if (!isElement(element)) { - return false; - } - return contains([ - 'br', - 'img', - 'hr', - 'input' - ], name(element)); - }; - const isNonEditable = element => isElement(element) && get$2(element, 'contenteditable') === 'false'; - const comparePosition = (element, other) => { - return element.dom.compareDocumentPosition(other.dom); - }; - const copyAttributesTo = (source, destination) => { - const as = clone(source); - setAll(destination, as); - }; - const isSpecial = element => { - const tag = name(element); - return contains([ - 'script', - 'noscript', - 'iframe', - 'noframes', - 'noembed', - 'title', - 'style', - 'textarea', - 'xmp' - ], tag); - }; - const getLanguage = element => isElement(element) ? getOpt(element, 'lang') : Optional.none(); - return { - up: constant({ - selector: ancestor, - closest: closest, - predicate: ancestor$1, - all: parents - }), - down: constant({ - selector: descendants, - predicate: descendants$1 - }), - styles: constant({ - get: get$1, - getRaw: getRaw, - set: set$1, - remove: remove$1 - }), - attrs: constant({ - get: get$2, - set: set$2, - remove: remove$2, - copyTo: copyAttributesTo - }), - insert: constant({ - before: before, - after: after$1, - afterAll: after, - append: append$1, - appendAll: append, - prepend: prepend, - wrap: wrap - }), - remove: constant({ - unwrap: unwrap, - remove: remove - }), - create: constant({ - nu: SugarElement.fromTag, - clone: clone$1, - text: SugarElement.fromText - }), - query: constant({ - comparePosition, - prevSibling: prevSibling, - nextSibling: nextSibling - }), - property: constant({ - children: children, - name: name, - parent: parent, - document, - isText: isText, - isComment: isComment, - isElement: isElement, - isSpecial, - getLanguage, - getText: get, - setText: set, - isBoundary, - isEmptyTag, - isNonEditable - }), - eq: eq, - is: is$1 - }; + const clone$1 = (element) => { + return SugarElement.fromDom(element.dom.cloneNode(false)); + }; + const document = (element) => documentOrOwner(element).dom; + const isBoundary = (element) => { + if (!isElement(element)) { + return false; + } + if (name(element) === 'body') { + return true; + } + return contains(TagBoundaries, name(element)); + }; + const isEmptyTag = (element) => { + if (!isElement(element)) { + return false; + } + return contains(['br', 'img', 'hr', 'input'], name(element)); + }; + const isNonEditable = (element) => isElement(element) && get$2(element, 'contenteditable') === 'false'; + const comparePosition = (element, other) => { + return element.dom.compareDocumentPosition(other.dom); + }; + const copyAttributesTo = (source, destination) => { + const as = clone(source); + setAll(destination, as); + }; + const isSpecial = (element) => { + const tag = name(element); + return contains([ + 'script', 'noscript', 'iframe', 'noframes', 'noembed', 'title', 'style', 'textarea', 'xmp' + ], tag); + }; + const getLanguage = (element) => isElement(element) ? getOpt(element, 'lang') : Optional.none(); + return { + up: constant({ + selector: ancestor, + closest: closest, + predicate: ancestor$1, + all: parents + }), + down: constant({ + selector: descendants, + predicate: descendants$1 + }), + styles: constant({ + get: get$1, + getRaw: getRaw, + set: set$1, + remove: remove + }), + attrs: constant({ + get: get$2, + set: set$2, + remove: remove$2, + copyTo: copyAttributesTo + }), + insert: constant({ + before: before, + after: after$1, + afterAll: after, + append: append$1, + appendAll: append, + prepend: prepend, + wrap: wrap + }), + remove: constant({ + unwrap: unwrap, + remove: remove$1 + }), + create: constant({ + nu: SugarElement.fromTag, + clone: clone$1, + text: SugarElement.fromText + }), + query: constant({ + comparePosition, + prevSibling: prevSibling, + nextSibling: nextSibling + }), + property: constant({ + children: children, + name: name, + parent: parent, + document, + isText: isText, + isComment: isComment, + isElement: isElement, + isSpecial, + getLanguage, + getText: get, + setText: set, + isBoundary, + isEmptyTag, + isNonEditable + }), + eq: eq, + is: is + }; }; - const point = (element, offset) => ({ - element, - offset - }); - const scan = (universe, element, direction) => { - if (universe.property().isText(element) && universe.property().getText(element).trim().length === 0 || universe.property().isComment(element)) { - return direction(element).bind(elem => { - return scan(universe, elem, direction).orThunk(() => { - return Optional.some(elem); - }); - }); - } else { - return Optional.none(); - } + // if a comment or zero-length text, scan the siblings + if ((universe.property().isText(element) && universe.property().getText(element).trim().length === 0) + || universe.property().isComment(element)) { + return direction(element).bind((elem) => { + return scan(universe, elem, direction).orThunk(() => { + return Optional.some(elem); + }); + }); + } + else { + return Optional.none(); + } }; const toEnd = (universe, element) => { - if (universe.property().isText(element)) { - return universe.property().getText(element).length; - } - const children = universe.property().children(element); - return children.length; + if (universe.property().isText(element)) { + return universe.property().getText(element).length; + } + const children = universe.property().children(element); + return children.length; }; const freefallRtl$2 = (universe, element) => { - const candidate = scan(universe, element, universe.query().prevSibling).getOr(element); - if (universe.property().isText(candidate)) { - return point(candidate, toEnd(universe, candidate)); - } - const children = universe.property().children(candidate); - return children.length > 0 ? freefallRtl$2(universe, children[children.length - 1]) : point(candidate, toEnd(universe, candidate)); + const candidate = scan(universe, element, universe.query().prevSibling).getOr(element); + if (universe.property().isText(candidate)) { + return point(candidate, toEnd(universe, candidate)); + } + const children = universe.property().children(candidate); + return children.length > 0 ? freefallRtl$2(universe, children[children.length - 1]) : point(candidate, toEnd(universe, candidate)); }; const freefallRtl$1 = freefallRtl$2; const universe = DomUniverse(); - const freefallRtl = element => { - return freefallRtl$1(universe, element); + const freefallRtl = (element) => { + return freefallRtl$1(universe, element); }; - const fireToggleAccordionEvent = (editor, element, state) => editor.dispatch('ToggledAccordion', { - element, - state - }); - const fireToggleAllAccordionsEvent = (editor, elements, state) => editor.dispatch('ToggledAllAccordions', { - elements, - state - }); + const fireToggleAccordionEvent = (editor, element, state) => editor.dispatch('ToggledAccordion', { element, state }); + const fireToggleAllAccordionsEvent = (editor, elements, state) => editor.dispatch('ToggledAllAccordions', { elements, state }); const accordionTag = 'details'; const accordionDetailsClass = 'mce-accordion'; @@ -738,320 +1014,336 @@ var global$3 = tinymce.util.Tools.resolve('tinymce.util.Tools'); - const isSummary = node => (node === null || node === void 0 ? void 0 : node.nodeName) === 'SUMMARY'; - const isDetails = node => (node === null || node === void 0 ? void 0 : node.nodeName) === 'DETAILS'; - const isOpen = details => details.hasAttribute('open'); - const isInSummary = editor => { - const node = editor.selection.getNode(); - return isSummary(node) || Boolean(editor.dom.getParent(node, isSummary)); - }; - const isAtDetailsStart = editor => { - const rng = editor.selection.getRng(); - return isDetails(rng.startContainer) && rng.collapsed && rng.startOffset === 0; - }; - const isInsertAllowed = editor => !isInSummary(editor) && editor.dom.isEditable(editor.selection.getNode()) && !editor.mode.isReadOnly(); - const getSelectedDetails = editor => Optional.from(editor.dom.getParent(editor.selection.getNode(), isDetails)); - const isDetailsSelected = editor => getSelectedDetails(editor).isSome(); - const insertBogus = element => { - element.innerHTML = '
'; - return element; - }; - const createParagraph = editor => insertBogus(editor.dom.create('p')); - const createSummary = editor => insertBogus(editor.dom.create('summary')); + const isSummary = (node) => (node === null || node === void 0 ? void 0 : node.nodeName) === 'SUMMARY'; + const isDetails = (node) => (node === null || node === void 0 ? void 0 : node.nodeName) === 'DETAILS'; + const isOpen = (details) => details.hasAttribute('open'); + const isInSummary = (editor) => { + const node = editor.selection.getNode(); + return isSummary(node) || Boolean(editor.dom.getParent(node, isSummary)); + }; + const isAtDetailsStart = (editor) => { + const rng = editor.selection.getRng(); + return isDetails(rng.startContainer) + && rng.collapsed + && rng.startOffset === 0; + }; + const isInsertAllowed = (editor) => !isInSummary(editor) && editor.dom.isEditable(editor.selection.getNode()) && !editor.mode.isReadOnly(); + const getSelectedDetails = (editor) => Optional.from(editor.dom.getParent(editor.selection.getNode(), isDetails)); + const isDetailsSelected = (editor) => getSelectedDetails(editor).isSome(); + const insertBogus = (element) => { + element.innerHTML = '
'; + return element; + }; + const createParagraph = (editor) => insertBogus(editor.dom.create('p')); + const createSummary = (editor) => insertBogus(editor.dom.create('summary')); const insertAndSelectParagraphAfter = (editor, target) => { - const paragraph = createParagraph(editor); - target.insertAdjacentElement('afterend', paragraph); - editor.selection.setCursorLocation(paragraph, 0); - }; - const normalizeContent = (editor, accordion) => { - if (isSummary(accordion === null || accordion === void 0 ? void 0 : accordion.lastChild)) { const paragraph = createParagraph(editor); - accordion.appendChild(paragraph); + target.insertAdjacentElement('afterend', paragraph); editor.selection.setCursorLocation(paragraph, 0); - } + }; + const normalizeContent = (editor, accordion) => { + if (isSummary(accordion === null || accordion === void 0 ? void 0 : accordion.lastChild)) { + const paragraph = createParagraph(editor); + accordion.appendChild(paragraph); + editor.selection.setCursorLocation(paragraph, 0); + } }; const normalizeSummary = (editor, accordion) => { - if (!isSummary(accordion === null || accordion === void 0 ? void 0 : accordion.firstChild)) { - const summary = createSummary(editor); - accordion.prepend(summary); - editor.selection.setCursorLocation(summary, 0); - } + if (!isSummary(accordion === null || accordion === void 0 ? void 0 : accordion.firstChild)) { + const summary = createSummary(editor); + accordion.prepend(summary); + editor.selection.setCursorLocation(summary, 0); + } }; - const normalizeAccordion = editor => accordion => { - normalizeContent(editor, accordion); - normalizeSummary(editor, accordion); + const normalizeAccordion = (editor) => (accordion) => { + normalizeContent(editor, accordion); + normalizeSummary(editor, accordion); }; - const normalizeDetails = editor => { - global$3.each(global$3.grep(editor.dom.select('details', editor.getBody())), normalizeAccordion(editor)); + const normalizeDetails = (editor) => { + global$3.each(global$3.grep(editor.dom.select('details', editor.getBody())), normalizeAccordion(editor)); }; - const insertAccordion = editor => { - if (!isInsertAllowed(editor)) { - return; - } - const editorBody = SugarElement.fromDom(editor.getBody()); - const uid = generate('acc'); - const summaryText = editor.dom.encode(editor.selection.getRng().toString() || editor.translate('Accordion summary...')); - const bodyText = editor.dom.encode(editor.translate('Accordion body...')); - const accordionSummaryHtml = `${ summaryText }`; - const accordionBodyHtml = `<${ accordionBodyWrapperTag } class="${ accordionBodyWrapperClass }">

${ bodyText }

`; - editor.undoManager.transact(() => { - editor.insertContent([ - `
`, - accordionSummaryHtml, - accordionBodyHtml, - `
` - ].join('')); - descendant(editorBody, `[data-mce-id="${ uid }"]`).each(detailsElm => { - remove$2(detailsElm, 'data-mce-id'); - descendant(detailsElm, `summary`).each(summaryElm => { - const rng = editor.dom.createRng(); - const des = freefallRtl(summaryElm); - rng.setStart(des.element.dom, des.offset); - rng.setEnd(des.element.dom, des.offset); - editor.selection.setRng(rng); - }); + const insertAccordion = (editor) => { + if (!isInsertAllowed(editor)) { + return; + } + const editorBody = SugarElement.fromDom(editor.getBody()); + const uid = generate('acc'); + const summaryText = editor.dom.encode(editor.selection.getRng().toString() || editor.translate('Accordion summary...')); + const bodyText = editor.dom.encode(editor.translate('Accordion body...')); + const accordionSummaryHtml = `${summaryText}`; + const accordionBodyHtml = `<${accordionBodyWrapperTag} class="${accordionBodyWrapperClass}">

${bodyText}

`; + editor.undoManager.transact(() => { + editor.insertContent([ + `
`, + accordionSummaryHtml, + accordionBodyHtml, + `
` + ].join('')); + descendant(editorBody, `[data-mce-id="${uid}"]`).each((detailsElm) => { + remove$2(detailsElm, 'data-mce-id'); + descendant(detailsElm, `summary`).each((summaryElm) => { + // Set the cursor location to be at the end of the summary text + const rng = editor.dom.createRng(); + const des = freefallRtl(summaryElm); + rng.setStart(des.element.dom, des.offset); + rng.setEnd(des.element.dom, des.offset); + editor.selection.setRng(rng); + }); + }); }); - }); }; const toggleDetailsElement = (details, state) => { - const shouldOpen = state !== null && state !== void 0 ? state : !isOpen(details); - if (shouldOpen) { - details.setAttribute('open', 'open'); - } else { - details.removeAttribute('open'); - } - return shouldOpen; + const shouldOpen = state !== null && state !== void 0 ? state : !isOpen(details); + if (shouldOpen) { + details.setAttribute('open', 'open'); + } + else { + details.removeAttribute('open'); + } + return shouldOpen; }; const toggleAccordion = (editor, state) => { - getSelectedDetails(editor).each(details => { - fireToggleAccordionEvent(editor, details, toggleDetailsElement(details, state)); - }); - }; - const removeAccordion = editor => { - if (!editor.mode.isReadOnly()) { - getSelectedDetails(editor).each(details => { - const {nextSibling} = details; - if (nextSibling) { - editor.selection.select(nextSibling, true); - editor.selection.collapse(true); - } else { - insertAndSelectParagraphAfter(editor, details); - } - details.remove(); + getSelectedDetails(editor).each((details) => { + fireToggleAccordionEvent(editor, details, toggleDetailsElement(details, state)); }); - } + }; + const removeAccordion = (editor) => { + if (!editor.mode.isReadOnly()) { + getSelectedDetails(editor) + .each((details) => { + const { nextSibling } = details; + if (nextSibling) { + editor.selection.select(nextSibling, true); + editor.selection.collapse(true); + } + else { + insertAndSelectParagraphAfter(editor, details); + } + details.remove(); + }); + } }; const toggleAllAccordions = (editor, state) => { - const accordions = Array.from(editor.getBody().querySelectorAll('details')); - if (accordions.length === 0) { - return; - } - each$1(accordions, accordion => toggleDetailsElement(accordion, state !== null && state !== void 0 ? state : !isOpen(accordion))); - fireToggleAllAccordionsEvent(editor, accordions, state); + const accordions = Array.from(editor.getBody().querySelectorAll('details')); + if (accordions.length === 0) { + return; + } + each$1(accordions, (accordion) => toggleDetailsElement(accordion, state !== null && state !== void 0 ? state : !isOpen(accordion))); + fireToggleAllAccordionsEvent(editor, accordions, state); }; - const register$1 = editor => { - editor.addCommand('InsertAccordion', () => insertAccordion(editor)); - editor.addCommand('ToggleAccordion', (_ui, value) => toggleAccordion(editor, value)); - editor.addCommand('ToggleAllAccordions', (_ui, value) => toggleAllAccordions(editor, value)); - editor.addCommand('RemoveAccordion', () => removeAccordion(editor)); + const register$1 = (editor) => { + editor.addCommand('InsertAccordion', () => insertAccordion(editor)); + editor.addCommand('ToggleAccordion', (_ui, value) => toggleAccordion(editor, value)); + editor.addCommand('ToggleAllAccordions', (_ui, value) => toggleAllAccordions(editor, value)); + editor.addCommand('RemoveAccordion', () => removeAccordion(editor)); }; var global$2 = tinymce.util.Tools.resolve('tinymce.html.Node'); - const getClassList = node => { - var _a, _b; - return (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : []; - }; + const getClassList = (node) => { var _a, _b; return (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : []; }; const addClasses = (node, classes) => { - const classListSet = new Set([ - ...getClassList(node), - ...classes - ]); - const newClassList = Array.from(classListSet); - if (newClassList.length > 0) { - node.attr('class', newClassList.join(' ')); - } + const classListSet = new Set([...getClassList(node), ...classes]); + const newClassList = Array.from(classListSet); + if (newClassList.length > 0) { + node.attr('class', newClassList.join(' ')); + } }; const removeClasses = (node, classes) => { - const newClassList = filter(getClassList(node), clazz => !classes.has(clazz)); - node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null); - }; - const isAccordionDetailsNode = node => node.name === accordionTag && contains(getClassList(node), accordionDetailsClass); - const isAccordionBodyWrapperNode = node => node.name === accordionBodyWrapperTag && contains(getClassList(node), accordionBodyWrapperClass); - const getAccordionChildren = accordionNode => { - const children = accordionNode.children(); - let summaryNode; - let wrapperNode; - const otherNodes = []; - for (let i = 0; i < children.length; i++) { - const child = children[i]; - if (child.name === 'summary' && isNullable(summaryNode)) { - summaryNode = child; - } else if (isAccordionBodyWrapperNode(child) && isNullable(wrapperNode)) { - wrapperNode = child; - } else { - otherNodes.push(child); - } - } - return { - summaryNode, - wrapperNode, - otherNodes - }; - }; - const padInputNode = node => { - const br = new global$2('br', 1); - br.attr('data-mce-bogus', '1'); - node.empty(); - node.append(br); - }; - const setup$2 = editor => { - editor.on('PreInit', () => { - const {serializer, parser} = editor; - parser.addNodeFilter(accordionTag, nodes => { - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; - if (isAccordionDetailsNode(node)) { - const accordionNode = node; - const {summaryNode, wrapperNode, otherNodes} = getAccordionChildren(accordionNode); - const hasSummaryNode = isNonNullable(summaryNode); - const newSummaryNode = hasSummaryNode ? summaryNode : new global$2('summary', 1); - if (isNullable(newSummaryNode.firstChild)) { - padInputNode(newSummaryNode); - } - addClasses(newSummaryNode, [accordionSummaryClass]); - if (!hasSummaryNode) { - if (isNonNullable(accordionNode.firstChild)) { - accordionNode.insert(newSummaryNode, accordionNode.firstChild, true); - } else { - accordionNode.append(newSummaryNode); - } - } - const hasWrapperNode = isNonNullable(wrapperNode); - const newWrapperNode = hasWrapperNode ? wrapperNode : new global$2(accordionBodyWrapperTag, 1); - newWrapperNode.attr('data-mce-bogus', '1'); - addClasses(newWrapperNode, [accordionBodyWrapperClass]); - if (otherNodes.length > 0) { - for (let j = 0; j < otherNodes.length; j++) { - const otherNode = otherNodes[j]; - newWrapperNode.append(otherNode); - } - } - if (isNullable(newWrapperNode.firstChild)) { - const pNode = new global$2('p', 1); - padInputNode(pNode); - newWrapperNode.append(pNode); - } - if (!hasWrapperNode) { - accordionNode.append(newWrapperNode); - } + const newClassList = filter(getClassList(node), (clazz) => !classes.has(clazz)); + node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null); + }; + const isAccordionDetailsNode = (node) => node.name === accordionTag && contains(getClassList(node), accordionDetailsClass); + const isAccordionBodyWrapperNode = (node) => node.name === accordionBodyWrapperTag && contains(getClassList(node), accordionBodyWrapperClass); + const getAccordionChildren = (accordionNode) => { + const children = accordionNode.children(); + let summaryNode; + let wrapperNode; + const otherNodes = []; + for (let i = 0; i < children.length; i++) { + const child = children[i]; + // Only want to get the first summary element + if (child.name === 'summary' && isNullable(summaryNode)) { + summaryNode = child; } - } - }); - serializer.addNodeFilter(accordionTag, nodes => { - const summaryClassRemoveSet = new Set([accordionSummaryClass]); - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; - if (isAccordionDetailsNode(node)) { - const accordionNode = node; - const {summaryNode, wrapperNode} = getAccordionChildren(accordionNode); - if (isNonNullable(summaryNode)) { - removeClasses(summaryNode, summaryClassRemoveSet); - } - if (isNonNullable(wrapperNode)) { - wrapperNode.unwrap(); - } + else if (isAccordionBodyWrapperNode(child) && isNullable(wrapperNode)) { + wrapperNode = child; } - } + else { + otherNodes.push(child); + } + } + return { + summaryNode, + wrapperNode, + otherNodes + }; + }; + const padInputNode = (node) => { + // Add br to node to ensure the cursor can be placed inside the node + // Mark as bogus so that it is converted to an nbsp on serialization + const br = new global$2('br', 1); + br.attr('data-mce-bogus', '1'); + node.empty(); + node.append(br); + }; + const setup$2 = (editor) => { + editor.on('PreInit', () => { + const { serializer, parser } = editor; + // Purpose: + // - add mce-accordion-summary class to summary node + // - wrap details body in div and add mce-accordion-body class (TINY-9959 assists with Chrome selection issue) + parser.addNodeFilter(accordionTag, (nodes) => { + // Using a traditional for loop here as we may have to iterate over many nodes and it is the most performant way of doing so + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (isAccordionDetailsNode(node)) { + const accordionNode = node; + const { summaryNode, wrapperNode, otherNodes } = getAccordionChildren(accordionNode); + const hasSummaryNode = isNonNullable(summaryNode); + const newSummaryNode = hasSummaryNode ? summaryNode : new global$2('summary', 1); + // If there is nothing in the summary, pad it with a br + // so the cursor can be put inside the accordion summary + if (isNullable(newSummaryNode.firstChild)) { + padInputNode(newSummaryNode); + } + addClasses(newSummaryNode, [accordionSummaryClass]); + if (!hasSummaryNode) { + if (isNonNullable(accordionNode.firstChild)) { + accordionNode.insert(newSummaryNode, accordionNode.firstChild, true); + } + else { + accordionNode.append(newSummaryNode); + } + } + const hasWrapperNode = isNonNullable(wrapperNode); + const newWrapperNode = hasWrapperNode ? wrapperNode : new global$2(accordionBodyWrapperTag, 1); + newWrapperNode.attr('data-mce-bogus', '1'); + addClasses(newWrapperNode, [accordionBodyWrapperClass]); + if (otherNodes.length > 0) { + for (let j = 0; j < otherNodes.length; j++) { + const otherNode = otherNodes[j]; + newWrapperNode.append(otherNode); + } + } + // If there is nothing in the wrapper, append a placeholder p tag + // so the cursor can be put inside the accordion body + if (isNullable(newWrapperNode.firstChild)) { + const pNode = new global$2('p', 1); + padInputNode(pNode); + newWrapperNode.append(pNode); + } + if (!hasWrapperNode) { + accordionNode.append(newWrapperNode); + } + } + } + }); + // Purpose: + // - remove div wrapping details content as it is only required during editor (see TINY-9959 for details) + // - remove mce-accordion-summary class on the summary node + serializer.addNodeFilter(accordionTag, (nodes) => { + const summaryClassRemoveSet = new Set([accordionSummaryClass]); + // Using a traditional for loop here as we may have to iterate over many nodes and it is the most performant way of doing so + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (isAccordionDetailsNode(node)) { + const accordionNode = node; + const { summaryNode, wrapperNode } = getAccordionChildren(accordionNode); + if (isNonNullable(summaryNode)) { + removeClasses(summaryNode, summaryClassRemoveSet); + } + if (isNonNullable(wrapperNode)) { + wrapperNode.unwrap(); + } + } + } + }); }); - }); }; var global$1 = tinymce.util.Tools.resolve('tinymce.util.VK'); - const setupEnterKeyInSummary = editor => { - editor.on('keydown', event => { - if (!event.shiftKey && event.keyCode === global$1.ENTER && isInSummary(editor) || isAtDetailsStart(editor)) { - event.preventDefault(); - editor.execCommand('ToggleAccordion'); - } - }); + const setupEnterKeyInSummary = (editor) => { + editor.on('keydown', (event) => { + if (!event.shiftKey && event.keyCode === global$1.ENTER + && isInSummary(editor) || isAtDetailsStart(editor)) { + event.preventDefault(); + editor.execCommand('ToggleAccordion'); + } + }); }; - const setup$1 = editor => { - setupEnterKeyInSummary(editor); - editor.on('ExecCommand', e => { - const cmd = e.command.toLowerCase(); - if ((cmd === 'delete' || cmd === 'forwarddelete') && isDetailsSelected(editor)) { - normalizeDetails(editor); - } - }); + const setup$1 = (editor) => { + setupEnterKeyInSummary(editor); + editor.on('ExecCommand', (e) => { + const cmd = e.command.toLowerCase(); + if ((cmd === 'delete' || cmd === 'forwarddelete') && isDetailsSelected(editor)) { + normalizeDetails(editor); + } + }); }; var global = tinymce.util.Tools.resolve('tinymce.Env'); - const setup = editor => { - if (global.browser.isSafari()) { - editor.on('click', e => { - if (isSummary(e.target)) { - const summary = e.target; - const rng = editor.selection.getRng(); - if (rng.collapsed && rng.startContainer === summary.parentNode && rng.startOffset === 0) { - editor.selection.setCursorLocation(summary, 0); - } - } - }); - } + const setup = (editor) => { + // TINY-10177: On Safari, clicking on the expand arrow of the `details` element sets the selection before the `summary`, + // so we override the selection to the beginning of `summary` content + if (global.browser.isSafari()) { + editor.on('click', (e) => { + if (isSummary(e.target)) { + const summary = e.target; + const rng = editor.selection.getRng(); + if (rng.collapsed && rng.startContainer === summary.parentNode && rng.startOffset === 0) { + editor.selection.setCursorLocation(summary, 0); + } + } + }); + } }; - const onSetup = editor => buttonApi => { - const onNodeChange = () => buttonApi.setEnabled(isInsertAllowed(editor)); - editor.on('NodeChange', onNodeChange); - return () => editor.off('NodeChange', onNodeChange); - }; - const register = editor => { - const onAction = () => editor.execCommand('InsertAccordion'); - editor.ui.registry.addButton('accordion', { - icon: 'accordion', - tooltip: 'Insert accordion', - onSetup: onSetup(editor), - onAction - }); - editor.ui.registry.addMenuItem('accordion', { - icon: 'accordion', - text: 'Accordion', - onSetup: onSetup(editor), - onAction - }); - editor.ui.registry.addToggleButton('accordiontoggle', { - icon: 'accordion-toggle', - tooltip: 'Toggle accordion', - onAction: () => editor.execCommand('ToggleAccordion') - }); - editor.ui.registry.addToggleButton('accordionremove', { - icon: 'remove', - tooltip: 'Delete accordion', - onAction: () => editor.execCommand('RemoveAccordion') - }); - editor.ui.registry.addContextToolbar('accordion', { - predicate: accordion => editor.dom.is(accordion, 'details') && editor.getBody().contains(accordion) && editor.dom.isEditable(accordion.parentNode), - items: 'accordiontoggle accordionremove', - scope: 'node', - position: 'node' - }); + const onSetup = (editor) => (buttonApi) => { + const onNodeChange = () => buttonApi.setEnabled(isInsertAllowed(editor)); + editor.on('NodeChange', onNodeChange); + return () => editor.off('NodeChange', onNodeChange); + }; + const register = (editor) => { + const onAction = () => editor.execCommand('InsertAccordion'); + editor.ui.registry.addButton('accordion', { icon: 'accordion', tooltip: 'Insert accordion', onSetup: onSetup(editor), onAction }); + editor.ui.registry.addMenuItem('accordion', { icon: 'accordion', text: 'Accordion', onSetup: onSetup(editor), onAction }); + editor.ui.registry.addToggleButton('accordiontoggle', { + icon: 'accordion-toggle', + tooltip: 'Toggle accordion', + onAction: () => editor.execCommand('ToggleAccordion') + }); + editor.ui.registry.addToggleButton('accordionremove', { + icon: 'remove', + tooltip: 'Delete accordion', + onAction: () => editor.execCommand('RemoveAccordion') + }); + editor.ui.registry.addContextToolbar('accordion', { + predicate: (accordion) => editor.dom.is(accordion, 'details') && editor.getBody().contains(accordion) && editor.dom.isEditable(accordion.parentNode), + items: 'accordiontoggle accordionremove', + scope: 'node', + position: 'node' + }); }; var Plugin = () => { - global$4.add('accordion', editor => { - register(editor); - register$1(editor); - setup$1(editor); - setup$2(editor); - setup(editor); - }); + global$4.add('accordion', (editor) => { + register(editor); + register$1(editor); + setup$1(editor); + setup$2(editor); + setup(editor); + }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/accordion/plugin.min.js b/public/ext/tinymce/plugins/accordion/plugin.min.js index 200a489..3b919dd 100644 --- a/public/ext/tinymce/plugins/accordion/plugin.min.js +++ b/public/ext/tinymce/plugins/accordion/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const o=e=>t=>typeof t===e,n=e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(e),r=o("boolean"),s=e=>null==e,i=e=>!s(e),a=o("function"),d=o("number"),l=e=>()=>e,c=(e,t)=>e===t,m=l(!1);class u{constructor(e,t){this.tag=e,this.value=t}static some(e){return new u(!0,e)}static none(){return u.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?u.some(e(this.value)):u.none()}bind(e){return this.tag?e(this.value):u.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:u.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return i(e)?u.some(e):u.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}u.singletonNone=new u(!1);const g=Array.prototype.indexOf,p=(e,t)=>{return o=e,n=t,g.call(o,n)>-1;var o,n},h=(e,t)=>{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;oe.dom.nodeName.toLowerCase(),w=e=>e.dom.nodeType,b=e=>t=>w(t)===e,N=b(1),T=b(3),A=b(9),C=b(11),S=(e,t,o)=>{if(!(n(o)||r(o)||d(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},x=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},D=(e,t)=>u.from(x(e,t)),E=(e,t)=>{e.dom.removeAttribute(t)},O=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},M={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return O(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return O(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return O(o)},fromDom:O,fromPoint:(e,t,o)=>u.from(e.dom.elementFromPoint(t,o)).map(O)},P=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},R=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,k=P,B=(L=/^\s+|\s+$/g,e=>e.replace(L,""));var L;const $=e=>void 0!==e.style&&a(e.style.getPropertyValue),V=e=>u.from(e.dom.parentNode).map(M.fromDom),I=e=>u.from(e.dom.nextSibling).map(M.fromDom),j=e=>h(e.dom.childNodes,M.fromDom),q=e=>M.fromDom(e.dom.host),F=e=>{const t=T(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=(e=>M.fromDom(e.dom.getRootNode()))(e);return C(o=t)&&i(o.dom.host)?u.some(t):u.none();var o})(M.fromDom(t)).fold((()=>o.body.contains(t)),(n=F,r=q,e=>n(r(e))));var n,r},H=(e,t)=>$(e)?e.style.getPropertyValue(t):"",z=(e,t)=>{V(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},K=(e,t)=>{I(e).fold((()=>{V(e).each((e=>{U(e,t)}))}),(e=>{z(e,t)}))},U=(e,t)=>{e.dom.appendChild(t.dom)},Y=(e,t)=>{f(t,((o,n)=>{const r=0===n?e:t[n-1];K(r,o)}))},_=(e,t)=>{let o=[];return f(j(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(_(e,t))})),o},G=(e,t,o)=>{let n=e.dom;const r=a(o)?o:m;for(;n.parentNode;){n=n.parentNode;const e=M.fromDom(n);if(t(e))return u.some(e);if(r(e))break}return u.none()},J=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Q=(e,t,o)=>G(e,(e=>P(e,t)),o),W=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return R(o)?u.none():u.from(o.querySelector(e)).map(M.fromDom)})(t,e),X=(e=>{const t=t=>e(t)?u.from(t.dom.nodeValue):u.none();return{get:o=>{if(!e(o))throw new Error("Can only get text value of a text node");return t(o).getOr("")},getOption:t,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(T);var Z=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"];const ee=(e,t)=>({element:e,offset:t}),te=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>te(e,t,o).orThunk((()=>u.some(t))))):u.none(),oe=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,ne=(e,t)=>{const o=te(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return ee(o,oe(e,o));const n=e.property().children(o);return n.length>0?ne(e,n[n.length-1]):ee(o,oe(e,o))},re=ne,se={up:l({selector:Q,closest:(e,t,o)=>((e,t,o,n,r)=>((e,t)=>P(e,t))(o,n)?u.some(o):a(r)&&r(o)?u.none():t(o,n,r))(0,Q,e,t,o),predicate:G,all:(e,t)=>{const o=a(t)?t:m;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=M.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r}}),down:l({selector:(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return R(o)?[]:h(o.querySelectorAll(e),M.fromDom)})(t,e),predicate:_}),styles:l({get:(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||F(e)?n:H(o,t)},getRaw:(e,t)=>{const o=e.dom,n=H(o,t);return u.from(n).filter((e=>e.length>0))},set:(e,t,o)=>{((e,t,o)=>{if(!n(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);$(e)&&e.style.setProperty(t,o)})(e.dom,t,o)},remove:(e,t)=>{((e,t)=>{$(e)&&e.style.removeProperty(t)})(e.dom,t),((e,t,o=c)=>e.exists((e=>o(e,t))))(D(e,"style").map(B),"")&&E(e,"style")}}),attrs:l({get:x,set:(e,t,o)=>{S(e.dom,t,o)},remove:E,copyTo:(e,t)=>{const o=(n=e.dom.attributes,r=(e,t)=>(e[t.name]=t.value,e),s={},f(n,((e,t)=>{s=r(s,e)})),s);var n,r,s;((e,t)=>{const o=e.dom;((e,t)=>{const o=y(e);for(let n=0,r=o.length;n{S(o,t,e)}))})(t,o)}}),insert:l({before:z,after:K,afterAll:Y,append:U,appendAll:(e,t)=>{f(t,(t=>{U(e,t)}))},prepend:(e,t)=>{(e=>(e=>{const t=e.dom.childNodes;return u.from(t[0]).map(M.fromDom)})(e))(e).fold((()=>{U(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},wrap:(e,t)=>{z(e,t),U(t,e)}}),remove:l({unwrap:e=>{const t=j(e);t.length>0&&Y(e,t),J(e)},remove:J}),create:l({nu:M.fromTag,clone:e=>M.fromDom(e.dom.cloneNode(!1)),text:M.fromText}),query:l({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:e=>u.from(e.dom.previousSibling).map(M.fromDom),nextSibling:I}),property:l({children:j,name:v,parent:V,document:e=>{return(t=e,A(t)?t:M.fromDom(t.dom.ownerDocument)).dom;var t},isText:T,isComment:e=>8===w(e)||"#comment"===v(e),isElement:N,isSpecial:e=>{const t=v(e);return p(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>N(e)?D(e,"lang"):u.none(),getText:e=>X.get(e),setText:(e,t)=>X.set(e,t),isBoundary:e=>!!N(e)&&("body"===v(e)||p(Z,v(e))),isEmptyTag:e=>!!N(e)&&p(["br","img","hr","input"],v(e)),isNonEditable:e=>N(e)&&"false"===x(e,"contenteditable")}),eq:(e,t)=>e.dom===t.dom,is:k},ie="details",ae="mce-accordion",de="mce-accordion-summary",le="mce-accordion-body",ce="div";var me=tinymce.util.Tools.resolve("tinymce.util.Tools");const ue=e=>"SUMMARY"===(null==e?void 0:e.nodeName),ge=e=>"DETAILS"===(null==e?void 0:e.nodeName),pe=e=>e.hasAttribute("open"),he=e=>{const t=e.selection.getNode();return ue(t)||Boolean(e.dom.getParent(t,ue))},fe=e=>!he(e)&&e.dom.isEditable(e.selection.getNode())&&!e.mode.isReadOnly(),ye=e=>u.from(e.dom.getParent(e.selection.getNode(),ge)),ve=e=>(e.innerHTML='
',e),we=e=>ve(e.dom.create("p")),be=e=>t=>{((e,t)=>{if(ue(null==t?void 0:t.lastChild)){const o=we(e);t.appendChild(o),e.selection.setCursorLocation(o,0)}})(e,t),((e,t)=>{if(!ue(null==t?void 0:t.firstChild)){const o=(e=>ve(e.dom.create("summary")))(e);t.prepend(o),e.selection.setCursorLocation(o,0)}})(e,t)},Ne=e=>{if(!fe(e))return;const o=M.fromDom(e.getBody()),n=(e=>{const o=(new Date).getTime(),n=Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295*1e9);return t++,e+"_"+n+t+String(o)})("acc"),r=e.dom.encode(e.selection.getRng().toString()||e.translate("Accordion summary...")),s=e.dom.encode(e.translate("Accordion body...")),i=`${r}`,a=`<${ce} class="${le}">

${s}

`;e.undoManager.transact((()=>{e.insertContent([`
`,i,a,"
"].join("")),W(o,`[data-mce-id="${n}"]`).each((t=>{E(t,"data-mce-id"),W(t,"summary").each((t=>{const o=e.dom.createRng(),n=re(se,t);o.setStart(n.element.dom,n.offset),o.setEnd(n.element.dom,n.offset),e.selection.setRng(o)}))}))}))},Te=(e,t)=>{const o=null!=t?t:!pe(e);return o?e.setAttribute("open","open"):e.removeAttribute("open"),o},Ae=e=>{e.addCommand("InsertAccordion",(()=>Ne(e))),e.addCommand("ToggleAccordion",((t,o)=>((e,t)=>{ye(e).each((o=>{((e,t,o)=>{e.dispatch("ToggledAccordion",{element:t,state:o})})(e,o,Te(o,t))}))})(e,o))),e.addCommand("ToggleAllAccordions",((t,o)=>((e,t)=>{const o=Array.from(e.getBody().querySelectorAll("details"));0!==o.length&&(f(o,(e=>Te(e,null!=t?t:!pe(e)))),((e,t,o)=>{e.dispatch("ToggledAllAccordions",{elements:t,state:o})})(e,o,t))})(e,o))),e.addCommand("RemoveAccordion",(()=>(e=>{e.mode.isReadOnly()||ye(e).each((t=>{const{nextSibling:o}=t;o?(e.selection.select(o,!0),e.selection.collapse(!0)):((e,t)=>{const o=we(e);t.insertAdjacentElement("afterend",o),e.selection.setCursorLocation(o,0)})(e,t),t.remove()}))})(e)))};var Ce=tinymce.util.Tools.resolve("tinymce.html.Node");const Se=e=>{var t,o;return null!==(o=null===(t=e.attr("class"))||void 0===t?void 0:t.split(" "))&&void 0!==o?o:[]},xe=(e,t)=>{const o=new Set([...Se(e),...t]),n=Array.from(o);n.length>0&&e.attr("class",n.join(" "))},De=(e,t)=>{const o=(e=>{const o=[];for(let r=0,s=e.length;r0?o.join(" "):null)},Ee=e=>e.name===ie&&p(Se(e),ae),Oe=e=>{const t=e.children();let o,n;const r=[];for(let e=0;e{const t=new Ce("br",1);t.attr("data-mce-bogus","1"),e.empty(),e.append(t)};var Pe=tinymce.util.Tools.resolve("tinymce.util.VK");const Re=e=>{(e=>{e.on("keydown",(t=>{(!t.shiftKey&&t.keyCode===Pe.ENTER&&he(e)||(e=>{const t=e.selection.getRng();return ge(t.startContainer)&&t.collapsed&&0===t.startOffset})(e))&&(t.preventDefault(),e.execCommand("ToggleAccordion"))}))})(e),e.on("ExecCommand",(t=>{const o=t.command.toLowerCase();"delete"!==o&&"forwarddelete"!==o||!(e=>ye(e).isSome())(e)||(e=>{me.each(me.grep(e.dom.select("details",e.getBody())),be(e))})(e)}))};var ke=tinymce.util.Tools.resolve("tinymce.Env");const Be=e=>t=>{const o=()=>t.setEnabled(fe(e));return e.on("NodeChange",o),()=>e.off("NodeChange",o)};e.add("accordion",(e=>{(e=>{const t=()=>e.execCommand("InsertAccordion");e.ui.registry.addButton("accordion",{icon:"accordion",tooltip:"Insert accordion",onSetup:Be(e),onAction:t}),e.ui.registry.addMenuItem("accordion",{icon:"accordion",text:"Accordion",onSetup:Be(e),onAction:t}),e.ui.registry.addToggleButton("accordiontoggle",{icon:"accordion-toggle",tooltip:"Toggle accordion",onAction:()=>e.execCommand("ToggleAccordion")}),e.ui.registry.addToggleButton("accordionremove",{icon:"remove",tooltip:"Delete accordion",onAction:()=>e.execCommand("RemoveAccordion")}),e.ui.registry.addContextToolbar("accordion",{predicate:t=>e.dom.is(t,"details")&&e.getBody().contains(t)&&e.dom.isEditable(t.parentNode),items:"accordiontoggle accordionremove",scope:"node",position:"node"})})(e),Ae(e),Re(e),(e=>{e.on("PreInit",(()=>{const{serializer:t,parser:o}=e;o.addNodeFilter(ie,(e=>{for(let t=0;t0)for(let e=0;e{const t=new Set([de]);for(let o=0;o{ke.browser.isSafari()&&e.on("click",(t=>{if(ue(t.target)){const o=t.target,n=e.selection.getRng();n.collapsed&&n.startContainer===o.parentNode&&0===n.startOffset&&e.selection.setCursorLocation(o,0)}}))})(e)}))}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>typeof t===e,o=e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(e),n=t("boolean"),r=e=>null==e,s=e=>!r(e),a=t("function"),i=t("number"),l=e=>()=>e,d=(e,t)=>e===t,c=l(!1);class m{constructor(e,t){this.tag=e,this.value=t}static some(e){return new m(!0,e)}static none(){return m.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?m.some(e(this.value)):m.none()}bind(e){return this.tag?e(this.value):m.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:m.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?m.some(e):m.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}m.singletonNone=new m(!1);const u=Array.prototype.indexOf,g=(e,t)=>{return o=e,n=t,u.call(o,n)>-1;var o,n},p=(e,t)=>{const o=e.length,n=new Array(o);for(let r=0;r{for(let o=0,n=e.length;oe.replace(w,""));var w;const b=(e,t)=>({element:e,offset:t}),N=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},T={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return N(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return N(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return N(o)},fromDom:N,fromPoint:(e,t,o)=>m.from(e.dom.elementFromPoint(t,o)).map(N)},A=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},C=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,S=A,x=e=>e.dom.nodeName.toLowerCase(),D=e=>e.dom.nodeType,E=e=>t=>D(t)===e,O=E(1),M=E(3),P=E(9),R=E(11),k=e=>m.from(e.dom.parentNode).map(T.fromDom),B=e=>m.from(e.dom.nextSibling).map(T.fromDom),L=e=>p(e.dom.childNodes,T.fromDom),$=e=>T.fromDom(e.dom.host),V=(e,t)=>{k(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},I=(e,t)=>{B(e).fold((()=>{k(e).each((e=>{j(e,t)}))}),(e=>{V(e,t)}))},j=(e,t)=>{e.dom.appendChild(t.dom)},q=(e,t)=>{h(t,((o,n)=>{const r=0===n?e:t[n-1];I(r,o)}))},H=(e,t,r)=>{if(!(o(r)||n(r)||i(r)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",r,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,r+"")},z=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},F=(e,t)=>m.from(z(e,t)),K=(e,t)=>{e.dom.removeAttribute(t)},U=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Y=e=>void 0!==e.style&&a(e.style.getPropertyValue),_=e=>{const t=M(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=(e=>T.fromDom(e.dom.getRootNode()))(e);return R(o=t)&&s(o.dom.host)?m.some(t):m.none();var o})(T.fromDom(t)).fold((()=>o.body.contains(t)),(n=_,r=$,e=>n(r(e))));var n,r},G=(e,t)=>Y(e)?e.style.getPropertyValue(t):"",J=(e=>{const t=t=>e(t)?m.from(t.dom.nodeValue):m.none();return{get:o=>{if(!e(o))throw new Error("Can only get text value of a text node");return t(o).getOr("")},getOption:t,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(M),Q=(e,t,o)=>{let n=e.dom;const r=a(o)?o:c;for(;n.parentNode;){n=n.parentNode;const e=T.fromDom(n);if(t(e))return m.some(e);if(r(e))break}return m.none()},W=(e,t,o)=>Q(e,(e=>A(e,t)),o),X=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return C(o)?m.none():m.from(o.querySelector(e)).map(T.fromDom)})(t,e),Z=(e,t)=>{let o=[];return h(L(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(Z(e,t))})),o};var ee=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"];const te=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>te(e,t,o).orThunk((()=>m.some(t))))):m.none(),oe=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,ne=(e,t)=>{const o=te(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return b(o,oe(e,o));const n=e.property().children(o);return n.length>0?ne(e,n[n.length-1]):b(o,oe(e,o))},re=ne,se={up:l({selector:W,closest:(e,t,o)=>((e,t,o,n,r)=>((e,t)=>A(e,t))(o,n)?m.some(o):a(r)&&r(o)?m.none():t(o,n,r))(0,W,e,t,o),predicate:Q,all:(e,t)=>{const o=a(t)?t:c;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=T.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r}}),down:l({selector:(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return C(o)?[]:p(o.querySelectorAll(e),T.fromDom)})(t,e),predicate:Z}),styles:l({get:(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||_(e)?n:G(o,t)},getRaw:(e,t)=>{const o=e.dom,n=G(o,t);return m.from(n).filter((e=>e.length>0))},set:(e,t,n)=>{((e,t,n)=>{if(!o(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);Y(e)&&e.style.setProperty(t,n)})(e.dom,t,n)},remove:(e,t)=>{((e,t)=>{Y(e)&&e.style.removeProperty(t)})(e.dom,t),((e,t,o=d)=>e.exists((e=>o(e,t))))(F(e,"style").map(v),"")&&K(e,"style")}}),attrs:l({get:z,set:(e,t,o)=>{H(e.dom,t,o)},remove:K,copyTo:(e,t)=>{const o=(n=e.dom.attributes,r=(e,t)=>(e[t.name]=t.value,e),s={},h(n,((e,t)=>{s=r(s,e)})),s);var n,r,s;((e,t)=>{const o=e.dom;((e,t)=>{const o=f(e);for(let n=0,r=o.length;n{H(o,t,e)}))})(t,o)}}),insert:l({before:V,after:I,afterAll:q,append:j,appendAll:(e,t)=>{h(t,(t=>{j(e,t)}))},prepend:(e,t)=>{(e=>(e=>{const t=e.dom.childNodes;return m.from(t[0]).map(T.fromDom)})(e))(e).fold((()=>{j(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},wrap:(e,t)=>{V(e,t),j(t,e)}}),remove:l({unwrap:e=>{const t=L(e);t.length>0&&q(e,t),U(e)},remove:U}),create:l({nu:T.fromTag,clone:e=>T.fromDom(e.dom.cloneNode(!1)),text:T.fromText}),query:l({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:e=>m.from(e.dom.previousSibling).map(T.fromDom),nextSibling:B}),property:l({children:L,name:x,parent:k,document:e=>{return(t=e,P(t)?t:T.fromDom(t.dom.ownerDocument)).dom;var t},isText:M,isComment:e=>8===D(e)||"#comment"===x(e),isElement:O,isSpecial:e=>{const t=x(e);return g(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>O(e)?F(e,"lang"):m.none(),getText:e=>J.get(e),setText:(e,t)=>J.set(e,t),isBoundary:e=>!!O(e)&&("body"===x(e)||g(ee,x(e))),isEmptyTag:e=>!!O(e)&&g(["br","img","hr","input"],x(e)),isNonEditable:e=>O(e)&&"false"===z(e,"contenteditable")}),eq:(e,t)=>e.dom===t.dom,is:S},ae="details",ie="mce-accordion",le="mce-accordion-summary",de="mce-accordion-body",ce="div";var me=tinymce.util.Tools.resolve("tinymce.util.Tools");const ue=e=>"SUMMARY"===(null==e?void 0:e.nodeName),ge=e=>"DETAILS"===(null==e?void 0:e.nodeName),pe=e=>e.hasAttribute("open"),he=e=>{const t=e.selection.getNode();return ue(t)||Boolean(e.dom.getParent(t,ue))},fe=e=>!he(e)&&e.dom.isEditable(e.selection.getNode())&&!e.mode.isReadOnly(),ye=e=>m.from(e.dom.getParent(e.selection.getNode(),ge)),ve=e=>(e.innerHTML='
',e),we=e=>ve(e.dom.create("p")),be=e=>t=>{((e,t)=>{if(ue(null==t?void 0:t.lastChild)){const o=we(e);t.appendChild(o),e.selection.setCursorLocation(o,0)}})(e,t),((e,t)=>{if(!ue(null==t?void 0:t.firstChild)){const o=(e=>ve(e.dom.create("summary")))(e);t.prepend(o),e.selection.setCursorLocation(o,0)}})(e,t)},Ne=e=>{if(!fe(e))return;const t=T.fromDom(e.getBody()),o=(e=>{const t=(new Date).getTime(),o=Math.floor(window.crypto.getRandomValues(new Uint32Array(1))[0]/4294967295*1e9);return y++,e+"_"+o+y+String(t)})("acc"),n=e.dom.encode(e.selection.getRng().toString()||e.translate("Accordion summary...")),r=e.dom.encode(e.translate("Accordion body...")),s=`${n}`,a=`<${ce} class="${de}">

${r}

`;e.undoManager.transact((()=>{e.insertContent([`
`,s,a,"
"].join("")),X(t,`[data-mce-id="${o}"]`).each((t=>{K(t,"data-mce-id"),X(t,"summary").each((t=>{const o=e.dom.createRng(),n=re(se,t);o.setStart(n.element.dom,n.offset),o.setEnd(n.element.dom,n.offset),e.selection.setRng(o)}))}))}))},Te=(e,t)=>{const o=null!=t?t:!pe(e);return o?e.setAttribute("open","open"):e.removeAttribute("open"),o},Ae=e=>{e.addCommand("InsertAccordion",(()=>Ne(e))),e.addCommand("ToggleAccordion",((t,o)=>((e,t)=>{ye(e).each((o=>{((e,t,o)=>{e.dispatch("ToggledAccordion",{element:t,state:o})})(e,o,Te(o,t))}))})(e,o))),e.addCommand("ToggleAllAccordions",((t,o)=>((e,t)=>{const o=Array.from(e.getBody().querySelectorAll("details"));0!==o.length&&(h(o,(e=>Te(e,null!=t?t:!pe(e)))),((e,t,o)=>{e.dispatch("ToggledAllAccordions",{elements:t,state:o})})(e,o,t))})(e,o))),e.addCommand("RemoveAccordion",(()=>(e=>{e.mode.isReadOnly()||ye(e).each((t=>{const{nextSibling:o}=t;o?(e.selection.select(o,!0),e.selection.collapse(!0)):((e,t)=>{const o=we(e);t.insertAdjacentElement("afterend",o),e.selection.setCursorLocation(o,0)})(e,t),t.remove()}))})(e)))};var Ce=tinymce.util.Tools.resolve("tinymce.html.Node");const Se=e=>{var t,o;return null!==(o=null===(t=e.attr("class"))||void 0===t?void 0:t.split(" "))&&void 0!==o?o:[]},xe=(e,t)=>{const o=new Set([...Se(e),...t]),n=Array.from(o);n.length>0&&e.attr("class",n.join(" "))},De=(e,t)=>{const o=(e=>{const o=[];for(let r=0,s=e.length;r0?o.join(" "):null)},Ee=e=>e.name===ae&&g(Se(e),ie),Oe=e=>{const t=e.children();let o,n;const s=[];for(let e=0;e{const t=new Ce("br",1);t.attr("data-mce-bogus","1"),e.empty(),e.append(t)};var Pe=tinymce.util.Tools.resolve("tinymce.util.VK");const Re=e=>{(e=>{e.on("keydown",(t=>{(!t.shiftKey&&t.keyCode===Pe.ENTER&&he(e)||(e=>{const t=e.selection.getRng();return ge(t.startContainer)&&t.collapsed&&0===t.startOffset})(e))&&(t.preventDefault(),e.execCommand("ToggleAccordion"))}))})(e),e.on("ExecCommand",(t=>{const o=t.command.toLowerCase();"delete"!==o&&"forwarddelete"!==o||!(e=>ye(e).isSome())(e)||(e=>{me.each(me.grep(e.dom.select("details",e.getBody())),be(e))})(e)}))};var ke=tinymce.util.Tools.resolve("tinymce.Env");const Be=e=>t=>{const o=()=>t.setEnabled(fe(e));return e.on("NodeChange",o),()=>e.off("NodeChange",o)};e.add("accordion",(e=>{(e=>{const t=()=>e.execCommand("InsertAccordion");e.ui.registry.addButton("accordion",{icon:"accordion",tooltip:"Insert accordion",onSetup:Be(e),onAction:t}),e.ui.registry.addMenuItem("accordion",{icon:"accordion",text:"Accordion",onSetup:Be(e),onAction:t}),e.ui.registry.addToggleButton("accordiontoggle",{icon:"accordion-toggle",tooltip:"Toggle accordion",onAction:()=>e.execCommand("ToggleAccordion")}),e.ui.registry.addToggleButton("accordionremove",{icon:"remove",tooltip:"Delete accordion",onAction:()=>e.execCommand("RemoveAccordion")}),e.ui.registry.addContextToolbar("accordion",{predicate:t=>e.dom.is(t,"details")&&e.getBody().contains(t)&&e.dom.isEditable(t.parentNode),items:"accordiontoggle accordionremove",scope:"node",position:"node"})})(e),Ae(e),Re(e),(e=>{e.on("PreInit",(()=>{const{serializer:t,parser:o}=e;o.addNodeFilter(ae,(e=>{for(let t=0;t0)for(let e=0;e{const t=new Set([le]);for(let o=0;o{ke.browser.isSafari()&&e.on("click",(t=>{if(ue(t.target)){const o=t.target,n=e.selection.getRng();n.collapsed&&n.startContainer===o.parentNode&&0===n.startOffset&&e.selection.setCursorLocation(o,0)}}))})(e)}))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/advlist/plugin.js b/public/ext/tinymce/plugins/advlist/plugin.js index e456414..825fd2a 100644 --- a/public/ext/tinymce/plugins/advlist/plugin.js +++ b/public/ext/tinymce/plugins/advlist/plugin.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -8,286 +8,464 @@ var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager'); const applyListFormat = (editor, listName, styleValue) => { - const cmd = listName === 'UL' ? 'InsertUnorderedList' : 'InsertOrderedList'; - editor.execCommand(cmd, false, styleValue === false ? null : { 'list-style-type': styleValue }); + const cmd = listName === 'UL' ? 'InsertUnorderedList' : 'InsertOrderedList'; + editor.execCommand(cmd, false, styleValue === false ? null : { 'list-style-type': styleValue }); }; - const register$2 = editor => { - editor.addCommand('ApplyUnorderedListStyle', (ui, value) => { - applyListFormat(editor, 'UL', value['list-style-type']); - }); - editor.addCommand('ApplyOrderedListStyle', (ui, value) => { - applyListFormat(editor, 'OL', value['list-style-type']); - }); + const register$2 = (editor) => { + editor.addCommand('ApplyUnorderedListStyle', (ui, value) => { + applyListFormat(editor, 'UL', value['list-style-type']); + }); + editor.addCommand('ApplyOrderedListStyle', (ui, value) => { + applyListFormat(editor, 'OL', value['list-style-type']); + }); }; - const option = name => editor => editor.options.get(name); - const register$1 = editor => { - const registerOption = editor.options.register; - registerOption('advlist_number_styles', { - processor: 'string[]', - default: 'default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman'.split(',') - }); - registerOption('advlist_bullet_styles', { - processor: 'string[]', - default: 'default,circle,square'.split(',') - }); + const option = (name) => (editor) => editor.options.get(name); + const register$1 = (editor) => { + const registerOption = editor.options.register; + registerOption('advlist_number_styles', { + processor: 'string[]', + default: 'default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman'.split(',') + }); + registerOption('advlist_bullet_styles', { + processor: 'string[]', + default: 'default,disc,circle,square'.split(',') + }); }; const getNumberStyles = option('advlist_number_styles'); const getBulletStyles = option('advlist_bullet_styles'); - const isNullable = a => a === null || a === undefined; - const isNonNullable = a => !isNullable(a); + /* eslint-disable @typescript-eslint/no-wrapper-object-types */ + const isNullable = (a) => a === null || a === undefined; + const isNonNullable = (a) => !isNullable(a); + /** + * The `Optional` type represents a value (of any type) that potentially does + * not exist. Any `Optional` can either be a `Some` (in which case the + * value does exist) or a `None` (in which case the value does not exist). This + * module defines a whole lot of FP-inspired utility functions for dealing with + * `Optional` objects. + * + * Comparison with null or undefined: + * - We don't get fancy null coalescing operators with `Optional` + * - We do get fancy helper functions with `Optional` + * - `Optional` support nesting, and allow for the type to still be nullable (or + * another `Optional`) + * - There is no option to turn off strict-optional-checks like there is for + * strict-null-checks + */ class Optional { - constructor(tag, value) { - this.tag = tag; - this.value = value; - } - static some(value) { - return new Optional(true, value); - } - static none() { - return Optional.singletonNone; - } - fold(onNone, onSome) { - if (this.tag) { - return onSome(this.value); - } else { - return onNone(); + // The internal representation has a `tag` and a `value`, but both are + // private: able to be console.logged, but not able to be accessed by code + constructor(tag, value) { + this.tag = tag; + this.value = value; } - } - isSome() { - return this.tag; - } - isNone() { - return !this.tag; - } - map(mapper) { - if (this.tag) { - return Optional.some(mapper(this.value)); - } else { - return Optional.none(); + // --- Identities --- + /** + * Creates a new `Optional` that **does** contain a value. + */ + static some(value) { + return new Optional(true, value); } - } - bind(binder) { - if (this.tag) { - return binder(this.value); - } else { - return Optional.none(); + /** + * Create a new `Optional` that **does not** contain a value. `T` can be + * any type because we don't actually have a `T`. + */ + static none() { + return Optional.singletonNone; } - } - exists(predicate) { - return this.tag && predicate(this.value); - } - forall(predicate) { - return !this.tag || predicate(this.value); - } - filter(predicate) { - if (!this.tag || predicate(this.value)) { - return this; - } else { - return Optional.none(); + /** + * Perform a transform on an `Optional` type. Regardless of whether this + * `Optional` contains a value or not, `fold` will return a value of type `U`. + * If this `Optional` does not contain a value, the `U` will be created by + * calling `onNone`. If this `Optional` does contain a value, the `U` will be + * created by calling `onSome`. + * + * For the FP enthusiasts in the room, this function: + * 1. Could be used to implement all of the functions below + * 2. Forms a catamorphism + */ + fold(onNone, onSome) { + if (this.tag) { + return onSome(this.value); + } + else { + return onNone(); + } } - } - getOr(replacement) { - return this.tag ? this.value : replacement; - } - or(replacement) { - return this.tag ? this : replacement; - } - getOrThunk(thunk) { - return this.tag ? this.value : thunk(); - } - orThunk(thunk) { - return this.tag ? this : thunk(); - } - getOrDie(message) { - if (!this.tag) { - throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); - } else { - return this.value; + /** + * Determine if this `Optional` object contains a value. + */ + isSome() { + return this.tag; } - } - static from(value) { - return isNonNullable(value) ? Optional.some(value) : Optional.none(); - } - getOrNull() { - return this.tag ? this.value : null; - } - getOrUndefined() { - return this.value; - } - each(worker) { - if (this.tag) { - worker(this.value); + /** + * Determine if this `Optional` object **does not** contain a value. + */ + isNone() { + return !this.tag; + } + // --- Functor (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. If + * you provide a function to turn a T into a U, this is the function you use + * to turn an `Optional` into an `Optional`. If this **does** contain + * a value then the output will also contain a value (that value being the + * output of `mapper(this.value)`), and if this **does not** contain a value + * then neither will the output. + */ + map(mapper) { + if (this.tag) { + return Optional.some(mapper(this.value)); + } + else { + return Optional.none(); + } + } + // --- Monad (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. + * Unlike `map`, here the transform itself also returns an `Optional`. + */ + bind(binder) { + if (this.tag) { + return binder(this.value); + } + else { + return Optional.none(); + } + } + // --- Traversable (name stolen from Haskell / maths) --- + /** + * For a given predicate, this function finds out if there **exists** a value + * inside this `Optional` object that meets the predicate. In practice, this + * means that for `Optional`s that do not contain a value it returns false (as + * no predicate-meeting value exists). + */ + exists(predicate) { + return this.tag && predicate(this.value); + } + /** + * For a given predicate, this function finds out if **all** the values inside + * this `Optional` object meet the predicate. In practice, this means that + * for `Optional`s that do not contain a value it returns true (as all 0 + * objects do meet the predicate). + */ + forall(predicate) { + return !this.tag || predicate(this.value); + } + filter(predicate) { + if (!this.tag || predicate(this.value)) { + return this; + } + else { + return Optional.none(); + } + } + // --- Getters --- + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. + */ + getOr(replacement) { + return this.tag ? this.value : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` object is also + * `Optional` - meaning that this method will always return an `Optional`. + */ + or(replacement) { + return this.tag ? this : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` value is + * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you + * pass a function which (if called) will **return** the `value` you want to + * use. + */ + getOrThunk(thunk) { + return this.tag ? this.value : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided Optional object does not contain a + * value. + * + * Unlike `or`, in this method the `replacement` value is "thunked" - that is + * to say that you don't pass a value to `orThunk`, you pass a function which + * (if called) will **return** the `value` you want to use. + * + * Unlike `getOrThunk`, in this method the `replacement` value is also + * `Optional`, meaning that this method will always return an `Optional`. + */ + orThunk(thunk) { + return this.tag ? this : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, throwing an + * exception if the provided `Optional` object does not contain a value. + * + * WARNING: + * You should only be using this function if you know that the `Optional` + * object **is not** empty (otherwise you're throwing exceptions in production + * code, which is bad). + * + * In tests this is more acceptable. + * + * Prefer other methods to this, such as `.each`. + */ + getOrDie(message) { + if (!this.tag) { + throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); + } + else { + return this.value; + } + } + // --- Interop with null and undefined --- + /** + * Creates an `Optional` value from a nullable (or undefined-able) input. + * Null, or undefined, is converted to `None`, and anything else is converted + * to `Some`. + */ + static from(value) { + return isNonNullable(value) ? Optional.some(value) : Optional.none(); + } + /** + * Converts an `Optional` to a nullable type, by getting the value if it + * exists, or returning `null` if it does not. + */ + getOrNull() { + return this.tag ? this.value : null; + } + /** + * Converts an `Optional` to an undefined-able type, by getting the value if + * it exists, or returning `undefined` if it does not. + */ + getOrUndefined() { + return this.value; + } + // --- Utilities --- + /** + * If the `Optional` contains a value, perform an action on that value. + * Unlike the rest of the methods on this type, `.each` has side-effects. If + * you want to transform an `Optional` **into** something, then this is not + * the method for you. If you want to use an `Optional` to **do** + * something, then this is the method for you - provided you're okay with not + * doing anything in the case where the `Optional` doesn't have a value inside + * it. If you're not sure whether your use-case fits into transforming + * **into** something or **doing** something, check whether it has a return + * value. If it does, you should be performing a transform. + */ + each(worker) { + if (this.tag) { + worker(this.value); + } + } + /** + * Turn the `Optional` object into an array that contains all of the values + * stored inside the `Optional`. In practice, this means the output will have + * either 0 or 1 elements. + */ + toArray() { + return this.tag ? [this.value] : []; + } + /** + * Turn the `Optional` object into a string for debugging or printing. Not + * recommended for production code, but good for debugging. Also note that + * these days an `Optional` object can be logged to the console directly, and + * its inner value (if it exists) will be visible. + */ + toString() { + return this.tag ? `some(${this.value})` : 'none()'; } - } - toArray() { - return this.tag ? [this.value] : []; - } - toString() { - return this.tag ? `some(${ this.value })` : 'none()'; - } } + // Sneaky optimisation: every instance of Optional.none is identical, so just + // reuse the same object Optional.singletonNone = new Optional(false); const nativeIndexOf = Array.prototype.indexOf; + /* eslint-enable */ const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t); const contains = (xs, x) => rawIndexOf(xs, x) > -1; const findUntil = (xs, pred, until) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - if (pred(x, i)) { - return Optional.some(x); - } else if (until(x, i)) { - break; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + if (pred(x, i)) { + return Optional.some(x); + } + else if (until(x, i)) { + break; + } } - } - return Optional.none(); + return Optional.none(); }; + // There are many variations of Object iteration that are faster than the 'for-in' style: + // http://jsperf.com/object-keys-iteration/107 + // + // Use the native keys if it is available (IE9+), otherwise fall back to manually filtering const keys = Object.keys; const each = (obj, f) => { - const props = keys(obj); - for (let k = 0, len = props.length; k < len; k++) { - const i = props[k]; - const x = obj[i]; - f(x, i); - } + const props = keys(obj); + for (let k = 0, len = props.length; k < len; k++) { + const i = props[k]; + const x = obj[i]; + f(x, i); + } }; const map = (obj, f) => { - return tupleMap(obj, (x, i) => ({ - k: i, - v: f(x, i) - })); + return tupleMap(obj, (x, i) => ({ + k: i, + v: f(x, i) + })); }; const tupleMap = (obj, f) => { - const r = {}; - each(obj, (x, i) => { - const tuple = f(x, i); - r[tuple.k] = tuple.v; - }); - return r; + const r = {}; + each(obj, (x, i) => { + const tuple = f(x, i); + r[tuple.k] = tuple.v; + }); + return r; }; var global = tinymce.util.Tools.resolve('tinymce.util.Tools'); - const isCustomList = list => /\btox\-/.test(list.className); + const isCustomList = (list) => /\btox\-/.test(list.className); const isChildOfBody = (editor, elm) => { - return editor.dom.isChildOf(elm, editor.getBody()); + return editor.dom.isChildOf(elm, editor.getBody()); }; - const matchNodeNames = regex => node => isNonNullable(node) && regex.test(node.nodeName); + const matchNodeNames = (regex) => (node) => isNonNullable(node) && regex.test(node.nodeName); const isListNode = matchNodeNames(/^(OL|UL|DL)$/); const isTableCellNode = matchNodeNames(/^(TH|TD)$/); - const inList = (editor, parents, nodeName) => findUntil(parents, parent => isListNode(parent) && !isCustomList(parent), isTableCellNode).exists(list => list.nodeName === nodeName && isChildOfBody(editor, list)); - const getSelectedStyleType = editor => { - const listElm = editor.dom.getParent(editor.selection.getNode(), 'ol,ul'); - const style = editor.dom.getStyle(listElm, 'listStyleType'); - return Optional.from(style); + const inList = (editor, parents, nodeName) => findUntil(parents, (parent) => isListNode(parent) && !isCustomList(parent), isTableCellNode) + .exists((list) => list.nodeName === nodeName && isChildOfBody(editor, list)); + const getSelectedStyleType = (editor) => { + const listElm = editor.dom.getParent(editor.selection.getNode(), 'ol,ul'); + const style = editor.dom.getStyle(listElm, 'listStyleType'); + return Optional.from(style); }; + // Lists/core/Util.ts - Duplicated in Lists plugin const isWithinNonEditable = (editor, element) => element !== null && !editor.dom.isEditable(element); const isWithinNonEditableList = (editor, element) => { - const parentList = editor.dom.getParent(element, 'ol,ul,dl'); - return isWithinNonEditable(editor, parentList) || !editor.selection.isEditable(); + const parentList = editor.dom.getParent(element, 'ol,ul,dl'); + return isWithinNonEditable(editor, parentList) || !editor.selection.isEditable(); }; const setNodeChangeHandler = (editor, nodeChangeHandler) => { - const initialNode = editor.selection.getNode(); - nodeChangeHandler({ - parents: editor.dom.getParents(initialNode), - element: initialNode - }); - editor.on('NodeChange', nodeChangeHandler); - return () => editor.off('NodeChange', nodeChangeHandler); + const initialNode = editor.selection.getNode(); + // Set the initial state + nodeChangeHandler({ + parents: editor.dom.getParents(initialNode), + element: initialNode + }); + editor.on('NodeChange', nodeChangeHandler); + return () => editor.off('NodeChange', nodeChangeHandler); }; - const styleValueToText = styleValue => { - return styleValue.replace(/\-/g, ' ').replace(/\b\w/g, chr => { - return chr.toUpperCase(); - }); + // + const styleValueToText = (styleValue) => { + return styleValue.replace(/\-/g, ' ').replace(/\b\w/g, (chr) => { + return chr.toUpperCase(); + }); }; - const normalizeStyleValue = styleValue => isNullable(styleValue) || styleValue === 'default' ? '' : styleValue; - const makeSetupHandler = (editor, nodeName) => api => { - const updateButtonState = (editor, parents) => { - const element = editor.selection.getStart(true); - api.setActive(inList(editor, parents, nodeName)); - api.setEnabled(!isWithinNonEditableList(editor, element)); - }; - const nodeChangeHandler = e => updateButtonState(editor, e.parents); - return setNodeChangeHandler(editor, nodeChangeHandler); + const normalizeStyleValue = (styleValue) => isNullable(styleValue) || styleValue === 'default' ? '' : styleValue; + const makeSetupHandler = (editor, nodeName) => (api) => { + const updateButtonState = (editor, parents) => { + const element = editor.selection.getStart(true); + api.setActive(inList(editor, parents, nodeName)); + api.setEnabled(!isWithinNonEditableList(editor, element)); + }; + const nodeChangeHandler = (e) => updateButtonState(editor, e.parents); + return setNodeChangeHandler(editor, nodeChangeHandler); }; const addSplitButton = (editor, id, tooltip, cmd, nodeName, styles) => { - const listStyleTypeAliases = { - 'lower-latin': 'lower-alpha', - 'upper-latin': 'upper-alpha', - 'lower-alpha': 'lower-latin', - 'upper-alpha': 'upper-latin' - }; - const stylesContainsAliasMap = map(listStyleTypeAliases, alias => contains(styles, alias)); - editor.ui.registry.addSplitButton(id, { - tooltip, - icon: nodeName === 'OL' ? 'ordered-list' : 'unordered-list', - presets: 'listpreview', - columns: 3, - fetch: callback => { - const items = global.map(styles, styleValue => { - const iconStyle = nodeName === 'OL' ? 'num' : 'bull'; - const iconName = styleValue === 'disc' || styleValue === 'decimal' ? 'default' : styleValue; - const itemValue = normalizeStyleValue(styleValue); - const displayText = styleValueToText(styleValue); - return { - type: 'choiceitem', - value: itemValue, - icon: 'list-' + iconStyle + '-' + iconName, - text: displayText - }; - }); - callback(items); - }, - onAction: () => editor.execCommand(cmd), - onItemAction: (_splitButtonApi, value) => { - applyListFormat(editor, nodeName, value); - }, - select: value => { - const listStyleType = getSelectedStyleType(editor); - return listStyleType.exists(listStyle => value === listStyle || listStyleTypeAliases[listStyle] === value && !stylesContainsAliasMap[value]); - }, - onSetup: makeSetupHandler(editor, nodeName) - }); + const listStyleTypeAliases = { + 'lower-latin': 'lower-alpha', + 'upper-latin': 'upper-alpha', + 'lower-alpha': 'lower-latin', + 'upper-alpha': 'upper-latin' + }; + const stylesContainsAliasMap = map(listStyleTypeAliases, (alias) => contains(styles, alias)); + editor.ui.registry.addSplitButton(id, { + tooltip, + icon: nodeName === "OL" /* ListType.OrderedList */ ? 'ordered-list' : 'unordered-list', + presets: 'listpreview', + columns: nodeName === "OL" /* ListType.OrderedList */ ? 3 : 4, + fetch: (callback) => { + const items = global.map(styles, (styleValue) => { + const iconStyle = nodeName === "OL" /* ListType.OrderedList */ ? 'num' : 'bull'; + const iconName = styleValue === 'decimal' ? 'default' : styleValue; + const itemValue = normalizeStyleValue(styleValue); + const displayText = styleValueToText(styleValue); + return { + type: 'choiceitem', + value: itemValue, + icon: 'list-' + iconStyle + '-' + iconName, + text: displayText + }; + }); + callback(items); + }, + onAction: () => editor.execCommand(cmd), + onItemAction: (_splitButtonApi, value) => { + applyListFormat(editor, nodeName, value); + }, + select: (value) => { + const listStyleType = getSelectedStyleType(editor); + return listStyleType.exists((listStyle) => value === listStyle || (listStyleTypeAliases[listStyle] === value && !stylesContainsAliasMap[value])); + }, + onSetup: makeSetupHandler(editor, nodeName) + }); }; const addButton = (editor, id, tooltip, cmd, nodeName, styleValue) => { - editor.ui.registry.addToggleButton(id, { - active: false, - tooltip, - icon: nodeName === 'OL' ? 'ordered-list' : 'unordered-list', - onSetup: makeSetupHandler(editor, nodeName), - onAction: () => editor.queryCommandState(cmd) || styleValue === '' ? editor.execCommand(cmd) : applyListFormat(editor, nodeName, styleValue) - }); + editor.ui.registry.addToggleButton(id, { + active: false, + tooltip, + icon: nodeName === "OL" /* ListType.OrderedList */ ? 'ordered-list' : 'unordered-list', + onSetup: makeSetupHandler(editor, nodeName), + // Need to make sure the button removes rather than applies if a list of the same type is selected + onAction: () => editor.queryCommandState(cmd) || styleValue === '' ? editor.execCommand(cmd) : applyListFormat(editor, nodeName, styleValue) + }); }; const addControl = (editor, id, tooltip, cmd, nodeName, styles) => { - if (styles.length > 1) { - addSplitButton(editor, id, tooltip, cmd, nodeName, styles); - } else { - addButton(editor, id, tooltip, cmd, nodeName, normalizeStyleValue(styles[0])); - } + if (styles.length > 1) { + addSplitButton(editor, id, tooltip, cmd, nodeName, styles); + } + else { + addButton(editor, id, tooltip, cmd, nodeName, normalizeStyleValue(styles[0])); + } }; - const register = editor => { - addControl(editor, 'numlist', 'Numbered list', 'InsertOrderedList', 'OL', getNumberStyles(editor)); - addControl(editor, 'bullist', 'Bullet list', 'InsertUnorderedList', 'UL', getBulletStyles(editor)); + const register = (editor) => { + addControl(editor, 'numlist', 'Numbered list', 'InsertOrderedList', "OL" /* ListType.OrderedList */, getNumberStyles(editor)); + addControl(editor, 'bullist', 'Bullet list', 'InsertUnorderedList', "UL" /* ListType.UnorderedList */, getBulletStyles(editor)); }; var Plugin = () => { - global$1.add('advlist', editor => { - if (editor.hasPlugin('lists')) { - register$1(editor); - register(editor); - register$2(editor); - } else { - console.error('Please use the Lists plugin together with the List Styles plugin.'); - } - }); + global$1.add('advlist', (editor) => { + if (editor.hasPlugin('lists')) { + register$1(editor); + register(editor); + register$2(editor); + } + else { + // eslint-disable-next-line no-console + console.error('Please use the Lists plugin together with the List Styles plugin.'); + } + }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/advlist/plugin.min.js b/public/ext/tinymce/plugins/advlist/plugin.min.js index f4faa4a..485788d 100644 --- a/public/ext/tinymce/plugins/advlist/plugin.min.js +++ b/public/ext/tinymce/plugins/advlist/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ -!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),l=t=>null==t,i=t=>!l(t);class o{constructor(t,e){this.tag=t,this.value=e}static some(t){return new o(!0,t)}static none(){return o.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?o.some(t(this.value)):o.none()}bind(t){return this.tag?t(this.value):o.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:o.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return i(t)?o.some(t):o.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}o.singletonNone=new o(!1);const a=Array.prototype.indexOf,u=Object.keys;var d=tinymce.util.Tools.resolve("tinymce.util.Tools");const c=t=>e=>i(e)&&t.test(e.nodeName),h=c(/^(OL|UL|DL)$/),g=c(/^(TH|TD)$/),p=t=>l(t)||"default"===t?"":t,m=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;ee.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)||!t.selection.isEditable()})(t,n))})(t,r.parents))),v=(t,s,r,n,l,i)=>{const c={"lower-latin":"lower-alpha","upper-latin":"upper-alpha","lower-alpha":"lower-latin","upper-alpha":"upper-latin"},h=(g=t=>{return e=i,s=t,a.call(e,s)>-1;var e,s},((t,e)=>{const s={};return((t,e)=>{const s=u(t);for(let r=0,n=s.length;r{const n=e(t,r);s[n.k]=n.v})),s})(c,((t,e)=>({k:e,v:g(t)}))));var g;t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===l?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(d.map(i,(t=>{const e="OL"===l?"num":"bull",s="disc"===t||"decimal"===t?"default":t,r=p(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,l,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return o.from(s)})(t);return s.exists((t=>e===t||c[t]===e&&!h[e]))},onSetup:m(t,l)})},y=(t,s,r,n,l,i)=>{i.length>1?v(t,s,r,n,l,i):((t,s,r,n,l,i)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===l?"ordered-list":"unordered-list",onSetup:m(t,l),onAction:()=>t.queryCommandState(n)||""===i?t.execCommand(n):e(t,l,i)})})(t,s,r,n,l,p(i[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{y(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),y(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the List Styles plugin.")}))}(); \ No newline at end of file +!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),l=t=>null==t,i=t=>!l(t);class o{constructor(t,e){this.tag=t,this.value=e}static some(t){return new o(!0,t)}static none(){return o.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?o.some(t(this.value)):o.none()}bind(t){return this.tag?t(this.value):o.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:o.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return i(t)?o.some(t):o.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}o.singletonNone=new o(!1);const a=Array.prototype.indexOf,u=Object.keys;var d=tinymce.util.Tools.resolve("tinymce.util.Tools");const c=t=>e=>i(e)&&t.test(e.nodeName),h=c(/^(OL|UL|DL)$/),g=c(/^(TH|TD)$/),p=t=>l(t)||"default"===t?"":t,m=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;ee.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)||!t.selection.isEditable()})(t,n))})(t,r.parents))),v=(t,s,r,n,l,i)=>{const c={"lower-latin":"lower-alpha","upper-latin":"upper-alpha","lower-alpha":"lower-latin","upper-alpha":"upper-latin"},h=(g=t=>{return e=i,s=t,a.call(e,s)>-1;var e,s},((t,e)=>{const s={};return((t,e)=>{const s=u(t);for(let r=0,n=s.length;r{const n=e(t,r);s[n.k]=n.v})),s})(c,((t,e)=>({k:e,v:g(t)}))));var g;t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===l?"ordered-list":"unordered-list",presets:"listpreview",columns:"OL"===l?3:4,fetch:t=>{t(d.map(i,(t=>{const e="OL"===l?"num":"bull",s="decimal"===t?"default":t,r=p(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,l,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return o.from(s)})(t);return s.exists((t=>e===t||c[t]===e&&!h[e]))},onSetup:m(t,l)})},y=(t,s,r,n,l,i)=>{i.length>1?v(t,s,r,n,l,i):((t,s,r,n,l,i)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===l?"ordered-list":"unordered-list",onSetup:m(t,l),onAction:()=>t.queryCommandState(n)||""===i?t.execCommand(n):e(t,l,i)})})(t,s,r,n,l,p(i[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,disc,circle,square".split(",")})})(t),(t=>{y(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),y(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the List Styles plugin.")}))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/anchor/plugin.js b/public/ext/tinymce/plugins/anchor/plugin.js index b5d42d0..f6eeef6 100644 --- a/public/ext/tinymce/plugins/anchor/plugin.js +++ b/public/ext/tinymce/plugins/anchor/plugin.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -11,204 +11,227 @@ var global = tinymce.util.Tools.resolve('tinymce.util.Tools'); - const option = name => editor => editor.options.get(name); - const register$2 = editor => { - const registerOption = editor.options.register; - registerOption('allow_html_in_named_anchor', { - processor: 'boolean', - default: false - }); + const option = (name) => (editor) => editor.options.get(name); + const register$2 = (editor) => { + const registerOption = editor.options.register; + registerOption('allow_html_in_named_anchor', { + processor: 'boolean', + default: false + }); }; const allowHtmlInNamedAnchor = option('allow_html_in_named_anchor'); const namedAnchorSelector = 'a:not([href])'; - const isEmptyString = str => !str; - const getIdFromAnchor = elm => { - const id = elm.getAttribute('id') || elm.getAttribute('name'); - return id || ''; - }; - const isAnchor = elm => elm.nodeName.toLowerCase() === 'a'; - const isNamedAnchor = elm => isAnchor(elm) && !elm.getAttribute('href') && getIdFromAnchor(elm) !== ''; - const isEmptyNamedAnchor = elm => isNamedAnchor(elm) && !elm.firstChild; + const isEmptyString = (str) => !str; + const getIdFromAnchor = (elm) => { + const id = elm.getAttribute('id') || elm.getAttribute('name'); + return id || ''; + }; + const isAnchor = (elm) => elm.nodeName.toLowerCase() === 'a'; + const isNamedAnchor = (elm) => isAnchor(elm) && !elm.getAttribute('href') && getIdFromAnchor(elm) !== ''; + const isEmptyNamedAnchor = (elm) => isNamedAnchor(elm) && !elm.firstChild; - const removeEmptyNamedAnchorsInSelection = editor => { - const dom = editor.dom; - global$1(dom).walk(editor.selection.getRng(), nodes => { - global.each(nodes, node => { - if (isEmptyNamedAnchor(node)) { - dom.remove(node, false); - } + const removeEmptyNamedAnchorsInSelection = (editor) => { + const dom = editor.dom; + global$1(dom).walk(editor.selection.getRng(), (nodes) => { + global.each(nodes, (node) => { + if (isEmptyNamedAnchor(node)) { + dom.remove(node, false); + } + }); }); - }); - }; - const isValidId = id => /^[A-Za-z][A-Za-z0-9\-:._]*$/.test(id); - const getNamedAnchor = editor => editor.dom.getParent(editor.selection.getStart(), namedAnchorSelector); - const getId = editor => { - const anchor = getNamedAnchor(editor); - if (anchor) { - return getIdFromAnchor(anchor); - } else { - return ''; - } }; - const createAnchor = (editor, id) => { - editor.undoManager.transact(() => { - if (!allowHtmlInNamedAnchor(editor)) { - editor.selection.collapse(true); + const isValidId = (id) => + // Follows HTML4 rules: https://www.w3.org/TR/html401/types.html#type-id + /^[A-Za-z][A-Za-z0-9\-:._]*$/.test(id); + const getNamedAnchor = (editor) => editor.dom.getParent(editor.selection.getStart(), namedAnchorSelector); + const getId = (editor) => { + const anchor = getNamedAnchor(editor); + if (anchor) { + return getIdFromAnchor(anchor); } - if (editor.selection.isCollapsed()) { - editor.insertContent(editor.dom.createHTML('a', { id })); - } else { - removeEmptyNamedAnchorsInSelection(editor); - editor.formatter.remove('namedAnchor', undefined, undefined, true); - editor.formatter.apply('namedAnchor', { value: id }); - editor.addVisual(); + else { + return ''; } - }); + }; + const createAnchor = (editor, id) => { + editor.undoManager.transact(() => { + if (!allowHtmlInNamedAnchor(editor)) { + editor.selection.collapse(true); + } + if (editor.selection.isCollapsed()) { + editor.insertContent(editor.dom.createHTML('a', { id })); + } + else { + // Remove any empty named anchors in the selection as they cannot be removed by the formatter since they are cef + removeEmptyNamedAnchorsInSelection(editor); + // Format is set up to truncate any partially selected named anchors so that they are not completely removed + editor.formatter.remove('namedAnchor', undefined, undefined, true); + // Insert new anchor using the formatter - will wrap selected content in anchor + editor.formatter.apply('namedAnchor', { value: id }); + // Need to add visual classes to anchors if required + editor.addVisual(); + } + }); }; const updateAnchor = (editor, id, anchorElement) => { - anchorElement.removeAttribute('name'); - anchorElement.id = id; - editor.addVisual(); - editor.undoManager.add(); + anchorElement.removeAttribute('name'); + anchorElement.id = id; + editor.addVisual(); // Need to add visual classes to anchors if required + editor.undoManager.add(); }; const insert = (editor, id) => { - const anchor = getNamedAnchor(editor); - if (anchor) { - updateAnchor(editor, id, anchor); - } else { - createAnchor(editor, id); - } - editor.focus(); + const anchor = getNamedAnchor(editor); + if (anchor) { + updateAnchor(editor, id, anchor); + } + else { + createAnchor(editor, id); + } + editor.focus(); }; const insertAnchor = (editor, newId) => { - if (!isValidId(newId)) { - editor.windowManager.alert('ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.'); - return false; - } else { - insert(editor, newId); - return true; - } - }; - const open = editor => { - const currentId = getId(editor); - editor.windowManager.open({ - title: 'Anchor', - size: 'normal', - body: { - type: 'panel', - items: [{ - name: 'id', - type: 'input', - label: 'ID', - placeholder: 'example' - }] - }, - buttons: [ - { - type: 'cancel', - name: 'cancel', - text: 'Cancel' - }, - { - type: 'submit', - name: 'save', - text: 'Save', - primary: true - } - ], - initialData: { id: currentId }, - onSubmit: api => { - if (insertAnchor(editor, api.getData().id)) { - api.close(); - } + if (!isValidId(newId)) { + editor.windowManager.alert('ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.'); + return false; + } + else { + insert(editor, newId); + return true; } - }); + }; + const open = (editor) => { + const currentId = getId(editor); + editor.windowManager.open({ + title: 'Anchor', + size: 'normal', + body: { + type: 'panel', + items: [ + { + name: 'id', + type: 'input', + label: 'ID', + placeholder: 'example' + } + ] + }, + buttons: [ + { + type: 'cancel', + name: 'cancel', + text: 'Cancel' + }, + { + type: 'submit', + name: 'save', + text: 'Save', + primary: true + } + ], + initialData: { + id: currentId + }, + onSubmit: (api) => { + if (insertAnchor(editor, api.getData().id)) { // TODO we need a better way to do validation + api.close(); + } + } + }); }; - const register$1 = editor => { - editor.addCommand('mceAnchor', () => { - open(editor); - }); + const register$1 = (editor) => { + editor.addCommand('mceAnchor', () => { + open(editor); + }); }; - const isNamedAnchorNode = node => isEmptyString(node.attr('href')) && !isEmptyString(node.attr('id') || node.attr('name')); - const isEmptyNamedAnchorNode = node => isNamedAnchorNode(node) && !node.firstChild; - const setContentEditable = state => nodes => { - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; - if (isEmptyNamedAnchorNode(node)) { - node.attr('contenteditable', state); + // Note: node.firstChild check is for the 'allow_html_in_named_anchor' setting + // Only want to add contenteditable attributes if there is no text within the anchor + const isNamedAnchorNode = (node) => isEmptyString(node.attr('href')) && !isEmptyString(node.attr('id') || node.attr('name')); + const isEmptyNamedAnchorNode = (node) => isNamedAnchorNode(node) && !node.firstChild; + const setContentEditable = (state) => (nodes) => { + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (isEmptyNamedAnchorNode(node)) { + node.attr('contenteditable', state); + } } - } }; - const setup = editor => { - editor.on('PreInit', () => { - editor.parser.addNodeFilter('a', setContentEditable('false')); - editor.serializer.addNodeFilter('a', setContentEditable(null)); - }); + const setup = (editor) => { + editor.on('PreInit', () => { + editor.parser.addNodeFilter('a', setContentEditable('false')); + editor.serializer.addNodeFilter('a', setContentEditable(null)); + }); }; - const registerFormats = editor => { - editor.formatter.register('namedAnchor', { - inline: 'a', - selector: namedAnchorSelector, - remove: 'all', - split: true, - deep: true, - attributes: { id: '%value' }, - onmatch: (node, _fmt, _itemName) => { - return isNamedAnchor(node); - } - }); + const registerFormats = (editor) => { + editor.formatter.register('namedAnchor', { + inline: 'a', + selector: namedAnchorSelector, + remove: 'all', + split: true, + deep: true, + attributes: { + id: '%value' + }, + onmatch: (node, _fmt, _itemName) => { + return isNamedAnchor(node); + } + }); }; - const onSetupEditable = editor => api => { - const nodeChanged = () => { - api.setEnabled(editor.selection.isEditable()); - }; - editor.on('NodeChange', nodeChanged); - nodeChanged(); - return () => { - editor.off('NodeChange', nodeChanged); - }; - }; - const register = editor => { - const onAction = () => editor.execCommand('mceAnchor'); - editor.ui.registry.addToggleButton('anchor', { - icon: 'bookmark', - tooltip: 'Anchor', - onAction, - onSetup: buttonApi => { - const unbindSelectorChanged = editor.selection.selectorChangedWithUnbind('a:not([href])', buttonApi.setActive).unbind; - const unbindEditableChanged = onSetupEditable(editor)(buttonApi); - return () => { - unbindSelectorChanged(); - unbindEditableChanged(); - }; - } - }); - editor.ui.registry.addMenuItem('anchor', { - icon: 'bookmark', - text: 'Anchor...', - onAction, - onSetup: onSetupEditable(editor) - }); + const onSetupEditable = (editor) => (api) => { + const nodeChanged = () => { + api.setEnabled(editor.selection.isEditable()); + }; + editor.on('NodeChange', nodeChanged); + nodeChanged(); + return () => { + editor.off('NodeChange', nodeChanged); + }; + }; + const register = (editor) => { + const onAction = () => editor.execCommand('mceAnchor'); + editor.ui.registry.addToggleButton('anchor', { + icon: 'bookmark', + tooltip: 'Anchor', + onAction, + onSetup: (buttonApi) => { + const unbindSelectorChanged = editor.selection.selectorChangedWithUnbind('a:not([href])', buttonApi.setActive).unbind; + const unbindEditableChanged = onSetupEditable(editor)(buttonApi); + return () => { + unbindSelectorChanged(); + unbindEditableChanged(); + }; + } + }); + editor.ui.registry.addMenuItem('anchor', { + icon: 'bookmark', + text: 'Anchor...', + onAction, + onSetup: onSetupEditable(editor) + }); }; var Plugin = () => { - global$2.add('anchor', editor => { - register$2(editor); - setup(editor); - register$1(editor); - register(editor); - editor.on('PreInit', () => { - registerFormats(editor); + global$2.add('anchor', (editor) => { + register$2(editor); + setup(editor); + register$1(editor); + register(editor); + editor.on('PreInit', () => { + registerFormats(editor); + }); }); - }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/anchor/plugin.min.js b/public/ext/tinymce/plugins/anchor/plugin.min.js index 7b32ef2..c52c6d7 100644 --- a/public/ext/tinymce/plugins/anchor/plugin.min.js +++ b/public/ext/tinymce/plugins/anchor/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>e.options.get("allow_html_in_named_anchor");const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;ot=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>{const o=e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind,n=u(e)(t);return()=>{o(),n()}}}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t,onSetup:u(e)})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/autolink/plugin.js b/public/ext/tinymce/plugins/autolink/plugin.js index 7ce730b..6ebfabc 100644 --- a/public/ext/tinymce/plugins/autolink/plugin.js +++ b/public/ext/tinymce/plugins/autolink/plugin.js @@ -1,228 +1,318 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { - 'use strict'; - - var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager'); - - const link = () => /(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g; - - const option = name => editor => editor.options.get(name); - const register = editor => { - const registerOption = editor.options.register; - registerOption('autolink_pattern', { - processor: 'regexp', - default: new RegExp('^' + link().source + '$', 'i') - }); - registerOption('link_default_target', { processor: 'string' }); - registerOption('link_default_protocol', { - processor: 'string', - default: 'https' - }); - }; - const getAutoLinkPattern = option('autolink_pattern'); - const getDefaultLinkTarget = option('link_default_target'); - const getDefaultLinkProtocol = option('link_default_protocol'); - const allowUnsafeLinkTarget = option('allow_unsafe_link_target'); - - const hasProto = (v, constructor, predicate) => { - var _a; - if (predicate(v, constructor.prototype)) { - return true; - } else { - return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; - } - }; - const typeOf = x => { - const t = typeof x; - if (x === null) { - return 'null'; - } else if (t === 'object' && Array.isArray(x)) { - return 'array'; - } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { - return 'string'; - } else { - return t; - } - }; - const isType = type => value => typeOf(value) === type; - const eq = t => a => t === a; - const isString = isType('string'); - const isUndefined = eq(undefined); - const isNullable = a => a === null || a === undefined; - const isNonNullable = a => !isNullable(a); - - const not = f => t => !f(t); - - const hasOwnProperty = Object.hasOwnProperty; - const has = (obj, key) => hasOwnProperty.call(obj, key); - - const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr; - const contains = (str, substr, start = 0, end) => { - const idx = str.indexOf(substr, start); - if (idx !== -1) { - return isUndefined(end) ? true : idx + substr.length <= end; - } else { - return false; - } - }; - const startsWith = (str, prefix) => { - return checkRange(str, prefix, 0); - }; - - const zeroWidth = '\uFEFF'; - const isZwsp = char => char === zeroWidth; - const removeZwsp = s => s.replace(/\uFEFF/g, ''); - - var global = tinymce.util.Tools.resolve('tinymce.dom.TextSeeker'); - - const isTextNode = node => node.nodeType === 3; - const isElement = node => node.nodeType === 1; - const isBracketOrSpace = char => /^[(\[{ \u00a0]$/.test(char); - const hasProtocol = url => /^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(url); - const isPunctuation = char => /[?!,.;:]/.test(char); - const findChar = (text, index, predicate) => { - for (let i = index - 1; i >= 0; i--) { - const char = text.charAt(i); - if (!isZwsp(char) && predicate(char)) { - return i; - } - } - return -1; - }; - const freefallRtl = (container, offset) => { - let tempNode = container; - let tempOffset = offset; - while (isElement(tempNode) && tempNode.childNodes[tempOffset]) { - tempNode = tempNode.childNodes[tempOffset]; - tempOffset = isTextNode(tempNode) ? tempNode.data.length : tempNode.childNodes.length; - } - return { - container: tempNode, - offset: tempOffset + 'use strict'; + + var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager'); + + /* eslint-disable @typescript-eslint/no-wrapper-object-types */ + const hasProto = (v, constructor, predicate) => { + var _a; + if (predicate(v, constructor.prototype)) { + return true; + } + else { + // String-based fallback time + return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; + } + }; + const typeOf = (x) => { + const t = typeof x; + if (x === null) { + return 'null'; + } + else if (t === 'object' && Array.isArray(x)) { + return 'array'; + } + else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { + return 'string'; + } + else { + return t; + } + }; + const isType = (type) => (value) => typeOf(value) === type; + const eq = (t) => (a) => t === a; + const isString = isType('string'); + const isUndefined = eq(undefined); + const isNullable = (a) => a === null || a === undefined; + const isNonNullable = (a) => !isNullable(a); + + const not = (f) => (t) => !f(t); + + // eslint-disable-next-line @typescript-eslint/unbound-method + const hasOwnProperty = Object.hasOwnProperty; + const has = (obj, key) => hasOwnProperty.call(obj, key); + + const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr; + const contains = (str, substr, start = 0, end) => { + const idx = str.indexOf(substr, start); + if (idx !== -1) { + return isUndefined(end) ? true : idx + substr.length <= end; + } + else { + return false; + } + }; + /** Does 'str' start with 'prefix'? + * Note: all strings start with the empty string. + * More formally, for all strings x, startsWith(x, ""). + * This is so that for all strings x and y, startsWith(y + x, y) + */ + const startsWith = (str, prefix) => { + return checkRange(str, prefix, 0); + }; + + const zeroWidth = '\uFEFF'; + const isZwsp = (char) => char === zeroWidth; + const removeZwsp = (s) => s.replace(/\uFEFF/g, ''); + + /* + The RegEx parses the following components (https://www.rfc-editor.org/rfc/rfc3986.txt): + + scheme:[//[user:password@]host[:port]][/]path[?query][#fragment] + + foo://example.com:8042/over/there?name=ferret#nose + \_/ \______________/\_________/ \_________/ \__/ + | | | | | + scheme authority path query fragment + + Originally from: + http://blog.mattheworiordan.com/post/13174566389/url-regular-expression-for-links-with-or-without-the + + Modified to: + - include port numbers + - allow full stops in email addresses + - allow [-.~*+=!&;:'%@?^${}(),\/\w] after the # + - allow [-.~*+=!&;:'%@?^${}(),\/\w] after the ? + - move allow -_.~*+=!&;:'%@?^${}() in email usernames to the first @ match (TBIO-4809) + - enforce domains to be [A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)* so they can't end in a period (TBIO-4809) + - removed a bunch of escaping, made every group non-capturing (during TBIO-4809) + - colons are only valid when followed directly by // or some text and then @ (TBIO-4867) + - only include the fragment '#' if it has 1 or more trailing matches + - only include the query '?' if it has 1 or more trailing matches + - allow commas in URL path + - exclude trailing comma and period in URL path + - allow up to 15 character schemes including all valid characters from the spec https://url.spec.whatwg.org/#url-scheme-string (TINY-5074) + - changed instances of 0-9 to be \d (TINY-5074) + - reduced duplication (TINY-5074) + - allow [*!;:'@$] in the path segment as they are valid characters per the spec: https://url.spec.whatwg.org/#url-path-segment-string (TINY-8069) + + (?: + (?: + [A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)? + | www\. + | [-;:&=+$,.\w]+@ + ) + [A-Za-z\d-]+ + (?:\.[A-Za-z\d-]+)* + ) + (?::\d+)? + (?: + \/ + (?: + [-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w] + )? + )? + (?: + \? + (?: + [-.~*+=!&;:'%@?^${}(),\/\w]+ + ) + )? + (?: + # + (?: + [-.~*+=!&;:'%@?^${}(),\/\w]+ + ) + )? + */ + const link = () => + // eslint-disable-next-line max-len + /(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g; + + const option = (name) => (editor) => editor.options.get(name); + const register = (editor) => { + const registerOption = editor.options.register; + registerOption('autolink_pattern', { + processor: 'regexp', + // Use the Polaris link detection, however for autolink we need to make it be an exact match + default: new RegExp('^' + link().source + '$', 'i') + }); + registerOption('link_default_target', { + processor: 'string' + }); + registerOption('link_default_protocol', { + processor: 'string', + default: 'https' + }); + }; + const getAutoLinkPattern = option('autolink_pattern'); + const getDefaultLinkTarget = option('link_default_target'); + const getDefaultLinkProtocol = option('link_default_protocol'); + const allowUnsafeLinkTarget = option('allow_unsafe_link_target'); + + var global = tinymce.util.Tools.resolve('tinymce.dom.TextSeeker'); + + const isTextNode = (node) => node.nodeType === 3; + const isElement = (node) => node.nodeType === 1; + const isBracketOrSpace = (char) => /^[(\[{ \u00a0]$/.test(char); + // Note: This is similar to the Polaris protocol detection, except it also handles `mailto` and any length scheme + const hasProtocol = (url) => /^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(url); + // A limited list of punctuation characters that might be used after a link + const isPunctuation = (char) => /[?!,.;:]/.test(char); + const findChar = (text, index, predicate) => { + for (let i = index - 1; i >= 0; i--) { + const char = text.charAt(i); + if (!isZwsp(char) && predicate(char)) { + return i; + } + } + return -1; + }; + const freefallRtl = (container, offset) => { + let tempNode = container; + let tempOffset = offset; + while (isElement(tempNode) && tempNode.childNodes[tempOffset]) { + tempNode = tempNode.childNodes[tempOffset]; + tempOffset = isTextNode(tempNode) ? tempNode.data.length : tempNode.childNodes.length; + } + return { container: tempNode, offset: tempOffset }; + }; + + const parseCurrentLine = (editor, offset) => { + var _a; + const voidElements = editor.schema.getVoidElements(); + const autoLinkPattern = getAutoLinkPattern(editor); + const { dom, selection } = editor; + // Never create a link when we are inside a link + if (dom.getParent(selection.getNode(), 'a[href]') !== null || editor.mode.isReadOnly()) { + return null; + } + const rng = selection.getRng(); + const textSeeker = global(dom, (node) => { + return dom.isBlock(node) || has(voidElements, node.nodeName.toLowerCase()) || dom.getContentEditable(node) === 'false' || dom.getParent(node, 'a[href]') !== null; + }); + // Descend down the end container to find the text node + const { container: endContainer, offset: endOffset } = freefallRtl(rng.endContainer, rng.endOffset); + // Find the root container to use when walking + const root = (_a = dom.getParent(endContainer, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot(); + // Move the selection backwards to the start of the potential URL to account for the pressed character + // while also excluding the last full stop from a word like "www.site.com." + const endSpot = textSeeker.backwards(endContainer, endOffset + offset, (node, offset) => { + const text = node.data; + const idx = findChar(text, offset, not(isBracketOrSpace)); + // Move forward one so the offset is after the found character unless the found char is a punctuation char + return idx === -1 || isPunctuation(text[idx]) ? idx : idx + 1; + }, root); + if (!endSpot) { + return null; + } + // Walk backwards until we find a boundary or a bracket/space + let lastTextNode = endSpot.container; + const startSpot = textSeeker.backwards(endSpot.container, endSpot.offset, (node, offset) => { + lastTextNode = node; + const idx = findChar(node.data, offset, isBracketOrSpace); + // Move forward one so that the offset is after the bracket/space + return idx === -1 ? idx : idx + 1; + }, root); + const newRng = dom.createRng(); + if (!startSpot) { + newRng.setStart(lastTextNode, 0); + } + else { + newRng.setStart(startSpot.container, startSpot.offset); + } + newRng.setEnd(endSpot.container, endSpot.offset); + const rngText = removeZwsp(newRng.toString()); + const matches = rngText.match(autoLinkPattern); + if (matches) { + let url = matches[0]; + if (startsWith(url, 'www.')) { + const protocol = getDefaultLinkProtocol(editor); + url = protocol + '://' + url; + } + else if (contains(url, '@') && !hasProtocol(url)) { + url = 'mailto:' + url; + } + return { rng: newRng, url }; + } + else { + return null; + } + }; + const convertToLink = (editor, result) => { + const { dom, selection } = editor; + const { rng, url } = result; + const bookmark = selection.getBookmark(); + selection.setRng(rng); + // Needs to be a native createlink command since this is executed in a keypress event handler + // so the pending character that is to be inserted needs to be inserted after the link. That will not + // happen if we use the formatter create link version. Since we're using the native command + // then we also need to ensure the exec command events are fired for backwards compatibility. + const command = 'createlink'; + const args = { command, ui: false, value: url }; + const beforeExecEvent = editor.dispatch('BeforeExecCommand', args); + if (!beforeExecEvent.isDefaultPrevented()) { + editor.getDoc().execCommand(command, false, url); + editor.dispatch('ExecCommand', args); + const defaultLinkTarget = getDefaultLinkTarget(editor); + if (isString(defaultLinkTarget)) { + const anchor = selection.getNode(); + dom.setAttrib(anchor, 'target', defaultLinkTarget); + // Ensure noopener is added for blank targets to prevent window opener attacks + if (defaultLinkTarget === '_blank' && !allowUnsafeLinkTarget(editor)) { + dom.setAttrib(anchor, 'rel', 'noopener'); + } + } + } + selection.moveToBookmark(bookmark); + editor.nodeChanged(); + }; + const handleSpacebar = (editor) => { + const result = parseCurrentLine(editor, -1); + if (isNonNullable(result)) { + convertToLink(editor, result); + } + }; + const handleBracket = handleSpacebar; + const handleEnter = (editor) => { + const result = parseCurrentLine(editor, 0); + if (isNonNullable(result)) { + convertToLink(editor, result); + } }; - }; - - const parseCurrentLine = (editor, offset) => { - var _a; - const voidElements = editor.schema.getVoidElements(); - const autoLinkPattern = getAutoLinkPattern(editor); - const {dom, selection} = editor; - if (dom.getParent(selection.getNode(), 'a[href]') !== null || editor.mode.isReadOnly()) { - return null; - } - const rng = selection.getRng(); - const textSeeker = global(dom, node => { - return dom.isBlock(node) || has(voidElements, node.nodeName.toLowerCase()) || dom.getContentEditable(node) === 'false'; - }); - const { - container: endContainer, - offset: endOffset - } = freefallRtl(rng.endContainer, rng.endOffset); - const root = (_a = dom.getParent(endContainer, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot(); - const endSpot = textSeeker.backwards(endContainer, endOffset + offset, (node, offset) => { - const text = node.data; - const idx = findChar(text, offset, not(isBracketOrSpace)); - return idx === -1 || isPunctuation(text[idx]) ? idx : idx + 1; - }, root); - if (!endSpot) { - return null; - } - let lastTextNode = endSpot.container; - const startSpot = textSeeker.backwards(endSpot.container, endSpot.offset, (node, offset) => { - lastTextNode = node; - const idx = findChar(node.data, offset, isBracketOrSpace); - return idx === -1 ? idx : idx + 1; - }, root); - const newRng = dom.createRng(); - if (!startSpot) { - newRng.setStart(lastTextNode, 0); - } else { - newRng.setStart(startSpot.container, startSpot.offset); - } - newRng.setEnd(endSpot.container, endSpot.offset); - const rngText = removeZwsp(newRng.toString()); - const matches = rngText.match(autoLinkPattern); - if (matches) { - let url = matches[0]; - if (startsWith(url, 'www.')) { - const protocol = getDefaultLinkProtocol(editor); - url = protocol + '://' + url; - } else if (contains(url, '@') && !hasProtocol(url)) { - url = 'mailto:' + url; - } - return { - rng: newRng, - url - }; - } else { - return null; - } - }; - const convertToLink = (editor, result) => { - const {dom, selection} = editor; - const {rng, url} = result; - const bookmark = selection.getBookmark(); - selection.setRng(rng); - const command = 'createlink'; - const args = { - command, - ui: false, - value: url + const setup = (editor) => { + editor.on('keydown', (e) => { + if (e.keyCode === 13 && !e.isDefaultPrevented()) { + handleEnter(editor); + } + }); + editor.on('keyup', (e) => { + if (e.keyCode === 32) { + handleSpacebar(editor); + // One of the closing bracket keys: ), ] or } + } + else if (e.keyCode === 48 && e.shiftKey || e.keyCode === 221) { + handleBracket(editor); + } + }); }; - const beforeExecEvent = editor.dispatch('BeforeExecCommand', args); - if (!beforeExecEvent.isDefaultPrevented()) { - editor.getDoc().execCommand(command, false, url); - editor.dispatch('ExecCommand', args); - const defaultLinkTarget = getDefaultLinkTarget(editor); - if (isString(defaultLinkTarget)) { - const anchor = selection.getNode(); - dom.setAttrib(anchor, 'target', defaultLinkTarget); - if (defaultLinkTarget === '_blank' && !allowUnsafeLinkTarget(editor)) { - dom.setAttrib(anchor, 'rel', 'noopener'); - } - } - } - selection.moveToBookmark(bookmark); - editor.nodeChanged(); - }; - const handleSpacebar = editor => { - const result = parseCurrentLine(editor, -1); - if (isNonNullable(result)) { - convertToLink(editor, result); - } - }; - const handleBracket = handleSpacebar; - const handleEnter = editor => { - const result = parseCurrentLine(editor, 0); - if (isNonNullable(result)) { - convertToLink(editor, result); - } - }; - const setup = editor => { - editor.on('keydown', e => { - if (e.keyCode === 13 && !e.isDefaultPrevented()) { - handleEnter(editor); - } - }); - editor.on('keyup', e => { - if (e.keyCode === 32) { - handleSpacebar(editor); - } else if (e.keyCode === 48 && e.shiftKey || e.keyCode === 221) { - handleBracket(editor); - } - }); - }; - - var Plugin = () => { - global$1.add('autolink', editor => { - register(editor); - setup(editor); - }); - }; - - Plugin(); + + var Plugin = () => { + global$1.add('autolink', (editor) => { + register(editor); + setup(editor); + }); + }; + + Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/autolink/plugin.min.js b/public/ext/tinymce/plugins/autolink/plugin.min.js index 3abfc6b..8d9f054 100644 --- a/public/ext/tinymce/plugins/autolink/plugin.min.js +++ b/public/ext/tinymce/plugins/autolink/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e);const l=e=>undefined===e;const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]")||e.mode.isReadOnly())return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),w=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),h=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),w);if(!h)return null;let v=h.container;const _=k.backwards(h.container,h.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),w),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(h.container,h.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=4&&b.substr(0,4)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e);const n=e=>undefined===e;const o=e=>!(e=>null==e)(e),r=Object.hasOwnProperty,a=e=>"\ufeff"===e,s=e=>t=>t.options.get(e),l=s("autolink_pattern"),i=s("link_default_target"),c=s("link_default_protocol"),d=s("allow_unsafe_link_target");var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!a(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=l(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]")||e.mode.isReadOnly())return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),r.call(t,n))||"false"===i.getContentEditable(e)||null!==i.getParent(e,"a[href]");var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),w=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),h=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),w);if(!h)return null;let v=h.container;const _=k.backwards(h.container,h.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),w),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(h.container,h.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return P="www.",(b=t).length>=4&&b.substr(0,4)===P?t=c(e)+"://"+t:((e,t,o=0,r)=>{const a=e.indexOf(t,o);return-1!==a&&(!!n(r)||a+t.length<=r)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,P;return null},k=(e,n)=>{const{dom:o,selection:r}=e,{rng:a,url:s}=n,l=r.getBookmark();r.setRng(a);const c="createlink",u={command:c,ui:!1,value:s};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(c,!1,s),e.dispatch("ExecCommand",u);const n=i(e);if(t(n)){const t=r.getNode();o.setAttrib(t,"target",n),"_blank"!==n||d(e)||o.setAttrib(t,"rel","noopener")}}r.moveToBookmark(l),e.nodeChanged()},p=e=>{const t=m(e,-1);o(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);o(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/autoresize/plugin.js b/public/ext/tinymce/plugins/autoresize/plugin.js index f99bd0b..2750a9a 100644 --- a/public/ext/tinymce/plugins/autoresize/plugin.js +++ b/public/ext/tinymce/plugins/autoresize/plugin.js @@ -1,179 +1,223 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { 'use strict'; - const Cell = initial => { - let value = initial; - const get = () => { - return value; - }; - const set = v => { - value = v; - }; - return { - get, - set - }; + const Cell = (initial) => { + let value = initial; + const get = () => { + return value; + }; + const set = (v) => { + value = v; + }; + return { + get, + set + }; }; var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager'); var global = tinymce.util.Tools.resolve('tinymce.Env'); - const fireResizeEditor = editor => editor.dispatch('ResizeEditor'); + const fireResizeEditor = (editor) => editor.dispatch('ResizeEditor'); - const option = name => editor => editor.options.get(name); - const register$1 = editor => { - const registerOption = editor.options.register; - registerOption('autoresize_overflow_padding', { - processor: 'number', - default: 1 - }); - registerOption('autoresize_bottom_margin', { - processor: 'number', - default: 50 - }); + const option = (name) => (editor) => editor.options.get(name); + const register$1 = (editor) => { + const registerOption = editor.options.register; + registerOption('autoresize_overflow_padding', { + processor: 'number', + default: 1 + }); + registerOption('autoresize_bottom_margin', { + processor: 'number', + default: 50 + }); }; const getMinHeight = option('min_height'); const getMaxHeight = option('max_height'); const getAutoResizeOverflowPadding = option('autoresize_overflow_padding'); const getAutoResizeBottomMargin = option('autoresize_bottom_margin'); - const isFullscreen = editor => editor.plugins.fullscreen && editor.plugins.fullscreen.isFullscreen(); + /** + * This class contains all core logic for the autoresize plugin. + * + * @class tinymce.autoresize.Plugin + * @private + */ + const isFullscreen = (editor) => editor.plugins.fullscreen && editor.plugins.fullscreen.isFullscreen(); const toggleScrolling = (editor, state) => { - const body = editor.getBody(); - if (body) { - body.style.overflowY = state ? '' : 'hidden'; - if (!state) { - body.scrollTop = 0; + const body = editor.getBody(); + if (body) { + body.style.overflowY = state ? '' : 'hidden'; + if (!state) { + body.scrollTop = 0; + } } - } }; const parseCssValueToInt = (dom, elm, name, computed) => { - var _a; - const value = parseInt((_a = dom.getStyle(elm, name, computed)) !== null && _a !== void 0 ? _a : '', 10); - return isNaN(value) ? 0 : value; + var _a; + const value = parseInt((_a = dom.getStyle(elm, name, computed)) !== null && _a !== void 0 ? _a : '', 10); + // The value maybe be an empty string, so in that case treat it as being 0 + return isNaN(value) ? 0 : value; }; - const shouldScrollIntoView = trigger => { - if ((trigger === null || trigger === void 0 ? void 0 : trigger.type.toLowerCase()) === 'setcontent') { - const setContentEvent = trigger; - return setContentEvent.selection === true || setContentEvent.paste === true; - } else { - return false; - } + const shouldScrollIntoView = (trigger) => { + // Only scroll the selection into view when we're inserting content. Any other + // triggers the selection should already be in view and resizing would only + // extend the content area. + if ((trigger === null || trigger === void 0 ? void 0 : trigger.type.toLowerCase()) === 'setcontent') { + const setContentEvent = trigger; + return setContentEvent.selection === true || setContentEvent.paste === true; + } + else { + return false; + } }; + /** + * This method gets executed each time the editor needs to resize. + */ const resize = (editor, oldSize, trigger, getExtraMarginBottom) => { - var _a; - const dom = editor.dom; - const doc = editor.getDoc(); - if (!doc) { - return; - } - if (isFullscreen(editor)) { - toggleScrolling(editor, true); - return; - } - const docEle = doc.documentElement; - const resizeBottomMargin = getExtraMarginBottom ? getExtraMarginBottom() : getAutoResizeOverflowPadding(editor); - const minHeight = (_a = getMinHeight(editor)) !== null && _a !== void 0 ? _a : editor.getElement().offsetHeight; - let resizeHeight = minHeight; - const marginTop = parseCssValueToInt(dom, docEle, 'margin-top', true); - const marginBottom = parseCssValueToInt(dom, docEle, 'margin-bottom', true); - let contentHeight = docEle.offsetHeight + marginTop + marginBottom + resizeBottomMargin; - if (contentHeight < 0) { - contentHeight = 0; - } - const containerHeight = editor.getContainer().offsetHeight; - const contentAreaHeight = editor.getContentAreaContainer().offsetHeight; - const chromeHeight = containerHeight - contentAreaHeight; - if (contentHeight + chromeHeight > minHeight) { - resizeHeight = contentHeight + chromeHeight; - } - const maxHeight = getMaxHeight(editor); - if (maxHeight && resizeHeight > maxHeight) { - resizeHeight = maxHeight; - toggleScrolling(editor, true); - } else { - toggleScrolling(editor, false); - } - const old = oldSize.get(); - if (old.set) { - editor.dom.setStyles(editor.getDoc().documentElement, { 'min-height': 0 }); - editor.dom.setStyles(editor.getBody(), { 'min-height': 'inherit' }); - } - if (resizeHeight !== old.totalHeight && (contentHeight - resizeBottomMargin !== old.contentHeight || !old.set)) { - const deltaSize = resizeHeight - old.totalHeight; - dom.setStyle(editor.getContainer(), 'height', resizeHeight + 'px'); - oldSize.set({ - totalHeight: resizeHeight, - contentHeight, - set: true - }); - fireResizeEditor(editor); - if (global.browser.isSafari() && (global.os.isMacOS() || global.os.isiOS())) { - const win = editor.getWin(); - win.scrollTo(win.pageXOffset, win.pageYOffset); + var _a; + const dom = editor.dom; + const doc = editor.getDoc(); + if (!doc) { + return; + } + if (isFullscreen(editor)) { + toggleScrolling(editor, true); + return; + } + const docEle = doc.documentElement; + const resizeBottomMargin = getExtraMarginBottom ? getExtraMarginBottom() : getAutoResizeOverflowPadding(editor); + const minHeight = (_a = getMinHeight(editor)) !== null && _a !== void 0 ? _a : editor.getElement().offsetHeight; + let resizeHeight = minHeight; + // Calculate outer height of the doc element using CSS styles + const marginTop = parseCssValueToInt(dom, docEle, 'margin-top', true); + const marginBottom = parseCssValueToInt(dom, docEle, 'margin-bottom', true); + let contentHeight = docEle.offsetHeight + marginTop + marginBottom + resizeBottomMargin; + // Make sure we have a valid height + if (contentHeight < 0) { + contentHeight = 0; + } + // Determine the size of the chroming (menubar, toolbar, etc...) + const containerHeight = editor.getContainer().offsetHeight; + const contentAreaHeight = editor.getContentAreaContainer().offsetHeight; + const chromeHeight = containerHeight - contentAreaHeight; + // Don't make it smaller than the minimum height + if (contentHeight + chromeHeight > minHeight) { + resizeHeight = contentHeight + chromeHeight; + } + // If a maximum height has been defined don't exceed this height + const maxHeight = getMaxHeight(editor); + if (maxHeight && resizeHeight > maxHeight) { + resizeHeight = maxHeight; + toggleScrolling(editor, true); } - if (editor.hasFocus() && shouldScrollIntoView(trigger)) { - editor.selection.scrollIntoView(); + else { + toggleScrolling(editor, false); } - if ((global.browser.isSafari() || global.browser.isChromium()) && deltaSize < 0) { - resize(editor, oldSize, trigger, getExtraMarginBottom); + const old = oldSize.get(); + if (old.set) { + editor.dom.setStyles(editor.getDoc().documentElement, { 'min-height': 0 }); + editor.dom.setStyles(editor.getBody(), { 'min-height': 'inherit' }); + } + // Resize content element + if (resizeHeight !== old.totalHeight && (contentHeight - resizeBottomMargin !== old.contentHeight || !old.set)) { + const deltaSize = (resizeHeight - old.totalHeight); + dom.setStyle(editor.getContainer(), 'height', resizeHeight + 'px'); + oldSize.set({ + totalHeight: resizeHeight, + contentHeight, + set: true, + }); + fireResizeEditor(editor); + // iPadOS has an issue where it won't rerender the body when the iframe is resized + // however if we reset the scroll position then it re-renders correctly + if (global.browser.isSafari() && (global.os.isMacOS() || global.os.isiOS())) { + const win = editor.getWin(); + win.scrollTo(win.pageXOffset, win.pageYOffset); + } + // Ensure the selection is in view, as it's potentially out of view after inserting content into the editor + if (editor.hasFocus() && shouldScrollIntoView(trigger)) { + editor.selection.scrollIntoView(); + } + // WebKit doesn't decrease the size of the body element until the iframe gets resized + // So we need to continue to resize the iframe down until the size gets fixed + if ((global.browser.isSafari() || global.browser.isChromium()) && deltaSize < 0) { + resize(editor, oldSize, trigger, getExtraMarginBottom); + } } - } }; const setup = (editor, oldSize) => { - const getExtraMarginBottom = () => getAutoResizeBottomMargin(editor); - editor.on('init', e => { - const overflowPadding = getAutoResizeOverflowPadding(editor); - const dom = editor.dom; - dom.setStyles(editor.getDoc().documentElement, { height: 'auto' }); - if (global.browser.isEdge() || global.browser.isIE()) { - dom.setStyles(editor.getBody(), { - 'paddingLeft': overflowPadding, - 'paddingRight': overflowPadding, - 'min-height': 0 - }); - } else { - dom.setStyles(editor.getBody(), { - paddingLeft: overflowPadding, - paddingRight: overflowPadding - }); - } - resize(editor, oldSize, e, getExtraMarginBottom); - }); - editor.on('NodeChange SetContent keyup FullscreenStateChanged ResizeContent', e => { - resize(editor, oldSize, e, getExtraMarginBottom); - }); + const getExtraMarginBottom = () => getAutoResizeBottomMargin(editor); + editor.on('init', (e) => { + const overflowPadding = getAutoResizeOverflowPadding(editor); + const dom = editor.dom; + // Disable height 100% on the root document element otherwise we'll end up resizing indefinitely + dom.setStyles(editor.getDoc().documentElement, { + height: 'auto' + }); + if (global.browser.isEdge() || global.browser.isIE()) { + dom.setStyles(editor.getBody(), { + 'paddingLeft': overflowPadding, + 'paddingRight': overflowPadding, + // IE & Edge have a min height of 150px by default on the body, so override that + 'min-height': 0 + }); + } + else { + dom.setStyles(editor.getBody(), { + paddingLeft: overflowPadding, + paddingRight: overflowPadding + }); + } + resize(editor, oldSize, e, getExtraMarginBottom); + }); + editor.on('NodeChange SetContent keyup FullscreenStateChanged ResizeContent', (e) => { + resize(editor, oldSize, e, getExtraMarginBottom); + }); }; const register = (editor, oldSize) => { - editor.addCommand('mceAutoResize', () => { - resize(editor, oldSize); - }); + editor.addCommand('mceAutoResize', () => { + resize(editor, oldSize); + }); }; + /** + * This class contains all core logic for the autoresize plugin. + * + * @class tinymce.autoresize.Plugin + * @private + */ var Plugin = () => { - global$1.add('autoresize', editor => { - register$1(editor); - if (!editor.options.isSet('resize')) { - editor.options.set('resize', false); - } - if (!editor.inline) { - const oldSize = Cell({ - totalHeight: 0, - contentHeight: 0, - set: false - }); - register(editor, oldSize); - setup(editor, oldSize); - } - }); + global$1.add('autoresize', (editor) => { + register$1(editor); + // If autoresize is enabled, disable resize if the user hasn't explicitly enabled it + // TINY-8288: This currently does nothing because of a bug in the theme + if (!editor.options.isSet('resize')) { + editor.options.set('resize', false); + } + if (!editor.inline) { + const oldSize = Cell({ + totalHeight: 0, + contentHeight: 0, + set: false, + }); + register(editor, oldSize); + setup(editor, oldSize); + } + }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/autoresize/plugin.min.js b/public/ext/tinymce/plugins/autoresize/plugin.min.js index 749ee8b..654d63f 100644 --- a/public/ext/tinymce/plugins/autoresize/plugin.min.js +++ b/public/ext/tinymce/plugins/autoresize/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ !function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),n=o("min_height"),s=o("max_height"),i=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),g=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},l=(e,t,o,n)=>{var s;const i=parseInt(null!==(s=e.getStyle(t,o,n))&&void 0!==s?s:"",10);return isNaN(i)?0:i},a=(e,o,r,c)=>{var d;const u=e.dom,h=e.getDoc();if(!h)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void g(e,!0);const m=h.documentElement,f=c?c():i(e),p=null!==(d=n(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=l(u,m,"margin-top",!0),v=l(u,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+f;C<0&&(C=0);const H=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+H>p&&(y=C+H);const b=s(e);b&&y>b?(y=b,g(e,!0)):g(e,!1);const w=o.get();if(w.set&&(e.dom.setStyles(e.getDoc().documentElement,{"min-height":0}),e.dom.setStyles(e.getBody(),{"min-height":"inherit"})),y!==w.totalHeight&&(C-f!==w.contentHeight||!w.set)){const n=y-w.totalHeight;if(u.setStyle(e.getContainer(),"height",y+"px"),o.set({totalHeight:y,contentHeight:C,set:!0}),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&n<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(()=>{let e={totalHeight:0,contentHeight:0,set:!1};return{get:()=>e,set:t=>{e=t}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{const n=()=>r(e);e.on("init",(s=>{const r=i(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,s,n)})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{a(e,o,t,n)}))})(e,o)}}))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/autosave/plugin.js b/public/ext/tinymce/plugins/autosave/plugin.js index 197cd31..2744d01 100644 --- a/public/ext/tinymce/plugins/autosave/plugin.js +++ b/public/ext/tinymce/plugins/autosave/plugin.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -7,28 +7,34 @@ var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager'); + /* eslint-disable @typescript-eslint/no-wrapper-object-types */ const hasProto = (v, constructor, predicate) => { - var _a; - if (predicate(v, constructor.prototype)) { - return true; - } else { - return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; - } - }; - const typeOf = x => { - const t = typeof x; - if (x === null) { - return 'null'; - } else if (t === 'object' && Array.isArray(x)) { - return 'array'; - } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { - return 'string'; - } else { - return t; - } - }; - const isType = type => value => typeOf(value) === type; - const eq = t => a => t === a; + var _a; + if (predicate(v, constructor.prototype)) { + return true; + } + else { + // String-based fallback time + return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; + } + }; + const typeOf = (x) => { + const t = typeof x; + if (x === null) { + return 'null'; + } + else if (t === 'object' && Array.isArray(x)) { + return 'array'; + } + else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { + return 'string'; + } + else { + return t; + } + }; + const isType = (type) => (value) => typeOf(value) === type; + const eq = (t) => (a) => t === a; const isString = isType('string'); const isUndefined = eq(undefined); @@ -38,197 +44,209 @@ var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools'); - const fireRestoreDraft = editor => editor.dispatch('RestoreDraft'); - const fireStoreDraft = editor => editor.dispatch('StoreDraft'); - const fireRemoveDraft = editor => editor.dispatch('RemoveDraft'); - - const parse = timeString => { - const multiples = { - s: 1000, - m: 60000 - }; - const parsedTime = /^(\d+)([ms]?)$/.exec(timeString); - return (parsedTime && parsedTime[2] ? multiples[parsedTime[2]] : 1) * parseInt(timeString, 10); - }; - - const option = name => editor => editor.options.get(name); - const register$1 = editor => { - const registerOption = editor.options.register; - const timeProcessor = value => { - const valid = isString(value); - if (valid) { - return { - value: parse(value), - valid - }; - } else { - return { - valid: false, - message: 'Must be a string.' - }; - } - }; - registerOption('autosave_ask_before_unload', { - processor: 'boolean', - default: true - }); - registerOption('autosave_prefix', { - processor: 'string', - default: 'tinymce-autosave-{path}{query}{hash}-{id}-' - }); - registerOption('autosave_restore_when_empty', { - processor: 'boolean', - default: false - }); - registerOption('autosave_interval', { - processor: timeProcessor, - default: '30s' - }); - registerOption('autosave_retention', { - processor: timeProcessor, - default: '20m' - }); + const fireRestoreDraft = (editor) => editor.dispatch('RestoreDraft'); + const fireStoreDraft = (editor) => editor.dispatch('StoreDraft'); + const fireRemoveDraft = (editor) => editor.dispatch('RemoveDraft'); + + const parse = (timeString) => { + const multiples = { + s: 1000, + m: 60000 + }; + const parsedTime = /^(\d+)([ms]?)$/.exec(timeString); + return (parsedTime && parsedTime[2] ? multiples[parsedTime[2]] : 1) * parseInt(timeString, 10); + }; + + const option = (name) => (editor) => editor.options.get(name); + const register$1 = (editor) => { + const registerOption = editor.options.register; + const timeProcessor = (value) => { + const valid = isString(value); + if (valid) { + return { value: parse(value), valid }; + } + else { + return { valid: false, message: 'Must be a string.' }; + } + }; + registerOption('autosave_ask_before_unload', { + processor: 'boolean', + default: true + }); + registerOption('autosave_prefix', { + processor: 'string', + default: 'tinymce-autosave-{path}{query}{hash}-{id}-' + }); + registerOption('autosave_restore_when_empty', { + processor: 'boolean', + default: false + }); + registerOption('autosave_interval', { + processor: timeProcessor, + default: '30s' + }); + registerOption('autosave_retention', { + processor: timeProcessor, + default: '20m' + }); }; const shouldAskBeforeUnload = option('autosave_ask_before_unload'); const shouldRestoreWhenEmpty = option('autosave_restore_when_empty'); const getAutoSaveInterval = option('autosave_interval'); const getAutoSaveRetention = option('autosave_retention'); - const getAutoSavePrefix = editor => { - const location = document.location; - return editor.options.get('autosave_prefix').replace(/{path}/g, location.pathname).replace(/{query}/g, location.search).replace(/{hash}/g, location.hash).replace(/{id}/g, editor.id); + const getAutoSavePrefix = (editor) => { + const location = document.location; + return editor.options.get('autosave_prefix').replace(/{path}/g, location.pathname) + .replace(/{query}/g, location.search) + .replace(/{hash}/g, location.hash) + .replace(/{id}/g, editor.id); }; const isEmpty = (editor, html) => { - if (isUndefined(html)) { - return editor.dom.isEmpty(editor.getBody()); - } else { - const trimmedHtml = global$1.trim(html); - if (trimmedHtml === '') { - return true; - } else { - const fragment = new DOMParser().parseFromString(trimmedHtml, 'text/html'); - return editor.dom.isEmpty(fragment); + if (isUndefined(html)) { + return editor.dom.isEmpty(editor.getBody()); + } + else { + const trimmedHtml = global$1.trim(html); + if (trimmedHtml === '') { + return true; + } + else { + const fragment = new DOMParser().parseFromString(trimmedHtml, 'text/html'); + return editor.dom.isEmpty(fragment); + } } - } }; - const hasDraft = editor => { - var _a; - const time = parseInt((_a = global$2.getItem(getAutoSavePrefix(editor) + 'time')) !== null && _a !== void 0 ? _a : '0', 10) || 0; - if (new Date().getTime() - time > getAutoSaveRetention(editor)) { - removeDraft(editor, false); - return false; - } - return true; + const hasDraft = (editor) => { + var _a; + const time = parseInt((_a = global$2.getItem(getAutoSavePrefix(editor) + 'time')) !== null && _a !== void 0 ? _a : '0', 10) || 0; + if (new Date().getTime() - time > getAutoSaveRetention(editor)) { + removeDraft(editor, false); + return false; + } + return true; }; const removeDraft = (editor, fire) => { - const prefix = getAutoSavePrefix(editor); - global$2.removeItem(prefix + 'draft'); - global$2.removeItem(prefix + 'time'); - if (fire !== false) { - fireRemoveDraft(editor); - } - }; - const storeDraft = editor => { - const prefix = getAutoSavePrefix(editor); - if (!isEmpty(editor) && editor.isDirty()) { - global$2.setItem(prefix + 'draft', editor.getContent({ - format: 'raw', - no_events: true - })); - global$2.setItem(prefix + 'time', new Date().getTime().toString()); - fireStoreDraft(editor); - } - }; - const restoreDraft = editor => { - var _a; - const prefix = getAutoSavePrefix(editor); - if (hasDraft(editor)) { - editor.setContent((_a = global$2.getItem(prefix + 'draft')) !== null && _a !== void 0 ? _a : '', { format: 'raw' }); - fireRestoreDraft(editor); - } - }; - const startStoreDraft = editor => { - const interval = getAutoSaveInterval(editor); - global$3.setEditorInterval(editor, () => { - storeDraft(editor); - }, interval); - }; - const restoreLastDraft = editor => { - editor.undoManager.transact(() => { - restoreDraft(editor); - removeDraft(editor); - }); - editor.focus(); - }; - - const get = editor => ({ - hasDraft: () => hasDraft(editor), - storeDraft: () => storeDraft(editor), - restoreDraft: () => restoreDraft(editor), - removeDraft: fire => removeDraft(editor, fire), - isEmpty: html => isEmpty(editor, html) + const prefix = getAutoSavePrefix(editor); + global$2.removeItem(prefix + 'draft'); + global$2.removeItem(prefix + 'time'); + if (fire !== false) { + fireRemoveDraft(editor); + } + }; + const storeDraft = (editor) => { + const prefix = getAutoSavePrefix(editor); + if (!isEmpty(editor) && editor.isDirty()) { + global$2.setItem(prefix + 'draft', editor.getContent({ format: 'raw', no_events: true })); + global$2.setItem(prefix + 'time', new Date().getTime().toString()); + fireStoreDraft(editor); + } + }; + const restoreDraft = (editor) => { + var _a; + const prefix = getAutoSavePrefix(editor); + if (hasDraft(editor)) { + editor.setContent((_a = global$2.getItem(prefix + 'draft')) !== null && _a !== void 0 ? _a : '', { format: 'raw' }); + fireRestoreDraft(editor); + } + }; + const startStoreDraft = (editor) => { + const interval = getAutoSaveInterval(editor); + global$3.setEditorInterval(editor, () => { + storeDraft(editor); + }, interval); + }; + const restoreLastDraft = (editor) => { + editor.undoManager.transact(() => { + restoreDraft(editor); + removeDraft(editor); + }); + editor.focus(); + }; + + const get = (editor) => ({ + hasDraft: () => hasDraft(editor), + storeDraft: () => storeDraft(editor), + restoreDraft: () => restoreDraft(editor), + removeDraft: (fire) => removeDraft(editor, fire), + isEmpty: (html) => isEmpty(editor, html) }); var global = tinymce.util.Tools.resolve('tinymce.EditorManager'); - const setup = editor => { - editor.editorManager.on('BeforeUnload', e => { - let msg; - global$1.each(global.get(), editor => { - if (editor.plugins.autosave) { - editor.plugins.autosave.storeDraft(); - } - if (!msg && editor.isDirty() && shouldAskBeforeUnload(editor)) { - msg = editor.translate('You have unsaved changes are you sure you want to navigate away?'); - } + const setup = (editor) => { + editor.editorManager.on('BeforeUnload', (e) => { + let msg; + global$1.each(global.get(), (editor) => { + // Store a draft for each editor instance + if (editor.plugins.autosave) { + editor.plugins.autosave.storeDraft(); + } + // Setup a return message if the editor is dirty + if (!msg && editor.isDirty() && shouldAskBeforeUnload(editor)) { + msg = editor.translate('You have unsaved changes are you sure you want to navigate away?'); + } + }); + if (msg) { + e.preventDefault(); + e.returnValue = msg; + } + }); + }; + + const makeSetupHandler = (editor) => (api) => { + const shouldEnable = () => hasDraft(editor) && !editor.mode.isReadOnly(); + api.setEnabled(shouldEnable()); + const editorEventCallback = () => api.setEnabled(shouldEnable()); + editor.on('StoreDraft RestoreDraft RemoveDraft', editorEventCallback); + return () => editor.off('StoreDraft RestoreDraft RemoveDraft', editorEventCallback); + }; + const register = (editor) => { + // TODO: This was moved from makeSetupHandler as it would only be called when the menu item was rendered? + // Is it safe to start this process when the plugin is registered? + startStoreDraft(editor); + const onAction = () => { + restoreLastDraft(editor); + }; + editor.ui.registry.addButton('restoredraft', { + tooltip: 'Restore last draft', + icon: 'restore-draft', + onAction, + onSetup: makeSetupHandler(editor) + }); + editor.ui.registry.addMenuItem('restoredraft', { + text: 'Restore last draft', + icon: 'restore-draft', + onAction, + onSetup: makeSetupHandler(editor) }); - if (msg) { - e.preventDefault(); - e.returnValue = msg; - } - }); - }; - - const makeSetupHandler = editor => api => { - const shouldEnable = () => hasDraft(editor) && !editor.mode.isReadOnly(); - api.setEnabled(shouldEnable()); - const editorEventCallback = () => api.setEnabled(shouldEnable()); - editor.on('StoreDraft RestoreDraft RemoveDraft', editorEventCallback); - return () => editor.off('StoreDraft RestoreDraft RemoveDraft', editorEventCallback); - }; - const register = editor => { - startStoreDraft(editor); - const onAction = () => { - restoreLastDraft(editor); - }; - editor.ui.registry.addButton('restoredraft', { - tooltip: 'Restore last draft', - icon: 'restore-draft', - onAction, - onSetup: makeSetupHandler(editor) - }); - editor.ui.registry.addMenuItem('restoredraft', { - text: 'Restore last draft', - icon: 'restore-draft', - onAction, - onSetup: makeSetupHandler(editor) - }); }; + /** + * This class contains all core logic for the autosave plugin. + * + * @class tinymce.autosave.Plugin + * @private + */ var Plugin = () => { - global$4.add('autosave', editor => { - register$1(editor); - setup(editor); - register(editor); - editor.on('init', () => { - if (shouldRestoreWhenEmpty(editor) && editor.dom.isEmpty(editor.getBody())) { - restoreDraft(editor); - } + global$4.add('autosave', (editor) => { + register$1(editor); + setup(editor); + register(editor); + editor.on('init', () => { + if (shouldRestoreWhenEmpty(editor) && editor.dom.isEmpty(editor.getBody())) { + restoreDraft(editor); + } + }); + return get(editor); }); - return get(editor); - }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/autosave/plugin.min.js b/public/ext/tinymce/plugins/autosave/plugin.min.js index 28c7392..4f4235a 100644 --- a/public/ext/tinymce/plugins/autosave/plugin.min.js +++ b/public/ext/tinymce/plugins/autosave/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ !function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t);const r=t=>undefined===t;var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},y=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},g=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{const r=()=>f(t)&&!t.mode.isReadOnly();e.setEnabled(r());const o=()=>e.setEnabled(r());return t.on("StoreDraft RestoreDraft RemoveDraft",o),()=>t.off("StoreDraft RestoreDraft RemoveDraft",o)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{y(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{g(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&g(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>y(t),restoreDraft:()=>g(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/charmap/plugin.js b/public/ext/tinymce/plugins/charmap/plugin.js index 2246b8a..82b01df 100644 --- a/public/ext/tinymce/plugins/charmap/plugin.js +++ b/public/ext/tinymce/plugins/charmap/plugin.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -8,194 +8,425 @@ var global$1 = tinymce.util.Tools.resolve('tinymce.PluginManager'); const fireInsertCustomChar = (editor, chr) => { - return editor.dispatch('insertCustomChar', { chr }); + return editor.dispatch('insertCustomChar', { chr }); }; const insertChar = (editor, chr) => { - const evtChr = fireInsertCustomChar(editor, chr).chr; - editor.execCommand('mceInsertContent', false, evtChr); + const evtChr = fireInsertCustomChar(editor, chr).chr; + editor.execCommand('mceInsertContent', false, evtChr); }; + /* eslint-disable @typescript-eslint/no-wrapper-object-types */ const hasProto = (v, constructor, predicate) => { - var _a; - if (predicate(v, constructor.prototype)) { - return true; - } else { - return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; - } + var _a; + if (predicate(v, constructor.prototype)) { + return true; + } + else { + // String-based fallback time + return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name; + } }; - const typeOf = x => { - const t = typeof x; - if (x === null) { - return 'null'; - } else if (t === 'object' && Array.isArray(x)) { - return 'array'; - } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { - return 'string'; - } else { - return t; - } + const typeOf = (x) => { + const t = typeof x; + if (x === null) { + return 'null'; + } + else if (t === 'object' && Array.isArray(x)) { + return 'array'; + } + else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) { + return 'string'; + } + else { + return t; + } }; - const isType = type => value => typeOf(value) === type; - const isSimpleType = type => value => typeof value === type; - const eq = t => a => t === a; + const isType = (type) => (value) => typeOf(value) === type; + const isSimpleType = (type) => (value) => typeof value === type; + const eq = (t) => (a) => t === a; const isArray$1 = isType('array'); const isNull = eq(null); const isUndefined = eq(undefined); - const isNullable = a => a === null || a === undefined; - const isNonNullable = a => !isNullable(a); + const isNullable = (a) => a === null || a === undefined; + const isNonNullable = (a) => !isNullable(a); const isFunction = isSimpleType('function'); - const constant = value => { - return () => { - return value; - }; + const constant = (value) => { + return () => { + return value; + }; }; const never = constant(false); + /** + * The `Optional` type represents a value (of any type) that potentially does + * not exist. Any `Optional` can either be a `Some` (in which case the + * value does exist) or a `None` (in which case the value does not exist). This + * module defines a whole lot of FP-inspired utility functions for dealing with + * `Optional` objects. + * + * Comparison with null or undefined: + * - We don't get fancy null coalescing operators with `Optional` + * - We do get fancy helper functions with `Optional` + * - `Optional` support nesting, and allow for the type to still be nullable (or + * another `Optional`) + * - There is no option to turn off strict-optional-checks like there is for + * strict-null-checks + */ class Optional { - constructor(tag, value) { - this.tag = tag; - this.value = value; - } - static some(value) { - return new Optional(true, value); - } - static none() { - return Optional.singletonNone; - } - fold(onNone, onSome) { - if (this.tag) { - return onSome(this.value); - } else { - return onNone(); + // The internal representation has a `tag` and a `value`, but both are + // private: able to be console.logged, but not able to be accessed by code + constructor(tag, value) { + this.tag = tag; + this.value = value; + } + // --- Identities --- + /** + * Creates a new `Optional` that **does** contain a value. + */ + static some(value) { + return new Optional(true, value); + } + /** + * Create a new `Optional` that **does not** contain a value. `T` can be + * any type because we don't actually have a `T`. + */ + static none() { + return Optional.singletonNone; + } + /** + * Perform a transform on an `Optional` type. Regardless of whether this + * `Optional` contains a value or not, `fold` will return a value of type `U`. + * If this `Optional` does not contain a value, the `U` will be created by + * calling `onNone`. If this `Optional` does contain a value, the `U` will be + * created by calling `onSome`. + * + * For the FP enthusiasts in the room, this function: + * 1. Could be used to implement all of the functions below + * 2. Forms a catamorphism + */ + fold(onNone, onSome) { + if (this.tag) { + return onSome(this.value); + } + else { + return onNone(); + } + } + /** + * Determine if this `Optional` object contains a value. + */ + isSome() { + return this.tag; + } + /** + * Determine if this `Optional` object **does not** contain a value. + */ + isNone() { + return !this.tag; + } + // --- Functor (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. If + * you provide a function to turn a T into a U, this is the function you use + * to turn an `Optional` into an `Optional`. If this **does** contain + * a value then the output will also contain a value (that value being the + * output of `mapper(this.value)`), and if this **does not** contain a value + * then neither will the output. + */ + map(mapper) { + if (this.tag) { + return Optional.some(mapper(this.value)); + } + else { + return Optional.none(); + } + } + // --- Monad (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. + * Unlike `map`, here the transform itself also returns an `Optional`. + */ + bind(binder) { + if (this.tag) { + return binder(this.value); + } + else { + return Optional.none(); + } + } + // --- Traversable (name stolen from Haskell / maths) --- + /** + * For a given predicate, this function finds out if there **exists** a value + * inside this `Optional` object that meets the predicate. In practice, this + * means that for `Optional`s that do not contain a value it returns false (as + * no predicate-meeting value exists). + */ + exists(predicate) { + return this.tag && predicate(this.value); + } + /** + * For a given predicate, this function finds out if **all** the values inside + * this `Optional` object meet the predicate. In practice, this means that + * for `Optional`s that do not contain a value it returns true (as all 0 + * objects do meet the predicate). + */ + forall(predicate) { + return !this.tag || predicate(this.value); + } + filter(predicate) { + if (!this.tag || predicate(this.value)) { + return this; + } + else { + return Optional.none(); + } + } + // --- Getters --- + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. + */ + getOr(replacement) { + return this.tag ? this.value : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` object is also + * `Optional` - meaning that this method will always return an `Optional`. + */ + or(replacement) { + return this.tag ? this : replacement; + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` value is + * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you + * pass a function which (if called) will **return** the `value` you want to + * use. + */ + getOrThunk(thunk) { + return this.tag ? this.value : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided Optional object does not contain a + * value. + * + * Unlike `or`, in this method the `replacement` value is "thunked" - that is + * to say that you don't pass a value to `orThunk`, you pass a function which + * (if called) will **return** the `value` you want to use. + * + * Unlike `getOrThunk`, in this method the `replacement` value is also + * `Optional`, meaning that this method will always return an `Optional`. + */ + orThunk(thunk) { + return this.tag ? this : thunk(); + } + /** + * Get the value out of the inside of the `Optional` object, throwing an + * exception if the provided `Optional` object does not contain a value. + * + * WARNING: + * You should only be using this function if you know that the `Optional` + * object **is not** empty (otherwise you're throwing exceptions in production + * code, which is bad). + * + * In tests this is more acceptable. + * + * Prefer other methods to this, such as `.each`. + */ + getOrDie(message) { + if (!this.tag) { + throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); + } + else { + return this.value; + } + } + // --- Interop with null and undefined --- + /** + * Creates an `Optional` value from a nullable (or undefined-able) input. + * Null, or undefined, is converted to `None`, and anything else is converted + * to `Some`. + */ + static from(value) { + return isNonNullable(value) ? Optional.some(value) : Optional.none(); } - } - isSome() { - return this.tag; - } - isNone() { - return !this.tag; - } - map(mapper) { - if (this.tag) { - return Optional.some(mapper(this.value)); - } else { - return Optional.none(); + /** + * Converts an `Optional` to a nullable type, by getting the value if it + * exists, or returning `null` if it does not. + */ + getOrNull() { + return this.tag ? this.value : null; } - } - bind(binder) { - if (this.tag) { - return binder(this.value); - } else { - return Optional.none(); + /** + * Converts an `Optional` to an undefined-able type, by getting the value if + * it exists, or returning `undefined` if it does not. + */ + getOrUndefined() { + return this.value; } - } - exists(predicate) { - return this.tag && predicate(this.value); - } - forall(predicate) { - return !this.tag || predicate(this.value); - } - filter(predicate) { - if (!this.tag || predicate(this.value)) { - return this; - } else { - return Optional.none(); + // --- Utilities --- + /** + * If the `Optional` contains a value, perform an action on that value. + * Unlike the rest of the methods on this type, `.each` has side-effects. If + * you want to transform an `Optional` **into** something, then this is not + * the method for you. If you want to use an `Optional` to **do** + * something, then this is the method for you - provided you're okay with not + * doing anything in the case where the `Optional` doesn't have a value inside + * it. If you're not sure whether your use-case fits into transforming + * **into** something or **doing** something, check whether it has a return + * value. If it does, you should be performing a transform. + */ + each(worker) { + if (this.tag) { + worker(this.value); + } } - } - getOr(replacement) { - return this.tag ? this.value : replacement; - } - or(replacement) { - return this.tag ? this : replacement; - } - getOrThunk(thunk) { - return this.tag ? this.value : thunk(); - } - orThunk(thunk) { - return this.tag ? this : thunk(); - } - getOrDie(message) { - if (!this.tag) { - throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); - } else { - return this.value; + /** + * Turn the `Optional` object into an array that contains all of the values + * stored inside the `Optional`. In practice, this means the output will have + * either 0 or 1 elements. + */ + toArray() { + return this.tag ? [this.value] : []; } - } - static from(value) { - return isNonNullable(value) ? Optional.some(value) : Optional.none(); - } - getOrNull() { - return this.tag ? this.value : null; - } - getOrUndefined() { - return this.value; - } - each(worker) { - if (this.tag) { - worker(this.value); + /** + * Turn the `Optional` object into a string for debugging or printing. Not + * recommended for production code, but good for debugging. Also note that + * these days an `Optional` object can be logged to the console directly, and + * its inner value (if it exists) will be visible. + */ + toString() { + return this.tag ? `some(${this.value})` : 'none()'; } - } - toArray() { - return this.tag ? [this.value] : []; - } - toString() { - return this.tag ? `some(${ this.value })` : 'none()'; - } } + // Sneaky optimisation: every instance of Optional.none is identical, so just + // reuse the same object Optional.singletonNone = new Optional(false); + /* eslint-disable @typescript-eslint/unbound-method */ + const nativeSlice = Array.prototype.slice; const nativePush = Array.prototype.push; const map = (xs, f) => { - const len = xs.length; - const r = new Array(len); - for (let i = 0; i < len; i++) { - const x = xs[i]; - r[i] = f(x, i); - } - return r; + // pre-allocating array size when it's guaranteed to be known + // http://jsperf.com/push-allocated-vs-dynamic/22 + const len = xs.length; + const r = new Array(len); + for (let i = 0; i < len; i++) { + const x = xs[i]; + r[i] = f(x, i); + } + return r; }; + // Unwound implementing other functions in terms of each. + // The code size is roughly the same, and it should allow for better optimisation. + // const each = function(xs: T[], f: (x: T, i?: number, xs?: T[]) => void): void { const each = (xs, f) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - f(x, i); - } + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + f(x, i); + } }; const findUntil = (xs, pred, until) => { - for (let i = 0, len = xs.length; i < len; i++) { - const x = xs[i]; - if (pred(x, i)) { - return Optional.some(x); - } else if (until(x, i)) { - break; + for (let i = 0, len = xs.length; i < len; i++) { + const x = xs[i]; + if (pred(x, i)) { + return Optional.some(x); + } + else if (until(x, i)) { + break; + } } - } - return Optional.none(); + return Optional.none(); }; const find = (xs, pred) => { - return findUntil(xs, pred, never); + return findUntil(xs, pred, never); }; - const flatten = xs => { - const r = []; - for (let i = 0, len = xs.length; i < len; ++i) { - if (!isArray$1(xs[i])) { - throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs); + const flatten = (xs) => { + // Note, this is possible because push supports multiple arguments: + // http://jsperf.com/concat-push/6 + // Note that in the past, concat() would silently work (very slowly) for array-like objects. + // With this change it will throw an error. + const r = []; + for (let i = 0, len = xs.length; i < len; ++i) { + // Ensure that each value is an array itself + if (!isArray$1(xs[i])) { + throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs); + } + nativePush.apply(r, xs[i]); } - nativePush.apply(r, xs[i]); - } - return r; + return r; }; const bind = (xs, f) => flatten(map(xs, f)); + isFunction(Array.from) ? Array.from : (x) => nativeSlice.call(x); + + const Cell = (initial) => { + let value = initial; + const get = () => { + return value; + }; + const set = (v) => { + value = v; + }; + return { + get, + set + }; + }; + + const contains = (str, substr, start = 0, end) => { + const idx = str.indexOf(substr, start); + if (idx !== -1) { + return isUndefined(end) ? true : idx + substr.length <= end; + } + else { + return false; + } + }; + const fromCodePoint = String.fromCodePoint; + + // Run a function fn after rate ms. If another invocation occurs + // during the time it is waiting, reschedule the function again + // with the new arguments. + const last = (fn, rate) => { + let timer = null; + const cancel = () => { + if (!isNull(timer)) { + clearTimeout(timer); + timer = null; + } + }; + const throttle = (...args) => { + cancel(); + timer = setTimeout(() => { + timer = null; + fn.apply(null, args); + }, rate); + }; + return { + cancel, + throttle + }; + }; var global = tinymce.util.Tools.resolve('tinymce.util.Tools'); - const option = name => editor => editor.options.get(name); - const register$2 = editor => { - const registerOption = editor.options.register; - const charMapProcessor = value => isFunction(value) || isArray$1(value); - registerOption('charmap', { processor: charMapProcessor }); - registerOption('charmap_append', { processor: charMapProcessor }); + const option = (name) => (editor) => editor.options.get(name); + const register$2 = (editor) => { + const registerOption = editor.options.register; + const charMapProcessor = (value) => isFunction(value) || isArray$1(value); + registerOption('charmap', { + processor: charMapProcessor, + }); + registerOption('charmap_append', { + processor: charMapProcessor + }); }; const getCharMap$1 = option('charmap'); const getCharMapAppend = option('charmap_append'); @@ -203,1456 +434,564 @@ const isArray = global.isArray; const UserDefined = 'User Defined'; const getDefaultCharMap = () => { - return [ - { - name: 'Currency', - characters: [ - [ - 36, - 'dollar sign' - ], - [ - 162, - 'cent sign' - ], - [ - 8364, - 'euro sign' - ], - [ - 163, - 'pound sign' - ], - [ - 165, - 'yen sign' - ], - [ - 164, - 'currency sign' - ], - [ - 8352, - 'euro-currency sign' - ], - [ - 8353, - 'colon sign' - ], - [ - 8354, - 'cruzeiro sign' - ], - [ - 8355, - 'french franc sign' - ], - [ - 8356, - 'lira sign' - ], - [ - 8357, - 'mill sign' - ], - [ - 8358, - 'naira sign' - ], - [ - 8359, - 'peseta sign' - ], - [ - 8360, - 'rupee sign' - ], - [ - 8361, - 'won sign' - ], - [ - 8362, - 'new sheqel sign' - ], - [ - 8363, - 'dong sign' - ], - [ - 8365, - 'kip sign' - ], - [ - 8366, - 'tugrik sign' - ], - [ - 8367, - 'drachma sign' - ], - [ - 8368, - 'german penny symbol' - ], - [ - 8369, - 'peso sign' - ], - [ - 8370, - 'guarani sign' - ], - [ - 8371, - 'austral sign' - ], - [ - 8372, - 'hryvnia sign' - ], - [ - 8373, - 'cedi sign' - ], - [ - 8374, - 'livre tournois sign' - ], - [ - 8375, - 'spesmilo sign' - ], - [ - 8376, - 'tenge sign' - ], - [ - 8377, - 'indian rupee sign' - ], - [ - 8378, - 'turkish lira sign' - ], - [ - 8379, - 'nordic mark sign' - ], - [ - 8380, - 'manat sign' - ], - [ - 8381, - 'ruble sign' - ], - [ - 20870, - 'yen character' - ], - [ - 20803, - 'yuan character' - ], - [ - 22291, - 'yuan character, in hong kong and taiwan' - ], - [ - 22278, - 'yen/yuan character variant one' - ] - ] - }, - { - name: 'Text', - characters: [ - [ - 169, - 'copyright sign' - ], - [ - 174, - 'registered sign' - ], - [ - 8482, - 'trade mark sign' - ], - [ - 8240, - 'per mille sign' - ], - [ - 181, - 'micro sign' - ], - [ - 183, - 'middle dot' - ], - [ - 8226, - 'bullet' - ], - [ - 8230, - 'three dot leader' - ], - [ - 8242, - 'minutes / feet' - ], - [ - 8243, - 'seconds / inches' - ], - [ - 167, - 'section sign' - ], - [ - 182, - 'paragraph sign' - ], - [ - 223, - 'sharp s / ess-zed' - ] - ] - }, - { - name: 'Quotations', - characters: [ - [ - 8249, - 'single left-pointing angle quotation mark' - ], - [ - 8250, - 'single right-pointing angle quotation mark' - ], - [ - 171, - 'left pointing guillemet' - ], - [ - 187, - 'right pointing guillemet' - ], - [ - 8216, - 'left single quotation mark' - ], - [ - 8217, - 'right single quotation mark' - ], - [ - 8220, - 'left double quotation mark' - ], - [ - 8221, - 'right double quotation mark' - ], - [ - 8218, - 'single low-9 quotation mark' - ], - [ - 8222, - 'double low-9 quotation mark' - ], - [ - 60, - 'less-than sign' - ], - [ - 62, - 'greater-than sign' - ], - [ - 8804, - 'less-than or equal to' - ], - [ - 8805, - 'greater-than or equal to' - ], - [ - 8211, - 'en dash' - ], - [ - 8212, - 'em dash' - ], - [ - 175, - 'macron' - ], - [ - 8254, - 'overline' - ], - [ - 164, - 'currency sign' - ], - [ - 166, - 'broken bar' - ], - [ - 168, - 'diaeresis' - ], - [ - 161, - 'inverted exclamation mark' - ], - [ - 191, - 'turned question mark' - ], - [ - 710, - 'circumflex accent' - ], - [ - 732, - 'small tilde' - ], - [ - 176, - 'degree sign' - ], - [ - 8722, - 'minus sign' - ], - [ - 177, - 'plus-minus sign' - ], - [ - 247, - 'division sign' - ], - [ - 8260, - 'fraction slash' - ], - [ - 215, - 'multiplication sign' - ], - [ - 185, - 'superscript one' - ], - [ - 178, - 'superscript two' - ], - [ - 179, - 'superscript three' - ], - [ - 188, - 'fraction one quarter' - ], - [ - 189, - 'fraction one half' - ], - [ - 190, - 'fraction three quarters' - ] - ] - }, - { - name: 'Mathematical', - characters: [ - [ - 402, - 'function / florin' - ], - [ - 8747, - 'integral' - ], - [ - 8721, - 'n-ary sumation' - ], - [ - 8734, - 'infinity' - ], - [ - 8730, - 'square root' - ], - [ - 8764, - 'similar to' - ], - [ - 8773, - 'approximately equal to' - ], - [ - 8776, - 'almost equal to' - ], - [ - 8800, - 'not equal to' - ], - [ - 8801, - 'identical to' - ], - [ - 8712, - 'element of' - ], - [ - 8713, - 'not an element of' - ], - [ - 8715, - 'contains as member' - ], - [ - 8719, - 'n-ary product' - ], - [ - 8743, - 'logical and' - ], - [ - 8744, - 'logical or' - ], - [ - 172, - 'not sign' - ], - [ - 8745, - 'intersection' - ], - [ - 8746, - 'union' - ], - [ - 8706, - 'partial differential' - ], - [ - 8704, - 'for all' - ], - [ - 8707, - 'there exists' - ], - [ - 8709, - 'diameter' - ], - [ - 8711, - 'backward difference' - ], - [ - 8727, - 'asterisk operator' - ], - [ - 8733, - 'proportional to' - ], - [ - 8736, - 'angle' - ] - ] - }, - { - name: 'Extended Latin', - characters: [ - [ - 192, - 'A - grave' - ], - [ - 193, - 'A - acute' - ], - [ - 194, - 'A - circumflex' - ], - [ - 195, - 'A - tilde' - ], - [ - 196, - 'A - diaeresis' - ], - [ - 197, - 'A - ring above' - ], - [ - 256, - 'A - macron' - ], - [ - 198, - 'ligature AE' - ], - [ - 199, - 'C - cedilla' - ], - [ - 200, - 'E - grave' - ], - [ - 201, - 'E - acute' - ], - [ - 202, - 'E - circumflex' - ], - [ - 203, - 'E - diaeresis' - ], - [ - 274, - 'E - macron' - ], - [ - 204, - 'I - grave' - ], - [ - 205, - 'I - acute' - ], - [ - 206, - 'I - circumflex' - ], - [ - 207, - 'I - diaeresis' - ], - [ - 298, - 'I - macron' - ], - [ - 208, - 'ETH' - ], - [ - 209, - 'N - tilde' - ], - [ - 210, - 'O - grave' - ], - [ - 211, - 'O - acute' - ], - [ - 212, - 'O - circumflex' - ], - [ - 213, - 'O - tilde' - ], - [ - 214, - 'O - diaeresis' - ], - [ - 216, - 'O - slash' - ], - [ - 332, - 'O - macron' - ], - [ - 338, - 'ligature OE' - ], - [ - 352, - 'S - caron' - ], - [ - 217, - 'U - grave' - ], - [ - 218, - 'U - acute' - ], - [ - 219, - 'U - circumflex' - ], - [ - 220, - 'U - diaeresis' - ], - [ - 362, - 'U - macron' - ], - [ - 221, - 'Y - acute' - ], - [ - 376, - 'Y - diaeresis' - ], - [ - 562, - 'Y - macron' - ], - [ - 222, - 'THORN' - ], - [ - 224, - 'a - grave' - ], - [ - 225, - 'a - acute' - ], - [ - 226, - 'a - circumflex' - ], - [ - 227, - 'a - tilde' - ], - [ - 228, - 'a - diaeresis' - ], - [ - 229, - 'a - ring above' - ], - [ - 257, - 'a - macron' - ], - [ - 230, - 'ligature ae' - ], - [ - 231, - 'c - cedilla' - ], - [ - 232, - 'e - grave' - ], - [ - 233, - 'e - acute' - ], - [ - 234, - 'e - circumflex' - ], - [ - 235, - 'e - diaeresis' - ], - [ - 275, - 'e - macron' - ], - [ - 236, - 'i - grave' - ], - [ - 237, - 'i - acute' - ], - [ - 238, - 'i - circumflex' - ], - [ - 239, - 'i - diaeresis' - ], - [ - 299, - 'i - macron' - ], - [ - 240, - 'eth' - ], - [ - 241, - 'n - tilde' - ], - [ - 242, - 'o - grave' - ], - [ - 243, - 'o - acute' - ], - [ - 244, - 'o - circumflex' - ], - [ - 245, - 'o - tilde' - ], - [ - 246, - 'o - diaeresis' - ], - [ - 248, - 'o slash' - ], - [ - 333, - 'o macron' - ], - [ - 339, - 'ligature oe' - ], - [ - 353, - 's - caron' - ], - [ - 249, - 'u - grave' - ], - [ - 250, - 'u - acute' - ], - [ - 251, - 'u - circumflex' - ], - [ - 252, - 'u - diaeresis' - ], - [ - 363, - 'u - macron' - ], - [ - 253, - 'y - acute' - ], - [ - 254, - 'thorn' - ], - [ - 255, - 'y - diaeresis' - ], - [ - 563, - 'y - macron' - ], - [ - 913, - 'Alpha' - ], - [ - 914, - 'Beta' - ], - [ - 915, - 'Gamma' - ], - [ - 916, - 'Delta' - ], - [ - 917, - 'Epsilon' - ], - [ - 918, - 'Zeta' - ], - [ - 919, - 'Eta' - ], - [ - 920, - 'Theta' - ], - [ - 921, - 'Iota' - ], - [ - 922, - 'Kappa' - ], - [ - 923, - 'Lambda' - ], - [ - 924, - 'Mu' - ], - [ - 925, - 'Nu' - ], - [ - 926, - 'Xi' - ], - [ - 927, - 'Omicron' - ], - [ - 928, - 'Pi' - ], - [ - 929, - 'Rho' - ], - [ - 931, - 'Sigma' - ], - [ - 932, - 'Tau' - ], - [ - 933, - 'Upsilon' - ], - [ - 934, - 'Phi' - ], - [ - 935, - 'Chi' - ], - [ - 936, - 'Psi' - ], - [ - 937, - 'Omega' - ], - [ - 945, - 'alpha' - ], - [ - 946, - 'beta' - ], - [ - 947, - 'gamma' - ], - [ - 948, - 'delta' - ], - [ - 949, - 'epsilon' - ], - [ - 950, - 'zeta' - ], - [ - 951, - 'eta' - ], - [ - 952, - 'theta' - ], - [ - 953, - 'iota' - ], - [ - 954, - 'kappa' - ], - [ - 955, - 'lambda' - ], - [ - 956, - 'mu' - ], - [ - 957, - 'nu' - ], - [ - 958, - 'xi' - ], - [ - 959, - 'omicron' - ], - [ - 960, - 'pi' - ], - [ - 961, - 'rho' - ], - [ - 962, - 'final sigma' - ], - [ - 963, - 'sigma' - ], - [ - 964, - 'tau' - ], - [ - 965, - 'upsilon' - ], - [ - 966, - 'phi' - ], - [ - 967, - 'chi' - ], - [ - 968, - 'psi' - ], - [ - 969, - 'omega' - ] - ] - }, - { - name: 'Symbols', - characters: [ - [ - 8501, - 'alef symbol' - ], - [ - 982, - 'pi symbol' - ], - [ - 8476, - 'real part symbol' - ], - [ - 978, - 'upsilon - hook symbol' - ], - [ - 8472, - 'Weierstrass p' - ], - [ - 8465, - 'imaginary part' - ] - ] - }, - { - name: 'Arrows', - characters: [ - [ - 8592, - 'leftwards arrow' - ], - [ - 8593, - 'upwards arrow' - ], - [ - 8594, - 'rightwards arrow' - ], - [ - 8595, - 'downwards arrow' - ], - [ - 8596, - 'left right arrow' - ], - [ - 8629, - 'carriage return' - ], - [ - 8656, - 'leftwards double arrow' - ], - [ - 8657, - 'upwards double arrow' - ], - [ - 8658, - 'rightwards double arrow' - ], - [ - 8659, - 'downwards double arrow' - ], - [ - 8660, - 'left right double arrow' - ], - [ - 8756, - 'therefore' - ], - [ - 8834, - 'subset of' - ], - [ - 8835, - 'superset of' - ], - [ - 8836, - 'not a subset of' - ], - [ - 8838, - 'subset of or equal to' - ], - [ - 8839, - 'superset of or equal to' - ], - [ - 8853, - 'circled plus' - ], - [ - 8855, - 'circled times' - ], - [ - 8869, - 'perpendicular' - ], - [ - 8901, - 'dot operator' - ], - [ - 8968, - 'left ceiling' - ], - [ - 8969, - 'right ceiling' - ], - [ - 8970, - 'left floor' - ], - [ - 8971, - 'right floor' - ], - [ - 9001, - 'left-pointing angle bracket' - ], - [ - 9002, - 'right-pointing angle bracket' - ], - [ - 9674, - 'lozenge' - ], - [ - 9824, - 'black spade suit' - ], - [ - 9827, - 'black club suit' - ], - [ - 9829, - 'black heart suit' - ], - [ - 9830, - 'black diamond suit' - ], - [ - 8194, - 'en space' - ], - [ - 8195, - 'em space' - ], - [ - 8201, - 'thin space' - ], - [ - 8204, - 'zero width non-joiner' - ], - [ - 8205, - 'zero width joiner' - ], - [ - 8206, - 'left-to-right mark' - ], - [ - 8207, - 'right-to-left mark' - ] - ] - } - ]; + return [ + // TODO: Merge categories with TBIO + // { + // name: 'Unknown', + // characters : [ + // [160, 'no-break space'], + // [173, 'soft hyphen'], + // [34, 'quotation mark'] + // ] + // }, + { name: 'Currency', + characters: [ + [36, 'dollar sign'], + [162, 'cent sign'], + [8364, 'euro sign'], + [163, 'pound sign'], + [165, 'yen sign'], + [164, 'currency sign'], + [8352, 'euro-currency sign'], + [8353, 'colon sign'], + [8354, 'cruzeiro sign'], + [8355, 'french franc sign'], + [8356, 'lira sign'], + [8357, 'mill sign'], + [8358, 'naira sign'], + [8359, 'peseta sign'], + [8360, 'rupee sign'], + [8361, 'won sign'], + [8362, 'new sheqel sign'], + [8363, 'dong sign'], + [8365, 'kip sign'], + [8366, 'tugrik sign'], + [8367, 'drachma sign'], + [8368, 'german penny symbol'], + [8369, 'peso sign'], + [8370, 'guarani sign'], + [8371, 'austral sign'], + [8372, 'hryvnia sign'], + [8373, 'cedi sign'], + [8374, 'livre tournois sign'], + [8375, 'spesmilo sign'], + [8376, 'tenge sign'], + [8377, 'indian rupee sign'], + [8378, 'turkish lira sign'], + [8379, 'nordic mark sign'], + [8380, 'manat sign'], + [8381, 'ruble sign'], + [20870, 'yen character'], + [20803, 'yuan character'], + [22291, 'yuan character, in hong kong and taiwan'], + [22278, 'yen/yuan character variant one'] + ] + }, + { name: 'Text', + characters: [ + [169, 'copyright sign'], + [174, 'registered sign'], + [8482, 'trade mark sign'], + [8240, 'per mille sign'], + [181, 'micro sign'], + [183, 'middle dot'], + [8226, 'bullet'], + [8230, 'three dot leader'], + [8242, 'minutes / feet'], + [8243, 'seconds / inches'], + [167, 'section sign'], + [182, 'paragraph sign'], + [223, 'sharp s / ess-zed'] + ] + }, + { name: 'Quotations', + characters: [ + [8249, 'single left-pointing angle quotation mark'], + [8250, 'single right-pointing angle quotation mark'], + [171, 'left pointing guillemet'], + [187, 'right pointing guillemet'], + [8216, 'left single quotation mark'], + [8217, 'right single quotation mark'], + [8220, 'left double quotation mark'], + [8221, 'right double quotation mark'], + [8218, 'single low-9 quotation mark'], + [8222, 'double low-9 quotation mark'], + [60, 'less-than sign'], + [62, 'greater-than sign'], + [8804, 'less-than or equal to'], + [8805, 'greater-than or equal to'], + [8211, 'en dash'], + [8212, 'em dash'], + [175, 'macron'], + [8254, 'overline'], + [164, 'currency sign'], + [166, 'broken bar'], + [168, 'diaeresis'], + [161, 'inverted exclamation mark'], + [191, 'turned question mark'], + [710, 'circumflex accent'], + [732, 'small tilde'], + [176, 'degree sign'], + [8722, 'minus sign'], + [177, 'plus-minus sign'], + [247, 'division sign'], + [8260, 'fraction slash'], + [215, 'multiplication sign'], + [185, 'superscript one'], + [178, 'superscript two'], + [179, 'superscript three'], + [188, 'fraction one quarter'], + [189, 'fraction one half'], + [190, 'fraction three quarters'] + ] + }, + { + name: 'Mathematical', + characters: [ + [402, 'function / florin'], + [8747, 'integral'], + [8721, 'n-ary sumation'], + [8734, 'infinity'], + [8730, 'square root'], + [8764, 'similar to'], + [8773, 'approximately equal to'], + [8776, 'almost equal to'], + [8800, 'not equal to'], + [8801, 'identical to'], + [8712, 'element of'], + [8713, 'not an element of'], + [8715, 'contains as member'], + [8719, 'n-ary product'], + [8743, 'logical and'], + [8744, 'logical or'], + [172, 'not sign'], + [8745, 'intersection'], + [8746, 'union'], + [8706, 'partial differential'], + [8704, 'for all'], + [8707, 'there exists'], + [8709, 'diameter'], + [8711, 'backward difference'], + [8727, 'asterisk operator'], + [8733, 'proportional to'], + [8736, 'angle'] + ] + }, + // TODO: Merge categories with TBIO + // { + // name: 'Undefined', + // characters: [ + // [180, 'acute accent'], + // [184, 'cedilla'], + // [170, 'feminine ordinal indicator'], + // [186, 'masculine ordinal indicator'], + // [8224, 'dagger'], + // [8225, 'double dagger'] + // ] + // }, + { + name: 'Extended Latin', + characters: [ + [192, 'A - grave'], + [193, 'A - acute'], + [194, 'A - circumflex'], + [195, 'A - tilde'], + [196, 'A - diaeresis'], + [197, 'A - ring above'], + [256, 'A - macron'], + [198, 'ligature AE'], + [199, 'C - cedilla'], + [200, 'E - grave'], + [201, 'E - acute'], + [202, 'E - circumflex'], + [203, 'E - diaeresis'], + [274, 'E - macron'], + [204, 'I - grave'], + [205, 'I - acute'], + [206, 'I - circumflex'], + [207, 'I - diaeresis'], + [298, 'I - macron'], + [208, 'ETH'], + [209, 'N - tilde'], + [210, 'O - grave'], + [211, 'O - acute'], + [212, 'O - circumflex'], + [213, 'O - tilde'], + [214, 'O - diaeresis'], + [216, 'O - slash'], + [332, 'O - macron'], + [338, 'ligature OE'], + [352, 'S - caron'], + [217, 'U - grave'], + [218, 'U - acute'], + [219, 'U - circumflex'], + [220, 'U - diaeresis'], + [362, 'U - macron'], + [221, 'Y - acute'], + [376, 'Y - diaeresis'], + [562, 'Y - macron'], + [222, 'THORN'], + [224, 'a - grave'], + [225, 'a - acute'], + [226, 'a - circumflex'], + [227, 'a - tilde'], + [228, 'a - diaeresis'], + [229, 'a - ring above'], + [257, 'a - macron'], + [230, 'ligature ae'], + [231, 'c - cedilla'], + [232, 'e - grave'], + [233, 'e - acute'], + [234, 'e - circumflex'], + [235, 'e - diaeresis'], + [275, 'e - macron'], + [236, 'i - grave'], + [237, 'i - acute'], + [238, 'i - circumflex'], + [239, 'i - diaeresis'], + [299, 'i - macron'], + [240, 'eth'], + [241, 'n - tilde'], + [242, 'o - grave'], + [243, 'o - acute'], + [244, 'o - circumflex'], + [245, 'o - tilde'], + [246, 'o - diaeresis'], + [248, 'o slash'], + [333, 'o macron'], + [339, 'ligature oe'], + [353, 's - caron'], + [249, 'u - grave'], + [250, 'u - acute'], + [251, 'u - circumflex'], + [252, 'u - diaeresis'], + [363, 'u - macron'], + [253, 'y - acute'], + [254, 'thorn'], + [255, 'y - diaeresis'], + [563, 'y - macron'], + [913, 'Alpha'], + [914, 'Beta'], + [915, 'Gamma'], + [916, 'Delta'], + [917, 'Epsilon'], + [918, 'Zeta'], + [919, 'Eta'], + [920, 'Theta'], + [921, 'Iota'], + [922, 'Kappa'], + [923, 'Lambda'], + [924, 'Mu'], + [925, 'Nu'], + [926, 'Xi'], + [927, 'Omicron'], + [928, 'Pi'], + [929, 'Rho'], + [931, 'Sigma'], + [932, 'Tau'], + [933, 'Upsilon'], + [934, 'Phi'], + [935, 'Chi'], + [936, 'Psi'], + [937, 'Omega'], + [945, 'alpha'], + [946, 'beta'], + [947, 'gamma'], + [948, 'delta'], + [949, 'epsilon'], + [950, 'zeta'], + [951, 'eta'], + [952, 'theta'], + [953, 'iota'], + [954, 'kappa'], + [955, 'lambda'], + [956, 'mu'], + [957, 'nu'], + [958, 'xi'], + [959, 'omicron'], + [960, 'pi'], + [961, 'rho'], + [962, 'final sigma'], + [963, 'sigma'], + [964, 'tau'], + [965, 'upsilon'], + [966, 'phi'], + [967, 'chi'], + [968, 'psi'], + [969, 'omega'] + ] + }, + { + name: 'Symbols', + characters: [ + [8501, 'alef symbol'], + [982, 'pi symbol'], + [8476, 'real part symbol'], + [978, 'upsilon - hook symbol'], + [8472, 'Weierstrass p'], + [8465, 'imaginary part'] + ] + }, + { + name: 'Arrows', + characters: [ + [8592, 'leftwards arrow'], + [8593, 'upwards arrow'], + [8594, 'rightwards arrow'], + [8595, 'downwards arrow'], + [8596, 'left right arrow'], + [8629, 'carriage return'], + [8656, 'leftwards double arrow'], + [8657, 'upwards double arrow'], + [8658, 'rightwards double arrow'], + [8659, 'downwards double arrow'], + [8660, 'left right double arrow'], + [8756, 'therefore'], + [8834, 'subset of'], + [8835, 'superset of'], + [8836, 'not a subset of'], + [8838, 'subset of or equal to'], + [8839, 'superset of or equal to'], + [8853, 'circled plus'], + [8855, 'circled times'], + [8869, 'perpendicular'], + [8901, 'dot operator'], + [8968, 'left ceiling'], + [8969, 'right ceiling'], + [8970, 'left floor'], + [8971, 'right floor'], + [9001, 'left-pointing angle bracket'], + [9002, 'right-pointing angle bracket'], + [9674, 'lozenge'], + [9824, 'black spade suit'], + [9827, 'black club suit'], + [9829, 'black heart suit'], + [9830, 'black diamond suit'], + [8194, 'en space'], + [8195, 'em space'], + [8201, 'thin space'], + [8204, 'zero width non-joiner'], + [8205, 'zero width joiner'], + [8206, 'left-to-right mark'], + [8207, 'right-to-left mark'] + ] + } + ]; }; - const charmapFilter = charmap => { - return global.grep(charmap, item => { - return isArray(item) && item.length === 2; - }); + const charmapFilter = (charmap) => { + return global.grep(charmap, (item) => { + return isArray(item) && item.length === 2; + }); }; - const getCharsFromOption = optionValue => { - if (isArray(optionValue)) { - return charmapFilter(optionValue); - } - if (typeof optionValue === 'function') { - return optionValue(); - } - return []; + const getCharsFromOption = (optionValue) => { + if (isArray(optionValue)) { + return charmapFilter(optionValue); + } + if (typeof optionValue === 'function') { + return optionValue(); + } + return []; }; const extendCharMap = (editor, charmap) => { - const userCharMap = getCharMap$1(editor); - if (userCharMap) { - charmap = [{ - name: UserDefined, - characters: getCharsFromOption(userCharMap) - }]; - } - const userCharMapAppend = getCharMapAppend(editor); - if (userCharMapAppend) { - const userDefinedGroup = global.grep(charmap, cg => cg.name === UserDefined); - if (userDefinedGroup.length) { - userDefinedGroup[0].characters = [ - ...userDefinedGroup[0].characters, - ...getCharsFromOption(userCharMapAppend) - ]; - return charmap; + const userCharMap = getCharMap$1(editor); + if (userCharMap) { + charmap = [{ name: UserDefined, characters: getCharsFromOption(userCharMap) }]; } - return charmap.concat({ - name: UserDefined, - characters: getCharsFromOption(userCharMapAppend) - }); - } - return charmap; - }; - const getCharMap = editor => { - const groups = extendCharMap(editor, getDefaultCharMap()); - return groups.length > 1 ? [{ - name: 'All', - characters: bind(groups, g => g.characters) - }].concat(groups) : groups; - }; - - const get = editor => { - const getCharMap$1 = () => { - return getCharMap(editor); - }; - const insertChar$1 = chr => { - insertChar(editor, chr); - }; - return { - getCharMap: getCharMap$1, - insertChar: insertChar$1 - }; + const userCharMapAppend = getCharMapAppend(editor); + if (userCharMapAppend) { + const userDefinedGroup = global.grep(charmap, (cg) => cg.name === UserDefined); + if (userDefinedGroup.length) { + userDefinedGroup[0].characters = [...userDefinedGroup[0].characters, ...getCharsFromOption(userCharMapAppend)]; + return charmap; + } + return charmap.concat({ name: UserDefined, characters: getCharsFromOption(userCharMapAppend) }); + } + return charmap; }; - - const Cell = initial => { - let value = initial; - const get = () => { - return value; - }; - const set = v => { - value = v; - }; - return { - get, - set - }; + const getCharMap = (editor) => { + const groups = extendCharMap(editor, getDefaultCharMap()); + return groups.length > 1 ? [ + { + name: 'All', + characters: bind(groups, (g) => g.characters) + } + ].concat(groups) : groups; }; - const last = (fn, rate) => { - let timer = null; - const cancel = () => { - if (!isNull(timer)) { - clearTimeout(timer); - timer = null; - } - }; - const throttle = (...args) => { - cancel(); - timer = setTimeout(() => { - timer = null; - fn.apply(null, args); - }, rate); - }; - return { - cancel, - throttle - }; + const get = (editor) => { + const getCharMap$1 = () => { + return getCharMap(editor); + }; + const insertChar$1 = (chr) => { + insertChar(editor, chr); + }; + return { + getCharMap: getCharMap$1, + insertChar: insertChar$1 + }; }; - const contains = (str, substr, start = 0, end) => { - const idx = str.indexOf(substr, start); - if (idx !== -1) { - return isUndefined(end) ? true : idx + substr.length <= end; - } else { - return false; - } - }; - const fromCodePoint = String.fromCodePoint; - const charMatches = (charCode, name, lowerCasePattern) => { - if (contains(fromCodePoint(charCode).toLowerCase(), lowerCasePattern)) { - return true; - } else { - return contains(name.toLowerCase(), lowerCasePattern) || contains(name.toLowerCase().replace(/\s+/g, ''), lowerCasePattern); - } + if (contains(fromCodePoint(charCode).toLowerCase(), lowerCasePattern)) { + return true; + } + else { + return contains(name.toLowerCase(), lowerCasePattern) || contains(name.toLowerCase().replace(/\s+/g, ''), lowerCasePattern); + } }; const scan = (group, pattern) => { - const matches = []; - const lowerCasePattern = pattern.toLowerCase(); - each(group.characters, g => { - if (charMatches(g[0], g[1], lowerCasePattern)) { - matches.push(g); - } - }); - return map(matches, m => ({ - text: m[1], - value: fromCodePoint(m[0]), - icon: fromCodePoint(m[0]) - })); + const matches = []; + const lowerCasePattern = pattern.toLowerCase(); + each(group.characters, (g) => { + if (charMatches(g[0], g[1], lowerCasePattern)) { + matches.push(g); + } + }); + return map(matches, (m) => ({ + text: m[1], + value: fromCodePoint(m[0]), + icon: fromCodePoint(m[0]) + })); }; const patternName = 'pattern'; const open = (editor, charMap) => { - const makeGroupItems = () => [ - { - label: 'Search', - type: 'input', - name: patternName - }, - { - type: 'collection', - name: 'results' - } - ]; - const makeTabs = () => map(charMap, charGroup => ({ - title: charGroup.name, - name: charGroup.name, - items: makeGroupItems() - })); - const makePanel = () => ({ - type: 'panel', - items: makeGroupItems() - }); - const makeTabPanel = () => ({ - type: 'tabpanel', - tabs: makeTabs() - }); - const currentTab = charMap.length === 1 ? Cell(UserDefined) : Cell('All'); - const scanAndSet = (dialogApi, pattern) => { - find(charMap, group => group.name === currentTab.get()).each(f => { - const items = scan(f, pattern); - dialogApi.setData({ results: items }); - }); - }; - const SEARCH_DELAY = 40; - const updateFilter = last(dialogApi => { - const pattern = dialogApi.getData().pattern; - scanAndSet(dialogApi, pattern); - }, SEARCH_DELAY); - const body = charMap.length === 1 ? makePanel() : makeTabPanel(); - const initialData = { - pattern: '', - results: scan(charMap[0], '') - }; - const bridgeSpec = { - title: 'Special Character', - size: 'normal', - body, - buttons: [{ - type: 'cancel', - name: 'close', - text: 'Close', - primary: true - }], - initialData, - onAction: (api, details) => { - if (details.name === 'results') { - insertChar(editor, details.value); - api.close(); - } - }, - onTabChange: (dialogApi, details) => { - currentTab.set(details.newTabName); - updateFilter.throttle(dialogApi); - }, - onChange: (dialogApi, changeData) => { - if (changeData.name === patternName) { - updateFilter.throttle(dialogApi); - } - } - }; - const dialogApi = editor.windowManager.open(bridgeSpec); - dialogApi.focus(patternName); + const makeGroupItems = () => [ + { + label: 'Search', + type: 'input', + name: patternName + }, + { + type: 'collection', + name: 'results' + // TODO TINY-3229 implement collection columns properly + // columns: 'auto' + } + ]; + const makeTabs = () => map(charMap, (charGroup) => ({ + title: charGroup.name, + name: charGroup.name, + items: makeGroupItems() + })); + const makePanel = () => ({ type: 'panel', items: makeGroupItems() }); + const makeTabPanel = () => ({ type: 'tabpanel', tabs: makeTabs() }); + const currentTab = charMap.length === 1 ? Cell(UserDefined) : Cell('All'); + const scanAndSet = (dialogApi, pattern) => { + find(charMap, (group) => group.name === currentTab.get()).each((f) => { + const items = scan(f, pattern); + dialogApi.setData({ + results: items + }); + }); + }; + const SEARCH_DELAY = 40; + const updateFilter = last((dialogApi) => { + const pattern = dialogApi.getData().pattern; + scanAndSet(dialogApi, pattern); + }, SEARCH_DELAY); + const body = charMap.length === 1 ? makePanel() : makeTabPanel(); + const initialData = { + pattern: '', + results: scan(charMap[0], '') + }; + const bridgeSpec = { + title: 'Special Character', + size: 'normal', + body, + buttons: [ + { + type: 'cancel', + name: 'close', + text: 'Close', + primary: true + } + ], + initialData, + onAction: (api, details) => { + if (details.name === 'results') { + insertChar(editor, details.value); + api.close(); + } + }, + onTabChange: (dialogApi, details) => { + currentTab.set(details.newTabName); + updateFilter.throttle(dialogApi); + }, + onChange: (dialogApi, changeData) => { + if (changeData.name === patternName) { + updateFilter.throttle(dialogApi); + } + } + }; + const dialogApi = editor.windowManager.open(bridgeSpec); + dialogApi.focus(patternName); }; const register$1 = (editor, charMap) => { - editor.addCommand('mceShowCharmap', () => { - open(editor, charMap); - }); + editor.addCommand('mceShowCharmap', () => { + open(editor, charMap); + }); }; const init = (editor, all) => { - editor.ui.registry.addAutocompleter('charmap', { - trigger: ':', - columns: 'auto', - minChars: 2, - fetch: (pattern, _maxResults) => new Promise((resolve, _reject) => { - resolve(scan(all, pattern)); - }), - onAction: (autocompleteApi, rng, value) => { - editor.selection.setRng(rng); - editor.insertContent(value); - autocompleteApi.hide(); - } - }); + editor.ui.registry.addAutocompleter('charmap', { + trigger: ':', + columns: 'auto', + minChars: 2, + fetch: (pattern, _maxResults) => new Promise((resolve, _reject) => { + resolve(scan(all, pattern)); + }), + onAction: (autocompleteApi, rng, value) => { + editor.selection.setRng(rng); + editor.insertContent(value); + autocompleteApi.hide(); + } + }); }; - const onSetupEditable = editor => api => { - const nodeChanged = () => { - api.setEnabled(editor.selection.isEditable()); - }; - editor.on('NodeChange', nodeChanged); - nodeChanged(); - return () => { - editor.off('NodeChange', nodeChanged); - }; + const onSetupEditable = (editor) => (api) => { + const nodeChanged = () => { + api.setEnabled(editor.selection.isEditable()); + }; + editor.on('NodeChange', nodeChanged); + nodeChanged(); + return () => { + editor.off('NodeChange', nodeChanged); + }; }; - const register = editor => { - const onAction = () => editor.execCommand('mceShowCharmap'); - editor.ui.registry.addButton('charmap', { - icon: 'insert-character', - tooltip: 'Special character', - onAction, - onSetup: onSetupEditable(editor) - }); - editor.ui.registry.addMenuItem('charmap', { - icon: 'insert-character', - text: 'Special character...', - onAction, - onSetup: onSetupEditable(editor) - }); + const register = (editor) => { + const onAction = () => editor.execCommand('mceShowCharmap'); + editor.ui.registry.addButton('charmap', { + icon: 'insert-character', + tooltip: 'Special character', + onAction, + onSetup: onSetupEditable(editor) + }); + editor.ui.registry.addMenuItem('charmap', { + icon: 'insert-character', + text: 'Special character...', + onAction, + onSetup: onSetupEditable(editor) + }); }; var Plugin = () => { - global$1.add('charmap', editor => { - register$2(editor); - const charMap = getCharMap(editor); - register$1(editor, charMap); - register(editor); - init(editor, charMap[0]); - return get(editor); - }); + global$1.add('charmap', (editor) => { + register$2(editor); + const charMap = getCharMap(editor); + register$1(editor, charMap); + register(editor); + init(editor, charMap[0]); + return get(editor); + }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/charmap/plugin.min.js b/public/ext/tinymce/plugins/charmap/plugin.min.js index 58a1dd6..4bc150d 100644 --- a/public/ext/tinymce/plugins/charmap/plugin.min.js +++ b/public/ext/tinymce/plugins/charmap/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(e,t)=>{const r=((e,t)=>e.dispatch("insertCustomChar",{chr:t}))(e,t).chr;e.execCommand("mceInsertContent",!1,r)},r=e=>t=>e===t,a=e=>"array"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(n=String).prototype.isPrototypeOf(r)||(null===(i=a.constructor)||void 0===i?void 0:i.name)===n.name)?"string":t;var r,a,n,i})(e);const n=r(null),i=r(void 0),o=e=>"function"==typeof e,s=()=>false;class l{constructor(e,t){this.tag=e,this.value=t}static some(e){return new l(!0,e)}static none(){return l.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?l.some(e(this.value)):l.none()}bind(e){return this.tag?e(this.value):l.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:l.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?l.none():l.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}l.singletonNone=new l(!1);const c=Array.prototype.push,u=(e,t)=>{const r=e.length,a=new Array(r);for(let n=0;nt=>t.options.get(e),m=h("charmap"),p=h("charmap_append"),d=g.isArray,f="User Defined",y=e=>{return d(e)?(t=e,g.grep(t,(e=>d(e)&&2===e.length))):"function"==typeof e?e():[];var t},b=e=>{const t=((e,t)=>{const r=m(e);r&&(t=[{name:f,characters:y(r)}]);const a=p(e);if(a){const e=g.grep(t,(e=>e.name===f));return e.length?(e[0].characters=[...e[0].characters,...y(a)],t):t.concat({name:f,characters:y(a)})}return t})(e,[{name:"Currency",characters:[[36,"dollar sign"],[162,"cent sign"],[8364,"euro sign"],[163,"pound sign"],[165,"yen sign"],[164,"currency sign"],[8352,"euro-currency sign"],[8353,"colon sign"],[8354,"cruzeiro sign"],[8355,"french franc sign"],[8356,"lira sign"],[8357,"mill sign"],[8358,"naira sign"],[8359,"peseta sign"],[8360,"rupee sign"],[8361,"won sign"],[8362,"new sheqel sign"],[8363,"dong sign"],[8365,"kip sign"],[8366,"tugrik sign"],[8367,"drachma sign"],[8368,"german penny symbol"],[8369,"peso sign"],[8370,"guarani sign"],[8371,"austral sign"],[8372,"hryvnia sign"],[8373,"cedi sign"],[8374,"livre tournois sign"],[8375,"spesmilo sign"],[8376,"tenge sign"],[8377,"indian rupee sign"],[8378,"turkish lira sign"],[8379,"nordic mark sign"],[8380,"manat sign"],[8381,"ruble sign"],[20870,"yen character"],[20803,"yuan character"],[22291,"yuan character, in hong kong and taiwan"],[22278,"yen/yuan character variant one"]]},{name:"Text",characters:[[169,"copyright sign"],[174,"registered sign"],[8482,"trade mark sign"],[8240,"per mille sign"],[181,"micro sign"],[183,"middle dot"],[8226,"bullet"],[8230,"three dot leader"],[8242,"minutes / feet"],[8243,"seconds / inches"],[167,"section sign"],[182,"paragraph sign"],[223,"sharp s / ess-zed"]]},{name:"Quotations",characters:[[8249,"single left-pointing angle quotation mark"],[8250,"single right-pointing angle quotation mark"],[171,"left pointing guillemet"],[187,"right pointing guillemet"],[8216,"left single quotation mark"],[8217,"right single quotation mark"],[8220,"left double quotation mark"],[8221,"right double quotation mark"],[8218,"single low-9 quotation mark"],[8222,"double low-9 quotation mark"],[60,"less-than sign"],[62,"greater-than sign"],[8804,"less-than or equal to"],[8805,"greater-than or equal to"],[8211,"en dash"],[8212,"em dash"],[175,"macron"],[8254,"overline"],[164,"currency sign"],[166,"broken bar"],[168,"diaeresis"],[161,"inverted exclamation mark"],[191,"turned question mark"],[710,"circumflex accent"],[732,"small tilde"],[176,"degree sign"],[8722,"minus sign"],[177,"plus-minus sign"],[247,"division sign"],[8260,"fraction slash"],[215,"multiplication sign"],[185,"superscript one"],[178,"superscript two"],[179,"superscript three"],[188,"fraction one quarter"],[189,"fraction one half"],[190,"fraction three quarters"]]},{name:"Mathematical",characters:[[402,"function / florin"],[8747,"integral"],[8721,"n-ary sumation"],[8734,"infinity"],[8730,"square root"],[8764,"similar to"],[8773,"approximately equal to"],[8776,"almost equal to"],[8800,"not equal to"],[8801,"identical to"],[8712,"element of"],[8713,"not an element of"],[8715,"contains as member"],[8719,"n-ary product"],[8743,"logical and"],[8744,"logical or"],[172,"not sign"],[8745,"intersection"],[8746,"union"],[8706,"partial differential"],[8704,"for all"],[8707,"there exists"],[8709,"diameter"],[8711,"backward difference"],[8727,"asterisk operator"],[8733,"proportional to"],[8736,"angle"]]},{name:"Extended Latin",characters:[[192,"A - grave"],[193,"A - acute"],[194,"A - circumflex"],[195,"A - tilde"],[196,"A - diaeresis"],[197,"A - ring above"],[256,"A - macron"],[198,"ligature AE"],[199,"C - cedilla"],[200,"E - grave"],[201,"E - acute"],[202,"E - circumflex"],[203,"E - diaeresis"],[274,"E - macron"],[204,"I - grave"],[205,"I - acute"],[206,"I - circumflex"],[207,"I - diaeresis"],[298,"I - macron"],[208,"ETH"],[209,"N - tilde"],[210,"O - grave"],[211,"O - acute"],[212,"O - circumflex"],[213,"O - tilde"],[214,"O - diaeresis"],[216,"O - slash"],[332,"O - macron"],[338,"ligature OE"],[352,"S - caron"],[217,"U - grave"],[218,"U - acute"],[219,"U - circumflex"],[220,"U - diaeresis"],[362,"U - macron"],[221,"Y - acute"],[376,"Y - diaeresis"],[562,"Y - macron"],[222,"THORN"],[224,"a - grave"],[225,"a - acute"],[226,"a - circumflex"],[227,"a - tilde"],[228,"a - diaeresis"],[229,"a - ring above"],[257,"a - macron"],[230,"ligature ae"],[231,"c - cedilla"],[232,"e - grave"],[233,"e - acute"],[234,"e - circumflex"],[235,"e - diaeresis"],[275,"e - macron"],[236,"i - grave"],[237,"i - acute"],[238,"i - circumflex"],[239,"i - diaeresis"],[299,"i - macron"],[240,"eth"],[241,"n - tilde"],[242,"o - grave"],[243,"o - acute"],[244,"o - circumflex"],[245,"o - tilde"],[246,"o - diaeresis"],[248,"o slash"],[333,"o macron"],[339,"ligature oe"],[353,"s - caron"],[249,"u - grave"],[250,"u - acute"],[251,"u - circumflex"],[252,"u - diaeresis"],[363,"u - macron"],[253,"y - acute"],[254,"thorn"],[255,"y - diaeresis"],[563,"y - macron"],[913,"Alpha"],[914,"Beta"],[915,"Gamma"],[916,"Delta"],[917,"Epsilon"],[918,"Zeta"],[919,"Eta"],[920,"Theta"],[921,"Iota"],[922,"Kappa"],[923,"Lambda"],[924,"Mu"],[925,"Nu"],[926,"Xi"],[927,"Omicron"],[928,"Pi"],[929,"Rho"],[931,"Sigma"],[932,"Tau"],[933,"Upsilon"],[934,"Phi"],[935,"Chi"],[936,"Psi"],[937,"Omega"],[945,"alpha"],[946,"beta"],[947,"gamma"],[948,"delta"],[949,"epsilon"],[950,"zeta"],[951,"eta"],[952,"theta"],[953,"iota"],[954,"kappa"],[955,"lambda"],[956,"mu"],[957,"nu"],[958,"xi"],[959,"omicron"],[960,"pi"],[961,"rho"],[962,"final sigma"],[963,"sigma"],[964,"tau"],[965,"upsilon"],[966,"phi"],[967,"chi"],[968,"psi"],[969,"omega"]]},{name:"Symbols",characters:[[8501,"alef symbol"],[982,"pi symbol"],[8476,"real part symbol"],[978,"upsilon - hook symbol"],[8472,"Weierstrass p"],[8465,"imaginary part"]]},{name:"Arrows",characters:[[8592,"leftwards arrow"],[8593,"upwards arrow"],[8594,"rightwards arrow"],[8595,"downwards arrow"],[8596,"left right arrow"],[8629,"carriage return"],[8656,"leftwards double arrow"],[8657,"upwards double arrow"],[8658,"rightwards double arrow"],[8659,"downwards double arrow"],[8660,"left right double arrow"],[8756,"therefore"],[8834,"subset of"],[8835,"superset of"],[8836,"not a subset of"],[8838,"subset of or equal to"],[8839,"superset of or equal to"],[8853,"circled plus"],[8855,"circled times"],[8869,"perpendicular"],[8901,"dot operator"],[8968,"left ceiling"],[8969,"right ceiling"],[8970,"left floor"],[8971,"right floor"],[9001,"left-pointing angle bracket"],[9002,"right-pointing angle bracket"],[9674,"lozenge"],[9824,"black spade suit"],[9827,"black club suit"],[9829,"black heart suit"],[9830,"black diamond suit"],[8194,"en space"],[8195,"em space"],[8201,"thin space"],[8204,"zero width non-joiner"],[8205,"zero width joiner"],[8206,"left-to-right mark"],[8207,"right-to-left mark"]]}]);return t.length>1?[{name:"All",characters:(r=t,n=e=>e.characters,(e=>{const t=[];for(let r=0,n=e.length;r{let t=e;return{get:()=>t,set:e=>{t=e}}},v=(e,t,r=0,a)=>{const n=e.indexOf(t,r);return-1!==n&&(!!i(a)||n+t.length<=a)},k=String.fromCodePoint,C=(e,t)=>{const r=[],a=t.toLowerCase();return(e=>{for(let n=0,i=e.length;n!!v(k(e).toLowerCase(),r)||v(t.toLowerCase(),r)||v(t.toLowerCase().replace(/\s+/g,""),r))((t=e[n])[0],t[1],a)&&r.push(t);var t})(e.characters),u(r,(e=>({text:e[1],value:k(e[0]),icon:k(e[0])})))},x="pattern",A=(e,r)=>{const a=()=>[{label:"Search",type:"input",name:x},{type:"collection",name:"results"}],i=1===r.length?w(f):w("All"),o=(e=>{let t=null;const r=()=>{n(t)||(clearTimeout(t),t=null)};return{cancel:r,throttle:(...a)=>{r(),t=setTimeout((()=>{t=null,e.apply(null,a)}),40)}}})((e=>{const t=e.getData().pattern;((e,t)=>{var a,n;(a=r,n=e=>e.name===i.get(),((e,t,r)=>{for(let a=0,n=e.length;a{const a=C(r,t);e.setData({results:a})}))})(e,t)})),c={title:"Special Character",size:"normal",body:1===r.length?{type:"panel",items:a()}:{type:"tabpanel",tabs:u(r,(e=>({title:e.name,name:e.name,items:a()})))},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{pattern:"",results:C(r[0],"")},onAction:(r,a)=>{"results"===a.name&&(t(e,a.value),r.close())},onTabChange:(e,t)=>{i.set(t.newTabName),o.throttle(e)},onChange:(e,t)=>{t.name===x&&o.throttle(e)}};e.windowManager.open(c).focus(x)},q=e=>t=>{const r=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",r),r(),()=>{e.off("NodeChange",r)}};e.add("charmap",(e=>{(e=>{const t=e.options.register,r=e=>o(e)||a(e);t("charmap",{processor:r}),t("charmap_append",{processor:r})})(e);const r=b(e);return((e,t)=>{e.addCommand("mceShowCharmap",(()=>{A(e,t)}))})(e,r),(e=>{const t=()=>e.execCommand("mceShowCharmap");e.ui.registry.addButton("charmap",{icon:"insert-character",tooltip:"Special character",onAction:t,onSetup:q(e)}),e.ui.registry.addMenuItem("charmap",{icon:"insert-character",text:"Special character...",onAction:t,onSetup:q(e)})})(e),((e,t)=>{e.ui.registry.addAutocompleter("charmap",{trigger:":",columns:"auto",minChars:2,fetch:(e,r)=>new Promise(((r,a)=>{r(C(t,e))})),onAction:(t,r,a)=>{e.selection.setRng(r),e.insertContent(a),t.hide()}})})(e,r[0]),(e=>({getCharMap:()=>b(e),insertChar:r=>{t(e,r)}}))(e)}))}(); \ No newline at end of file +!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(e,t)=>{const r=((e,t)=>e.dispatch("insertCustomChar",{chr:t}))(e,t).chr;e.execCommand("mceInsertContent",!1,r)},r=e=>t=>e===t,a=e=>"array"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(n=String).prototype.isPrototypeOf(r)||(null===(i=a.constructor)||void 0===i?void 0:i.name)===n.name)?"string":t;var r,a,n,i})(e);const n=r(null),i=r(void 0),o=e=>"function"==typeof e,s=()=>false;class l{constructor(e,t){this.tag=e,this.value=t}static some(e){return new l(!0,e)}static none(){return l.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?l.some(e(this.value)):l.none()}bind(e){return this.tag?e(this.value):l.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:l.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?l.none():l.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}l.singletonNone=new l(!1),Array.prototype.slice;const c=Array.prototype.push,u=(e,t)=>{const r=e.length,a=new Array(r);for(let n=0;n{let t=e;return{get:()=>t,set:e=>{t=e}}},h=(e,t,r=0,a)=>{const n=e.indexOf(t,r);return-1!==n&&(!!i(a)||n+t.length<=a)},m=String.fromCodePoint;var p=tinymce.util.Tools.resolve("tinymce.util.Tools");const d=e=>t=>t.options.get(e),f=d("charmap"),y=d("charmap_append"),b=p.isArray,w="User Defined",v=e=>{return b(e)?(t=e,p.grep(t,(e=>b(e)&&2===e.length))):"function"==typeof e?e():[];var t},k=e=>{const t=((e,t)=>{const r=f(e);r&&(t=[{name:w,characters:v(r)}]);const a=y(e);if(a){const e=p.grep(t,(e=>e.name===w));return e.length?(e[0].characters=[...e[0].characters,...v(a)],t):t.concat({name:w,characters:v(a)})}return t})(e,[{name:"Currency",characters:[[36,"dollar sign"],[162,"cent sign"],[8364,"euro sign"],[163,"pound sign"],[165,"yen sign"],[164,"currency sign"],[8352,"euro-currency sign"],[8353,"colon sign"],[8354,"cruzeiro sign"],[8355,"french franc sign"],[8356,"lira sign"],[8357,"mill sign"],[8358,"naira sign"],[8359,"peseta sign"],[8360,"rupee sign"],[8361,"won sign"],[8362,"new sheqel sign"],[8363,"dong sign"],[8365,"kip sign"],[8366,"tugrik sign"],[8367,"drachma sign"],[8368,"german penny symbol"],[8369,"peso sign"],[8370,"guarani sign"],[8371,"austral sign"],[8372,"hryvnia sign"],[8373,"cedi sign"],[8374,"livre tournois sign"],[8375,"spesmilo sign"],[8376,"tenge sign"],[8377,"indian rupee sign"],[8378,"turkish lira sign"],[8379,"nordic mark sign"],[8380,"manat sign"],[8381,"ruble sign"],[20870,"yen character"],[20803,"yuan character"],[22291,"yuan character, in hong kong and taiwan"],[22278,"yen/yuan character variant one"]]},{name:"Text",characters:[[169,"copyright sign"],[174,"registered sign"],[8482,"trade mark sign"],[8240,"per mille sign"],[181,"micro sign"],[183,"middle dot"],[8226,"bullet"],[8230,"three dot leader"],[8242,"minutes / feet"],[8243,"seconds / inches"],[167,"section sign"],[182,"paragraph sign"],[223,"sharp s / ess-zed"]]},{name:"Quotations",characters:[[8249,"single left-pointing angle quotation mark"],[8250,"single right-pointing angle quotation mark"],[171,"left pointing guillemet"],[187,"right pointing guillemet"],[8216,"left single quotation mark"],[8217,"right single quotation mark"],[8220,"left double quotation mark"],[8221,"right double quotation mark"],[8218,"single low-9 quotation mark"],[8222,"double low-9 quotation mark"],[60,"less-than sign"],[62,"greater-than sign"],[8804,"less-than or equal to"],[8805,"greater-than or equal to"],[8211,"en dash"],[8212,"em dash"],[175,"macron"],[8254,"overline"],[164,"currency sign"],[166,"broken bar"],[168,"diaeresis"],[161,"inverted exclamation mark"],[191,"turned question mark"],[710,"circumflex accent"],[732,"small tilde"],[176,"degree sign"],[8722,"minus sign"],[177,"plus-minus sign"],[247,"division sign"],[8260,"fraction slash"],[215,"multiplication sign"],[185,"superscript one"],[178,"superscript two"],[179,"superscript three"],[188,"fraction one quarter"],[189,"fraction one half"],[190,"fraction three quarters"]]},{name:"Mathematical",characters:[[402,"function / florin"],[8747,"integral"],[8721,"n-ary sumation"],[8734,"infinity"],[8730,"square root"],[8764,"similar to"],[8773,"approximately equal to"],[8776,"almost equal to"],[8800,"not equal to"],[8801,"identical to"],[8712,"element of"],[8713,"not an element of"],[8715,"contains as member"],[8719,"n-ary product"],[8743,"logical and"],[8744,"logical or"],[172,"not sign"],[8745,"intersection"],[8746,"union"],[8706,"partial differential"],[8704,"for all"],[8707,"there exists"],[8709,"diameter"],[8711,"backward difference"],[8727,"asterisk operator"],[8733,"proportional to"],[8736,"angle"]]},{name:"Extended Latin",characters:[[192,"A - grave"],[193,"A - acute"],[194,"A - circumflex"],[195,"A - tilde"],[196,"A - diaeresis"],[197,"A - ring above"],[256,"A - macron"],[198,"ligature AE"],[199,"C - cedilla"],[200,"E - grave"],[201,"E - acute"],[202,"E - circumflex"],[203,"E - diaeresis"],[274,"E - macron"],[204,"I - grave"],[205,"I - acute"],[206,"I - circumflex"],[207,"I - diaeresis"],[298,"I - macron"],[208,"ETH"],[209,"N - tilde"],[210,"O - grave"],[211,"O - acute"],[212,"O - circumflex"],[213,"O - tilde"],[214,"O - diaeresis"],[216,"O - slash"],[332,"O - macron"],[338,"ligature OE"],[352,"S - caron"],[217,"U - grave"],[218,"U - acute"],[219,"U - circumflex"],[220,"U - diaeresis"],[362,"U - macron"],[221,"Y - acute"],[376,"Y - diaeresis"],[562,"Y - macron"],[222,"THORN"],[224,"a - grave"],[225,"a - acute"],[226,"a - circumflex"],[227,"a - tilde"],[228,"a - diaeresis"],[229,"a - ring above"],[257,"a - macron"],[230,"ligature ae"],[231,"c - cedilla"],[232,"e - grave"],[233,"e - acute"],[234,"e - circumflex"],[235,"e - diaeresis"],[275,"e - macron"],[236,"i - grave"],[237,"i - acute"],[238,"i - circumflex"],[239,"i - diaeresis"],[299,"i - macron"],[240,"eth"],[241,"n - tilde"],[242,"o - grave"],[243,"o - acute"],[244,"o - circumflex"],[245,"o - tilde"],[246,"o - diaeresis"],[248,"o slash"],[333,"o macron"],[339,"ligature oe"],[353,"s - caron"],[249,"u - grave"],[250,"u - acute"],[251,"u - circumflex"],[252,"u - diaeresis"],[363,"u - macron"],[253,"y - acute"],[254,"thorn"],[255,"y - diaeresis"],[563,"y - macron"],[913,"Alpha"],[914,"Beta"],[915,"Gamma"],[916,"Delta"],[917,"Epsilon"],[918,"Zeta"],[919,"Eta"],[920,"Theta"],[921,"Iota"],[922,"Kappa"],[923,"Lambda"],[924,"Mu"],[925,"Nu"],[926,"Xi"],[927,"Omicron"],[928,"Pi"],[929,"Rho"],[931,"Sigma"],[932,"Tau"],[933,"Upsilon"],[934,"Phi"],[935,"Chi"],[936,"Psi"],[937,"Omega"],[945,"alpha"],[946,"beta"],[947,"gamma"],[948,"delta"],[949,"epsilon"],[950,"zeta"],[951,"eta"],[952,"theta"],[953,"iota"],[954,"kappa"],[955,"lambda"],[956,"mu"],[957,"nu"],[958,"xi"],[959,"omicron"],[960,"pi"],[961,"rho"],[962,"final sigma"],[963,"sigma"],[964,"tau"],[965,"upsilon"],[966,"phi"],[967,"chi"],[968,"psi"],[969,"omega"]]},{name:"Symbols",characters:[[8501,"alef symbol"],[982,"pi symbol"],[8476,"real part symbol"],[978,"upsilon - hook symbol"],[8472,"Weierstrass p"],[8465,"imaginary part"]]},{name:"Arrows",characters:[[8592,"leftwards arrow"],[8593,"upwards arrow"],[8594,"rightwards arrow"],[8595,"downwards arrow"],[8596,"left right arrow"],[8629,"carriage return"],[8656,"leftwards double arrow"],[8657,"upwards double arrow"],[8658,"rightwards double arrow"],[8659,"downwards double arrow"],[8660,"left right double arrow"],[8756,"therefore"],[8834,"subset of"],[8835,"superset of"],[8836,"not a subset of"],[8838,"subset of or equal to"],[8839,"superset of or equal to"],[8853,"circled plus"],[8855,"circled times"],[8869,"perpendicular"],[8901,"dot operator"],[8968,"left ceiling"],[8969,"right ceiling"],[8970,"left floor"],[8971,"right floor"],[9001,"left-pointing angle bracket"],[9002,"right-pointing angle bracket"],[9674,"lozenge"],[9824,"black spade suit"],[9827,"black club suit"],[9829,"black heart suit"],[9830,"black diamond suit"],[8194,"en space"],[8195,"em space"],[8201,"thin space"],[8204,"zero width non-joiner"],[8205,"zero width joiner"],[8206,"left-to-right mark"],[8207,"right-to-left mark"]]}]);return t.length>1?[{name:"All",characters:(r=t,n=e=>e.characters,(e=>{const t=[];for(let r=0,n=e.length;r{const r=[],a=t.toLowerCase();return(e=>{for(let n=0,i=e.length;n!!h(m(e).toLowerCase(),r)||h(t.toLowerCase(),r)||h(t.toLowerCase().replace(/\s+/g,""),r))((t=e[n])[0],t[1],a)&&r.push(t);var t})(e.characters),u(r,(e=>({text:e[1],value:m(e[0]),icon:m(e[0])})))},C="pattern",x=(e,r)=>{const a=()=>[{label:"Search",type:"input",name:C},{type:"collection",name:"results"}],i=1===r.length?g(w):g("All"),o=(e=>{let t=null;const r=()=>{n(t)||(clearTimeout(t),t=null)};return{cancel:r,throttle:(...a)=>{r(),t=setTimeout((()=>{t=null,e.apply(null,a)}),40)}}})((e=>{const t=e.getData().pattern;((e,t)=>{var a,n;(a=r,n=e=>e.name===i.get(),((e,t,r)=>{for(let a=0,n=e.length;a{const a=A(r,t);e.setData({results:a})}))})(e,t)})),c={title:"Special Character",size:"normal",body:1===r.length?{type:"panel",items:a()}:{type:"tabpanel",tabs:u(r,(e=>({title:e.name,name:e.name,items:a()})))},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{pattern:"",results:A(r[0],"")},onAction:(r,a)=>{"results"===a.name&&(t(e,a.value),r.close())},onTabChange:(e,t)=>{i.set(t.newTabName),o.throttle(e)},onChange:(e,t)=>{t.name===C&&o.throttle(e)}};e.windowManager.open(c).focus(C)},q=e=>t=>{const r=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",r),r(),()=>{e.off("NodeChange",r)}};e.add("charmap",(e=>{(e=>{const t=e.options.register,r=e=>o(e)||a(e);t("charmap",{processor:r}),t("charmap_append",{processor:r})})(e);const r=k(e);return((e,t)=>{e.addCommand("mceShowCharmap",(()=>{x(e,t)}))})(e,r),(e=>{const t=()=>e.execCommand("mceShowCharmap");e.ui.registry.addButton("charmap",{icon:"insert-character",tooltip:"Special character",onAction:t,onSetup:q(e)}),e.ui.registry.addMenuItem("charmap",{icon:"insert-character",text:"Special character...",onAction:t,onSetup:q(e)})})(e),((e,t)=>{e.ui.registry.addAutocompleter("charmap",{trigger:":",columns:"auto",minChars:2,fetch:(e,r)=>new Promise(((r,a)=>{r(A(t,e))})),onAction:(t,r,a)=>{e.selection.setRng(r),e.insertContent(a),t.hide()}})})(e,r[0]),(e=>({getCharMap:()=>k(e),insertChar:r=>{t(e,r)}}))(e)}))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/code/plugin.js b/public/ext/tinymce/plugins/code/plugin.js index c31b3d4..5c5a9e3 100644 --- a/public/ext/tinymce/plugins/code/plugin.js +++ b/public/ext/tinymce/plugins/code/plugin.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -8,78 +8,90 @@ var global = tinymce.util.Tools.resolve('tinymce.PluginManager'); const setContent = (editor, html) => { - editor.focus(); - editor.undoManager.transact(() => { - editor.setContent(html); - }); - editor.selection.setCursorLocation(); - editor.nodeChanged(); + // We get a lovely "Wrong document" error in IE 11 if we + // don't move the focus to the editor before creating an undo + // transaction since it tries to make a bookmark for the current selection + editor.focus(); + editor.undoManager.transact(() => { + editor.setContent(html); + }); + editor.selection.setCursorLocation(); + editor.nodeChanged(); }; - const getContent = editor => { - return editor.getContent({ source_view: true }); + const getContent = (editor) => { + return editor.getContent({ source_view: true }); }; - const open = editor => { - const editorContent = getContent(editor); - editor.windowManager.open({ - title: 'Source Code', - size: 'large', - body: { - type: 'panel', - items: [{ - type: 'textarea', - name: 'code' - }] - }, - buttons: [ - { - type: 'cancel', - name: 'cancel', - text: 'Cancel' - }, - { - type: 'submit', - name: 'save', - text: 'Save', - primary: true - } - ], - initialData: { code: editorContent }, - onSubmit: api => { - setContent(editor, api.getData().code); - api.close(); - } - }); + const open = (editor) => { + const editorContent = getContent(editor); + editor.windowManager.open({ + title: 'Source Code', + size: 'large', + body: { + type: 'panel', + items: [ + { + type: 'textarea', + name: 'code' + } + ] + }, + buttons: [ + { + type: 'cancel', + name: 'cancel', + text: 'Cancel' + }, + { + type: 'submit', + name: 'save', + text: 'Save', + primary: true + } + ], + initialData: { + code: editorContent + }, + onSubmit: (api) => { + setContent(editor, api.getData().code); + api.close(); + } + }); }; - const register$1 = editor => { - editor.addCommand('mceCodeEditor', () => { - open(editor); - }); + const register$1 = (editor) => { + editor.addCommand('mceCodeEditor', () => { + open(editor); + }); }; - const register = editor => { - const onAction = () => editor.execCommand('mceCodeEditor'); - editor.ui.registry.addButton('code', { - icon: 'sourcecode', - tooltip: 'Source code', - onAction - }); - editor.ui.registry.addMenuItem('code', { - icon: 'sourcecode', - text: 'Source code', - onAction - }); + const register = (editor) => { + const onAction = () => editor.execCommand('mceCodeEditor'); + editor.ui.registry.addButton('code', { + icon: 'sourcecode', + tooltip: 'Source code', + onAction + }); + editor.ui.registry.addMenuItem('code', { + icon: 'sourcecode', + text: 'Source code', + onAction + }); }; var Plugin = () => { - global.add('code', editor => { - register$1(editor); - register(editor); - return {}; - }); + global.add('code', (editor) => { + register$1(editor); + register(editor); + return {}; + }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/code/plugin.min.js b/public/ext/tinymce/plugins/code/plugin.min.js index 263ad55..3e323ac 100644 --- a/public/ext/tinymce/plugins/code/plugin.min.js +++ b/public/ext/tinymce/plugins/code/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ !function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}(); \ No newline at end of file diff --git a/public/ext/tinymce/plugins/codesample/plugin.js b/public/ext/tinymce/plugins/codesample/plugin.js index 641b24a..ad576d6 100644 --- a/public/ext/tinymce/plugins/codesample/plugin.js +++ b/public/ext/tinymce/plugins/codesample/plugin.js @@ -1,5 +1,5 @@ /** - * TinyMCE version 7.7.2 (2025-03-19) + * TinyMCE version 7.9.1 (2025-05-29) */ (function () { @@ -7,2457 +7,3648 @@ var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager'); - const isNullable = a => a === null || a === undefined; - const isNonNullable = a => !isNullable(a); + /* eslint-disable @typescript-eslint/no-wrapper-object-types */ + const isNullable = (a) => a === null || a === undefined; + const isNonNullable = (a) => !isNullable(a); - const noop = () => { - }; - const constant = value => { - return () => { - return value; - }; + const noop = () => { }; + const constant = (value) => { + return () => { + return value; + }; }; + /** + * The `Optional` type represents a value (of any type) that potentially does + * not exist. Any `Optional` can either be a `Some` (in which case the + * value does exist) or a `None` (in which case the value does not exist). This + * module defines a whole lot of FP-inspired utility functions for dealing with + * `Optional` objects. + * + * Comparison with null or undefined: + * - We don't get fancy null coalescing operators with `Optional` + * - We do get fancy helper functions with `Optional` + * - `Optional` support nesting, and allow for the type to still be nullable (or + * another `Optional`) + * - There is no option to turn off strict-optional-checks like there is for + * strict-null-checks + */ class Optional { - constructor(tag, value) { - this.tag = tag; - this.value = value; - } - static some(value) { - return new Optional(true, value); - } - static none() { - return Optional.singletonNone; - } - fold(onNone, onSome) { - if (this.tag) { - return onSome(this.value); - } else { - return onNone(); + // The internal representation has a `tag` and a `value`, but both are + // private: able to be console.logged, but not able to be accessed by code + constructor(tag, value) { + this.tag = tag; + this.value = value; } - } - isSome() { - return this.tag; - } - isNone() { - return !this.tag; - } - map(mapper) { - if (this.tag) { - return Optional.some(mapper(this.value)); - } else { - return Optional.none(); + // --- Identities --- + /** + * Creates a new `Optional` that **does** contain a value. + */ + static some(value) { + return new Optional(true, value); } - } - bind(binder) { - if (this.tag) { - return binder(this.value); - } else { - return Optional.none(); + /** + * Create a new `Optional` that **does not** contain a value. `T` can be + * any type because we don't actually have a `T`. + */ + static none() { + return Optional.singletonNone; } - } - exists(predicate) { - return this.tag && predicate(this.value); - } - forall(predicate) { - return !this.tag || predicate(this.value); - } - filter(predicate) { - if (!this.tag || predicate(this.value)) { - return this; - } else { - return Optional.none(); + /** + * Perform a transform on an `Optional` type. Regardless of whether this + * `Optional` contains a value or not, `fold` will return a value of type `U`. + * If this `Optional` does not contain a value, the `U` will be created by + * calling `onNone`. If this `Optional` does contain a value, the `U` will be + * created by calling `onSome`. + * + * For the FP enthusiasts in the room, this function: + * 1. Could be used to implement all of the functions below + * 2. Forms a catamorphism + */ + fold(onNone, onSome) { + if (this.tag) { + return onSome(this.value); + } + else { + return onNone(); + } } - } - getOr(replacement) { - return this.tag ? this.value : replacement; - } - or(replacement) { - return this.tag ? this : replacement; - } - getOrThunk(thunk) { - return this.tag ? this.value : thunk(); - } - orThunk(thunk) { - return this.tag ? this : thunk(); - } - getOrDie(message) { - if (!this.tag) { - throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); - } else { - return this.value; + /** + * Determine if this `Optional` object contains a value. + */ + isSome() { + return this.tag; } - } - static from(value) { - return isNonNullable(value) ? Optional.some(value) : Optional.none(); - } - getOrNull() { - return this.tag ? this.value : null; - } - getOrUndefined() { - return this.value; - } - each(worker) { - if (this.tag) { - worker(this.value); + /** + * Determine if this `Optional` object **does not** contain a value. + */ + isNone() { + return !this.tag; } - } - toArray() { - return this.tag ? [this.value] : []; - } - toString() { - return this.tag ? `some(${ this.value })` : 'none()'; - } - } - Optional.singletonNone = new Optional(false); - - const get$1 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none(); - const head = xs => get$1(xs, 0); - - var global$1 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils'); - - const Global = typeof window !== 'undefined' ? window : Function('return this;')(); - - const prismjs = function (global, module, exports) { - const oldprism = window.Prism; - window.Prism = { manual: true }; - var _self = typeof window !== 'undefined' ? window : typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope ? self : {}; - var Prism = function (_self) { - var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; - var uniqueId = 0; - var plainTextGrammar = {}; - var _ = { - manual: _self.Prism && _self.Prism.manual, - disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler, - util: { - encode: function encode(tokens) { - if (tokens instanceof Token) { - return new Token(tokens.type, encode(tokens.content), tokens.alias); - } else if (Array.isArray(tokens)) { - return tokens.map(encode); - } else { - return tokens.replace(/&/g, '&').replace(/` into an `Optional`. If this **does** contain + * a value then the output will also contain a value (that value being the + * output of `mapper(this.value)`), and if this **does not** contain a value + * then neither will the output. + */ + map(mapper) { + if (this.tag) { + return Optional.some(mapper(this.value)); } - if (!env.code) { - _.hooks.run('complete', env); - callback && callback.call(env.element); - return; - } - _.hooks.run('before-highlight', env); - if (!env.grammar) { - insertHighlightedCode(_.util.encode(env.code)); - return; - } - if (async && _self.Worker) { - var worker = new Worker(_.filename); - worker.onmessage = function (evt) { - insertHighlightedCode(evt.data); - }; - worker.postMessage(JSON.stringify({ - language: env.language, - code: env.code, - immediateClose: true - })); - } else { - insertHighlightedCode(_.highlight(env.code, env.grammar, env.language)); - } - }, - highlight: function (text, grammar, language) { - var env = { - code: text, - grammar: grammar, - language: language - }; - _.hooks.run('before-tokenize', env); - if (!env.grammar) { - throw new Error('The language "' + env.language + '" has no grammar.'); - } - env.tokens = _.tokenize(env.code, env.grammar); - _.hooks.run('after-tokenize', env); - return Token.stringify(_.util.encode(env.tokens), env.language); - }, - tokenize: function (text, grammar) { - var rest = grammar.rest; - if (rest) { - for (var token in rest) { - grammar[token] = rest[token]; - } - delete grammar.rest; - } - var tokenList = new LinkedList(); - addAfter(tokenList, tokenList.head, text); - matchGrammar(text, tokenList, grammar, tokenList.head, 0); - return toArray(tokenList); - }, - hooks: { - all: {}, - add: function (name, callback) { - var hooks = _.hooks.all; - hooks[name] = hooks[name] || []; - hooks[name].push(callback); - }, - run: function (name, env) { - var callbacks = _.hooks.all[name]; - if (!callbacks || !callbacks.length) { - return; - } - for (var i = 0, callback; callback = callbacks[i++];) { - callback(env); - } - } - }, - Token: Token - }; - _self.Prism = _; - function Token(type, content, alias, matchedStr) { - this.type = type; - this.content = content; - this.alias = alias; - this.length = (matchedStr || '').length | 0; - } - Token.stringify = function stringify(o, language) { - if (typeof o == 'string') { - return o; - } - if (Array.isArray(o)) { - var s = ''; - o.forEach(function (e) { - s += stringify(e, language); - }); - return s; - } - var env = { - type: o.type, - content: stringify(o.content, language), - tag: 'span', - classes: [ - 'token', - o.type - ], - attributes: {}, - language: language - }; - var aliases = o.alias; - if (aliases) { - if (Array.isArray(aliases)) { - Array.prototype.push.apply(env.classes, aliases); - } else { - env.classes.push(aliases); + else { + return Optional.none(); } - } - _.hooks.run('wrap', env); - var attributes = ''; - for (var name in env.attributes) { - attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; - } - return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + ''; - }; - function matchPattern(pattern, pos, text, lookbehind) { - pattern.lastIndex = pos; - var match = pattern.exec(text); - if (match && lookbehind && match[1]) { - var lookbehindLength = match[1].length; - match.index += lookbehindLength; - match[0] = match[0].slice(lookbehindLength); - } - return match; } - function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) { - for (var token in grammar) { - if (!grammar.hasOwnProperty(token) || !grammar[token]) { - continue; + // --- Monad (name stolen from Haskell / maths) --- + /** + * Perform a transform on an `Optional` object, **if** there is a value. + * Unlike `map`, here the transform itself also returns an `Optional`. + */ + bind(binder) { + if (this.tag) { + return binder(this.value); } - var patterns = grammar[token]; - patterns = Array.isArray(patterns) ? patterns : [patterns]; - for (var j = 0; j < patterns.length; ++j) { - if (rematch && rematch.cause == token + ',' + j) { - return; - } - var patternObj = patterns[j]; - var inside = patternObj.inside; - var lookbehind = !!patternObj.lookbehind; - var greedy = !!patternObj.greedy; - var alias = patternObj.alias; - if (greedy && !patternObj.pattern.global) { - var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0]; - patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g'); - } - var pattern = patternObj.pattern || patternObj; - for (var currentNode = startNode.next, pos = startPos; currentNode !== tokenList.tail; pos += currentNode.value.length, currentNode = currentNode.next) { - if (rematch && pos >= rematch.reach) { - break; - } - var str = currentNode.value; - if (tokenList.length > text.length) { - return; - } - if (str instanceof Token) { - continue; - } - var removeCount = 1; - var match; - if (greedy) { - match = matchPattern(pattern, pos, text, lookbehind); - if (!match || match.index >= text.length) { - break; - } - var from = match.index; - var to = match.index + match[0].length; - var p = pos; - p += currentNode.value.length; - while (from >= p) { - currentNode = currentNode.next; - p += currentNode.value.length; - } - p -= currentNode.value.length; - pos = p; - if (currentNode.value instanceof Token) { - continue; - } - for (var k = currentNode; k !== tokenList.tail && (p < to || typeof k.value === 'string'); k = k.next) { - removeCount++; - p += k.value.length; - } - removeCount--; - str = text.slice(pos, p); - match.index -= pos; - } else { - match = matchPattern(pattern, 0, str, lookbehind); - if (!match) { - continue; - } - } - var from = match.index; - var matchStr = match[0]; - var before = str.slice(0, from); - var after = str.slice(from + matchStr.length); - var reach = pos + str.length; - if (rematch && reach > rematch.reach) { - rematch.reach = reach; - } - var removeFrom = currentNode.prev; - if (before) { - removeFrom = addAfter(tokenList, removeFrom, before); - pos += before.length; - } - removeRange(tokenList, removeFrom, removeCount); - var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr); - currentNode = addAfter(tokenList, removeFrom, wrapped); - if (after) { - addAfter(tokenList, currentNode, after); - } - if (removeCount > 1) { - var nestedRematch = { - cause: token + ',' + j, - reach: reach - }; - matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch); - if (rematch && nestedRematch.reach > rematch.reach) { - rematch.reach = nestedRematch.reach; - } - } - } + else { + return Optional.none(); } - } - } - function LinkedList() { - var head = { - value: null, - prev: null, - next: null - }; - var tail = { - value: null, - prev: head, - next: null - }; - head.next = tail; - this.head = head; - this.tail = tail; - this.length = 0; - } - function addAfter(list, node, value) { - var next = node.next; - var newNode = { - value: value, - prev: node, - next: next - }; - node.next = newNode; - next.prev = newNode; - list.length++; - return newNode; - } - function removeRange(list, node, count) { - var next = node.next; - for (var i = 0; i < count && next !== list.tail; i++) { - next = next.next; - } - node.next = next; - next.prev = node; - list.length -= i; - } - function toArray(list) { - var array = []; - var node = list.head.next; - while (node !== list.tail) { - array.push(node.value); - node = node.next; - } - return array; } - if (!_self.document) { - if (!_self.addEventListener) { - return _; - } - if (!_.disableWorkerMessageHandler) { - _self.addEventListener('message', function (evt) { - var message = JSON.parse(evt.data); - var lang = message.language; - var code = message.code; - var immediateClose = message.immediateClose; - _self.postMessage(_.highlight(code, _.languages[lang], lang)); - if (immediateClose) { - _self.close(); - } - }, false); - } - return _; + // --- Traversable (name stolen from Haskell / maths) --- + /** + * For a given predicate, this function finds out if there **exists** a value + * inside this `Optional` object that meets the predicate. In practice, this + * means that for `Optional`s that do not contain a value it returns false (as + * no predicate-meeting value exists). + */ + exists(predicate) { + return this.tag && predicate(this.value); } - var script = _.util.currentScript(); - if (script) { - _.filename = script.src; - if (script.hasAttribute('data-manual')) { - _.manual = true; - } + /** + * For a given predicate, this function finds out if **all** the values inside + * this `Optional` object meet the predicate. In practice, this means that + * for `Optional`s that do not contain a value it returns true (as all 0 + * objects do meet the predicate). + */ + forall(predicate) { + return !this.tag || predicate(this.value); } - function highlightAutomaticallyCallback() { - if (!_.manual) { - _.highlightAll(); - } - } - if (!_.manual) { - var readyState = document.readyState; - if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) { - document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback); - } else { - if (window.requestAnimationFrame) { - window.requestAnimationFrame(highlightAutomaticallyCallback); - } else { - window.setTimeout(highlightAutomaticallyCallback, 16); - } - } - } - return _; - }(_self); - if (typeof module !== 'undefined' && module.exports) { - module.exports = Prism; - } - if (typeof global !== 'undefined') { - global.Prism = Prism; - } - Prism.languages.clike = { - 'comment': [ - { - pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, - lookbehind: true, - greedy: true - }, - { - pattern: /(^|[^\\:])\/\/.*/, - lookbehind: true, - greedy: true - } - ], - 'string': { - pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, - greedy: true - }, - 'class-name': { - pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, - lookbehind: true, - inside: { 'punctuation': /[.\\]/ } - }, - 'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/, - 'boolean': /\b(?:false|true)\b/, - 'function': /\b\w+(?=\()/, - 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, - 'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, - 'punctuation': /[{}[\];(),.:]/ - }; - (function (Prism) { - function getPlaceholder(language, index) { - return '___' + language.toUpperCase() + index + '___'; - } - Object.defineProperties(Prism.languages['markup-templating'] = {}, { - buildPlaceholders: { - value: function (env, language, placeholderPattern, replaceFilter) { - if (env.language !== language) { - return; - } - var tokenStack = env.tokenStack = []; - env.code = env.code.replace(placeholderPattern, function (match) { - if (typeof replaceFilter === 'function' && !replaceFilter(match)) { - return match; - } - var i = tokenStack.length; - var placeholder; - while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1) { - ++i; - } - tokenStack[i] = match; - return placeholder; - }); - env.grammar = Prism.languages.markup; - } - }, - tokenizePlaceholders: { - value: function (env, language) { - if (env.language !== language || !env.tokenStack) { - return; - } - env.grammar = Prism.languages[language]; - var j = 0; - var keys = Object.keys(env.tokenStack); - function walkTokens(tokens) { - for (var i = 0; i < tokens.length; i++) { - if (j >= keys.length) { - break; - } - var token = tokens[i]; - if (typeof token === 'string' || token.content && typeof token.content === 'string') { - var k = keys[j]; - var t = env.tokenStack[k]; - var s = typeof token === 'string' ? token : token.content; - var placeholder = getPlaceholder(language, k); - var index = s.indexOf(placeholder); - if (index > -1) { - ++j; - var before = s.substring(0, index); - var middle = new Prism.Token(language, Prism.tokenize(t, env.grammar), 'language-' + language, t); - var after = s.substring(index + placeholder.length); - var replacement = []; - if (before) { - replacement.push.apply(replacement, walkTokens([before])); - } - replacement.push(middle); - if (after) { - replacement.push.apply(replacement, walkTokens([after])); - } - if (typeof token === 'string') { - tokens.splice.apply(tokens, [ - i, - 1 - ].concat(replacement)); - } else { - token.content = replacement; - } - } - } else if (token.content) { - walkTokens(token.content); - } - } - return tokens; - } - walkTokens(env.tokens); + filter(predicate) { + if (!this.tag || predicate(this.value)) { + return this; } - } - }); - }(Prism)); - Prism.languages.c = Prism.languages.extend('clike', { - 'comment': { - pattern: /\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/, - greedy: true - }, - 'string': { - pattern: /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/, - greedy: true - }, - 'class-name': { - pattern: /(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/, - lookbehind: true - }, - 'keyword': /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/, - 'function': /\b[a-z_]\w*(?=\s*\()/i, - 'number': /(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i, - 'operator': />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/ - }); - Prism.languages.insertBefore('c', 'string', { - 'char': { - pattern: /'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/, - greedy: true - } - }); - Prism.languages.insertBefore('c', 'string', { - 'macro': { - pattern: /(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im, - lookbehind: true, - greedy: true, - alias: 'property', - inside: { - 'string': [ - { - pattern: /^(#\s*include\s*)<[^>]+>/, - lookbehind: true - }, - Prism.languages.c['string'] - ], - 'char': Prism.languages.c['char'], - 'comment': Prism.languages.c['comment'], - 'macro-name': [ - { - pattern: /(^#\s*define\s+)\w+\b(?!\()/i, - lookbehind: true - }, - { - pattern: /(^#\s*define\s+)\w+\b(?=\()/i, - lookbehind: true, - alias: 'function' - } - ], - 'directive': { - pattern: /^(#\s*)[a-z]+/, - lookbehind: true, - alias: 'keyword' - }, - 'directive-hash': /^#/, - 'punctuation': /##|\\(?=[\r\n])/, - 'expression': { - pattern: /\S[\s\S]*/, - inside: Prism.languages.c + else { + return Optional.none(); } - } } - }); - Prism.languages.insertBefore('c', 'function', { 'constant': /\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/ }); - delete Prism.languages.c['boolean']; - (function (Prism) { - var keyword = /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/; - var modName = /\b(?!)\w+(?:\s*\.\s*\w+)*\b/.source.replace(//g, function () { - return keyword.source; - }); - Prism.languages.cpp = Prism.languages.extend('c', { - 'class-name': [ - { - pattern: RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!)\w+/.source.replace(//g, function () { - return keyword.source; - })), - lookbehind: true - }, - /\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/, - /\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i, - /\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/ - ], - 'keyword': keyword, - 'number': { - pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i, - greedy: true - }, - 'operator': />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/, - 'boolean': /\b(?:false|true)\b/ - }); - Prism.languages.insertBefore('cpp', 'string', { - 'module': { - pattern: RegExp(/(\b(?:import|module)\s+)/.source + '(?:' + /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source + '|' + /(?:\s*:\s*)?|:\s*/.source.replace(//g, function () { - return modName; - }) + ')'), - lookbehind: true, - greedy: true, - inside: { - 'string': /^[<"][\s\S]+/, - 'operator': /:/, - 'punctuation': /\./ - } - }, - 'raw-string': { - pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/, - alias: 'string', - greedy: true - } - }); - Prism.languages.insertBefore('cpp', 'keyword', { - 'generic-function': { - pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i, - inside: { - 'function': /^\w+/, - 'generic': { - pattern: /<[\s\S]+/, - alias: 'class-name', - inside: Prism.languages.cpp - } - } - } - }); - Prism.languages.insertBefore('cpp', 'operator', { - 'double-colon': { - pattern: /::/, - alias: 'punctuation' - } - }); - Prism.languages.insertBefore('cpp', 'class-name', { - 'base-clause': { - pattern: /(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/, - lookbehind: true, - greedy: true, - inside: Prism.languages.extend('cpp', {}) - } - }); - Prism.languages.insertBefore('inside', 'double-colon', { 'class-name': /\b[a-z_]\w*\b(?!\s*::)/i }, Prism.languages.cpp['base-clause']); - }(Prism)); - (function (Prism) { - function replace(pattern, replacements) { - return pattern.replace(/<<(\d+)>>/g, function (m, index) { - return '(?:' + replacements[+index] + ')'; - }); + // --- Getters --- + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. + */ + getOr(replacement) { + return this.tag ? this.value : replacement; } - function re(pattern, replacements, flags) { - return RegExp(replace(pattern, replacements), flags || ''); + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` object is also + * `Optional` - meaning that this method will always return an `Optional`. + */ + or(replacement) { + return this.tag ? this : replacement; } - function nested(pattern, depthLog2) { - for (var i = 0; i < depthLog2; i++) { - pattern = pattern.replace(/<>/g, function () { - return '(?:' + pattern + ')'; - }); - } - return pattern.replace(/<>/g, '[^\\s\\S]'); + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided `Optional` object does not contain a + * value. Unlike `getOr`, in this method the `replacement` value is + * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you + * pass a function which (if called) will **return** the `value` you want to + * use. + */ + getOrThunk(thunk) { + return this.tag ? this.value : thunk(); } - var keywordKinds = { - type: 'bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void', - typeDeclaration: 'class enum interface record struct', - contextual: 'add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)', - other: 'abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield' - }; - function keywordsToPattern(words) { - return '\\b(?:' + words.trim().replace(/ /g, '|') + ')\\b'; + /** + * Get the value out of the inside of the `Optional` object, using a default + * `replacement` value if the provided Optional object does not contain a + * value. + * + * Unlike `or`, in this method the `replacement` value is "thunked" - that is + * to say that you don't pass a value to `orThunk`, you pass a function which + * (if called) will **return** the `value` you want to use. + * + * Unlike `getOrThunk`, in this method the `replacement` value is also + * `Optional`, meaning that this method will always return an `Optional`. + */ + orThunk(thunk) { + return this.tag ? this : thunk(); } - var typeDeclarationKeywords = keywordsToPattern(keywordKinds.typeDeclaration); - var keywords = RegExp(keywordsToPattern(keywordKinds.type + ' ' + keywordKinds.typeDeclaration + ' ' + keywordKinds.contextual + ' ' + keywordKinds.other)); - var nonTypeKeywords = keywordsToPattern(keywordKinds.typeDeclaration + ' ' + keywordKinds.contextual + ' ' + keywordKinds.other); - var nonContextualKeywords = keywordsToPattern(keywordKinds.type + ' ' + keywordKinds.typeDeclaration + ' ' + keywordKinds.other); - var generic = nested(/<(?:[^<>;=+\-*/%&|^]|<>)*>/.source, 2); - var nestedRound = nested(/\((?:[^()]|<>)*\)/.source, 2); - var name = /@?\b[A-Za-z_]\w*\b/.source; - var genericName = replace(/<<0>>(?:\s*<<1>>)?/.source, [ - name, - generic - ]); - var identifier = replace(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source, [ - nonTypeKeywords, - genericName - ]); - var array = /\[\s*(?:,\s*)*\]/.source; - var typeExpressionWithoutTuple = replace(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source, [ - identifier, - array - ]); - var tupleElement = replace(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source, [ - generic, - nestedRound, - array - ]); - var tuple = replace(/\(<<0>>+(?:,<<0>>+)+\)/.source, [tupleElement]); - var typeExpression = replace(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source, [ - tuple, - identifier, - array - ]); - var typeInside = { - 'keyword': keywords, - 'punctuation': /[<>()?,.:[\]]/ - }; - var character = /'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source; - var regularString = /"(?:\\.|[^\\"\r\n])*"/.source; - var verbatimString = /@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source; - Prism.languages.csharp = Prism.languages.extend('clike', { - 'string': [ - { - pattern: re(/(^|[^$\\])<<0>>/.source, [verbatimString]), - lookbehind: true, - greedy: true - }, - { - pattern: re(/(^|[^@$\\])<<0>>/.source, [regularString]), - lookbehind: true, - greedy: true - } - ], - 'class-name': [ - { - pattern: re(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source, [identifier]), - lookbehind: true, - inside: typeInside - }, - { - pattern: re(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source, [ - name, - typeExpression - ]), - lookbehind: true, - inside: typeInside - }, - { - pattern: re(/(\busing\s+)<<0>>(?=\s*=)/.source, [name]), - lookbehind: true - }, - { - pattern: re(/(\b<<0>>\s+)<<1>>/.source, [ - typeDeclarationKeywords, - genericName - ]), - lookbehind: true, - inside: typeInside - }, - { - pattern: re(/(\bcatch\s*\(\s*)<<0>>/.source, [identifier]), - lookbehind: true, - inside: typeInside - }, - { - pattern: re(/(\bwhere\s+)<<0>>/.source, [name]), - lookbehind: true - }, - { - pattern: re(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source, [typeExpressionWithoutTuple]), - lookbehind: true, - inside: typeInside - }, - { - pattern: re(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source, [ - typeExpression, - nonContextualKeywords, - name - ]), - inside: typeInside - } - ], - 'keyword': keywords, - 'number': /(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i, - 'operator': />>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/, - 'punctuation': /\?\.?|::|[{}[\];(),.:]/ - }); - Prism.languages.insertBefore('csharp', 'number', { - 'range': { - pattern: /\.\./, - alias: 'operator' - } - }); - Prism.languages.insertBefore('csharp', 'punctuation', { - 'named-parameter': { - pattern: re(/([(,]\s*)<<0>>(?=\s*:)/.source, [name]), - lookbehind: true, - alias: 'punctuation' - } - }); - Prism.languages.insertBefore('csharp', 'class-name', { - 'namespace': { - pattern: re(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source, [name]), - lookbehind: true, - inside: { 'punctuation': /\./ } - }, - 'type-expression': { - pattern: re(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source, [nestedRound]), - lookbehind: true, - alias: 'class-name', - inside: typeInside - }, - 'return-type': { - pattern: re(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source, [ - typeExpression, - identifier - ]), - inside: typeInside, - alias: 'class-name' - }, - 'constructor-invocation': { - pattern: re(/(\bnew\s+)<<0>>(?=\s*[[({])/.source, [typeExpression]), - lookbehind: true, - inside: typeInside, - alias: 'class-name' - }, - 'generic-method': { - pattern: re(/<<0>>\s*<<1>>(?=\s*\()/.source, [ - name, - generic - ]), - inside: { - 'function': re(/^<<0>>/.source, [name]), - 'generic': { - pattern: RegExp(generic), - alias: 'class-name', - inside: typeInside - } - } - }, - 'type-list': { - pattern: re(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source, [ - typeDeclarationKeywords, - genericName, - name, - typeExpression, - keywords.source, - nestedRound, - /\bnew\s*\(\s*\)/.source - ]), - lookbehind: true, - inside: { - 'record-arguments': { - pattern: re(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source, [ - genericName, - nestedRound - ]), - lookbehind: true, - greedy: true, - inside: Prism.languages.csharp - }, - 'keyword': keywords, - 'class-name': { - pattern: RegExp(typeExpression), - greedy: true, - inside: typeInside - }, - 'punctuation': /[,()]/ + /** + * Get the value out of the inside of the `Optional` object, throwing an + * exception if the provided `Optional` object does not contain a value. + * + * WARNING: + * You should only be using this function if you know that the `Optional` + * object **is not** empty (otherwise you're throwing exceptions in production + * code, which is bad). + * + * In tests this is more acceptable. + * + * Prefer other methods to this, such as `.each`. + */ + getOrDie(message) { + if (!this.tag) { + throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None'); } - }, - 'preprocessor': { - pattern: /(^[\t ]*)#.*/m, - lookbehind: true, - alias: 'property', - inside: { - 'directive': { - pattern: /(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/, - lookbehind: true, - alias: 'keyword' - } + else { + return this.value; } - } - }); - var regularStringOrCharacter = regularString + '|' + character; - var regularStringCharacterOrComment = replace(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source, [regularStringOrCharacter]); - var roundExpression = nested(replace(/[^"'/()]|<<0>>|\(<>*\)/.source, [regularStringCharacterOrComment]), 2); - var attrTarget = /\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source; - var attr = replace(/<<0>>(?:\s*\(<<1>>*\))?/.source, [ - identifier, - roundExpression - ]); - Prism.languages.insertBefore('csharp', 'class-name', { - 'attribute': { - pattern: re(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source, [ - attrTarget, - attr - ]), - lookbehind: true, - greedy: true, - inside: { - 'target': { - pattern: re(/^<<0>>(?=\s*:)/.source, [attrTarget]), - alias: 'keyword' - }, - 'attribute-arguments': { - pattern: re(/\(<<0>>*\)/.source, [roundExpression]), - inside: Prism.languages.csharp - }, - 'class-name': { - pattern: RegExp(identifier), - inside: { 'punctuation': /\./ } - }, - 'punctuation': /[:,]/ - } - } - }); - var formatString = /:[^}\r\n]+/.source; - var mInterpolationRound = nested(replace(/[^"'/()]|<<0>>|\(<>*\)/.source, [regularStringCharacterOrComment]), 2); - var mInterpolation = replace(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source, [ - mInterpolationRound, - formatString - ]); - var sInterpolationRound = nested(replace(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<>*\)/.source, [regularStringOrCharacter]), 2); - var sInterpolation = replace(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source, [ - sInterpolationRound, - formatString - ]); - function createInterpolationInside(interpolation, interpolationRound) { - return { - 'interpolation': { - pattern: re(/((?:^|[^{])(?:\{\{)*)<<0>>/.source, [interpolation]), - lookbehind: true, - inside: { - 'format-string': { - pattern: re(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source, [ - interpolationRound, - formatString - ]), - lookbehind: true, - inside: { 'punctuation': /^:/ } - }, - 'punctuation': /^\{|\}$/, - 'expression': { - pattern: /[\s\S]+/, - alias: 'language-csharp', - inside: Prism.languages.csharp - } - } - }, - 'string': /[\s\S]+/ - }; } - Prism.languages.insertBefore('csharp', 'string', { - 'interpolation-string': [ - { - pattern: re(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source, [mInterpolation]), - lookbehind: true, - greedy: true, - inside: createInterpolationInside(mInterpolation, mInterpolationRound) - }, - { - pattern: re(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source, [sInterpolation]), - lookbehind: true, - greedy: true, - inside: createInterpolationInside(sInterpolation, sInterpolationRound) - } - ], - 'char': { - pattern: RegExp(character), - greedy: true - } - }); - Prism.languages.dotnet = Prism.languages.cs = Prism.languages.csharp; - }(Prism)); - (function (Prism) { - var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/; - Prism.languages.css = { - 'comment': /\/\*[\s\S]*?\*\//, - 'atrule': { - pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source), - inside: { - 'rule': /^@[\w-]+/, - 'selector-function-argument': { - pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/, - lookbehind: true, - alias: 'selector' - }, - 'keyword': { - pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/, - lookbehind: true - } - } - }, - 'url': { - pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'), - greedy: true, - inside: { - 'function': /^url/i, - 'punctuation': /^\(|\)$/, - 'string': { - pattern: RegExp('^' + string.source + '$'), - alias: 'url' - } - } - }, - 'selector': { - pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'), - lookbehind: true - }, - 'string': { - pattern: string, - greedy: true - }, - 'property': { - pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i, - lookbehind: true - }, - 'important': /!important\b/i, - 'function': { - pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, - lookbehind: true - }, - 'punctuation': /[(){};:,]/ - }; - Prism.languages.css['atrule'].inside.rest = Prism.languages.css; - var markup = Prism.languages.markup; - if (markup) { - markup.tag.addInlined('style', 'css'); - markup.tag.addAttribute('style', 'css'); + // --- Interop with null and undefined --- + /** + * Creates an `Optional` value from a nullable (or undefined-able) input. + * Null, or undefined, is converted to `None`, and anything else is converted + * to `Some`. + */ + static from(value) { + return isNonNullable(value) ? Optional.some(value) : Optional.none(); } - }(Prism)); - (function (Prism) { - var keywords = /\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/; - var classNamePrefix = /(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source; - var className = { - pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source), - lookbehind: true, - inside: { - 'namespace': { - pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/, - inside: { 'punctuation': /\./ } - }, - 'punctuation': /\./ - } - }; - Prism.languages.java = Prism.languages.extend('clike', { - 'string': { - pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"/, - lookbehind: true, - greedy: true - }, - 'class-name': [ - className, - { - pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source), - lookbehind: true, - inside: className.inside - }, - { - pattern: RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source + classNamePrefix + /[A-Z]\w*\b/.source), - lookbehind: true, - inside: className.inside - } - ], - 'keyword': keywords, - 'function': [ - Prism.languages.clike.function, - { - pattern: /(::\s*)[a-z_]\w*/, - lookbehind: true - } - ], - 'number': /\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i, - 'operator': { - pattern: /(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m, - lookbehind: true - }, - 'constant': /\b[A-Z][A-Z_\d]+\b/ - }); - Prism.languages.insertBefore('java', 'string', { - 'triple-quoted-string': { - pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/, - greedy: true, - alias: 'string' - }, - 'char': { - pattern: /'(?:\\.|[^'\\\r\n]){1,6}'/, - greedy: true - } - }); - Prism.languages.insertBefore('java', 'class-name', { - 'annotation': { - pattern: /(^|[^.])@\w+(?:\s*\.\s*\w+)*/, - lookbehind: true, - alias: 'punctuation' - }, - 'generics': { - pattern: /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/, - inside: { - 'class-name': className, - 'keyword': keywords, - 'punctuation': /[<>(),.:]/, - 'operator': /[?&|]/ - } - }, - 'import': [ - { - pattern: RegExp(/(\bimport\s+)/.source + classNamePrefix + /(?:[A-Z]\w*|\*)(?=\s*;)/.source), - lookbehind: true, - inside: { - 'namespace': className.inside.namespace, - 'punctuation': /\./, - 'operator': /\*/, - 'class-name': /\w+/ - } - }, - { - pattern: RegExp(/(\bimport\s+static\s+)/.source + classNamePrefix + /(?:\w+|\*)(?=\s*;)/.source), - lookbehind: true, - alias: 'static', - inside: { - 'namespace': className.inside.namespace, - 'static': /\b\w+$/, - 'punctuation': /\./, - 'operator': /\*/, - 'class-name': /\w+/ - } - } - ], - 'namespace': { - pattern: RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(//g, function () { - return keywords.source; - })), - lookbehind: true, - inside: { 'punctuation': /\./ } - } - }); - }(Prism)); - Prism.languages.javascript = Prism.languages.extend('clike', { - 'class-name': [ - Prism.languages.clike['class-name'], - { - pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/, - lookbehind: true - } - ], - 'keyword': [ - { - pattern: /((?:^|\})\s*)catch\b/, - lookbehind: true - }, - { - pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, - lookbehind: true - } - ], - 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, - 'number': { - pattern: RegExp(/(^|[^\w$])/.source + '(?:' + (/NaN|Infinity/.source + '|' + /0[bB][01]+(?:_[01]+)*n?/.source + '|' + /0[oO][0-7]+(?:_[0-7]+)*n?/.source + '|' + /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source + '|' + /\d+(?:_\d+)*n/.source + '|' + /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source) + ')' + /(?![\w$])/.source), - lookbehind: true - }, - 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/ - }); - Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/; - Prism.languages.insertBefore('javascript', 'keyword', { - 'regex': { - pattern: RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source + /\//.source + '(?:' + /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source + '|' + /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source + ')' + /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source), - lookbehind: true, - greedy: true, - inside: { - 'regex-source': { - pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/, - lookbehind: true, - alias: 'language-regex', - inside: Prism.languages.regex - }, - 'regex-delimiter': /^\/|\/$/, - 'regex-flags': /^[a-z]+$/ - } - }, - 'function-variable': { - pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/, - alias: 'function' - }, - 'parameter': [ - { - pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/, - lookbehind: true, - inside: Prism.languages.javascript - }, - { - pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i, - lookbehind: true, - inside: Prism.languages.javascript - }, - { - pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/, - lookbehind: true, - inside: Prism.languages.javascript - }, - { - pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/, - lookbehind: true, - inside: Prism.languages.javascript - } - ], - 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/ - }); - Prism.languages.insertBefore('javascript', 'string', { - 'hashbang': { - pattern: /^#!.*/, - greedy: true, - alias: 'comment' - }, - 'template-string': { - pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/, - greedy: true, - inside: { - 'template-punctuation': { - pattern: /^`|`$/, - alias: 'string' - }, - 'interpolation': { - pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/, - lookbehind: true, - inside: { - 'interpolation-punctuation': { - pattern: /^\$\{|\}$/, - alias: 'punctuation' - }, - rest: Prism.languages.javascript - } - }, - 'string': /[\s\S]+/ - } - }, - 'string-property': { - pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m, - lookbehind: true, - greedy: true, - alias: 'property' + /** + * Converts an `Optional` to a nullable type, by getting the value if it + * exists, or returning `null` if it does not. + */ + getOrNull() { + return this.tag ? this.value : null; } - }); - Prism.languages.insertBefore('javascript', 'operator', { - 'literal-property': { - pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m, - lookbehind: true, - alias: 'property' + /** + * Converts an `Optional` to an undefined-able type, by getting the value if + * it exists, or returning `undefined` if it does not. + */ + getOrUndefined() { + return this.value; } - }); - if (Prism.languages.markup) { - Prism.languages.markup.tag.addInlined('script', 'javascript'); - Prism.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source, 'javascript'); - } - Prism.languages.js = Prism.languages.javascript; - Prism.languages.markup = { - 'comment': { - pattern: //, - greedy: true - }, - 'prolog': { - pattern: /<\?[\s\S]+?\?>/, - greedy: true - }, - 'doctype': { - pattern: /"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i, - greedy: true, - inside: { - 'internal-subset': { - pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, - lookbehind: true, - greedy: true, - inside: null - }, - 'string': { - pattern: /"[^"]*"|'[^']*'/, - greedy: true - }, - 'punctuation': /^$|[[\]]/, - 'doctype-tag': /^DOCTYPE/i, - 'name': /[^\s<>'"]+/ - } - }, - 'cdata': { - pattern: //i, - greedy: true - }, - 'tag': { - pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, - greedy: true, - inside: { - 'tag': { - pattern: /^<\/?[^\s>\/]+/, - inside: { - 'punctuation': /^<\/?/, - 'namespace': /^[^\s>\/:]+:/ - } - }, - 'special-attr': [], - 'attr-value': { - pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, - inside: { - 'punctuation': [ - { - pattern: /^=/, - alias: 'attr-equals' - }, - { - pattern: /^(\s*)["']|["']$/, - lookbehind: true - } - ] - } - }, - 'punctuation': /\/?>/, - 'attr-name': { - pattern: /[^\s>\/]+/, - inside: { 'namespace': /^[^\s>\/:]+:/ } + // --- Utilities --- + /** + * If the `Optional` contains a value, perform an action on that value. + * Unlike the rest of the methods on this type, `.each` has side-effects. If + * you want to transform an `Optional` **into** something, then this is not + * the method for you. If you want to use an `Optional` to **do** + * something, then this is the method for you - provided you're okay with not + * doing anything in the case where the `Optional` doesn't have a value inside + * it. If you're not sure whether your use-case fits into transforming + * **into** something or **doing** something, check whether it has a return + * value. If it does, you should be performing a transform. + */ + each(worker) { + if (this.tag) { + worker(this.value); } - } - }, - 'entity': [ - { - pattern: /&[\da-z]{1,8};/i, - alias: 'named-entity' - }, - /&#x?[\da-f]{1,8};/i - ] - }; - Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] = Prism.languages.markup['entity']; - Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup; - Prism.hooks.add('wrap', function (env) { - if (env.type === 'entity') { - env.attributes['title'] = env.content.replace(/&/, '&'); } - }); - Object.defineProperty(Prism.languages.markup.tag, 'addInlined', { - value: function addInlined(tagName, lang) { - var includedCdataInside = {}; - includedCdataInside['language-' + lang] = { - pattern: /(^$)/i, - lookbehind: true, - inside: Prism.languages[lang] - }; - includedCdataInside['cdata'] = /^$/i; - var inside = { - 'included-cdata': { - pattern: //i, - inside: includedCdataInside - } - }; - inside['language-' + lang] = { - pattern: /[\s\S]+/, - inside: Prism.languages[lang] - }; - var def = {}; - def[tagName] = { - pattern: RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g, function () { - return tagName; - }), 'i'), - lookbehind: true, - greedy: true, - inside: inside - }; - Prism.languages.insertBefore('markup', 'cdata', def); + /** + * Turn the `Optional` object into an array that contains all of the values + * stored inside the `Optional`. In practice, this means the output will have + * either 0 or 1 elements. + */ + toArray() { + return this.tag ? [this.value] : []; } - }); - Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', { - value: function (attrName, lang) { - Prism.languages.markup.tag.inside['special-attr'].push({ - pattern: RegExp(/(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source, 'i'), - lookbehind: true, - inside: { - 'attr-name': /^[^\s=]+/, - 'attr-value': { - pattern: /=[\s\S]+/, - inside: { - 'value': { - pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, - lookbehind: true, - alias: [ - lang, - 'language-' + lang - ], - inside: Prism.languages[lang] - }, - 'punctuation': [ - { - pattern: /^=/, - alias: 'attr-equals' - }, - /"|'/ - ] - } - } - } - }); + /** + * Turn the `Optional` object into a string for debugging or printing. Not + * recommended for production code, but good for debugging. Also note that + * these days an `Optional` object can be logged to the console directly, and + * its inner value (if it exists) will be visible. + */ + toString() { + return this.tag ? `some(${this.value})` : 'none()'; } - }); - Prism.languages.html = Prism.languages.markup; - Prism.languages.mathml = Prism.languages.markup; - Prism.languages.svg = Prism.languages.markup; - Prism.languages.xml = Prism.languages.extend('markup', {}); - Prism.languages.ssml = Prism.languages.xml; - Prism.languages.atom = Prism.languages.xml; - Prism.languages.rss = Prism.languages.xml; - (function (Prism) { - var comment = /\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/; - var constant = [ - { - pattern: /\b(?:false|true)\b/i, - alias: 'boolean' - }, - { - pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i, - greedy: true, - lookbehind: true - }, - { - pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i, - greedy: true, - lookbehind: true - }, - /\b(?:null)\b/i, - /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/ - ]; - var number = /\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i; - var operator = /|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/; - var punctuation = /[{}\[\](),:;]/; - Prism.languages.php = { - 'delimiter': { - pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i, - alias: 'important' - }, - 'comment': comment, - 'variable': /\$+(?:\w+\b|(?=\{))/, - 'package': { - pattern: /(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, - lookbehind: true, - inside: { 'punctuation': /\\/ } - }, - 'class-name-definition': { - pattern: /(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i, - lookbehind: true, - alias: 'class-name' - }, - 'function-definition': { - pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i, - lookbehind: true, - alias: 'function' - }, - 'keyword': [ - { - pattern: /(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i, - alias: 'type-casting', - greedy: true, - lookbehind: true - }, - { - pattern: /([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i, - alias: 'type-hint', - greedy: true, - lookbehind: true - }, - { - pattern: /(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i, - alias: 'return-type', - greedy: true, - lookbehind: true - }, - { - pattern: /\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i, - alias: 'type-declaration', - greedy: true - }, - { - pattern: /(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i, - alias: 'type-declaration', - greedy: true, - lookbehind: true - }, - { - pattern: /\b(?:parent|self|static)(?=\s*::)/i, - alias: 'static-context', - greedy: true - }, - { - pattern: /(\byield\s+)from\b/i, - lookbehind: true - }, - /\bclass\b/i, - { - pattern: /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i, - lookbehind: true - } - ], - 'argument-name': { - pattern: /([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i, - lookbehind: true - }, - 'class-name': [ - { - pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i, - greedy: true, - lookbehind: true - }, - { - pattern: /(\|\s*)\b[a-z_]\w*(?!\\)\b/i, - greedy: true, - lookbehind: true - }, - { - pattern: /\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i, - greedy: true - }, - { - pattern: /(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i, - alias: 'class-name-fully-qualified', - greedy: true, - lookbehind: true, - inside: { 'punctuation': /\\/ } - }, - { - pattern: /(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i, - alias: 'class-name-fully-qualified', - greedy: true, - inside: { 'punctuation': /\\/ } - }, - { - pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, - alias: 'class-name-fully-qualified', - greedy: true, - lookbehind: true, - inside: { 'punctuation': /\\/ } - }, - { - pattern: /\b[a-z_]\w*(?=\s*\$)/i, - alias: 'type-declaration', - greedy: true - }, - { - pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i, - alias: [ - 'class-name-fully-qualified', - 'type-declaration' - ], - greedy: true, - inside: { 'punctuation': /\\/ } - }, - { - pattern: /\b[a-z_]\w*(?=\s*::)/i, - alias: 'static-context', - greedy: true - }, - { - pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*::)/i, - alias: [ - 'class-name-fully-qualified', - 'static-context' - ], - greedy: true, - inside: { 'punctuation': /\\/ } - }, - { - pattern: /([(,?]\s*)[a-z_]\w*(?=\s*\$)/i, - alias: 'type-hint', - greedy: true, - lookbehind: true - }, - { - pattern: /([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i, - alias: [ - 'class-name-fully-qualified', - 'type-hint' - ], - greedy: true, - lookbehind: true, - inside: { 'punctuation': /\\/ } - }, - { - pattern: /(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i, - alias: 'return-type', - greedy: true, - lookbehind: true - }, - { - pattern: /(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, - alias: [ - 'class-name-fully-qualified', - 'return-type' - ], - greedy: true, - lookbehind: true, - inside: { 'punctuation': /\\/ } - } - ], - 'constant': constant, - 'function': { - pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i, - lookbehind: true, - inside: { 'punctuation': /\\/ } - }, - 'property': { - pattern: /(->\s*)\w+/, - lookbehind: true - }, - 'number': number, - 'operator': operator, - 'punctuation': punctuation - }; - var string_interpolation = { - pattern: /\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/, - lookbehind: true, - inside: Prism.languages.php - }; - var string = [ - { - pattern: /<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/, - alias: 'nowdoc-string', - greedy: true, - inside: { - 'delimiter': { - pattern: /^<<<'[^']+'|[a-z_]\w*;$/i, - alias: 'symbol', - inside: { 'punctuation': /^<<<'?|[';]$/ } - } - } - }, - { - pattern: /<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i, - alias: 'heredoc-string', - greedy: true, - inside: { - 'delimiter': { - pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i, - alias: 'symbol', - inside: { 'punctuation': /^<<<"?|[";]$/ } - }, - 'interpolation': string_interpolation - } - }, - { - pattern: /`(?:\\[\s\S]|[^\\`])*`/, - alias: 'backtick-quoted-string', - greedy: true - }, - { - pattern: /'(?:\\[\s\S]|[^\\'])*'/, - alias: 'single-quoted-string', - greedy: true - }, - { - pattern: /"(?:\\[\s\S]|[^\\"])*"/, - alias: 'double-quoted-string', - greedy: true, - inside: { 'interpolation': string_interpolation } - } - ]; - Prism.languages.insertBefore('php', 'variable', { - 'string': string, - 'attribute': { - pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im, - greedy: true, - inside: { - 'attribute-content': { - pattern: /^(#\[)[\s\S]+(?=\]$)/, - lookbehind: true, - inside: { - 'comment': comment, - 'string': string, - 'attribute-class-name': [ - { - pattern: /([^:]|^)\b[a-z_]\w*(?!\\)\b/i, - alias: 'class-name', - greedy: true, - lookbehind: true - }, - { - pattern: /([^:]|^)(?:\\?\b[a-z_]\w*)+/i, - alias: [ - 'class-name', - 'class-name-fully-qualified' - ], - greedy: true, - lookbehind: true, - inside: { 'punctuation': /\\/ } - } - ], - 'constant': constant, - 'number': number, - 'operator': operator, - 'punctuation': punctuation - } - }, - 'delimiter': { - pattern: /^#\[|\]$/, - alias: 'punctuation' - } - } - } - }); - Prism.hooks.add('before-tokenize', function (env) { - if (!/<\?/.test(env.code)) { - return; - } - var phpPattern = /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g; - Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern); - }); - Prism.hooks.add('after-tokenize', function (env) { - Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php'); - }); - }(Prism)); - Prism.languages.python = { - 'comment': { - pattern: /(^|[^\\])#.*/, - lookbehind: true, - greedy: true - }, - 'string-interpolation': { - pattern: /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i, - greedy: true, - inside: { - 'interpolation': { - pattern: /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/, - lookbehind: true, - inside: { - 'format-spec': { - pattern: /(:)[^:(){}]+(?=\}$)/, - lookbehind: true - }, - 'conversion-option': { - pattern: /![sra](?=[:}]$)/, - alias: 'punctuation' - }, - rest: null - } - }, - 'string': /[\s\S]+/ - } - }, - 'triple-quoted-string': { - pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i, - greedy: true, - alias: 'string' - }, - 'string': { - pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i, - greedy: true - }, - 'function': { - pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g, - lookbehind: true - }, - 'class-name': { - pattern: /(\bclass\s+)\w+/i, - lookbehind: true - }, - 'decorator': { - pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m, - lookbehind: true, - alias: [ - 'annotation', - 'punctuation' - ], - inside: { 'punctuation': /\./ } - }, - 'keyword': /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/, - 'builtin': /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/, - 'boolean': /\b(?:False|None|True)\b/, - 'number': /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i, - 'operator': /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/, - 'punctuation': /[{}[\];(),.:]/ - }; - Prism.languages.python['string-interpolation'].inside['interpolation'].inside.rest = Prism.languages.python; - Prism.languages.py = Prism.languages.python; - (function (Prism) { - Prism.languages.ruby = Prism.languages.extend('clike', { - 'comment': { - pattern: /#.*|^=begin\s[\s\S]*?^=end/m, - greedy: true - }, - 'class-name': { - pattern: /(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/, - lookbehind: true, - inside: { 'punctuation': /[.\\]/ } - }, - 'keyword': /\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/, - 'operator': /\.{2,3}|&\.|===||[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/, - 'punctuation': /[(){}[\].,;]/ - }); - Prism.languages.insertBefore('ruby', 'operator', { - 'double-colon': { - pattern: /::/, - alias: 'punctuation' - } - }); - var interpolation = { - pattern: /((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/, - lookbehind: true, - inside: { - 'content': { - pattern: /^(#\{)[\s\S]+(?=\}$)/, - lookbehind: true, - inside: Prism.languages.ruby - }, - 'delimiter': { - pattern: /^#\{|\}$/, - alias: 'punctuation' - } - } - }; - delete Prism.languages.ruby.function; - var percentExpression = '(?:' + [ - /([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source, - /\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source, - /\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source, - /\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source, - /<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source - ].join('|') + ')'; - var symbolName = /(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source; - Prism.languages.insertBefore('ruby', 'keyword', { - 'regex-literal': [ - { - pattern: RegExp(/%r/.source + percentExpression + /[egimnosux]{0,6}/.source), - greedy: true, - inside: { - 'interpolation': interpolation, - 'regex': /[\s\S]+/ - } - }, - { - pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/, - lookbehind: true, - greedy: true, - inside: { - 'interpolation': interpolation, - 'regex': /[\s\S]+/ - } - } - ], - 'variable': /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/, - 'symbol': [ - { - pattern: RegExp(/(^|[^:]):/.source + symbolName), - lookbehind: true, - greedy: true - }, - { - pattern: RegExp(/([\r\n{(,][ \t]*)/.source + symbolName + /(?=:(?!:))/.source), - lookbehind: true, - greedy: true - } - ], - 'method-definition': { - pattern: /(\bdef\s+)\w+(?:\s*\.\s*\w+)?/, - lookbehind: true, - inside: { - 'function': /\b\w+$/, - 'keyword': /^self\b/, - 'class-name': /^\w+/, - 'punctuation': /\./ - } - } - }); - Prism.languages.insertBefore('ruby', 'string', { - 'string-literal': [ - { - pattern: RegExp(/%[qQiIwWs]?/.source + percentExpression), - greedy: true, - inside: { - 'interpolation': interpolation, - 'string': /[\s\S]+/ - } - }, - { - pattern: /("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/, - greedy: true, - inside: { - 'interpolation': interpolation, - 'string': /[\s\S]+/ - } - }, - { - pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i, - alias: 'heredoc-string', - greedy: true, - inside: { - 'delimiter': { - pattern: /^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i, - inside: { - 'symbol': /\b\w+/, - 'punctuation': /^<<[-~]?/ - } - }, - 'interpolation': interpolation, - 'string': /[\s\S]+/ - } - }, - { - pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i, - alias: 'heredoc-string', - greedy: true, - inside: { - 'delimiter': { - pattern: /^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i, - inside: { - 'symbol': /\b\w+/, - 'punctuation': /^<<[-~]?'|'$/ - } - }, - 'string': /[\s\S]+/ - } - } - ], - 'command-literal': [ - { - pattern: RegExp(/%x/.source + percentExpression), - greedy: true, - inside: { - 'interpolation': interpolation, - 'command': { - pattern: /[\s\S]+/, - alias: 'string' - } - } - }, - { - pattern: /`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/, - greedy: true, - inside: { - 'interpolation': interpolation, - 'command': { - pattern: /[\s\S]+/, - alias: 'string' - } - } - } - ] - }); - delete Prism.languages.ruby.string; - Prism.languages.insertBefore('ruby', 'number', { - 'builtin': /\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/, - 'constant': /\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/ - }); - Prism.languages.rb = Prism.languages.ruby; - }(Prism)); - window.Prism = oldprism; - return Prism; - }(undefined, undefined); + } + // Sneaky optimisation: every instance of Optional.none is identical, so just + // reuse the same object + Optional.singletonNone = new Optional(false); - const option = name => editor => editor.options.get(name); - const register$2 = editor => { - const registerOption = editor.options.register; - registerOption('codesample_languages', { processor: 'object[]' }); - registerOption('codesample_global_prismjs', { - processor: 'boolean', - default: false - }); - }; - const getLanguages$1 = option('codesample_languages'); - const useGlobalPrismJS = option('codesample_global_prismjs'); + const get$1 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none(); + const head = (xs) => get$1(xs, 0); - const get = editor => Global.Prism && useGlobalPrismJS(editor) ? Global.Prism : prismjs; + // Use window object as the global if it's available since CSP will block script evals + // eslint-disable-next-line @typescript-eslint/no-implied-eval + const Global = typeof window !== 'undefined' ? window : Function('return this;')(); - const isCodeSample = elm => { - return isNonNullable(elm) && elm.nodeName === 'PRE' && elm.className.indexOf('language-') !== -1; - }; + const blank = (r) => (s) => s.replace(r, ''); + /** removes all leading and trailing spaces */ + const trim = blank(/^\s+|\s+$/g); - const getSelectedCodeSample = editor => { - const node = editor.selection ? editor.selection.getNode() : null; - return isCodeSample(node) ? Optional.some(node) : Optional.none(); - }; - const insertCodeSample = (editor, language, code) => { - const dom = editor.dom; - editor.undoManager.transact(() => { - const node = getSelectedCodeSample(editor); - code = global$1.DOM.encode(code); - return node.fold(() => { - editor.insertContent('
' + code + '
'); - const newPre = dom.select('#__new')[0]; - dom.setAttrib(newPre, 'id', null); - editor.selection.select(newPre); - }, n => { - dom.setAttrib(n, 'class', 'language-' + language); - n.innerHTML = code; - get(editor).highlightElement(n); - editor.selection.select(n); - }); - }); - }; - const getCurrentCode = editor => { - const node = getSelectedCodeSample(editor); - return node.bind(n => Optional.from(n.textContent)).getOr(''); - }; + var global$1 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils'); - const getLanguages = editor => { - const defaultLanguages = [ - { - text: 'HTML/XML', - value: 'markup' - }, - { - text: 'JavaScript', - value: 'javascript' - }, - { - text: 'CSS', - value: 'css' - }, - { - text: 'PHP', - value: 'php' - }, - { - text: 'Ruby', - value: 'ruby' - }, - { - text: 'Python', - value: 'python' - }, - { - text: 'Java', - value: 'java' - }, - { - text: 'C', - value: 'c' - }, - { - text: 'C#', - value: 'csharp' - }, - { - text: 'C++', - value: 'cpp' - } - ]; - const customLanguages = getLanguages$1(editor); - return customLanguages ? customLanguages : defaultLanguages; - }; - const getCurrentLanguage = (editor, fallback) => { - const node = getSelectedCodeSample(editor); - return node.fold(() => fallback, n => { - const matches = n.className.match(/language-(\w+)/); - return matches ? matches[1] : fallback; - }); - }; + const prismjs = function(global, module, exports) { + // preserve the global if it has already been loaded + const oldprism = window.Prism; + window.Prism = { manual: true }; + /// - const open = editor => { - const languages = getLanguages(editor); - const defaultLanguage = head(languages).fold(constant(''), l => l.value); - const currentLanguage = getCurrentLanguage(editor, defaultLanguage); - const currentCode = getCurrentCode(editor); - editor.windowManager.open({ - title: 'Insert/Edit Code Sample', - size: 'large', - body: { - type: 'panel', - items: [ - { - type: 'listbox', - name: 'language', - label: 'Language', - items: languages - }, - { - type: 'textarea', - name: 'code', - label: 'Code view' - } - ] - }, - buttons: [ - { - type: 'cancel', - name: 'cancel', - text: 'Cancel' - }, - { - type: 'submit', - name: 'save', - text: 'Save', - primary: true - } - ], - initialData: { - language: currentLanguage, - code: currentCode - }, - onSubmit: api => { - const data = api.getData(); - insertCodeSample(editor, data.language, data.code); - api.close(); - } - }); - }; + var _self = (typeof window !== 'undefined') + ? window // if in browser + : ( + (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) + ? self // if in worker + : {} // if in node js + ); - const register$1 = editor => { - editor.addCommand('codesample', () => { - const node = editor.selection.getNode(); - if (editor.selection.isCollapsed() || isCodeSample(node)) { - open(editor); - } else { - editor.formatter.toggle('code'); - } - }); - }; + /** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT + * @author Lea Verou + * @namespace + * @public + */ + var Prism = (function (_self) { - const blank = r => s => s.replace(r, ''); - const trim = blank(/^\s+|\s+$/g); + // Private helper vars + var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; + var uniqueId = 0; - var global = tinymce.util.Tools.resolve('tinymce.util.Tools'); + // The grammar object for plaintext + var plainTextGrammar = {}; - const setup = editor => { - editor.on('PreProcess', e => { - const dom = editor.dom; - const pres = dom.select('pre[contenteditable=false]', e.node); - global.each(global.grep(pres, isCodeSample), elm => { - const code = elm.textContent; - dom.setAttrib(elm, 'class', trim(dom.getAttrib(elm, 'class'))); - dom.setAttrib(elm, 'contentEditable', null); - dom.setAttrib(elm, 'data-mce-highlighted', null); - let child; - while (child = elm.firstChild) { - elm.removeChild(child); - } - const codeElm = dom.add(elm, 'code'); - codeElm.textContent = code; - }); - }); - editor.on('SetContent', () => { - const dom = editor.dom; - const unprocessedCodeSamples = global.grep(dom.select('pre'), elm => { - return isCodeSample(elm) && dom.getAttrib(elm, 'data-mce-highlighted') !== 'true'; - }); - if (unprocessedCodeSamples.length) { - editor.undoManager.transact(() => { - global.each(unprocessedCodeSamples, elm => { - var _a; - global.each(dom.select('br', elm), elm => { - dom.replace(editor.getDoc().createTextNode('\n'), elm); - }); - elm.innerHTML = dom.encode((_a = elm.textContent) !== null && _a !== void 0 ? _a : ''); - get(editor).highlightElement(elm); - dom.setAttrib(elm, 'data-mce-highlighted', true); - elm.className = trim(elm.className); - }); - }); - } - }); - editor.on('PreInit', () => { - editor.parser.addNodeFilter('pre', nodes => { - var _a; - for (let i = 0, l = nodes.length; i < l; i++) { - const node = nodes[i]; - const isCodeSample = ((_a = node.attr('class')) !== null && _a !== void 0 ? _a : '').indexOf('language-') !== -1; - if (isCodeSample) { - node.attr('contenteditable', 'false'); - node.attr('data-mce-highlighted', 'false'); - } - } - }); - }); - }; - const onSetupEditable = (editor, onChanged = noop) => api => { - const nodeChanged = () => { - api.setEnabled(editor.selection.isEditable()); - onChanged(api); - }; - editor.on('NodeChange', nodeChanged); - nodeChanged(); - return () => { - editor.off('NodeChange', nodeChanged); - }; - }; - const isCodeSampleSelection = editor => { - const node = editor.selection.getStart(); - return editor.dom.is(node, 'pre[class*="language-"]'); - }; - const register = editor => { - const onAction = () => editor.execCommand('codesample'); - editor.ui.registry.addToggleButton('codesample', { - icon: 'code-sample', - tooltip: 'Insert/edit code sample', - onAction, - onSetup: onSetupEditable(editor, api => { - api.setActive(isCodeSampleSelection(editor)); - }) - }); - editor.ui.registry.addMenuItem('codesample', { - text: 'Code sample...', - icon: 'code-sample', - onAction, - onSetup: onSetupEditable(editor) - }); - }; + var _ = { + /** + * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the + * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load + * additional languages or plugins yourself. + * + * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. + * + * You obviously have to change this value before the automatic highlighting started. To do this, you can add an + * empty Prism object into the global scope before loading the Prism script like this: + * + * ```js + * window.Prism = window.Prism || {}; + * Prism.manual = true; + * // add a new `; + }, false); + }; + return ``; }; var global = tinymce.util.Tools.resolve('tinymce.util.Tools'); - const option = name => editor => editor.options.get(name); + const option = (name) => (editor) => editor.options.get(name); const getContentStyle = option('content_style'); const shouldUseContentCssCors = option('content_css_cors'); const getBodyClass = option('body_class'); const getBodyId = option('body_id'); - const getPreviewHtml = editor => { - var _a; - let headHtml = ''; - const encode = editor.dom.encode; - const contentStyle = (_a = getContentStyle(editor)) !== null && _a !== void 0 ? _a : ''; - headHtml += ``; - const cors = shouldUseContentCssCors(editor) ? ' crossorigin="anonymous"' : ''; - global.each(editor.contentCSS, url => { - headHtml += ''; - }); - if (contentStyle) { - headHtml += ''; - } - const bodyId = getBodyId(editor); - const bodyClass = getBodyClass(editor); - const directionality = editor.getBody().dir; - const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : ''; - const previewHtml = '' + '' + '' + headHtml + '' + '' + editor.getContent() + getPreventClicksOnLinksScript() + '' + ''; - return previewHtml; + const getPreviewHtml = (editor) => { + var _a; + let headHtml = ''; + const encode = editor.dom.encode; + const contentStyle = (_a = getContentStyle(editor)) !== null && _a !== void 0 ? _a : ''; + headHtml += ``; + const cors = shouldUseContentCssCors(editor) ? ' crossorigin="anonymous"' : ''; + global.each(editor.contentCSS, (url) => { + headHtml += ''; + }); + if (contentStyle) { + headHtml += ''; + } + const bodyId = getBodyId(editor); + const bodyClass = getBodyClass(editor); + const directionality = editor.getBody().dir; + const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : ''; + const previewHtml = ('' + + '' + + '' + + headHtml + + '' + + '' + + editor.getContent() + + getPreventClicksOnLinksScript() + + '' + + ''); + return previewHtml; }; - const open = editor => { - const content = getPreviewHtml(editor); - const dataApi = editor.windowManager.open({ - title: 'Preview', - size: 'large', - body: { - type: 'panel', - items: [{ - name: 'preview', - type: 'iframe', - sandboxed: true, - transparent: false - }] - }, - buttons: [{ - type: 'cancel', - name: 'close', - text: 'Close', - primary: true - }], - initialData: { preview: content } - }); - dataApi.focus('close'); + const open = (editor) => { + const content = getPreviewHtml(editor); + const dataApi = editor.windowManager.open({ + title: 'Preview', + size: 'large', + body: { + type: 'panel', + items: [ + { + name: 'preview', + type: 'iframe', + sandboxed: true, + transparent: false + } + ] + }, + buttons: [ + { + type: 'cancel', + name: 'close', + text: 'Close', + primary: true + } + ], + initialData: { + preview: content + } + }); + // Focus the close button, as by default the first element in the body is selected + // which we don't want to happen here since the body only has the iframe content + dataApi.focus('close'); }; - const register$1 = editor => { - editor.addCommand('mcePreview', () => { - open(editor); - }); + const register$1 = (editor) => { + editor.addCommand('mcePreview', () => { + open(editor); + }); }; - const register = editor => { - const onAction = () => editor.execCommand('mcePreview'); - editor.ui.registry.addButton('preview', { - icon: 'preview', - tooltip: 'Preview', - onAction, - context: 'any' - }); - editor.ui.registry.addMenuItem('preview', { - icon: 'preview', - text: 'Preview', - onAction, - context: 'any' - }); + const register = (editor) => { + const onAction = () => editor.execCommand('mcePreview'); + editor.ui.registry.addButton('preview', { + icon: 'preview', + tooltip: 'Preview', + onAction, + context: 'any' + }); + editor.ui.registry.addMenuItem('preview', { + icon: 'preview', + text: 'Preview', + onAction, + context: 'any' + }); }; var Plugin = () => { - global$1.add('preview', editor => { - register$1(editor); - register(editor); - }); + global$1.add('preview', (editor) => { + register$1(editor); + register(editor); + }); }; Plugin(); + /** ***** + * DO NOT EXPORT ANYTHING + * + * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE + *******/ })(); diff --git a/public/ext/tinymce/plugins/preview/plugin.min.js b/public/ext/tinymce/plugins/preview/plugin.min.js index b93c94f..45fa49d 100644 --- a/public/ext/tinymce/plugins/preview/plugin.min.js +++ b/public/ext/tinymce/plugins/preview/plugin.min.js @@ -1,4 +1 @@ -/** - * TinyMCE version 7.7.2 (2025-03-19) - */ -!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>undefined===e;class r{constructor(e,t){this.tag=e,this.value=t}static some(e){return new r(!0,e)}static none(){return r.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?r.some(e(this.value)):r.none()}bind(e){return this.tag?e(this.value):r.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:r.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?r.none():r.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}r.singletonNone=new r(!1);const n=e=>()=>e,s=n(!1),i=(e,t)=>((e,t,n)=>{for(let s=0,i=e.length;sa(0,0),a=(e,t)=>({major:e,minor:t}),c={nu:a,detect:(e,t)=>{const r=String(t).toLowerCase();return 0===e.length?o():((e,t)=>{const r=((e,t)=>{for(let r=0;rNumber(t.replace(r,"$"+e));return a(n(1),n(2))})(e,r)},unknown:o},u=(e,t)=>{const r=String(t).toLowerCase();return i(e,(e=>e.search(r)))},d=(e,r,n=0,s)=>{const i=e.indexOf(r,n);return-1!==i&&(!!t(s)||i+r.length<=s)},l=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,h=e=>t=>d(t,e),m=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>d(e,"edge/")&&d(e,"chrome")&&d(e,"safari")&&d(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,l],search:e=>d(e,"chrome")&&!d(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>d(e,"msie")||d(e,"trident")},{name:"Opera",versionRegexes:[l,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:h("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:h("firefox")},{name:"Safari",versionRegexes:[l,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(d(e,"safari")||d(e,"mobile/"))&&d(e,"applewebkit")}],v=[{name:"Windows",search:h("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>d(e,"iphone")||d(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:h("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:h("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:h("linux"),versionRegexes:[]},{name:"Solaris",search:h("sunos"),versionRegexes:[]},{name:"FreeBSD",search:h("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:h("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],g={browsers:n(m),oses:n(v)},p="Edge",w="Chromium",f="Opera",x="Firefox",S="Safari",y=e=>{const t=e.current,r=e.version,n=e=>()=>t===e;return{current:t,version:r,isEdge:n(p),isChromium:n(w),isIE:n("IE"),isOpera:n(f),isFirefox:n(x),isSafari:n(S)}},b=()=>y({current:void 0,version:c.unknown()}),O=y,R=(n(p),n(w),n("IE"),n(f),n(x),n(S),"Windows"),C="Android",A="Linux",k="macOS",D="Solaris",E="FreeBSD",I="ChromeOS",P=e=>{const t=e.current,r=e.version,n=e=>()=>t===e;return{current:t,version:r,isWindows:n(R),isiOS:n("iOS"),isAndroid:n(C),isMacOS:n(k),isLinux:n(A),isSolaris:n(D),isFreeBSD:n(E),isChromeOS:n(I)}},T=()=>P({current:void 0,version:c.unknown()}),_=P,B=(n(R),n("iOS"),n(C),n(A),n(k),n(D),n(E),n(I),(e,t,s)=>{const o=g.browsers(),a=g.oses(),d=t.bind((e=>((e,t)=>((e,t)=>{for(let r=0;r{const r=t.brand.toLowerCase();return i(e,(e=>{var t;return r===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:c.nu(parseInt(t.version,10),0)})))})))(o,e))).orThunk((()=>((e,t)=>u(e,t).map((e=>{const r=c.detect(e.versionRegexes,t);return{current:e.name,version:r}})))(o,e))).fold(b,O),l=((e,t)=>u(e,t).map((e=>{const r=c.detect(e.versionRegexes,t);return{current:e.name,version:r}})))(a,e).fold(T,_),h=((e,t,r,s)=>{const i=e.isiOS()&&!0===/ipad/i.test(r),o=e.isiOS()&&!i,a=e.isiOS()||e.isAndroid(),c=a||s("(pointer:coarse)"),u=i||!o&&a&&s("(min-device-width:768px)"),d=o||a&&!u,l=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(r),h=!d&&!u&&!l;return{isiPad:n(i),isiPhone:n(o),isTablet:n(u),isPhone:n(d),isTouch:n(c),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:n(l),isDesktop:n(h)}})(l,d,e,s);return{browser:d,os:l,deviceType:h}}),L=e=>window.matchMedia(e).matches;let N=(e=>{let t,r=!1;return(...n)=>(r||(r=!0,t=e.apply(null,n)),t)})((()=>B(window.navigator.userAgent,r.from(window.navigator.userAgentData),L)));const F=()=>N();var M=tinymce.util.Tools.resolve("tinymce.util.Tools");const $=e=>t=>t.options.get(e),W=$("content_style"),U=$("content_css_cors"),K=$("body_class"),j=$("body_id"),V=e=>{const t=(e=>{var t;let r="";const n=e.dom.encode,s=null!==(t=W(e))&&void 0!==t?t:"";r+=``;const i=U(e)?' crossorigin="anonymous"':"";M.each(e.contentCSS,(t=>{r+='"})),s&&(r+='");const o=j(e),a=K(e),c=e.getBody().dir,u=c?' dir="'+n(c)+'"':"";return""+r+'"+e.getContent()+(()=>{const e=F().os.isMacOS()||F().os.isiOS();return`