From 01e9a8e40351a87f6548a4f55de842d6f6918ad0 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 15 Sep 2026 02:44:28 +0000
Subject: [PATCH] =Found little glitch with auto-adding rewrite rules to taxonomy Registrar instances where we have the post type as the base in the url rewrite

---
 assets/js/concise/FormController.js |  164 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 154 insertions(+), 10 deletions(-)

diff --git a/assets/js/concise/FormController.js b/assets/js/concise/FormController.js
index e5f3868..bd245ce 100644
--- a/assets/js/concise/FormController.js
+++ b/assets/js/concise/FormController.js
@@ -10,6 +10,7 @@
 		this.inputs = new Map();
 		this.repeaters = new Map();
 		this.tagLists = new Map();
+		this.locations = new Map();
 		this.charLimits = new Map();
 		this.quantityFields = new Map();
 		this.quillInstances = new Map(); // formId -> Set of quill instances
@@ -23,6 +24,7 @@
 		this.summaryTemplate = false;
 
 		this.init();
+
 	}
 	init() {
 		this.templates = window.jvbTemplates;
@@ -104,6 +106,14 @@
 				inputs: this.inputSelectors,				//querySelectorAll
 				value: 'input[type="hidden"]'		//querySelectorAll
 			},
+			location: {
+				location: '[data-field-type="location"]',	//querySelectorAll
+				search: '[data-location-search]',
+				results: '.search-results',
+				message: '.message',
+				preview: '.location-preview',
+				fields: 'fieldset.location input',
+			},
 			tag: {
 				label: '.tag-label'
 			},
@@ -418,6 +428,7 @@
 		}
 
 		let form = this.getForm(e.target);
+		console.log(this.getFieldValue(e.target), 'value');
 		this.updateItem(field.dataset.field, this.getFieldValue(e.target), form);
 	}
 
@@ -506,6 +517,9 @@
 	 * @param form
 	 */
 	updateItem(name, value, form) {
+		console.log('Updating field');
+		console.log(name,'name');
+		console.log(value,'value');
 		if (value === undefined) return;
 		if (!this.changes.has(form.id)) {
 			this.changes.set(form.id, {
@@ -853,7 +867,8 @@
 			repeater: this.repeaters,
 			tagList: this.tagLists,
 			charLimit: this.charLimits,
-			quantity: this.quantityFields
+			quantity: this.quantityFields,
+			location: this.locations
 		};
 		for (let [type, check] of Object.entries(checks)) {
 			if (check.size === 0) continue;
@@ -873,6 +888,9 @@
 						case 'quantity':
 							this.removeQuantityListeners(item.element);
 							break;
+						case 'location':
+							this.removeLocationListeners(item.element);
+							break;
 					}
 
 					if (check.has(item.id)) {
@@ -963,6 +981,7 @@
 	initializeFields(container, config = null) {
 		const fieldHandlers = {
 			'[data-editor]': () => this.checkForQuill(container,config),
+			'[data-field-type="location"]': () => this.checkForLocationFields(container, config),
 			'div.quantity': () => this.checkForQuantity(container),
 			'.repeater': () => this.checkForRepeaters(container, config),
 			'.field.tag-list': () => this.checkForTagLists(container),
@@ -1336,6 +1355,127 @@
 
 	}
 
+	checkForLocationFields(form, config) {
+		form.querySelectorAll(this.selectors.location.location).forEach(field => {
+			let ui = window.uiFromSelectors(this.selectors.location, field);
+			if (!ui.search) return;
+
+			ui.fields = {};
+			field.querySelectorAll(this.selectors.location.fields).forEach(f => {
+				ui.fields[f.dataset.fieldName] = f;
+			});
+
+			let id = window.generateID('location');
+			field.dataset.locationId = id;
+
+			this.locations.set(id, {
+				id: id,
+				form: config?.id,
+				element: field,
+				ui: ui,
+				results: []
+			});
+
+			this.addLocationListeners(field);
+		});
+	}
+		addLocationListeners(el) {
+			el.addEventListener('input', this.locationInputHandler ??= this.handleLocationInput.bind(this));
+			el.addEventListener('click', this.locationClickHandler ??= this.handleLocationClick.bind(this));
+		}
+		removeLocationListeners(el) {
+			el.removeEventListener('input', this.locationInputHandler);
+			el.removeEventListener('click', this.locationClickHandler);
+		}
+		handleLocationInput(e) {
+			if (!e.target.matches(this.selectors.location.search)) return;
+			let field = e.target.closest('[data-location-id]');
+			if (!field) return;
+			let conf = this.locations.get(field.dataset.locationId);
+			if (!conf) return;
+
+			let query = e.target.value.trim();
+			if (query.length < 3) {
+				conf.ui.results.replaceChildren();
+				return;
+			}
+
+			window.debouncer.schedule(
+				`location:${conf.id}`,
+				() => this.searchLocation(conf, query),
+				400
+			);
+		}
+		async searchLocation(conf, query) {
+			conf.ui.message.hidden = false;
+			try {
+				let response = await window.auth.fetch(
+					`${jvbSettings.api}geocode?q=${encodeURIComponent(query)}`,
+					{ method: 'GET' }
+				);
+
+				conf.results = response.ok ? await response.json() : [];
+			} catch (err) {
+				console.error('Geocode error:', err);
+				conf.results = [];
+			}
+			conf.ui.message.hidden = true;
+			this.renderLocationResults(conf);
+		}
+		renderLocationResults(conf) {
+			conf.ui.results.replaceChildren();
+			if (conf.results.length === 0) {
+				conf.ui.results.innerHTML = '<li>No results found</li>';
+				return;
+			}
+			conf.results.forEach((result, index) => {
+				let li = document.createElement('li');
+				li.className = 'autocomplete item btn';
+				li.dataset.resultIndex = index;
+				li.textContent = result.display_name;
+				conf.ui.results.append(li);
+			});
+		}
+		handleLocationClick(e) {
+			let item = e.target.closest('[data-result-index]');
+			if (!item) return;
+			let field = e.target.closest('[data-location-id]');
+			if (!field) return;
+			let conf = this.locations.get(field.dataset.locationId);
+			if (!conf) return;
+
+			let result = conf.results[item.dataset.resultIndex];
+			if (!result) return;
+
+			this.populateLocationFromResult(conf, result);
+			conf.ui.results.replaceChildren();
+			conf.ui.search.value = result.display_name;
+
+			let form = this.getForm(field);
+			if (form) this.updateItem(field.dataset.field, this.getLocationValue(field), form);
+		}
+		populateLocationFromResult(conf, result) {
+			const addr = result.address ?? {};
+			const map = {
+				address: addr.house_number || '',
+				lat: result.lat,
+				lng: result.lon,
+				street: addr.road || '',
+				city: addr.city || addr.town || addr.village || '',
+				province: addr.state || '',
+				postal_code: addr.postcode || '',
+				country: addr.country || '',
+			};
+			for (let [field, input] of Object.entries(conf.ui.fields)) {
+				input.value = map[field]??'';
+			}
+
+			if (conf.ui.preview) {
+				conf.ui.preview.dataset.lat = map.lat;
+				conf.ui.preview.dataset.lng = map.lng;
+			}
+		}
+
 	checkForConditionalFields(form) {
 		form.querySelectorAll(this.selectors.dependsOn).forEach( field => {
 			const dependsOn = field.dataset.dependsOn;
@@ -1892,6 +2032,7 @@
 		let conf = this.getItem(element);
 
 		let fieldName = conf.field?.dataset.field??false;
+
 		if (!fieldName) return false;
 
 		switch (type) {
@@ -1906,7 +2047,7 @@
 			//Do we actually need anything here? I think each subfield just
 
 			case 'location':
-				return this.getLocationValue(element, conf);
+				return this.getLocationValue(element);
 
 			case 'selector':
 			case 'upload':
@@ -2015,15 +2156,15 @@
 		});
 		return value;
 	}
-	getLocationValue(element, conf) {
-		if(!conf.values){
-			conf.values = Array.from(conf.field?.querySelectorAll('[data-location-field]'));
-			this.saveItem(conf);
-		}
+	getLocationValue(element) {
+		let field = this.getField(element);
+		let conf = this.locations.get(field.dataset.locationId);
+		if (!conf) return;
+
 		let value = {};
-		conf.values.forEach(input => {
-			value[input.dataset.locationField] = input.value;
-		});
+		for (let [field, input] of Object.entries(conf.ui.fields)) {
+			value[field] = input.value;
+		}
 		return value;
 	}
 	getHiddenInputValue(element, conf, fieldName) {
@@ -2356,10 +2497,13 @@
 
 	}
 }
+
+
 document.addEventListener('DOMContentLoaded', async function () {
 	window.auth.subscribe(event => {
 		if (event === 'auth-loaded') {
 			window.jvbForm = new FormController();
+			document.dispatchEvent(new CustomEvent('jvbFormLoaded'));
 			document.querySelectorAll('form[data-auto]').forEach(form => {
 				window.jvbForm.registerForm(form, {});
 			});

--
Gitblit v1.10.0