lightgallery
Version:
lightGallery is a feature-rich, modular JavaScript gallery plugin for building beautiful image and video galleries for the web and the mobile
1 lines • 234 kB
Source Map (JSON)
{"version":3,"file":"lightgallery.umd.js","sources":["../src/lg-events.ts","../src/lg-settings.ts","../src/lgQuery.ts","../src/lg-utils.ts","../src/lightgallery.ts","../src/index.ts"],"sourcesContent":["import { LightGallery } from './lightgallery';\nimport { VideoSource } from './plugins/video/types';\n\n/**\n * List of lightGallery events\n * All events should be documented here\n * Below interfaces are used to build the website documentations\n * */\nexport const lGEvents: {\n [key: string]: string;\n} = {\n afterAppendSlide: 'lgAfterAppendSlide',\n init: 'lgInit',\n hasVideo: 'lgHasVideo',\n containerResize: 'lgContainerResize',\n updateSlides: 'lgUpdateSlides',\n afterAppendSubHtml: 'lgAfterAppendSubHtml',\n beforeOpen: 'lgBeforeOpen',\n afterOpen: 'lgAfterOpen',\n slideItemLoad: 'lgSlideItemLoad',\n beforeSlide: 'lgBeforeSlide',\n afterSlide: 'lgAfterSlide',\n posterClick: 'lgPosterClick',\n dragStart: 'lgDragStart',\n dragMove: 'lgDragMove',\n dragEnd: 'lgDragEnd',\n beforeNextSlide: 'lgBeforeNextSlide',\n beforePrevSlide: 'lgBeforePrevSlide',\n beforeClose: 'lgBeforeClose',\n afterClose: 'lgAfterClose',\n rotateLeft: 'lgRotateLeft',\n rotateRight: 'lgRotateRight',\n flipHorizontal: 'lgFlipHorizontal',\n flipVertical: 'lgFlipVertical',\n autoplay: 'lgAutoplay',\n autoplayStart: 'lgAutoplayStart',\n autoplayStop: 'lgAutoplayStop',\n};\n\n// Follow the below format for the event documentation\n// @method is the method name when event is used with Angular/React components\n\n/**\n * Fired only once when lightGallery is initialized\n * @name lgInit\n * @method onInit\n * @example\n * const lg = document.getElementById('custom-events-demo');\n * // Perform any action on lightGallery initialization.\n * // Init event returns the plugin instance that can be used to call any lightGalley public method\n * let pluginInstance = null;\n * lg.addEventListener('lgInit', (event) => {\n * pluginInstance = event.detail.instance;\n * });\n * lightGallery(lg);\n * @see <a href=\"/docs/methods\">Methods<a>\n */\nexport interface InitDetail {\n /**\n * lightGallery plugin instance\n */\n instance: LightGallery;\n}\n\n/**\n * Fired when the slide content has been inserted into it's slide container.\n * @name lgAfterAppendSlide\n * @method onAfterAppendSlide\n */\nexport interface AfterAppendSlideEventDetail {\n /**\n * Index of the slide\n */\n index: number;\n}\n\n/**\n * Fired immediately before opening the gallery\n * @name lgBeforeOpen\n * @method onBeforeOpen\n */\nexport interface BeforeOpenDetail {}\n\n/**\n * Fired immediately after opening the gallery\n * @name lgAfterOpen\n * @method onAfterOpen\n */\nexport interface AfterOpenDetail {}\n\n/**\n * Fired once the media inside the slide has been completely loaded .\n * @name lgSlideItemLoad\n * @method onSlideItemLoad\n */\nexport interface SlideItemLoadDetail {\n /**\n * Index of the slide\n */\n index: number;\n /**\n * For the first slide, lightGallery adds some delay for displaying the loaded slide item.\n * This delay is required for the transition effect when the slide item is displayed\n * Respect the delay when you use this event\n */\n delay: number;\n\n // Will be true for the first slide\n isFirstSlide: boolean;\n}\n\n/**\n * Fired immediately before each slide transition.\n * @name lgBeforeSlide\n * @method onBeforeSlide\n * @example\n * const lg = document.getElementById('custom-events-demo');\n * // Perform any action before each slide transition\n * lg.addEventListener('lgBeforeSlide', (event) => {\n * const { index, prevIndex } = event.detail;\n * alert(index, prevIndex);\n * });\n * lightGallery(lg);\n */\nexport interface BeforeSlideDetail {\n /**\n * Index of the previous slide\n */\n prevIndex: number;\n /**\n * Index of the slide\n */\n index: number;\n /**\n * true if slide function called via touch event or mouse drag\n */\n fromTouch: boolean;\n /**\n * true if slide function called via thumbnail click\n */\n fromThumb: boolean;\n}\n\n/**\n * Fired immediately after each slide transition.\n * @name lgAfterSlide\n * @method onAfterSlide\n */\nexport interface AfterSlideDetail {\n /**\n * Index of the previous slide\n */\n prevIndex: number;\n /**\n * Index of the slide\n */\n index: number;\n /**\n * true if slide function called via touch event or mouse drag\n */\n fromTouch: boolean;\n /**\n * true if slide function called via thumbnail click\n */\n fromThumb: boolean;\n}\n\n/**\n * Fired when the video poster is clicked.\n * @name lgPosterClick\n * @method onPosterClick\n */\nexport interface PosterClickDetail {}\n\n/**\n * Fired when the drag event to move to different slide starts.\n * @name lgDragStart\n * @method onDragStart\n */\nexport interface DragStartDetail {}\n\n/**\n * Fired periodically during the drag operation.\n * @name lgDragMove\n * @method onDragMove\n */\nexport interface DragMoveDetail {}\n\n/**\n * Fired when the user has finished the drag operation\n * @name lgDragEnd\n * @method onDragEnd\n */\nexport interface DragEndDetail {}\n\n/**\n * Fired immediately before the start of the close process.\n * @name lgBeforeClose\n * @method onBeforeClose\n */\nexport interface BeforeCloseDetail {}\n\n/**\n * Fired immediately once lightGallery is closed.\n * @name lgAfterClose\n * @method onAfterClose\n */\nexport interface AfterCloseDetail {\n /**\n * lightGallery plugin instance\n */\n instance: LightGallery;\n}\n\n/**\n * Fired immediately before each \"next\" slide transition\n * @name lgBeforeNextSlide\n * @method onBeforeNextSlide\n */\nexport interface BeforeNextSlideDetail {\n /**\n * Index of the slide\n */\n index: number;\n /**\n * true if slide function called via touch event or mouse drag\n */\n fromTouch: boolean;\n}\n\n/**\n * Fired immediately before each \"prev\" slide transition\n * @name lgBeforePrevSlide\n * @method onBeforePrevSlide\n */\nexport interface BeforePrevSlideDetail {\n /**\n * Index of the slide\n */\n index: number;\n /**\n * true if slide function called via touch event or mouse drag\n */\n fromTouch: boolean;\n}\n\n/**\n * Fired when the sub-html content (ex : title/ description) has been appended into the slide.\n * @name lgAfterAppendSubHtml\n * @method onAfterAppendSubHtml\n */\nexport interface AfterAppendSubHtmlDetail {\n /**\n * Index of the slide\n */\n index: number;\n}\n\n/**\n * Fired when the lightGallery container has been resized.\n * @name lgContainerResize\n * @method onContainerResize\n */\nexport interface ContainerResizeDetail {\n /**\n * Index of the slide\n */\n index: number;\n}\n\n/**\n * Fired when lightGallery detects video slide\n * @name lgHasVideo\n * @method onHasVideo\n */\nexport interface HasVideoDetail {\n /**\n * Index of the slide,\n */\n index: number;\n /**\n * Video source\n */\n src: string;\n /**\n * HTML5 video source if available\n * <p>\n HTML5 video source = source: {\n src: string;\n type: string;\n }[];\n attributes: HTMLVideoElement;\n * </p>\n */\n html5Video: VideoSource;\n /**\n * True if video has poster\n */\n hasPoster: boolean;\n}\n\n/**\n * Fired when the image is rotated in anticlockwise direction\n * @name lgRotateLeft\n * @method onRotateLeft\n */\nexport interface RotateLeftDetail {\n /**\n * Index of the slide\n */\n index: number;\n}\n\n/**\n * Fired when the image is rotated in clockwise direction\n * @name lgRotateRight\n * @method onRotateRight\n */\nexport interface RotateRightDetail {\n /**\n * Index of the slide\n */\n index: number;\n}\n\n/**\n * Fired when the image is flipped horizontally\n * @name lgFlipHorizontal\n * @method onFlipHorizontal\n */\nexport interface FlipHorizontalDetail {\n /**\n * Index of the slide\n */\n index: number;\n}\n\n/**\n * Fired when the image is flipped vertically\n * @name lgFlipVertical\n * @method onFlipVertical\n */\nexport interface FlipVerticalDetail {\n /**\n * Index of the slide\n */\n index: number;\n}\n","import { GalleryItem } from './lg-utils';\nimport { LgQuery } from './lgQuery';\nimport { LightGallery } from './lightgallery';\nimport { AutoplaySettings } from './plugins/autoplay/lg-autoplay-settings';\nimport { CommentSettings } from './plugins/comment/lg-comment-settings';\nimport { FullscreenSettings } from './plugins/fullscreen/lg-fullscreen-settings';\nimport { HashSettings } from './plugins/hash/lg-hash-settings';\nimport { MediumZoomSettings } from './plugins/mediumZoom/lg-medium-zoom-settings';\nimport { PagerSettings } from './plugins/pager/lg-pager-settings';\nimport { RotateSettings } from './plugins/rotate/lg-rotate-settings';\nimport { ShareSettings } from './plugins/share/lg-share-settings';\nimport { ThumbnailsSettings } from './plugins/thumbnail/lg-thumbnail-settings';\nimport { VideoSettings } from './plugins/video/lg-video-settings';\nimport { ZoomSettings } from './plugins/zoom/lg-zoom-settings';\n\ntype LightGalleryCoreMobileSettings = Exclude<\n LightGalleryCoreSettings,\n 'mobileSettings'\n>;\n\n// @todo use separate mobile settings for plugins\nexport interface MobileSettings\n extends LightGalleryCoreMobileSettings,\n Partial<ZoomSettings>,\n Partial<ThumbnailsSettings>,\n Partial<VideoSettings>,\n Partial<AutoplaySettings>,\n Partial<CommentSettings>,\n Partial<FullscreenSettings>,\n Partial<HashSettings>,\n Partial<PagerSettings>,\n Partial<RotateSettings>,\n Partial<ShareSettings> {}\n\nexport interface LightGalleryCoreStrings {\n closeGallery: string;\n toggleMaximize: string;\n previousSlide: string;\n nextSlide: string;\n download: string;\n playVideo: string;\n mediaLoadingFailed: string;\n}\n\nexport type LightGalleryAllSettings = LightGalleryCoreSettings &\n ZoomSettings &\n ThumbnailsSettings &\n VideoSettings &\n AutoplaySettings &\n CommentSettings &\n FullscreenSettings &\n HashSettings &\n PagerSettings &\n RotateSettings &\n ShareSettings &\n MediumZoomSettings;\n\nexport type LightGallerySettings = Partial<LightGalleryAllSettings>;\n\nexport interface LightGalleryCoreSettings {\n /**\n * Type of transition between images.\n */\n mode:\n | 'lg-slide'\n | 'lg-fade'\n | 'lg-zoom-in'\n | 'lg-zoom-in-big'\n | 'lg-zoom-out'\n | 'lg-zoom-out-big'\n | 'lg-zoom-out-in'\n | 'lg-zoom-in-out'\n | 'lg-soft-zoom'\n | 'lg-scale-up'\n | 'lg-slide-circular'\n | 'lg-slide-circular-vertical'\n | 'lg-slide-vertical'\n | 'lg-slide-vertical-growth'\n | 'lg-slide-skew-only'\n | 'lg-slide-skew-only-rev'\n | 'lg-slide-skew-only-y'\n | 'lg-slide-skew-only-y-rev'\n | 'lg-slide-skew'\n | 'lg-slide-skew-rev'\n | 'lg-slide-skew-cross'\n | 'lg-slide-skew-cross-rev'\n | 'lg-slide-skew-ver'\n | 'lg-slide-skew-ver-rev'\n | 'lg-slide-skew-ver-cross'\n | 'lg-slide-skew-ver-cross-rev'\n | 'lg-lollipop'\n | 'lg-lollipop-rev'\n | 'lg-rotate'\n | 'lg-rotate-rev'\n | 'lg-tube';\n\n /**\n * Slide animation CSS easing property\n */\n easing: string;\n\n /**\n *Transition duration (in ms).\n */\n speed: number;\n\n /**\n * If you are using lightGallery for commercial projects, you need to purchase a commercial license\n * to get the license key. For projects that are compatible with GPLv3 license,\n * please contact us for getting a license key at <a href=\"mailto:contact@lightgalleryjs.com\">contact@lightgalleryjs.com</a>.\n * If you want to test lightGallery before purchasing a commercial license, you can\n * use `0000-0000-000-0000` as a temporary license key\n */\n\n licenseKey: string;\n\n /**\n * Height of the gallery.\n * example '100%' , '300px'\n */\n height: string;\n\n /**\n * Width of the gallery.\n * example '100%' , '300px'\n */\n width: string;\n\n /**\n * Add custom class for gallery container\n * This can be used to set different style for different galleries\n */\n addClass: string;\n\n /**\n * Start animation class for the gallery.\n * @description\n * <ul>\n * <li>startClass will be empty zoomFromOrigin is true.</li>\n * <li>This can be used to change the starting effect when the image is loaded</li>\n * <li>This is also applied when navigating to new slides</li>\n * </ul>\n */\n startClass: string;\n\n /**\n * Enable zoom from origin effect.\n * @description You need to know the original image size upfront and provide it via data-lg-size attribute as <code> data-lg-size=\"1920-1280</code>\"\n *\n * If you don't know, the size of a few images in the list, you can skip the data-lg-size attribute for the particular slides,\n * lightGallery will show the default animation if data-lg-size is not available\n *\n * If you are using responsive images,\n * you can pass a comma separated list of sizes combined with a max-width (up to what size the particular image should be used)\n *\n * example -\n * <code> data-lg-size=\"240-160-375, 400-267-480, 1600-1067\"\n * data-responsive=\"img-240.jpg 375, img-400.jpg 480\"\n * data-src=\"img-1600.jpg\" </code>\n *\n * In the above example, upto 375 width img.240.jpg and lg-size 240-160 will be used.\n * Similarly, upto 480 pixel width size 400-267 and img-400.jpg will be used\n * And above 480, lg-size 1600-1067 and img-1600.jpg will be used\n *\n * <ul>\n * <li>At the moment, zoomFromOrigin options is supported only for image slides.</li>\n * <li>Will be false if dynamic option is enabled or galleryID found in the URL.</li>\n * <li>startClass will be empty if zoomFromOrigin is true to avoid css conflicts.</li>\n * </ul>\n */\n zoomFromOrigin: boolean;\n\n /**\n * Zoom from image animation duration\n */\n startAnimationDuration: number;\n\n /**\n * Backdrop transition duration.\n * Note - Do not change the value of backdrop via css.\n */\n backdropDuration: number;\n\n /**\n * Configure where the gallery should be appended.\n * Useful to create inline galleries and more\n * It is an empty string in the default settings and later assigned to document.body to avoid accessing document for SSR\n */\n container: HTMLElement | (() => HTMLElement | null) | (string | null);\n\n /**\n * Delay for hiding gallery controls in ms.\n * Pass <code>0</code> if you don't want to hide the controls\n */\n hideBarsDelay: number;\n\n /**\n * Delay in hiding controls for the first time when gallery is opened\n */\n showBarsAfter: number;\n\n /**\n * Delay slide transitions.\n * @description This is useful if you want to do any action in the current slide before moving to next slide.\n * <section>\n * For example, fading out the captions before going to next slide.\n * <code>.lg-slide-progress</code> class name is added to the current slide immediately after calling the slide method.\n * But transition begins only after the delay\n * </section>\n */\n slideDelay: number;\n\n /**\n * Support legacy browsers\n * @description Currently this is used only for adding support to srcset attribute via picturefill library\n * If true lightGallery will show warning message to include picturefill library\n */\n supportLegacyBrowser: boolean;\n\n /**\n * If true, toolbar, captions and thumbnails will not overlap with media element\n * This will not effect thumbnails if animateThumb is false\n * Also, toggle thumbnails button is not displayed if allowMediaOverlap is false\n * <section>\n * Note - Changing the position of the media on every slide transition creates a flickering effect.\n * Therefore, the height of the caption is calculated dynamically, only once based on the first slide caption.\n * </section>\n * <section>\n * if you have dynamic captions for each media,\n * you can provide an appropriate height for the captions via allowMediaOverlap option\n * </section>\n */\n allowMediaOverlap: boolean;\n\n /**\n * Video max size.\n * @description This can be over-written by passing specific size via data-lg-size attribute\n * Recommended video resolution and & aspect ratios <a href=\"https://support.google.com/youtube/answer/6375112\">https://support.google.com/youtube/answer/6375112</a>\n */\n videoMaxSize: string;\n\n /**\n * Automatically load poster image for YouTube videos\n */\n loadYouTubePoster: boolean;\n\n /**\n * Height of the caption for calculating allowMediaOverlap positions\n * Note - this is only used to find the position of media item if allowMediaOverlap is true.\n * Not for setting height of the captions\n * Set 0 if you want to calculate the height of captions dynamically\n */\n defaultCaptionHeight: number;\n\n /**\n * aria-labelledby attribute fot gallery\n */\n ariaLabelledby: string;\n\n /**\n * aria-describedby attribute for gallery\n */\n ariaDescribedby: string;\n\n /**\n * Hide scrollbar when gallery is opened\n * @version V2.5.0\n */\n hideScrollbar: boolean;\n\n /**\n * Reset to previous scrollPosition when lightGallery is closed\n * @description By default, lightGallery doesn't hide the scrollbar for a smooth opening transition.\n * If a user changes the scroll position, lightGallery resets it to the previous value\n * @version V2.5.0\n */\n resetScrollPosition: boolean;\n\n /**\n * If false user won't be able to close the gallery at all\n * This is useful for creating inline galleries.\n */\n closable: boolean;\n\n /**\n * allows vertical drag/swipe to close gallery\n * <code>false</code> if option <code>closable</code> is <code>false</code>\n */\n swipeToClose: boolean;\n /**\n * allows clicks on black area to close gallery.\n */\n closeOnTap: boolean;\n\n /**\n * If false, close button won't be displayed.\n * Useful for creating inline galleries.\n */\n showCloseIcon: boolean;\n\n /**\n * Show maximize icon.\n * Useful for creating inline galleries.\n */\n showMaximizeIcon: boolean;\n\n /**\n * If false, will disable the ability to loop back to the beginning of the gallery from the last slide.\n */\n loop: boolean;\n\n /**\n * Whether the LightGallery could be closed by pressing the \"Esc\" key.\n */\n escKey: boolean;\n\n /**\n * Enable keyboard navigation\n */\n keyPress: boolean;\n\n /**\n * Trap focus within the lightGallery\n * @version V2.5.0\n */\n trapFocus: boolean;\n\n /**\n * If false, prev/next buttons will not be displayed.\n */\n controls: boolean;\n\n /**\n * Enable slideEnd animation\n */\n slideEndAnimation: boolean;\n\n /**\n * If true, prev/next button will be hidden on first/last image.\n * @description Note - this option will be ignored if <code>loop</code> or <code>slideEndAnimation</code> is set to true\n */\n hideControlOnEnd: boolean;\n\n /**\n * ability to navigate to next/prev slides on mousewheel\n */\n mousewheel: boolean;\n\n /**\n * Option to get captions from alt or title tags.\n */\n getCaptionFromTitleOrAlt: boolean;\n\n /**\n * control where the sub-html should be appended.\n * If you choose '.lg-outer', you are responsible for placing the div at the right position.\n * '.lg-outer' is useful if you want show custom HTML outside the normal gallery\n */\n appendSubHtmlTo: '.lg-sub-html' | '.lg-item' | '.lg-outer';\n\n /**\n * Set to true if the selector in \"data-sub-html\" should use the current item as its origin.\n */\n subHtmlSelectorRelative: boolean;\n\n /**\n * number of preload slides\n * @description will exicute only after the current slide is fully loaded.\n * for example, if you click on 4th image and if preload = 1 then 3rd slide and 5th\n * slide will be loaded in the background after the 4th slide is fully loaded..\n * if preload is 2 then 2nd 3rd 5th 6th slides will be preloaded.\n */\n preload: number;\n\n /**\n * Control how many slide items should be kept in dom at a time\n * @description To improve performance by reducing number of gallery items in the dom,\n * lightGallery keeps only the lowest possible number of slides in the dom at a time.\n * This has a minimum value of 3\n */\n numberOfSlideItemsInDom: number;\n\n /**\n * Custom selector property instead of direct children.\n * @description Based on your markup structure, you can specify custom selectors to fetch media data for the gallery\n * Pass \"this\" to select same element\n * You can also pass HTMLCollection directly\n * Example - '.my-selector' | '#my-selector' | this | document.querySelectorAll('.my-selector')\n */\n selector: string | HTMLCollection[];\n\n /**\n * By default selector element relative to the current gallery.\n * Instead of that you can tell lightGallery to select element relative to another element.\n * Example - '.my-selector-container' | '#my-selector-container'\n * In the code this become selector = document.querySelector(this.s.selectWithin ).querySelectorAll(this.s.selector);\n */\n selectWithin: string;\n\n /**\n * Custom html for next control\n */\n nextHtml: string;\n\n /**\n * Custom html for prev control\n */\n prevHtml: string;\n\n /**\n * specify which slide should load initially\n */\n index: number;\n\n /**\n * Set width for iframe.\n */\n iframeWidth: string;\n\n /**\n * Set height for iframe.\n */\n iframeHeight: string;\n\n /**\n * Set max width for iframe.\n */\n iframeMaxWidth: string;\n\n /**\n * Set max height for iframe.\n */\n iframeMaxHeight: string;\n\n /**\n * Enable download button.\n * @description By default download url will be taken from data-src/href attribute but it supports only for modern browsers.\n * If you want you can provide another url for download via data-download-url.\n * pass false in data-download-url if you want to hide download button for the particular slide.\n */\n download: boolean;\n\n /**\n * Whether to show total number of images and index number of currently displayed image.\n */\n counter: boolean;\n\n /**\n * Where the counter should be appended\n */\n appendCounterTo: string;\n\n /**\n * By setting the swipeThreshold (in px) you can set how far the user must swipe for the next/prev image.\n */\n swipeThreshold: number;\n\n /**\n * Enables swipe support for touch devices\n */\n enableSwipe: boolean;\n\n /**\n * Enables desktop mouse drag support\n */\n enableDrag: boolean;\n\n /**\n * LightGallery can be instantiated and launched programmatically by setting this option to true and populating dynamicEl option (see below) with the definitions of images.\n */\n dynamic: boolean;\n\n /**\n * An array of objects (src, iframe, subHtml, thumb, poster, responsive, srcset sizes) representing gallery elements.\n */\n dynamicEl: GalleryItem[];\n\n /**\n * Fetch custom properties from the selector\n * @description this is useful for plugin development\n * By default lightGallery fetches and store all the props selectors to\n * reduce frequent dom interaction for fetching props every time.\n *\n * If you need any addition data to be fetched and stored in the galleryItems variable,\n * you can do this just by passing the prop names via extraProps\n * @example\n * HTML:\n * <div id=\"lightGallery\">\n * <a href=\"a.jpg\" data-custom-prop=\"abc\"><img src=\"thumb.jpg\" /></a>\n * <a href=\"a.jpg\" data-custom-prop=\"xyz\"><img src=\"thumb.jpg\" /></a>\n * </div>\n * JS:\n * lightGallery(document.getElementById('lightGallery'), {\n * extraProps: ['customProp']\n * })\n * // Note - If you are using dynamic mode, you can pass any custom prop in the galleryItem\n * lightGallery(document.getElementById('lightGallery'), {\n * dynamic: true,\n * dynamicEl: [{\n * src: 'img/img1.jpg',\n * customProp:'abc',\n * }]\n * })\n *\n */\n extraProps: string[];\n\n /**\n * Option to fetch different thumbnail image other than first image\n * @description If you want to use external image for thumbnail,\n * add the path of that image inside \"data-\" attribute\n * and set value of this option to the name of your custom attribute.\n *\n * @example\n * <div id=\"lightGallery\">\n * <a href=\"a.jpg\" data-external-thumb-image=\"images/externalThumb.jpg\" ><img src=\"thumb.jpg\" /></a>\n * </div>\n *\n * lightGallery(document.getElementById('lightGallery'), {\n * exThumbImage: 'data-external-thumb-image'\n * })\n */\n exThumbImage: string;\n\n /**\n * Function to detect mobile devices\n */\n isMobile?: () => boolean;\n\n /**\n * Separate settings for mobile devices\n * @description Note - this is applied only at the time of loading\n * by default controls and close buttons are disabled on mobile devices.\n * use this options if you want to enable them or change any other settings for mobile devices\n * Note - mobileSettings does not merge default values, You need to provide all mobileSettings including default values\n */\n mobileSettings: Partial<MobileSettings>;\n\n /**\n * Customize string.\n * @description This can be useful if you want to localize the lightGallery strings to other languages.\n * Use your own service to translate the strings and pass it via settings.strings\n * You can find dedicated strings option for all lightGallery modules in their respective documentation.\n * Note - You need to provide values for all the strings. For example, even if you just want to change the closeGallery string, you need to provide all the other strings as well.\n */\n strings: LightGalleryCoreStrings;\n\n plugins: (new (instance: LightGallery, $LG: LgQuery) => any)[];\n}\n\nexport const lightGalleryCoreSettings: LightGalleryCoreSettings = {\n mode: 'lg-slide',\n easing: 'ease',\n speed: 400,\n licenseKey: '0000-0000-000-0000',\n height: '100%',\n width: '100%',\n addClass: '',\n startClass: 'lg-start-zoom',\n backdropDuration: 300,\n container: '',\n startAnimationDuration: 400,\n zoomFromOrigin: true,\n hideBarsDelay: 0,\n showBarsAfter: 10000,\n slideDelay: 0,\n supportLegacyBrowser: true,\n allowMediaOverlap: false,\n videoMaxSize: '1280-720',\n loadYouTubePoster: true,\n defaultCaptionHeight: 0,\n ariaLabelledby: '',\n ariaDescribedby: '',\n resetScrollPosition: true,\n hideScrollbar: false,\n closable: true,\n swipeToClose: true,\n closeOnTap: true,\n showCloseIcon: true,\n showMaximizeIcon: false,\n loop: true,\n escKey: true,\n keyPress: true,\n trapFocus: true,\n controls: true,\n slideEndAnimation: true,\n hideControlOnEnd: false,\n mousewheel: false,\n getCaptionFromTitleOrAlt: true,\n appendSubHtmlTo: '.lg-sub-html',\n subHtmlSelectorRelative: false,\n preload: 2,\n numberOfSlideItemsInDom: 10,\n selector: '',\n selectWithin: '',\n nextHtml: '',\n prevHtml: '',\n index: 0,\n iframeWidth: '100%',\n iframeHeight: '100%',\n iframeMaxWidth: '100%',\n iframeMaxHeight: '100%',\n download: true,\n counter: true,\n appendCounterTo: '.lg-toolbar',\n swipeThreshold: 50,\n enableSwipe: true,\n enableDrag: true,\n dynamic: false,\n dynamicEl: [],\n extraProps: [],\n exThumbImage: '',\n isMobile: undefined,\n mobileSettings: {\n controls: false,\n showCloseIcon: false,\n download: false,\n } as MobileSettings,\n plugins: [],\n strings: {\n closeGallery: 'Close gallery',\n toggleMaximize: 'Toggle maximize',\n previousSlide: 'Previous slide',\n nextSlide: 'Next slide',\n download: 'Download',\n playVideo: 'Play video',\n mediaLoadingFailed: 'Oops... Failed to load content...',\n } as LightGalleryCoreStrings,\n};\n","interface Offset {\n left: number;\n top: number;\n}\n\nfunction initLgPolyfills() {\n (function () {\n if (typeof window.CustomEvent === 'function') return false;\n\n function CustomEvent(event: string, params: any) {\n params = params || {\n bubbles: false,\n cancelable: false,\n detail: null,\n };\n const evt = document.createEvent('CustomEvent');\n evt.initCustomEvent(\n event,\n params.bubbles,\n params.cancelable,\n params.detail,\n );\n return evt;\n }\n\n window.CustomEvent = CustomEvent as any;\n })();\n (function () {\n if (!Element.prototype.matches) {\n Element.prototype.matches =\n (Element.prototype as any).msMatchesSelector ||\n Element.prototype.webkitMatchesSelector;\n }\n })();\n}\n\nexport type LgQuery = (selector: any) => lgQuery;\nexport class lgQuery {\n static eventListeners: { [key: string]: any[] } = {};\n static generateUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\n /[xy]/g,\n function (c) {\n const r = (Math.random() * 16) | 0,\n v = c == 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n },\n );\n }\n\n private selector: any;\n private firstElement: any;\n private cssVenderPrefixes: string[] = [\n 'TransitionDuration',\n 'TransitionTimingFunction',\n 'Transform',\n 'Transition',\n ];\n constructor(selector: string | Element) {\n this.selector = this._getSelector(selector);\n this.firstElement = this._getFirstEl();\n return this;\n }\n\n private _getSelector(\n selector: string | Element,\n context: Element | Document = document,\n ): Element | null | NodeListOf<Element> {\n if (typeof selector !== 'string') {\n return selector;\n }\n context = context || document;\n const fl = selector.substring(0, 1);\n if (fl === '#') {\n return context.querySelector(selector);\n } else {\n return context.querySelectorAll(selector);\n }\n }\n\n private _each(\n func: (\n elements: Element | NodeListOf<Element> | null,\n index: number,\n ) => void,\n ): this {\n if (!this.selector) {\n return this;\n }\n if (this.selector.length !== undefined) {\n [].forEach.call(this.selector, func);\n } else {\n func(this.selector, 0);\n }\n return this;\n }\n\n private _setCssVendorPrefix(\n el: any,\n cssProperty: string,\n value?: string | number,\n ): void {\n // prettier-ignore\n const property = cssProperty.replace(/-([a-z])/gi, function (\n s,\n group1,\n ) {\n return group1.toUpperCase();\n });\n if (this.cssVenderPrefixes.indexOf(property) !== -1) {\n el.style[\n property.charAt(0).toLowerCase() + property.slice(1)\n ] = value;\n el.style['webkit' + property] = value;\n el.style['moz' + property] = value;\n el.style['ms' + property] = value;\n el.style['o' + property] = value;\n } else {\n el.style[property] = value;\n }\n }\n\n private _getFirstEl() {\n if (this.selector && this.selector.length !== undefined) {\n return this.selector[0];\n } else {\n return this.selector;\n }\n }\n\n private isEventMatched(event: string, eventName: string): boolean {\n const eventNamespace = eventName.split('.');\n return event\n .split('.')\n .filter((e) => e)\n .every((e) => {\n return eventNamespace.indexOf(e) !== -1;\n });\n }\n\n attr(attr: string): string;\n attr(attr: string, value: string | number | boolean): this;\n attr(attr: string, value?: string | number | boolean): string | this {\n if (value === undefined) {\n if (!this.firstElement) {\n return '';\n }\n return this.firstElement.getAttribute(attr);\n }\n this._each((el: any) => {\n el.setAttribute(attr, value);\n });\n return this;\n }\n\n find(selector: any): lgQuery {\n return $LG(this._getSelector(selector, this.selector));\n }\n\n first(): lgQuery {\n if (this.selector && this.selector.length !== undefined) {\n return $LG(this.selector[0]);\n } else {\n return $LG(this.selector);\n }\n }\n\n eq(index: number): lgQuery {\n return $LG(this.selector[index]);\n }\n\n parent(): lgQuery {\n return $LG(this.selector.parentElement);\n }\n\n get(): HTMLElement {\n return this._getFirstEl();\n }\n\n removeAttr(attributes: string): this {\n const attrs = attributes.split(' ');\n this._each((el: any) => {\n attrs.forEach((attr: string) => el.removeAttribute(attr));\n });\n return this;\n }\n\n wrap(className: string): this {\n if (!this.firstElement) {\n return this;\n }\n const wrapper = document.createElement('div');\n wrapper.className = className;\n this.firstElement.parentNode.insertBefore(wrapper, this.firstElement);\n this.firstElement.parentNode.removeChild(this.firstElement);\n wrapper.appendChild(this.firstElement);\n return this;\n }\n\n addClass(classNames = ''): this {\n this._each((el: any) => {\n // IE doesn't support multiple arguments\n classNames.split(' ').forEach((className) => {\n if (className) {\n el.classList.add(className);\n }\n });\n });\n return this;\n }\n\n removeClass(classNames: string): this {\n this._each((el: any) => {\n // IE doesn't support multiple arguments\n classNames.split(' ').forEach((className) => {\n if (className) {\n el.classList.remove(className);\n }\n });\n });\n return this;\n }\n\n hasClass(className: string): boolean {\n if (!this.firstElement) {\n return false;\n }\n return this.firstElement.classList.contains(className);\n }\n hasAttribute(attribute: string): boolean {\n if (!this.firstElement) {\n return false;\n }\n return this.firstElement.hasAttribute(attribute);\n }\n toggleClass(className: string): this {\n if (!this.firstElement) {\n return this;\n }\n if (this.hasClass(className)) {\n this.removeClass(className);\n } else {\n this.addClass(className);\n }\n return this;\n }\n\n css(property: string, value?: string | number): this {\n this._each((el: any) => {\n this._setCssVendorPrefix(el, property, value);\n });\n return this;\n }\n // Need to pass separate namespaces for separate elements\n on(events: string, listener: (e: any) => void): this {\n if (!this.selector) {\n return this;\n }\n events.split(' ').forEach((event: string) => {\n if (!Array.isArray(lgQuery.eventListeners[event])) {\n lgQuery.eventListeners[event] = [];\n }\n lgQuery.eventListeners[event].push(listener);\n this.selector.addEventListener(event.split('.')[0], listener);\n });\n\n return this;\n }\n // @todo - test this\n once(event: string, listener: (e: any) => void): this {\n this.on(event, () => {\n this.off(event);\n listener(event);\n });\n return this;\n }\n off(event: string): this {\n if (!this.selector) {\n return this;\n }\n Object.keys(lgQuery.eventListeners).forEach((eventName) => {\n if (this.isEventMatched(event, eventName)) {\n lgQuery.eventListeners[eventName].forEach((listener) => {\n this.selector.removeEventListener(\n eventName.split('.')[0],\n listener,\n );\n });\n lgQuery.eventListeners[eventName] = [];\n }\n });\n\n return this;\n }\n trigger<Detail>(event: string, detail?: Detail): this {\n if (!this.firstElement) {\n return this;\n }\n\n const customEvent = new CustomEvent(event.split('.')[0], {\n detail: detail || null,\n });\n this.firstElement.dispatchEvent(customEvent);\n return this;\n }\n\n // Does not support IE\n load(url: string): this {\n fetch(url)\n .then((res) => res.text())\n .then((html) => {\n this.selector.innerHTML = html;\n });\n return this;\n }\n\n html(): string;\n html(html: string): this;\n html(html?: string): string | this {\n if (html === undefined) {\n if (!this.firstElement) {\n return '';\n }\n return this.firstElement.innerHTML;\n }\n this._each((el: any) => {\n el.innerHTML = html;\n });\n return this;\n }\n append(html: string | HTMLElement): this {\n this._each((el: any) => {\n if (typeof html === 'string') {\n el.insertAdjacentHTML('beforeend', html);\n } else {\n el.appendChild(html);\n }\n });\n return this;\n }\n prepend(html: string | HTMLElement): this {\n this._each((el: any) => {\n if (typeof html === 'string') {\n el.insertAdjacentHTML('afterbegin', html);\n } else if (html instanceof HTMLElement) {\n el.insertBefore(html.cloneNode(true), el.firstChild);\n }\n });\n return this;\n }\n remove(): this {\n this._each((el: any) => {\n el.parentNode.removeChild(el);\n });\n return this;\n }\n empty(): this {\n this._each((el: any) => {\n el.innerHTML = '';\n });\n return this;\n }\n // Supports only window\n scrollTop(): number;\n scrollTop(scrollTop: number): this;\n scrollTop(scrollTop?: number): number | this {\n if (scrollTop !== undefined) {\n document.body.scrollTop = scrollTop;\n document.documentElement.scrollTop = scrollTop;\n return this;\n } else {\n return (\n window.pageYOffset ||\n document.documentElement.scrollTop ||\n document.body.scrollTop ||\n 0\n );\n }\n }\n // Supports only window\n scrollLeft(): number;\n scrollLeft(scrollLeft?: number): this;\n scrollLeft(scrollLeft?: number): number | this {\n if (scrollLeft !== undefined) {\n document.body.scrollLeft = scrollLeft;\n document.documentElement.scrollLeft = scrollLeft;\n return this;\n } else {\n return (\n window.pageXOffset ||\n document.documentElement.scrollLeft ||\n document.body.scrollLeft ||\n 0\n );\n }\n }\n offset(): Offset {\n if (!this.firstElement) {\n return {\n left: 0,\n top: 0,\n };\n }\n const rect = this.firstElement.getBoundingClientRect();\n const bodyMarginLeft = $LG('body').style().marginLeft;\n\n // Minus body margin - https://stackoverflow.com/questions/30711548/is-getboundingclientrect-left-returning-a-wrong-value\n return {\n left: rect.left - parseFloat(bodyMarginLeft) + this.scrollLeft(),\n top: rect.top + this.scrollTop(),\n };\n }\n style(): CSSStyleDeclaration {\n if (!this.firstElement) {\n return {} as CSSStyleDeclaration;\n }\n return (\n this.firstElement.currentStyle ||\n window.getComputedStyle(this.firstElement)\n );\n }\n // Width without padding and border even if box-sizing is used.\n width(): number {\n const style = this.style();\n return (\n this.firstElement.clientWidth -\n parseFloat(style.paddingLeft) -\n parseFloat(style.paddingRight)\n );\n }\n // Height without padding and border even if box-sizing is used.\n height(): number {\n const style = this.style();\n return (\n this.firstElement.clientHeight -\n parseFloat(style.paddingTop) -\n parseFloat(style.paddingBottom)\n );\n }\n}\n\nexport function $LG(selector: any): lgQuery {\n initLgPolyfills();\n return new lgQuery(selector);\n}\n","import { $LG, lgQuery } from './lgQuery';\nimport { VideoSource } from './plugins/video/types';\nimport { VideoInfo } from './types';\n\nexport interface ImageSize {\n width: number;\n height: number;\n}\n\nexport interface ImageSources {\n media?: string;\n srcset: string;\n sizes?: string;\n type?: string;\n}\n\nexport interface GalleryItem {\n /**\n * url of the media\n * @data-attr data-src\n */\n src?: string;\n\n /**\n * Source attributes for the <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source#attributes\">picture</a> element\n * @data-attr data-sources\n */\n sources?: ImageSources[];\n\n /**\n * Thumbnail url\n * @description By default lightGallery uses the image inside gallery selector as thumbnail.\n * But, If you want to use external image for thumbnail,\n * pass the thumbnail url via any data attribute and\n * pass the attribute name via exThumbImage option\n * @example\n * <div id=\"lightGallery\">\n * <a href=\"a.jpg\" data-external-thumb-image=\"images/externalThumb.jpg\" ><img src=\"thumb.jpg\" /></a>\n * </div>\n *\n * lightGallery(document.getElementById('lightGallery'), {\n * exThumbImage: 'data-external-thumb-image'\n * })\n * @data-attr data-*\n */\n thumb?: string;\n\n /**\n * alt attribute for the image\n * @data-attr alt\n */\n alt?: string;\n\n /**\n * Title attribute for the video\n * @data-attr title\n */\n title?: string;\n\n /**\n * Title for iframe\n * @data-attr data-iframe-title\n */\n iframeTitle?: string;\n\n /**\n * Caption for the slide\n * @description You can either pass the HTML markup or the ID or class name of the element which contains the captions\n * @data-attr data-sub-html\n */\n subHtml?: string;\n\n /**\n * url of the file which contain the sub html.\n * @description Note - Does not support Internet Explorer browser\n * @data-attr data-sub-html-url\n */\n subHtmlUrl?: string;\n\n /**\n * Video source\n * @data-attr data-video\n */\n video?: VideoSource;\n\n /**\n * Poster url\n * @data-attr data-poster\n */\n poster?: string;\n\n /**\n * Custom slide name to use in the url when hash plugin is enabled\n * @data-attr data-slide-name\n */\n slideName?: string;\n\n /**\n * List of images and viewport's max width separated by comma.\n * @description Ex?: img/1-375.jpg 375, img/1-480.jpg 480, img/1-757.jpg 757.\n * @data-attr data-responsive\n */\n responsive?: string;\n\n /**\n * srcset attribute values for the main image\n * @data-attr data-srcset\n */\n srcset?: string;\n\n /**\n * srcset sizes attribute for the main image\n * @data-attr data-sizes\n */\n sizes?: string;\n\n /**\n * Set true is you want to open your url in an iframe\n * @data-attr data-iframe\n */\n iframe?: boolean;\n\n /**\n * Download url for your image/video.\n * @description Pass false if you want to disable the download button.\n * @data-attr data-download-url\n */\n downloadUrl?: string | boolean;\n\n /**\n * Name of the file after it is downloaded.\n * @description The HTML value of the download attribute.\n * There are no restrictions on allowed values, and the browser will automatically\n * detect the correct file extension and add it to the file (.img, .pdf, .txt, .html, etc.).\n * <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download\">More info</a>\n * @data-attr data-download\n */\n download?: string | boolean;\n\n /**\n * Actual size of the image in px.\n * @description This is used in zoom plugin to see the actual size of the image when double taped on the image.\n * @data-attr data-width\n */\n width?: string;\n\n /**\n * Facebook share URL.\n * @description Specify only if you want to provide separate share URL for the specific slide. By default, current browser URL is taken.\n * @data-attr data-facebook-share-url\n */\n facebookShareUrl?: string;\n\n /**\n * Tweet text\n * @data-attr data-tweet-text\n */\n tweetText?: string;\n\n /**\n * Twitter share URL.\n * @description Specify only if you want to provide separate share URL for the specific slide. By default, current browser URL will be taken.\n * @data-attr data-twitter-share-url\n */\n twitterShareUrl?: string;\n\n /**\n * Pinterest share URL.\n * @description Specify only if you want to provide separate share URL for the specific slide. By default, current browser URL will be taken.\n * Note?: Pinterest requires absolute URL\n * @data-attr data-pinterest-share-url\n */\n pinterestShareUrl?: string;\n\n /**\n * Description for Pinterest post.\n * @data-attr data-pinterest-text\n */\n pinterestText?: string;\n\n /**\n * Facebook comments body html\n * @description Please refer <a href=\"https://developers.facebook.com/docs/plugins/comments/#comments-plugin\">facebook official documentation</a> for generating the HTML markup\n * @example\n * <div\n * class=\"fb-comments\"\n * data-href=\"https://www.lightgalleryjs.com/demos/comment-box/#facebook-comments-demo\"\n * data-width=\"400\"\n * data-numposts=\"5\">\n * </div>\n * @data-attr data-fb-html\n */\n fbHtml?: string;\n\n /**\n * Disqus page identifier\n * @description Please refer official <a href=\"https://help.disqus.com/en/articles/1717084-javascript-configuration-variables\">disqus documentation</a> for more info\n * @data-attr data-disqus-identifier\n */\n disqusIdentifier?: string;\n\n /**\n * Disqus page url\n * @description Please refer official <a href=\"https://help.disqus.com/en/articles/1717084-javascript-configuration-variables\">disqus documentation</a> for more info\n * @data-attr data-disqus-url\n */\n disqusUrl?: string;\n\n __slideVideoInfo?: VideoInfo;\n [key: string]: any;\n}\n\nconst defaultDynamicOptions = [\n 'src',\n 'sources',\n 'subHtml',\n 'subHtmlUrl',\n 'html',\n 'video',\n 'poster',\n 'slideName',\n 'responsive',\n 'srcset',\n 'sizes',\n 'iframe',\n 'downloadUrl',\n 'download',\n 'width',\n 'facebookShareUrl',\n 'tweetText',\n 'iframeTitle',\n 'twitterShareUrl',\n 'pinterestShareUrl',\n 'pinterestText',\n 'fbHtml',\n 'disqusIdentifier',\n 'disqusUrl',\n];\n\n// Convert html data-attribute to camalcase\nexport function convertToData(attr: string): string {\n // FInd a way for lgsize\n if (attr === 'href') {\n return 'src';\n }\n attr = attr.replace('data-', '');\n attr = attr.charAt(0).toLowerCase() + attr.slice(1);\n attr = attr.replace(/-([a-z])/g, (g) => g[1].toUpperCase());\n\n return attr;\n}\n\nconst utils = {\n /**\n * Fetches HTML content from a given URL and inserts it into a specified element.\n *\n * @param url - T