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.0.3 to 2.1.0

253

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

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

this.value = []; // An array holding all the (currently used) tags
this.stringValue = ""; // same as above, only as a String

@@ -68,13 +69,22 @@ // events' callbacks references will be stores here, so events could be unbinded

TEXTS: {
empty: "empty",
exceed: "number of tags exceeded",
pattern: "pattern mismatch",
duplicate: "already exists",
notAllowed: "not allowed"
},
DEFAULTS: {
delimiters: ",", // [regex] split tags by any of these delimiters ("null" to cancel) Example: ",| |."
pattern: null, // regex pattern to validate input by. Ex: /[1-9]/
maxTags: Infinity, // maximum number of tags
callbacks: {}, // exposed callbacks object to be triggered on certain events
addTagOnBlur: true, // flag - automatically adds the text which was inputed as a tag when blur event happens
duplicates: false, // flag - allow tuplicate tags
whitelist: [], // is this list has any items, then only allow tags from this list
blacklist: [], // a list of non-allowed tags
enforceWhitelist: false, // flag - should ONLY use tags allowed in whitelist
autoComplete: true, // flag - tries to autocomplete the input's value while typing
delimiters: ",", // [RegEx] split tags by any of these delimiters ("null" to cancel) Example: ",| |."
pattern: null, // RegEx pattern to validate input by. Ex: /[1-9]/
maxTags: Infinity, // Maximum number of tags
callbacks: {}, // Exposed callbacks object to be triggered on certain events
addTagOnBlur: true, // Flag - automatically adds the text which was inputed as a tag when blur event happens
duplicates: false, // Flag - allow tuplicate tags
whitelist: [], // Array of tags to suggest as the user types (can be used along with "enforceWhitelist" setting)
blacklist: [], // A list of non-allowed tags
enforceWhitelist: false, // Flag - Only allow tags allowed in whitelist
keepInvalidTags: false, // Flag - if true, do not remove tags which did not pass validation
autoComplete: true, // Flag - tries to autocomplete the input's value while typing
mapValueToProp: "", // String - when tags have multiple properties, and for each tag another property should be used besides the "value"

@@ -88,3 +98,3 @@ dropdown: {

customEventsList: ['add', 'remove', 'duplicate', 'maxTagsExceed', 'blacklisted', 'notWhitelisted'],
customEventsList: ['add', 'remove', 'invalid'],

@@ -121,3 +131,3 @@ /**

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

@@ -129,3 +139,2 @@ this.DOM.originalInput = input;

// if "autocomplete" flag on toggeled & "whitelist" has items, build suggestions list
if (this.settings.dropdown.enabled && this.settings.whitelist.length) {

@@ -139,2 +148,4 @@ this.dropdown.init.call(this);

});
input.autofocus && this.DOM.input.focus();
},

@@ -295,14 +306,22 @@

onInput: function onInput(e) {
var value = e.target.textContent.trim(),
var value = this.input.normalize.call(this),
showSuggestions = value.length >= this.settings.dropdown.enabled;
if (this.input.value == value) return;
// save the value on the input state object
this.input.value = value;
this.input.normalize.call(this);
this.input.autocomplete.suggest.call(this, ''); // cleanup any possible previous suggestion
if (!value) {
this.input.set.call(this, '');
return;
}
if (this.input.value == value) return; // for IE; since IE doesn't have an "input" event so "keyDown" is used instead
// save the value on the input's State object
this.input.set.call(this, value, false);
if (value.search(this.settings.delimiters) != -1) {
if (this.addTags(value).length) this.input.set.call(this); // clear the input field's value
} else if (this.settings.dropdown.enabled && this.settings.whitelist.length) this.dropdown[showSuggestions ? "show" : "hide"].call(this, value);
if (this.addTags(value).length) {
this.input.set.call(this); // clear the input field's value
}
} else if (this.settings.dropdown.enabled && this.settings.whitelist.length) {
this.dropdown[showSuggestions ? "show" : "hide"].call(this, value);
}
},

@@ -333,14 +352,34 @@ onInputIE: function onInputIE(e) {

var s = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var updateDOM = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
this.input.value = this.DOM.input.innerHTML = s;
this.input.value = s;
if (updateDOM) this.DOM.input.innerHTML = s;
if (s.length < 2) this.input.autocomplete.suggest.call(this, '');
this.input.validate.call(this);
},
/**
* Marks the tagify's input as "invalid" if the value did not pass "validateTag()"
*/
validate: function validate() {
var isValid = !this.input.value || this.validateTag.call(this, this.input.value);
this.DOM.input.classList.toggle('tagify__input--invalid', isValid !== true);
},
// remove any child DOM elements that aren't of type TEXT (like <br>)
normalize: function normalize() {
while (this.DOM.input.firstElementChild) {
this.DOM.input.removeChild(this.DOM.input.firstElementChild);
var clone = this.DOM.input.cloneNode(true),
v = clone.textContent.replace(/\s/g, ' '); // replace NBSPs with spaces characters
while (clone.firstElementChild) {
v += clone.firstElementChild.textContent;
clone.removeChild(clone.firstElementChild);
}
return v.replace(/^\s+/, ""); // trimLeft
},

@@ -382,5 +421,6 @@

isTagDuplicate: function isTagDuplicate(s) {
return this.value.some(function (item) {
return this.value.findIndex(function (item) {
return s.toLowerCase() === item.value.toLowerCase();
});
// return this.value.some(item => s.toLowerCase() === item.value.toLowerCase());
},

@@ -396,9 +436,7 @@

markTagByValue: function markTagByValue(value, tagElm) {
var tagsElms, tagsElmsLen;
var tagsElms, tagsElmsLen, tagIdx;
if (!tagElm) {
tagsElms = this.DOM.scope.querySelectorAll('tag');
for (tagsElmsLen = tagsElms.length; tagsElmsLen--;) {
if (tagsElms[tagsElmsLen].value.toLowerCase().includes(value.toLowerCase())) tagElm = tagsElms[tagsElmsLen];
}
tagIdx = this.isTagDuplicate.call(this, value);
tagElm = this.DOM.scope.querySelectorAll('tag')[tagIdx];
}

@@ -411,5 +449,5 @@

tagElm.classList.remove('tagify--mark');
}, 2000);
return true;
} else {}
}, 100);
return tagElm;
}

@@ -443,2 +481,27 @@ return false;

