From 7c9c39f02c316b4b8a2033dbdcd991ddbe492fb1 Mon Sep 17 00:00:00 2001 From: Nils Haagen Date: Tue, 5 Aug 2025 15:35:31 +0200 Subject: [PATCH] UI/TagInput: 45566, raw-encode tags --- components/ILIAS/UI/UI.php | 4 - .../js/Input/Field/dist/input.factory.min.js | 2 +- .../resources/js/Input/Field/rollup.config.js | 1 + .../js/Input/Field/src/Tag/tag.factory.js | 91 ++++++++++++++++++ .../js/Input/Field/src/input.factory.js | 4 +- .../UI/resources/js/Input/Field/tagInput.js | 96 ------------------- .../Component/Input/Field/Renderer.php | 4 +- .../Component/Input/Field/Tag.php | 4 +- .../Component/Input/Field/TagInputTest.php | 34 +++++++ 9 files changed, 133 insertions(+), 107 deletions(-) create mode 100644 components/ILIAS/UI/resources/js/Input/Field/src/Tag/tag.factory.js delete mode 100755 components/ILIAS/UI/resources/js/Input/Field/tagInput.js diff --git a/components/ILIAS/UI/UI.php b/components/ILIAS/UI/UI.php index 5bf2b5b2bc1e..c449b30460b8 100644 --- a/components/ILIAS/UI/UI.php +++ b/components/ILIAS/UI/UI.php @@ -573,8 +573,6 @@ public function init( new Component\Resource\ComponentJS($this, "js/Input/Field/file.js"); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "js/Input/Field/input.js"); - $contribute[Component\Resource\PublicAsset::class] = fn() => - new Component\Resource\ComponentJS($this, "js/Input/Field/tagInput.js"); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\ComponentJS($this, "js/Item/dist/notification.js"); $contribute[Component\Resource\PublicAsset::class] = fn() => @@ -607,8 +605,6 @@ public function init( new Component\Resource\OfComponent($this, "fonts", "assets"); $contribute[Component\Resource\PublicAsset::class] = fn() => new Component\Resource\OfComponent($this, "ui-examples", "assets"); - $contribute[Component\Resource\PublicAsset::class] = static fn() => - new Component\Resource\NodeModule("@yaireo/tagify/dist/tagify.js"); $contribute[Component\Resource\PublicAsset::class] = static fn() => new Component\Resource\NodeModule("@yaireo/tagify/dist/tagify.css"); $contribute[Component\Resource\PublicAsset::class] = static fn() => diff --git a/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js b/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js index dc2dc3f768fa..ad740f5f8986 100644 --- a/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js +++ b/components/ILIAS/UI/resources/js/Input/Field/dist/input.factory.min.js @@ -12,4 +12,4 @@ * https://www.ilias.de * https://github.com/ILIAS-eLearning */ -!function(e,t,n){"use strict";class r{textarea;remainder=null;constructor(e){if(this.textarea=document.getElementById(e),null===this.textarea)throw new Error(`Could not find textarea for input-id '${e}'.`);if(this.shouldShowRemainder()){if(this.remainder=this.textarea.parentNode.querySelector('[data-action="remainder"]'),!this.remainder instanceof HTMLSpanElement)throw new Error(`Could not find remainder-element for input-id '${e}'.`);this.textarea.addEventListener("input",(()=>{this.updateRemainderCountHook()}))}}updateRemainderCountHook(){this.shouldShowRemainder()&&null!==this.remainder&&(this.remainder.innerHTML=(this.textarea.maxLength-this.textarea.value.length).toString())}updateTextareaContent(e,t=null,n=null){if(!this.isDisabled()){if(this.isContentTooLarge(e))return this.updateRemainderCountHook(),void this.textarea.focus();t=t??this.textarea.selectionStart,n=n??this.textarea.selectionEnd,this.textarea.value=e,tthis.textarea.selectionEnd?this.textarea.selectionStart:this.textarea.selectionEnd}getLinesBeforeSelection(){return o(this.textarea.value).slice(0,i(this.getTextBeforeSelection()))}getLinesAfterSelection(){const e=o(this.textarea.value);return e.slice(i(this.getTextBeforeSelection()+this.getTextOfSelection())+1,e.length)}getLinesOfSelection(){const e=o(this.textarea.value);return e.slice(this.getLinesBeforeSelection().length,e.length-this.getLinesAfterSelection().length)}isContentTooLarge(e){const t=this.getMaxLength();return!(t<0)&&t0}getMaxLength(){return Number(this.textarea.getAttribute("maxlength")??-1)}isDisabled(){return this.textarea.disabled}}function i(e){return(e.match(/\n/g)??[]).length}function o(e){return e.split(/\n/)}class s{instances=[];init(e){if(void 0!==this.instances[e])throw new Error(`Textarea with input-id '${e}' has already been initialized.`);this.instances[e]=new r(e)}get(e){return this.instances[e]??null}}class l{preview_parameter;preview_url;constructor(e,t){this.preview_parameter=e,this.preview_url=t}async getPreviewHtmlOf(e){if(0===e.length)return"";let t=new FormData;return t.append(this.preview_parameter,e),(await fetch(this.preview_url,{method:"POST",body:t})).text()}}const a="textarea",c="preview";class d extends r{preview_history=[];preview_renderer;content_wrappers;view_controls;actions;constructor(e,t){super(t);const n=this.textarea.closest(".c-field-markdown");if(null===n)throw new Error(`Could not find input-wrapper for input-id '${t}'.`);this.preview_renderer=e,this.content_wrappers=function(e){const t=new Map;return t.set(a,e.querySelector("textarea")),t.set(c,e.querySelector(".c-field-markdown__preview")),t.forEach((e=>{if(null===e)throw new Error("Could not find all content-wrappers for markdown-input.")})),t}(n),this.view_controls=function(e){const t=e.querySelector(".il-viewcontrol-mode")?.getElementsByTagName("button");if(!t instanceof HTMLCollection||2!==t.length)throw new Error("Could not find exactly two view-controls.");return[...t]}(n),this.actions=function(e){const t=e.querySelector(".c-field-markdown__actions")?.getElementsByTagName("button");if(t instanceof HTMLCollection)return[...t];return[]}(n);let r=!0;this.textarea.addEventListener("keydown",(e=>{r=this.handleEnterKeyBeforeInsertionHook(e)})),this.textarea.addEventListener("keyup",(e=>{this.handleEnterKeyAfterInsertionHook(e,r)})),this.actions.forEach((e=>{e.addEventListener("click",(e=>{this.performMarkdownActionHook(e)}))})),this.view_controls.forEach((e=>{e.addEventListener("click",(()=>{this.toggleViewingModeHook()}))}))}handleEnterKeyAfterInsertionHook(e,t){if(!t||!f(e))return;const n=this.getLinesBeforeSelection().pop();void 0!==n&&S(n)?this.applyTransformationToSelection(u):void 0!==n&&p(n)&&this.insertSingleEnumeration()}handleEnterKeyBeforeInsertionHook(e){if(!f(e))return!1;const t=this.getLinesOfSelection().shift();if(void 0===t||!((t.match(/((^(\s*-)|(^(\s*\d+\.)))\s*)$/g)??[]).length>0))return!0;let n=this.getLinesBeforeSelection().join("\n"),r=this.getLinesAfterSelection().join("\n");return n.length>0&&(n+="\n"),r.length>0&&(r=`\n${r}`),this.updateTextareaContent(n+r,this.getAbsoluteSelectionStart()-t.length,this.getAbsoluteSelectionEnd()-t.length),e.preventDefault(),!1}performMarkdownActionHook(e){const t=function(e){const t=e.closest("span[data-action]");if(!t instanceof HTMLSpanElement)return null;if(!t.hasAttribute("data-action"))return null;return t.dataset.action}(e.target);switch(t){case"insert-heading":this.insertCharactersAroundSelection("# ","");break;case"insert-link":this.insertCharactersAroundSelection("[","](url)");break;case"insert-bold":this.insertCharactersAroundSelection("**","**");break;case"insert-italic":this.insertCharactersAroundSelection("_","_");break;case"insert-bullet-points":this.applyTransformationToSelection(u);break;case"insert-enumeration":this.isMultilineTextSelected()?this.applyTransformationToSelection(h):this.insertSingleEnumeration();break;default:throw new Error(`Could not perform markdown-action '${t}'.`)}}toggleViewingModeHook(){this.content_wrappers.forEach((e=>{g(e,"hidden")})),this.view_controls.forEach((e=>{g(e,"engaged")})),this.isDisabled()||this.actions.forEach((e=>{e.disabled=!e.disabled;const t=e.querySelector(".glyph");null!==t&&g(t,"disabled")})),this.maybeUpdatePreviewContent()}insertSingleEnumeration(){const e=this.getLinesOfSelection();if(1!==e.length)return void this.textarea.focus();const t=this.getLinesBeforeSelection(),n=t.length-1;let r=n>=0?function(e){const t=e.match(/([0-9]+)/);if(null!==t)return parseInt(t[0]);return null}(t[n])??0:0;const i=h(e,++r),o=function(e,t=0){if(e.length<1)return[];const n=[];for(const r of e){if(!p(r))break;n.push(r.replace(/([0-9]+)/,(++t).toString()))}n.length>0&&(e=n.concat(e.slice(n.length)));return e}(this.getLinesAfterSelection(),r);let s=t.join("\n");const l=o.join("\n");let a=i.join("\n");s.length>0&&a.length>0&&(s+="\n"),a.length>0&&l.length>0&&(a+="\n");const c=s+a+l,d=c.length-this.textarea.value.length;this.updateTextareaContent(c,this.getAbsoluteSelectionStart()+d,this.getAbsoluteSelectionEnd()+d)}applyTransformationToSelection(e){if(!e instanceof Function)throw new Error(`Transformation must be an instance of Function, ${typeof e} given.`);const t=e(this.getLinesOfSelection());if(!t instanceof Array)throw new Error(`Transformation must return an instance of Array, ${typeof t} returned.`);const n=t.length>1;let r=this.getLinesBeforeSelection().join("\n");const i=this.getLinesAfterSelection().join("\n");let o=t.join("\n");r.length>0&&o.length>0&&(r+="\n"),o.length>0&&i.length>0&&(o+="\n");const s=r+o+i,l=s.length-this.textarea.value.length,a=n?r.length:this.getAbsoluteSelectionStart()+l,c=n?a+o.length-1:this.getAbsoluteSelectionEnd()+l;this.updateTextareaContent(s,a,c)}insertCharactersAroundSelection(e,t){const n=this.getTextBeforeSelection()+e+this.getTextOfSelection()+t+this.getTextAfterSelection(),r=this.getAbsoluteSelectionStart()+e.length,i=this.getAbsoluteSelectionEnd()+e.length;this.updateTextareaContent(n,r,i)}maybeUpdatePreviewContent(){const e=this.preview_history[this.preview_history.length-1]??"",t=this.textarea.value;t!==e&&(this.preview_history.push(t),this.preview_renderer.getPreviewHtmlOf(t).then((e=>{this.content_wrappers.get(c).innerHTML=e})))}getBulletPointTransformation(){return u}getEnumerationTransformation(){return h}}function u(e){const t=[],n=!S(e[0]??"");for(const r of e)t.push(n?`- ${r}`:m(r));return t}function h(e,t=1){const n=[],r=!p(e[0]??"");for(const i of e)n.push(r?`${t++}. ${i}`:m(i));return n}function g(e,t){e.classList.contains(t)?e.classList.remove(t):e.classList.add(t)}function f(e){return e instanceof KeyboardEvent&&"Enter"===e.code}function m(e){return e.replace(/((^(\s*[-])|(^(\s*\d+\.)))\s*)/g,"")}function S(e){return(e.match(/^(\s*[-])/g)??[]).length>0}function p(e){return(e.match(/^(\s*\d+\.)/g)??[]).length>0}class w{instances=[];init(e,t,n){if(void 0!==this.instances[e])throw new Error(`Markdown with input-id '${e}' has already been initialized.`);this.instances[e]=new d(new l(n,t),e)}get(e){return this.instances[e]??null}}class E{constructor(e,t,n,r,i,o=null,s=null,l=null){this.id=e,this.name=t,this.element=n,this.selectButton=r,this.drilldownParentLevel=i,this.drilldownButton=o,this.listElement=s,this.renderUrl=l}}const y="data-node-id",b="data-node-name",v="data-render-url",x="data-ddindex",A="c-input-node",C="c-input-tree_select",L=`${A}__async`,B=`${A}__leaf`,T=`${A}--selected`,N="hidden",q="disabled",k=".glyph",$=`.${A}`,_=`.${C}`,M=`.${C}__selection`,H='[data-action="remove"]',I='[data-action="select"]',D=`.${A}__select`,R=".c-drilldown__menulevel--trigger";function j(e){return function(e){return e.classList.contains(L)}(e)&&e.hasAttribute(v)?e.getAttribute(v):null}function O(e){return!e.classList.contains(B)&&e.classList.contains(A)}function U(e,t=null){return e.reduce(((e,t)=>{const n=function(e){const t=e.getAttribute(y);if(null===t)throw new Error("Could not find data-node-id attribute.");return t}(t);if(e.has(n))throw new Error(`Node '${n}' has already been parsed. There might be a rendering issue.`);return e.set(n,new E(n,function(e){const t=e.querySelector(`[${b}]`);if(null===t)throw new Error("Could not find element with data-node-name attribute.");return t.textContent}(t),t,function(e){const t=e.querySelector(`:scope > ${D}`);if(null===t)throw new Error("Could not find node select button.");return t}(t),function(e){const t=e.closest(`ul[${x}]`);if(null===t)throw new Error("Could not find drilldown menu of node.");return t.getAttribute(x)}(t),function(e){if(!O(e))return null;const t=e.querySelector(`${R}`);if(null===t)throw new Error("Could not find drilldown menu button of branch node.");return t}(t),function(e){if(!O(e))return null;const t=e.querySelector("ul");if(null===t)throw new Error("Could not find list element of branch node.");return t}(t),j(t)))}),new Map(t??[]))}function F(e,t){for(let n=0;n{this.#m()})),this.#f.querySelectorAll('[data-action="close"]').forEach((e=>{e.addEventListener("click",(()=>{this.#S()}))})),this.#d.querySelectorAll("li").forEach((e=>{const t=function(e){const t=e.getAttribute(y);if(null===t)throw new Error(`Could not find '${y}' attribbute of element.`);return t}(e);this.#p(e,t),this.#w(t)})),this.#l.addEngageListener((e=>{this.#E(e)})),this.#g.addEventListener("click",(()=>{this.#y()})),this.#e.forEach((e=>{this.#b(e)})),this.#v()}unselectNode(e){if(this.#x(e),this.#v(),this.#A(e),this.#e.has(e)){const t=this.#e.get(e);P(t.element,!1),this.#C(t.selectButton,t.name),this.updateNodeSelectButtonStates()}}selectNode(e){if(this.#w(e),this.#v(),this.#e.has(e)){const t=this.#e.get(e);P(t.element,!0),this.#L(t.selectButton,t.name),this.#B(t),this.updateNodeSelectButtonStates()}}updateNodeSelectButtonStates(){this.#e.forEach(((e,t)=>{this.#t.size>0?(e.selectButton.disabled=!this.#t.has(t),e.selectButton.querySelector(k).classList.toggle(q,!this.#t.has(t))):(e.selectButton.disabled=!1,e.selectButton.querySelector(k).classList.toggle(q,!1))}))}getSelection(){return new Set(this.#t)}getNodes(){return new Map(this.#e)}async#T(e){var t,n,r;if(!this.#n.has(e.id)&&!this.#r.has(e.id))try{this.#r.add(e.id);const i=await this.#o.loadContent(e.renderUrl);e.listElement.append(...i.children),this.#l.parseLevels();const o=U((r=e.listElement,Array.from(r.querySelectorAll($))),this.#e),s=(t=o,n=this.#e,Array.from(t.entries()).filter((([e])=>!n.has(e))).map((([,e])=>e)));this.#e=o,F(s,(e=>{this.#t.has(e.id)?this.selectNode(e.id):this.unselectNode(e.id),this.#b(e)})),this.#n.add(e.id)}catch(e){throw new Error(`Could not render async node children: ${e.message}`)}finally{this.#r.delete(e.id)}}#N(e){F(function(e,t,n=255){const r=[];let i=e;for(let e=0;e{const t=e.getAttribute(y);if(null===t||!this.#e.has(t))throw new Error(`Could not find '${y}' of node element.`);const n=this.#e.get(t);this.#q(n)}))}#q(e){const t=this.#i.createContent(this.#c).querySelector(".crumb");t.setAttribute(x,e.drilldownParentLevel),t.firstElementChild.textContent=e.name,t.addEventListener("click",(()=>{this.#l.engageLevel(e.drilldownParentLevel),e.drilldownButton.click()})),this.#a.append(t)}#m(){const e=this.#a.querySelectorAll(".crumb");e.item(e.length-1)?.remove()}#k(){F(this.#a.querySelectorAll(".crumb"),(e=>{e.remove()}))}#E(e){if("0"===e)return void this.#k();const t=this.#f.querySelector(`ul[${x}="${e}"]`)?.closest($)?.getAttribute(y);if(null===t||!this.#e.has(t))throw new Error(`Could not find node for drilldown-level '${e}'.`);this.#k(),this.#N(this.#e.get(t))}#$(e,t){e.addEventListener("click",(()=>{null!==t.renderUrl&&this.#T(t)}))}#p(e,t){e.querySelector(H)?.addEventListener("click",(()=>{this.unselectNode(t),e.remove()}))}#_(e,t){e.addEventListener("click",(()=>{this.#t.has(t.id)?this.unselectNode(t.id):this.selectNode(t.id)}))}#B(e){if(null!==this.#d.querySelector(`li[${y}="${e.id}"]`))return;const t=this.#i.createContent(this.#u),n=t.querySelector("[data-node-id]");n.setAttribute(y,e.id),n.querySelector(`[${b}]`).textContent=e.name,n.querySelector("input").value=e.id,this.#p(n,e.id),this.#d.append(...t.children)}#A(e){this.#d.querySelector(`li[${y}="${e}"]`)?.remove()}#b(e){this.#_(e.selectButton,e),null!==e.drilldownButton&&this.#$(e.drilldownButton,e)}#C(e,t){e.querySelector(H)?.classList.add(N),e.querySelector(I)?.classList.remove(N),e.setAttribute("aria-label",this.#M("select_node",t))}#L(e,t){e.querySelector(I)?.classList.add(N),e.querySelector(H)?.classList.remove(N),e.setAttribute("aria-label",this.#M("unselect_node",t))}#v(){this.#h.disabled=this.#t.size<=0}#x(e){this.#t.has(e)&&this.#t.delete(e)}#w(e){this.#t.has(e)||this.#t.add(e)}#M(e,...t){return function(e,...t){const n=[...t];return e.replace(/%s/g,(()=>n.shift()??""))}(this.#s.txt(e),t)}#S(){this.#f.close()}#y(){this.#f.showModal()}}class z extends K{#H;constructor(e,t,n,r,i,o,s,l,a,c,d,u,h,g){super(e,t,n,r,i,o,s,l,a,c,d,u,h),this.#H=g}selectNode(e){if(!this.#H){const t=Array.from(this.getSelection().add(e));this.#I(t,this.getNodes())}super.selectNode(e)}updateNodeSelectButtonStates(){if(this.#H)return;const e=this.getNodes();e.forEach((e=>{e.selectButton.disabled=!1,e.selectButton.querySelector(k).classList.remove(q)})),this.getSelection().forEach((t=>{const n=e.get(t);null!==n&&null!==n.listElement&&n.listElement.querySelectorAll(D).forEach((e=>{e.disabled=!0,e.querySelector(k).classList.add(q)}))}))}#I(e,t){for(let r=0;r{const r=e.getAttribute(n);if(!t.has(r))throw new Error(`Element references '${r}' which does not exist.`);e.setAttribute(n,t.get(r))}))}class W{#D;constructor(e){this.#D=e}createContent(e){const t=e.content.cloneNode(!0),n=new Map;return t.querySelectorAll("[id]").forEach((e=>{const t=function(e=""){return`${e}${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`}("il_ui_fw_");n.set(e.id,t),e.id=t})),t.querySelectorAll("[for]").forEach((e=>{e.htmlFor=n.get(e.htmlFor)})),V(t,n,"aria-describedby"),V(t,n,"aria-labelledby"),V(t,n,"aria-controls"),V(t,n,"aria-owns"),Q(this.#D,t.children)}}class G{#D;constructor(e){this.#D=e}loadContent(e){return fetch(e.toString()).then((e=>e.text())).then((e=>this.#R(e))).then((e=>Q(this.#D,e))).catch((t=>{throw new Error(`Could not render element(s) from '${e}': ${t.message}`)}))}#j(e){const t=this.#D.createElement("script");return e.hasAttribute("type")&&t.setAttribute("type",e.getAttribute("type")),e.hasAttribute("src")&&t.setAttribute("src",e.getAttribute("src")),e.textContent.length>0&&(t.textContent=e.textContent),t}#R(e){const t=this.#D.createElement("div");return t.innerHTML=e.trim(),t.querySelectorAll("script").forEach((e=>{const t=this.#j(e);e.replaceWith(t)})),t.children}}function J(e){return Array.from(e.querySelectorAll($))}class X{#O=new Map;#U;#F;#s;#D;constructor(e,t,n,r){this.#U=e,this.#F=t,this.#s=n,this.#D=r}initTreeMultiSelect(e,t){if(this.#O.has(e))throw new Error(`TreeSelect '${e}' already exists.`);const[n,r,i,o,s,l,a,c]=this.#P(e),d=this.#K(r),u=new z(U(J(a)),this.#U,new W(this.#D),new G(this.#D),this.#s,d,i,o,s,l,c,n,a,t);return this.#O.set(e,u),u}initTreeSelect(e){if(this.#O.has(e))throw new Error(`TreeSelect '${e}' already exists.`);const[t,n,r,i,o,s,l,a]=this.#P(e),c=this.#K(n),d=new K(U(J(l)),this.#U,new W(this.#D),new G(this.#D),this.#s,c,r,i,o,s,a,t,l);return this.#O.set(e,d),d}getInstance(e){return this.#O.has(e)?this.#O.get(e):null}#P(e){const t=this.#D.getElementById(e),n=t?.closest(_),r=n?.querySelector(".breadcrumb"),i=n?.querySelector(".modal-body > template"),o=n?.querySelector(M),s=o?.querySelector(":scope > template"),l=n?.querySelector("dialog"),a=l?.querySelector(".btn-primary");if(null===r||null===i||null===o||null===s||null===a||null===t||null===l)throw new Error(`Could not find some element(s) for Tree Select Input '${e}'.`);return[t,n,r,i,o,s,l,a]}#K(e){const t=e.querySelector(".c-drilldown");if(null===t||!t.hasAttribute("id"))throw new Error("Could not find drilldown element.");const n=this.#F.getInstance(t.id);if(null===t)throw new Error("Could not find drilldown instance.");return n}}class Y{#z;constructor(e){this.#z=e}on(e,t,n){this.#z(e).on(t,n)}off(e,t,n){this.#z(e).off(t,n)}}var Z;t.UI=t.UI||{},t.UI.Input=t.UI.Input||{},(Z=t.UI.Input).textarea=new s,Z.markdown=new w,Z.treeSelect=new X(new Y(e),t.UI.menu.drilldown,{txt:e=>t.Language.txt(e)},n)}($,il,document); +!function(t,e,i){"use strict";class s{textarea;remainder=null;constructor(t){if(this.textarea=document.getElementById(t),null===this.textarea)throw new Error(`Could not find textarea for input-id '${t}'.`);if(this.shouldShowRemainder()){if(this.remainder=this.textarea.parentNode.querySelector('[data-action="remainder"]'),!this.remainder instanceof HTMLSpanElement)throw new Error(`Could not find remainder-element for input-id '${t}'.`);this.textarea.addEventListener("input",(()=>{this.updateRemainderCountHook()}))}}updateRemainderCountHook(){this.shouldShowRemainder()&&null!==this.remainder&&(this.remainder.innerHTML=(this.textarea.maxLength-this.textarea.value.length).toString())}updateTextareaContent(t,e=null,i=null){if(!this.isDisabled()){if(this.isContentTooLarge(t))return this.updateRemainderCountHook(),void this.textarea.focus();e=e??this.textarea.selectionStart,i=i??this.textarea.selectionEnd,this.textarea.value=t,ethis.textarea.selectionEnd?this.textarea.selectionStart:this.textarea.selectionEnd}getLinesBeforeSelection(){return a(this.textarea.value).slice(0,n(this.getTextBeforeSelection()))}getLinesAfterSelection(){const t=a(this.textarea.value);return t.slice(n(this.getTextBeforeSelection()+this.getTextOfSelection())+1,t.length)}getLinesOfSelection(){const t=a(this.textarea.value);return t.slice(this.getLinesBeforeSelection().length,t.length-this.getLinesAfterSelection().length)}isContentTooLarge(t){const e=this.getMaxLength();return!(e<0)&&e0}getMaxLength(){return Number(this.textarea.getAttribute("maxlength")??-1)}isDisabled(){return this.textarea.disabled}}function n(t){return(t.match(/\n/g)??[]).length}function a(t){return t.split(/\n/)}class o{instances=[];init(t){if(void 0!==this.instances[t])throw new Error(`Textarea with input-id '${t}' has already been initialized.`);this.instances[t]=new s(t)}get(t){return this.instances[t]??null}}class r{preview_parameter;preview_url;constructor(t,e){this.preview_parameter=t,this.preview_url=e}async getPreviewHtmlOf(t){if(0===t.length)return"";let e=new FormData;return e.append(this.preview_parameter,t),(await fetch(this.preview_url,{method:"POST",body:e})).text()}}const l="textarea",d="preview";class h extends s{preview_history=[];preview_renderer;content_wrappers;view_controls;actions;constructor(t,e){super(e);const i=this.textarea.closest(".c-field-markdown");if(null===i)throw new Error(`Could not find input-wrapper for input-id '${e}'.`);this.preview_renderer=t,this.content_wrappers=function(t){const e=new Map;return e.set(l,t.querySelector("textarea")),e.set(d,t.querySelector(".c-field-markdown__preview")),e.forEach((t=>{if(null===t)throw new Error("Could not find all content-wrappers for markdown-input.")})),e}(i),this.view_controls=function(t){const e=t.querySelector(".il-viewcontrol-mode")?.getElementsByTagName("button");if(!e instanceof HTMLCollection||2!==e.length)throw new Error("Could not find exactly two view-controls.");return[...e]}(i),this.actions=function(t){const e=t.querySelector(".c-field-markdown__actions")?.getElementsByTagName("button");if(e instanceof HTMLCollection)return[...e];return[]}(i);let s=!0;this.textarea.addEventListener("keydown",(t=>{s=this.handleEnterKeyBeforeInsertionHook(t)})),this.textarea.addEventListener("keyup",(t=>{this.handleEnterKeyAfterInsertionHook(t,s)})),this.actions.forEach((t=>{t.addEventListener("click",(t=>{this.performMarkdownActionHook(t)}))})),this.view_controls.forEach((t=>{t.addEventListener("click",(()=>{this.toggleViewingModeHook()}))}))}handleEnterKeyAfterInsertionHook(t,e){if(!e||!p(t))return;const i=this.getLinesBeforeSelection().pop();void 0!==i&&f(i)?this.applyTransformationToSelection(c):void 0!==i&&v(i)&&this.insertSingleEnumeration()}handleEnterKeyBeforeInsertionHook(t){if(!p(t))return!1;const e=this.getLinesOfSelection().shift();if(void 0===e||!((e.match(/((^(\s*-)|(^(\s*\d+\.)))\s*)$/g)??[]).length>0))return!0;let i=this.getLinesBeforeSelection().join("\n"),s=this.getLinesAfterSelection().join("\n");return i.length>0&&(i+="\n"),s.length>0&&(s=`\n${s}`),this.updateTextareaContent(i+s,this.getAbsoluteSelectionStart()-e.length,this.getAbsoluteSelectionEnd()-e.length),t.preventDefault(),!1}performMarkdownActionHook(t){const e=function(t){const e=t.closest("span[data-action]");if(!e instanceof HTMLSpanElement)return null;if(!e.hasAttribute("data-action"))return null;return e.dataset.action}(t.target);switch(e){case"insert-heading":this.insertCharactersAroundSelection("# ","");break;case"insert-link":this.insertCharactersAroundSelection("[","](url)");break;case"insert-bold":this.insertCharactersAroundSelection("**","**");break;case"insert-italic":this.insertCharactersAroundSelection("_","_");break;case"insert-bullet-points":this.applyTransformationToSelection(c);break;case"insert-enumeration":this.isMultilineTextSelected()?this.applyTransformationToSelection(g):this.insertSingleEnumeration();break;default:throw new Error(`Could not perform markdown-action '${e}'.`)}}toggleViewingModeHook(){this.content_wrappers.forEach((t=>{u(t,"hidden")})),this.view_controls.forEach((t=>{u(t,"engaged")})),this.isDisabled()||this.actions.forEach((t=>{t.disabled=!t.disabled;const e=t.querySelector(".glyph");null!==e&&u(e,"disabled")})),this.maybeUpdatePreviewContent()}insertSingleEnumeration(){const t=this.getLinesOfSelection();if(1!==t.length)return void this.textarea.focus();const e=this.getLinesBeforeSelection(),i=e.length-1;let s=i>=0?function(t){const e=t.match(/([0-9]+)/);if(null!==e)return parseInt(e[0]);return null}(e[i])??0:0;const n=g(t,++s),a=function(t,e=0){if(t.length<1)return[];const i=[];for(const s of t){if(!v(s))break;i.push(s.replace(/([0-9]+)/,(++e).toString()))}i.length>0&&(t=i.concat(t.slice(i.length)));return t}(this.getLinesAfterSelection(),s);let o=e.join("\n");const r=a.join("\n");let l=n.join("\n");o.length>0&&l.length>0&&(o+="\n"),l.length>0&&r.length>0&&(l+="\n");const d=o+l+r,h=d.length-this.textarea.value.length;this.updateTextareaContent(d,this.getAbsoluteSelectionStart()+h,this.getAbsoluteSelectionEnd()+h)}applyTransformationToSelection(t){if(!t instanceof Function)throw new Error(`Transformation must be an instance of Function, ${typeof t} given.`);const e=t(this.getLinesOfSelection());if(!e instanceof Array)throw new Error(`Transformation must return an instance of Array, ${typeof e} returned.`);const i=e.length>1;let s=this.getLinesBeforeSelection().join("\n");const n=this.getLinesAfterSelection().join("\n");let a=e.join("\n");s.length>0&&a.length>0&&(s+="\n"),a.length>0&&n.length>0&&(a+="\n");const o=s+a+n,r=o.length-this.textarea.value.length,l=i?s.length:this.getAbsoluteSelectionStart()+r,d=i?l+a.length-1:this.getAbsoluteSelectionEnd()+r;this.updateTextareaContent(o,l,d)}insertCharactersAroundSelection(t,e){const i=this.getTextBeforeSelection()+t+this.getTextOfSelection()+e+this.getTextAfterSelection(),s=this.getAbsoluteSelectionStart()+t.length,n=this.getAbsoluteSelectionEnd()+t.length;this.updateTextareaContent(i,s,n)}maybeUpdatePreviewContent(){const t=this.preview_history[this.preview_history.length-1]??"",e=this.textarea.value;e!==t&&(this.preview_history.push(e),this.preview_renderer.getPreviewHtmlOf(e).then((t=>{this.content_wrappers.get(d).innerHTML=t})))}getBulletPointTransformation(){return c}getEnumerationTransformation(){return g}}function c(t){const e=[],i=!f(t[0]??"");for(const s of t)e.push(i?`- ${s}`:m(s));return e}function g(t,e=1){const i=[],s=!v(t[0]??"");for(const n of t)i.push(s?`${e++}. ${n}`:m(n));return i}function u(t,e){t.classList.contains(e)?t.classList.remove(e):t.classList.add(e)}function p(t){return t instanceof KeyboardEvent&&"Enter"===t.code}function m(t){return t.replace(/((^(\s*[-])|(^(\s*\d+\.)))\s*)/g,"")}function f(t){return(t.match(/^(\s*[-])/g)??[]).length>0}function v(t){return(t.match(/^(\s*\d+\.)/g)??[]).length>0}class w{instances=[];init(t,e,i){if(void 0!==this.instances[t])throw new Error(`Markdown with input-id '${t}' has already been initialized.`);this.instances[t]=new h(new r(i,e),t)}get(t){return this.instances[t]??null}}class T{constructor(t,e,i,s,n,a=null,o=null,r=null){this.id=t,this.name=e,this.element=i,this.selectButton=s,this.drilldownParentLevel=n,this.drilldownButton=a,this.listElement=o,this.renderUrl=r}}const b="data-node-id",y="data-node-name",S="data-render-url",x="data-ddindex",E="c-input-node",D="c-input-tree_select",N=`${E}__async`,M=`${E}__leaf`,O=`${E}--selected`,C="hidden",I="disabled",_=".glyph",A=`.${E}`,L=`.${D}`,k=`.${D}__selection`,B='[data-action="remove"]',$='[data-action="select"]',V=`.${E}__select`,H=".c-drilldown__menulevel--trigger";function R(t){return function(t){return t.classList.contains(N)}(t)&&t.hasAttribute(S)?t.getAttribute(S):null}function q(t){return!t.classList.contains(M)&&t.classList.contains(E)}function F(t,e=null){return t.reduce(((t,e)=>{const i=function(t){const e=t.getAttribute(b);if(null===e)throw new Error("Could not find data-node-id attribute.");return e}(e);if(t.has(i))throw new Error(`Node '${i}' has already been parsed. There might be a rendering issue.`);return t.set(i,new T(i,function(t){const e=t.querySelector(`[${y}]`);if(null===e)throw new Error("Could not find element with data-node-name attribute.");return e.textContent}(e),e,function(t){const e=t.querySelector(`:scope > ${V}`);if(null===e)throw new Error("Could not find node select button.");return e}(e),function(t){const e=t.closest(`ul[${x}]`);if(null===e)throw new Error("Could not find drilldown menu of node.");return e.getAttribute(x)}(e),function(t){if(!q(t))return null;const e=t.querySelector(`${H}`);if(null===e)throw new Error("Could not find drilldown menu button of branch node.");return e}(e),function(t){if(!q(t))return null;const e=t.querySelector("ul");if(null===e)throw new Error("Could not find list element of branch node.");return e}(e),R(e)))}),new Map(e??[]))}function P(t,e){for(let i=0;i{this.#m()})),this.#p.querySelectorAll('[data-action="close"]').forEach((t=>{t.addEventListener("click",(()=>{this.#f()}))})),this.#h.querySelectorAll("li").forEach((t=>{const e=function(t){const e=t.getAttribute(b);if(null===e)throw new Error(`Could not find '${b}' attribbute of element.`);return e}(t);this.#v(t,e),this.#w(e)})),this.#r.addEngageListener((t=>{this.#T(t)})),this.#u.addEventListener("click",(()=>{this.#b()})),this.#t.forEach((t=>{this.#y(t)})),this.#S()}unselectNode(t){if(this.#x(t),this.#S(),this.#E(t),this.#t.has(t)){const e=this.#t.get(t);j(e.element,!1),this.#D(e.selectButton,e.name),this.updateNodeSelectButtonStates()}}selectNode(t){if(this.#w(t),this.#S(),this.#t.has(t)){const e=this.#t.get(t);j(e.element,!0),this.#N(e.selectButton,e.name),this.#M(e),this.updateNodeSelectButtonStates()}}updateNodeSelectButtonStates(){this.#t.forEach(((t,e)=>{this.#e.size>0?(t.selectButton.disabled=!this.#e.has(e),t.selectButton.querySelector(_).classList.toggle(I,!this.#e.has(e))):(t.selectButton.disabled=!1,t.selectButton.querySelector(_).classList.toggle(I,!1))}))}getSelection(){return new Set(this.#e)}getNodes(){return new Map(this.#t)}async#O(t){var e,i,s;if(!this.#i.has(t.id)&&!this.#s.has(t.id))try{this.#s.add(t.id);const n=await this.#a.loadContent(t.renderUrl);t.listElement.append(...n.children),this.#r.parseLevels();const a=F((s=t.listElement,Array.from(s.querySelectorAll(A))),this.#t),o=(e=a,i=this.#t,Array.from(e.entries()).filter((([t])=>!i.has(t))).map((([,t])=>t)));this.#t=a,P(o,(t=>{this.#e.has(t.id)?this.selectNode(t.id):this.unselectNode(t.id),this.#y(t)})),this.#i.add(t.id)}catch(t){throw new Error(`Could not render async node children: ${t.message}`)}finally{this.#s.delete(t.id)}}#C(t){P(function(t,e,i=255){const s=[];let n=t;for(let t=0;t{const e=t.getAttribute(b);if(null===e||!this.#t.has(e))throw new Error(`Could not find '${b}' of node element.`);const i=this.#t.get(e);this.#I(i)}))}#I(t){const e=this.#n.createContent(this.#d).querySelector(".crumb");e.setAttribute(x,t.drilldownParentLevel),e.firstElementChild.textContent=t.name,e.addEventListener("click",(()=>{this.#r.engageLevel(t.drilldownParentLevel),t.drilldownButton.click()})),this.#l.append(e)}#m(){const t=this.#l.querySelectorAll(".crumb");t.item(t.length-1)?.remove()}#_(){P(this.#l.querySelectorAll(".crumb"),(t=>{t.remove()}))}#T(t){if("0"===t)return void this.#_();const e=this.#p.querySelector(`ul[${x}="${t}"]`)?.closest(A)?.getAttribute(b);if(null===e||!this.#t.has(e))throw new Error(`Could not find node for drilldown-level '${t}'.`);this.#_(),this.#C(this.#t.get(e))}#A(t,e){t.addEventListener("click",(()=>{null!==e.renderUrl&&this.#O(e)}))}#v(t,e){t.querySelector(B)?.addEventListener("click",(()=>{this.unselectNode(e),t.remove()}))}#L(t,e){t.addEventListener("click",(()=>{this.#e.has(e.id)?this.unselectNode(e.id):this.selectNode(e.id)}))}#M(t){if(null!==this.#h.querySelector(`li[${b}="${t.id}"]`))return;const e=this.#n.createContent(this.#c),i=e.querySelector("[data-node-id]");i.setAttribute(b,t.id),i.querySelector(`[${y}]`).textContent=t.name,i.querySelector("input").value=t.id,this.#v(i,t.id),this.#h.append(...e.children)}#E(t){this.#h.querySelector(`li[${b}="${t}"]`)?.remove()}#y(t){this.#L(t.selectButton,t),null!==t.drilldownButton&&this.#A(t.drilldownButton,t)}#D(t,e){t.querySelector(B)?.classList.add(C),t.querySelector($)?.classList.remove(C),t.setAttribute("aria-label",this.#k("select_node",e))}#N(t,e){t.querySelector($)?.classList.add(C),t.querySelector(B)?.classList.remove(C),t.setAttribute("aria-label",this.#k("unselect_node",e))}#S(){this.#g.disabled=this.#e.size<=0}#x(t){this.#e.has(t)&&this.#e.delete(t)}#w(t){this.#e.has(t)||this.#e.add(t)}#k(t,...e){return function(t,...e){const i=[...e];return t.replace(/%s/g,(()=>i.shift()??""))}(this.#o.txt(t),e)}#f(){this.#p.close()}#b(){this.#p.showModal()}}class W extends U{#B;constructor(t,e,i,s,n,a,o,r,l,d,h,c,g,u){super(t,e,i,s,n,a,o,r,l,d,h,c,g),this.#B=u}selectNode(t){if(!this.#B){const e=Array.from(this.getSelection().add(t));this.#$(e,this.getNodes())}super.selectNode(t)}updateNodeSelectButtonStates(){if(this.#B)return;const t=this.getNodes();t.forEach((t=>{t.selectButton.disabled=!1,t.selectButton.querySelector(_).classList.remove(I)})),this.getSelection().forEach((e=>{const i=t.get(e);null!==i&&null!==i.listElement&&i.listElement.querySelectorAll(V).forEach((t=>{t.disabled=!0,t.querySelector(_).classList.add(I)}))}))}#$(t,e){for(let s=0;s{const s=t.getAttribute(i);if(!e.has(s))throw new Error(`Element references '${s}' which does not exist.`);t.setAttribute(i,e.get(s))}))}class X{#V;constructor(t){this.#V=t}createContent(t){const e=t.content.cloneNode(!0),i=new Map;return e.querySelectorAll("[id]").forEach((t=>{const e=function(t=""){return`${t}${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`}("il_ui_fw_");i.set(t.id,e),t.id=e})),e.querySelectorAll("[for]").forEach((t=>{t.htmlFor=i.get(t.htmlFor)})),z(e,i,"aria-describedby"),z(e,i,"aria-labelledby"),z(e,i,"aria-controls"),z(e,i,"aria-owns"),K(this.#V,e.children)}}class J{#V;constructor(t){this.#V=t}loadContent(t){return fetch(t.toString()).then((t=>t.text())).then((t=>this.#H(t))).then((t=>K(this.#V,t))).catch((e=>{throw new Error(`Could not render element(s) from '${t}': ${e.message}`)}))}#R(t){const e=this.#V.createElement("script");return t.hasAttribute("type")&&e.setAttribute("type",t.getAttribute("type")),t.hasAttribute("src")&&e.setAttribute("src",t.getAttribute("src")),t.textContent.length>0&&(e.textContent=t.textContent),e}#H(t){const e=this.#V.createElement("div");return e.innerHTML=t.trim(),e.querySelectorAll("script").forEach((t=>{const e=this.#R(t);t.replaceWith(e)})),e.children}}function Q(t){return Array.from(t.querySelectorAll(A))}class G{#q=new Map;#F;#P;#o;#V;constructor(t,e,i,s){this.#F=t,this.#P=e,this.#o=i,this.#V=s}initTreeMultiSelect(t,e){if(this.#q.has(t))throw new Error(`TreeSelect '${t}' already exists.`);const[i,s,n,a,o,r,l,d]=this.#j(t),h=this.#U(s),c=new W(F(Q(l)),this.#F,new X(this.#V),new J(this.#V),this.#o,h,n,a,o,r,d,i,l,e);return this.#q.set(t,c),c}initTreeSelect(t){if(this.#q.has(t))throw new Error(`TreeSelect '${t}' already exists.`);const[e,i,s,n,a,o,r,l]=this.#j(t),d=this.#U(i),h=new U(F(Q(r)),this.#F,new X(this.#V),new J(this.#V),this.#o,d,s,n,a,o,l,e,r);return this.#q.set(t,h),h}getInstance(t){return this.#q.has(t)?this.#q.get(t):null}#j(t){const e=this.#V.getElementById(t),i=e?.closest(L),s=i?.querySelector(".breadcrumb"),n=i?.querySelector(".modal-body > template"),a=i?.querySelector(k),o=a?.querySelector(":scope > template"),r=i?.querySelector("dialog"),l=r?.querySelector(".btn-primary");if(null===s||null===n||null===a||null===o||null===l||null===e||null===r)throw new Error(`Could not find some element(s) for Tree Select Input '${t}'.`);return[e,i,s,n,a,o,r,l]}#U(t){const e=t.querySelector(".c-drilldown");if(null===e||!e.hasAttribute("id"))throw new Error("Could not find drilldown element.");const i=this.#P.getInstance(e.id);if(null===e)throw new Error("Could not find drilldown instance.");return i}}class Y{#W;constructor(t){this.#W=t}on(t,e,i){this.#W(t).on(e,i)}off(t,e,i){this.#W(t).off(e,i)}}var Z="​";const tt={isEnabled:()=>window.TAGIFY_DEBUG??!0,log(...t){this.isEnabled()&&console.log("[Tagify]:",...t)},warn(...t){this.isEnabled()&&console.warn("[Tagify]:",...t)}},et=(t,e,i,s)=>(t=""+t,e=""+e,s&&(t=t.trim(),e=e.trim()),i?t==e:t.toLowerCase()==e.toLowerCase()),it=(t,e)=>t&&Array.isArray(t)&&t.map((t=>st(t,e)));function st(t,e){var i,s={};for(i in t)e.indexOf(i)<0&&(s[i]=t[i]);return s}function nt(t){return(new DOMParser).parseFromString(t.trim(),"text/html").body.firstElementChild}function at(t,e){for(e=e||"previous";t=t[e+"Sibling"];)if(3==t.nodeType)return t}function ot(t){return"string"==typeof t?t.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/`|'/g,"'"):t}function rt(t){var e=Object.prototype.toString.call(t).split(" ")[1].slice(0,-1);return t===Object(t)&&"Array"!=e&&"Function"!=e&&"RegExp"!=e&&"HTMLUnknownElement"!=e}function lt(t,e,i){function s(t,e){for(var i in e)if(e.hasOwnProperty(i)){if(rt(e[i])){rt(t[i])?s(t[i],e[i]):t[i]=Object.assign({},e[i]);continue}if(Array.isArray(e[i])){t[i]=Object.assign([],e[i]);continue}t[i]=e[i]}}return t instanceof Object||(t={}),s(t,e),i&&s(t,i),t}function dt(){const t=[],e={};for(let i of arguments)for(let s of i)rt(s)?e[s.value]||(t.push(s),e[s.value]=1):t.includes(s)||t.push(s);return t}function ht(t){return String.prototype.normalize?"string"==typeof t?t.normalize("NFD").replace(/[\u0300-\u036f]/g,""):void 0:t}var ct=()=>/(?=.*chrome)(?=.*android)/i.test(navigator.userAgent);function gt(){return([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,(t=>(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16)))}function ut(t){return mt.call(this,t)&&t?.classList?.contains(this.settings.classNames.tag)}function pt(t){return mt.call(this,t)&&t?.closest(this.settings.classNames.tagSelector)}function mt(t){let e=t?.closest?.(this.settings.classNames.namespaceSelector);return e===this.DOM.scope}function ft(t,e){var i=window.getSelection();return e=e||i.getRangeAt(0),"string"==typeof t&&(t=document.createTextNode(t)),e&&(e.deleteContents(),e.insertNode(t)),t}function vt(t,e,i){return t?(e&&(t.__tagifyTagData=i?e:lt({},t.__tagifyTagData||{},e)),t.__tagifyTagData):(tt.warn("tag element doesn't exist",{tagElm:t,data:e}),e)}function wt(t){if(t&&t.parentNode){var e=t,i=window.getSelection(),s=i.getRangeAt(0);i.rangeCount&&(s.setStartAfter(e),s.collapse(!0),i.removeAllRanges(),i.addRange(s))}}function Tt(t,e){t.forEach((t=>{if(vt(t.previousSibling)||!t.previousSibling){var i=document.createTextNode("​");t.before(i),e&&wt(i)}}))}var bt={delimiters:",",pattern:null,tagTextProp:"value",maxTags:1/0,callbacks:{},addTagOnBlur:!0,addTagOn:["blur","tab","enter"],onChangeAfterBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,userInput:!0,focusable:!0,keepInvalidTags:!1,createInvalidTags:!0,mixTagsAllowedAfter:/,|\.|\:|\s/,mixTagsInterpolator:["[[","]]"],backspace:!0,skipInvalid:!1,pasteAsTags:!0,editTags:{clicks:2,keepInvalid:!0},transformTag:()=>{},trim:!0,a11y:{focusableTags:!1},mixMode:{insertAfterTag:" "},autoComplete:{enabled:!0,rightKey:!1,tabKey:!1},classNames:{namespace:"tagify",mixMode:"tagify--mix",selectMode:"tagify--select",input:"tagify__input",focus:"tagify--focus",tagNoAnimation:"tagify--noAnim",tagInvalid:"tagify--invalid",tagNotAllowed:"tagify--notAllowed",scopeLoading:"tagify--loading",hasMaxTags:"tagify--hasMaxTags",hasNoTags:"tagify--noTags",empty:"tagify--empty",inputInvalid:"tagify__input--invalid",dropdown:"tagify__dropdown",dropdownWrapper:"tagify__dropdown__wrapper",dropdownHeader:"tagify__dropdown__header",dropdownFooter:"tagify__dropdown__footer",dropdownItem:"tagify__dropdown__item",dropdownItemActive:"tagify__dropdown__item--active",dropdownItemHidden:"tagify__dropdown__item--hidden",dropdownItemSelected:"tagify__dropdown__item--selected",dropdownInital:"tagify__dropdown--initial",tag:"tagify__tag",tagText:"tagify__tag-text",tagX:"tagify__tag__removeBtn",tagLoading:"tagify__tag--loading",tagEditing:"tagify__tag--editable",tagFlash:"tagify__tag--flash",tagHide:"tagify__tag--hide"},dropdown:{classname:"",enabled:2,maxItems:10,searchKeys:["value","searchBy"],fuzzySearch:!0,caseSensitive:!1,accentedSearch:!0,includeSelectedTags:!1,escapeHTML:!0,highlightFirst:!0,closeOnSelect:!0,clearOnSelect:!0,position:"all",appendTarget:null},hooks:{beforeRemoveTag:()=>Promise.resolve(),beforePaste:()=>Promise.resolve(),suggestionClick:()=>Promise.resolve(),beforeKeyDown:()=>Promise.resolve()}};function yt(){this.dropdown={};for(let t in this._dropdown)this.dropdown[t]="function"==typeof this._dropdown[t]?this._dropdown[t].bind(this):this._dropdown[t];this.dropdown.refs(),this.DOM.dropdown.__tagify=this}var St={...{events:{binding(t=!0){var e=this.dropdown.events.callbacks,i=this.listeners.dropdown=this.listeners.dropdown||{position:this.dropdown.position.bind(this,null),onKeyDown:e.onKeyDown.bind(this),onMouseOver:e.onMouseOver.bind(this),onMouseLeave:e.onMouseLeave.bind(this),onClick:e.onClick.bind(this),onScroll:e.onScroll.bind(this)},s=t?"addEventListener":"removeEventListener";"manual"!=this.settings.dropdown.position&&(document[s]("scroll",i.position,!0),window[s]("resize",i.position),window[s]("keydown",i.onKeyDown)),this.DOM.dropdown[s]("mouseover",i.onMouseOver),this.DOM.dropdown[s]("mouseleave",i.onMouseLeave),this.DOM.dropdown[s]("mousedown",i.onClick),this.DOM.dropdown.content[s]("scroll",i.onScroll)},callbacks:{onKeyDown(t){if(this.state.hasFocus&&!this.state.composing){var e=this.settings,i=e.dropdown.includeSelectedTags,s=this.DOM.dropdown.querySelector(e.classNames.dropdownItemActiveSelector),n=this.dropdown.getSuggestionDataByNode(s),a="mix"==e.mode,o="select"==e.mode;e.hooks.beforeKeyDown(t,{tagify:this}).then((r=>{switch(t.key){case"ArrowDown":case"ArrowUp":case"Down":case"Up":t.preventDefault();var l=this.dropdown.getAllSuggestionsRefs(),d="ArrowUp"==t.key||"Up"==t.key;s&&(s=this.dropdown.getNextOrPrevOption(s,!d)),s&&s.matches(e.classNames.dropdownItemSelector)||(s=l[d?l.length-1:0]),this.dropdown.highlightOption(s,!0);break;case"PageUp":case"PageDown":{t.preventDefault();const e=this.dropdown.getAllSuggestionsRefs(),i=Math.floor(this.DOM.dropdown.content.clientHeight/e[0]?.offsetHeight)||1,n="PageUp"===t.key;if(s){const t=e.indexOf(s),a=n?Math.max(0,t-i):Math.min(e.length-1,t+i);s=e[a]}else s=e[0];this.dropdown.highlightOption(s,!0);break}case"Home":case"End":{t.preventDefault();const e=this.dropdown.getAllSuggestionsRefs();s=e["Home"===t.key?0:e.length-1],this.dropdown.highlightOption(s,!0);break}case"Escape":case"Esc":this.dropdown.hide();break;case"ArrowRight":if(this.state.actions.ArrowLeft||e.autoComplete.rightKey)return;case"Tab":{let i=!e.autoComplete.rightKey||!e.autoComplete.tabKey;if(!a&&!o&&s&&i&&!this.state.editing&&n){t.preventDefault();var h=this.dropdown.getMappedValue(n);return this.state.autoCompleteData=n,this.input.autocomplete.set.call(this,h),!1}return!0}case"Enter":t.preventDefault(),this.state.actions.selectOption=!0,setTimeout((()=>this.state.actions.selectOption=!1),100),e.hooks.suggestionClick(t,{tagify:this,tagData:n,suggestionElm:s}).then((()=>{if(s){var e=i?s:this.dropdown.getNextOrPrevOption(s,!d);this.dropdown.selectOption(s,t,(()=>{if(e){var t=e.getAttribute("value");e=this.dropdown.getSuggestionNodeByValue(t),this.dropdown.highlightOption(e)}}))}else this.dropdown.hide(),a||this.addTags(this.state.inputText.trim(),!0)})).catch((t=>tt.warn(t)));break;case"Backspace":{if(a||this.state.editing.scope)return;const t=this.input.raw.call(this);""!=t&&8203!=t.charCodeAt(0)||(!0===e.backspace?this.removeTags():"edit"==e.backspace&&setTimeout(this.editTag.bind(this),0))}}}))}},onMouseOver(t){var e=t.target.closest(this.settings.classNames.dropdownItemSelector);this.dropdown.highlightOption(e)},onMouseLeave(t){this.dropdown.highlightOption()},onClick(t){if(0==t.button&&t.target!=this.DOM.dropdown&&t.target!=this.DOM.dropdown.content){var e=t.target.closest(this.settings.classNames.dropdownItemSelector),i=this.dropdown.getSuggestionDataByNode(e);this.state.actions.selectOption=!0,setTimeout((()=>this.state.actions.selectOption=!1),100),this.settings.hooks.suggestionClick(t,{tagify:this,tagData:i,suggestionElm:e}).then((()=>{e?this.dropdown.selectOption(e,t):this.dropdown.hide()})).catch((t=>tt.warn(t)))}},onScroll(t){var e=t.target,i=e.scrollTop/(e.scrollHeight-e.parentNode.clientHeight)*100;this.trigger("dropdown:scroll",{percentage:Math.round(i)})}}},refilter(t){t=t||this.state.dropdown.query||"",this.suggestedListItems=this.dropdown.filterListItems(t),this.dropdown.fill(),this.suggestedListItems.length||this.dropdown.hide(),this.trigger("dropdown:updated",this.DOM.dropdown)},getSuggestionDataByNode(t){for(var e,i=t&&t.getAttribute("value"),s=this.suggestedListItems.length;s--;){if(rt(e=this.suggestedListItems[s])&&e.value==i)return e;if(e==i)return{value:e}}},getSuggestionNodeByValue(t){return this.dropdown.getAllSuggestionsRefs().find((e=>e.getAttribute("value")===t))},getNextOrPrevOption(t,e=!0){var i=this.dropdown.getAllSuggestionsRefs(),s=i.findIndex((e=>e===t));return e?i[s+1]:i[s-1]},highlightOption(t,e){var i,s=this.settings.classNames.dropdownItemActive;if(this.state.ddItemElm&&(this.state.ddItemElm.classList.remove(s),this.state.ddItemElm.removeAttribute("aria-selected")),!t)return this.state.ddItemData=null,this.state.ddItemElm=null,void this.input.autocomplete.suggest.call(this);i=this.dropdown.getSuggestionDataByNode(t),this.state.ddItemData=i,this.state.ddItemElm=t,t.classList.add(s),t.setAttribute("aria-selected",!0),e&&(t.parentNode.scrollTop=t.clientHeight+t.offsetTop-t.parentNode.clientHeight),this.settings.autoComplete&&(this.input.autocomplete.suggest.call(this,i),this.dropdown.position())},selectOption(t,e,i){var s=this.settings,n=s.dropdown.includeSelectedTags,{clearOnSelect:a,closeOnSelect:o}=s.dropdown;if(!t)return this.addTags(this.state.inputText,!0),void(o&&this.dropdown.hide());e=e||{};var r=t.getAttribute("value"),l="noMatch"==r,d="mix"==s.mode,h=this.suggestedListItems.find((t=>(t.value??t)==r));if(this.trigger("dropdown:select",{data:h,elm:t,event:e}),h||l){if(this.state.editing){let t=this.normalizeTags([h])[0];h=s.transformTag.call(this,t)||t,this.onEditTagDone(null,lt({__isValid:!0},h))}else this[d?"addMixTags":"addTags"]([h||this.input.raw.call(this)],a);(d||this.DOM.input.parentNode)&&(setTimeout((()=>{this.DOM.input.focus(),this.toggleFocusClass(!0)})),o&&setTimeout(this.dropdown.hide.bind(this)),n?i&&i():(t.addEventListener("transitionend",(()=>{this.dropdown.fillHeaderFooter(),setTimeout((()=>{t.remove(),this.dropdown.refilter(),i&&i()}),100)}),{once:!0}),t.classList.add(this.settings.classNames.dropdownItemHidden)))}else o&&setTimeout(this.dropdown.hide.bind(this))},selectAll(t){this.suggestedListItems.length=0,this.dropdown.hide(),this.dropdown.filterListItems("");var e=this.dropdown.filterListItems("");return t||(e=this.state.dropdown.suggestions),this.addTags(e,!0),this},filterListItems(t,e){var i,s,n,a,o,r=this.settings,l=r.dropdown,d=(e=e||{},[]),h=[],c=r.whitelist,g=l.maxItems>=0?l.maxItems:1/0,u=l.includeSelectedTags,p="function"==typeof l.sortby,m=l.searchKeys,f=0;if(!(t="select"==r.mode&&this.value.length&&this.value[0][r.tagTextProp]==t?"":t)||!m.length){d=u?c:c.filter((t=>!this.isTagDuplicate(rt(t)?t.value:t)));var v=p?l.sortby(d,o):d.slice(0,g);return this.state.dropdown.suggestions=v,v}function w(t,e){return e.toLowerCase().split(" ").every((e=>t.includes(e.toLowerCase())))}for(o=l.caseSensitive?""+t:(""+t).toLowerCase();fm.includes(t)))?["value"]:m;l.fuzzySearch&&!e.exact?(n=g.reduce(((t,e)=>t+" "+(i[e]||"")),"").toLowerCase().trim(),l.accentedSearch&&(n=ht(n),o=ht(o)),t=0==n.indexOf(o),r=n===o,s=w(n,o)):(t=!0,s=g.some((t=>{var s=""+(i[t]||"");return l.accentedSearch&&(s=ht(s),o=ht(o)),l.caseSensitive||(s=s.toLowerCase()),r=s===o,e.exact?s===o:0==s.indexOf(o)}))),a=!l.includeSelectedTags&&this.isTagDuplicate(rt(i)?i.value:i),s&&!a&&(r&&t?h.push(i):"startsWith"==l.sortby&&t?d.unshift(i):d.push(i))}this.state.dropdown.suggestions=h.concat(d);v=p?l.sortby(h.concat(d),o):h.concat(d).slice(0,g);return this.state.dropdown.suggestions=v,v},getMappedValue(t){var e=this.settings.dropdown.mapValueTo;return e?"function"==typeof e?e(t):t[e]||t.value:t.value},createListHTML(t){return lt([],t).map(((t,e)=>{"string"!=typeof t&&"number"!=typeof t||(t={value:t});var i=this.dropdown.getMappedValue(t);return i="string"==typeof i&&this.settings.dropdown.escapeHTML?ot(i):i,this.settings.templates.dropdownItem.apply(this,[{...t,mappedValue:i},this])})).join("")}},refs(){this.DOM.dropdown=this.parseTemplate("dropdown",[this.settings]),this.DOM.dropdown.content=this.DOM.dropdown.querySelector("[data-selector='tagify-suggestions-wrapper']")},getHeaderRef(){return this.DOM.dropdown.querySelector("[data-selector='tagify-suggestions-header']")},getFooterRef(){return this.DOM.dropdown.querySelector("[data-selector='tagify-suggestions-footer']")},getAllSuggestionsRefs(){return[...this.DOM.dropdown.content.querySelectorAll(this.settings.classNames.dropdownItemSelector)]},show(t){var e,i,s,n=this.settings,a="mix"==n.mode&&!n.enforceWhitelist,o=!n.whitelist||!n.whitelist.length,r="manual"==n.dropdown.position;if(t=void 0===t?this.state.inputText:t,!(o&&!a&&!n.templates.dropdownItemNoMatch||!1===n.dropdown.enabled||this.state.isLoading||this.settings.readonly)){if(clearTimeout(this.dropdownHide__bindEventsTimeout),this.suggestedListItems=this.dropdown.filterListItems(t),t&&!this.suggestedListItems.length&&(this.trigger("dropdown:noMatch",t),n.templates.dropdownItemNoMatch&&(s=n.templates.dropdownItemNoMatch.call(this,{value:t}))),!s){if(this.suggestedListItems.length)t&&a&&!this.state.editing.scope&&!et(this.suggestedListItems[0].value,t)&&this.suggestedListItems.unshift({value:t});else{if(!t||!a||this.state.editing.scope)return this.input.autocomplete.suggest.call(this),void this.dropdown.hide();this.suggestedListItems=[{value:t}]}i=""+(rt(e=this.suggestedListItems[0])?e.value:e),n.autoComplete&&i&&0==i.indexOf(t)&&this.input.autocomplete.suggest.call(this,e)}this.dropdown.fill(s),n.dropdown.highlightFirst&&this.dropdown.highlightOption(this.DOM.dropdown.content.querySelector(n.classNames.dropdownItemSelector)),this.state.dropdown.visible||setTimeout(this.dropdown.events.binding.bind(this)),this.state.dropdown.visible=t||!0,this.state.dropdown.query=t,this.setStateSelection(),r||setTimeout((()=>{this.dropdown.position(),this.dropdown.render()})),setTimeout((()=>{this.trigger("dropdown:show",this.DOM.dropdown)}))}},hide(t){var{scope:e,dropdown:i}=this.DOM,s="manual"==this.settings.dropdown.position&&!t;if(i&&document.body.contains(i)&&!s)return window.removeEventListener("resize",this.dropdown.position),this.dropdown.events.binding.call(this,!1),e.setAttribute("aria-expanded",!1),i.parentNode.removeChild(i),setTimeout((()=>{this.state.dropdown.visible=!1}),100),this.state.dropdown.query=this.state.ddItemData=this.state.ddItemElm=this.state.selection=null,this.state.tag&&this.state.tag.value.length&&(this.state.flaggedTags[this.state.tag.baseOffset]=this.state.tag),this.trigger("dropdown:hide",i),this},toggle(t){this.dropdown[this.state.dropdown.visible&&!t?"hide":"show"]()},getAppendTarget(){var t=this.settings.dropdown;return"function"==typeof t.appendTarget?t.appendTarget():t.appendTarget},render(){var t,e,i,s=(t=this.DOM.dropdown,(i=t.cloneNode(!0)).style.cssText="position:fixed; top:-9999px; opacity:0",document.body.appendChild(i),e=i.clientHeight,i.parentNode.removeChild(i),e),n=this.settings,a=this.dropdown.getAppendTarget();return!1===n.dropdown.enabled||(this.DOM.scope.setAttribute("aria-expanded",!0),document.body.contains(this.DOM.dropdown)||(this.DOM.dropdown.classList.add(n.classNames.dropdownInital),this.dropdown.position(s),a.appendChild(this.DOM.dropdown),setTimeout((()=>this.DOM.dropdown.classList.remove(n.classNames.dropdownInital))))),this},fill(t){t="string"==typeof t?t:this.dropdown.createListHTML(t||this.suggestedListItems);var e,i=this.settings.templates.dropdownContent.call(this,t);this.DOM.dropdown.content.innerHTML=(e=i)?e.replace(/\>[\r\n ]+\<").split(/>\s+<").trim():""},fillHeaderFooter(){var t=this.dropdown.filterListItems(this.state.dropdown.query),e=this.parseTemplate("dropdownHeader",[t]),i=this.parseTemplate("dropdownFooter",[t]),s=this.dropdown.getHeaderRef(),n=this.dropdown.getFooterRef();e&&s?.parentNode.replaceChild(e,s),i&&n?.parentNode.replaceChild(i,n)},position(t){var e=this.settings.dropdown,i=this.dropdown.getAppendTarget();if("manual"!=e.position&&i){var s,n,a,o,r,l,d,h,c,g,u=this.DOM.dropdown,p=e.RTL,m=i===document.body,f=i===this.DOM.scope,v=m?window.pageYOffset:i.scrollTop,w=document.fullscreenElement||document.webkitFullscreenElement||document.documentElement,T=w.clientHeight,b=Math.max(w.clientWidth||0,window.innerWidth||0),y=b>480?e.position:"all",S=this.DOM["input"==y?"input":"scope"];if(t=t||u.clientHeight,this.state.dropdown.visible){if("text"==y?(a=(s=function(){const t=document.getSelection();if(t.rangeCount){const e=t.getRangeAt(0),i=e.startContainer,s=e.startOffset;let n,a;if(s>0)return a=document.createRange(),a.setStart(i,s-1),a.setEnd(i,s),n=a.getBoundingClientRect(),{left:n.right,top:n.top,bottom:n.bottom};if(i.getBoundingClientRect)return i.getBoundingClientRect()}return{left:-9999,top:-9999}}()).bottom,n=s.top,o=s.left,r="auto"):(l=function(t){var e=0,i=0;for(t=t.parentNode;t&&t!=w;)e+=t.offsetTop||0,i+=t.offsetLeft||0,t=t.parentNode;return{top:e,left:i}}(i),s=S.getBoundingClientRect(),n=f?-1:s.top-l.top,a=(f?s.height:s.bottom-l.top)-1,o=f?-1:s.left-l.left,r=s.width+"px"),!m){let t=function(){for(var t=0,i=e.appendTarget.parentNode;i;)t+=i.scrollTop||0,i=i.parentNode;return t}();n+=t,a+=t}n=Math.floor(n),a=Math.ceil(a),h=b-o<120,c=((d=e.placeAbove??T-s.bottom\n ${this.settings.templates.input.call(this)}\n ${Z}\n `},input(){var t=this.settings,e=t.placeholder||Z;return``},tag(t,{settings:e}){return`\n \n
\n ${t[e.tagTextProp]||t.value}\n
\n
`},dropdown(t){var e=t.dropdown;return`
\n
\n
`},dropdownContent(t){var e=this.settings.templates,i=this.state.dropdown.suggestions;return`\n ${e.dropdownHeader.call(this,i)}\n ${t}\n ${e.dropdownFooter.call(this,i)}\n `},dropdownItem(t){return`
${t.mappedValue||t.value}
`},dropdownHeader(t){return`
`},dropdownFooter(t){var e=t.length-this.settings.dropdown.maxItems;return e>0?`
\n ${e} more items. Refine your search.\n
`:""},dropdownItemNoMatch:null};var Nt,Mt={customBinding(){this.customEventsList.forEach((t=>{this.on(t,this.settings.callbacks[t])}))},binding(t=!0){var e,i=this.settings,s=this.events.callbacks,n=t?"addEventListener":"removeEventListener";if(!this.state.mainEvents||!t){for(var a in this.state.mainEvents=t,t&&!this.listeners.main&&(this.events.bindGlobal.call(this),this.settings.isJQueryPlugin&&jQuery(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this))),e=this.listeners.main=this.listeners.main||{keydown:["input",s.onKeydown.bind(this)],click:["scope",s.onClickScope.bind(this)],dblclick:"select"!=i.mode&&["scope",s.onDoubleClickScope.bind(this)],paste:["input",s.onPaste.bind(this)],drop:["input",s.onDrop.bind(this)],compositionstart:["input",s.onCompositionStart.bind(this)],compositionend:["input",s.onCompositionEnd.bind(this)]})e[a]&&this.DOM[e[a][0]][n](a,e[a][1]);var o=this.listeners.main.inputMutationObserver||new MutationObserver(s.onInputDOMChange.bind(this));o.disconnect(),"mix"==i.mode&&o.observe(this.DOM.input,{childList:!0}),this.events.bindOriginaInputListener.call(this)}},bindOriginaInputListener(t){const e=(t||0)+500;this.listeners.main&&(clearInterval(this.listeners.main.originalInputValueObserverInterval),this.listeners.main.originalInputValueObserverInterval=setInterval(this.events.callbacks.observeOriginalInputValue.bind(this),e))},bindGlobal(t){var e,i=this.events.callbacks,s=t?"removeEventListener":"addEventListener";if(this.listeners&&(t||!this.listeners.global))for(e of(this.listeners.global=this.listeners.global||[{type:this.isIE?"keydown":"input",target:this.DOM.input,cb:i[this.isIE?"onInputIE":"onInput"].bind(this)},{type:"keydown",target:window,cb:i.onWindowKeyDown.bind(this)},{type:"focusin",target:this.DOM.scope,cb:i.onFocusBlur.bind(this)},{type:"focusout",target:this.DOM.scope,cb:i.onFocusBlur.bind(this)},{type:"click",target:document,cb:i.onClickAnywhere.bind(this),useCapture:!0}],this.listeners.global))e.target[s](e.type,e.cb,!!e.useCapture)},unbindGlobal(){this.events.bindGlobal.call(this,!0)},callbacks:{onFocusBlur(t){var e=this.settings,i=pt.call(this,t.relatedTarget),s=ut.call(this,t.relatedTarget),n=t.target.classList.contains(e.classNames.tagX),a="focusin"==t.type,o="focusout"==t.type;n&&"mix"!=e.mode&&this.DOM.input.focus(),i&&a&&!s&&!n&&this.toggleFocusClass(this.state.hasFocus=+new Date);var r=t.target?this.trim(this.DOM.input.textContent):"",l=this.value?.[0]?.[e.tagTextProp],d=e.dropdown.enabled>=0,h={relatedTarget:t.relatedTarget},c=this.state.actions.selectOption&&(d||!e.dropdown.closeOnSelect),g=this.state.actions.addNew&&d;if(o){if(t.relatedTarget===this.DOM.scope)return this.dropdown.hide(),void this.DOM.input.focus();this.postUpdate(),e.onChangeAfterBlur&&this.triggerChangeEvent()}if(!(c||g||n))if(this.state.hasFocus=!(!a&&!i)&&+new Date,this.toggleFocusClass(this.state.hasFocus),"mix"!=e.mode){if(a){if(!e.focusable)return;var u=0===e.dropdown.enabled&&!this.state.dropdown.visible,p=!s||"select"===e.mode,m=this.DOM.scope.querySelector(this.settings.classNames.tagTextSelector);return this.trigger("focus",h),void(u&&p&&(this.dropdown.show(this.value.length?"":void 0),this.setRangeAtStartEnd(!1,m)))}if(o){if(this.trigger("blur",h),this.loading(!1),"select"==e.mode){if(this.value.length){let t=this.getTagElms()[0];r=this.trim(t.textContent)}l===r&&(r="")}r&&!this.state.actions.selectOption&&e.addTagOnBlur&&e.addTagOn.includes("blur")&&this.addTags(r,!0)}i||(this.DOM.input.removeAttribute("style"),this.dropdown.hide())}else a?this.trigger("focus",h):o&&(this.trigger("blur",h),this.loading(!1),this.dropdown.hide(),this.state.dropdown.visible=void 0,this.setStateSelection())},onCompositionStart(t){this.state.composing=!0},onCompositionEnd(t){this.state.composing=!1},onWindowKeyDown(t){var e,i=this.settings,s=document.activeElement,n=pt.call(this,s)&&this.DOM.scope.contains(s),a=s===this.DOM.input,o=n&&s.hasAttribute("readonly"),r=this.DOM.scope.querySelector(this.settings.classNames.tagTextSelector),l=this.state.dropdown.visible;if(("Tab"===t.key&&l||this.state.hasFocus||n&&!o)&&!a){e=s.nextElementSibling;var d=t.target.classList.contains(i.classNames.tagX);switch(t.key){case"Backspace":i.readonly||this.state.editing||(this.removeTags(s),(e||this.DOM.input).focus());break;case"Enter":if(d)return void this.removeTags(t.target.parentNode);i.a11y.focusableTags&&ut.call(this,s)&&setTimeout(this.editTag.bind(this),0,s);break;case"ArrowDown":this.state.dropdown.visible||"mix"==i.mode||this.dropdown.show();break;case"Tab":r?.focus()}}},onKeydown(t){var e=this.settings;if(!this.state.composing&&e.userInput){"select"==e.mode&&e.enforceWhitelist&&this.value.length&&"Tab"!=t.key&&t.preventDefault();var i=this.trim(t.target.textContent);this.trigger("keydown",{event:t}),e.hooks.beforeKeyDown(t,{tagify:this}).then((s=>{if("mix"==e.mode){switch(t.key){case"Left":case"ArrowLeft":this.state.actions.ArrowLeft=!0;break;case"Delete":case"Backspace":if(this.state.editing)return;var n=document.getSelection(),a="Delete"==t.key&&n.anchorOffset==(n.anchorNode.length||0),o=n.anchorNode.previousSibling,r=1==n.anchorNode.nodeType||!n.anchorOffset&&o&&1==o.nodeType&&n.anchorNode.previousSibling;!function(t){var e=document.createElement("div");t.replace(/\&#?[0-9a-z]+;/gi,(function(t){return e.innerHTML=t,e.innerText}))}(this.DOM.input.innerHTML);var l,d,h,c=this.getTagElms(),g=1===n.anchorNode.length&&n.anchorNode.nodeValue==String.fromCharCode(8203);if("edit"==e.backspace&&r)return l=1==n.anchorNode.nodeType?null:n.anchorNode.previousElementSibling,setTimeout(this.editTag.bind(this),0,l),void t.preventDefault();if(ct()&&r instanceof Element)return h=at(r),r.hasAttribute("readonly")||r.remove(),this.DOM.input.focus(),void setTimeout((()=>{wt(h),this.DOM.input.click()}));if("BR"==n.anchorNode.nodeName)return;if((a||r)&&1==n.anchorNode.nodeType?d=0==n.anchorOffset?a?c[0]:null:c[Math.min(c.length,n.anchorOffset)-1]:a?d=n.anchorNode.nextElementSibling:r instanceof Element&&(d=r),3==n.anchorNode.nodeType&&!n.anchorNode.nodeValue&&n.anchorNode.previousElementSibling&&t.preventDefault(),(r||a)&&!e.backspace)return void t.preventDefault();if("Range"!=n.type&&!n.anchorOffset&&n.anchorNode==this.DOM.input&&"Delete"!=t.key)return void t.preventDefault();if("Range"!=n.type&&d&&d.hasAttribute("readonly"))return void wt(at(d));"Delete"==t.key&&g&&vt(n.anchorNode.nextSibling)&&this.removeTags(n.anchorNode.nextSibling)}return!0}var u="manual"==e.dropdown.position;switch(t.key){case"Backspace":"select"==e.mode&&e.enforceWhitelist&&this.value.length?this.removeTags():this.state.dropdown.visible&&"manual"!=e.dropdown.position||""!=t.target.textContent&&8203!=i.charCodeAt(0)||(!0===e.backspace?this.removeTags():"edit"==e.backspace&&setTimeout(this.editTag.bind(this),0));break;case"Esc":case"Escape":if(this.state.dropdown.visible)return;t.target.blur();break;case"Down":case"ArrowDown":this.state.dropdown.visible||this.dropdown.show();break;case"ArrowRight":{let t=this.state.inputSuggestion||this.state.ddItemData;if(t&&e.autoComplete.rightKey)return void this.addTags([t],!0);break}case"Tab":return!0;case"Enter":if(this.state.dropdown.visible&&!u)return;t.preventDefault();var p=this.state.autoCompleteData||i;setTimeout((()=>{this.state.dropdown.visible&&!u||this.state.actions.selectOption||!e.addTagOn.includes(t.key.toLowerCase())||(this.addTags([p],!0),this.state.autoCompleteData=null)}))}})).catch((t=>t))}},onInput(t){this.postUpdate();var e=this.settings;if("mix"==e.mode)return this.events.callbacks.onMixTagsInput.call(this,t);var i=this.input.normalize.call(this,void 0,{trim:!1}),s=i.length>=e.dropdown.enabled,n={value:i,inputElm:this.DOM.input},a=this.validateTag({value:i});"select"==e.mode&&this.toggleScopeValidation(a),n.isValid=a,this.state.inputText!=i&&(this.input.set.call(this,i,!1),-1!=i.search(e.delimiters)?this.addTags(i)&&this.input.set.call(this):e.dropdown.enabled>=0&&this.dropdown[s?"show":"hide"](i),this.trigger("input",n))},onMixTagsInput(t){var e,i,s,n,a,o,r,l,d=this.settings,h=this.value.length,c=this.getTagElms(),g=document.createDocumentFragment(),u=window.getSelection().getRangeAt(0),p=[].map.call(c,(t=>vt(t).value));if("deleteContentBackward"==t.inputType&&ct()&&this.events.callbacks.onKeydown.call(this,{target:t.target,key:"Backspace"}),Tt(this.getTagElms()),this.value.slice().forEach((t=>{t.readonly&&!p.includes(t.value)&&g.appendChild(this.createTagElem(t))})),g.childNodes.length&&(u.insertNode(g),this.setRangeAtStartEnd(!1,g.lastChild)),c.length!=h)return this.value=[].map.call(this.getTagElms(),(t=>vt(t))),void this.update({withoutChangeEvent:!0});if(this.hasMaxTags())return!0;if(window.getSelection&&(o=window.getSelection()).rangeCount>0&&3==o.anchorNode.nodeType){if((u=o.getRangeAt(0).cloneRange()).collapse(!0),u.setStart(o.focusNode,0),s=(e=u.toString().slice(0,u.endOffset)).split(d.pattern).length-1,(i=e.match(d.pattern))&&(n=e.slice(e.lastIndexOf(i[i.length-1]))),n){if(this.state.actions.ArrowLeft=!1,this.state.tag={prefix:n.match(d.pattern)[0],value:n.replace(d.pattern,"")},this.state.tag.baseOffset=o.baseOffset-this.state.tag.value.length,l=this.state.tag.value.match(d.delimiters))return this.state.tag.value=this.state.tag.value.replace(d.delimiters,""),this.state.tag.delimiters=l[0],this.addTags(this.state.tag.value,d.dropdown.clearOnSelect),void this.dropdown.hide();a=this.state.tag.value.length>=d.dropdown.enabled;try{r=(r=this.state.flaggedTags[this.state.tag.baseOffset]).prefix==this.state.tag.prefix&&r.value[0]==this.state.tag.value[0],this.state.flaggedTags[this.state.tag.baseOffset]&&!this.state.tag.value&&delete this.state.flaggedTags[this.state.tag.baseOffset]}catch(t){}(r||s{this.update({withoutChangeEvent:!0}),this.trigger("input",lt({},this.state.tag,{textContent:this.DOM.input.textContent})),this.state.tag&&this.dropdown[a?"show":"hide"](this.state.tag.value)}),10)},onInputIE(t){var e=this;setTimeout((function(){e.events.callbacks.onInput.call(e,t)}))},observeOriginalInputValue(){this.DOM.originalInput.parentNode||this.destroy(),this.DOM.originalInput.value!=this.DOM.originalInput.tagifyValue&&this.loadOriginalValues()},onClickAnywhere(t){if(t.target!=this.DOM.scope&&!this.DOM.scope.contains(t.target)){this.toggleFocusClass(!1),this.state.hasFocus=!1;let e=t.target.closest(this.settings.classNames.dropdownSelector);e?.__tagify!=this&&this.dropdown.hide()}},onClickScope(t){var e=this.settings,i=t.target.closest("."+e.classNames.tag),s=t.target===this.DOM.scope,n=+new Date-this.state.hasFocus;if(s&&"select"!=e.mode)this.DOM.input.focus();else{if(!t.target.classList.contains(e.classNames.tagX))return i&&!this.state.editing?(this.trigger("click",{tag:i,index:this.getNodeIndex(i),data:vt(i),event:t}),void(1!==e.editTags&&1!==e.editTags.clicks&&"select"!=e.mode||this.events.callbacks.onDoubleClickScope.call(this,t))):void(t.target==this.DOM.input&&("mix"==e.mode&&this.fixFirefoxLastTagNoCaret(),n>500||!e.focusable)?this.state.dropdown.visible?this.dropdown.hide():0===e.dropdown.enabled&&"mix"!=e.mode&&this.dropdown.show(this.value.length?"":void 0):"select"!=e.mode||0!==e.dropdown.enabled||this.state.dropdown.visible||(this.events.callbacks.onDoubleClickScope.call(this,{...t,target:this.getTagElms()[0]}),!e.userInput&&this.dropdown.show()));this.removeTags(t.target.parentNode)}},onPaste(t){t.preventDefault();var e,i,s,n=this.settings;if(!n.userInput)return!1;n.readonly||(i=t.clipboardData||window.clipboardData,s=i.getData("Text"),n.hooks.beforePaste(t,{tagify:this,pastedText:s,clipboardData:i}).then((n=>{void 0===n&&(n=s),n&&(this.injectAtCaret(n,window.getSelection().getRangeAt(0)),"mix"==this.settings.mode?this.events.callbacks.onMixTagsInput.call(this,t):this.settings.pasteAsTags?e=this.addTags(this.state.inputText+n,!0):(this.state.inputText=n,this.dropdown.show(n))),this.trigger("paste",{event:t,pastedText:s,clipboardData:i,tagsElems:e})})).catch((t=>t)))},onDrop(t){t.preventDefault()},onEditTagInput(t,e){var i=t.closest("."+this.settings.classNames.tag),s=this.getNodeIndex(i),n=vt(i),a=this.input.normalize.call(this,t),o={[this.settings.tagTextProp]:a,__tagId:n.__tagId},r=this.validateTag(o);this.editTagChangeDetected(lt(n,o))||!0!==t.originalIsValid||(r=!0),i.classList.toggle(this.settings.classNames.tagInvalid,!0!==r),n.__isValid=r,i.title=!0===r?n.title||n.value:r,a.length>=this.settings.dropdown.enabled&&(this.state.editing&&(this.state.editing.value=a),this.dropdown.show(a)),this.trigger("edit:input",{tag:i,index:s,data:lt({},this.value[s],{newValue:a}),event:e})},onEditTagPaste(t,e){var i=(e.clipboardData||window.clipboardData).getData("Text");e.preventDefault();var s=ft(i);this.setRangeAtStartEnd(!1,s)},onEditTagClick(t,e){this.events.callbacks.onClickScope.call(this,e)},onEditTagFocus(t){this.state.editing={scope:t,input:t.querySelector("[contenteditable]")}},onEditTagBlur(t,e){var i=ut.call(this,e.relatedTarget);if("select"==this.settings.mode&&i&&e.relatedTarget.contains(e.target))this.dropdown.hide();else if(this.state.editing&&(this.state.hasFocus||this.toggleFocusClass(),this.DOM.scope.contains(document.activeElement)||this.trigger("blur",{}),this.DOM.scope.contains(t))){var s,n,a=this.settings,o=t.closest("."+a.classNames.tag),r=vt(o),l=this.input.normalize.call(this,t),d={[a.tagTextProp]:l,__tagId:r.__tagId},h=r.__originalData,c=this.editTagChangeDetected(lt(r,d)),g=this.validateTag(d);if(l)if(c){if(s=this.hasMaxTags(),n=lt({},h,{[a.tagTextProp]:this.trim(l),__isValid:g}),a.transformTag.call(this,n,h),!0!==(g=(!s||!0===h.__isValid)&&this.validateTag(n))){if(this.trigger("invalid",{data:n,tag:o,message:g}),a.editTags.keepInvalid)return;a.keepInvalidTags?n.__isValid=g:n=h}else a.keepInvalidTags&&(delete n.title,delete n["aria-invalid"],delete n.class);this.onEditTagDone(o,n)}else this.onEditTagDone(o,h);else this.onEditTagDone(o)}},onEditTagkeydown(t,e){if(!this.state.composing)switch(this.trigger("edit:keydown",{event:t}),t.key){case"Esc":case"Escape":this.state.editing=!1,!!e.__tagifyTagData.__originalData.value?e.parentNode.replaceChild(e.__tagifyTagData.__originalHTML,e):e.remove();break;case"Enter":case"Tab":t.preventDefault();setTimeout((()=>t.target.blur()),0)}},onDoubleClickScope(t){var e=t.target.closest("."+this.settings.classNames.tag);if(e){var i,s,n=vt(e),a=this.settings;!1!==n?.editable&&(i=e.classList.contains(this.settings.classNames.tagEditing),s=e.hasAttribute("readonly"),a.readonly||i||s||!this.settings.editTags||!a.userInput||(this.events.callbacks.onEditTagFocus.call(this,e),this.editTag(e)),this.toggleFocusClass(!0),"select"!=a.mode&&this.trigger("dblclick",{tag:e,index:this.getNodeIndex(e),data:vt(e)}))}},onInputDOMChange(t){t.forEach((t=>{t.addedNodes.forEach((t=>{if("

"==t.outerHTML)t.replaceWith(document.createElement("br"));else if(1==t.nodeType&&t.querySelector(this.settings.classNames.tagSelector)){let e=document.createTextNode("");3==t.childNodes[0].nodeType&&"BR"!=t.previousSibling.nodeName&&(e=document.createTextNode("\n")),t.replaceWith(e,...[...t.childNodes].slice(0,-1)),wt(e)}else if(ut.call(this,t))if(3!=t.previousSibling?.nodeType||t.previousSibling.textContent||t.previousSibling.remove(),t.previousSibling&&"BR"==t.previousSibling.nodeName){t.previousSibling.replaceWith("\n​");let e=t.nextSibling,i="";for(;e;)i+=e.textContent,e=e.nextSibling;i.trim()&&wt(t.previousSibling)}else t.previousSibling&&!vt(t.previousSibling)||t.before("​")})),t.removedNodes.forEach((t=>{t&&"BR"==t.nodeName&&ut.call(this,e)&&(this.removeTags(e),this.fixFirefoxLastTagNoCaret())}))}));var e=this.DOM.input.lastChild;e&&""==e.nodeValue&&e.remove(),e&&"BR"==e.nodeName||this.DOM.input.appendChild(document.createElement("br"))}}};function Ot(t,e){if(!t){tt.warn("input element not found",t);const e=new Proxy(this,{get:()=>()=>e});return e}if(t.__tagify)return tt.warn("input element is already Tagified - Same instance is returned.",t),t.__tagify;var i;lt(this,function(t){var e=document.createTextNode(""),i={};function s(t,i,s){s&&i.split(/\s+/g).forEach((i=>e[t+"EventListener"].call(e,i,s)))}return{removeAllCustomListeners(){Object.entries(i).forEach((([t,e])=>{e.forEach((e=>s("remove",t,e)))})),i={}},off(t,e){return t&&(e?s("remove",t,e):t.split(/\s+/g).forEach((t=>{i[t]?.forEach((e=>s("remove",t,e))),delete i[t]}))),this},on(t,e){return e&&"function"==typeof e&&(t.split(/\s+/g).forEach((t=>{Array.isArray(i[t])?i[t].push(e):i[t]=[e]})),s("add",t,e)),this},trigger(i,s,n){var a;if(n=n||{cloneData:!0},i)if(t.settings.isJQueryPlugin)"remove"==i&&(i="removeTag"),jQuery(t.DOM.originalInput).triggerHandler(i,[s]);else{try{var o="object"==typeof s?s:{value:s};if((o=n.cloneData?lt({},o):o).tagify=this,s.event&&(o.event=this.cloneEvent(s.event)),s instanceof Object)for(var r in s)s[r]instanceof HTMLElement&&(o[r]=s[r]);a=new CustomEvent(i,{detail:o})}catch(t){tt.warn(t)}e.dispatchEvent(a)}}}}(this)),this.isFirefox=/firefox|fxios/i.test(navigator.userAgent)&&!/seamonkey/i.test(navigator.userAgent),this.isIE=window.document.documentMode,e=e||{},this.getPersistedData=(i=e.id,t=>{if(!i)return;let e,s="/"+t,n=localStorage?.getItem(xt+i+"/v");if(1===n)try{e=JSON.parse(localStorage[xt+i+s])}catch(t){}return e}),this.setPersistedData=(t=>t?(localStorage?.setItem(xt+t+"/v",1),(e,i)=>{let s="/"+i,n=JSON.stringify(e);e&&i&&(localStorage?.setItem(xt+t+s,n),dispatchEvent(new Event("storage")))}):()=>{})(e.id),this.clearPersistedData=(t=>e=>{const i=xt+"/"+t+"/";if(e)localStorage.removeItem(i+e);else for(let t in localStorage)t.includes(i)&&localStorage.removeItem(t)})(e.id),this.applySettings(t,e),this.state={inputText:"",editing:!1,composing:!1,actions:{},mixMode:{},dropdown:{},flaggedTags:{}},this.value=[],this.listeners={},this.DOM={},this.build(t),yt.call(this),this.getCSSVars(),this.loadOriginalValues(),this.events.customBinding.call(this),this.events.binding.call(this),t.autofocus&&this.DOM.input.focus(),t.__tagify=this}Ot.prototype={_dropdown:St,placeCaretAfterNode:wt,getSetTagData:vt,helpers:{sameStr:et,removeCollectionProp:it,omit:st,isObject:rt,parseHTML:nt,escapeHTML:ot,extend:lt,concatWithoutDups:dt,getUID:gt,isNodeTag:ut},customEventsList:["change","add","remove","invalid","input","paste","click","keydown","focus","blur","edit:input","edit:beforeUpdate","edit:updated","edit:start","edit:keydown","dropdown:show","dropdown:hide","dropdown:select","dropdown:updated","dropdown:noMatch","dropdown:scroll"],dataProps:["__isValid","__removed","__originalData","__originalHTML","__tagId"],trim(t){return this.settings.trim&&t&&"string"==typeof t?t.trim():t},parseHTML:nt,templates:Dt,parseTemplate(t,e){return nt((t=this.settings.templates[t]||t).apply(this,e))},set whitelist(t){const e=t&&Array.isArray(t);this.settings.whitelist=e?t:[],this.setPersistedData(e?t:[],"whitelist")},get whitelist(){return this.settings.whitelist},set userInput(t){this.settings.userInput=!!t,this.setContentEditable(!!t)},get userInput(){return this.settings.userInput},generateClassSelectors(t){for(let e in t){let i=e;Object.defineProperty(t,i+"Selector",{get(){return"."+this[i].split(" ")[0]}})}},applySettings(t,e){bt.templates=this.templates;var i=lt({},bt,"mix"==e.mode?{dropdown:{position:"text"}}:{}),s=this.settings=lt({},i,e);if(s.disabled=t.hasAttribute("disabled"),s.readonly=s.readonly||t.hasAttribute("readonly"),s.placeholder=ot(t.getAttribute("placeholder")||s.placeholder||""),s.required=t.hasAttribute("required"),this.generateClassSelectors(s.classNames),this.isIE&&(s.autoComplete=!1),["whitelist","blacklist"].forEach((e=>{var i=t.getAttribute("data-"+e);i&&(i=i.split(s.delimiters))instanceof Array&&(s[e]=i)})),"autoComplete"in e&&!rt(e.autoComplete)&&(s.autoComplete=bt.autoComplete,s.autoComplete.enabled=e.autoComplete),"mix"==s.mode&&(s.pattern=s.pattern||/@/,s.autoComplete.rightKey=!0,s.delimiters=e.delimiters||null,s.tagTextProp&&!s.dropdown.searchKeys.includes(s.tagTextProp)&&s.dropdown.searchKeys.push(s.tagTextProp)),t.pattern)try{s.pattern=new RegExp(t.pattern)}catch(t){}if(s.delimiters){s._delimiters=s.delimiters;try{s.delimiters=new RegExp(this.settings.delimiters,"g")}catch(t){}}s.disabled&&(s.userInput=!1),this.TEXTS={...Et,...s.texts||{}},"select"==s.mode&&(s.dropdown.includeSelectedTags=!0),("select"!=s.mode||e.dropdown?.enabled)&&s.userInput||(s.dropdown.enabled=0),s.dropdown.appendTarget=e.dropdown?.appendTarget||document.body,void 0===s.dropdown.includeSelectedTags&&(s.dropdown.includeSelectedTags=s.duplicates);let n=this.getPersistedData("whitelist");Array.isArray(n)&&(this.whitelist=Array.isArray(s.whitelist)?dt(s.whitelist,n):n)},getAttributes(t){var e,i=this.getCustomAttributes(t),s="";for(e in i)s+=" "+e+(void 0!==t[e]?`="${i[e]}"`:"");return s},getCustomAttributes(t){if(!rt(t))return"";var e,i={};for(e in t)"__"!=e.slice(0,2)&&"class"!=e&&t.hasOwnProperty(e)&&void 0!==t[e]&&(i[e]=ot(t[e]));return i},setStateSelection(){var t=window.getSelection(),e={anchorOffset:t.anchorOffset,anchorNode:t.anchorNode,range:t.getRangeAt&&t.rangeCount&&t.getRangeAt(0)};return this.state.selection=e,e},getCSSVars(){var t=getComputedStyle(this.DOM.scope,null);var e;this.CSSVars={tagHideTransition:(({value:t,unit:e})=>"s"==e?1e3*t:t)(function(t){if(!t)return{};var e=(t=t.trim().split(" ")[0]).split(/\d+/g).filter((t=>t)).pop().trim();return{value:+t.split(e).filter((t=>t))[0].trim(),unit:e}}((e="tag-hide-transition",t.getPropertyValue("--"+e))))}},build(t){var e=this.DOM,i=t.closest("label");this.settings.mixMode.integrated?(e.originalInput=null,e.scope=t,e.input=t):(e.originalInput=t,e.originalInput_tabIndex=t.tabIndex,e.scope=this.parseTemplate("wrapper",[t,this.settings]),e.input=e.scope.querySelector(this.settings.classNames.inputSelector),t.parentNode.insertBefore(e.scope,t),t.tabIndex=-1),i&&i.setAttribute("for","")},destroy(){this.events.unbindGlobal.call(this),this.DOM.scope.parentNode?.removeChild(this.DOM.scope),this.DOM.originalInput.tabIndex=this.DOM.originalInput_tabIndex,delete this.DOM.originalInput.__tagify,this.dropdown.hide(!0),this.removeAllCustomListeners(),clearTimeout(this.dropdownHide__bindEventsTimeout),clearInterval(this.listeners.main.originalInputValueObserverInterval)},loadOriginalValues(t){var e,i=this.settings;if(this.state.blockChangeEvent=!0,void 0===t){const e=this.getPersistedData("value");t=e&&!this.DOM.originalInput.value?e:i.mixMode.integrated?this.DOM.input.textContent:this.DOM.originalInput.value}if(this.removeAllTags(),t)if("mix"==i.mode)this.parseMixTags(t),(e=this.DOM.input.lastChild)&&"BR"==e.tagName||this.DOM.input.insertAdjacentHTML("beforeend","
");else{try{JSON.parse(t)instanceof Array&&(t=JSON.parse(t))}catch(t){}this.addTags(t,!0).forEach((t=>t&&t.classList.add(i.classNames.tagNoAnimation)))}else this.postUpdate();this.state.lastOriginalValueReported=i.mixMode.integrated?"":this.DOM.originalInput.value},cloneEvent(t){var e={};for(var i in t)"path"!=i&&(e[i]=t[i]);return e},loading(t){return this.state.isLoading=t,this.DOM.scope.classList[t?"add":"remove"](this.settings.classNames.scopeLoading),this},tagLoading(t,e){return t&&t.classList[e?"add":"remove"](this.settings.classNames.tagLoading),this},toggleClass(t,e){"string"==typeof t&&this.DOM.scope.classList.toggle(t,e)},toggleScopeValidation(t){var e=!0===t||void 0===t;!this.settings.required&&t&&t===this.TEXTS.empty&&(e=!0),this.toggleClass(this.settings.classNames.tagInvalid,!e),this.DOM.scope.title=e?"":t},toggleFocusClass(t){this.toggleClass(this.settings.classNames.focus,!!t)},setPlaceholder(t){["data","aria"].forEach((e=>this.DOM.input.setAttribute(`${e}-placeholder`,t)))},triggerChangeEvent:function(){if(!this.settings.mixMode.integrated){var t=this.DOM.originalInput,e=this.state.lastOriginalValueReported!==t.value,i=new CustomEvent("change",{bubbles:!0});e&&(this.state.lastOriginalValueReported=t.value,i.simulated=!0,t._valueTracker&&t._valueTracker.setValue(Math.random()),t.dispatchEvent(i),this.trigger("change",this.state.lastOriginalValueReported),t.value=this.state.lastOriginalValueReported)}},events:Mt,fixFirefoxLastTagNoCaret(){},setRangeAtStartEnd(t,e){if(e){t="number"==typeof t?t:!!t,e=e.lastChild||e;var i=document.getSelection();if(i.focusNode instanceof Element&&!this.DOM.input.contains(i.focusNode))return!0;try{i.rangeCount>=1&&["Start","End"].forEach((s=>i.getRangeAt(0)["set"+s](e,t||e.length)))}catch(t){console.warn(t)}}},insertAfterTag(t,e){if(e=e||this.settings.mixMode.insertAfterTag,t&&t.parentNode&&e)return e="string"==typeof e?document.createTextNode(e):e,t.parentNode.insertBefore(e,t.nextSibling),e},editTagChangeDetected(t){var e=t.__originalData;for(var i in e)if(!this.dataProps.includes(i)&&t[i]!=e[i])return!0;return!1},getTagTextNode(t){return t.querySelector(this.settings.classNames.tagTextSelector)},setTagTextNode(t,e){this.getTagTextNode(t).innerHTML=ot(e)},editTag(t,e){t=t||this.getLastTag(),e=e||{};var i=this.settings,s=this.getTagTextNode(t),n=this.getNodeIndex(t),a=vt(t),o=this.events.callbacks,r=!0,l="select"==i.mode;if(!l&&this.dropdown.hide(),s){if(!(a instanceof Object&&"editable"in a)||a.editable)return a=vt(t,{__originalData:lt({},a),__originalHTML:t.cloneNode(!0)}),vt(a.__originalHTML,a.__originalData),s.setAttribute("contenteditable",!0),t.classList.add(i.classNames.tagEditing),this.events.callbacks.onEditTagFocus.call(this,t),s.addEventListener("click",o.onEditTagClick.bind(this,t)),s.addEventListener("blur",o.onEditTagBlur.bind(this,this.getTagTextNode(t))),s.addEventListener("input",o.onEditTagInput.bind(this,s)),s.addEventListener("paste",o.onEditTagPaste.bind(this,s)),s.addEventListener("keydown",(e=>o.onEditTagkeydown.call(this,e,t))),s.addEventListener("compositionstart",o.onCompositionStart.bind(this)),s.addEventListener("compositionend",o.onCompositionEnd.bind(this)),e.skipValidation||(r=this.editTagToggleValidity(t)),s.originalIsValid=r,this.trigger("edit:start",{tag:t,index:n,data:a,isValid:r}),s.focus(),!l&&this.setRangeAtStartEnd(!1,s),0===i.dropdown.enabled&&!l&&this.dropdown.show(),this.state.hasFocus=!0,this}else tt.warn("Cannot find element in Tag template: .",i.classNames.tagTextSelector)},editTagToggleValidity(t,e){var i;if(e=e||vt(t))return(i=!("__isValid"in e)||!0===e.__isValid)||this.removeTagsFromValue(t),this.update(),t.classList.toggle(this.settings.classNames.tagNotAllowed,!i),e.__isValid=i,e.__isValid;tt.warn("tag has no data: ",t,e)},onEditTagDone(t,e){t=t||this.state.editing.scope,e=e||{};var i,s=this.settings,n={tag:t,index:this.getNodeIndex(t),previousData:vt(t),data:e};this.trigger("edit:beforeUpdate",n,{cloneData:!1}),this.state.editing=!1,delete e.__originalData,delete e.__originalHTML,t&&t.parentNode&&((void 0!==(i=e[s.tagTextProp])?(i+="",i.trim?.()):s.tagTextProp in e?void 0:e.value)?(t=this.replaceTag(t,e),this.editTagToggleValidity(t,e),s.a11y.focusableTags?t.focus():"select"!=s.mode&&wt(t)):this.removeTags(t)),this.trigger("edit:updated",n),s.dropdown.closeOnSelect&&this.dropdown.hide(),this.settings.keepInvalidTags&&this.reCheckInvalidTags()},replaceTag(t,e){e&&""!==e.value&&void 0!==e.value||(e=t.__tagifyTagData),e.__isValid&&1!=e.__isValid&<(e,this.getInvalidTagAttrs(e,e.__isValid));var i=this.createTagElem(e);return t.parentNode.replaceChild(i,t),this.updateValueByDOMTags(),i},updateValueByDOMTags(){this.value.length=0;var t=this.settings.classNames,e=[t.tagNotAllowed.split(" ")[0],t.tagHide];[].forEach.call(this.getTagElms(),(t=>{[...t.classList].some((t=>e.includes(t)))||this.value.push(vt(t))})),this.update(),this.dropdown.refilter()},injectAtCaret(t,e){if(e=e||this.state.selection?.range,"string"==typeof t&&(t=document.createTextNode(t)),!e&&t)return this.appendMixTags(t),this;let i=ft(t,e);return this.setRangeAtStartEnd(!1,i),this.updateValueByDOMTags(),this.update(),this},input:{set(t="",e=!0){var i=this.settings,s=i.dropdown.closeOnSelect;this.state.inputText=t,e&&(this.DOM.input.innerHTML=ot(""+t),t&&this.toggleClass(i.classNames.empty,!this.DOM.input.innerHTML)),!t&&s&&this.dropdown.hide.bind(this),this.input.autocomplete.suggest.call(this),this.input.validate.call(this)},raw(){return this.DOM.input.textContent},validate(){var t=!this.state.inputText||!0===this.validateTag({value:this.state.inputText});return this.DOM.input.classList.toggle(this.settings.classNames.inputInvalid,!t),t},normalize(t,e){var i=t||this.DOM.input,s=[];i.childNodes.forEach((t=>3==t.nodeType&&s.push(t.nodeValue))),s=s.join("\n");try{s=s.replace(/(?:\r\n|\r|\n)/g,this.settings.delimiters.source.charAt(0))}catch(t){}return s=s.replace(/\s/g," "),e?.trim?this.trim(s):s},autocomplete:{suggest(t){if(this.settings.autoComplete.enabled){"object"!=typeof(t=t||{value:""})&&(t={value:t});var e=this.dropdown.getMappedValue(t);if("number"!=typeof e){var i=this.state.inputText.toLowerCase(),s=e.substr(0,this.state.inputText.length).toLowerCase(),n=e.substring(this.state.inputText.length);e&&this.state.inputText&&s==i?(this.DOM.input.setAttribute("data-suggest",n),this.state.inputSuggestion=t):(this.DOM.input.removeAttribute("data-suggest"),delete this.state.inputSuggestion)}}},set(t){var e=this.DOM.input.getAttribute("data-suggest"),i=t||(e?this.state.inputText+e:null);return!!i&&("mix"==this.settings.mode?this.replaceTextWithNode(document.createTextNode(this.state.tag.prefix+i)):(this.input.set.call(this,i),this.setRangeAtStartEnd(!1,this.DOM.input)),this.input.autocomplete.suggest.call(this),this.dropdown.hide(),!0)}}},getTagIdx(t){return this.value.findIndex((e=>e.__tagId==(t||{}).__tagId))},getNodeIndex(t){var e=0;if(t)for(;t=t.previousElementSibling;)e++;return e},getTagElms(...t){var e="."+[...this.settings.classNames.tag.split(" "),...t].join(".");return[].slice.call(this.DOM.scope.querySelectorAll(e))},getLastTag(){var t=this.settings.classNames,e=this.DOM.scope.querySelectorAll(`${t.tagSelector}:not(.${t.tagHide}):not([readonly])`);return e[e.length-1]},isTagDuplicate(t,e,i){var s=0;for(let n of this.value){et(this.trim(""+t),n.value,e)&&i!=n.__tagId&&s++}return s},getTagIndexByValue(t){var e=[],i=this.settings.dropdown.caseSensitive;return this.getTagElms().forEach(((s,n)=>{s.__tagifyTagData&&et(this.trim(s.__tagifyTagData.value),t,i)&&e.push(n)})),e},getTagElmByValue(t){var e=this.getTagIndexByValue(t)[0];return this.getTagElms()[e]},flashTag(t){t&&(t.classList.add(this.settings.classNames.tagFlash),setTimeout((()=>{t.classList.remove(this.settings.classNames.tagFlash)}),100))},isTagBlacklisted(t){return t=this.trim(t.toLowerCase()),this.settings.blacklist.filter((e=>(""+e).toLowerCase()==t)).length},isTagWhitelisted(t){return!!this.getWhitelistItem(t)},getWhitelistItem(t,e,i){e=e||"value";var s,n=this.settings;return(i=i||n.whitelist).some((i=>{var a="object"==typeof i?i[e]||i.value:i;if(et(a,t,n.dropdown.caseSensitive,n.trim))return s="object"==typeof i?i:{value:i},!0})),s||"value"!=e||"value"==n.tagTextProp||(s=this.getWhitelistItem(t,n.tagTextProp,i)),s},validateTag(t){var e=this.settings,i="value"in t?"value":e.tagTextProp,s=this.trim(t[i]+"");return(t[i]+"").trim()?"mix"!=e.mode&&e.pattern&&e.pattern instanceof RegExp&&!e.pattern.test(s)?this.TEXTS.pattern:!e.duplicates&&this.isTagDuplicate(s,e.dropdown.caseSensitive,t.__tagId)?this.TEXTS.duplicate:this.isTagBlacklisted(s)||e.enforceWhitelist&&!this.isTagWhitelisted(s)?this.TEXTS.notAllowed:!e.validate||e.validate(t):this.TEXTS.empty},getInvalidTagAttrs(t,e){return{"aria-invalid":!0,class:`${t.class||""} ${this.settings.classNames.tagNotAllowed}`.trim(),title:e}},hasMaxTags(){return this.value.length>=this.settings.maxTags&&this.TEXTS.exceed},setReadonly(t,e){var i=this.settings;this.DOM.scope.contains(document.activeElement)&&document.activeElement.blur(),i[e||"readonly"]=t,this.DOM.scope[(t?"set":"remove")+"Attribute"](e||"readonly",!0),this.settings.userInput=!0,this.setContentEditable(!t)},setContentEditable(t){this.DOM.input.contentEditable=t,this.DOM.input.tabIndex=t?0:-1},setDisabled(t){this.setReadonly(t,"disabled")},normalizeTags(t){var{whitelist:e,delimiters:i,mode:s,tagTextProp:n}=this.settings,a=[],o=!!e&&e[0]instanceof Object,r=Array.isArray(t),l=r&&t[0].value,d=t=>(t+"").split(i).reduce(((t,e)=>{const i=this.trim(e);return i&&t.push({[n]:i,value:i}),t}),[]);if("number"==typeof t&&(t=t.toString()),"string"==typeof t){if(!t.trim())return[];t=d(t)}else r&&(t=t.reduce(((t,e)=>{if(rt(e)){var i=lt({},e);n in i||(n="value"),i[n]=this.trim(i[n]),(i[n]||0===i[n])&&t.push(i)}else null!=e&&""!==e&&void 0!==e&&t.push(...d(e));return t}),[]));return o&&!l&&(t.forEach((t=>{var e=a.map((t=>t.value)),i=this.dropdown.filterListItems.call(this,t[n],{exact:!0});this.settings.duplicates||(i=i.filter((t=>!e.includes(t.value))));var o=i.length>1?this.getWhitelistItem(t[n],n,i):i[0];o&&o instanceof Object?a.push(o):"mix"!=s&&(null==t.value&&(t.value=t[n]),a.push(t))})),a.length&&(t=a)),t},parseMixTags(t){var{mixTagsInterpolator:e,duplicates:i,transformTag:s,enforceWhitelist:n,maxTags:a,tagTextProp:o}=this.settings,r=[];t=t.split(e[0]).map(((t,l)=>{var d,h,c,g=t.split(e[1]),u=g[0],p=r.length==a;try{if(u==+u)throw Error;h=JSON.parse(u)}catch(t){h=this.normalizeTags(u)[0]||{value:u}}if(s.call(this,h),p||!(g.length>1)||n&&!this.isTagWhitelisted(h.value)||!i&&this.isTagDuplicate(h.value)){if(t)return l?e[0]+t:t}else h[d=h[o]?o:"value"]=this.trim(h[d]),c=this.createTagElem(h),r.push(h),c.classList.add(this.settings.classNames.tagNoAnimation),g[0]=c.outerHTML,this.value.push(h);return g.join("")})).join(""),this.DOM.input.innerHTML=t,this.DOM.input.appendChild(document.createTextNode("")),this.DOM.input.normalize();var l=this.getTagElms();return l.forEach(((t,e)=>vt(t,r[e]))),this.update({withoutChangeEvent:!0}),Tt(l,this.state.hasFocus),t},replaceTextWithNode(t,e){if(this.state.tag||e){e=e||this.state.tag.prefix+this.state.tag.value;var i,s,n=this.state.selection||window.getSelection(),a=n.anchorNode,o=this.state.tag.delimiters?this.state.tag.delimiters.length:0;return a.splitText(n.anchorOffset-o),-1==(i=a.nodeValue.lastIndexOf(e))?!0:(s=a.splitText(i),t&&a.parentNode.replaceChild(t,s),!0)}},prepareNewTagNode(t,e){e=e||{};var i=this.settings,s=[],n={},a=Object.assign({},t,{value:t.value+""});if(t=Object.assign({},a),i.transformTag.call(this,t),t.__isValid=this.hasMaxTags()||this.validateTag(t),!0!==t.__isValid){if(e.skipInvalid)return;if(lt(n,this.getInvalidTagAttrs(t,t.__isValid),{__preInvalidData:a}),t.__isValid==this.TEXTS.duplicate&&this.flashTag(this.getTagElmByValue(t.value)),!i.createInvalidTags)return void s.push(t.value)}return"readonly"in t&&(t.readonly?n["aria-readonly"]=!0:delete t.readonly),{tagElm:this.createTagElem(t,n),tagData:t,aggregatedInvalidInput:s}},postProcessNewTagNode(t,e){var i=this.settings,s=e.__isValid;s&&!0===s?this.value.push(e):(this.trigger("invalid",{data:e,index:this.value.length,tag:t,message:s}),i.keepInvalidTags||setTimeout((()=>this.removeTags(t,!0)),1e3)),this.dropdown.position()},selectTag(t,e){if(!this.settings.enforceWhitelist||this.isTagWhitelisted(e.value)){this.state.actions.selectOption&&setTimeout((()=>this.setRangeAtStartEnd(!1,this.DOM.input)));var i=this.getLastTag();return i?this.replaceTag(i,e):this.appendTag(t),this.value[0]=e,this.update(),this.trigger("add",{tag:t,data:e}),[t]}},addEmptyTag(t){var e=lt({value:""},t||{}),i=this.createTagElem(e);vt(i,e),this.appendTag(i),this.editTag(i,{skipValidation:!0}),this.toggleFocusClass(!0)},addTags(t,e,i){var s=[],n=this.settings,a=[],o=document.createDocumentFragment(),r=[];if(!t||0==t.length)return s;switch(t=this.normalizeTags(t),n.mode){case"mix":return this.addMixTags(t);case"select":e=!1,this.removeAllTags()}return this.DOM.input.removeAttribute("style"),t.forEach((t=>{const e=this.prepareNewTagNode(t,{skipInvalid:i||n.skipInvalid});if(!e)return;const l=e.tagElm;if(t=e.tagData,a=e.aggregatedInvalidInput,s.push(l),"select"==n.mode)return this.selectTag(l,t);o.appendChild(l),this.postProcessNewTagNode(l,t),r.push({tagElm:l,tagData:t})})),this.appendTag(o),r.forEach((({tagElm:t,tagData:e})=>this.trigger("add",{tag:t,index:this.getTagIdx(e),data:e}))),this.update(),t.length&&e&&(this.input.set.call(this,n.createInvalidTags?"":a.join(n._delimiters)),this.setRangeAtStartEnd(!1,this.DOM.input)),this.dropdown.refilter(),s},addMixTags(t){if((t=this.normalizeTags(t))[0].prefix||this.state.tag)return this.prefixedTextToTag(t[0]);var e=document.createDocumentFragment();return t.forEach((t=>{const i=this.prepareNewTagNode(t);e.appendChild(i.tagElm),this.insertAfterTag(i.tagElm),this.postProcessNewTagNode(i.tagElm,i.tagData)})),this.appendMixTags(e),e.children},appendMixTags(t){var e=!!this.state.selection;e?this.injectAtCaret(t):(this.DOM.input.focus(),(e=this.setStateSelection()).range.setStart(this.DOM.input,e.range.endOffset),e.range.setEnd(this.DOM.input,e.range.endOffset),this.DOM.input.appendChild(t),this.updateValueByDOMTags(),this.update())},prefixedTextToTag(t){var e,i,s=this.settings,n=this.state.tag?.delimiters;if(t.prefix=t.prefix||this.state.tag?this.state.tag.prefix:(s.pattern.source||s.pattern)[0],i=this.prepareNewTagNode(t),e=i.tagElm,this.replaceTextWithNode(e)||this.DOM.input.appendChild(e),setTimeout((()=>e.classList.add(this.settings.classNames.tagNoAnimation)),300),this.update(),!n){var a=this.insertAfterTag(e)||e;setTimeout(wt,0,a)}return this.state.tag=null,this.postProcessNewTagNode(e,i.tagData),e},appendTag(t){var e=this.DOM,i=e.input;e.scope.insertBefore(t,i)},createTagElem(t,e){t.__tagId=gt();var i,s=lt({},t,{value:ot(t.value+""),...e});return function(t){for(var e,i=document.createNodeIterator(t,NodeFilter.SHOW_TEXT,null,!1);e=i.nextNode();)e.textContent.trim()||e.parentNode.removeChild(e)}(i=this.parseTemplate("tag",[s,this])),vt(i,t),i},reCheckInvalidTags(){var t=this.settings;this.getTagElms(t.classNames.tagNotAllowed).forEach(((e,i)=>{var s=vt(e),n=this.hasMaxTags(),a=this.validateTag(s),o=!0===a&&!n;if("select"==t.mode&&this.toggleScopeValidation(a),o)return s=s.__preInvalidData?s.__preInvalidData:{value:s.value},this.replaceTag(e,s);e.title=n||a}))},removeTags(t,e,i){var s,n=this.settings;if(t=t&&t instanceof HTMLElement?[t]:t instanceof Array?t:t?[t]:[this.getLastTag()].filter((t=>t)),s=t.reduce(((t,e)=>{e&&"string"==typeof e&&(e=this.getTagElmByValue(e));var i=vt(e);return e&&i&&!i.readonly&&t.push({node:e,idx:this.getTagIdx(i),data:vt(e,{__removed:!0})}),t}),[]),i="number"==typeof i?i:this.CSSVars.tagHideTransition,"select"==n.mode&&(i=0,this.input.set.call(this)),1==s.length&&"select"!=n.mode&&s[0].node.classList.contains(n.classNames.tagNotAllowed)&&(e=!0),s.length)return n.hooks.beforeRemoveTag(s,{tagify:this}).then((()=>{function t(t){t.node.parentNode&&(t.node.parentNode.removeChild(t.node),e?n.keepInvalidTags&&this.trigger("remove",{tag:t.node,index:t.idx}):(this.trigger("remove",{tag:t.node,index:t.idx,data:t.data}),this.dropdown.refilter(),this.dropdown.position(),this.DOM.input.normalize(),n.keepInvalidTags&&this.reCheckInvalidTags()))}i&&i>10&&1==s.length?function(e){e.node.style.width=parseFloat(window.getComputedStyle(e.node).width)+"px",document.body.clientTop,e.node.classList.add(n.classNames.tagHide),setTimeout(t.bind(this),i,e)}.call(this,s[0]):s.forEach(t.bind(this)),e||(this.removeTagsFromValue(s.map((t=>t.node))),this.update(),"select"==n.mode&&n.userInput&&this.setContentEditable(!0))})).catch((t=>{}))},removeTagsFromDOM(){this.getTagElms().forEach((t=>t.remove()))},removeTagsFromValue(t){(t=Array.isArray(t)?t:[t]).forEach((t=>{var e=vt(t),i=this.getTagIdx(e);i>-1&&this.value.splice(i,1)}))},removeAllTags(t){t=t||{},this.value=[],"mix"==this.settings.mode?this.DOM.input.innerHTML="":this.removeTagsFromDOM(),this.dropdown.refilter(),this.dropdown.position(),this.state.dropdown.visible&&setTimeout((()=>{this.DOM.input.focus()})),"select"==this.settings.mode&&(this.input.set.call(this),this.settings.userInput&&this.setContentEditable(!0)),this.update(t)},postUpdate(){this.state.blockChangeEvent=!1;var t=this.settings,e=t.classNames,i="mix"==t.mode?t.mixMode.integrated?this.DOM.input.textContent:this.DOM.originalInput.value.trim():this.value.length+this.input.raw.call(this).length;this.toggleClass(e.hasMaxTags,this.value.length>=t.maxTags),this.toggleClass(e.hasNoTags,!this.value.length),this.toggleClass(e.empty,!i),"select"==t.mode&&this.toggleScopeValidation(this.value?.[0]?.__isValid)},setOriginalInputValue(t){var e=this.DOM.originalInput;this.settings.mixMode.integrated||(e.value=t,e.tagifyValue=e.value,this.setPersistedData(t,"value"))},update(t){clearTimeout(this.debouncedUpdateTimeout),this.debouncedUpdateTimeout=setTimeout(function(){var e=this.getInputValue();this.setOriginalInputValue(e),this.settings.onChangeAfterBlur&&(t||{}).withoutChangeEvent||this.state.blockChangeEvent||this.triggerChangeEvent();this.postUpdate()}.bind(this),100),this.events.bindOriginaInputListener.call(this,100)},getInputValue(){var t=this.getCleanValue();return"mix"==this.settings.mode?this.getMixedTagsAsString(t):t.length?this.settings.originalInputValueFormat?this.settings.originalInputValueFormat(t):JSON.stringify(t):""},getCleanValue(t){return it(t||this.value,this.dataProps)},getMixedTagsAsString(){var t="",e=this,i=this.settings,s=i.originalInputValueFormat||JSON.stringify,n=i.mixTagsInterpolator;return function i(a){a.childNodes.forEach((a=>{if(1==a.nodeType){const o=vt(a);if("BR"==a.tagName&&(t+="\r\n"),o&&ut.call(e,a)){if(o.__removed)return;t+=n[0]+s(st(o,e.dataProps))+n[1]}else a.getAttribute("style")||["B","I","U"].includes(a.tagName)?t+=a.textContent:"DIV"!=a.tagName&&"P"!=a.tagName||(t+="\r\n",i(a))}else t+=a.textContent}))}(this.DOM.input),t}},Ot.prototype.removeTag=Ot.prototype.removeTags;class Ct{instances=[];init(t,e,i){if(void 0!==this.instances[t])throw new Error(`Tag with input-id '${t}' has already been initialized.`);const s=document.querySelector(`#${t} .c-input__field .c-field-tag__wrapper input`)?.id,n=new Ot(document.getElementById(s),{whitelist:e.options,enforceWhitelist:!e.userInput,duplicates:e.allowDuplicates,maxTags:e.maxItems,delimiters:null,templates:{tag:t=>`\n \n
\n ${t.display}\n
\n
`,dropdownItem:t=>`
\n ${t.display}\n
`},originalInputValueFormat:t=>t.map((t=>t.value)),dropdown:{enabled:e.dropdownSuggestionsStartAfter,maxItems:e.dropdownMaxItems,closeOnSelect:e.dropdownCloseOnSelect,highlightFirst:e.highlight},transformTag:t=>{t.display||(t.display=t.value,t.value=encodeURIComponent(t.value)),t.display=t.display.replace(//g,">")}});n.addTags(i),this.instances[t]=n}get(t){return this.instances[t]??null}}e.UI=e.UI||{},e.UI.Input=e.UI.Input||{},(Nt=e.UI.Input).textarea=new o,Nt.markdown=new w,Nt.treeSelect=new G(new Y(t),e.UI.menu.drilldown,{txt:t=>e.Language.txt(t)},i),Nt.tagInput=new Ct}($,il,document); diff --git a/components/ILIAS/UI/resources/js/Input/Field/rollup.config.js b/components/ILIAS/UI/resources/js/Input/Field/rollup.config.js index c9db74217bb2..32827a564b33 100755 --- a/components/ILIAS/UI/resources/js/Input/Field/rollup.config.js +++ b/components/ILIAS/UI/resources/js/Input/Field/rollup.config.js @@ -23,6 +23,7 @@ export default { 'jquery', 'ilias', 'document', + 'Tagify', ], output: { // file: '../../../../../../../public/assets/js/input.factory.min.js', diff --git a/components/ILIAS/UI/resources/js/Input/Field/src/Tag/tag.factory.js b/components/ILIAS/UI/resources/js/Input/Field/src/Tag/tag.factory.js new file mode 100644 index 000000000000..2ed44b57ab39 --- /dev/null +++ b/components/ILIAS/UI/resources/js/Input/Field/src/Tag/tag.factory.js @@ -0,0 +1,91 @@ +/** + * This file is part of ILIAS, a powerful learning management system + * published by ILIAS open source e-Learning e.V. + * + * ILIAS is licensed with the GPL-3.0, + * see https://www.gnu.org/licenses/gpl-3.0.en.html + * You should have received a copy of said license along with the + * source code, too. + * + * If this is not the case or you just want to try ILIAS, you'll find + * us at: + * https://www.ilias.de + * https://github.com/ILIAS-eLearning + */ + +import Tagify from '../../../../../../../../../node_modules/@yaireo/tagify/src/tagify.js'; + +export default class TagFactory { + /** + * @type {Array} + */ + instances = []; + + /** + * @param {string} componentId + * @param {array} config + * @param {array} value + * @return {void} + * @throws {Error} if the input was already initialized. + */ + init(componentId, config, value) { + if (undefined !== this.instances[componentId]) { + throw new Error(`Tag with input-id '${componentId}' has already been initialized.`); + } + const inputId = document.querySelector(`#${componentId} .c-input__field .c-field-tag__wrapper input`)?.id; + const input = document.getElementById(inputId); + const settings = { + whitelist: config.options, + enforceWhitelist: !config.userInput, + duplicates: config.allowDuplicates, + maxTags: config.maxItems, + delimiters: null, + templates: { + tag: (tagData) => ` + +
+ ${tagData.display} +
+
`, + dropdownItem: (tagData) => `
+ ${tagData.display} +
`, + }, + originalInputValueFormat: (valuesArr) => valuesArr.map((item) => item.value), + dropdown: { + enabled: config.dropdownSuggestionsStartAfter, + maxItems: config.dropdownMaxItems, + closeOnSelect: config.dropdownCloseOnSelect, + highlightFirst: config.highlight, + }, + transformTag: (tagData) => { + if (!tagData.display) { + tagData.display = tagData.value; + tagData.value = encodeURIComponent(tagData.value); + } + tagData.display = tagData.display + .replace(//g, '>'); + }, + }; + + const tagify = new Tagify(input, settings); + tagify.addTags(value); + this.instances[componentId] = tagify; + } + + /** + * @param {string} componentId + * @return {Tagify|null} + */ + get(componentId) { + return this.instances[componentId] ?? null; + } +} diff --git a/components/ILIAS/UI/resources/js/Input/Field/src/input.factory.js b/components/ILIAS/UI/resources/js/Input/Field/src/input.factory.js index 497552fb8985..193cd8d3c193 100755 --- a/components/ILIAS/UI/resources/js/Input/Field/src/input.factory.js +++ b/components/ILIAS/UI/resources/js/Input/Field/src/input.factory.js @@ -31,6 +31,7 @@ import TextareaFactory from './Textarea/textarea.factory.js'; import MarkdownFactory from './Markdown/markdown.factory.js'; import TreeSelectFactory from './TreeSelect/TreeSelectFactory.js'; import JQueryEventListener from '../../../Core/src/JQueryEventListener.js'; +import TagFactory from './Tag/tag.factory.js'; il.UI = il.UI || {}; il.UI.Input = il.UI.Input || {}; @@ -42,7 +43,8 @@ il.UI.Input = il.UI.Input || {}; new JQueryEventListener($), il.UI.menu.drilldown, // workaround for language being initialised after UI - {txt: (s) => il.Language.txt(s)}, + { txt: (s) => il.Language.txt(s) }, document, ); + Input.tagInput = new TagFactory(); }(il.UI.Input)); diff --git a/components/ILIAS/UI/resources/js/Input/Field/tagInput.js b/components/ILIAS/UI/resources/js/Input/Field/tagInput.js deleted file mode 100755 index e5d76e140ab8..000000000000 --- a/components/ILIAS/UI/resources/js/Input/Field/tagInput.js +++ /dev/null @@ -1,96 +0,0 @@ -/** - * This file is part of ILIAS, a powerful learning management system - * published by ILIAS open source e-Learning e.V. - * - * ILIAS is licensed with the GPL-3.0, - * see https://www.gnu.org/licenses/gpl-3.0.en.html - * You should have received a copy of said license along with the - * source code, too. - * - * If this is not the case or you just want to try ILIAS, you'll find - * us at: - * https://www.ilias.de - * https://github.com/ILIAS-eLearning - */ - -/** - * Wraps the TagsInput - * - * @author Fabian Schmid - * @author Nils Haagen - */ -var il = il || {}; -il.UI = il.UI || {}; -il.UI.Input = il.UI.Input || {}; -(function ($) { - il.UI.Input.tagInput = (function ($) { - const instances = []; - const init = function (raw_id, config, value) { - let _CONFIG = {}; - const _getSettings = function () { - return { - whitelist: _CONFIG.options, - enforceWhitelist: !_CONFIG.userInput, - duplicates: _CONFIG.allowDuplicates, - maxTags: _CONFIG.maxItems, - originalInputValueFormat: (valuesArr) => valuesArr.map((item) => item.value), - dropdown: { - enabled: _CONFIG.dropdownSuggestionsStartAfter, - maxItems: _CONFIG.dropdownMaxItems, - closeOnSelect: _CONFIG.dropdownCloseOnSelect, - highlightFirst: _CONFIG.highlight, - }, - transformTag(tagData) { - if (!tagData.display) { - tagData.display = tagData.value; - tagData.value = encodeURI(tagData.value); - } - tagData.display = tagData.display - .replace(//g, '>'); - }, - }; - }; - - // Initialize ID and Configuration - _CONFIG = $.extend(_CONFIG, config); - _CONFIG.id = document.querySelector(`#${raw_id} .c-input__field .c-field-tag__wrapper input`)?.id; - - const settings = _getSettings(); - settings.delimiters = null; - settings.templates = {}; - settings.templates.tag = function (tagData) { - return ` - -
- ${tagData.display} -
-
`; - }; - settings.templates.dropdownItem = function (tagData) { - return `
- ${tagData.display} -
`; - }; - - const input = document.getElementById(_CONFIG.id); - const tagify = new Tagify(input, settings); - - tagify.addTags(value); - - instances[raw_id] = tagify; - }; - - const getTagifyInstance = function (raw_id) { - return instances[raw_id]; - }; - - return { - init, - getTagifyInstance, - }; - }($)); -}($, il.UI.Input)); diff --git a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Renderer.php b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Renderer.php index 6db5a8b751e1..41fd9a064414 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Renderer.php +++ b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Renderer.php @@ -399,7 +399,7 @@ protected function renderTagField(F\Tag $component, RendererInterface $default_r if ($value) { $value = array_map( function ($v) { - return ['value' => urlencode($v), 'display' => $v]; + return ['value' => rawurlencode($v), 'display' => $v]; }, $value ); @@ -847,9 +847,7 @@ protected function renderHiddenField(F\Hidden $input): string public function registerResources(ResourceRegistry $registry): void { parent::registerResources($registry); - $registry->register('assets/js/tagify.js'); $registry->register('assets/css/tagify.css'); - $registry->register('assets/js/tagInput.js'); $registry->register('assets/js/dropzone.min.js'); $registry->register('assets/js/dropzone.js'); diff --git a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Tag.php b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Tag.php index 4131aa5b3e03..edcc121134a7 100755 --- a/components/ILIAS/UI/src/Implementation/Component/Input/Field/Tag.php +++ b/components/ILIAS/UI/src/Implementation/Component/Input/Field/Tag.php @@ -75,7 +75,7 @@ protected function addAdditionalTransformations(): void if (count($v) == 1 && $v[0] === '') { return []; } - $array = array_map("urldecode", $v); + $array = array_map("rawurldecode", $v); return array_map('strip_tags', $array); })); } @@ -84,7 +84,7 @@ public function getConfiguration(): stdClass { $options = array_map( fn($tag) => [ - 'value' => urlencode(trim($tag)), + 'value' => rawurlencode(trim($tag)), 'display' => $tag, 'searchBy' => $tag ], diff --git a/components/ILIAS/UI/tests/Component/Input/Field/TagInputTest.php b/components/ILIAS/UI/tests/Component/Input/Field/TagInputTest.php index 9d04a9bf9cbe..a2fdefe55f1b 100755 --- a/components/ILIAS/UI/tests/Component/Input/Field/TagInputTest.php +++ b/components/ILIAS/UI/tests/Component/Input/Field/TagInputTest.php @@ -231,4 +231,38 @@ public function testMaxTaglengthTagsNotOk(): void ) ); } + + public static function getUITagSpecialCharValues(): array + { + return [ + ['1', '2', '3'], + ['++1#*', '[-2]', '{?3}'], + ['some\'thing "else"', '&/\\'], + ['fünf, sechs', 'sieben, acht'], + ]; + } + + /** @dataProvider getUITagSpecialCharValues */ + public function testUITagInputSpecialChars(string ...$tags): void + { + $f = $this->getFieldFactory(); + $name = "name_0"; + $tag = $f->tag('', $tags)->withNameFrom($this->name_source); + + $encoded_tags = array_map('rawurlencode', $tags); + + $this->assertEquals( + $encoded_tags, + array_map( + fn($o) => $o['value'], + $tag->getConfiguration()->options + ) + ); + + $raw_value = implode(',', $encoded_tags); + $tag = $tag->withInput(new DefInputData([$name => $raw_value])); + $content = $tag->getContent(); + $this->assertTrue($content->isOk()); + $this->assertEquals($tags, $content->value()); + } }