copyparty/copyparty/web/baguettebox.js

1365 lines
41 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
/*!
* baguetteBox.js
* @author feimosi
* @version 1.11.1-mod
* @url https://github.com/feimosi/baguetteBox.js
*/
var J_BBX = 1;
window.baguetteBox = (function () {
'use strict';
var options = {},
defaults = {
captions: true,
buttons: 'auto',
noScrollbars: false,
bodyClass: 'bbox-open',
titleTag: false,
async: false,
preload: 2,
refocus: true,
afterShow: null,
afterHide: null,
duringHide: null,
onChange: null,
readDirRtl: false,
},
overlay, slider, btnPrev, btnNext, btnHelp, btnAnim, btnRotL, btnRotR, btnSel, btnFull, btnZoom, btnVmode, btnReadDir, btnClose,
currentGallery = [],
currentIndex = 0,
isOverlayVisible = false,
touch = {}, // start-pos
touchFlag = false, // busy
scrollCSS = ['', ''],
scrollTimer = 0,
re_i = APPLE ?
/^[^?]+\.(a?png|avif|bmp|gif|hei[cf]s?|jfif|jpe?g|jxl|svg|tiff?|webp)(\?|$)/i :
/^[^?]+\.(a?png|avif|bmp|gif|jfif|jpe?g|jxl|svg|tiff?|webp)(\?|$)/i,
re_v = /^[^?]+\.(webm|mkv|mp4|m4v|mov)(\?|$)/i,
re_cbz = /^[^?]+\.(cbz)(\?|$)/i,
anims = ['slideIn', 'fadeIn', 'none'],
data = {}, // all galleries
imagesElements = [],
documentLastFocus = null,
isFullscreen = false,
vmute = false,
vloop = sread('vmode') == 'L',
vnext = sread('vmode') == 'C',
loopA = null,
loopB = null,
url_ts = null,
un_pp = 0,
resume_mp = false;
var onFSC = function (e) {
isFullscreen = !!document.fullscreenElement;
clmod(document.documentElement, 'bb_fsc', isFullscreen);
};
var overlayClickHandler = function (e) {
if (e.target.id.indexOf('baguette-img') !== -1)
hideOverlay();
};
var vtouch = function (e) {
var v = vid(),
bv = v.getBoundingClientRect(),
tp = e.changedTouches[0];
if (bv.bottom - tp.clientY < 90)
touchFlag = true;
};
var touchstartHandler = function (e) {
touch.count = e.touches.length;
if (touch.count > 1)
touch.multitouch = true;
touch.startX = e.changedTouches[0].pageX;
touch.startY = e.changedTouches[0].pageY;
};
var touchmoveHandler = function (e) {
if (touchFlag || touch.multitouch)
return;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
var touchEvent = e.touches[0] || e.changedTouches[0];
if (touchEvent.pageX - touch.startX > 40) {
touchFlag = true;
showLeftImage();
} else if (touchEvent.pageX - touch.startX < -40) {
touchFlag = true;
showRightImage();
} else if (touch.startY - touchEvent.pageY > 100) {
hideOverlay();
}
};
var touchendHandler = function (e) {
touch.count--;
if (e && e.touches)
touch.count = e.touches.length;
if (touch.count <= 0)
touch.multitouch = false;
touchFlag = false;
};
var contextmenuHandler = function () {
touchendHandler();
};
var overlayWheelHandler = function (e) {
if (!options.noScrollbars || anymod(e))
return;
ev(e);
var x = e.deltaX,
y = e.deltaY,
d = Math.abs(x) > Math.abs(y) ? x : y;
if (e.deltaMode)
d *= 10;
if (Date.now() - scrollTimer < (Math.abs(d) > 20 ? 100 : 300))
return;
scrollTimer = Date.now();
if (d > 0)
showNextImageIgnoreReadDir();
else
showPreviousImageIgnoreReadDir();
};
var trapFocusInsideOverlay = function (e) {
if (overlay.style.display === 'block' && (overlay.contains && !overlay.contains(e.target))) {
e.stopPropagation();
btnClose.focus();
}
};
function run(selector, userOptions) {
buildOverlay();
removeFromCache(selector);
return bindImageClickListeners(selector, userOptions);
}
function bindImageClickListeners(selector, userOptions) {
var galleryNodeList = QSA(selector);
var selectorData = {
galleries: [],
nodeList: galleryNodeList
};
data[selector] = selectorData;
[].forEach.call(galleryNodeList, function (galleryElement) {
var tagsNodeList = [];
if (galleryElement.tagName === 'A')
tagsNodeList = [galleryElement];
else
tagsNodeList = galleryElement.getElementsByTagName('a');
if (have_zls)
bindCbzClickListeners(tagsNodeList, userOptions);
tagsNodeList = [].filter.call(tagsNodeList, function (element) {
if (element.className.indexOf(userOptions && userOptions.ignoreClass) === -1)
return re_i.test(element.href) || re_v.test(element.href);
});
if (!tagsNodeList.length)
return;
var gallery = [];
[].forEach.call(tagsNodeList, function (imageElement, imageIndex) {
var imageElementClickHandler = function (e) {
if (ctrl(e) || e && e.shiftKey)
return true;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
prepareOverlay(gallery, userOptions);
showOverlay(imageIndex);
};
var imageItem = {
eventHandler: imageElementClickHandler,
imageElement: imageElement,
};
bind(imageElement, 'click', imageElementClickHandler);
gallery.push(imageItem);
});
selectorData.galleries.push(gallery);
});
return [selectorData.galleries, options];
}
function bindCbzClickListeners(tagsNodeList, userOptions) {
var cbzNodes = [].filter.call(tagsNodeList, function (element) {
return re_cbz.test(element.href);
});
if (!tagsNodeList.length) {
return;
}
[].forEach.call(cbzNodes, function (cbzElement, index) {
var gallery = [];
var eventHandler = function (e) {
if (ctrl(e) || e && e.shiftKey)
return true;
e.preventDefault ? e.preventDefault() : e.returnValue = false;
fillCbzGallery(gallery, cbzElement, eventHandler).then(function () {
prepareOverlay(gallery, userOptions);
showOverlay(0);
}
).catch(function (reason) {
console.error("cbz-ded", reason);
var t;
try {
t = uricom_dec(cbzElement.href.split('/').pop());
} catch (ex) { }
var msg = "Could not browse " + (t ? t : 'archive');
try {
msg += "\n\n" + reason.message;
} catch (ex) { }
toast.err(20, msg, 'cbz-ded');
});
}
bind(cbzElement, "click", eventHandler);
})
}
function fillCbzGallery(gallery, cbzElement, eventHandler) {
if (gallery.length !== 0) {
return Promise.resolve();
}
var href = cbzElement.href;
var zlsHref = href + (href.indexOf("?") === -1 ? "?" : "&") + "zls";
return fetch(zlsHref)
.then(function (response) {
if (response.ok) {
return response.json();
} else {
throw new Error("Archive is invalid");
}
})
.then(function (fileList) {
var imagesList = fileList.map(function (file) {
return file["fn"];
}).filter(function (file) {
return re_i.test(file);
}).sort();
if (imagesList.length === 0) {
throw new Error("Archive does not contain any images");
}
imagesList.forEach(function (imageName, index) {
var imageHref = href
+ (href.indexOf("?") === -1 ? "?" : "&")
+ "zget="
+ encodeURIComponent(imageName);
var galleryItem = {
href: imageHref,
imageElement: cbzElement,
eventHandler: eventHandler,
};
gallery.push(galleryItem);
});
});
}
function clearCachedData() {
for (var selector in data)
if (data.hasOwnProperty(selector))
removeFromCache(selector);
}
function removeFromCache(selector) {
if (!data.hasOwnProperty(selector))
return;
var galleries = data[selector].galleries;
[].forEach.call(galleries, function (gallery) {
[].forEach.call(gallery, function (imageItem) {
unbind(imageItem.imageElement, 'click', imageItem.eventHandler);
});
if (currentGallery === gallery)
currentGallery = [];
});
delete data[selector];
}
function buildOverlay() {
overlay = ebi('bbox-overlay');
if (!overlay) {
var ctr = mknod('div');
ctr.innerHTML = (
'<div id="bbox-overlay" role="dialog">' +
'<div id="bbox-slider"></div>' +
'<div id="bbox-prev"><a class="btn" aria-label="Previous">◀</a></div>' +
'<div id="bbox-next"><a class="btn" aria-label="Next">▶</a></div>' +
'<div id="bbox-btns">' +
'<a id="bbox-close" class="btn" aria-label="Close">✕</a>' +
'<a id="bbox-vmode" class="btn" tt="a"></a>' +
'<a id="bbzoom" class="tgl btn" tt="zoom/stretch smaller images to fill screen">↕</a>' +
'<a id="bbox-full" class="btn" tt="full-screen">⛶</a>' +
'<a id="bbox-tsel" class="tgl btn">☑sel</a>' +
'<a id="bbox-rotr" class="btn">↷</a>' +
'<a id="bbox-rotl" class="btn">↶</a>' +
'<a id="bbox-readdir" class="btn" tt="a">ltr</a>' +
'<a id="bbox-anim" class="btn" tt="a">-</a>' +
'<a id="bbox-help" class="btn">?</a>' +
'</div></div>'
);
overlay = ctr.firstChild;
QS('body').appendChild(overlay);
tt.att(overlay);
}
slider = ebi('bbox-slider');
btnPrev = ebi('bbox-prev');
btnNext = ebi('bbox-next');
btnHelp = ebi('bbox-help');
btnAnim = ebi('bbox-anim');
btnReadDir = ebi('bbox-readdir');
btnRotL = ebi('bbox-rotl');
btnRotR = ebi('bbox-rotr');
btnSel = ebi('bbox-tsel');
btnFull = ebi('bbox-full');
btnZoom = ebi('bbzoom');
btnVmode = ebi('bbox-vmode');
btnClose = ebi('bbox-close');
bcfg_bind(options, 'bbzoom', 'bbzoom', false, setzoom);
setzoom();
}
function halp() {
if (ebi('bbox-halp'))
return;
var list = [
['<b># hotkey</b>', '<b># operation</b>'],
['escape', 'close'],
['left, J', 'previous file'],
['right, L', 'next file'],
['home', 'first file'],
['end', 'last file'],
['R', 'rotate (shift=ccw)'],
['F', 'toggle fullscreen'],
['Z', 'toggle zoom/stretch'],
['S', 'toggle file selection'],
['space, P, K', 'video: play / pause'],
['U', 'video: seek 10sec back'],
['O', 'video: seek 10sec ahead'],
['0..9', 'video: seek 0%..90%'],
['M', 'video: toggle mute'],
['V', 'video: toggle loop'],
['C', 'video: toggle auto-next'],
['<code>[</code>, <code>]</code>', 'video: loop start / end'],
],
d = mknod('table', 'bbox-halp'),
html = ['<tbody>'];
for (var a = 0; a < list.length; a++)
html.push('<tr><td>' + list[a][0] + '</td><td>' + list[a][1] + '</td></tr>');
html.push('<tr><td colspan="2">tap middle of img to hide btns</td></tr>');
html.push('<tr><td colspan="2">tap left/right sides for prev/next</td></tr>');
d.innerHTML = html.join('\n') + '</tbody>';
d.onclick = function () {
overlay.removeChild(d);
};
overlay.appendChild(d);
}
function keyDownHandler(e) {
if (modal.busy)
return;
if (anymod(e, true))
return;
var k = (e.key || e.code) + '', v = vid();
if (k.startsWith('Key'))
k = k.slice(3);
else if (k.startsWith('Digit'))
k = k.slice(5);
var kl = k.toLowerCase();
if (k == '?')
return halp();
if (k == "[" || k == "BracketLeft")
setloop(1);
else if (k == "]" || k == "BracketRight")
setloop(2);
else if (e.shiftKey && kl != "r")
return;
else if (k == "ArrowLeft" || k == "Left" || kl == "j")
showLeftImage();
else if (k == "ArrowRight" || k == "Right" || kl == "l")
showRightImage();
else if (k == "Escape" || k == "Esc")
hideOverlay();
else if (k == "Home")
showFirstImage(e);
else if (k == "End")
showLastImage(e);
else if (k == "Space" || k == "Spacebar" || kl == " " || kl == "p" || kl == "k")
playpause();
else if (kl == "u" || kl == "o")
relseek(kl == "u" ? -10 : 10);
else if (v && /^[0-9]$/.test(k) && isNum(v.duration))
v.currentTime = v.duration * parseInt(k) * 0.1;
else if (kl == "m" && v) {
v.muted = vmute = !vmute;
mp_ctl();
}
else if (kl == "v" && v) {
vloop = !vloop;
vnext = vnext && !vloop;
setVmode();
}
else if (kl == "c" && v) {
vnext = !vnext;
vloop = vloop && !vnext;
setVmode();
}
else if (kl == "f")
tglfull();
else if (kl == "z")
btnZoom.click();
else if (kl == "s")
tglsel();
else if (kl == "r")
rotn(e.shiftKey ? -1 : 1);
else if (kl == "y")
dlpic();
else
return;
return ev(e);
}
function anim() {
var i = (anims.indexOf(options.animation) + 1) % anims.length,
o = options;
swrite('ganim', anims[i]);
options = {};
setOptions(o);
if (tt.en)
tt.show.call(this);
}
function toggleReadDir() {
var o = options,
next = options.readDirRtl ? "ltr" : "rtl";
swrite('greaddir', next);
slider.className = "no-transition";
options = {};
setOptions(o);
updateOffset(true);
window.getComputedStyle(slider).opacity; // force a restyle
slider.className = "";
if (tt.en)
tt.show.call(this);
}
function setVmode() {
var v = vid();
ebi('bbox-vmode').style.display = v ? '' : 'none';
if (!v)
return;
var msg = 'When video ends, ', tts = '', lbl;
if (vloop) {
lbl = 'Loop';
msg += 'repeat it';
tts = '$NHotkey: V';
}
else if (vnext) {
lbl = 'Cont';
msg += 'continue to next';
tts = '$NHotkey: C';
}
else {
lbl = 'Stop';
msg += 'just stop'
}
btnVmode.setAttribute('aria-label', msg);
btnVmode.setAttribute('tt', msg + tts);
btnVmode.textContent = lbl;
swrite('vmode', lbl[0]);
v.loop = vloop
if (vloop && v.paused)
v.play();
}
function tglVmode() {
if (vloop) {
vnext = true;
vloop = false;
}
else if (vnext)
vnext = false;
else
vloop = true;
setVmode();
if (tt.en)
tt.show.call(this);
}
function findfile() {
var thumb = currentGallery[currentIndex].imageElement,
name = vsplit(thumb.href)[1].split('?')[0],
files = msel.getall();
for (var a = 0; a < files.length; a++)
if (vsplit(files[a].vp)[1] == name)
return [name, a, files, ebi(files[a].id)];
}
function tglfull() {
try {
if (isFullscreen)
document.exitFullscreen();
else
ebi('bbox-overlay').requestFullscreen();
}
catch (ex) {
if (IPHONE)
alert('sorry, apple decided to make this impossible on iphones (should work on ipad tho)');
else
alert(ex);
}
}
function setzoom() {
var sel = clgot(btnZoom, 'on')
clmod(ebi('bbox-overlay'), 'fill', sel);
btnState(btnZoom, sel);
}
function tglsel() {
var o = findfile()[3];
clmod(o.closest('tr'), 'sel', 't');
msel.selui();
selbg();
}
function dlpic() {
var url = addq(findfile()[3].href, 'cache');
dl_file(url);
}
function selbg() {
var img = vidimg(),
thumb = currentGallery[currentIndex].imageElement,
name = vsplit(thumb.href)[1].split('?')[0],
files = msel.getsel(),
sel = false;
for (var a = 0; a < files.length; a++)
if (vsplit(files[a].vp)[1] == name)
sel = true;
clmod(ebi('bbox-overlay'), 'sel', sel);
img.style.borderRadius = sel ? '1em' : '';
btnState(btnSel, sel);
}
function btnState(btn, sel) {
clmod(btn, 'on', sel);
}
function keyUpHandler(e) {
if (anymod(e))
return;
var k = (e.key || e.code) + '';
if (k == "Space" || k == "Spacebar" || k == " ") {
un_pp = Date.now();
return ev(e);
}
}
var passiveSupp = false;
try {
var opts = {
get passive() {
passiveSupp = true;
return false;
}
};
window.addEventListener('test', null, opts);
window.removeEventListener('test', null, opts);
}
catch (ex) {
passiveSupp = false;
}
var passiveEvent = passiveSupp ? { passive: false } : null;
var nonPassiveEvent = passiveSupp ? { passive: true } : null;
function bindEvents() {
bind(document, 'keydown', keyDownHandler);
bind(document, 'keyup', keyUpHandler);
bind(document, 'fullscreenchange', onFSC);
bind(overlay, 'click', overlayClickHandler);
bind(overlay, 'wheel', overlayWheelHandler);
bind(btnPrev, 'click', showLeftImage);
bind(btnNext, 'click', showRightImage);
bind(btnClose, 'click', hideOverlay);
bind(btnVmode, 'click', tglVmode);
bind(btnHelp, 'click', halp);
bind(btnAnim, 'click', anim);
bind(btnReadDir, 'click', toggleReadDir);
bind(btnRotL, 'click', rotl);
bind(btnRotR, 'click', rotr);
bind(btnSel, 'click', tglsel);
bind(btnFull, 'click', tglfull);
bind(slider, 'contextmenu', contextmenuHandler);
bind(overlay, 'touchstart', touchstartHandler, nonPassiveEvent);
bind(overlay, 'touchmove', touchmoveHandler, passiveEvent);
bind(overlay, 'touchend', touchendHandler);
bind(document, 'focus', trapFocusInsideOverlay, true);
}
function unbindEvents() {
unbind(document, 'keydown', keyDownHandler);
unbind(document, 'keyup', keyUpHandler);
unbind(document, 'fullscreenchange', onFSC);
unbind(overlay, 'click', overlayClickHandler);
unbind(overlay, 'wheel', overlayWheelHandler);
unbind(btnPrev, 'click', showLeftImage);
unbind(btnNext, 'click', showRightImage);
unbind(btnClose, 'click', hideOverlay);
unbind(btnVmode, 'click', tglVmode);
unbind(btnHelp, 'click', halp);
unbind(btnAnim, 'click', anim);
unbind(btnReadDir, 'click', toggleReadDir);
unbind(btnRotL, 'click', rotl);
unbind(btnRotR, 'click', rotr);
unbind(btnSel, 'click', tglsel);
unbind(btnFull, 'click', tglfull);
unbind(slider, 'contextmenu', contextmenuHandler);
unbind(overlay, 'touchstart', touchstartHandler, nonPassiveEvent);
unbind(overlay, 'touchmove', touchmoveHandler, passiveEvent);
unbind(overlay, 'touchend', touchendHandler);
unbind(document, 'focus', trapFocusInsideOverlay, true);
timer.rm(rotn);
}
function prepareOverlay(gallery, userOptions) {
if (currentGallery === gallery)
return;
currentGallery = gallery;
setOptions(userOptions);
slider.innerHTML = '';
imagesElements.length = 0;
var imagesFiguresIds = [];
var imagesCaptionsIds = [];
for (var i = 0, fullImage; i < gallery.length; i++) {
fullImage = mknod('div', 'baguette-img-' + i);
fullImage.className = 'full-image';
imagesElements.push(fullImage);
imagesFiguresIds.push('bbox-figure-' + i);
imagesCaptionsIds.push('bbox-figcaption-' + i);
slider.appendChild(imagesElements[i]);
}
overlay.setAttribute('aria-labelledby', imagesFiguresIds.join(' '));
overlay.setAttribute('aria-describedby', imagesCaptionsIds.join(' '));
}
function setOptions(newOptions) {
if (!newOptions)
newOptions = {};
for (var item in defaults) {
options[item] = defaults[item];
if (typeof newOptions[item] !== 'undefined')
options[item] = newOptions[item];
}
var an = options.animation = sread('ganim', anims) || anims[ANIM ? 0 : 2];
btnAnim.textContent = ['⇄', '⮺', '⚡'][anims.indexOf(an)];
btnAnim.setAttribute('tt', 'animation: ' + an);
options.readDirRtl = sread('greaddir') === "rtl";
var msg;
if (options.readDirRtl) {
btnReadDir.innerText = "rtl";
msg = "browse from right to left";
slider.style.display = "flex";
slider.style.flexDirection = "row-reverse";
} else {
btnReadDir.innerText = "ltr";
msg = "browse from left to right";
slider.style.flexDirection = "";
slider.style.display = "block";
}
btnReadDir.setAttribute("tt", msg);
btnReadDir.setAttribute("aria-label", msg);
slider.style.transition = (options.animation === 'fadeIn' ? 'opacity .3s ease' :
options.animation === 'slideIn' ? '' : 'none');
if (options.buttons === 'auto' && ('ontouchstart' in window || currentGallery.length === 1))
options.buttons = false;
QS('#bbox-next .btn').style.display = QS('#bbox-prev .btn').style.display = (options.buttons ? '' : 'none');
}
function showOverlay(chosenImageIndex) {
if (options.noScrollbars) {
var a = document.documentElement.style.overflowY,
b = document.body.style.overflowY;
if (a != 'hidden' || b != 'scroll')
scrollCSS = [a, b];
document.documentElement.style.overflowY = 'hidden';
document.body.style.overflowY = 'scroll';
}
if (overlay.style.display === 'block')
return;
bindEvents();
currentIndex = chosenImageIndex;
touch = {
count: 0,
startX: null,
startY: null
};
loadImage(currentIndex, function () {
preloadNext(currentIndex);
preloadPrev(currentIndex);
});
show_buttons(0);
updateOffset();
overlay.style.display = 'block';
// Fade in overlay
setTimeout(function () {
clmod(overlay, 'visible', 1);
if (options.bodyClass && document.body.classList)
document.body.classList.add(options.bodyClass);
if (options.afterShow)
options.afterShow();
}, 50);
if (options.onChange && !url_ts)
options.onChange.call(currentGallery, currentIndex, imagesElements.length);
url_ts = null;
documentLastFocus = document.activeElement;
btnClose.focus();
isOverlayVisible = true;
}
function hideOverlay(e, dtor) {
ev(e);
playvid(false);
removeFromCache('#files');
if (options.noScrollbars) {
document.documentElement.style.overflowY = scrollCSS[0];
document.body.style.overflowY = scrollCSS[1];
}
try {
if (document.fullscreenElement)
document.exitFullscreen();
}
catch (ex) { }
isFullscreen = false;
if (toast.tag == 'bb-ded')
toast.hide();
if (dtor || overlay.style.display === 'none')
return;
if (options.duringHide)
options.duringHide();
sethash('');
unbindEvents();
// Fade out and hide the overlay
clmod(overlay, 'visible');
setTimeout(function () {
overlay.style.display = 'none';
if (options.bodyClass && document.body.classList)
document.body.classList.remove(options.bodyClass);
qsr('#bbox-halp');
if (options.afterHide)
options.afterHide();
options.refocus && documentLastFocus && documentLastFocus.focus();
isOverlayVisible = false;
unvid();
unfig();
}, 250);
}
function unvid(keep) {
var vids = QSA('#bbox-overlay video');
for (var a = vids.length - 1; a >= 0; a--) {
var v = vids[a];
if (v == keep)
continue;
unbind(v, 'touchstart', vtouch, nonPassiveEvent);
unbind(v, 'error', lerr);
v.src = '';
v.load();
var p = v.parentNode;
p.removeChild(v);
p.parentNode.removeChild(p);
}
}
function unfig(keep) {
var figs = QSA('#bbox-overlay figure'),
npre = options.preload || 0,
k = [];
if (keep === undefined)
keep = -9;
for (var a = keep - npre; a <= keep + npre; a++)
k.push('bbox-figure-' + a);
for (var a = figs.length - 1; a >= 0; a--) {
var f = figs[a];
if (!has(k, f.getAttribute('id')))
f.parentNode.removeChild(f);
}
}
function lerr() {
var t;
try {
t = this.getAttribute('src');
t = uricom_dec(t.split('/').pop().split('?')[0]);
}
catch (ex) { }
t = 'Failed to open ' + (t?t:'file');
console.log('bb-ded', t);
t += '\n\nEither the file is corrupt, or your browser does not understand the file format or codec';
try {
t += "\n\nerr#" + this.error.code + ", " + this.error.message;
}
catch (ex) { }
this.ded = esc(t);
if (this === vidimg())
toast.err(20, this.ded, 'bb-ded');
}
function loadImage(index, callback) {
var imageContainer = imagesElements[index];
var galleryItem = currentGallery[index];
if (typeof imageContainer === 'undefined' || typeof galleryItem === 'undefined')
return; // out-of-bounds or gallery dirty
if (imageContainer.querySelector('img, video'))
// was loaded, cb and bail
return callback ? callback() : null;
// maybe unloaded video
while (imageContainer.firstChild)
imageContainer.removeChild(imageContainer.firstChild);
var imageElement = galleryItem.imageElement,
imageSrc = galleryItem.href || imageElement.href,
is_vid = re_v.test(imageSrc),
thumbnailElement = imageElement.querySelector('img, video'),
imageCaption = typeof options.captions === 'function' ?
options.captions.call(currentGallery, imageElement, index) :
imageElement.getAttribute('data-caption') || imageElement.title;
imageSrc = addq(imageSrc, 'cache');
if (is_vid && index != currentIndex)
return; // no preload
var figure = mknod('figure', 'bbox-figure-' + index);
figure.innerHTML = '<div class="bbox-spinner">' +
'<div class="bbox-double-bounce1"></div>' +
'<div class="bbox-double-bounce2"></div>' +
'</div>';
if (options.captions && imageCaption) {
var figcaption = mknod('figcaption', 'bbox-figcaption-' + index);
figcaption.innerHTML = imageCaption;
figure.appendChild(figcaption);
}
imageContainer.appendChild(figure);
var image = mknod(is_vid ? 'video' : 'img');
clmod(imageContainer, 'vid', is_vid);
bind(image, 'error', lerr);
bind(image, is_vid ? 'loadedmetadata' : 'load', function () {
// Remove loader element
qsr('#baguette-img-' + index + ' .bbox-spinner');
if (!options.async && callback)
callback();
});
image.setAttribute('src', imageSrc);
if (is_vid) {
image.volume = clamp(fcfg_get('vol', dvol / 100), 0, 1);
image.setAttribute('controls', 'controls');
image.setAttribute('playsinline', '1');
// ios ignores poster
image.onended = vidEnd;
image.onplay = image.onpause = ppHandler;
}
image.alt = thumbnailElement ? thumbnailElement.alt || '' : '';
if (options.titleTag && imageCaption)
image.title = imageCaption;
figure.appendChild(image);
if (is_vid && window.afilt)
afilt.apply(undefined, image);
if (options.async && callback)
callback();
}
function ppHandler() {
var now = Date.now();
if (now - un_pp < 50) {
un_pp = 0;
return playpause(); // browser undid space hotkey
}
show_buttons(this.paused ? 0 : 1);
}
function showRightImage(e) {
ev(e);
var dir = options.readDirRtl ? -1 : 1;
return show(currentIndex + dir);
}
function showLeftImage(e) {
ev(e);
var dir = options.readDirRtl ? 1 : -1;
return show(currentIndex + dir);
}
function showNextImageIgnoreReadDir(e) {
ev(e);
return show(currentIndex + 1);
}
function showPreviousImageIgnoreReadDir(e) {
ev(e);
return show(currentIndex - 1);
}
function showFirstImage(e) {
if (e)
e.preventDefault();
return show(0);
}
function showLastImage(e) {
if (e)
e.preventDefault();
return show(currentGallery.length - 1);
}
function show(index, gallery) {
gallery = gallery || currentGallery;
if (!isOverlayVisible && index >= 0 && index < gallery.length) {
prepareOverlay(gallery, options);
showOverlay(index);
return true;
}
if (index < 0)
return bounceAnimation(options.readDirRtl ? 'right' : 'left');
if (index >= imagesElements.length)
return bounceAnimation(options.readDirRtl ? 'left' : 'right');
var orot;
try {
orot = vidimg().getAttribute('rot');
vid().pause();
}
catch (ex) { }
currentIndex = index;
loadImage(currentIndex, function () {
preloadNext(currentIndex);
preloadPrev(currentIndex);
});
updateOffset();
var im = vidimg();
if (im && im.ded)
toast.err(20, im.ded, 'bb-ded');
else if (toast.tag == 'bb-ded')
toast.hide();
if (orot && im.getAttribute('rot') === null)
rotn(orot / 90, 1);
if (options.animation == 'none')
unvid(vid());
else
setTimeout(function () {
unvid(vid());
}, 100);
unfig(index);
if (options.onChange)
options.onChange.call(currentGallery, currentIndex, imagesElements.length);
return true;
}
var prev_cw = 0, prev_ch = 0, unrot_timer = null;
function rotn(n, asap) {
var el = vidimg(),
orot = parseInt(el.getAttribute('rot') || 0),
frot = orot + (n || 0) * 90;
if (!frot && !orot)
return; // reflow noop
var co = ebi('bbox-overlay'),
cw = co.clientWidth,
ch = co.clientHeight;
if (!n && prev_cw === cw && prev_ch === ch)
return; // reflow noop
clmod(el, 'asap', asap);
prev_cw = cw;
prev_ch = ch;
var rot = frot,
iw = el.naturalWidth || el.videoWidth,
ih = el.naturalHeight || el.videoHeight,
magic = 4, // idk, works in enough browsers
dl = el.closest('div').querySelector('figcaption a'),
vw = cw,
vh = ch - dl.offsetHeight + magic,
pmag = Math.min(vw / ih, vh / iw),
wmag = Math.min(vw / iw, vh / ih);
if (!options.bbzoom) {
pmag = Math.min(1, pmag);
wmag = Math.min(1, wmag);
}
while (rot < 0) rot += 360;
while (rot >= 360) rot -= 360;
var q = rot == 90 || rot == 270 ? 1 : 0,
mag = q ? pmag : wmag;
el.style.cssText = 'max-width:none; max-height:none; position:absolute; display:block; margin:0';
if (!orot) {
el.style.width = iw * wmag + 'px';
el.style.height = ih * wmag + 'px';
el.style.left = (vw - iw * wmag) / 2 + 'px';
el.style.top = (vh - ih * wmag) / 2 - magic + 'px';
q = el.offsetHeight;
}
el.style.width = iw * mag + 'px';
el.style.height = ih * mag + 'px';
el.style.left = (vw - iw * mag) / 2 + 'px';
el.style.top = (vh - ih * mag) / 2 - magic + 'px';
el.style.transform = 'rotate(' + frot + 'deg)';
el.setAttribute('rot', frot);
timer.add(rotn);
if (!rot) {
clearTimeout(unrot_timer);
unrot_timer = setTimeout(unrot, 300);
}
}
function rotl() {
rotn(-1);
}
function rotr() {
rotn(1);
}
function unrot() {
var el = vidimg(),
orot = el.getAttribute('rot'),
rot = parseInt(orot || 0);
while (rot < 0) rot += 360;
while (rot >= 360) rot -= 360;
if (rot || orot === null)
return;
clmod(el, 'nt', 1);
el.setAttribute('rot', 0);
el.removeAttribute("style");
rot = el.offsetHeight;
clmod(el, 'nt');
timer.rm(rotn);
}
function vid() {
if (currentIndex >= imagesElements.length)
return;
return imagesElements[currentIndex].querySelector('video');
}
function vidimg() {
if (currentIndex >= imagesElements.length)
return;
return imagesElements[currentIndex].querySelector('img, video');
}
function playvid(play) {
if (!play) {
timer.rm(loopchk);
loopA = loopB = null;
}
var v = vid();
if (!v)
return;
v[play ? 'play' : 'pause']();
if (play && loopA !== null && v.currentTime < loopA)
v.currentTime = loopA;
}
function playpause() {
var v = vid();
if (v)
v[v.paused ? "play" : "pause"]();
}
function relseek(sec) {
var v = vid(),
t = v && v.currentTime;
if (isNum(t))
v.currentTime = t + sec;
}
function vidEnd() {
if (this == vid() && vnext)
showNextImageIgnoreReadDir();
}
function setloop(side) {
var v = vid();
if (!v)
return;
var t = v.currentTime;
if (side == 1) loopA = t;
if (side == 2) loopB = t;
if (side)
toast.inf(5, 'Loop' + (side == 1 ? 'A' : 'B') + ': ' + f2f(t, 2));
if (loopB !== null) {
timer.add(loopchk);
sethash(location.hash.slice(1).split('&')[0] + '&t=' + (loopA || 0) + '-' + loopB);
}
}
function loopchk() {
if (loopB === null)
return;
var v = vid();
if (!v || v.paused || v.currentTime < loopB)
return;
v.currentTime = loopA || 0;
}
function urltime(txt) {
url_ts = txt;
}
function mp_ctl() {
var v = vid();
if (!vmute && v && mp.au && !mp.au.paused) {
mp.fade_out();
resume_mp = true;
}
else if (resume_mp && (vmute || !v) && mp.au && mp.au.paused) {
mp.fade_in();
resume_mp = false;
}
}
function show_buttons(v) {
clmod(ebi('bbox-overlay'), 'immersive', v);
}
function bounceAnimation(direction) {
slider.className = options.animation == 'slideIn' ? 'bounce-from-' + direction : 'eog';
setTimeout(function () {
slider.className = '';
}, 300);
return false;
}
function updateOffset(noTransition) {
var dir = options.readDirRtl ? 1 : -1,
offset = dir * currentIndex * 100 + '%',
xform = slider.style.perspective !== undefined;
if (options.animation === 'fadeIn' && !noTransition) {
slider.style.opacity = 0;
setTimeout(function () {
xform ?
slider.style.transform = 'translate3d(' + offset + ',0,0)' :
slider.style.left = offset;
slider.style.opacity = 1;
}, 100);
} else {
xform ?
slider.style.transform = 'translate3d(' + offset + ',0,0)' :
slider.style.left = offset;
}
playvid(false);
var v = vid();
if (v) {
playvid(true);
v.muted = vmute;
v.loop = vloop;
if (url_ts) {
var seek = ('' + url_ts).split('-');
v.currentTime = seek[0];
if (seek.length > 1) {
loopA = parseFloat(seek[0]);
loopB = parseFloat(seek[1]);
setloop();
}
}
bind(v, 'touchstart', vtouch, nonPassiveEvent);
}
selbg();
mp_ctl();
setVmode();
var el = vidimg();
if (el.getAttribute('rot'))
timer.add(rotn);
else
timer.rm(rotn);
var ctime = 0;
el.onclick = v ? null : function (e) {
var rc = e.target.getBoundingClientRect(),
x = e.clientX - rc.left,
fx = x / (rc.right - rc.left);
// if (fx < 0.3)
// return showLeftImage();
// if (fx > 0.7)
// return showRightImage();
show_buttons('t');
if (Date.now() - ctime <= 500 && !IPHONE)
tglfull();
ctime = Date.now();
};
var prev = QS('.full-image.vis');
if (prev)
clmod(prev, 'vis');
clmod(el.closest('div'), 'vis', 1);
}
function preloadNext(index) {
if (index - currentIndex >= options.preload)
return;
loadImage(index + 1, function () {
preloadNext(index + 1);
});
}
function preloadPrev(index) {
if (currentIndex - index >= options.preload)
return;
loadImage(index - 1, function () {
preloadPrev(index - 1);
});
}
function bind(element, event, callback, options) {
element.addEventListener(event, callback, options);
}
function unbind(element, event, callback, options) {
element.removeEventListener(event, callback, options);
}
function destroyPlugin() {
hideOverlay(undefined, true);
unbindEvents();
clearCachedData();
document.getElementsByTagName('body')[0].removeChild(ebi('bbox-overlay'));
data = {};
currentGallery = [];
currentIndex = 0;
}
return {
run: run,
show: show,
showNext: showRightImage,
showPrevious: showLeftImage,
relseek: relseek,
urltime: urltime,
playpause: playpause,
hide: hideOverlay,
destroy: destroyPlugin
};
})();
J_BBX = 2;