From 9d4ab5afcf1c839d4d9d5972311e9344fdf3f319 Mon Sep 17 00:00:00 2001 From: Jimmy Cai Date: Sun, 12 Jun 2022 12:10:17 +0000 Subject: feat: upgrade to PhotoSwipe v5 --- assets/ts/gallery.ts | 240 +++++++-------------- assets/ts/main.ts | 2 - .../partials/article/components/photoswipe.html | 88 ++------ 3 files changed, 93 insertions(+), 237 deletions(-) diff --git a/assets/ts/gallery.ts b/assets/ts/gallery.ts index 9840f1e..e0124d1 100644 --- a/assets/ts/gallery.ts +++ b/assets/ts/gallery.ts @@ -1,186 +1,92 @@ -declare global { - interface Window { - PhotoSwipe: any; - PhotoSwipeUI_Default: any - } -} +const wrap = (figures: HTMLElement[]) => { + const galleryContainer = document.createElement('div'); + galleryContainer.className = 'gallery'; -interface PhotoSwipeItem { - w: number; - h: number; - src: string; - msrc: string; - title?: string; - el: HTMLElement; -} + const parentNode = figures[0].parentNode, + first = figures[0]; -class StackGallery { - private galleryUID: number; - private items: PhotoSwipeItem[] = []; - - constructor(container: HTMLElement, galleryUID = 1) { - if (window.PhotoSwipe == undefined || window.PhotoSwipeUI_Default == undefined) { - console.error("PhotoSwipe lib not loaded."); - return; - } + parentNode.insertBefore(galleryContainer, first) - this.galleryUID = galleryUID; - - StackGallery.createGallery(container); - this.loadItems(container); - this.bindClick(); + for (const figure of figures) { + galleryContainer.appendChild(figure); } +} - private loadItems(container: HTMLElement) { - this.items = []; - - const figures = container.querySelectorAll('figure.gallery-image'); - - for (const el of figures) { - const figcaption = el.querySelector('figcaption'), - img = el.querySelector('img'); - - let aux: PhotoSwipeItem = { - w: parseInt(img.getAttribute('width')), - h: parseInt(img.getAttribute('height')), - src: img.src, - msrc: img.getAttribute('data-thumb') || img.src, - el: el - } - - if (figcaption) { - aux.title = figcaption.innerHTML; - } - - this.items.push(aux); +export default (container: HTMLElement) => { + /// The process of wrapping image with figure tag is done using JavaScript instead of only Hugo markdown render hook + /// because it can not detect whether image is being wrapped by a link or not + /// and it lead to a invalid HTML construction (
) + const images = container.querySelectorAll('img.gallery-image') as NodeListOf; + for (const img of Array.from(images)) { + /// Images are wrapped with figure tag if the paragraph has only images without texts + /// This is done to allow inline images within paragraphs + const paragraph = img.closest('p'); + + if (!paragraph || !container.contains(paragraph)) continue; + + if (paragraph.textContent.trim() == '') { + /// Once we insert figcaption, this check no longer works + /// So we add a class to paragraph to mark it + paragraph.classList.add('no-text'); } - } - - public static createGallery(container: HTMLElement) { - /// The process of wrapping image with figure tag is done using JavaScript instead of only Hugo markdown render hook - /// because it can not detect whether image is being wrapped by a link or not - /// and it lead to a invalid HTML construction (
) - - const images = container.querySelectorAll('img.gallery-image'); - for (const img of Array.from(images)) { - /// Images are wrapped with figure tag if the paragraph has only images without texts - /// This is done to allow inline images within paragraphs - const paragraph = img.closest('p'); - - if (!paragraph || !container.contains(paragraph)) continue; - - if (paragraph.textContent.trim() == '') { - /// Once we insert figcaption, this check no longer works - /// So we add a class to paragraph to mark it - paragraph.classList.add('no-text'); - } - - let isNewLineImage = paragraph.classList.contains('no-text'); - if (!isNewLineImage) continue; - const hasLink = img.parentElement.tagName == 'A'; + let isNewLineImage = paragraph.classList.contains('no-text'); + if (!isNewLineImage) continue; - let el: HTMLElement = img; - /// Wrap image with figure tag, with flex-grow and flex-basis values extracted from img's data attributes - const figure = document.createElement('figure'); - figure.style.setProperty('flex-grow', img.getAttribute('data-flex-grow') || '1'); - figure.style.setProperty('flex-basis', img.getAttribute('data-flex-basis') || '0'); - if (hasLink) { - /// Wrap if it exists - el = img.parentElement; - } - el.parentElement.insertBefore(figure, el); - figure.appendChild(el); + const hasLink = img.parentElement.tagName == 'A'; - /// Add figcaption if it exists - if (img.hasAttribute('alt')) { - const figcaption = document.createElement('figcaption'); - figcaption.innerText = img.getAttribute('alt'); - figure.appendChild(figcaption); - } - - /// Wrap img tag with tag if image was not wrapped by tag - if (!hasLink) { - figure.className = 'gallery-image'; - - const a = document.createElement('a'); - a.href = img.src; - a.setAttribute('target', '_blank'); - img.parentNode.insertBefore(a, img); - a.appendChild(img); - } + let el: HTMLElement = img; + /// Wrap image with figure tag, with flex-grow and flex-basis values extracted from img's data attributes + const figure = document.createElement('figure'); + figure.style.setProperty('flex-grow', img.getAttribute('data-flex-grow') || '1'); + figure.style.setProperty('flex-basis', img.getAttribute('data-flex-basis') || '0'); + if (hasLink) { + /// Wrap if it exists + el = img.parentElement; } - - const figuresEl = container.querySelectorAll('figure.gallery-image'); - - let currentGallery = []; - - for (const figure of figuresEl) { - if (!currentGallery.length) { - /// First iteration - currentGallery = [figure]; - } - else if (figure.previousElementSibling === currentGallery[currentGallery.length - 1]) { - /// Adjacent figures - currentGallery.push(figure); - } - else if (currentGallery.length) { - /// End gallery - StackGallery.wrap(currentGallery); - currentGallery = [figure]; - } + el.parentElement.insertBefore(figure, el); + figure.appendChild(el); + + /// Add figcaption if it exists + if (img.hasAttribute('alt')) { + const figcaption = document.createElement('figcaption'); + figcaption.innerText = img.getAttribute('alt'); + figure.appendChild(figcaption); } - if (currentGallery.length > 0) { - StackGallery.wrap(currentGallery); + /// Wrap img tag with tag if image was not wrapped by tag + if (!hasLink) { + figure.className = 'gallery-image'; + + const a = document.createElement('a'); + a.href = img.src; + a.setAttribute('target', '_blank'); + a.setAttribute('data-pswp-width', img.width.toString()); + a.setAttribute('data-pswp-height', img.height.toString()); + img.parentNode.insertBefore(a, img); + a.appendChild(img); } } - /** - * Wrap adjacent figure tags with div.gallery - * @param figures - */ - public static wrap(figures: HTMLElement[]) { - const galleryContainer = document.createElement('div'); - galleryContainer.className = 'gallery'; - - const parentNode = figures[0].parentNode, - first = figures[0]; - - parentNode.insertBefore(galleryContainer, first) - - for (const figure of figures) { - galleryContainer.appendChild(figure); + const figuresEl = container.querySelectorAll('figure.gallery-image') as NodeListOf; + let currentGallery = []; + for (const figure of Array.from(figuresEl)) { + if (!currentGallery.length) { + /// First iteration + currentGallery = [figure]; } - } - - public open(index: number) { - const pswp = document.querySelector('.pswp') as HTMLDivElement; - const ps = new window.PhotoSwipe(pswp, window.PhotoSwipeUI_Default, this.items, { - index: index, - galleryUID: this.galleryUID, - getThumbBoundsFn: (index) => { - const thumbnail = this.items[index].el.getElementsByTagName('img')[0], - pageYScroll = window.pageYOffset || document.documentElement.scrollTop, - rect = thumbnail.getBoundingClientRect(); - - return { x: rect.left, y: rect.top + pageYScroll, w: rect.width }; - } - }); - - ps.init(); - } - - private bindClick() { - for (const [index, item] of this.items.entries()) { - const a = item.el.querySelector('a'); - - a.addEventListener('click', (e) => { - e.preventDefault(); - this.open(index); - }) + else if (figure.previousElementSibling === currentGallery[currentGallery.length - 1]) { + /// Adjacent figures + currentGallery.push(figure); + } + else if (currentGallery.length) { + /// End gallery + wrap(currentGallery); + currentGallery = [figure]; } } -} -export default StackGallery; \ No newline at end of file + if (currentGallery.length > 0) { + wrap(currentGallery); + } +}; \ No newline at end of file diff --git a/assets/ts/main.ts b/assets/ts/main.ts index 5370b2c..0668c7c 100644 --- a/assets/ts/main.ts +++ b/assets/ts/main.ts @@ -5,7 +5,6 @@ * @website: https://jimmycai.com * @link: https://github.com/CaiJimmy/hugo-theme-stack */ -import StackGallery from "ts/gallery"; import StackCodeBlock from "ts/codeblock"; import menu from 'ts/menu'; import createElement from 'ts/createElement'; @@ -22,7 +21,6 @@ let Stack = { const articleContent = document.querySelector('.article-content') as HTMLElement; if (articleContent) { - new StackGallery(articleContent); setupSmoothAnchors(); setupScrollspy(); } diff --git a/layouts/partials/article/components/photoswipe.html b/layouts/partials/article/components/photoswipe.html index c33ff49..425825c 100644 --- a/layouts/partials/article/components/photoswipe.html +++ b/layouts/partials/article/components/photoswipe.html @@ -1,68 +1,20 @@ - - - -{{- partial "helper/external" (dict "Context" . "Namespace" "PhotoSwipe") -}} \ No newline at end of file +{{- $opts := dict "minify" hugo.IsProduction "format" "esm" -}} +{{- $galleryScript := resources.Get "ts/gallery.ts" | js.Build $opts -}} + + + + \ No newline at end of file -- cgit v1.2.3