/**
|
* This separates out all create logic from the base TaxonomySelector.js, so that we only enqueue create logic if it's creatable
|
* Updated to work with the refactored centralized TaxonomySelector
|
*/
|
|
class TaxonomyCreator {
|
|
constructor(selector) {
|
this.selector = selector;
|
|
// Get taxonomy from current active field config
|
this.taxonomy = selector.currentConfig?.taxonomy;
|
if (!this.taxonomy) {
|
console.error('TaxonomyCreator: No active field or taxonomy found');
|
return;
|
}
|
|
this.createNew = selector.modal.querySelector('.create-new-term');
|
this.toggle = selector.modal.querySelector('.new-term-toggle');
|
this.form = this.createNew.querySelector('.create-new-term-section');
|
|
this.initListeners();
|
this.initTermCreation();
|
}
|
|
initListeners() {
|
document.addEventListener('click', this.handleClick.bind(this));
|
}
|
|
handleClick(e) {
|
if (window.targetCheck(e, '.create-new-term summary')) {
|
if (this.createNew.open) {
|
this.createNew.querySelector('input[name="term_name"]').focus();
|
}
|
this.resetParentOptions();
|
}
|
|
if (window.targetCheck(e, '.submit-term')) {
|
this.handleTermCreation(e);
|
}
|
}
|
|
async handleTermCreation(e) {
|
const termName = this.form.querySelector('input[name="term_name"]').value.trim();
|
const parentId = this.form.querySelector('input#select_parent')?.value;
|
|
try {
|
this.form.querySelector('button').disabled = true;
|
const response = await this.createTerm(termName, parentId);
|
|
if (response.success) {
|
let term = response.term;
|
|
// Close the create new section
|
this.createNew.open = false;
|
|
// Add to the terms list UI
|
this.selector.createTermElement({
|
id: parseInt(term.id),
|
name: term.name,
|
hasChildren: term.hasChildren || false,
|
path: term.path || term.name,
|
show: false
|
});
|
|
// Add to current modal selection
|
this.selector.addSelectedTermToModal(term.id, term.name, term.path);
|
|
// Clear the form
|
this.form.querySelector('input[name="term_name"]').value = '';
|
}
|
} catch (error) {
|
console.error('Error creating term:', error);
|
this.selector.showError?.('Failed to create term') ||
|
console.error('Failed to create term');
|
} finally {
|
this.form.querySelector('button').disabled = false;
|
}
|
}
|
|
initTermCreation() {
|
if (!this.form) {
|
return;
|
}
|
|
this.form.addEventListener('change', (e) => {
|
e.preventDefault();
|
e.stopPropagation();
|
});
|
}
|
|
resetParentOptions() {
|
let select = this.createNew.querySelector('#select_parent');
|
if (!select) return;
|
|
let defaultOption = select.querySelector('option');
|
if (!defaultOption) return;
|
|
// Clear existing options
|
window.removeChildren(select);
|
select.append(defaultOption.cloneNode(true));
|
|
// Add current parent if we're in a sub-category
|
if (this.selector.currentParentName !== '') {
|
let parentOption = defaultOption.cloneNode(true);
|
parentOption.value = this.selector.currentParent;
|
parentOption.textContent = this.selector.currentParentName;
|
select.append(parentOption);
|
}
|
|
// Add terms from current taxonomy cache
|
const taxonomyTerms = this.selector.currentTerms;
|
if (taxonomyTerms && taxonomyTerms.length > 0) {
|
taxonomyTerms.forEach(term => {
|
let option = defaultOption.cloneNode(true);
|
option.id = `select-parent-${term.id}`;
|
option.value = term.id;
|
option.textContent = ' — ' + term.name;
|
select.append(option);
|
});
|
}
|
}
|
|
async createTerm(name, parent = 0) {
|
let loadingMessage = this.createNew.querySelector('.loading-message.create-term');
|
let text = loadingMessage?.querySelector('span');
|
|
try {
|
if (loadingMessage) {
|
loadingMessage.hidden = false;
|
}
|
|
if (text && window.typeText) {
|
window.typeText(text, 'Checking term...');
|
} else if (text) {
|
text.textContent = 'Checking term...';
|
}
|
|
// Check if term already exists by searching
|
const originalSearchQuery = this.selector.searchQuery;
|
const originalFetchSpecific = this.selector.fetchSpecificTerms;
|
|
this.selector.searchQuery = name;
|
this.selector.fetchSpecificTerms = false; // We want to search, not fetch specific IDs
|
|
const existingTerms = await this.selector.fetchTerms(
|
this.selector.activeField,
|
false,
|
true // isSearch = true
|
);
|
|
// Restore original search state
|
this.selector.searchQuery = originalSearchQuery;
|
this.selector.fetchSpecificTerms = originalFetchSpecific;
|
|
// Check if any existing terms match exactly
|
const exactMatches = existingTerms.filter(term =>
|
term.name.toLowerCase() === name.toLowerCase()
|
);
|
|
if (exactMatches.length > 0) {
|
this.showTermSuggestions(exactMatches);
|
return { success: false, reason: 'exists' };
|
}
|
|
// Show similar terms if found
|
if (existingTerms.length > 0) {
|
this.showTermSuggestions(existingTerms);
|
return { success: false, reason: 'similar' };
|
}
|
|
// Term doesn't exist, create it
|
if (text) {
|
text.textContent = 'Creating term...';
|
}
|
|
const response = await fetch(`${jvbSettings.api}terms`, {
|
method: 'POST',
|
headers: {
|
'Content-Type': 'application/json',
|
'X-WP-Nonce': jvbSettings.nonce
|
},
|
body: JSON.stringify({
|
taxonomy: this.taxonomy,
|
name: name,
|
parent: parent
|
})
|
});
|
|
if (!response.ok) {
|
throw new Error(`Server error: ${response.status}`);
|
}
|
|
const result = await response.json();
|
return result;
|
|
} catch (error) {
|
console.error('Error creating term:', error);
|
throw error;
|
} finally {
|
this.form.querySelector('button').disabled = false;
|
if (loadingMessage) {
|
loadingMessage.hidden = true;
|
}
|
}
|
}
|
|
// Helper method to show term suggestions when similar terms exist
|
showTermSuggestions(suggestions) {
|
const suggestionContainer = this.createNew.querySelector('.term-suggestions') ||
|
this.createSuggestionContainer();
|
|
// Clear existing suggestions
|
window.removeChildren(suggestionContainer);
|
|
// Add heading
|
const heading = document.createElement('h4');
|
heading.textContent = 'Similar terms already exist:';
|
suggestionContainer.appendChild(heading);
|
|
// Create list of suggestions
|
const list = document.createElement('ul');
|
list.className = 'term-suggestion-list';
|
|
suggestions.forEach(term => {
|
const item = document.createElement('li');
|
|
// Create term path display if available
|
let termDisplay = term.path || term.name;
|
|
const button = document.createElement('button');
|
button.type = 'button';
|
button.className = 'use-existing-term';
|
button.setAttribute('data-id', term.id);
|
button.textContent = termDisplay;
|
|
button.addEventListener('click', () => {
|
// Add this term to modal selection
|
this.selector.addSelectedTermToModal(term.id, term.name, term.path);
|
|
// Close the create new section
|
this.createNew.open = false;
|
|
// Clear suggestions
|
suggestionContainer.hidden = true;
|
|
// Clear the form
|
this.form.querySelector('input[name="term_name"]').value = '';
|
});
|
|
item.appendChild(button);
|
list.appendChild(item);
|
});
|
|
suggestionContainer.appendChild(list);
|
suggestionContainer.hidden = false;
|
}
|
|
// Create container for term suggestions if it doesn't exist
|
createSuggestionContainer() {
|
const container = document.createElement('div');
|
container.className = 'term-suggestions';
|
container.hidden = true;
|
|
// Insert after the form
|
this.createNew.querySelector('form').after(container);
|
return container;
|
}
|
|
/**
|
* Clean up when modal closes
|
*/
|
destroy() {
|
// Remove event listeners if needed
|
// Clear any pending operations
|
const loadingMessage = this.createNew?.querySelector('.loading-message.create-term');
|
if (loadingMessage) {
|
loadingMessage.hidden = true;
|
}
|
|
// Clear suggestions
|
const suggestionContainer = this.createNew?.querySelector('.term-suggestions');
|
if (suggestionContainer) {
|
suggestionContainer.hidden = true;
|
}
|
}
|
}
|
|
window.jvbTaxCreator = TaxonomyCreator;
|