Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@yaireo/tagify

Package Overview
Dependencies
Maintainers
1
Versions
266
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@yaireo/tagify - npm Package Compare versions

Comparing version 2.3.0 to 2.5.0

mix.gif

213

dist/jQuery.tagify.js
"use strict";
/**
* Tagify (v 2.2.10)- tags input component
* Tagify (v 2.5.0)- tags input component
* By Yair Even-Or (2016)

@@ -48,2 +48,3 @@ * Don't sell this code. (c)

this.state = {};
this.value = []; // tags' data

@@ -131,3 +132,3 @@ // events' callbacks references will be stores here, so events could be unbinded

DOM = this.DOM,
template = "<tags class=\"tagify " + input.className + "\" " + (this.settings.readonly ? 'readonly' : '') + ">\n <div contenteditable data-placeholder=\"" + input.placeholder + "\" class=\"tagify__input\"></div>\n </tags>";
template = "<tags class=\"tagify " + (this.settings.mode ? "tagify--mix" : "") + " " + input.className + "\" " + (this.settings.readonly ? 'readonly' : '') + ">\n <div contenteditable data-placeholder=\"" + input.placeholder + "\" class=\"tagify__input\"></div>\n </tags>";
DOM.originalInput = input;

@@ -153,2 +154,21 @@ DOM.scope = this.parseHTML(template);

/**
* If the original input had an values, add them as tags
*/
loadOriginalValues: function loadOriginalValues() {
var value = this.DOM.originalInput.value; // if the original input already had any value (tags)
if (!value) return;
try {
value = JSON.parse(value);
} catch (err) {}
if (this.settings.mode == 'mix') {
this.DOM.input.innerHTML = this.parseMixTags(value);
} else this.addTags(value).forEach(function (tag) {
tag && tag.classList.add('tagify--noAnim');
});
},
/**
* Merge two objects into a new one

@@ -238,3 +258,13 @@ * TEST: extend({}, {a:{foo:1}, b:[]}, {a:{bar:2}, b:[1], c:()=>{}})

var _CB = this.events.callbacks,
// setup callback references so events could be removed later
_CBR,
action = bindUnbind ? 'addEventListener' : 'removeEventListener';
if (bindUnbind && !this.listeners.main) {
// this event should never be unbinded
// IE cannot register "input" events on contenteditable elements, so the "keydown" should be used instead..
this.DOM.input.addEventListener(this.isIE ? "keydown" : "input", _CB[this.isIE ? "onInputIE" : "onInput"].bind(this));
if (this.settings.isJQueryPlugin) $(this.DOM.originalInput).on('tagify.removeAllTags', this.removeAllTags.bind(this));
} // setup callback references so events could be removed later
_CBR = this.listeners.main = this.listeners.main || {

@@ -246,4 +276,3 @@ paste: ['input', _CB.onPaste.bind(this)],

click: ['scope', _CB.onClickScope.bind(this)]
},
action = bindUnbind ? 'addEventListener' : 'removeEventListener';
};

@@ -253,9 +282,2 @@ for (var eventName in _CBR) {

}
if (bindUnbind) {
// this event should never be unbinded
// IE cannot register "input" events on contenteditable elements, so the "keydown" should be used instead..
this.DOM.input.addEventListener(this.isIE ? "keydown" : "input", _CB[this.isIE ? "onInputIE" : "onInput"].bind(this));
if (this.settings.isJQueryPlugin) $(this.DOM.originalInput).on('tagify.removeAllTags', this.removeAllTags.bind(this));
}
},

@@ -269,2 +291,3 @@

var s = e.target.textContent.trim();
if (this.settings.mode == 'mix') return;

@@ -287,2 +310,3 @@ if (e.type == "focus") {

lastTag;
if (this.settings.mode == 'mix') return;

@@ -305,2 +329,3 @@ if (e.key == 'Backspace' && (s == "" || s.charCodeAt(0) == 8203)) {

showSuggestions = value.length >= this.settings.dropdown.enabled;
if (this.settings.mode == 'mix') return this.events.callbacks.onMixTagsInput.call(this, e);

@@ -325,2 +350,26 @@ if (!value) {

},
onMixTagsInput: function onMixTagsInput(e) {
var sel,
range,
split,
tag,
patternLen = this.settings.pattern.length;
this.state.tag = null;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0).cloneRange();
range.collapse(true);
range.setStart(window.getSelection().focusNode, 0);
split = range.toString().split(/,|\.|\s/); // ["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.dropdown[tag ? "show" : "hide"].call(this, tag);
},
onInputIE: function onInputIE(e) {

@@ -344,19 +393,2 @@ var _this = this; // for the "e.target.textContent" to be changed, the browser requires a small delay

/**
* If the original input had an values, add them as tags
*/
loadOriginalValues: function loadOriginalValues() {
var value = this.DOM.originalInput.value; // if the original input already had any value (tags)
if (!value) return;
try {
value = JSON.parse(value);
} catch (err) {}
this.addTags(value).forEach(function (tag) {
tag && tag.classList.add('tagify--noAnim');
});
},
/**
* input bridge for accessing & setting

@@ -377,8 +409,10 @@ * @type {Object}

// https://stackoverflow.com/a/3866442/104380
setRangeAtEnd: function setRangeAtEnd() {
setRangeAtStartEnd: function setRangeAtStartEnd() {
var start = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var node = arguments[1];
var range, selection;
if (!document.createRange) return;
range = document.createRange();
range.selectNodeContents(this.DOM.input);
range.collapse(false);
range.selectNodeContents(node || this.DOM.input);
range.collapse(start);
selection = window.getSelection();

@@ -425,3 +459,3 @@ selection.removeAllRanges();

this.dropdown.hide.call(this);
this.input.setRangeAtEnd.call(this);
this.input.setRangeAtStartEnd.call(this);
} // if( suggestion && this.addTags(this.input.value + suggestion).length ){

@@ -544,3 +578,3 @@ // this.input.set.call(this);

return tagsItems.split(this.settings.delimiters).filter(function (n) {
tagsItems = tagsItems.split(this.settings.delimiters).filter(function (n) {
return n;

@@ -552,5 +586,3 @@ }).map(function (v) {

});
}
if (tagsItems instanceof Array) return tagsItems.map(function (v) {
} else if (tagsItems instanceof Array) tagsItems = tagsItems.map(function (v) {
return {

@@ -561,2 +593,3 @@ value: v.trim()

if (whitelistWithProps) {

@@ -569,9 +602,66 @@ tagsItems.forEach(function (tag) {

if (matchObj[0]) temp.push(matchObj[0]); // set the Array (with the found Object) as the new value
else temp.push(tag);
else if (_this3.settings.mode != 'mix') temp.push(tag);
});
return temp;
}
return tagsItems;
},
parseMixTags: function parseMixTags(s) {
var _this4 = this;
var htmlString = '';
s = s.split(this.settings.pattern); // this.DOM.scope.innerHTML
htmlString = s.shift() + s.map(function (part) {
var tagElm, i, normalizedTag;
if (!part) return '';
for (i in part) {
if (part[i].match(/,|\.| /)) {
normalizedTag = _this4.normalizeTags.call(_this4, part.substr(0, i))[0];
if (normalizedTag) tagElm = _this4.createTagElem(normalizedTag);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) : _this4.settings.pattern + part;
}).join('');
return htmlString;
},
/**
* Add a tag where it might be beside textNodes
*/
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 (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);
}
node.parentNode.replaceChild(wrapElm, node);
this.input.setRangeAtStartEnd.call(this, true, textNodeAfter);
},
/**
* add a "tag" element to the "tags" component

@@ -583,15 +673,16 @@ * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]

addTags: function addTags(tagsItems, clearInput) {
var _this4 = this;
var _this5 = this;
var tagElems = [];
tagsItems = this.normalizeTags.call(this, tagsItems);
if (this.settings.mode == 'mix') return this.addMixTag(tagsItems[0]);
this.DOM.input.removeAttribute('style');
tagsItems = this.normalizeTags.call(this, tagsItems);
tagsItems.forEach(function (tagData) {
var tagValidation, tagElm;
if (typeof _this4.settings.transformTag === 'function') {
tagData.value = _this4.settings.transformTag.call(_this4, tagData.value) || tagData.value;
if (typeof _this5.settings.transformTag === 'function') {
tagData.value = _this5.settings.transformTag.call(_this5, tagData.value) || tagData.value;
}
tagValidation = _this4.validateTag.call(_this4, tagData.value);
tagValidation = _this5.validateTag.call(_this5, tagData.value);

@@ -602,7 +693,7 @@ if (tagValidation !== true) {

_this4.markTagByValue(tagData.value);
_this5.markTagByValue(tagData.value);
_this4.trigger("invalid", {
_this5.trigger("invalid", {
value: tagData.value,
index: _this4.value.length,
index: _this5.value.length,
message: tagValidation

@@ -613,21 +704,21 @@ });

tagElm = _this4.createTagElem(tagData);
tagElm = _this5.createTagElem(tagData);
tagElems.push(tagElm); // add the tag to the component's DOM
appendTag.call(_this4, tagElm);
appendTag.call(_this5, tagElm);
if (tagValidation === true) {
// update state
_this4.value.push(tagData);
_this5.value.push(tagData);
_this4.update();
_this5.update();
_this4.trigger('add', _this4.extend({}, {
index: _this4.value.length,
_this5.trigger('add', _this5.extend({}, {
index: _this5.value.length,
tag: tagElm
}, tagData));
} else if (!_this4.settings.keepInvalidTags) {
} else if (!_this5.settings.keepInvalidTags) {
// remove invalid tags (if "keepInvalidTags" is set to "false")
setTimeout(function () {
_this4.removeTag(tagElm, true);
_this5.removeTag(tagElm, true);
}, 1000);

@@ -653,2 +744,5 @@ }

},
minify: function minify(html) {
return html.replace(new RegExp("\>[\r\n ]+\<", "g"), "><");
},

@@ -663,3 +757,3 @@ /**

v = this.escapeHtml(tagData.value),
template = "<tag title='" + v + "'>\n <x title=''></x><div><span>" + v + "</span></div>\n </tag>";
template = "<tag title='" + v + "' contenteditable='false'>\n <x title=''></x><div><span>" + v + "</span></div>\n </tag>";

@@ -684,2 +778,3 @@ if (typeof this.settings.tagTemplate === "function") {

template = this.minify(template);
tagElm = this.parseHTML(template); // add any attribuets, if exists

@@ -871,6 +966,6 @@

onClick: function onClick(e) {
var _this5 = this;
var _this6 = this;
var onClickOutside = function onClickOutside() {
return _this5.dropdown.hide.call(_this5);
return _this6.dropdown.hide.call(_this6);
},

@@ -887,4 +982,4 @@ listItemElm;

if (listItemElm) {
this.input.set.call(this);
this.addTags(listItemElm.textContent);
this.addTags(listItemElm.textContent, true);
this.dropdown.hide.call(this);
} // clicked outside the dropdown, so just close it

@@ -891,0 +986,0 @@ else onClickOutside();

@@ -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.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"],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 '+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.settings.whitelist.length&&this.dropdown.init.call(this),t.autofocus&&e.input.focus()},destroy:function(){this.DOM.scope.parentNode.removeChild(this.DOM.scope)},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=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],e=this.events.callbacks,i=this.listeners.main=this.listeners.main||{paste:["input",e.onPaste.bind(this)],focus:["input",e.onFocusBlur.bind(this)],blur:["input",e.onFocusBlur.bind(this)],keydown:["input",e.onKeydown.bind(this)],click:["scope",e.onClickScope.bind(this)]},n=t?"addEventListener":"removeEventListener";for(var s in i)this.DOM[i[s][0]][n](s,i[s][1]);t&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",e[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&a(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this)))},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"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;"Backspace"!=t.key||""!=i&&8203!=i.charCodeAt(0)?"Escape"==t.key||"Esc"==t.key?(this.input.set.call(this),t.target.blur()):"Enter"==t.key?(t.preventDefault(),this.addTags(this.input.value,!0)):"ArrowRight"==t.key&&this.input.autocomplete.set.call(this):(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide)"))[e.length-1],this.removeTag(e))},onInput:function(t){var e=this.input.normalize.call(this),i=e.length>=this.settings.dropdown.enabled;e?this.input.value!=e&&(this.input.set.call(this,e,!1),-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,"")},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)}}},loadOriginalValues:function(){var t=this.DOM.originalInput.value;if(t){try{t=JSON.parse(t)}catch(t){}this.addTags(t).forEach(function(t){t&&t.classList.add("tagify--noAnim")})}},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)},setRangeAtEnd:function(){var t,e;document.createRange&&((t=document.createRange()).selectNodeContents(this.DOM.input),t.collapse(!1),(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);i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtEnd.call(this))}}},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.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=[];return n?t:"string"==typeof t?t.trim()?t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}}):[]:t instanceof Array?t.map(function(t){return{value:t.trim()}}):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]):s.push(e)}),s):void 0},addTags:function(t,e){var n=this,s=[];return this.DOM.input.removeAttribute("style"),(t=this.normalizeTags.call(this,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},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag title='"+i+"'>\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 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){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=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(a,400)):a(),e||(n=this.value.splice(s,1)[0],this.update(),this.trigger("remove",this.extend({},{index:s,tag:t},n)))}function a(){t.parentNode.removeChild(t)}},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=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;this.settings.whitelist.length&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.slice(0),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),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"Enter":t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":return t.preventDefault(),this.input.autocomplete.set.call(this,e?e.textContent:null),!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.input.set.call(this),this.addTags(e.textContent)):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().replace(/\s/g,"").indexOf(t.toLowerCase().replace(/\s/g,""))&&-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+"</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,dropdown:{classname:"",enabled:2,maxItems:10,itemTemplate:""}},customEventsList:["add","remove","invalid"],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.settings.whitelist.length&&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;"mix"!=this.settings.mode&&("Backspace"!=t.key||""!=i&&8203!=i.charCodeAt(0)?"Escape"==t.key||"Esc"==t.key?(this.input.set.call(this),t.target.blur()):"Enter"==t.key?(t.preventDefault(),this.addTags(this.input.value,!0)):"ArrowRight"==t.key&&this.input.autocomplete.set.call(this):(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide)"))[e.length-1],this.removeTag(e)))},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),-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.dropdown[s?"show":"hide"].call(this,s)},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);i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtStartEnd.call(this))}}},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.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.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){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=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(a,400)):a(),e||(n=this.value.splice(s,1)[0],this.update(),this.trigger("remove",this.extend({},{index:s,tag:t},n)))}function a(){t.parentNode.removeChild(t)}},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=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;this.settings.whitelist.length&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.slice(0),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),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"Enter":t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":return t.preventDefault(),this.input.autocomplete.set.call(this,e?e.textContent:null),!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().replace(/\s/g,"").indexOf(t.toLowerCase().replace(/\s/g,""))&&-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+"</div>"};return t.map(e).join("")}}}}(jQuery);
/**
* Tagify (v 2.2.10)- tags input component
* Tagify (v 2.5.0)- tags input component
* By Yair Even-Or (2016)

@@ -40,2 +40,3 @@ * Don't sell this code. (c)

this.state = {};
this.value = []; // tags' data

@@ -123,3 +124,3 @@ // events' callbacks references will be stores here, so events could be unbinded

DOM = this.DOM,
template = "<tags class=\"tagify " + input.className + "\" " + (this.settings.readonly ? 'readonly' : '') + ">\n <div contenteditable data-placeholder=\"" + input.placeholder + "\" class=\"tagify__input\"></div>\n </tags>";
template = "<tags class=\"tagify " + (this.settings.mode ? "tagify--mix" : "") + " " + input.className + "\" " + (this.settings.readonly ? 'readonly' : '') + ">\n <div contenteditable data-placeholder=\"" + input.placeholder + "\" class=\"tagify__input\"></div>\n </tags>";
DOM.originalInput = input;

@@ -145,2 +146,21 @@ DOM.scope = this.parseHTML(template);

/**
* If the original input had an values, add them as tags
*/
loadOriginalValues: function loadOriginalValues() {
var value = this.DOM.originalInput.value; // if the original input already had any value (tags)
if (!value) return;
try {
value = JSON.parse(value);
} catch (err) {}
if (this.settings.mode == 'mix') {
this.DOM.input.innerHTML = this.parseMixTags(value);
} else this.addTags(value).forEach(function (tag) {
tag && tag.classList.add('tagify--noAnim');
});
},
/**
* Merge two objects into a new one

@@ -230,3 +250,13 @@ * TEST: extend({}, {a:{foo:1}, b:[]}, {a:{bar:2}, b:[1], c:()=>{}})

var _CB = this.events.callbacks,
// setup callback references so events could be removed later
_CBR,
action = bindUnbind ? 'addEventListener' : 'removeEventListener';
if (bindUnbind && !this.listeners.main) {
// this event should never be unbinded
// IE cannot register "input" events on contenteditable elements, so the "keydown" should be used instead..
this.DOM.input.addEventListener(this.isIE ? "keydown" : "input", _CB[this.isIE ? "onInputIE" : "onInput"].bind(this));
if (this.settings.isJQueryPlugin) $(this.DOM.originalInput).on('tagify.removeAllTags', this.removeAllTags.bind(this));
} // setup callback references so events could be removed later
_CBR = this.listeners.main = this.listeners.main || {

@@ -238,4 +268,3 @@ paste: ['input', _CB.onPaste.bind(this)],

click: ['scope', _CB.onClickScope.bind(this)]
},
action = bindUnbind ? 'addEventListener' : 'removeEventListener';
};

@@ -245,9 +274,2 @@ for (var eventName in _CBR) {

}
if (bindUnbind) {
// this event should never be unbinded
// IE cannot register "input" events on contenteditable elements, so the "keydown" should be used instead..
this.DOM.input.addEventListener(this.isIE ? "keydown" : "input", _CB[this.isIE ? "onInputIE" : "onInput"].bind(this));
if (this.settings.isJQueryPlugin) $(this.DOM.originalInput).on('tagify.removeAllTags', this.removeAllTags.bind(this));
}
},

@@ -261,2 +283,3 @@

var s = e.target.textContent.trim();
if (this.settings.mode == 'mix') return;

@@ -279,2 +302,3 @@ if (e.type == "focus") {

lastTag;
if (this.settings.mode == 'mix') return;

@@ -297,2 +321,3 @@ if (e.key == 'Backspace' && (s == "" || s.charCodeAt(0) == 8203)) {

showSuggestions = value.length >= this.settings.dropdown.enabled;
if (this.settings.mode == 'mix') return this.events.callbacks.onMixTagsInput.call(this, e);

@@ -317,2 +342,26 @@ if (!value) {

},
onMixTagsInput: function onMixTagsInput(e) {
var sel,
range,
split,
tag,
patternLen = this.settings.pattern.length;
this.state.tag = null;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0).cloneRange();
range.collapse(true);
range.setStart(window.getSelection().focusNode, 0);
split = range.toString().split(/,|\.|\s/); // ["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.dropdown[tag ? "show" : "hide"].call(this, tag);
},
onInputIE: function onInputIE(e) {

@@ -336,19 +385,2 @@ var _this = this; // for the "e.target.textContent" to be changed, the browser requires a small delay

/**
* If the original input had an values, add them as tags
*/
loadOriginalValues: function loadOriginalValues() {
var value = this.DOM.originalInput.value; // if the original input already had any value (tags)
if (!value) return;
try {
value = JSON.parse(value);
} catch (err) {}
this.addTags(value).forEach(function (tag) {
tag && tag.classList.add('tagify--noAnim');
});
},
/**
* input bridge for accessing & setting

@@ -369,8 +401,10 @@ * @type {Object}

// https://stackoverflow.com/a/3866442/104380
setRangeAtEnd: function setRangeAtEnd() {
setRangeAtStartEnd: function setRangeAtStartEnd() {
var start = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var node = arguments[1];
var range, selection;
if (!document.createRange) return;
range = document.createRange();
range.selectNodeContents(this.DOM.input);
range.collapse(false);
range.selectNodeContents(node || this.DOM.input);
range.collapse(start);
selection = window.getSelection();

@@ -417,3 +451,3 @@ selection.removeAllRanges();

this.dropdown.hide.call(this);
this.input.setRangeAtEnd.call(this);
this.input.setRangeAtStartEnd.call(this);
} // if( suggestion && this.addTags(this.input.value + suggestion).length ){

@@ -536,3 +570,3 @@ // this.input.set.call(this);

return tagsItems.split(this.settings.delimiters).filter(function (n) {
tagsItems = tagsItems.split(this.settings.delimiters).filter(function (n) {
return n;

@@ -544,5 +578,3 @@ }).map(function (v) {

});
}
if (tagsItems instanceof Array) return tagsItems.map(function (v) {
} else if (tagsItems instanceof Array) tagsItems = tagsItems.map(function (v) {
return {

@@ -553,2 +585,3 @@ value: v.trim()

if (whitelistWithProps) {

@@ -561,9 +594,66 @@ tagsItems.forEach(function (tag) {

if (matchObj[0]) temp.push(matchObj[0]); // set the Array (with the found Object) as the new value
else temp.push(tag);
else if (_this3.settings.mode != 'mix') temp.push(tag);
});
return temp;
}
return tagsItems;
},
parseMixTags: function parseMixTags(s) {
var _this4 = this;
var htmlString = '';
s = s.split(this.settings.pattern); // this.DOM.scope.innerHTML
htmlString = s.shift() + s.map(function (part) {
var tagElm, i, normalizedTag;
if (!part) return '';
for (i in part) {
if (part[i].match(/,|\.| /)) {
normalizedTag = _this4.normalizeTags.call(_this4, part.substr(0, i))[0];
if (normalizedTag) tagElm = _this4.createTagElem(normalizedTag);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) : _this4.settings.pattern + part;
}).join('');
return htmlString;
},
/**
* Add a tag where it might be beside textNodes
*/
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 (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);
}
node.parentNode.replaceChild(wrapElm, node);
this.input.setRangeAtStartEnd.call(this, true, textNodeAfter);
},
/**
* add a "tag" element to the "tags" component

@@ -575,15 +665,16 @@ * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]

addTags: function addTags(tagsItems, clearInput) {
var _this4 = this;
var _this5 = this;
var tagElems = [];
tagsItems = this.normalizeTags.call(this, tagsItems);
if (this.settings.mode == 'mix') return this.addMixTag(tagsItems[0]);
this.DOM.input.removeAttribute('style');
tagsItems = this.normalizeTags.call(this, tagsItems);
tagsItems.forEach(function (tagData) {
var tagValidation, tagElm;
if (typeof _this4.settings.transformTag === 'function') {
tagData.value = _this4.settings.transformTag.call(_this4, tagData.value) || tagData.value;
if (typeof _this5.settings.transformTag === 'function') {
tagData.value = _this5.settings.transformTag.call(_this5, tagData.value) || tagData.value;
}
tagValidation = _this4.validateTag.call(_this4, tagData.value);
tagValidation = _this5.validateTag.call(_this5, tagData.value);

@@ -594,7 +685,7 @@ if (tagValidation !== true) {

_this4.markTagByValue(tagData.value);
_this5.markTagByValue(tagData.value);
_this4.trigger("invalid", {
_this5.trigger("invalid", {
value: tagData.value,
index: _this4.value.length,
index: _this5.value.length,
message: tagValidation

@@ -605,21 +696,21 @@ });

tagElm = _this4.createTagElem(tagData);
tagElm = _this5.createTagElem(tagData);
tagElems.push(tagElm); // add the tag to the component's DOM
appendTag.call(_this4, tagElm);
appendTag.call(_this5, tagElm);
if (tagValidation === true) {
// update state
_this4.value.push(tagData);
_this5.value.push(tagData);
_this4.update();
_this5.update();
_this4.trigger('add', _this4.extend({}, {
index: _this4.value.length,
_this5.trigger('add', _this5.extend({}, {
index: _this5.value.length,
tag: tagElm
}, tagData));
} else if (!_this4.settings.keepInvalidTags) {
} else if (!_this5.settings.keepInvalidTags) {
// remove invalid tags (if "keepInvalidTags" is set to "false")
setTimeout(function () {
_this4.removeTag(tagElm, true);
_this5.removeTag(tagElm, true);
}, 1000);

@@ -645,2 +736,5 @@ }

},
minify: function minify(html) {
return html.replace(new RegExp("\>[\r\n ]+\<", "g"), "><");
},

@@ -655,3 +749,3 @@ /**

v = this.escapeHtml(tagData.value),
template = "<tag title='" + v + "'>\n <x title=''></x><div><span>" + v + "</span></div>\n </tag>";
template = "<tag title='" + v + "' contenteditable='false'>\n <x title=''></x><div><span>" + v + "</span></div>\n </tag>";

@@ -676,2 +770,3 @@ if (typeof this.settings.tagTemplate === "function") {

template = this.minify(template);
tagElm = this.parseHTML(template); // add any attribuets, if exists

@@ -863,6 +958,6 @@

onClick: function onClick(e) {
var _this5 = this;
var _this6 = this;
var onClickOutside = function onClickOutside() {
return _this5.dropdown.hide.call(_this5);
return _this6.dropdown.hide.call(_this6);
},

@@ -879,4 +974,4 @@ listItemElm;

if (listItemElm) {
this.input.set.call(this);
this.addTags(listItemElm.textContent);
this.addTags(listItemElm.textContent, true);
this.dropdown.hide.call(this);
} // clicked outside the dropdown, so just close it

@@ -883,0 +978,0 @@ else onClickOutside();

@@ -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.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"],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 '+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.settings.whitelist.length&&this.dropdown.init.call(this),t.autofocus&&e.input.focus()},destroy:function(){this.DOM.scope.parentNode.removeChild(this.DOM.scope)},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=!(0<arguments.length&&void 0!==arguments[0])||arguments[0],e=this.events.callbacks,i=this.listeners.main=this.listeners.main||{paste:["input",e.onPaste.bind(this)],focus:["input",e.onFocusBlur.bind(this)],blur:["input",e.onFocusBlur.bind(this)],keydown:["input",e.onKeydown.bind(this)],click:["scope",e.onClickScope.bind(this)]},n=t?"addEventListener":"removeEventListener";for(var s in i)this.DOM[i[s][0]][n](s,i[s][1]);t&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",e[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&$(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this)))},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"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;"Backspace"!=t.key||""!=i&&8203!=i.charCodeAt(0)?"Escape"==t.key||"Esc"==t.key?(this.input.set.call(this),t.target.blur()):"Enter"==t.key?(t.preventDefault(),this.addTags(this.input.value,!0)):"ArrowRight"==t.key&&this.input.autocomplete.set.call(this):(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide)"))[e.length-1],this.removeTag(e))},onInput:function(t){var e=this.input.normalize.call(this),i=e.length>=this.settings.dropdown.enabled;e?this.input.value!=e&&(this.input.set.call(this,e,!1),-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,"")},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)}}},loadOriginalValues:function(){var t=this.DOM.originalInput.value;if(t){try{t=JSON.parse(t)}catch(t){}this.addTags(t).forEach(function(t){t&&t.classList.add("tagify--noAnim")})}},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)},setRangeAtEnd:function(){var t,e;document.createRange&&((t=document.createRange()).selectNodeContents(this.DOM.input),t.collapse(!1),(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);i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtEnd.call(this))}}},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.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=[];return n?t:"string"==typeof t?t.trim()?t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}}):[]:t instanceof Array?t.map(function(t){return{value:t.trim()}}):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]):s.push(e)}),s):void 0},addTags:function(t,e){var n=this,s=[];return this.DOM.input.removeAttribute("style"),(t=this.normalizeTags.call(this,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},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag title='"+i+"'>\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 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){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=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(a,400)):a(),e||(n=this.value.splice(s,1)[0],this.update(),this.trigger("remove",this.extend({},{index:s,tag:t},n)))}function a(){t.parentNode.removeChild(t)}},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=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;this.settings.whitelist.length&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.slice(0),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),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"Enter":t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":return t.preventDefault(),this.input.autocomplete.set.call(this,e?e.textContent:null),!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.input.set.call(this),this.addTags(e.textContent)):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().replace(/\s/g,"").indexOf(t.toLowerCase().replace(/\s/g,""))&&-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+"</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,dropdown:{classname:"",enabled:2,maxItems:10,itemTemplate:""}},customEventsList:["add","remove","invalid"],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.settings.whitelist.length&&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;"mix"!=this.settings.mode&&("Backspace"!=t.key||""!=i&&8203!=i.charCodeAt(0)?"Escape"==t.key||"Esc"==t.key?(this.input.set.call(this),t.target.blur()):"Enter"==t.key?(t.preventDefault(),this.addTags(this.input.value,!0)):"ArrowRight"==t.key&&this.input.autocomplete.set.call(this):(e=(e=this.DOM.scope.querySelectorAll("tag:not(.tagify--hide)"))[e.length-1],this.removeTag(e)))},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),-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.dropdown[s?"show":"hide"].call(this,s)},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);i&&(this.input.set.call(this,i),this.input.autocomplete.suggest.call(this,""),this.dropdown.hide.call(this),this.input.setRangeAtStartEnd.call(this))}}},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.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.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){"string"==typeof t&&(t=this.getTagElmByValue(t));var n,s=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(a,400)):a(),e||(n=this.value.splice(s,1)[0],this.update(),this.trigger("remove",this.extend({},{index:s,tag:t},n)))}function a(){t.parentNode.removeChild(t)}},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=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;this.settings.whitelist.length&&(e=t?this.dropdown.filterListItems.call(this,t):this.settings.whitelist.slice(0),i=this.dropdown.createListHTML.call(this,e),this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),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"Enter":t.preventDefault(),i=e?e.textContent:this.input.value,this.addTags(i,!0),this.dropdown.hide.call(this);break;case"ArrowRight":case"Tab":return t.preventDefault(),this.input.autocomplete.set.call(this,e?e.textContent:null),!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().replace(/\s/g,"").indexOf(t.toLowerCase().replace(/\s/g,""))&&-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+"</div>"};return t.map(e).join("")}}},t});
{
"name": "@yaireo/tagify",
"version": "2.3.0",
"version": "2.5.0",
"homepage": "https://github.com/yairEO/tagify",

@@ -5,0 +5,0 @@ "description": "Want to simply convert an input field into a tags element, in a easy customizable way, with good performance and smallest code footprint? You are in the right place my friend.",

@@ -15,8 +15,31 @@ [Tagify](https://yaireo.github.io/tagify) - lightweight input "tags" script

-->
<p align="center">
<img src="https://raw.githubusercontent.com/yairEO/tagify/master/mix.gif" />
</p>
<p align="center">
<img src="https://raw.githubusercontent.com/yairEO/tagify/master/demo.gif" />
</p>
![alt tag](https://raw.githubusercontent.com/yairEO/tagify/master/demo.gif)
Transforms an input field or a textarea into a *Tags* component, in an easy, customizable way,
with great performance and tiny code footprint.
## [Documentation & Demos](https://yaireo.github.io/tagify)
## Table of contents
<!--ts-->
* [Installation](#installation)
* [Selling points](#selling-points)
* [What can Tagify do](#what-can-tagify-do)
* [Building the project](#building-the-project)
* [Adding tags dynamically](#adding-tags-dynamically)
* [Suggestions selectbox](#suggestions-selectbox)
* [jQuery version](#jquery-version)
* [Methods](#methods)
* [Events](#events)
* [Settings](#settings)
<!--te-->
## Installation
npm i @yaireo/tagify --save

@@ -27,6 +50,6 @@

## [Documentation & Demos](https://yaireo.github.io/tagify)
var tagify = new Tagify(...)
## Selling points
* JS at `~13kb` (`4kb` GZIP) (less than *900* easily understandable lines of code)
* JS minified `~16kb` (`~4kb` GZIP)
* SCSS file is `~6kb` of well-crafted flexible code

@@ -41,2 +64,3 @@ * Easily change direction to RTL via the SCSS file only

* Can be applied on input & textarea elements
* Supports mix content (text and tags together)
* Supports whitelist

@@ -63,139 +87,14 @@ * Supports blacklists

## Basic usage
Lets say this is your markup, and you already have a value set on the input (which was pre-filled by data from the server):
### Adding tags dynamically
```html
<input name='tags' placeholder='write some tags' value='foo, bar,buzz'>
<textarea name='tags' pattern=".{3,}" placeholder='write some tags'>foo, bar,buzz</textarea>
```
What you need to do to convert that nice input into "tags" is simply select your input/textarea and run `tagify()`:
```javascript
// vanilla component
var input = document.querySelector('input[name=tags]'),
tagify = new Tagify( input );
// with settings passed
tagify = new Tagify( input, {
duplicates: true,
whitelist: ['foo', 'bar'],
callbacks: {
add : onAddTag // calls an imaginary "onAddTag" function when a tag is added
}
});
// listen to custom tags' events such as 'add' or 'remove' (see full list below).
// listeners are chainable
tagify.on('remove', onTagRemoved)
.on('add', onTagAdded);
.on('invalid', onInvaildTag)
function onTagRemoved(e){
console.log(e, e.detail);
// remove listener after first tag removal
tagify.off('remove', onTagRemoved);
}
function onTagAdded(e){
// do whatever
}
function onInvaildTag(e){
// e.detail ...
}
```
The value of the Tagify component can be accessed like so:
```javascript
var tagify = new Tagify(...);
console.log( tagify.value )
// [{"value":"tag1"}, {"value":"tag2"}, ...]
tagify.addTags(["banana", "orange", "apple"])
// The original input's value is a String representing Array of Objects.
// To parse it, use: `JSON.parse(input.value)`
console.log( input.value )
// "[{value:"tag1"}, {value:"tag2"}, ...]"
```
// or add tags with pre-defined propeties
If the Tags were added with custom properties, the *value* output might look something like this:
```javascript
tagify.value
// [{"value":"tag1", "class":"red", "id":1}, ...]
tagify.addTags([{value:"banana", color:"yellow"}, {value:"apple", color:"red"}, {value:"watermelon", color:"green"}])
```
### Tags with properties ([example](https://yaireo.github.io/tagify#section-extra-properties))
The below example will populate the Tags component with 2 tags, each with specific attributes & values.
the `addTags` method accepts an Array of Objects with **any** key/value, as long as the `value` key is defined.
```html
<input placeholder="add tags">
```
```javascript
var allowedTags = [
{
"value" : "apple",
"data-id" : 3,
"class" : 'color-green'
},
{
"value" : "orange",
"data-id" : 56,
"class" : 'color-orange'
},
{
"value" : "passion fruit",
"data-id" : 17,
"class" : 'color-purple'
},
{
"value" : "banana",
"data-id" : 12,
"class" : 'color-yellow'
},
{
"value" : "paprika",
"data-id" : 25,
"class" : 'color-red'
}
];
var input = document.querySelector('input'),
tagify = new Tagify(input, {
whitelist : allowedTags
});
// Add the first 2 tags from the "allowedTags" Array
tagify.addTags( allowedTags.slice(0,2) )
```
The above will prepend a "tags" element before the original input element:
```html
<tags class="tagify">
<tag readonly="true" class="color-red" data-id="8" value="strawberry">
<x></x><div><span title="strawberry">strawberry</span></div>
</tag>
<tag readonly="true" class="color-darkblue" data-id="6" value="blueberry">
<x></x><div><span title="blueberry">blueberry</span></div>
</tag>
<div contenteditable data-placeholder="add tags" class="tagify--input"></div>
</tags>
<input placeholder="add tags">
```
Another way to add tags is:
```javascript
tagify.addTags(
["banana", "orange", "apple"].map( item => ({ value:item }) )
);
```
### Suggestions selectbox

@@ -238,4 +137,9 @@ The suggestions selectbox is shown is a whitelist Array of Strings or Objects was passed in the settings when the Tagify instance was created.

### jQuery plugin version (jQuery.tagify.js)
### jQuery version
`jQuery.tagify.js`
A jQuery wrapper verison is also available, but I advise not using it because it's basically the exact same as the "normal"
script (non-jqueryfied) and all the jQuery's wrapper does is allowing to chain the event listeners for ('add', 'remove', 'invalid')
```javascript

@@ -258,2 +162,3 @@ $('[name=tags]')

removeTag | Removes a specific tag (argument is the tag DOM element to be removed. see source code.)
loadOriginalValues | Converts the input's value into tags. This method gets called automatically when instansiating Tagify
getTagIndexByValue |

@@ -263,3 +168,3 @@ getTagElmByValue |

## Exposed events
## Events

@@ -279,2 +184,3 @@ Name | Info

pattern | String | null | Validate input by REGEX pattern (can also be applied on the input itself as an attribute) Ex: /[1-9]/
mode | String | null | use 'mix' as value to allow mixed-content. The 'pattern' setting must be set to some character.
duplicates | Boolean | false | (flag) Should duplicate tags be allowed or not

@@ -281,0 +187,0 @@ enforceWhitelist | Boolean | false | Should ONLY use tags allowed in whitelist

@@ -24,2 +24,3 @@ function Tagify( input, settings ){

this.state = {};
this.value = []; // tags' data

@@ -100,3 +101,3 @@

DOM = this.DOM,
template = `<tags class="tagify ${input.className}" ${this.settings.readonly ? 'readonly' : ''}>
template = `<tags class="tagify ${this.settings.mode ? "tagify--mix" : "" } ${input.className}" ${this.settings.readonly ? 'readonly' : ''}>
<div contenteditable data-placeholder="${input.placeholder}" class="tagify__input"></div>

@@ -125,2 +126,24 @@ </tags>`;

/**
* If the original input had an values, add them as tags
*/
loadOriginalValues(){
var value = this.DOM.originalInput.value;
// if the original input already had any value (tags)
if( !value ) return;
try{ value = JSON.parse(value) }
catch(err){}
if( this.settings.mode == 'mix' ){
this.DOM.input.innerHTML = this.parseMixTags(value);
}
else
this.addTags(value).forEach(tag => {
tag && tag.classList.add('tagify--noAnim');
});
},
/**
* Merge two objects into a new one

@@ -210,17 +233,6 @@ * TEST: extend({}, {a:{foo:1}, b:[]}, {a:{bar:2}, b:[1], c:()=>{}})

var _CB = this.events.callbacks,
// setup callback references so events could be removed later
_CBR = (this.listeners.main = this.listeners.main || {
paste : ['input', _CB.onPaste.bind(this)],
focus : ['input', _CB.onFocusBlur.bind(this)],
blur : ['input', _CB.onFocusBlur.bind(this)],
keydown : ['input', _CB.onKeydown.bind(this)],
click : ['scope', _CB.onClickScope.bind(this)]
}),
_CBR,
action = bindUnbind ? 'addEventListener' : 'removeEventListener';
for( var eventName in _CBR ){
this.DOM[_CBR[eventName][0]][action](eventName, _CBR[eventName][1]);
}
if( bindUnbind ){
if( bindUnbind && !this.listeners.main ){
// this event should never be unbinded

@@ -233,2 +245,15 @@ // IE cannot register "input" events on contenteditable elements, so the "keydown" should be used instead..

}
// setup callback references so events could be removed later
_CBR = (this.listeners.main = this.listeners.main || {
paste : ['input', _CB.onPaste.bind(this)],
focus : ['input', _CB.onFocusBlur.bind(this)],
blur : ['input', _CB.onFocusBlur.bind(this)],
keydown : ['input', _CB.onKeydown.bind(this)],
click : ['scope', _CB.onClickScope.bind(this)]
});
for( var eventName in _CBR ){
this.DOM[_CBR[eventName][0]][action](eventName, _CBR[eventName][1]);
}
},

@@ -243,2 +268,4 @@

if( this.settings.mode == 'mix' ) return;
if( e.type == "focus" ){

@@ -266,2 +293,4 @@ // e.target.classList.remove('placeholder');

if( this.settings.mode == 'mix' ) return;
if( e.key == 'Backspace' && (s == "" || s.charCodeAt(0) == 8203) ){

@@ -291,2 +320,5 @@ lastTag = this.DOM.scope.querySelectorAll('tag:not(.tagify--hide)');

if( this.settings.mode == 'mix' )
return this.events.callbacks.onMixTagsInput.call(this, e);
if( !value ){

@@ -312,2 +344,25 @@ this.input.set.call(this, '');

onMixTagsInput( e ){
var sel, range, split, tag,
patternLen = this.settings.pattern.length;
this.state.tag = null;
if( window.getSelection ){
sel = window.getSelection();
if( sel.rangeCount > 0 ){
range = sel.getRangeAt(0).cloneRange();
range.collapse(true);
range.setStart(window.getSelection().focusNode, 0);
split = range.toString().split(/,|\.|\s/); // ["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.dropdown[tag ? "show" : "hide"].call(this, tag);
},
onInputIE(e){

@@ -335,19 +390,2 @@ var _this = this;

/**
* If the original input had an values, add them as tags
*/
loadOriginalValues(){
var value = this.DOM.originalInput.value;
// if the original input already had any value (tags)
if( !value ) return;
try{ value = JSON.parse(value) }
catch(err){}
this.addTags(value).forEach(tag => {
tag && tag.classList.add('tagify--noAnim');
});
},
/**
* input bridge for accessing & setting

@@ -369,3 +407,3 @@ * @type {Object}

// https://stackoverflow.com/a/3866442/104380
setRangeAtEnd(){
setRangeAtStartEnd( start=false, node ){
var range, selection;

@@ -376,4 +414,4 @@

range = document.createRange();
range.selectNodeContents(this.DOM.input);
range.collapse(false);
range.selectNodeContents(node || this.DOM.input);
range.collapse(start);
selection = window.getSelection();

@@ -424,3 +462,3 @@ selection.removeAllRanges();

this.dropdown.hide.call(this);
this.input.setRangeAtEnd.call(this);
this.input.setRangeAtStartEnd.call(this);
}

@@ -555,3 +593,2 @@

// if the value is a "simple" String, ex: "aaa, bbb, ccc"

@@ -562,7 +599,7 @@ if( typeof tagsItems == 'string' ){

// go over each tag and add it (if there were multiple ones)
return tagsItems.split(this.settings.delimiters).filter(n => n).map(v => ({ value:v.trim() }));
tagsItems = tagsItems.split(this.settings.delimiters).filter(n => n).map(v => ({ value:v.trim() }));
}
if( tagsItems instanceof Array )
return tagsItems.map(v => ({ value:v.trim() }))
else if( tagsItems instanceof Array )
tagsItems = tagsItems.map(v => ({ value:v.trim() }))

@@ -575,3 +612,3 @@ // search if the tag exists in the whitelist as an Object (has props), to be able to use its properties

temp.push( matchObj[0] ); // set the Array (with the found Object) as the new value
else
else if( this.settings.mode != 'mix' )
temp.push(tag)

@@ -582,5 +619,69 @@ })

}
return tagsItems;
},
parseMixTags( s ){
var htmlString = '';
s = s.split( this.settings.pattern );
// this.DOM.scope.innerHTML
htmlString = s.shift() + s.map(part => {
var tagElm, i, normalizedTag;
if( !part ) return '';
for( i in part ){
if( part[i].match(/,|\.| /) ){
normalizedTag = this.normalizeTags.call(this, part.substr(0, i))[0];
if( normalizedTag ) tagElm = this.createTagElem(normalizedTag);
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;
},
/**
* Add a tag where it might be beside textNodes
*/
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( 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 );
}
node.parentNode.replaceChild(wrapElm, node);
this.input.setRangeAtStartEnd.call(this, true, textNodeAfter);
},
/**
* add a "tag" element to the "tags" component

@@ -594,6 +695,9 @@ * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]

tagsItems = this.normalizeTags.call(this, tagsItems);
if( this.settings.mode == 'mix' )
return this.addMixTag(tagsItems[0]);
this.DOM.input.removeAttribute('style');
tagsItems = this.normalizeTags.call(this, tagsItems);
tagsItems.forEach(tagData => {

@@ -654,2 +758,6 @@ var tagValidation, tagElm;

minify( html ){
return html.replace( new RegExp( "\>[\r\n ]+\<" , "g" ) , "><" );
},
/**

@@ -660,6 +768,6 @@ * creates a DOM tag element and injects it into the component (this.DOM.scope)

*/
createTagElem(tagData){
createTagElem( tagData ){
var tagElm,
v = this.escapeHtml(tagData.value),
template = `<tag title='${v}'>
template = `<tag title='${v}' contenteditable='false'>
<x title=''></x><div><span>${v}</span></div>

@@ -685,2 +793,3 @@ </tag>`;

template = this.minify(template);
tagElm = this.parseHTML(template);

@@ -900,4 +1009,4 @@

if( listItemElm ){
this.input.set.call(this)
this.addTags( listItemElm.textContent );
this.addTags( listItemElm.textContent, true );
this.dropdown.hide.call(this);
}

@@ -904,0 +1013,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc