From b5abd615697146beeca6dba4acd057d049554a30 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 02 Jan 2026 00:16:00 +0000
Subject: [PATCH] Merge branch 'main' of https://github.com/jakevdwerf/jvb

---
 src/feed/view.js |  215 ++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 139 insertions(+), 76 deletions(-)

diff --git a/src/feed/view.js b/src/feed/view.js
index 4a1e1a5..7110cad 100644
--- a/src/feed/view.js
+++ b/src/feed/view.js
@@ -394,35 +394,32 @@
 	 */
 	createItemElement(item) {
 		let template = window.getTemplate(`feedItem${window.uppercaseFirst(item.content)}`);
-		if (Object.hasOwn(template.dataset, 'timeline')) {
-			return this.createTimelineElement(item, template);
-		}
-		//fields
+
+		const isTimeline = Object.hasOwn(template.dataset, 'timeline');
+
+		// Format fields using helpers
 		for (let [fieldName, value] of Object.entries(item.fields)) {
+			if (isTimeline && ['timeline', 'number'].includes(fieldName)) continue;
 			let el = template.querySelector(`[data-field="${fieldName}"]`);
-			if (!el) {
-				continue;
-			}
-			if (Object.keys(item.images).map((img)=> parseInt(img)).includes(value)) {
-				[
-					el.src,
-					el.srcset,
-					el.alt
-				] = [
-					item.images[value].tiny,
-					`${item.images[value].tiny} 50w, ${item.images[value].small} 300w, ${item.images[value].medium} 1024w`,
-					item.images[value]['image-alt-text']
-				];
-			} else if (el.tagName === 'TIME') {
-				el.setAttribute('datetime', value);
-				el.textContent = window.formatTimeAgo(value);
-			} else {
-				el.textContent = value;
-			}
+			if (!el) continue;
+
 			if (value === '') {
 				el.remove();
+				continue;
+			}
+
+			if (this.isImageField(item, value)) {
+				this.formatImageFields(el, value, item);
+			} else if (this.isTaxonomyField(item, fieldName)) {
+				this.formatTaxonomyField(el, item, fieldName, value);
+			} else if (this.isTimeField(el)) {
+				this.formatTimeField(el, value);
+			} else {
+				this.formatField(el, value);
 			}
 		}
+
+		// Handle link
 		let link = template.querySelector('a');
 		if (link && item.url !== '') {
 			[
@@ -433,68 +430,134 @@
 				`View ${item.fields['post_title']??'Item'}`
 			];
 		}
+
+		if (isTimeline) {
+			this.addTimelineElements(item, template);
+		}
+
 		return template;
 	}
