`):\n *\n * ```javascript\n * var hljs = require('highlight.js') // https://highlightjs.org/\n *\n * // Actual default values\n * var md = require('markdown-it')({\n * highlight: function (str, lang) {\n * if (lang && hljs.getLanguage(lang)) {\n * try {\n * return '' +\n * hljs.highlight(str, { language: lang, ignoreIllegals: true }).value +\n * '
';\n * } catch (__) {}\n * }\n *\n * return '' + md.utils.escapeHtml(str) + '
';\n * }\n * });\n * ```\n *\n **/\nfunction MarkdownIt (presetName, options) {\n if (!(this instanceof MarkdownIt)) {\n return new MarkdownIt(presetName, options)\n }\n\n if (!options) {\n if (!utils.isString(presetName)) {\n options = presetName || {}\n presetName = 'default'\n }\n }\n\n /**\n * MarkdownIt#inline -> ParserInline\n *\n * Instance of [[ParserInline]]. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.inline = new ParserInline()\n\n /**\n * MarkdownIt#block -> ParserBlock\n *\n * Instance of [[ParserBlock]]. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.block = new ParserBlock()\n\n /**\n * MarkdownIt#core -> Core\n *\n * Instance of [[Core]] chain executor. You may need it to add new rules when\n * writing plugins. For simple rules control use [[MarkdownIt.disable]] and\n * [[MarkdownIt.enable]].\n **/\n this.core = new ParserCore()\n\n /**\n * MarkdownIt#renderer -> Renderer\n *\n * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering\n * rules for new token types, generated by plugins.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')();\n *\n * function myToken(tokens, idx, options, env, self) {\n * //...\n * return result;\n * };\n *\n * md.renderer.rules['my_token'] = myToken\n * ```\n *\n * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.mjs).\n **/\n this.renderer = new Renderer()\n\n /**\n * MarkdownIt#linkify -> LinkifyIt\n *\n * [linkify-it](https://github.com/markdown-it/linkify-it) instance.\n * Used by [linkify](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/linkify.mjs)\n * rule.\n **/\n this.linkify = new LinkifyIt()\n\n /**\n * MarkdownIt#validateLink(url) -> Boolean\n *\n * Link validation function. CommonMark allows too much in links. By default\n * we disable `javascript:`, `vbscript:`, `file:` schemas, and almost all `data:...` schemas\n * except some embedded image types.\n *\n * You can change this behaviour:\n *\n * ```javascript\n * var md = require('markdown-it')();\n * // enable everything\n * md.validateLink = function () { return true; }\n * ```\n **/\n this.validateLink = validateLink\n\n /**\n * MarkdownIt#normalizeLink(url) -> String\n *\n * Function used to encode link url to a machine-readable format,\n * which includes url-encoding, punycode, etc.\n **/\n this.normalizeLink = normalizeLink\n\n /**\n * MarkdownIt#normalizeLinkText(url) -> String\n *\n * Function used to decode link url to a human-readable format`\n **/\n this.normalizeLinkText = normalizeLinkText\n\n // Expose utils & helpers for easy acces from plugins\n\n /**\n * MarkdownIt#utils -> utils\n *\n * Assorted utility functions, useful to write plugins. See details\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.mjs).\n **/\n this.utils = utils\n\n /**\n * MarkdownIt#helpers -> helpers\n *\n * Link components parser functions, useful to write plugins. See details\n * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).\n **/\n this.helpers = utils.assign({}, helpers)\n\n this.options = {}\n this.configure(presetName)\n\n if (options) { this.set(options) }\n}\n\n/** chainable\n * MarkdownIt.set(options)\n *\n * Set parser options (in the same format as in constructor). Probably, you\n * will never need it, but you can change options after constructor call.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')()\n * .set({ html: true, breaks: true })\n * .set({ typographer, true });\n * ```\n *\n * __Note:__ To achieve the best possible performance, don't modify a\n * `markdown-it` instance options on the fly. If you need multiple configurations\n * it's best to create multiple instances and initialize each with separate\n * config.\n **/\nMarkdownIt.prototype.set = function (options) {\n utils.assign(this.options, options)\n return this\n}\n\n/** chainable, internal\n * MarkdownIt.configure(presets)\n *\n * Batch load of all options and compenent settings. This is internal method,\n * and you probably will not need it. But if you will - see available presets\n * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets)\n *\n * We strongly recommend to use presets instead of direct config loads. That\n * will give better compatibility with next versions.\n **/\nMarkdownIt.prototype.configure = function (presets) {\n const self = this\n\n if (utils.isString(presets)) {\n const presetName = presets\n presets = config[presetName]\n if (!presets) { throw new Error('Wrong `markdown-it` preset \"' + presetName + '\", check name') }\n }\n\n if (!presets) { throw new Error('Wrong `markdown-it` preset, can\\'t be empty') }\n\n if (presets.options) { self.set(presets.options) }\n\n if (presets.components) {\n Object.keys(presets.components).forEach(function (name) {\n if (presets.components[name].rules) {\n self[name].ruler.enableOnly(presets.components[name].rules)\n }\n if (presets.components[name].rules2) {\n self[name].ruler2.enableOnly(presets.components[name].rules2)\n }\n })\n }\n return this\n}\n\n/** chainable\n * MarkdownIt.enable(list, ignoreInvalid)\n * - list (String|Array): rule name or list of rule names to enable\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * Enable list or rules. It will automatically find appropriate components,\n * containing rules with given names. If rule not found, and `ignoreInvalid`\n * not set - throws exception.\n *\n * ##### Example\n *\n * ```javascript\n * var md = require('markdown-it')()\n * .enable(['sub', 'sup'])\n * .disable('smartquotes');\n * ```\n **/\nMarkdownIt.prototype.enable = function (list, ignoreInvalid) {\n let result = []\n\n if (!Array.isArray(list)) { list = [list] }\n\n ['core', 'block', 'inline'].forEach(function (chain) {\n result = result.concat(this[chain].ruler.enable(list, true))\n }, this)\n\n result = result.concat(this.inline.ruler2.enable(list, true))\n\n const missed = list.filter(function (name) { return result.indexOf(name) < 0 })\n\n if (missed.length && !ignoreInvalid) {\n throw new Error('MarkdownIt. Failed to enable unknown rule(s): ' + missed)\n }\n\n return this\n}\n\n/** chainable\n * MarkdownIt.disable(list, ignoreInvalid)\n * - list (String|Array): rule name or list of rule names to disable.\n * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.\n *\n * The same as [[MarkdownIt.enable]], but turn specified rules off.\n **/\nMarkdownIt.prototype.disable = function (list, ignoreInvalid) {\n let result = []\n\n if (!Array.isArray(list)) { list = [list] }\n\n ['core', 'block', 'inline'].forEach(function (chain) {\n result = result.concat(this[chain].ruler.disable(list, true))\n }, this)\n\n result = result.concat(this.inline.ruler2.disable(list, true))\n\n const missed = list.filter(function (name) { return result.indexOf(name) < 0 })\n\n if (missed.length && !ignoreInvalid) {\n throw new Error('MarkdownIt. Failed to disable unknown rule(s): ' + missed)\n }\n return this\n}\n\n/** chainable\n * MarkdownIt.use(plugin, params)\n *\n * Load specified plugin with given params into current parser instance.\n * It's just a sugar to call `plugin(md, params)` with curring.\n *\n * ##### Example\n *\n * ```javascript\n * var iterator = require('markdown-it-for-inline');\n * var md = require('markdown-it')()\n * .use(iterator, 'foo_replace', 'text', function (tokens, idx) {\n * tokens[idx].content = tokens[idx].content.replace(/foo/g, 'bar');\n * });\n * ```\n **/\nMarkdownIt.prototype.use = function (plugin /*, params, ... */) {\n const args = [this].concat(Array.prototype.slice.call(arguments, 1))\n plugin.apply(plugin, args)\n return this\n}\n\n/** internal\n * MarkdownIt.parse(src, env) -> Array\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Parse input string and return list of block tokens (special token type\n * \"inline\" will contain list of inline tokens). You should not call this\n * method directly, until you write custom renderer (for example, to produce\n * AST).\n *\n * `env` is used to pass data between \"distributed\" rules and return additional\n * metadata like reference info, needed for the renderer. It also can be used to\n * inject data in specific cases. Usually, you will be ok to pass `{}`,\n * and then pass updated object to renderer.\n **/\nMarkdownIt.prototype.parse = function (src, env) {\n if (typeof src !== 'string') {\n throw new Error('Input data should be a String')\n }\n\n const state = new this.core.State(src, this, env)\n\n this.core.process(state)\n\n return state.tokens\n}\n\n/**\n * MarkdownIt.render(src [, env]) -> String\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Render markdown string into html. It does all magic for you :).\n *\n * `env` can be used to inject additional metadata (`{}` by default).\n * But you will not need it with high probability. See also comment\n * in [[MarkdownIt.parse]].\n **/\nMarkdownIt.prototype.render = function (src, env) {\n env = env || {}\n\n return this.renderer.render(this.parse(src, env), this.options, env)\n}\n\n/** internal\n * MarkdownIt.parseInline(src, env) -> Array\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the\n * block tokens list with the single `inline` element, containing parsed inline\n * tokens in `children` property. Also updates `env` object.\n **/\nMarkdownIt.prototype.parseInline = function (src, env) {\n const state = new this.core.State(src, this, env)\n\n state.inlineMode = true\n this.core.process(state)\n\n return state.tokens\n}\n\n/**\n * MarkdownIt.renderInline(src [, env]) -> String\n * - src (String): source string\n * - env (Object): environment sandbox\n *\n * Similar to [[MarkdownIt.render]] but for single paragraph content. Result\n * will NOT be wrapped into `` tags.\n **/\nMarkdownIt.prototype.renderInline = function (src, env) {\n env = env || {}\n\n return this.renderer.render(this.parseInline(src, env), this.options, env)\n}\n\nexport default MarkdownIt\n", "import { Controller } from \"@hotwired/stimulus\"\nimport markdownit from 'markdown-it'\n\n// Connects to data-controller=\"markdown-display\"\nexport default class extends Controller {\n connect() {\n const md = markdownit({\n html: true,\n linkify: true,\n typographer: true\n })\n this.element.innerHTML = md.render(this.element.textContent.trim())\n }\n}\n", "import { Controller } from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"modal\"\nexport default class extends Controller {\n connect() {\n this.element.showModal()\n }\n // hide modal\n // action: \"turbo-modal#hideModal\"\n hideModal() {\n this.element.parentElement.removeAttribute(\"src\")\n // Remove src reference from parent frame element\n // Without this, turbo won't re-open the modal on subsequent click\n this.element.remove()\n }\n\n // hide modal on successful form submission\n // action: \"turbo:submit-end->turbo-modal#submitEnd\"\n submitEnd(e) {\n if (e.detail.success) {\n this.hideModal()\n }\n }\n\n // hide modal when clicking ESC\n // action: \"keyup@window->turbo-modal#closeWithKeyboard\"\n closeWithKeyboard(e) {\n if (e.code == \"Escape\") {\n this.hideModal()\n }\n }\n\n // hide modal when clicking outside of modal\n // action: \"click@window->turbo-modal#closeBackground\"\n closeBackground(e) {\n if (e && this.element.contains(e.target)) {\n return;\n }\n this.hideModal()\n }\n}\n", "import { Controller } from \"@hotwired/stimulus\"\n\nexport default class extends Controller {\n static targets = [\"options\", \"template\", \"option\"]\n\n connect() {\n this.choiceTypeChanged()\n }\n\n add(event) {\n event.preventDefault()\n const template = this.templateTarget.innerHTML\n const timestamp = new Date().getTime()\n const newOption = template.replace(/NEW_RECORD/g, timestamp)\n this.optionsTarget.insertAdjacentHTML('beforeend', newOption)\n this.choiceTypeChanged()\n }\n\n remove(event) {\n event.preventDefault()\n const optionField = event.target.closest('.nested-fields')\n if (optionField.dataset.newRecord === \"true\") {\n optionField.remove()\n } else {\n const destroyField = optionField.querySelector(\"input[name*='_destroy']\")\n destroyField.value = 1\n optionField.style.display = 'none'\n }\n }\n\n choiceTypeChanged(event) {\n const choiceTypeSelect = document.querySelector('select[name=\"poll[choice_type]\"]')\n const choiceType = choiceTypeSelect.value\n\n this.optionTargets.forEach(option => {\n const nameField = option.querySelector('[data-choice-type=\"name\"]')\n const webField = option.querySelector('[data-choice-type=\"versus\"]')\n\n if (choiceType === 'versus') {\n if (nameField) { nameField.style.display = 'none' }\n if (webField) { webField.style.display = '' }\n } else {\n if (nameField) { nameField.style.display = '' }\n if (webField) { webField.style.display = 'none' }\n }\n })\n }\n}", "import { Controller } from \"@hotwired/stimulus\"\nimport { Turbo } from \"@hotwired/turbo-rails\"\n\nexport default class extends Controller {\n static values = {\n delay: Number\n }\n\n connect() {\n // Store the original delay to restore it later\n this.originalDelay = 200\n }\n\n initialize() {\n // Bind the click method to this instance\n this.click = this.click.bind(this)\n }\n\n click(event) {\n if (this.hasDelayValue) {\n // Set the new delay\n Turbo.setProgressBarDelay(this.delayValue)\n\n // Define a one-time handler to restore the original delay after navigation\n const restoreDelay = () => {\n Turbo.setProgressBarDelay(this.originalDelay)\n // Remove the event listeners after restoring\n document.removeEventListener(\"turbo:render\", restoreDelay)\n document.removeEventListener(\"turbo:frame-render\", restoreDelay)\n }\n\n // Attach the one-time event listeners\n document.addEventListener(\"turbo:render\", restoreDelay, { once: true })\n document.addEventListener(\"turbo:frame-render\", restoreDelay, { once: true })\n }\n }\n}", "import { Controller } from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"removal\"\nexport default class extends Controller {\n static targets = [\"removable\"];\n connect() {\n console.log(\"Removal controller connected\");\n }\n\n remove() {\n this.removableTarget.remove(); // \u79FB\u9664\u5143\u7D20\n }\n}\n", "import { Controller } from \"@hotwired/stimulus\";\n\n// Connects to data-controller=\"select-button\"\nexport default class extends Controller {\n\tstatic targets = [\"label\"];\n\tstatic classes = [\"label\"];\n\n\tconnect() {\n\t\tconsole.log(\"select button controller connected\");\n\t}\n\n\tselect(event) {\n\t\t// \u9700\u8981\u5148\u5220\u9664\u6240\u6709\u7684labelClass\uFF0C\u7136\u540E\u518D\u6DFB\u52A0\n\t\t// \u8FD9\u6837\u53EF\u4EE5\u4FDD\u8BC1\u53EA\u6709\u4E00\u4E2AlabelClass\n\t\t// \u5982\u679C\u76F4\u63A5\u4F7F\u7528toggle\uFF0C\u4F1A\u5BFC\u81F4\u591A\u4E2AlabelClass\n\t\tthis.labelTargets.forEach((label) => {\n\t\t\tlabel.classList.remove(this.labelClass);\n\t\t});\n\t\tevent.currentTarget.labels[0].classList.add(this.labelClass);\n\t}\n\n\ttoggle(event) {\n\t\t// Toggle the label classes based on the checkbox state\n\t\tif (event.currentTarget.checked) {\n\t\t\tthis.labelClasses.forEach((labelClass) => {\n\t\t\t\tevent.currentTarget.labels[0].classList.add(labelClass);\n\t\t\t});\n\t\t} else {\n\t\t\tthis.labelClasses.forEach((labelClass) => {\n\t\t\t\tevent.currentTarget.labels[0].classList.remove(labelClass);\n\t\t\t});\n\t\t}\n\t}\n}\n", "import { Controller } from \"@hotwired/stimulus\";\n\n// Connects to data-controller=\"send-message\"\nexport default class extends Controller {\n static targets = [\"textarea\", \"button\", \"save\"];\n\n connect() {\n console.log(\"SendMessage controller connected\");\n }\n\n send(event) {\n event.preventDefault();\n\n // Prevent sending empty messages\n const message = this.textareaTarget.value.trim();\n if (message === \"\") {\n return;\n }\n\n // Submit the form\n this.element.requestSubmit();\n\n // Handle post-send UI updates\n this.clearText();\n }\n\n save = this.debounce((event) => {\n event.preventDefault();\n\n // Simulate save operation\n this.saveTarget.click();\n this.saveTarget.textContent = \"Saving...\";\n setTimeout(() => {\n this.saveTarget.textContent = \"Saved\";\n }, 1500); // Adjust save delay as needed\n }, 2000); // Add debounce to prevent frequent saves\n\n // Utility method for clearing textarea and updating button state\n clearText(event) {\n event.preventDefault();\n this.textareaTarget.value = \"\";\n this.textareaTarget.focus();\n\n this.buttonTarget.disabled = true;\n setTimeout(() => {\n this.buttonTarget.disabled = false;\n }, 1500);\n }\n\n // Utility method for debouncing\n debounce(func, wait) {\n let timeout;\n return (...args) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n };\n }\n}", "/**\n * @preserve\n * Sharer.js\n *\n * @description Create your own social share buttons\n * @version 0.5.1\n * @author Ellison Leao \n * @license MIT\n *\n */\n\n(function(window, document) {\n 'use strict';\n /**\n * @constructor\n */\n var Sharer = function(elem) {\n this.elem = elem;\n };\n\n /**\n * @function init\n * @description bind the events for multiple sharer elements\n * @returns {Empty}\n */\n Sharer.init = function() {\n var elems = document.querySelectorAll('[data-sharer]'),\n i,\n l = elems.length;\n\n for (i = 0; i < l; i++) {\n elems[i].addEventListener('click', Sharer.add);\n }\n };\n\n /**\n * @function add\n * @description bind the share event for a single dom element\n * @returns {Empty}\n */\n Sharer.add = function(elem) {\n var target = elem.currentTarget || elem.srcElement;\n var sharer = new Sharer(target);\n sharer.share();\n };\n\n // instance methods\n Sharer.prototype = {\n constructor: Sharer,\n /**\n * @function getValue\n * @description Helper to get the attribute of a DOM element\n * @param {String} attr DOM element attribute\n * @returns {String|Empty} returns the attr value or empty string\n */\n getValue: function(attr) {\n var val = this.elem.getAttribute('data-' + attr);\n // handing facebook hashtag attribute\n if (val && attr === 'hashtag') {\n if (!val.startsWith('#')) {\n val = '#' + val;\n }\n }\n return val === null ? '' : val;\n },\n\n /**\n * @event share\n * @description Main share event. Will pop a window or redirect to a link\n * based on the data-sharer attribute.\n */\n share: function() {\n var sharer = this.getValue('sharer').toLowerCase(),\n sharers = {\n facebook: {\n shareUrl: 'https://www.facebook.com/sharer/sharer.php',\n params: {\n u: this.getValue('url'),\n hashtag: this.getValue('hashtag'),\n quote: this.getValue('quote'),\n },\n },\n linkedin: {\n shareUrl: 'https://www.linkedin.com/shareArticle',\n params: {\n url: this.getValue('url'),\n mini: true,\n },\n },\n twitter: {\n shareUrl: 'https://twitter.com/intent/tweet',\n params: {\n text: this.getValue('title'),\n url: this.getValue('url'),\n hashtags: this.getValue('hashtags'),\n via: this.getValue('via'),\n related: this.getValue('related'),\n in_reply_to: this.getValue('in_reply_to'),\n },\n },\n x: {\n shareUrl: 'https://x.com/intent/tweet',\n params: {\n text: this.getValue('title'),\n url: this.getValue('url'),\n hashtags: this.getValue('hashtags'),\n via: this.getValue('via'),\n related: this.getValue('related'),\n in_reply_to: this.getValue('in_reply_to'),\n },\n },\n threads: {\n shareUrl: 'https://threads.net/intent/post',\n params: {\n text: this.getValue('title') + ' ' + this.getValue('url'),\n },\n },\n email: {\n shareUrl: 'mailto:' + this.getValue('to'),\n params: {\n subject: this.getValue('subject'),\n body: this.getValue('title') + '\\n' + this.getValue('url'),\n },\n },\n whatsapp: {\n shareUrl: this.getValue('web') === 'true' ? 'https://web.whatsapp.com/send' : 'https://wa.me/',\n params: {\n phone: this.getValue('to'),\n text: this.getValue('title') + ' ' + this.getValue('url'),\n },\n },\n telegram: {\n shareUrl: 'https://t.me/share',\n params: {\n text: this.getValue('title'),\n url: this.getValue('url'),\n },\n },\n viber: {\n shareUrl: 'viber://forward',\n params: {\n text: this.getValue('title') + ' ' + this.getValue('url'),\n },\n },\n line: {\n shareUrl:\n 'http://line.me/R/msg/text/?' + encodeURIComponent(this.getValue('title') + ' ' + this.getValue('url')),\n },\n pinterest: {\n shareUrl: 'https://www.pinterest.com/pin/create/button/',\n params: {\n url: this.getValue('url'),\n media: this.getValue('image'),\n description: this.getValue('description'),\n },\n },\n tumblr: {\n shareUrl: 'http://tumblr.com/widgets/share/tool',\n params: {\n canonicalUrl: this.getValue('url'),\n content: this.getValue('url'),\n posttype: 'link',\n title: this.getValue('title'),\n caption: this.getValue('caption'),\n tags: this.getValue('tags'),\n },\n },\n hackernews: {\n shareUrl: 'https://news.ycombinator.com/submitlink',\n params: {\n u: this.getValue('url'),\n t: this.getValue('title'),\n },\n },\n reddit: {\n shareUrl: 'https://www.reddit.com/submit',\n params: { url: this.getValue('url'), title: this.getValue('title') },\n },\n vk: {\n shareUrl: 'http://vk.com/share.php',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n description: this.getValue('caption'),\n image: this.getValue('image'),\n },\n },\n xing: {\n shareUrl: 'https://www.xing.com/social/share/spi',\n params: {\n url: this.getValue('url'),\n },\n },\n buffer: {\n shareUrl: 'https://buffer.com/add',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n via: this.getValue('via'),\n picture: this.getValue('picture'),\n },\n },\n instapaper: {\n shareUrl: 'http://www.instapaper.com/edit',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n description: this.getValue('description'),\n },\n },\n pocket: {\n shareUrl: 'https://getpocket.com/save',\n params: {\n url: this.getValue('url'),\n },\n },\n mashable: {\n shareUrl: 'https://mashable.com/submit',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n },\n },\n mix: {\n shareUrl: 'https://mix.com/add',\n params: {\n url: this.getValue('url'),\n },\n },\n flipboard: {\n shareUrl: 'https://share.flipboard.com/bookmarklet/popout',\n params: {\n v: 2,\n title: this.getValue('title'),\n url: this.getValue('url'),\n t: Date.now(),\n },\n },\n weibo: {\n shareUrl: 'http://service.weibo.com/share/share.php',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n pic: this.getValue('image'),\n appkey: this.getValue('appkey'),\n ralateUid: this.getValue('ralateuid'),\n language: 'zh_cn',\n },\n },\n blogger: {\n shareUrl: 'https://www.blogger.com/blog-this.g',\n params: {\n u: this.getValue('url'),\n n: this.getValue('title'),\n t: this.getValue('description'),\n },\n },\n baidu: {\n shareUrl: 'http://cang.baidu.com/do/add',\n params: {\n it: this.getValue('title'),\n iu: this.getValue('url'),\n },\n },\n douban: {\n shareUrl: 'https://www.douban.com/share/service',\n params: {\n name: this.getValue('name'),\n href: this.getValue('url'),\n image: this.getValue('image'),\n comment: this.getValue('description'),\n },\n },\n okru: {\n shareUrl: 'https://connect.ok.ru/dk',\n params: {\n 'st.cmd': 'WidgetSharePreview',\n 'st.shareUrl': this.getValue('url'),\n title: this.getValue('title'),\n },\n },\n mailru: {\n shareUrl: 'http://connect.mail.ru/share',\n params: {\n share_url: this.getValue('url'),\n linkname: this.getValue('title'),\n linknote: this.getValue('description'),\n type: 'page',\n },\n },\n evernote: {\n shareUrl: 'https://www.evernote.com/clip.action',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n },\n },\n skype: {\n shareUrl: 'https://web.skype.com/share',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n },\n },\n delicious: {\n shareUrl: 'https://del.icio.us/post',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n },\n },\n sms: {\n shareUrl: 'sms://',\n params: {\n body: this.getValue('body'),\n },\n },\n trello: {\n shareUrl: 'https://trello.com/add-card',\n params: {\n url: this.getValue('url'),\n name: this.getValue('title'),\n desc: this.getValue('description'),\n mode: 'popup',\n },\n },\n messenger: {\n shareUrl: 'fb-messenger://share',\n params: {\n link: this.getValue('url'),\n },\n },\n odnoklassniki: {\n shareUrl: 'https://connect.ok.ru/dk',\n params: {\n st: {\n cmd: 'WidgetSharePreview',\n deprecated: 1,\n shareUrl: this.getValue('url'),\n },\n },\n },\n meneame: {\n shareUrl: 'https://www.meneame.net/submit',\n params: {\n url: this.getValue('url'),\n },\n },\n diaspora: {\n shareUrl: 'https://share.diasporafoundation.org',\n params: {\n title: this.getValue('title'),\n url: this.getValue('url'),\n },\n },\n googlebookmarks: {\n shareUrl: 'https://www.google.com/bookmarks/mark',\n params: {\n op: 'edit',\n bkmk: this.getValue('url'),\n title: this.getValue('title'),\n },\n },\n qzone: {\n shareUrl: 'https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey',\n params: {\n url: this.getValue('url'),\n },\n },\n refind: {\n shareUrl: 'https://refind.com',\n params: {\n url: this.getValue('url'),\n },\n },\n surfingbird: {\n shareUrl: 'https://surfingbird.ru/share',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n description: this.getValue('description'),\n },\n },\n yahoomail: {\n shareUrl: 'http://compose.mail.yahoo.com',\n params: {\n to: this.getValue('to'),\n subject: this.getValue('subject'),\n body: this.getValue('body'),\n },\n },\n wordpress: {\n shareUrl: 'https://wordpress.com/wp-admin/press-this.php',\n params: {\n u: this.getValue('url'),\n t: this.getValue('title'),\n s: this.getValue('title'),\n },\n },\n amazon: {\n shareUrl: 'https://www.amazon.com/gp/wishlist/static-add',\n params: {\n u: this.getValue('url'),\n t: this.getValue('title'),\n },\n },\n pinboard: {\n shareUrl: 'https://pinboard.in/add',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n description: this.getValue('description'),\n },\n },\n threema: {\n shareUrl: 'threema://compose',\n params: {\n text: this.getValue('text'),\n id: this.getValue('id'),\n },\n },\n kakaostory: {\n shareUrl: 'https://story.kakao.com/share',\n params: {\n url: this.getValue('url'),\n },\n },\n yummly: {\n shareUrl: 'http://www.yummly.com/urb/verify',\n params: {\n url: this.getValue('url'),\n title: this.getValue('title'),\n yumtype: 'button',\n },\n },\n },\n s = sharers[sharer];\n\n // custom popups sizes\n if (s) {\n s.width = this.getValue('width');\n s.height = this.getValue('height');\n }\n return s !== undefined ? this.urlSharer(s) : false;\n },\n /**\n * @event urlSharer\n * @param {Object} sharer\n */\n urlSharer: function(sharer) {\n var p = sharer.params || {},\n keys = Object.keys(p),\n i,\n str = keys.length > 0 ? '?' : '';\n for (i = 0; i < keys.length; i++) {\n if (str !== '?') {\n str += '&';\n }\n if (p[keys[i]]) {\n str += keys[i] + '=' + encodeURIComponent(p[keys[i]]);\n }\n }\n sharer.shareUrl += str;\n\n var isLink = this.getValue('link') === 'true';\n var isBlank = this.getValue('blank') === 'true';\n\n if (isLink) {\n if (isBlank) {\n window.open(sharer.shareUrl, '_blank');\n } else {\n window.location.href = sharer.shareUrl;\n }\n } else {\n console.log(sharer.shareUrl);\n // defaults to popup if no data-link is provided\n var popWidth = sharer.width || 600,\n popHeight = sharer.height || 480,\n left = window.innerWidth / 2 - popWidth / 2 + window.screenX,\n top = window.innerHeight / 2 - popHeight / 2 + window.screenY,\n popParams = 'scrollbars=no, width=' + popWidth + ', height=' + popHeight + ', top=' + top + ', left=' + left,\n newWindow = window.open(sharer.shareUrl, '', popParams);\n\n if (window.focus) {\n newWindow.focus();\n }\n }\n },\n };\n\n // adding sharer events on domcontentload\n if (document.readyState === 'complete' || document.readyState !== 'loading') {\n Sharer.init();\n } else {\n document.addEventListener('DOMContentLoaded', Sharer.init);\n }\n\n // exporting sharer for external usage\n window.Sharer = Sharer;\n})(window, document);\n", "import { Controller } from \"@hotwired/stimulus\"\nimport 'sharer.js'\n\n// Connects to data-controller=\"sharer\"\nexport default class extends Controller {\n connect() {\n window.Sharer.init();\n console.log('Sharer controller connected');\n }\n}\n", "import { Controller } from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"show-more\"\nexport default class extends Controller {\n static targets = [\"content\", \"button\"]\n static values = {\n moreText: String,\n lessText: String,\n defaultLine: Number\n }\n\n connect() {\n // \u68C0\u67E5\u5185\u5BB9\u662F\u5426\u8D85\u8FC7\u9ED8\u8BA4\u7684\u884C\u6570\n this.checkContentOverflow()\n this.toggleLineClamp(true) // \u9ED8\u8BA4\u5E94\u7528 line-clamp\n }\n\n checkContentOverflow() {\n const lineHeight = parseFloat(getComputedStyle(this.contentTarget).lineHeight)\n const maxHeight = this.defaultLineValue * lineHeight\n const actualHeight = this.contentTarget.scrollHeight\n\n // \u5982\u679C\u5185\u5BB9\u6CA1\u6709\u8D85\u8FC7\u9ED8\u8BA4\u884C\u6570\uFF0C\u9690\u85CF\u6309\u94AE\n if (actualHeight <= maxHeight) {\n this.buttonTarget.classList.add('hidden')\n } else {\n this.buttonTarget.classList.remove('hidden')\n this.updateButtonLabel(this.moreTextValue)\n }\n }\n\n toggle() {\n // Toggle line-clamp class\n if (this.contentTarget.classList.contains(`line-clamp-${this.defaultLineValue}`)) {\n this.toggleLineClamp(false)\n this.updateButtonLabel(this.lessTextValue)\n } else {\n this.toggleLineClamp(true)\n this.updateButtonLabel(this.moreTextValue)\n }\n }\n\n toggleLineClamp(add) {\n const className = `line-clamp-${this.defaultLineValue}`\n if (add) {\n this.contentTarget.classList.add(className)\n } else {\n this.contentTarget.classList.remove(className)\n }\n }\n\n updateButtonLabel(label) {\n this.buttonTarget.textContent = label\n }\n}\n", "/*\n * stimulus-use 0.52.2\n */\nimport { Controller } from \"@hotwired/stimulus\";\n\nconst method = (controller, methodName) => {\n const method = controller[methodName];\n if (typeof method == \"function\") {\n return method;\n } else {\n return (...args) => {};\n }\n};\n\nconst composeEventName = (name, controller, eventPrefix) => {\n let composedName = name;\n if (eventPrefix === true) {\n composedName = `${controller.identifier}:${name}`;\n } else if (typeof eventPrefix === \"string\") {\n composedName = `${eventPrefix}:${name}`;\n }\n return composedName;\n};\n\nconst extendedEvent = (type, event, detail) => {\n const {bubbles: bubbles, cancelable: cancelable, composed: composed} = event || {\n bubbles: true,\n cancelable: true,\n composed: true\n };\n if (event) {\n Object.assign(detail, {\n originalEvent: event\n });\n }\n const customEvent = new CustomEvent(type, {\n bubbles: bubbles,\n cancelable: cancelable,\n composed: composed,\n detail: detail\n });\n return customEvent;\n};\n\nfunction isElementInViewport(el) {\n const rect = el.getBoundingClientRect();\n const windowHeight = window.innerHeight || document.documentElement.clientHeight;\n const windowWidth = window.innerWidth || document.documentElement.clientWidth;\n const vertInView = rect.top <= windowHeight && rect.top + rect.height > 0;\n const horInView = rect.left <= windowWidth && rect.left + rect.width > 0;\n return vertInView && horInView;\n}\n\nfunction camelize(value) {\n return value.replace(/(?:[_-])([a-z0-9])/g, ((_, char) => char.toUpperCase()));\n}\n\n/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise */ function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nconst defaultOptions$8 = {\n debug: false,\n logger: console,\n dispatchEvent: true,\n eventPrefix: true\n};\n\nclass StimulusUse {\n constructor(controller, options = {}) {\n var _a, _b, _c;\n this.log = (functionName, args) => {\n if (!this.debug) return;\n this.logger.groupCollapsed(`%c${this.controller.identifier} %c#${functionName}`, \"color: #3B82F6\", \"color: unset\");\n this.logger.log(Object.assign({\n controllerId: this.controllerId\n }, args));\n this.logger.groupEnd();\n };\n this.warn = message => {\n this.logger.warn(`%c${this.controller.identifier} %c${message}`, \"color: #3B82F6; font-weight: bold\", \"color: unset\");\n };\n this.dispatch = (eventName, details = {}) => {\n if (this.dispatchEvent) {\n const {event: event} = details, eventDetails = __rest(details, [ \"event\" ]);\n const customEvent = this.extendedEvent(eventName, event || null, eventDetails);\n this.targetElement.dispatchEvent(customEvent);\n this.log(\"dispatchEvent\", Object.assign({\n eventName: customEvent.type\n }, eventDetails));\n }\n };\n this.call = (methodName, args = {}) => {\n const method = this.controller[methodName];\n if (typeof method == \"function\") {\n return method.call(this.controller, args);\n }\n };\n this.extendedEvent = (name, event, detail) => {\n const {bubbles: bubbles, cancelable: cancelable, composed: composed} = event || {\n bubbles: true,\n cancelable: true,\n composed: true\n };\n if (event) {\n Object.assign(detail, {\n originalEvent: event\n });\n }\n const customEvent = new CustomEvent(this.composeEventName(name), {\n bubbles: bubbles,\n cancelable: cancelable,\n composed: composed,\n detail: detail\n });\n return customEvent;\n };\n this.composeEventName = name => {\n let composedName = name;\n if (this.eventPrefix === true) {\n composedName = `${this.controller.identifier}:${name}`;\n } else if (typeof this.eventPrefix === \"string\") {\n composedName = `${this.eventPrefix}:${name}`;\n }\n return composedName;\n };\n this.debug = (_b = (_a = options === null || options === void 0 ? void 0 : options.debug) !== null && _a !== void 0 ? _a : controller.application.stimulusUseDebug) !== null && _b !== void 0 ? _b : defaultOptions$8.debug;\n this.logger = (_c = options === null || options === void 0 ? void 0 : options.logger) !== null && _c !== void 0 ? _c : defaultOptions$8.logger;\n this.controller = controller;\n this.controllerId = controller.element.id || controller.element.dataset.id;\n this.targetElement = (options === null || options === void 0 ? void 0 : options.element) || controller.element;\n const {dispatchEvent: dispatchEvent, eventPrefix: eventPrefix} = Object.assign({}, defaultOptions$8, options);\n Object.assign(this, {\n dispatchEvent: dispatchEvent,\n eventPrefix: eventPrefix\n });\n this.controllerInitialize = controller.initialize.bind(controller);\n this.controllerConnect = controller.connect.bind(controller);\n this.controllerDisconnect = controller.disconnect.bind(controller);\n }\n}\n\nconst defaultOptions$7 = {\n eventPrefix: true,\n bubbles: true,\n cancelable: true\n};\n\nclass UseDispatch extends StimulusUse {\n constructor(controller, options = {}) {\n var _a, _b, _c, _d;\n super(controller, options);\n this.dispatch = (eventName, detail = {}) => {\n const {controller: controller, targetElement: targetElement, eventPrefix: eventPrefix, bubbles: bubbles, cancelable: cancelable, log: log, warn: warn} = this;\n Object.assign(detail, {\n controller: controller\n });\n const eventNameWithPrefix = composeEventName(eventName, this.controller, eventPrefix);\n const event = new CustomEvent(eventNameWithPrefix, {\n detail: detail,\n bubbles: bubbles,\n cancelable: cancelable\n });\n targetElement.dispatchEvent(event);\n warn(\"`useDispatch()` is deprecated. Please use the built-in `this.dispatch()` function from Stimulus. You can find more information on how to upgrade at: https://stimulus-use.github.io/stimulus-use/#/use-dispatch\");\n log(\"dispatch\", {\n eventName: eventNameWithPrefix,\n detail: detail,\n bubbles: bubbles,\n cancelable: cancelable\n });\n return event;\n };\n this.targetElement = (_a = options.element) !== null && _a !== void 0 ? _a : controller.element;\n this.eventPrefix = (_b = options.eventPrefix) !== null && _b !== void 0 ? _b : defaultOptions$7.eventPrefix;\n this.bubbles = (_c = options.bubbles) !== null && _c !== void 0 ? _c : defaultOptions$7.bubbles;\n this.cancelable = (_d = options.cancelable) !== null && _d !== void 0 ? _d : defaultOptions$7.cancelable;\n this.enhanceController();\n }\n enhanceController() {\n Object.assign(this.controller, {\n dispatch: this.dispatch\n });\n }\n}\n\nconst useDispatch = (controller, options = {}) => new UseDispatch(controller, options);\n\nconst defaultOptions$6 = {\n overwriteDispatch: true\n};\n\nconst useApplication = (controller, options = {}) => {\n const {overwriteDispatch: overwriteDispatch} = Object.assign({}, defaultOptions$6, options);\n Object.defineProperty(controller, \"isPreview\", {\n get() {\n return document.documentElement.hasAttribute(\"data-turbolinks-preview\") || document.documentElement.hasAttribute(\"data-turbo-preview\");\n }\n });\n Object.defineProperty(controller, \"isConnected\", {\n get() {\n return !!Array.from(this.context.module.connectedContexts).find((c => c === this.context));\n }\n });\n Object.defineProperty(controller, \"csrfToken\", {\n get() {\n return this.metaValue(\"csrf-token\");\n }\n });\n if (overwriteDispatch) {\n useDispatch(controller, options);\n }\n Object.assign(controller, {\n metaValue(name) {\n const element = document.head.querySelector(`meta[name=\"${name}\"]`);\n return element && element.getAttribute(\"content\");\n }\n });\n};\n\nclass ApplicationController extends Controller {\n constructor(context) {\n super(context);\n this.isPreview = false;\n this.isConnected = false;\n this.csrfToken = \"\";\n useApplication(this, this.options);\n }\n}\n\nconst defaultOptions$5 = {\n events: [ \"click\", \"touchend\" ],\n onlyVisible: true,\n dispatchEvent: true,\n eventPrefix: true\n};\n\nconst useClickOutside = (composableController, options = {}) => {\n const controller = composableController;\n const {onlyVisible: onlyVisible, dispatchEvent: dispatchEvent, events: events, eventPrefix: eventPrefix} = Object.assign({}, defaultOptions$5, options);\n const onEvent = event => {\n const targetElement = (options === null || options === void 0 ? void 0 : options.element) || controller.element;\n if (targetElement.contains(event.target) || !isElementInViewport(targetElement) && onlyVisible) {\n return;\n }\n if (controller.clickOutside) {\n controller.clickOutside(event);\n }\n if (dispatchEvent) {\n const eventName = composeEventName(\"click:outside\", controller, eventPrefix);\n const clickOutsideEvent = extendedEvent(eventName, event, {\n controller: controller\n });\n targetElement.dispatchEvent(clickOutsideEvent);\n }\n };\n const observe = () => {\n events === null || events === void 0 ? void 0 : events.forEach((event => {\n window.addEventListener(event, onEvent, true);\n }));\n };\n const unobserve = () => {\n events === null || events === void 0 ? void 0 : events.forEach((event => {\n window.removeEventListener(event, onEvent, true);\n }));\n };\n const controllerDisconnect = controller.disconnect.bind(controller);\n Object.assign(controller, {\n disconnect() {\n unobserve();\n controllerDisconnect();\n }\n });\n observe();\n return [ observe, unobserve ];\n};\n\nclass ClickOutsideComposableController extends Controller {}\n\nclass ClickOutsideController extends ClickOutsideComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useClickOutside(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nclass DebounceController extends Controller {}\n\nDebounceController.debounces = [];\n\nconst defaultWait$1 = 200;\n\nconst debounce = (fn, wait = defaultWait$1) => {\n let timeoutId = null;\n return function() {\n const args = Array.from(arguments);\n const context = this;\n const params = args.map((arg => arg.params));\n const callback = () => {\n args.forEach(((arg, index) => arg.params = params[index]));\n return fn.apply(context, args);\n };\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = setTimeout(callback, wait);\n };\n};\n\nconst useDebounce = (composableController, options) => {\n const controller = composableController;\n const constructor = controller.constructor;\n constructor.debounces.forEach((func => {\n if (typeof func === \"string\") {\n controller[func] = debounce(controller[func], options === null || options === void 0 ? void 0 : options.wait);\n }\n if (typeof func === \"object\") {\n const {name: name, wait: wait} = func;\n if (!name) return;\n controller[name] = debounce(controller[name], wait || (options === null || options === void 0 ? void 0 : options.wait));\n }\n }));\n};\n\nclass UseHover extends StimulusUse {\n constructor(controller, options = {}) {\n super(controller, options);\n this.observe = () => {\n this.targetElement.addEventListener(\"mouseenter\", this.onEnter);\n this.targetElement.addEventListener(\"mouseleave\", this.onLeave);\n };\n this.unobserve = () => {\n this.targetElement.removeEventListener(\"mouseenter\", this.onEnter);\n this.targetElement.removeEventListener(\"mouseleave\", this.onLeave);\n };\n this.onEnter = event => {\n this.call(\"mouseEnter\", event);\n this.log(\"mouseEnter\", {\n hover: true\n });\n this.dispatch(\"mouseEnter\", {\n hover: false\n });\n };\n this.onLeave = event => {\n this.call(\"mouseLeave\", event);\n this.log(\"mouseLeave\", {\n hover: false\n });\n this.dispatch(\"mouseLeave\", {\n hover: false\n });\n };\n this.controller = controller;\n this.enhanceController();\n this.observe();\n }\n enhanceController() {\n const controllerDisconnect = this.controller.disconnect.bind(this.controller);\n const disconnect = () => {\n this.unobserve();\n controllerDisconnect();\n };\n Object.assign(this.controller, {\n disconnect: disconnect\n });\n }\n}\n\nconst useHover = (composableController, options = {}) => {\n const controller = composableController;\n const observer = new UseHover(controller, options);\n return [ observer.observe, observer.unobserve ];\n};\n\nclass HoverComposableController extends Controller {}\n\nclass HoverController extends HoverComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useHover(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nconst defaultEvents = [ \"mousemove\", \"mousedown\", \"resize\", \"keydown\", \"touchstart\", \"wheel\" ];\n\nconst oneMinute = 6e4;\n\nconst defaultOptions$4 = {\n ms: oneMinute,\n initialState: false,\n events: defaultEvents,\n dispatchEvent: true,\n eventPrefix: true\n};\n\nconst useIdle = (composableController, options = {}) => {\n const controller = composableController;\n const {ms: ms, initialState: initialState, events: events, dispatchEvent: dispatchEvent, eventPrefix: eventPrefix} = Object.assign({}, defaultOptions$4, options);\n let isIdle = initialState;\n let timeout = setTimeout((() => {\n isIdle = true;\n dispatchAway();\n }), ms);\n const dispatchAway = event => {\n const eventName = composeEventName(\"away\", controller, eventPrefix);\n controller.isIdle = true;\n method(controller, \"away\").call(controller, event);\n if (dispatchEvent) {\n const clickOutsideEvent = extendedEvent(eventName, event || null, {\n controller: controller\n });\n controller.element.dispatchEvent(clickOutsideEvent);\n }\n };\n const dispatchBack = event => {\n const eventName = composeEventName(\"back\", controller, eventPrefix);\n controller.isIdle = false;\n method(controller, \"back\").call(controller, event);\n if (dispatchEvent) {\n const clickOutsideEvent = extendedEvent(eventName, event || null, {\n controller: controller\n });\n controller.element.dispatchEvent(clickOutsideEvent);\n }\n };\n const onEvent = event => {\n if (isIdle) dispatchBack(event);\n isIdle = false;\n clearTimeout(timeout);\n timeout = setTimeout((() => {\n isIdle = true;\n dispatchAway(event);\n }), ms);\n };\n const onVisibility = event => {\n if (!document.hidden) onEvent(event);\n };\n if (isIdle) {\n dispatchAway();\n } else {\n dispatchBack();\n }\n const controllerDisconnect = controller.disconnect.bind(controller);\n const observe = () => {\n events.forEach((event => {\n window.addEventListener(event, onEvent);\n }));\n document.addEventListener(\"visibilitychange\", onVisibility);\n };\n const unobserve = () => {\n clearTimeout(timeout);\n events.forEach((event => {\n window.removeEventListener(event, onEvent);\n }));\n document.removeEventListener(\"visibilitychange\", onVisibility);\n };\n Object.assign(controller, {\n disconnect() {\n unobserve();\n controllerDisconnect();\n }\n });\n observe();\n return [ observe, unobserve ];\n};\n\nclass IdleComposableController extends Controller {\n constructor() {\n super(...arguments);\n this.isIdle = false;\n }\n}\n\nclass IdleController extends IdleComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useIdle(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nconst defaultOptions$3 = {\n dispatchEvent: true,\n eventPrefix: true,\n visibleAttribute: \"isVisible\"\n};\n\nconst useIntersection = (composableController, options = {}) => {\n const controller = composableController;\n const {dispatchEvent: dispatchEvent, eventPrefix: eventPrefix, visibleAttribute: visibleAttribute} = Object.assign({}, defaultOptions$3, options);\n const targetElement = (options === null || options === void 0 ? void 0 : options.element) || controller.element;\n if (!controller.intersectionElements) controller.intersectionElements = [];\n controller.intersectionElements.push(targetElement);\n const callback = entries => {\n const [entry] = entries;\n if (entry.isIntersecting) {\n dispatchAppear(entry);\n } else if (targetElement.hasAttribute(visibleAttribute)) {\n dispatchDisappear(entry);\n }\n };\n const observer = new IntersectionObserver(callback, options);\n const dispatchAppear = entry => {\n targetElement.setAttribute(visibleAttribute, \"true\");\n method(controller, \"appear\").call(controller, entry, observer);\n if (dispatchEvent) {\n const eventName = composeEventName(\"appear\", controller, eventPrefix);\n const appearEvent = extendedEvent(eventName, null, {\n controller: controller,\n entry: entry,\n observer: observer\n });\n targetElement.dispatchEvent(appearEvent);\n }\n };\n const dispatchDisappear = entry => {\n targetElement.removeAttribute(visibleAttribute);\n method(controller, \"disappear\").call(controller, entry, observer);\n if (dispatchEvent) {\n const eventName = composeEventName(\"disappear\", controller, eventPrefix);\n const disappearEvent = extendedEvent(eventName, null, {\n controller: controller,\n entry: entry,\n observer: observer\n });\n targetElement.dispatchEvent(disappearEvent);\n }\n };\n const controllerDisconnect = controller.disconnect.bind(controller);\n const disconnect = () => {\n unobserve();\n controllerDisconnect();\n };\n const observe = () => {\n observer.observe(targetElement);\n };\n const unobserve = () => {\n observer.unobserve(targetElement);\n };\n const noneVisible = () => controller.intersectionElements.filter((element => element.hasAttribute(visibleAttribute))).length === 0;\n const oneVisible = () => controller.intersectionElements.filter((element => element.hasAttribute(visibleAttribute))).length === 1;\n const atLeastOneVisible = () => controller.intersectionElements.some((element => element.hasAttribute(visibleAttribute)));\n const allVisible = () => controller.intersectionElements.every((element => element.hasAttribute(visibleAttribute)));\n const isVisible = allVisible;\n Object.assign(controller, {\n isVisible: isVisible,\n noneVisible: noneVisible,\n oneVisible: oneVisible,\n atLeastOneVisible: atLeastOneVisible,\n allVisible: allVisible,\n disconnect: disconnect\n });\n observe();\n return [ observe, unobserve ];\n};\n\nclass IntersectionComposableController extends Controller {}\n\nclass IntersectionController extends IntersectionComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useIntersection(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nconst useLazyLoad = (controller, options) => {\n const callback = entries => {\n const [entry] = entries;\n if (entry.isIntersecting && !controller.isLoaded) {\n handleAppear();\n }\n };\n const handleAppear = entry => {\n const src = controller.data.get(\"src\");\n if (!src) return;\n const imageElement = controller.element;\n controller.isLoading = true;\n method(controller, \"loading\").call(controller, src);\n imageElement.onload = () => {\n handleLoaded(src);\n };\n imageElement.src = src;\n };\n const handleLoaded = src => {\n controller.isLoading = false;\n controller.isLoaded = true;\n method(controller, \"loaded\").call(controller, src);\n };\n const controllerDisconnect = controller.disconnect.bind(controller);\n const observer = new IntersectionObserver(callback, options);\n const observe = () => {\n observer.observe(controller.element);\n };\n const unobserve = () => {\n observer.unobserve(controller.element);\n };\n Object.assign(controller, {\n isVisible: false,\n disconnect() {\n unobserve();\n controllerDisconnect();\n }\n });\n observe();\n return [ observe, unobserve ];\n};\n\nclass LazyLoadComposableController extends Controller {\n constructor() {\n super(...arguments);\n this.isLoading = false;\n this.isLoaded = false;\n }\n}\n\nclass LazyLoadController extends LazyLoadComposableController {\n constructor(context) {\n super(context);\n this.options = {\n rootMargin: \"10%\"\n };\n requestAnimationFrame((() => {\n const [observe, unobserve] = useLazyLoad(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nconst defaultOptions$2 = {\n mediaQueries: {},\n dispatchEvent: true,\n eventPrefix: true,\n debug: false\n};\n\nclass UseMatchMedia extends StimulusUse {\n constructor(controller, options = {}) {\n var _a, _b, _c, _d;\n super(controller, options);\n this.matches = [];\n this.callback = event => {\n const name = Object.keys(this.mediaQueries).find((name => this.mediaQueries[name] === event.media));\n if (!name) return;\n const {media: media, matches: matches} = event;\n this.changed({\n name: name,\n media: media,\n matches: matches,\n event: event\n });\n };\n this.changed = payload => {\n const {name: name} = payload;\n if (payload.event) {\n this.call(camelize(`${name}_changed`), payload);\n this.dispatch(`${name}:changed`, payload);\n this.log(`media query \"${name}\" changed`, payload);\n }\n if (payload.matches) {\n this.call(camelize(`is_${name}`), payload);\n this.dispatch(`is:${name}`, payload);\n } else {\n this.call(camelize(`not_${name}`), payload);\n this.dispatch(`not:${name}`, payload);\n }\n };\n this.observe = () => {\n Object.keys(this.mediaQueries).forEach((name => {\n const media = this.mediaQueries[name];\n const match = window.matchMedia(media);\n match.addListener(this.callback);\n this.matches.push(match);\n this.changed({\n name: name,\n media: media,\n matches: match.matches\n });\n }));\n };\n this.unobserve = () => {\n this.matches.forEach((match => match.removeListener(this.callback)));\n };\n this.controller = controller;\n this.mediaQueries = (_a = options.mediaQueries) !== null && _a !== void 0 ? _a : defaultOptions$2.mediaQueries;\n this.dispatchEvent = (_b = options.dispatchEvent) !== null && _b !== void 0 ? _b : defaultOptions$2.dispatchEvent;\n this.eventPrefix = (_c = options.eventPrefix) !== null && _c !== void 0 ? _c : defaultOptions$2.eventPrefix;\n this.debug = (_d = options.debug) !== null && _d !== void 0 ? _d : defaultOptions$2.debug;\n if (!window.matchMedia) {\n console.error(\"window.matchMedia() is not available\");\n return;\n }\n this.enhanceController();\n this.observe();\n }\n enhanceController() {\n const controllerDisconnect = this.controller.disconnect.bind(this.controller);\n const disconnect = () => {\n this.unobserve();\n controllerDisconnect();\n };\n Object.assign(this.controller, {\n disconnect: disconnect\n });\n }\n}\n\nconst useMatchMedia = (controller, options = {}) => {\n const observer = new UseMatchMedia(controller, options);\n return [ observer.observe, observer.unobserve ];\n};\n\nconst memoize = (controller, name, value) => {\n Object.defineProperty(controller, name, {\n value: value\n });\n return value;\n};\n\nconst useMemo = controller => {\n var _a;\n (_a = controller.constructor.memos) === null || _a === void 0 ? void 0 : _a.forEach((getter => {\n memoize(controller, getter, controller[getter]);\n }));\n};\n\nconst defineMetaGetter = (controller, metaName, suffix) => {\n const getterName = suffix ? `${camelize(metaName)}Meta` : camelize(metaName);\n Object.defineProperty(controller, getterName, {\n get() {\n return typeCast(metaValue(metaName));\n }\n });\n};\n\nfunction metaValue(name) {\n const element = document.head.querySelector(`meta[name=\"${name}\"]`);\n return element && element.getAttribute(\"content\");\n}\n\nfunction typeCast(value) {\n try {\n return JSON.parse(value);\n } catch (o_O) {\n return value;\n }\n}\n\nconst useMeta = (controller, options = {\n suffix: true\n}) => {\n const metaNames = controller.constructor.metaNames;\n const suffix = options.suffix;\n metaNames === null || metaNames === void 0 ? void 0 : metaNames.forEach((metaName => {\n defineMetaGetter(controller, metaName, suffix);\n }));\n Object.defineProperty(controller, \"metas\", {\n get() {\n const result = {};\n metaNames === null || metaNames === void 0 ? void 0 : metaNames.forEach((metaName => {\n const value = typeCast(metaValue(metaName));\n if (value !== undefined && value !== null) {\n result[camelize(metaName)] = value;\n }\n }));\n return result;\n }\n });\n};\n\nclass UseMutation extends StimulusUse {\n constructor(controller, options = {}) {\n super(controller, options);\n this.observe = () => {\n try {\n this.observer.observe(this.targetElement, this.options);\n } catch (error) {\n this.controller.application.handleError(error, \"At a minimum, one of childList, attributes, and/or characterData must be true\", {});\n }\n };\n this.unobserve = () => {\n this.observer.disconnect();\n };\n this.mutation = entries => {\n this.call(\"mutate\", entries);\n this.log(\"mutate\", {\n entries: entries\n });\n this.dispatch(\"mutate\", {\n entries: entries\n });\n };\n this.targetElement = (options === null || options === void 0 ? void 0 : options.element) || controller.element;\n this.controller = controller;\n this.options = options;\n this.observer = new MutationObserver(this.mutation);\n this.enhanceController();\n this.observe();\n }\n enhanceController() {\n const controllerDisconnect = this.controller.disconnect.bind(this.controller);\n const disconnect = () => {\n this.unobserve();\n controllerDisconnect();\n };\n Object.assign(this.controller, {\n disconnect: disconnect\n });\n }\n}\n\nconst useMutation = (controller, options = {}) => {\n const observer = new UseMutation(controller, options);\n return [ observer.observe, observer.unobserve ];\n};\n\nclass MutationComposableController extends Controller {}\n\nclass MutationController extends MutationComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useMutation(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nconst defaultOptions$1 = {\n dispatchEvent: true,\n eventPrefix: true\n};\n\nconst useResize = (composableController, options = {}) => {\n const controller = composableController;\n const {dispatchEvent: dispatchEvent, eventPrefix: eventPrefix} = Object.assign({}, defaultOptions$1, options);\n const targetElement = (options === null || options === void 0 ? void 0 : options.element) || controller.element;\n const callback = entries => {\n const [entry] = entries;\n method(controller, \"resize\").call(controller, entry.contentRect);\n if (dispatchEvent) {\n const eventName = composeEventName(\"resize\", controller, eventPrefix);\n const appearEvent = extendedEvent(eventName, null, {\n controller: controller,\n entry: entry\n });\n targetElement.dispatchEvent(appearEvent);\n }\n };\n const controllerDisconnect = controller.disconnect.bind(controller);\n const observer = new ResizeObserver(callback);\n const observe = () => {\n observer.observe(targetElement);\n };\n const unobserve = () => {\n observer.unobserve(targetElement);\n };\n Object.assign(controller, {\n disconnect() {\n unobserve();\n controllerDisconnect();\n }\n });\n observe();\n return [ observe, unobserve ];\n};\n\nclass ResizeComposableController extends Controller {}\n\nclass ResizeController extends ResizeComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useResize(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nclass UseTargetMutation extends StimulusUse {\n constructor(controller, options = {}) {\n super(controller, options);\n this.observe = () => {\n this.observer.observe(this.targetElement, {\n subtree: true,\n characterData: true,\n childList: true,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: [ this.targetSelector, this.scopedTargetSelector ]\n });\n };\n this.unobserve = () => {\n this.observer.disconnect();\n };\n this.mutation = entries => {\n for (const mutation of entries) {\n switch (mutation.type) {\n case \"attributes\":\n let newValue = mutation.target.getAttribute(mutation.attributeName);\n let oldValue = mutation.oldValue;\n if (mutation.attributeName === this.targetSelector || mutation.attributeName === this.scopedTargetSelector) {\n let oldTargets = this.targetsUsedByThisController(oldValue);\n let newTargets = this.targetsUsedByThisController(newValue);\n let removedTargets = oldTargets.filter((target => !newTargets.includes(target)));\n let addedTargets = newTargets.filter((target => !oldTargets.includes(target)));\n removedTargets.forEach((target => this.targetRemoved(this.stripIdentifierPrefix(target), mutation.target, \"attributeChange\")));\n addedTargets.forEach((target => this.targetAdded(this.stripIdentifierPrefix(target), mutation.target, \"attributeChange\")));\n }\n break;\n\n case \"characterData\":\n let nodule = this.findTargetInAncestry(mutation.target);\n if (nodule == null) {\n return;\n } else {\n let supportedTargets = this.targetsUsedByThisControllerFromNode(nodule);\n supportedTargets.forEach((target => {\n this.targetChanged(this.stripIdentifierPrefix(target), nodule, \"domMutation\");\n }));\n }\n break;\n\n case \"childList\":\n let {addedNodes: addedNodes, removedNodes: removedNodes} = mutation;\n addedNodes.forEach((node => this.processNodeDOMMutation(node, this.targetAdded)));\n removedNodes.forEach((node => this.processNodeDOMMutation(node, this.targetRemoved)));\n break;\n }\n }\n };\n this.controller = controller;\n this.options = options;\n this.targetElement = controller.element;\n this.identifier = controller.scope.identifier;\n this.identifierPrefix = `${this.identifier}.`;\n this.targetSelector = controller.scope.schema.targetAttribute;\n this.scopedTargetSelector = `data-${this.identifier}-target`;\n this.targets = options.targets || controller.constructor.targets;\n this.prefixedTargets = this.targets.map((target => `${this.identifierPrefix}${target}`));\n this.observer = new MutationObserver(this.mutation);\n this.enhanceController();\n this.observe();\n }\n processNodeDOMMutation(node, initialChangeModeAssumption) {\n let nodule = node;\n let change = initialChangeModeAssumption;\n let supportedTargets = [];\n if (nodule.nodeName == \"#text\" || this.targetsUsedByThisControllerFromNode(nodule).length == 0) {\n change = this.targetChanged;\n nodule = this.findTargetInAncestry(node);\n } else {\n supportedTargets = this.targetsUsedByThisControllerFromNode(nodule);\n }\n if (nodule == null) {\n return;\n } else if (supportedTargets.length == 0) {\n supportedTargets = this.targetsUsedByThisControllerFromNode(nodule);\n }\n supportedTargets.forEach((target => {\n change.call(this, this.stripIdentifierPrefix(target), nodule, \"domMutation\");\n }));\n }\n findTargetInAncestry(node) {\n let nodule = node;\n let supportedTargets = [];\n if (nodule.nodeName != \"#text\") {\n supportedTargets = this.targetsUsedByThisControllerFromNode(nodule);\n }\n while (nodule.parentNode !== null && nodule.parentNode != this.targetElement && supportedTargets.length == 0) {\n nodule = nodule.parentNode;\n if (nodule.nodeName !== \"#text\") {\n let supportedTargets = this.targetsUsedByThisControllerFromNode(nodule);\n if (supportedTargets.length > 0) {\n return nodule;\n }\n }\n }\n if (nodule.nodeName == \"#text\") {\n return null;\n }\n if (nodule.parentNode == null) {\n return null;\n }\n if (nodule.parentNode == this.targetElement) {\n if (this.targetsUsedByThisControllerFromNode(nodule).length > 0) {\n return nodule;\n }\n return null;\n }\n return null;\n }\n targetAdded(name, node, trigger) {\n let targetCallback = `${name}TargetAdded`;\n this.controller[targetCallback] && method(this.controller, targetCallback).call(this.controller, node);\n this.warn(\"`[target]TargetAdded` is deprecated. Please use the built-in `[target]TargetConnected()` function from Stimulus.\");\n this.log(\"targetAdded\", {\n target: name,\n node: node,\n trigger: trigger\n });\n }\n targetRemoved(name, node, trigger) {\n let targetCallback = `${name}TargetRemoved`;\n this.controller[targetCallback] && method(this.controller, targetCallback).call(this.controller, node);\n this.warn(\"`[target]TargetRemoved` is deprecated. Please use the built-in `[target]TargetDisconnected()` function from Stimulus.\");\n this.log(\"targetRemoved\", {\n target: name,\n node: node,\n trigger: trigger\n });\n }\n targetChanged(name, node, trigger) {\n let targetCallback = `${name}TargetChanged`;\n this.controller[targetCallback] && method(this.controller, targetCallback).call(this.controller, node);\n this.log(\"targetChanged\", {\n target: name,\n node: node,\n trigger: trigger\n });\n }\n targetsUsedByThisControllerFromNode(node) {\n if (node.nodeName == \"#text\" || node.nodeName == \"#comment\") {\n return [];\n }\n let nodeElement = node;\n return this.targetsUsedByThisController(nodeElement.getAttribute(this.scopedTargetSelector) || nodeElement.getAttribute(this.targetSelector));\n }\n targetsUsedByThisController(targetStr) {\n targetStr = targetStr || \"\";\n let targetsToCheck = this.stripIdentifierPrefix(targetStr).split(\" \");\n return this.targets.filter((n => targetsToCheck.indexOf(n) !== -1));\n }\n stripIdentifierPrefix(target) {\n return target.replace(new RegExp(this.identifierPrefix, \"g\"), \"\");\n }\n enhanceController() {\n const controllerDisconnect = this.controller.disconnect.bind(this.controller);\n const disconnect = () => {\n this.unobserve();\n controllerDisconnect();\n };\n Object.assign(this.controller, {\n disconnect: disconnect\n });\n }\n}\n\nconst useTargetMutation = (composableController, options = {}) => {\n const controller = composableController;\n const observer = new UseTargetMutation(controller, options);\n observer.warn(\"`[target]TargetAdded` and `[target]TargetRemoved` are deprecated. Please use the built-in `[target]TargetConnected()` and `[target]TargetDisconnected()` functions from Stimulus.\");\n return [ observer.observe, observer.unobserve ];\n};\n\nclass TargetMutationComposableController extends Controller {}\n\nclass TargetMutationController extends TargetMutationComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useTargetMutation(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nclass ThrottleController extends Controller {}\n\nThrottleController.throttles = [];\n\nconst defaultWait = 200;\n\nfunction throttle(func, wait = defaultWait) {\n let inThrottle;\n return function() {\n const args = arguments;\n const context = this;\n if (!inThrottle) {\n inThrottle = true;\n func.apply(context, args);\n setTimeout((() => inThrottle = false), wait);\n }\n };\n}\n\nconst useThrottle = (composableController, options = {}) => {\n var _a;\n const controller = composableController;\n const constructor = controller.constructor;\n (_a = constructor.throttles) === null || _a === void 0 ? void 0 : _a.forEach((func => {\n if (typeof func === \"string\") {\n controller[func] = throttle(controller[func], options === null || options === void 0 ? void 0 : options.wait);\n }\n if (typeof func === \"object\") {\n const {name: name, wait: wait} = func;\n if (!name) return;\n controller[name] = throttle(controller[name], wait || (options === null || options === void 0 ? void 0 : options.wait));\n }\n }));\n};\n\nconst alpineNames = {\n enterFromClass: \"enter\",\n enterActiveClass: \"enterStart\",\n enterToClass: \"enterEnd\",\n leaveFromClass: \"leave\",\n leaveActiveClass: \"leaveStart\",\n leaveToClass: \"leaveEnd\"\n};\n\nconst defaultOptions = {\n transitioned: false,\n hiddenClass: \"hidden\",\n preserveOriginalClass: true,\n removeToClasses: true\n};\n\nconst useTransition = (composableController, options = {}) => {\n var _a, _b, _c;\n const controller = composableController;\n const targetName = controller.element.dataset.transitionTarget;\n let targetFromAttribute;\n if (targetName) {\n targetFromAttribute = controller[`${targetName}Target`];\n }\n const targetElement = (options === null || options === void 0 ? void 0 : options.element) || targetFromAttribute || controller.element;\n if (!(targetElement instanceof HTMLElement || targetElement instanceof SVGElement)) return;\n const dataset = targetElement.dataset;\n const leaveAfter = parseInt(dataset.leaveAfter || \"\") || options.leaveAfter || 0;\n const {transitioned: transitioned, hiddenClass: hiddenClass, preserveOriginalClass: preserveOriginalClass, removeToClasses: removeToClasses} = Object.assign({}, defaultOptions, options);\n const controllerEnter = (_a = controller.enter) === null || _a === void 0 ? void 0 : _a.bind(controller);\n const controllerLeave = (_b = controller.leave) === null || _b === void 0 ? void 0 : _b.bind(controller);\n const controllerToggleTransition = (_c = controller.toggleTransition) === null || _c === void 0 ? void 0 : _c.bind(controller);\n async function enter(event) {\n if (controller.transitioned) return;\n controller.transitioned = true;\n controllerEnter && controllerEnter(event);\n const enterFromClasses = getAttribute(\"enterFrom\", options, dataset);\n const enterActiveClasses = getAttribute(\"enterActive\", options, dataset);\n const enterToClasses = getAttribute(\"enterTo\", options, dataset);\n const leaveToClasses = getAttribute(\"leaveTo\", options, dataset);\n if (!!hiddenClass) {\n targetElement.classList.remove(hiddenClass);\n }\n if (!removeToClasses) {\n removeClasses(targetElement, leaveToClasses);\n }\n await transition(targetElement, enterFromClasses, enterActiveClasses, enterToClasses, hiddenClass, preserveOriginalClass, removeToClasses);\n if (leaveAfter > 0) {\n setTimeout((() => {\n leave(event);\n }), leaveAfter);\n }\n }\n async function leave(event) {\n if (!controller.transitioned) return;\n controller.transitioned = false;\n controllerLeave && controllerLeave(event);\n const leaveFromClasses = getAttribute(\"leaveFrom\", options, dataset);\n const leaveActiveClasses = getAttribute(\"leaveActive\", options, dataset);\n const leaveToClasses = getAttribute(\"leaveTo\", options, dataset);\n const enterToClasses = getAttribute(\"enterTo\", options, dataset);\n if (!removeToClasses) {\n removeClasses(targetElement, enterToClasses);\n }\n await transition(targetElement, leaveFromClasses, leaveActiveClasses, leaveToClasses, hiddenClass, preserveOriginalClass, removeToClasses);\n if (!!hiddenClass) {\n targetElement.classList.add(hiddenClass);\n }\n }\n function toggleTransition(event) {\n controllerToggleTransition && controllerToggleTransition(event);\n if (controller.transitioned) {\n leave();\n } else {\n enter();\n }\n }\n async function transition(element, initialClasses, activeClasses, endClasses, hiddenClass, preserveOriginalClass, removeEndClasses) {\n const stashedClasses = [];\n if (preserveOriginalClass) {\n initialClasses.forEach((cls => element.classList.contains(cls) && cls !== hiddenClass && stashedClasses.push(cls)));\n activeClasses.forEach((cls => element.classList.contains(cls) && cls !== hiddenClass && stashedClasses.push(cls)));\n endClasses.forEach((cls => element.classList.contains(cls) && cls !== hiddenClass && stashedClasses.push(cls)));\n }\n addClasses(element, initialClasses);\n removeClasses(element, stashedClasses);\n addClasses(element, activeClasses);\n await nextAnimationFrame();\n removeClasses(element, initialClasses);\n addClasses(element, endClasses);\n await afterTransition(element);\n removeClasses(element, activeClasses);\n if (removeEndClasses) {\n removeClasses(element, endClasses);\n }\n addClasses(element, stashedClasses);\n }\n function initialState() {\n controller.transitioned = transitioned;\n if (transitioned) {\n if (!!hiddenClass) {\n targetElement.classList.remove(hiddenClass);\n }\n enter();\n } else {\n if (!!hiddenClass) {\n targetElement.classList.add(hiddenClass);\n }\n leave();\n }\n }\n function addClasses(element, classes) {\n if (classes.length > 0) {\n element.classList.add(...classes);\n }\n }\n function removeClasses(element, classes) {\n if (classes.length > 0) {\n element.classList.remove(...classes);\n }\n }\n initialState();\n Object.assign(controller, {\n enter: enter,\n leave: leave,\n toggleTransition: toggleTransition\n });\n return [ enter, leave, toggleTransition ];\n};\n\nfunction getAttribute(name, options, dataset) {\n const datasetName = `transition${name[0].toUpperCase()}${name.substr(1)}`;\n const datasetAlpineName = alpineNames[name];\n const classes = options[name] || dataset[datasetName] || dataset[datasetAlpineName] || \" \";\n return isEmpty(classes) ? [] : classes.split(\" \");\n}\n\nasync function afterTransition(element) {\n return new Promise((resolve => {\n const duration = Number(getComputedStyle(element).transitionDuration.split(\",\")[0].replace(\"s\", \"\")) * 1e3;\n setTimeout((() => {\n resolve(duration);\n }), duration);\n }));\n}\n\nasync function nextAnimationFrame() {\n return new Promise((resolve => {\n requestAnimationFrame((() => {\n requestAnimationFrame(resolve);\n }));\n }));\n}\n\nfunction isEmpty(str) {\n return str.length === 0 || !str.trim();\n}\n\nclass TransitionComposableController extends Controller {\n constructor() {\n super(...arguments);\n this.transitioned = false;\n }\n}\n\nclass TransitionController extends TransitionComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n useTransition(this, this.options);\n }));\n }\n}\n\nclass UseVisibility extends StimulusUse {\n constructor(controller, options = {}) {\n super(controller, options);\n this.observe = () => {\n this.controller.isVisible = !document.hidden;\n document.addEventListener(\"visibilitychange\", this.handleVisibilityChange);\n this.handleVisibilityChange();\n };\n this.unobserve = () => {\n document.removeEventListener(\"visibilitychange\", this.handleVisibilityChange);\n };\n this.becomesInvisible = event => {\n this.controller.isVisible = false;\n this.call(\"invisible\", event);\n this.log(\"invisible\", {\n isVisible: false\n });\n this.dispatch(\"invisible\", {\n event: event,\n isVisible: false\n });\n };\n this.becomesVisible = event => {\n this.controller.isVisible = true;\n this.call(\"visible\", event);\n this.log(\"visible\", {\n isVisible: true\n });\n this.dispatch(\"visible\", {\n event: event,\n isVisible: true\n });\n };\n this.handleVisibilityChange = event => {\n if (document.hidden) {\n this.becomesInvisible(event);\n } else {\n this.becomesVisible(event);\n }\n };\n this.controller = controller;\n this.enhanceController();\n this.observe();\n }\n enhanceController() {\n const controllerDisconnect = this.controllerDisconnect;\n const disconnect = () => {\n this.unobserve();\n controllerDisconnect();\n };\n Object.assign(this.controller, {\n disconnect: disconnect\n });\n }\n}\n\nconst useVisibility = (composableController, options = {}) => {\n const controller = composableController;\n const observer = new UseVisibility(controller, options);\n return [ observer.observe, observer.unobserve ];\n};\n\nclass VisibilityComposableController extends Controller {\n constructor() {\n super(...arguments);\n this.isVisible = false;\n }\n}\n\nclass VisibilityController extends VisibilityComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useVisibility(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nclass UseWindowFocus extends StimulusUse {\n constructor(controller, options = {}) {\n super(controller, options);\n this.observe = () => {\n if (document.hasFocus()) {\n this.becomesFocused();\n } else {\n this.becomesUnfocused();\n }\n this.interval = setInterval((() => {\n this.handleWindowFocusChange();\n }), this.intervalDuration);\n };\n this.unobserve = () => {\n clearInterval(this.interval);\n };\n this.becomesUnfocused = event => {\n this.controller.hasFocus = false;\n this.call(\"unfocus\", event);\n this.log(\"unfocus\", {\n hasFocus: false\n });\n this.dispatch(\"unfocus\", {\n event: event,\n hasFocus: false\n });\n };\n this.becomesFocused = event => {\n this.controller.hasFocus = true;\n this.call(\"focus\", event);\n this.log(\"focus\", {\n hasFocus: true\n });\n this.dispatch(\"focus\", {\n event: event,\n hasFocus: true\n });\n };\n this.handleWindowFocusChange = event => {\n if (document.hasFocus() && !this.controller.hasFocus) {\n this.becomesFocused(event);\n } else if (!document.hasFocus() && this.controller.hasFocus) {\n this.becomesUnfocused(event);\n }\n };\n this.controller = controller;\n this.intervalDuration = options.interval || 200;\n this.enhanceController();\n this.observe();\n }\n enhanceController() {\n const controllerDisconnect = this.controllerDisconnect;\n const disconnect = () => {\n this.unobserve();\n controllerDisconnect();\n };\n Object.assign(this.controller, {\n disconnect: disconnect\n });\n }\n}\n\nconst useWindowFocus = (composableController, options = {}) => {\n const controller = composableController;\n const observer = new UseWindowFocus(controller, options);\n return [ observer.observe, observer.unobserve ];\n};\n\nclass WindowFocusComposableController extends Controller {\n constructor() {\n super(...arguments);\n this.hasFocus = false;\n }\n}\n\nclass WindowFocusController extends WindowFocusComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useWindowFocus(this, this.options);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nconst useWindowResize = composableController => {\n const controller = composableController;\n const callback = event => {\n const {innerWidth: innerWidth, innerHeight: innerHeight} = window;\n const payload = {\n height: innerHeight || Infinity,\n width: innerWidth || Infinity,\n event: event\n };\n method(controller, \"windowResize\").call(controller, payload);\n };\n const controllerDisconnect = controller.disconnect.bind(controller);\n const observe = () => {\n window.addEventListener(\"resize\", callback);\n callback();\n };\n const unobserve = () => {\n window.removeEventListener(\"resize\", callback);\n };\n Object.assign(controller, {\n disconnect() {\n unobserve();\n controllerDisconnect();\n }\n });\n observe();\n return [ observe, unobserve ];\n};\n\nclass WindowResizeComposableController extends Controller {}\n\nclass WindowResizeController extends WindowResizeComposableController {\n constructor(context) {\n super(context);\n requestAnimationFrame((() => {\n const [observe, unobserve] = useWindowResize(this);\n Object.assign(this, {\n observe: observe,\n unobserve: unobserve\n });\n }));\n }\n}\n\nfunction useHotkeys() {\n throw \"[stimulus-use] Notice: The import for `useHotkeys()` has been moved from `stimulus-use` to `stimulus-use/hotkeys`. \\nPlease change the import accordingly and add `hotkey-js` as a dependency to your project. \\n\\nFor more information see: https://stimulus-use.github.io/stimulus-use/#/use-hotkeys?id=importing-the-behavior\";\n}\n\nexport { ApplicationController, ClickOutsideController, HoverController, IdleController, IntersectionController, LazyLoadController, MutationController, ResizeController, TargetMutationController, TransitionController, UseHover, UseMutation, UseTargetMutation, UseVisibility, UseWindowFocus, VisibilityController, WindowFocusController, WindowResizeController, debounce, useApplication, useClickOutside, useDebounce, useDispatch, useHotkeys, useHover, useIdle, useIntersection, useLazyLoad, useMatchMedia, useMemo, useMeta, useMutation, useResize, useTargetMutation, useThrottle, useTransition, useVisibility, useWindowFocus, useWindowResize };\n", "import { Controller } from \"@hotwired/stimulus\"\nimport { useClickOutside } from 'stimulus-use'\n\n// Connects to data-controller=\"slide\"\nexport default class extends Controller {\n static values = {\n dismissAfter: Number,\n showDelay: { type: Number, default: 200 },\n removeDelay: { type: Number, default: 1100 }\n }\n static classes = [\"show\", \"hide\"]\n\n initialize() {\n this.hide()\n }\n\n connect() {\n useClickOutside(this)\n\n setTimeout(() => {\n this.show()\n }, this.showDelayValue)\n\n // Auto dimiss if defined\n if (this.hasDismissAfterValue) {\n setTimeout(() => {\n this.close()\n }, this.dismissAfterValue)\n }\n }\n\n close() {\n this.hide()\n\n setTimeout(() => {\n this.element.remove()\n }, this.removeDelayValue)\n }\n\n AutoClose(event) {\n event.preventDefault()\n this.close()\n }\n\n show() {\n this.element.classList.add(...this.showClasses)\n this.element.classList.remove(...this.hideClasses)\n }\n\n hide() {\n this.element.classList.add(...this.hideClasses)\n this.element.classList.remove(...this.showClasses)\n }\n}\n", "export class FetchResponse {\n constructor (response) {\n this.response = response\n }\n\n get statusCode () {\n return this.response.status\n }\n\n get redirected () {\n return this.response.redirected\n }\n\n get ok () {\n return this.response.ok\n }\n\n get unauthenticated () {\n return this.statusCode === 401\n }\n\n get unprocessableEntity () {\n return this.statusCode === 422\n }\n\n get authenticationURL () {\n return this.response.headers.get('WWW-Authenticate')\n }\n\n get contentType () {\n const contentType = this.response.headers.get('Content-Type') || ''\n\n return contentType.replace(/;.*$/, '')\n }\n\n get headers () {\n return this.response.headers\n }\n\n get html () {\n if (this.contentType.match(/^(application|text)\\/(html|xhtml\\+xml)$/)) {\n return this.text\n }\n\n return Promise.reject(new Error(`Expected an HTML response but got \"${this.contentType}\" instead`))\n }\n\n get json () {\n if (this.contentType.match(/^application\\/.*json$/)) {\n return this.responseJson || (this.responseJson = this.response.json())\n }\n\n return Promise.reject(new Error(`Expected a JSON response but got \"${this.contentType}\" instead`))\n }\n\n get text () {\n return this.responseText || (this.responseText = this.response.text())\n }\n\n get isTurboStream () {\n return this.contentType.match(/^text\\/vnd\\.turbo-stream\\.html/)\n }\n\n async renderTurboStream () {\n if (this.isTurboStream) {\n if (window.Turbo) {\n await window.Turbo.renderStreamMessage(await this.text)\n } else {\n console.warn('You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js')\n }\n } else {\n return Promise.reject(new Error(`Expected a Turbo Stream response but got \"${this.contentType}\" instead`))\n }\n }\n}\n", "export class RequestInterceptor {\n static register (interceptor) {\n this.interceptor = interceptor\n }\n\n static get () {\n return this.interceptor\n }\n\n static reset () {\n this.interceptor = undefined\n }\n}\n", "export function getCookie (name) {\n const cookies = document.cookie ? document.cookie.split('; ') : []\n const prefix = `${encodeURIComponent(name)}=`\n const cookie = cookies.find(cookie => cookie.startsWith(prefix))\n\n if (cookie) {\n const value = cookie.split('=').slice(1).join('=')\n\n if (value) {\n return decodeURIComponent(value)\n }\n }\n}\n\nexport function compact (object) {\n const result = {}\n\n for (const key in object) {\n const value = object[key]\n if (value !== undefined) {\n result[key] = value\n }\n }\n\n return result\n}\n\nexport function metaContent (name) {\n const element = document.head.querySelector(`meta[name=\"${name}\"]`)\n return element && element.content\n}\n\nexport function stringEntriesFromFormData (formData) {\n return [...formData].reduce((entries, [name, value]) => {\n return entries.concat(typeof value === 'string' ? [[name, value]] : [])\n }, [])\n}\n\nexport function mergeEntries (searchParams, entries) {\n for (const [name, value] of entries) {\n if (value instanceof window.File) continue\n\n if (searchParams.has(name) && !name.includes('[]')) {\n searchParams.delete(name)\n searchParams.set(name, value)\n } else {\n searchParams.append(name, value)\n }\n }\n}\n", "import { FetchResponse } from './fetch_response'\nimport { RequestInterceptor } from './request_interceptor'\nimport { getCookie, compact, metaContent, stringEntriesFromFormData, mergeEntries } from './lib/utils'\n\nexport class FetchRequest {\n constructor (method, url, options = {}) {\n this.method = method\n this.options = options\n this.originalUrl = url.toString()\n }\n\n async perform () {\n try {\n const requestInterceptor = RequestInterceptor.get()\n if (requestInterceptor) {\n await requestInterceptor(this)\n }\n } catch (error) {\n console.error(error)\n }\n\n const response = new FetchResponse(await window.fetch(this.url, this.fetchOptions))\n\n if (response.unauthenticated && response.authenticationURL) {\n return Promise.reject(window.location.href = response.authenticationURL)\n }\n\n const responseStatusIsTurboStreamable = response.ok || response.unprocessableEntity\n\n if (responseStatusIsTurboStreamable && response.isTurboStream) {\n await response.renderTurboStream()\n }\n\n return response\n }\n\n addHeader (key, value) {\n const headers = this.additionalHeaders\n headers[key] = value\n this.options.headers = headers\n }\n\n sameHostname () {\n if (!this.originalUrl.startsWith('http:')) {\n return true\n }\n\n try {\n return new URL(this.originalUrl).hostname === window.location.hostname\n } catch (_) {\n return true\n }\n }\n\n get fetchOptions () {\n return {\n method: this.method.toUpperCase(),\n headers: this.headers,\n body: this.formattedBody,\n signal: this.signal,\n credentials: this.credentials,\n redirect: this.redirect\n }\n }\n\n get headers () {\n const baseHeaders = {\n 'X-Requested-With': 'XMLHttpRequest',\n 'Content-Type': this.contentType,\n Accept: this.accept\n }\n\n if (this.sameHostname()) {\n baseHeaders['X-CSRF-Token'] = this.csrfToken\n }\n\n return compact(\n Object.assign(baseHeaders, this.additionalHeaders)\n )\n }\n\n get csrfToken () {\n return getCookie(metaContent('csrf-param')) || metaContent('csrf-token')\n }\n\n get contentType () {\n if (this.options.contentType) {\n return this.options.contentType\n } else if (this.body == null || this.body instanceof window.FormData) {\n return undefined\n } else if (this.body instanceof window.File) {\n return this.body.type\n }\n\n return 'application/json'\n }\n\n get accept () {\n switch (this.responseKind) {\n case 'html':\n return 'text/html, application/xhtml+xml'\n case 'turbo-stream':\n return 'text/vnd.turbo-stream.html, text/html, application/xhtml+xml'\n case 'json':\n return 'application/json, application/vnd.api+json'\n default:\n return '*/*'\n }\n }\n\n get body () {\n return this.options.body\n }\n\n get query () {\n const originalQuery = (this.originalUrl.split('?')[1] || '').split('#')[0]\n const params = new URLSearchParams(originalQuery)\n\n let requestQuery = this.options.query\n if (requestQuery instanceof window.FormData) {\n requestQuery = stringEntriesFromFormData(requestQuery)\n } else if (requestQuery instanceof window.URLSearchParams) {\n requestQuery = requestQuery.entries()\n } else {\n requestQuery = Object.entries(requestQuery || {})\n }\n\n mergeEntries(params, requestQuery)\n\n const query = params.toString()\n return (query.length > 0 ? `?${query}` : '')\n }\n\n get url () {\n return (this.originalUrl.split('?')[0]).split('#')[0] + this.query\n }\n\n get responseKind () {\n return this.options.responseKind || 'html'\n }\n\n get signal () {\n return this.options.signal\n }\n\n get redirect () {\n return this.options.redirect || 'follow'\n }\n\n get credentials () {\n return this.options.credentials || 'same-origin'\n }\n\n get additionalHeaders () {\n return this.options.headers || {}\n }\n\n get formattedBody () {\n const bodyIsAString = Object.prototype.toString.call(this.body) === '[object String]'\n const contentTypeIsJson = this.headers['Content-Type'] === 'application/json'\n\n if (contentTypeIsJson && !bodyIsAString) {\n return JSON.stringify(this.body)\n }\n\n return this.body\n }\n}\n", "import { FetchRequest } from './fetch_request'\n\nasync function get (url, options) {\n const request = new FetchRequest('get', url, options)\n return request.perform()\n}\n\nasync function post (url, options) {\n const request = new FetchRequest('post', url, options)\n return request.perform()\n}\n\nasync function put (url, options) {\n const request = new FetchRequest('put', url, options)\n return request.perform()\n}\n\nasync function patch (url, options) {\n const request = new FetchRequest('patch', url, options)\n return request.perform()\n}\n\nasync function destroy (url, options) {\n const request = new FetchRequest('delete', url, options)\n return request.perform()\n}\n\nexport { get, post, put, patch, destroy }\n", "/**!\n * Sortable 1.15.6\n * @author\tRubaXa \n * @author\towenm \n * @license MIT\n */\nfunction ownKeys(object, enumerableOnly) {\n var keys = Object.keys(object);\n if (Object.getOwnPropertySymbols) {\n var symbols = Object.getOwnPropertySymbols(object);\n if (enumerableOnly) {\n symbols = symbols.filter(function (sym) {\n return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n });\n }\n keys.push.apply(keys, symbols);\n }\n return keys;\n}\nfunction _objectSpread2(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i] != null ? arguments[i] : {};\n if (i % 2) {\n ownKeys(Object(source), true).forEach(function (key) {\n _defineProperty(target, key, source[key]);\n });\n } else if (Object.getOwnPropertyDescriptors) {\n Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));\n } else {\n ownKeys(Object(source)).forEach(function (key) {\n Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n });\n }\n }\n return target;\n}\nfunction _typeof(obj) {\n \"@babel/helpers - typeof\";\n\n if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n _typeof = function (obj) {\n return typeof obj;\n };\n } else {\n _typeof = function (obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n };\n }\n return _typeof(obj);\n}\nfunction _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n return obj;\n}\nfunction _extends() {\n _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n return target;\n };\n return _extends.apply(this, arguments);\n}\nfunction _objectWithoutPropertiesLoose(source, excluded) {\n if (source == null) return {};\n var target = {};\n var sourceKeys = Object.keys(source);\n var key, i;\n for (i = 0; i < sourceKeys.length; i++) {\n key = sourceKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n target[key] = source[key];\n }\n return target;\n}\nfunction _objectWithoutProperties(source, excluded) {\n if (source == null) return {};\n var target = _objectWithoutPropertiesLoose(source, excluded);\n var key, i;\n if (Object.getOwnPropertySymbols) {\n var sourceSymbolKeys = Object.getOwnPropertySymbols(source);\n for (i = 0; i < sourceSymbolKeys.length; i++) {\n key = sourceSymbolKeys[i];\n if (excluded.indexOf(key) >= 0) continue;\n if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;\n target[key] = source[key];\n }\n }\n return target;\n}\nfunction _toConsumableArray(arr) {\n return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();\n}\nfunction _arrayWithoutHoles(arr) {\n if (Array.isArray(arr)) return _arrayLikeToArray(arr);\n}\nfunction _iterableToArray(iter) {\n if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter);\n}\nfunction _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n}\nfunction _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n return arr2;\n}\nfunction _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\n\nvar version = \"1.15.6\";\n\nfunction userAgent(pattern) {\n if (typeof window !== 'undefined' && window.navigator) {\n return !! /*@__PURE__*/navigator.userAgent.match(pattern);\n }\n}\nvar IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\\.|msie|iemobile|Windows Phone)/i);\nvar Edge = userAgent(/Edge/i);\nvar FireFox = userAgent(/firefox/i);\nvar Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);\nvar IOS = userAgent(/iP(ad|od|hone)/i);\nvar ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);\n\nvar captureMode = {\n capture: false,\n passive: false\n};\nfunction on(el, event, fn) {\n el.addEventListener(event, fn, !IE11OrLess && captureMode);\n}\nfunction off(el, event, fn) {\n el.removeEventListener(event, fn, !IE11OrLess && captureMode);\n}\nfunction matches( /**HTMLElement*/el, /**String*/selector) {\n if (!selector) return;\n selector[0] === '>' && (selector = selector.substring(1));\n if (el) {\n try {\n if (el.matches) {\n return el.matches(selector);\n } else if (el.msMatchesSelector) {\n return el.msMatchesSelector(selector);\n } else if (el.webkitMatchesSelector) {\n return el.webkitMatchesSelector(selector);\n }\n } catch (_) {\n return false;\n }\n }\n return false;\n}\nfunction getParentOrHost(el) {\n return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;\n}\nfunction closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {\n if (el) {\n ctx = ctx || document;\n do {\n if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {\n return el;\n }\n if (el === ctx) break;\n /* jshint boss:true */\n } while (el = getParentOrHost(el));\n }\n return null;\n}\nvar R_SPACE = /\\s+/g;\nfunction toggleClass(el, name, state) {\n if (el && name) {\n if (el.classList) {\n el.classList[state ? 'add' : 'remove'](name);\n } else {\n var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');\n el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');\n }\n }\n}\nfunction css(el, prop, val) {\n var style = el && el.style;\n if (style) {\n if (val === void 0) {\n if (document.defaultView && document.defaultView.getComputedStyle) {\n val = document.defaultView.getComputedStyle(el, '');\n } else if (el.currentStyle) {\n val = el.currentStyle;\n }\n return prop === void 0 ? val : val[prop];\n } else {\n if (!(prop in style) && prop.indexOf('webkit') === -1) {\n prop = '-webkit-' + prop;\n }\n style[prop] = val + (typeof val === 'string' ? '' : 'px');\n }\n }\n}\nfunction matrix(el, selfOnly) {\n var appliedTransforms = '';\n if (typeof el === 'string') {\n appliedTransforms = el;\n } else {\n do {\n var transform = css(el, 'transform');\n if (transform && transform !== 'none') {\n appliedTransforms = transform + ' ' + appliedTransforms;\n }\n /* jshint boss:true */\n } while (!selfOnly && (el = el.parentNode));\n }\n var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;\n /*jshint -W056 */\n return matrixFn && new matrixFn(appliedTransforms);\n}\nfunction find(ctx, tagName, iterator) {\n if (ctx) {\n var list = ctx.getElementsByTagName(tagName),\n i = 0,\n n = list.length;\n if (iterator) {\n for (; i < n; i++) {\n iterator(list[i], i);\n }\n }\n return list;\n }\n return [];\n}\nfunction getWindowScrollingElement() {\n var scrollingElement = document.scrollingElement;\n if (scrollingElement) {\n return scrollingElement;\n } else {\n return document.documentElement;\n }\n}\n\n/**\r\n * Returns the \"bounding client rect\" of given element\r\n * @param {HTMLElement} el The element whose boundingClientRect is wanted\r\n * @param {[Boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container\r\n * @param {[Boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr\r\n * @param {[Boolean]} undoScale Whether the container's scale() should be undone\r\n * @param {[HTMLElement]} container The parent the element will be placed in\r\n * @return {Object} The boundingClientRect of el, with specified adjustments\r\n */\nfunction getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {\n if (!el.getBoundingClientRect && el !== window) return;\n var elRect, top, left, bottom, right, height, width;\n if (el !== window && el.parentNode && el !== getWindowScrollingElement()) {\n elRect = el.getBoundingClientRect();\n top = elRect.top;\n left = elRect.left;\n bottom = elRect.bottom;\n right = elRect.right;\n height = elRect.height;\n width = elRect.width;\n } else {\n top = 0;\n left = 0;\n bottom = window.innerHeight;\n right = window.innerWidth;\n height = window.innerHeight;\n width = window.innerWidth;\n }\n if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {\n // Adjust for translate()\n container = container || el.parentNode;\n\n // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)\n // Not needed on <= IE11\n if (!IE11OrLess) {\n do {\n if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {\n var containerRect = container.getBoundingClientRect();\n\n // Set relative to edges of padding box of container\n top -= containerRect.top + parseInt(css(container, 'border-top-width'));\n left -= containerRect.left + parseInt(css(container, 'border-left-width'));\n bottom = top + elRect.height;\n right = left + elRect.width;\n break;\n }\n /* jshint boss:true */\n } while (container = container.parentNode);\n }\n }\n if (undoScale && el !== window) {\n // Adjust for scale()\n var elMatrix = matrix(container || el),\n scaleX = elMatrix && elMatrix.a,\n scaleY = elMatrix && elMatrix.d;\n if (elMatrix) {\n top /= scaleY;\n left /= scaleX;\n width /= scaleX;\n height /= scaleY;\n bottom = top + height;\n right = left + width;\n }\n }\n return {\n top: top,\n left: left,\n bottom: bottom,\n right: right,\n width: width,\n height: height\n };\n}\n\n/**\r\n * Checks if a side of an element is scrolled past a side of its parents\r\n * @param {HTMLElement} el The element who's side being scrolled out of view is in question\r\n * @param {String} elSide Side of the element in question ('top', 'left', 'right', 'bottom')\r\n * @param {String} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom')\r\n * @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element\r\n */\nfunction isScrolledPast(el, elSide, parentSide) {\n var parent = getParentAutoScrollElement(el, true),\n elSideVal = getRect(el)[elSide];\n\n /* jshint boss:true */\n while (parent) {\n var parentSideVal = getRect(parent)[parentSide],\n visible = void 0;\n if (parentSide === 'top' || parentSide === 'left') {\n visible = elSideVal >= parentSideVal;\n } else {\n visible = elSideVal <= parentSideVal;\n }\n if (!visible) return parent;\n if (parent === getWindowScrollingElement()) break;\n parent = getParentAutoScrollElement(parent, false);\n }\n return false;\n}\n\n/**\r\n * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)\r\n * and non-draggable elements\r\n * @param {HTMLElement} el The parent element\r\n * @param {Number} childNum The index of the child\r\n * @param {Object} options Parent Sortable's options\r\n * @return {HTMLElement} The child at index childNum, or null if not found\r\n */\nfunction getChild(el, childNum, options, includeDragEl) {\n var currentChild = 0,\n i = 0,\n children = el.children;\n while (i < children.length) {\n if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) {\n if (currentChild === childNum) {\n return children[i];\n }\n currentChild++;\n }\n i++;\n }\n return null;\n}\n\n/**\r\n * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)\r\n * @param {HTMLElement} el Parent element\r\n * @param {selector} selector Any other elements that should be ignored\r\n * @return {HTMLElement} The last child, ignoring ghostEl\r\n */\nfunction lastChild(el, selector) {\n var last = el.lastElementChild;\n while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {\n last = last.previousElementSibling;\n }\n return last || null;\n}\n\n/**\r\n * Returns the index of an element within its parent for a selected set of\r\n * elements\r\n * @param {HTMLElement} el\r\n * @param {selector} selector\r\n * @return {number}\r\n */\nfunction index(el, selector) {\n var index = 0;\n if (!el || !el.parentNode) {\n return -1;\n }\n\n /* jshint boss:true */\n while (el = el.previousElementSibling) {\n if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {\n index++;\n }\n }\n return index;\n}\n\n/**\r\n * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.\r\n * The value is returned in real pixels.\r\n * @param {HTMLElement} el\r\n * @return {Array} Offsets in the format of [left, top]\r\n */\nfunction getRelativeScrollOffset(el) {\n var offsetLeft = 0,\n offsetTop = 0,\n winScroller = getWindowScrollingElement();\n if (el) {\n do {\n var elMatrix = matrix(el),\n scaleX = elMatrix.a,\n scaleY = elMatrix.d;\n offsetLeft += el.scrollLeft * scaleX;\n offsetTop += el.scrollTop * scaleY;\n } while (el !== winScroller && (el = el.parentNode));\n }\n return [offsetLeft, offsetTop];\n}\n\n/**\r\n * Returns the index of the object within the given array\r\n * @param {Array} arr Array that may or may not hold the object\r\n * @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find\r\n * @return {Number} The index of the object in the array, or -1\r\n */\nfunction indexOfObject(arr, obj) {\n for (var i in arr) {\n if (!arr.hasOwnProperty(i)) continue;\n for (var key in obj) {\n if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);\n }\n }\n return -1;\n}\nfunction getParentAutoScrollElement(el, includeSelf) {\n // skip to window\n if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();\n var elem = el;\n var gotSelf = false;\n do {\n // we don't need to get elem css if it isn't even overflowing in the first place (performance)\n if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {\n var elemCSS = css(elem);\n if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {\n if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();\n if (gotSelf || includeSelf) return elem;\n gotSelf = true;\n }\n }\n /* jshint boss:true */\n } while (elem = elem.parentNode);\n return getWindowScrollingElement();\n}\nfunction extend(dst, src) {\n if (dst && src) {\n for (var key in src) {\n if (src.hasOwnProperty(key)) {\n dst[key] = src[key];\n }\n }\n }\n return dst;\n}\nfunction isRectEqual(rect1, rect2) {\n return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);\n}\nvar _throttleTimeout;\nfunction throttle(callback, ms) {\n return function () {\n if (!_throttleTimeout) {\n var args = arguments,\n _this = this;\n if (args.length === 1) {\n callback.call(_this, args[0]);\n } else {\n callback.apply(_this, args);\n }\n _throttleTimeout = setTimeout(function () {\n _throttleTimeout = void 0;\n }, ms);\n }\n };\n}\nfunction cancelThrottle() {\n clearTimeout(_throttleTimeout);\n _throttleTimeout = void 0;\n}\nfunction scrollBy(el, x, y) {\n el.scrollLeft += x;\n el.scrollTop += y;\n}\nfunction clone(el) {\n var Polymer = window.Polymer;\n var $ = window.jQuery || window.Zepto;\n if (Polymer && Polymer.dom) {\n return Polymer.dom(el).cloneNode(true);\n } else if ($) {\n return $(el).clone(true)[0];\n } else {\n return el.cloneNode(true);\n }\n}\nfunction setRect(el, rect) {\n css(el, 'position', 'absolute');\n css(el, 'top', rect.top);\n css(el, 'left', rect.left);\n css(el, 'width', rect.width);\n css(el, 'height', rect.height);\n}\nfunction unsetRect(el) {\n css(el, 'position', '');\n css(el, 'top', '');\n css(el, 'left', '');\n css(el, 'width', '');\n css(el, 'height', '');\n}\nfunction getChildContainingRectFromElement(container, options, ghostEl) {\n var rect = {};\n Array.from(container.children).forEach(function (child) {\n var _rect$left, _rect$top, _rect$right, _rect$bottom;\n if (!closest(child, options.draggable, container, false) || child.animated || child === ghostEl) return;\n var childRect = getRect(child);\n rect.left = Math.min((_rect$left = rect.left) !== null && _rect$left !== void 0 ? _rect$left : Infinity, childRect.left);\n rect.top = Math.min((_rect$top = rect.top) !== null && _rect$top !== void 0 ? _rect$top : Infinity, childRect.top);\n rect.right = Math.max((_rect$right = rect.right) !== null && _rect$right !== void 0 ? _rect$right : -Infinity, childRect.right);\n rect.bottom = Math.max((_rect$bottom = rect.bottom) !== null && _rect$bottom !== void 0 ? _rect$bottom : -Infinity, childRect.bottom);\n });\n rect.width = rect.right - rect.left;\n rect.height = rect.bottom - rect.top;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\nvar expando = 'Sortable' + new Date().getTime();\n\nfunction AnimationStateManager() {\n var animationStates = [],\n animationCallbackId;\n return {\n captureAnimationState: function captureAnimationState() {\n animationStates = [];\n if (!this.options.animation) return;\n var children = [].slice.call(this.el.children);\n children.forEach(function (child) {\n if (css(child, 'display') === 'none' || child === Sortable.ghost) return;\n animationStates.push({\n target: child,\n rect: getRect(child)\n });\n var fromRect = _objectSpread2({}, animationStates[animationStates.length - 1].rect);\n\n // If animating: compensate for current animation\n if (child.thisAnimationDuration) {\n var childMatrix = matrix(child, true);\n if (childMatrix) {\n fromRect.top -= childMatrix.f;\n fromRect.left -= childMatrix.e;\n }\n }\n child.fromRect = fromRect;\n });\n },\n addAnimationState: function addAnimationState(state) {\n animationStates.push(state);\n },\n removeAnimationState: function removeAnimationState(target) {\n animationStates.splice(indexOfObject(animationStates, {\n target: target\n }), 1);\n },\n animateAll: function animateAll(callback) {\n var _this = this;\n if (!this.options.animation) {\n clearTimeout(animationCallbackId);\n if (typeof callback === 'function') callback();\n return;\n }\n var animating = false,\n animationTime = 0;\n animationStates.forEach(function (state) {\n var time = 0,\n target = state.target,\n fromRect = target.fromRect,\n toRect = getRect(target),\n prevFromRect = target.prevFromRect,\n prevToRect = target.prevToRect,\n animatingRect = state.rect,\n targetMatrix = matrix(target, true);\n if (targetMatrix) {\n // Compensate for current animation\n toRect.top -= targetMatrix.f;\n toRect.left -= targetMatrix.e;\n }\n target.toRect = toRect;\n if (target.thisAnimationDuration) {\n // Could also check if animatingRect is between fromRect and toRect\n if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) &&\n // Make sure animatingRect is on line between toRect & fromRect\n (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {\n // If returning to same place as started from animation and on same axis\n time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);\n }\n }\n\n // if fromRect != toRect: animate\n if (!isRectEqual(toRect, fromRect)) {\n target.prevFromRect = fromRect;\n target.prevToRect = toRect;\n if (!time) {\n time = _this.options.animation;\n }\n _this.animate(target, animatingRect, toRect, time);\n }\n if (time) {\n animating = true;\n animationTime = Math.max(animationTime, time);\n clearTimeout(target.animationResetTimer);\n target.animationResetTimer = setTimeout(function () {\n target.animationTime = 0;\n target.prevFromRect = null;\n target.fromRect = null;\n target.prevToRect = null;\n target.thisAnimationDuration = null;\n }, time);\n target.thisAnimationDuration = time;\n }\n });\n clearTimeout(animationCallbackId);\n if (!animating) {\n if (typeof callback === 'function') callback();\n } else {\n animationCallbackId = setTimeout(function () {\n if (typeof callback === 'function') callback();\n }, animationTime);\n }\n animationStates = [];\n },\n animate: function animate(target, currentRect, toRect, duration) {\n if (duration) {\n css(target, 'transition', '');\n css(target, 'transform', '');\n var elMatrix = matrix(this.el),\n scaleX = elMatrix && elMatrix.a,\n scaleY = elMatrix && elMatrix.d,\n translateX = (currentRect.left - toRect.left) / (scaleX || 1),\n translateY = (currentRect.top - toRect.top) / (scaleY || 1);\n target.animatingX = !!translateX;\n target.animatingY = !!translateY;\n css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');\n this.forRepaintDummy = repaint(target); // repaint\n\n css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));\n css(target, 'transform', 'translate3d(0,0,0)');\n typeof target.animated === 'number' && clearTimeout(target.animated);\n target.animated = setTimeout(function () {\n css(target, 'transition', '');\n css(target, 'transform', '');\n target.animated = false;\n target.animatingX = false;\n target.animatingY = false;\n }, duration);\n }\n }\n };\n}\nfunction repaint(target) {\n return target.offsetWidth;\n}\nfunction calculateRealTime(animatingRect, fromRect, toRect, options) {\n return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;\n}\n\nvar plugins = [];\nvar defaults = {\n initializeByDefault: true\n};\nvar PluginManager = {\n mount: function mount(plugin) {\n // Set default static properties\n for (var option in defaults) {\n if (defaults.hasOwnProperty(option) && !(option in plugin)) {\n plugin[option] = defaults[option];\n }\n }\n plugins.forEach(function (p) {\n if (p.pluginName === plugin.pluginName) {\n throw \"Sortable: Cannot mount plugin \".concat(plugin.pluginName, \" more than once\");\n }\n });\n plugins.push(plugin);\n },\n pluginEvent: function pluginEvent(eventName, sortable, evt) {\n var _this = this;\n this.eventCanceled = false;\n evt.cancel = function () {\n _this.eventCanceled = true;\n };\n var eventNameGlobal = eventName + 'Global';\n plugins.forEach(function (plugin) {\n if (!sortable[plugin.pluginName]) return;\n // Fire global events if it exists in this sortable\n if (sortable[plugin.pluginName][eventNameGlobal]) {\n sortable[plugin.pluginName][eventNameGlobal](_objectSpread2({\n sortable: sortable\n }, evt));\n }\n\n // Only fire plugin event if plugin is enabled in this sortable,\n // and plugin has event defined\n if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {\n sortable[plugin.pluginName][eventName](_objectSpread2({\n sortable: sortable\n }, evt));\n }\n });\n },\n initializePlugins: function initializePlugins(sortable, el, defaults, options) {\n plugins.forEach(function (plugin) {\n var pluginName = plugin.pluginName;\n if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;\n var initialized = new plugin(sortable, el, sortable.options);\n initialized.sortable = sortable;\n initialized.options = sortable.options;\n sortable[pluginName] = initialized;\n\n // Add default options from plugin\n _extends(defaults, initialized.defaults);\n });\n for (var option in sortable.options) {\n if (!sortable.options.hasOwnProperty(option)) continue;\n var modified = this.modifyOption(sortable, option, sortable.options[option]);\n if (typeof modified !== 'undefined') {\n sortable.options[option] = modified;\n }\n }\n },\n getEventProperties: function getEventProperties(name, sortable) {\n var eventProperties = {};\n plugins.forEach(function (plugin) {\n if (typeof plugin.eventProperties !== 'function') return;\n _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));\n });\n return eventProperties;\n },\n modifyOption: function modifyOption(sortable, name, value) {\n var modifiedValue;\n plugins.forEach(function (plugin) {\n // Plugin must exist on the Sortable\n if (!sortable[plugin.pluginName]) return;\n\n // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin\n if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {\n modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);\n }\n });\n return modifiedValue;\n }\n};\n\nfunction dispatchEvent(_ref) {\n var sortable = _ref.sortable,\n rootEl = _ref.rootEl,\n name = _ref.name,\n targetEl = _ref.targetEl,\n cloneEl = _ref.cloneEl,\n toEl = _ref.toEl,\n fromEl = _ref.fromEl,\n oldIndex = _ref.oldIndex,\n newIndex = _ref.newIndex,\n oldDraggableIndex = _ref.oldDraggableIndex,\n newDraggableIndex = _ref.newDraggableIndex,\n originalEvent = _ref.originalEvent,\n putSortable = _ref.putSortable,\n extraEventProperties = _ref.extraEventProperties;\n sortable = sortable || rootEl && rootEl[expando];\n if (!sortable) return;\n var evt,\n options = sortable.options,\n onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);\n // Support for new CustomEvent feature\n if (window.CustomEvent && !IE11OrLess && !Edge) {\n evt = new CustomEvent(name, {\n bubbles: true,\n cancelable: true\n });\n } else {\n evt = document.createEvent('Event');\n evt.initEvent(name, true, true);\n }\n evt.to = toEl || rootEl;\n evt.from = fromEl || rootEl;\n evt.item = targetEl || rootEl;\n evt.clone = cloneEl;\n evt.oldIndex = oldIndex;\n evt.newIndex = newIndex;\n evt.oldDraggableIndex = oldDraggableIndex;\n evt.newDraggableIndex = newDraggableIndex;\n evt.originalEvent = originalEvent;\n evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;\n var allEventProperties = _objectSpread2(_objectSpread2({}, extraEventProperties), PluginManager.getEventProperties(name, sortable));\n for (var option in allEventProperties) {\n evt[option] = allEventProperties[option];\n }\n if (rootEl) {\n rootEl.dispatchEvent(evt);\n }\n if (options[onName]) {\n options[onName].call(sortable, evt);\n }\n}\n\nvar _excluded = [\"evt\"];\nvar pluginEvent = function pluginEvent(eventName, sortable) {\n var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},\n originalEvent = _ref.evt,\n data = _objectWithoutProperties(_ref, _excluded);\n PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread2({\n dragEl: dragEl,\n parentEl: parentEl,\n ghostEl: ghostEl,\n rootEl: rootEl,\n nextEl: nextEl,\n lastDownEl: lastDownEl,\n cloneEl: cloneEl,\n cloneHidden: cloneHidden,\n dragStarted: moved,\n putSortable: putSortable,\n activeSortable: Sortable.active,\n originalEvent: originalEvent,\n oldIndex: oldIndex,\n oldDraggableIndex: oldDraggableIndex,\n newIndex: newIndex,\n newDraggableIndex: newDraggableIndex,\n hideGhostForTarget: _hideGhostForTarget,\n unhideGhostForTarget: _unhideGhostForTarget,\n cloneNowHidden: function cloneNowHidden() {\n cloneHidden = true;\n },\n cloneNowShown: function cloneNowShown() {\n cloneHidden = false;\n },\n dispatchSortableEvent: function dispatchSortableEvent(name) {\n _dispatchEvent({\n sortable: sortable,\n name: name,\n originalEvent: originalEvent\n });\n }\n }, data));\n};\nfunction _dispatchEvent(info) {\n dispatchEvent(_objectSpread2({\n putSortable: putSortable,\n cloneEl: cloneEl,\n targetEl: dragEl,\n rootEl: rootEl,\n oldIndex: oldIndex,\n oldDraggableIndex: oldDraggableIndex,\n newIndex: newIndex,\n newDraggableIndex: newDraggableIndex\n }, info));\n}\nvar dragEl,\n parentEl,\n ghostEl,\n rootEl,\n nextEl,\n lastDownEl,\n cloneEl,\n cloneHidden,\n oldIndex,\n newIndex,\n oldDraggableIndex,\n newDraggableIndex,\n activeGroup,\n putSortable,\n awaitingDragStarted = false,\n ignoreNextClick = false,\n sortables = [],\n tapEvt,\n touchEvt,\n lastDx,\n lastDy,\n tapDistanceLeft,\n tapDistanceTop,\n moved,\n lastTarget,\n lastDirection,\n pastFirstInvertThresh = false,\n isCircumstantialInvert = false,\n targetMoveDistance,\n // For positioning ghost absolutely\n ghostRelativeParent,\n ghostRelativeParentInitialScroll = [],\n // (left, top)\n\n _silent = false,\n savedInputChecked = [];\n\n/** @const */\nvar documentExists = typeof document !== 'undefined',\n PositionGhostAbsolutely = IOS,\n CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',\n // This will not pass for IE9, because IE9 DnD only works on anchors\n supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),\n supportCssPointerEvents = function () {\n if (!documentExists) return;\n // false when <= IE11\n if (IE11OrLess) {\n return false;\n }\n var el = document.createElement('x');\n el.style.cssText = 'pointer-events:auto';\n return el.style.pointerEvents === 'auto';\n }(),\n _detectDirection = function _detectDirection(el, options) {\n var elCSS = css(el),\n elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),\n child1 = getChild(el, 0, options),\n child2 = getChild(el, 1, options),\n firstChildCSS = child1 && css(child1),\n secondChildCSS = child2 && css(child2),\n firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,\n secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;\n if (elCSS.display === 'flex') {\n return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';\n }\n if (elCSS.display === 'grid') {\n return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';\n }\n if (child1 && firstChildCSS[\"float\"] && firstChildCSS[\"float\"] !== 'none') {\n var touchingSideChild2 = firstChildCSS[\"float\"] === 'left' ? 'left' : 'right';\n return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';\n }\n return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';\n },\n _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {\n var dragElS1Opp = vertical ? dragRect.left : dragRect.top,\n dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,\n dragElOppLength = vertical ? dragRect.width : dragRect.height,\n targetS1Opp = vertical ? targetRect.left : targetRect.top,\n targetS2Opp = vertical ? targetRect.right : targetRect.bottom,\n targetOppLength = vertical ? targetRect.width : targetRect.height;\n return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;\n },\n /**\r\n * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.\r\n * @param {Number} x X position\r\n * @param {Number} y Y position\r\n * @return {HTMLElement} Element of the first found nearest Sortable\r\n */\n _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {\n var ret;\n sortables.some(function (sortable) {\n var threshold = sortable[expando].options.emptyInsertThreshold;\n if (!threshold || lastChild(sortable)) return;\n var rect = getRect(sortable),\n insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,\n insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;\n if (insideHorizontally && insideVertically) {\n return ret = sortable;\n }\n });\n return ret;\n },\n _prepareGroup = function _prepareGroup(options) {\n function toFn(value, pull) {\n return function (to, from, dragEl, evt) {\n var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;\n if (value == null && (pull || sameGroup)) {\n // Default pull value\n // Default pull and put value if same group\n return true;\n } else if (value == null || value === false) {\n return false;\n } else if (pull && value === 'clone') {\n return value;\n } else if (typeof value === 'function') {\n return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);\n } else {\n var otherGroup = (pull ? to : from).options.group.name;\n return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;\n }\n };\n }\n var group = {};\n var originalGroup = options.group;\n if (!originalGroup || _typeof(originalGroup) != 'object') {\n originalGroup = {\n name: originalGroup\n };\n }\n group.name = originalGroup.name;\n group.checkPull = toFn(originalGroup.pull, true);\n group.checkPut = toFn(originalGroup.put);\n group.revertClone = originalGroup.revertClone;\n options.group = group;\n },\n _hideGhostForTarget = function _hideGhostForTarget() {\n if (!supportCssPointerEvents && ghostEl) {\n css(ghostEl, 'display', 'none');\n }\n },\n _unhideGhostForTarget = function _unhideGhostForTarget() {\n if (!supportCssPointerEvents && ghostEl) {\n css(ghostEl, 'display', '');\n }\n };\n\n// #1184 fix - Prevent click event on fallback if dragged but item not changed position\nif (documentExists && !ChromeForAndroid) {\n document.addEventListener('click', function (evt) {\n if (ignoreNextClick) {\n evt.preventDefault();\n evt.stopPropagation && evt.stopPropagation();\n evt.stopImmediatePropagation && evt.stopImmediatePropagation();\n ignoreNextClick = false;\n return false;\n }\n }, true);\n}\nvar nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {\n if (dragEl) {\n evt = evt.touches ? evt.touches[0] : evt;\n var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);\n if (nearest) {\n // Create imitation event\n var event = {};\n for (var i in evt) {\n if (evt.hasOwnProperty(i)) {\n event[i] = evt[i];\n }\n }\n event.target = event.rootEl = nearest;\n event.preventDefault = void 0;\n event.stopPropagation = void 0;\n nearest[expando]._onDragOver(event);\n }\n }\n};\nvar _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {\n if (dragEl) {\n dragEl.parentNode[expando]._isOutsideThisEl(evt.target);\n }\n};\n\n/**\r\n * @class Sortable\r\n * @param {HTMLElement} el\r\n * @param {Object} [options]\r\n */\nfunction Sortable(el, options) {\n if (!(el && el.nodeType && el.nodeType === 1)) {\n throw \"Sortable: `el` must be an HTMLElement, not \".concat({}.toString.call(el));\n }\n this.el = el; // root element\n this.options = options = _extends({}, options);\n\n // Export instance\n el[expando] = this;\n var defaults = {\n group: null,\n sort: true,\n disabled: false,\n store: null,\n handle: null,\n draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',\n swapThreshold: 1,\n // percentage; 0 <= x <= 1\n invertSwap: false,\n // invert always\n invertedSwapThreshold: null,\n // will be set to same as swapThreshold if default\n removeCloneOnHide: true,\n direction: function direction() {\n return _detectDirection(el, this.options);\n },\n ghostClass: 'sortable-ghost',\n chosenClass: 'sortable-chosen',\n dragClass: 'sortable-drag',\n ignore: 'a, img',\n filter: null,\n preventOnFilter: true,\n animation: 0,\n easing: null,\n setData: function setData(dataTransfer, dragEl) {\n dataTransfer.setData('Text', dragEl.textContent);\n },\n dropBubble: false,\n dragoverBubble: false,\n dataIdAttr: 'data-id',\n delay: 0,\n delayOnTouchOnly: false,\n touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,\n forceFallback: false,\n fallbackClass: 'sortable-fallback',\n fallbackOnBody: false,\n fallbackTolerance: 0,\n fallbackOffset: {\n x: 0,\n y: 0\n },\n // Disabled on Safari: #1571; Enabled on Safari IOS: #2244\n supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && (!Safari || IOS),\n emptyInsertThreshold: 5\n };\n PluginManager.initializePlugins(this, el, defaults);\n\n // Set default options\n for (var name in defaults) {\n !(name in options) && (options[name] = defaults[name]);\n }\n _prepareGroup(options);\n\n // Bind all private methods\n for (var fn in this) {\n if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {\n this[fn] = this[fn].bind(this);\n }\n }\n\n // Setup drag mode\n this.nativeDraggable = options.forceFallback ? false : supportDraggable;\n if (this.nativeDraggable) {\n // Touch start threshold cannot be greater than the native dragstart threshold\n this.options.touchStartThreshold = 1;\n }\n\n // Bind events\n if (options.supportPointer) {\n on(el, 'pointerdown', this._onTapStart);\n } else {\n on(el, 'mousedown', this._onTapStart);\n on(el, 'touchstart', this._onTapStart);\n }\n if (this.nativeDraggable) {\n on(el, 'dragover', this);\n on(el, 'dragenter', this);\n }\n sortables.push(this.el);\n\n // Restore sorting\n options.store && options.store.get && this.sort(options.store.get(this) || []);\n\n // Add animation state manager\n _extends(this, AnimationStateManager());\n}\nSortable.prototype = /** @lends Sortable.prototype */{\n constructor: Sortable,\n _isOutsideThisEl: function _isOutsideThisEl(target) {\n if (!this.el.contains(target) && target !== this.el) {\n lastTarget = null;\n }\n },\n _getDirection: function _getDirection(evt, target) {\n return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;\n },\n _onTapStart: function _onTapStart( /** Event|TouchEvent */evt) {\n if (!evt.cancelable) return;\n var _this = this,\n el = this.el,\n options = this.options,\n preventOnFilter = options.preventOnFilter,\n type = evt.type,\n touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,\n target = (touch || evt).target,\n originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,\n filter = options.filter;\n _saveInputCheckedState(el);\n\n // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.\n if (dragEl) {\n return;\n }\n if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {\n return; // only left button and enabled\n }\n\n // cancel dnd if original target is content editable\n if (originalTarget.isContentEditable) {\n return;\n }\n\n // Safari ignores further event handling after mousedown\n if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') {\n return;\n }\n target = closest(target, options.draggable, el, false);\n if (target && target.animated) {\n return;\n }\n if (lastDownEl === target) {\n // Ignoring duplicate `down`\n return;\n }\n\n // Get the index of the dragged element within its parent\n oldIndex = index(target);\n oldDraggableIndex = index(target, options.draggable);\n\n // Check filter\n if (typeof filter === 'function') {\n if (filter.call(this, evt, target, this)) {\n _dispatchEvent({\n sortable: _this,\n rootEl: originalTarget,\n name: 'filter',\n targetEl: target,\n toEl: el,\n fromEl: el\n });\n pluginEvent('filter', _this, {\n evt: evt\n });\n preventOnFilter && evt.preventDefault();\n return; // cancel dnd\n }\n } else if (filter) {\n filter = filter.split(',').some(function (criteria) {\n criteria = closest(originalTarget, criteria.trim(), el, false);\n if (criteria) {\n _dispatchEvent({\n sortable: _this,\n rootEl: criteria,\n name: 'filter',\n targetEl: target,\n fromEl: el,\n toEl: el\n });\n pluginEvent('filter', _this, {\n evt: evt\n });\n return true;\n }\n });\n if (filter) {\n preventOnFilter && evt.preventDefault();\n return; // cancel dnd\n }\n }\n if (options.handle && !closest(originalTarget, options.handle, el, false)) {\n return;\n }\n\n // Prepare `dragstart`\n this._prepareDragStart(evt, touch, target);\n },\n _prepareDragStart: function _prepareDragStart( /** Event */evt, /** Touch */touch, /** HTMLElement */target) {\n var _this = this,\n el = _this.el,\n options = _this.options,\n ownerDocument = el.ownerDocument,\n dragStartFn;\n if (target && !dragEl && target.parentNode === el) {\n var dragRect = getRect(target);\n rootEl = el;\n dragEl = target;\n parentEl = dragEl.parentNode;\n nextEl = dragEl.nextSibling;\n lastDownEl = target;\n activeGroup = options.group;\n Sortable.dragged = dragEl;\n tapEvt = {\n target: dragEl,\n clientX: (touch || evt).clientX,\n clientY: (touch || evt).clientY\n };\n tapDistanceLeft = tapEvt.clientX - dragRect.left;\n tapDistanceTop = tapEvt.clientY - dragRect.top;\n this._lastX = (touch || evt).clientX;\n this._lastY = (touch || evt).clientY;\n dragEl.style['will-change'] = 'all';\n dragStartFn = function dragStartFn() {\n pluginEvent('delayEnded', _this, {\n evt: evt\n });\n if (Sortable.eventCanceled) {\n _this._onDrop();\n return;\n }\n // Delayed drag has been triggered\n // we can re-enable the events: touchmove/mousemove\n _this._disableDelayedDragEvents();\n if (!FireFox && _this.nativeDraggable) {\n dragEl.draggable = true;\n }\n\n // Bind the events: dragstart/dragend\n _this._triggerDragStart(evt, touch);\n\n // Drag start event\n _dispatchEvent({\n sortable: _this,\n name: 'choose',\n originalEvent: evt\n });\n\n // Chosen item\n toggleClass(dragEl, options.chosenClass, true);\n };\n\n // Disable \"draggable\"\n options.ignore.split(',').forEach(function (criteria) {\n find(dragEl, criteria.trim(), _disableDraggable);\n });\n on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);\n on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);\n on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);\n if (options.supportPointer) {\n on(ownerDocument, 'pointerup', _this._onDrop);\n // Native D&D triggers pointercancel\n !this.nativeDraggable && on(ownerDocument, 'pointercancel', _this._onDrop);\n } else {\n on(ownerDocument, 'mouseup', _this._onDrop);\n on(ownerDocument, 'touchend', _this._onDrop);\n on(ownerDocument, 'touchcancel', _this._onDrop);\n }\n\n // Make dragEl draggable (must be before delay for FireFox)\n if (FireFox && this.nativeDraggable) {\n this.options.touchStartThreshold = 4;\n dragEl.draggable = true;\n }\n pluginEvent('delayStart', this, {\n evt: evt\n });\n\n // Delay is impossible for native DnD in Edge or IE\n if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {\n if (Sortable.eventCanceled) {\n this._onDrop();\n return;\n }\n // If the user moves the pointer or let go the click or touch\n // before the delay has been reached:\n // disable the delayed drag\n if (options.supportPointer) {\n on(ownerDocument, 'pointerup', _this._disableDelayedDrag);\n on(ownerDocument, 'pointercancel', _this._disableDelayedDrag);\n } else {\n on(ownerDocument, 'mouseup', _this._disableDelayedDrag);\n on(ownerDocument, 'touchend', _this._disableDelayedDrag);\n on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);\n }\n on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);\n on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);\n options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);\n _this._dragStartTimer = setTimeout(dragStartFn, options.delay);\n } else {\n dragStartFn();\n }\n }\n },\n _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( /** TouchEvent|PointerEvent **/e) {\n var touch = e.touches ? e.touches[0] : e;\n if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {\n this._disableDelayedDrag();\n }\n },\n _disableDelayedDrag: function _disableDelayedDrag() {\n dragEl && _disableDraggable(dragEl);\n clearTimeout(this._dragStartTimer);\n this._disableDelayedDragEvents();\n },\n _disableDelayedDragEvents: function _disableDelayedDragEvents() {\n var ownerDocument = this.el.ownerDocument;\n off(ownerDocument, 'mouseup', this._disableDelayedDrag);\n off(ownerDocument, 'touchend', this._disableDelayedDrag);\n off(ownerDocument, 'touchcancel', this._disableDelayedDrag);\n off(ownerDocument, 'pointerup', this._disableDelayedDrag);\n off(ownerDocument, 'pointercancel', this._disableDelayedDrag);\n off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);\n off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);\n off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);\n },\n _triggerDragStart: function _triggerDragStart( /** Event */evt, /** Touch */touch) {\n touch = touch || evt.pointerType == 'touch' && evt;\n if (!this.nativeDraggable || touch) {\n if (this.options.supportPointer) {\n on(document, 'pointermove', this._onTouchMove);\n } else if (touch) {\n on(document, 'touchmove', this._onTouchMove);\n } else {\n on(document, 'mousemove', this._onTouchMove);\n }\n } else {\n on(dragEl, 'dragend', this);\n on(rootEl, 'dragstart', this._onDragStart);\n }\n try {\n if (document.selection) {\n _nextTick(function () {\n document.selection.empty();\n });\n } else {\n window.getSelection().removeAllRanges();\n }\n } catch (err) {}\n },\n _dragStarted: function _dragStarted(fallback, evt) {\n awaitingDragStarted = false;\n if (rootEl && dragEl) {\n pluginEvent('dragStarted', this, {\n evt: evt\n });\n if (this.nativeDraggable) {\n on(document, 'dragover', _checkOutsideTargetEl);\n }\n var options = this.options;\n\n // Apply effect\n !fallback && toggleClass(dragEl, options.dragClass, false);\n toggleClass(dragEl, options.ghostClass, true);\n Sortable.active = this;\n fallback && this._appendGhost();\n\n // Drag start event\n _dispatchEvent({\n sortable: this,\n name: 'start',\n originalEvent: evt\n });\n } else {\n this._nulling();\n }\n },\n _emulateDragOver: function _emulateDragOver() {\n if (touchEvt) {\n this._lastX = touchEvt.clientX;\n this._lastY = touchEvt.clientY;\n _hideGhostForTarget();\n var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);\n var parent = target;\n while (target && target.shadowRoot) {\n target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);\n if (target === parent) break;\n parent = target;\n }\n dragEl.parentNode[expando]._isOutsideThisEl(target);\n if (parent) {\n do {\n if (parent[expando]) {\n var inserted = void 0;\n inserted = parent[expando]._onDragOver({\n clientX: touchEvt.clientX,\n clientY: touchEvt.clientY,\n target: target,\n rootEl: parent\n });\n if (inserted && !this.options.dragoverBubble) {\n break;\n }\n }\n target = parent; // store last element\n }\n /* jshint boss:true */ while (parent = getParentOrHost(parent));\n }\n _unhideGhostForTarget();\n }\n },\n _onTouchMove: function _onTouchMove( /**TouchEvent*/evt) {\n if (tapEvt) {\n var options = this.options,\n fallbackTolerance = options.fallbackTolerance,\n fallbackOffset = options.fallbackOffset,\n touch = evt.touches ? evt.touches[0] : evt,\n ghostMatrix = ghostEl && matrix(ghostEl, true),\n scaleX = ghostEl && ghostMatrix && ghostMatrix.a,\n scaleY = ghostEl && ghostMatrix && ghostMatrix.d,\n relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),\n dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),\n dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1);\n\n // only set the status to dragging, when we are actually dragging\n if (!Sortable.active && !awaitingDragStarted) {\n if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {\n return;\n }\n this._onDragStart(evt, true);\n }\n if (ghostEl) {\n if (ghostMatrix) {\n ghostMatrix.e += dx - (lastDx || 0);\n ghostMatrix.f += dy - (lastDy || 0);\n } else {\n ghostMatrix = {\n a: 1,\n b: 0,\n c: 0,\n d: 1,\n e: dx,\n f: dy\n };\n }\n var cssMatrix = \"matrix(\".concat(ghostMatrix.a, \",\").concat(ghostMatrix.b, \",\").concat(ghostMatrix.c, \",\").concat(ghostMatrix.d, \",\").concat(ghostMatrix.e, \",\").concat(ghostMatrix.f, \")\");\n css(ghostEl, 'webkitTransform', cssMatrix);\n css(ghostEl, 'mozTransform', cssMatrix);\n css(ghostEl, 'msTransform', cssMatrix);\n css(ghostEl, 'transform', cssMatrix);\n lastDx = dx;\n lastDy = dy;\n touchEvt = touch;\n }\n evt.cancelable && evt.preventDefault();\n }\n },\n _appendGhost: function _appendGhost() {\n // Bug if using scale(): https://stackoverflow.com/questions/2637058\n // Not being adjusted for\n if (!ghostEl) {\n var container = this.options.fallbackOnBody ? document.body : rootEl,\n rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),\n options = this.options;\n\n // Position absolutely\n if (PositionGhostAbsolutely) {\n // Get relatively positioned parent\n ghostRelativeParent = container;\n while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {\n ghostRelativeParent = ghostRelativeParent.parentNode;\n }\n if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {\n if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();\n rect.top += ghostRelativeParent.scrollTop;\n rect.left += ghostRelativeParent.scrollLeft;\n } else {\n ghostRelativeParent = getWindowScrollingElement();\n }\n ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);\n }\n ghostEl = dragEl.cloneNode(true);\n toggleClass(ghostEl, options.ghostClass, false);\n toggleClass(ghostEl, options.fallbackClass, true);\n toggleClass(ghostEl, options.dragClass, true);\n css(ghostEl, 'transition', '');\n css(ghostEl, 'transform', '');\n css(ghostEl, 'box-sizing', 'border-box');\n css(ghostEl, 'margin', 0);\n css(ghostEl, 'top', rect.top);\n css(ghostEl, 'left', rect.left);\n css(ghostEl, 'width', rect.width);\n css(ghostEl, 'height', rect.height);\n css(ghostEl, 'opacity', '0.8');\n css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');\n css(ghostEl, 'zIndex', '100000');\n css(ghostEl, 'pointerEvents', 'none');\n Sortable.ghost = ghostEl;\n container.appendChild(ghostEl);\n\n // Set transform-origin\n css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');\n }\n },\n _onDragStart: function _onDragStart( /**Event*/evt, /**boolean*/fallback) {\n var _this = this;\n var dataTransfer = evt.dataTransfer;\n var options = _this.options;\n pluginEvent('dragStart', this, {\n evt: evt\n });\n if (Sortable.eventCanceled) {\n this._onDrop();\n return;\n }\n pluginEvent('setupClone', this);\n if (!Sortable.eventCanceled) {\n cloneEl = clone(dragEl);\n cloneEl.removeAttribute(\"id\");\n cloneEl.draggable = false;\n cloneEl.style['will-change'] = '';\n this._hideClone();\n toggleClass(cloneEl, this.options.chosenClass, false);\n Sortable.clone = cloneEl;\n }\n\n // #1143: IFrame support workaround\n _this.cloneId = _nextTick(function () {\n pluginEvent('clone', _this);\n if (Sortable.eventCanceled) return;\n if (!_this.options.removeCloneOnHide) {\n rootEl.insertBefore(cloneEl, dragEl);\n }\n _this._hideClone();\n _dispatchEvent({\n sortable: _this,\n name: 'clone'\n });\n });\n !fallback && toggleClass(dragEl, options.dragClass, true);\n\n // Set proper drop events\n if (fallback) {\n ignoreNextClick = true;\n _this._loopId = setInterval(_this._emulateDragOver, 50);\n } else {\n // Undo what was set in _prepareDragStart before drag started\n off(document, 'mouseup', _this._onDrop);\n off(document, 'touchend', _this._onDrop);\n off(document, 'touchcancel', _this._onDrop);\n if (dataTransfer) {\n dataTransfer.effectAllowed = 'move';\n options.setData && options.setData.call(_this, dataTransfer, dragEl);\n }\n on(document, 'drop', _this);\n\n // #1276 fix:\n css(dragEl, 'transform', 'translateZ(0)');\n }\n awaitingDragStarted = true;\n _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));\n on(document, 'selectstart', _this);\n moved = true;\n window.getSelection().removeAllRanges();\n if (Safari) {\n css(document.body, 'user-select', 'none');\n }\n },\n // Returns true - if no further action is needed (either inserted or another condition)\n _onDragOver: function _onDragOver( /**Event*/evt) {\n var el = this.el,\n target = evt.target,\n dragRect,\n targetRect,\n revert,\n options = this.options,\n group = options.group,\n activeSortable = Sortable.active,\n isOwner = activeGroup === group,\n canSort = options.sort,\n fromSortable = putSortable || activeSortable,\n vertical,\n _this = this,\n completedFired = false;\n if (_silent) return;\n function dragOverEvent(name, extra) {\n pluginEvent(name, _this, _objectSpread2({\n evt: evt,\n isOwner: isOwner,\n axis: vertical ? 'vertical' : 'horizontal',\n revert: revert,\n dragRect: dragRect,\n targetRect: targetRect,\n canSort: canSort,\n fromSortable: fromSortable,\n target: target,\n completed: completed,\n onMove: function onMove(target, after) {\n return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);\n },\n changed: changed\n }, extra));\n }\n\n // Capture animation state\n function capture() {\n dragOverEvent('dragOverAnimationCapture');\n _this.captureAnimationState();\n if (_this !== fromSortable) {\n fromSortable.captureAnimationState();\n }\n }\n\n // Return invocation when dragEl is inserted (or completed)\n function completed(insertion) {\n dragOverEvent('dragOverCompleted', {\n insertion: insertion\n });\n if (insertion) {\n // Clones must be hidden before folding animation to capture dragRectAbsolute properly\n if (isOwner) {\n activeSortable._hideClone();\n } else {\n activeSortable._showClone(_this);\n }\n if (_this !== fromSortable) {\n // Set ghost class to new sortable's ghost class\n toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);\n toggleClass(dragEl, options.ghostClass, true);\n }\n if (putSortable !== _this && _this !== Sortable.active) {\n putSortable = _this;\n } else if (_this === Sortable.active && putSortable) {\n putSortable = null;\n }\n\n // Animation\n if (fromSortable === _this) {\n _this._ignoreWhileAnimating = target;\n }\n _this.animateAll(function () {\n dragOverEvent('dragOverAnimationComplete');\n _this._ignoreWhileAnimating = null;\n });\n if (_this !== fromSortable) {\n fromSortable.animateAll();\n fromSortable._ignoreWhileAnimating = null;\n }\n }\n\n // Null lastTarget if it is not inside a previously swapped element\n if (target === dragEl && !dragEl.animated || target === el && !target.animated) {\n lastTarget = null;\n }\n\n // no bubbling and not fallback\n if (!options.dragoverBubble && !evt.rootEl && target !== document) {\n dragEl.parentNode[expando]._isOutsideThisEl(evt.target);\n\n // Do not detect for empty insert if already inserted\n !insertion && nearestEmptyInsertDetectEvent(evt);\n }\n !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();\n return completedFired = true;\n }\n\n // Call when dragEl has been inserted\n function changed() {\n newIndex = index(dragEl);\n newDraggableIndex = index(dragEl, options.draggable);\n _dispatchEvent({\n sortable: _this,\n name: 'change',\n toEl: el,\n newIndex: newIndex,\n newDraggableIndex: newDraggableIndex,\n originalEvent: evt\n });\n }\n if (evt.preventDefault !== void 0) {\n evt.cancelable && evt.preventDefault();\n }\n target = closest(target, options.draggable, el, true);\n dragOverEvent('dragOver');\n if (Sortable.eventCanceled) return completedFired;\n if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {\n return completed(false);\n }\n ignoreNextClick = false;\n if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = parentEl !== rootEl) // Reverting item into the original list\n : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {\n vertical = this._getDirection(evt, target) === 'vertical';\n dragRect = getRect(dragEl);\n dragOverEvent('dragOverValid');\n if (Sortable.eventCanceled) return completedFired;\n if (revert) {\n parentEl = rootEl; // actualization\n capture();\n this._hideClone();\n dragOverEvent('revert');\n if (!Sortable.eventCanceled) {\n if (nextEl) {\n rootEl.insertBefore(dragEl, nextEl);\n } else {\n rootEl.appendChild(dragEl);\n }\n }\n return completed(true);\n }\n var elLastChild = lastChild(el, options.draggable);\n if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {\n // Insert to end of list\n\n // If already at end of list: Do not insert\n if (elLastChild === dragEl) {\n return completed(false);\n }\n\n // if there is a last element, it is the target\n if (elLastChild && el === evt.target) {\n target = elLastChild;\n }\n if (target) {\n targetRect = getRect(target);\n }\n if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {\n capture();\n if (elLastChild && elLastChild.nextSibling) {\n // the last draggable element is not the last node\n el.insertBefore(dragEl, elLastChild.nextSibling);\n } else {\n el.appendChild(dragEl);\n }\n parentEl = el; // actualization\n\n changed();\n return completed(true);\n }\n } else if (elLastChild && _ghostIsFirst(evt, vertical, this)) {\n // Insert to start of list\n var firstChild = getChild(el, 0, options, true);\n if (firstChild === dragEl) {\n return completed(false);\n }\n target = firstChild;\n targetRect = getRect(target);\n if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) {\n capture();\n el.insertBefore(dragEl, firstChild);\n parentEl = el; // actualization\n\n changed();\n return completed(true);\n }\n } else if (target.parentNode === el) {\n targetRect = getRect(target);\n var direction = 0,\n targetBeforeFirstSwap,\n differentLevel = dragEl.parentNode !== el,\n differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),\n side1 = vertical ? 'top' : 'left',\n scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),\n scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;\n if (lastTarget !== target) {\n targetBeforeFirstSwap = targetRect[side1];\n pastFirstInvertThresh = false;\n isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;\n }\n direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);\n var sibling;\n if (direction !== 0) {\n // Check if target is beside dragEl in respective direction (ignoring hidden elements)\n var dragIndex = index(dragEl);\n do {\n dragIndex -= direction;\n sibling = parentEl.children[dragIndex];\n } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));\n }\n // If dragEl is already beside target: Do not insert\n if (direction === 0 || sibling === target) {\n return completed(false);\n }\n lastTarget = target;\n lastDirection = direction;\n var nextSibling = target.nextElementSibling,\n after = false;\n after = direction === 1;\n var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);\n if (moveVector !== false) {\n if (moveVector === 1 || moveVector === -1) {\n after = moveVector === 1;\n }\n _silent = true;\n setTimeout(_unsilent, 30);\n capture();\n if (after && !nextSibling) {\n el.appendChild(dragEl);\n } else {\n target.parentNode.insertBefore(dragEl, after ? nextSibling : target);\n }\n\n // Undo chrome's scroll adjustment (has no effect on other browsers)\n if (scrolledPastTop) {\n scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);\n }\n parentEl = dragEl.parentNode; // actualization\n\n // must be done before animation\n if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {\n targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);\n }\n changed();\n return completed(true);\n }\n }\n if (el.contains(dragEl)) {\n return completed(false);\n }\n }\n return false;\n },\n _ignoreWhileAnimating: null,\n _offMoveEvents: function _offMoveEvents() {\n off(document, 'mousemove', this._onTouchMove);\n off(document, 'touchmove', this._onTouchMove);\n off(document, 'pointermove', this._onTouchMove);\n off(document, 'dragover', nearestEmptyInsertDetectEvent);\n off(document, 'mousemove', nearestEmptyInsertDetectEvent);\n off(document, 'touchmove', nearestEmptyInsertDetectEvent);\n },\n _offUpEvents: function _offUpEvents() {\n var ownerDocument = this.el.ownerDocument;\n off(ownerDocument, 'mouseup', this._onDrop);\n off(ownerDocument, 'touchend', this._onDrop);\n off(ownerDocument, 'pointerup', this._onDrop);\n off(ownerDocument, 'pointercancel', this._onDrop);\n off(ownerDocument, 'touchcancel', this._onDrop);\n off(document, 'selectstart', this);\n },\n _onDrop: function _onDrop( /**Event*/evt) {\n var el = this.el,\n options = this.options;\n\n // Get the index of the dragged element within its parent\n newIndex = index(dragEl);\n newDraggableIndex = index(dragEl, options.draggable);\n pluginEvent('drop', this, {\n evt: evt\n });\n parentEl = dragEl && dragEl.parentNode;\n\n // Get again after plugin event\n newIndex = index(dragEl);\n newDraggableIndex = index(dragEl, options.draggable);\n if (Sortable.eventCanceled) {\n this._nulling();\n return;\n }\n awaitingDragStarted = false;\n isCircumstantialInvert = false;\n pastFirstInvertThresh = false;\n clearInterval(this._loopId);\n clearTimeout(this._dragStartTimer);\n _cancelNextTick(this.cloneId);\n _cancelNextTick(this._dragStartId);\n\n // Unbind events\n if (this.nativeDraggable) {\n off(document, 'drop', this);\n off(el, 'dragstart', this._onDragStart);\n }\n this._offMoveEvents();\n this._offUpEvents();\n if (Safari) {\n css(document.body, 'user-select', '');\n }\n css(dragEl, 'transform', '');\n if (evt) {\n if (moved) {\n evt.cancelable && evt.preventDefault();\n !options.dropBubble && evt.stopPropagation();\n }\n ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);\n if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {\n // Remove clone(s)\n cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);\n }\n if (dragEl) {\n if (this.nativeDraggable) {\n off(dragEl, 'dragend', this);\n }\n _disableDraggable(dragEl);\n dragEl.style['will-change'] = '';\n\n // Remove classes\n // ghostClass is added in dragStarted\n if (moved && !awaitingDragStarted) {\n toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);\n }\n toggleClass(dragEl, this.options.chosenClass, false);\n\n // Drag stop event\n _dispatchEvent({\n sortable: this,\n name: 'unchoose',\n toEl: parentEl,\n newIndex: null,\n newDraggableIndex: null,\n originalEvent: evt\n });\n if (rootEl !== parentEl) {\n if (newIndex >= 0) {\n // Add event\n _dispatchEvent({\n rootEl: parentEl,\n name: 'add',\n toEl: parentEl,\n fromEl: rootEl,\n originalEvent: evt\n });\n\n // Remove event\n _dispatchEvent({\n sortable: this,\n name: 'remove',\n toEl: parentEl,\n originalEvent: evt\n });\n\n // drag from one list and drop into another\n _dispatchEvent({\n rootEl: parentEl,\n name: 'sort',\n toEl: parentEl,\n fromEl: rootEl,\n originalEvent: evt\n });\n _dispatchEvent({\n sortable: this,\n name: 'sort',\n toEl: parentEl,\n originalEvent: evt\n });\n }\n putSortable && putSortable.save();\n } else {\n if (newIndex !== oldIndex) {\n if (newIndex >= 0) {\n // drag & drop within the same list\n _dispatchEvent({\n sortable: this,\n name: 'update',\n toEl: parentEl,\n originalEvent: evt\n });\n _dispatchEvent({\n sortable: this,\n name: 'sort',\n toEl: parentEl,\n originalEvent: evt\n });\n }\n }\n }\n if (Sortable.active) {\n /* jshint eqnull:true */\n if (newIndex == null || newIndex === -1) {\n newIndex = oldIndex;\n newDraggableIndex = oldDraggableIndex;\n }\n _dispatchEvent({\n sortable: this,\n name: 'end',\n toEl: parentEl,\n originalEvent: evt\n });\n\n // Save sorting\n this.save();\n }\n }\n }\n this._nulling();\n },\n _nulling: function _nulling() {\n pluginEvent('nulling', this);\n rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;\n savedInputChecked.forEach(function (el) {\n el.checked = true;\n });\n savedInputChecked.length = lastDx = lastDy = 0;\n },\n handleEvent: function handleEvent( /**Event*/evt) {\n switch (evt.type) {\n case 'drop':\n case 'dragend':\n this._onDrop(evt);\n break;\n case 'dragenter':\n case 'dragover':\n if (dragEl) {\n this._onDragOver(evt);\n _globalDragOver(evt);\n }\n break;\n case 'selectstart':\n evt.preventDefault();\n break;\n }\n },\n /**\r\n * Serializes the item into an array of string.\r\n * @returns {String[]}\r\n */\n toArray: function toArray() {\n var order = [],\n el,\n children = this.el.children,\n i = 0,\n n = children.length,\n options = this.options;\n for (; i < n; i++) {\n el = children[i];\n if (closest(el, options.draggable, this.el, false)) {\n order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));\n }\n }\n return order;\n },\n /**\r\n * Sorts the elements according to the array.\r\n * @param {String[]} order order of the items\r\n */\n sort: function sort(order, useAnimation) {\n var items = {},\n rootEl = this.el;\n this.toArray().forEach(function (id, i) {\n var el = rootEl.children[i];\n if (closest(el, this.options.draggable, rootEl, false)) {\n items[id] = el;\n }\n }, this);\n useAnimation && this.captureAnimationState();\n order.forEach(function (id) {\n if (items[id]) {\n rootEl.removeChild(items[id]);\n rootEl.appendChild(items[id]);\n }\n });\n useAnimation && this.animateAll();\n },\n /**\r\n * Save the current sorting\r\n */\n save: function save() {\n var store = this.options.store;\n store && store.set && store.set(this);\n },\n /**\r\n * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.\r\n * @param {HTMLElement} el\r\n * @param {String} [selector] default: `options.draggable`\r\n * @returns {HTMLElement|null}\r\n */\n closest: function closest$1(el, selector) {\n return closest(el, selector || this.options.draggable, this.el, false);\n },\n /**\r\n * Set/get option\r\n * @param {string} name\r\n * @param {*} [value]\r\n * @returns {*}\r\n */\n option: function option(name, value) {\n var options = this.options;\n if (value === void 0) {\n return options[name];\n } else {\n var modifiedValue = PluginManager.modifyOption(this, name, value);\n if (typeof modifiedValue !== 'undefined') {\n options[name] = modifiedValue;\n } else {\n options[name] = value;\n }\n if (name === 'group') {\n _prepareGroup(options);\n }\n }\n },\n /**\r\n * Destroy\r\n */\n destroy: function destroy() {\n pluginEvent('destroy', this);\n var el = this.el;\n el[expando] = null;\n off(el, 'mousedown', this._onTapStart);\n off(el, 'touchstart', this._onTapStart);\n off(el, 'pointerdown', this._onTapStart);\n if (this.nativeDraggable) {\n off(el, 'dragover', this);\n off(el, 'dragenter', this);\n }\n // Remove draggable attributes\n Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {\n el.removeAttribute('draggable');\n });\n this._onDrop();\n this._disableDelayedDragEvents();\n sortables.splice(sortables.indexOf(this.el), 1);\n this.el = el = null;\n },\n _hideClone: function _hideClone() {\n if (!cloneHidden) {\n pluginEvent('hideClone', this);\n if (Sortable.eventCanceled) return;\n css(cloneEl, 'display', 'none');\n if (this.options.removeCloneOnHide && cloneEl.parentNode) {\n cloneEl.parentNode.removeChild(cloneEl);\n }\n cloneHidden = true;\n }\n },\n _showClone: function _showClone(putSortable) {\n if (putSortable.lastPutMode !== 'clone') {\n this._hideClone();\n return;\n }\n if (cloneHidden) {\n pluginEvent('showClone', this);\n if (Sortable.eventCanceled) return;\n\n // show clone at dragEl or original position\n if (dragEl.parentNode == rootEl && !this.options.group.revertClone) {\n rootEl.insertBefore(cloneEl, dragEl);\n } else if (nextEl) {\n rootEl.insertBefore(cloneEl, nextEl);\n } else {\n rootEl.appendChild(cloneEl);\n }\n if (this.options.group.revertClone) {\n this.animate(dragEl, cloneEl);\n }\n css(cloneEl, 'display', '');\n cloneHidden = false;\n }\n }\n};\nfunction _globalDragOver( /**Event*/evt) {\n if (evt.dataTransfer) {\n evt.dataTransfer.dropEffect = 'move';\n }\n evt.cancelable && evt.preventDefault();\n}\nfunction _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {\n var evt,\n sortable = fromEl[expando],\n onMoveFn = sortable.options.onMove,\n retVal;\n // Support for new CustomEvent feature\n if (window.CustomEvent && !IE11OrLess && !Edge) {\n evt = new CustomEvent('move', {\n bubbles: true,\n cancelable: true\n });\n } else {\n evt = document.createEvent('Event');\n evt.initEvent('move', true, true);\n }\n evt.to = toEl;\n evt.from = fromEl;\n evt.dragged = dragEl;\n evt.draggedRect = dragRect;\n evt.related = targetEl || toEl;\n evt.relatedRect = targetRect || getRect(toEl);\n evt.willInsertAfter = willInsertAfter;\n evt.originalEvent = originalEvent;\n fromEl.dispatchEvent(evt);\n if (onMoveFn) {\n retVal = onMoveFn.call(sortable, evt, originalEvent);\n }\n return retVal;\n}\nfunction _disableDraggable(el) {\n el.draggable = false;\n}\nfunction _unsilent() {\n _silent = false;\n}\nfunction _ghostIsFirst(evt, vertical, sortable) {\n var firstElRect = getRect(getChild(sortable.el, 0, sortable.options, true));\n var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);\n var spacer = 10;\n return vertical ? evt.clientX < childContainingRect.left - spacer || evt.clientY < firstElRect.top && evt.clientX < firstElRect.right : evt.clientY < childContainingRect.top - spacer || evt.clientY < firstElRect.bottom && evt.clientX < firstElRect.left;\n}\nfunction _ghostIsLast(evt, vertical, sortable) {\n var lastElRect = getRect(lastChild(sortable.el, sortable.options.draggable));\n var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);\n var spacer = 10;\n return vertical ? evt.clientX > childContainingRect.right + spacer || evt.clientY > lastElRect.bottom && evt.clientX > lastElRect.left : evt.clientY > childContainingRect.bottom + spacer || evt.clientX > lastElRect.right && evt.clientY > lastElRect.top;\n}\nfunction _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {\n var mouseOnAxis = vertical ? evt.clientY : evt.clientX,\n targetLength = vertical ? targetRect.height : targetRect.width,\n targetS1 = vertical ? targetRect.top : targetRect.left,\n targetS2 = vertical ? targetRect.bottom : targetRect.right,\n invert = false;\n if (!invertSwap) {\n // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold\n if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {\n // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2\n // check if past first invert threshold on side opposite of lastDirection\n if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {\n // past first invert threshold, do not restrict inverted threshold to dragEl shadow\n pastFirstInvertThresh = true;\n }\n if (!pastFirstInvertThresh) {\n // dragEl shadow (target move distance shadow)\n if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow\n : mouseOnAxis > targetS2 - targetMoveDistance) {\n return -lastDirection;\n }\n } else {\n invert = true;\n }\n } else {\n // Regular\n if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {\n return _getInsertDirection(target);\n }\n }\n }\n invert = invert || invertSwap;\n if (invert) {\n // Invert of regular\n if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {\n return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;\n }\n }\n return 0;\n}\n\n/**\r\n * Gets the direction dragEl must be swapped relative to target in order to make it\r\n * seem that dragEl has been \"inserted\" into that element's position\r\n * @param {HTMLElement} target The target whose position dragEl is being inserted at\r\n * @return {Number} Direction dragEl must be swapped\r\n */\nfunction _getInsertDirection(target) {\n if (index(dragEl) < index(target)) {\n return 1;\n } else {\n return -1;\n }\n}\n\n/**\r\n * Generate id\r\n * @param {HTMLElement} el\r\n * @returns {String}\r\n * @private\r\n */\nfunction _generateId(el) {\n var str = el.tagName + el.className + el.src + el.href + el.textContent,\n i = str.length,\n sum = 0;\n while (i--) {\n sum += str.charCodeAt(i);\n }\n return sum.toString(36);\n}\nfunction _saveInputCheckedState(root) {\n savedInputChecked.length = 0;\n var inputs = root.getElementsByTagName('input');\n var idx = inputs.length;\n while (idx--) {\n var el = inputs[idx];\n el.checked && savedInputChecked.push(el);\n }\n}\nfunction _nextTick(fn) {\n return setTimeout(fn, 0);\n}\nfunction _cancelNextTick(id) {\n return clearTimeout(id);\n}\n\n// Fixed #973:\nif (documentExists) {\n on(document, 'touchmove', function (evt) {\n if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {\n evt.preventDefault();\n }\n });\n}\n\n// Export utils\nSortable.utils = {\n on: on,\n off: off,\n css: css,\n find: find,\n is: function is(el, selector) {\n return !!closest(el, selector, el, false);\n },\n extend: extend,\n throttle: throttle,\n closest: closest,\n toggleClass: toggleClass,\n clone: clone,\n index: index,\n nextTick: _nextTick,\n cancelNextTick: _cancelNextTick,\n detectDirection: _detectDirection,\n getChild: getChild,\n expando: expando\n};\n\n/**\r\n * Get the Sortable instance of an element\r\n * @param {HTMLElement} element The element\r\n * @return {Sortable|undefined} The instance of Sortable\r\n */\nSortable.get = function (element) {\n return element[expando];\n};\n\n/**\r\n * Mount a plugin to Sortable\r\n * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted\r\n */\nSortable.mount = function () {\n for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {\n plugins[_key] = arguments[_key];\n }\n if (plugins[0].constructor === Array) plugins = plugins[0];\n plugins.forEach(function (plugin) {\n if (!plugin.prototype || !plugin.prototype.constructor) {\n throw \"Sortable: Mounted plugin must be a constructor function, not \".concat({}.toString.call(plugin));\n }\n if (plugin.utils) Sortable.utils = _objectSpread2(_objectSpread2({}, Sortable.utils), plugin.utils);\n PluginManager.mount(plugin);\n });\n};\n\n/**\r\n * Create sortable instance\r\n * @param {HTMLElement} el\r\n * @param {Object} [options]\r\n */\nSortable.create = function (el, options) {\n return new Sortable(el, options);\n};\n\n// Export\nSortable.version = version;\n\nvar autoScrolls = [],\n scrollEl,\n scrollRootEl,\n scrolling = false,\n lastAutoScrollX,\n lastAutoScrollY,\n touchEvt$1,\n pointerElemChangedInterval;\nfunction AutoScrollPlugin() {\n function AutoScroll() {\n this.defaults = {\n scroll: true,\n forceAutoScrollFallback: false,\n scrollSensitivity: 30,\n scrollSpeed: 10,\n bubbleScroll: true\n };\n\n // Bind all private methods\n for (var fn in this) {\n if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {\n this[fn] = this[fn].bind(this);\n }\n }\n }\n AutoScroll.prototype = {\n dragStarted: function dragStarted(_ref) {\n var originalEvent = _ref.originalEvent;\n if (this.sortable.nativeDraggable) {\n on(document, 'dragover', this._handleAutoScroll);\n } else {\n if (this.options.supportPointer) {\n on(document, 'pointermove', this._handleFallbackAutoScroll);\n } else if (originalEvent.touches) {\n on(document, 'touchmove', this._handleFallbackAutoScroll);\n } else {\n on(document, 'mousemove', this._handleFallbackAutoScroll);\n }\n }\n },\n dragOverCompleted: function dragOverCompleted(_ref2) {\n var originalEvent = _ref2.originalEvent;\n // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)\n if (!this.options.dragOverBubble && !originalEvent.rootEl) {\n this._handleAutoScroll(originalEvent);\n }\n },\n drop: function drop() {\n if (this.sortable.nativeDraggable) {\n off(document, 'dragover', this._handleAutoScroll);\n } else {\n off(document, 'pointermove', this._handleFallbackAutoScroll);\n off(document, 'touchmove', this._handleFallbackAutoScroll);\n off(document, 'mousemove', this._handleFallbackAutoScroll);\n }\n clearPointerElemChangedInterval();\n clearAutoScrolls();\n cancelThrottle();\n },\n nulling: function nulling() {\n touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;\n autoScrolls.length = 0;\n },\n _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {\n this._handleAutoScroll(evt, true);\n },\n _handleAutoScroll: function _handleAutoScroll(evt, fallback) {\n var _this = this;\n var x = (evt.touches ? evt.touches[0] : evt).clientX,\n y = (evt.touches ? evt.touches[0] : evt).clientY,\n elem = document.elementFromPoint(x, y);\n touchEvt$1 = evt;\n\n // IE does not seem to have native autoscroll,\n // Edge's autoscroll seems too conditional,\n // MACOS Safari does not have autoscroll,\n // Firefox and Chrome are good\n if (fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari) {\n autoScroll(evt, this.options, elem, fallback);\n\n // Listener for pointer element change\n var ogElemScroller = getParentAutoScrollElement(elem, true);\n if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {\n pointerElemChangedInterval && clearPointerElemChangedInterval();\n // Detect for pointer elem change, emulating native DnD behaviour\n pointerElemChangedInterval = setInterval(function () {\n var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);\n if (newElem !== ogElemScroller) {\n ogElemScroller = newElem;\n clearAutoScrolls();\n }\n autoScroll(evt, _this.options, newElem, fallback);\n }, 10);\n lastAutoScrollX = x;\n lastAutoScrollY = y;\n }\n } else {\n // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll\n if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {\n clearAutoScrolls();\n return;\n }\n autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);\n }\n }\n };\n return _extends(AutoScroll, {\n pluginName: 'scroll',\n initializeByDefault: true\n });\n}\nfunction clearAutoScrolls() {\n autoScrolls.forEach(function (autoScroll) {\n clearInterval(autoScroll.pid);\n });\n autoScrolls = [];\n}\nfunction clearPointerElemChangedInterval() {\n clearInterval(pointerElemChangedInterval);\n}\nvar autoScroll = throttle(function (evt, options, rootEl, isFallback) {\n // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521\n if (!options.scroll) return;\n var x = (evt.touches ? evt.touches[0] : evt).clientX,\n y = (evt.touches ? evt.touches[0] : evt).clientY,\n sens = options.scrollSensitivity,\n speed = options.scrollSpeed,\n winScroller = getWindowScrollingElement();\n var scrollThisInstance = false,\n scrollCustomFn;\n\n // New scroll root, set scrollEl\n if (scrollRootEl !== rootEl) {\n scrollRootEl = rootEl;\n clearAutoScrolls();\n scrollEl = options.scroll;\n scrollCustomFn = options.scrollFn;\n if (scrollEl === true) {\n scrollEl = getParentAutoScrollElement(rootEl, true);\n }\n }\n var layersOut = 0;\n var currentParent = scrollEl;\n do {\n var el = currentParent,\n rect = getRect(el),\n top = rect.top,\n bottom = rect.bottom,\n left = rect.left,\n right = rect.right,\n width = rect.width,\n height = rect.height,\n canScrollX = void 0,\n canScrollY = void 0,\n scrollWidth = el.scrollWidth,\n scrollHeight = el.scrollHeight,\n elCSS = css(el),\n scrollPosX = el.scrollLeft,\n scrollPosY = el.scrollTop;\n if (el === winScroller) {\n canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');\n canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');\n } else {\n canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');\n canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');\n }\n var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);\n var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);\n if (!autoScrolls[layersOut]) {\n for (var i = 0; i <= layersOut; i++) {\n if (!autoScrolls[i]) {\n autoScrolls[i] = {};\n }\n }\n }\n if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {\n autoScrolls[layersOut].el = el;\n autoScrolls[layersOut].vx = vx;\n autoScrolls[layersOut].vy = vy;\n clearInterval(autoScrolls[layersOut].pid);\n if (vx != 0 || vy != 0) {\n scrollThisInstance = true;\n /* jshint loopfunc:true */\n autoScrolls[layersOut].pid = setInterval(function () {\n // emulate drag over during autoscroll (fallback), emulating native DnD behaviour\n if (isFallback && this.layer === 0) {\n Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely\n }\n var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;\n var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;\n if (typeof scrollCustomFn === 'function') {\n if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {\n return;\n }\n }\n scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);\n }.bind({\n layer: layersOut\n }), 24);\n }\n }\n layersOut++;\n } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));\n scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not\n}, 30);\n\nvar drop = function drop(_ref) {\n var originalEvent = _ref.originalEvent,\n putSortable = _ref.putSortable,\n dragEl = _ref.dragEl,\n activeSortable = _ref.activeSortable,\n dispatchSortableEvent = _ref.dispatchSortableEvent,\n hideGhostForTarget = _ref.hideGhostForTarget,\n unhideGhostForTarget = _ref.unhideGhostForTarget;\n if (!originalEvent) return;\n var toSortable = putSortable || activeSortable;\n hideGhostForTarget();\n var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;\n var target = document.elementFromPoint(touch.clientX, touch.clientY);\n unhideGhostForTarget();\n if (toSortable && !toSortable.el.contains(target)) {\n dispatchSortableEvent('spill');\n this.onSpill({\n dragEl: dragEl,\n putSortable: putSortable\n });\n }\n};\nfunction Revert() {}\nRevert.prototype = {\n startIndex: null,\n dragStart: function dragStart(_ref2) {\n var oldDraggableIndex = _ref2.oldDraggableIndex;\n this.startIndex = oldDraggableIndex;\n },\n onSpill: function onSpill(_ref3) {\n var dragEl = _ref3.dragEl,\n putSortable = _ref3.putSortable;\n this.sortable.captureAnimationState();\n if (putSortable) {\n putSortable.captureAnimationState();\n }\n var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);\n if (nextSibling) {\n this.sortable.el.insertBefore(dragEl, nextSibling);\n } else {\n this.sortable.el.appendChild(dragEl);\n }\n this.sortable.animateAll();\n if (putSortable) {\n putSortable.animateAll();\n }\n },\n drop: drop\n};\n_extends(Revert, {\n pluginName: 'revertOnSpill'\n});\nfunction Remove() {}\nRemove.prototype = {\n onSpill: function onSpill(_ref4) {\n var dragEl = _ref4.dragEl,\n putSortable = _ref4.putSortable;\n var parentSortable = putSortable || this.sortable;\n parentSortable.captureAnimationState();\n dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);\n parentSortable.animateAll();\n },\n drop: drop\n};\n_extends(Remove, {\n pluginName: 'removeOnSpill'\n});\n\nvar lastSwapEl;\nfunction SwapPlugin() {\n function Swap() {\n this.defaults = {\n swapClass: 'sortable-swap-highlight'\n };\n }\n Swap.prototype = {\n dragStart: function dragStart(_ref) {\n var dragEl = _ref.dragEl;\n lastSwapEl = dragEl;\n },\n dragOverValid: function dragOverValid(_ref2) {\n var completed = _ref2.completed,\n target = _ref2.target,\n onMove = _ref2.onMove,\n activeSortable = _ref2.activeSortable,\n changed = _ref2.changed,\n cancel = _ref2.cancel;\n if (!activeSortable.options.swap) return;\n var el = this.sortable.el,\n options = this.options;\n if (target && target !== el) {\n var prevSwapEl = lastSwapEl;\n if (onMove(target) !== false) {\n toggleClass(target, options.swapClass, true);\n lastSwapEl = target;\n } else {\n lastSwapEl = null;\n }\n if (prevSwapEl && prevSwapEl !== lastSwapEl) {\n toggleClass(prevSwapEl, options.swapClass, false);\n }\n }\n changed();\n completed(true);\n cancel();\n },\n drop: function drop(_ref3) {\n var activeSortable = _ref3.activeSortable,\n putSortable = _ref3.putSortable,\n dragEl = _ref3.dragEl;\n var toSortable = putSortable || this.sortable;\n var options = this.options;\n lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);\n if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {\n if (dragEl !== lastSwapEl) {\n toSortable.captureAnimationState();\n if (toSortable !== activeSortable) activeSortable.captureAnimationState();\n swapNodes(dragEl, lastSwapEl);\n toSortable.animateAll();\n if (toSortable !== activeSortable) activeSortable.animateAll();\n }\n }\n },\n nulling: function nulling() {\n lastSwapEl = null;\n }\n };\n return _extends(Swap, {\n pluginName: 'swap',\n eventProperties: function eventProperties() {\n return {\n swapItem: lastSwapEl\n };\n }\n });\n}\nfunction swapNodes(n1, n2) {\n var p1 = n1.parentNode,\n p2 = n2.parentNode,\n i1,\n i2;\n if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;\n i1 = index(n1);\n i2 = index(n2);\n if (p1.isEqualNode(p2) && i1 < i2) {\n i2++;\n }\n p1.insertBefore(n2, p1.children[i1]);\n p2.insertBefore(n1, p2.children[i2]);\n}\n\nvar multiDragElements = [],\n multiDragClones = [],\n lastMultiDragSelect,\n // for selection with modifier key down (SHIFT)\n multiDragSortable,\n initialFolding = false,\n // Initial multi-drag fold when drag started\n folding = false,\n // Folding any other time\n dragStarted = false,\n dragEl$1,\n clonesFromRect,\n clonesHidden;\nfunction MultiDragPlugin() {\n function MultiDrag(sortable) {\n // Bind all private methods\n for (var fn in this) {\n if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {\n this[fn] = this[fn].bind(this);\n }\n }\n if (!sortable.options.avoidImplicitDeselect) {\n if (sortable.options.supportPointer) {\n on(document, 'pointerup', this._deselectMultiDrag);\n } else {\n on(document, 'mouseup', this._deselectMultiDrag);\n on(document, 'touchend', this._deselectMultiDrag);\n }\n }\n on(document, 'keydown', this._checkKeyDown);\n on(document, 'keyup', this._checkKeyUp);\n this.defaults = {\n selectedClass: 'sortable-selected',\n multiDragKey: null,\n avoidImplicitDeselect: false,\n setData: function setData(dataTransfer, dragEl) {\n var data = '';\n if (multiDragElements.length && multiDragSortable === sortable) {\n multiDragElements.forEach(function (multiDragElement, i) {\n data += (!i ? '' : ', ') + multiDragElement.textContent;\n });\n } else {\n data = dragEl.textContent;\n }\n dataTransfer.setData('Text', data);\n }\n };\n }\n MultiDrag.prototype = {\n multiDragKeyDown: false,\n isMultiDrag: false,\n delayStartGlobal: function delayStartGlobal(_ref) {\n var dragged = _ref.dragEl;\n dragEl$1 = dragged;\n },\n delayEnded: function delayEnded() {\n this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);\n },\n setupClone: function setupClone(_ref2) {\n var sortable = _ref2.sortable,\n cancel = _ref2.cancel;\n if (!this.isMultiDrag) return;\n for (var i = 0; i < multiDragElements.length; i++) {\n multiDragClones.push(clone(multiDragElements[i]));\n multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;\n multiDragClones[i].draggable = false;\n multiDragClones[i].style['will-change'] = '';\n toggleClass(multiDragClones[i], this.options.selectedClass, false);\n multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);\n }\n sortable._hideClone();\n cancel();\n },\n clone: function clone(_ref3) {\n var sortable = _ref3.sortable,\n rootEl = _ref3.rootEl,\n dispatchSortableEvent = _ref3.dispatchSortableEvent,\n cancel = _ref3.cancel;\n if (!this.isMultiDrag) return;\n if (!this.options.removeCloneOnHide) {\n if (multiDragElements.length && multiDragSortable === sortable) {\n insertMultiDragClones(true, rootEl);\n dispatchSortableEvent('clone');\n cancel();\n }\n }\n },\n showClone: function showClone(_ref4) {\n var cloneNowShown = _ref4.cloneNowShown,\n rootEl = _ref4.rootEl,\n cancel = _ref4.cancel;\n if (!this.isMultiDrag) return;\n insertMultiDragClones(false, rootEl);\n multiDragClones.forEach(function (clone) {\n css(clone, 'display', '');\n });\n cloneNowShown();\n clonesHidden = false;\n cancel();\n },\n hideClone: function hideClone(_ref5) {\n var _this = this;\n var sortable = _ref5.sortable,\n cloneNowHidden = _ref5.cloneNowHidden,\n cancel = _ref5.cancel;\n if (!this.isMultiDrag) return;\n multiDragClones.forEach(function (clone) {\n css(clone, 'display', 'none');\n if (_this.options.removeCloneOnHide && clone.parentNode) {\n clone.parentNode.removeChild(clone);\n }\n });\n cloneNowHidden();\n clonesHidden = true;\n cancel();\n },\n dragStartGlobal: function dragStartGlobal(_ref6) {\n var sortable = _ref6.sortable;\n if (!this.isMultiDrag && multiDragSortable) {\n multiDragSortable.multiDrag._deselectMultiDrag();\n }\n multiDragElements.forEach(function (multiDragElement) {\n multiDragElement.sortableIndex = index(multiDragElement);\n });\n\n // Sort multi-drag elements\n multiDragElements = multiDragElements.sort(function (a, b) {\n return a.sortableIndex - b.sortableIndex;\n });\n dragStarted = true;\n },\n dragStarted: function dragStarted(_ref7) {\n var _this2 = this;\n var sortable = _ref7.sortable;\n if (!this.isMultiDrag) return;\n if (this.options.sort) {\n // Capture rects,\n // hide multi drag elements (by positioning them absolute),\n // set multi drag elements rects to dragRect,\n // show multi drag elements,\n // animate to rects,\n // unset rects & remove from DOM\n\n sortable.captureAnimationState();\n if (this.options.animation) {\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n css(multiDragElement, 'position', 'absolute');\n });\n var dragRect = getRect(dragEl$1, false, true, true);\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n setRect(multiDragElement, dragRect);\n });\n folding = true;\n initialFolding = true;\n }\n }\n sortable.animateAll(function () {\n folding = false;\n initialFolding = false;\n if (_this2.options.animation) {\n multiDragElements.forEach(function (multiDragElement) {\n unsetRect(multiDragElement);\n });\n }\n\n // Remove all auxiliary multidrag items from el, if sorting enabled\n if (_this2.options.sort) {\n removeMultiDragElements();\n }\n });\n },\n dragOver: function dragOver(_ref8) {\n var target = _ref8.target,\n completed = _ref8.completed,\n cancel = _ref8.cancel;\n if (folding && ~multiDragElements.indexOf(target)) {\n completed(false);\n cancel();\n }\n },\n revert: function revert(_ref9) {\n var fromSortable = _ref9.fromSortable,\n rootEl = _ref9.rootEl,\n sortable = _ref9.sortable,\n dragRect = _ref9.dragRect;\n if (multiDragElements.length > 1) {\n // Setup unfold animation\n multiDragElements.forEach(function (multiDragElement) {\n sortable.addAnimationState({\n target: multiDragElement,\n rect: folding ? getRect(multiDragElement) : dragRect\n });\n unsetRect(multiDragElement);\n multiDragElement.fromRect = dragRect;\n fromSortable.removeAnimationState(multiDragElement);\n });\n folding = false;\n insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);\n }\n },\n dragOverCompleted: function dragOverCompleted(_ref10) {\n var sortable = _ref10.sortable,\n isOwner = _ref10.isOwner,\n insertion = _ref10.insertion,\n activeSortable = _ref10.activeSortable,\n parentEl = _ref10.parentEl,\n putSortable = _ref10.putSortable;\n var options = this.options;\n if (insertion) {\n // Clones must be hidden before folding animation to capture dragRectAbsolute properly\n if (isOwner) {\n activeSortable._hideClone();\n }\n initialFolding = false;\n // If leaving sort:false root, or already folding - Fold to new location\n if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {\n // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible\n var dragRectAbsolute = getRect(dragEl$1, false, true, true);\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n setRect(multiDragElement, dragRectAbsolute);\n\n // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted\n // while folding, and so that we can capture them again because old sortable will no longer be fromSortable\n parentEl.appendChild(multiDragElement);\n });\n folding = true;\n }\n\n // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out\n if (!isOwner) {\n // Only remove if not folding (folding will remove them anyways)\n if (!folding) {\n removeMultiDragElements();\n }\n if (multiDragElements.length > 1) {\n var clonesHiddenBefore = clonesHidden;\n activeSortable._showClone(sortable);\n\n // Unfold animation for clones if showing from hidden\n if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {\n multiDragClones.forEach(function (clone) {\n activeSortable.addAnimationState({\n target: clone,\n rect: clonesFromRect\n });\n clone.fromRect = clonesFromRect;\n clone.thisAnimationDuration = null;\n });\n }\n } else {\n activeSortable._showClone(sortable);\n }\n }\n }\n },\n dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {\n var dragRect = _ref11.dragRect,\n isOwner = _ref11.isOwner,\n activeSortable = _ref11.activeSortable;\n multiDragElements.forEach(function (multiDragElement) {\n multiDragElement.thisAnimationDuration = null;\n });\n if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {\n clonesFromRect = _extends({}, dragRect);\n var dragMatrix = matrix(dragEl$1, true);\n clonesFromRect.top -= dragMatrix.f;\n clonesFromRect.left -= dragMatrix.e;\n }\n },\n dragOverAnimationComplete: function dragOverAnimationComplete() {\n if (folding) {\n folding = false;\n removeMultiDragElements();\n }\n },\n drop: function drop(_ref12) {\n var evt = _ref12.originalEvent,\n rootEl = _ref12.rootEl,\n parentEl = _ref12.parentEl,\n sortable = _ref12.sortable,\n dispatchSortableEvent = _ref12.dispatchSortableEvent,\n oldIndex = _ref12.oldIndex,\n putSortable = _ref12.putSortable;\n var toSortable = putSortable || this.sortable;\n if (!evt) return;\n var options = this.options,\n children = parentEl.children;\n\n // Multi-drag selection\n if (!dragStarted) {\n if (options.multiDragKey && !this.multiDragKeyDown) {\n this._deselectMultiDrag();\n }\n toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));\n if (!~multiDragElements.indexOf(dragEl$1)) {\n multiDragElements.push(dragEl$1);\n dispatchEvent({\n sortable: sortable,\n rootEl: rootEl,\n name: 'select',\n targetEl: dragEl$1,\n originalEvent: evt\n });\n\n // Modifier activated, select from last to dragEl\n if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {\n var lastIndex = index(lastMultiDragSelect),\n currentIndex = index(dragEl$1);\n if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {\n (function () {\n // Must include lastMultiDragSelect (select it), in case modified selection from no selection\n // (but previous selection existed)\n var n, i;\n if (currentIndex > lastIndex) {\n i = lastIndex;\n n = currentIndex;\n } else {\n i = currentIndex;\n n = lastIndex + 1;\n }\n var filter = options.filter;\n for (; i < n; i++) {\n if (~multiDragElements.indexOf(children[i])) continue;\n // Check if element is draggable\n if (!closest(children[i], options.draggable, parentEl, false)) continue;\n // Check if element is filtered\n var filtered = filter && (typeof filter === 'function' ? filter.call(sortable, evt, children[i], sortable) : filter.split(',').some(function (criteria) {\n return closest(children[i], criteria.trim(), parentEl, false);\n }));\n if (filtered) continue;\n toggleClass(children[i], options.selectedClass, true);\n multiDragElements.push(children[i]);\n dispatchEvent({\n sortable: sortable,\n rootEl: rootEl,\n name: 'select',\n targetEl: children[i],\n originalEvent: evt\n });\n }\n })();\n }\n } else {\n lastMultiDragSelect = dragEl$1;\n }\n multiDragSortable = toSortable;\n } else {\n multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);\n lastMultiDragSelect = null;\n dispatchEvent({\n sortable: sortable,\n rootEl: rootEl,\n name: 'deselect',\n targetEl: dragEl$1,\n originalEvent: evt\n });\n }\n }\n\n // Multi-drag drop\n if (dragStarted && this.isMultiDrag) {\n folding = false;\n // Do not \"unfold\" after around dragEl if reverted\n if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {\n var dragRect = getRect(dragEl$1),\n multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');\n if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;\n toSortable.captureAnimationState();\n if (!initialFolding) {\n if (options.animation) {\n dragEl$1.fromRect = dragRect;\n multiDragElements.forEach(function (multiDragElement) {\n multiDragElement.thisAnimationDuration = null;\n if (multiDragElement !== dragEl$1) {\n var rect = folding ? getRect(multiDragElement) : dragRect;\n multiDragElement.fromRect = rect;\n\n // Prepare unfold animation\n toSortable.addAnimationState({\n target: multiDragElement,\n rect: rect\n });\n }\n });\n }\n\n // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert\n // properly they must all be removed\n removeMultiDragElements();\n multiDragElements.forEach(function (multiDragElement) {\n if (children[multiDragIndex]) {\n parentEl.insertBefore(multiDragElement, children[multiDragIndex]);\n } else {\n parentEl.appendChild(multiDragElement);\n }\n multiDragIndex++;\n });\n\n // If initial folding is done, the elements may have changed position because they are now\n // unfolding around dragEl, even though dragEl may not have his index changed, so update event\n // must be fired here as Sortable will not.\n if (oldIndex === index(dragEl$1)) {\n var update = false;\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement.sortableIndex !== index(multiDragElement)) {\n update = true;\n return;\n }\n });\n if (update) {\n dispatchSortableEvent('update');\n dispatchSortableEvent('sort');\n }\n }\n }\n\n // Must be done after capturing individual rects (scroll bar)\n multiDragElements.forEach(function (multiDragElement) {\n unsetRect(multiDragElement);\n });\n toSortable.animateAll();\n }\n multiDragSortable = toSortable;\n }\n\n // Remove clones if necessary\n if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {\n multiDragClones.forEach(function (clone) {\n clone.parentNode && clone.parentNode.removeChild(clone);\n });\n }\n },\n nullingGlobal: function nullingGlobal() {\n this.isMultiDrag = dragStarted = false;\n multiDragClones.length = 0;\n },\n destroyGlobal: function destroyGlobal() {\n this._deselectMultiDrag();\n off(document, 'pointerup', this._deselectMultiDrag);\n off(document, 'mouseup', this._deselectMultiDrag);\n off(document, 'touchend', this._deselectMultiDrag);\n off(document, 'keydown', this._checkKeyDown);\n off(document, 'keyup', this._checkKeyUp);\n },\n _deselectMultiDrag: function _deselectMultiDrag(evt) {\n if (typeof dragStarted !== \"undefined\" && dragStarted) return;\n\n // Only deselect if selection is in this sortable\n if (multiDragSortable !== this.sortable) return;\n\n // Only deselect if target is not item in this sortable\n if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return;\n\n // Only deselect if left click\n if (evt && evt.button !== 0) return;\n while (multiDragElements.length) {\n var el = multiDragElements[0];\n toggleClass(el, this.options.selectedClass, false);\n multiDragElements.shift();\n dispatchEvent({\n sortable: this.sortable,\n rootEl: this.sortable.el,\n name: 'deselect',\n targetEl: el,\n originalEvent: evt\n });\n }\n },\n _checkKeyDown: function _checkKeyDown(evt) {\n if (evt.key === this.options.multiDragKey) {\n this.multiDragKeyDown = true;\n }\n },\n _checkKeyUp: function _checkKeyUp(evt) {\n if (evt.key === this.options.multiDragKey) {\n this.multiDragKeyDown = false;\n }\n }\n };\n return _extends(MultiDrag, {\n // Static methods & properties\n pluginName: 'multiDrag',\n utils: {\n /**\r\n * Selects the provided multi-drag item\r\n * @param {HTMLElement} el The element to be selected\r\n */\n select: function select(el) {\n var sortable = el.parentNode[expando];\n if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;\n if (multiDragSortable && multiDragSortable !== sortable) {\n multiDragSortable.multiDrag._deselectMultiDrag();\n multiDragSortable = sortable;\n }\n toggleClass(el, sortable.options.selectedClass, true);\n multiDragElements.push(el);\n },\n /**\r\n * Deselects the provided multi-drag item\r\n * @param {HTMLElement} el The element to be deselected\r\n */\n deselect: function deselect(el) {\n var sortable = el.parentNode[expando],\n index = multiDragElements.indexOf(el);\n if (!sortable || !sortable.options.multiDrag || !~index) return;\n toggleClass(el, sortable.options.selectedClass, false);\n multiDragElements.splice(index, 1);\n }\n },\n eventProperties: function eventProperties() {\n var _this3 = this;\n var oldIndicies = [],\n newIndicies = [];\n multiDragElements.forEach(function (multiDragElement) {\n oldIndicies.push({\n multiDragElement: multiDragElement,\n index: multiDragElement.sortableIndex\n });\n\n // multiDragElements will already be sorted if folding\n var newIndex;\n if (folding && multiDragElement !== dragEl$1) {\n newIndex = -1;\n } else if (folding) {\n newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');\n } else {\n newIndex = index(multiDragElement);\n }\n newIndicies.push({\n multiDragElement: multiDragElement,\n index: newIndex\n });\n });\n return {\n items: _toConsumableArray(multiDragElements),\n clones: [].concat(multiDragClones),\n oldIndicies: oldIndicies,\n newIndicies: newIndicies\n };\n },\n optionListeners: {\n multiDragKey: function multiDragKey(key) {\n key = key.toLowerCase();\n if (key === 'ctrl') {\n key = 'Control';\n } else if (key.length > 1) {\n key = key.charAt(0).toUpperCase() + key.substr(1);\n }\n return key;\n }\n }\n });\n}\nfunction insertMultiDragElements(clonesInserted, rootEl) {\n multiDragElements.forEach(function (multiDragElement, i) {\n var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];\n if (target) {\n rootEl.insertBefore(multiDragElement, target);\n } else {\n rootEl.appendChild(multiDragElement);\n }\n });\n}\n\n/**\r\n * Insert multi-drag clones\r\n * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted\r\n * @param {HTMLElement} rootEl\r\n */\nfunction insertMultiDragClones(elementsInserted, rootEl) {\n multiDragClones.forEach(function (clone, i) {\n var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];\n if (target) {\n rootEl.insertBefore(clone, target);\n } else {\n rootEl.appendChild(clone);\n }\n });\n}\nfunction removeMultiDragElements() {\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);\n });\n}\n\nSortable.mount(new AutoScrollPlugin());\nSortable.mount(Remove, Revert);\n\nexport default Sortable;\nexport { MultiDragPlugin as MultiDrag, Sortable, SwapPlugin as Swap };\n", "import { Controller } from \"@hotwired/stimulus\";\nimport { put } from \"@rails/request.js\";\nimport Sortable from \"sortablejs\";\n\n// Connects to data-controller=\"sortable\"\nexport default class extends Controller {\n\tstatic values = {\n\t\tgroup: String,\n\t};\n\n\tconnect() {\n\t\tthis.sortable = Sortable.create(this.element, {\n\t\t\tonEnd: this.onEnd.bind(this),\n\t\t\tgroup: this.groupValue,\n\t\t});\n\t}\n\n\tonEnd(event) {\n\t\tvar sortableUpdateUrl = event.item.dataset.sortableUpdateUrl;\n\t\tvar newIndex = event.newIndex;\n\t\tvar sortableCategoryId = event.to.dataset.sortableCategoryId;\n\t\tconsole.log(sortableUpdateUrl);\n\t\tconsole.log(newIndex);\n\t\tconsole.log(sortableCategoryId);\n\t\tput(sortableUpdateUrl, {\n\t\t\tbody: JSON.stringify({\n\t\t\t\trow_order_position: newIndex,\n\t\t\t\tcategory_id: sortableCategoryId,\n\t\t\t}),\n\t\t});\n\t}\n}\n", "import { Controller } from \"@hotwired/stimulus\";\n\n// Connects to data-controller=\"sticky-form\"\nexport default class extends Controller {\n\tstatic targets = [\"form\"];\n\tstatic classes = [\"fixed\"];\n\n\tconnect() {\n\t\tthis.originalPosition = this.formTarget.getBoundingClientRect().bottom;\n\t}\n\n\tsticky() {\n\t\tthis.formTarget.classList.add(...this.fixedClasses);\n\t}\n\n\tunsticky() {\n\t\tthis.formTarget.classList.remove(...this.fixedClasses);\n\t}\n\n\ttoggleSticky(event) {\n\t\tif (this.formTarget.classList.contains(\"fixed\")) {\n\t\t\tthis.unsticky();\n\t\t} else {\n\t\t\tthis.sticky();\n\t\t}\n\t}\n}\n", "import { Controller } from \"@hotwired/stimulus\"\n\nexport default class extends Controller {\n static values = {\n publicKey: String,\n clientSecret: String,\n }\n\n async connect() {\n this.stripe = Stripe(this.publicKeyValue)\n this.checkout = await this.stripe.initEmbeddedCheckout({clientSecret: this.clientSecretValue})\n this.checkout.mount(this.element)\n }\n\n disconnect() {\n this.checkout.destroy()\n }\n}", "import { Controller } from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"tab-click\"\nexport default class extends Controller {\n static values = {\n targetId: String\n }\n\n handleClick() {\n const targetElement = document.getElementById(this.targetIdValue);\n if (targetElement) {\n targetElement.click();\n }\n }\n}", "import { Controller } from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"tabs-pro\"\nexport default class extends Controller {\n connect() {\n this.loadSelectedTab();\n }\n\n changeTab(event) {\n const label = event.target.getAttribute('aria-label');\n const nameValue = this.element.querySelector('.tab').name; // Assuming all tabs in the same list have the same 'name' attribute\n const storageKey = `selectedTab-${nameValue}`;\n localStorage.setItem(storageKey, label);\n }\n\n loadSelectedTab() {\n const nameValue = this.element.querySelector('.tab').name; // Assuming all tabs in the same list have the same 'name' attribute\n const storageKey = `selectedTab-${nameValue}`;\n const selectedTab = localStorage.getItem(storageKey);\n const tabInputs = this.element.querySelectorAll('.tab');\n\n // Check if a tab is stored in localStorage\n if (selectedTab) {\n tabInputs.forEach((input) => {\n input.checked = (input.getAttribute('aria-label') === selectedTab);\n });\n } else {\n // If there's no tab stored in localStorage, check the first tab\n if (tabInputs.length > 0) {\n tabInputs[0].checked = true;\n }\n }\n }\n}\n", "import {Controller} from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"theme\"\nexport default class extends Controller {\n static targets = [\"button\"]\n\n connect() {\n this.loadTheme();\n }\n\n loadTheme() {\n const savedTheme = localStorage.getItem('theme'); // \u9ED8\u8BA4\u4E3B\u9898\u4E3A 'default'\n this.updateButtonText(savedTheme); // \u6839\u636E\u4FDD\u5B58\u7684\u4E3B\u9898\u66F4\u65B0\u6309\u94AE\u6587\u672C\n }\n\n applyTheme(newTheme) {\n document.documentElement.setAttribute('data-theme',newTheme);\n }\n\n changeTheme(event) {\n const newTheme = event.target.value;\n localStorage.setItem('theme', newTheme);\n this.applyTheme(newTheme);\n this.updateButtonText(newTheme); // \u66F4\u65B0\u6309\u94AE\u6587\u672C\n }\n\n updateButtonText(theme) {\n // \u786E\u4FDD\u4E3B\u9898\u540D\u9996\u5B57\u6BCD\u5927\u5199\n this.buttonTarget.textContent = theme\n .split('_')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n }\n}\n", "import { Controller } from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"theme-loading\"\nexport default class extends Controller {\n connect() {\n const savedTheme = localStorage.getItem('theme') || 'cupcake';\n document.documentElement.setAttribute('data-theme', savedTheme);\n }\n}", "import { Controller } from \"@hotwired/stimulus\"\n// import { transition } from \"./transition\"\n\n// Connects to data-controller=\"toggleable\"\nexport default class extends Controller {\n static targets = ['toggleable', 'open', 'close']\n static values = {\n open: { type: Boolean, default: false },\n id: { type: String, default: \"default\" }\n }\n\n connect() {\n // \u628A id \u4F5C\u4E3A 'toggleable' \u6807\u8BC6\u7B26\u7684\u4E00\u90E8\u5206\uFF0C\u4FDD\u5B58\u5230 localStorage\n // \u5982\u679C localStorage \u4E2D\u6709 id \u5BF9\u5E94\u7684\u503C\uFF0C\u5C31\u4F7F\u7528\u5B83\uFF0C\u5426\u5219\u4F7F\u7528\u9ED8\u8BA4\u503C\n if (localStorage.getItem(`toggleable-${this.idValue}`) === 'open') {\n this.show()\n } else {\n this.hide()\n }\n }\n\n toggle(event) {\n this.openValue = !this.openValue\n // this.animate()\n }\n\n // Sets open to value of checkbox or radio\n toggleInput(event) {\n this.openValue = event.target.checked\n // this.animate()\n }\n\n show() {\n localStorage.setItem(`toggleable-${this.idValue}`, 'open')\n if (this.hasOpenTarget) {\n this.openTarget.classList.add('hidden')\n }\n if (this.hasCloseTarget) {\n this.closeTarget.classList.remove('hidden')\n }\n this.toggleableTargets.forEach(target => {\n target.classList.remove('hidden')\n })\n // this.animate()\n }\n\n hide() {\n localStorage.setItem(`toggleable-${this.idValue}`, 'close')\n if (this.hasCloseTarget) {\n this.closeTarget.classList.add('hidden')\n }\n if (this.hasOpenTarget) {\n this.openTarget.classList.remove('hidden')\n }\n this.toggleableTargets.forEach(target => {\n target.classList.add('hidden')\n })\n // this.animate()\n }\n\n animate() {\n this.toggleableTargets.forEach(target => {\n transition(target, this.openValue)\n })\n }\n}\n", "import { Controller } from \"@hotwired/stimulus\"\n\n// Connects to data-controller=\"sidebar-scroll-position\"\nexport default class extends Controller {\n connect() {\n const scrollTop = localStorage.getItem(\"sidebarScrollPosition\");\n\n if (scrollTop) {\n this.element.style.overflow = \"hidden\"; // \u4E34\u65F6\u9690\u85CF\u6EDA\u52A8\u6761\n this.element.scrollTop = scrollTop;\n\n // \u77ED\u6682\u5EF6\u8FDF\u540E\u6062\u590D\u6EDA\u52A8\u6761\n setTimeout(() => {\n this.element.style.overflow = \"auto\";\n }, 50);\n }\n }\n\n scroll() {\n localStorage.setItem(\"sidebarScrollPosition\", this.element.scrollTop);\n }\n}\n", "// This file is auto-generated by ./bin/rails stimulus:manifest:update\n// Run that command whenever you add a new controller or create them with\n// ./bin/rails generate stimulus controllerName\n\nimport { application } from \"./application\"\n\nimport AutogrowController from \"./autogrow_controller\"\napplication.register(\"autogrow\", AutogrowController)\n\nimport ChildrenCommentsController from \"./children_comments_controller\"\napplication.register(\"children-comments\", ChildrenCommentsController)\n\nimport CommentReplyController from \"./comment_reply_controller\"\napplication.register(\"comment-reply\", CommentReplyController)\n\nimport ExtensionAuthController from \"./extension_auth_controller\"\napplication.register(\"extension-auth\", ExtensionAuthController)\n\nimport FilterController from \"./filter_controller\"\napplication.register(\"filter\", FilterController)\n\nimport HelloController from \"./hello_controller\"\napplication.register(\"hello\", HelloController)\n\nimport LinkActiveController from \"./link_active_controller\"\napplication.register(\"link-active\", LinkActiveController)\n\nimport MarkdownDisplayController from \"./markdown_display_controller\"\napplication.register(\"markdown-display\", MarkdownDisplayController)\n\nimport ModalController from \"./modal_controller\"\napplication.register(\"modal\", ModalController)\n\nimport OptionsController from \"./options_controller\"\napplication.register(\"options\", OptionsController)\n\nimport ProgressDelayController from \"./progress_delay_controller\"\napplication.register(\"progress-delay\", ProgressDelayController)\n\nimport RemovalController from \"./removal_controller\"\napplication.register(\"removal\", RemovalController)\n\nimport SelectButtonController from \"./select_button_controller\"\napplication.register(\"select-button\", SelectButtonController)\n\nimport SendMessageController from \"./send_message_controller\"\napplication.register(\"send-message\", SendMessageController)\n\nimport SharerController from \"./sharer_controller\"\napplication.register(\"sharer\", SharerController)\n\nimport ShowMoreController from \"./show_more_controller\"\napplication.register(\"show-more\", ShowMoreController)\n\nimport SlideController from \"./slide_controller\"\napplication.register(\"slide\", SlideController)\n\nimport SortableController from \"./sortable_controller\"\napplication.register(\"sortable\", SortableController)\n\nimport StickyFormController from \"./sticky_form_controller\"\napplication.register(\"sticky-form\", StickyFormController)\n\nimport Stripe__EmbeddedCheckoutController from \"./stripe/embedded_checkout_controller\"\napplication.register(\"stripe--embedded-checkout\", Stripe__EmbeddedCheckoutController)\n\nimport TabClickController from \"./tab_click_controller\"\napplication.register(\"tab-click\", TabClickController)\n\nimport TabsProController from \"./tabs_pro_controller\"\napplication.register(\"tabs-pro\", TabsProController)\n\nimport ThemeController from \"./theme_controller\"\napplication.register(\"theme\", ThemeController)\n\nimport ThemeLoadingController from \"./theme_loading_controller\"\napplication.register(\"theme-loading\", ThemeLoadingController)\n\nimport ToggleableController from \"./toggleable_controller\"\napplication.register(\"toggleable\", ToggleableController)\n\nimport SidebarScrollPositionController from \"./sidebar_scroll_position_controller\"\napplication.register(\"sidebar-scroll-position\", SidebarScrollPositionController)\n", "export const attachmentSelector = \"[data-trix-attachment]\"\n\nconst attachments = {\n preview: {\n presentation: \"gallery\",\n caption: {\n name: true,\n size: true,\n },\n },\n file: {\n caption: {\n size: true,\n },\n },\n}\nexport default attachments\n", "const attributes = {\n default: {\n tagName: \"div\",\n parse: false,\n },\n quote: {\n tagName: \"blockquote\",\n nestable: true,\n },\n heading1: {\n tagName: \"h1\",\n terminal: true,\n breakOnReturn: true,\n group: false,\n },\n code: {\n tagName: \"pre\",\n terminal: true,\n htmlAttributes: [ \"language\" ],\n text: {\n plaintext: true,\n },\n },\n bulletList: {\n tagName: \"ul\",\n parse: false,\n },\n bullet: {\n tagName: \"li\",\n listAttribute: \"bulletList\",\n group: false,\n nestable: true,\n test(element) {\n return tagName(element.parentNode) === attributes[this.listAttribute].tagName\n },\n },\n numberList: {\n tagName: \"ol\",\n parse: false,\n },\n number: {\n tagName: \"li\",\n listAttribute: \"numberList\",\n group: false,\n nestable: true,\n test(element) {\n return tagName(element.parentNode) === attributes[this.listAttribute].tagName\n },\n },\n attachmentGallery: {\n tagName: \"div\",\n exclusive: true,\n terminal: true,\n parse: false,\n group: false,\n },\n}\n\nconst tagName = (element) => element?.tagName?.toLowerCase()\n\nexport default attributes\n", "const androidVersionMatch = navigator.userAgent.match(/android\\s([0-9]+.*Chrome)/i)\nconst androidVersion = androidVersionMatch && parseInt(androidVersionMatch[1])\n\nexport default {\n // Android emits composition events when moving the cursor through existing text\n // Introduced in Chrome 65: https://bugs.chromium.org/p/chromium/issues/detail?id=764439#c9\n composesExistingText: /Android.*Chrome/.test(navigator.userAgent),\n\n // Android 13, especially on Samsung keyboards, emits extra compositionend and beforeinput events\n // that can make the input handler lose the current selection or enter an infinite input -> render -> input\n // loop.\n recentAndroid: androidVersion && androidVersion > 12,\n samsungAndroid: androidVersion && navigator.userAgent.match(/Android.*SM-/),\n\n // IE 11 activates resizing handles on editable elements that have \"layout\"\n forcesObjectResizing: /Trident.*rv:11/.test(navigator.userAgent),\n // https://www.w3.org/TR/input-events-1/ + https://www.w3.org/TR/input-events-2/\n supportsInputEvents: typeof InputEvent !== \"undefined\" &&\n [ \"data\", \"getTargetRanges\", \"inputType\" ].every(prop => prop in InputEvent.prototype),\n}\n", "export default {\n ADD_ATTR: [ \"language\" ],\n SAFE_FOR_XML: false,\n RETURN_DOM: true\n}\n", "export default {\n attachFiles: \"Attach Files\",\n bold: \"Bold\",\n bullets: \"Bullets\",\n byte: \"Byte\",\n bytes: \"Bytes\",\n captionPlaceholder: \"Add a caption…\",\n code: \"Code\",\n heading1: \"Heading\",\n indent: \"Increase Level\",\n italic: \"Italic\",\n link: \"Link\",\n numbers: \"Numbers\",\n outdent: \"Decrease Level\",\n quote: \"Quote\",\n redo: \"Redo\",\n remove: \"Remove\",\n strike: \"Strikethrough\",\n undo: \"Undo\",\n unlink: \"Unlink\",\n url: \"URL\",\n urlPlaceholder: \"Enter a URL…\",\n GB: \"GB\",\n KB: \"KB\",\n MB: \"MB\",\n PB: \"PB\",\n TB: \"TB\",\n}\n", "/* eslint-disable\n no-case-declarations,\n*/\nimport lang from \"trix/config/lang\"\n\nconst sizes = [ lang.bytes, lang.KB, lang.MB, lang.GB, lang.TB, lang.PB ]\n\nexport default {\n prefix: \"IEC\",\n precision: 2,\n\n formatter(number) {\n switch (number) {\n case 0:\n return `0 ${lang.bytes}`\n case 1:\n return `1 ${lang.byte}`\n default:\n let base\n\n if (this.prefix === \"SI\") {\n base = 1000\n } else if (this.prefix === \"IEC\") {\n base = 1024\n }\n\n const exp = Math.floor(Math.log(number) / Math.log(base))\n const humanSize = number / Math.pow(base, exp)\n const string = humanSize.toFixed(this.precision)\n const withoutInsignificantZeros = string.replace(/0*$/, \"\").replace(/\\.$/, \"\")\n return `${withoutInsignificantZeros} ${sizes[exp]}`\n }\n },\n}\n", "export const ZERO_WIDTH_SPACE = \"\\uFEFF\"\nexport const NON_BREAKING_SPACE = \"\\u00A0\"\nexport const OBJECT_REPLACEMENT_CHARACTER = \"\\uFFFC\"\n", "export const extend = function(properties) {\n for (const key in properties) {\n const value = properties[key]\n this[key] = value\n }\n return this\n}\n", "import blockAttributes from \"trix/config/block_attributes\"\nimport { ZERO_WIDTH_SPACE } from \"trix/constants\"\nimport { extend } from \"./extend\"\nimport { attachmentSelector } from \"trix/config/attachments\"\n\nconst html = document.documentElement\nconst match = html.matches\n\nexport const handleEvent = function(eventName, { onElement, matchingSelector, withCallback, inPhase, preventDefault, times } = {}) {\n const element = onElement ? onElement : html\n const selector = matchingSelector\n const useCapture = inPhase === \"capturing\"\n\n const handler = function(event) {\n if (times != null && --times === 0) {\n handler.destroy()\n }\n const target = findClosestElementFromNode(event.target, { matchingSelector: selector })\n if (target != null) {\n withCallback?.call(target, event, target)\n if (preventDefault) {\n event.preventDefault()\n }\n }\n }\n\n handler.destroy = () => element.removeEventListener(eventName, handler, useCapture)\n\n element.addEventListener(eventName, handler, useCapture)\n return handler\n}\n\nexport const handleEventOnce = function(eventName, options = {}) {\n options.times = 1\n return handleEvent(eventName, options)\n}\n\nexport const triggerEvent = function(eventName, { onElement, bubbles, cancelable, attributes } = {}) {\n const element = onElement != null ? onElement : html\n bubbles = bubbles !== false\n cancelable = cancelable !== false\n\n const event = document.createEvent(\"Events\")\n event.initEvent(eventName, bubbles, cancelable)\n if (attributes != null) {\n extend.call(event, attributes)\n }\n return element.dispatchEvent(event)\n}\n\nexport const elementMatchesSelector = function(element, selector) {\n if (element?.nodeType === 1) {\n return match.call(element, selector)\n }\n}\n\nexport const findClosestElementFromNode = function(node, { matchingSelector, untilNode } = {}) {\n while (node && node.nodeType !== Node.ELEMENT_NODE) {\n node = node.parentNode\n }\n if (node == null) {\n return\n }\n\n if (matchingSelector != null) {\n if (node.closest && untilNode == null) {\n return node.closest(matchingSelector)\n } else {\n while (node && node !== untilNode) {\n if (elementMatchesSelector(node, matchingSelector)) {\n return node\n }\n node = node.parentNode\n }\n }\n } else {\n return node\n }\n}\n\nexport const findInnerElement = function(element) {\n while (element?.firstElementChild) {\n element = element.firstElementChild\n }\n return element\n}\n\nexport const innerElementIsActive = (element) =>\n document.activeElement !== element && elementContainsNode(element, document.activeElement)\n\nexport const elementContainsNode = function(element, node) {\n if (!element || !node) {\n return\n }\n while (node) {\n if (node === element) {\n return true\n }\n node = node.parentNode\n }\n}\n\nexport const findNodeFromContainerAndOffset = function(container, offset) {\n if (!container) {\n return\n }\n if (container.nodeType === Node.TEXT_NODE) {\n return container\n } else if (offset === 0) {\n return container.firstChild != null ? container.firstChild : container\n } else {\n return container.childNodes.item(offset - 1)\n }\n}\n\nexport const findElementFromContainerAndOffset = function(container, offset) {\n const node = findNodeFromContainerAndOffset(container, offset)\n return findClosestElementFromNode(node)\n}\n\nexport const findChildIndexOfNode = function(node) {\n if (!node?.parentNode) {\n return\n }\n let childIndex = 0\n node = node.previousSibling\n while (node) {\n childIndex++\n node = node.previousSibling\n }\n return childIndex\n}\n\nexport const removeNode = (node) => node?.parentNode?.removeChild(node)\n\nexport const walkTree = function(tree, { onlyNodesOfType, usingFilter, expandEntityReferences } = {}) {\n const whatToShow = (() => {\n switch (onlyNodesOfType) {\n case \"element\":\n return NodeFilter.SHOW_ELEMENT\n case \"text\":\n return NodeFilter.SHOW_TEXT\n case \"comment\":\n return NodeFilter.SHOW_COMMENT\n default:\n return NodeFilter.SHOW_ALL\n }\n })()\n\n return document.createTreeWalker(\n tree,\n whatToShow,\n usingFilter != null ? usingFilter : null,\n expandEntityReferences === true\n )\n}\n\nexport const tagName = (element) => element?.tagName?.toLowerCase()\n\nexport const makeElement = function(tag, options = {}) {\n let key, value\n if (typeof tag === \"object\") {\n options = tag\n tag = options.tagName\n } else {\n options = { attributes: options }\n }\n\n const element = document.createElement(tag)\n\n if (options.editable != null) {\n if (options.attributes == null) {\n options.attributes = {}\n }\n options.attributes.contenteditable = options.editable\n }\n\n if (options.attributes) {\n for (key in options.attributes) {\n value = options.attributes[key]\n element.setAttribute(key, value)\n }\n }\n\n if (options.style) {\n for (key in options.style) {\n value = options.style[key]\n element.style[key] = value\n }\n }\n\n if (options.data) {\n for (key in options.data) {\n value = options.data[key]\n element.dataset[key] = value\n }\n }\n\n if (options.className) {\n options.className.split(\" \").forEach((className) => {\n element.classList.add(className)\n })\n }\n\n if (options.textContent) {\n element.textContent = options.textContent\n }\n\n if (options.childNodes) {\n [].concat(options.childNodes).forEach((childNode) => {\n element.appendChild(childNode)\n })\n }\n\n return element\n}\n\nlet blockTagNames = undefined\n\nexport const getBlockTagNames = function() {\n if (blockTagNames != null) {\n return blockTagNames\n }\n\n blockTagNames = []\n for (const key in blockAttributes) {\n const attributes = blockAttributes[key]\n if (attributes.tagName) {\n blockTagNames.push(attributes.tagName)\n }\n }\n\n return blockTagNames\n}\n\nexport const nodeIsBlockContainer = (node) => nodeIsBlockStartComment(node?.firstChild)\n\nexport const nodeProbablyIsBlockContainer = function(node) {\n return getBlockTagNames().includes(tagName(node)) && !getBlockTagNames().includes(tagName(node.firstChild))\n}\n\nexport const nodeIsBlockStart = function(node, { strict } = { strict: true }) {\n if (strict) {\n return nodeIsBlockStartComment(node)\n } else {\n return (\n nodeIsBlockStartComment(node) || !nodeIsBlockStartComment(node.firstChild) && nodeProbablyIsBlockContainer(node)\n )\n }\n}\n\nexport const nodeIsBlockStartComment = (node) => nodeIsCommentNode(node) && node?.data === \"block\"\n\nexport const nodeIsCommentNode = (node) => node?.nodeType === Node.COMMENT_NODE\n\nexport const nodeIsCursorTarget = function(node, { name } = {}) {\n if (!node) {\n return\n }\n if (nodeIsTextNode(node)) {\n if (node.data === ZERO_WIDTH_SPACE) {\n if (name) {\n return node.parentNode.dataset.trixCursorTarget === name\n } else {\n return true\n }\n }\n } else {\n return nodeIsCursorTarget(node.firstChild)\n }\n}\n\nexport const nodeIsAttachmentElement = (node) => elementMatchesSelector(node, attachmentSelector)\n\nexport const nodeIsEmptyTextNode = (node) => nodeIsTextNode(node) && node?.data === \"\"\n\nexport const nodeIsTextNode = (node) => node?.nodeType === Node.TEXT_NODE\n", "import browser from \"trix/config/browser\"\nimport { makeElement, removeNode } from \"trix/core/helpers/dom\"\n\nconst input = {\n level2Enabled: true,\n\n getLevel() {\n if (this.level2Enabled && browser.supportsInputEvents) {\n return 2\n } else {\n return 0\n }\n },\n pickFiles(callback) {\n const input = makeElement(\"input\", { type: \"file\", multiple: true, hidden: true, id: this.fileInputId })\n\n input.addEventListener(\"change\", () => {\n callback(input.files)\n removeNode(input)\n })\n\n removeNode(document.getElementById(this.fileInputId))\n document.body.appendChild(input)\n input.click()\n }\n}\n\nexport default input\n", "export default {\n 8: \"backspace\",\n 9: \"tab\",\n 13: \"return\",\n 27: \"escape\",\n 37: \"left\",\n 39: \"right\",\n 46: \"delete\",\n 68: \"d\",\n 72: \"h\",\n 79: \"o\",\n}\n", "export default {\n removeBlankTableCells: false,\n tableCellSeparator: \" | \",\n tableRowSeparator: \"\\n\",\n}\n", "import { attachmentSelector } from \"trix/config/attachments\"\n\nexport default {\n bold: {\n tagName: \"strong\",\n inheritable: true,\n parser(element) {\n const style = window.getComputedStyle(element)\n return style.fontWeight === \"bold\" || style.fontWeight >= 600\n },\n },\n italic: {\n tagName: \"em\",\n inheritable: true,\n parser(element) {\n const style = window.getComputedStyle(element)\n return style.fontStyle === \"italic\"\n },\n },\n href: {\n groupTagName: \"a\",\n parser(element) {\n const matchingSelector = `a:not(${attachmentSelector})`\n const link = element.closest(matchingSelector)\n if (link) {\n return link.getAttribute(\"href\")\n }\n },\n },\n strike: {\n tagName: \"del\",\n inheritable: true,\n },\n frozen: {\n style: { backgroundColor: \"highlight\" },\n },\n}\n", "import lang from \"trix/config/lang\"\n\nexport default {\n getDefaultHTML() {\n return `\n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n\n \n \n \n\n \n\n \n \n \n \n
\n\n `\n },\n}\n", "const undo = { interval: 5000 }\nexport default undo\n", "export default {\n attachment: \"attachment\",\n attachmentCaption: \"attachment__caption\",\n attachmentCaptionEditor: \"attachment__caption-editor\",\n attachmentMetadata: \"attachment__metadata\",\n attachmentMetadataContainer: \"attachment__metadata-container\",\n attachmentName: \"attachment__name\",\n attachmentProgress: \"attachment__progress\",\n attachmentSize: \"attachment__size\",\n attachmentToolbar: \"attachment__toolbar\",\n attachmentGallery: \"attachment-gallery\",\n}\n", "export default class BasicObject {\n static proxyMethod(expression) {\n const { name, toMethod, toProperty, optional } = parseProxyMethodExpression(expression)\n\n this.prototype[name] = function() {\n let subject\n let object\n\n if (toMethod) {\n if (optional) {\n object = this[toMethod]?.()\n } else {\n object = this[toMethod]()\n }\n } else if (toProperty) {\n object = this[toProperty]\n }\n\n if (optional) {\n subject = object?.[name]\n if (subject) {\n return apply.call(subject, object, arguments)\n }\n } else {\n subject = object[name]\n return apply.call(subject, object, arguments)\n }\n }\n }\n}\n\nconst parseProxyMethodExpression = function(expression) {\n const match = expression.match(proxyMethodExpressionPattern)\n if (!match) {\n throw new Error(`can't parse @proxyMethod expression: ${expression}`)\n }\n\n const args = { name: match[4] }\n\n if (match[2] != null) {\n args.toMethod = match[1]\n } else {\n args.toProperty = match[1]\n }\n\n if (match[3] != null) {\n args.optional = true\n }\n\n return args\n}\n\nconst { apply } = Function.prototype\n\nconst proxyMethodExpressionPattern = new RegExp(\"\\\n^\\\n(.+?)\\\n(\\\\(\\\\))?\\\n(\\\\?)?\\\n\\\\.\\\n(.+?)\\\n$\\\n\")\n", "import BasicObject from \"trix/core/basic_object\"\n\nexport default class UTF16String extends BasicObject {\n static box(value = \"\") {\n if (value instanceof this) {\n return value\n } else {\n return this.fromUCS2String(value?.toString())\n }\n }\n\n static fromUCS2String(ucs2String) {\n return new this(ucs2String, ucs2decode(ucs2String))\n }\n\n static fromCodepoints(codepoints) {\n return new this(ucs2encode(codepoints), codepoints)\n }\n\n constructor(ucs2String, codepoints) {\n super(...arguments)\n this.ucs2String = ucs2String\n this.codepoints = codepoints\n this.length = this.codepoints.length\n this.ucs2Length = this.ucs2String.length\n }\n\n offsetToUCS2Offset(offset) {\n return ucs2encode(this.codepoints.slice(0, Math.max(0, offset))).length\n }\n\n offsetFromUCS2Offset(ucs2Offset) {\n return ucs2decode(this.ucs2String.slice(0, Math.max(0, ucs2Offset))).length\n }\n\n slice() {\n return this.constructor.fromCodepoints(this.codepoints.slice(...arguments))\n }\n\n charAt(offset) {\n return this.slice(offset, offset + 1)\n }\n\n isEqualTo(value) {\n return this.constructor.box(value).ucs2String === this.ucs2String\n }\n\n toJSON() {\n return this.ucs2String\n }\n\n getCacheKey() {\n return this.ucs2String\n }\n\n toString() {\n return this.ucs2String\n }\n}\n\nconst hasArrayFrom = Array.from?.(\"\\ud83d\\udc7c\").length === 1\nconst hasStringCodePointAt = \" \".codePointAt?.(0) != null\nconst hasStringFromCodePoint = String.fromCodePoint?.(32, 128124) === \" \\ud83d\\udc7c\"\n\n// UCS-2 conversion helpers ported from Mathias Bynens' Punycode.js:\n// https://github.com/bestiejs/punycode.js#punycodeucs2\n\nlet ucs2decode, ucs2encode\n\n// Creates an array containing the numeric code points of each Unicode\n// character in the string. While JavaScript uses UCS-2 internally,\n// this function will convert a pair of surrogate halves (each of which\n// UCS-2 exposes as separate characters) into a single code point,\n// matching UTF-16.\nif (hasArrayFrom && hasStringCodePointAt) {\n ucs2decode = (string) => Array.from(string).map((char) => char.codePointAt(0))\n} else {\n ucs2decode = function(string) {\n const output = []\n let counter = 0\n const { length } = string\n\n while (counter < length) {\n let value = string.charCodeAt(counter++)\n if (0xd800 <= value && value <= 0xdbff && counter < length) {\n // high surrogate, and there is a next character\n const extra = string.charCodeAt(counter++)\n if ((extra & 0xfc00) === 0xdc00) {\n // low surrogate\n value = ((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000\n } else {\n // unmatched surrogate; only append this code unit, in case the\n // next code unit is the high surrogate of a surrogate pair\n counter--\n }\n }\n output.push(value)\n }\n\n return output\n }\n}\n\n// Creates a string based on an array of numeric code points.\nif (hasStringFromCodePoint) {\n ucs2encode = (array) => String.fromCodePoint(...Array.from(array || []))\n} else {\n ucs2encode = function(array) {\n const characters = (() => {\n const result = []\n\n Array.from(array).forEach((value) => {\n let output = \"\"\n if (value > 0xffff) {\n value -= 0x10000\n output += String.fromCharCode(value >>> 10 & 0x3ff | 0xd800)\n value = 0xdc00 | value & 0x3ff\n }\n result.push(output + String.fromCharCode(value))\n })\n\n return result\n })()\n\n return characters.join(\"\")\n }\n}\n", "import BasicObject from \"trix/core/basic_object\"\nimport UTF16String from \"trix/core/utilities/utf16_string\"\n\nlet id = 0\n\nexport default class TrixObject extends BasicObject {\n static fromJSONString(jsonString) {\n return this.fromJSON(JSON.parse(jsonString))\n }\n\n constructor() {\n super(...arguments)\n this.id = ++id\n }\n\n hasSameConstructorAs(object) {\n return this.constructor === object?.constructor\n }\n\n isEqualTo(object) {\n return this === object\n }\n\n inspect() {\n const parts = []\n const contents = this.contentsForInspection() || {}\n\n for (const key in contents) {\n const value = contents[key]\n parts.push(`${key}=${value}`)\n }\n\n return `#<${this.constructor.name}:${this.id}${parts.length ? ` ${parts.join(\", \")}` : \"\"}>`\n }\n\n contentsForInspection() {}\n\n toJSONString() {\n return JSON.stringify(this)\n }\n\n toUTF16String() {\n return UTF16String.box(this)\n }\n\n getCacheKey() {\n return this.id.toString()\n }\n}\n", "/* eslint-disable\n id-length,\n*/\nexport const arraysAreEqual = function(a = [], b = []) {\n if (a.length !== b.length) {\n return false\n }\n for (let index = 0; index < a.length; index++) {\n const value = a[index]\n if (value !== b[index]) {\n return false\n }\n }\n return true\n}\n\nexport const arrayStartsWith = (a = [], b = []) => arraysAreEqual(a.slice(0, b.length), b)\n\nexport const spliceArray = function(array, ...args) {\n const result = array.slice(0)\n result.splice(...args)\n return result\n}\n\nexport const summarizeArrayChange = function(oldArray = [], newArray = []) {\n const added = []\n const removed = []\n\n const existingValues = new Set()\n\n oldArray.forEach((value) => {\n existingValues.add(value)\n })\n\n const currentValues = new Set()\n\n newArray.forEach((value) => {\n currentValues.add(value)\n if (!existingValues.has(value)) {\n added.push(value)\n }\n })\n\n oldArray.forEach((value) => {\n if (!currentValues.has(value)) {\n removed.push(value)\n }\n })\n\n return { added, removed }\n}\n", "import { makeElement } from \"trix/core/helpers/dom\"\n\n// https://github.com/mathiasbynens/unicode-2.1.8/blob/master/Bidi_Class/Right_To_Left/regex.js\nconst RTL_PATTERN =\n /[\\u05BE\\u05C0\\u05C3\\u05D0-\\u05EA\\u05F0-\\u05F4\\u061B\\u061F\\u0621-\\u063A\\u0640-\\u064A\\u066D\\u0671-\\u06B7\\u06BA-\\u06BE\\u06C0-\\u06CE\\u06D0-\\u06D5\\u06E5\\u06E6\\u200F\\u202B\\u202E\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE72\\uFE74\\uFE76-\\uFEFC]/\n\nexport const getDirection = (function() {\n const input = makeElement(\"input\", { dir: \"auto\", name: \"x\", dirName: \"x.dir\" })\n const textArea = makeElement(\"textarea\", { dir: \"auto\", name: \"y\", dirName: \"y.dir\" })\n const form = makeElement(\"form\")\n form.appendChild(input)\n form.appendChild(textArea)\n\n const supportsDirName = (function() {\n try {\n return new FormData(form).has(textArea.dirName)\n } catch (error) {\n return false\n }\n })()\n\n const supportsDirSelector = (function() {\n try {\n return input.matches(\":dir(ltr),:dir(rtl)\")\n } catch (error) {\n return false\n }\n })()\n\n if (supportsDirName) {\n return function(string) {\n textArea.value = string\n return new FormData(form).get(textArea.dirName)\n }\n } else if (supportsDirSelector) {\n return function(string) {\n input.value = string\n if (input.matches(\":dir(rtl)\")) {\n return \"rtl\"\n } else {\n return \"ltr\"\n }\n }\n } else {\n return function(string) {\n const char = string.trim().charAt(0)\n if (RTL_PATTERN.test(char)) {\n return \"rtl\"\n } else {\n return \"ltr\"\n }\n }\n }\n})()\n", "import * as config from \"trix/config\"\n\nlet allAttributeNames = null\nlet blockAttributeNames = null\nlet textAttributeNames = null\nlet listAttributeNames = null\n\nexport const getAllAttributeNames = () => {\n if (!allAttributeNames) {\n allAttributeNames = getTextAttributeNames().concat(getBlockAttributeNames())\n }\n return allAttributeNames\n}\n\nexport const getBlockConfig = (attributeName) => config.blockAttributes[attributeName]\n\nexport const getBlockAttributeNames = () => {\n if (!blockAttributeNames) {\n blockAttributeNames = Object.keys(config.blockAttributes)\n }\n return blockAttributeNames\n}\n\nexport const getTextConfig = (attributeName) => config.textAttributes[attributeName]\n\nexport const getTextAttributeNames = () => {\n if (!textAttributeNames) {\n textAttributeNames = Object.keys(config.textAttributes)\n }\n return textAttributeNames\n}\n\nexport const getListAttributeNames = () => {\n if (!listAttributeNames) {\n listAttributeNames = []\n for (const key in config.blockAttributes) {\n const { listAttribute } = config.blockAttributes[key]\n if (listAttribute != null) {\n listAttributeNames.push(listAttribute)\n }\n }\n }\n return listAttributeNames\n}\n", "/* eslint-disable\n*/\nexport const installDefaultCSSForTagName = function(tagName, defaultCSS) {\n const styleElement = insertStyleElementForTagName(tagName)\n styleElement.textContent = defaultCSS.replace(/%t/g, tagName)\n}\n\nconst insertStyleElementForTagName = function(tagName) {\n const element = document.createElement(\"style\")\n element.setAttribute(\"type\", \"text/css\")\n element.setAttribute(\"data-tag-name\", tagName.toLowerCase())\n const nonce = getCSPNonce()\n if (nonce) {\n element.setAttribute(\"nonce\", nonce)\n }\n document.head.insertBefore(element, document.head.firstChild)\n return element\n}\n\nconst getCSPNonce = function() {\n const element = getMetaElement(\"trix-csp-nonce\") || getMetaElement(\"csp-nonce\")\n if (element) {\n const { nonce, content } = element\n return nonce == \"\" ? content : nonce\n }\n}\n\nconst getMetaElement = (name) => document.head.querySelector(`meta[name=${name}]`)\n", "const testTransferData = { \"application/x-trix-feature-detection\": \"test\" }\n\nexport const dataTransferIsPlainText = function(dataTransfer) {\n const text = dataTransfer.getData(\"text/plain\")\n const html = dataTransfer.getData(\"text/html\")\n\n if (text && html) {\n const { body } = new DOMParser().parseFromString(html, \"text/html\")\n if (body.textContent === text) {\n return !body.querySelector(\"*\")\n }\n } else {\n return text?.length\n }\n}\n\nexport const dataTransferIsMsOfficePaste = ({ dataTransfer }) => {\n return dataTransfer.types.includes(\"Files\") &&\n dataTransfer.types.includes(\"text/html\") &&\n dataTransfer.getData(\"text/html\").includes(\"urn:schemas-microsoft-com:office:office\")\n}\n\nexport const dataTransferIsWritable = function(dataTransfer) {\n if (!dataTransfer?.setData) return false\n\n for (const key in testTransferData) {\n const value = testTransferData[key]\n\n try {\n dataTransfer.setData(key, value)\n if (!dataTransfer.getData(key) === value) return false\n } catch (error) {\n return false\n }\n }\n return true\n}\n\nexport const keyEventIsKeyboardCommand = (function() {\n if (/Mac|^iP/.test(navigator.platform)) {\n return (event) => event.metaKey\n } else {\n return (event) => event.ctrlKey\n }\n})()\n\nexport function shouldRenderInmmediatelyToDealWithIOSDictation(inputEvent) {\n if (/iPhone|iPad/.test(navigator.userAgent)) {\n // Handle garbled content and duplicated newlines when using dictation on iOS 18+. Upon dictation completion, iOS sends\n // the list of insertText / insertParagraph events in a quick sequence. If we don't render\n // the editor synchronously, the internal range fails to update and results in garbled content or duplicated newlines.\n //\n // This workaround is necessary because iOS doesn't send composing events as expected while dictating:\n // https://bugs.webkit.org/show_bug.cgi?id=261764\n return !inputEvent.inputType || inputEvent.inputType === \"insertParagraph\"\n } else {\n return false\n }\n}\n", "export const defer = (fn) => setTimeout(fn, 1)\n", "/* eslint-disable\n id-length,\n*/\nexport const copyObject = function(object = {}) {\n const result = {}\n for (const key in object) {\n const value = object[key]\n result[key] = value\n }\n return result\n}\n\nexport const objectsAreEqual = function(a = {}, b = {}) {\n if (Object.keys(a).length !== Object.keys(b).length) {\n return false\n }\n for (const key in a) {\n const value = a[key]\n if (value !== b[key]) {\n return false\n }\n }\n return true\n}\n", "import { copyObject, objectsAreEqual } from \"trix/core/helpers/objects\"\n\nexport const normalizeRange = function(range) {\n if (range == null) return\n\n if (!Array.isArray(range)) {\n range = [ range, range ]\n }\n return [ copyValue(range[0]), copyValue(range[1] != null ? range[1] : range[0]) ]\n}\n\nexport const rangeIsCollapsed = function(range) {\n if (range == null) return\n\n const [ start, end ] = normalizeRange(range)\n return rangeValuesAreEqual(start, end)\n}\n\nexport const rangesAreEqual = function(leftRange, rightRange) {\n if (leftRange == null || rightRange == null) return\n\n const [ leftStart, leftEnd ] = normalizeRange(leftRange)\n const [ rightStart, rightEnd ] = normalizeRange(rightRange)\n return rangeValuesAreEqual(leftStart, rightStart) && rangeValuesAreEqual(leftEnd, rightEnd)\n}\n\nconst copyValue = function(value) {\n if (typeof value === \"number\") {\n return value\n } else {\n return copyObject(value)\n }\n}\n\nconst rangeValuesAreEqual = function(left, right) {\n if (typeof left === \"number\") {\n return left === right\n } else {\n return objectsAreEqual(left, right)\n }\n}\n", "import BasicObject from \"trix/core/basic_object\"\n\nexport default class SelectionChangeObserver extends BasicObject {\n constructor() {\n super(...arguments)\n this.update = this.update.bind(this)\n this.selectionManagers = []\n }\n\n start() {\n if (!this.started) {\n this.started = true\n document.addEventListener(\"selectionchange\", this.update, true)\n }\n }\n\n stop() {\n if (this.started) {\n this.started = false\n return document.removeEventListener(\"selectionchange\", this.update, true)\n }\n }\n\n registerSelectionManager(selectionManager) {\n if (!this.selectionManagers.includes(selectionManager)) {\n this.selectionManagers.push(selectionManager)\n return this.start()\n }\n }\n\n unregisterSelectionManager(selectionManager) {\n this.selectionManagers = this.selectionManagers.filter((sm) => sm !== selectionManager)\n if (this.selectionManagers.length === 0) {\n return this.stop()\n }\n }\n\n notifySelectionManagersOfSelectionChange() {\n return this.selectionManagers.map((selectionManager) => selectionManager.selectionDidChange())\n }\n\n update() {\n this.notifySelectionManagersOfSelectionChange()\n }\n\n reset() {\n this.update()\n }\n}\n\nexport const selectionChangeObserver = new SelectionChangeObserver()\n\nexport const getDOMSelection = function() {\n const selection = window.getSelection()\n if (selection.rangeCount > 0) {\n return selection\n }\n}\n\nexport const getDOMRange = function() {\n const domRange = getDOMSelection()?.getRangeAt(0)\n if (domRange) {\n if (!domRangeIsPrivate(domRange)) {\n return domRange\n }\n }\n}\n\nexport const setDOMRange = function(domRange) {\n const selection = window.getSelection()\n selection.removeAllRanges()\n selection.addRange(domRange)\n return selectionChangeObserver.update()\n}\n\n// In Firefox, clicking certain elements changes the selection to a\n// private element used to draw its UI. Attempting to access properties of those\n// elements throws an error.\n// https://bugzilla.mozilla.org/show_bug.cgi?id=208427\nconst domRangeIsPrivate = (domRange) => nodeIsPrivate(domRange.startContainer) || nodeIsPrivate(domRange.endContainer)\n\nconst nodeIsPrivate = (node) => !Object.getPrototypeOf(node)\n", "/* eslint-disable\n id-length,\n no-useless-escape,\n*/\nimport { NON_BREAKING_SPACE, ZERO_WIDTH_SPACE } from \"trix/constants\"\nimport UTF16String from \"trix/core/utilities/utf16_string\"\n\nexport const normalizeSpaces = (string) =>\n string.replace(new RegExp(`${ZERO_WIDTH_SPACE}`, \"g\"), \"\").replace(new RegExp(`${NON_BREAKING_SPACE}`, \"g\"), \" \")\n\nexport const normalizeNewlines = (string) => string.replace(/\\r\\n?/g, \"\\n\")\n\nexport const breakableWhitespacePattern = new RegExp(`[^\\\\S${NON_BREAKING_SPACE}]`)\n\nexport const squishBreakableWhitespace = (string) =>\n string\n // Replace all breakable whitespace characters with a space\n .replace(new RegExp(`${breakableWhitespacePattern.source}`, \"g\"), \" \")\n // Replace two or more spaces with a single space\n .replace(/\\ {2,}/g, \" \")\n\nexport const summarizeStringChange = function(oldString, newString) {\n let added, removed\n oldString = UTF16String.box(oldString)\n newString = UTF16String.box(newString)\n\n if (newString.length < oldString.length) {\n [ removed, added ] = utf16StringDifferences(oldString, newString)\n } else {\n [ added, removed ] = utf16StringDifferences(newString, oldString)\n }\n\n return { added, removed }\n}\n\nconst utf16StringDifferences = function(a, b) {\n if (a.isEqualTo(b)) {\n return [ \"\", \"\" ]\n }\n\n const diffA = utf16StringDifference(a, b)\n const { length } = diffA.utf16String\n\n let diffB\n\n if (length) {\n const { offset } = diffA\n const codepoints = a.codepoints.slice(0, offset).concat(a.codepoints.slice(offset + length))\n diffB = utf16StringDifference(b, UTF16String.fromCodepoints(codepoints))\n } else {\n diffB = utf16StringDifference(b, a)\n }\n\n return [ diffA.utf16String.toString(), diffB.utf16String.toString() ]\n}\n\nconst utf16StringDifference = function(a, b) {\n let leftIndex = 0\n let rightIndexA = a.length\n let rightIndexB = b.length\n\n while (leftIndex < rightIndexA && a.charAt(leftIndex).isEqualTo(b.charAt(leftIndex))) {\n leftIndex++\n }\n\n while (rightIndexA > leftIndex + 1 && a.charAt(rightIndexA - 1).isEqualTo(b.charAt(rightIndexB - 1))) {\n rightIndexA--\n rightIndexB--\n }\n\n return {\n utf16String: a.slice(leftIndex, rightIndexA),\n offset: leftIndex,\n }\n}\n", "import TrixObject from \"trix/core/object\" // Don't override window.Object\nimport { arraysAreEqual } from \"trix/core/helpers\"\n\nexport default class Hash extends TrixObject {\n static fromCommonAttributesOfObjects(objects = []) {\n if (!objects.length) {\n return new this()\n }\n let hash = box(objects[0])\n let keys = hash.getKeys()\n\n objects.slice(1).forEach((object) => {\n keys = hash.getKeysCommonToHash(box(object))\n hash = hash.slice(keys)\n })\n\n return hash\n }\n\n static box(values) {\n return box(values)\n }\n\n constructor(values = {}) {\n super(...arguments)\n this.values = copy(values)\n }\n\n add(key, value) {\n return this.merge(object(key, value))\n }\n\n remove(key) {\n return new Hash(copy(this.values, key))\n }\n\n get(key) {\n return this.values[key]\n }\n\n has(key) {\n return key in this.values\n }\n\n merge(values) {\n return new Hash(merge(this.values, unbox(values)))\n }\n\n slice(keys) {\n const values = {}\n\n Array.from(keys).forEach((key) => {\n if (this.has(key)) {\n values[key] = this.values[key]\n }\n })\n\n return new Hash(values)\n }\n\n getKeys() {\n return Object.keys(this.values)\n }\n\n getKeysCommonToHash(hash) {\n hash = box(hash)\n return this.getKeys().filter((key) => this.values[key] === hash.values[key])\n }\n\n isEqualTo(values) {\n return arraysAreEqual(this.toArray(), box(values).toArray())\n }\n\n isEmpty() {\n return this.getKeys().length === 0\n }\n\n toArray() {\n if (!this.array) {\n const result = []\n for (const key in this.values) {\n const value = this.values[key]\n result.push(result.push(key, value))\n }\n this.array = result.slice(0)\n }\n\n return this.array\n }\n\n toObject() {\n return copy(this.values)\n }\n\n toJSON() {\n return this.toObject()\n }\n\n contentsForInspection() {\n return { values: JSON.stringify(this.values) }\n }\n}\n\nconst object = function(key, value) {\n const result = {}\n result[key] = value\n return result\n}\n\nconst merge = function(object, values) {\n const result = copy(object)\n for (const key in values) {\n const value = values[key]\n result[key] = value\n }\n return result\n}\n\nconst copy = function(object, keyToRemove) {\n const result = {}\n const sortedKeys = Object.keys(object).sort()\n\n sortedKeys.forEach((key) => {\n if (key !== keyToRemove) {\n result[key] = object[key]\n }\n })\n\n return result\n}\n\nconst box = function(object) {\n if (object instanceof Hash) {\n return object\n } else {\n return new Hash(object)\n }\n}\n\nconst unbox = function(object) {\n if (object instanceof Hash) {\n return object.values\n } else {\n return object\n }\n}\n", "export default class ObjectGroup {\n static groupObjects(ungroupedObjects = [], { depth, asTree } = {}) {\n let group\n if (asTree) {\n if (depth == null) {\n depth = 0\n }\n }\n const objects = []\n\n Array.from(ungroupedObjects).forEach((object) => {\n if (group) {\n if (object.canBeGrouped?.(depth) && group[group.length - 1].canBeGroupedWith?.(object, depth)) {\n group.push(object)\n return\n } else {\n objects.push(new this(group, { depth, asTree }))\n group = null\n }\n }\n\n if (object.canBeGrouped?.(depth)) {\n group = [ object ]\n } else {\n objects.push(object)\n }\n })\n\n if (group) {\n objects.push(new this(group, { depth, asTree }))\n }\n return objects\n }\n\n constructor(objects = [], { depth, asTree }) {\n this.objects = objects\n if (asTree) {\n this.depth = depth\n this.objects = this.constructor.groupObjects(this.objects, { asTree, depth: this.depth + 1 })\n }\n }\n\n getObjects() {\n return this.objects\n }\n\n getDepth() {\n return this.depth\n }\n\n getCacheKey() {\n const keys = [ \"objectGroup\" ]\n Array.from(this.getObjects()).forEach((object) => {\n keys.push(object.getCacheKey())\n })\n return keys.join(\"/\")\n }\n}\n", "import BasicObject from \"trix/core/basic_object\"\n\nexport default class ObjectMap extends BasicObject {\n constructor(objects = []) {\n super(...arguments)\n this.objects = {}\n\n Array.from(objects).forEach((object) => {\n const hash = JSON.stringify(object)\n if (this.objects[hash] == null) {\n this.objects[hash] = object\n }\n })\n }\n\n find(object) {\n const hash = JSON.stringify(object)\n return this.objects[hash]\n }\n}\n", "export default class ElementStore {\n constructor(elements) {\n this.reset(elements)\n }\n\n add(element) {\n const key = getKey(element)\n this.elements[key] = element\n }\n\n remove(element) {\n const key = getKey(element)\n const value = this.elements[key]\n if (value) {\n delete this.elements[key]\n return value\n }\n }\n\n reset(elements = []) {\n this.elements = {}\n Array.from(elements).forEach((element) => {\n this.add(element)\n })\n return elements\n }\n}\n\nconst getKey = (element) => element.dataset.trixStoreKey\n", "import BasicObject from \"trix/core/basic_object\"\n\nexport default class Operation extends BasicObject {\n isPerforming() {\n return this.performing === true\n }\n\n hasPerformed() {\n return this.performed === true\n }\n\n hasSucceeded() {\n return this.performed && this.succeeded\n }\n\n hasFailed() {\n return this.performed && !this.succeeded\n }\n\n getPromise() {\n if (!this.promise) {\n this.promise = new Promise((resolve, reject) => {\n this.performing = true\n return this.perform((succeeded, result) => {\n this.succeeded = succeeded\n this.performing = false\n this.performed = true\n\n if (this.succeeded) {\n resolve(result)\n } else {\n reject(result)\n }\n })\n })\n }\n\n return this.promise\n }\n\n perform(callback) {\n return callback(false)\n }\n\n release() {\n this.promise?.cancel?.()\n this.promise = null\n this.performing = null\n this.performed = null\n this.succeeded = null\n }\n}\n\nOperation.proxyMethod(\"getPromise().then\")\nOperation.proxyMethod(\"getPromise().catch\")\n", "import BasicObject from \"trix/core/basic_object\"\nimport ObjectGroup from \"trix/core/collections/object_group\"\n\nexport default class ObjectView extends BasicObject {\n constructor(object, options = {}) {\n super(...arguments)\n this.object = object\n this.options = options\n this.childViews = []\n this.rootView = this\n }\n\n getNodes() {\n if (!this.nodes) { this.nodes = this.createNodes() }\n return this.nodes.map((node) => node.cloneNode(true))\n }\n\n invalidate() {\n this.nodes = null\n this.childViews = []\n return this.parentView?.invalidate()\n }\n\n invalidateViewForObject(object) {\n return this.findViewForObject(object)?.invalidate()\n }\n\n findOrCreateCachedChildView(viewClass, object, options) {\n let view = this.getCachedViewForObject(object)\n if (view) {\n this.recordChildView(view)\n } else {\n view = this.createChildView(...arguments)\n this.cacheViewForObject(view, object)\n }\n return view\n }\n\n createChildView(viewClass, object, options = {}) {\n if (object instanceof ObjectGroup) {\n options.viewClass = viewClass\n viewClass = ObjectGroupView\n }\n\n const view = new viewClass(object, options)\n return this.recordChildView(view)\n }\n\n recordChildView(view) {\n view.parentView = this\n view.rootView = this.rootView\n this.childViews.push(view)\n return view\n }\n\n getAllChildViews() {\n let views = []\n\n this.childViews.forEach((childView) => {\n views.push(childView)\n views = views.concat(childView.getAllChildViews())\n })\n\n return views\n }\n\n findElement() {\n return this.findElementForObject(this.object)\n }\n\n findElementForObject(object) {\n const id = object?.id\n if (id) {\n return this.rootView.element.querySelector(`[data-trix-id='${id}']`)\n }\n }\n\n findViewForObject(object) {\n for (const view of this.getAllChildViews()) {\n if (view.object === object) {\n return view\n }\n }\n }\n\n getViewCache() {\n if (this.rootView === this) {\n if (this.isViewCachingEnabled()) {\n if (!this.viewCache) { this.viewCache = {} }\n return this.viewCache\n }\n } else {\n return this.rootView.getViewCache()\n }\n }\n\n isViewCachingEnabled() {\n return this.shouldCacheViews !== false\n }\n\n enableViewCaching() {\n this.shouldCacheViews = true\n }\n\n disableViewCaching() {\n this.shouldCacheViews = false\n }\n\n getCachedViewForObject(object) {\n return this.getViewCache()?.[object.getCacheKey()]\n }\n\n cacheViewForObject(view, object) {\n const cache = this.getViewCache()\n if (cache) {\n cache[object.getCacheKey()] = view\n }\n }\n\n garbageCollectCachedViews() {\n const cache = this.getViewCache()\n if (cache) {\n const views = this.getAllChildViews().concat(this)\n const objectKeys = views.map((view) => view.object.getCacheKey())\n for (const key in cache) {\n if (!objectKeys.includes(key)) {\n delete cache[key]\n }\n }\n }\n }\n}\n\nexport class ObjectGroupView extends ObjectView {\n constructor() {\n super(...arguments)\n this.objectGroup = this.object\n this.viewClass = this.options.viewClass\n delete this.options.viewClass\n }\n\n getChildViews() {\n if (!this.childViews.length) {\n Array.from(this.objectGroup.getObjects()).forEach((object) => {\n this.findOrCreateCachedChildView(this.viewClass, object, this.options)\n })\n }\n return this.childViews\n }\n\n createNodes() {\n const element = this.createContainerElement()\n\n this.getChildViews().forEach((view) => {\n Array.from(view.getNodes()).forEach((node) => {\n element.appendChild(node)\n })\n })\n\n return [ element ]\n }\n\n createContainerElement(depth = this.objectGroup.getDepth()) {\n return this.getChildViews()[0].createContainerElement(depth)\n }\n}\n", "import BasicObject from \"trix/core/basic_object\"\n\nimport { nodeIsAttachmentElement, removeNode, tagName, walkTree } from \"trix/core/helpers\"\nimport DOMPurify from \"dompurify\"\nimport * as config from \"trix/config\"\n\nDOMPurify.addHook(\"uponSanitizeAttribute\", function (node, data) {\n const allowedAttributePattern = /^data-trix-/\n if (allowedAttributePattern.test(data.attrName)) {\n data.forceKeepAttr = true\n }\n})\n\nconst DEFAULT_ALLOWED_ATTRIBUTES = \"style href src width height language class\".split(\" \")\nconst DEFAULT_FORBIDDEN_PROTOCOLS = \"javascript:\".split(\" \")\nconst DEFAULT_FORBIDDEN_ELEMENTS = \"script iframe form noscript\".split(\" \")\n\nexport default class HTMLSanitizer extends BasicObject {\n static setHTML(element, html) {\n const sanitizedElement = new this(html).sanitize()\n const sanitizedHtml = sanitizedElement.getHTML ? sanitizedElement.getHTML() : sanitizedElement.outerHTML\n element.innerHTML = sanitizedHtml\n }\n\n static sanitize(html, options) {\n const sanitizer = new this(html, options)\n sanitizer.sanitize()\n return sanitizer\n }\n\n constructor(html, { allowedAttributes, forbiddenProtocols, forbiddenElements } = {}) {\n super(...arguments)\n this.allowedAttributes = allowedAttributes || DEFAULT_ALLOWED_ATTRIBUTES\n this.forbiddenProtocols = forbiddenProtocols || DEFAULT_FORBIDDEN_PROTOCOLS\n this.forbiddenElements = forbiddenElements || DEFAULT_FORBIDDEN_ELEMENTS\n this.body = createBodyElementForHTML(html)\n }\n\n sanitize() {\n this.sanitizeElements()\n this.normalizeListElementNesting()\n DOMPurify.setConfig(config.dompurify)\n this.body = DOMPurify.sanitize(this.body)\n\n return this.body\n }\n\n getHTML() {\n return this.body.innerHTML\n }\n\n getBody() {\n return this.body\n }\n\n // Private\n\n sanitizeElements() {\n const walker = walkTree(this.body)\n const nodesToRemove = []\n\n while (walker.nextNode()) {\n const node = walker.currentNode\n switch (node.nodeType) {\n case Node.ELEMENT_NODE:\n if (this.elementIsRemovable(node)) {\n nodesToRemove.push(node)\n } else {\n this.sanitizeElement(node)\n }\n break\n case Node.COMMENT_NODE:\n nodesToRemove.push(node)\n break\n }\n }\n\n nodesToRemove.forEach((node) => removeNode(node))\n\n return this.body\n }\n\n sanitizeElement(element) {\n if (element.hasAttribute(\"href\")) {\n if (this.forbiddenProtocols.includes(element.protocol)) {\n element.removeAttribute(\"href\")\n }\n }\n\n Array.from(element.attributes).forEach(({ name }) => {\n if (!this.allowedAttributes.includes(name) && name.indexOf(\"data-trix\") !== 0) {\n element.removeAttribute(name)\n }\n })\n\n return element\n }\n\n normalizeListElementNesting() {\n Array.from(this.body.querySelectorAll(\"ul,ol\")).forEach((listElement) => {\n const previousElement = listElement.previousElementSibling\n if (previousElement) {\n if (tagName(previousElement) === \"li\") {\n previousElement.appendChild(listElement)\n }\n }\n })\n\n return this.body\n }\n\n elementIsRemovable(element) {\n if (element?.nodeType !== Node.ELEMENT_NODE) return\n return this.elementIsForbidden(element) || this.elementIsntSerializable(element)\n }\n\n elementIsForbidden(element) {\n return this.forbiddenElements.includes(tagName(element))\n }\n\n elementIsntSerializable(element) {\n return element.getAttribute(\"data-trix-serialize\") === \"false\" && !nodeIsAttachmentElement(element)\n }\n}\n\nconst createBodyElementForHTML = function(html = \"\") {\n // Remove everything after