exarcheia-vue-silentbox
Version:
A simple lightbox inspired Vue.js component.
989 lines • 63.7 kB
JavaScript
var VueSilentbox = (function (exports) {
'use strict';
var VideoUrlDecoderMixin = {
methods: {
getYoutubeVideoId(url) {
const regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
const match = url.match(regExp);
return match !== undefined && match[7] !== undefined ? match[7] : false;
},
getVimeoVideoId(url) {
return /(vimeo(pro)?\.com)\/(?:[^\d]+)?(\d+)\??(.*)?$/.exec(url)[3];
}
}
};
var itemMixin = {
mixins: [VideoUrlDecoderMixin],
data: () => ({
sizeVideoYoutube: 'maxresdefault',
sizesYoutube: ['maxresdefault', 'sddefault', 'hqdefault'],
youtubeDomain: '//img.youtube.com/vi',
vimeoDomain: '//vimeo.com/api/v2/video'
}),
methods: {
isEmbedVideo(itemSrc) {
const supportedVideoServices = ['youtube.com', 'youtu.be', 'vimeo.com'];
return supportedVideoServices.some(service => {
return itemSrc.includes(service);
});
},
isLocalVideo(itemSrc) {
const supportedVideoServices = ['.mp4', '.ogg', '.webm', '.mov', '.flv', '.wmv', '.mkv'];
return supportedVideoServices.some(service => {
return itemSrc.includes(service);
});
},
async getYoutubeThumbnail(videoId) {
for (const size of this.sizesYoutube) {
const url = await new Promise(resolve => {
try {
const image = new Image();
image.src = `${location.protocol}${this.youtubeDomain}/${videoId}/${size}.jpg`;
image.onload = ({
target
}) => {
resolve(target.width !== 120 ? target.src : false);
};
image.onerror = () => resolve(false);
} catch (e) {
return false;
}
});
if (url) {
return url;
}
}
},
async getThumbnail(src) {
if (src.includes('youtube.com') || src.includes('youtu.be')) {
return await this.getYoutubeThumbnail(this.getYoutubeVideoId(src));
} else if (src.includes('vimeo.com')) {
const videoId = this.getVimeoVideoId(src);
const videoDetails = await this.httpGet(`${location.protocol}${this.vimeoDomain}/${videoId}.json`);
return videoDetails[0].thumbnail_large;
} else {
return src;
}
},
async httpGet(url) {
const result = await fetch(url);
return await result.json();
}
}
};
//
var script = {
name: 'SilentboxOverlay',
mixins: [itemMixin],
props: {
overlayItem: {
type: Object,
default: () => ({
src: '',
srcSet: '',
sources: [],
description: ''
})
},
visible: {
type: Boolean,
default: false
},
totalItems: {
type: Number,
default: 1
}
},
data() {
return {
touchHandling: {
posX: 0,
posY: 0
},
animationName: 'silentbox-animation__swipe-left'
};
},
computed: {
/**
* Check if there are other sources of the image
*/
isSources() {
return Array.isArray(this.overlayItem.sources) && this.overlayItem.sources.length;
},
/**
* Get other image sources
*/
getSources() {
return this.overlayItem.sources;
}
},
created() {
// Listen to key events.
window.addEventListener('keyup', event => {
// Escape: 27
if (event.which === 27) {
this.closeSilentboxOverlay();
} // Right arrow: 39
if (event.which === 39) {
this.moveToNextItem();
} // Left arrow: 37
if (event.which === 37) {
this.moveToPreviousItem();
}
}); // Disable browser scrolling.
this.enableScrollLock();
},
methods: {
/**
* Registers the finger position on website so we can later calculate users
* swipe direction.
*/
touchStart(event) {
const {
clientX: x,
clientY: y
} = event.touches[0];
this.touchHandling.posX = x;
this.touchHandling.posY = y;
},
/**
* Handles touch movement events, at the moment only swipe left and right
* are supported, but later could be extended with up and down swipes.
* It should be good to implement some kind of minimal swipe lenght support.
*/
touchMove(event) {
const {
clientX: x,
clientY: y
} = event.touches[0];
const {
posX,
posY
} = this.touchHandling;
if (posX === 0 || posY === 0) {
return;
}
const xDiff = posX - x;
const yDiff = posY - y;
if (Math.abs(xDiff) > Math.abs(yDiff)) {
if (xDiff > 0) {
// left
this.moveToNextItem();
} else {
// right
this.moveToPreviousItem();
}
} // reset
this.touchHandling.posX = 0;
this.touchHandling.posY = 0;
},
/**
* This method enables browser scrolling lock which prevent from horizontal
* and vertical scrolling. This makes touch navigation less confusing.
*/
enableScrollLock() {
if (!document.body.classList.contains('silentbox-is-opened')) {
return document.body.classList.add('silentbox-is-opened');
}
},
/**
* This method removes browser scrolling lock.
*/
removeScrollLock() {
if (document.body.classList.contains('silentbox-is-opened')) {
return document.body.classList.remove('silentbox-is-opened');
}
},
/**
* Move to next item.
*/
moveToNextItem() {
this.animationName = 'silentbox-animation__swipe-left';
this.$emit('requestNextSilentBoxItem');
},
/**
* Move to previous item.
*/
moveToPreviousItem() {
this.animationName = 'silentbox-animation__swipe-right';
this.$emit('requestPreviousSilentBoxItem');
},
/**
* Hide silentbox overlay.
*/
closeSilentboxOverlay() {
this.removeScrollLock();
this.$emit('closeSilentboxOverlay');
},
/**
* Search for known video services URLs and return their players if recognized.
* Unrecognized URLs are handled as images.
*
* @param {string} url
* @return {string}
*/
handleUrl(url) {
if (url.includes('youtube.com') || url.includes('youtu.be')) {
return this.parseYoutubeVideo(url);
} else if (url.includes('vimeo')) {
return this.parseVimeoVideo(url);
}
return url;
},
/**
* Get embed URL for youtube.com
*
* @param {string} url
* @return {string}
*/
parseYoutubeVideo(url) {
let videoUrl = '';
const videoId = this.getYoutubeVideoId(url);
if (videoId) {
videoUrl = `${location.protocol}//www.youtube.com/embed/${videoId}?rel=0`;
if (this.overlayItem.autoplay) {
videoUrl += '&autoplay=1';
}
if (!this.overlayItem.controls) {
videoUrl += '&controls=0';
}
}
return videoUrl;
},
/**
* Get embed URL for vimeo.com
*
* @param {string} url
* @return {string}
*/
parseVimeoVideo(url) {
let videoUrl = '';
const vimoId = /(vimeo(pro)?\.com)\/(?:[^\d]+)?(\d+)\??(.*)?$/.exec(url)[3];
if (vimoId !== undefined) {
videoUrl = `${location.protocol}//player.vimeo.com/video/${vimoId}?rel=0`;
if (this.overlayItem.autoplay === 'autoplay') {
videoUrl += '&autoplay=1';
}
}
return videoUrl;
}
}
};
function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier
/* server only */
, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
if (typeof shadowMode !== 'boolean') {
createInjectorSSR = createInjector;
createInjector = shadowMode;
shadowMode = false;
} // Vue.extend constructor export interop.
const options = typeof script === 'function' ? script.options : script; // render functions
if (template && template.render) {
options.render = template.render;
options.staticRenderFns = template.staticRenderFns;
options._compiled = true; // functional template
if (isFunctionalTemplate) {
options.functional = true;
}
} // scopedId
if (scopeId) {
options._scopeId = scopeId;
}
let hook;
if (moduleIdentifier) {
// server build
hook = function (context) {
// 2.3 injection
context = context || // cached call
this.$vnode && this.$vnode.ssrContext || // stateful
this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; // functional
// 2.2 with runInNewContext: true
if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
context = __VUE_SSR_CONTEXT__;
} // inject component styles
if (style) {
style.call(this, createInjectorSSR(context));
} // register component module identifier for async chunk inference
if (context && context._registeredComponents) {
context._registeredComponents.add(moduleIdentifier);
}
}; // used by ssr in case component is cached and beforeCreate
// never gets called
options._ssrRegister = hook;
} else if (style) {
hook = shadowMode ? function (context) {
style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
} : function (context) {
style.call(this, createInjector(context));
};
}
if (hook) {
if (options.functional) {
// register for functional component in vue file
const originalRender = options.render;
options.render = function renderWithStyleInjection(h, context) {
hook.call(context);
return originalRender(h, context);
};
} else {
// inject component registration as beforeCreate hook
const existing = options.beforeCreate;
options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
}
}
return script;
}
const isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase());
function createInjector(context) {
return (id, style) => addStyle(id, style);
}
let HEAD;
const styles = {};
function addStyle(id, css) {
const group = isOldIE ? css.media || 'default' : id;
const style = styles[group] || (styles[group] = {
ids: new Set(),
styles: []
});
if (!style.ids.has(id)) {
style.ids.add(id);
let code = css.source;
if (css.map) {
// https://developer.chrome.com/devtools/docs/javascript-debugging
// this makes source maps inside style tags work properly in Chrome
code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; // http://stackoverflow.com/a/26603875
code += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + ' */';
}
if (!style.element) {
style.element = document.createElement('style');
style.element.type = 'text/css';
if (css.media) style.element.setAttribute('media', css.media);
if (HEAD === undefined) {
HEAD = document.head || document.getElementsByTagName('head')[0];
}
HEAD.appendChild(style.element);
}
if ('styleSheet' in style.element) {
style.styles.push(code);
style.element.styleSheet.cssText = style.styles.filter(Boolean).join('\n');
} else {
const index = style.ids.size - 1;
const textNode = document.createTextNode(code);
const nodes = style.element.childNodes;
if (nodes[index]) style.element.removeChild(nodes[index]);
if (nodes.length) style.element.insertBefore(textNode, nodes[index]);else style.element.appendChild(textNode);
}
}
}
/* script */
const __vue_script__ = script;
/* template */
var __vue_render__ = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _vm.visible
? _c(
"div",
{
staticClass: "silentbox-overlay",
on: { touchstart: _vm.touchStart, touchmove: _vm.touchMove }
},
[
_c(
"button",
{
staticClass: "silentbox-overlay__close",
on: {
click: function($event) {
$event.stopPropagation();
return _vm.closeSilentboxOverlay($event)
}
}
},
[_c("i", { staticClass: "icon" })]
),
_vm._v(" "),
_c("div", { staticClass: "silentbox-overlay__background" }),
_vm._v(" "),
_c(
"transition",
{ attrs: { name: _vm.animationName, mode: "out-in" } },
[
_c(
"div",
{
key: _vm.overlayItem.src,
staticClass: "silentbox-overlay__content",
on: {
click: function($event) {
$event.stopPropagation();
return _vm.closeSilentboxOverlay($event)
}
}
},
[
_c("div", { staticClass: "silentbox-overlay__embed" }, [
_c("div", { staticClass: "silentbox-overlay__container" }, [
_vm.isEmbedVideo(_vm.overlayItem.src)
? _c("iframe", {
attrs: {
allow:
"accelerometer; " +
(!!_vm.overlayItem.autoplay && "autoplay;") +
" encrypted-media; gyroscope; picture-in-picture",
src: _vm.handleUrl(_vm.overlayItem.src),
frameborder: "0",
width: "100%",
height: "100%",
allowfullscreen: ""
}
})
: _vm.isLocalVideo(_vm.overlayItem.src)
? _c(
"div",
{ staticClass: "silentbox-overlay__frame" },
[
_c("video", {
staticClass: "silentbox-overlay__embed",
attrs: {
src: _vm.overlayItem.src,
autoplay: _vm.overlayItem.autoplay,
controls: ""
}
})
]
)
: _c(
"picture",
{
staticClass: "silentbox-overlay__picture",
on: {
click: function($event) {
$event.stopPropagation();
return _vm.moveToNextItem($event)
}
}
},
[
_vm.isSources
? _vm._l(_vm.getSources, function(source) {
return _c("source", {
key: source.src,
attrs: {
srcset: source.srcSet,
media: source.media,
src: source.src,
type: source.type
}
})
})
: _vm._e(),
_vm._v(" "),
_c("img", {
attrs: {
srcset: _vm.overlayItem.srcSet
? _vm.overlayItem.srcSet
: _vm.overlayItem.src,
src: _vm.overlayItem.src,
alt: _vm.overlayItem.alt,
width: "auto",
height: "auto"
}
})
],
2
)
]),
_vm._v(" "),
_vm.overlayItem.description
? _c(
"p",
{ staticClass: "silentbox-overlay__description" },
[
_vm._v(
"\n " +
_vm._s(_vm.overlayItem.description) +
"\n "
)
]
)
: _vm._e()
])
]
)
]
),
_vm._v(" "),
_vm.totalItems > 1
? _c("div", { staticClass: "silentbox-overlay__buttons" }, [
_c(
"button",
{
staticClass:
"silentbox-overlay__buttons-arrow silentbox-overlay__buttons-arrow--previous",
on: {
click: function($event) {
$event.stopPropagation();
return _vm.moveToPreviousItem($event)
}
}
},
[_c("i", { staticClass: "arrow-icon" })]
),
_vm._v(" "),
_c(
"button",
{
staticClass:
"silentbox-overlay__buttons-arrow silentbox-overlay__buttons-arrow--next",
on: {
click: function($event) {
$event.stopPropagation();
return _vm.moveToNextItem($event)
}
}
},
[_c("i", { staticClass: "arrow-icon" })]
)
])
: _vm._e()
],
1
)
: _vm._e()
};
var __vue_staticRenderFns__ = [];
__vue_render__._withStripped = true;
/* style */
const __vue_inject_styles__ = function (inject) {
if (!inject) return
inject("data-v-575b43a3_0", { source: ".silentbox-is-opened {\n overflow: hidden;\n}\n.silentbox-overlay {\n position: fixed;\n left: 0;\n top: 0;\n z-index: 999;\n display: block;\n width: 100vw;\n height: 100vh;\n}\n.silentbox-overlay__picture {\n cursor: pointer;\n}\n.silentbox-overlay__frame {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.silentbox-overlay__background {\n position: absolute;\n left: 0;\n top: 0;\n display: block;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(20px);\n}\n.silentbox-overlay__content {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.silentbox-overlay__embed {\n width: 75%;\n height: 80%;\n}\n.silentbox-overlay__embed img,\n.silentbox-overlay__embed iframe {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n display: block;\n margin: auto;\n max-width: 100%;\n max-height: 100%;\n box-shadow: 0 0 1.5rem rgba(0, 0, 0, 0.45);\n background-color: #000;\n}\n.silentbox-overlay__embed:active, .silentbox-overlay__embed:focus, .silentbox-overlay__embed:hover {\n outline: none;\n}\n.silentbox-overlay__container {\n position: relative;\n margin: 0;\n width: 100%;\n height: 100%;\n text-align: center;\n}\n.silentbox-overlay__description {\n display: block;\n padding-top: 1rem;\n text-align: center;\n color: #fff;\n}\n.silentbox-overlay__buttons-arrow {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 6%;\n height: 100%;\n transition: 0.3s;\n cursor: pointer;\n}\n.silentbox-overlay__buttons-arrow .arrow-icon {\n border-top: 2px solid #fff;\n border-left: 2px solid #fff;\n width: 1.5rem;\n height: 1.5rem;\n}\n.silentbox-overlay__buttons-arrow:hover {\n background: rgba(0, 0, 0, 0.2);\n}\n.silentbox-overlay__buttons-arrow--previous {\n left: 0;\n}\n.silentbox-overlay__buttons-arrow--previous .arrow-icon {\n transform: rotate(-45deg);\n}\n.silentbox-overlay__buttons-arrow--previous:hover .arrow-icon, .silentbox-overlay__buttons-arrow--previous:focus .arrow-icon {\n opacity: 0.7;\n animation-name: pulsingPrevious;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n}\n.silentbox-overlay__buttons-arrow--next {\n right: 0;\n}\n.silentbox-overlay__buttons-arrow--next .arrow-icon {\n transform: rotate(135deg);\n}\n.silentbox-overlay__buttons-arrow--next:hover .arrow-icon, .silentbox-overlay__buttons-arrow--next:focus .arrow-icon {\n opacity: 0.7;\n animation-name: pulsingNext;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n}\n@media (max-width: 1199px) {\n.silentbox-overlay__buttons-arrow {\n width: 12%;\n}\n}\n.silentbox-overlay__close {\n position: absolute;\n right: 7%;\n top: 16px;\n z-index: 2000;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5em;\n height: 2.5em;\n color: #fff;\n cursor: pointer;\n}\n.silentbox-overlay__close .icon {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.silentbox-overlay__close .icon::before {\n transform: rotate(-45deg);\n}\n.silentbox-overlay__close .icon::before, .silentbox-overlay__close .icon::after {\n content: \"\";\n position: absolute;\n width: 100%;\n height: 2.5px;\n background: #fff;\n}\n.silentbox-overlay__close .icon::after {\n transform: rotate(45deg);\n}\n.silentbox-overlay__close:hover {\n opacity: 0.75;\n}\n@media (max-width: 1199px) {\n.silentbox-overlay__close {\n width: 1.8em;\n height: 1.8em;\n}\n}\n@media (max-width: 1199px) {\n.silentbox-overlay__close {\n right: 13%;\n}\n}\n.silentbox-overlay .silentbox-animation__swipe-left-enter-active {\n opacity: 0;\n transform: translateX(25vw);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-left-leave-active {\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-left-enter-to {\n opacity: 1;\n transform: translateX(0);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-left-leave-to {\n opacity: 0;\n transform: translateX(-25vw);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-enter-active {\n opacity: 0;\n transform: translateX(-25vw);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-leave-active {\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-enter-to {\n opacity: 1;\n transform: translateX(0);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-leave-to {\n opacity: 0;\n transform: translateX(25vw);\n transition: all 0.3s ease;\n}\n@keyframes pulsingNext {\n0% {\n margin-right: 0;\n animation-timing-function: ease-in;\n}\n25% {\n margin-right: 0.25rem;\n animation-timing-function: ease-in;\n}\n50% {\n margin-right: 0.5rem;\n animation-timing-function: ease-in;\n}\n75% {\n margin-right: 0.25rem;\n animation-timing-function: ease-in;\n}\n100% {\n margin-right: 0;\n animation-timing-function: ease-in;\n}\n}\n@keyframes pulsingPrevious {\n0% {\n margin-left: 0;\n animation-timing-function: ease-in;\n}\n25% {\n margin-left: 0.25rem;\n animation-timing-function: ease-in;\n}\n50% {\n margin-left: 0.5rem;\n animation-timing-function: ease-in;\n}\n75% {\n margin-left: 0.25rem;\n animation-timing-function: ease-in;\n}\n100% {\n margin-left: 0;\n animation-timing-function: ease-in;\n}\n}\n\n/*# sourceMappingURL=overlay.vue.map */", map: {"version":3,"sources":["N:\\Projects\\silentbox\\src\\components\\overlay.vue","overlay.vue"],"names":[],"mappings":"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","file":"overlay.vue","sourcesContent":["<template>\n <div\n class=\"silentbox-overlay\"\n v-if=\"visible\"\n @touchstart=\"touchStart\"\n @touchmove=\"touchMove\"\n >\n <button\n class=\"silentbox-overlay__close\"\n @click.stop=\"closeSilentboxOverlay\"\n >\n <i class=\"icon\" />\n </button>\n <div class=\"silentbox-overlay__background\" />\n <transition :name=\"animationName\" mode=\"out-in\">\n <div\n class=\"silentbox-overlay__content\"\n :key=\"overlayItem.src\"\n @click.stop=\"closeSilentboxOverlay\"\n >\n <div class=\"silentbox-overlay__embed\">\n <div class=\"silentbox-overlay__container\">\n <!-- embed video rendering -->\n <iframe\n v-if=\"isEmbedVideo(overlayItem.src)\"\n :allow=\"`accelerometer; ${\n !!overlayItem.autoplay && 'autoplay;'\n } encrypted-media; gyroscope; picture-in-picture`\"\n :src=\"handleUrl(overlayItem.src)\"\n frameborder=\"0\"\n width=\"100%\"\n height=\"100%\"\n allowfullscreen\n />\n <!-- local video rendering -->\n <div\n v-else-if=\"isLocalVideo(overlayItem.src)\"\n class=\"silentbox-overlay__frame\"\n >\n <video\n :src=\"overlayItem.src\"\n :autoplay=\"overlayItem.autoplay\"\n controls\n class=\"silentbox-overlay__embed\"\n />\n </div>\n <!-- local/embed image rendering -->\n <picture\n v-else\n @click.stop=\"moveToNextItem\"\n class=\"silentbox-overlay__picture\"\n >\n <template v-if=\"isSources\">\n <source\n v-for=\"source in getSources\"\n :key=\"source.src\"\n :srcset=\"source.srcSet\"\n :media=\"source.media\"\n :src=\"source.src\"\n :type=\"source.type\"\n />\n </template>\n <img\n :srcset=\"\n overlayItem.srcSet ? overlayItem.srcSet : overlayItem.src\n \"\n :src=\"overlayItem.src\"\n :alt=\"overlayItem.alt\"\n width=\"auto\"\n height=\"auto\"\n />\n </picture>\n </div>\n <p\n class=\"silentbox-overlay__description\"\n v-if=\"overlayItem.description\"\n >\n {{ overlayItem.description }}\n </p>\n </div>\n </div>\n </transition>\n\n <div class=\"silentbox-overlay__buttons\" v-if=\"totalItems > 1\">\n <button\n class=\"silentbox-overlay__buttons-arrow silentbox-overlay__buttons-arrow--previous\"\n @click.stop=\"moveToPreviousItem\"\n >\n <i class=\"arrow-icon\" />\n </button>\n <button\n class=\"silentbox-overlay__buttons-arrow silentbox-overlay__buttons-arrow--next\"\n @click.stop=\"moveToNextItem\"\n >\n <i class=\"arrow-icon\" />\n </button>\n </div>\n </div>\n</template>\n\n<script>\nimport itemMixim from './../mixins/item'\n\nexport default {\n name: 'SilentboxOverlay',\n mixins: [itemMixim],\n props: {\n overlayItem: {\n type: Object,\n default: () => ({\n src: '',\n srcSet: '',\n sources: [],\n description: '',\n }),\n },\n visible: {\n type: Boolean,\n default: false,\n },\n totalItems: {\n type: Number,\n default: 1,\n },\n },\n data() {\n return {\n touchHandling: {\n posX: 0,\n posY: 0,\n },\n animationName: 'silentbox-animation__swipe-left',\n }\n },\n computed: {\n /**\n * Check if there are other sources of the image\n */\n isSources() {\n return (\n Array.isArray(this.overlayItem.sources) &&\n this.overlayItem.sources.length\n )\n },\n /**\n * Get other image sources\n */\n getSources() {\n return this.overlayItem.sources\n },\n },\n created() {\n // Listen to key events.\n window.addEventListener('keyup', (event) => {\n // Escape: 27\n if (event.which === 27) {\n this.closeSilentboxOverlay()\n }\n // Right arrow: 39\n if (event.which === 39) {\n this.moveToNextItem()\n }\n // Left arrow: 37\n if (event.which === 37) {\n this.moveToPreviousItem()\n }\n })\n\n // Disable browser scrolling.\n this.enableScrollLock()\n },\n methods: {\n /**\n * Registers the finger position on website so we can later calculate users\n * swipe direction.\n */\n touchStart(event) {\n const { clientX: x, clientY: y } = event.touches[0]\n this.touchHandling.posX = x\n this.touchHandling.posY = y\n },\n /**\n * Handles touch movement events, at the moment only swipe left and right\n * are supported, but later could be extended with up and down swipes.\n * It should be good to implement some kind of minimal swipe lenght support.\n */\n touchMove(event) {\n const { clientX: x, clientY: y } = event.touches[0]\n const { posX, posY } = this.touchHandling\n\n if (posX === 0 || posY === 0) {\n return\n }\n\n const xDiff = posX - x\n const yDiff = posY - y\n\n if (Math.abs(xDiff) > Math.abs(yDiff)) {\n if (xDiff > 0) {\n // left\n this.moveToNextItem()\n } else {\n // right\n this.moveToPreviousItem()\n }\n } else {\n if (yDiff > 0) {\n // up\n } else {\n // down\n // this.closeSilentboxOverlay()\n }\n }\n\n // reset\n this.touchHandling.posX = 0\n this.touchHandling.posY = 0\n },\n /**\n * This method enables browser scrolling lock which prevent from horizontal\n * and vertical scrolling. This makes touch navigation less confusing.\n */\n enableScrollLock() {\n if (!document.body.classList.contains('silentbox-is-opened')) {\n return document.body.classList.add('silentbox-is-opened')\n }\n },\n /**\n * This method removes browser scrolling lock.\n */\n removeScrollLock() {\n if (document.body.classList.contains('silentbox-is-opened')) {\n return document.body.classList.remove('silentbox-is-opened')\n }\n },\n /**\n * Move to next item.\n */\n moveToNextItem() {\n this.animationName = 'silentbox-animation__swipe-left'\n this.$emit('requestNextSilentBoxItem')\n },\n /**\n * Move to previous item.\n */\n moveToPreviousItem() {\n this.animationName = 'silentbox-animation__swipe-right'\n this.$emit('requestPreviousSilentBoxItem')\n },\n /**\n * Hide silentbox overlay.\n */\n closeSilentboxOverlay() {\n this.removeScrollLock()\n this.$emit('closeSilentboxOverlay')\n },\n /**\n * Search for known video services URLs and return their players if recognized.\n * Unrecognized URLs are handled as images.\n *\n * @param {string} url\n * @return {string}\n */\n handleUrl(url) {\n if (url.includes('youtube.com') || url.includes('youtu.be')) {\n return this.parseYoutubeVideo(url)\n } else if (url.includes('vimeo')) {\n return this.parseVimeoVideo(url)\n }\n return url\n },\n /**\n * Get embed URL for youtube.com\n *\n * @param {string} url\n * @return {string}\n */\n parseYoutubeVideo(url) {\n let videoUrl = ''\n const videoId = this.getYoutubeVideoId(url)\n\n if (videoId) {\n videoUrl = `${location.protocol}//www.youtube.com/embed/${videoId}?rel=0`\n\n if (this.overlayItem.autoplay) {\n videoUrl += '&autoplay=1'\n }\n if (!this.overlayItem.controls) {\n videoUrl += '&controls=0'\n }\n }\n\n return videoUrl\n },\n /**\n * Get embed URL for vimeo.com\n *\n * @param {string} url\n * @return {string}\n */\n parseVimeoVideo(url) {\n let videoUrl = ''\n const vimoId = /(vimeo(pro)?\\.com)\\/(?:[^\\d]+)?(\\d+)\\??(.*)?$/.exec(\n url\n )[3]\n\n if (vimoId !== undefined) {\n videoUrl = `${location.protocol}//player.vimeo.com/video/${vimoId}?rel=0`\n if (this.overlayItem.autoplay === 'autoplay') {\n videoUrl += '&autoplay=1'\n }\n }\n\n return videoUrl\n },\n },\n}\n</script>\n\n<style lang=\"scss\">\n// Colours used in silentbox\n$main: #fff;\n$accent: #58e8d2;\n$bg: #000;\n\n.silentbox-is-opened {\n overflow: hidden;\n}\n\n.silentbox-overlay {\n position: fixed;\n left: 0;\n top: 0;\n z-index: 999;\n display: block;\n width: 100vw;\n height: 100vh;\n\n &__picture {\n cursor: pointer;\n }\n\n &__frame {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n }\n\n &__background {\n position: absolute;\n left: 0;\n top: 0;\n display: block;\n width: 100%;\n height: 100%;\n background: rgba($bg, 0.75);\n backdrop-filter: blur(20px);\n }\n\n &__content {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n }\n\n &__embed {\n width: 75%;\n height: 80%;\n\n img,\n iframe {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n display: block;\n margin: auto;\n max-width: 100%;\n max-height: 100%;\n box-shadow: 0 0 1.5rem rgba($bg, 0.45);\n background-color: $bg;\n }\n\n &:active,\n &:focus,\n &:hover {\n outline: none;\n }\n }\n\n &__container {\n position: relative;\n margin: 0;\n width: 100%;\n height: 100%;\n text-align: center;\n }\n\n &__description {\n display: block;\n padding-top: 1rem;\n text-align: center;\n color: $main;\n }\n\n &__buttons {\n &-arrow {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 6%;\n height: 100%;\n transition: 0.3s;\n cursor: pointer;\n\n .arrow-icon {\n border-top: 2px solid $main;\n border-left: 2px solid $main;\n width: 1.5rem;\n height: 1.5rem;\n }\n\n &:hover {\n background: rgba($bg, 0.2);\n }\n\n &--previous {\n left: 0;\n\n .arrow-icon {\n transform: rotate(-45deg);\n }\n\n &:hover .arrow-icon,\n &:focus .arrow-icon {\n opacity: 0.7;\n animation-name: pulsingPrevious;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n }\n }\n\n &--next {\n right: 0;\n\n .arrow-icon {\n transform: rotate(135deg);\n }\n\n &:hover .arrow-icon,\n &:focus .arrow-icon {\n opacity: 0.7;\n animation-name: pulsingNext;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n }\n }\n\n @media (max-width: 1199px) {\n width: 12%;\n }\n }\n }\n\n &__close {\n position: absolute;\n right: 7%;\n top: 16px;\n z-index: 2000;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5em;\n height: 2.5em;\n color: $main;\n cursor: pointer;\n\n .icon {\n display: flex;\n align-items: center;\n justify-content: center;\n\n &::before {\n transform: rotate(-45deg);\n }\n\n &::before,\n &::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 2.5px;\n background: $main;\n }\n\n &::after {\n transform: rotate(45deg);\n }\n }\n\n &:hover {\n opacity: 0.75;\n }\n\n @media (max-width: 1199px) {\n width: 1.8em;\n height: 1.8em;\n }\n\n @media (max-width: 1199px) {\n right: 13%;\n }\n }\n\n // Transitions\n .silentbox-animation__swipe-left-enter-active {\n opacity: 0;\n transform: translateX(25vw);\n transition: all 0.3s ease;\n }\n\n .silentbox-animation__swipe-left-leave-active {\n transition: all 0.3s ease;\n }\n\n .silentbox-animation__swipe-left-enter-to {\n opacity: 1;\n transform: translateX(0);\n transition: all 0.3s ease;\n }\n\n .silentbox-animation__swipe-left-leave-to {\n opacity: 0;\n transform: translateX(-25vw);\n transition: all 0.3s ease;\n }\n\n .silentbox-animation__swipe-right-enter-active {\n opacity: 0;\n transform: translateX(-25vw);\n transition: all 0.3s ease;\n }\n\n .silentbox-animation__swipe-right-leave-active {\n transition: all 0.3s ease;\n }\n\n .silentbox-animation__swipe-right-enter-to {\n opacity: 1;\n transform: translateX(0);\n transition: all 0.3s ease;\n }\n\n .silentbox-animation__swipe-right-leave-to {\n opacity: 0;\n transform: translateX(25vw);\n transition: all 0.3s ease;\n }\n\n // Animations\n @keyframes pulsingNext {\n 0% {\n margin-right: 0;\n animation-timing-function: ease-in;\n }\n\n 25% {\n margin-right: 0.25rem;\n animation-timing-function: ease-in;\n }\n\n 50% {\n margin-right: 0.5rem;\n animation-timing-function: ease-in;\n }\n\n 75% {\n margin-right: 0.25rem;\n animation-timing-function: ease-in;\n }\n\n 100% {\n margin-right: 0;\n animation-timing-function: ease-in;\n }\n }\n\n @keyframes pulsingPrevious {\n 0% {\n margin-left: 0;\n animation-timing-function: ease-in;\n }\n\n 25% {\n margin-left: 0.25rem;\n animation-timing-function: ease-in;\n }\n\n 50% {\n margin-left: 0.5rem;\n animation-timing-function: ease-in;\n }\n\n 75% {\n margin-left: 0.25rem;\n animation-timing-function: ease-in;\n }\n\n 100% {\n margin-left: 0;\n animation-timing-function: ease-in;\n }\n }\n}\n</style>\n",".silentbox-is-opened {\n overflow: hidden;\n}\n\n.silentbox-overlay {\n position: fixed;\n left: 0;\n top: 0;\n z-index: 999;\n display: block;\n width: 100vw;\n height: 100vh;\n}\n.silentbox-overlay__picture {\n cursor: pointer;\n}\n.silentbox-overlay__frame {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.silentbox-overlay__background {\n position: absolute;\n left: 0;\n top: 0;\n display: block;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(20px);\n}\n.silentbox-overlay__content {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n.silentbox-overlay__embed {\n width: 75%;\n height: 80%;\n}\n.silentbox-overlay__embed img,\n.silentbox-overlay__embed iframe {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n display: block;\n margin: auto;\n max-width: 100%;\n max-height: 100%;\n box-shadow: 0 0 1.5rem rgba(0, 0, 0, 0.45);\n background-color: #000;\n}\n.silentbox-overlay__embed:active, .silentbox-overlay__embed:focus, .silentbox-overlay__embed:hover {\n outline: none;\n}\n.silentbox-overlay__container {\n position: relative;\n margin: 0;\n width: 100%;\n height: 100%;\n text-align: center;\n}\n.silentbox-overlay__description {\n display: block;\n padding-top: 1rem;\n text-align: center;\n color: #fff;\n}\n.silentbox-overlay__buttons-arrow {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 6%;\n height: 100%;\n transition: 0.3s;\n cursor: pointer;\n}\n.silentbox-overlay__buttons-arrow .arrow-icon {\n border-top: 2px solid #fff;\n border-left: 2px solid #fff;\n width: 1.5rem;\n height: 1.5rem;\n}\n.silentbox-overlay__buttons-arrow:hover {\n background: rgba(0, 0, 0, 0.2);\n}\n.silentbox-overlay__buttons-arrow--previous {\n left: 0;\n}\n.silentbox-overlay__buttons-arrow--previous .arrow-icon {\n transform: rotate(-45deg);\n}\n.silentbox-overlay__buttons-arrow--previous:hover .arrow-icon, .silentbox-overlay__buttons-arrow--previous:focus .arrow-icon {\n opacity: 0.7;\n animation-name: pulsingPrevious;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n}\n.silentbox-overlay__buttons-arrow--next {\n right: 0;\n}\n.silentbox-overlay__buttons-arrow--next .arrow-icon {\n transform: rotate(135deg);\n}\n.silentbox-overlay__buttons-arrow--next:hover .arrow-icon, .silentbox-overlay__buttons-arrow--next:focus .arrow-icon {\n opacity: 0.7;\n animation-name: pulsingNext;\n animation-duration: 1s;\n animation-iteration-count: infinite;\n}\n@media (max-width: 1199px) {\n .silentbox-overlay__buttons-arrow {\n width: 12%;\n }\n}\n.silentbox-overlay__close {\n position: absolute;\n right: 7%;\n top: 16px;\n z-index: 2000;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5em;\n height: 2.5em;\n color: #fff;\n cursor: pointer;\n}\n.silentbox-overlay__close .icon {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.silentbox-overlay__close .icon::before {\n transform: rotate(-45deg);\n}\n.silentbox-overlay__close .icon::before, .silentbox-overlay__close .icon::after {\n content: \"\";\n position: absolute;\n width: 100%;\n height: 2.5px;\n background: #fff;\n}\n.silentbox-overlay__close .icon::after {\n transform: rotate(45deg);\n}\n.silentbox-overlay__close:hover {\n opacity: 0.75;\n}\n@media (max-width: 1199px) {\n .silentbox-overlay__close {\n width: 1.8em;\n height: 1.8em;\n }\n}\n@media (max-width: 1199px) {\n .silentbox-overlay__close {\n right: 13%;\n }\n}\n.silentbox-overlay .silentbox-animation__swipe-left-enter-active {\n opacity: 0;\n transform: translateX(25vw);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-left-leave-active {\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-left-enter-to {\n opacity: 1;\n transform: translateX(0);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-left-leave-to {\n opacity: 0;\n transform: translateX(-25vw);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-enter-active {\n opacity: 0;\n transform: translateX(-25vw);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-leave-active {\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-enter-to {\n opacity: 1;\n transform: translateX(0);\n transition: all 0.3s ease;\n}\n.silentbox-overlay .silentbox-animation__swipe-right-leave-to {\n opacity: 0;\n transform: translateX(25vw);\n transition: all 0.3s ease;\n}\n@keyframes pulsingNext {\n 0% {\n margin-right: 0;\n animation-timing-function: ease-in;\n }\n 25% {\n margin-right: 0.25rem;\n animation-timing-function: ease-in;\n }\n 50% {\n margin-right: 0.5rem;\n animation-timing-function: ease-in;\n }\n 75% {\n margin-right: 0.25rem;\n animation-timing-function: ease-in;\n }\n 100% {\n margin-right: 0;\n animation-timing-function: ease-in;\n }\n}\n@keyframes pulsingPrevious {\n 0% {\n margin-left: 0;\n animation-timing-function: ease-in;\n }\n 25% {\n margin-left: 0.25rem;\n animation-timing-function: ease-in;\n }\n 50% {\n margin-left: 0.5rem;\n animation-timing-function: ease-in;\n }\n 75% {\n margin-left: 0.25rem;\n animation-timing-function: ease-in;\n }\n 100% {\n margin-left: 0;\n animation-timing-function: ease-in;\n }\n}\n\n/*# sourceMappingURL=overlay.vue.map */"]}, media: undefined });
};
/* scoped */
const __vue_scope_id__ = undefined;
/* module identifier */
const __vue_module_identifier__ = undefined;
/* functional template */
const __vue_is_functional_template__ = false;
/* style inject SSR */
/* style inject shadow dom */
const __vue_component__ = /*#__PURE__*/normalizeComponent(
{ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
__vue_inject_styles__,
__vue_script__,
__vue_scope_id__,
__vue_is_functional_template__,
__vue_module_identifier__,
false,
createInjector,
undefined,
undefined
);
//
var script$1 = {
name: 'silentboxGallery',
mixins: [itemMixin],
props: {
lazyLoading: {
type: Boolean,
default: true
},
previewCount: {
type: Number,
default: null
},
gallery: {
type: Array,
default: () => []
},
image: {
type: Object,
default: () => ({
src: '',
alt: '',
sources: [],
thumbnailWidth: 'auto',
thumbnailHeight: 'auto',
thumbnail: '',
thumbnailSources: [],
autoplay: false,
controls: true,
description: ''
})
}
},
components: {
'silentbox-overlay': __vue_component__
},
data: () => ({
overlay: {
item: {
src: '',
alt: '',
sources: [],
thumbnailWidth: 'auto',
thumbnailHeight: 'auto',
thumbnail: '',
thumbnailSources: [],
autoplay: false,
controls: true,
description: ''
},
visible: false,
currentItem: 0
}
}),
computed: {
totalItems() {
return this.gallery.length || 1;
},
previewGallery() {
if (Number.isInteger(this.previewCount)) {
return this.gallery.slice(0, this.previewCount).map(item => {
return { ...this.overlay.item,
...item,
thumbnail: this.setThumbnail(item),
autoplay: this.setAutoplay(item)
};
});
}
return this.galleryItems;
},
galleryItems() {
if (this.gallery.length > 0) {
return this.gallery.map(item => {
return { ...this.overlay.item,
...item,
thumbnail: this.setThumbnail(item),
autoplay: this.setAutoplay(item)
};
});
}
return [{ ...this.overlay.item,
...this.image,
thumbnail: this.setThumbnail(this.image)
}];
}
},
methods: {
isSources(image) {
return this.isNotEmptyThumbnailSources(image) || this.isNotEmptySources(image);
},
isNotEmptyThumbnailSources(image) {
return Array.isArray(image.thumbnailSources) && image.thumbnailSources.length;
},
isNotEmptySources(image) {
return Array.isArray(image.sources) && image.sources.length;
},
getSources(image) {
return this.isNotEmptyThumbnailSources(image) ? image.thumbnailSources : image.sources;
},
openOverlay(image, index = 0) {
this.overlay.visible = true;
this.overlay.item = image;
this.overlay.currentItem = index;
this.$emit('silentbox-overlay-opened', {
item: image
});
},
hideOverlay() {
this.overlay.visible = false;
this.$emit('silentbox-overlay-hidden', {
item: this.overlay.item
});
},
showNextItem() {
let newItemIndex = this.overlay.currentItem + 1;
newItemIndex = newItemIndex <= this.galleryItems.length - 1 ? newItemIndex : 0;
this.overlay.item = this.galleryItems[newItemIndex];
this.overlay.currentItem = newItemIndex;
this.$emit('silentbox-overlay-next-item-displayed', {
item: this.overlay.item
});
},
showPreviousItem() {
let newItemIndex = this.overlay.currentItem - 1;
newItemIndex = newItemIndex > -1 ? newItemIndex : this.galleryItems.length - 1;
this.overlay.item = this.galleryItems[newItemIndex];
this.overlay.currentItem = newItemIndex;
this.$emit('silentbox-overlay-previous-item-displayed', {
item: this.overlay.item
});
},
setAutoplay(item) {
return item.autoplay ? 'autoplay' : '';
},
async setThumbnail(item) {
if (this.isEmbedVideo(item.src) && item.thumbnail === undefined) {
return await this.getThumbnail(item.src);
}
return item.thumbnail || item.src;
}
}
};
/* script */
const __vue_script__$1 = script$1;
/* template */
var __vue_render__$1 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
return _c(
"section",
{ attrs: { id: "silentbox-gallery" } },
[
_vm._t("default"),
_vm._v(" "),
_vm._l(_vm.previewGallery, function(image, index) {
return _c(
"div",
{
key: image.src,
staticClass: "silentbox-item",
on: {
click: function($event) {
return _vm.openOverlay(image, index)
}
}
},
[
_vm._t(
"silentbox-item",
[
_c(
"picture",
[
_vm.isSources(image)
? _vm._l(_vm.getSources(image), function(source) {
return _c("source", {
key: source.src,
attrs: {
srcset: source.srcSet,
media: source.media,
src: source.src,
type: source.type
}
})
})
: _vm._e(),
_vm._v(" "),
_c("img", {
attrs: {
loading: _vm.lazyLoading ? "lazy" : "eager",
src: image.thumbnail,
alt: image.alt,
width: image.thumbnailWidth,
height: image.thumbnailHeight
}
})
],
2
)
],
{ silentboxItem: image }
)
],
2
)
}),
_vm._v(" "),
_vm.overlay.visible
? _c("silentbox-overlay", {
attrs: {
"overlay-item": _vm.overlay.item,
visible: _vm.overlay.visible,
"total-items": _vm.totalItems
},
on: {
closeSilentboxOverlay: _vm.hideOverlay,
requestNextSilentBoxItem: _vm.showNextItem,
requestPreviousSilentBoxItem: _vm.showPreviousItem
}
})
: _vm._e()
],
2
)
};
var __vue_staticRenderFns__$1 = [];
__vue_render__$1._withStripped = true;
/* style */
const __vue_inject_styles__$1 = function (inject) {
if (!inject) return
inject("data-v-f1fdbc9a_0", { source: ".silentbox-item {\n display: inline-block;\n text-decoration: underline;\n cursor: pointer;\n}\n\n/*# sourceMappingURL=gallery.vue.map */", map: {"version":3,"sources":["N:\\Projects\\silentbox\\src\\components\\gallery.vue","gallery.vue"],"names":[],"mappings":"AA2MA;EACA,qBAAA;EACA,0BAAA;EACA,eAAA;AC1MA;;AAEA,sCAAsC","file":"gallery.vue","sourcesContent":["<template>\n <section id=\"silentbox-gallery\">\n <slot />\n <div\n v-for=\"(image, index) in previewGallery\"\n :key=\"image.src\"\n @click=\"openOverlay(image, index)\"\n class=\"silentbox-item\"\n >\n <slot name=\"silentbox-item\" v-bind:silentboxItem=\"image\">\n <picture>\n <template v-if=\"isSources(image)\">\n <source\n v-for=\"source in getSources(image)\"\n :key=\"source.src\"\n :srcset=\"source.srcSet\"\n :media=\"source.media\"\n :src=\"source.src\"\n :type=\"source.type\"\n />\n </template>\n <img\n :loading=\"lazyLoading ? 'lazy' : 'eager'\"\n :src=\"image.thumbnail\"\n :alt=\"image.alt\"\n :width=\"image.thumbnailWidth\"\n :height=\"image.thumbnailHeight\"\n />\n </picture>\n </slot>\n </div>\n <silentbox-overlay\n v-if=\"overlay.visible\"\n :overlay-item=\"overlay.item\"\n :visible=\"overlay.visible\"\n :total-items=\"totalItems\"\n @closeSilentboxOverlay=\"hideOverlay\"\n @requestNextSilentBoxItem=\"showNextItem\"\n @requestPreviousSilentBoxItem=\"showPreviousItem\"\n />\n </section>\n</template>\n\n<script>\nimport overlay from './overlay.vue'\nimport itemMixin from './../mixins/item'\n\nexport default {\n name: 'silentboxGallery',\n mixins: [itemMixin],\n props: {\n lazyLoading: {\n type: Boolean,\n default: true,\n },\n previewCount: {\n type: Number,\n default: null,\n },\n gallery: {\n type: Array,\n default: () => [],\n },\n image: {\n type: Object,\n default: () => ({\n src: '',\n alt: '',\n sources: [],\n thumbnailWidth: 'auto',\n thumbnailHeight: 'auto',\n thumbnail: '',\n thumbnailSources: [],\n autoplay: false,\n controls: true,\n description: '',\n }),\n },\n },\n components: {\n 'silentbox-overlay': overlay,\n },\n data: () => ({\n overlay: {\n item: {\n src: '',\n alt: '',\n sources: [],\n thumbnailWidth: 'auto',\n thumbnailHeight: 'auto',\n thumbnail: '',\n thumbnailSources: [],\n autoplay: false,\n controls: true,\n description: '',\n },\n visible: false,\n currentItem: 0,\n },\n }),\n computed: {\n totalItems() {\n return this.gallery.length || 1\n },\n previewGallery() {\n if (Number.isInteger(this.previewCount)) {\n return this.gallery.slice(0, this.previewCount).map((item) => {\n return {\n ...this.overlay.item,\n ...item,\n thumbnail: this.setThumbnail(item),\n autoplay: this.setAutoplay(item),\n }\n })\n }\n return this.galleryItems\n },\n galleryItems() {\n if (this.gallery.length > 0) {\n return this.gallery.map((item) => {\n return {\n ...this.overlay.item,\n ...item,\n thumbnail: this.setThumbnail(item),\n autoplay: this.setAutoplay(item),\n }\n })\n }\n return [\n {\n ...this.overlay.item,\n ...this.image,\n thumbnail: this.setThumbnail(this.image),\n },\n ]\n },\n },\n methods: {\n isSources(image) {\n return (\n this.isNotEmptyThumbnailSources(image) || this.isNotEmptySources(image)\n )\n },\n isNotEmptyThumbnailSources(image) {\n return (\n Array.isArray(image.thumbnailSources) && image.thumbnailSources.length\n )\n },\n isNotEmptySources(image) {\n return Array.isArray(image.sources) && image.sources.length\n },\n getSources(image) {\n return this.isNotEmptyThumbnailSources(image)\n ? image.thumbnailSources\n : image.sources\n },\n openOverlay(image, index = 0) {\n this.overlay.visible = true\n this.overlay.item = image\n this.overlay.currentItem = index\n this.$emit('silentbox-overlay-opened', { item: image })\n },\n hideOverlay() {\n this.overlay.visible = false\n this.$emit('silentbox-overlay-hidden', { item: this.overlay.item })\n },\n showNextItem() {\n let newItemIndex = this.overlay.currentItem + 1\n newItemIndex =\n newItemIndex <= this.galleryItems.length - 1 ? newItemIndex : 0\n\n this.overlay.item = this.galleryItems[newItemIndex]\n this.overlay.currentItem = newItemIndex\n this.$emit('silentbox-overlay-next-item-displayed', {\n item: this.overlay.item,\n })\n },\n showPreviousItem() {\n let newItemIndex = this.overlay.currentItem - 1\n newItemIndex =\n newItemIndex > -1 ? newItemIndex : this.galleryItems.length - 1\n\n this.overlay.item = this.galleryItems[newItemIndex]\n this.overlay.currentItem = newItemIndex\n this.$emit('silentbox-overlay-previous-item-displayed', {\n item: this.overlay.item,\n })\n },\n setAutoplay(item) {\n return item.autoplay ? 'autoplay' : ''\n },\n async setThumbnail(item) {\n if (this.isEmbedVideo(item.src) && item.thumbnail === undefined) {\n return await this.getThumbnail(item.src)\n }\n\n return item.thumbnail || item.src\n },\n },\n}\n</script>\n\n<style lang=\"scss\">\n.silentbox-item {\n display: inline-block;\n text-decoration: underline;\n cursor: pointer;\n}\n</style>\n",".silentbox-item {\n display: inline-block;\n text-decoration: underline;\n cursor: pointer;\n}\n\n/*# sourceMappingURL=gallery.vue.map */"]}, media: undefined });
};
/* scoped */
const __vue_scope_id__$1 = undefined;
/* module identifier */
const __vue_module_identifier__$1 = undefined;
/* functional template */
const __vue_is_functional_template__$1 = false;
/* style inject SSR */
/* style inject shadow dom */
const __vue_component__$1 = /*#__PURE__*/normalizeComponent(
{ render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 },
__vue_inject_styles__$1,
__vue_script__$1,
__vue_scope_id__$1,
__vue_is_functional_template__$1,
__vue_module_identifier__$1,
false,
createInjector,
undefined,
undefined
);
const VueSilentbox = {};
VueSilentbox.install = function (Vue) {
Vue.mixin({
components: {
'silent-box': __vue_component__$1
}
});
Vue.prototype.$silentbox = {
/**
* Programatically open SilentBox overlay.
*
* @param {Object} image
*/
open: image => {
const OverlayClass = Vue.extend(__vue_component__);
const instance = new OverlayClass().$mount();
instance.$set(instance, 'visible', true);
instance.$set(instance, 'overlayItem', image); // Get the website body, so we can append false silentbox root to it later
const bodyRoot = document.getElementsByTagName('body')[0]; // Create false silentbox root
const silentboxRoot = document.createElement('div'); // Set ID to false silentbox root, so we can target it in some cases
silentboxRoot.setAttribute('id', 'silentbox--false-root'); // Register the elements
silentboxRoot.appendChild(instance.$el);
bodyRoot.appendChild(silentboxRoot);
instance.$on('closeSilentboxOverlay', () => {
// Remove and destroy the instance after closing.
silentboxRoot.remove();
instance.$destroy();
});
}
};
};
exports.default = VueSilentbox;
return exports;
}({}));