@yaireo/tagify
Advanced tools
Comparing version 2.6.6 to 2.7.0
"use strict"; | ||
/** | ||
* Tagify (v 2.6.6)- tags input component | ||
* Tagify (v 2.7.0)- tags input component | ||
* By Yair Even-Or (2016) | ||
@@ -95,2 +95,4 @@ * Don't sell this code. (c) | ||
// Flag - tries to autocomplete the input's value while typing | ||
mixTagsAllowedAfter: /,|\.|\:|\s/, | ||
// RegEx - Define conditions in which mix-tags content is allowing a tag to be added after | ||
dropdown: { | ||
@@ -105,2 +107,5 @@ classname: '', | ||
customEventsList: ['add', 'remove', 'invalid', 'input'], | ||
// generateUID(){ | ||
// return Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36) | ||
// }, | ||
@@ -166,3 +171,3 @@ /** | ||
if (this.settings.mode == 'mix') { | ||
this.DOM.input.innerHTML = this.parseMixTags(value); | ||
this.parseMixTags(value); | ||
} else this.addTags(value).forEach(function (tag) { | ||
@@ -304,9 +309,34 @@ tag && tag.classList.add('tagify--noAnim'); | ||
onKeydown: function onKeydown(e) { | ||
var _this3 = this; | ||
var s = e.target.textContent, | ||
lastTag; | ||
if (this.settings.mode == 'mix') return; | ||
lastTag, | ||
tags; | ||
if (this.settings.mode == 'mix') { | ||
switch (e.key) { | ||
case 'Backspace': | ||
var values = []; // find out which tag(s) were deleted and update "this.value" accordingly | ||
tags = this.DOM.input.children; // a delay is in need before the node actually is ditached from the document | ||
setTimeout(function () { | ||
// iterate over the list of tags still in the document and then filter only those from the "this.value" collection | ||
[].forEach.call(tags, function (tagElm) { | ||
return values.push(tagElm.title); | ||
}); | ||
_this3.value = _this3.value.filter(function (d) { | ||
return values.indexOf(d.title) != -1; | ||
}); | ||
}, 20); | ||
break; | ||
} | ||
return true; | ||
} | ||
switch (e.key) { | ||
case 'Backspace': | ||
if (s == "" || s.charCodeAt(0) == 8203) { | ||
// 8203: ZERO WIDTH SPACE unicode | ||
lastTag = this.DOM.scope.querySelectorAll('tag:not(.tagify--hide):not([readonly])'); | ||
@@ -362,8 +392,3 @@ lastTag = lastTag[lastTag.length - 1]; | ||
onMixTagsInput: function onMixTagsInput(e) { | ||
var sel, | ||
range, | ||
split, | ||
tag, | ||
patternLen = this.settings.pattern.length; | ||
this.state.tag = null; | ||
var sel, range, split, tag, showSuggestions; | ||
@@ -377,14 +402,25 @@ if (window.getSelection) { | ||
range.setStart(window.getSelection().focusNode, 0); | ||
split = range.toString().split(/,|\.|\s/); // ["foo", "bar", "@a"] | ||
split = range.toString().split(this.settings.mixTagsAllowedAfter); // ["foo", "bar", "@a"] | ||
tag = split[split.length - 1]; | ||
tag = this.state.tag = tag.substr(0, patternLen) == this.settings.pattern && tag.length > patternLen ? tag.slice(patternLen) : null; | ||
this.trigger("input", { | ||
value: tag | ||
}); | ||
tag = split[split.length - 1].match(this.settings.pattern); | ||
if (tag) { | ||
this.state.tag = { | ||
prefix: tag[0], | ||
value: tag.input.split(tag[0])[1] | ||
}; | ||
this.trigger("input", { | ||
prefix: tag[0], | ||
value: this.state.tag.value | ||
}); | ||
tag = this.state.tag; | ||
showSuggestions = this.state.tag.value.length >= this.settings.dropdown.enabled; | ||
} | ||
} | ||
} | ||
this.dropdown[tag ? "show" : "hide"].call(this, tag); | ||
this.update(); | ||
if (this.state.tag) { | ||
this.dropdown[showSuggestions ? "show" : "hide"].call(this, this.state.tag.value); | ||
this.update(); | ||
} | ||
}, | ||
@@ -580,3 +616,3 @@ onInputIE: function onInputIE(e) { | ||
normalizeTags: function normalizeTags(tagsItems) { | ||
var _this3 = this; | ||
var _this4 = this; | ||
@@ -609,3 +645,3 @@ var whitelistWithProps = this.settings.whitelist[0] instanceof Object, | ||
tagsItems.forEach(function (tag) { | ||
var matchObj = _this3.settings.whitelist.filter(function (WL_item) { | ||
var matchObj = _this4.settings.whitelist.filter(function (WL_item) { | ||
return WL_item.value.toLowerCase() == tag.value.toLowerCase(); | ||
@@ -615,3 +651,3 @@ }); | ||
if (matchObj[0]) temp.push(matchObj[0]); // set the Array (with the found Object) as the new value | ||
else if (_this3.settings.mode != 'mix') temp.push(tag); | ||
else if (_this4.settings.mode != 'mix') temp.push(tag); | ||
}); | ||
@@ -624,23 +660,39 @@ return temp; | ||
parseMixTags: function parseMixTags(s) { | ||
var _this4 = this; | ||
var _this5 = this; | ||
var htmlString = ''; | ||
s = s.split(this.settings.pattern); // this.DOM.scope.innerHTML | ||
// example: "@cartman ,@kyle do not know:#homer".split(/,|\.|\:|\s/).filter(item => item.match(/@|#/) ) | ||
s.split(this.settings.mixTagsAllowedAfter).filter(function (item) { | ||
return item.match(_this5.settings.pattern); | ||
}).forEach(function (tag) { | ||
var value = tag.replace(_this5.settings.pattern, ''), | ||
tagData; | ||
htmlString = s.shift() + s.map(function (part) { | ||
var tagElm, i, tagData; | ||
if (!part) return ''; | ||
if (_this5.isTagWhitelisted(value)) { | ||
tagData = _this5.normalizeTags.call(_this5, value)[0]; | ||
s = _this5.replaceMixStringWithTag(s, tag, tagData).s; | ||
} | ||
}); | ||
this.DOM.input.innerHTML = s; | ||
this.update(); | ||
return s; | ||
}, | ||
for (i in part) { | ||
if (part[i].match(/,|\.| /)) { | ||
tagData = _this4.normalizeTags.call(_this4, part.substr(0, i))[0]; | ||
if (tagData) tagElm = _this4.createTagElem(tagData);else i = 0; // a tag was found but was not in the whitelist, so reset the "i" index | ||
/** | ||
* [replaceMixStringWithTag description] | ||
* @param {String} s [whole string] | ||
* @param {String} tag [tag string to replace with tag element] | ||
* @param {Object} tagData [value, plus any other optional attributes] | ||
* @return {[type]} [description] | ||
*/ | ||
replaceMixStringWithTag: function replaceMixStringWithTag(s, tag, tagData, tagElm) { | ||
if (tagData && s && s.indexOf(tag) != -1) { | ||
tagElm = this.createTagElem(tagData); | ||
this.value.push(tagData); | ||
s = s.replace(tag, tagElm.outerHTML + "⁠"); // put a zero-space at the end to the caret won't jump back to the start (when the last input child is a tag) | ||
} | ||
break; | ||
} | ||
} | ||
return tagElm ? tagElm.outerHTML + part.slice(i) : _this4.settings.pattern + part; | ||
}).join(''); | ||
return htmlString; | ||
return { | ||
s: s, | ||
tagElm: tagElm | ||
}; | ||
}, | ||
@@ -652,29 +704,34 @@ | ||
addMixTag: function addMixTag(tagData) { | ||
if (!tagData) return; | ||
var sel = window.getSelection(), | ||
node = sel.focusNode, | ||
nodeText = node.textContent, | ||
wrapElm = document.createDocumentFragment(), | ||
tagElm = this.createTagElem(tagData), | ||
textNodeBefore, | ||
textNodeAfter, | ||
range, | ||
parrernLen = this.settings.pattern.length; | ||
if (!tagData || !this.state.tag) return; | ||
var tag = this.state.tag.prefix + this.state.tag.value, | ||
iter = document.createNodeIterator(this.DOM.input, NodeFilter.SHOW_TEXT), | ||
textnode, | ||
tagElm, | ||
idx, | ||
replacedNode; | ||
if (sel.rangeCount > 0) { | ||
range = sel.getRangeAt(0).cloneRange(); | ||
range.collapse(true); | ||
range.setStart(node, 0); | ||
textNodeBefore = range.toString().slice(0, -this.state.tag.length - parrernLen); | ||
textNodeAfter = nodeText.slice(textNodeBefore.length + this.state.tag.length + parrernLen, nodeText.length); | ||
textNodeBefore = document.createTextNode(textNodeBefore); | ||
textNodeAfter = document.createTextNode(textNodeAfter.trim() ? textNodeAfter : " \u200B"); | ||
wrapElm.appendChild(textNodeBefore); | ||
wrapElm.appendChild(tagElm); | ||
wrapElm.appendChild(textNodeAfter); | ||
while (textnode = iter.nextNode()) { | ||
if (textnode.nodeType === Node.TEXT_NODE) { | ||
// get the index of which the tag (string) is within the textNode (if at all) | ||
idx = textnode.nodeValue.indexOf(tag); | ||
if (idx == -1) continue; | ||
replacedNode = textnode.splitText(idx); | ||
tagElm = this.createTagElem(tagData); // clean up the tag's string and put tag element instead | ||
replacedNode.nodeValue = replacedNode.nodeValue.replace(tag, ''); | ||
textnode.parentNode.insertBefore(tagElm, replacedNode); | ||
tagElm.insertAdjacentHTML('afterend', '⁠'); | ||
} | ||
} | ||
node.parentNode.replaceChild(wrapElm, node); | ||
this.update(); | ||
this.input.setRangeAtStartEnd.call(this, true, textNodeAfter); | ||
if (tagElm) { | ||
this.value.push(tagData); | ||
this.update(); | ||
this.trigger('add', this.extend({}, { | ||
index: this.value.length, | ||
tag: tagElm | ||
}, tagData)); | ||
} | ||
this.state.tag = null; | ||
}, | ||
@@ -689,3 +746,3 @@ | ||
addTags: function addTags(tagsItems, clearInput) { | ||
var _this5 = this; | ||
var _this6 = this; | ||
@@ -699,7 +756,7 @@ var tagElems = []; | ||
if (typeof _this5.settings.transformTag === 'function') { | ||
tagData.value = _this5.settings.transformTag.call(_this5, tagData.value) || tagData.value; | ||
if (typeof _this6.settings.transformTag === 'function') { | ||
tagData.value = _this6.settings.transformTag.call(_this6, tagData.value) || tagData.value; | ||
} | ||
tagValidation = _this5.validateTag.call(_this5, tagData.value); | ||
tagValidation = _this6.validateTag.call(_this6, tagData.value); | ||
@@ -710,7 +767,7 @@ if (tagValidation !== true) { | ||
_this5.markTagByValue(tagData.value); | ||
_this6.markTagByValue(tagData.value); | ||
_this5.trigger("invalid", { | ||
_this6.trigger("invalid", { | ||
value: tagData.value, | ||
index: _this5.value.length, | ||
index: _this6.value.length, | ||
message: tagValidation | ||
@@ -721,21 +778,21 @@ }); | ||
tagElm = _this5.createTagElem(tagData); | ||
tagElm = _this6.createTagElem(tagData); | ||
tagElems.push(tagElm); // add the tag to the component's DOM | ||
appendTag.call(_this5, tagElm); | ||
appendTag.call(_this6, tagElm); | ||
if (tagValidation === true) { | ||
// update state | ||
_this5.value.push(tagData); | ||
_this6.value.push(tagData); | ||
_this5.update(); | ||
_this6.update(); | ||
_this5.trigger('add', _this5.extend({}, { | ||
index: _this5.value.length, | ||
_this6.trigger('add', _this6.extend({}, { | ||
index: _this6.value.length, | ||
tag: tagElm | ||
}, tagData)); | ||
} else if (!_this5.settings.keepInvalidTags) { | ||
} else if (!_this6.settings.keepInvalidTags) { | ||
// remove invalid tags (if "keepInvalidTags" is set to "false") | ||
setTimeout(function () { | ||
_this5.removeTag(tagElm, true); | ||
_this6.removeTag(tagElm, true); | ||
}, 1000); | ||
@@ -779,3 +836,3 @@ } | ||
} catch (err) {} | ||
} // for a certain Tag element, add attributes. | ||
} // add HTML attributes from tagData | ||
@@ -875,10 +932,10 @@ | ||
show: function show(value) { | ||
var _this6 = this; | ||
var _this7 = this; | ||
var listItems, listHTML; | ||
if (!this.settings.whitelist.length) return; // if no value was supplied, show all the "whitelist" items in the dropdown | ||
if (!this.settings.whitelist.length || !this.settings.dropdown.enabled) return; // if no value was supplied, show all the "whitelist" items in the dropdown | ||
// @type [Array] listItems | ||
listItems = value ? this.dropdown.filterListItems.call(this, value) : this.settings.whitelist.filter(function (item) { | ||
return _this6.isTagDuplicate(item.value || item) == -1; | ||
return _this7.isTagDuplicate(item.value || item) == -1; | ||
}); // don't include already preset tags | ||
@@ -993,6 +1050,6 @@ | ||
onClick: function onClick(e) { | ||
var _this7 = this; | ||
var _this8 = this; | ||
var onClickOutside = function onClickOutside() { | ||
return _this7.dropdown.hide.call(_this7); | ||
return _this8.dropdown.hide.call(_this8); | ||
}, | ||
@@ -999,0 +1056,0 @@ listItemElm; |
@@ -1,1 +0,1 @@ | ||
"use strict";!function(a){function n(t,e){if(!t)return console.warn("Tagify: ","invalid input element ",t),this;if(this.settings=this.extend({},this.DEFAULTS,e),this.settings.readonly=t.hasAttribute("readonly"),this.isIE&&(this.settings.autoComplete=!1),t.pattern)try{this.settings.pattern=new RegExp(t.pattern)}catch(t){}if(this.settings&&this.settings.delimiters)try{this.settings.delimiters=new RegExp("["+this.settings.delimiters+"]","g")}catch(t){}this.state={},this.value=[],this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),this.loadOriginalValues(),this.events.customBinding.call(this),this.events.binding.call(this)}a.fn.tagify=function(){var i=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};return this.each(function(){var t,e=a(this);if(e.data("tagify"))return this;i.isJQueryPlugin=!0,t=new n(e[0],i),e.data("tagify",t)})},n.prototype={isIE:window.document.documentMode,TEXTS:{empty:"empty",exceed:"number of tags exceeded",pattern:"pattern mismatch",duplicate:"already exists",notAllowed:"not allowed"},DEFAULTS:{delimiters:",",pattern:null,maxTags:1/0,callbacks:{},addTagOnBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,keepInvalidTags:!1,autoComplete:!0,dropdown:{classname:"",enabled:2,maxItems:10,itemTemplate:""}},customEventsList:["add","remove","invalid","input"],parseHTML:function(t){return(new DOMParser).parseFromString(t.trim(),"text/html").body.firstElementChild},escapeHtml:function(t){var e=document.createTextNode(t),i=document.createElement("p");return i.appendChild(e),i.innerHTML},build:function(t){var e=this.DOM,i='<tags class="tagify '+(this.settings.mode?"tagify--mix":"")+" "+t.className+'" '+(this.settings.readonly?"readonly":"")+'>\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify__input"></div>\n </tags>';e.originalInput=t,e.scope=this.parseHTML(i),e.input=e.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(e.scope,t),0<=this.settings.dropdown.enabled&&this.dropdown.init.call(this),t.autofocus&&e.input.focus()},destroy:function(){this.DOM.scope.parentNode.removeChild(this.DOM.scope)},loadOriginalValues:function(){var t=this.DOM.originalInput.value;if(t){try{t=JSON.parse(t)}catch(t){}"mix"==this.settings.mode?this.DOM.input.innerHTML=this.parseMixTags(t):this.addTags(t).forEach(function(t){t&&t.classList.add("tagify--noAnim")})}},extend:function(t,e,i){function n(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 s(t,e){for(var i in e)e.hasOwnProperty(i)&&(n(e[i])?n(t[i])?s(t[i],e[i]):t[i]=Object.assign({},e[i]):t[i]=e[i])}return t instanceof Object||(t={}),s(t,e),i&&s(t,i),t},EventDispatcher:function(n){var s=document.createTextNode("");this.off=function(t,e){return e&&s.removeEventListener.call(s,t,e),this},this.on=function(t,e){return e&&s.addEventListener.call(s,t,e),this},this.trigger=function(t,e){var i;if(t)if(n.settings.isJQueryPlugin)a(n.DOM.originalInput).triggerHandler(t,[e]);else{try{i=new CustomEvent(t,{detail:e})}catch(t){console.warn(t)}s.dispatchEvent(i)}}},events:{customBinding:function(){var e=this;this.customEventsList.forEach(function(t){e.on(t,e.settings.callbacks[t])})},binding:function(){var t,e=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],i=this.events.callbacks,n=e?"addEventListener":"removeEventListener";for(var s in e&&!this.listeners.main&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",i[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&a(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this))),t=this.listeners.main=this.listeners.main||{paste:["input",i.onPaste.bind(this)],focus:["input",i.onFocusBlur.bind(this)],blur:["input",i.onFocusBlur.bind(this)],keydown:["input",i.onKeydown.bind(this)],click:["scope",i.onClickScope.bind(this)]})this.DOM[t[s][0]][n](s,t[s][1])},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"mix"!=this.settings.mode&&("focus"==t.type?0===this.settings.dropdown.enabled&&this.dropdown.show.call(this):"blur"==t.type&&e?this.settings.addTagOnBlur&&this.addTags(e,!0).length:(this.DOM.input.removeAttribute("style"),this.dropdown.hide.call(this)))},onKeydown:function(t){var e,i=t.target.textContent;if("mix"!=this.settings.mode)switch(t.key){case"Backspace":""!=i&&8203!=i.charCodeAt(0)||(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide):not([readonly])"))[e.length-1],this.removeTag(e));break;case"Esc":case"Escape":this.input.set.call(this),t.target.blur();break;case"ArrowRight":case"Tab":if(!i)return!0;case"Enter":t.preventDefault(),this.addTags(this.input.value,!0)}},onInput:function(t){var e=this.input.normalize.call(this),i=e.length>=this.settings.dropdown.enabled;if("mix"==this.settings.mode)return this.events.callbacks.onMixTagsInput.call(this,t);e?this.input.value!=e&&(this.input.set.call(this,e,!1),this.trigger("input",{value:e}),-1!=e.search(this.settings.delimiters)?this.addTags(e).length&&this.input.set.call(this):0<=this.settings.dropdown.enabled&&this.dropdown[i?"show":"hide"].call(this,e)):this.input.set.call(this,"")},onMixTagsInput:function(t){var e,i,n,s,a=this.settings.pattern.length;this.state.tag=null,window.getSelection&&0<(e=window.getSelection()).rangeCount&&((i=e.getRangeAt(0).cloneRange()).collapse(!0),i.setStart(window.getSelection().focusNode,0),s=(n=i.toString().split(/,|\.|\s/))[n.length-1],s=this.state.tag=s.substr(0,a)==this.settings.pattern&&s.length>a?s.slice(a):null,this.trigger("input",{value:s})),this.dropdown[s?"show":"hide"].call(this,s),this.update()},onInputIE:function(t){var e=this;setTimeout(function(){e.events.callbacks.onInput.call(e,t)})},onPaste:function(t){},onClickScope:function(t){"TAGS"==t.target.tagName?this.DOM.input.focus():"X"==t.target.tagName&&this.removeTag(t.target.parentNode)}}},input:{value:"",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=!(1<arguments.length&&void 0!==arguments[1])||arguments[1];this.input.value=t,e&&(this.DOM.input.innerHTML=t),t||this.dropdown.hide.call(this),t.length<2&&this.input.autocomplete.suggest.call(this,""),this.input.validate.call(this)},setRangeAtStartEnd:function(){var t,e,i=0<arguments.length&&void 0!==arguments[0]&&arguments[0],n=arguments[1];document.createRange&&((t=document.createRange()).selectNodeContents(n||this.DOM.input),t.collapse(i),(e=window.getSelection()).removeAllRanges(),e.addRange(t))},validate:function(){var t=!this.input.value||this.validateTag.call(this,this.input.value);this.DOM.input.classList.toggle("tagify__input--invalid",!0!==t)},normalize:function(){for(var t=this.DOM.input.cloneNode(!0),e=t.textContent.replace(/\s/g," ");t.firstElementChild;)e+=t.firstElementChild.textContent,t.removeChild(t.firstElementChild);return e.replace(/^\s+/,"")},autocomplete:{suggest:function(t){t&&this.input.value?this.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(t){var e=this.DOM.input.getAttribute("data-suggest"),i=t||(e?this.input.value+e:null);return!!i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtStartEnd.call(this),!0)}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(e){return this.value.findIndex(function(t){return e.trim().toLowerCase()===t.value.toLowerCase()})},getTagIndexByValue:function(i){var n=[];return this.DOM.scope.querySelectorAll("tag").forEach(function(t,e){t.textContent.trim().toLowerCase()==i.toLowerCase()&&n.push(e)}),n},getTagElmByValue:function(t){var e=this.getTagIndexByValue(t)[0];return this.DOM.scope.querySelectorAll("tag")[e]},markTagByValue:function(t,e){return!!(e=e||this.getTagElmByValue(t))&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},100),e)},isTagBlacklisted:function(e){return e=e.split(" "),this.settings.blacklist.filter(function(t){return-1!=e.indexOf(t)}).length},isTagWhitelisted:function(e){return this.settings.whitelist.some(function(t){if((t.value||t).toLowerCase()===e.toLowerCase())return!0})},validateTag:function(t){var e=t.trim(),i=this.value.length>=this.settings.maxTags,n=!0;return e?i?n=this.TEXTS.exceed:this.settings.pattern&&!this.settings.pattern.test(e)?n=this.TEXTS.pattern:this.settings.duplicates||-1===this.isTagDuplicate(e)?(this.isTagBlacklisted(e)||this.settings.enforceWhitelist&&!this.isTagWhitelisted(e))&&(n=this.TEXTS.notAllowed):n=this.TEXTS.duplicate:n=this.TEXTS.empty,n},normalizeTags:function(t){var i=this,e=this.settings.whitelist[0]instanceof Object,n=t instanceof Array&&t[0]instanceof Object&&"value"in t[0],s=[];if(n)return t;if("string"==typeof t){if(!t.trim())return[];t=t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}})}else t instanceof Array&&(t=t.map(function(t){return{value:t.trim()}}));return e?(t.forEach(function(e){var t=i.settings.whitelist.filter(function(t){return t.value.toLowerCase()==e.value.toLowerCase()});t[0]?s.push(t[0]):"mix"!=i.settings.mode&&s.push(e)}),s):t},parseMixTags:function(t){var s=this;return(t=t.split(this.settings.pattern)).shift()+t.map(function(t){var e,i,n;if(!t)return"";for(i in t)if(t[i].match(/,|\.| /)){(n=s.normalizeTags.call(s,t.substr(0,i))[0])?e=s.createTagElem(n):i=0;break}return e?e.outerHTML+t.slice(i):s.settings.pattern+t}).join("")},addMixTag:function(t){if(t){var e,i,n,s=window.getSelection(),a=s.focusNode,o=a.textContent,r=document.createDocumentFragment(),l=this.createTagElem(t),h=this.settings.pattern.length;0<s.rangeCount&&((n=s.getRangeAt(0).cloneRange()).collapse(!0),n.setStart(a,0),e=n.toString().slice(0,-this.state.tag.length-h),i=o.slice(e.length+this.state.tag.length+h,o.length),e=document.createTextNode(e),i=document.createTextNode(i.trim()?i:" "),r.appendChild(e),r.appendChild(l),r.appendChild(i)),a.parentNode.replaceChild(r,a),this.update(),this.input.setRangeAtStartEnd.call(this,!0,i)}},addTags:function(t,e){var n=this,s=[];if(t=this.normalizeTags.call(this,t),"mix"==this.settings.mode)return this.addMixTag(t[0]);return this.DOM.input.removeAttribute("style"),t.forEach(function(t){var e,i;"function"==typeof n.settings.transformTag&&(t.value=n.settings.transformTag.call(n,t.value)||t.value),!0!==(e=n.validateTag.call(n,t.value))&&(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",t.title=e,n.markTagByValue(t.value),n.trigger("invalid",{value:t.value,index:n.value.length,message:e})),i=n.createTagElem(t),s.push(i),function(t){var e=this.DOM.scope.lastElementChild;e===this.DOM.input?this.DOM.scope.insertBefore(t,e):this.DOM.scope.appendChild(t)}.call(n,i),!0===e?(n.value.push(t),n.update(),n.trigger("add",n.extend({},{index:n.value.length,tag:i},t))):n.settings.keepInvalidTags||setTimeout(function(){n.removeTag(i,!0)},1e3)}),t.length&&e&&this.input.set.call(this),s},minify:function(t){return t.replace(new RegExp(">[\r\n ]+<","g"),"><")},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag title='"+i+"' contenteditable='false'>\n <x title=''></x><div><span>"+i+"</span></div>\n </tag>";if("function"==typeof this.settings.tagTemplate)try{n=this.settings.tagTemplate(i,t)}catch(t){}return n=this.minify(n),function(t,e){var i,n=Object.keys(e);for(i=n.length;i--;){var s=n[i];if(!e.hasOwnProperty(s))return;t.setAttribute(s,e[s])}}(e=this.parseHTML(n),t),e},removeTag:function(t,e){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:250;if(t&&t instanceof HTMLElement){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=this,a=this.getTagIndexByValue(t.textContent);i&&10<i?(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(o,400)):o(),e||(n=this.value.splice(a,1)[0],this.trigger("remove",this.extend({},{index:a,tag:t},n)))}function o(){t.parentNode&&(t.parentNode.removeChild(t),s.update())}},removeAllTags:function(){this.value=[],this.update(),Array.prototype.slice.call(this.DOM.scope.querySelectorAll("tag")).forEach(function(t){return t.parentNode.removeChild(t)})},update:function(){this.DOM.originalInput.value="mix"==this.settings.mode?this.DOM.input.textContent:JSON.stringify(this.value)},dropdown:{init:function(){this.DOM.dropdown=this.dropdown.build.call(this)},build:function(){var t='<div class="'+("tagify__dropdown "+this.settings.dropdown.classname).trim()+'"></div>';return this.parseHTML(t)},show:function(t){var e,i,n=this;this.settings.whitelist.length&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.filter(function(t){return-1==n.isTagDuplicate(t.value||t)}),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),i&&(this.DOM.dropdown.innerHTML=i,this.dropdown.position.call(this),!this.DOM.dropdown.parentNode!=document.body&&(document.body.appendChild(this.DOM.dropdown),this.events.binding.call(this,!1),this.dropdown.events.binding.call(this))))},hide:function(){this.DOM.dropdown&&this.DOM.dropdown.parentNode==document.body&&(document.body.removeChild(this.DOM.dropdown),window.removeEventListener("resize",this.dropdown.position),this.dropdown.events.binding.call(this,!1),this.events.binding.call(this))},position:function(){var t=this.DOM.scope.getBoundingClientRect();this.DOM.dropdown.style.cssText="left: "+(t.left+window.pageXOffset)+"px; top: "+(t.top+t.height-1+window.pageYOffset)+"px; width: "+t.width+"px"},events:{binding:function(){var t=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],e=this.listeners.dropdown=this.listeners.dropdown||{position:this.dropdown.position.bind(this),onKeyDown:this.dropdown.events.callbacks.onKeyDown.bind(this),onMouseOver:this.dropdown.events.callbacks.onMouseOver.bind(this),onClick:this.dropdown.events.callbacks.onClick.bind(this)},i=t?"addEventListener":"removeEventListener";window[i]("resize",e.position),window[i]("keydown",e.onKeyDown),window[i]("mousedown",e.onClick),this.DOM.dropdown[i]("mouseover",e.onMouseOver)},callbacks:{onKeyDown:function(t){var e=this.DOM.dropdown.querySelectorAll("[class$='--active']")[0],i="";switch(t.key){case"ArrowDown":case"ArrowUp":case"Down":case"Up":t.preventDefault(),e&&(e=e[("ArrowUp"==t.key||"Up"==t.key?"previous":"next")+"ElementSibling"]),e||(e=this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0]),this.dropdown.highlightOption.call(this,e,!0);break;case"Escape":case"Esc":this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":if(t.preventDefault(),!this.input.autocomplete.set.call(this,e?e.textContent:null))return!1;case"Enter":return t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this),!1}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){var e,i=this,n=function(){return i.dropdown.hide.call(i)};if(0==t.button){if(t.target==document.documentElement)return n();(e=[t.target,t.target.parentNode].filter(function(t){return t.className.includes("tagify__dropdown__item")})[0])?(this.addTags(e.textContent,!0),this.dropdown.hide.call(this)):n()}}}},highlightOption:function(t,e){if(t){var i="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){return t.classList.remove(i)}),t.classList.add(i),e&&(t.parentNode.scrollTop=t.clientHeight+t.offsetTop-t.parentNode.clientHeight)}},filterListItems:function(t){if(!t)return"";for(var e,i=[],n=this.settings.whitelist,s=this.settings.dropdown.maxItems||1/0,a=0;a<n.length&&(0==(e=n[a]instanceof Object?n[a]:{value:n[a]}).value.toLowerCase().indexOf(t.toLowerCase())&&-1==this.isTagDuplicate(e.value)&&s--&&i.push(e),0!=s);a++);return i},createListHTML:function(t){var e=this.settings.dropdown.itemTemplate||function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+function(t){var e,i=Object.keys(t),n="";for(e=i.length;e--;){var s=i[e];if("class"!=s&&!t.hasOwnProperty(s))return;n+=" "+s+(t[s]?"="+t[s]:"")}return n}(t)+">"+(t.value||t)+"</div>"};return t.map(e).join("")}}}}(jQuery); | ||
"use strict";!function(a){function n(t,e){if(!t)return console.warn("Tagify: ","invalid input element ",t),this;if(this.settings=this.extend({},this.DEFAULTS,e),this.settings.readonly=t.hasAttribute("readonly"),this.isIE&&(this.settings.autoComplete=!1),t.pattern)try{this.settings.pattern=new RegExp(t.pattern)}catch(t){}if(this.settings&&this.settings.delimiters)try{this.settings.delimiters=new RegExp("["+this.settings.delimiters+"]","g")}catch(t){}this.state={},this.value=[],this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),this.loadOriginalValues(),this.events.customBinding.call(this),this.events.binding.call(this)}a.fn.tagify=function(){var i=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};return this.each(function(){var t,e=a(this);if(e.data("tagify"))return this;i.isJQueryPlugin=!0,t=new n(e[0],i),e.data("tagify",t)})},n.prototype={isIE:window.document.documentMode,TEXTS:{empty:"empty",exceed:"number of tags exceeded",pattern:"pattern mismatch",duplicate:"already exists",notAllowed:"not allowed"},DEFAULTS:{delimiters:",",pattern:null,maxTags:1/0,callbacks:{},addTagOnBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,keepInvalidTags:!1,autoComplete:!0,mixTagsAllowedAfter:/,|\.|\:|\s/,dropdown:{classname:"",enabled:2,maxItems:10,itemTemplate:""}},customEventsList:["add","remove","invalid","input"],parseHTML:function(t){return(new DOMParser).parseFromString(t.trim(),"text/html").body.firstElementChild},escapeHtml:function(t){var e=document.createTextNode(t),i=document.createElement("p");return i.appendChild(e),i.innerHTML},build:function(t){var e=this.DOM,i='<tags class="tagify '+(this.settings.mode?"tagify--mix":"")+" "+t.className+'" '+(this.settings.readonly?"readonly":"")+'>\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify__input"></div>\n </tags>';e.originalInput=t,e.scope=this.parseHTML(i),e.input=e.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(e.scope,t),0<=this.settings.dropdown.enabled&&this.dropdown.init.call(this),t.autofocus&&e.input.focus()},destroy:function(){this.DOM.scope.parentNode.removeChild(this.DOM.scope)},loadOriginalValues:function(){var t=this.DOM.originalInput.value;if(t){try{t=JSON.parse(t)}catch(t){}"mix"==this.settings.mode?this.parseMixTags(t):this.addTags(t).forEach(function(t){t&&t.classList.add("tagify--noAnim")})}},extend:function(t,e,i){function n(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 s(t,e){for(var i in e)e.hasOwnProperty(i)&&(n(e[i])?n(t[i])?s(t[i],e[i]):t[i]=Object.assign({},e[i]):t[i]=e[i])}return t instanceof Object||(t={}),s(t,e),i&&s(t,i),t},EventDispatcher:function(n){var s=document.createTextNode("");this.off=function(t,e){return e&&s.removeEventListener.call(s,t,e),this},this.on=function(t,e){return e&&s.addEventListener.call(s,t,e),this},this.trigger=function(t,e){var i;if(t)if(n.settings.isJQueryPlugin)a(n.DOM.originalInput).triggerHandler(t,[e]);else{try{i=new CustomEvent(t,{detail:e})}catch(t){console.warn(t)}s.dispatchEvent(i)}}},events:{customBinding:function(){var e=this;this.customEventsList.forEach(function(t){e.on(t,e.settings.callbacks[t])})},binding:function(){var t,e=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],i=this.events.callbacks,n=e?"addEventListener":"removeEventListener";for(var s in e&&!this.listeners.main&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",i[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&a(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this))),t=this.listeners.main=this.listeners.main||{paste:["input",i.onPaste.bind(this)],focus:["input",i.onFocusBlur.bind(this)],blur:["input",i.onFocusBlur.bind(this)],keydown:["input",i.onKeydown.bind(this)],click:["scope",i.onClickScope.bind(this)]})this.DOM[t[s][0]][n](s,t[s][1])},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"mix"!=this.settings.mode&&("focus"==t.type?0===this.settings.dropdown.enabled&&this.dropdown.show.call(this):"blur"==t.type&&e?this.settings.addTagOnBlur&&this.addTags(e,!0).length:(this.DOM.input.removeAttribute("style"),this.dropdown.hide.call(this)))},onKeydown:function(t){var e,i,n=this,s=t.target.textContent;if("mix"==this.settings.mode){switch(t.key){case"Backspace":var a=[];i=this.DOM.input.children,setTimeout(function(){[].forEach.call(i,function(t){return a.push(t.title)}),n.value=n.value.filter(function(t){return-1!=a.indexOf(t.title)})},20)}return!0}switch(t.key){case"Backspace":""!=s&&8203!=s.charCodeAt(0)||(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide):not([readonly])"))[e.length-1],this.removeTag(e));break;case"Esc":case"Escape":this.input.set.call(this),t.target.blur();break;case"ArrowRight":case"Tab":if(!s)return!0;case"Enter":t.preventDefault(),this.addTags(this.input.value,!0)}},onInput:function(t){var e=this.input.normalize.call(this),i=e.length>=this.settings.dropdown.enabled;if("mix"==this.settings.mode)return this.events.callbacks.onMixTagsInput.call(this,t);e?this.input.value!=e&&(this.input.set.call(this,e,!1),this.trigger("input",{value:e}),-1!=e.search(this.settings.delimiters)?this.addTags(e).length&&this.input.set.call(this):0<=this.settings.dropdown.enabled&&this.dropdown[i?"show":"hide"].call(this,e)):this.input.set.call(this,"")},onMixTagsInput:function(t){var e,i,n,s,a;window.getSelection&&0<(e=window.getSelection()).rangeCount&&((i=e.getRangeAt(0).cloneRange()).collapse(!0),i.setStart(window.getSelection().focusNode,0),(s=(n=i.toString().split(this.settings.mixTagsAllowedAfter))[n.length-1].match(this.settings.pattern))&&(this.state.tag={prefix:s[0],value:s.input.split(s[0])[1]},this.trigger("input",{prefix:s[0],value:this.state.tag.value}),s=this.state.tag,a=this.state.tag.value.length>=this.settings.dropdown.enabled)),this.state.tag&&(this.dropdown[a?"show":"hide"].call(this,this.state.tag.value),this.update())},onInputIE:function(t){var e=this;setTimeout(function(){e.events.callbacks.onInput.call(e,t)})},onPaste:function(t){},onClickScope:function(t){"TAGS"==t.target.tagName?this.DOM.input.focus():"X"==t.target.tagName&&this.removeTag(t.target.parentNode)}}},input:{value:"",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=!(1<arguments.length&&void 0!==arguments[1])||arguments[1];this.input.value=t,e&&(this.DOM.input.innerHTML=t),t||this.dropdown.hide.call(this),t.length<2&&this.input.autocomplete.suggest.call(this,""),this.input.validate.call(this)},setRangeAtStartEnd:function(){var t,e,i=0<arguments.length&&void 0!==arguments[0]&&arguments[0],n=arguments[1];document.createRange&&((t=document.createRange()).selectNodeContents(n||this.DOM.input),t.collapse(i),(e=window.getSelection()).removeAllRanges(),e.addRange(t))},validate:function(){var t=!this.input.value||this.validateTag.call(this,this.input.value);this.DOM.input.classList.toggle("tagify__input--invalid",!0!==t)},normalize:function(){for(var t=this.DOM.input.cloneNode(!0),e=t.textContent.replace(/\s/g," ");t.firstElementChild;)e+=t.firstElementChild.textContent,t.removeChild(t.firstElementChild);return e.replace(/^\s+/,"")},autocomplete:{suggest:function(t){t&&this.input.value?this.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(t){var e=this.DOM.input.getAttribute("data-suggest"),i=t||(e?this.input.value+e:null);return!!i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtStartEnd.call(this),!0)}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(e){return this.value.findIndex(function(t){return e.trim().toLowerCase()===t.value.toLowerCase()})},getTagIndexByValue:function(i){var n=[];return this.DOM.scope.querySelectorAll("tag").forEach(function(t,e){t.textContent.trim().toLowerCase()==i.toLowerCase()&&n.push(e)}),n},getTagElmByValue:function(t){var e=this.getTagIndexByValue(t)[0];return this.DOM.scope.querySelectorAll("tag")[e]},markTagByValue:function(t,e){return!!(e=e||this.getTagElmByValue(t))&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},100),e)},isTagBlacklisted:function(e){return e=e.split(" "),this.settings.blacklist.filter(function(t){return-1!=e.indexOf(t)}).length},isTagWhitelisted:function(e){return this.settings.whitelist.some(function(t){if((t.value||t).toLowerCase()===e.toLowerCase())return!0})},validateTag:function(t){var e=t.trim(),i=this.value.length>=this.settings.maxTags,n=!0;return e?i?n=this.TEXTS.exceed:this.settings.pattern&&!this.settings.pattern.test(e)?n=this.TEXTS.pattern:this.settings.duplicates||-1===this.isTagDuplicate(e)?(this.isTagBlacklisted(e)||this.settings.enforceWhitelist&&!this.isTagWhitelisted(e))&&(n=this.TEXTS.notAllowed):n=this.TEXTS.duplicate:n=this.TEXTS.empty,n},normalizeTags:function(t){var i=this,e=this.settings.whitelist[0]instanceof Object,n=t instanceof Array&&t[0]instanceof Object&&"value"in t[0],s=[];if(n)return t;if("string"==typeof t){if(!t.trim())return[];t=t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}})}else t instanceof Array&&(t=t.map(function(t){return{value:t.trim()}}));return e?(t.forEach(function(e){var t=i.settings.whitelist.filter(function(t){return t.value.toLowerCase()==e.value.toLowerCase()});t[0]?s.push(t[0]):"mix"!=i.settings.mode&&s.push(e)}),s):t},parseMixTags:function(n){var s=this;return n.split(this.settings.mixTagsAllowedAfter).filter(function(t){return t.match(s.settings.pattern)}).forEach(function(t){var e,i=t.replace(s.settings.pattern,"");s.isTagWhitelisted(i)&&(e=s.normalizeTags.call(s,i)[0],n=s.replaceMixStringWithTag(n,t,e).s)}),this.DOM.input.innerHTML=n,this.update(),n},replaceMixStringWithTag:function(t,e,i,n){return i&&t&&-1!=t.indexOf(e)&&(n=this.createTagElem(i),this.value.push(i),t=t.replace(e,n.outerHTML+"⁠")),{s:t,tagElm:n}},addMixTag:function(t){if(t&&this.state.tag){for(var e,i,n,s,a=this.state.tag.prefix+this.state.tag.value,o=document.createNodeIterator(this.DOM.input,NodeFilter.SHOW_TEXT);e=o.nextNode();)if(e.nodeType===Node.TEXT_NODE){if(-1==(n=e.nodeValue.indexOf(a)))continue;s=e.splitText(n),i=this.createTagElem(t),s.nodeValue=s.nodeValue.replace(a,""),e.parentNode.insertBefore(i,s),i.insertAdjacentHTML("afterend","⁠")}i&&(this.value.push(t),this.update(),this.trigger("add",this.extend({},{index:this.value.length,tag:i},t))),this.state.tag=null}},addTags:function(t,e){var n=this,s=[];if(t=this.normalizeTags.call(this,t),"mix"==this.settings.mode)return this.addMixTag(t[0]);return this.DOM.input.removeAttribute("style"),t.forEach(function(t){var e,i;"function"==typeof n.settings.transformTag&&(t.value=n.settings.transformTag.call(n,t.value)||t.value),!0!==(e=n.validateTag.call(n,t.value))&&(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",t.title=e,n.markTagByValue(t.value),n.trigger("invalid",{value:t.value,index:n.value.length,message:e})),i=n.createTagElem(t),s.push(i),function(t){var e=this.DOM.scope.lastElementChild;e===this.DOM.input?this.DOM.scope.insertBefore(t,e):this.DOM.scope.appendChild(t)}.call(n,i),!0===e?(n.value.push(t),n.update(),n.trigger("add",n.extend({},{index:n.value.length,tag:i},t))):n.settings.keepInvalidTags||setTimeout(function(){n.removeTag(i,!0)},1e3)}),t.length&&e&&this.input.set.call(this),s},minify:function(t){return t.replace(new RegExp(">[\r\n ]+<","g"),"><")},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag title='"+i+"' contenteditable='false'>\n <x title=''></x><div><span>"+i+"</span></div>\n </tag>";if("function"==typeof this.settings.tagTemplate)try{n=this.settings.tagTemplate(i,t)}catch(t){}return n=this.minify(n),function(t,e){var i,n=Object.keys(e);for(i=n.length;i--;){var s=n[i];if(!e.hasOwnProperty(s))return;t.setAttribute(s,e[s])}}(e=this.parseHTML(n),t),e},removeTag:function(t,e){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:250;if(t&&t instanceof HTMLElement){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=this,a=this.getTagIndexByValue(t.textContent);i&&10<i?(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(o,400)):o(),e||(n=this.value.splice(a,1)[0],this.trigger("remove",this.extend({},{index:a,tag:t},n)))}function o(){t.parentNode&&(t.parentNode.removeChild(t),s.update())}},removeAllTags:function(){this.value=[],this.update(),Array.prototype.slice.call(this.DOM.scope.querySelectorAll("tag")).forEach(function(t){return t.parentNode.removeChild(t)})},update:function(){this.DOM.originalInput.value="mix"==this.settings.mode?this.DOM.input.textContent:JSON.stringify(this.value)},dropdown:{init:function(){this.DOM.dropdown=this.dropdown.build.call(this)},build:function(){var t='<div class="'+("tagify__dropdown "+this.settings.dropdown.classname).trim()+'"></div>';return this.parseHTML(t)},show:function(t){var e,i,n=this;this.settings.whitelist.length&&this.settings.dropdown.enabled&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.filter(function(t){return-1==n.isTagDuplicate(t.value||t)}),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),i&&(this.DOM.dropdown.innerHTML=i,this.dropdown.position.call(this),!this.DOM.dropdown.parentNode!=document.body&&(document.body.appendChild(this.DOM.dropdown),this.events.binding.call(this,!1),this.dropdown.events.binding.call(this))))},hide:function(){this.DOM.dropdown&&this.DOM.dropdown.parentNode==document.body&&(document.body.removeChild(this.DOM.dropdown),window.removeEventListener("resize",this.dropdown.position),this.dropdown.events.binding.call(this,!1),this.events.binding.call(this))},position:function(){var t=this.DOM.scope.getBoundingClientRect();this.DOM.dropdown.style.cssText="left: "+(t.left+window.pageXOffset)+"px; top: "+(t.top+t.height-1+window.pageYOffset)+"px; width: "+t.width+"px"},events:{binding:function(){var t=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],e=this.listeners.dropdown=this.listeners.dropdown||{position:this.dropdown.position.bind(this),onKeyDown:this.dropdown.events.callbacks.onKeyDown.bind(this),onMouseOver:this.dropdown.events.callbacks.onMouseOver.bind(this),onClick:this.dropdown.events.callbacks.onClick.bind(this)},i=t?"addEventListener":"removeEventListener";window[i]("resize",e.position),window[i]("keydown",e.onKeyDown),window[i]("mousedown",e.onClick),this.DOM.dropdown[i]("mouseover",e.onMouseOver)},callbacks:{onKeyDown:function(t){var e=this.DOM.dropdown.querySelectorAll("[class$='--active']")[0],i="";switch(t.key){case"ArrowDown":case"ArrowUp":case"Down":case"Up":t.preventDefault(),e&&(e=e[("ArrowUp"==t.key||"Up"==t.key?"previous":"next")+"ElementSibling"]),e||(e=this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0]),this.dropdown.highlightOption.call(this,e,!0);break;case"Escape":case"Esc":this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":if(t.preventDefault(),!this.input.autocomplete.set.call(this,e?e.textContent:null))return!1;case"Enter":return t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this),!1}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){var e,i=this,n=function(){return i.dropdown.hide.call(i)};if(0==t.button){if(t.target==document.documentElement)return n();(e=[t.target,t.target.parentNode].filter(function(t){return t.className.includes("tagify__dropdown__item")})[0])?(this.addTags(e.textContent,!0),this.dropdown.hide.call(this)):n()}}}},highlightOption:function(t,e){if(t){var i="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){return t.classList.remove(i)}),t.classList.add(i),e&&(t.parentNode.scrollTop=t.clientHeight+t.offsetTop-t.parentNode.clientHeight)}},filterListItems:function(t){if(!t)return"";for(var e,i=[],n=this.settings.whitelist,s=this.settings.dropdown.maxItems||1/0,a=0;a<n.length&&(0==(e=n[a]instanceof Object?n[a]:{value:n[a]}).value.toLowerCase().indexOf(t.toLowerCase())&&-1==this.isTagDuplicate(e.value)&&s--&&i.push(e),0!=s);a++);return i},createListHTML:function(t){var e=this.settings.dropdown.itemTemplate||function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+function(t){var e,i=Object.keys(t),n="";for(e=i.length;e--;){var s=i[e];if("class"!=s&&!t.hasOwnProperty(s))return;n+=" "+s+(t[s]?"="+t[s]:"")}return n}(t)+">"+(t.value||t)+"</div>"};return t.map(e).join("")}}}}(jQuery); |
/** | ||
* Tagify (v 2.6.6)- tags input component | ||
* Tagify (v 2.7.0)- tags input component | ||
* By Yair Even-Or (2016) | ||
@@ -87,2 +87,4 @@ * Don't sell this code. (c) | ||
// Flag - tries to autocomplete the input's value while typing | ||
mixTagsAllowedAfter: /,|\.|\:|\s/, | ||
// RegEx - Define conditions in which mix-tags content is allowing a tag to be added after | ||
dropdown: { | ||
@@ -97,2 +99,5 @@ classname: '', | ||
customEventsList: ['add', 'remove', 'invalid', 'input'], | ||
// generateUID(){ | ||
// return Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36) | ||
// }, | ||
@@ -158,3 +163,3 @@ /** | ||
if (this.settings.mode == 'mix') { | ||
this.DOM.input.innerHTML = this.parseMixTags(value); | ||
this.parseMixTags(value); | ||
} else this.addTags(value).forEach(function (tag) { | ||
@@ -296,9 +301,34 @@ tag && tag.classList.add('tagify--noAnim'); | ||
onKeydown: function onKeydown(e) { | ||
var _this3 = this; | ||
var s = e.target.textContent, | ||
lastTag; | ||
if (this.settings.mode == 'mix') return; | ||
lastTag, | ||
tags; | ||
if (this.settings.mode == 'mix') { | ||
switch (e.key) { | ||
case 'Backspace': | ||
var values = []; // find out which tag(s) were deleted and update "this.value" accordingly | ||
tags = this.DOM.input.children; // a delay is in need before the node actually is ditached from the document | ||
setTimeout(function () { | ||
// iterate over the list of tags still in the document and then filter only those from the "this.value" collection | ||
[].forEach.call(tags, function (tagElm) { | ||
return values.push(tagElm.title); | ||
}); | ||
_this3.value = _this3.value.filter(function (d) { | ||
return values.indexOf(d.title) != -1; | ||
}); | ||
}, 20); | ||
break; | ||
} | ||
return true; | ||
} | ||
switch (e.key) { | ||
case 'Backspace': | ||
if (s == "" || s.charCodeAt(0) == 8203) { | ||
// 8203: ZERO WIDTH SPACE unicode | ||
lastTag = this.DOM.scope.querySelectorAll('tag:not(.tagify--hide):not([readonly])'); | ||
@@ -354,8 +384,3 @@ lastTag = lastTag[lastTag.length - 1]; | ||
onMixTagsInput: function onMixTagsInput(e) { | ||
var sel, | ||
range, | ||
split, | ||
tag, | ||
patternLen = this.settings.pattern.length; | ||
this.state.tag = null; | ||
var sel, range, split, tag, showSuggestions; | ||
@@ -369,14 +394,25 @@ if (window.getSelection) { | ||
range.setStart(window.getSelection().focusNode, 0); | ||
split = range.toString().split(/,|\.|\s/); // ["foo", "bar", "@a"] | ||
split = range.toString().split(this.settings.mixTagsAllowedAfter); // ["foo", "bar", "@a"] | ||
tag = split[split.length - 1]; | ||
tag = this.state.tag = tag.substr(0, patternLen) == this.settings.pattern && tag.length > patternLen ? tag.slice(patternLen) : null; | ||
this.trigger("input", { | ||
value: tag | ||
}); | ||
tag = split[split.length - 1].match(this.settings.pattern); | ||
if (tag) { | ||
this.state.tag = { | ||
prefix: tag[0], | ||
value: tag.input.split(tag[0])[1] | ||
}; | ||
this.trigger("input", { | ||
prefix: tag[0], | ||
value: this.state.tag.value | ||
}); | ||
tag = this.state.tag; | ||
showSuggestions = this.state.tag.value.length >= this.settings.dropdown.enabled; | ||
} | ||
} | ||
} | ||
this.dropdown[tag ? "show" : "hide"].call(this, tag); | ||
this.update(); | ||
if (this.state.tag) { | ||
this.dropdown[showSuggestions ? "show" : "hide"].call(this, this.state.tag.value); | ||
this.update(); | ||
} | ||
}, | ||
@@ -572,3 +608,3 @@ onInputIE: function onInputIE(e) { | ||
normalizeTags: function normalizeTags(tagsItems) { | ||
var _this3 = this; | ||
var _this4 = this; | ||
@@ -601,3 +637,3 @@ var whitelistWithProps = this.settings.whitelist[0] instanceof Object, | ||
tagsItems.forEach(function (tag) { | ||
var matchObj = _this3.settings.whitelist.filter(function (WL_item) { | ||
var matchObj = _this4.settings.whitelist.filter(function (WL_item) { | ||
return WL_item.value.toLowerCase() == tag.value.toLowerCase(); | ||
@@ -607,3 +643,3 @@ }); | ||
if (matchObj[0]) temp.push(matchObj[0]); // set the Array (with the found Object) as the new value | ||
else if (_this3.settings.mode != 'mix') temp.push(tag); | ||
else if (_this4.settings.mode != 'mix') temp.push(tag); | ||
}); | ||
@@ -616,23 +652,39 @@ return temp; | ||
parseMixTags: function parseMixTags(s) { | ||
var _this4 = this; | ||
var _this5 = this; | ||
var htmlString = ''; | ||
s = s.split(this.settings.pattern); // this.DOM.scope.innerHTML | ||
// example: "@cartman ,@kyle do not know:#homer".split(/,|\.|\:|\s/).filter(item => item.match(/@|#/) ) | ||
s.split(this.settings.mixTagsAllowedAfter).filter(function (item) { | ||
return item.match(_this5.settings.pattern); | ||
}).forEach(function (tag) { | ||
var value = tag.replace(_this5.settings.pattern, ''), | ||
tagData; | ||
htmlString = s.shift() + s.map(function (part) { | ||
var tagElm, i, tagData; | ||
if (!part) return ''; | ||
if (_this5.isTagWhitelisted(value)) { | ||
tagData = _this5.normalizeTags.call(_this5, value)[0]; | ||
s = _this5.replaceMixStringWithTag(s, tag, tagData).s; | ||
} | ||
}); | ||
this.DOM.input.innerHTML = s; | ||
this.update(); | ||
return s; | ||
}, | ||
for (i in part) { | ||
if (part[i].match(/,|\.| /)) { | ||
tagData = _this4.normalizeTags.call(_this4, part.substr(0, i))[0]; | ||
if (tagData) tagElm = _this4.createTagElem(tagData);else i = 0; // a tag was found but was not in the whitelist, so reset the "i" index | ||
/** | ||
* [replaceMixStringWithTag description] | ||
* @param {String} s [whole string] | ||
* @param {String} tag [tag string to replace with tag element] | ||
* @param {Object} tagData [value, plus any other optional attributes] | ||
* @return {[type]} [description] | ||
*/ | ||
replaceMixStringWithTag: function replaceMixStringWithTag(s, tag, tagData, tagElm) { | ||
if (tagData && s && s.indexOf(tag) != -1) { | ||
tagElm = this.createTagElem(tagData); | ||
this.value.push(tagData); | ||
s = s.replace(tag, tagElm.outerHTML + "⁠"); // put a zero-space at the end to the caret won't jump back to the start (when the last input child is a tag) | ||
} | ||
break; | ||
} | ||
} | ||
return tagElm ? tagElm.outerHTML + part.slice(i) : _this4.settings.pattern + part; | ||
}).join(''); | ||
return htmlString; | ||
return { | ||
s: s, | ||
tagElm: tagElm | ||
}; | ||
}, | ||
@@ -644,29 +696,34 @@ | ||
addMixTag: function addMixTag(tagData) { | ||
if (!tagData) return; | ||
var sel = window.getSelection(), | ||
node = sel.focusNode, | ||
nodeText = node.textContent, | ||
wrapElm = document.createDocumentFragment(), | ||
tagElm = this.createTagElem(tagData), | ||
textNodeBefore, | ||
textNodeAfter, | ||
range, | ||
parrernLen = this.settings.pattern.length; | ||
if (!tagData || !this.state.tag) return; | ||
var tag = this.state.tag.prefix + this.state.tag.value, | ||
iter = document.createNodeIterator(this.DOM.input, NodeFilter.SHOW_TEXT), | ||
textnode, | ||
tagElm, | ||
idx, | ||
replacedNode; | ||
if (sel.rangeCount > 0) { | ||
range = sel.getRangeAt(0).cloneRange(); | ||
range.collapse(true); | ||
range.setStart(node, 0); | ||
textNodeBefore = range.toString().slice(0, -this.state.tag.length - parrernLen); | ||
textNodeAfter = nodeText.slice(textNodeBefore.length + this.state.tag.length + parrernLen, nodeText.length); | ||
textNodeBefore = document.createTextNode(textNodeBefore); | ||
textNodeAfter = document.createTextNode(textNodeAfter.trim() ? textNodeAfter : " \u200B"); | ||
wrapElm.appendChild(textNodeBefore); | ||
wrapElm.appendChild(tagElm); | ||
wrapElm.appendChild(textNodeAfter); | ||
while (textnode = iter.nextNode()) { | ||
if (textnode.nodeType === Node.TEXT_NODE) { | ||
// get the index of which the tag (string) is within the textNode (if at all) | ||
idx = textnode.nodeValue.indexOf(tag); | ||
if (idx == -1) continue; | ||
replacedNode = textnode.splitText(idx); | ||
tagElm = this.createTagElem(tagData); // clean up the tag's string and put tag element instead | ||
replacedNode.nodeValue = replacedNode.nodeValue.replace(tag, ''); | ||
textnode.parentNode.insertBefore(tagElm, replacedNode); | ||
tagElm.insertAdjacentHTML('afterend', '⁠'); | ||
} | ||
} | ||
node.parentNode.replaceChild(wrapElm, node); | ||
this.update(); | ||
this.input.setRangeAtStartEnd.call(this, true, textNodeAfter); | ||
if (tagElm) { | ||
this.value.push(tagData); | ||
this.update(); | ||
this.trigger('add', this.extend({}, { | ||
index: this.value.length, | ||
tag: tagElm | ||
}, tagData)); | ||
} | ||
this.state.tag = null; | ||
}, | ||
@@ -681,3 +738,3 @@ | ||
addTags: function addTags(tagsItems, clearInput) { | ||
var _this5 = this; | ||
var _this6 = this; | ||
@@ -691,7 +748,7 @@ var tagElems = []; | ||
if (typeof _this5.settings.transformTag === 'function') { | ||
tagData.value = _this5.settings.transformTag.call(_this5, tagData.value) || tagData.value; | ||
if (typeof _this6.settings.transformTag === 'function') { | ||
tagData.value = _this6.settings.transformTag.call(_this6, tagData.value) || tagData.value; | ||
} | ||
tagValidation = _this5.validateTag.call(_this5, tagData.value); | ||
tagValidation = _this6.validateTag.call(_this6, tagData.value); | ||
@@ -702,7 +759,7 @@ if (tagValidation !== true) { | ||
_this5.markTagByValue(tagData.value); | ||
_this6.markTagByValue(tagData.value); | ||
_this5.trigger("invalid", { | ||
_this6.trigger("invalid", { | ||
value: tagData.value, | ||
index: _this5.value.length, | ||
index: _this6.value.length, | ||
message: tagValidation | ||
@@ -713,21 +770,21 @@ }); | ||
tagElm = _this5.createTagElem(tagData); | ||
tagElm = _this6.createTagElem(tagData); | ||
tagElems.push(tagElm); // add the tag to the component's DOM | ||
appendTag.call(_this5, tagElm); | ||
appendTag.call(_this6, tagElm); | ||
if (tagValidation === true) { | ||
// update state | ||
_this5.value.push(tagData); | ||
_this6.value.push(tagData); | ||
_this5.update(); | ||
_this6.update(); | ||
_this5.trigger('add', _this5.extend({}, { | ||
index: _this5.value.length, | ||
_this6.trigger('add', _this6.extend({}, { | ||
index: _this6.value.length, | ||
tag: tagElm | ||
}, tagData)); | ||
} else if (!_this5.settings.keepInvalidTags) { | ||
} else if (!_this6.settings.keepInvalidTags) { | ||
// remove invalid tags (if "keepInvalidTags" is set to "false") | ||
setTimeout(function () { | ||
_this5.removeTag(tagElm, true); | ||
_this6.removeTag(tagElm, true); | ||
}, 1000); | ||
@@ -771,3 +828,3 @@ } | ||
} catch (err) {} | ||
} // for a certain Tag element, add attributes. | ||
} // add HTML attributes from tagData | ||
@@ -867,10 +924,10 @@ | ||
show: function show(value) { | ||
var _this6 = this; | ||
var _this7 = this; | ||
var listItems, listHTML; | ||
if (!this.settings.whitelist.length) return; // if no value was supplied, show all the "whitelist" items in the dropdown | ||
if (!this.settings.whitelist.length || !this.settings.dropdown.enabled) return; // if no value was supplied, show all the "whitelist" items in the dropdown | ||
// @type [Array] listItems | ||
listItems = value ? this.dropdown.filterListItems.call(this, value) : this.settings.whitelist.filter(function (item) { | ||
return _this6.isTagDuplicate(item.value || item) == -1; | ||
return _this7.isTagDuplicate(item.value || item) == -1; | ||
}); // don't include already preset tags | ||
@@ -985,6 +1042,6 @@ | ||
onClick: function onClick(e) { | ||
var _this7 = this; | ||
var _this8 = this; | ||
var onClickOutside = function onClickOutside() { | ||
return _this7.dropdown.hide.call(_this7); | ||
return _this8.dropdown.hide.call(_this8); | ||
}, | ||
@@ -991,0 +1048,0 @@ listItemElm; |
@@ -1,1 +0,1 @@ | ||
!function(t,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?module.exports=e():t.Tagify=e()}(this,function(){"use strict";function t(t,e){if(!t)return console.warn("Tagify: ","invalid input element ",t),this;if(this.settings=this.extend({},this.DEFAULTS,e),this.settings.readonly=t.hasAttribute("readonly"),this.isIE&&(this.settings.autoComplete=!1),t.pattern)try{this.settings.pattern=new RegExp(t.pattern)}catch(t){}if(this.settings&&this.settings.delimiters)try{this.settings.delimiters=new RegExp("["+this.settings.delimiters+"]","g")}catch(t){}this.state={},this.value=[],this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),this.loadOriginalValues(),this.events.customBinding.call(this),this.events.binding.call(this)}return t.prototype={isIE:window.document.documentMode,TEXTS:{empty:"empty",exceed:"number of tags exceeded",pattern:"pattern mismatch",duplicate:"already exists",notAllowed:"not allowed"},DEFAULTS:{delimiters:",",pattern:null,maxTags:1/0,callbacks:{},addTagOnBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,keepInvalidTags:!1,autoComplete:!0,dropdown:{classname:"",enabled:2,maxItems:10,itemTemplate:""}},customEventsList:["add","remove","invalid","input"],parseHTML:function(t){return(new DOMParser).parseFromString(t.trim(),"text/html").body.firstElementChild},escapeHtml:function(t){var e=document.createTextNode(t),i=document.createElement("p");return i.appendChild(e),i.innerHTML},build:function(t){var e=this.DOM,i='<tags class="tagify '+(this.settings.mode?"tagify--mix":"")+" "+t.className+'" '+(this.settings.readonly?"readonly":"")+'>\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify__input"></div>\n </tags>';e.originalInput=t,e.scope=this.parseHTML(i),e.input=e.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(e.scope,t),0<=this.settings.dropdown.enabled&&this.dropdown.init.call(this),t.autofocus&&e.input.focus()},destroy:function(){this.DOM.scope.parentNode.removeChild(this.DOM.scope)},loadOriginalValues:function(){var t=this.DOM.originalInput.value;if(t){try{t=JSON.parse(t)}catch(t){}"mix"==this.settings.mode?this.DOM.input.innerHTML=this.parseMixTags(t):this.addTags(t).forEach(function(t){t&&t.classList.add("tagify--noAnim")})}},extend:function(t,e,i){function n(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 s(t,e){for(var i in e)e.hasOwnProperty(i)&&(n(e[i])?n(t[i])?s(t[i],e[i]):t[i]=Object.assign({},e[i]):t[i]=e[i])}return t instanceof Object||(t={}),s(t,e),i&&s(t,i),t},EventDispatcher:function(n){var s=document.createTextNode("");this.off=function(t,e){return e&&s.removeEventListener.call(s,t,e),this},this.on=function(t,e){return e&&s.addEventListener.call(s,t,e),this},this.trigger=function(t,e){var i;if(t)if(n.settings.isJQueryPlugin)$(n.DOM.originalInput).triggerHandler(t,[e]);else{try{i=new CustomEvent(t,{detail:e})}catch(t){console.warn(t)}s.dispatchEvent(i)}}},events:{customBinding:function(){var e=this;this.customEventsList.forEach(function(t){e.on(t,e.settings.callbacks[t])})},binding:function(){var t,e=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],i=this.events.callbacks,n=e?"addEventListener":"removeEventListener";for(var s in e&&!this.listeners.main&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",i[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&$(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this))),t=this.listeners.main=this.listeners.main||{paste:["input",i.onPaste.bind(this)],focus:["input",i.onFocusBlur.bind(this)],blur:["input",i.onFocusBlur.bind(this)],keydown:["input",i.onKeydown.bind(this)],click:["scope",i.onClickScope.bind(this)]})this.DOM[t[s][0]][n](s,t[s][1])},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"mix"!=this.settings.mode&&("focus"==t.type?0===this.settings.dropdown.enabled&&this.dropdown.show.call(this):"blur"==t.type&&e?this.settings.addTagOnBlur&&this.addTags(e,!0).length:(this.DOM.input.removeAttribute("style"),this.dropdown.hide.call(this)))},onKeydown:function(t){var e,i=t.target.textContent;if("mix"!=this.settings.mode)switch(t.key){case"Backspace":""!=i&&8203!=i.charCodeAt(0)||(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide):not([readonly])"))[e.length-1],this.removeTag(e));break;case"Esc":case"Escape":this.input.set.call(this),t.target.blur();break;case"ArrowRight":case"Tab":if(!i)return!0;case"Enter":t.preventDefault(),this.addTags(this.input.value,!0)}},onInput:function(t){var e=this.input.normalize.call(this),i=e.length>=this.settings.dropdown.enabled;if("mix"==this.settings.mode)return this.events.callbacks.onMixTagsInput.call(this,t);e?this.input.value!=e&&(this.input.set.call(this,e,!1),this.trigger("input",{value:e}),-1!=e.search(this.settings.delimiters)?this.addTags(e).length&&this.input.set.call(this):0<=this.settings.dropdown.enabled&&this.dropdown[i?"show":"hide"].call(this,e)):this.input.set.call(this,"")},onMixTagsInput:function(t){var e,i,n,s,a=this.settings.pattern.length;this.state.tag=null,window.getSelection&&0<(e=window.getSelection()).rangeCount&&((i=e.getRangeAt(0).cloneRange()).collapse(!0),i.setStart(window.getSelection().focusNode,0),s=(n=i.toString().split(/,|\.|\s/))[n.length-1],s=this.state.tag=s.substr(0,a)==this.settings.pattern&&s.length>a?s.slice(a):null,this.trigger("input",{value:s})),this.dropdown[s?"show":"hide"].call(this,s),this.update()},onInputIE:function(t){var e=this;setTimeout(function(){e.events.callbacks.onInput.call(e,t)})},onPaste:function(t){},onClickScope:function(t){"TAGS"==t.target.tagName?this.DOM.input.focus():"X"==t.target.tagName&&this.removeTag(t.target.parentNode)}}},input:{value:"",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=!(1<arguments.length&&void 0!==arguments[1])||arguments[1];this.input.value=t,e&&(this.DOM.input.innerHTML=t),t||this.dropdown.hide.call(this),t.length<2&&this.input.autocomplete.suggest.call(this,""),this.input.validate.call(this)},setRangeAtStartEnd:function(){var t,e,i=0<arguments.length&&void 0!==arguments[0]&&arguments[0],n=arguments[1];document.createRange&&((t=document.createRange()).selectNodeContents(n||this.DOM.input),t.collapse(i),(e=window.getSelection()).removeAllRanges(),e.addRange(t))},validate:function(){var t=!this.input.value||this.validateTag.call(this,this.input.value);this.DOM.input.classList.toggle("tagify__input--invalid",!0!==t)},normalize:function(){for(var t=this.DOM.input.cloneNode(!0),e=t.textContent.replace(/\s/g," ");t.firstElementChild;)e+=t.firstElementChild.textContent,t.removeChild(t.firstElementChild);return e.replace(/^\s+/,"")},autocomplete:{suggest:function(t){t&&this.input.value?this.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(t){var e=this.DOM.input.getAttribute("data-suggest"),i=t||(e?this.input.value+e:null);return!!i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtStartEnd.call(this),!0)}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(e){return this.value.findIndex(function(t){return e.trim().toLowerCase()===t.value.toLowerCase()})},getTagIndexByValue:function(i){var n=[];return this.DOM.scope.querySelectorAll("tag").forEach(function(t,e){t.textContent.trim().toLowerCase()==i.toLowerCase()&&n.push(e)}),n},getTagElmByValue:function(t){var e=this.getTagIndexByValue(t)[0];return this.DOM.scope.querySelectorAll("tag")[e]},markTagByValue:function(t,e){return!!(e=e||this.getTagElmByValue(t))&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},100),e)},isTagBlacklisted:function(e){return e=e.split(" "),this.settings.blacklist.filter(function(t){return-1!=e.indexOf(t)}).length},isTagWhitelisted:function(e){return this.settings.whitelist.some(function(t){if((t.value||t).toLowerCase()===e.toLowerCase())return!0})},validateTag:function(t){var e=t.trim(),i=this.value.length>=this.settings.maxTags,n=!0;return e?i?n=this.TEXTS.exceed:this.settings.pattern&&!this.settings.pattern.test(e)?n=this.TEXTS.pattern:this.settings.duplicates||-1===this.isTagDuplicate(e)?(this.isTagBlacklisted(e)||this.settings.enforceWhitelist&&!this.isTagWhitelisted(e))&&(n=this.TEXTS.notAllowed):n=this.TEXTS.duplicate:n=this.TEXTS.empty,n},normalizeTags:function(t){var i=this,e=this.settings.whitelist[0]instanceof Object,n=t instanceof Array&&t[0]instanceof Object&&"value"in t[0],s=[];if(n)return t;if("string"==typeof t){if(!t.trim())return[];t=t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}})}else t instanceof Array&&(t=t.map(function(t){return{value:t.trim()}}));return e?(t.forEach(function(e){var t=i.settings.whitelist.filter(function(t){return t.value.toLowerCase()==e.value.toLowerCase()});t[0]?s.push(t[0]):"mix"!=i.settings.mode&&s.push(e)}),s):t},parseMixTags:function(t){var s=this;return(t=t.split(this.settings.pattern)).shift()+t.map(function(t){var e,i,n;if(!t)return"";for(i in t)if(t[i].match(/,|\.| /)){(n=s.normalizeTags.call(s,t.substr(0,i))[0])?e=s.createTagElem(n):i=0;break}return e?e.outerHTML+t.slice(i):s.settings.pattern+t}).join("")},addMixTag:function(t){if(t){var e,i,n,s=window.getSelection(),a=s.focusNode,o=a.textContent,r=document.createDocumentFragment(),l=this.createTagElem(t),h=this.settings.pattern.length;0<s.rangeCount&&((n=s.getRangeAt(0).cloneRange()).collapse(!0),n.setStart(a,0),e=n.toString().slice(0,-this.state.tag.length-h),i=o.slice(e.length+this.state.tag.length+h,o.length),e=document.createTextNode(e),i=document.createTextNode(i.trim()?i:" "),r.appendChild(e),r.appendChild(l),r.appendChild(i)),a.parentNode.replaceChild(r,a),this.update(),this.input.setRangeAtStartEnd.call(this,!0,i)}},addTags:function(t,e){var n=this,s=[];if(t=this.normalizeTags.call(this,t),"mix"==this.settings.mode)return this.addMixTag(t[0]);return this.DOM.input.removeAttribute("style"),t.forEach(function(t){var e,i;"function"==typeof n.settings.transformTag&&(t.value=n.settings.transformTag.call(n,t.value)||t.value),!0!==(e=n.validateTag.call(n,t.value))&&(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",t.title=e,n.markTagByValue(t.value),n.trigger("invalid",{value:t.value,index:n.value.length,message:e})),i=n.createTagElem(t),s.push(i),function(t){var e=this.DOM.scope.lastElementChild;e===this.DOM.input?this.DOM.scope.insertBefore(t,e):this.DOM.scope.appendChild(t)}.call(n,i),!0===e?(n.value.push(t),n.update(),n.trigger("add",n.extend({},{index:n.value.length,tag:i},t))):n.settings.keepInvalidTags||setTimeout(function(){n.removeTag(i,!0)},1e3)}),t.length&&e&&this.input.set.call(this),s},minify:function(t){return t.replace(new RegExp(">[\r\n ]+<","g"),"><")},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag title='"+i+"' contenteditable='false'>\n <x title=''></x><div><span>"+i+"</span></div>\n </tag>";if("function"==typeof this.settings.tagTemplate)try{n=this.settings.tagTemplate(i,t)}catch(t){}return n=this.minify(n),function(t,e){var i,n=Object.keys(e);for(i=n.length;i--;){var s=n[i];if(!e.hasOwnProperty(s))return;t.setAttribute(s,e[s])}}(e=this.parseHTML(n),t),e},removeTag:function(t,e){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:250;if(t&&t instanceof HTMLElement){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=this,a=this.getTagIndexByValue(t.textContent);i&&10<i?(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(o,400)):o(),e||(n=this.value.splice(a,1)[0],this.trigger("remove",this.extend({},{index:a,tag:t},n)))}function o(){t.parentNode&&(t.parentNode.removeChild(t),s.update())}},removeAllTags:function(){this.value=[],this.update(),Array.prototype.slice.call(this.DOM.scope.querySelectorAll("tag")).forEach(function(t){return t.parentNode.removeChild(t)})},update:function(){this.DOM.originalInput.value="mix"==this.settings.mode?this.DOM.input.textContent:JSON.stringify(this.value)},dropdown:{init:function(){this.DOM.dropdown=this.dropdown.build.call(this)},build:function(){var t='<div class="'+("tagify__dropdown "+this.settings.dropdown.classname).trim()+'"></div>';return this.parseHTML(t)},show:function(t){var e,i,n=this;this.settings.whitelist.length&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.filter(function(t){return-1==n.isTagDuplicate(t.value||t)}),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),i&&(this.DOM.dropdown.innerHTML=i,this.dropdown.position.call(this),!this.DOM.dropdown.parentNode!=document.body&&(document.body.appendChild(this.DOM.dropdown),this.events.binding.call(this,!1),this.dropdown.events.binding.call(this))))},hide:function(){this.DOM.dropdown&&this.DOM.dropdown.parentNode==document.body&&(document.body.removeChild(this.DOM.dropdown),window.removeEventListener("resize",this.dropdown.position),this.dropdown.events.binding.call(this,!1),this.events.binding.call(this))},position:function(){var t=this.DOM.scope.getBoundingClientRect();this.DOM.dropdown.style.cssText="left: "+(t.left+window.pageXOffset)+"px; top: "+(t.top+t.height-1+window.pageYOffset)+"px; width: "+t.width+"px"},events:{binding:function(){var t=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],e=this.listeners.dropdown=this.listeners.dropdown||{position:this.dropdown.position.bind(this),onKeyDown:this.dropdown.events.callbacks.onKeyDown.bind(this),onMouseOver:this.dropdown.events.callbacks.onMouseOver.bind(this),onClick:this.dropdown.events.callbacks.onClick.bind(this)},i=t?"addEventListener":"removeEventListener";window[i]("resize",e.position),window[i]("keydown",e.onKeyDown),window[i]("mousedown",e.onClick),this.DOM.dropdown[i]("mouseover",e.onMouseOver)},callbacks:{onKeyDown:function(t){var e=this.DOM.dropdown.querySelectorAll("[class$='--active']")[0],i="";switch(t.key){case"ArrowDown":case"ArrowUp":case"Down":case"Up":t.preventDefault(),e&&(e=e[("ArrowUp"==t.key||"Up"==t.key?"previous":"next")+"ElementSibling"]),e||(e=this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0]),this.dropdown.highlightOption.call(this,e,!0);break;case"Escape":case"Esc":this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":if(t.preventDefault(),!this.input.autocomplete.set.call(this,e?e.textContent:null))return!1;case"Enter":return t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this),!1}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){var e,i=this,n=function(){return i.dropdown.hide.call(i)};if(0==t.button){if(t.target==document.documentElement)return n();(e=[t.target,t.target.parentNode].filter(function(t){return t.className.includes("tagify__dropdown__item")})[0])?(this.addTags(e.textContent,!0),this.dropdown.hide.call(this)):n()}}}},highlightOption:function(t,e){if(t){var i="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){return t.classList.remove(i)}),t.classList.add(i),e&&(t.parentNode.scrollTop=t.clientHeight+t.offsetTop-t.parentNode.clientHeight)}},filterListItems:function(t){if(!t)return"";for(var e,i=[],n=this.settings.whitelist,s=this.settings.dropdown.maxItems||1/0,a=0;a<n.length&&(0==(e=n[a]instanceof Object?n[a]:{value:n[a]}).value.toLowerCase().indexOf(t.toLowerCase())&&-1==this.isTagDuplicate(e.value)&&s--&&i.push(e),0!=s);a++);return i},createListHTML:function(t){var e=this.settings.dropdown.itemTemplate||function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+function(t){var e,i=Object.keys(t),n="";for(e=i.length;e--;){var s=i[e];if("class"!=s&&!t.hasOwnProperty(s))return;n+=" "+s+(t[s]?"="+t[s]:"")}return n}(t)+">"+(t.value||t)+"</div>"};return t.map(e).join("")}}},t}); | ||
!function(t,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?module.exports=e():t.Tagify=e()}(this,function(){"use strict";function t(t,e){if(!t)return console.warn("Tagify: ","invalid input element ",t),this;if(this.settings=this.extend({},this.DEFAULTS,e),this.settings.readonly=t.hasAttribute("readonly"),this.isIE&&(this.settings.autoComplete=!1),t.pattern)try{this.settings.pattern=new RegExp(t.pattern)}catch(t){}if(this.settings&&this.settings.delimiters)try{this.settings.delimiters=new RegExp("["+this.settings.delimiters+"]","g")}catch(t){}this.state={},this.value=[],this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),this.loadOriginalValues(),this.events.customBinding.call(this),this.events.binding.call(this)}return t.prototype={isIE:window.document.documentMode,TEXTS:{empty:"empty",exceed:"number of tags exceeded",pattern:"pattern mismatch",duplicate:"already exists",notAllowed:"not allowed"},DEFAULTS:{delimiters:",",pattern:null,maxTags:1/0,callbacks:{},addTagOnBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,keepInvalidTags:!1,autoComplete:!0,mixTagsAllowedAfter:/,|\.|\:|\s/,dropdown:{classname:"",enabled:2,maxItems:10,itemTemplate:""}},customEventsList:["add","remove","invalid","input"],parseHTML:function(t){return(new DOMParser).parseFromString(t.trim(),"text/html").body.firstElementChild},escapeHtml:function(t){var e=document.createTextNode(t),i=document.createElement("p");return i.appendChild(e),i.innerHTML},build:function(t){var e=this.DOM,i='<tags class="tagify '+(this.settings.mode?"tagify--mix":"")+" "+t.className+'" '+(this.settings.readonly?"readonly":"")+'>\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify__input"></div>\n </tags>';e.originalInput=t,e.scope=this.parseHTML(i),e.input=e.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(e.scope,t),0<=this.settings.dropdown.enabled&&this.dropdown.init.call(this),t.autofocus&&e.input.focus()},destroy:function(){this.DOM.scope.parentNode.removeChild(this.DOM.scope)},loadOriginalValues:function(){var t=this.DOM.originalInput.value;if(t){try{t=JSON.parse(t)}catch(t){}"mix"==this.settings.mode?this.parseMixTags(t):this.addTags(t).forEach(function(t){t&&t.classList.add("tagify--noAnim")})}},extend:function(t,e,i){function n(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 s(t,e){for(var i in e)e.hasOwnProperty(i)&&(n(e[i])?n(t[i])?s(t[i],e[i]):t[i]=Object.assign({},e[i]):t[i]=e[i])}return t instanceof Object||(t={}),s(t,e),i&&s(t,i),t},EventDispatcher:function(n){var s=document.createTextNode("");this.off=function(t,e){return e&&s.removeEventListener.call(s,t,e),this},this.on=function(t,e){return e&&s.addEventListener.call(s,t,e),this},this.trigger=function(t,e){var i;if(t)if(n.settings.isJQueryPlugin)$(n.DOM.originalInput).triggerHandler(t,[e]);else{try{i=new CustomEvent(t,{detail:e})}catch(t){console.warn(t)}s.dispatchEvent(i)}}},events:{customBinding:function(){var e=this;this.customEventsList.forEach(function(t){e.on(t,e.settings.callbacks[t])})},binding:function(){var t,e=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],i=this.events.callbacks,n=e?"addEventListener":"removeEventListener";for(var s in e&&!this.listeners.main&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",i[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&$(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this))),t=this.listeners.main=this.listeners.main||{paste:["input",i.onPaste.bind(this)],focus:["input",i.onFocusBlur.bind(this)],blur:["input",i.onFocusBlur.bind(this)],keydown:["input",i.onKeydown.bind(this)],click:["scope",i.onClickScope.bind(this)]})this.DOM[t[s][0]][n](s,t[s][1])},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"mix"!=this.settings.mode&&("focus"==t.type?0===this.settings.dropdown.enabled&&this.dropdown.show.call(this):"blur"==t.type&&e?this.settings.addTagOnBlur&&this.addTags(e,!0).length:(this.DOM.input.removeAttribute("style"),this.dropdown.hide.call(this)))},onKeydown:function(t){var e,i,n=this,s=t.target.textContent;if("mix"==this.settings.mode){switch(t.key){case"Backspace":var a=[];i=this.DOM.input.children,setTimeout(function(){[].forEach.call(i,function(t){return a.push(t.title)}),n.value=n.value.filter(function(t){return-1!=a.indexOf(t.title)})},20)}return!0}switch(t.key){case"Backspace":""!=s&&8203!=s.charCodeAt(0)||(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide):not([readonly])"))[e.length-1],this.removeTag(e));break;case"Esc":case"Escape":this.input.set.call(this),t.target.blur();break;case"ArrowRight":case"Tab":if(!s)return!0;case"Enter":t.preventDefault(),this.addTags(this.input.value,!0)}},onInput:function(t){var e=this.input.normalize.call(this),i=e.length>=this.settings.dropdown.enabled;if("mix"==this.settings.mode)return this.events.callbacks.onMixTagsInput.call(this,t);e?this.input.value!=e&&(this.input.set.call(this,e,!1),this.trigger("input",{value:e}),-1!=e.search(this.settings.delimiters)?this.addTags(e).length&&this.input.set.call(this):0<=this.settings.dropdown.enabled&&this.dropdown[i?"show":"hide"].call(this,e)):this.input.set.call(this,"")},onMixTagsInput:function(t){var e,i,n,s,a;window.getSelection&&0<(e=window.getSelection()).rangeCount&&((i=e.getRangeAt(0).cloneRange()).collapse(!0),i.setStart(window.getSelection().focusNode,0),(s=(n=i.toString().split(this.settings.mixTagsAllowedAfter))[n.length-1].match(this.settings.pattern))&&(this.state.tag={prefix:s[0],value:s.input.split(s[0])[1]},this.trigger("input",{prefix:s[0],value:this.state.tag.value}),s=this.state.tag,a=this.state.tag.value.length>=this.settings.dropdown.enabled)),this.state.tag&&(this.dropdown[a?"show":"hide"].call(this,this.state.tag.value),this.update())},onInputIE:function(t){var e=this;setTimeout(function(){e.events.callbacks.onInput.call(e,t)})},onPaste:function(t){},onClickScope:function(t){"TAGS"==t.target.tagName?this.DOM.input.focus():"X"==t.target.tagName&&this.removeTag(t.target.parentNode)}}},input:{value:"",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"",e=!(1<arguments.length&&void 0!==arguments[1])||arguments[1];this.input.value=t,e&&(this.DOM.input.innerHTML=t),t||this.dropdown.hide.call(this),t.length<2&&this.input.autocomplete.suggest.call(this,""),this.input.validate.call(this)},setRangeAtStartEnd:function(){var t,e,i=0<arguments.length&&void 0!==arguments[0]&&arguments[0],n=arguments[1];document.createRange&&((t=document.createRange()).selectNodeContents(n||this.DOM.input),t.collapse(i),(e=window.getSelection()).removeAllRanges(),e.addRange(t))},validate:function(){var t=!this.input.value||this.validateTag.call(this,this.input.value);this.DOM.input.classList.toggle("tagify__input--invalid",!0!==t)},normalize:function(){for(var t=this.DOM.input.cloneNode(!0),e=t.textContent.replace(/\s/g," ");t.firstElementChild;)e+=t.firstElementChild.textContent,t.removeChild(t.firstElementChild);return e.replace(/^\s+/,"")},autocomplete:{suggest:function(t){t&&this.input.value?this.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(t){var e=this.DOM.input.getAttribute("data-suggest"),i=t||(e?this.input.value+e:null);return!!i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtStartEnd.call(this),!0)}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(e){return this.value.findIndex(function(t){return e.trim().toLowerCase()===t.value.toLowerCase()})},getTagIndexByValue:function(i){var n=[];return this.DOM.scope.querySelectorAll("tag").forEach(function(t,e){t.textContent.trim().toLowerCase()==i.toLowerCase()&&n.push(e)}),n},getTagElmByValue:function(t){var e=this.getTagIndexByValue(t)[0];return this.DOM.scope.querySelectorAll("tag")[e]},markTagByValue:function(t,e){return!!(e=e||this.getTagElmByValue(t))&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},100),e)},isTagBlacklisted:function(e){return e=e.split(" "),this.settings.blacklist.filter(function(t){return-1!=e.indexOf(t)}).length},isTagWhitelisted:function(e){return this.settings.whitelist.some(function(t){if((t.value||t).toLowerCase()===e.toLowerCase())return!0})},validateTag:function(t){var e=t.trim(),i=this.value.length>=this.settings.maxTags,n=!0;return e?i?n=this.TEXTS.exceed:this.settings.pattern&&!this.settings.pattern.test(e)?n=this.TEXTS.pattern:this.settings.duplicates||-1===this.isTagDuplicate(e)?(this.isTagBlacklisted(e)||this.settings.enforceWhitelist&&!this.isTagWhitelisted(e))&&(n=this.TEXTS.notAllowed):n=this.TEXTS.duplicate:n=this.TEXTS.empty,n},normalizeTags:function(t){var i=this,e=this.settings.whitelist[0]instanceof Object,n=t instanceof Array&&t[0]instanceof Object&&"value"in t[0],s=[];if(n)return t;if("string"==typeof t){if(!t.trim())return[];t=t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}})}else t instanceof Array&&(t=t.map(function(t){return{value:t.trim()}}));return e?(t.forEach(function(e){var t=i.settings.whitelist.filter(function(t){return t.value.toLowerCase()==e.value.toLowerCase()});t[0]?s.push(t[0]):"mix"!=i.settings.mode&&s.push(e)}),s):t},parseMixTags:function(n){var s=this;return n.split(this.settings.mixTagsAllowedAfter).filter(function(t){return t.match(s.settings.pattern)}).forEach(function(t){var e,i=t.replace(s.settings.pattern,"");s.isTagWhitelisted(i)&&(e=s.normalizeTags.call(s,i)[0],n=s.replaceMixStringWithTag(n,t,e).s)}),this.DOM.input.innerHTML=n,this.update(),n},replaceMixStringWithTag:function(t,e,i,n){return i&&t&&-1!=t.indexOf(e)&&(n=this.createTagElem(i),this.value.push(i),t=t.replace(e,n.outerHTML+"⁠")),{s:t,tagElm:n}},addMixTag:function(t){if(t&&this.state.tag){for(var e,i,n,s,a=this.state.tag.prefix+this.state.tag.value,o=document.createNodeIterator(this.DOM.input,NodeFilter.SHOW_TEXT);e=o.nextNode();)if(e.nodeType===Node.TEXT_NODE){if(-1==(n=e.nodeValue.indexOf(a)))continue;s=e.splitText(n),i=this.createTagElem(t),s.nodeValue=s.nodeValue.replace(a,""),e.parentNode.insertBefore(i,s),i.insertAdjacentHTML("afterend","⁠")}i&&(this.value.push(t),this.update(),this.trigger("add",this.extend({},{index:this.value.length,tag:i},t))),this.state.tag=null}},addTags:function(t,e){var n=this,s=[];if(t=this.normalizeTags.call(this,t),"mix"==this.settings.mode)return this.addMixTag(t[0]);return this.DOM.input.removeAttribute("style"),t.forEach(function(t){var e,i;"function"==typeof n.settings.transformTag&&(t.value=n.settings.transformTag.call(n,t.value)||t.value),!0!==(e=n.validateTag.call(n,t.value))&&(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",t.title=e,n.markTagByValue(t.value),n.trigger("invalid",{value:t.value,index:n.value.length,message:e})),i=n.createTagElem(t),s.push(i),function(t){var e=this.DOM.scope.lastElementChild;e===this.DOM.input?this.DOM.scope.insertBefore(t,e):this.DOM.scope.appendChild(t)}.call(n,i),!0===e?(n.value.push(t),n.update(),n.trigger("add",n.extend({},{index:n.value.length,tag:i},t))):n.settings.keepInvalidTags||setTimeout(function(){n.removeTag(i,!0)},1e3)}),t.length&&e&&this.input.set.call(this),s},minify:function(t){return t.replace(new RegExp(">[\r\n ]+<","g"),"><")},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag title='"+i+"' contenteditable='false'>\n <x title=''></x><div><span>"+i+"</span></div>\n </tag>";if("function"==typeof this.settings.tagTemplate)try{n=this.settings.tagTemplate(i,t)}catch(t){}return n=this.minify(n),function(t,e){var i,n=Object.keys(e);for(i=n.length;i--;){var s=n[i];if(!e.hasOwnProperty(s))return;t.setAttribute(s,e[s])}}(e=this.parseHTML(n),t),e},removeTag:function(t,e){var i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:250;if(t&&t instanceof HTMLElement){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=this,a=this.getTagIndexByValue(t.textContent);i&&10<i?(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(o,400)):o(),e||(n=this.value.splice(a,1)[0],this.trigger("remove",this.extend({},{index:a,tag:t},n)))}function o(){t.parentNode&&(t.parentNode.removeChild(t),s.update())}},removeAllTags:function(){this.value=[],this.update(),Array.prototype.slice.call(this.DOM.scope.querySelectorAll("tag")).forEach(function(t){return t.parentNode.removeChild(t)})},update:function(){this.DOM.originalInput.value="mix"==this.settings.mode?this.DOM.input.textContent:JSON.stringify(this.value)},dropdown:{init:function(){this.DOM.dropdown=this.dropdown.build.call(this)},build:function(){var t='<div class="'+("tagify__dropdown "+this.settings.dropdown.classname).trim()+'"></div>';return this.parseHTML(t)},show:function(t){var e,i,n=this;this.settings.whitelist.length&&this.settings.dropdown.enabled&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.filter(function(t){return-1==n.isTagDuplicate(t.value||t)}),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),i&&(this.DOM.dropdown.innerHTML=i,this.dropdown.position.call(this),!this.DOM.dropdown.parentNode!=document.body&&(document.body.appendChild(this.DOM.dropdown),this.events.binding.call(this,!1),this.dropdown.events.binding.call(this))))},hide:function(){this.DOM.dropdown&&this.DOM.dropdown.parentNode==document.body&&(document.body.removeChild(this.DOM.dropdown),window.removeEventListener("resize",this.dropdown.position),this.dropdown.events.binding.call(this,!1),this.events.binding.call(this))},position:function(){var t=this.DOM.scope.getBoundingClientRect();this.DOM.dropdown.style.cssText="left: "+(t.left+window.pageXOffset)+"px; top: "+(t.top+t.height-1+window.pageYOffset)+"px; width: "+t.width+"px"},events:{binding:function(){var t=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],e=this.listeners.dropdown=this.listeners.dropdown||{position:this.dropdown.position.bind(this),onKeyDown:this.dropdown.events.callbacks.onKeyDown.bind(this),onMouseOver:this.dropdown.events.callbacks.onMouseOver.bind(this),onClick:this.dropdown.events.callbacks.onClick.bind(this)},i=t?"addEventListener":"removeEventListener";window[i]("resize",e.position),window[i]("keydown",e.onKeyDown),window[i]("mousedown",e.onClick),this.DOM.dropdown[i]("mouseover",e.onMouseOver)},callbacks:{onKeyDown:function(t){var e=this.DOM.dropdown.querySelectorAll("[class$='--active']")[0],i="";switch(t.key){case"ArrowDown":case"ArrowUp":case"Down":case"Up":t.preventDefault(),e&&(e=e[("ArrowUp"==t.key||"Up"==t.key?"previous":"next")+"ElementSibling"]),e||(e=this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0]),this.dropdown.highlightOption.call(this,e,!0);break;case"Escape":case"Esc":this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":if(t.preventDefault(),!this.input.autocomplete.set.call(this,e?e.textContent:null))return!1;case"Enter":return t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this),!1}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){var e,i=this,n=function(){return i.dropdown.hide.call(i)};if(0==t.button){if(t.target==document.documentElement)return n();(e=[t.target,t.target.parentNode].filter(function(t){return t.className.includes("tagify__dropdown__item")})[0])?(this.addTags(e.textContent,!0),this.dropdown.hide.call(this)):n()}}}},highlightOption:function(t,e){if(t){var i="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){return t.classList.remove(i)}),t.classList.add(i),e&&(t.parentNode.scrollTop=t.clientHeight+t.offsetTop-t.parentNode.clientHeight)}},filterListItems:function(t){if(!t)return"";for(var e,i=[],n=this.settings.whitelist,s=this.settings.dropdown.maxItems||1/0,a=0;a<n.length&&(0==(e=n[a]instanceof Object?n[a]:{value:n[a]}).value.toLowerCase().indexOf(t.toLowerCase())&&-1==this.isTagDuplicate(e.value)&&s--&&i.push(e),0!=s);a++);return i},createListHTML:function(t){var e=this.settings.dropdown.itemTemplate||function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+function(t){var e,i=Object.keys(t),n="";for(e=i.length;e--;){var s=i[e];if("class"!=s&&!t.hasOwnProperty(s))return;n+=" "+s+(t[s]?"="+t[s]:"")}return n}(t)+">"+(t.value||t)+"</div>"};return t.map(e).join("")}}},t}); |
{ | ||
"name": "@yaireo/tagify", | ||
"version": "2.6.6", | ||
"version": "2.7.0", | ||
"homepage": "https://github.com/yairEO/tagify", | ||
@@ -26,4 +26,4 @@ "description": "Convert an input field into a Tags element. Easy, customizable, with good performance and small code footprint.", | ||
"devDependencies": { | ||
"@babel/core": "^7.1.0", | ||
"@babel/preset-env": "^7.1.0", | ||
"@babel/core": "^7.1.5", | ||
"@babel/preset-env": "^7.1.5", | ||
"babel-core": "^6.26.3", | ||
@@ -46,3 +46,3 @@ "babel-jest": "^23.6.0", | ||
"gulp-replace": "^1.0.0", | ||
"gulp-sass": "^4.0.1", | ||
"gulp-sass": "^4.0.2", | ||
"gulp-sourcemaps": "^2.6.4", | ||
@@ -54,7 +54,7 @@ "gulp-uglify": "^3.0.1", | ||
"jest": "^23.6.0", | ||
"jsdom": "^12.0.0", | ||
"jsdom": "^13.0.0", | ||
"path": "^0.12.7", | ||
"run-sequence": "^2.2.1", | ||
"puppeteer": "^1.8.0" | ||
"puppeteer": "^1.10.0" | ||
} | ||
} |
@@ -51,13 +51,14 @@ function Tagify( input, settings ){ | ||
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 | ||
autoComplete : true, // Flag - tries to autocomplete the input's value while typing | ||
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 | ||
autoComplete : true, // Flag - tries to autocomplete the input's value while typing | ||
mixTagsAllowedAfter : /,|\.|\:|\s/, // RegEx - Define conditions in which mix-tags content is allowing a tag to be added after | ||
dropdown : { | ||
@@ -73,2 +74,6 @@ classname : '', | ||
// generateUID(){ | ||
// return Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36) | ||
// }, | ||
/** | ||
@@ -138,3 +143,3 @@ * utility method | ||
if( this.settings.mode == 'mix' ){ | ||
this.DOM.input.innerHTML = this.parseMixTags(value); | ||
this.parseMixTags(value); | ||
} | ||
@@ -288,9 +293,25 @@ | ||
var s = e.target.textContent, | ||
lastTag; | ||
lastTag, tags; | ||
if( this.settings.mode == 'mix' ) return; | ||
if( this.settings.mode == 'mix' ){ | ||
switch( e.key ){ | ||
case 'Backspace' : | ||
var values = []; | ||
// find out which tag(s) were deleted and update "this.value" accordingly | ||
tags = this.DOM.input.children; | ||
// a delay is in need before the node actually is ditached from the document | ||
setTimeout(()=>{ | ||
// iterate over the list of tags still in the document and then filter only those from the "this.value" collection | ||
[].forEach.call(tags, tagElm => values.push(tagElm.title)) | ||
this.value = this.value.filter(d => values.indexOf(d.title) != -1); | ||
}, 20) | ||
break; | ||
} | ||
return true; | ||
} | ||
switch( e.key ){ | ||
case 'Backspace' : | ||
if( s == "" || s.charCodeAt(0) == 8203 ){ | ||
if( s == "" || s.charCodeAt(0) == 8203 ){ // 8203: ZERO WIDTH SPACE unicode | ||
lastTag = this.DOM.scope.querySelectorAll('tag:not(.tagify--hide):not([readonly])'); | ||
@@ -348,7 +369,4 @@ lastTag = lastTag[lastTag.length - 1]; | ||
onMixTagsInput( e ){ | ||
var sel, range, split, tag, | ||
patternLen = this.settings.pattern.length; | ||
var sel, range, split, tag, showSuggestions; | ||
this.state.tag = null; | ||
if( window.getSelection ){ | ||
@@ -361,12 +379,23 @@ sel = window.getSelection(); | ||
split = range.toString().split(/,|\.|\s/); // ["foo", "bar", "@a"] | ||
split = range.toString().split(this.settings.mixTagsAllowedAfter); // ["foo", "bar", "@a"] | ||
tag = split[split.length-1]; | ||
tag = this.state.tag = (tag.substr(0, patternLen) == this.settings.pattern && tag.length > patternLen) ? tag.slice(patternLen) : null; | ||
this.trigger("input", {value:tag}); | ||
tag = split[split.length-1].match(this.settings.pattern); | ||
if( tag ){ | ||
this.state.tag = { | ||
prefix : tag[0], | ||
value : tag.input.split(tag[0])[1], | ||
} | ||
this.trigger("input", { prefix:tag[0], value:this.state.tag.value }); | ||
tag = this.state.tag; | ||
showSuggestions = this.state.tag.value.length >= this.settings.dropdown.enabled | ||
} | ||
} | ||
} | ||
this.dropdown[tag ? "show" : "hide"].call(this, tag); | ||
this.update(); | ||
if( this.state.tag ){ | ||
this.dropdown[showSuggestions ? "show" : "hide"].call(this, this.state.tag.value); | ||
this.update(); | ||
} | ||
}, | ||
@@ -625,25 +654,35 @@ | ||
parseMixTags( s ){ | ||
var htmlString = ''; | ||
// example: "@cartman ,@kyle do not know:#homer".split(/,|\.|\:|\s/).filter(item => item.match(/@|#/) ) | ||
s.split(this.settings.mixTagsAllowedAfter) | ||
.filter(item => item.match(this.settings.pattern) ) | ||
.forEach(tag => { | ||
var value = tag.replace(this.settings.pattern, ''), | ||
tagData; | ||
s = s.split( this.settings.pattern ); | ||
if( this.isTagWhitelisted(value) ){ | ||
tagData = this.normalizeTags.call(this, value)[0]; | ||
s = this.replaceMixStringWithTag(s, tag, tagData).s; | ||
} | ||
}) | ||
// this.DOM.scope.innerHTML | ||
htmlString = s.shift() + s.map(part => { | ||
var tagElm, i, tagData; | ||
this.DOM.input.innerHTML = s; | ||
this.update(); | ||
return s; | ||
}, | ||
if( !part ) return ''; | ||
/** | ||
* [replaceMixStringWithTag description] | ||
* @param {String} s [whole string] | ||
* @param {String} tag [tag string to replace with tag element] | ||
* @param {Object} tagData [value, plus any other optional attributes] | ||
* @return {[type]} [description] | ||
*/ | ||
replaceMixStringWithTag( s, tag, tagData, tagElm ){ | ||
if( tagData && s && s.indexOf(tag) != -1 ){ | ||
tagElm = this.createTagElem(tagData); | ||
this.value.push(tagData); | ||
s = s.replace(tag, tagElm.outerHTML + "⁠") // put a zero-space at the end to the caret won't jump back to the start (when the last input child is a tag) | ||
} | ||
for( i in part ){ | ||
if( part[i].match(/,|\.| /) ){ | ||
tagData = this.normalizeTags.call(this, part.substr(0, i))[0]; | ||
if( tagData ) tagElm = this.createTagElem(tagData); | ||
else i = 0; // a tag was found but was not in the whitelist, so reset the "i" index | ||
break; | ||
} | ||
} | ||
return tagElm ? tagElm.outerHTML + part.slice(i) : this.settings.pattern + part | ||
}).join(''); | ||
return htmlString; | ||
return {s, tagElm}; | ||
}, | ||
@@ -655,34 +694,33 @@ | ||
addMixTag( tagData ){ | ||
if( !tagData ) return; | ||
if( !tagData || !this.state.tag ) return; | ||
var sel = window.getSelection(), | ||
node = sel.focusNode, | ||
nodeText = node.textContent, | ||
wrapElm = document.createDocumentFragment(), | ||
tagElm = this.createTagElem(tagData), | ||
textNodeBefore, | ||
textNodeAfter, | ||
range, | ||
parrernLen = this.settings.pattern.length; | ||
var tag = this.state.tag.prefix + this.state.tag.value, | ||
iter = document.createNodeIterator(this.DOM.input, NodeFilter.SHOW_TEXT), | ||
textnode, | ||
tagElm, | ||
idx, | ||
replacedNode; | ||
if( sel.rangeCount > 0 ){ | ||
range = sel.getRangeAt(0).cloneRange(); | ||
range.collapse(true); | ||
range.setStart(node, 0); | ||
while( textnode = iter.nextNode() ){ | ||
if( textnode.nodeType === Node.TEXT_NODE ){ | ||
// get the index of which the tag (string) is within the textNode (if at all) | ||
idx = textnode.nodeValue.indexOf(tag); | ||
if( idx == -1 ) continue; | ||
textNodeBefore = range.toString().slice(0, - this.state.tag.length - parrernLen); | ||
textNodeAfter = nodeText.slice(textNodeBefore.length + this.state.tag.length + parrernLen, nodeText.length); | ||
replacedNode = textnode.splitText(idx); | ||
tagElm = this.createTagElem(tagData); | ||
// clean up the tag's string and put tag element instead | ||
replacedNode.nodeValue = replacedNode.nodeValue.replace(tag, ''); | ||
textnode.parentNode.insertBefore(tagElm, replacedNode); | ||
tagElm.insertAdjacentHTML('afterend', '⁠'); | ||
} | ||
} | ||
textNodeBefore = document.createTextNode(textNodeBefore); | ||
textNodeAfter = document.createTextNode(textNodeAfter.trim() ? textNodeAfter : " \u200b"); | ||
wrapElm.appendChild( textNodeBefore ); | ||
wrapElm.appendChild( tagElm ); | ||
wrapElm.appendChild( textNodeAfter ); | ||
if( tagElm ){ | ||
this.value.push(tagData); | ||
this.update(); | ||
this.trigger('add', this.extend({}, {index:this.value.length, tag:tagElm}, tagData)); | ||
} | ||
node.parentNode.replaceChild(wrapElm, node); | ||
this.update(); | ||
this.input.setRangeAtStartEnd.call(this, true, textNodeAfter); | ||
this.state.tag = null; | ||
}, | ||
@@ -784,5 +822,6 @@ | ||
// for a certain Tag element, add attributes. | ||
// add HTML attributes from tagData | ||
function addTagAttrs(tagElm, tagData){ | ||
var i, keys = Object.keys(tagData); | ||
for( i=keys.length; i--; ){ | ||
@@ -820,3 +859,3 @@ var propName = keys[i]; | ||
if( tranDuration && tranDuration > 10 ) animation() | ||
if( tranDuration && tranDuration > 10 ) animation() | ||
else removeNode(); | ||
@@ -878,5 +917,4 @@ | ||
var listItems, listHTML; | ||
if( !this.settings.whitelist.length || !this.settings.dropdown.enabled ) return; | ||
if( !this.settings.whitelist.length ) return; | ||
// if no value was supplied, show all the "whitelist" items in the dropdown | ||
@@ -1059,2 +1097,3 @@ // @type [Array] listItems | ||
whitelistItem = whitelist[i] instanceof Object ? whitelist[i] : { value:whitelist[i] }, //normalize value as an Object | ||
valueIsInWhitelist = whitelistItem.value.toLowerCase().indexOf(value.toLowerCase()) == 0; // for fuzzy-search use ">=" | ||
@@ -1061,0 +1100,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
383998
3118