Files
nds/public/js/gallerydeluxe/cdn/index.js
2024-10-14 01:28:50 +02:00

780 lines
28 KiB
JavaScript

(() => {
// ns-hugo:/home/julien/Sync/delmar.bzh/nds/themes/gallerydeluxe/assets/js/gallerydeluxe/src/pig.js
var optimizedResize = /* @__PURE__ */ function() {
const callbacks = [];
let running = false;
function resize() {
if (!running) {
running = true;
if (window.requestAnimationFrame) {
window.requestAnimationFrame(runCallbacks);
} else {
setTimeout(runCallbacks, 66);
}
}
}
function runCallbacks() {
callbacks.forEach(function(callback) {
callback();
});
running = false;
}
return {
/**
* Add a callback to be run on resize.
*
* @param {function} callback - the callback to run on resize.
*/
add: function(callback) {
if (!callbacks.length) {
window.addEventListener("resize", resize);
}
callbacks.push(callback);
},
/**
* Disables all resize handlers.
*/
disable: function() {
window.removeEventListener("resize", resize);
},
/**
* Enables all resize handlers, if they were disabled.
*/
reEnable: function() {
window.addEventListener("resize", resize);
}
};
}();
function _injectStyle(containerId, classPrefix, transitionSpeed) {
const css = "#" + containerId + " { position: relative;}." + classPrefix + "-figure { background-color: #D5D5D5; overflow: hidden; left: 0; position: absolute; top: 0; margin: 0;}." + classPrefix + "-figure img { left: 0; position: absolute; top: 0; height: 100%; width: 100%; opacity: 0; transition: " + (transitionSpeed / 1e3).toString(10) + "s ease opacity; -webkit-transition: " + (transitionSpeed / 1e3).toString(10) + "s ease opacity;}." + classPrefix + "-figure img." + classPrefix + "-thumbnail { -webkit-filter: blur(30px); filter: blur(30px); left: auto; position: relative; width: auto;}." + classPrefix + "-figure img." + classPrefix + "-loaded { opacity: 1;}";
const head = document.head || document.getElementsByTagName("head")[0];
const style = document.createElement("style");
style.type = "text/css";
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
function _extend(obj1, obj2) {
for (const i in obj2) {
if (obj2.hasOwnProperty(i)) {
obj1[i] = obj2[i];
}
}
}
function _getOffsetTop(elem) {
let offsetTop = 0;
do {
if (!isNaN(elem.offsetTop)) {
offsetTop += elem.offsetTop;
}
elem = elem.offsetParent;
} while (elem);
return offsetTop;
}
function Pig(imageData, options) {
this.inRAF = false;
this.isTransitioning = false;
this.minAspectRatioRequiresTransition = false;
this.minAspectRatio = null;
this.latestYOffset = 0;
this.lastWindowWidth = window.innerWidth;
this.scrollDirection = "down";
this.visibleImages = [];
this.settings = {
/**
* Type: string
* Default: 'pig'
* Description: The class name of the element inside of which images should
* be loaded.
*/
containerId: "pig",
/**
* Type: window | HTMLElement
* Default: window
* Description: The window or HTML element that the grid scrolls in.
*/
scroller: window,
/**
* Type: string
* Default: 'pig'
* Description: The prefix associated with this library that should be
* prepended to class names within the grid.
*/
classPrefix: "pig",
/**
* Type: string
* Default: 'figure'
* Description: The tag name to use for each figure. The default setting is
* to use a <figure></figure> tag.
*/
figureTagName: "figure",
/**
* Type: Number
* Default: 8
* Description: Size in pixels of the gap between images in the grid.
*/
spaceBetweenImages: 8,
/**
* Type: Number
* Default: 500
* Description: Transition speed in milliseconds
*/
transitionSpeed: 500,
/**
* Type: Number
* Default: 3000
* Description: Height in pixels of images to preload in the direction
* that the user is scrolling. For example, in the default case, if the
* user is scrolling down, 1000px worth of images will be loaded below
* the viewport.
*/
primaryImageBufferHeight: 1e3,
/**
* Type: Number
* Default: 100
* Description: Height in pixels of images to preload in the direction
* that the user is NOT scrolling. For example, in the default case, if
* the user is scrolling down, 300px worth of images will be loaded
* above the viewport. Images further up will be removed.
*/
secondaryImageBufferHeight: 300,
/**
* Type: Number
* Default: 20
* Description: The height in pixels of the thumbnail that should be
* loaded and blurred to give the effect that images are loading out of
* focus and then coming into focus.
*/
thumbnailSize: 20,
/**
* Get the URL for an image with the given filename & size.
*
* @param {string} filename - The filename of the image.
* @param {Number} size - The size (height in pixels) of the image.
*
* @returns {string} The URL of the image at the given size.
*/
urlForSize: function(filename, size) {
return "/img/" + size.toString(10) + "/" + filename;
},
/**
* Get the a custom style for the container element.
*
* * @param {string} filename - The filename of the image.
*/
styleForElement: function(filename) {
return "";
},
/**
* Get a callback with the filename of the image
* which was clicked.
*
* @param {string} filename - The filename property of the image.
*/
onClickHandler: null,
/**
* Get the minimum required aspect ratio for a valid row of images. The
* perfect rows are maintained by building up a row of images by adding
* together their aspect ratios (the aspect ratio when they are placed
* next to each other) until that aspect ratio exceeds the value returned
* by this function. Responsive reordering is achieved through changes
* to what this function returns at different values of the passed
* parameter `lastWindowWidth`.
*
* @param {Number} lastWindowWidth - The last computed width of the
* browser window.
*
* @returns {Number} The minimum aspect ratio at this window width.
*/
getMinAspectRatio: function(lastWindowWidth) {
if (lastWindowWidth <= 640) {
return 2;
} else if (lastWindowWidth <= 1280) {
return 4;
} else if (lastWindowWidth <= 1920) {
return 5;
}
return 6;
},
/**
* Get the image size (height in pixels) to use for this window width.
* Responsive resizing of images is achieved through changes to what this
* function returns at different values of the passed parameter
* `lastWindowWidth`.
*
* @param {Number} lastWindowWidth - The last computed width of the
* browser window.
*
* @returns {Number} The size (height in pixels) of the images to load.
*/
getImageSize: function(lastWindowWidth) {
if (lastWindowWidth <= 640) {
return 100;
} else if (lastWindowWidth <= 1920) {
return 250;
}
return 500;
}
};
_extend(this.settings, options || {});
this.container = document.getElementById(this.settings.containerId);
if (!this.container) {
console.error("Could not find element with ID " + this.settings.containerId);
}
this.scroller = this.settings.scroller;
this.images = this._parseImageData(imageData);
_injectStyle(this.settings.containerId, this.settings.classPrefix, this.settings.transitionSpeed);
return this;
}
Pig.prototype._getTransitionTimeout = function() {
const transitionTimeoutScaleFactor = 1.5;
return this.settings.transitionSpeed * transitionTimeoutScaleFactor;
};
Pig.prototype._getTransitionString = function() {
if (this.isTransitioning) {
return (this.settings.transitionSpeed / 1e3).toString(10) + "s transform ease";
}
return "none";
};
Pig.prototype._recomputeMinAspectRatio = function() {
const oldMinAspectRatio = this.minAspectRatio;
this.minAspectRatio = this.settings.getMinAspectRatio(this.lastWindowWidth);
if (oldMinAspectRatio !== null && oldMinAspectRatio !== this.minAspectRatio) {
this.minAspectRatioRequiresTransition = true;
} else {
this.minAspectRatioRequiresTransition = false;
}
};
Pig.prototype._parseImageData = function(imageData) {
const progressiveImages = [];
imageData.forEach(
function(image, index) {
const progressiveImage = new ProgressiveImage(image, index, this);
progressiveImages.push(progressiveImage);
}.bind(this)
);
return progressiveImages;
};
Pig.prototype._computeLayout = function() {
const wrapperWidth = parseInt(this.container.clientWidth, 10);
let row = [];
let translateX = 0;
let translateY = 0;
let rowAspectRatio = 0;
this._recomputeMinAspectRatio();
if (!this.isTransitioning && this.minAspectRatioRequiresTransition) {
this.isTransitioning = true;
setTimeout(function() {
this.isTransitioning = false;
}, this._getTransitionTimeout());
}
const transition = this._getTransitionString();
[].forEach.call(
this.images,
function(image, index) {
rowAspectRatio += parseFloat(image.aspectRatio);
row.push(image);
if (rowAspectRatio >= this.minAspectRatio || index + 1 === this.images.length) {
rowAspectRatio = Math.max(rowAspectRatio, this.minAspectRatio);
const totalDesiredWidthOfImages = wrapperWidth - this.settings.spaceBetweenImages * (row.length - 1);
const rowHeight = totalDesiredWidthOfImages / rowAspectRatio;
row.forEach(
function(img) {
const imageWidth = rowHeight * img.aspectRatio;
img.style = {
width: parseInt(imageWidth, 10),
height: parseInt(rowHeight, 10),
translateX,
translateY,
transition
};
translateX += imageWidth + this.settings.spaceBetweenImages;
}.bind(this)
);
row = [];
rowAspectRatio = 0;
translateY += parseInt(rowHeight, 10) + this.settings.spaceBetweenImages;
translateX = 0;
}
}.bind(this)
);
this.totalHeight = translateY - this.settings.spaceBetweenImages;
};
Pig.prototype._doLayout = function() {
this.container.style.height = this.totalHeight + "px";
const bufferTop = this.scrollDirection === "up" ? this.settings.primaryImageBufferHeight : this.settings.secondaryImageBufferHeight;
const bufferBottom = this.scrollDirection === "down" ? this.settings.secondaryImageBufferHeight : this.settings.primaryImageBufferHeight;
const containerOffset = _getOffsetTop(this.container);
const scrollerHeight = this.scroller === window ? window.innerHeight : this.scroller.offsetHeight;
const minTranslateYPlusHeight = this.latestYOffset - containerOffset - bufferTop;
const maxTranslateY = this.latestYOffset - containerOffset + scrollerHeight + bufferBottom;
this.images.forEach(
function(image) {
if (image.style.translateY + image.style.height < minTranslateYPlusHeight || image.style.translateY > maxTranslateY) {
image.hide();
} else {
image.load();
}
}.bind(this)
);
};
Pig.prototype._getOnScroll = function() {
const _this = this;
const onScroll = function() {
const newYOffset = _this.scroller === window ? window.pageYOffset : _this.scroller.scrollTop;
_this.previousYOffset = _this.latestYOffset || newYOffset;
_this.latestYOffset = newYOffset;
_this.scrollDirection = _this.latestYOffset > _this.previousYOffset ? "down" : "up";
if (!_this.inRAF) {
_this.inRAF = true;
window.requestAnimationFrame(function() {
_this._doLayout();
_this.inRAF = false;
});
}
};
return onScroll;
};
Pig.prototype.enable = function() {
this.onScroll = this._getOnScroll();
this.scroller.addEventListener("scroll", this.onScroll);
this.onScroll();
this._computeLayout();
this._doLayout();
const windowWidth = () => {
return this.scroller === window ? window.innerWidth : this.scroller.offsetWidth;
};
optimizedResize.add(
function() {
this.lastWindowWidth = windowWidth();
this._computeLayout();
this._doLayout();
let newWindowWidth = windowWidth();
if (newWindowWidth !== this.lastWindowWidth) {
this.lastWindowWidth = newWindowWidth;
this._computeLayout();
this._doLayout();
}
}.bind(this)
);
return this;
};
Pig.prototype.disable = function() {
this.scroller.removeEventListener("scroll", this.onScroll);
optimizedResize.disable();
return this;
};
function ProgressiveImage(singleImageData, index, pig) {
this.existsOnPage = false;
this.aspectRatio = singleImageData.aspectRatio;
this.filename = singleImageData.filename;
this.index = index;
this.pig = pig;
this.classNames = {
figure: pig.settings.classPrefix + "-figure",
thumbnail: pig.settings.classPrefix + "-thumbnail",
loaded: pig.settings.classPrefix + "-loaded"
};
return this;
}
ProgressiveImage.prototype.load = function() {
this.existsOnPage = true;
this._updateStyles();
this.pig.container.appendChild(this.getElement());
setTimeout(
function() {
if (!this.existsOnPage) {
return;
}
if (!this.thumbnail) {
this.thumbnail = new Image();
this.thumbnail.src = this.pig.settings.urlForSize(this.filename, this.pig.settings.thumbnailSize);
this.thumbnail.className = this.classNames.thumbnail;
this.thumbnail.onload = function() {
if (this.thumbnail) {
this.thumbnail.className += " " + this.classNames.loaded;
}
}.bind(this);
this.getElement().appendChild(this.thumbnail);
}
if (!this.fullImage) {
this.fullImage = new Image();
this.fullImage.src = this.pig.settings.urlForSize(
this.filename,
this.pig.settings.getImageSize(this.pig.lastWindowWidth)
);
this.fullImage.onload = function() {
if (this.fullImage) {
this.fullImage.className += " " + this.classNames.loaded;
}
}.bind(this);
this.getElement().appendChild(this.fullImage);
}
}.bind(this),
100
);
};
ProgressiveImage.prototype.hide = function() {
if (this.getElement()) {
if (this.thumbnail) {
this.thumbnail.src = "";
this.getElement().removeChild(this.thumbnail);
delete this.thumbnail;
}
if (this.fullImage) {
this.fullImage.src = "";
this.getElement().removeChild(this.fullImage);
delete this.fullImage;
}
}
if (this.existsOnPage) {
this.pig.container.removeChild(this.getElement());
}
this.existsOnPage = false;
};
ProgressiveImage.prototype.getElement = function() {
if (!this.element) {
this.element = document.createElement(this.pig.settings.figureTagName);
this.element.className = this.classNames.figure;
let style = this.pig.settings.styleForElement(this.filename);
if (this.style) {
this.element.style = style;
}
if (this.pig.settings.onClickHandler !== null) {
this.element.addEventListener(
"click",
function() {
this.pig.settings.onClickHandler(this.filename);
}.bind(this)
);
}
this._updateStyles();
}
return this.element;
};
ProgressiveImage.prototype._updateStyles = function() {
this.getElement().style.transition = this.style.transition;
this.getElement().style.width = this.style.width + "px";
this.getElement().style.height = this.style.height + "px";
this.getElement().style.transform = "translate3d(" + this.style.translateX + "px," + this.style.translateY + "px, 0)";
};
// ns-hugo:/home/julien/Sync/delmar.bzh/nds/themes/gallerydeluxe/assets/js/gallerydeluxe/src/helpers.js
function newSwiper(el, callback) {
const debug2 = 0 ? console.log.bind(console, "[swiper]") : function() {
};
const simulateTwoFingers = false;
const moveThreshold = 50;
const fingerDistance = (touches) => {
return Math.hypot(touches[0].pageX - touches[1].pageX, touches[0].pageY - touches[1].pageY);
};
var touch = {
touchstart: { x: -1, y: -1, x2: -1, y2: -1, d: -1 },
touchmove: { x: -1, y: -1, x2: -1, y2: -1, d: -1 },
multitouch: false
};
touch.direction = function() {
if (this.touchmove.x == -1) {
return "";
}
let distancex = this.touchmove.x - this.touchstart.x;
if (Math.abs(distancex) < moveThreshold) {
let distancey = this.touchmove.y - this.touchstart.y;
if (Math.abs(distancey) < moveThreshold) {
return "";
}
return distancey > 0 ? "down" : "up";
}
return distancex > 0 ? "right" : "left";
};
touch.reset = function() {
this.touchstart.x = -1, this.touchstart.y = -1;
this.touchmove.x = -1, this.touchmove.y = -1;
this.touchstart.d = -1, this.touchmove.d = -1;
this.touchstart.x2 = -1, this.touchstart.y2 = -1;
this.touchmove.x2 = -1, this.touchmove.y2 = -1;
this.multitouch = false;
};
touch.update = function(event, touches) {
this.multitouch = this.multitouch || touches.length > 1;
if (touches.length > 1) {
this[event.type].d = fingerDistance(touches);
this[event.type].x2 = touches[1].pageX;
this[event.type].y2 = touches[1].pageY;
}
this[event.type].x = touches[0].pageX;
this[event.type].y = touches[0].pageY;
};
const pinch = function(event, touches) {
let scale = 1;
if (touches.length === 2) {
if (event.scale) {
scale = event.scale;
} else {
scale = touch.touchmove.d / touch.touchstart.d;
scale = Math.round(scale * 100) / 100;
}
if (scale < 1) {
scale = 1;
}
let distancex = ((touch.touchmove.x + touch.touchmove.x2) / 2 - (touch.touchstart.x + touch.touchstart.x2) / 2) * 2;
let distancey = ((touch.touchmove.y + touch.touchmove.y2) / 2 - (touch.touchstart.y + touch.touchstart.y2) / 2) * 2;
el.style.transform = `translate3d(${distancex}px, ${distancey}px, 0) scale(${scale})`;
el.style.zIndex = 1e3;
} else {
el.style.transform = "";
el.style.zIndex = "";
}
};
var handleTouch = function(event) {
debug2("event", event.type);
if (typeof event !== "undefined" && typeof event.touches !== "undefined") {
let touches = event.touches;
if (simulateTwoFingers && touches.length === 1) {
touches = [
{ pageX: touches[0].pageX, pageY: touches[0].pageY },
{ pageX: 0, pageY: 0 }
];
}
switch (event.type) {
case "touchstart":
touch.reset();
touch.update(event, touches);
break;
case "touchmove":
touch.update(event, touches);
pinch(event, touches);
break;
case "touchend":
el.style.transform = "";
if (!touch.multitouch) {
let direction = touch.direction();
debug2("direction", direction);
if (direction) {
callback(direction);
}
}
break;
default:
break;
}
}
};
el.addEventListener("touchstart", handleTouch, { passive: true });
el.addEventListener("touchmove", handleTouch, { passive: true });
el.addEventListener("touchend", handleTouch, { passive: true });
}
// ns-hugo:/home/julien/Sync/delmar.bzh/nds/themes/gallerydeluxe/assets/js/gallerydeluxe/src/index.js
var debug = 0 ? console.log.bind(console, "[gallery-deluxe]") : function() {
};
var GalleryDeluxe = {
init: async function() {
const galleryId = "gallerydeluxe";
const dataAttributeName = "data-gd-image-data-url";
const container = document.getElementById(galleryId);
if (!container) {
throw new Error(`No element with id ${galleryId} found.`);
}
const dataUrl = container.getAttribute(dataAttributeName);
if (!dataUrl) {
throw new Error(`No ${dataAttributeName} attribute found.`);
}
let activeImage;
let exifTimeoutId;
const modal = document.getElementById("gd-modal");
const modalClose = modal.querySelector("#gd-modal-close");
const preventDefault = function(e) {
e.preventDefault();
};
let imageWrapper = document.createElement("div");
imageWrapper.classList.add("gd-modal-content-wrapper");
modal.insertBefore(imageWrapper, modal.firstChild);
const closeModal = (e) => {
if (e) {
e.preventDefault();
}
imageWrapper.removeEventListener("touchmove", preventDefault);
imageWrapper.removeEventListener("gesturestart", preventDefault);
modal.style.display = "none";
document.body.style.overflow = "auto";
};
modalClose.addEventListener("click", function() {
closeModal();
});
const swipe = function(direction) {
debug("swipe", direction);
switch (direction) {
case "left":
activeImage = activeImage.next;
openActiveImage();
break;
case "right":
activeImage = activeImage.prev;
openActiveImage();
break;
default:
closeModal();
break;
}
};
newSwiper(imageWrapper, function(direction) {
swipe(direction);
});
document.addEventListener("keydown", function(e) {
switch (e.key) {
case "ArrowLeft":
swipe("right");
break;
case "ArrowRight":
swipe("left");
break;
case "Escape":
closeModal(e);
break;
}
});
const openActiveImage = () => {
imageWrapper.addEventListener("touchmove", preventDefault);
imageWrapper.addEventListener("gesturestart", preventDefault);
const classLoaded = "gd-modal-loaded";
const classThumbnail = "gd-modal-thumbnail";
document.body.style.overflow = "hidden";
let oldEls = modal.querySelectorAll(".gd-modal-content");
let oldElsRemoved = false;
const removeOldEls = () => {
if (oldElsRemoved) {
return;
}
oldElsRemoved = true;
oldEls.forEach((element) => {
element.remove();
});
};
if (activeImage) {
let modal2 = document.getElementById("gd-modal");
if (void 0) {
if (exifTimeoutId) {
clearTimeout(exifTimeoutId);
}
let exif = modal2.querySelector("#gd-modal-exif");
const onTimeOutClass = "gd-modal-exif-ontimeout";
let child = exif.lastElementChild;
while (child) {
exif.removeChild(child);
child = exif.lastElementChild;
}
let dl = document.createElement("dl");
exif.appendChild(dl);
const addTag = (tag, value) => {
let dt = document.createElement("dt");
dt.innerText = camelToTitle(tag);
dl.appendChild(dt);
let dd = document.createElement("dd");
dd.innerText = value;
dl.appendChild(dd);
};
let date = new Date(activeImage.exif.Date);
var dateString = new Date(date.getTime() - date.getTimezoneOffset() * 6e4).toISOString().split("T")[0];
addTag("Date", dateString);
let tags = activeImage.exif.Tags;
for (const tag in tags) {
addTag(tag, tags[tag]);
}
exif.classList.remove(onTimeOutClass);
exifTimeoutId = setTimeout(() => {
exif.classList.add(onTimeOutClass);
}, 1200);
}
let thumbnail = new Image();
thumbnail.classList.add("gd-modal-content");
thumbnail.width = activeImage.width;
thumbnail.height = activeImage.height;
thumbnail.style.aspectRatio = activeImage.width / activeImage.height;
const fullImage = thumbnail.cloneNode(false);
thumbnail.classList.add(classThumbnail);
fullImage.src = activeImage.full;
thumbnail.src = activeImage["20"];
thumbnail.onload = function() {
if (thumbnail) {
imageWrapper.appendChild(thumbnail);
removeOldEls();
}
};
fullImage.onload = function() {
if (fullImage) {
imageWrapper.appendChild(fullImage);
fullImage.classList.add(classLoaded);
if (thumbnail) {
thumbnail.classList.add(classLoaded);
}
removeOldEls();
}
};
modal2.style.display = "block";
}
setTimeout(function() {
removeOldEls();
}, 1e3);
};
let images = await (await fetch(dataUrl)).json();
if (void 0) {
images = images.map((value) => ({ value, sort: Math.random() })).sort((a, b) => a.sort - b.sort).map(({ value }) => value);
} else if (void 0) {
images = images.reverse();
}
let imagesMap = /* @__PURE__ */ new Map();
let imageData = [];
for (let i = 0; i < images.length; i++) {
let image = images[i];
image.prev = images[(i + images.length - 1) % images.length];
image.next = images[(i + 1) % images.length];
imageData.push({ filename: image.name, aspectRatio: image.width / image.height, image });
imagesMap.set(image.name, image);
}
var options = {
onClickHandler: function(filename) {
debug("onClickHandler", filename);
activeImage = imagesMap.get(filename);
if (activeImage) {
openActiveImage();
}
},
containerId: galleryId,
classPrefix: "gd",
spaceBetweenImages: 1,
urlForSize: function(filename, size) {
return imagesMap.get(filename)[size];
},
styleForElement: function(filename) {
let image = imagesMap.get(filename);
if (!image || image.colors.size < 1) {
return "";
}
let colors = image.colors;
let first = colors[0];
let second = "#ccc";
if (colors.length > 1) {
second = colors[1];
}
return ` background: linear-gradient(15deg, ${first}, ${second});`;
}
};
new Pig(imageData, options).enable();
}
};
function camelToTitle(text) {
return text.replace(/([A-Z])/g, " $1").replace(/^./, function(str) {
return str.toUpperCase();
});
}
var src_default = GalleryDeluxe;
// <stdin>
src_default.init();
})();
/*! The Pig library is MIT License (MIT) Copyright (c) 2015 Dan Schlosser, see https://github.com/schlosser/pig.js/blob/master/LICENSE.md */