Skip to content

Commit

Permalink
Merge pull request #331 from statikbe/KarelJanVanHaute/issue305
Browse files Browse the repository at this point in the history
Optimize autocomplete component
  • Loading branch information
HannahDeWachter authored Oct 18, 2024
2 parents 6be4c13 + a14000a commit 0833cad
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 28 deletions.
77 changes: 60 additions & 17 deletions tailoff/js/components/autocomplete.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,46 @@ interface AutocompleteOption {

export class AutocompleteComponent {
constructor() {
Array.from(document.querySelectorAll('[data-s-autocomplete]')).forEach((autocomplete, index) => {
Array.from(document.querySelectorAll('[data-s-autocomplete]')).forEach((autocomplete) => {
if (autocomplete.tagName === 'SELECT') {
new Autocomplete(autocomplete as HTMLSelectElement, index);
new Autocomplete(autocomplete as HTMLSelectElement);
}
});

DOMHelper.onDynamicContent(
document.documentElement,
'select[data-s-autocomplete]',
(autocompletes) => {
Array.from(autocompletes).forEach((ac: HTMLSelectElement) => {
if (!ac.hasAttribute('data-s-autocomplete')) return;
new Autocomplete(ac);
});
},
'data-s-autocomplete'
);

DOMHelper.onDynamicContent(
document.documentElement,
'select[data-s-autocomplete-init]',
(autocompletes) => {
Array.from(autocompletes).forEach((ac: HTMLSelectElement) => {
const oldList = document.getElementById(`autocompleteList${ac.getAttribute('data-s-autocomplete-init')}`);
if (oldList) {
oldList.remove();
}
});
},
false,
true
);
}
}

class Autocomplete {
private siteLang = SiteLang.getLang();
private lang;

private autocompleteListIndex: number = 0;
private autocompleteListIndex: string = '';

private selectElement: HTMLSelectElement;
private autocompleteElement: HTMLDivElement;
Expand All @@ -32,6 +59,7 @@ class Autocomplete {
private autocompleteInputWrapper: HTMLDivElement;
private autocompletePlaceholderElement: HTMLDivElement;
private autocompleteListElement: HTMLUListElement;
private autocompleteListReference: HTMLElement;
private statusElement: HTMLDivElement;
private freeTypeOption: HTMLOptionElement;

Expand Down Expand Up @@ -68,16 +96,18 @@ class Autocomplete {
backspace: 8,
};

constructor(autocomplete: HTMLSelectElement, index) {
constructor(autocomplete: HTMLSelectElement) {
autocomplete.removeAttribute('data-s-autocomplete');
autocomplete.setAttribute('data-s-autocomplete-init', '');
this.getLang().then(() => {
this.init(autocomplete, index);
this.init(autocomplete);
});
}

private init(autocomplete: HTMLSelectElement, index) {
this.autocompleteListIndex = index;
private init(autocomplete: HTMLSelectElement) {
this.autocompleteListIndex = DOMHelper.getPathTo(autocomplete);
autocomplete.setAttribute('data-s-autocomplete-init', this.autocompleteListIndex);
this.selectElement = autocomplete;
autocomplete.removeAttribute('data-s-autocomplete');

this.selectMutationObserver = new MutationObserver(this.selectMutation.bind(this));
this.selectMutationObserver.observe(this.selectElement, {
Expand Down Expand Up @@ -124,6 +154,10 @@ class Autocomplete {
this.autocompleteSelectElement.classList.add(c);
});

this.autocompleteListReference = autocomplete.hasAttribute('data-s-autocomplete-reference')
? document.querySelector(autocomplete.getAttribute('data-s-autocomplete-reference'))
: this.autocompleteElement;

this.autocompleteSelectElement.addEventListener('click', () => {
if (!this.isDisabled) {
this.hidePlaceholder();
Expand All @@ -143,7 +177,7 @@ class Autocomplete {
this.autocompleteSelectElement.insertAdjacentElement('beforeend', this.autocompleteInputWrapper);

this.inputElement = document.createElement('input');
this.inputElement.setAttribute('aria-controls', `autocompleteList${index}`);
this.inputElement.setAttribute('aria-controls', `autocompleteList${this.autocompleteListIndex}`);
this.inputElement.setAttribute('autocapitalize', 'none');
this.inputElement.setAttribute('type', 'text');
this.inputElement.setAttribute('autocomplete', 'off');
Expand Down Expand Up @@ -189,9 +223,16 @@ class Autocomplete {

this.autocompleteSelectElement.insertAdjacentElement('beforeend', icon);

// const previousList = document.getElementById(
// `autocompleteList${this.autocompleteListIndex}`
// );
// if (previousList) {
// previousList.remove();
// }
this.autocompleteListElement = document.createElement('ul');
this.autocompleteListElement.setAttribute('id', `autocompleteList${index}`);
this.autocompleteListElement.setAttribute('id', `autocompleteList${this.autocompleteListIndex}`);
this.autocompleteListElement.setAttribute('role', 'listbox');
this.autocompleteListElement.classList.add('autocomplete-list');
this.autocompleteListElement.classList.add('hidden');
if (this.isMultiple) {
this.autocompleteListElement.setAttribute('aria-multiselectable', 'true');
Expand All @@ -200,7 +241,7 @@ class Autocomplete {
this.menuClickListener = this.onMenuClick.bind(this);
this.autocompleteListElement.addEventListener('click', this.menuClickListener);

this.autocompleteElement.insertAdjacentElement('beforeend', this.autocompleteListElement);
this.autocompleteListReference.insertAdjacentElement('beforeend', this.autocompleteListElement);

this.setOptions();
this.fillList(this.options);
Expand Down Expand Up @@ -394,12 +435,12 @@ class Autocomplete {

private onKeyDown(e) {
switch (e.keyCode) {
// case this.keys.enter:
// e.preventDefault();
// // if (this.isFreeType) {
// // this.hideMenu();
// // }
// break;
case this.keys.enter:
e.preventDefault();
if (this.isFreeType) {
this.hideMenu();
}
break;
case this.keys.backspace:
if (this.inputElement.value == '' && this.isMultiple && this.selectedOptions.length > 0) {
this.selectedOptions.pop();
Expand Down Expand Up @@ -643,6 +684,8 @@ class Autocomplete {
});
this.hideMenu();
this.hidePlaceholder();

this.hoverOption = null;
this.inputElement.focus();
this.inputElement.size = Math.max(this.inputElement.value.length + 1, 1);
}
Expand Down
69 changes: 58 additions & 11 deletions tailoff/js/utils/domHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,51 @@ export class DOMHelper {
document.body.appendChild(script);
}

public static loadScriptContent(content) {
var script = document.createElement("script");
script.type = "text/javascript";
script.innerHTML = content;
document.body.appendChild(script);
}

public static onDynamicContent(
parent: Element,
selector: string,
callback: Function,
includeAttributes: boolean | string = false
includeAttributes: boolean | string = false,
checkRemoved: boolean = false
) {
const mutationObserver: MutationObserver = new MutationObserver(
(mutationsList) => {
for (let mutation of mutationsList) {
if (mutation.type === "childList") {
Array.from(mutation.addedNodes).forEach((node: HTMLElement) => {
if (node.nodeType == 1) {
const results = node.querySelectorAll(selector);
if (results.length > 0) {
callback(results);
} else {
if (node.matches(selector)) {
callback([node]);
if (checkRemoved) {
Array.from(mutation.removedNodes).forEach((node: HTMLElement) => {
if (node.nodeType == 1) {
const results = node.querySelectorAll(selector);
if (results.length > 0) {
callback(results);
} else {
if (node.matches(selector)) {
callback([node]);
}
}
}
}
});
});
} else {
Array.from(mutation.addedNodes).forEach((node: HTMLElement) => {
if (node.nodeType == 1) {
const results = node.querySelectorAll(selector);
if (results.length > 0) {
callback(results);
} else {
if (node.matches(selector)) {
callback([node]);
}
}
}
});
}
}
if (mutation.type === "attributes" && includeAttributes) {
if (typeof includeAttributes == "string") {
Expand Down Expand Up @@ -69,4 +92,28 @@ export class DOMHelper {
subtree: true,
});
}

public static getPathTo(element) {
if (element.id !== "") return "#" + element.id;

if (element === document.body) return element.tagName.toLowerCase();

var ix = 0;
var siblings = element.parentNode.childNodes;
for (var i = 0; i < siblings.length; i++) {
var sibling = siblings[i];

if (sibling === element)
return (
this.getPathTo(element.parentNode) +
"-" +
element.tagName.toLowerCase() +
(ix + 1)
);

if (sibling.nodeType === 1 && sibling.tagName === element.tagName) {
ix++;
}
}
}
}

0 comments on commit 0833cad

Please sign in to comment.