Description
Description
Hi, we are using lightGallery in a larger project where we use Sentry for error logging. For some time now we have been receiving thousands of errors that seem to be related to lightGallery.
Unfortunately I have not been able to reproduce these errors myself. That's the reason why I created this issue.
In the following a few stack traces from Sentry:
Cannot read properties of undefined (reading 'getBoundingClientRect')
{snip} is.core.index).find(".lg-image").first().get(),i=0,r=0,s=n.getBoundingClientRect();t?(i=n.offsetHeight*t,r=n.offsetWidth*t):e?(i=s.height+e* {snip}
Cannot read properties of undefined (reading 'width')
{snip} ,e,n,i){if(!(Math.abs(e)<=0)){var r,s,o=this.containerRect.width/2+this.containerRect.left,a=this.containerRect.height/2+this.containerRect. {snip}
undefined is not an object (evaluating 'this.containerRect.height')
{snip} t,e,n,i){if(!(Math.abs(e)<=0)){var r,s,o=this.containerRect.width/2+this.containerRect.left,a=this.containerRect.height/2+this.containerRect {snip}
In the project we use Vue 2 + Laravel and lightGallery as a normal JS bundle.
Many thanks in advance!
Steps to reproduce
Unfortunately, I can't provide a demo, even though that would be much better to understand where the error might be.
JS code that you use to initialize lightGallery.
<!-- Bild-Slider in der Lightbox -->
<template>
<div class="m-lightbox">
<transition name="fade-fast">
<!-- Benachrichtigung, dass der Link der Produktdetailseite in die Zwischenablage kopiert wurde -->
<div class="c-alert c-alert--success c-alert--success-buybox-image"
v-if="this.showLinkCopiedTooltip">
{{ __('product_box.tooltips.copied') }}
</div>
</transition>
</div>
</template>
<script>
import lightGallery from 'lightgallery';
import 'lightgallery/css/lightgallery.css';
import 'lightgallery/css/lg-thumbnail.css';
import 'lightgallery/css/lg-video.css';
import 'lightgallery/css/lg-zoom.css';
import lgThumbnail from 'lightgallery/plugins/thumbnail';
import lgZoom from 'lightgallery/plugins/zoom';
import lgVideo from 'lightgallery/plugins/video';
export default {
name: 'LightboxWrapper',
props: {
lightGallerySelector: {
type: String,
default: '#vendor-light-gallery',
},
hasInfoText: {
type: Boolean,
default: false,
},
},
data() {
return {
showLinkCopiedTooltip: false,
lightGalleryDOMElement: null,
currentImage: null,
};
},
methods: {
initLightGallery() {
this.$callIfElementExists(this.lightGallerySelector, el => {
// Docs: https://www.lightgalleryjs.com/docs/settings/
lightGallery(el, {
plugins: [lgThumbnail, lgZoom, lgVideo],
thumbnail: true,
animateThumb: false,
showThumbByDefault: false,
licenseKey: process.env.MIX_LIGHT_GALLERY_KEY,
speed: 500,
download: false, // zeige keinem Download-Icon an
autoplayFirstVideo: false, // starte Videos nicht automatisch
strings: {
previousSlide: this.__('slider.prev_button'),
nextSlide: this.__('slider.next_button'),
closeGallery: this.__('general.close'),
playVideo: this.__('Play video'),
},
mobileSettings: {
controls: false,
showCloseIcon: true,
},
});
this.lightGalleryDOMElement = el;
this.setUpLightGalleryEventListeners();
});
},
/**
* Initialisiere Event Listeners für die Bilder im Gallery
* */
setUpLightGalleryEventListeners() {
// Nachdem ein Bild geladen wurde, erstelle auch einen Event-Listener fürs Bild, für das Öffnen vom Kontextmenü
// Docs: https://www.lightgalleryjs.com/docs/events/#lgSlideItemLoad
this.lightGalleryDOMElement.addEventListener('lgSlideItemLoad', event => {
this.currentImage = document.querySelector(`#lg-item-1-${event.detail.index} img`);
if (!this.currentImage) return;
this.currentImage.addEventListener('contextmenu', this.imageEventListener);
});
// Bevor das Gallery geschlossen wird, bzw. bevor ein Bild gewechselt wird, entferne den Event-Listener
// Docs: https://www.lightgalleryjs.com/docs/events/#lgBeforeSlide
this.lightGalleryDOMElement.addEventListener('lgBeforeSlide', this.removeImageEventListener);
// Docs: https://www.lightgalleryjs.com/docs/events/#lgBeforeClose
this.lightGalleryDOMElement.addEventListener('lgBeforeClose', this.removeImageEventListener);
},
/**
* Die Funktion die immer auf Rechtsklick vom Bild ausgeführt wird
* */
imageEventListener(e) {
e.preventDefault();
this.$copyProductLinkToClipBoard();
},
/**
* Cleanup-Funktion für den Event-Listener
* */
removeImageEventListener() {
if (!this.currentImage) return;
this.currentImage.removeEventListener('contextmenu', this.imageEventListener);
this.currentImage = null;
},
},
mounted() {
this.initLightGallery();
},
};
</script>
Sample HTML markup
@php
$combinedImages = array_merge([data_get($article, 'images.main')], data_get($article, 'images.additional', []));
@endphp
<!-- Bild-Slider in der Buybox auf der Artikeldetailseite -->
<div class="m-buybox__wrap-img is-loading">
<transition name="fade-fast" v-cloak>
<!-- Benachrichtigung, dass der Link der Produktdetailseite in die Zwischenablage kopiert wurde -->
<div class="c-alert c-alert--success c-alert--success-buybox-image"
v-if="this.showLinkCopiedTooltip">
{{ __('product_box.tooltips.copied') }}
</div>
</transition>
<div class="m-buybox__slider">
<!-- Slider main container -->
<div class="c-slider c-slider--buybox swiper-container">
<!-- Additional required wrapper -->
{{-- Folgendes Markup, muss kompatibel mit Anforderungen aus lightGallery sein--}}
{{-- Für Doku dazu, siehe: https://www.lightgalleryjs.com/docs/getting-started/#the-markup --}}
<div class="c-slider__wrapper swiper-wrapper vendor-light-gallery" id="product-slider-wrapper">
@foreach($combinedImages as $key => $image)
@php
$productImage = new \App\Helpers\ImageHelper(data_get($image, 'src'));
$imageClasses = 'c-slider__image m-buybox__img';
if (data_get($image, 'src') !== null) $imageClasses .= ' has-pointer';
@endphp
<div data-src="{{ $productImage->getImage(2400) }}"
class="c-slider__item swiper-slide vendor-light-gallery-item"
data-sub-html="{{ __('product_box.product_image_info_text') }}"
@dragstart.prevent="()=> false"
@drop.prevent="()=> false"
@contextmenu.prevent="$copyProductLinkToClipBoard()">
<img
alt="{{ __('product_slider.product_img_alt', ['number' => $key, 'product' => trim(escapeZWNJChar(data_get($article, 'standard.title'))) ]) }}"
decoding="async"
height="566"
width="566"
v-on:error="$setFallbackImage($event, '600x600')"
class="{{ $imageClasses }}"
src="{{ $productImage->getImage(600) }}"
loading="{{ $key === 0 ? 'eager' : 'lazy' }}"
fetchpriority="{{ $key === 0 ? 'high' : 'low' }}"
>
@if(data_get($image, 'src'))
<span class="m-buybox__info-txt">{{ __('product_box.product_image_info_text') }}</span>
@endif
</div>
@endforeach
</div>
</div>
@if(count($combinedImages) > 1)
<div class="c-slider__nav c-slider__nav--prev swiper-button-prev"
aria-label="{{ __('slider.prev_button') }}"
role="button"
aria-controls="product-slider-wrapper">
<i class="c-slider__nav-icon icon icon-arrow-left"></i>
</div>
<div class="c-slider__nav c-slider__nav--next swiper-button-next"
aria-label="{{ __('slider.next_button') }}"
role="button"
aria-controls="product-slider-wrapper">
<i class="c-slider__nav-icon icon icon-arrow-left"></i>
</div>
@endif
@if(data_get($article, 'homologation.icon') && data_get($article, 'homologation.value'))
<button type="button"
title="{{ data_get($article, 'homologation.value') }}"
class="m-buybox__homologation"
@click.prevent="$modal.show('homologationModal', { homologation: '{{ data_get($article, 'homologation.value') }}' })">
<img src="{{ data_get($article, 'homologation.icon') }}"
alt="{{ escapeZWNJChar(data_get($article, 'homologation.value')) }}" decoding="async"
loading="eager">
</button>
@endif
</div>
@if(!empty(data_get($article, 'images.additional', [])) || !empty($videos))
<div class="m-buybox__thumbnails">
<div class="c-slider c-slider--thumbnails swiper-thumb-container">
<div class="c-slider__wrapper swiper-wrapper">
@unless(empty($videos))
<a href="#productvideo" v-anchor-scroll aria-label="{{ __('product_slider.jump_to_video') }}">
<div class="c-slider__item swiper-slide is-video-thumbnail-slide">
<i class="fa fa-play-circle-o"></i>
</div>
</a>
@endunless
@foreach($combinedImages as $key => $image)
@php($productImage = new \App\Helpers\ImageHelper(data_get($image, 'src')))
<div class="c-slider__item swiper-slide">
<img src="{{ $productImage->getImage(155) }}"
loading="eager"
decoding="async"
v-on:error="$setFallbackImage($event, '155x155')"
alt="{{ __('product_slider.product_img_alt', ['number' => $key, 'product' => trim(escapeZWNJChar(data_get($article, 'standard.title'))) ]) }}"
class="m-buybox__img c-slider__image">
</div>
@endforeach
</div>
</div>
</div>
@endif
<lightbox light-gallery-selector=".vendor-light-gallery"></lightbox>
</div>
Environment
- lightGallery version: 2.7.1