/**
* validate a tag object BEFORE the actual tag will be created & appeneded
* @param {String} s
* @return {Boolean/String} ["true" if validation has passed, String for a fail]
*/
validateTag: function validateTag(s) {
var value = s.trim(),
maxTagsExceed = this.value.length >= this.settings.maxTags,
isDuplicate,
eventName__error,
result = true;
// check for empty value
if (!value) result = this.TEXTS.empty;else if (maxTagsExceed) result = this.TEXTS.exceed;
// check if pattern should be used and if so, use it to test the value
else if (this.settings.pattern && !this.settings.pattern.test(value)) result = this.TEXTS.pattern;
// if duplicates are not allowed and there is a duplicate
else if (!this.settings.duplicates && this.isTagDuplicate(value) !== -1) result = this.TEXTS.duplicate;else if (this.isTagBlacklisted(value) || this.settings.enforceWhitelist && !this.isTagWhitelisted(value)) result = this.TEXTS.notAllowed;
return result;
},
/**
* add a "tag" element to the "tags" component

@@ -450,5 +513,6 @@ * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects]

addTags: function addTags(tagsItems, clearInput) {
var that = this,
tagElems = [];
var _this3 = this;
var tagElems = [];
this.DOM.input.removeAttribute('style');

@@ -484,7 +548,8 @@

if (!isComplex) {
tagsItems = tagsItems.trim();
if (!tagsItems) return [];
if (!tagsItems.trim()) return [];
// go over each tag and add it (if there were multiple ones)
result = tagsItems.split(this.settings.delimiters).map(function (v) {
result = tagsItems.split(this.settings.delimiters).filter(function (n) {
return n;
}).map(function (v) {
return { value: v.trim() };

@@ -494,54 +559,6 @@ });

return result.filter(function (n) {
return n;
}); // cleanup the array from "undefined", "false" or empty items;
return result;
}
/**
* validate a tag object BEFORE the actual tag will be created & appeneded
* @param {Object} tagData [{"value":"text", "class":whatever", ...}]
* @return {Boolean/String} ["true" if validation has passed, String or "false" for any type of error]
*/
function validateTag(tagData) {
var value = tagData.value.trim(),
maxTagsExceed = this.value.length >= this.settings.maxTags,
isDuplicate,
eventName__error,
tagAllowed;
// check for empty value
if (!value) return "empty";
// check if pattern should be used and if so, use it to test the value
if (this.settings.pattern && !this.settings.pattern.test(value)) return "pattern";
// check if the tag already exists
if (this.isTagDuplicate(value)) {
this.trigger('duplicate', value);
if (!this.settings.duplicates) {
// this.markTagByValue(value, tagElm)
return "duplicate";
}
}
// check if the tag is allowed by the rules set
tagAllowed = !this.isTagBlacklisted(value) && (!this.settings.enforceWhitelist || this.isTagWhitelisted(value)) && !maxTagsExceed;
// Check against blacklist & whitelist (if enforced)
if (!tagAllowed) {
tagData.class = tagData.class ? tagData.class + " tagify--notAllowed" : "tagify--notAllowed";
// broadcast why the tag was not allowed
if (maxTagsExceed) eventName__error = 'maxTagsExceed';else if (this.isTagBlacklisted(value)) eventName__error = 'blacklisted';else if (this.settings.enforceWhitelist && !this.isTagWhitelisted(value)) eventName__error = 'notWhitelisted';
this.trigger(eventName__error, { value: value, index: this.value.length });
return "notAllowed";
}
return true;
}
/**
* appened (validated) tag to the component's DOM scope

@@ -558,24 +575,29 @@ * @return {[type]} [description]

tagsItems.forEach(function (tagData) {
var tagValidation = _this3.validateTag.call(_this3, tagData.value),
tagElm;
var isTagValidated = validateTag.call(that, tagData);
if (isTagValidated === true || isTagValidated == "notAllowed") {
// create the tag element
var tagElm = that.createTagElem(tagData);
if (tagValidation !== true) {
tagData.class = tagData.class ? tagData.class + " tagify--notAllowed" : "tagify--notAllowed";
tagData.title = tagValidation;
_this3.markTagByValue.call(_this3, tagData.value);
_this3.trigger("invalid", { value: tagData.value, index: _this3.value.length, message: tagValidation });
}
// add the tag to the component's DOM
appendTag.call(that, tagElm);
// Create tag HTML element
tagElm = _this3.createTagElem(tagData);
tagElems.push(tagElm);
// remove the tag "slowly"
if (isTagValidated == "notAllowed") {
setTimeout(function () {
that.removeTag(tagElm, true);
}, 1000);
} else {
// update state
that.value.push(tagData);
that.update();
that.trigger('add', that.extend({}, { index: that.value.length, tag: tagElm }, tagData));
// add the tag to the component's DOM
appendTag.call(_this3, tagElm);
tagElems.push(tagElm);
}
if (tagValidation === true) {
// update state
_this3.value.push(tagData);
_this3.update();
_this3.trigger('add', _this3.extend({}, { index: _this3.value.length, tag: tagElm }, tagData));
} else if (!_this3.settings.keepInvalidTags) {
// remove invalid tags (if "keepInvalidTags" is set to "false")
setTimeout(function () {
_this3.removeTag(tagElm, true);
}, 1000);
}

@@ -600,3 +622,3 @@ });

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

@@ -629,2 +651,4 @@ // for a certain Tag element, add attributes.

removeTag: function removeTag(tagElm, silent) {
if (!tagElm) return;
var tagData,

@@ -664,8 +688,9 @@ tagIdx = this.getNodeIndex(tagElm);

update: function update() {
var _this3 = this;
var _this4 = this;
var tagsAsString = this.value.map(function (v) {
return v[_this3.settings.mapValueToProp || "value"] || v.value;
return v[_this4.settings.mapValueToProp || "value"] || v.value;
});
this.DOM.originalInput.value = JSON.stringify(tagsAsString).slice(1, -1);
this.stringValue = JSON.stringify(tagsAsString).slice(1, -1);
this.DOM.originalInput.value = this.stringValue;
},

@@ -691,3 +716,5 @@

if (listItems.length && this.settings.autoComplete) this.input.autocomplete.suggest.call(this, listItems[0].value);
if (this.settings.autoComplete) {
this.input.autocomplete.suggest.call(this, listItems.length ? listItems[0].value : '');
}

@@ -722,3 +749,3 @@ if (!listHTML || listItems.length < 2) {

this.DOM.dropdown.style.cssText = "left: " + rect.left + window.pageXOffset + "px; \
this.DOM.dropdown.style.cssText = "left: " + (rect.left + window.pageXOffset) + "px; \
top: " + (rect.top + rect.height - 1 + window.pageYOffset) + "px; \

@@ -844,3 +871,3 @@ width: " + rect.width + "px";

// match for the value within each "whitelist" item
if (valueIsInWhitelist && !this.isTagDuplicate(whitelistItem.value) && suggestionsCount--) list.push(whitelistItem);
if (valueIsInWhitelist && this.isTagDuplicate(whitelistItem.value) == -1 && suggestionsCount--) list.push(whitelistItem);
if (suggestionsCount == 0) break;

@@ -847,0 +874,0 @@ }

@@ -1,1 +0,1 @@

"use strict";!function(t){function e(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.id=Math.random().toString(36).substr(2,9),this.value=[],this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),this.events.customBinding.call(this),this.events.binding.call(this)}t.fn.tagify=function(){var i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.each(function(){var n,s=t(this);if(s.data("tagify"))return this;i.isJQueryPlugin=!0,n=new e(s[0],i),s.data("tagify",n)})},e.prototype={isIE:window.document.documentMode,DEFAULTS:{delimiters:",",pattern:null,maxTags:1/0,callbacks:{},addTagOnBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,autoComplete:!0,mapValueToProp:"",dropdown:{classname:"",enabled:2,maxItems:10}},customEventsList:["add","remove","duplicate","maxTagsExceed","blacklisted","notWhitelisted"],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=t.value,i='\n <tags class="tagify '+t.className+" "+(this.settings.readonly?"readonly":"")+'">\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify--input"></div>\n </tags>';this.DOM.originalInput=t,this.DOM.scope=this.parseHTML(i),this.DOM.input=this.DOM.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(this.DOM.scope,t),this.settings.dropdown.enabled&&this.settings.whitelist.length&&this.dropdown.init.call(this),e&&this.addTags(e).forEach(function(t){t&&t.classList.add("tagify--noAnim")})},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}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(e){var i=document.createTextNode("");this.off=function(t,e){return e&&i.removeEventListener.call(i,t,e),this},this.on=function(t,e){return e&&i.addEventListener.call(i,t,e),this},this.trigger=function(n,s){var o;if(n)if(e.settings.isJQueryPlugin)t(e.DOM.originalInput).triggerHandler(n,[s]);else{try{o=new CustomEvent(n,{detail:s})}catch(t){console.warn(t)}i.dispatchEvent(o)}}},events:{customBinding:function(){var t=this;this.customEventsList.forEach(function(e){t.on(e,t.settings.callbacks[e])})},binding:function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],i=this.events.callbacks,n=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)]},s=e?"addEventListener":"removeEventListener";for(var o in n)this.DOM[n[o][0]][s](o,n[o][1]);e&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",i[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&t(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this)))},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"focus"==t.type||("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?(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=t.target.textContent.trim(),i=e.length>=this.settings.dropdown.enabled;this.input.value!=e&&(this.input.value=e,this.input.normalize.call(this),this.input.autocomplete.suggest.call(this,""),-1!=e.search(this.settings.delimiters)?this.addTags(e).length&&this.input.set.call(this):this.settings.dropdown.enabled&&this.settings.whitelist.length&&this.dropdown[i?"show":"hide"].call(this,e))},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=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";this.input.value=this.DOM.input.innerHTML=t,t.length<2&&this.input.autocomplete.suggest.call(this,"")},normalize:function(){for(;this.DOM.input.firstElementChild;)this.DOM.input.removeChild(this.DOM.input.firstElementChild)},autocomplete:{suggest:function(t){t?this.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(){var t=this.DOM.input.getAttribute("data-suggest");t&&this.addTags(this.input.value+t).length&&(this.input.set.call(this),this.dropdown.hide.call(this))}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(t){return this.value.some(function(e){return t.toLowerCase()===e.value.toLowerCase()})},markTagByValue:function(t,e){var i,n;if(!e)for(n=(i=this.DOM.scope.querySelectorAll("tag")).length;n--;)i[n].value.toLowerCase().includes(t.toLowerCase())&&(e=i[n]);return!!e&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},2e3),!0)},isTagBlacklisted:function(t){return t=t.split(" "),this.settings.blacklist.filter(function(e){return-1!=t.indexOf(e)}).length},isTagWhitelisted:function(t){return this.settings.whitelist.some(function(e){if((e.value?e.value:e).toLowerCase()===t.toLowerCase())return!0})},addTags:function(t,e){function i(t){var e,i=t.value.trim(),n=this.value.length>=this.settings.maxTags;return i?this.settings.pattern&&!this.settings.pattern.test(i)?"pattern":this.isTagDuplicate(i)&&(this.trigger("duplicate",i),!this.settings.duplicates)?"duplicate":!!(!this.isTagBlacklisted(i)&&(!this.settings.enforceWhitelist||this.isTagWhitelisted(i))&&!n)||(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",n?e="maxTagsExceed":this.isTagBlacklisted(i)?e="blacklisted":this.settings.enforceWhitelist&&!this.isTagWhitelisted(i)&&(e="notWhitelisted"),this.trigger(e,{value:i,index:this.value.length}),"notAllowed"):"empty"}function n(t){this.DOM.scope.insertBefore(t,this.DOM.input)}var s=this,o=[];return this.DOM.input.removeAttribute("style"),(t=function(t){var e=this.settings.whitelist[0]instanceof Object,i=t instanceof Array&&"value"in t[0],n=t;if(i)return n;if(!i&&"string"==typeof t&&e){var s=this.settings.whitelist.filter(function(e){return e.value.toLowerCase()==t.toLowerCase()});s[0]&&(i=!0,n=s)}if(!i){if(!(t=t.trim()))return[];n=t.split(this.settings.delimiters).map(function(t){return{value:t.trim()}})}return n.filter(function(t){return t})}.call(this,t)).forEach(function(t){var e=i.call(s,t);if(!0===e||"notAllowed"==e){var a=s.createTagElem(t);n.call(s,a),"notAllowed"==e?setTimeout(function(){s.removeTag(a,!0)},1e3):(s.value.push(t),s.update(),s.trigger("add",s.extend({},{index:s.value.length,tag:a},t)),o.push(a))}}),t.length&&e&&this.input.set.call(this),o},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag>\n <x></x><div><span title='"+i+"'>"+i+"</span></div>\n </tag>";return e=this.parseHTML(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,t),e},removeTag:function(t,e){var i,n=this.getNodeIndex(t);t&&(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(function(){t.parentNode.removeChild(t)},400),e||(i=this.value.splice(n,1)[0],this.update(),this.trigger("remove",this.extend({},{index:n,tag:t},i))))},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(){var t=this,e=this.value.map(function(e){return e[t.settings.mapValueToProp||"value"]||e.value});this.DOM.originalInput.value=JSON.stringify(e).slice(1,-1)},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=this.dropdown.filterListItems.call(this,t),i=this.dropdown.createListHTML(e);e.length&&this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e[0].value),!i||e.length<2?this.dropdown.hide.call(this):(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=!(arguments.length>0&&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]("click",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?"previousElementSibling":"nextElementSibling"]:this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0],this.dropdown.highlightOption.call(this,e);break;case"Escape":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":this.input.autocomplete.set.call(this)}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){t.target.className.includes("tagify__dropdown__item")&&(this.input.set.call(this),this.addTags(t.target.textContent)),this.dropdown.hide.call(this)}}},highlightOption:function(t){if(t){var e="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){t.classList.remove(e)}),t.classList.add(e)}},filterListItems:function(t){if(!t)return"";for(var e,i=[],n=this.settings.whitelist,s=this.settings.dropdown.maxItems||1/0,o=0;o<n.length&&(e=n[o]instanceof Object?n[o]:{value:n[o]},0==e.value.toLowerCase().replace(/\s/g,"").indexOf(t.toLowerCase().replace(/\s/g,""))&&!this.isTagDuplicate(e.value)&&s--&&i.push(e),0!=s);o++);return i},createListHTML:function(t){function e(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}return t.map(function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+e(t)+">"+t.value+"</div>"}).join("")}}}}(jQuery);
"use strict";!function(t){function e(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.id=Math.random().toString(36).substr(2,9),this.value=[],this.stringValue="",this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),this.events.customBinding.call(this),this.events.binding.call(this)}t.fn.tagify=function(){var i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.each(function(){var n,s=t(this);if(s.data("tagify"))return this;i.isJQueryPlugin=!0,n=new e(s[0],i),s.data("tagify",n)})},e.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,mapValueToProp:"",dropdown:{classname:"",enabled:2,maxItems:10}},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=t.value,i='\n <tags class="tagify '+t.className+" "+(this.settings.readonly?"readonly":"")+'">\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify__input"></div>\n </tags>';this.DOM.originalInput=t,this.DOM.scope=this.parseHTML(i),this.DOM.input=this.DOM.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(this.DOM.scope,t),this.settings.dropdown.enabled&&this.settings.whitelist.length&&this.dropdown.init.call(this),e&&this.addTags(e).forEach(function(t){t&&t.classList.add("tagify--noAnim")}),t.autofocus&&this.DOM.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}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(e){var i=document.createTextNode("");this.off=function(t,e){return e&&i.removeEventListener.call(i,t,e),this},this.on=function(t,e){return e&&i.addEventListener.call(i,t,e),this},this.trigger=function(n,s){var a;if(n)if(e.settings.isJQueryPlugin)t(e.DOM.originalInput).triggerHandler(n,[s]);else{try{a=new CustomEvent(n,{detail:s})}catch(t){console.warn(t)}i.dispatchEvent(a)}}},events:{customBinding:function(){var t=this;this.customEventsList.forEach(function(e){t.on(e,t.settings.callbacks[e])})},binding:function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],i=this.events.callbacks,n=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)]},s=e?"addEventListener":"removeEventListener";for(var a in n)this.DOM[n[a][0]][s](a,n[a][1]);e&&(this.DOM.input.addEventListener(this.isIE?"keydown":"input",i[this.isIE?"onInputIE":"onInput"].bind(this)),this.settings.isJQueryPlugin&&t(this.DOM.originalInput).on("tagify.removeAllTags",this.removeAllTags.bind(this)))},callbacks:{onFocusBlur:function(t){var e=t.target.textContent.trim();"focus"==t.type||("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?(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):this.settings.dropdown.enabled&&this.settings.whitelist.length&&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)}}},input:{value:"",set:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.input.value=t,e&&(this.DOM.input.innerHTML=t),t.length<2&&this.input.autocomplete.suggest.call(this,""),this.input.validate.call(this)},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.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(){var t=this.DOM.input.getAttribute("data-suggest");t&&this.addTags(this.input.value+t).length&&(this.input.set.call(this),this.dropdown.hide.call(this))}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(t){return this.value.findIndex(function(e){return t.toLowerCase()===e.value.toLowerCase()})},markTagByValue:function(t,e){var i;return e||(i=this.isTagDuplicate.call(this,t),e=this.DOM.scope.querySelectorAll("tag")[i]),!!e&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},100),e)},isTagBlacklisted:function(t){return t=t.split(" "),this.settings.blacklist.filter(function(e){return-1!=t.indexOf(e)}).length},isTagWhitelisted:function(t){return this.settings.whitelist.some(function(e){if((e.value?e.value:e).toLowerCase()===t.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},addTags:function(t,e){function i(t){this.DOM.scope.insertBefore(t,this.DOM.input)}var n=this,s=[];return this.DOM.input.removeAttribute("style"),(t=function(t){var e=this.settings.whitelist[0]instanceof Object,i=t instanceof Array&&"value"in t[0],n=t;if(i)return n;if(!i&&"string"==typeof t&&e){var s=this.settings.whitelist.filter(function(e){return e.value.toLowerCase()==t.toLowerCase()});s[0]&&(i=!0,n=s)}if(!i){if(!t.trim())return[];n=t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}})}return n}.call(this,t)).forEach(function(t){var e,a=n.validateTag.call(n,t.value);!0!==a&&(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",t.title=a,n.markTagByValue.call(n,t.value),n.trigger("invalid",{value:t.value,index:n.value.length,message:a})),e=n.createTagElem(t),s.push(e),i.call(n,e),!0===a?(n.value.push(t),n.update(),n.trigger("add",n.extend({},{index:n.value.length,tag:e},t))):n.settings.keepInvalidTags||setTimeout(function(){n.removeTag(e,!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>";return e=this.parseHTML(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,t),e},removeTag:function(t,e){if(t){var i,n=this.getNodeIndex(t);t&&(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(function(){t.parentNode.removeChild(t)},400),e||(i=this.value.splice(n,1)[0],this.update(),this.trigger("remove",this.extend({},{index:n,tag:t},i))))}},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(){var t=this,e=this.value.map(function(e){return e[t.settings.mapValueToProp||"value"]||e.value});this.stringValue=JSON.stringify(e).slice(1,-1),this.DOM.originalInput.value=this.stringValue},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=this.dropdown.filterListItems.call(this,t),i=this.dropdown.createListHTML(e);this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),!i||e.length<2?this.dropdown.hide.call(this):(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=!(arguments.length>0&&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]("click",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?"previousElementSibling":"nextElementSibling"]:this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0],this.dropdown.highlightOption.call(this,e);break;case"Escape":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":this.input.autocomplete.set.call(this)}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){t.target.className.includes("tagify__dropdown__item")&&(this.input.set.call(this),this.addTags(t.target.textContent)),this.dropdown.hide.call(this)}}},highlightOption:function(t){if(t){var e="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){t.classList.remove(e)}),t.classList.add(e)}},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&&(e=n[a]instanceof Object?n[a]:{value:n[a]},0==e.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){function e(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}return t.map(function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+e(t)+">"+t.value+"</div>"}).join("")}}}}(jQuery);
/**
* Tagify (v 2.0.2)- tags input component
* Tagify (v 2.0.4)- tags input component
* By Yair Even-Or (2016)

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

this.value = []; // An array holding all the (currently used) tags
this.stringValue = ""; // same as above, only as a String

@@ -59,13 +60,22 @@ // events' callbacks references will be stores here, so events could be unbinded

TEXTS: {
empty: "empty",
exceed: "number of tags exceeded",
pattern: "pattern mismatch",
duplicate: "already exists",
notAllowed: "not allowed"
},
DEFAULTS: {
delimiters: ",", // [regex] split tags by any of these delimiters ("null" to cancel) Example: ",| |."
pattern: null, // regex pattern to validate input by. Ex: /[1-9]/
maxTags: Infinity, // maximum number of tags
callbacks: {}, // exposed callbacks object to be triggered on certain events
addTagOnBlur: true, // flag - automatically adds the text which was inputed as a tag when blur event happens
duplicates: false, // flag - allow tuplicate tags
whitelist: [], // is this list has any items, then only allow tags from this list
blacklist: [], // a list of non-allowed tags
enforceWhitelist: false, // flag - should ONLY use tags allowed in whitelist
autoComplete: true, // flag - tries to autocomplete the input's value while typing
delimiters: ",", // [RegEx] split tags by any of these delimiters ("null" to cancel) Example: ",| |."
pattern: null, // RegEx pattern to validate input by. Ex: /[1-9]/
maxTags: Infinity, // Maximum number of tags
callbacks: {}, // Exposed callbacks object to be triggered on certain events
addTagOnBlur: true, // Flag - automatically adds the text which was inputed as a tag when blur event happens
duplicates: false, // Flag - allow tuplicate tags
whitelist: [], // Array of tags to suggest as the user types (can be used along with "enforceWhitelist" setting)
blacklist: [], // A list of non-allowed tags
enforceWhitelist: false, // Flag - Only allow tags allowed in whitelist
keepInvalidTags: false, // Flag - if true, do not remove tags which did not pass validation
autoComplete: true, // Flag - tries to autocomplete the input's value while typing
mapValueToProp: "", // String - when tags have multiple properties, and for each tag another property should be used besides the "value"

@@ -79,3 +89,3 @@ dropdown: {

customEventsList: ['add', 'remove', 'duplicate', 'maxTagsExceed', 'blacklisted', 'notWhitelisted'],
customEventsList: ['add', 'remove', 'invalid'],

@@ -112,3 +122,3 @@ /**

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

@@ -120,3 +130,2 @@ this.DOM.originalInput = input;

// if "autocomplete" flag on toggeled & "whitelist" has items, build suggestions list
if (this.settings.dropdown.enabled && this.settings.whitelist.length) {

@@ -130,2 +139,4 @@ this.dropdown.init.call(this);

});
input.autofocus && this.DOM.input.focus();
},

@@ -286,14 +297,22 @@

onInput: function onInput(e) {
var value = e.target.textContent.trim(),
var value = this.input.normalize.call(this),
showSuggestions = value.length >= this.settings.dropdown.enabled;
if (this.input.value == value) return;
// save the value on the input state object
this.input.value = value;
this.input.normalize.call(this);
this.input.autocomplete.suggest.call(this, ''); // cleanup any possible previous suggestion
if (!value) {
this.input.set.call(this, '');
return;
}
if (this.input.value == value) return; // for IE; since IE doesn't have an "input" event so "keyDown" is used instead
// save the value on the input's State object
this.input.set.call(this, value, false);
if (value.search(this.settings.delimiters) != -1) {
if (this.addTags(value).length) this.input.set.call(this); // clear the input field's value
} else if (this.settings.dropdown.enabled && this.settings.whitelist.length) this.dropdown[showSuggestions ? "show" : "hide"].call(this, value);
if (this.addTags(value).length) {
this.input.set.call(this); // clear the input field's value
}
} else if (this.settings.dropdown.enabled && this.settings.whitelist.length) {
this.dropdown[showSuggestions ? "show" : "hide"].call(this, value);
}
},

@@ -324,14 +343,34 @@ onInputIE: function onInputIE(e) {

var s = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var updateDOM = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
this.input.value = this.DOM.input.innerHTML = s;
this.input.value = s;
if (updateDOM) this.DOM.input.innerHTML = s;
if (s.length < 2) this.input.autocomplete.suggest.call(this, '');
this.input.validate.call(this);
},
/**
* Marks the tagify's input as "invalid" if the value did not pass "validateTag()"
*/
validate: function validate() {
var isValid = !this.input.value || this.validateTag.call(this, this.input.value);
this.DOM.input.classList.toggle('tagify__input--invalid', isValid !== true);
},
// remove any child DOM elements that aren't of type TEXT (like <br>)
normalize: function normalize() {
while (this.DOM.input.firstElementChild) {
this.DOM.input.removeChild(this.DOM.input.firstElementChild);
var clone = this.DOM.input.cloneNode(true),
v = clone.textContent.replace(/\s/g, ' '); // replace NBSPs with spaces characters
while (clone.firstElementChild) {
v += clone.firstElementChild.textContent;
clone.removeChild(clone.firstElementChild);
}
return v.replace(/^\s+/, ""); // trimLeft
},

@@ -373,5 +412,6 @@

isTagDuplicate: function isTagDuplicate(s) {
return this.value.some(function (item) {
return this.value.findIndex(function (item) {
return s.toLowerCase() === item.value.toLowerCase();
});
// return this.value.some(item => s.toLowerCase() === item.value.toLowerCase());
},

@@ -387,9 +427,7 @@

markTagByValue: function markTagByValue(value, tagElm) {
var tagsElms, tagsElmsLen;
var tagsElms, tagsElmsLen, tagIdx;
if (!tagElm) {
tagsElms = this.DOM.scope.querySelectorAll('tag');
for (tagsElmsLen = tagsElms.length; tagsElmsLen--;) {
if (tagsElms[tagsElmsLen].value.toLowerCase().includes(value.toLowerCase())) tagElm = tagsElms[tagsElmsLen];
}
tagIdx = this.isTagDuplicate.call(this, value);
tagElm = this.DOM.scope.querySelectorAll('tag')[tagIdx];
}

@@ -402,5 +440,5 @@

tagElm.classList.remove('tagify--mark');
}, 2000);
return true;
} else {}
}, 100);
return tagElm;
}

