From c761b288a89128499770677f641ed5da23b77014 Mon Sep 17 00:00:00 2001 From: Jaejun Yu Date: Mon, 17 May 2021 12:06:28 +0800 Subject: [PATCH] upgrade tagify --- css/tagify.css | 446 +--------- lib/tagify.js | 2128 +----------------------------------------------- manifest.json | 2 +- 3 files changed, 3 insertions(+), 2573 deletions(-) diff --git a/css/tagify.css b/css/tagify.css index e0961db..31afa05 100644 --- a/css/tagify.css +++ b/css/tagify.css @@ -1,445 +1 @@ -:root{ - --tagify-dd-color-primary:rgb(53,149,246); - --tagify-dd-bg-color:white -} -.tagify{ - --tags-border-color:#DDD; - --tag-bg:#E5E5E5; - --tag-hover:#D3E2E2; - --tag-text-color:black; - --tag-text-color--edit:black; - --tag-pad:0.3em 0.5em; - --tag-inset-shadow-size:1.1em; - --tag-invalid-color:#D39494; - --tag-invalid-bg:rgba(211, 148, 148, 0.5); - --tag-remove-bg:rgba(211, 148, 148, 0.3); - --tag-remove-btn-bg:none; - --tag-remove-btn-bg--hover:#c77777; - --tag--min-width:1ch; - --tag--max-width:auto; - --tag-hide-transition:.3s; - --loader-size:.8em; - display:flex; - align-items:flex-start; - flex-wrap:wrap; - border:1px solid #ddd; - border:1px solid var(--tags-border-color); - padding:0; - line-height:1.1; - cursor:text; - outline:0; - position:relative; - transition:.1s -} -@keyframes tags--bump{ - 30%{ - transform:scale(1.2) - } -} -@keyframes rotateLoader{ - to{ - transform:rotate(1turn) - } -} -.tagify:hover{ - border-color:#ccc -} -.tagify.tagify--focus{ - transition:0s; - border-color:#3595f6 -} -.tagify[readonly]{ - cursor:default -} -.tagify[readonly]>.tagify__input{ - visibility:hidden; - width:0; - margin:5px 0 -} -.tagify[readonly] .tagify__tag__removeBtn{ - display:none -} -.tagify[readonly] .tagify__tag>div{ - padding:.3em .5em; - padding:var(--tag-pad) -} -.tagify[readonly] .tagify__tag>div::before{ - background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px; - box-shadow:none; - filter:brightness(.95) -} -.tagify--loading .tagify__input::before{ - content:none -} -.tagify--loading .tagify__input::after{ - content:''; - vertical-align:middle; - margin:-2px 0 -2px .5em; - opacity:1; - width:.7em; - height:.7em; - width:var(--loader-size); - height:var(--loader-size); - border:3px solid; - border-color:#eee #bbb #888 transparent; - border-radius:50%; - animation:rotateLoader .4s infinite linear -} -.tagify--loading .tagify__input:empty::after{ - margin-left:0 -} -.tagify+input,.tagify+textarea{ - display:none!important -} -.tagify__tag{ - display:inline-flex; - align-items:center; - margin:5px 0 5px 5px; - position:relative; - z-index:1; - outline:0; - cursor:default; - transition:.13s ease-out -} -.tagify__tag>div{ - vertical-align:top; - box-sizing:border-box; - max-width:100%; - padding:.3em .5em; - padding:var(--tag-pad); - color:#000; - color:var(--tag-text-color); - line-height:inherit; - border-radius:3px; - -webkit-user-select:none; - user-select:none; - transition:.13s ease-out -} -.tagify__tag>div>*{ - white-space:nowrap; - overflow:hidden; - text-overflow:ellipsis; - display:inline-block; - vertical-align:top; - min-width:var(--tag--min-width); - max-width:var(--tag--max-width); - transition:.8s ease,.1s color -} -.tagify__tag>div>[contenteditable]{ - outline:0; - -webkit-user-select:text; - user-select:text; - cursor:text; - margin:-2px; - padding:2px; - max-width:350px -} -.tagify__tag>div::before{ - content:''; - position:absolute; - border-radius:inherit; - left:0; - top:0; - right:0; - bottom:0; - z-index:-1; - pointer-events:none; - transition:120ms ease; - animation:tags--bump .3s ease-out 1; - box-shadow:0 0 0 1.1em #e5e5e5 inset; - box-shadow:0 0 0 calc(var(--tag-inset-shadow-size)) var(--tag-bg) inset -} -.tagify__tag:hover:not([readonly]) div::before{ - top:-2px; - right:-2px; - bottom:-2px; - left:-2px; - box-shadow:0 0 0 1.1em #d3e2e2 inset; - box-shadow:0 0 0 var(--tag-inset-shadow-size) var(--tag-hover) inset -} -.tagify__tag.tagify--noAnim>div::before{ - animation:none -} -.tagify__tag.tagify--hide{ - width:0!important; - padding-left:0; - padding-right:0; - margin-left:0; - margin-right:0; - opacity:0; - transform:scale(0); - transition:.3s; - transition:var(--tag-hide-transition); - pointer-events:none -} -.tagify__tag.tagify--mark div::before{ - animation:none -} -.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div>span{ - opacity:.5 -} -.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div::before{ - box-shadow:0 0 0 1.1em rgba(211,148,148,.5) inset!important; - box-shadow:0 0 0 var(--tag-inset-shadow-size) var(--tag-invalid-bg) inset!important; - transition:.2s -} -.tagify__tag[readonly] .tagify__tag__removeBtn{ - display:none -} -.tagify__tag[readonly]>div::before{ - background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px; - box-shadow:none; - filter:brightness(.95) -} -.tagify__tag--editable>div{ - color:#000; - color:var(--tag-text-color--edit) -} -.tagify__tag--editable>div::before{ - box-shadow:0 0 0 2px #d3e2e2 inset!important; - box-shadow:0 0 0 2px var(--tag-hover) inset!important -} -.tagify__tag--editable.tagify--invalid>div::before{ - box-shadow:0 0 0 2px #d39494 inset!important; - box-shadow:0 0 0 2px var(--tag-invalid-color) inset!important -} -.tagify__tag__removeBtn{ - order:5; - display:inline-flex; - align-items:center; - justify-content:center; - border-radius:50px; - cursor:pointer; - font:14px Serif; - background:0 0; - background:var(--tag-remove-btn-bg); - color:#000; - color:var(--tag-text-color); - width:14px; - height:14px; - margin-right:4.66667px; - margin-left:-4.66667px; - transition:.2s ease-out -} -.tagify__tag__removeBtn::after{ - content:"\00D7" -} -.tagify__tag__removeBtn:hover{ - color:#fff; - background:#c77777; - background:var(--tag-remove-btn-bg--hover) -} -.tagify__tag__removeBtn:hover+div>span{ - opacity:.5 -} -.tagify__tag__removeBtn:hover+div::before{ - box-shadow:0 0 0 1.1em rgba(211,148,148,.3) inset!important; - box-shadow:0 0 0 var(--tag-inset-shadow-size) var(--tag-remove-bg) inset!important; - transition:.2s -} -.tagify:not(.tagify--mix) .tagify__input br{ - display:none -} -.tagify:not(.tagify--mix) .tagify__input *{ - display:inline; - white-space:nowrap -} -.tagify__input{ - display:block; - min-width:110px; - margin:5px; - padding:.3em .5em; - padding:var(--tag-pad,.3em .5em); - line-height:inherit; - position:relative; - white-space:pre-line -} -.tagify__input::before{ - display:inline-block; - width:0 -} -.tagify__input:empty{ - display:flex -} -.tagify__input:empty::before{ - transition:.2s ease-out; - opacity:.5; - transform:none; - width:auto -} -.tagify__input:focus{ - outline:0 -} -.tagify__input:focus::before{ - transition:.2s ease-out; - opacity:0; - transform:translatex(6px) -} -@supports (-moz-appearance:none){ - .tagify__input:focus::before{ - display:none - } -} -.tagify__input:focus:empty::before{ - transition:.2s ease-out; - opacity:.3; - transform:none -} -@supports (-moz-appearance:none){ - .tagify__input:focus:empty::before{ - display:inline-block - } -} -.tagify__input::before{ - content:attr(data-placeholder); - line-height:1.8; - position:absolute; - top:0; - z-index:1; - color:#000; - white-space:nowrap; - pointer-events:none; - opacity:0 -} -.tagify--mix .tagify__input::before{ - position:static; - line-height:inherit -} -@supports (-moz-appearance:none){ - .tagify__input::before{ - line-height:inherit; - position:relative - } -} -.tagify__input::after{ - content:attr(data-suggest); - display:inline-block; - white-space:pre; - color:#000; - opacity:.3; - pointer-events:none; - max-width:100px -} -.tagify__input .tagify__tag{ - margin:0 -} -.tagify__input .tagify__tag>div{ - padding-top:0; - padding-bottom:0 -} -.tagify--mix{ - line-height:1.7 -} -.tagify--mix .tagify__input{ - padding:5px; - margin:0; - width:100%; - height:100%; - line-height:inherit -} -.tagify--mix .tagify__input::after{ - content:none -} -.tagify--select::after{ - content:'>'; - opacity:.5; - position:absolute; - top:50%; - right:0; - bottom:0; - font:16px monospace; - line-height:8px; - height:8px; - pointer-events:none; - transform:translate(-150%,-50%) scaleX(1.2) rotate(90deg); - transition:.2s ease-in-out -} -.tagify--select[aria-expanded=true]::after{ - transform:translate(-150%,-50%) rotate(270deg) scaleY(1.2) -} -.tagify--select .tagify__tag{ - position:absolute; - top:0; - right:1.8em; - bottom:0 -} -.tagify--select .tagify__tag div{ - display:none -} -.tagify--select .tagify__input{ - width:100% -} -.tagify--invalid{ - --tags-border-color:#D39494 -} -.tagify__dropdown{ - position:absolute; - z-index:9999; - transform:translateY(1px); - overflow:hidden -} -.tagify__dropdown[placement=top]{ - margin-top:0; - transform:translateY(-2px) -} -.tagify__dropdown[placement=top] .tagify__dropdown__wrapper{ - border-top-width:1px; - border-bottom-width:0 -} -.tagify__dropdown--text{ - box-shadow:0 0 0 3px rgba(var(--tagify-dd-color-primary),.1); - font-size:.9em -} -.tagify__dropdown--text .tagify__dropdown__wrapper{ - border-width:1px -} -.tagify__dropdown__wrapper{ - max-height:300px; - overflow:hidden; - background:#fff; - background:var(--tagify-dd-bg-color); - border:1px solid #3595f6; - border-color:var(--tagify-dd-color-primary); - border-top-width:0; - box-shadow:0 2px 4px -2px rgba(0,0,0,.2); - transition:.25s cubic-bezier(0,1,.5,1) -} -.tagify__dropdown__wrapper:hover{ - overflow:auto -} -.tagify__dropdown--initial .tagify__dropdown__wrapper{ - max-height:20px; - transform:translateY(-1em) -} -.tagify__dropdown--initial[placement=top] .tagify__dropdown__wrapper{ - transform:translateY(2em) -} -.tagify__dropdown__item{ - box-sizing:inherit; - padding:.3em .5em; - margin:1px; - cursor:pointer; - border-radius:2px; - position:relative; - outline:0 -} -.tagify__dropdown__item--active{ - /* Ricky */ - /* background: #f5f8fa; */ - /* background:#3595f6; */ - background: lightgray; - /* background:var(--tagify-dd-color-primary); */ - /* color:#fff; */ - /* font-weight: bold; */ -} -.tagify__dropdown__item:active{ - filter:brightness(105%) -} -.tagify__dropdown__createTagBtn{ - width:100%; - background:#3595f6; - background:var(--tagify-dd-color-primary); - color:#fff; - color:var(--tagify-dd-bg-color); - border:none -} +:root{--tagify-dd-color-primary:rgb(53,149,246);--tagify-dd-bg-color:white}.tagify{--tags-border-color:#DDD;--tags-hover-border-color:#CCC;--tags-focus-border-color:#3595f6;--tag-bg:#E5E5E5;--tag-hover:#D3E2E2;--tag-text-color:black;--tag-text-color--edit:black;--tag-pad:0.3em 0.5em;--tag-inset-shadow-size:1.1em;--tag-invalid-color:#D39494;--tag-invalid-bg:rgba(211, 148, 148, 0.5);--tag-remove-bg:rgba(211, 148, 148, 0.3);--tag-remove-btn-color:black;--tag-remove-btn-bg:none;--tag-remove-btn-bg--hover:#c77777;--input-color:inherit;--tag--min-width:1ch;--tag--max-width:auto;--tag-hide-transition:0.3s;--placeholder-color:rgba(0, 0, 0, 0.4);--placeholder-color-focus:rgba(0, 0, 0, 0.25);--loader-size:.8em;display:flex;align-items:flex-start;flex-wrap:wrap;border:1px solid #ddd;border:1px solid var(--tags-border-color);padding:0;line-height:normal;cursor:text;outline:0;position:relative;box-sizing:border-box;transition:.1s}@keyframes tags--bump{30%{transform:scale(1.2)}}@keyframes rotateLoader{to{transform:rotate(1turn)}}.tagify:hover{border-color:#ccc;border-color:var(--tags-hover-border-color)}.tagify.tagify--focus{transition:0s;border-color:#3595f6;border-color:var(--tags-focus-border-color)}.tagify[readonly]:not(.tagify--mix){cursor:default}.tagify[readonly]:not(.tagify--mix)>.tagify__input{visibility:hidden;width:0;margin:5px 0}.tagify[readonly]:not(.tagify--mix) .tagify__tag>div{padding:.3em .5em;padding:var(--tag-pad)}.tagify[readonly]:not(.tagify--mix) .tagify__tag>div::before{background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px;box-shadow:none;filter:brightness(.95)}.tagify[readonly] .tagify__tag__removeBtn{display:none}.tagify--loading .tagify__input>br:last-child{display:none}.tagify--loading .tagify__input::before{content:none}.tagify--loading .tagify__input::after{content:'';vertical-align:middle;opacity:1;width:.7em;height:.7em;width:var(--loader-size);height:var(--loader-size);border:3px solid;border-color:#eee #bbb #888 transparent;border-radius:50%;animation:rotateLoader .4s infinite linear;content:''!important;margin:-2px 0 -2px .5em}.tagify--loading .tagify__input:empty::after{margin-left:0}.tagify+input,.tagify+textarea{position:absolute!important;left:-9999em!important;transform:scale(0)!important}.tagify__tag{display:inline-flex;align-items:center;margin:5px 0 5px 5px;position:relative;z-index:1;outline:0;cursor:default;transition:.13s ease-out}.tagify__tag>div{vertical-align:top;box-sizing:border-box;max-width:100%;padding:.3em .5em;padding:var(--tag-pad,.3em .5em);color:#000;color:var(--tag-text-color,#000);line-height:inherit;border-radius:3px;white-space:nowrap;transition:.13s ease-out}.tagify__tag>div>*{white-space:pre-wrap;overflow:hidden;text-overflow:ellipsis;display:inline-block;vertical-align:top;min-width:1ch;max-width:auto;min-width:var(--tag--min-width,1ch);max-width:var(--tag--max-width,auto);transition:.8s ease,.1s color}.tagify__tag>div>[contenteditable]{outline:0;-webkit-user-select:text;user-select:text;cursor:text;margin:-2px;padding:2px;max-width:350px}.tagify__tag>div::before{content:'';position:absolute;border-radius:inherit;left:0;top:0;right:0;bottom:0;z-index:-1;pointer-events:none;transition:120ms ease;animation:tags--bump .3s ease-out 1;box-shadow:0 0 0 1.1em #e5e5e5 inset;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-bg,#e5e5e5) inset}.tagify__tag:focus div::before,.tagify__tag:hover:not([readonly]) div::before{top:-2px;right:-2px;bottom:-2px;left:-2px;box-shadow:0 0 0 1.1em #d3e2e2 inset;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-hover,#d3e2e2) inset}.tagify__tag--loading{pointer-events:none}.tagify__tag--loading .tagify__tag__removeBtn{display:none}.tagify__tag--loading::after{--loader-size:.4em;content:'';vertical-align:middle;opacity:1;width:.7em;height:.7em;width:var(--loader-size);height:var(--loader-size);border:3px solid;border-color:#eee #bbb #888 transparent;border-radius:50%;animation:rotateLoader .4s infinite linear;margin:0 .5em 0 -.1em}.tagify__tag--flash div::before{animation:none}.tagify__tag--hide{width:0!important;padding-left:0;padding-right:0;margin-left:0;margin-right:0;opacity:0;transform:scale(0);transition:.3s;transition:var(--tag-hide-transition,.3s);pointer-events:none}.tagify__tag--hide>div>*{white-space:nowrap}.tagify__tag.tagify--noAnim>div::before{animation:none}.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div>span{opacity:.5}.tagify__tag.tagify--notAllowed:not(.tagify__tag--editable) div::before{box-shadow:0 0 0 1.1em rgba(211,148,148,.5) inset!important;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-invalid-bg,rgba(211,148,148,.5)) inset!important;transition:.2s}.tagify__tag[readonly] .tagify__tag__removeBtn{display:none}.tagify__tag[readonly]>div::before{background:linear-gradient(45deg,var(--tag-bg) 25%,transparent 25%,transparent 50%,var(--tag-bg) 50%,var(--tag-bg) 75%,transparent 75%,transparent) 0/5px 5px;box-shadow:none;filter:brightness(.95)}.tagify__tag--editable>div{color:#000;color:var(--tag-text-color--edit,#000)}.tagify__tag--editable>div::before{box-shadow:0 0 0 2px #d3e2e2 inset!important;box-shadow:0 0 0 2px var(--tag-hover,#d3e2e2) inset!important}.tagify__tag--editable>.tagify__tag__removeBtn{pointer-events:none}.tagify__tag--editable>.tagify__tag__removeBtn::after{opacity:0;transform:translateX(100%) translateX(5px)}.tagify__tag--editable.tagify--invalid>div::before{box-shadow:0 0 0 2px #d39494 inset!important;box-shadow:0 0 0 2px var(--tag-invalid-color,#d39494) inset!important}.tagify__tag__removeBtn{order:5;display:inline-flex;align-items:center;justify-content:center;border-radius:50px;cursor:pointer;font:14px/1 Arial;background:0 0;background:var(--tag-remove-btn-bg,none);color:#000;color:var(--tag-remove-btn-color,#000);width:14px;height:14px;margin-right:4.66667px;margin-left:auto;overflow:hidden;transition:.2s ease-out}.tagify__tag__removeBtn::after{content:"\00D7";transition:.3s,color 0s}.tagify__tag__removeBtn:hover{color:#fff;background:#c77777;background:var(--tag-remove-btn-bg--hover,#c77777)}.tagify__tag__removeBtn:hover+div>span{opacity:.5}.tagify__tag__removeBtn:hover+div::before{box-shadow:0 0 0 1.1em rgba(211,148,148,.3) inset!important;box-shadow:0 0 0 var(--tag-inset-shadow-size,1.1em) var(--tag-remove-bg,rgba(211,148,148,.3)) inset!important;transition:box-shadow .2s}.tagify:not(.tagify--mix) .tagify__input br{display:none}.tagify:not(.tagify--mix) .tagify__input *{display:inline;white-space:nowrap}.tagify__input{flex-grow:1;display:inline-block;min-width:110px;margin:5px;padding:.3em .5em;padding:var(--tag-pad,.3em .5em);line-height:inherit;position:relative;white-space:pre-wrap;color:inherit;color:var(--input-color,inherit);box-sizing:inherit}.tagify__input:empty::before{transition:.2s ease-out;opacity:1;transform:none;display:inline-block;width:auto}.tagify--mix .tagify__input:empty::before{display:inline-block}.tagify__input:focus{outline:0}.tagify__input:focus::before{transition:.2s ease-out;opacity:0;transform:translatex(6px)}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.tagify__input:focus::before{display:none}}@supports (-ms-ime-align:auto){.tagify__input:focus::before{display:none}}.tagify__input:focus:empty::before{transition:.2s ease-out;opacity:1;transform:none;color:rgba(0,0,0,.25);color:var(--placeholder-color-focus)}@-moz-document url-prefix(){.tagify__input:focus:empty::after{display:none}}.tagify__input::before{content:attr(data-placeholder);height:1em;line-height:1em;margin:auto 0;z-index:1;color:rgba(0,0,0,.4);color:var(--placeholder-color);white-space:nowrap;pointer-events:none;opacity:0;position:absolute}.tagify--mix .tagify__input::before{display:none;position:static;line-height:inherit}.tagify__input::after{content:attr(data-suggest);display:inline-block;white-space:pre;color:#000;opacity:.3;pointer-events:none;max-width:100px}.tagify__input .tagify__tag{margin:0 1px}.tagify__input .tagify__tag>div{padding-top:0;padding-bottom:0}.tagify--mix{display:block}.tagify--mix .tagify__input{padding:5px;margin:0;width:100%;height:100%;line-height:1.5;display:block}.tagify--mix .tagify__input::before{height:auto}.tagify--mix .tagify__input::after{content:none}.tagify--select::after{content:'>';opacity:.5;position:absolute;top:50%;right:0;bottom:0;font:16px monospace;line-height:8px;height:8px;pointer-events:none;transform:translate(-150%,-50%) scaleX(1.2) rotate(90deg);transition:.2s ease-in-out}.tagify--select[aria-expanded=true]::after{transform:translate(-150%,-50%) rotate(270deg) scaleY(1.2)}.tagify--select .tagify__tag{position:absolute;top:0;right:1.8em;bottom:0}.tagify--select .tagify__tag div{display:none}.tagify--select .tagify__input{width:100%}.tagify--invalid{--tags-border-color:#D39494}.tagify__dropdown{position:absolute;z-index:9999;transform:translateY(1px);overflow:hidden}.tagify__dropdown[placement=top]{margin-top:0;transform:translateY(-100%)}.tagify__dropdown[placement=top] .tagify__dropdown__wrapper{border-top-width:1px;border-bottom-width:0}.tagify__dropdown[position=text]{box-shadow:0 0 0 3px rgba(var(--tagify-dd-color-primary),.1);font-size:.9em}.tagify__dropdown[position=text] .tagify__dropdown__wrapper{border-width:1px}.tagify__dropdown__wrapper{max-height:300px;overflow:hidden;background:#fff;background:var(--tagify-dd-bg-color);border:1px solid #3595f6;border-color:var(--tagify-dd-color-primary);border-width:1.1px;border-top-width:0;box-shadow:0 2px 4px -2px rgba(0,0,0,.2);transition:.25s cubic-bezier(0,1,.5,1)}.tagify__dropdown__wrapper:hover{overflow:auto}.tagify__dropdown--initial .tagify__dropdown__wrapper{max-height:20px;transform:translateY(-1em)}.tagify__dropdown--initial[placement=top] .tagify__dropdown__wrapper{transform:translateY(2em)}.tagify__dropdown__item{box-sizing:inherit;padding:.3em .5em;margin:1px;cursor:pointer;border-radius:2px;position:relative;outline:0}.tagify__dropdown__item--active{background:#3595f6;background:var(--tagify-dd-color-primary);color:#fff}.tagify__dropdown__item:active{filter:brightness(105%)} \ No newline at end of file diff --git a/lib/tagify.js b/lib/tagify.js index 68e28de..4237a2c 100644 --- a/lib/tagify.js +++ b/lib/tagify.js @@ -1,2127 +1 @@ -/** - * Tagify (v 3.4.0)- tags input component - * By Yair Even-Or - * Don't sell this code. (c) - * https://github.com/yairEO/tagify - */ -;(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.Tagify = factory(); - } -}(this, function() { -"use strict"; - -function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } - -function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } - -function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } - -function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } - -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -var isFirefox = typeof InstallTrigger !== 'undefined'; - -var getUID = function getUID() { - return (new Date().getTime() + Math.floor(Math.random() * 10000 + 1)).toString(16); -}; - -var removeCollectionProp = function removeCollectionProp(collection, unwantedProp) { - return collection.map(function (v) { - var props = {}; - - for (var p in v) { - if (p != unwantedProp) props[p] = v[p]; - } - - return props; - }); -}; - -function decode(s) { - var el = document.createElement('div'); - return s.replace(/\&#?[0-9a-z]+;/gi, function (enc) { - el.innerHTML = enc; - return el.innerText; - }); -} -/** - * utility method - * https://stackoverflow.com/a/6234804/104380 - */ - - -function escapeHTML(s) { - return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); -} // ☝☝☝ ALL THE ABOVE WILL BE MOVED INTO SEPARATE FILES ☝☝☝ - -/** - * @constructor - * @param {Object} input DOM element - * @param {Object} settings settings object - */ - - -function Tagify(input, settings) { - // protection - if (!input) { - console.warn('Tagify: ', 'invalid input element ', input); - return this; - } - - this.applySettings(input, settings || {}); - this.state = { - editing: {}, - actions: {}, - // UI actions for state-locking - dropdown: {} - }; - this.value = []; // tags' data - - this.tagsDataById = {}; // events' callbacks references will be stores here, so events could be unbinded - - this.listeners = {}; - this.DOM = {}; // Store all relevant DOM elements in an Object - - this.extend(this, new this.EventDispatcher(this)); - this.build(input); - this.getCSSVars(); - this.loadOriginalValues(); - this.events.customBinding.call(this); - this.events.binding.call(this); - input.autofocus && this.DOM.input.focus(); -} - -Tagify.prototype = { - isIE: window.document.documentMode, - // https://developer.mozilla.org/en-US/docs/Web/API/Document/compatMode#Browser_compatibility - TEXTS: { - empty: "empty", - exceed: "number of tags exceeded", - pattern: "pattern mismatch", - duplicate: "already exists", - notAllowed: "not allowed" - }, - DEFAULTS: { - delimiters: ",", - // [RegEx] split tags by any of these delimiters ("null" to cancel) Example: ",| |." - pattern: null, - // RegEx pattern to validate input by. Ex: /[1-9]/ - maxTags: Infinity, - // Maximum number of tags - callbacks: {}, - // Exposed callbacks object to be triggered on certain events - addTagOnBlur: true, - // Flag - automatically adds the text which was inputed as a tag when blur event happens - duplicates: false, - // Flag - allow tuplicate tags - whitelist: [], - // Array of tags to suggest as the user types (can be used along with "enforceWhitelist" setting) - blacklist: [], - // A list of non-allowed tags - enforceWhitelist: false, - // Flag - Only allow tags allowed in whitelist - keepInvalidTags: false, - // Flag - if true, do not remove tags which did not pass validation - mixTagsAllowedAfter: /,|\.|\:|\s/, - // RegEx - Define conditions in which mix-tags content is allowing a tag to be added after - mixTagsInterpolator: ['[[', ']]'], - // Interpolation for mix mode. Everything between this will becmoe a tag - backspace: true, - // false / true / "edit" - skipInvalid: false, - // If `true`, do not add invalid, temporary, tags before automatically removing them - editTags: 2, - // 1 or 2 clicks to edit a tag. false/null for not allowing editing - transformTag: function transformTag() {}, - // Takes a tag input string as argument and returns a transformed value - autoComplete: { - enabled: true, - // Tries to suggest the input's value while typing (match from whitelist) by adding the rest of term as grayed-out text - rightKey: false // If `true`, when Right key is pressed, use the suggested value to create a tag, else just auto-completes the input. in mixed-mode this is set to "true" - - }, - dropdown: { - classname: '', - enabled: 2, - // minimum input characters needs to be typed for the dropdown to show - maxItems: 10, - searchKeys: [], - fuzzySearch: true, - highlightFirst: false, - // highlights first-matched item in the list - closeOnSelect: true, - // closes the dropdown after selecting an item, if `enabled:0` (which means always show dropdown) - position: 'all' // 'manual' / 'text' / 'all' - - } - }, - // Using ARIA & role attributes - // https://www.w3.org/TR/wai-aria-practices/examples/combobox/aria1.1pattern/listbox-combo.html - templates: { - wrapper: function wrapper(input, settings) { - return ""); - }, - tag: function tag(value, tagData) { - return "\n \n
\n ").concat(value, "\n
\n
"); - }, - dropdownItem: function dropdownItem(item) { - var mapValueTo = this.settings.dropdown.mapValueTo, - value = (mapValueTo ? typeof mapValueTo == 'function' ? mapValueTo(item) : item[mapValueTo] : item.value) || item.value, - sanitizedValue = (value || item).replace(/`|'/g, "'"); - return "
").concat(sanitizedValue, "
"); - } - }, - customEventsList: ['add', 'remove', 'invalid', 'input', 'click', 'keydown', 'focus', 'blur', 'edit:input', 'edit:updated', 'edit:start', 'edit:keydown', 'dropdown:show', 'dropdown:hide', 'dropdown:select'], - applySettings: function applySettings(input, settings) { - var _this2 = this; - - this.DEFAULTS.templates = this.templates; - this.settings = this.extend({}, this.DEFAULTS, settings); - this.settings.readonly = input.hasAttribute('readonly'); // if "readonly" do not include an "input" element inside the Tags component - - this.settings.placeholder = input.getAttribute('placeholder') || this.settings.placeholder || ""; - if (this.isIE) this.settings.autoComplete = false; // IE goes crazy if this isn't false - - ["whitelist", "blacklist"].forEach(function (name) { - var attrVal = input.getAttribute('data-' + name); - - if (attrVal) { - attrVal = attrVal.split(_this2.settings.delimiters); - if (attrVal instanceof Array) _this2.settings[name] = attrVal; - } - }); // backward-compatibility for old version of "autoComplete" setting: - - if ("autoComplete" in settings && !this.isObject(settings.autoComplete)) { - this.settings.autoComplete = this.DEFAULTS.autoComplete; - this.settings.autoComplete.enabled = settings.autoComplete; - } - - if (input.pattern) try { - this.settings.pattern = new RegExp(input.pattern); - } catch (e) {} // Convert the "delimiters" setting into a REGEX object - - if (this.settings.delimiters) { - try { - this.settings.delimiters = new RegExp(this.settings.delimiters, "g"); - } catch (e) {} - } // make sure the dropdown will be shown on "focus" and not only after typing something (in "select" mode) - - - if (this.settings.mode == 'select') this.settings.dropdown.enabled = 0; - if (this.settings.mode == 'mix') this.settings.autoComplete.rightKey = true; - }, - - /** - * Returns a string of HTML element attributes - * @param {Object} data [Tag data] - */ - getAttributes: function getAttributes(data) { - // only items which are objects have properties which can be used as attributes - if (Object.prototype.toString.call(data) != "[object Object]") return ''; - var keys = Object.keys(data), - s = "", - propName, - i; - - for (i = keys.length; i--;) { - propName = keys[i]; - if (propName != 'class' && data.hasOwnProperty(propName) && data[propName]) s += " " + propName + (data[propName] ? "=\"".concat(data[propName], "\"") : ""); - } - - return s; - }, - - /** - * utility method - * https://stackoverflow.com/a/35385518/104380 - * @param {String} s [HTML string] - * @return {Object} [DOM node] - */ - parseHTML: function parseHTML(s) { - var parser = new DOMParser(), - node = parser.parseFromString(s.trim(), "text/html"); - return node.body.firstElementChild; - }, - - /** - * Get the caret position relative to the viewport - * https://stackoverflow.com/q/58985076/104380 - * - * @returns {object} left, top distance in pixels - */ - getCaretGlobalPosition: function getCaretGlobalPosition() { - var sel = document.getSelection(); - - if (sel.rangeCount) { - var r = sel.getRangeAt(0); - var node = r.startContainer; - var offset = r.startOffset; - var rect, r2; - - if (offset > 0) { - r2 = document.createRange(); - r2.setStart(node, offset - 1); - r2.setEnd(node, offset); - rect = r2.getBoundingClientRect(); - return { - left: rect.right, - top: rect.top, - bottom: rect.bottom - }; - } - } - - return { - left: -9999, - top: -9999 - }; - }, - - /** - * Get specific CSS variables which are relevant to this script and parse them as needed. - * The result is saved on the instance in "this.CSSVars" - */ - getCSSVars: function getCSSVars() { - var compStyle = getComputedStyle(this.DOM.scope, null); - - var getProp = function getProp(name) { - return compStyle.getPropertyValue('--' + name); - }; - - function seprateUnitFromValue(a) { - if (!a) return {}; - a = a.trim().split(' ')[0]; - var unit = a.split(/\d+/g).filter(function (n) { - return n; - }).pop().trim(), - value = +a.split(unit).filter(function (n) { - return n; - })[0].trim(); - return { - value: value, - unit: unit - }; - } - - this.CSSVars = { - tagHideTransition: function (_ref) { - var value = _ref.value, - unit = _ref.unit; - return unit == 's' ? value * 1000 : value; - }(seprateUnitFromValue(getProp('tag-hide-transition'))) - }; - }, - - /** - * builds the HTML of this component - * @param {Object} input [DOM element which would be "transformed" into "Tags"] - */ - build: function build(input) { - var DOM = this.DOM, - template = this.settings.templates.wrapper(input, this.settings); - DOM.originalInput = input; - DOM.scope = this.parseHTML(template); - DOM.input = DOM.scope.querySelector('[contenteditable]'); - input.parentNode.insertBefore(DOM.scope, input); - - if (this.settings.dropdown.enabled >= 0) { - this.dropdown.init.call(this); - } - }, - - /** - * revert any changes made by this component - */ - destroy: function destroy() { - this.DOM.scope.parentNode.removeChild(this.DOM.scope); - this.dropdown.hide.call(this, true); - }, - - /** - * if the original input had any values, add them as tags - */ - loadOriginalValues: function loadOriginalValues(value) { - value = value || this.DOM.originalInput.value; // if the original input already had any value (tags) - - if (!value) return; - this.removeAllTags(); - if (this.settings.mode == 'mix') this.parseMixTags(value.trim());else { - try { - if (typeof JSON.parse(value) !== 'string') value = JSON.parse(value); - } catch (err) {} - - this.addTags(value).forEach(function (tag) { - return tag && tag.classList.add('tagify--noAnim'); - }); - } - }, - - /** - * Checks if an argument is a javascript Object - */ - isObject: function isObject(obj) { - var type = Object.prototype.toString.call(obj).split(' ')[1].slice(0, -1); - return obj === Object(obj) && type != 'Array' && type != 'Function' && type != 'RegExp' && type != 'HTMLUnknownElement'; - }, - - /** - * merge objects into a single new one - * TEST: extend({}, {a:{foo:1}, b:[]}, {a:{bar:2}, b:[1], c:()=>{}}) - */ - extend: function extend(o, o1, o2) { - var that = this; - if (!(o instanceof Object)) o = {}; - copy(o, o1); - if (o2) copy(o, o2); - - function copy(a, b) { - // copy o2 to o - for (var key in b) { - if (b.hasOwnProperty(key)) { - if (that.isObject(b[key])) { - if (!that.isObject(a[key])) a[key] = Object.assign({}, b[key]);else copy(a[key], b[key]); - } else a[key] = b[key]; - } - } - } - - return o; - }, - cloneEvent: function cloneEvent(e) { - var clonedEvent = {}; - - for (var v in e) { - clonedEvent[v] = e[v]; - } - - return clonedEvent; - }, - - /** - * A constructor for exposing events to the outside - */ - EventDispatcher: function EventDispatcher(instance) { - // Create a DOM EventTarget object - var target = document.createTextNode(''); - - function addRemove(op, events, cb) { - if (cb) events.split(/\s+/g).forEach(function (name) { - return target[op + 'EventListener'].call(target, name, cb); - }); - } // Pass EventTarget interface calls to DOM EventTarget object - - - this.off = function (events, cb) { - addRemove('remove', events, cb); - return this; - }; - - this.on = function (events, cb) { - if (cb && typeof cb == 'function') addRemove('add', events, cb); - return this; - }; - - this.trigger = function (eventName, data) { - var e; - if (!eventName) return; - - if (instance.settings.isJQueryPlugin) { - if (eventName == 'remove') eventName = 'removeTag'; // issue #222 - - jQuery(instance.DOM.originalInput).triggerHandler(eventName, [data]); - } else { - try { - e = new CustomEvent(eventName, { - "detail": this.extend({}, data, { - tagify: this - }) - }); - } catch (err) { - console.warn(err); - } - - target.dispatchEvent(e); - } - }; - }, - - /** - * Toogle loading state on/off - * @param {Boolean} isLoading - */ - loading: function loading(isLoading) { - // IE11 doesn't support toggle with second parameter - this.DOM.scope.classList[isLoading ? "add" : "remove"]('tagify--loading'); - return this; - }, - toggleFocusClass: function toggleFocusClass(force) { - this.DOM.scope.classList.toggle('tagify--focus', !!force); - }, - - /** - * DOM events listeners binding - */ - events: { - // bind custom events which were passed in the settings - customBinding: function customBinding() { - var _this3 = this; - - this.customEventsList.forEach(function (name) { - _this3.on(name, _this3.settings.callbacks[name]); - }); - }, - binding: function binding() { - var bindUnbind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; - - var _CB = this.events.callbacks, - _CBR, - action = bindUnbind ? 'addEventListener' : 'removeEventListener'; // do not allow the main events to be bound more than once - - - if (this.state.mainEvents && bindUnbind) return; // set the binding state of the main events, so they will not be bound more than once - - this.state.mainEvents = bindUnbind; - - if (bindUnbind && !this.listeners.main) { - // this event should never be unbinded: - // IE cannot register "input" events on contenteditable elements, so the "keydown" should be used instead.. - this.DOM.input.addEventListener(this.isIE ? "keydown" : "input", _CB[this.isIE ? "onInputIE" : "onInput"].bind(this)); - if (this.settings.isJQueryPlugin) jQuery(this.DOM.originalInput).on('tagify.removeAllTags', this.removeAllTags.bind(this)); - } // setup callback references so events could be removed later - - - _CBR = this.listeners.main = this.listeners.main || { - focus: ['input', _CB.onFocusBlur.bind(this)], - blur: ['input', _CB.onFocusBlur.bind(this)], - keydown: ['input', _CB.onKeydown.bind(this)], - click: ['scope', _CB.onClickScope.bind(this)], - dblclick: ['scope', _CB.onDoubleClickScope.bind(this)] - }; - - for (var eventName in _CBR) { - // make sure the focus/blur event is always regesitered (and never more than once) - if (eventName == 'blur' && !bindUnbind) return; - - this.DOM[_CBR[eventName][0]][action](eventName, _CBR[eventName][1]); - } - }, - - /** - * DOM events callbacks - */ - callbacks: { - onFocusBlur: function onFocusBlur(e) { - var text = e.target ? e.target.textContent.trim() : '', - // a string - _s = this.settings, - type = e.type, - shouldAddTags; // goes into this scenario only on input "blur" and a tag was clicked - - if (e.relatedTarget && e.relatedTarget.classList.contains('tagify__tag') && this.DOM.scope.contains(e.relatedTarget)) return; - - if (type == 'blur' && e.relatedTarget === this.DOM.scope) { - this.dropdown.hide.call(this); - this.DOM.input.focus(); - return; - } - - if (this.state.actions.selectOption && (_s.dropdown.enabled || !_s.dropdown.closeOnSelect)) return; - this.state.hasFocus = type == "focus" ? +new Date() : false; - this.toggleFocusClass(this.state.hasFocus); - this.setRangeAtStartEnd(false); - - if (_s.mode == 'mix') { - if (e.type == "blur") this.dropdown.hide.call(this); - return; - } - - if (type == "focus") { - this.trigger("focus", { - relatedTarget: e.relatedTarget - }); // e.target.classList.remove('placeholder'); - - if (_s.dropdown.enabled === 0 && _s.mode != "select") { - this.dropdown.show.call(this); - } - - return; - } else if (type == "blur") { - this.trigger("blur", { - relatedTarget: e.relatedTarget - }); - this.loading(false); - shouldAddTags = this.settings.mode == 'select' ? !this.value.length || this.value[0].value != text : text && !this.state.actions.selectOption && _s.addTagOnBlur; // do not add a tag if "selectOption" action was just fired (this means a tag was just added from the dropdown) - - shouldAddTags && this.addTags(text, true); - } - - this.DOM.input.removeAttribute('style'); - this.dropdown.hide.call(this); - }, - onKeydown: function onKeydown(e) { - var _this4 = this; - - var s = e.target.textContent.trim(); - this.trigger("keydown", { - originalEvent: this.cloneEvent(e) - }); - - if (this.settings.mode == 'mix') { - switch (e.key) { - case 'Left': - case 'ArrowLeft': - { - // when left arrow was pressed, raise a flag so when the dropdown is shown, right-arrow will be ignored - // because it seems likely the user wishes to use the arrows to move the caret - this.state.actions.ArrowLeft = true; - break; - } - - case 'Delete': - case 'Backspace': - { - // e.preventDefault() - var selection = document.getSelection(), - values = [], - lastInputValue = decode(this.DOM.input.innerHTML); // if( isFirefox && selection && selection.anchorOffset == 0 ) - // this.removeTag(selection.anchorNode.previousSibling) - // a minimum delay is needed before the node actually gets ditached from the document (don't know why), - // to know exactly which tag was deleted. This is the easiest way of knowing besides using MutationObserver - - setTimeout(function () { - // fixes #384, where the first and only tag will not get removed with backspace - if (decode(_this4.DOM.input.innerHTML).length >= lastInputValue.length) { - _this4.removeTag(selection.anchorNode.previousElementSibling); // the above "removeTag" methods removes the tag with a transition. Chrome adds a
element for some reason at this stage - - - if (_this4.DOM.input.children.length == 2 && _this4.DOM.input.children[1].tagName == "BR") { - _this4.DOM.input.innerHTML = ""; - _this4.value.length = 0; - return true; - } - } - - var tagElms = _this4.DOM.input.querySelectorAll('.tagify__tag'); // find out which tag(s) were deleted and update "this.value" accordingly - // iterate over the list of tags still in the document and then filter only those from the "this.value" collection - - - [].forEach.call(tagElms, function (node) { - return values.push(node.getAttribute('value')); - }); - _this4.value = _this4.value.filter(function (d) { - return values.indexOf(d.value) != -1; - }); - }, 50); // Firefox needs this higher duration for some reason or things get buggy when to deleting text from the end - - break; - } - // currently commented to allow new lines in mixed-mode - // case 'Enter' : - // e.preventDefault(); // solves Chrome bug - http://stackoverflow.com/a/20398191/104380 - } - - return true; - } - - switch (e.key) { - case 'Backspace': - if (!this.state.dropdown.visible) { - if (s == "" || s.charCodeAt(0) == 8203) { - // 8203: ZERO WIDTH SPACE unicode - if (this.settings.backspace === true) this.removeTag();else if (this.settings.backspace == 'edit') setTimeout(this.editTag.bind(this), 0); // timeout reason: when edited tag gets focused and the caret is placed at the end, the last character gets deletec (because of backspace) - } - } - - break; - - case 'Esc': - case 'Escape': - if (this.state.dropdown.visible) return; - e.target.blur(); - break; - - case 'Down': - case 'ArrowDown': - // if( this.settings.mode == 'select' ) // issue #333 - if (!this.state.dropdown.visible) this.dropdown.show.call(this); - break; - - case 'ArrowRight': - { - var tagData = this.state.inputSuggestion || this.state.ddItemData; - - if (tagData && this.settings.autoComplete.rightKey) { - this.addTags([tagData], true); - return; - } - - break; - } - - case 'Tab': - { - if (!s || this.settings.mode == 'select') return true; - } - - case 'Enter': - e.preventDefault(); // solves Chrome bug - http://stackoverflow.com/a/20398191/104380 - // because the main "keydown" event is bound before the dropdown events, this will fire first and will not *yet* - // know if an option was just selected from the dropdown menu. If an option was selected, - // the dropdown events should handle adding the tag - - setTimeout(function () { - if (_this4.state.actions.selectOption) return; - - _this4.addTags(s, true); - }); - } - }, - onInput: function onInput(e) { - var value = this.settings.mode == 'mix' ? this.DOM.input.textContent : this.input.normalize.call(this), - showSuggestions = value.length >= this.settings.dropdown.enabled, - data = { - value: value, - inputElm: this.DOM.input - }; - if (this.settings.mode == 'mix') return this.events.callbacks.onMixTagsInput.call(this, e); - - if (!value) { - this.input.set.call(this, ''); - return; - } - - if (this.input.value == value) return; // for IE; since IE doesn't have an "input" event so "keyDown" is used instead - - data.isValid = this.validateTag(value); - this.trigger('input', data); // "input" event must be triggered at this point, before the dropdown is shown - // save the value on the input's State object - - this.input.set.call(this, value, false); // update the input with the normalized value and run validations - // this.setRangeAtStartEnd(); // fix caret position - - if (value.search(this.settings.delimiters) != -1) { - if (this.addTags(value)) { - this.input.set.call(this); // clear the input field's value - } - } else if (this.settings.dropdown.enabled >= 0) { - this.dropdown[showSuggestions ? "show" : "hide"].call(this, value); - } - }, - onMixTagsInput: function onMixTagsInput(e) { - var _this5 = this; - - var sel, - range, - split, - tag, - showSuggestions, - _s = this.settings; - if (this.hasMaxTags()) return true; - - if (window.getSelection) { - sel = window.getSelection(); - - if (sel.rangeCount > 0) { - range = sel.getRangeAt(0).cloneRange(); - range.collapse(true); - range.setStart(window.getSelection().focusNode, 0); - split = range.toString().split(_s.mixTagsAllowedAfter); // ["foo", "bar", "@a"] - - tag = split[split.length - 1].match(_s.pattern); - - if (tag) { - this.state.actions.ArrowLeft = false; // start fresh, assuming the user did not (yet) used any arrow to move the caret - - this.state.tag = { - prefix: tag[0], - value: tag.input.split(tag[0])[1] - }; - showSuggestions = this.state.tag.value.length >= _s.dropdown.enabled; - } - } - } // wait until the "this.value" has been updated (see "onKeydown" method for "mix-mode") - // the dropdown must be shown only after this event has been driggered, so an implementer could - // dynamically change the whitelist. - - - setTimeout(function () { - _this5.update(); - - _this5.trigger("input", _this5.extend({}, _this5.state.tag, { - textContent: _this5.DOM.input.textContent - })); - - if (_this5.state.tag) _this5.dropdown[showSuggestions ? "show" : "hide"].call(_this5, _this5.state.tag.value); - }, 10); - }, - onInputIE: function onInputIE(e) { - var _this = this; // for the "e.target.textContent" to be changed, the browser requires a small delay - - - setTimeout(function () { - _this.events.callbacks.onInput.call(_this, e); - }); - }, - onClickScope: function onClickScope(e) { - var tagElm = e.target.closest('.tagify__tag'), - _s = this.settings, - timeDiffFocus = +new Date() - this.state.hasFocus, - tagElmIdx; - - if (e.target == this.DOM.scope) { - // if( !this.state.hasFocus ) - // this.dropdown.hide.call(this) - this.DOM.input.focus(); - return; - } else if (e.target.classList.contains("tagify__tag__removeBtn")) { - this.removeTag(e.target.parentNode); - return; - } else if (tagElm) { - tagElmIdx = this.getNodeIndex(tagElm); - this.trigger("click", { - tag: tagElm, - index: tagElmIdx, - data: this.value[tagElmIdx], - originalEvent: this.cloneEvent(e) - }); - if (this.settings.editTags == 1) this.events.callbacks.onDoubleClickScope.call(this, e); - return; - } // when clicking on the input itself - else if (e.target == this.DOM.input && timeDiffFocus > 500) { - if (this.state.dropdown.visible) this.dropdown.hide.call(this);else if (_s.dropdown.enabled === 0 && _s.mode != 'mix') this.dropdown.show.call(this); - return; - } - - if (_s.mode == 'select') !this.state.dropdown.visible && this.dropdown.show.call(this); - }, - onEditTagInput: function onEditTagInput(editableElm, e) { - var tagElm = editableElm.closest('tag'), - tagElmIdx = this.getNodeIndex(tagElm), - value = this.input.normalize.call(this, editableElm), - isValid = value.toLowerCase() == editableElm.originalValue.toLowerCase() || this.validateTag(value); - tagElm.classList.toggle('tagify--invalid', isValid !== true); - tagElm.isValid = isValid === true; // show dropdown if typed text is equal or more than the "enabled" dropdown setting - - if (value.length >= this.settings.dropdown.enabled) { - this.state.editing.value = value; - this.dropdown.show.call(this, value); - } - - this.trigger("edit:input", { - tag: tagElm, - index: tagElmIdx, - data: this.extend({}, this.value[tagElmIdx], { - newValue: value - }), - originalEvent: this.cloneEvent(e) - }); - }, - onEditTagBlur: function onEditTagBlur(editableElm) { - if (!this.state.hasFocus) this.toggleFocusClass(); - if (!this.DOM.scope.contains(editableElm)) return; - - var tagElm = editableElm.closest('.tagify__tag'), - currentValue = this.input.normalize.call(this, editableElm), - value = currentValue || editableElm.originalValue, - hasChanged = value != editableElm.originalValue, - isValid = tagElm.isValid, - tagData = _objectSpread({}, this.tagsDataById[tagElm.__tagifyId], { - value: value - }); // this.DOM.input.focus() - - - if (!currentValue) { - this.removeTag(tagElm); - this.onEditTagDone(); - return; - } - - if (hasChanged) { - this.settings.transformTag.call(this, tagData); // re-validate after tag transformation - - isValid = this.validateTag(tagData.value) === true; - } else { - this.onEditTagDone(tagElm); - return; - } - - if (isValid !== true) return; - this.onEditTagDone(tagElm, tagData); - }, - onEditTagkeydown: function onEditTagkeydown(e) { - this.trigger("edit:keydown", { - originalEvent: this.cloneEvent(e) - }); - - switch (e.key) { - case 'Esc': - case 'Escape': - e.target.textContent = e.target.originalValue; - - case 'Enter': - case 'Tab': - e.preventDefault(); - e.target.blur(); - } - }, - onDoubleClickScope: function onDoubleClickScope(e) { - var tagElm = e.target.closest('tag'), - _s = this.settings, - isEditingTag, - isReadyOnlyTag; - if (!tagElm) return; - isEditingTag = tagElm.classList.contains('tagify__tag--editable'); - isReadyOnlyTag = tagElm.hasAttribute('readonly'); - if (_s.mode != 'select' && !_s.readonly && !isEditingTag && !isReadyOnlyTag && this.settings.editTags) this.editTag(tagElm); - this.toggleFocusClass(true); - } - } - }, - - /** - * @param {Node} tagElm the tag element to edit. if nothing specified, use last last - */ - editTag: function editTag(tagElm, opts) { - var _this6 = this; - - tagElm = tagElm || this.getLastTag(); - opts = opts || {}; - - var editableElm = tagElm.querySelector('.tagify__tag-text'), - tagIdx = this.getNodeIndex(tagElm), - tagData = this.tagsDataById[tagElm.__tagifyId], - _CB = this.events.callbacks, - that = this, - isValid = true, - delayed_onEditTagBlur = function delayed_onEditTagBlur() { - setTimeout(_CB.onEditTagBlur.bind(that), 0, editableElm); - }; - - if (!editableElm) { - console.warn('Cannot find element in Tag template: ', '.tagify__tag-text'); - return; - } - - if (tagData instanceof Object && "editable" in tagData && !tagData.editable) return; - tagElm.classList.add('tagify__tag--editable'); - editableElm.originalValue = editableElm.textContent; - editableElm.setAttribute('contenteditable', true); - editableElm.addEventListener('blur', delayed_onEditTagBlur); - editableElm.addEventListener('input', _CB.onEditTagInput.bind(this, editableElm)); - editableElm.addEventListener('keydown', function (e) { - return _CB.onEditTagkeydown.call(_this6, e); - }); - editableElm.focus(); - this.setRangeAtStartEnd(false, editableElm); - if (!opts.skipValidation) isValid = this.editTagToggleValidity(tagElm, tagData.value); - this.state.editing = { - scope: tagElm, - input: tagElm.querySelector("[contenteditable]") - }; - this.trigger("edit:start", { - tag: tagElm, - index: tagIdx, - data: tagData, - isValid: isValid - }); - return this; - }, - editTagToggleValidity: function editTagToggleValidity(tagElm, value) { - var isValid = this.validateTag(value, tagElm.__tagifyId); - tagElm.classList.toggle('tagify--invalid', isValid !== true); - tagElm.isValid = isValid; - return isValid; - }, - onEditTagDone: function onEditTagDone(tagElm, tagData) { - var eventData = { - tag: tagElm, - index: this.getNodeIndex(tagElm), - data: tagData - }; - this.trigger("edit:beforeUpdate", eventData); - tagElm && this.replaceTag(tagElm, tagData); - this.trigger("edit:updated", eventData); - this.dropdown.hide.call(this); - }, - - /** - * Replaces an exisitng tag with a new one and update the relevant state - * @param {Object} tagElm [DOM node to replace] - * @param {Object} tagData [data to create new tag from] - */ - replaceTag: function replaceTag(tagElm, tagData) { - var _this7 = this; - - if (!tagData || !tagData.value) tagData = this.tagsDataById[tagElm.__tagifyId]; // if tag is invalid, make the according changes in the newly created element - - tagData = tagElm.isValid === true ? tagData : this.extend(tagData, this.getInvaildTagParams(tagData, tagData)); - var newTag = this.createTagElem(tagData); // when editing a tag and selecting a dropdown suggested item, the state should be "locked" - // so "onEditTagBlur" won't run and change the tag also *after* it was just changed. - - if (this.state.editing.locked) return; - this.state.editing = { - locked: true - }; - setTimeout(function () { - return delete _this7.state.editing.locked; - }, 500); // update DOM - - newTag.__tagifyId = tagElm.__tagifyId; - tagElm.parentNode.replaceChild(newTag, tagElm); - this.tagsDataById[tagElm.__tagifyId] = tagData; - this.updateValueByDOMTags(); - }, - - /** - * update value by traversing all valid tags - */ - updateValueByDOMTags: function updateValueByDOMTags() { - var _this8 = this; - - this.value = []; - [].forEach.call(this.getTagElms(), function (node) { - if (node.classList.contains('tagify--notAllowed')) return; - - _this8.value.push(_this8.tagsDataById[node.__tagifyId]); - }); - this.update(); - }, - - /** https://stackoverflow.com/a/59156872/104380 - * @param {Boolean} start indicating where to place it (start or end of the node) - * @param {Object} node DOM node to place the caret at - */ - setRangeAtStartEnd: function setRangeAtStartEnd(start, node) { - node = node || this.DOM.input; - node = node.lastChild || node; - var sel = document.getSelection(); - - if (sel.rangeCount) { - ['Start', 'End'].forEach(function (pos) { - return sel.getRangeAt(0)["set" + pos](node, start ? 0 : node.length); - }); - } - }, - - /** - * input bridge for accessing & setting - * @type {Object} - */ - input: { - value: '', - set: function set() { - var s = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; - var updateDOM = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - var hideDropdown = this.settings.dropdown.closeOnSelect; - this.input.value = s; - if (updateDOM) this.DOM.input.innerHTML = s; - if (!s && hideDropdown) setTimeout(this.dropdown.hide.bind(this), 20); // setTimeout duration must be HIGER than the dropdown's item "onClick" method's "focus()" event, because the "hide" method re-binds the main events and it will catch the "blur" event and will cause - - this.input.autocomplete.suggest.call(this); - this.input.validate.call(this); - }, - - /** - * Marks the tagify's input as "invalid" if the value did not pass "validateTag()" - */ - validate: function validate() { - var isValid = !this.input.value || this.validateTag(this.input.value); - if (this.settings.mode == 'select') this.DOM.scope.classList.toggle('tagify--invalid', isValid !== true);else this.DOM.input.classList.toggle('tagify__input--invalid', isValid !== true); - }, - // remove any child DOM elements that aren't of type TEXT (like
) - normalize: function normalize(node) { - var clone = node || this.DOM.input, - //.cloneNode(true), - v = []; // when a text was pasted in FF, the "this.DOM.input" element will have
but no newline symbols (\n), and this will - // result in tags no being properly created if one wishes to create a separate tag per newline. - - clone.childNodes.forEach(function (n) { - return n.nodeType == 3 && v.push(n.nodeValue); - }); - v = v.join("\n"); - - try { - // "delimiters" might be of a non-regex value, where this will fail ("Tags With Properties" example in demo page): - v = v.replace(/(?:\r\n|\r|\n)/g, this.settings.delimiters.source.charAt(0)); - } catch (err) {} - - v = v.replace(/\s/g, ' ') // replace NBSPs with spaces characters - .replace(/^\s+/, ""); // trimLeft - - return v; - }, - - /** - * suggest the rest of the input's value (via CSS "::after" using "content:attr(...)") - * @param {String} s [description] - */ - autocomplete: { - suggest: function suggest(data) { - if (!this.settings.autoComplete.enabled) return; - data = data || {}; - if (typeof data == 'string') data = { - value: data - }; - var suggestedText = data.value || '', - suggestionStart = suggestedText.substr(0, this.input.value.length).toLowerCase(), - suggestionTrimmed = suggestedText.substring(this.input.value.length); - - if (!suggestedText || !this.input.value || suggestionStart != this.input.value.toLowerCase()) { - this.DOM.input.removeAttribute("data-suggest"); - delete this.state.inputSuggestion; - } else { - this.DOM.input.setAttribute("data-suggest", suggestionTrimmed); - this.state.inputSuggestion = data; - } - }, - - /** - * sets the suggested text as the input's value & cleanup the suggestion autocomplete. - * @param {String} s [text] - */ - set: function set(s) { - var dataSuggest = this.DOM.input.getAttribute('data-suggest'), - suggestion = s || (dataSuggest ? this.input.value + dataSuggest : null); - - if (suggestion) { - if (this.settings.mode == 'mix') { - this.replaceTextWithNode(document.createTextNode(this.state.tag.prefix + suggestion)); - } else { - this.input.set.call(this, suggestion); - this.setRangeAtStartEnd(); - } - - this.input.autocomplete.suggest.call(this); - this.dropdown.hide.call(this); - return true; - } - - return false; - } - } - }, - getNodeIndex: function getNodeIndex(node) { - var index = 0; - if (node) while (node = node.previousElementSibling) { - index++; - } - return index; - }, - getTagElms: function getTagElms() { - return this.DOM.scope.querySelectorAll('.tagify__tag'); - }, - getLastTag: function getLastTag() { - var lastTag = this.DOM.scope.querySelectorAll('tag:not(.tagify--hide):not([readonly])'); - return lastTag[lastTag.length - 1]; - }, - - /** - * Searches if any tag with a certain value already exis - * @param {String/Object} v [text value / tag data object] - * @return {Boolean} - */ - isTagDuplicate: function isTagDuplicate(v, uid) { - var _this9 = this; - - // duplications are irrelevant for this scenario - if (this.settings.mode == 'select') return false; - return this.value.some(function (item) { - return (// if this item has the same uid as the one checked, it cannot be a duplicate of itself. - // most of the time uid will be "undefined" - item.__tagifyId == uid ? false : _this9.isObject(v) ? JSON.stringify(item).toLowerCase() === JSON.stringify(v).toLowerCase() : v.trim().toLowerCase() === item.value.toLowerCase() - ); - }); - }, - getTagIndexByValue: function getTagIndexByValue(value) { - var result = []; - this.getTagElms().forEach(function (tagElm, i) { - if (tagElm.textContent.trim().toLowerCase() == value.toLowerCase()) result.push(i); - }); - return result; - }, - getTagElmByValue: function getTagElmByValue(value) { - var tagIdx = this.getTagIndexByValue(value)[0]; - return this.getTagElms()[tagIdx]; - }, - - /** - * Mark a tag element by its value - * @param {String|Number} value [text value to search for] - * @param {Object} tagElm [a specific "tag" element to compare to the other tag elements siblings] - * @return {boolean} [found / not found] - */ - markTagByValue: function markTagByValue(value, tagElm) { - tagElm = tagElm || this.getTagElmByValue(value); // check AGAIN if "tagElm" is defined - - if (tagElm) { - tagElm.classList.add('tagify--mark'); - setTimeout(function () { - tagElm.classList.remove('tagify--mark'); - }, 100); - return tagElm; - } - - return false; - }, - - /** - * make sure the tag, or words in it, is not in the blacklist - */ - isTagBlacklisted: function isTagBlacklisted(v) { - v = v.toLowerCase().trim(); - return this.settings.blacklist.filter(function (x) { - return v == x.toLowerCase(); - }).length; - }, - - /** - * make sure the tag, or words in it, is not in the blacklist - */ - isTagWhitelisted: function isTagWhitelisted(v) { - return this.settings.whitelist.some(function (item) { - return typeof v == 'string' ? v.trim().toLowerCase() === (item.value || item).toLowerCase() : JSON.stringify(item).toLowerCase() === JSON.stringify(v).toLowerCase(); - }); - }, - - /** - * validate a tag object BEFORE the actual tag will be created & appeneded - * @param {String} s - * @param {String} uid [unique ID, to not inclue own tag when cheking for duplicates] - * @return {Boolean/String} ["true" if validation has passed, String for a fail] - */ - validateTag: function validateTag(s, uid) { - var value = s.trim(), - _s = this.settings, - result = true; // check for empty value - - if (!value) result = this.TEXTS.empty; // check if pattern should be used and if so, use it to test the value - else if (_s.pattern && !_s.pattern.test(value)) result = this.TEXTS.pattern; // if duplicates are not allowed and there is a duplicate - else if (!_s.duplicates && this.isTagDuplicate(value, uid)) result = this.TEXTS.duplicate;else if (this.isTagBlacklisted(value) || _s.enforceWhitelist && !this.isTagWhitelisted(value)) result = this.TEXTS.notAllowed; - return result; - }, - getInvaildTagParams: function getInvaildTagParams(tagData, validation) { - return { - "aria-invalid": true, - "class": (tagData["class"] || '') + ' tagify--notAllowed', - "title": validation - }; - }, - hasMaxTags: function hasMaxTags() { - if (this.value.length >= this.settings.maxTags) return this.TEXTS.exceed; - return false; - }, - - /** - * pre-proccess the tagsItems, which can be a complex tagsItems like an Array of Objects or a string comprised of multiple words - * so each item should be iterated on and a tag created for. - * @return {Array} [Array of Objects] - */ - normalizeTags: function normalizeTags(tagsItems) { - var _this$settings = this.settings, - whitelist = _this$settings.whitelist, - delimiters = _this$settings.delimiters, - mode = _this$settings.mode, - whitelistWithProps = whitelist ? whitelist[0] instanceof Object : false, - isArray = tagsItems instanceof Array, - isCollection = isArray && tagsItems[0] instanceof Object && "value" in tagsItems[0], - temp = [], - mapStringToCollection = function mapStringToCollection(s) { - return (s + "").split(delimiters).filter(function (n) { - return n; - }).map(function (v) { - return { - value: v.trim() - }; - }); - }; // no need to continue if "tagsItems" is an Array of Objects - - - if (isCollection) { - var _ref2; - - // iterate the collection items and check for values that can be splitted into multiple tags - tagsItems = (_ref2 = []).concat.apply(_ref2, _toConsumableArray(tagsItems.map(function (item) { - return mapStringToCollection(item.value).map(function (newItem) { - return _objectSpread({}, item, {}, newItem); - }); - }))); - return tagsItems; - } - - if (typeof tagsItems == 'number') tagsItems = tagsItems.toString(); // if the value is a "simple" String, ex: "aaa, bbb, ccc" - - if (typeof tagsItems == 'string') { - if (!tagsItems.trim()) return []; // go over each tag and add it (if there were multiple ones) - - tagsItems = mapStringToCollection(tagsItems); - } else if (isArray) { - var _ref3; - - tagsItems = (_ref3 = []).concat.apply(_ref3, _toConsumableArray(tagsItems.map(function (item) { - return mapStringToCollection(item); - }))); - } // search if the tag exists in the whitelist as an Object (has props), - // to be able to use its properties - - - if (whitelistWithProps) { - tagsItems.forEach(function (item) { - // the "value" prop should preferably be unique - var matchObj = whitelist.filter(function (WL_item) { - return WL_item.value.toLowerCase() == item.value.toLowerCase(); - }); - - if (matchObj[0]) { - temp.push(matchObj[0]); // set the Array (with the found Object) as the new value - } else if (mode != 'mix') temp.push(item); - }); - tagsItems = temp; - } - - return tagsItems; - }, - - /** - * Used to parse the initial value of a textarea (or input) element and gemerate mixed text w/ tags - * https://stackoverflow.com/a/57598892/104380 - * @param {String} s - */ - parseMixTags: function parseMixTags(s) { - var _this10 = this; - - var _this$settings2 = this.settings, - mixTagsInterpolator = _this$settings2.mixTagsInterpolator, - duplicates = _this$settings2.duplicates, - transformTag = _this$settings2.transformTag, - enforceWhitelist = _this$settings2.enforceWhitelist; - s = s.split(mixTagsInterpolator[0]).map(function (s1, i) { - var s2 = s1.split(mixTagsInterpolator[1]), - preInterpolated = s2[0], - tagData, - tagElm; - - try { - tagData = JSON.parse(preInterpolated); - } catch (err) { - tagData = _this10.normalizeTags(preInterpolated)[0]; //{value:preInterpolated} - } - - if (s2.length > 1 && (!enforceWhitelist || _this10.isTagWhitelisted(tagData.value)) && !(!duplicates && _this10.isTagDuplicate(tagData))) { - transformTag.call(_this10, tagData); - tagData.__tagifyId = getUID(); - tagElm = _this10.createTagElem(tagData); - tagElm.classList.add('tagify--noAnim'); - tagElm.__tagifyId = tagData.__tagifyId; - _this10.tagsDataById[tagElm.__tagifyId] = tagData; - s2[0] = tagElm.outerHTML; //+ "⁠" // put a zero-space at the end so the caret won't jump back to the start (when the last input's child element is a tag) - - _this10.value.push(tagData); - } else if (s1) return i ? mixTagsInterpolator[0] + s1 : s1; - - return s2.join(''); - }).join(''); - this.DOM.input.innerHTML = s; - this.DOM.input.appendChild(document.createTextNode('')); - this.update(); - return s; - }, - - /** - * For mixed-mode: replaces a text starting with a prefix with a wrapper element (tag or something) - * First there *has* to be a "this.state.tag" which is a string that was just typed and is staring with a prefix - */ - replaceTextWithNode: function replaceTextWithNode(wrapperElm, tagString) { - if (!this.state.tag && !tagString) return; - tagString = tagString || this.state.tag.prefix + this.state.tag.value; - var idx, - replacedNode, - selection = this.state.selection || window.getSelection(), - nodeAtCaret = selection.anchorNode; // ex. replace #ba with the tag "bart" where "|" is where the caret is: - // start with: "#ba #ba| #ba" - // split the text node at the index of the caret - - nodeAtCaret.splitText(selection.anchorOffset); // "#ba #ba" - // get index of last occurence of "#ba" - - idx = nodeAtCaret.nodeValue.lastIndexOf(tagString); - replacedNode = nodeAtCaret.splitText(idx); // clean up the tag's string and put tag element instead - - replacedNode.nodeValue = replacedNode.nodeValue.replace(tagString, ''); - nodeAtCaret.parentNode.insertBefore(wrapperElm, replacedNode); - this.DOM.input.normalize(); - return replacedNode; - }, - - /** - * For selecting a single option (not used for multiple tags) - * @param {Object} tagElm Tag DOM node - * @param {Object} tagData Tag data - */ - selectTag: function selectTag(tagElm, tagData) { - this.input.set.call(this, tagData.value, true); // place the caret at the end of the input, only if a dropdown option was selected (and not by manually typing another value and clicking "TAB") - - if (this.state.actions.selectOption) setTimeout(this.setRangeAtStartEnd.bind(this)); - if (this.getLastTag()) this.replaceTag(this.getLastTag(), tagData);else this.appendTag(tagElm); - this.value[0] = tagData; - this.trigger('add', { - tag: tagElm, - data: tagData - }); - this.update(); - return [tagElm]; - }, - - /** - * add an empty "tag" element in an editable state - */ - addEmptyTag: function addEmptyTag() { - var tagData = { - value: "", - __tagifyId: getUID() - }, - tagElm = this.createTagElem(tagData); // must be assigned ASAP, before "validateTag" method below - - this.tagsDataById[tagData.__tagifyId] = tagData; - tagElm.__tagifyId = tagData.__tagifyId; // add the tag to the component's DOM - - this.appendTag(tagElm); - this.editTag(tagElm, { - skipValidation: true - }); - }, - - /** - * add a "tag" element to the "tags" component - * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings] - * @param {Boolean} clearInput [flag if the input's value should be cleared after adding tags] - * @param {Boolean} skipInvalid [do not add, mark & remove invalid tags] - * @return {Array} Array of DOM elements (tags) - */ - addTags: function addTags(tagsItems, clearInput) { - var _this11 = this; - - var skipInvalid = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.settings.skipInvalid; - var tagElems = [], - tagElm, - _s = this.settings; - - if (!tagsItems || tagsItems.length == 0) { - // is mode is "select" clean all tags - if (_s.mode == 'select') this.removeAllTags(); - return tagElems; - } // converts Array/String/Object to an Array of Objects - - - tagsItems = this.normalizeTags(tagsItems); // if in edit-mode, do not continue but instead replace the tag's text - - if (this.state.editing.scope) { - return this.onEditTagDone(this.state.editing.scope, tagsItems[0]); - } - - if (_s.mode == 'mix') { - _s.transformTag.call(this, tagsItems[0]); - - tagElm = this.createTagElem(tagsItems[0]); // insert the new tag to the END if "addTags" was called from outside - - if (!this.replaceTextWithNode(tagElm)) { - this.DOM.input.appendChild(tagElm); - } // fixes a firefox bug where if the last child of the input is a tag and not a text, the input cannot get focus (by Tab key) - - - this.DOM.input.appendChild(document.createTextNode('')); - setTimeout(function () { - return tagElm.classList.add('tagify--noAnim'); - }, 300); - tagsItems[0].prefix = tagsItems[0].prefix || this.state.tag ? this.state.tag.prefix : (_s.pattern.source || _s.pattern)[0]; - this.value.push(tagsItems[0]); - this.update(); - this.state.tag = null; - this.trigger('add', this.extend({}, { - tag: tagElm - }, { - data: tagsItems[0] - })); // fixes a firefox bug where if the last child of the input is a tag and not a text, the input cannot get focus (by Tab key) - - this.DOM.input.appendChild(document.createTextNode('')); - return tagElm; - } - - if (_s.mode == 'select') clearInput = false; - this.DOM.input.removeAttribute('style'); - tagsItems.forEach(function (tagData) { - var tagValidation, - tagElm, - tagElmParams = {}; // shallow-clone tagData so later modifications will not apply to the source - - tagData = Object.assign({}, tagData); // generate unique ID for this tag, not to keep the data object on the DOM node itself - - tagData.__tagifyId = getUID(); // must be assigned ASAP, before "validateTag" method below - - _this11.tagsDataById[tagData.__tagifyId] = tagData; - - _s.transformTag.call(_this11, tagData); ///////////////// ( validation )////////////////////// - - - tagValidation = _this11.hasMaxTags() || _this11.validateTag(tagData.value); - - if (tagValidation !== true) { - if (skipInvalid) return; - - _this11.extend(tagElmParams, _this11.getInvaildTagParams(tagData, tagValidation)); // mark, for a brief moment, the tag this current tag is a duplcate of - - - if (tagValidation == _this11.TEXTS.duplicate) _this11.markTagByValue(tagData.value); - } ///////////////////////////////////////////////////// - // add accessibility attributes - - - tagElmParams.role = "tag"; - if (tagData.readonly) tagElmParams["aria-readonly"] = true; // Create tag HTML element - - tagElm = _this11.createTagElem(_this11.extend({}, tagData, tagElmParams)); - tagElm.__tagifyId = tagData.__tagifyId; - tagElems.push(tagElm); // mode-select overrides - - if (_s.mode == 'select') { - return _this11.selectTag(tagElm, tagData); - } // add the tag to the component's DOM - - - _this11.appendTag(tagElm); - - if (tagValidation === true) { - // update state - _this11.value.push(tagData); - - _this11.update(); - - _this11.trigger('add', { - tag: tagElm, - index: _this11.value.length - 1, - data: tagData - }); - } else { - _this11.trigger("invalid", { - data: tagData, - index: _this11.value.length, - tag: tagElm, - message: tagValidation - }); - - if (!_s.keepInvalidTags) // remove invalid tags (if "keepInvalidTags" is set to "false") - setTimeout(function () { - return _this11.removeTag(tagElm, true); - }, 1000); - } - - _this11.dropdown.position.call(_this11); // reposition the dropdown because the just-added tag might cause a new-line - - }); - - if (tagsItems.length && clearInput) { - this.input.set.call(this); - } - - this.dropdown.refilter.call(this); - return tagElems; - }, - - /** - * appened (validated) tag to the component's DOM scope - */ - appendTag: function appendTag(tagElm) { - var insertBeforeNode = this.DOM.scope.lastElementChild; - if (insertBeforeNode === this.DOM.input) this.DOM.scope.insertBefore(tagElm, insertBeforeNode);else this.DOM.scope.appendChild(tagElm); - }, - - /** - * Removed new lines and irrelevant spaces which might affect layout, and are better gone - * @param {string} s [HTML string] - */ - minify: function minify(s) { - return s ? s.replace(/\>[\r\n ]+\<").replace(/(<.*?>)|\s+/g, function (m, $1) { - return $1 ? $1 : ' '; - }) // https://stackoverflow.com/a/44841484/104380 - : ""; - }, - - /** - * creates a DOM tag element and injects it into the component (this.DOM.scope) - * @param {Object} tagData [text value & properties for the created tag] - * @return {Object} [DOM element] - */ - createTagElem: function createTagElem(tagData) { - var tagElm, - v = escapeHTML(tagData.value), - template = this.settings.templates.tag.call(this, v, tagData); - if (this.settings.readonly) tagData.readonly = true; - template = this.minify(template); - tagElm = this.parseHTML(template); - return tagElm; - }, - reCheckInvalidTags: function reCheckInvalidTags() { - var _this12 = this; - - // find all invalid tags and re-check them - var tagElms = this.DOM.scope.querySelectorAll('.tagify__tag.tagify--notAllowed'); - [].forEach.call(tagElms, function (node) { - var nodeData = _this12.tagsDataById[node.__tagifyId], - wasNodeDuplicate = node.getAttribute('title') == _this12.TEXTS.duplicate, - isNodeValid = _this12.validateTag(nodeData.value, nodeData.__tagifyId) === true; // if this tag node was marked as a dulpicate, unmark it (it might have been marked as "notAllowed" for other reasons) - - - if (wasNodeDuplicate && isNodeValid) { - node.isValid = true; - - _this12.replaceTag(node, nodeData); - } - }); - }, - - /** - * Removes a tag - * @param {Object|String} tagElm [DOM element or a String value. if undefined or null, remove last added tag] - * @param {Boolean} silent [A flag, which when turned on, does not removes any value and does not update the original input value but simply removes the tag from tagify] - * @param {Number} tranDuration [Transition duration in MS] - */ - removeTag: function removeTag(tagElm, silent, tranDuration) { - tagElm = tagElm || this.getLastTag(); - tranDuration = tranDuration || this.CSSVars.tagHideTransition; - if (typeof tagElm == 'string') tagElm = this.getTagElmByValue(tagElm); - if (!(tagElm instanceof HTMLElement)) return; - var that = this, - uid = tagElm.__tagifyId, - tagIdx = this.getNodeIndex(tagElm); // this.getTagIndexByValue(tagElm.textContent) - - if (this.settings.mode == 'select') { - tranDuration = 0; - this.input.set.call(this); - } - - if (tagElm.classList.contains('tagify--notAllowed')) silent = true; - - function removeNode() { - if (!tagElm.parentNode) return; - tagElm.parentNode.removeChild(tagElm); - - if (!silent) { - that.removeValueById(uid); - delete that.tagsDataById[uid]; - that.update(); // update the original input with the current value - - that.trigger('remove', { - tag: tagElm, - index: tagIdx, - data: that.tagsDataById[uid] - }); - that.dropdown.refilter.call(that); - that.dropdown.position.call(that); // check if any of the current tags which might have been marked as "duplicate" should be now un-marked - - if (that.settings.keepInvalidTags) that.reCheckInvalidTags(); - } else if (that.settings.keepInvalidTags) that.trigger('remove', { - tag: tagElm, - index: tagIdx - }); - } - - function animation() { - tagElm.style.width = parseFloat(window.getComputedStyle(tagElm).width) + 'px'; - document.body.clientTop; // force repaint for the width to take affect before the "hide" class below - - tagElm.classList.add('tagify--hide'); // manual timeout (hack, since transitionend cannot be used because of hover) - - setTimeout(removeNode, tranDuration); - } - - if (tranDuration && tranDuration > 10) animation();else removeNode(); - }, - removeAllTags: function removeAllTags() { - this.value = []; - this.update(); - Array.prototype.slice.call(this.getTagElms()).forEach(function (elm) { - return elm.parentNode.removeChild(elm); - }); - this.dropdown.position.call(this); - if (this.settings.mode == 'select') this.input.set.call(this); - }, - - /** - * Removes an item in "this.value" by its UID - * @param {String} uid - */ - removeValueById: function removeValueById(uid) { - this.value = this.value.filter(function (item) { - return item.__tagifyId != uid; - }); - }, - preUpdate: function preUpdate() { - this.DOM.scope.classList.toggle('tagify--hasMaxTags', this.value.length >= this.settings.maxTags); - this.DOM.scope.classList.toggle('tagify--noTags', !this.value.length); - }, - - /** - * update the origianl (hidden) input field's value - * see - https://stackoverflow.com/q/50957841/104380 - */ - update: function update() { - this.preUpdate(); - var value = removeCollectionProp(this.value, "__tagifyId"); - this.DOM.originalInput.value = this.settings.mode == 'mix' ? this.getMixedTagsAsString(value) : this.value.length ? JSON.stringify(value) : ""; - }, - getMixedTagsAsString: function getMixedTagsAsString(value) { - var result = "", - i = 0, - currentTags = value, - _interpolator = this.settings.mixTagsInterpolator; - - function iterateChildren(rootNode) { - rootNode.childNodes.forEach(function (node) { - if (node.nodeType == 1) { - if (node.classList.contains("tagify__tag")) { - result += _interpolator[0] + JSON.stringify(currentTags[i++]) + _interpolator[1]; - return; - } // Chrome adds

for empty new lines, and FF only adds
- - - if (isFirefox && node.tagName == 'BR') result += "\r\n";else if (node.tagName == 'DIV') { - result += "\r\n"; - iterateChildren(node); - } - } else result += node.textContent; - }); - } - - iterateChildren(this.DOM.input); - return result; - }, - - /** - * Meassures an element's height, which might yet have been added DOM - * https://stackoverflow.com/q/5944038/104380 - * @param {DOM} node - */ - getNodeHeight: function getNodeHeight(node) { - var height, - clone = node.cloneNode(true); - clone.style.cssText = "position:fixed; top:-9999px; opacity:0"; - document.body.appendChild(clone); - height = clone.clientHeight; - clone.parentNode.removeChild(clone); - return height; - }, - - /** - * Dropdown controller - * @type {Object} - */ - dropdown: { - init: function init() { - this.DOM.dropdown = this.dropdown.build.call(this); - this.DOM.dropdown.content = this.DOM.dropdown.querySelector('.tagify__dropdown__wrapper'); - }, - build: function build() { - var _this$settings$dropdo = this.settings.dropdown, - position = _this$settings$dropdo.position, - classname = _this$settings$dropdo.classname, - _className = "".concat(position == 'manual' ? "" : "tagify__dropdown tagify__dropdown--".concat(position), " ").concat(classname).trim(), - elm = this.parseHTML("
\n
\n
")); - - return elm; - }, - show: function show(value) { - var _this13 = this; - - var HTMLContent, - _s = this.settings, - firstListItem, - firstListItemValue, - ddHeight, - selection = window.getSelection(), - isManual = _s.dropdown.position == 'manual'; - if (!_s.whitelist || !_s.whitelist.length || _s.dropdown.enable === false) return; // if no value was supplied, show all the "whitelist" items in the dropdown - // @type [Array] listItems - // TODO: add a Setting to control items' sort order for "listItems" - - this.suggestedListItems = this.dropdown.filterListItems.call(this, value); - - if (!this.suggestedListItems.length) { - // in mix-mode, if the value isn't included in the whilelist & "enforceWhitelist" setting is "false", - // then add a custom suggestion item to the dropdown - if (_s.mode == 'mix' && !_s.enforceWhitelist) { - this.suggestedListItems = [{ - value: value - }]; - } // hide suggestions list if no suggestions were matched & cleanup - else { - this.input.autocomplete.suggest.call(this); - this.dropdown.hide.call(this); - return; - } - } - - firstListItem = this.suggestedListItems[0]; - firstListItemValue = firstListItem.value || firstListItem; - - if (_s.autoComplete) { - // only fill the sugegstion if the value of the first list item STARTS with the input value (regardless of "fuzzysearch" setting) - if (firstListItemValue.indexOf(value) == 0) this.input.autocomplete.suggest.call(this, firstListItem); - } - - HTMLContent = this.dropdown.createListHTML.call(this, this.suggestedListItems); - this.DOM.dropdown.content.innerHTML = this.minify(HTMLContent); // if "enforceWhitelist" is "true", highlight the first suggested item - - if (_s.enforceWhitelist && !isManual || _s.dropdown.highlightFirst) this.dropdown.highlightOption.call(this, this.DOM.dropdown.content.children[0]); - this.DOM.scope.setAttribute("aria-expanded", true); - this.trigger("dropdown:show", this.DOM.dropdown); // set the dropdown visible state to be the same as the searched value. - // MUST be set *before* position() is called - - this.state.dropdown.visible = value || true; - this.state.selection = { - anchorOffset: selection.anchorOffset, - anchorNode: selection.anchorNode - }; - this.dropdown.position.call(this); // if the dropdown has yet to be appended to the document, - // append the dropdown to the body element & handle events - - if (!document.body.contains(this.DOM.dropdown)) { - if (!isManual) { - this.events.binding.call(this, false); // unbind the main events - // let the element render in the DOM first to accurately measure it - // this.DOM.dropdown.style.cssText = "left:-9999px; top:-9999px;"; - - ddHeight = this.getNodeHeight(this.DOM.dropdown); - this.DOM.dropdown.classList.add('tagify__dropdown--initial'); - this.dropdown.position.call(this, ddHeight); - document.body.appendChild(this.DOM.dropdown); - setTimeout(function () { - return _this13.DOM.dropdown.classList.remove('tagify__dropdown--initial'); - }); - } // timeout is needed for when pressing arrow down to show the dropdown, - // so the key event won't get registered in the dropdown events listeners - - - setTimeout(this.dropdown.events.binding.bind(this)); - } - }, - hide: function hide(force) { - var _this$DOM = this.DOM, - scope = _this$DOM.scope, - dropdown = _this$DOM.dropdown, - isManual = this.settings.dropdown.position == 'manual' && !force; - if (!dropdown || !document.body.contains(dropdown) || isManual) return; - window.removeEventListener('resize', this.dropdown.position); - this.dropdown.events.binding.call(this, false); // unbind all events - // must delay because if the dropdown is open, and the input (scope) is clicked, - // the dropdown should be now closed, and the next click should re-open it, - // and without this timeout, clicking to close will re-open immediately - - setTimeout(this.events.binding.bind(this), 250); // re-bind main events - - scope.setAttribute("aria-expanded", false); - dropdown.parentNode.removeChild(dropdown); - this.state.dropdown.visible = false; - this.state.ddItemData = this.state.ddItemElm = this.state.selection = null; - this.trigger("dropdown:hide", dropdown); - }, - - /** - * fill data into the suggestions list (mainly used to update the list when removing tags, so they will be re-added to the list. not efficient) - */ - refilter: function refilter() { - this.suggestedListItems = this.dropdown.filterListItems.call(this, ''); - var listHTML = this.dropdown.createListHTML.call(this, this.suggestedListItems); - this.DOM.dropdown.content.innerHTML = this.minify(listHTML); - this.trigger("dropdown:updated", this.DOM.dropdown); - }, - position: function position(ddHeight) { - var isBelowViewport, - rect, - top, - bottom, - left, - width, - ddElm = this.DOM.dropdown; - if (!this.state.dropdown.visible) return; - - if (this.settings.dropdown.position == 'text') { - rect = this.getCaretGlobalPosition(); - bottom = rect.bottom; - top = rect.top; - left = rect.left; - width = 'auto'; - } else { - rect = this.DOM.scope.getBoundingClientRect(); - top = rect.top; - bottom = rect.bottom - 1; - left = rect.left; - width = rect.width + "px"; - } - - top = Math.floor(top); - bottom = Math.ceil(bottom); - isBelowViewport = document.documentElement.clientHeight - bottom < (ddHeight || ddElm.clientHeight); // flip vertically if there is no space for the dropdown below the input - - ddElm.style.cssText = "left:" + (left + window.pageXOffset) + "px; width:" + width + ";" + (isBelowViewport ? "bottom:" + (document.documentElement.clientHeight - top - window.pageYOffset - 2) + "px;" : "top: " + (bottom + window.pageYOffset) + "px"); - ddElm.setAttribute('placement', isBelowViewport ? "top" : "bottom"); - }, - events: { - /** - * Events should only be binded when the dropdown is rendered and removed when isn't - * @param {Boolean} bindUnbind [optional. true when wanting to unbind all the events] - */ - binding: function binding() { - var bindUnbind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; - - // references to the ".bind()" methods must be saved so they could be unbinded later - var _CB = this.dropdown.events.callbacks, - _CBR = this.listeners.dropdown = this.listeners.dropdown || { - position: this.dropdown.position.bind(this), - onKeyDown: _CB.onKeyDown.bind(this), - onMouseOver: _CB.onMouseOver.bind(this), - onMouseLeave: _CB.onMouseLeave.bind(this), - onClick: _CB.onClick.bind(this), - onScroll: _CB.onScroll.bind(this) - }, - action = bindUnbind ? 'addEventListener' : 'removeEventListener'; - - if (this.settings.dropdown.position != 'manual') { - window[action]('resize', _CBR.position); - window[action]('keydown', _CBR.onKeyDown); - } // window[action]('mousedown', _CBR.onClick); - - - this.DOM.dropdown[action]('mouseover', _CBR.onMouseOver); - this.DOM.dropdown[action]('mouseleave', _CBR.onMouseLeave); - this.DOM.dropdown[action]('mousedown', _CBR.onClick); - this.DOM.dropdown.content[action]('scroll', _CBR.onScroll); // add back the main "click" event because it is needed for removing/clicking already-existing tags, even if dropdown is shown - - this.DOM[this.listeners.main.click[0]][action]('click', this.listeners.main.click[1]); - }, - callbacks: { - onKeyDown: function onKeyDown(e) { - // get the "active" element, and if there was none (yet) active, use first child - var activeListElm = this.DOM.dropdown.querySelector("[class$='--active']"), - selectedElm = activeListElm; - - switch (e.key) { - case 'ArrowDown': - case 'ArrowUp': - case 'Down': // >IE11 - - case 'Up': - { - // >IE11 - e.preventDefault(); - var dropdownItems; - if (selectedElm) selectedElm = selectedElm[(e.key == 'ArrowUp' || e.key == 'Up' ? "previous" : "next") + "ElementSibling"]; // if no element was found, loop - - if (!selectedElm) { - dropdownItems = this.DOM.dropdown.content.children; - selectedElm = dropdownItems[e.key == 'ArrowUp' || e.key == 'Up' ? dropdownItems.length - 1 : 0]; - } - - this.dropdown.highlightOption.call(this, selectedElm, true); - break; - } - - case 'Escape': - case 'Esc': - // IE11 - this.dropdown.hide.call(this); - break; - - case 'ArrowRight': - if (this.state.actions.ArrowLeft) return; - - case 'Tab': - { - // in mix-mode, treat arrowRight like Enter key, so a tag will be created - if (this.settings.mode != 'mix' && !this.settings.autoComplete.rightKey) { - try { - var value = selectedElm ? selectedElm.textContent : this.suggestedListItems[0].value; - this.input.autocomplete.set.call(this, value); - } catch (err) {} - - return false; - } - } - - case 'Enter': - { - e.preventDefault(); - this.dropdown.selectOption.call(this, activeListElm); - break; - } - - case 'Backspace': - { - if (this.settings.mode == 'mix' || this.state.editing.scope) return; - - var _value = this.input.value.trim(); - - if (_value == "" || _value.charCodeAt(0) == 8203) { - if (this.settings.backspace === true) this.removeTag();else if (this.settings.backspace == 'edit') setTimeout(this.editTag.bind(this), 0); - } - } - } - }, - onMouseOver: function onMouseOver(e) { - var ddItem = e.target.closest('.tagify__dropdown__item'); // event delegation check - - ddItem && this.dropdown.highlightOption.call(this, ddItem); - }, - onMouseLeave: function onMouseLeave(e) { - // de-highlight any previously highlighted option - this.dropdown.highlightOption.call(this); - }, - onClick: function onClick(e) { - if (e.button != 0 || e.target == this.DOM.dropdown) return; // allow only mouse left-clicks - - var listItemElm = e.target.closest(".tagify__dropdown__item"); - this.dropdown.selectOption.call(this, listItemElm); - }, - onScroll: function onScroll(e) { - var elm = e.target, - pos = elm.scrollTop / (elm.scrollHeight - elm.parentNode.clientHeight) * 100; - this.trigger("dropdown:scroll", { - percentage: Math.round(pos) - }); - } - } - }, - - /** - * mark the currently active suggestion option - * @param {Object} elm option DOM node - * @param {Boolean} adjustScroll when navigation with keyboard arrows (up/down), aut-scroll to always show the highlighted element - */ - highlightOption: function highlightOption(elm, adjustScroll) { - var className = "tagify__dropdown__item--active", - itemData; // focus casues a bug in Firefox with the placeholder been shown on the input element - // if( this.settings.dropdown.position != 'manual' ) - // elm.focus(); - - if (this.state.ddItemElm) { - this.state.ddItemElm.classList.remove(className); - this.state.ddItemElm.removeAttribute("aria-selected"); - } - - if (!elm) { - this.state.ddItemData = null; - this.state.ddItemElm = null; - this.input.autocomplete.suggest.call(this); - return; - } - - itemData = this.suggestedListItems[this.getNodeIndex(elm)]; - this.state.ddItemData = itemData; - this.state.ddItemElm = elm; // this.DOM.dropdown.querySelectorAll("[class$='--active']").forEach(activeElm => activeElm.classList.remove(className)); - - elm.classList.add(className); - elm.setAttribute("aria-selected", true); - if (adjustScroll) elm.parentNode.scrollTop = elm.clientHeight + elm.offsetTop - elm.parentNode.clientHeight; // Try to autocomplete the typed value with the currently highlighted dropdown item - - if (this.settings.autoComplete) { - this.input.autocomplete.suggest.call(this, itemData); - if (this.settings.dropdown.position != 'manual') this.dropdown.position.call(this); // suggestions might alter the height of the tagify wrapper because of unkown suggested term length that could drop to the next line - } - }, - - /** - * Create a tag from the currently active suggestion option - * @param {Object} elm DOM node to select - */ - selectOption: function selectOption(elm) { - var _this14 = this; - - if (!elm) return; // temporary set the "actions" state to indicate to the main "blur" event it shouldn't run - - this.state.actions.selectOption = true; - setTimeout(function () { - return _this14.state.actions.selectOption = false; - }, 50); - var hideDropdown = this.settings.dropdown.closeOnSelect, - value = this.suggestedListItems[this.getNodeIndex(elm)] || this.input.value; - this.trigger("dropdown:select", value); - this.addTags([value], true); // Tagify instances should re-focus to the input element once an option was selected, to allow continuous typing - - setTimeout(function () { - _this14.DOM.input.focus(); - - _this14.toggleFocusClass(true); - }); - - if (hideDropdown) { - this.dropdown.hide.call(this); // setTimeout(() => this.events.callbacks.onFocusBlur.call(this, {type:"blur"}), 60) - } - }, - - /** - * returns an HTML string of the suggestions' list items - * @param {string} value string to filter the whitelist by - * @return {Array} list of filtered whitelist items according to the settings provided and current value - */ - filterListItems: function filterListItems(value) { - var _this15 = this; - - var _s = this.settings, - list = [], - whitelist = _s.whitelist, - suggestionsCount = _s.dropdown.maxItems || Infinity, - searchKeys = _s.dropdown.searchKeys.concat(["searchBy", "value"]), - whitelistItem, - valueIsInWhitelist, - whitelistItemValueIndex, - searchBy, - isDuplicate, - i = 0; - - if (!value) { - return (_s.duplicates ? whitelist : whitelist.filter(function (item) { - return !_this15.isTagDuplicate(item.value || item); - }) // don't include tags which have already been added. - ).slice(0, suggestionsCount); // respect "maxItems" dropdown setting - } - - for (; i < whitelist.length; i++) { - whitelistItem = whitelist[i] instanceof Object ? whitelist[i] : { - value: whitelist[i] - }; //normalize value as an Object - - searchBy = searchKeys.reduce(function (values, k) { - return values + " " + (whitelistItem[k] || ""); - }, "").toLowerCase(); - whitelistItemValueIndex = searchBy.indexOf(value.toLowerCase()); - valueIsInWhitelist = _s.dropdown.fuzzySearch ? whitelistItemValueIndex >= 0 : whitelistItemValueIndex == 0; - isDuplicate = !_s.duplicates && this.isTagDuplicate(whitelistItem.value); // match for the value within each "whitelist" item - - if (valueIsInWhitelist && !isDuplicate && suggestionsCount--) list.push(whitelistItem); - if (suggestionsCount == 0) break; - } - - return list; - }, - - /** - * Creates the dropdown items' HTML - * @param {Array} list [Array of Objects] - * @return {String} - */ - createListHTML: function createListHTML(optionsArr) { - var template = this.settings.templates.dropdownItem.bind(this); - return this.minify(optionsArr.map(template).join("")); - } - } -}; -return Tagify; -})); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Tagify=e()}(this,(function(){"use strict";function t(t,e,i){return e in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}function e(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);e&&(s=s.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,s)}return i}const i=(t,e,i,s)=>(t=""+t,e=""+e,s&&(t=t.trim(),e=e.trim()),i?t==e:t.toLowerCase()==e.toLowerCase());function s(t,e){var i,s={};for(i in t)e.indexOf(i)<0&&(s[i]=t[i]);return s}function a(t){var e=document.createElement("div");return t.replace(/\&#?[0-9a-z]+;/gi,(function(t){return e.innerHTML=t,e.innerText}))}function n(t,e){for(e=e||"previous";t=t[e+"Sibling"];)if(3==t.nodeType)return t}function o(t){return t.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/`|'/g,"'")}function r(t){return t instanceof Array}function l(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 d(t,e,i){function s(t,e){for(var i in e)if(e.hasOwnProperty(i)){if(l(e[i])){l(t[i])?s(t[i],e[i]):t[i]=Object.assign({},e[i]);continue}if(r(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 h(t){return String.prototype.normalize?"string"==typeof t?t.normalize("NFD").replace(/[\u0300-\u036f]/g,""):void 0:t}var g=()=>/(?=.*chrome)(?=.*android)/i.test(navigator.userAgent);var c,p={init(){this.DOM.dropdown=this.parseTemplate("dropdown",[this.settings]),this.DOM.dropdown.content=this.DOM.dropdown.querySelector(this.settings.classNames.dropdownWrapperSelector)},show(t){var e,s,a,n=this.settings,o="mix"==n.mode&&!n.enforceWhitelist,r=!n.whitelist||!n.whitelist.length,d="manual"==n.dropdown.position;if(t=void 0===t?this.state.inputText:t,(!r||o||n.templates.dropdownItemNoMatch)&&!1!==n.dropdown.enable&&!this.state.isLoading){if(clearTimeout(this.dropdownHide__bindEventsTimeout),this.suggestedListItems=this.dropdown.filterListItems.call(this,t),t&&!this.suggestedListItems.length&&(this.trigger("dropdown:noMatch",t),n.templates.dropdownItemNoMatch&&(a=n.templates.dropdownItemNoMatch.call(this,{value:t}))),!a){if(this.suggestedListItems.length)t&&o&&!this.state.editing.scope&&!i(this.suggestedListItems[0].value,t)&&this.suggestedListItems.unshift({value:t});else{if(!t||!o||this.state.editing.scope)return this.input.autocomplete.suggest.call(this),void this.dropdown.hide.call(this);this.suggestedListItems=[{value:t}]}s=""+(l(e=this.suggestedListItems[0])?e.value:e),n.autoComplete&&s&&0==s.indexOf(t)&&this.input.autocomplete.suggest.call(this,e)}this.dropdown.fill.call(this,a),n.dropdown.highlightFirst&&this.dropdown.highlightOption.call(this,this.DOM.dropdown.content.children[0]),this.state.dropdown.visible||setTimeout(this.dropdown.events.binding.bind(this)),this.state.dropdown.visible=t||!0,this.state.dropdown.query=t,this.setStateSelection(),d||setTimeout((()=>{this.dropdown.position.call(this),this.dropdown.render.call(this)})),setTimeout((()=>{this.trigger("dropdown:show",this.DOM.dropdown)}))}},hide(t){var e=this.DOM,i=e.scope,s=e.dropdown,a="manual"==this.settings.dropdown.position&&!t;if(s&&document.body.contains(s)&&!a)return window.removeEventListener("resize",this.dropdown.position),this.dropdown.events.binding.call(this,!1),i.setAttribute("aria-expanded",!1),s.parentNode.removeChild(s),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",s),this},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),a=this.settings;return this.DOM.scope.setAttribute("aria-expanded",!0),document.body.contains(this.DOM.dropdown)||(this.DOM.dropdown.classList.add(a.classNames.dropdownInital),this.dropdown.position.call(this,s),a.dropdown.appendTarget.appendChild(this.DOM.dropdown),setTimeout((()=>this.DOM.dropdown.classList.remove(a.classNames.dropdownInital)))),this},fill(t){var e;t="string"==typeof t?t:this.dropdown.createListHTML.call(this,t||this.suggestedListItems),this.DOM.dropdown.content.innerHTML=(e=t)?e.replace(/\>[\r\n ]+\<").replace(/(<.*?>)|\s+/g,((t,e)=>e||" ")):""},refilter(t){t=t||this.state.dropdown.query||"",this.suggestedListItems=this.dropdown.filterListItems.call(this,t),this.dropdown.fill.call(this),this.suggestedListItems.length||this.dropdown.hide.call(this),this.trigger("dropdown:updated",this.DOM.dropdown)},position(t){var e=this.settings.dropdown;if("manual"!=e.position){var i,s,a,n,o,r,l=this.DOM.dropdown,d=e.placeAbove,h=document.documentElement.clientHeight,g=Math.max(document.documentElement.clientWidth||0,window.innerWidth||0)>480?e.position:"all",c=this.DOM["input"==g?"input":"scope"];t=t||l.clientHeight,this.state.dropdown.visible&&("text"==g?(a=(i=this.getCaretGlobalPosition()).bottom,s=i.top,n=i.left,o="auto"):(r=function(t){for(var e=0,i=0;t;)e+=t.offsetLeft||0,i+=t.offsetTop||0,t=t.parentNode;return{left:e,top:i}}(this.settings.dropdown.appendTarget),s=(i=c.getBoundingClientRect()).top-r.top,a=i.bottom-1-r.top,n=i.left-r.left,o=i.width+"px"),s=Math.floor(s),a=Math.ceil(a),d=void 0===d?h-i.bottom{e?this.dropdown.selectOption.call(this,e):this.dropdown.hide.call(this)})).catch((t=>t));break;case"Backspace":{if("mix"==this.settings.mode||this.state.editing.scope)return;let t=this.state.inputText.trim();""!=t&&8203!=t.charCodeAt(0)||(!0===this.settings.backspace?this.removeTags():"edit"==this.settings.backspace&&setTimeout(this.editTag.bind(this),0))}}},onMouseOver(t){var e=t.target.closest(this.settings.classNames.dropdownItemSelector);e&&this.dropdown.highlightOption.call(this,e)},onMouseLeave(t){this.dropdown.highlightOption.call(this)},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.call(this,e);this.state.actions.selectOption=!0,setTimeout((()=>this.state.actions.selectOption=!1),50),this.settings.hooks.suggestionClick(t,{tagify:this,tagData:i,suggestionElm:e}).then((()=>{e?this.dropdown.selectOption.call(this,e):this.dropdown.hide.call(this)})).catch((t=>t))}},onScroll(t){var e=t.target,i=e.scrollTop/(e.scrollHeight-e.parentNode.clientHeight)*100;this.trigger("dropdown:scroll",{percentage:Math.round(i)})}}},getSuggestionDataByNode(t){var e=t?+t.getAttribute("tagifySuggestionIdx"):-1;return this.suggestedListItems[e]||null},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.suggestedListItems[this.getNodeIndex(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.call(this))},selectOption(t){var e=this.settings.dropdown,i=e.clearOnSelect,s=e.closeOnSelect;if(!t)return this.addTags(this.state.inputText,!0),void(s&&this.dropdown.hide.call(this));var a=t.getAttribute("tagifySuggestionIdx"),n=this.suggestedListItems[+a];this.trigger("dropdown:select",{data:n,elm:t}),a&&n?(this.state.editing?this.onEditTagDone(null,d({__isValid:!0},n)):this["mix"==this.settings.mode?"addMixTags":"addTags"]([n],i),setTimeout((()=>{this.DOM.input.focus(),this.toggleFocusClass(!0)})),s?setTimeout(this.dropdown.hide.bind(this)):this.dropdown.refilter.call(this)):this.dropdown.hide.call(this)},selectAll(){return this.suggestedListItems.length=0,this.dropdown.hide.call(this),this.addTags(this.dropdown.filterListItems.call(this,""),!0),this},filterListItems(t,e){var i,s,a,n,o,r=this.settings,d=r.dropdown,g=(e=e||{},t="select"==r.mode&&this.value.length&&this.value[0][r.tagTextProp]==t?"":t,[]),c=r.whitelist,p=d.maxItems||1/0,u=d.searchKeys,m=0;if(!t||!u.length)return(r.duplicates?c:c.filter((t=>!this.isTagDuplicate(l(t)?t.value:t)))).slice(0,p);function v(t,e){return e.toLowerCase().split(" ").every((e=>t.includes(e.toLowerCase())))}for(o=d.caseSensitive?""+t:(""+t).toLowerCase();mu.includes(t)))?["value"]:u;if(d.fuzzySearch&&!e.exact?(a=t.reduce(((t,e)=>t+" "+(i[e]||"")),"").toLowerCase(),d.accentedSearch&&(a=h(a),o=h(o)),s=v(a,o)):s=t.some((t=>{var s=""+(i[t]||"");return d.accentedSearch&&(s=h(s),o=h(o)),d.caseSensitive||(s=s.toLowerCase()),e.exact?s==o:0==s.indexOf(o)})),n=!r.duplicates&&this.isTagDuplicate(l(i)?i.value:i),s&&!n&&p--&&g.push(i),0==p)break}return g},getMappedValue(t){var e=this.settings.dropdown.mapValueTo;return e?"function"==typeof e?e(t):t[e]||t.value:t.value},createListHTML(t){return d([],t).map(((t,e)=>{"string"!=typeof t&&"number"!=typeof t||(t={value:t});var i=this.dropdown.getMappedValue.call(this,t);t.value=i&&"string"==typeof i?o(i):i;var s=this.settings.templates.dropdownItem.call(this,t);return s=s.replace(/\s*tagifySuggestionIdx=(["'])(.*?)\1/gim,"").replace(">",` tagifySuggestionIdx="${e}">`)})).join("")}},u={delimiters:",",pattern:null,tagTextProp:"value",maxTags:1/0,callbacks:{},addTagOnBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,keepInvalidTags:!1,mixTagsAllowedAfter:/,|\.|\:|\s/,mixTagsInterpolator:["[[","]]"],backspace:!0,skipInvalid:!1,editTags:{clicks:2,keepInvalid:!0},transformTag:()=>{},trim:!0,a11y:{focusableTags:!1},mixMode:{insertAfterTag:" "},autoComplete:{enabled:!0,rightKey:!1},classNames:{namespace:"tagify",mixMode:"tagify--mix",selectMode:"tagify--select",input:"tagify__input",focus:"tagify--focus",tag:"tagify__tag",tagNoAnimation:"tagify--noAnim",tagInvalid:"tagify--invalid",tagNotAllowed:"tagify--notAllowed",inputInvalid:"tagify__input--invalid",tagX:"tagify__tag__removeBtn",tagText:"tagify__tag-text",dropdown:"tagify__dropdown",dropdownWrapper:"tagify__dropdown__wrapper",dropdownItem:"tagify__dropdown__item",dropdownItemActive:"tagify__dropdown__item--active",dropdownInital:"tagify__dropdown--initial",scopeLoading:"tagify--loading",tagLoading:"tagify__tag--loading",tagEditing:"tagify__tag--editable",tagFlash:"tagify__tag--flash",tagHide:"tagify__tag--hide",hasMaxTags:"tagify--hasMaxTags",hasNoTags:"tagify--noTags",empty:"tagify--empty"},dropdown:{classname:"",enabled:2,maxItems:10,searchKeys:["value","searchBy"],fuzzySearch:!0,caseSensitive:!1,accentedSearch:!0,highlightFirst:!1,closeOnSelect:!0,clearOnSelect:!0,position:"all",appendTarget:null},hooks:{beforeRemoveTag:()=>Promise.resolve(),beforePaste:()=>Promise.resolve(),suggestionClick:()=>Promise.resolve()}},m={wrapper:(t,e)=>`\n \n `,tag(t){return`\n \n
\n ${t[this.settings.tagTextProp]||t.value}\n
\n
`},dropdown(t){var e=t.dropdown,i="manual"==e.position,s=`${t.classNames.dropdown}`;return`
\n
\n
`},dropdownItem(t){return`
${t.value}
`},dropdownItemNoMatch:null};var v={customBinding(){this.customEventsList.forEach((t=>{this.on(t,this.settings.callbacks[t])}))},binding(t=!0){var e,i=this.events.callbacks,s=t?"addEventListener":"removeEventListener";if(!this.state.mainEvents||!t)for(var a in this.state.mainEvents=t,t&&!this.listeners.main&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",i[this.isIE?"onInputIE":"onInput"].bind(this)),window.addEventListener("keydown",i.onWindowKeyDown.bind(this)),this.settings.isJQueryPlugin&&jQuery(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this))),e=this.listeners.main=this.listeners.main||{focus:["input",i.onFocusBlur.bind(this)],blur:["input",i.onFocusBlur.bind(this)],keydown:["input",i.onKeydown.bind(this)],click:["scope",i.onClickScope.bind(this)],dblclick:["scope",i.onDoubleClickScope.bind(this)],paste:["input",i.onPaste.bind(this)]})("blur"!=a||t)&&this.DOM[e[a][0]][s](a,e[a][1])},callbacks:{onFocusBlur(t){var e=t.target?this.trim(t.target.textContent):"",i=this.settings,s=t.type,a=i.dropdown.enabled>=0,n={relatedTarget:t.relatedTarget},o=this.state.actions.selectOption&&(a||!i.dropdown.closeOnSelect),r=this.state.actions.addNew&&a,l=t.relatedTarget&&t.relatedTarget.classList.contains(i.classNames.tag)&&this.DOM.scope.contains(t.relatedTarget);if("blur"==s){if(t.relatedTarget===this.DOM.scope)return this.dropdown.hide.call(this),void this.DOM.input.focus();this.postUpdate(),this.triggerChangeEvent()}if(!o&&!r)if(this.state.hasFocus="focus"==s&&+new Date,this.toggleFocusClass(this.state.hasFocus),"mix"!=i.mode){if("focus"==s)return this.trigger("focus",n),void(0===i.dropdown.enabled&&this.dropdown.show.call(this));"blur"==s&&(this.trigger("blur",n),this.loading(!1),"select"==this.settings.mode&&l&&(e=""),("select"==this.settings.mode&&e?!this.value.length||this.value[0].value!=e:e&&!this.state.actions.selectOption&&i.addTagOnBlur)&&this.addTags(e,!0),"select"!=this.settings.mode||e||this.removeTags()),this.DOM.input.removeAttribute("style"),this.dropdown.hide.call(this)}else"focus"==s?this.trigger("focus",n):"blur"==t.type&&(this.trigger("blur",n),this.loading(!1),this.dropdown.hide.call(this),this.state.dropdown.visible=void 0,this.setStateSelection())},onWindowKeyDown(t){var e,i=document.activeElement;if(i.classList.contains(this.settings.classNames.tag)&&this.DOM.scope.contains(document.activeElement))switch(e=i.nextElementSibling,t.key){case"Backspace":this.removeTags(i),(e||this.DOM.input).focus();break;case"Enter":setTimeout(this.editTag.bind(this),0,i)}},onKeydown(t){var e=this.trim(t.target.textContent);if(this.trigger("keydown",{originalEvent:this.cloneEvent(t)}),"mix"==this.settings.mode){switch(t.key){case"Left":case"ArrowLeft":this.state.actions.ArrowLeft=!0;break;case"Delete":case"Backspace":if(this.state.editing)return;var i,s,o,r=document.getSelection(),l="Delete"==t.key&&r.anchorOffset==(r.anchorNode.length||0),d=1==r.anchorNode.nodeType||!r.anchorOffset&&r.anchorNode.previousElementSibling,h=a(this.DOM.input.innerHTML),p=this.getTagElms();if("edit"==this.settings.backspace&&d)return i=1==r.anchorNode.nodeType?null:r.anchorNode.previousElementSibling,setTimeout(this.editTag.bind(this),0,i),void t.preventDefault();if(g()&&d)return o=n(d),d.hasAttribute("readonly")||d.remove(),this.DOM.input.focus(),void setTimeout((()=>{this.placeCaretAfterNode(o),this.DOM.input.click()}));if("BR"==r.anchorNode.nodeName)return;if((l||d)&&1==r.anchorNode.nodeType?s=0==r.anchorOffset?l?p[0]:null:p[r.anchorOffset-1]:l?s=r.anchorNode.nextElementSibling:d&&(s=d),3==r.anchorNode.nodeType&&!r.anchorNode.nodeValue&&r.anchorNode.previousElementSibling&&t.preventDefault(),(d||l)&&!this.settings.backspace)return void t.preventDefault();if("Range"!=r.type&&!r.anchorOffset&&r.anchorNode==this.DOM.input&&"Delete"!=t.key)return void t.preventDefault();if("Range"!=r.type&&s&&s.hasAttribute("readonly"))return void this.placeCaretAfterNode(n(s));clearTimeout(c),c=setTimeout((()=>{var t=document.getSelection(),e=a(this.DOM.input.innerHTML),i=t.anchorNode.previousElementSibling;if(!g()&&e.length>=h.length&&i&&!i.hasAttribute("readonly")&&(this.removeTags(i),this.fixFirefoxLastTagNoCaret(),2==this.DOM.input.children.length&&"BR"==this.DOM.input.children[1].tagName))return this.DOM.input.innerHTML="",this.value.length=0,!0;this.value=[].map.call(p,((t,e)=>{var i=this.tagData(t);if(t.parentNode||i.readonly)return i;this.trigger("remove",{tag:t,index:e,data:i})})).filter((t=>t))}),20)}return!0}switch(t.key){case"Backspace":this.state.dropdown.visible&&"manual"!=this.settings.dropdown.position||""!=e&&8203!=e.charCodeAt(0)||(!0===this.settings.backspace?this.removeTags():"edit"==this.settings.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.call(this);break;case"ArrowRight":{let t=this.state.inputSuggestion||this.state.ddItemData;if(t&&this.settings.autoComplete.rightKey)return void this.addTags([t],!0);break}case"Tab":{let i="select"==this.settings.mode;if(!e||i)return!0;t.preventDefault()}case"Enter":if(this.state.dropdown.visible||229==t.keyCode)return;t.preventDefault(),setTimeout((()=>{this.state.actions.selectOption||this.addTags(e,!0)}))}},onInput(t){if("mix"==this.settings.mode)return this.events.callbacks.onMixTagsInput.call(this,t);var e=this.input.normalize.call(this),i=e.length>=this.settings.dropdown.enabled,s={value:e,inputElm:this.DOM.input};s.isValid=this.validateTag({value:e}),this.trigger("input",s),this.state.inputText!=e&&(this.input.set.call(this,e,!1),-1!=e.search(this.settings.delimiters)?this.addTags(e)&&this.input.set.call(this):this.settings.dropdown.enabled>=0&&this.dropdown[i?"show":"hide"].call(this,e))},onMixTagsInput(t){var e,i,s,a,n,o,r,l,h=this.settings,c=this.value.length,p=this.getTagElms(),u=document.createDocumentFragment(),m=window.getSelection().getRangeAt(0),v=[].map.call(p,(t=>this.tagData(t).value));if("deleteContentBackward"==t.inputType&&g()&&this.events.callbacks.onKeydown.call(this,{target:t.target,key:"Backspace"}),this.value.slice().forEach((t=>{t.readonly&&!v.includes(t.value)&&u.appendChild(this.createTagElem(t))})),u.childNodes.length&&(m.insertNode(u),this.setRangeAtStartEnd(!1,u.lastChild)),p.length!=c)return this.value=[].map.call(this.getTagElms(),(t=>this.tagData(t))),void this.update({withoutChangeEvent:!0});if(this.hasMaxTags())return!0;if(window.getSelection&&(o=window.getSelection()).rangeCount>0&&3==o.anchorNode.nodeType){if((m=o.getRangeAt(0).cloneRange()).collapse(!0),m.setStart(o.focusNode,0),s=(e=m.toString().slice(0,m.endOffset)).split(h.pattern).length-1,(i=e.match(h.pattern))&&(a=e.slice(e.lastIndexOf(i[i.length-1]))),a){if(this.state.actions.ArrowLeft=!1,this.state.tag={prefix:a.match(h.pattern)[0],value:a.replace(h.pattern,"")},this.state.tag.baseOffset=o.baseOffset-this.state.tag.value.length,l=this.state.tag.value.match(h.delimiters))return this.state.tag.value=this.state.tag.value.replace(h.delimiters,""),this.state.tag.delimiters=l[0],this.addTags(this.state.tag.value,h.dropdown.clearOnSelect),void this.dropdown.hide.call(this);n=this.state.tag.value.length>=h.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",d({},this.state.tag,{textContent:this.DOM.input.textContent})),this.state.tag&&this.dropdown[n?"show":"hide"].call(this,this.state.tag.value)}),10)},onInputIE(t){var e=this;setTimeout((function(){e.events.callbacks.onInput.call(e,t)}))},onClickScope(t){var e=this.settings,i=t.target.closest("."+e.classNames.tag),s=+new Date-this.state.hasFocus;if(t.target!=this.DOM.scope){if(!t.target.classList.contains(e.classNames.tagX))return i?(this.trigger("click",{tag:i,index:this.getNodeIndex(i),data:this.tagData(i),originalEvent:this.cloneEvent(t)}),void(1!==e.editTags&&1!==e.editTags.clicks||this.events.callbacks.onDoubleClickScope.call(this,t))):void(t.target==this.DOM.input&&("mix"==e.mode&&this.fixFirefoxLastTagNoCaret(),s>500)?this.state.dropdown.visible?this.dropdown.hide.call(this):0===e.dropdown.enabled&&"mix"!=e.mode&&this.dropdown.show.call(this):"select"==e.mode&&!this.state.dropdown.visible&&this.dropdown.show.call(this));this.removeTags(t.target.parentNode)}else this.state.hasFocus||this.DOM.input.focus()},onPaste(t){var e,i;t.preventDefault(),this.settings.readonly||(e=t.clipboardData||window.clipboardData,i=e.getData("Text"),this.settings.hooks.beforePaste(t,{tagify:this,pastedText:i,clipboardData:e}).then((e=>{void 0===e&&(e=i),e&&(this.injectAtCaret(e,window.getSelection().getRangeAt(0)),"mix"==this.settings.mode?this.events.callbacks.onMixTagsInput.call(this,t):this.addTags(this.DOM.input.textContent,!0))})).catch((t=>t)))},onEditTagInput(t,e){var i=t.closest("."+this.settings.classNames.tag),s=this.getNodeIndex(i),a=this.tagData(i),n=this.input.normalize.call(this,t),o=i.innerHTML!=i.__tagifyTagData.__originalHTML,r=this.validateTag({[this.settings.tagTextProp]:n});o||!0!==t.originalIsValid||(r=!0),i.classList.toggle(this.settings.classNames.tagInvalid,!0!==r),a.__isValid=r,i.title=!0===r?a.title||a.value:r,n.length>=this.settings.dropdown.enabled&&(this.state.editing&&(this.state.editing.value=n),this.dropdown.show.call(this,n)),this.trigger("edit:input",{tag:i,index:s,data:d({},this.value[s],{newValue:n}),originalEvent:this.cloneEvent(e)})},onEditTagFocus(t){this.state.editing={scope:t,input:t.querySelector("[contenteditable]")}},onEditTagBlur(t){if(this.state.hasFocus||this.toggleFocusClass(),this.DOM.scope.contains(t)){var e,i=this.settings,s=t.closest("."+i.classNames.tag),a=this.input.normalize.call(this,t),n=this.tagData(s).__originalData,o=s.innerHTML!=s.__tagifyTagData.__originalHTML,r=this.validateTag({[i.tagTextProp]:a});if(a)if(o){if(e=this.getWhitelistItem(a)||d({},n,{[i.tagTextProp]:a,value:a}),i.transformTag.call(this,e,n),!0!==(r=this.validateTag({[i.tagTextProp]:e[i.tagTextProp]}))){if(this.trigger("invalid",{data:e,tag:s,message:r}),i.editTags.keepInvalid)return;i.keepInvalidTags?e.__isValid=r:e=n}this.onEditTagDone(s,e)}else this.onEditTagDone(s,n);else this.onEditTagDone(s)}},onEditTagkeydown(t,e){switch(this.trigger("edit:keydown",{originalEvent:this.cloneEvent(t)}),t.key){case"Esc":case"Escape":e.innerHTML=e.__tagifyTagData.__originalHTML;case"Enter":case"Tab":t.preventDefault(),t.target.blur()}},onDoubleClickScope(t){var e,i,s=t.target.closest("."+this.settings.classNames.tag),a=this.settings;s&&(e=s.classList.contains(this.settings.classNames.tagEditing),i=s.hasAttribute("readonly"),"select"==a.mode||a.readonly||e||i||!this.settings.editTags||this.editTag(s),this.toggleFocusClass(!0),this.trigger("dblclick",{tag:s,index:this.getNodeIndex(s),data:this.tagData(s)}))}}};function f(t,e){return t?t.previousElementSibling&&t.previousElementSibling.classList.contains("tagify")?(console.warn("Tagify: ","input element is already Tagified",t),this):(d(this,function(t){var e=document.createTextNode("");function i(t,i,s){s&&i.split(/\s+/g).forEach((i=>e[t+"EventListener"].call(e,i,s)))}return{off(t,e){return i("remove",t,e),this},on(t,e){return e&&"function"==typeof e&&i("add",t,e),this},trigger(i,s,a){var n;if(a=a||{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=a.cloneData?d({},o):o).tagify=this,s instanceof Object)for(var r in s)s[r]instanceof HTMLElement&&(o[r]=s[r]);n=new CustomEvent(i,{detail:o})}catch(t){console.warn(t)}e.dispatchEvent(n)}}}}(this)),this.isFirefox="undefined"!=typeof InstallTrigger,this.isIE=window.document.documentMode,this.applySettings(t,e||{}),this.state={inputText:"",editing:!1,actions:{},mixMode:{},dropdown:{},flaggedTags:{}},this.value=[],this.listeners={},this.DOM={},this.build(t),this.getCSSVars(),this.loadOriginalValues(),this.events.customBinding.call(this),this.events.binding.call(this),void(t.autofocus&&this.DOM.input.focus())):(console.warn("Tagify: ","input element not found",t),this)}return f.prototype={dropdown:p,TEXTS:{empty:"empty",exceed:"number of tags exceeded",pattern:"pattern mismatch",duplicate:"already exists",notAllowed:"not allowed"},customEventsList:["change","add","remove","invalid","input","click","keydown","focus","blur","edit:input","edit:beforeUpdate","edit:updated","edit:start","edit:keydown","dropdown:show","dropdown:hide","dropdown:select","dropdown:updated","dropdown:noMatch"],dataProps:["__isValid","__removed","__originalData","__originalHTML","__tagId"],trim(t){return this.settings.trim&&t&&"string"==typeof t?t.trim():t},parseHTML:function(t){return(new DOMParser).parseFromString(t.trim(),"text/html").body.firstElementChild},templates:m,parseTemplate(t,e){return t=this.settings.templates[t]||t,this.parseHTML(t.apply(this,e))},applySettings(t,e){u.templates=this.templates;var i=this.settings=d({},u,e);i.readonly=t.hasAttribute("readonly"),i.placeholder=t.getAttribute("placeholder")||i.placeholder||"",i.required=t.hasAttribute("required");for(let t in i.classNames)Object.defineProperty(i.classNames,t+"Selector",{get(){return"."+this[t].split(" ").join(".")}});if(this.isIE&&(i.autoComplete=!1),["whitelist","blacklist"].forEach((e=>{var s=t.getAttribute("data-"+e);s&&(s=s.split(i.delimiters))instanceof Array&&(i[e]=s)})),"autoComplete"in e&&!l(e.autoComplete)&&(i.autoComplete=u.autoComplete,i.autoComplete.enabled=e.autoComplete),"mix"==i.mode&&(i.autoComplete.rightKey=!0,i.delimiters=e.delimiters||null,i.tagTextProp&&!i.dropdown.searchKeys.includes(i.tagTextProp)&&i.dropdown.searchKeys.push(i.tagTextProp)),t.pattern)try{i.pattern=new RegExp(t.pattern)}catch(t){}if(this.settings.delimiters)try{i.delimiters=new RegExp(this.settings.delimiters,"g")}catch(t){}"select"==i.mode&&(i.dropdown.enabled=0),i.dropdown.appendTarget=e.dropdown&&e.dropdown.appendTarget?e.dropdown.appendTarget:document.body},getAttributes(t){if("[object Object]"!=Object.prototype.toString.call(t))return"";var e,i,s=Object.keys(t),a="";for(i=s.length;i--;)"__"!=(e=s[i]).slice(0,2)&&"class"!=e&&t.hasOwnProperty(e)&&void 0!==t[e]&&(a+=" "+e+(void 0!==t[e]?`="${t[e]}"`:""));return a},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},getCaretGlobalPosition(){const t=document.getSelection();if(t.rangeCount){const e=t.getRangeAt(0),i=e.startContainer,s=e.startOffset;let a,n;if(s>0)return n=document.createRange(),n.setStart(i,s-1),n.setEnd(i,s),a=n.getBoundingClientRect(),{left:a.right,top:a.top,bottom:a.bottom};if(i.getBoundingClientRect)return i.getBoundingClientRect()}return{left:-9999,top:-9999}},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;this.settings.mixMode.integrated?(e.originalInput=null,e.scope=t,e.input=t):(e.originalInput=t,e.scope=this.parseTemplate("wrapper",[t,this.settings]),e.input=e.scope.querySelector(this.settings.classNames.inputSelector),t.parentNode.insertBefore(e.scope,t)),this.settings.dropdown.enabled>=0&&this.dropdown.init.call(this)},destroy(){this.DOM.scope.parentNode.removeChild(this.DOM.scope),this.dropdown.hide.call(this,!0),clearTimeout(this.dropdownHide__bindEventsTimeout)},loadOriginalValues(t){var e,i=this.settings;if(void 0===t&&(t=i.mixMode.integrated?this.DOM.input.textContent:this.DOM.originalInput.value),this.removeAllTags({withoutChangeEvent:!0}),t)if("mix"==i.mode)this.parseMixTags(t.trim()),(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).forEach((t=>t&&t.classList.add(i.classNames.tagNoAnimation)))}else this.postUpdate();this.state.lastOriginalValueReported=i.mixMode.integrated?"":this.DOM.originalInput.value,this.state.loadedOriginalValues=!0},cloneEvent(t){var e={};for(var i in t)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)},toggleFocusClass(t){this.toggleClass(this.settings.classNames.focus,!!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:v,fixFirefoxLastTagNoCaret(){},placeCaretAfterNode(t){if(t&&t.parentNode){var e=t.nextSibling,i=window.getSelection(),s=i.getRangeAt(0);i.rangeCount&&(s.setStartBefore(e||t),s.setEndBefore(e||t),i.removeAllRanges(),i.addRange(s))}},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},editTag(t,e){t=t||this.getLastTag(),e=e||{},this.dropdown.hide.call(this);var i=this.settings;function s(){return t.querySelector(i.classNames.tagTextSelector)}var a=s(),n=this.getNodeIndex(t),o=this.tagData(t),r=this.events.callbacks,l=this,h=!0;if(a){if(!(o instanceof Object&&"editable"in o)||o.editable)return a.setAttribute("contenteditable",!0),t.classList.add(i.classNames.tagEditing),this.tagData(t,{__originalData:d({},o),__originalHTML:t.innerHTML}),a.addEventListener("focus",r.onEditTagFocus.bind(this,t)),a.addEventListener("blur",(function(){setTimeout((()=>r.onEditTagBlur.call(l,s())))})),a.addEventListener("input",r.onEditTagInput.bind(this,a)),a.addEventListener("keydown",(e=>r.onEditTagkeydown.call(this,e,t))),a.focus(),this.setRangeAtStartEnd(!1,a),e.skipValidation||(h=this.editTagToggleValidity(t,o.value)),a.originalIsValid=h,this.trigger("edit:start",{tag:t,index:n,data:o,isValid:h}),this}else console.warn("Cannot find element in Tag template: .",i.classNames.tagTextSelector)},editTagToggleValidity(t,e){var i,s=this.tagData(t);if(s)return i=!(!s.__isValid||1==s.__isValid),t.classList.toggle(this.settings.classNames.tagInvalid,i),s.__isValid;console.warn("tag has no data: ",t,s)},onEditTagDone(t,e){e=e||{};var i={tag:t=t||this.state.editing.scope,index:this.getNodeIndex(t),previousData:this.tagData(t),data:e};this.trigger("edit:beforeUpdate",i,{cloneData:!1}),this.state.editing=!1,delete e.__originalData,delete e.__originalHTML,t&&e[this.settings.tagTextProp]?(this.editTagToggleValidity(t),t=this.replaceTag(t,e),this.settings.a11y.focusableTags&&t.focus()):t&&this.removeTags(t),this.trigger("edit:updated",i),this.dropdown.hide.call(this),this.settings.keepInvalidTags&&this.reCheckInvalidTags()},replaceTag(t,e){e&&e.value||(e=t.__tagifyTagData),e.__isValid&&1!=e.__isValid&&d(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,[].forEach.call(this.getTagElms(),(t=>{t.classList.contains(this.settings.classNames.tagNotAllowed.split(" ")[0])||this.value.push(this.tagData(t))})),this.update()},setRangeAtStartEnd(t,e){t="number"==typeof t?t:!!t,e=(e=e||this.DOM.input).lastChild||e;var i=document.getSelection();try{i.rangeCount>=1&&["Start","End"].forEach((s=>i.getRangeAt(0)["set"+s](e,t||e.length)))}catch(t){console.warn("Tagify: ",t)}},injectAtCaret(t,e){if(e=e||this.state.selection.range)return"string"==typeof t&&(t=document.createTextNode(t)),e.deleteContents(),e.insertNode(t),this.setRangeAtStartEnd(!1,t),this.updateValueByDOMTags(),this.update(),this},input:{set(t="",e=!0){var i=this.settings.dropdown.closeOnSelect;this.state.inputText=t,e&&(this.DOM.input.innerHTML=o(""+t)),!t&&i&&this.dropdown.hide.bind(this),this.input.autocomplete.suggest.call(this),this.input.validate.call(this)},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){var e=t||this.DOM.input,i=[];e.childNodes.forEach((t=>3==t.nodeType&&i.push(t.nodeValue))),i=i.join("\n");try{i=i.replace(/(?:\r\n|\r|\n)/g,this.settings.delimiters.source.charAt(0))}catch(t){}return i=i.replace(/\s/g," "),this.settings.trim&&(i=i.replace(/^\s+/,"")),i},autocomplete:{suggest(t){if(this.settings.autoComplete.enabled){"string"==typeof(t=t||{})&&(t={value:t});var e=t.value?""+t.value:"",i=e.substr(0,this.state.inputText.length).toLowerCase(),s=e.substring(this.state.inputText.length);e&&this.state.inputText&&i==this.state.inputText.toLowerCase()?(this.DOM.input.setAttribute("data-suggest",s),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()),this.input.autocomplete.suggest.call(this),this.dropdown.hide.call(this),!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.DOM.scope.querySelectorAll(`${this.settings.classNames.tagSelector}:not(.${this.settings.classNames.tagHide}):not([readonly])`);return t[t.length-1]},tagData:(t,e,i)=>t?(e&&(t.__tagifyTagData=i?e:d({},t.__tagifyTagData||{},e)),t.__tagifyTagData):(console.warn("tag elment doesn't exist",t,e),e),isTagDuplicate(t,e){var s=this.settings;return"select"!=s.mode&&this.value.reduce(((a,n)=>i(this.trim(""+t),n.value,e||s.dropdown.caseSensitive)?a+1:a),0)},getTagIndexByValue(t){var e=[];return this.getTagElms().forEach(((s,a)=>{i(this.trim(s.textContent),t,this.settings.dropdown.caseSensitive)&&e.push(a)})),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,s){e=e||"value";var a,n=this.settings;return(s=s||n.whitelist).some((s=>{var o="string"==typeof s?s:s[e]||s.value;if(i(o,t,n.dropdown.caseSensitive,n.trim))return a="string"==typeof s?{value:s}:s,!0})),a||"value"!=e||"value"==n.tagTextProp||(a=this.getWhitelistItem(t,n.tagTextProp,s)),a},validateTag(t){var e=this.settings,i="value"in t?"value":e.tagTextProp,s=this.trim(t[i]+"");return(t[i]+"").trim()?e.pattern&&e.pattern instanceof RegExp&&!e.pattern.test(s)?this.TEXTS.pattern:!e.duplicates&&this.isTagDuplicate(s,this.state.editing)?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){var e=this.settings;document.activeElement.blur(),e.readonly=t,this.DOM.scope[(t?"set":"remove")+"Attribute"]("readonly",!0),"mix"==e.mode&&(this.DOM.input.contentEditable=!t)},normalizeTags(t){var e=this.settings,i=e.whitelist,s=e.delimiters,a=e.mode,n=e.tagTextProp;e.enforceWhitelist;var o=[],r=!!i&&i[0]instanceof Object,l=t instanceof Array,d=t=>(t+"").split(s).filter((t=>t)).map((t=>({[n]:this.trim(t),value:this.trim(t)})));if("number"==typeof t&&(t=t.toString()),"string"==typeof t){if(!t.trim())return[];t=d(t)}else l&&(t=[].concat(...t.map((t=>t.value?t:d(t)))));return r&&(t.forEach((t=>{var e=o.map((t=>t.value)),i=this.dropdown.filterListItems.call(this,t[n],{exact:!0}).filter((t=>!e.includes(t.value))),s=i.length>1?this.getWhitelistItem(t[n],n,i):i[0];s&&s instanceof Object?o.push(s):"mix"!=a&&(null==t.value&&(t.value=t[n]),o.push(t))})),t=o),t},parseMixTags(t){var e=this.settings,i=e.mixTagsInterpolator,s=e.duplicates,a=e.transformTag,n=e.enforceWhitelist,o=e.maxTags,r=e.tagTextProp,l=[];return t=t.split(i[0]).map(((t,e)=>{var d,h,g,c=t.split(i[1]),p=c[0],u=l.length==o;try{if(p==+p)throw Error;h=JSON.parse(p)}catch(t){h=this.normalizeTags(p)[0]||{value:p}}if(u||!(c.length>1)||n&&!this.isTagWhitelisted(h.value)||!s&&this.isTagDuplicate(h.value)){if(t)return e?i[0]+t:t}else a.call(this,h),h[d=h[r]?r:"value"]=this.trim(h[d]),g=this.createTagElem(h),l.push(h),g.classList.add(this.settings.classNames.tagNoAnimation),c[0]=g.outerHTML,this.value.push(h);return c.join("")})).join(""),this.DOM.input.innerHTML=t,this.DOM.input.appendChild(document.createTextNode("")),this.DOM.input.normalize(),this.getTagElms().forEach(((t,e)=>this.tagData(t,l[e]))),this.update({withoutChangeEvent:!0}),t},replaceTextWithNode(t,e){if(this.state.tag||e){e=e||this.state.tag.prefix+this.state.tag.value;var i,s,a=window.getSelection(),n=a.anchorNode,o=this.state.tag.delimiters?this.state.tag.delimiters.length:0;return n.splitText(a.anchorOffset-o),i=n.nodeValue.lastIndexOf(e),s=n.splitText(i),t&&n.parentNode.replaceChild(t,s),!0}},selectTag(t,e){if(!this.settings.enforceWhitelist||this.isTagWhitelisted(e.value))return this.input.set.call(this,e[this.settings.tagTextProp||"value"],!0),this.state.actions.selectOption&&setTimeout(this.setRangeAtStartEnd.bind(this)),this.getLastTag()?this.replaceTag(this.getLastTag(),e):this.appendTag(t),this.value[0]=e,this.trigger("add",{tag:t,data:e}),this.update(),[t]},addEmptyTag(t){var e=d({value:""},t||{}),i=this.createTagElem(e);this.tagData(i,e),this.appendTag(i),this.editTag(i,{skipValidation:!0})},addTags(t,e,i=this.settings.skipInvalid){var s=[],a=this.settings,n=document.createDocumentFragment();return t&&0!=t.length?(t=this.normalizeTags(t),"mix"==a.mode?this.addMixTags(t):("select"==a.mode&&(e=!1),this.DOM.input.removeAttribute("style"),t.forEach((t=>{var e,o={},r=Object.assign({},t,{value:t.value+""});if((t=Object.assign({},r)).__isValid=this.hasMaxTags()||this.validateTag(t),a.transformTag.call(this,t),!0!==t.__isValid){if(i)return;d(o,this.getInvalidTagAttrs(t,t.__isValid),{__preInvalidData:r}),t.__isValid==this.TEXTS.duplicate&&this.flashTag(this.getTagElmByValue(t.value))}if(t.readonly&&(o["aria-readonly"]=!0),e=this.createTagElem(t,o),s.push(e),"select"==a.mode)return this.selectTag(e,t);n.appendChild(e),t.__isValid&&!0===t.__isValid?(this.value.push(t),this.update(),this.trigger("add",{tag:e,index:this.value.length-1,data:t})):(this.trigger("invalid",{data:t,index:this.value.length,tag:e,message:t.__isValid}),a.keepInvalidTags||setTimeout((()=>this.removeTags(e,!0)),1e3)),this.dropdown.position.call(this)})),this.appendTag(n),t.length&&e&&this.input.set.call(this),this.dropdown.refilter.call(this),s)):("select"==a.mode&&this.removeAllTags(),s)},addMixTags(t){if(t[0].prefix||this.state.tag)this.prefixedTextToTag(t[0]);else{"string"==typeof t&&(t=[{value:t}]);var e=!!this.state.selection,i=document.createDocumentFragment();t.forEach((t=>{var e=this.createTagElem(t);i.appendChild(e),this.insertAfterTag(e)})),e?this.injectAtCaret(i):(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(i),this.updateValueByDOMTags(),this.update())}},prefixedTextToTag(t){var e,i=this.settings,s=this.state.tag.delimiters;if(i.transformTag.call(this,t),t.prefix=t.prefix||this.state.tag?this.state.tag.prefix:(i.pattern.source||i.pattern)[0],e=this.createTagElem(t),this.replaceTextWithNode(e)||this.DOM.input.appendChild(e),setTimeout((()=>e.classList.add(this.settings.classNames.tagNoAnimation)),300),this.value.push(t),this.update(),!s){var a=this.insertAfterTag(e)||e;this.placeCaretAfterNode(a)}return this.state.tag=null,this.trigger("add",d({},{tag:e},{data:t})),e},appendTag(t){var e=this.DOM,i=e.scope.lastElementChild;i===e.input?e.scope.insertBefore(t,i):e.scope.appendChild(t)},createTagElem(i,s){i.__tagId=([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,(t=>(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16)));var a,n=d({},i,function(i){for(var s=1;s{var e=this.tagData(t),i=t.getAttribute("title")==this.TEXTS.duplicate,s=!0===this.validateTag(e);i&&s&&(e=e.__preInvalidData?e.__preInvalidData:{value:e.value},this.replaceTag(t,e))}))},removeTags(t,e,i){var s;t=t&&t instanceof HTMLElement?[t]:t instanceof Array?t:t?[t]:[this.getLastTag()],s=t.reduce(((t,e)=>(e&&"string"==typeof e&&(e=this.getTagElmByValue(e)),e&&t.push({node:e,idx:this.getTagIdx(this.tagData(e)),data:this.tagData(e,{__removed:!0})}),t)),[]),i="number"==typeof i?i:this.CSSVars.tagHideTransition,"select"==this.settings.mode&&(i=0,this.input.set.call(this)),1==s.length&&s[0].node.classList.contains(this.settings.classNames.tagNotAllowed)&&(e=!0),s.length&&this.settings.hooks.beforeRemoveTag(s,{tagify:this}).then((()=>{function t(t){t.node.parentNode&&(t.node.parentNode.removeChild(t.node),e?this.settings.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.call(this),this.dropdown.position.call(this),this.DOM.input.normalize(),this.settings.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(this.settings.classNames.tagHide),setTimeout(t.bind(this),i,e)}.call(this,s[0]):s.forEach(t.bind(this)),e||(s.forEach((t=>{var e=Object.assign({},t.data);delete e.__removed;var i=this.getTagIdx(e);i>-1&&this.value.splice(i,1)})),this.update())})).catch((t=>{}))},removeTagsFromDOM(){[].slice.call(this.getTagElms()).forEach((t=>t.parentNode.removeChild(t)))},removeAllTags(t){t=t||{},this.value=[],"mix"==this.settings.mode?this.DOM.input.innerHTML="":this.removeTagsFromDOM(),this.dropdown.position.call(this),"select"==this.settings.mode&&this.input.set.call(this),this.update(t)},postUpdate(){var t=this.settings.classNames,e="mix"==this.settings.mode?this.settings.mixMode.integrated?this.DOM.input.textContent:this.DOM.originalInput.value:this.value.length;this.toggleClass(t.hasMaxTags,this.value.length>=this.settings.maxTags),this.toggleClass(t.hasNoTags,!this.value.length),this.toggleClass(t.empty,!e)},update(t){var e=this.DOM.originalInput,i=(t||{}).withoutChangeEvent;this.settings.mixMode.integrated||(e.value=this.getInputValue()),this.postUpdate(),!i&&this.state.loadedOriginalValues&&this.triggerChangeEvent()},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 e=t||this.value,i=this.dataProps,e&&r(e)&&e.map((t=>s(t,i)));var e,i},getMixedTagsAsString(){var t="",e=this,i=this.settings.mixTagsInterpolator;return function a(n){n.childNodes.forEach((n=>{if(1==n.nodeType){if(n.classList.contains(e.settings.classNames.tag)&&e.tagData(n)){if(e.tagData(n).__removed)return;return void(t+=i[0]+JSON.stringify(s(e.tagData(n),e.dataProps))+i[1])}"BR"!=n.tagName||n.parentNode!=e.DOM.input&&1!=n.parentNode.childNodes.length?"DIV"!=n.tagName&&"P"!=n.tagName||(t+="\r\n",a(n)):t+="\r\n"}else t+=n.textContent}))}(this.DOM.input),t}},f.prototype.removeTag=f.prototype.removeTags,f})); diff --git a/manifest.json b/manifest.json index 2ef4c48..94a6284 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "Creative Review for MoPub", - "version": "0.1.0", + "version": "0.1.1", "description": "Preview creatives from MoPub MPX. This helps you to find the problematic creative easily", "manifest_version": 2, "background": {