Jake Vanderwerf
2026-01-22 58e8ae0759ccfa97c478ccae4e0778bdce70966f
assets/js/concise/TaxonomySelector.js
@@ -44,7 +44,7 @@
            indexes: [
               {name: 'taxonomy', keyPath: 'taxonomy'},
               {name: 'parent', keyPath: 'parent'},
               {name: 'slug', keyPath: 'slug', unique: true},
               {name: 'slug', keyPath: 'slug'},
               {name: 'count', keyPath: 'count'},
            ],
            endpoint: 'terms',
@@ -96,14 +96,14 @@
            if (refs.checkbox) {
               refs.checkbox.dataset.id = data.id;
               refs.checkbox.id = `${field.element.id}-${data.id}`;
               refs.checkbox.name = `${field.element.id}-${field.taxonomy}-select`;
               refs.checkbox.id = `${field.id}-${data.id}`;
               refs.checkbox.name = `${field.id}-${field.taxonomy}-select`;
               refs.checkbox.value = data.id;
               refs.checkbox.disabled = !isSelected && limitReached;
               refs.checkbox.checked = isSelected;
            }
            if (refs.label) {
               refs.label.htmlFor = `${field.element.id}-${data.id}`;
               refs.label.htmlFor = `${field.id}-${data.id}`;
               refs.label.title = data.path??data.name;
               refs.label.dataset.path = data.path;
            }
@@ -841,9 +841,11 @@
      const field = this.fields.get(fieldId);
      if (!field) return;
      let selected = Array.from(this.selectedTerms.get(fieldId));
      if (field.ui.value) {
      field.ui.value.value = selected.join(',')??'';
      field.ui.value.dispatchEvent(new Event('change', { bubbles: true }));
   }
   }
   checkLimits(fieldId) {
      if (!this.container.open) return;
@@ -875,9 +877,9 @@
   updateFieldsForTaxonomy(taxonomy) {
      let fields = Array.from(this.fields.values())
         .filter(field => !field.checked && field.taxonomy === taxonomy);
         .filter(field => field.taxonomy === taxonomy);
      const hasItems = Array.from(this.store.data.values())
         .some(term=>term.taxonomy === taxonomy);
         .some(term => term && term.taxonomy === taxonomy);
      fields.forEach(field => {
         if (!field.toggle) return;
@@ -938,11 +940,9 @@
   showAutocompleteTerms() {
      const field = this.currentField();
      const terms = this.currentTerms();
      if (!field) return;
      if (!field || !field.hasAutocomplete || !field.ui.dropdown?.list) return;
      const dropdown = field.ui.dropdown.list;
      if (!dropdown) return;
      const terms = this.currentTerms();
      window.removeChildren(dropdown);
      if (terms.length === 0) {
@@ -1090,7 +1090,6 @@
   handleDataLoaded() {
      const taxonomy = this.store.filters.taxonomy;
      // Always update fields for loaded taxonomies (handles both single and batch)
      if (taxonomy) {
         const taxonomies = taxonomy.split(',').map(t => t.trim());
         taxonomies.forEach(tax => this.updateFieldsForTaxonomy(tax));
@@ -1118,6 +1117,9 @@
         filters
      });
      if (!this.activeField && isAutoComplete) {
         return;
      }
      if (isAutoComplete) {
         this.showAutocompleteTerms();
@@ -1143,10 +1145,8 @@
   }
   async batchFetchTaxonomies() {
      if (this.batchFetch.size === 0) return;
      const taxonomies = Array.from(this.batchFetch);
      this.batchFetch.clear();
      try {
         await this.store.setFilters({
            taxonomy: taxonomies.join(','),
@@ -1198,40 +1198,63 @@
      if (!field) return;
      window.debouncer.cancel(`${field.id}-search-results`);
      let data = {
         taxonomy: field.taxonomy,
         parent: this.store.filters.parent??0
      }
      //If it's autocomplete or the selector's search input, we just need the name
      if (!this.container.open || this.ui.search.input.value !== '') {
         data.name = (this.container.open) ? this.ui.search.input.value : field.ui.search.value;
      } else {
         //Otherwise, we've created it from the details element
         data.parent = this.creator.ui.parent.value??data.parent;
         data.name = this.creator.ui.name.value??false;
      }
      if (data.parent !== undefined && data.name) {
         this.setMessage(true, `Creating "${data.name}"...`);
         this.setCreateButton(false);
         if (this.container.open) {
            window.removeChildren(this.ui.terms.list);
         } else {
            field.ui.search.disabled = true;
            window.removeChildren(field.ui.dropdown.list);
            if (field.ui.dropdown.wrapper) {
               field.ui.dropdown.wrapper.hidden = false;
            }
         }
         let term = await this.creator.handleTermCreation(data);
         if (term) {
            // Stop any typeLoop animation and show success message WITHOUT typeLoop
            this.setMessage(true, `"${term.name}" created!`, false);
            this.addSelected(term.id, field.id);
            this.updateFieldValue(field.id);
            // For autocomplete, show the newly created term in dropdown
            if (!this.container.open && field.ui.dropdown.list) {
               window.removeChildren(field.ui.dropdown.list);
               const termElement = this.createAutocompleteTerm(term);
               if (termElement) {
                  termElement.classList.add('newly-created');
                  field.ui.dropdown.list.append(termElement);
         }
            }
            this.scheduleHideDropdown(field.id, 300);
            this.setMessage(false);
         } else {
            // Creation failed - hide immediately
            this.setMessage(false);
            if (!this.container.open && field.ui.dropdown.wrapper) {
               field.ui.dropdown.wrapper.hidden = true;
            }
         }
         if (!this.container.open) {
            field.ui.search.disabled = false;
            field.ui.search.value = '';
         }
         this.scheduleHideDropdown(field.id);
         this.setMessage(false);
      }
   }
   setMessage(show = true, message = '', type = true) {