Skip to content

Commit af20ad8

Browse files
committed
[Autocomplete] Attempting a simpler "reset" of items
1 parent a2418ef commit af20ad8

File tree

9 files changed

+304
-307
lines changed

9 files changed

+304
-307
lines changed

src/Autocomplete/assets/dist/controller.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ export default class extends Controller {
3333
private mutationObserver;
3434
private isObserving;
3535
private hasLoadedChoicesPreviously;
36+
private originalOptions;
3637
initialize(): void;
3738
connect(): void;
39+
initializeTomSelect(): void;
3840
disconnect(): void;
3941
private getMaxOptions;
4042
get selectElement(): HTMLSelectElement | null;
@@ -43,9 +45,9 @@ export default class extends Controller {
4345
get preload(): string | boolean;
4446
private resetTomSelect;
4547
private changeTomSelectDisabledState;
46-
private updateTomSelectPlaceholder;
4748
private startMutationObserver;
4849
private stopMutationObserver;
4950
private onMutations;
50-
private requiresLiveIgnore;
51+
private createOptionsDataStructure;
52+
private areOptionsEquivalent;
5153
}

src/Autocomplete/assets/dist/controller.js

Lines changed: 48 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,25 @@ class default_1 extends Controller {
2929
_default_1_instances.add(this);
3030
this.isObserving = false;
3131
this.hasLoadedChoicesPreviously = false;
32+
this.originalOptions = [];
3233
}
3334
initialize() {
34-
if (this.requiresLiveIgnore()) {
35-
this.element.setAttribute('data-live-ignore', '');
36-
if (this.element.id) {
37-
const label = document.querySelector(`label[for="${this.element.id}"]`);
38-
if (label) {
39-
label.setAttribute('data-live-ignore', '');
40-
}
41-
}
42-
}
43-
else {
44-
if (!this.mutationObserver) {
45-
this.mutationObserver = new MutationObserver((mutations) => {
46-
this.onMutations(mutations);
47-
});
48-
}
35+
if (!this.mutationObserver) {
36+
this.mutationObserver = new MutationObserver((mutations) => {
37+
this.onMutations(mutations);
38+
});
4939
}
5040
}
5141
connect() {
42+
if (this.selectElement) {
43+
this.originalOptions = this.createOptionsDataStructure(this.selectElement);
44+
}
45+
this.initializeTomSelect();
46+
}
47+
initializeTomSelect() {
48+
if (this.selectElement) {
49+
this.selectElement.setAttribute('data-skip-morph', '');
50+
}
5251
if (this.urlValue) {
5352
this.tomSelect = __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_createAutocompleteWithRemoteData).call(this, this.urlValue, this.hasMinCharactersValue ? this.minCharactersValue : null);
5453
return;
@@ -97,9 +96,12 @@ class default_1 extends Controller {
9796
resetTomSelect() {
9897
if (this.tomSelect) {
9998
this.stopMutationObserver();
100-
this.tomSelect.clearOptions();
101-
this.tomSelect.settings.maxOptions = this.getMaxOptions();
102-
this.tomSelect.sync();
99+
const currentHtml = this.element.innerHTML;
100+
const currentValue = this.tomSelect.getValue();
101+
this.tomSelect.destroy();
102+
this.element.innerHTML = currentHtml;
103+
this.initializeTomSelect();
104+
this.tomSelect.setValue(currentValue);
103105
this.startMutationObserver();
104106
}
105107
}
@@ -113,22 +115,6 @@ class default_1 extends Controller {
113115
}
114116
this.startMutationObserver();
115117
}
116-
updateTomSelectPlaceholder() {
117-
const input = this.element;
118-
let placeholder = input.getAttribute('placeholder') || input.getAttribute('data-placeholder');
119-
if (!placeholder && !this.tomSelect.allowEmptyOption) {
120-
const option = input.querySelector('option[value=""]');
121-
if (option) {
122-
placeholder = option.textContent;
123-
}
124-
}
125-
if (placeholder) {
126-
this.stopMutationObserver();
127-
this.tomSelect.settings.placeholder = placeholder;
128-
this.tomSelect.control_input.setAttribute('placeholder', placeholder);
129-
this.startMutationObserver();
130-
}
131-
}
132118
startMutationObserver() {
133119
if (!this.isObserving && this.mutationObserver) {
134120
this.mutationObserver.observe(this.element, {
@@ -147,73 +133,51 @@ class default_1 extends Controller {
147133
}
148134
}
149135
onMutations(mutations) {
150-
const addedOptionElements = [];
151-
const removedOptionElements = [];
152-
let hasAnOptionChanged = false;
153136
let changeDisabledState = false;
154-
let changePlaceholder = false;
137+
let requireReset = false;
155138
mutations.forEach((mutation) => {
156139
switch (mutation.type) {
157-
case 'childList':
158-
if (mutation.target instanceof HTMLOptionElement) {
159-
if (mutation.target.value === '') {
160-
changePlaceholder = true;
161-
break;
162-
}
163-
hasAnOptionChanged = true;
164-
break;
165-
}
166-
mutation.addedNodes.forEach((node) => {
167-
if (node instanceof HTMLOptionElement) {
168-
if (removedOptionElements.includes(node)) {
169-
removedOptionElements.splice(removedOptionElements.indexOf(node), 1);
170-
return;
171-
}
172-
addedOptionElements.push(node);
173-
}
174-
});
175-
mutation.removedNodes.forEach((node) => {
176-
if (node instanceof HTMLOptionElement) {
177-
if (addedOptionElements.includes(node)) {
178-
addedOptionElements.splice(addedOptionElements.indexOf(node), 1);
179-
return;
180-
}
181-
removedOptionElements.push(node);
182-
}
183-
});
184-
break;
185140
case 'attributes':
186-
if (mutation.target instanceof HTMLOptionElement) {
187-
hasAnOptionChanged = true;
188-
break;
189-
}
190141
if (mutation.target === this.element && mutation.attributeName === 'disabled') {
191142
changeDisabledState = true;
192143
break;
193144
}
194-
break;
195-
case 'characterData':
196-
if (mutation.target instanceof Text && mutation.target.parentElement instanceof HTMLOptionElement) {
197-
if (mutation.target.parentElement.value === '') {
198-
changePlaceholder = true;
199-
break;
200-
}
201-
hasAnOptionChanged = true;
145+
if (mutation.target === this.element && mutation.attributeName === 'multiple') {
146+
requireReset = true;
147+
break;
202148
}
149+
break;
203150
}
204151
});
205-
if (hasAnOptionChanged || addedOptionElements.length > 0 || removedOptionElements.length > 0) {
152+
const newOptions = this.selectElement ? this.createOptionsDataStructure(this.selectElement) : [];
153+
const areOptionsEquivalent = this.areOptionsEquivalent(newOptions);
154+
if (!areOptionsEquivalent || requireReset) {
155+
this.originalOptions = newOptions;
206156
this.resetTomSelect();
207157
}
208158
if (changeDisabledState) {
209159
this.changeTomSelectDisabledState(this.formElement.disabled);
210160
}
211-
if (changePlaceholder) {
212-
this.updateTomSelectPlaceholder();
213-
}
214161
}
215-
requiresLiveIgnore() {
216-
return this.element instanceof HTMLSelectElement && this.element.multiple;
162+
createOptionsDataStructure(selectElement) {
163+
return Array.from(selectElement.options).map((option) => {
164+
const optgroup = option.closest('optgroup');
165+
return {
166+
value: option.value,
167+
text: option.text,
168+
group: optgroup ? optgroup.label : null,
169+
};
170+
});
171+
}
172+
areOptionsEquivalent(newOptions) {
173+
if (this.originalOptions.length !== newOptions.length) {
174+
return false;
175+
}
176+
const normalizeOption = (option) => `${option.value}-${option.text}-${option.group}`;
177+
const originalOptionsSet = new Set(this.originalOptions.map(normalizeOption));
178+
const newOptionsSet = new Set(newOptions.map(normalizeOption));
179+
return (originalOptionsSet.size === newOptionsSet.size &&
180+
[...originalOptionsSet].every((option) => newOptionsSet.has(option)));
217181
}
218182
}
219183
_default_1_instances = new WeakSet(), _default_1_getCommonConfig = function _default_1_getCommonConfig() {
@@ -233,19 +197,12 @@ _default_1_instances = new WeakSet(), _default_1_getCommonConfig = function _def
233197
return `<div class="no-results">${this.noResultsFoundTextValue}</div>`;
234198
},
235199
};
236-
const requiresLiveIgnore = this.requiresLiveIgnore();
237200
const config = {
238201
render,
239202
plugins,
240203
onItemAdd: () => {
241204
this.tomSelect.setTextboxValue('');
242205
},
243-
onInitialize: function () {
244-
if (requiresLiveIgnore) {
245-
const tomSelect = this;
246-
tomSelect.wrapper.setAttribute('data-live-ignore', '');
247-
}
248-
},
249206
closeAfterSelect: true,
250207
};
251208
if (!this.selectElement && !this.urlValue) {

0 commit comments

Comments
 (0)