hexo-theme-redefine
Version:
Redefine your writing with Hexo Theme Redefine.
2 lines • 15.7 kB
JavaScript
const e={isBigImage:!1,scale:1,fitScale:1,userZoomed:!1,isMouseDown:!1,dragged:!1,currentImgIndex:0,lastMouseX:0,lastMouseY:0,translateX:0,translateY:0,maskDom:null,targetImg:null},i=".markdown-body img, .masonry-item img, #shuoshuo-content img",n={prevButton:null,nextButton:null,closeButton:null},a={toggleButton:null,panel:null,cardsContainer:null,closeButton:null,cardTemplate:null,requestId:0},t=(e,i="")=>{const n=(e=>{if(!e)return null;const i=String(e).split(".").filter(Boolean);let n=window.i18n;for(const e of i){if(!n||"object"!=typeof n)return null;n=n[e]}return n??null})(e);return"string"==typeof n?n:null!=n?String(n):i};let r=[],l=!1;const applyTransform=()=>{e.targetImg&&(e.targetImg.style.transform=`translate(${e.translateX}px, ${e.translateY}px) scale(${e.scale})`)},fitToViewport=(i={})=>{if(!e.targetImg)return;if(!(()=>{if(!e.maskDom)return null;const i=e.maskDom.querySelector(".image-viewer-frame");return i?i.getBoundingClientRect():e.maskDom.getBoundingClientRect()})())return;const n=i.marginFactor??.98;e.scale=1,e.translateX=0,e.translateY=0,applyTransform();const a=e.targetImg.getBoundingClientRect();if(!a.width||!a.height)return;const r=window.innerHeight*n,l=window.innerWidth,o=r/a.height,s=l/a.width,u=Math.min(1,o,s);e.fitScale=u,e.scale=u,e.translateX=0,e.translateY=0,e.userZoomed=!1,applyTransform()},showHandle=i=>{e.maskDom&&(document.body.style.overflow=i?"hidden":"auto",e.maskDom.classList.toggle("active",i))},closeViewer=()=>{e.isBigImage&&(e.isBigImage=!1,showHandle(!1),fitToViewport(),e.userZoomed=!1,resetExifUI())},updateImageNodes=()=>{r=Array.from(document.querySelectorAll(i))},canGoPrev=()=>e.currentImgIndex>0,canGoNext=()=>e.currentImgIndex<Math.max(r.length-1,0),updateNavButtons=()=>{n.prevButton&&n.nextButton&&(n.prevButton.classList.toggle("is-disabled",!canGoPrev()),n.nextButton.classList.toggle("is-disabled",!canGoNext()))},hasExifFlag=e=>"true"===e?.dataset?.exif,formatExifValue=e=>{if(!e)return null;if("object"==typeof e){if(null!=e.description)return String(e.description).trim();if(null!=e.value)return Array.isArray(e.value)?e.value.map((e=>String(e))).join(", ").trim():String(e.value).trim()}return"string"==typeof e?e.trim():String(e).trim()},getExifValueByKeys=(e,i=[])=>{if(!e||!Array.isArray(i))return null;for(const n of i){const i=formatExifValue(e[n]);if(i)return i}return null},parseRational=e=>{if("number"==typeof e)return Number.isFinite(e)?e:null;if(e&&"object"==typeof e){const i=e.numerator??e.num,n=e.denominator??e.den;if(Number.isFinite(i)&&Number.isFinite(n)&&0!==n)return i/n;if(Number.isFinite(e.value))return e.value}if("string"==typeof e){const i=Number.parseFloat(e);return Number.isFinite(i)?i:null}return null},formatGpsCoordinate=(e,i,n)=>{if(!e)return null;const a=e[i];if(!a)return null;const r=(l=a)?"object"==typeof l&&"value"in l?l.value:l:null;var l;const o=formatExifValue(e[n]);let s=null;if(Array.isArray(r)){const e=r.map(parseRational).filter((e=>null!=e));if(e.length>=3){const[i,n,a]=e;s=i+n/60+a/3600}}else s=parseRational(r);if(null==s){const e=formatExifValue(a);return e?o&&!e.includes(o)?`${e} ${o}`:e:null}const u=o?String(o).trim().toUpperCase():"",c=Math.abs(s).toFixed(4);return u?`${c} ${u}`:s.toFixed(4)},setExifPanelOpen=e=>{a.panel&&a.toggleButton&&(a.panel.classList.toggle("hidden",!e),a.panel.setAttribute("aria-hidden",e?"false":"true"),a.toggleButton.setAttribute("aria-expanded",e?"true":"false"))},clearExifCards=()=>{a.cardsContainer&&(a.cardsContainer.innerHTML="")},createExifCard=e=>{const i=a.cardTemplate,n=i?.content?.firstElementChild;let r=n?n.cloneNode(!0):null;if(!r){r=document.createElement("div"),r.className="rounded-lg border border-border-color bg-background-color-transparent-80 px-3 py-2 shadow-redefine-flat";const e=document.createElement("div");e.className="image-viewer-exif-card-header flex items-center gap-2 mb-1";const i=document.createElement("i");i.className="image-viewer-exif-card-icon fa-solid fa-circle-info text-xs text-third-text-color";const n=document.createElement("div");n.className="image-viewer-exif-card-title text-xs font-semibold text-first-text-color",e.appendChild(i),e.appendChild(n);const a=document.createElement("div");a.className="image-viewer-exif-card-items flex flex-col gap-1",r.appendChild(e),r.appendChild(a)}const l=r.querySelector(".image-viewer-exif-card-title"),o=r.querySelector(".image-viewer-exif-card-icon");let s=r.querySelector(".image-viewer-exif-card-items");if(s||(s=document.createElement("div"),s.className="image-viewer-exif-card-items flex flex-col gap-1",r.appendChild(s)),l&&(l.textContent=e.title),o){const i=e.icon||"fa-solid fa-circle-info";o.className=`image-viewer-exif-card-icon ${i} text-xs text-third-text-color`}return s.innerHTML="",e.items.forEach((e=>{s.appendChild(((e,i)=>{const n=document.createElement("div");n.className="image-viewer-exif-item flex items-start justify-between gap-2";const a=document.createElement("div");a.className="image-viewer-exif-item-label text-[0.65rem] uppercase tracking-wide shrink-0 text-third-text-color",a.textContent=e;const r=document.createElement("div");return r.className="image-viewer-exif-item-value text-[0.65rem] text-first-text-color text-right",r.textContent=i,n.appendChild(a),n.appendChild(r),n})(e.label,e.value))})),r},renderExifGroups=e=>{if(!a.cardsContainer)return;clearExifCards();const i=Array.isArray(e)?e.map((e=>{if(!e||"object"!=typeof e)return null;const i=String(e.title||"").trim(),n=String(e.icon||"").trim(),a=Array.isArray(e.items)?e.items.map((e=>{if(!e||"object"!=typeof e)return null;const i=String(e.label||"").trim(),n=String(e.value??"").trim();return i&&n?{label:i,value:n}:null})).filter(Boolean):[];return i&&0!==a.length?{title:i,icon:n,items:a}:null})).filter(Boolean):[],n=t("exif.title","EXIF"),r=i.length?i:[{title:n,icon:"fa-solid fa-circle-info",items:[{label:n,value:t("exif.status.no_exif","No EXIF available")}]}],l=document.createDocumentFragment();r.forEach((e=>{l.appendChild(createExifCard(e))})),a.cardsContainer.appendChild(l)},bumpExifRequestId=()=>(a.requestId=(a.requestId||0)+1,a.requestId),renderExifMessage=e=>{const i=t("exif.title","EXIF");renderExifGroups([{title:i,icon:"fa-solid fa-circle-info",items:[{label:i,value:e}]}])},loadExifForImage=async e=>{const i=bumpExifRequestId();renderExifMessage(t("exif.status.loading","Loading..."));const n=window.ExifReader;if(!n||"function"!=typeof n.load){if(a.requestId!==i)return;return void renderExifMessage(t("exif.status.library_missing","EXIF library not loaded"))}const r=(e=>{if(!e)return null;const i=e.getAttribute("data-src")||e.currentSrc||e.src;if(!i)return null;try{return new URL(i,window.location.href).toString()}catch(e){return i}})(e);if(r)try{const e=await n.load(r);if(a.requestId!==i)return;const l=(e=>{if(!e)return[];const i=[],pushGroup=(e,n,a)=>{const r=(a||[]).filter(Boolean);0!==r.length&&i.push({title:e,icon:n,items:r})},n=getExifValueByKeys(e,["Make"]),a=getExifValueByKeys(e,["Model"]),r=getExifValueByKeys(e,["DateTimeOriginal","DateTime"]);pushGroup(t("exif.cards.camera","Camera"),"fa-solid fa-camera",[n&&{label:t("exif.fields.make","Brand"),value:n},a&&{label:t("exif.fields.model","Model"),value:a},r&&{label:t("exif.fields.date_taken","Date taken"),value:r}]);const l=getExifValueByKeys(e,["LensModel","Lens","LensSpecification"]),o=getExifValueByKeys(e,["FocalLength","FocalLengthIn35mmFilm"]),s=getExifValueByKeys(e,["FocusMode","AFMode","AFAreaMode","FocusingMode","AutoFocus","FocusMethod"]);pushGroup(t("exif.cards.lens","Lens"),"fa-solid fa-eye",[l&&{label:t("exif.fields.lens_model","Lens"),value:l},o&&{label:t("exif.fields.focal_length","Focal length"),value:o},s&&{label:t("exif.fields.focus_mode","Focus mode"),value:s}]);const u=getExifValueByKeys(e,["ExposureTime"]),c=getExifValueByKeys(e,["FNumber"]),d=getExifValueByKeys(e,["ISO","PhotographicSensitivity"]),g=getExifValueByKeys(e,["ExposureProgram"]),m=getExifValueByKeys(e,["ExposureBiasValue"]),f=getExifValueByKeys(e,["MeteringMode"]);pushGroup(t("exif.cards.exposure","Exposure"),"fa-solid fa-sun",[u&&{label:t("exif.fields.shutter","Shutter"),value:u},c&&{label:t("exif.fields.aperture","Aperture"),value:c},d&&{label:t("exif.fields.iso","ISO"),value:d},g&&{label:t("exif.fields.exposure_program","Exposure program"),value:g},m&&{label:t("exif.fields.exposure_compensation","Exposure compensation"),value:m},f&&{label:t("exif.fields.metering_mode","Metering mode"),value:f}]);const v=getExifValueByKeys(e,["Flash"]),p=getExifValueByKeys(e,["WhiteBalance"]),x=formatGpsCoordinate(e,"GPSLatitude","GPSLatitudeRef"),w=formatGpsCoordinate(e,"GPSLongitude","GPSLongitudeRef"),h=getExifValueByKeys(e,["GPSAltitude"]);return pushGroup(t("exif.cards.other","Other"),"fa-solid fa-gear",[v&&{label:t("exif.fields.flash","Flash"),value:v},p&&{label:t("exif.fields.white_balance","White balance"),value:p},x&&{label:t("exif.fields.latitude","Latitude"),value:x},w&&{label:t("exif.fields.longitude","Longitude"),value:w},h&&{label:t("exif.fields.altitude","Altitude"),value:h}]),i})(e);if(0===l.length)return void renderExifMessage(t("exif.status.no_exif","No EXIF available"));renderExifGroups(l)}catch(e){if(a.requestId!==i)return;renderExifMessage(t("exif.status.unavailable","EXIF unavailable (blocked by CORS or missing metadata)"))}else{if(a.requestId!==i)return;renderExifMessage(t("exif.status.image_source_missing","Image source unavailable"))}},resetExifUI=()=>{bumpExifRequestId(),a.toggleButton&&(a.toggleButton.classList.add("hidden"),a.toggleButton.setAttribute("aria-expanded","false")),setExifPanelOpen(!1),clearExifCards()},updateViewerImage=i=>{const n=r[i];if(!n||!e.targetImg)return;e.currentImgIndex=i;let l=n.src;n.hasAttribute("lazyload")&&(l=n.getAttribute("data-src")||l,l&&(n.src=l),n.removeAttribute("lazyload")),l&&(e.targetImg.src=l),e.targetImg.alt=n.alt||"";const handleImageLoad=()=>{e.targetImg?.removeEventListener("load",handleImageLoad),fitToViewport()};e.targetImg.complete?fitToViewport():e.targetImg.addEventListener("load",handleImageLoad,{once:!0}),updateNavButtons(),(e=>{const i=hasExifFlag(e);bumpExifRequestId(),a.toggleButton&&(a.toggleButton.classList.toggle("hidden",!i),a.toggleButton.disabled=!i),setExifPanelOpen(!1),clearExifCards()})(n)},goPrev=()=>{e.isBigImage&&canGoPrev()&&updateViewerImage(e.currentImgIndex-1)},goNext=()=>{e.isBigImage&&canGoNext()&&updateViewerImage(e.currentImgIndex+1)},handleArrowKeys=i=>{if(e.isBigImage)return"Escape"===i.key?(i.preventDefault(),void closeViewer()):"ArrowUp"===i.key||"ArrowLeft"===i.key?(i.preventDefault(),void goPrev()):void("ArrowDown"!==i.key&&"ArrowRight"!==i.key||(i.preventDefault(),goNext()))};export default function initImageViewer({signal:o,appSignal:s}={}){const u=document.querySelector(".image-viewer-container");if(!u)return void console.warn("Image viewer container not found. Exiting imageViewer function.");const c=u.querySelector("img");if(!c)return void console.warn("Target image not found in image viewer container. Exiting imageViewer function.");e.maskDom=u,e.targetImg=c,e.dragged=!1,n.prevButton=u.querySelector(".image-viewer-prev"),n.nextButton=u.querySelector(".image-viewer-next"),n.closeButton=u.querySelector(".image-viewer-close"),a.toggleButton=u.querySelector(".image-viewer-exif-toggle"),a.panel=u.querySelector(".image-viewer-exif-panel"),a.cardsContainer=u.querySelector(".image-viewer-exif-cards"),a.closeButton=u.querySelector(".image-viewer-exif-close"),a.cardTemplate=u.querySelector(".image-viewer-exif-card-template"),updateImageNodes(),(e=>{l||(l=!0,e?document.addEventListener("keydown",handleArrowKeys,{signal:e}):document.addEventListener("keydown",handleArrowKeys))})(s),updateNavButtons(),resetExifUI();const zoomHandle=i=>{if(!i.ctrlKey)return;if(i.preventDefault(),!e.targetImg)return;const n=e.targetImg.getBoundingClientRect(),a=i.clientX-n.left,r=i.clientY-n.top,l=a-n.width/2,o=r-n.height/2,s=e.scale,u=Math.max(.2,.8*e.fitScale),c=Math.min(8,4*e.fitScale);e.scale+=-.001*i.deltaY,e.scale=Math.min(Math.max(u,e.scale),c),e.userZoomed=Math.abs(e.scale-e.fitScale)>.01,s<e.scale?(e.translateX-=l*(e.scale-s),e.translateY-=o*(e.scale-s)):(e.translateX=0,e.translateY=0),applyTransform()},dragStartHandle=i=>{e.scale<=e.fitScale+.01||(i.preventDefault(),e.isMouseDown=!0,e.lastMouseX=i.clientX,e.lastMouseY=i.clientY,g=i.clientX,m=i.clientY,e.targetImg.style.cursor="grabbing",e.userZoomed=!0)};let d=null,g=null,m=null;const dragHandle=i=>{e.isMouseDown&&(e.scale<=e.fitScale+.01||(g=i.clientX,m=i.clientY,null===d&&(d=window.requestAnimationFrame((()=>{if(null==g||null==m)return void(d=null);const i=g-e.lastMouseX,n=m-e.lastMouseY;e.translateX+=i,e.translateY+=n,e.lastMouseX=g,e.lastMouseY=m,applyTransform(),e.dragged=!0,d=null})))))},dragEndHandle=i=>{e.isMouseDown&&i.stopPropagation(),e.isMouseDown=!1,null!==d&&(window.cancelAnimationFrame(d),d=null),g=null,m=null,e.dragged&&window.setTimeout((()=>{e.dragged=!1}),0),e.targetImg.style.cursor="grab"},handleImageClick=n=>{const a=n.target.closest(i);if(!a||a.closest(".image-viewer-container"))return;updateImageNodes();const l=r.indexOf(a);e.isBigImage=!0,e.dragged=!1,e.userZoomed=!1,showHandle(!0),updateViewerImage(-1===l?0:l)},handleMaskClick=i=>{if(e.dragged)return;const n=i.target;if(n.closest(".image-viewer-prev, .image-viewer-next, .image-viewer-close, .image-viewer-exif-panel, .image-viewer-exif-toggle"))return;if(n.closest(".image-viewer-frame img"))return;const a=u.querySelector(".image-viewer-frame");(n===u||a&&n===a)&&closeViewer()},handlePrevClick=e=>{e.stopPropagation(),goPrev()},handleNextClick=e=>{e.stopPropagation(),goNext()},handleCloseClick=e=>{e.stopPropagation(),closeViewer()},handleExifToggle=i=>{if(i.stopPropagation(),!a.panel)return;if(!a.panel.classList.contains("hidden"))return void setExifPanelOpen(!1);setExifPanelOpen(!0);const n=r[e.currentImgIndex];hasExifFlag(n)?loadExifForImage(n):renderExifMessage(t("exif.status.flag_unavailable","EXIF unavailable"))},handleExifClose=e=>{e.stopPropagation(),setExifPanelOpen(!1)},handleResize=()=>{e.isBigImage&&!e.userZoomed&&fitToViewport()};o?(c.addEventListener("wheel",zoomHandle,{passive:!1,signal:o}),c.addEventListener("mousedown",dragStartHandle,{passive:!1,signal:o}),c.addEventListener("mousemove",dragHandle,{passive:!1,signal:o}),c.addEventListener("mouseup",dragEndHandle,{passive:!1,signal:o}),c.addEventListener("mouseleave",dragEndHandle,{passive:!1,signal:o}),u.addEventListener("click",handleMaskClick,{signal:o}),window.addEventListener("resize",handleResize,{signal:o}),document.addEventListener("click",handleImageClick,{signal:o}),n.prevButton?.addEventListener("click",handlePrevClick,{signal:o}),n.nextButton?.addEventListener("click",handleNextClick,{signal:o}),n.closeButton?.addEventListener("click",handleCloseClick,{signal:o}),a.toggleButton?.addEventListener("click",handleExifToggle,{signal:o}),a.closeButton?.addEventListener("click",handleExifClose,{signal:o})):(c.addEventListener("wheel",zoomHandle,{passive:!1}),c.addEventListener("mousedown",dragStartHandle,{passive:!1}),c.addEventListener("mousemove",dragHandle,{passive:!1}),c.addEventListener("mouseup",dragEndHandle,{passive:!1}),c.addEventListener("mouseleave",dragEndHandle,{passive:!1}),u.addEventListener("click",handleMaskClick),window.addEventListener("resize",handleResize),document.addEventListener("click",handleImageClick),n.prevButton?.addEventListener("click",handlePrevClick),n.nextButton?.addEventListener("click",handleNextClick),n.closeButton?.addEventListener("click",handleCloseClick),a.toggleButton?.addEventListener("click",handleExifToggle),a.closeButton?.addEventListener("click",handleExifClose))}
//# sourceMappingURL=imageViewer.js.map