From 9e3a4aecc859ab6fe0179ac7c79a4164e29d2569 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 04 Jan 2026 19:19:10 +0000
Subject: [PATCH] =TaxonomyCreator.js minor fixes; found that when creating multiple terms across separate fields, it got 'stuck' and wouldn't finish some of them
---
assets/js/concise/TaxonomyCreator.js | 69 ++++++++--------------------------
assets/js/min/creator.min.js | 2
2 files changed, 17 insertions(+), 54 deletions(-)
diff --git a/assets/js/concise/TaxonomyCreator.js b/assets/js/concise/TaxonomyCreator.js
index 91ed836..277185c 100644
--- a/assets/js/concise/TaxonomyCreator.js
+++ b/assets/js/concise/TaxonomyCreator.js
@@ -37,12 +37,12 @@
}
if (window.targetCheck(e, '.submit-term')) {
- this.handleTermCreation(e);
+ this.handleTermCreation(e).then(()=>{});
}
// Handle autocomplete create button
if (window.targetCheck(e, '.create-term')) {
- this.handleAutocompleteCreate(e);
+ this.handleAutocompleteCreate(e).then(()=>{});
}
}
@@ -56,28 +56,31 @@
if (!termName) return;
try {
- this.form.querySelector('button').disabled = true;
+ const submitButton = this.form.querySelector('button');
+ if (submitButton) {
+ submitButton.disabled = true;
+ }
const response = await this.createTerm(termName, parentId, taxonomy);
if (response.success && response.term) {
let term = response.term;
+ const termPath = term.path || term.name;
this.createNew.open = false;
await this.selector.store.clearCache();
- // Add to store's data BEFORE display update
this.selector.store.data.set(term.id, {
id: term.id,
name: term.name,
path: termPath,
- taxonomy: field.taxonomy,
- parent: 0,
+ taxonomy: taxonomy,
+ parent: parentId,
count: 0,
hasChildren: false,
slug: term.slug || termName.toLowerCase().replace(/\s+/g, '-')
});
- this.selector.addSelectedTermToModal(term.id, term.name, term.path || term.name);
+ this.selector.addSelectedTermToModal(term.id, term.name, termPath);
const currentParent = this.selector.store.filters.parent || 0;
if (currentParent === parentId) {
@@ -94,7 +97,7 @@
if (suggestionContainer) {
suggestionContainer.hidden = true;
}
- this.selector.store.cache.clear();
+
}
} catch (error) {
console.error('Error creating term:', error);
@@ -132,7 +135,6 @@
const termPath = term.path || term.name;
field.selectedTerms.add(parseInt(term.id));
- // Add to store's data BEFORE display update
this.selector.store.data.set(term.id, {
id: term.id,
name: term.name,
@@ -151,15 +153,9 @@
field.autocompleteDropdown.hidden = true;
if (input) input.value = '';
+ // Only clear cache, don't refetch - term is already in store.data
this.selector.store.clearCache();
- await this.selector.store.setFilters({
- taxonomy: field.taxonomy,
- page: 1,
- search: '',
- parent: 0
- });
} else if (response.reason === 'exists' && response.term) {
- // Term already exists - just add it
const term = response.term;
field.selectedTerms.add(parseInt(term.id));
this.selector.addTermToDisplay(field.id, term.id, term.name, term.path || term.name);
@@ -172,12 +168,13 @@
}
} catch (error) {
console.error('Error creating term:', error);
- button.innerHTML = originalHTML;
- button.disabled = false;
this.selector.error?.log(error, {
component: 'TaxonomyCreator',
action: 'handleAutocompleteCreate'
});
+ } finally {
+ button.innerHTML = originalHTML;
+ button.disabled = false;
}
}
@@ -243,15 +240,7 @@
async createTerm(name, parent = 0, taxonomy) {
try {
- // Search for the exact term first
- await this.selector.store.setFilters({
- taxonomy: taxonomy,
- search: name,
- page: 1,
- parent: 0
- });
-
- // Check if exact match exists in results
+ // Check existing data first without fetching
const exactMatch = Array.from(this.selector.store.data.values())
.find(term =>
term.taxonomy === taxonomy &&
@@ -259,7 +248,6 @@
);
if (exactMatch) {
- // For modal context, show suggestions
if (this.createNew) {
this.showTermSuggestions([exactMatch], true);
}
@@ -293,31 +281,6 @@
}
/**
- * Search for existing terms using the store
- */
- async searchExistingTerms(searchQuery, taxonomy) {
- return new Promise((resolve) => {
- // Set up a one-time listener for the search results
- const handleSearchResults = (event, data) => {
- if (event === 'data-loaded') {
- this.selector.store.unsubscribe(handleSearchResults);
- resolve(data.data?.items || []);
- }
- };
-
- this.selector.store.subscribe(handleSearchResults);
-
- // Trigger search
- this.selector.store.setFilters({
- taxonomy: taxonomy,
- search: searchQuery,
- page: 1,
- parent: 0
- });
- });
- }
-
- /**
* Show term suggestions when similar terms exist
*/
showTermSuggestions(suggestions, isExact = false) {
diff --git a/assets/js/min/creator.min.js b/assets/js/min/creator.min.js
index 79ffc30..4799308 100644
--- a/assets/js/min/creator.min.js
+++ b/assets/js/min/creator.min.js
@@ -1 +1 @@
-window.jvbTaxCreator=class{constructor(e){this.selector=e,e.modal&&(this.createNew=e.modal.querySelector(".create-new-term"),this.toggle=e.modal.querySelector(".new-term-toggle"),this.form=this.createNew?.querySelector(".create-new-term-section")),this.initListeners(),this.form&&this.initTermCreation()}initListeners(){this.clickHandler=this.handleClick.bind(this),document.addEventListener("click",this.clickHandler)}handleClick(e){window.targetCheck(e,".create-new-term summary")&&(this.createNew.open&&this.createNew.querySelector('input[name="term_name"]').focus(),this.resetParentOptions()),window.targetCheck(e,".submit-term")&&this.handleTermCreation(e),window.targetCheck(e,".create-term")&&this.handleAutocompleteCreate(e)}async handleTermCreation(e){const t=this.selector.currentConfig?.taxonomy;if(!t)return;const r=this.form.querySelector('input[name="term_name"]').value.trim(),s=parseInt(this.form.querySelector("input#select_parent")?.value)||0;if(r)try{this.form.querySelector("button").disabled=!0;const e=await this.createTerm(r,s,t);if(e.success&&e.term){let o=e.term;this.createNew.open=!1,await this.selector.store.clearCache(),this.selector.store.data.set(o.id,{id:o.id,name:o.name,path:termPath,taxonomy:field.taxonomy,parent:0,count:0,hasChildren:!1,slug:o.slug||r.toLowerCase().replace(/\s+/g,"-")}),this.selector.addSelectedTermToModal(o.id,o.name,o.path||o.name),(this.selector.store.filters.parent||0)===s&&await this.selector.store.setFilters({taxonomy:t,parent:s,page:1,search:""}),this.form.querySelector('input[name="term_name"]').value="";const a=this.createNew.querySelector(".term-suggestions");a&&(a.hidden=!0),this.selector.store.cache.clear()}}catch(e){console.error("Error creating term:",e),this.selector.error?.log(e,{component:"TaxonomyCreator",action:"handleTermCreation"})}finally{this.form.querySelector("button").disabled=!1}}async handleAutocompleteCreate(e){const t=e.target.closest(".create-term"),r=this.selector.getFieldId(t),s=this.selector.fields.get(r);if(!s)return;const o=s.container.querySelector("input[data-autocomplete]"),a=o?.value.trim()||t.dataset.query;if(!a)return;const n=t.innerHTML;try{t.disabled=!0,t.textContent="Creating...";const e=await this.createTerm(a,0,s.taxonomy);if(e.success&&e.term){const t=e.term,r=t.path||t.name;s.selectedTerms.add(parseInt(t.id)),this.selector.store.data.set(t.id,{id:t.id,name:t.name,path:r,taxonomy:s.taxonomy,parent:0,count:0,hasChildren:!1,slug:t.slug||a.toLowerCase().replace(/\s+/g,"-")}),this.selector.addTermToDisplay(s.id,t.id,t.name,r),s.input.value=Array.from(s.selectedTerms).join(","),s.input.dispatchEvent(new Event("change",{bubbles:!0})),s.autocompleteDropdown.hidden=!0,o&&(o.value=""),this.selector.store.clearCache(),await this.selector.store.setFilters({taxonomy:s.taxonomy,page:1,search:"",parent:0})}else if("exists"===e.reason&&e.term){const t=e.term;s.selectedTerms.add(parseInt(t.id)),this.selector.addTermToDisplay(s.id,t.id,t.name,t.path||t.name),s.input.value=Array.from(s.selectedTerms).join(","),s.input.dispatchEvent(new Event("change",{bubbles:!0})),s.autocompleteDropdown.hidden=!0,o&&(o.value="")}}catch(e){console.error("Error creating term:",e),t.innerHTML=n,t.disabled=!1,this.selector.error?.log(e,{component:"TaxonomyCreator",action:"handleAutocompleteCreate"})}}initTermCreation(){this.form&&this.form.addEventListener("change",(e=>{e.preventDefault(),e.stopPropagation()}))}resetParentOptions(){const e=this.selector.currentConfig?.taxonomy;if(!e)return;let t=this.createNew.querySelector("#select_parent");if(!t)return;let r=t.querySelector("option");if(!r)return;window.removeChildren(t),t.append(r.cloneNode(!0));const s=this.selector.store.filters.parent||0;if(0!==s){const e=this.selector.store.data.get(s);if(e){let s=r.cloneNode(!0);s.value=e.id,s.textContent=e.name,t.append(s)}}const o=[];this.selector.store.data.forEach((t=>{t.taxonomy===e&&t.parent===s&&o.push(t)})),o.sort(((e,t)=>e.name.localeCompare(t.name))),o.forEach((e=>{let s=r.cloneNode(!0);s.id=`select-parent-${e.id}`,s.value=e.id,s.textContent=" — "+e.name,t.append(s)}))}async createTerm(e,t=0,r){try{await this.selector.store.setFilters({taxonomy:r,search:e,page:1,parent:0});const s=Array.from(this.selector.store.data.values()).find((t=>t.taxonomy===r&&t.name.toLowerCase()===e.toLowerCase()));if(s)return this.createNew&&this.showTermSuggestions([s],!0),{success:!1,reason:"exists",term:s};const o=await fetch(`${jvbSettings.api}terms`,{method:"POST",headers:{"Content-Type":"application/json","X-WP-Nonce":window.auth.getNonce()},body:JSON.stringify({taxonomy:r,name:e,parent:t})});if(!o.ok)throw new Error(`Server error: ${o.status}`);return await o.json()}catch(e){throw console.error("Error creating term:",e),e}}async searchExistingTerms(e,t){return new Promise((r=>{const s=(e,t)=>{"data-loaded"===e&&(this.selector.store.unsubscribe(s),r(t.data?.items||[]))};this.selector.store.subscribe(s),this.selector.store.setFilters({taxonomy:t,search:e,page:1,parent:0})}))}showTermSuggestions(e,t=!1){const r=this.createNew.querySelector(".term-suggestions")||this.createSuggestionContainer();window.removeChildren(r);const s=document.createElement("h4");s.textContent=t?"This term already exists:":"Similar terms already exist:",r.appendChild(s);const o=document.createElement("ul");o.className="term-suggestion-list",e.forEach((e=>{const t=document.createElement("li"),s=document.createElement("button");s.type="button",s.className="use-existing-term",s.setAttribute("data-id",e.id),s.textContent=e.path||e.name,s.addEventListener("click",(()=>{this.selector.addSelectedTermToModal(e.id,e.name,e.path||e.name),this.createNew.open=!1,r.hidden=!0,this.form.querySelector('input[name="term_name"]').value=""})),t.appendChild(s),o.appendChild(t)})),r.appendChild(o),r.hidden=!1}createSuggestionContainer(){const e=document.createElement("div");return e.className="term-suggestions",e.hidden=!0,this.createNew.querySelector("form").after(e),e}destroy(){this.clickHandler&&document.removeEventListener("click",this.clickHandler);const e=this.createNew?.querySelector(".loading-message.create-term");e&&(e.hidden=!0);const t=this.createNew?.querySelector(".term-suggestions");t&&(t.hidden=!0)}};
\ No newline at end of file
+window.jvbTaxCreator=class{constructor(e){this.selector=e,e.modal&&(this.createNew=e.modal.querySelector(".create-new-term"),this.toggle=e.modal.querySelector(".new-term-toggle"),this.form=this.createNew?.querySelector(".create-new-term-section")),this.initListeners(),this.form&&this.initTermCreation()}initListeners(){this.clickHandler=this.handleClick.bind(this),document.addEventListener("click",this.clickHandler)}handleClick(e){window.targetCheck(e,".create-new-term summary")&&(this.createNew.open&&this.createNew.querySelector('input[name="term_name"]').focus(),this.resetParentOptions()),window.targetCheck(e,".submit-term")&&this.handleTermCreation(e).then((()=>{})),window.targetCheck(e,".create-term")&&this.handleAutocompleteCreate(e).then((()=>{}))}async handleTermCreation(e){const t=this.selector.currentConfig?.taxonomy;if(!t)return;const r=this.form.querySelector('input[name="term_name"]').value.trim(),n=parseInt(this.form.querySelector("input#select_parent")?.value)||0;if(r)try{const e=this.form.querySelector("button");e&&(e.disabled=!0);const o=await this.createTerm(r,n,t);if(o.success&&o.term){let e=o.term;const a=e.path||e.name;this.createNew.open=!1,await this.selector.store.clearCache(),this.selector.store.data.set(e.id,{id:e.id,name:e.name,path:a,taxonomy:t,parent:n,count:0,hasChildren:!1,slug:e.slug||r.toLowerCase().replace(/\s+/g,"-")}),this.selector.addSelectedTermToModal(e.id,e.name,a),(this.selector.store.filters.parent||0)===n&&await this.selector.store.setFilters({taxonomy:t,parent:n,page:1,search:""}),this.form.querySelector('input[name="term_name"]').value="";const s=this.createNew.querySelector(".term-suggestions");s&&(s.hidden=!0)}}catch(e){console.error("Error creating term:",e),this.selector.error?.log(e,{component:"TaxonomyCreator",action:"handleTermCreation"})}finally{this.form.querySelector("button").disabled=!1}}async handleAutocompleteCreate(e){const t=e.target.closest(".create-term"),r=this.selector.getFieldId(t),n=this.selector.fields.get(r);if(!n)return;const o=n.container.querySelector("input[data-autocomplete]"),a=o?.value.trim()||t.dataset.query;if(!a)return;const s=t.innerHTML;try{t.disabled=!0,t.textContent="Creating...";const e=await this.createTerm(a,0,n.taxonomy);if(e.success&&e.term){const t=e.term,r=t.path||t.name;n.selectedTerms.add(parseInt(t.id)),this.selector.store.data.set(t.id,{id:t.id,name:t.name,path:r,taxonomy:n.taxonomy,parent:0,count:0,hasChildren:!1,slug:t.slug||a.toLowerCase().replace(/\s+/g,"-")}),this.selector.addTermToDisplay(n.id,t.id,t.name,r),n.input.value=Array.from(n.selectedTerms).join(","),n.input.dispatchEvent(new Event("change",{bubbles:!0})),n.autocompleteDropdown.hidden=!0,o&&(o.value=""),this.selector.store.clearCache()}else if("exists"===e.reason&&e.term){const t=e.term;n.selectedTerms.add(parseInt(t.id)),this.selector.addTermToDisplay(n.id,t.id,t.name,t.path||t.name),n.input.value=Array.from(n.selectedTerms).join(","),n.input.dispatchEvent(new Event("change",{bubbles:!0})),n.autocompleteDropdown.hidden=!0,o&&(o.value="")}}catch(e){console.error("Error creating term:",e),this.selector.error?.log(e,{component:"TaxonomyCreator",action:"handleAutocompleteCreate"})}finally{t.innerHTML=s,t.disabled=!1}}initTermCreation(){this.form&&this.form.addEventListener("change",(e=>{e.preventDefault(),e.stopPropagation()}))}resetParentOptions(){const e=this.selector.currentConfig?.taxonomy;if(!e)return;let t=this.createNew.querySelector("#select_parent");if(!t)return;let r=t.querySelector("option");if(!r)return;window.removeChildren(t),t.append(r.cloneNode(!0));const n=this.selector.store.filters.parent||0;if(0!==n){const e=this.selector.store.data.get(n);if(e){let n=r.cloneNode(!0);n.value=e.id,n.textContent=e.name,t.append(n)}}const o=[];this.selector.store.data.forEach((t=>{t.taxonomy===e&&t.parent===n&&o.push(t)})),o.sort(((e,t)=>e.name.localeCompare(t.name))),o.forEach((e=>{let n=r.cloneNode(!0);n.id=`select-parent-${e.id}`,n.value=e.id,n.textContent=" — "+e.name,t.append(n)}))}async createTerm(e,t=0,r){try{const n=Array.from(this.selector.store.data.values()).find((t=>t.taxonomy===r&&t.name.toLowerCase()===e.toLowerCase()));if(n)return this.createNew&&this.showTermSuggestions([n],!0),{success:!1,reason:"exists",term:n};const o=await fetch(`${jvbSettings.api}terms`,{method:"POST",headers:{"Content-Type":"application/json","X-WP-Nonce":window.auth.getNonce()},body:JSON.stringify({taxonomy:r,name:e,parent:t})});if(!o.ok)throw new Error(`Server error: ${o.status}`);return await o.json()}catch(e){throw console.error("Error creating term:",e),e}}showTermSuggestions(e,t=!1){const r=this.createNew.querySelector(".term-suggestions")||this.createSuggestionContainer();window.removeChildren(r);const n=document.createElement("h4");n.textContent=t?"This term already exists:":"Similar terms already exist:",r.appendChild(n);const o=document.createElement("ul");o.className="term-suggestion-list",e.forEach((e=>{const t=document.createElement("li"),n=document.createElement("button");n.type="button",n.className="use-existing-term",n.setAttribute("data-id",e.id),n.textContent=e.path||e.name,n.addEventListener("click",(()=>{this.selector.addSelectedTermToModal(e.id,e.name,e.path||e.name),this.createNew.open=!1,r.hidden=!0,this.form.querySelector('input[name="term_name"]').value=""})),t.appendChild(n),o.appendChild(t)})),r.appendChild(o),r.hidden=!1}createSuggestionContainer(){const e=document.createElement("div");return e.className="term-suggestions",e.hidden=!0,this.createNew.querySelector("form").after(e),e}destroy(){this.clickHandler&&document.removeEventListener("click",this.clickHandler);const e=this.createNew?.querySelector(".loading-message.create-term");e&&(e.hidden=!0);const t=this.createNew?.querySelector(".term-suggestions");t&&(t.hidden=!0)}};
\ No newline at end of file
--
Gitblit v1.10.0