@@ -434,2 +472,27 @@ return false;

/**
* validate a tag object BEFORE the actual tag will be created & appeneded
* @param {String} s
* @return {Boolean/String} ["true" if validation has passed, String for a fail]
*/
validateTag: function validateTag(s) {
var value = s.trim(),
maxTagsExceed = this.value.length >= this.settings.maxTags,
isDuplicate,
eventName__error,
result = true;
// check for empty value
if (!value) result = this.TEXTS.empty;else if (maxTagsExceed) result = this.TEXTS.exceed;
// check if pattern should be used and if so, use it to test the value
else if (this.settings.pattern && !this.settings.pattern.test(value)) result = this.TEXTS.pattern;
// if duplicates are not allowed and there is a duplicate
else if (!this.settings.duplicates && this.isTagDuplicate(value) !== -1) result = this.TEXTS.duplicate;else if (this.isTagBlacklisted(value) || this.settings.enforceWhitelist && !this.isTagWhitelisted(value)) result = this.TEXTS.notAllowed;
return result;
},
/**
* add a "tag" element to the "tags" component

@@ -441,5 +504,6 @@ * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects]

addTags: function addTags(tagsItems, clearInput) {
var that = this,
tagElems = [];
var _this3 = this;
var tagElems = [];
this.DOM.input.removeAttribute('style');

@@ -475,7 +539,8 @@

if (!isComplex) {
tagsItems = tagsItems.trim();
if (!tagsItems) return [];
if (!tagsItems.trim()) return [];
// go over each tag and add it (if there were multiple ones)
result = tagsItems.split(this.settings.delimiters).map(function (v) {
result = tagsItems.split(this.settings.delimiters).filter(function (n) {
return n;
}).map(function (v) {
return { value: v.trim() };

@@ -485,54 +550,6 @@ });

return result.filter(function (n) {
return n;
}); // cleanup the array from "undefined", "false" or empty items;
return result;
}
/**
* validate a tag object BEFORE the actual tag will be created & appeneded
* @param {Object} tagData [{"value":"text", "class":whatever", ...}]
* @return {Boolean/String} ["true" if validation has passed, String or "false" for any type of error]
*/
function validateTag(tagData) {
var value = tagData.value.trim(),
maxTagsExceed = this.value.length >= this.settings.maxTags,
isDuplicate,
eventName__error,
tagAllowed;
// check for empty value
if (!value) return "empty";
// check if pattern should be used and if so, use it to test the value
if (this.settings.pattern && !this.settings.pattern.test(value)) return "pattern";
// check if the tag already exists
if (this.isTagDuplicate(value)) {
this.trigger('duplicate', value);
if (!this.settings.duplicates) {
// this.markTagByValue(value, tagElm)
return "duplicate";
}
}
// check if the tag is allowed by the rules set
tagAllowed = !this.isTagBlacklisted(value) && (!this.settings.enforceWhitelist || this.isTagWhitelisted(value)) && !maxTagsExceed;
// Check against blacklist & whitelist (if enforced)
if (!tagAllowed) {
tagData.class = tagData.class ? tagData.class + " tagify--notAllowed" : "tagify--notAllowed";
// broadcast why the tag was not allowed
if (maxTagsExceed) eventName__error = 'maxTagsExceed';else if (this.isTagBlacklisted(value)) eventName__error = 'blacklisted';else if (this.settings.enforceWhitelist && !this.isTagWhitelisted(value)) eventName__error = 'notWhitelisted';
this.trigger(eventName__error, { value: value, index: this.value.length });
return "notAllowed";
}
return true;
}
/**
* appened (validated) tag to the component's DOM scope

@@ -549,24 +566,29 @@ * @return {[type]} [description]

tagsItems.forEach(function (tagData) {
var tagValidation = _this3.validateTag.call(_this3, tagData.value),
tagElm;
var isTagValidated = validateTag.call(that, tagData);
if (isTagValidated === true || isTagValidated == "notAllowed") {
// create the tag element
var tagElm = that.createTagElem(tagData);
if (tagValidation !== true) {
tagData.class = tagData.class ? tagData.class + " tagify--notAllowed" : "tagify--notAllowed";
tagData.title = tagValidation;
_this3.markTagByValue.call(_this3, tagData.value);
_this3.trigger("invalid", { value: tagData.value, index: _this3.value.length, message: tagValidation });
}
// add the tag to the component's DOM
appendTag.call(that, tagElm);
// Create tag HTML element
tagElm = _this3.createTagElem(tagData);
tagElems.push(tagElm);
// remove the tag "slowly"
if (isTagValidated == "notAllowed") {
setTimeout(function () {
that.removeTag(tagElm, true);
}, 1000);
} else {
// update state
that.value.push(tagData);
that.update();
that.trigger('add', that.extend({}, { index: that.value.length, tag: tagElm }, tagData));
// add the tag to the component's DOM
appendTag.call(_this3, tagElm);
tagElems.push(tagElm);
}
if (tagValidation === true) {
// update state
_this3.value.push(tagData);
_this3.update();
_this3.trigger('add', _this3.extend({}, { index: _this3.value.length, tag: tagElm }, tagData));
} else if (!_this3.settings.keepInvalidTags) {
// remove invalid tags (if "keepInvalidTags" is set to "false")
setTimeout(function () {
_this3.removeTag(tagElm, true);
}, 1000);
}

@@ -591,3 +613,3 @@ });

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

@@ -620,2 +642,4 @@ // for a certain Tag element, add attributes.

removeTag: function removeTag(tagElm, silent) {
if (!tagElm) return;
var tagData,

@@ -655,8 +679,9 @@ tagIdx = this.getNodeIndex(tagElm);

update: function update() {
var _this3 = this;
var _this4 = this;
var tagsAsString = this.value.map(function (v) {
return v[_this3.settings.mapValueToProp || "value"] || v.value;
return v[_this4.settings.mapValueToProp || "value"] || v.value;
});
this.DOM.originalInput.value = JSON.stringify(tagsAsString).slice(1, -1);
this.stringValue = JSON.stringify(tagsAsString).slice(1, -1);
this.DOM.originalInput.value = this.stringValue;
},

@@ -682,3 +707,5 @@

if (listItems.length && this.settings.autoComplete) this.input.autocomplete.suggest.call(this, listItems[0].value);
if (this.settings.autoComplete) {
this.input.autocomplete.suggest.call(this, listItems.length ? listItems[0].value : '');
}

@@ -713,3 +740,3 @@ if (!listHTML || listItems.length < 2) {

this.DOM.dropdown.style.cssText = "left: " + rect.left + window.pageXOffset + "px; \
this.DOM.dropdown.style.cssText = "left: " + (rect.left + window.pageXOffset) + "px; \
top: " + (rect.top + rect.height - 1 + window.pageYOffset) + "px; \

@@ -835,3 +862,3 @@ width: " + rect.width + "px";

// match for the value within each "whitelist" item
if (valueIsInWhitelist && !this.isTagDuplicate(whitelistItem.value) && suggestionsCount--) list.push(whitelistItem);
if (valueIsInWhitelist && this.isTagDuplicate(whitelistItem.value) == -1 && suggestionsCount--) list.push(whitelistItem);
if (suggestionsCount == 0) break;

@@ -838,0 +865,0 @@ }

@@ -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.id=Math.random().toString(36).substr(2,9),this.value=[],this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),this.events.customBinding.call(this),this.events.binding.call(this)}return t.prototype={isIE:window.document.documentMode,DEFAULTS:{delimiters:",",pattern:null,maxTags:1/0,callbacks:{},addTagOnBlur:!0,duplicates:!1,whitelist:[],blacklist:[],enforceWhitelist:!1,autoComplete:!0,mapValueToProp:"",dropdown:{classname:"",enabled:2,maxItems:10}},customEventsList:["add","remove","duplicate","maxTagsExceed","blacklisted","notWhitelisted"],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=t.value,i='\n <tags class="tagify '+t.className+" "+(this.settings.readonly?"readonly":"")+'">\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify--input"></div>\n </tags>';this.DOM.originalInput=t,this.DOM.scope=this.parseHTML(i),this.DOM.input=this.DOM.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(this.DOM.scope,t),this.settings.dropdown.enabled&&this.settings.whitelist.length&&this.dropdown.init.call(this),e&&this.addTags(e).forEach(function(t){t&&t.classList.add("tagify--noAnim")})},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}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(t){var e=document.createTextNode("");this.off=function(t,i){return i&&e.removeEventListener.call(e,t,i),this},this.on=function(t,i){return i&&e.addEventListener.call(e,t,i),this},this.trigger=function(i,n){var s;if(i)if(t.settings.isJQueryPlugin)$(t.DOM.originalInput).triggerHandler(i,[n]);else{try{s=new CustomEvent(i,{detail:n})}catch(t){console.warn(t)}e.dispatchEvent(s)}}},events:{customBinding:function(){var t=this;this.customEventsList.forEach(function(e){t.on(e,t.settings.callbacks[e])})},binding:function(){var t=!(arguments.length>0&&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||("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?(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=t.target.textContent.trim(),i=e.length>=this.settings.dropdown.enabled;this.input.value!=e&&(this.input.value=e,this.input.normalize.call(this),this.input.autocomplete.suggest.call(this,""),-1!=e.search(this.settings.delimiters)?this.addTags(e).length&&this.input.set.call(this):this.settings.dropdown.enabled&&this.settings.whitelist.length&&this.dropdown[i?"show":"hide"].call(this,e))},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=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";this.input.value=this.DOM.input.innerHTML=t,t.length<2&&this.input.autocomplete.suggest.call(this,"")},normalize:function(){for(;this.DOM.input.firstElementChild;)this.DOM.input.removeChild(this.DOM.input.firstElementChild)},autocomplete:{suggest:function(t){t?this.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(){var t=this.DOM.input.getAttribute("data-suggest");t&&this.addTags(this.input.value+t).length&&(this.input.set.call(this),this.dropdown.hide.call(this))}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(t){return this.value.some(function(e){return t.toLowerCase()===e.value.toLowerCase()})},markTagByValue:function(t,e){var i,n;if(!e)for(n=(i=this.DOM.scope.querySelectorAll("tag")).length;n--;)i[n].value.toLowerCase().includes(t.toLowerCase())&&(e=i[n]);return!!e&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},2e3),!0)},isTagBlacklisted:function(t){return t=t.split(" "),this.settings.blacklist.filter(function(e){return-1!=t.indexOf(e)}).length},isTagWhitelisted:function(t){return this.settings.whitelist.some(function(e){if((e.value?e.value:e).toLowerCase()===t.toLowerCase())return!0})},addTags:function(t,e){function i(t){var e,i=t.value.trim(),n=this.value.length>=this.settings.maxTags;return i?this.settings.pattern&&!this.settings.pattern.test(i)?"pattern":this.isTagDuplicate(i)&&(this.trigger("duplicate",i),!this.settings.duplicates)?"duplicate":!!(!this.isTagBlacklisted(i)&&(!this.settings.enforceWhitelist||this.isTagWhitelisted(i))&&!n)||(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",n?e="maxTagsExceed":this.isTagBlacklisted(i)?e="blacklisted":this.settings.enforceWhitelist&&!this.isTagWhitelisted(i)&&(e="notWhitelisted"),this.trigger(e,{value:i,index:this.value.length}),"notAllowed"):"empty"}function n(t){this.DOM.scope.insertBefore(t,this.DOM.input)}var s=this,o=[];return this.DOM.input.removeAttribute("style"),(t=function(t){var e=this.settings.whitelist[0]instanceof Object,i=t instanceof Array&&"value"in t[0],n=t;if(i)return n;if(!i&&"string"==typeof t&&e){var s=this.settings.whitelist.filter(function(e){return e.value.toLowerCase()==t.toLowerCase()});s[0]&&(i=!0,n=s)}if(!i){if(!(t=t.trim()))return[];n=t.split(this.settings.delimiters).map(function(t){return{value:t.trim()}})}return n.filter(function(t){return t})}.call(this,t)).forEach(function(t){var e=i.call(s,t);if(!0===e||"notAllowed"==e){var a=s.createTagElem(t);n.call(s,a),"notAllowed"==e?setTimeout(function(){s.removeTag(a,!0)},1e3):(s.value.push(t),s.update(),s.trigger("add",s.extend({},{index:s.value.length,tag:a},t)),o.push(a))}}),t.length&&e&&this.input.set.call(this),o},createTagElem:function(t){var e,i=this.escapeHtml(t.value),n="<tag>\n <x></x><div><span title='"+i+"'>"+i+"</span></div>\n </tag>";return e=this.parseHTML(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,t),e},removeTag:function(t,e){var i,n=this.getNodeIndex(t);t&&(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(function(){t.parentNode.removeChild(t)},400),e||(i=this.value.splice(n,1)[0],this.update(),this.trigger("remove",this.extend({},{index:n,tag:t},i))))},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(){var t=this,e=this.value.map(function(e){return e[t.settings.mapValueToProp||"value"]||e.value});this.DOM.originalInput.value=JSON.stringify(e).slice(1,-1)},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=this.dropdown.filterListItems.call(this,t),i=this.dropdown.createListHTML(e);e.length&&this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e[0].value),!i||e.length<2?this.dropdown.hide.call(this):(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=!(arguments.length>0&&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]("click",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?"previousElementSibling":"nextElementSibling"]:this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0],this.dropdown.highlightOption.call(this,e);break;case"Escape":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":this.input.autocomplete.set.call(this)}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){t.target.className.includes("tagify__dropdown__item")&&(this.input.set.call(this),this.addTags(t.target.textContent)),this.dropdown.hide.call(this)}}},highlightOption:function(t){if(t){var e="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){t.classList.remove(e)}),t.classList.add(e)}},filterListItems:function(t){if(!t)return"";for(var e,i=[],n=this.settings.whitelist,s=this.settings.dropdown.maxItems||1/0,o=0;o<n.length&&(e=n[o]instanceof Object?n[o]:{value:n[o]},0==e.value.toLowerCase().replace(/\s/g,"").indexOf(t.toLowerCase().replace(/\s/g,""))&&!this.isTagDuplicate(e.value)&&s--&&i.push(e),0!=s);o++);return i},createListHTML:function(t){function e(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}return t.map(function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+e(t)+">"+t.value+"</div>"}).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.id=Math.random().toString(36).substr(2,9),this.value=[],this.stringValue="",this.listeners={},this.DOM={},this.extend(this,new this.EventDispatcher(this)),this.build(t),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,mapValueToProp:"",dropdown:{classname:"",enabled:2,maxItems:10}},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=t.value,i='\n <tags class="tagify '+t.className+" "+(this.settings.readonly?"readonly":"")+'">\n <div contenteditable data-placeholder="'+t.placeholder+'" class="tagify__input"></div>\n </tags>';this.DOM.originalInput=t,this.DOM.scope=this.parseHTML(i),this.DOM.input=this.DOM.scope.querySelector("[contenteditable]"),t.parentNode.insertBefore(this.DOM.scope,t),this.settings.dropdown.enabled&&this.settings.whitelist.length&&this.dropdown.init.call(this),e&&this.addTags(e).forEach(function(t){t&&t.classList.add("tagify--noAnim")}),t.autofocus&&this.DOM.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}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(t){var e=document.createTextNode("");this.off=function(t,i){return i&&e.removeEventListener.call(e,t,i),this},this.on=function(t,i){return i&&e.addEventListener.call(e,t,i),this},this.trigger=function(i,n){var s;if(i)if(t.settings.isJQueryPlugin)$(t.DOM.originalInput).triggerHandler(i,[n]);else{try{s=new CustomEvent(i,{detail:n})}catch(t){console.warn(t)}e.dispatchEvent(s)}}},events:{customBinding:function(){var t=this;this.customEventsList.forEach(function(e){t.on(e,t.settings.callbacks[e])})},binding:function(){var t=!(arguments.length>0&&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||("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?(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):this.settings.dropdown.enabled&&this.settings.whitelist.length&&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)}}},input:{value:"",set:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.input.value=t,e&&(this.DOM.input.innerHTML=t),t.length<2&&this.input.autocomplete.suggest.call(this,""),this.input.validate.call(this)},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.DOM.input.setAttribute("data-suggest",t.substring(this.input.value.length)):this.DOM.input.removeAttribute("data-suggest")},set:function(){var t=this.DOM.input.getAttribute("data-suggest");t&&this.addTags(this.input.value+t).length&&(this.input.set.call(this),this.dropdown.hide.call(this))}}},getNodeIndex:function(t){for(var e=0;t=t.previousSibling;)3==t.nodeType&&/^\s*$/.test(t.data)||e++;return e},isTagDuplicate:function(t){return this.value.findIndex(function(e){return t.toLowerCase()===e.value.toLowerCase()})},markTagByValue:function(t,e){var i;return e||(i=this.isTagDuplicate.call(this,t),e=this.DOM.scope.querySelectorAll("tag")[i]),!!e&&(e.classList.add("tagify--mark"),setTimeout(function(){e.classList.remove("tagify--mark")},100),e)},isTagBlacklisted:function(t){return t=t.split(" "),this.settings.blacklist.filter(function(e){return-1!=t.indexOf(e)}).length},isTagWhitelisted:function(t){return this.settings.whitelist.some(function(e){if((e.value?e.value:e).toLowerCase()===t.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},addTags:function(t,e){function i(t){this.DOM.scope.insertBefore(t,this.DOM.input)}var n=this,s=[];return this.DOM.input.removeAttribute("style"),(t=function(t){var e=this.settings.whitelist[0]instanceof Object,i=t instanceof Array&&"value"in t[0],n=t;if(i)return n;if(!i&&"string"==typeof t&&e){var s=this.settings.whitelist.filter(function(e){return e.value.toLowerCase()==t.toLowerCase()});s[0]&&(i=!0,n=s)}if(!i){if(!t.trim())return[];n=t.split(this.settings.delimiters).filter(function(t){return t}).map(function(t){return{value:t.trim()}})}return n}.call(this,t)).forEach(function(t){var e,a=n.validateTag.call(n,t.value);!0!==a&&(t.class=t.class?t.class+" tagify--notAllowed":"tagify--notAllowed",t.title=a,n.markTagByValue.call(n,t.value),n.trigger("invalid",{value:t.value,index:n.value.length,message:a})),e=n.createTagElem(t),s.push(e),i.call(n,e),!0===a?(n.value.push(t),n.update(),n.trigger("add",n.extend({},{index:n.value.length,tag:e},t))):n.settings.keepInvalidTags||setTimeout(function(){n.removeTag(e,!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>";return e=this.parseHTML(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,t),e},removeTag:function(t,e){if(t){var i,n=this.getNodeIndex(t);t&&(t.style.width=parseFloat(window.getComputedStyle(t).width)+"px",document.body.clientTop,t.classList.add("tagify--hide"),setTimeout(function(){t.parentNode.removeChild(t)},400),e||(i=this.value.splice(n,1)[0],this.update(),this.trigger("remove",this.extend({},{index:n,tag:t},i))))}},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(){var t=this,e=this.value.map(function(e){return e[t.settings.mapValueToProp||"value"]||e.value});this.stringValue=JSON.stringify(e).slice(1,-1),this.DOM.originalInput.value=this.stringValue},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=this.dropdown.filterListItems.call(this,t),i=this.dropdown.createListHTML(e);this.settings.autoComplete&&this.input.autocomplete.suggest.call(this,e.length?e[0].value:""),!i||e.length<2?this.dropdown.hide.call(this):(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=!(arguments.length>0&&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]("click",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?"previousElementSibling":"nextElementSibling"]:this.DOM.dropdown.children["ArrowUp"==t.key||"Up"==t.key?this.DOM.dropdown.children.length-1:0],this.dropdown.highlightOption.call(this,e);break;case"Escape":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":this.input.autocomplete.set.call(this)}},onMouseOver:function(t){t.target.className.includes("__item")&&this.dropdown.highlightOption.call(this,t.target)},onClick:function(t){t.target.className.includes("tagify__dropdown__item")&&(this.input.set.call(this),this.addTags(t.target.textContent)),this.dropdown.hide.call(this)}}},highlightOption:function(t){if(t){var e="tagify__dropdown__item--active";[].forEach.call(this.DOM.dropdown.querySelectorAll("[class$='--active']"),function(t){t.classList.remove(e)}),t.classList.add(e)}},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&&(e=n[a]instanceof Object?n[a]:{value:n[a]},0==e.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){function e(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}return t.map(function(t){return"<div class='tagify__dropdown__item "+(t.class?t.class:"")+"' "+e(t)+">"+t.value+"</div>"}).join("")}}},t});
(function(){
if( !String.prototype.includes ){
String.prototype.includes = function(search, start) {
'use strict';
if (typeof start !== 'number')
start = 0;
if( !String.prototype.includes ){
String.prototype.includes = function(search, start) {
'use strict';
if (typeof start !== 'number')
start = 0;
if (start + search.length > this.length)
return false;
if (start + search.length > this.length)
return false;
else
return this.indexOf(search, start) !== -1;
};
}
else
return this.indexOf(search, start) !== -1;
};
}
//////////////////////////////////////////////////////////////////
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
if ( typeof window.CustomEvent === "function" ) return false;
//////////////////////////////////////////////////////////////////
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
if ( typeof window.CustomEvent === "function" ) return false;
function CustomEvent ( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}
function CustomEvent ( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}
CustomEvent.prototype = window.Event.prototype;
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
window.CustomEvent = CustomEvent;
//////////////////////////////////////////////////////////////////
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill
//
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
//////////////////////////////////////////////////////////////////
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill
//
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
if (!Array.prototype.findIndex) {
Object.defineProperty(Array.prototype, 'findIndex', {
value: function(predicate) {
if (this == null)
throw new TypeError('"this" is null or not defined');
var o = Object(this), len = o.length >>> 0;
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
}
}
}
return to;
},
writable: true,
configurable: true
});
var thisArg = arguments[1], k = 0;
while (k < len) {
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return k;
}
k++;
}
return -1;
},
configurable: true,
writable: true
});
}
})()
{
"name": "@yaireo/tagify",
"version": "2.0.3",
"version": "2.1.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.",

@@ -1,2 +0,2 @@

Tagify - lightweight input "tags" script
[Tagify](https://yaireo.github.io/tagify) - lightweight input "tags" script
========

@@ -24,3 +24,3 @@

## Selling points
* JS weights `~12kb` (`4kb` GZIP) (less than 900 easily understandale lines of code)
* JS at `~12kb` (`4kb` GZIP) (less than *900* easily understandable lines of code)
* SCSS file is `~6kb` of well-crafted flexible code

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

* Easily customized
* Exposed custom events (Add, Remove, Invalid, Duplicate)
* Exposed custom events (add, remove, invalid)
* For Internet Explorer 11 include the script `tagify.polyfills.js` under `/dist`

@@ -84,2 +84,3 @@

.on('add', onTagAdded);
.on('invalid', onInvaildTag)

@@ -95,2 +96,6 @@ function onTagRemoved(e){

}
function onInvaildTag(e){
// e.detail ...
}
```

@@ -234,2 +239,3 @@

## Exposed events

@@ -241,9 +247,5 @@

remove | A tag has been removed
duplicate | A tag has been added and found to be a duplicate of existing one
maxTagsExceed | Number of tags exceeds the allowed quantity and the exceed tags were denied (removed)
blacklisted | A tag which is in the blacklist has been added and denied (removed)
notWhitelisted | A tag which is not in the whitelist has been added and denied (removed)
invalid | A tag has been added but did not pass vaildation. See [event detail](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events)
## Settings

@@ -266,4 +268,2 @@

dropdown.maxItems | Number | 10 | maximum items to show in the suggestions list dropdown
dropdown.classname | String | "" | custom class name for the dropdown suggestions selectbox
dropdown.classname | String | "" | custom class name for the dropdown suggestions selectbox

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

this.value = []; // An array holding all the (currently used) tags
this.stringValue = ""; // same as above, only as a String

@@ -42,13 +43,22 @@ // events' callbacks references will be stores here, so events could be unbinded

TEXTS : {
empty : "empty",
exceed : "number of tags exceeded",
pattern : "pattern mismatch",
duplicate : "already exists",
notAllowed : "not allowed"
},
DEFAULTS : {
delimiters : ",", // [regex] split tags by any of these delimiters ("null" to cancel) Example: ",| |."
pattern : null, // regex pattern to validate input by. Ex: /[1-9]/
maxTags : Infinity, // maximum number of tags
callbacks : {}, // exposed callbacks object to be triggered on certain events
addTagOnBlur : true, // flag - automatically adds the text which was inputed as a tag when blur event happens
duplicates : false, // flag - allow tuplicate tags
whitelist : [], // is this list has any items, then only allow tags from this list
blacklist : [], // a list of non-allowed tags
enforceWhitelist : false, // flag - should ONLY use tags allowed in whitelist
autoComplete : true, // flag - tries to autocomplete the input's value while typing
delimiters : ",", // [RegEx] split tags by any of these delimiters ("null" to cancel) Example: ",| |."
pattern : null, // RegEx pattern to validate input by. Ex: /[1-9]/
maxTags : Infinity, // Maximum number of tags
callbacks : {}, // Exposed callbacks object to be triggered on certain events
addTagOnBlur : true, // Flag - automatically adds the text which was inputed as a tag when blur event happens
duplicates : false, // Flag - allow tuplicate tags
whitelist : [], // Array of tags to suggest as the user types (can be used along with "enforceWhitelist" setting)
blacklist : [], // A list of non-allowed tags
enforceWhitelist : false, // Flag - Only allow tags allowed in whitelist
keepInvalidTags : false, // Flag - if true, do not remove tags which did not pass validation
autoComplete : true, // Flag - tries to autocomplete the input's value while typing
mapValueToProp : "", // String - when tags have multiple properties, and for each tag another property should be used besides the "value"

@@ -62,3 +72,3 @@ dropdown : {

customEventsList : ['add', 'remove', 'duplicate', 'maxTagsExceed', 'blacklisted', 'notWhitelisted'],
customEventsList : ['add', 'remove', 'invalid'],

@@ -95,3 +105,3 @@ /**

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

@@ -104,3 +114,2 @@

// if "autocomplete" flag on toggeled & "whitelist" has items, build suggestions list
if( this.settings.dropdown.enabled && this.settings.whitelist.length ){

@@ -115,2 +124,4 @@ this.dropdown.init.call(this);

});
input.autofocus && this.DOM.input.focus()
},

@@ -282,17 +293,23 @@

onInput(e){
var value = e.target.textContent.trim(),
var value = this.input.normalize.call(this),
showSuggestions = value.length >= this.settings.dropdown.enabled;
if( this.input.value == value ) return;
// save the value on the input state object
this.input.value = value;
this.input.normalize.call(this);
this.input.autocomplete.suggest.call(this, ''); // cleanup any possible previous suggestion
if( !value ){
this.input.set.call(this, '');
return;
}
if( this.input.value == value ) return; // for IE; since IE doesn't have an "input" event so "keyDown" is used instead
// save the value on the input's State object
this.input.set.call(this, value, false);
if( value.search(this.settings.delimiters) != -1 ){
if( this.addTags( value ).length )
if( this.addTags( value ).length ){
this.input.set.call(this); // clear the input field's value
}
}
else if( this.settings.dropdown.enabled && this.settings.whitelist.length )
else if( this.settings.dropdown.enabled && this.settings.whitelist.length ){
this.dropdown[showSuggestions ? "show" : "hide"].call(this, value);
}
},

@@ -327,14 +344,33 @@

value : '',
set(s = ''){
this.input.value = this.DOM.input.innerHTML = s;
set(s = '', updateDOM = true){
this.input.value = s;
if( updateDOM )
this.DOM.input.innerHTML = s;
if( s.length < 2 )
this.input.autocomplete.suggest.call(this, '');
this.input.validate.call(this);
},
/**
* Marks the tagify's input as "invalid" if the value did not pass "validateTag()"
*/
validate(){
var isValid = !this.input.value || this.validateTag.call(this, this.input.value);
this.DOM.input.classList.toggle('tagify__input--invalid', isValid !== true);
},
// remove any child DOM elements that aren't of type TEXT (like <br>)
normalize(){
while (this.DOM.input.firstElementChild ){
this.DOM.input.removeChild(this.DOM.input.firstElementChild );
var clone = this.DOM.input.cloneNode(true),
v = clone.textContent.replace(/\s/g,' '); // replace NBSPs with spaces characters
while( clone.firstElementChild ){
v += clone.firstElementChild.textContent;
clone.removeChild(clone.firstElementChild);
}
return v.replace(/^\s+/,""); // trimLeft
},

@@ -376,3 +412,4 @@

isTagDuplicate(s){
return this.value.some(item => s.toLowerCase() === item.value.toLowerCase());
return this.value.findIndex(item => s.toLowerCase() === item.value.toLowerCase());
// return this.value.some(item => s.toLowerCase() === item.value.toLowerCase());
},

@@ -387,10 +424,7 @@

markTagByValue(value, tagElm){
var tagsElms, tagsElmsLen;
var tagsElms, tagsElmsLen, tagIdx
if( !tagElm ){
tagsElms = this.DOM.scope.querySelectorAll('tag');
for( tagsElmsLen = tagsElms.length; tagsElmsLen--; ){
if( tagsElms[tagsElmsLen].value.toLowerCase().includes(value.toLowerCase()) )
tagElm = tagsElms[tagsElmsLen];
}
tagIdx = this.isTagDuplicate.call(this, value);
tagElm = this.DOM.scope.querySelectorAll('tag')[tagIdx];
}

@@ -401,10 +435,6 @@

tagElm.classList.add('tagify--mark');
setTimeout(() => { tagElm.classList.remove('tagify--mark') }, 2000);
return true;
setTimeout(() => { tagElm.classList.remove('tagify--mark') }, 100);
return tagElm;
}
else{
}
return false;

@@ -433,2 +463,35 @@ },

