From 75a097a018a0090f5902758353c578fce4aa2a25 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sat, 23 May 2026 18:43:42 +0000
Subject: [PATCH] =CustomBlocks.php overhaul relatively complete. Also refactored the gallery in gallery.min.js and the jvbRenderGallery.

---
 assets/js/concise/Gallery.js |  154 ++++++++++++++++++++++++---------------------------
 1 files changed, 73 insertions(+), 81 deletions(-)

diff --git a/assets/js/concise/Gallery.js b/assets/js/concise/Gallery.js
index 07eaef1..948ab0f 100644
--- a/assets/js/concise/Gallery.js
+++ b/assets/js/concise/Gallery.js
@@ -26,14 +26,14 @@
 		this.initModal();
 		this.initListeners();
 		this.initSubscribers();
-
+		console.log('Gallery loaded...');
 	}
 	/*********************************************************************
 	 ELEMENTS
 	 *********************************************************************/
 	initElements() {
 		this.elements = {
-			imageSelector: 'a.open-gallery',
+			imageSelector: 'img[data-gallery]',
 			gallery: {
 				modal: 'dialog.gallery',
 				wrap: '.wrap',
@@ -56,25 +56,24 @@
 				closeMessage: 'Closed Gallery',
 			}
 		);
-		this.modal.subscribe((event, data) => {
+		this.modal.subscribe((event) => {
 			if (event === 'modal-close') {
 				this.toggleGallery(false);
 			}
 		});
 	}
 	buildGalleryItems(filtered = null) {
-		let selector = filtered ? `[data-opens="${filtered}"]` : this.elements.imageSelector;
+		let selector = filtered ? `[data-gallery="${filtered}"]` : this.elements.imageSelector;
 		this.items = Array.from(document.querySelectorAll(selector))
 			.map((img, index) => {
-				let image = img.querySelector('img');
-
 				return {
 					id: img.dataset.id||index,
-					small: image.dataset.small || img.src,
-					medium: image.dataset.medium || img.src,
-					full: image.dataset.full || img.src,
-					alt: image.alt || '',
-					element: image
+					srcset: img.srcset || img.src, // Clone the srcset from page
+					sizes: img.sizes || '100vw',
+					src: img.currentSrc || img.src, // Fallback
+					full: img.dataset.full || img.src,
+					alt: img.alt || '',
+					element: img
 				};
 			});
 	}
@@ -95,9 +94,10 @@
 		let target = window.targetCheck(e, this.elements.imageSelector);
 		if (target && !this.modal.isOpen) {
 			e.preventDefault();
-			this.buildGalleryItems((Object.hasOwn(target.dataset, 'opens')) ? target.dataset.opens : null);
+			this.buildGalleryItems(target.dataset.gallery || null);
 
-			this.index = this.items.findIndex(item => item.element === target.querySelector('img'));
+			// Target is now the img element itself
+			this.index = this.items.findIndex(item => item.element === target);
 			this.toggleGallery(true);
 		} else if (this.modal.isOpen) {
 			if (window.targetCheck(e, this.elements.gallery.nextButton)) {
@@ -140,6 +140,9 @@
 	}
 
 	onPointerDown(e) {
+		// Always prevent default to stop browser's native image drag
+		e.preventDefault();
+
 		this.swipe.startX = e.clientX;
 		this.swipe.startY = e.clientY;
 		this.ui.gallery.image.setPointerCapture(e.pointerId);
@@ -177,6 +180,8 @@
 			this.zoom.panning = true;
 			this.zoom.startX = e.clientX - this.zoom.x;
 			this.zoom.startY = e.clientY - this.zoom.y;
+			// Change cursor to grabbing
+			this.ui.gallery.image.style.cursor = 'grabbing';
 		}
 	}
 
@@ -188,17 +193,12 @@
 		// PINCH (two pointers)
 		if (this.activePointers.size === 2) {
 			const pts = [...this.activePointers.values()];
-			const dist = Math.hypot(
-				pts[0].x - pts[1].x,
-				pts[0].y - pts[1].y
-			);
+			const dist = Math.hypot(pts[0].x - pts[1].x, pts[0].y - pts[1].y);
+			const increment = this.pinchStartScale * (dist / this.pinchStartDist) - this.zoom.scale;
 
-			const newScale = this.pinchStartScale * (dist / this.pinchStartDist);
-			const increment = newScale - this.zoom.scale;
-
-			// Zoom centered (NO midpoint)
-			this.handleZoom(increment);
-
+			const midX = (pts[0].x + pts[1].x) / 2;  // ← anchor to finger midpoint
+			const midY = (pts[0].y + pts[1].y) / 2;
+			this.handleZoom(increment, midX, midY);
 			return;
 		}
 
@@ -211,30 +211,27 @@
 	}
 
 	onPointerUp(e) {
+		const last = this.activePointers.get(e.pointerId); // grab before delete
 		this.activePointers.delete(e.pointerId);
 
 		if (this.activePointers.size < 2) {
 			this.pinchStartDist = 0;
 		}
 
-		if (!this.zoom.panning && this.activePointers.size === 0) {
-			// End of tap or swipe - detect swipe
-			this.swipe.endX = e.clientX;
-			this.swipe.endY = e.clientY;
-			const dx = this.swipe.endX - this.swipe.startX;
-			const dy = this.swipe.endY - this.swipe.startY;
+		if (this.zoom.scale <= 1 && !this.zoom.panning && this.activePointers.size === 0) {
+			const endX = last?.x ?? e.clientX; // use tracked position, fall back to event
+			const endY = last?.y ?? e.clientY;
+			const dx = endX - this.swipe.startX;
+			const dy = endY - this.swipe.startY;
 
-			if (Math.abs(dx) > this.zoom.threshold) {
-				if (dx > 0) {
-					console.log('Swipe right');
-					this.prevElement();
-				} else {
-					console.log('Swipe left');
-					this.nextElement();
-				}
+			if (Math.abs(dx) > this.zoom.threshold && Math.abs(dx) > Math.abs(dy)) {
+				dx > 0 ? this.prevElement() : this.nextElement();
 			}
+		}
 
+		if (this.activePointers.size === 0) {
 			this.zoom.panning = false;
+			this.ui.gallery.image.style.cursor = this.zoom.scale > 1 ? 'grab' : 'default';
 		}
 	}
 
@@ -249,45 +246,6 @@
 		this.handleZoom(increment, e.clientX, e.clientY);
 	}
 
-	clampPan() {
-		const BORDER = 32; // 2rem
-		const wrap = this.ui.gallery.wrap;
-		if (!wrap) return;
-
-		const wrapRect = wrap.getBoundingClientRect();
-
-		// MUST use natural dimensions
-		const naturalW = 1920;
-		const naturalH = 1920;
-
-		// But they must be constrained by how the CSS fits them (max-width: 90vw, max-height: 85vh)
-		// So compute the base display size:
-		const displayRatio = Math.min(
-			wrapRect.width / naturalW,
-			wrapRect.height / naturalH
-		);
-
-		const baseWidth  = naturalW * displayRatio;
-		const baseHeight = naturalH * displayRatio;
-
-		const scaledWidth  = baseWidth  * this.zoom.scale;
-		const scaledHeight = baseHeight * this.zoom.scale;
-
-		// Allowed pan range
-		const minX = wrapRect.width - scaledWidth - BORDER;
-		const maxX = BORDER;
-
-		const minY = wrapRect.height - scaledHeight - BORDER;
-		const maxY = BORDER;
-
-		// clamp
-		this.zoom.x = Math.min(maxX, Math.max(minX, this.zoom.x));
-		this.zoom.y = Math.min(maxY, Math.max(minY, this.zoom.y));
-	}
-
-
-
-
 	handleZoom(increment, clientX=null, clientY=null) {
 		const oldScale = this.zoom.scale;
 		let newScale = oldScale + increment;
@@ -318,9 +276,18 @@
 	}
 
 	applyTransform() {
-		// this.clampPan();
+		this.clampPan();
 		const img = this.ui.gallery.image;
 		img.style.transform = `translate(${this.zoom.x}px, ${this.zoom.y}px) scale(${this.zoom.scale})`;
+		// Update cursor based on zoom level
+		img.style.cursor = this.zoom.scale > 1 ? 'grab' : 'default';
+	}
+	clampPan() {
+		const img = this.ui.gallery.image;
+		const excessX = Math.max(0, (img.offsetWidth  * this.zoom.scale - window.innerWidth)  / 2);
+		const excessY = Math.max(0, (img.offsetHeight * this.zoom.scale - window.innerHeight) / 2);
+		this.zoom.x = Math.max(-excessX, Math.min(excessX, this.zoom.x));
+		this.zoom.y = Math.max(-excessY, Math.min(excessY, this.zoom.y));
 	}
 	resetZoom() {
 		this.zoom.scale = 1;
@@ -344,10 +311,13 @@
 	/**
 	 *
 	 * @param {boolean} open
-	 * @param {null|number} index
 	 */
-	toggleGallery(open, index= null) {
+	toggleGallery(open) {
 		if (open) {
+			// Disable native image dragging
+			this.ui.gallery.image.draggable = false;
+			this.ui.gallery.image.style.userSelect = 'none';
+
 			this.ui.gallery.image.addEventListener("pointerdown", this.pointerDownHandler);
 			this.ui.gallery.image.addEventListener("pointermove", this.pointerMoveHandler);
 			this.ui.gallery.image.addEventListener("pointerup", this.pointerUpHandler);
@@ -406,8 +376,30 @@
 	updateDisplay() {
 		const item = this.items[this.index];
 		if (!item) return;
-		this.ui.gallery.image.src = item.full;
-		this.ui.gallery.image.alt = item.alt;
+
+		const galleryImg = this.ui.gallery.image;
+
+		// Set srcset first - browser uses cached version instantly (no wait)
+		if (item.srcset) {
+			galleryImg.srcset = item.srcset;
+			galleryImg.sizes = item.sizes;
+		}
+		galleryImg.src = item.src; // Fallback
+		galleryImg.alt = item.alt;
+
+		// ALWAYS load full resolution for zoom quality
+		if (item.full && item.full !== item.src) {
+			const fullImg = new Image();
+			fullImg.onload = () => {
+				if (this.items[this.index] === item) {
+					galleryImg.src = item.full;
+					galleryImg.removeAttribute('srcset'); // Switch to full res directly
+					galleryImg.removeAttribute('sizes');
+				}
+			};
+			fullImg.src = item.full;
+		}
+
 		this.ui.gallery.counter.textContent = `${this.index + 1} / ${this.items.length}`;
 
 		this.ui.gallery.prevButton.disabled = this.items.length <= 1;

--
Gitblit v1.10.0