<div>
<div class="acl-tag-input__container">
<div class="acl-tag-input__display"></div>
</div>
</div>
<script>
const tagEl = document.querySelector('.acl-tag-input__container');
const tagsInput = new acl.ACLTagInput(tagEl, {
tags: ['Tag 1', 'Tag 2', 'Tag 3']
});
tagEl.addEventListener('tagadded', event => {
console.log(`tagadded => ${event.detail}`);
});
tagEl.addEventListener('tagremoved', event => {
console.log(`tagremoved => ${event.detail}`);
});
</script>
<div>
<div class="acl-tag-input__container">
<div class="acl-tag-input__display"></div>
</div>
</div>
<script>
const tagEl = document.querySelector('.acl-tag-input__container');
const tagsInput = new acl.ACLTagInput(tagEl, { tags: ['Tag 1', 'Tag 2', 'Tag 3']});
tagEl.addEventListener('tagadded', event => {
console.log(`tagadded => ${event.detail}`);
});
tagEl.addEventListener('tagremoved', event => {
console.log(`tagremoved => ${event.detail}`);
});
</script>
/* No context defined. */
.acl-tag-input {
border: none;
flex: 1;
background-color: rgba(0, 0, 0, 0);
&__container {
display: flex;
border: 1px solid #e0e0e0;
padding: 10px;
flex-wrap: wrap;
border-radius: 5px;
cursor: text;
min-height: 23px;
}
&__display {
display: flex;
flex-wrap: wrap;
flex: 1;
gap: 5px;
}
&__tag {
display: flex;
color: white;
align-items: center;
border-radius: 3px;
padding: 2px 7px;
background: #35c3aa;
&-title {
margin-right: 3px;
font-size: 14px;
}
&-icon {
font-size: 14px;
max-width: 14px;
}
&-close-btn {
display: flex;
cursor: pointer;
}
}
}
class ACLTagInput {
constructor(tagsEl, tagInputOptions) {
this.className = Object.freeze({
CLOSE_BTN: 'acl-tag-input__tag-close-btn',
ACL_TAGS_INPUT: 'acl-tag-input',
ACL_TAGS_INPUT_TAG: 'acl-tag-input__tag',
FLASH: 'flash',
ANIMATED: 'animated',
});
this.selector = Object.freeze({
INPUT: 'input',
DIV: 'div',
ACL_TAGS_INPUT_DISPLAY: '.acl-tag-input__display',
});
this.eventName = Object.freeze({
BLUR: 'blur',
KEYDOWN: 'keydown',
CLICK: 'click',
TAG_ADDED: 'tagadded',
TAG_REMOVED: 'tagremoved',
});
this.keys = Object.freeze({
ENTER: 'Enter',
INSERT: 'Insert',
BACKSPACE: 'Backspace',
});
this.tags =
tagInputOptions && tagInputOptions.tags && tagInputOptions.tags.length > 0 ? tagInputOptions.tags : [];
this.submitKeys = [this.keys.ENTER, this.keys.INSERT];
this.tagsEl = tagsEl;
this.inputElement = document.createElement(this.selector.INPUT);
this.inputElement.classList.add(this.className.ACL_TAGS_INPUT);
this.renderTags();
this.handleEventListeners();
}
handleEventListeners() {
this.tagsEl.addEventListener(this.eventName.CLICK, () => {
this.inputElement.focus();
});
const tagInputSelector = `.${this.className.ACL_TAGS_INPUT}`;
this.tagsEl.querySelector(tagInputSelector).addEventListener(this.eventName.KEYDOWN, event => {
if (this.submitKeys.includes(event.key)) this.tagifyInput();
if (event.key === this.keys.BACKSPACE) {
const tagsInput = this.tagsEl.querySelector(`.${this.className.ACL_TAGS_INPUT}`);
if (tagsInput.value.length == 0 && this.tags.length > 0) {
this.removeTag(this.tags[this.tags.length - 1]);
}
}
});
this.tagsEl.querySelector(tagInputSelector).addEventListener(this.eventName.BLUR, () => {
this.tagifyInput();
});
}
updateTags(tags) {
this.tags = tags;
this.renderTags();
}
tagifyInput() {
const tagsInput = this.tagsEl.querySelector(`.${this.className.ACL_TAGS_INPUT}`);
if (!tagsInput.value.trim()) {
return;
}
if (this.tags.includes(tagsInput.value)) {
this.flashTag(tagsInput.value);
return;
}
this.tags.push(tagsInput.value);
this.renderTags();
this.tagsEl.dispatchEvent(
new CustomEvent(this.eventName.TAG_ADDED, {
detail: tagsInput.value,
})
);
tagsInput.value = '';
}
renderTags() {
const tagsDisplay = this.tagsEl.querySelector(this.selector.ACL_TAGS_INPUT_DISPLAY);
const tagElements = [];
this.tags.forEach(tag => {
tagElements.push(this.renderTag(tag));
});
while (tagsDisplay.firstChild) {
tagsDisplay.firstChild.remove();
}
tagElements.forEach(tagElement => {
tagsDisplay.appendChild(tagElement);
});
tagsDisplay.appendChild(this.inputElement);
tagElements.forEach(tagElement => {
tagElement.querySelector(`.${this.className.CLOSE_BTN}`).addEventListener(this.eventName.CLICK, () => {
this.removeTag(tagElement.dataset.tag);
});
});
this.inputElement.focus();
}
renderTag(tag) {
const tagWrapper = document.createElement(this.selector.DIV);
tagWrapper.classList.add(this.className.ACL_TAGS_INPUT_TAG);
tagWrapper.dataset.tag = tag;
const template = `<span class="acl-tag-input__tag-title">${tag}</span> <div class="${this.className.CLOSE_BTN}"><i class="aforza-icons acl-tag-input__tag-icon">acl_close_small</i></div>`;
tagWrapper.innerHTML = template;
return tagWrapper;
}
removeTag(tag) {
this.tags = this.tags.filter(currentTag => currentTag != tag);
this.tagsEl.dispatchEvent(
new CustomEvent(this.eventName.TAG_REMOVED, {
detail: tag,
})
);
this.renderTags();
}
flashTag(tag) {
const tagElement = this.tagsEl.querySelector(`[data-tag="${tag}"]`);
if (tagElement) {
tagElement.classList.remove(this.className.FLASH);
setTimeout(() => {
tagElement.classList.add(this.className.ANIMATED, this.className.FLASH);
});
}
}
}
export { ACLTagInput };
No notes defined.