+	splitIDs(value) {
+		return String(value).split(',').map((value) => parseInt(value.trim())).filter(value=>value);
+	}
+	isImageField(item, value) {
+		if (!Object.hasOwn(item, 'images') || Object.keys(item.images).length === 0) {
+			return false;
+		}
+		let values = this.splitIDs(value);
 
+		return values.some(v =>
+			Object.keys(item.images).map(k => parseInt(k)).includes(parseInt(v))
+		);
+	}
+	formatImageFields(element, value, item) {
+		let values = this.splitIDs(value); // Convert string to array first
+		if (values.length === 0) return;
 
-	createTimelineElement(item, template) {
-		console.log(item);
-		console.log(template);
+		if (values.length > 1) {
+			let image = element.querySelector('img');
+			if (!image) return;
+			values.forEach(imgID => {
+				let img = image.cloneNode(true);
+				this.formatImageField(img, imgID, item);
+				element.append(img);
+			});
+			image.remove();
+		} else {
+			if (element.tagName !== 'IMG') {
+				element = element.querySelector('img');
+				if (!element) return;
+			}
+			this.formatImageField(element, values[0], item);
+		}
+	}
+		formatImageField(element, value, item) {
+			let imgData = item.images[value]??false;
+			if (!imgData) return;
+				[
+					element.src,
+					element.srcset,
+					element.alt
+				] = [
+					imgData.tiny,
+					`${imgData.tiny} 50w, ${imgData.small} 300w, ${imgData.medium} 1024w`,
+					imgData['image-alt-text']
+				]
+		}
+	isTaxonomyField(item, field) {
+		if (!Object.hasOwn(item, 'taxonomies') || Object.keys(item.taxonomies).length === 0) {
+			return false;
+		}
+
+		return Object.keys(item.taxonomies).includes(field);
+	}
+	formatTaxonomyField(element, item, field, value) {
+		if (element.tagName !== 'UL' || !element.querySelector('li')) return;
+		let values = this.splitIDs(value);
+		if (values.length === 0) {
+			element.remove();
+		}
+		let listItem = element.querySelector('li');
+		for (let termID of values) {
+			let term = item.taxonomies[field][termID]??false;
+			if (!term) continue;
+			let termItem = listItem.cloneNode(true);
+			let link = termItem.querySelector('a');
+			if (!link) continue;
+
+			[
+				link.href,
+				link.title,
+				link.textContent
+			] = [
+				term.url,
+				`See more ${term.title}`,
+				term.title
+			];
+			element.append(termItem);
+		}
+		listItem.remove();
+	}
+	isTimeField(el) {
+		return el.tagName === 'TIME' || el.querySelector('time') !== null;
+	}
+	formatTimeField(element, value) {
+		if (element.tagName !== 'TIME') {
+			element = element.querySelector('time');
+			if (!element) return;
+		}
+		element.setAttribute('datetime', value);
+		element.textContent = window.formatTimeAgo(value, 'F Y');
+	}
+	formatField(element, value) {
+		element.textContent = value;
+	}
+
+	addTimelineElements(item, template) {
 		let [
-			main,
-			link,
-			beforeImg,
-			afterImg,
-			afterText,
+			afterEl,
+			number,
 			started,
-			lastTreated,
-			total,
-			termList,
-			timeline
+			last
 		] = [
-			template,
-			template.querySelector('a'),
-			template.querySelector('img.before'),
-			template.querySelector('img.after'),
-			template.querySelector('summary span:last-of-type'),
-			template.querySelector('p.started time'),
-			template.querySelector('p.updated time'),
-			template.querySelector('p.total b'),
-			template.querySelector('.term-list'),
-			Object.values(item.fields.order)
+			template.querySelector('span.after-text'),
+			template.querySelector('[data-field="number"] b'),
+			template.querySelector('[data-field="started"] time'),
+			template.querySelector('[data-field="updated"] time')
 		];
-		let numberTreatments = timeline.length - 1;
-		let beforeImgData = item.images[timeline[0]['post_thumbnail']];
-		let afterImgData = item.images[timeline[numberTreatments]['post_thumbnail']];
 
-		[
-			main.dataset.id,
-			link.href,
-			beforeImg.src,
-			beforeImg.dataset.small,
-			beforeImg.dataset.medium,
-			afterImg.src,
-			afterImg.dataset.small,
-			afterImg.dataset.medium,
-			afterText.textContent,
-			started.textContent,
-			lastTreated.textContent,
-			total.textContent
-		] = [
-			item.id,
-			item.url,
-			beforeImgData['tiny'],
-			beforeImgData.small,
-			beforeImgData.medium,
-			afterImgData['tiny'],
-			afterImgData.small,
-			afterImgData.medium,
-			`${afterText.textContent} ${numberTreatments} Tx`,
-			timeline[0].date??item.date,
-			timeline[numberTreatments].date??'',
-			`${numberTreatments} Treatments`
-		];
-		return template;
+		if (afterEl) {
+			afterEl.textContent = `After ${item.fields.number} Tx`;
+		}
+		if (number) {
+			number.textContent = item.fields.number;
+		}
+		if (started) {
+			this.formatTimeField(started, item.fields.timeline[0]['post_date']);
+		}
+		if (last) {
+			this.formatTimeField(last, item.fields.timeline[item.fields.timeline.length - 1]['post_date']);
+		}
 	}
 
 	removePlaceholders() {

--
Gitblit v1.10.0