Add back/forward buttons to switch between images in tasks

This commit is contained in:
Olivia Godone-Maresca 2023-04-03 19:35:37 -04:00
parent 75445185c4
commit 88d415d3f9
2 changed files with 129 additions and 15 deletions

View File

@ -1,6 +1,28 @@
"use strict" "use strict"
/**
* @typedef {object} ImageModalRequest
* @property {string} src
* @property {ImageModalRequest | () => ImageModalRequest | undefined} previous
* @property {ImageModalRequest | () => ImageModalRequest | undefined} next
*/
/**
* @type {(() => (string | ImageModalRequest) | string | ImageModalRequest) => {}}
*/
const imageModal = (function() { const imageModal = (function() {
const backElem = createElement(
'i',
undefined,
['fa-solid', 'fa-arrow-left', 'tertiaryButton'],
)
const forwardElem = createElement(
'i',
undefined,
['fa-solid', 'fa-arrow-right', 'tertiaryButton'],
)
const zoomElem = createElement( const zoomElem = createElement(
'i', 'i',
undefined, undefined,
@ -13,7 +35,7 @@ const imageModal = (function() {
['fa-solid', 'fa-xmark', 'tertiaryButton'], ['fa-solid', 'fa-xmark', 'tertiaryButton'],
) )
const menuBarElem = createElement('div', undefined, 'menu-bar', [zoomElem, closeElem]) const menuBarElem = createElement('div', undefined, 'menu-bar', [backElem, forwardElem, zoomElem, closeElem])
const imageContainer = createElement('div', undefined, 'image-wrapper') const imageContainer = createElement('div', undefined, 'image-wrapper')
@ -63,15 +85,87 @@ const imageModal = (function() {
() => setZoomLevel(imageContainer.querySelector('img')?.classList?.contains('natural-zoom')), () => setZoomLevel(imageContainer.querySelector('img')?.classList?.contains('natural-zoom')),
) )
const close = () => { const state = {
previous: undefined,
next: undefined,
}
const clear = () => {
imageContainer.innerHTML = '' imageContainer.innerHTML = ''
Object.keys(state).forEach(key => delete state[key])
}
const close = () => {
clear()
modalElem.classList.remove('active') modalElem.classList.remove('active')
document.body.style.overflow = 'initial' document.body.style.overflow = 'initial'
} }
window.addEventListener('keydown', (e) => { /**
if (e.key === 'Escape' && modalElem.classList.contains('active')) { * @param {() => (string | ImageModalRequest) | string | ImageModalRequest} optionsFactory
*/
function init(optionsFactory) {
if (!optionsFactory) {
close() close()
return
}
clear()
const options = typeof optionsFactory === 'function' ? optionsFactory() : optionsFactory
const src = typeof options === 'string' ? options : options.src
const imgElem = createElement('img', { src }, 'natural-zoom')
imageContainer.appendChild(imgElem)
modalElem.classList.add('active')
document.body.style.overflow = 'hidden'
setZoomLevel(false)
if (typeof options === 'object' && options.previous) {
state.previous = options.previous
backElem.style.display = 'unset'
} else {
backElem.style.display = 'none'
}
if (typeof options === 'object' && options.next) {
state.next = options.next
forwardElem.style.display = 'unset'
} else {
forwardElem.style.display = 'none'
}
}
const back = () => {
if (state.previous) {
init(state.previous)
} else {
backElem.style.display = 'none'
}
}
const forward = () => {
if (state.next) {
init(state.next)
} else {
forwardElem.style.display = 'none'
}
}
window.addEventListener('keydown', (e) => {
if (modalElem.classList.contains('active')) {
switch (e.key) {
case 'Escape':
close()
break
case 'ArrowLeft':
back()
break
case 'ArrowRight':
forward()
break
}
} }
}) })
window.addEventListener('click', (e) => { window.addEventListener('click', (e) => {
@ -86,15 +180,12 @@ const imageModal = (function() {
} }
}) })
return (optionsFactory) => { backElem.addEventListener('click', back)
const options = typeof optionsFactory === 'function' ? optionsFactory() : optionsFactory
const src = typeof options === 'string' ? options : options.src
// TODO center it if < window size forwardElem.addEventListener('click', forward)
const imgElem = createElement('img', { src }, 'natural-zoom')
imageContainer.appendChild(imgElem) /**
modalElem.classList.add('active') * @param {() => (string | ImageModalRequest) | string | ImageModalRequest} optionsFactory
document.body.style.overflow = 'hidden' */
setZoomLevel(false) return (optionsFactory) => init(optionsFactory)
}
})() })()

View File

@ -398,7 +398,30 @@ function showImages(reqBody, res, outputContainer, livePreview) {
if ('seed' in result && !imageElem.hasAttribute('data-seed')) { if ('seed' in result && !imageElem.hasAttribute('data-seed')) {
const imageExpandBtn = imageItemElem.querySelector('.imgExpandBtn') const imageExpandBtn = imageItemElem.querySelector('.imgExpandBtn')
imageExpandBtn.addEventListener('click', function() { imageExpandBtn.addEventListener('click', function() {
imageModal(imageElem.src) function previousImage(img) {
const allImages = Array.from(outputContainer.parentNode.querySelectorAll('.imgItem img'))
const index = allImages.indexOf(img)
return allImages.slice(0, index).reverse()[0]
}
function nextImage(img) {
const allImages = Array.from(outputContainer.parentNode.querySelectorAll('.imgItem img'))
const index = allImages.indexOf(img)
return allImages.slice(index + 1)[0]
}
function imageModalParameter(img) {
const previousImg = previousImage(img)
const nextImg = nextImage(img)
return {
src: img.src,
previous: previousImg ? () => imageModalParameter(previousImg) : undefined,
next: nextImg ? () => imageModalParameter(nextImg) : undefined,
}
}
imageModal(imageModalParameter(imageElem))
}) })
const req = Object.assign({}, reqBody, { const req = Object.assign({}, reqBody, {