From ac444cba221832c012c0435fdc8339fe9f37febb Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 11 May 2026 18:35:04 +0000
Subject: [PATCH] =Some changes to the CRUD.js editing, timeline post configuration
---
assets/js/concise/TaxonomySelector.js | 139 ++++++++++++++++++++++++++--------------------
1 files changed, 79 insertions(+), 60 deletions(-)
diff --git a/assets/js/concise/TaxonomySelector.js b/assets/js/concise/TaxonomySelector.js
index bdbe06b..e61835f 100644
--- a/assets/js/concise/TaxonomySelector.js
+++ b/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;
}
@@ -184,7 +184,7 @@
},
favourites: '.favourite-terms',
field: {
- toggle: 'button.taxonomy-toggle, [data-filter="taxonomy"]',
+ toggle: 'button.selector-toggle, [data-filter="taxonomy"]',
value: 'input[type="hidden"]',
selected: '.selected-items',
dropdown: {
@@ -239,6 +239,22 @@
const field = this.fields.get(fieldId);
if (!fieldId || !field) return;
+ if (this.creator) {
+ let button = window.targetCheck(e, this.selectors.create.button);
+ if (button) {
+ this.maybeCreateTerm(e).then(()=>{});
+ }
+ }
+
+ const removeButton = window.targetCheck(e, '.remove-term');
+ if (removeButton) {
+ const termId = removeButton.closest('[data-id]').dataset.id??false;
+ if (fieldId && termId) {
+ this.removeSelected(parseInt(termId), fieldId);
+ }
+ return;
+ }
+
const autocomplete = window.targetCheck(e, '.item.autocomplete');
if (autocomplete) {
@@ -259,14 +275,6 @@
return;
}
- const removeButton = window.targetCheck(e, '.remove-term');
- if (removeButton) {
- const termId = removeButton.closest('[data-id]').dataset.id??false;
- if (fieldId && termId) {
- this.removeSelected(parseInt(termId), fieldId);
- }
- return;
- }
if (e.target.matches('.modal-close')) {
this.updateFieldValue(fieldId);
@@ -320,14 +328,6 @@
this.ui.search.input.value = '';
}
}
-
- if (this.creator) {
- let button = window.targetCheck(e, this.selectors.create.button);
- if (button) {
- this.maybeCreateTerm(e).then(()=>{});
- }
- }
-
}
handleChange(e) {
if (!this.container.contains(e.target) && !e.target.closest('[data-type="selector"], [data-field-type="selector"]')) {
@@ -365,7 +365,7 @@
}
let query = e.target.value.trim();
- this.setMessage(true, `Searching for "${query}" in ${field.plural??'items'}`);
+ this.setMessage(field,true, `Searching for "${query}" in ${field.plural??'items'}`);
window.debouncer.schedule(
`${fieldId}-search`,
async () => {
@@ -390,7 +390,7 @@
return;
}
this.activeField = fieldId;
- this.setMessage(true, `Loading ${field.plural}...`);
+ this.setMessage(field,true, `Loading ${field.plural}...`);
this.resetFilters({taxonomy: field.taxonomy});
}
@@ -434,6 +434,8 @@
const field = this.fields.get(fieldId);
if (!field) return;
if (!field.hasAutocomplete || this.container.open) return;
+ if (e.target.closest('.remove-item')) return;
+
if (e.relatedTarget && field.ui.dropdown.wrapper?.contains(e.relatedTarget)) return;
this.scheduleHideDropdown(fieldId);
@@ -702,7 +704,7 @@
let selectors = this.selectors.field;
const isFilter = Object.hasOwn(element.dataset,'filter') && element.dataset.filter === 'taxonomy';
- let button = (isFilter) ? element : element.querySelector('button.taxonomy-toggle');
+ let button = (isFilter) ? element : element.querySelector('button.selector-toggle');
if (Object.keys(options).length === 0){
if (!button) return;
@@ -841,8 +843,10 @@
const field = this.fields.get(fieldId);
if (!field) return;
let selected = Array.from(this.selectedTerms.get(fieldId));
- field.ui.value.value = selected.join(',')??'';
- field.ui.value.dispatchEvent(new Event('change', { bubbles: true }));
+ if (field.ui.value) {
+ field.ui.value.value = selected.join(',')??'';
+ field.ui.value.dispatchEvent(new Event('change', { bubbles: true }));
+ }
}
checkLimits(fieldId) {
@@ -875,9 +879,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;
@@ -897,7 +901,7 @@
if (this.store.filters.page??1 === 1) {
window.removeChildren(this.ui.terms.list);
}
- this.setMessage(true, this.store.filters.search === ''
+ this.setMessage(field,true, this.store.filters.search === ''
? `No matching ${field.plural}.`
: `No ${field.plural} found.`,
false);
@@ -907,7 +911,7 @@
return;
}
- this.setCreateButton(true);
+ this.setCreateButton(field,true);
if (this.ui.terms.sentinel) {
if (this.store.lastResponse?.has_more) {
@@ -928,7 +932,7 @@
).then(()=>{});
if (terms.length > 0) {
- this.setMessage(false);
+ this.setMessage(field,false);
}
}
createTermElement(term) {
@@ -938,15 +942,13 @@
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) {
- this.setMessage(true, `No ${field.plural} found.`, false);
+ this.setMessage(field,true, `No ${field.plural} found.`, false);
} else {
window.chunkIt(
terms,
@@ -954,9 +956,9 @@
(fragment) => dropdown.append(fragment)
).then(()=>{});
- this.setMessage(false);
+ this.setMessage(field,false);
}
- this.setCreateButton(true);
+ this.setCreateButton(field,true);
if (field.ui.dropdown.wrapper) {
field.ui.dropdown.wrapper.hidden = false;
@@ -1084,13 +1086,11 @@
handlers[event]?.(data);
} catch (error) {
console.error(`Error handling store event "${event}":`, error);
- this.setMessage(true, 'An error occurred loading data', false);
}
}
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));
@@ -1104,11 +1104,9 @@
this.showResults(true);
return;
}
- this.setMessage(false);
}
showResults(isAutoComplete = false) {
- this.setMessage(false);
const terms = this.store.getFiltered();
const filters = this.store.filters;
const isSearch = filters.search && filters.search.length > 0;
@@ -1118,7 +1116,10 @@
filters
});
-
+ if (!this.activeField && isAutoComplete) {
+ return;
+ }
+ this.setMessage(this.currentField(), false);
if (isAutoComplete) {
this.showAutocompleteTerms();
} else {
@@ -1138,15 +1139,13 @@
? `Failed to load ${field.plural}`
: 'Failed to load data';
- this.setMessage(true, message, false);
+ this.setMessage(field,true, message, false);
console.error('Store fetch error:', error);
}
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(','),
@@ -1171,14 +1170,14 @@
/**************************************************
LOADING
**************************************************/
- setCreateButton(show = true) {
- const field = this.currentField();
- if (!field || !field.canCreate || !this.creator) return;
+ setCreateButton(field, show = true) {
+ if (!field.canCreate || !this.creator) return;
const conf = (this.container.open) ? this.ui : field.ui;
if (!conf.create?.button || !conf.create?.span) return;
const createButton = conf.create.button;
+ createButton.hidden = !show;
const buttonSpan = conf.create.span;
const input = (this.container.open) ? conf.search.input : conf.search;
if (!input) return;
@@ -1198,46 +1197,66 @@
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);
+ this.setMessage(field,true, `Creating "${data.name}"...`);
+ this.setCreateButton(field,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(field,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(field,false);
+ } else {
+ // Creation failed - hide immediately
+ this.setMessage(field,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) {
- const field = this.currentField();
- if (!field) return;
-
+ setMessage(field, show = true, message = '', type = true) {
const conf = this.container.open||field.isFilter ? this.ui : (field.isFilter ? null : field.ui);
if (!conf?.message?.message) return;
--
Gitblit v1.10.0