/**
* validate a tag object BEFORE the actual tag will be created & appeneded
* @param {String} s
* @return {Boolean/String} ["true" if validation has passed, String for a fail]
*/
validateTag( s ){
var value = s.trim(),
maxTagsExceed = this.value.length >= this.settings.maxTags,
isDuplicate,
eventName__error,
result = true;
// check for empty value
if( !value )
result = this.TEXTS.empty;
else if( maxTagsExceed )
result = this.TEXTS.exceed;
// check if pattern should be used and if so, use it to test the value
else if( this.settings.pattern && !(this.settings.pattern.test(value)) )
result = this.TEXTS.pattern;
// if duplicates are not allowed and there is a duplicate
else if( !this.settings.duplicates && this.isTagDuplicate(value) !== -1 )
result = this.TEXTS.duplicate;
else if( this.isTagBlacklisted(value) ||(this.settings.enforceWhitelist && !this.isTagWhitelisted(value)) )
result = this.TEXTS.notAllowed;
return result;
},
/**
* add a "tag" element to the "tags" component

@@ -440,4 +503,3 @@ * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects]

addTags( tagsItems, clearInput ){
var that = this,
tagElems = [];
var tagElems = [];

@@ -472,63 +534,12 @@ this.DOM.input.removeAttribute('style');

if( !isComplex ){
tagsItems = tagsItems.trim();
if( !tagsItems ) return [];
if( !tagsItems.trim() ) return [];
// go over each tag and add it (if there were multiple ones)
result = tagsItems.split(this.settings.delimiters).map(v => ({ value:v.trim() }));
result = tagsItems.split(this.settings.delimiters).filter(n => n).map(v => ({ value:v.trim() }));
}
return result.filter(n => n); // cleanup the array from "undefined", "false" or empty items;
return result;
}
/**
* validate a tag object BEFORE the actual tag will be created & appeneded
* @param {Object} tagData [{"value":"text", "class":whatever", ...}]
* @return {Boolean/String} ["true" if validation has passed, String or "false" for any type of error]
*/
function validateTag( tagData ){
var value = tagData.value.trim(),
maxTagsExceed = this.value.length >= this.settings.maxTags,
isDuplicate,
eventName__error,
tagAllowed;
// check for empty value
if( !value )
return "empty";
// check if pattern should be used and if so, use it to test the value
if( this.settings.pattern && !(this.settings.pattern.test(value)) )
return "pattern";
// check if the tag already exists
if( this.isTagDuplicate(value) ){
this.trigger('duplicate', value);
if( !this.settings.duplicates ){
// this.markTagByValue(value, tagElm)
return "duplicate";
}
}
// check if the tag is allowed by the rules set
tagAllowed = !this.isTagBlacklisted(value) && (!this.settings.enforceWhitelist || this.isTagWhitelisted(value)) && !maxTagsExceed;
// Check against blacklist & whitelist (if enforced)
if( !tagAllowed ){
tagData.class = tagData.class ? tagData.class + " tagify--notAllowed" : "tagify--notAllowed";
// broadcast why the tag was not allowed
if( maxTagsExceed ) eventName__error = 'maxTagsExceed';
else if( this.isTagBlacklisted(value) ) eventName__error = 'blacklisted';
else if( this.settings.enforceWhitelist && !this.isTagWhitelisted(value) ) eventName__error = 'notWhitelisted';
this.trigger(eventName__error, {value:value, index:this.value.length});
return "notAllowed";
}
return true;
}
/**
* appened (validated) tag to the component's DOM scope

@@ -545,25 +556,29 @@ * @return {[type]} [description]

tagsItems.forEach(tagData => {
var tagValidation = this.validateTag.call(this, tagData.value),
tagElm;
var isTagValidated = validateTag.call(that, tagData);
if( isTagValidated === true || isTagValidated == "notAllowed" ){
// create the tag element
var tagElm = that.createTagElem(tagData);
if( tagValidation !== true ){
tagData.class = tagData.class ? tagData.class + " tagify--notAllowed" : "tagify--notAllowed";
tagData.title = tagValidation;
this.markTagByValue.call(this, tagData.value);
this.trigger("invalid", {value:tagData.value, index:this.value.length, message:tagValidation});
}
// add the tag to the component's DOM
appendTag.call(that, tagElm);
// Create tag HTML element
tagElm = this.createTagElem(tagData);
tagElems.push(tagElm);
// remove the tag "slowly"
if( isTagValidated == "notAllowed" ){
setTimeout(() => { that.removeTag(tagElm, true) }, 1000);
}
// add the tag to the component's DOM
appendTag.call(this, tagElm);
else{
// update state
that.value.push(tagData);
that.update();
that.trigger('add', that.extend({}, {index:that.value.length, tag:tagElm}, tagData));
tagElems.push(tagElm);
}
if( tagValidation === true ){
// update state
this.value.push(tagData);
this.update();
this.trigger('add', this.extend({}, {index:this.value.length, tag:tagElm}, tagData));
}
else if( !this.settings.keepInvalidTags ){
// remove invalid tags (if "keepInvalidTags" is set to "false")
setTimeout(() => { this.removeTag(tagElm, true) }, 1000);
}
})

@@ -586,4 +601,4 @@

escapedValue = this.escapeHtml(tagData.value),
template = `<tag>
<x></x><div><span title='${escapedValue}'>${escapedValue}</span></div>
template = `<tag title='${escapedValue}'>
<x title=''></x><div><span>${escapedValue}</span></div>
</tag>`;

@@ -615,2 +630,4 @@

removeTag( tagElm, silent ){
if( !tagElm ) return;
var tagData,

@@ -649,3 +666,4 @@ tagIdx = this.getNodeIndex(tagElm);

var tagsAsString = this.value.map(v => v[this.settings.mapValueToProp || "value"] || v.value);
this.DOM.originalInput.value = JSON.stringify(tagsAsString).slice(1,-1);
this.stringValue = JSON.stringify(tagsAsString).slice(1,-1);
this.DOM.originalInput.value = this.stringValue;
},

@@ -672,4 +690,5 @@

if( listItems.length && this.settings.autoComplete )
this.input.autocomplete.suggest.call(this, listItems[0].value);
if( this.settings.autoComplete ){
this.input.autocomplete.suggest.call(this, listItems.length ? listItems[0].value : '');
}

@@ -706,3 +725,3 @@ if( !listHTML || listItems.length < 2 ){

this.DOM.dropdown.style.cssText = "left: " + rect.left + window.pageXOffset + "px; \
this.DOM.dropdown.style.cssText = "left: " + (rect.left + window.pageXOffset) + "px; \
top: " + (rect.top + rect.height - 1 + window.pageYOffset) + "px; \

@@ -830,3 +849,3 @@ width: " + rect.width + "px";

// match for the value within each "whitelist" item
if( valueIsInWhitelist && !this.isTagDuplicate(whitelistItem.value) && suggestionsCount-- )
if( valueIsInWhitelist && this.isTagDuplicate(whitelistItem.value) == -1 && suggestionsCount-- )
list.push(whitelistItem);

@@ -833,0 +852,0 @@ if( suggestionsCount == 0 ) break;

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