From bad59c66549eb601fed963ed013f9b79305ca003 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 07 Jan 2026 20:09:14 +0000
Subject: [PATCH] =Feedblock integrated with refactored taxonomy selector

---
 assets/js/concise/TaxonomySelector.js |   94 ++++++++++++++++++++++++++++------------------
 1 files changed, 57 insertions(+), 37 deletions(-)

diff --git a/assets/js/concise/TaxonomySelector.js b/assets/js/concise/TaxonomySelector.js
index 0565dee..1d84d93 100644
--- a/assets/js/concise/TaxonomySelector.js
+++ b/assets/js/concise/TaxonomySelector.js
@@ -1,3 +1,4 @@
+
 class TaxonomySelector {
 	constructor() {
 		this.container = document.querySelector('dialog#jvb-selector');
@@ -67,7 +68,7 @@
 	initElements() {
 		this.selectors = {
 			search: {
-				input: '[type=search]',
+				input: '[type="search"]',
 				clear: '.clear-search',
 				container: '.search-wrapper',
 				results: '.search-results',
@@ -99,7 +100,7 @@
 			},
 			favourites: '.favourite-terms',
 			field: {
-				toggle: 'button.taxonomy-toggle',
+				toggle: 'button.taxonomy-toggle, [data-filter="taxonomy"]',
 				value: 'input[type="hidden"]',
 				selected: '.selected-items',
 				dropdown: {
@@ -147,18 +148,16 @@
 	}
 
 	handleClick(e) {
-		const fieldId = (this.container.open) ? this.activeField : this.getFieldId(e.target);
+		const fieldId = this.getFieldId(e.target) || this.activeField;
 		const field = this.fields.get(fieldId);
 		if (!fieldId || !field) return;
 
-		const autoComplete = window.targetCheck(e, '[data-autocomplete-select]');
+		const autoComplete = window.targetCheck(e, '.item.autocomplete');
+
 		if (autoComplete) {
 			let termId = parseInt(autoComplete.dataset.id);
 			this.addSelected(termId, fieldId);
-			if (field.ui.dropdown.wrapper) {
-				field.ui.dropdown.wrapper.hidden = true;
-			}
-
+			this.scheduleHideDropdown(fieldId);
 			if (field.ui.search) {
 				field.ui.search.value = '';
 			}
@@ -244,7 +243,7 @@
 		if (!this.container.contains(e.target)) {
 			return;
 		}
-		if (e.target.type !== 'checkbox') return;
+		if (!['checkbox', 'button'].includes(e.target.type)) return;
 		e.preventDefault();
 		e.stopPropagation();
 
@@ -262,7 +261,7 @@
 		if (!fieldId) return;
 		const field = this.fields.get(fieldId);
 		if (!field) return;
-		if (e.target.type === 'checkbox') return;
+		if (['checkbox', 'button'].includes(e.target.type)) return;
 
 		e.preventDefault();
 		e.stopPropagation();
@@ -334,6 +333,7 @@
 		const field = this.fields.get(fieldId);
 		if (!fieldId || ! field) return;
 		if (!field.hasAutocomplete || this.container.open) return;
+		if (e.relatedTarget && field.ui.dropdown.wrapper?.contains(e.relatedTarget)) return;
 
 		this.scheduleHideDropdown(fieldId);
 	}
@@ -372,7 +372,9 @@
 		);
 		this.modal.subscribe((event, data) => {
 			switch (event) {
-
+				case 'modal-close':
+					this.closeModal()
+					break;
 			}
 		});
 	}
@@ -393,7 +395,7 @@
 		if (!field) return;
 
 		this.setField(fieldId);
-		this.ui.modal.title.textContent = `Select ${field.plural}`;
+		this.ui.modal.title.textContent = (field.isFilter) ?`Filter by ${field.singular}` : `Select ${field.plural}`;
 		if (this.ui.search.container) {
 			this.ui.search.container.hidden = !field.canSearch;
 		}
@@ -402,6 +404,7 @@
 		}
 		let message = `Opened ${field.singular} selection. Choose from checkboxes, or search to filter results.`;
 
+		window.removeChildren(this.ui.selected);
 		window.removeChildren(this.ui.terms.list);
 		this.modal.handleOpen();
 
@@ -409,7 +412,6 @@
 	}
 
 	closeModal() {
-		this.modal.handleClose();
 		const field = this.fields.get(this.activeField);
 		if (!field) return;
 		this.observer.unobserve(this.ui.terms.sentinel);
@@ -493,7 +495,7 @@
 
 	registerField(element, options = {}) {
 		let input = element.querySelector('input[type="hidden"]');
-		if (!input) {
+		if (!input && !Object.hasOwn(element.dataset, 'filter')) {
 			console.warn('TaxonomySelector: No hidden input found for field', element);
 			return;
 		}
@@ -505,7 +507,8 @@
 
 
 		let selectors = this.selectors.field;
-		let button = element.querySelector('button.taxonomy-toggle');
+		const isFilter = Object.hasOwn(element.dataset,'filter') && element.dataset.filter === 'taxonomy';
+		let button = (isFilter) ? element : element.querySelector('button.taxonomy-toggle');
 
 		if (Object.keys(options).length === 0){
 			if (!button) return;
@@ -536,6 +539,7 @@
 			hasAutocomplete: options.autocomplete??false,
 			canCreate: options.creatable??false,
 			isRequired: options.required??false,
+			isFilter: isFilter,
 			toggle: button,
 			create: {
 				button: null,
@@ -545,6 +549,10 @@
 			ui: window.uiFromSelectors(selectors, element),
 			checked: false,
 		};
+
+		if (isFilter && !config.ui.toggle) {
+			config.ui.toggle = element;
+		}
 		if (!config.taxonomy) {
 			console.error('TaxonomySelector: Field missing taxonomy', element);
 			return;
@@ -569,17 +577,19 @@
 	}
 
 	setSelectedFromValue(fieldId, input) {
-		if (!input) return;
 		if (!fieldId) return;
 		let field = this.fields.get(fieldId);
 		if (!field) return;
+		if (!input && !field.isFilter) return;
 
 		let selected = new Set();
-		input.value.trim()
-			.split(',')
-			.map(id => parseInt(id.trim()))
-			.filter(id => !isNaN(id))
-			.forEach(id => selected.add(id));
+		if (input) {
+			input.value.trim()
+				.split(',')
+				.map(id => parseInt(id.trim()))
+				.filter(id => !isNaN(id))
+				.forEach(id => selected.add(id));
+		}
 		this.selectedTerms.set(fieldId, selected);
 	}
 
@@ -594,7 +604,7 @@
 		if (field.limit !== 0 && selected.size >= field.limit) return;
 
 		selected.add(parseInt(termId));
-		if (!this.container.open) {
+		if (!this.container.open && !field.isFilter) {
 			this.updateFieldValue(fieldId);
 		}
 		this.addTermToDisplay(termId, fieldId);
@@ -607,17 +617,17 @@
 		if (!field || !term) return;
 		this.selectedTerms.get(fieldId).delete(parseInt(termId));
 
-		const selectedItem = field.ui.selected.querySelector(`[data-id="${termId}"]`);
+		const selectedItem = (field.ui.selected) ? field.ui.selected.querySelector(`[data-id="${termId}"]`) : false;
 		if (selectedItem) selectedItem.remove();
 		if (this.container.open) {
-			let item = this.ui.selected.querySelector(`[data-id="${termId}"]`);
+			let item = (this.ui.selected) ? this.ui.selected.querySelector(`[data-id="${termId}"]`) : false;
 			if (item) item.remove();
 			let checkbox = this.ui.terms.list.querySelector(`[type=checkbox][data-id="${termId}"]`);
 			if (checkbox) {
 				checkbox.checked = false;
 			}
 		}
-		if (!this.container.open) {
+		if (!this.container.open && !field.isFilter) {
 			this.updateFieldValue(fieldId);
 		}
 
@@ -633,7 +643,7 @@
 	checkLimits(fieldId) {
 		if (!this.container.open) return;
 		const field = this.fields.get(fieldId);
-		if (!field || field.limit === 0) return;
+		if (!field || !field.isFilter || field.limit === 0) return;
 		const disabled = this.selectedTerms.get(fieldId).size >= field.limit;
 		this.setCheckboxes(disabled);
 	}
@@ -651,7 +661,7 @@
 	updateFieldUI(fieldId) {
 		const field = this.fields.get(fieldId);
 		let selected = this.selectedTerms.get(fieldId)??new Set();
-		if (!field || selected.size === 0) return;
+		if (!field || field.isFilter || selected.size === 0) return;
 
 		Array.from(selected).forEach(termId => {
 			this.addTermToDisplay(termId, fieldId);
@@ -665,8 +675,8 @@
 			.some(term=>term.taxonomy === taxonomy);
 
 		fields.forEach(field => {
-			field.ui.toggle.disabled = !hasItems && !field.canCreate;
-			field.ui.toggle.title = !hasItems
+			field.toggle.disabled = !hasItems && !field.canCreate;
+			field.toggle.title = !hasItems
 				? `No ${field.singular} available`
 				: `Select ${field.plural}`;
 
@@ -690,6 +700,8 @@
 			}
 		}
 
+		this.setCreateButton(true);
+
 		if (this.ui.terms.sentinel) {
 			if (this.store.lastResponse?.has_more) {
 				this.observer.observe(this.ui.terms.sentinel);
@@ -712,7 +724,9 @@
 			}
 		});
 
-		this.setMessage(false);
+		if (terms.length > 0) {
+			this.setMessage(false);
+		}
 
 		this.ui.terms.list.append(fragment);
 	}
@@ -793,7 +807,7 @@
 		}
 		this.setCreateButton(true);
 
-		if (field.ui.dropdown?.wrapper) {
+		if (field.ui.dropdown.wrapper) {
 			field.ui.dropdown.wrapper.hidden = false;
 		}
 	}
@@ -803,6 +817,7 @@
 
 		item.dataset.id = term.id;
 		item.textContent = term.path || term.name;
+
 		return item;
 	}
 	/******************************************************************
@@ -813,7 +828,7 @@
 		const field = this.fields.get(fieldId);
 		if (!term || !field) return;
 		//if the term already exists in the selected items, bail early
-		if (field.ui.selected.querySelector(`[data-id="${termId}"]`)) return;
+		if (field.ui.selected && field.ui.selected.querySelector(`[data-id="${termId}"]`)) return;
 
 		const item = window.getTemplate('selectedTerm');
 		if (!item) return;
@@ -823,7 +838,9 @@
 		item.querySelector('.item-name').textContent = term.path;
 		item.querySelector('button').title = `Remove ${term.name}`;
 
-		field.ui.selected.append(item);
+		if (field.ui.selected) {
+			field.ui.selected.append(item);
+		}
 
 		if (this.container.open) {
 			this.addTermToModal(termId);
@@ -929,7 +946,9 @@
 	}
 	handleDataLoaded() {
 		const taxonomy = this.store.filters.taxonomy;
-		if (taxonomy?.includes(',')) {
+
+		// 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));
 		}
@@ -1014,7 +1033,6 @@
 		if (!field || !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;
@@ -1076,9 +1094,12 @@
 	setMessage(show = true, message = '', type = true) {
 		const field = this.currentField();
 		if (!field) return;
+
+		const conf = this.container.open||field.isFilter ? this.ui : (field.isFilter ? null : field.ui);
+		if (!conf?.message?.message) return;
+
 		message = (message === '') ? `No ${field.plural??'items'} found.` : message;
 
-		const conf = (this.container.open) ? this.ui : field.ui;
 		const p = conf.message.message;
 		const pText = conf.message.text;
 
@@ -1176,4 +1197,3 @@
 		}
 	});
 });
-

--
Gitblit v1.10.0