// Modified from https://github.com/mrhuo/image-viewer class ImageViewer { constructor() { this.imageList = []; this.fromArtwork = false; this.artworkFileIndex = -1; this.currentIndex = -1; this.oldURI = ""; this.SettingSubmitting = false; this.preview = document.getElementById("preview"); this.sidebar = document.getElementById("sidebar"); this.imageWrapper = document.getElementById("image-wrapper"); this.previewImg = document.getElementById("preview-img"); this.navControls = document.getElementById("nav-controls"); this.prevBtn = document.getElementById("prev-btn"); this.nextBtn = document.getElementById("next-btn"); this.infoBox = document.getElementById("info-box"); this.imageCaption = document.getElementById("image-caption"); this.imageIndex = document.getElementById("image-index"); this.imageInfo = document.getElementById("image-info"); this.downloadBtn = document.getElementById("download-btn"); this.deleteBtn = document.getElementById("delete-btn"); this.sidebarBtn = document.getElementById("sidebar-btn"); this.sidebarContent = document.getElementById("sidebar-content"); this.sidebarImageArtworkLink = document.getElementById("img-artwork-a"); this.sidebarImageAuthor = document.getElementById("img-author"); this.sidebarImageSource = document.getElementById("img-source"); this.sidebarImageTag = document.getElementById("img-tag"); this.sidebarImageInfo = document.getElementById("img-info"); this.sidebarImageSetting = document.getElementById("img-setting"); this.sidebarImageSettingSselect = document.getElementById("sensitive-select"); this.sidebarImageSettingPselect = document.getElementById("private-select"); this.sidebarImageSettingButton = document.getElementById("setting-button"); this.sidebarImageSettingPostInput = document.getElementById("post-input"); this.sidebarImageSettingPostButton = document.getElementById("post-button"); this.sidebarImageSettingUploadFileButton = document.getElementById("upload-file-button"); this.sidebarImageSettingUploadURLInput = document.getElementById("upload-url-input"); this.sidebarImageSettingUploadButton = document.getElementById("upload-button"); let on = false; let status = localStorage.getItem("sidebar_on") if (status) { if (status === "true" && window.innerWidth > 640) { on = true; } } else if (window.innerWidth > 1600) { on = true; } if (on) this.openSidebar(); if (document.cookie.includes("_trpic_user")) { this.deleteBtn.style.display = "flex"; this.sidebarImageSetting.style.display = "block"; } this.imageWrapper.addEventListener('wheel', this.wheel, { passive: false }) this.imageWrapper.addEventListener('pointerdown', this.down) this.imageWrapper.addEventListener('pointermove', this.move) this.imageWrapper.addEventListener('pointerup', this.up) this.imageWrapper.addEventListener('pointercancel', this.up) this.prevBtn.addEventListener("click", this.showPrevImage.bind(this)); this.nextBtn.addEventListener("click", this.showNextImage.bind(this)); document.addEventListener("keydown", this.handleKeyDown.bind(this)); this.downloadBtn.addEventListener("click", this.downloadImage.bind(this)); this.deleteBtn.addEventListener("click", this.deleteImage.bind(this)); this.sidebarBtn.addEventListener("click", this.toggleSidebar.bind(this)); this.sidebarImageSettingSselect.addEventListener("change", this.updateSettingButtonBackground.bind(this)); this.sidebarImageSettingPselect.addEventListener("change", this.updateSettingButtonBackground.bind(this)); this.sidebarImageSettingButton.addEventListener("click", this.patchArtwork.bind(this)); this.sidebarImageSettingPostButton.addEventListener("click", this.postSource.bind(this)); this.sidebarImageSettingUploadButton.addEventListener("click", this.postArtworkFile.bind(this)); this.state = { x: 0, y: 0, scale: 1, } this.tap = { startX: 0, startY: 0, moved: false, isMultiTouch: false, } this.input = { pointers: new Map(), wheel: null, dirty: false, } this.prevPan = null this.prevPinch = null } down = (e) => { this.imageWrapper.style.cursor = "grabbing" this.previewImg.style.willChange = "transform" this.imageWrapper.setPointerCapture(e.pointerId) this.input.pointers.set(e.pointerId, { x: e.clientX, y: e.clientY, }) if (this.input.pointers.size === 1) { this.tap.startX = e.clientX this.tap.startY = e.clientY this.tap.moved = false this.tap.isMultiTouch = false } else { this.tap.isMultiTouch = true } this.input.dirty = true } move = (e) => { const p = this.input.pointers.get(e.pointerId) if (!p) return p.x = e.clientX p.y = e.clientY const moveDist = Math.hypot( e.clientX - this.tap.startX, e.clientY - this.tap.startY ) if (moveDist > 5) { this.tap.moved = true } this.input.dirty = true } up = (e) => { this.imageWrapper.style.cursor = "" this.previewImg.style.willChange = "" this.input.pointers.delete(e.pointerId) if (this.input.pointers.size === 0 && !this.tap.moved && !this.tap.isMultiTouch) this.closePreview(); this.input.dirty = true } wheel = (e) => { e.preventDefault() this.input.wheel = { x: e.clientX, y: e.clientY, delta: e.deltaY, } this.input.dirty = true } loop = () => { this.update() if (this.preview.style.display == "flex") requestAnimationFrame(this.loop); } update() { if (!this.input.dirty) return this.input.dirty = false const pts = [...this.input.pointers.values()] if (this.input.wheel) { const { x, y, delta } = this.input.wheel const scaleFactor = Math.exp(-delta * 0.001) this.zoomAt(x, y, scaleFactor) this.input.wheel = null } if (pts.length === 1) { this.pan(pts[0]) } else if (pts.length >= 2) { this.pinch(pts[0], pts[1]) } if (pts.length < 2) this.prevPinch = null if (pts.length !== 1) this.prevPan = null this.render() } pan(p) { if (!this.prevPan) { this.prevPan = { ...p } return } this.state.x += p.x - this.prevPan.x this.state.y += p.y - this.prevPan.y this.prevPan = { ...p } } pinch(p1, p2) { const center = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2, } const dist = Math.hypot(p1.x - p2.x, p1.y - p2.y) if (!this.prevPinch) { this.prevPinch = { center, dist } return } const scaleFactor = dist / this.prevPinch.dist this.zoomAt(center.x, center.y, scaleFactor) this.state.x += center.x - this.prevPinch.center.x this.state.y += center.y - this.prevPinch.center.y this.prevPinch = { center, dist } } zoomAt(cx, cy, scaleFactor) { const rect = this.previewImg.getBoundingClientRect() const centerX = rect.left + rect.width / 2 const centerY = rect.top + rect.height / 2 const dx = cx - centerX const dy = cy - centerY const prevScale = this.state.scale let newScale = prevScale * scaleFactor newScale = Math.max(.5, Math.min(8, newScale)) const ratio = newScale / prevScale this.state.x -= dx * (ratio - 1) this.state.y -= dy * (ratio - 1) this.state.scale = newScale } render() { const { x, y, scale } = this.state this.previewImg.style.transform = `translate(${x}px, ${y}px) scale(${scale})` } resetTransform() { this.state.x = 0 this.state.y = 0 this.state.scale = 1 this.render(); } updateSettingButtonBackground() { this.sidebarImageSettingButton.style.backgroundColor = "#99af4c"; } postArtworkFile() { const link = this.sidebarImageSettingUploadURLInput.value; const files = this.sidebarImageSettingUploadFileButton.files; if (link == "" && files.length == 0) { alert("请填入链接或文件"); return; } this.SettingSubmitting = true; this.sidebarImageSettingUploadButton.style.backgroundColor = "rgb(50, 50, 50)"; let artwork; if (this.fromArtwork) { artwork = this.imageList[this.currentIndex]; } else { artwork = this.imageList[this.currentIndex].edges.artwork; } if (link) { const formData = new FormData(); formData.append("link", link); fetch(`/api/artworks/${artwork.id}/files`, { method: "POST", body: formData, }) .then(res => { res.json().then(resjson => { switch (res.status) { case 201: break; case 401: alert("提交失败:需要验证"); break; default: alert(`提交失败:${resjson.msg}: ${resjson.error}`); break; } }) }) .finally(() => { this.sidebarImageSettingUploadButton.style.backgroundColor = "rgb(50, 50, 50)"; this.sidebarImageSettingUploadURLInput.value = ""; this.sidebarImageSettingUploadFileButton.value = ""; this.SettingSubmitting = false; }) .catch(error => { alert(`请求失败: ${error}`); }); } else { for (const file of files) { const formData = new FormData(); formData.append("file", file); fetch(`/api/artworks/${artwork.id}/files`, { method: "POST", body: formData, }) .then(res => { res.json().then(resjson => { switch (res.status) { case 201: break; case 401: alert("提交失败:需要验证"); break; default: alert(`提交失败:${resjson.msg}: ${resjson.error}`); break; } }) }) .finally(() => { this.sidebarImageSettingUploadButton.style.backgroundColor = "rgb(50, 50, 50)"; this.sidebarImageSettingUploadURLInput.value = ""; this.sidebarImageSettingUploadFileButton.value = ""; this.SettingSubmitting = false; }) .catch(error => { alert(`请求失败: ${error}`); }); } } } postSource() { const link = this.sidebarImageSettingPostInput.value; if (link == "" || this.SettingSubmitting == true) return; this.SettingSubmitting = true; this.sidebarImageSettingPostButton.style.backgroundColor = "rgb(50, 80, 80)"; let artwork; if (this.fromArtwork) { artwork = this.imageList[this.currentIndex]; } else { artwork = this.imageList[this.currentIndex].edges.artwork; } const formData = new FormData(); formData.append("link", link); fetch(`/api/artworks/${artwork.id}/posts`, { method: "POST", body: formData, }) .then(res => { res.json().then(resjson => { switch (res.status) { case 200: artwork.edges.posts = resjson.edges.posts; artwork.edges.socials = resjson.edges.socials; artwork.edges.tags = resjson.edges.tags; this.updateInfoBar(); break; case 401: alert("提交失败:需要验证"); break; case 409: if (confirm("此来源已链接到另一个作品,前往查看?")) { window.location.href = `/artworks/${resjson.artwork_id}`; } break; default: alert(`提交失败:${resjson.msg}: ${resjson.error}`); break; } }) }) .finally(() => { this.sidebarImageSettingPostButton.style.backgroundColor = "rgb(50, 50, 50)"; this.sidebarImageSettingPostInput.value = ""; this.SettingSubmitting = false; }) .catch(error => { alert(`请求失败: ${error}`); }); } patchArtwork() { if (this.SettingSubmitting) return; this.SettingSubmitting = true; let artwork; if (this.fromArtwork) { artwork = this.imageList[this.currentIndex]; } else { artwork = this.imageList[this.currentIndex].edges.artwork; } let Svalue = this.sidebarImageSettingSselect.value; if (Svalue < 0 || Svalue > 5) { this.SettingSubmitting = false; return; } let Pvalue = this.sidebarImageSettingPselect.value; const formData = new FormData(); formData.append("private", Pvalue); formData.append("sensitive", Svalue); this.sidebarImageSettingButton.style.backgroundColor = "rgb(50, 80, 80)"; fetch(`/api/artworks/${artwork.id}`, { method: "PATCH", body: formData, }) .then(res => { res.json().then(resjson => { switch (res.status) { case 200: artwork.sensitive = resjson.sensitive ? resjson.sensitive : 0; artwork.private = resjson.private ? true : false; this.updateInfoBar(); break; case 401: alert("提交失败:需要验证"); break; case 409: if (confirm("此来源已链接到另一个作品,前往查看?")) { window.location.href = `/artworks/${resjson.artwork_id}`; } break; default: alert(`提交失败:${resjson.msg}: ${resjson.error}`); break; } }) }) .finally(() => { this.SettingSubmitting = false; setInterval(() => { this.sidebarImageSettingButton.style.backgroundColor = "rgb(50, 50, 50)"; }, 1000) }) .catch(error => { alert(`请求失败: ${error}`); }); } appendFiles(files) { if (files.length === 0) return; if (this.fromArtwork) { this.imageList = []; this.artworkFileIndex = 0; this.currentIndex = 0; } this.imageList.push(...files); this.fromArtwork = false; } appendArtworks(artworks) { if (artworks.length === 0) return; if (!this.fromArtwork) { this.imageList = []; this.currentIndex = 0; } this.imageList.push(...artworks); this.fromArtwork = true; } resetList() { this.imageList = []; this.currentIndex = 0; } deleteArtwork() { let artwork_id; if (this.fromArtwork) { artwork_id = this.imageList[this.currentIndex].id; } else { artwork_id = this.imageList[this.currentIndex].edges.artwork.id; } fetch(`/api/artworks/${artwork_id}`, { method: "DELETE", }) .then((response) => { if (response.ok) { setTimeout(() => { this.closePreview(); resetGallery(); }, 1000); } else { response.json().then((resjson) => { alert(`Failed to delete artwork: ${resjson.msg}`); }); } }) .catch((err) => { console.error(err); alert(`Failed to delete artwork: ${err}`); }); } deleteImage() { let file; if (this.fromArtwork) { file = this.imageList[this.currentIndex].edges.files[this.artworkFileIndex]; } else { file = this.imageList[this.currentIndex]; } if (!confirm(`Are you sure you want to delete this ${file.id_str} image?`)) return; fetch(`/api/files/${file.id_str}`, { method: "DELETE", }) .then((response) => { if (response.ok) { setTimeout(() => { this.closePreview(); resetGallery(); }, 1000); } else { response.json().then((resjson) => { if (resjson.code == 403) { if (confirm(`This is last image of this artwork, are you want to delete this artwork?`)) this.deleteArtwork(); return } alert(`Failed to delete image: ${resjson.msg}`); }); } }) .catch((err) => { console.error(err); alert(`Failed to delete image: ${err}`); }); } downloadImage() { let file; if (this.fromArtwork) { file = this.imageList[this.currentIndex].edges.files[this.artworkFileIndex]; } else { file = this.imageList[this.currentIndex]; } const link = document.createElement("a"); const filename = `${ file.id_str }.${ file.ext }` link.download = `trpic_${filename}`; link.href = `/files/${filename}`; link.click(); link.remove(); } openSidebar() { localStorage.setItem("sidebar_on", true); this.sidebar.style.width = "30vw"; this.sidebar.classList.add("open"); this.navControls.classList.add("min-hide"); this.sidebarBtn.style.backgroundColor = "rgba(105, 105, 105, 0.3)"; } closeSidebar() { localStorage.setItem("sidebar_on", false); this.sidebar.style.width = "0px"; this.sidebar.classList.remove("open"); this.navControls.classList.remove("min-hide"); this.sidebarBtn.style.backgroundColor = ""; } toggleSidebar() { if (this.sidebar.classList.contains("open")) { this.closeSidebar(); } else { this.openSidebar(); } } showImageByIndex(index, prev) { if (index < 0 || index >= this.imageList.length) { return; } if (index === this.imageList.length - 7 && index > prev) { loadMore(); } this.currentIndex = index; let file; if (this.fromArtwork) { file = this.imageList[this.currentIndex].edges.files[this.artworkFileIndex]; } else { file = this.imageList[this.currentIndex]; } this.resetTransform(); const highResSrc = `/files/${file.id_str}.${file.ext}`; const lowResSrc = `/thumbnails/${file.id_str}.jpg`; this.previewImg.src = (file.thumbed && !file.highres_loaded) ? lowResSrc : highResSrc; this.updateInfoBar(); this.updateNavButtons(); this.previewImg.onload = () => { // 如果有高分辨率图片,异步加载并在完成后替换 if (file.thumbed) { this.loadHighResImage(file, highResSrc); } }; this.previewImg.onerror = () => { this.updateInfoBar("Failed to load image"); }; if (this.preview.style.display == "none") { this.preview.style.display = "flex"; this.loop(); } this.infoBox.style.opacity = 0; document.body.style.overflow = "hidden"; document.body.style.touchAction = "none"; gallery.style.opacity = 0.1; } loadHighResImage(file, highResSrc) { this.imageIndex.textContent += " loading..."; const listIndex = this.currentIndex; const fileIndex = this.artworkFileIndex; const highResImg = new Image(); highResImg.onload = () => { this.previewImg.onload = null; // Check if the image index has changed if (this.currentIndex != listIndex || this.artworkFileIndex != fileIndex) return; // High-resolution image loaded, replace current image this.previewImg.src = highResSrc; file.highres_loaded = "true"; this.updateInfoBar(); }; highResImg.onerror = (err) => { if (this.currentIndex != listIndex || this.artworkFileIndex != fileIndex) return; this.updateInfoBar(); alert(`Failed to load high res image: ${err}`) }; highResImg.src = highResSrc; } updateInfoBar() { if (this.fromArtwork) { this.updateInfoBarArtwork(); } else { this.updateInfoBarFile(); } } updateInfoBarArtwork() { const artwork = this.imageList[this.currentIndex]; this.imageIndex.textContent = `${this.currentIndex + 1}${artwork.edges.files.length > 1 ? ` - ${this.artworkFileIndex + 1}` : ""} / ${this.imageList.length}`; this.sidebarImageAuthor.replaceChildren(); if (artwork.edges.socials) { artwork.edges.socials.forEach((social, index) => { const author = document.createElement("p"); if (index > 0) { author.style.borderTop = "1px solid #777"; } const authorLink = document.createElement("a"); authorLink.textContent = `${social.platform}/${social.display_name}`; authorLink.href = social.url; authorLink.target = "_blank"; author.appendChild(authorLink); this.sidebarImageAuthor.appendChild(author); }) } this.sidebarImageSource.replaceChildren(); if (artwork.edges.posts) { artwork.edges.posts.forEach((post, index) => { const source = document.createElement("div"); if (index > 0) { source.style.borderTop = "1px solid #777"; } const link = document.createElement("a"); link.textContent = `${post.platform}/${post.post_id}`; link.href = post.url; link.target = "_blank"; source.appendChild(link); if (post.time) { const time = document.createElement("p"); time.classList.add("time"); time.textContent = post.time.substring(0, 19); source.appendChild(time); } if (post.title) { const title = document.createElement("p"); title.classList.add("title"); title.textContent = post.title; source.appendChild(title); } if (post.text) { const text = document.createElement("p"); text.classList.add("desc"); text.textContent = post.text; // text.innerHTML = post.text; source.appendChild(text); } this.sidebarImageSource.appendChild(source); }) } this.sidebarImageTag.replaceChildren(); if (artwork.edges.tags) { artwork.edges.tags.forEach(tag => { const tagLink = document.createElement("a"); tagLink.textContent = `#${tag.text}`; tagLink.href = `/artworks/?tags=${tag.id}`; this.sidebarImageTag.appendChild(tagLink); }) } const file = artwork.edges.files[this.artworkFileIndex]; const fileRes = document.createElement("p"); fileRes.textContent = `${file.width}*${file.height}px`; const fileInfo = document.createElement("p"); fileInfo.textContent = `${file.size_str} · ${file.ext}`; const id = document.createElement("p"); id.id = "img-id"; id.textContent = `${file.id_str} L${artwork.sensitive ? artwork.sensitive : 0} ${artwork.private ? " (private)" : ""}`; this.sidebarImageInfo.replaceChildren(fileRes, fileInfo, id); if (document.cookie.includes("_trpic_user")) { const a = document.createElement("a"); a.href = `/convert/${file.id_str}`; a.target = "_blank"; a.textContent = `${file.quality ? `${file.quality}% ` : ""}Convert`; this.sidebarImageInfo.appendChild(a); } this.sidebarImageSettingSselect.value = artwork.sensitive ? artwork.sensitive : 0; this.sidebarImageSettingPselect.value = Boolean(artwork.private); this.sidebarImageSettingPselect.style.backgroundColor = artwork.private ? "rgb(80, 70, 50)" : "rgb(50, 80, 50)"; this.sidebarImageArtworkLink.textContent = this.sidebarImageArtworkLink.href = `/artworks/${artwork.id}`; history.replaceState(null, null, `/artworks/${artwork.id}${this.artworkFileIndex > 0 ? `/photo/${this.artworkFileIndex}` : ""}`); } updateInfoBarFile() { const file = this.imageList[this.currentIndex]; const artwork = file.edges.artwork this.imageIndex.textContent = `${this.currentIndex + 1} / ${this.imageList.length}`; this.sidebarImageAuthor.replaceChildren(); if (artwork.edges.socials) { artwork.edges.socials.forEach((social, index) => { const author = document.createElement("p"); if (index > 0) { author.style.borderTop = "1px solid #777"; } const authorLink = document.createElement("a"); authorLink.textContent = `${social.platform}/${social.display_name}`; authorLink.href = social.url; authorLink.target = "_blank"; author.appendChild(authorLink); this.sidebarImageAuthor.appendChild(author); }) } this.sidebarImageSource.replaceChildren(); if (artwork.edges.posts) { artwork.edges.posts.forEach((post, index) => { const source = document.createElement("div"); if (index > 0) { source.style.borderTop = "1px solid #777"; } const link = document.createElement("a"); link.textContent = `${post.platform}/${post.post_id}`; link.href = post.url; link.target = "_blank"; source.appendChild(link); if (post.time) { const time = document.createElement("p"); time.classList.add("time"); time.textContent = post.time.substring(0, 19); source.appendChild(time); } if (post.title) { const title = document.createElement("p"); title.textContent = post.title; source.appendChild(title); } if (post.text) { const text = document.createElement("p"); text.classList.add("desc"); text.textContent = post.text; // text.innerHTML = post.text; source.appendChild(text); } this.sidebarImageSource.appendChild(source); }) } this.sidebarImageTag.replaceChildren(); if (artwork.edges.tags) { artwork.edges.tags.forEach(tag => { const tagLink = document.createElement("a"); tagLink.textContent = `#${tag.text}`; tagLink.href = `/artworks/?tags=${tag.id}`; this.sidebarImageTag.appendChild(tagLink); }) } const fileRes = document.createElement("p"); fileRes.textContent = `${file.width}*${file.height}px`; const fileInfo = document.createElement("p"); fileInfo.textContent = `${file.size_str} · ${file.ext}`; const id = document.createElement("p"); id.id = "img-id"; id.textContent = `${file.id_str} L${artwork.sensitive ? artwork.sensitive : 0 } ${artwork.private ? " (private)" : ""}`; this.sidebarImageInfo.replaceChildren(fileRes, fileInfo, id); if (document.cookie.includes("_trpic_user")) { const a = document.createElement("a"); a.href = `/convert/${file.id_str}`; a.target = "_blank"; a.textContent = `${file.quality ? `${file.quality}% ` : ""}Convert`; this.sidebarImageInfo.appendChild(a); } this.sidebarImageSettingSselect.value = artwork.sensitive ? artwork.sensitive : 0; this.sidebarImageSettingPselect.value = Boolean(artwork.private); this.sidebarImageSettingPselect.style.backgroundColor = artwork.private ? "rgb(80, 70, 50)" : "rgb(50, 80, 50)"; this.sidebarImageArtworkLink.textContent = this.sidebarImageArtworkLink.href = `/artworks/${artwork.id}`; history.replaceState(null, null, `/artworks/${artwork.id}`); } updateNavButtons() { let hasPrev = false; let hasNext = false; if (this.fromArtwork) { hasPrev = this.artworkFileIndex > 0 || this.currentIndex > 0; hasNext = this.artworkFileIndex < this.imageList[this.currentIndex].edges.files.length - 1 || this.currentIndex < this.imageList.length - 1; } else { hasPrev = this.currentIndex > 0; hasNext = this.currentIndex < this.imageList.length - 1; } this.prevBtn.style.opacity = hasPrev ? "1" : "0"; this.prevBtn.style.pointerEvents = hasPrev ? "auto" : "none"; this.nextBtn.style.opacity = hasNext ? "1" : "0"; this.nextBtn.style.pointerEvents = hasNext ? "auto" : "none"; } openPreview(e, img) { if (img.tagName != "IMG") return; e.stopPropagation(); let index; if (this.fromArtwork) { index = this.imageList.findIndex((i) => i.id == img.dataset.artwork_id); this.artworkFileIndex = this.imageList[index].edges.files.findIndex((i) => i.id_str == img.dataset.id_str); } else { index = this.imageList.findIndex((i) => i.id_str === img.dataset.id_str); } if (index !== -1) { this.oldURI = window.location.pathname + window.location.search; if (window.innerWidth <= 640) this.closeSidebar(); this.showImageByIndex(index, 0); } } closePreview() { this.currentIndex = -1; this.infoBox.style.opacity = 1; this.preview.style.display = "none"; document.body.style.overflow = ""; document.body.style.touchAction = ""; gallery.style.opacity = 1; history.replaceState(null, null, this.oldURI); } showNextImage() { if (this.fromArtwork) { if (this.artworkFileIndex < this.imageList[this.currentIndex].edges.files.length - 1) { this.artworkFileIndex++; this.showImageByIndex(this.currentIndex, this.currentIndex); return; } if (this.currentIndex < this.imageList.length - 1) { this.artworkFileIndex = 0; this.showImageByIndex(this.currentIndex + 1, this.currentIndex); } } else { if (this.currentIndex < this.imageList.length - 1) { this.showImageByIndex(this.currentIndex + 1, this.currentIndex); } } } showPrevImage() { if (this.fromArtwork) { if (this.artworkFileIndex > 0) { this.artworkFileIndex--; this.showImageByIndex(this.currentIndex, this.currentIndex); return; } if (this.currentIndex > 0) { this.artworkFileIndex = this.imageList[this.currentIndex - 1].edges.files.length - 1; this.showImageByIndex(this.currentIndex - 1, this.currentIndex); } } else { if (this.currentIndex > 0) { this.showImageByIndex(this.currentIndex - 1, this.currentIndex); } } } handleKeyDown(e) { if (e.key == "Enter") { this.openPreview(e, document.activeElement); return; } if (this.preview.style.display !== "flex") return; if (document.activeElement === this.sidebarImageSettingPostInput || document.activeElement === this.sidebarImageSettingUploadURLInput) return; switch (e.key) { case "Escape": this.closePreview(); break; case "ArrowRight": this.showNextImage(); break; case "ArrowLeft": this.showPrevImage(); break; case "b": if (e.ctrlKey) { this.toggleSidebar(); } break; } } bindClickEvents(img) { img.addEventListener("click", (e) => this.openPreview(e, img)); img.style.cursor = "zoom-in"; } } let imgviewer; document.addEventListener('DOMContentLoaded', () => { imgviewer = new ImageViewer({}) });