UNPKG

@ks89/angular-modal-gallery

Version:
1 lines 409 kB
{"version":3,"file":"ks89-angular-modal-gallery.mjs","sources":["../../../../projects/ks89/angular-modal-gallery/src/lib/utils/user-input.util.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/accessible.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/model/image.class.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/model/action.enum.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/utils/image.util.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/model/description.interface.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/accessibility-default.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/model/buttons-config.interface.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/model/plain-gallery-config.interface.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/model/loading-config.interface.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/services/config.service.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/modal-gallery/modal-gallery-ref.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/modal-gallery/modal-gallery.service.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/size.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/fallback-image.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/carousel/carousel-previews/carousel-previews.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/carousel/carousel-previews/carousel-previews.html","../../../../projects/ks89/angular-modal-gallery/src/lib/components/dots/dots.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/dots/dots.html","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/description.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/max-size.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/carousel/carousel.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/carousel/carousel.html","../../../../projects/ks89/angular-modal-gallery/src/lib/components/upper-buttons/upper-buttons-default.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/upper-buttons/upper-buttons.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/upper-buttons/upper-buttons.html","../../../../projects/ks89/angular-modal-gallery/src/lib/components/previews/previews.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/previews/previews.html","../../../../projects/ks89/angular-modal-gallery/src/lib/model/keyboard.enum.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/current-image/loading-spinner/loading-spinner.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/current-image/loading-spinner/loading-spinner.html","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/keyboard-navigation.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/swipe.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/current-image/current-image.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/current-image/current-image.html","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/wrap.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/direction.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/a-tag-bg-image.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/plain-gallery/plain-gallery.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/plain-gallery/plain-gallery.html","../../../../projects/ks89/angular-modal-gallery/src/lib/components/modal-gallery/modal-gallery.tokens.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/services/id-validator.service.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/click-outside.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/modal-gallery/modal-gallery.component.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/modal-gallery/modal-gallery.component.html","../../../../projects/ks89/angular-modal-gallery/src/lib/components/components.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/margin.directive.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/directives/directives.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/components/modal-gallery/attach-to-overlay.service.ts","../../../../projects/ks89/angular-modal-gallery/src/lib/modal-gallery.module.ts","../../../../projects/ks89/angular-modal-gallery/src/public-api.ts","../../../../projects/ks89/angular-modal-gallery/src/ks89-angular-modal-gallery.ts"],"sourcesContent":["/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n/**\n * Key of the keyboard's key `enter`\n */\nexport const ENTER_KEY: string = 'Enter';\n/**\n * Code of the keyboard's key `enter`\n */\nexport const ENTER_CODE: string = 'Enter';\n\n/**\n * Key of the keyboard's key `esc`\n */\nexport const ESC_KEY: string = 'Escape';\n/**\n * Code of the keyboard's key `esc`\n */\nexport const ESC_CODE: string = 'Escape';\n/**\n * Key of the keyboard's key 'right arrow'\n */\nexport const RIGHT_ARROW_KEY: string = 'ArrowRight';\n/**\n * Code of the keyboard's key 'right arrow'\n */\nexport const RIGHT_ARROW_CODE: string = 'ArrowRight';\n/**\n * Key of the keyboard's key 'left arrow'\n */\nexport const LEFT_ARROW_KEY: string = 'ArrowLeft';\n/**\n * Code of the keyboard's key 'left arrow'\n */\nexport const LEFT_ARROW_CODE: string = 'ArrowLeft';\n/**\n * Key of the keyboard's key 'left arrow'\n */\nexport const UP_ARROW_KEY: string = 'ArrowUp';\n/**\n * Code of the keyboard's key 'left arrow'\n */\nexport const UP_ARROW_CODE: string = 'ArrowUp';\n/**\n * Key of the keyboard's key 'left arrow'\n */\nexport const DOWN_ARROW_KEY: string = 'ArrowDown';\n/**\n * Code of the keyboard's key 'left arrow'\n */\nexport const DOWN_ARROW_CODE: string = 'ArrowDown';\n/**\n * Key of the keyboard's key `space`\n */\nexport const SPACE_KEY : string= '';\n/**\n * Code of the keyboard's key `space`\n */\nexport const SPACE_CODE: string = 'Space';\n\n/**\n * Const to represent the right direction\n */\nexport const DIRECTION_RIGHT: string = 'right';\n/**\n * Const to represent the left direction\n */\nexport const DIRECTION_LEFT: string = 'left';\n\n\n/**\n * Keycode of the main mouse button\n */\nexport const MOUSE_MAIN_BUTTON_CLICK = 0;\n\n/**\n * Const NEXT\n */\nexport const NEXT = 1;\n/**\n * Const PREV\n */\nexport const PREV = -1;\n/**\n * Const NOTHING to represents a situation when it isn't both NEXT and PREV\n */\nexport const NOTHING = 0;\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\nimport { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { DIRECTION_RIGHT, MOUSE_MAIN_BUTTON_CLICK, NEXT, NOTHING, PREV, ENTER_CODE, SPACE_CODE } from '../utils/user-input.util';\n\n/**\n * Provides some useful methods to add accessibility features to subclasses.\n * In particular, it exposes a method to handle navigation event with both Keyboard and Mouse\n * and another with also the direction (right or left).\n */\n@Component({\n selector: 'ks-accessible',\n template: ``,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false\n})\nexport class AccessibleComponent {\n constructor() {}\n\n /**\n * Method to handle navigation events with both Keyboard and Mouse.\n * @param string direction of the navigation that can be either 'next' or 'prev'\n * @param KeyboardEvent | MouseEvent event payload\n * @returns number -1 for PREV, 1 for NEXT and 0 for NOTHING\n */\n handleNavigationEvent(direction: string, event: KeyboardEvent | MouseEvent): number {\n if (!event) {\n return NOTHING;\n }\n if (event instanceof KeyboardEvent) {\n return this.handleKeyboardNavigationEvent(direction, event);\n } else if (event instanceof MouseEvent) {\n return this.handleMouseNavigationEvent(direction, event);\n }\n return NOTHING;\n }\n\n /**\n * Method to handle events over an image, for instance a keypress with the Keyboard or a Mouse click.\n * @param event KeyboardEvent | MouseEvent payload\n * @returns number 1 for NEXT and 0 for NOTHING\n */\n handleImageEvent(event: KeyboardEvent | MouseEvent): number {\n if (!event) {\n return NOTHING;\n }\n if (event instanceof KeyboardEvent) {\n return this.handleImageKeyboardEvent(event);\n } else if (event instanceof MouseEvent) {\n return this.handleImageMouseEvent(event);\n }\n return NOTHING;\n }\n\n /**\n * Private method to handle keyboard events over an image.\n * @param event KeyboardEvent payload\n * @returns number 1 for NEXT and 0 for NOTHING\n */\n private handleImageKeyboardEvent(event: KeyboardEvent): number {\n const key: string = event.code;\n if (key === SPACE_CODE || key === ENTER_CODE) {\n return NEXT;\n }\n return NOTHING;\n }\n\n /**\n * Private method to handle mouse events over an image.\n * @param MouseEvent event payload\n * @returns number 1 for NEXT and 0 for NOTHING\n */\n private handleImageMouseEvent(event: MouseEvent): number {\n const mouseBtn: number = event.button;\n if (mouseBtn === MOUSE_MAIN_BUTTON_CLICK) {\n return NEXT;\n }\n return NOTHING;\n }\n\n /**\n * Method to handle events over an image, for instance a keypress with the Keyboard or a Mouse click.\n * @param string direction of the navigation that can be either 'next' or 'prev'\n * @param KeyboardEvent event payload\n * @returns number -1 for PREV, 1 for NEXT and 0 for NOTHING\n */\n private handleKeyboardNavigationEvent(direction: string, event: KeyboardEvent): number {\n const key: string = event.code;\n if (key === SPACE_CODE || key === ENTER_CODE) {\n return direction === DIRECTION_RIGHT ? NEXT : PREV;\n }\n return NOTHING;\n }\n\n /**\n * Method to handle events over an image, for instance a keypress with the Keyboard or a Mouse click.\n * @param string direction of the navigation that can be either 'next' or 'prev'\n * @param MouseEvent event payload\n * @returns number -1 for PREV, 1 for NEXT and 0 for NOTHING\n */\n private handleMouseNavigationEvent(direction: string, event: MouseEvent): number {\n const mouseBtn: number = event.button;\n if (mouseBtn === MOUSE_MAIN_BUTTON_CLICK) {\n return direction === DIRECTION_RIGHT ? NEXT : PREV;\n }\n return NOTHING;\n }\n}\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\nimport { Action } from './action.enum';\nimport { Size } from './size.interface';\nimport { SafeResourceUrl } from '@angular/platform-browser';\n\n/**\n * Class `Image` that represents an image with both `modal` and `plain` configurations.\n * Both image `id` and `modal` are mandatory, instead `plain` is optional.\n */\nexport class Image {\n id: number;\n loading: 'eager' | 'lazy';\n fetchpriority: 'high' | 'low' | 'auto';\n modal: ModalImage;\n plain?: PlainImage;\n\n constructor(id: number, modal: ModalImage, plain?: PlainImage, loading: 'eager' | 'lazy' = 'lazy', fetchpriority: 'high' | 'low' | 'auto' = 'auto') {\n this.id = id;\n this.modal = modal;\n this.plain = plain;\n this.loading = loading;\n this.fetchpriority = fetchpriority\n }\n}\n\n/**\n * Interface `ImageData` to configure an image, but it isn't used directly.\n * Please, refers to `PlainImage` or `ModalImage`.\n */\nexport interface ImageData {\n img: string | SafeResourceUrl;\n description?: string;\n title?: string;\n alt?: string;\n ariaLabel?: string;\n fallbackImg?: string | SafeResourceUrl;\n}\n\n/**\n * Interface `ModalImage` to configure the modal image.\n */\nexport interface ModalImage extends ImageData {\n extUrl?: string;\n downloadFileName?: string;\n sources?: Source[];\n}\n\n/**\n * Interface `PlainImage` to configure the plain image.\n */\nexport interface PlainImage extends ImageData {\n size?: Size;\n}\n\n/**\n * Class `ImageEvent` that represents the event payload with the result and the triggered action.\n * It also contains the source id of the gallery that emitted this event\n */\nexport class ImageEvent {\n galleryId: number;\n action: Action;\n result: number | boolean;\n\n constructor(galleryId: number, action: Action, result: number | boolean) {\n this.galleryId = galleryId;\n this.action = action;\n this.result = result;\n }\n}\n\n/**\n * Class `ImageModalEvent` that represents the event payload with galleryId, result and the triggered action.\n */\nexport class ImageModalEvent extends ImageEvent {\n constructor(galleryId: number, action: Action, result: number | boolean) {\n super(galleryId, action, result);\n }\n}\n\n/**\n * Interface `Source` to configure sources of picture element.\n */\nexport interface Source {\n srcset: string;\n media: string;\n}\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n/**\n * Enum `Action` with a list of possible actions, based on the source of the action.\n */\nexport enum Action {\n NORMAL, // default value\n CLICK, // mouse click\n KEYBOARD,\n SWIPE,\n LOAD,\n AUTOPLAY\n}\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\nimport { Image } from '../model/image.class';\n\n/**\n * Utility function to get the index of the input `image` from `arrayOfImages`\n * @param image Image to get the index. The image 'id' must be a number >= 0\n * @param arrayOfImages Image[] to search the image within it\n * @returns number the index of the image. -1 if not found.\n * @throws an Error if either image or arrayOfImages are not valid,\n * or if the input image doesn't contain an 'id', or the 'id' is < 0\n */\nexport function getIndex(image: Image, arrayOfImages: Image[]): number {\n if (!image) {\n throw new Error('image must be a valid Image object');\n }\n\n if (!arrayOfImages) {\n throw new Error('arrayOfImages must be a valid Image[]');\n }\n\n if (!image.id && image.id !== 0) {\n // id = 0 is admitted\n throw new Error(`A numeric Image 'id' is mandatory`);\n }\n\n if (image.id < 0) {\n throw new Error(`Image 'id' must be >= 0`);\n }\n\n return arrayOfImages.findIndex((val: Image) => val.id === image.id);\n}\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n/**\n * Interface `Description` to change the description, either with a full custom\n * description or with a small and simple customization.\n * Also, you could change margins, background style and so on.\n */\nexport interface Description {\n strategy: DescriptionStrategy;\n customFullDescription?: string;\n imageText?: string;\n numberSeparator?: string;\n beforeTextDescription?: string;\n\n style?: DescriptionStyle;\n}\n\n/**\n * Enum `DescriptionStrategy` with keys and their relative key codes.\n */\nexport enum DescriptionStrategy {\n ALWAYS_HIDDEN = 1,\n ALWAYS_VISIBLE,\n HIDE_IF_EMPTY\n}\n\n/**\n * Interface to change css properties.\n */\nexport interface DescriptionStyle {\n bgColor?: string;\n textColor?: string;\n width?: string;\n height?: string;\n position?: string;\n top?: string;\n bottom?: string;\n left?: string;\n right?: string;\n marginTop?: string;\n marginBottom?: string;\n marginRight?: string;\n marginLeft?: string;\n}\n","import { AccessibilityConfig } from '../model/accessibility.interface';\n\n/**\n * Default accessibility configuration.\n */\nexport const KS_DEFAULT_ACCESSIBILITY_CONFIG: AccessibilityConfig = {\n backgroundAriaLabel: 'Modal gallery full screen background',\n backgroundTitle: '',\n\n plainGalleryContentAriaLabel: 'Plain gallery content',\n plainGalleryContentTitle: '',\n\n modalGalleryContentAriaLabel: 'Modal gallery content',\n modalGalleryContentTitle: '',\n\n loadingSpinnerAriaLabel: 'The current image is loading. Please be patient.',\n loadingSpinnerTitle: 'The current image is loading. Please be patient.',\n\n mainContainerAriaLabel: 'Current image and navigation',\n mainContainerTitle: '',\n mainPrevImageAriaLabel: 'Previous image',\n mainPrevImageTitle: 'Previous image',\n mainNextImageAriaLabel: 'Next image',\n mainNextImageTitle: 'Next image',\n\n dotsContainerAriaLabel: 'Image navigation dots',\n dotsContainerTitle: '',\n dotAriaLabel: 'Navigate to image number',\n\n previewsContainerAriaLabel: 'Image previews',\n previewsContainerTitle: '',\n previewScrollPrevAriaLabel: 'Scroll previous previews',\n previewScrollPrevTitle: 'Scroll previous previews',\n previewScrollNextAriaLabel: 'Scroll next previews',\n previewScrollNextTitle: 'Scroll next previews',\n\n carouselContainerAriaLabel: 'Current image and navigation',\n carouselContainerTitle: '',\n carouselPrevImageAriaLabel: 'Previous image',\n carouselPrevImageTitle: 'Previous image',\n carouselNextImageAriaLabel: 'Next image',\n carouselNextImageTitle: 'Next image',\n carouselPreviewsContainerAriaLabel: 'Image previews',\n carouselPreviewsContainerTitle: '',\n carouselPreviewScrollPrevAriaLabel: 'Scroll previous previews',\n carouselPreviewScrollPrevTitle: 'Scroll previous previews',\n carouselPreviewScrollNextAriaLabel: 'Scroll next previews',\n carouselPreviewScrollNextTitle: 'Scroll next previews'\n};\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\nimport { Action } from './action.enum';\nimport { InternalLibImage } from './image-internal.class';\nimport { Size } from './size.interface';\n\n/**\n * Interface `ButtonsConfig` to add buttons, show/hide their, and to add the strategy.\n */\nexport interface ButtonsConfig {\n visible: boolean;\n strategy: ButtonsStrategy;\n buttons?: ButtonConfig[];\n}\n\n/**\n * Interface `ButtonConfig` to configure a single button.\n */\nexport interface ButtonConfig {\n className?: string;\n size?: Size;\n fontSize?: string;\n type: ButtonType;\n title?: string;\n ariaLabel?: string;\n extUrlInNewTab?: boolean; // to open the external url in a new tab, instead of the current one\n}\n\n/**\n * Interface `ButtonEvent` to represent the event payload when a button is clicked.\n */\nexport interface ButtonEvent {\n button: ButtonConfig;\n image: InternalLibImage | null;\n action: Action;\n galleryId: number;\n}\n\n/**\n * Enum `ButtonsStrategy` to configure the logic of a button.\n */\nexport enum ButtonsStrategy {\n // don't use 0 here\n // the first index is 1 and all of the following members are auto-incremented from that point on\n DEFAULT = 1,\n SIMPLE,\n ADVANCED,\n FULL,\n CUSTOM\n}\n\n/**\n * Enum `ButtonType` is the type of a button.\n */\nexport enum ButtonType {\n // don't use 0 here\n // the first index is 1 and all of the following members are auto-incremented from that point on\n DELETE = 1,\n EXTURL,\n DOWNLOAD,\n CLOSE,\n CUSTOM,\n FULLSCREEN\n}\n\n/**\n * Array of admitted types of buttons.\n */\nexport const WHITELIST_BUTTON_TYPES: ButtonType[] = [\n ButtonType.FULLSCREEN,\n ButtonType.DELETE,\n ButtonType.EXTURL,\n ButtonType.DOWNLOAD,\n ButtonType.CLOSE,\n ButtonType.CUSTOM\n];\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\nimport { Size } from './size.interface';\n\n/**\n * Interface `PlainGalleryConfig` to configure plain-gallery features.\n */\nexport interface PlainGalleryConfig {\n strategy: PlainGalleryStrategy;\n layout: PlainGalleryLayout;\n advanced?: AdvancedConfig;\n}\n\n/**\n * Interface `PlainGalleryLayout` to configure the layout. This interface isn't used directly, instead\n * refers to either `LineLayout`, `GridLayout`.\n */\n// tslint:disable-next-line no-empty-interface\nexport interface PlainGalleryLayout {}\n\n/**\n * Class `LineLayout` to configure a linear plain gallery.\n */\nexport class LineLayout implements PlainGalleryLayout {\n breakConfig: BreakConfig;\n justify: string;\n size: Size;\n\n constructor(size: Size, breakConfig: BreakConfig, justify: string) {\n this.size = size;\n this.breakConfig = breakConfig;\n this.justify = justify;\n }\n}\n\n/**\n * Class `GridLayout` to configure a grid plain gallery.\n */\nexport class GridLayout implements PlainGalleryLayout {\n breakConfig: BreakConfig;\n size: Size;\n\n constructor(size: Size, breakConfig: BreakConfig) {\n this.size = size;\n this.breakConfig = breakConfig;\n }\n}\n\n/**\n * Enum `PlainGalleryStrategy` to choose the behaviour of the plain gallery.\n */\nexport enum PlainGalleryStrategy {\n // don't use 0 here\n // the first index is 1 and all of the following members are auto-incremented from that point on\n ROW = 1,\n COLUMN,\n GRID,\n CUSTOM // full custom strategy\n}\n\n/**\n * Interface `BreakConfig` to limit the number of items of the plain gallery or to force it to fill other lines.\n */\nexport interface BreakConfig {\n length: number;\n wrap: boolean;\n}\n\n/**\n * Interface `AdvancedConfig` to use `<a>` tags instead of `<img>`.\n * It also contains a string property to customize the css background property.\n * For more info check here https://www.w3schools.com/cssref/css3_pr_background.asp\n */\nexport interface AdvancedConfig {\n aTags: boolean;\n additionalBackground: string;\n}\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\n/**\n * Interface `LoadingConfig` to configure loading icon.\n */\nexport interface LoadingConfig {\n enable: boolean;\n type: LoadingType;\n}\n\n/**\n * Enum `LoadingType` with a list of possible types.\n */\nexport enum LoadingType {\n STANDARD = 1,\n CIRCULAR,\n BARS,\n DOTS,\n CUBE_FLIPPING,\n CIRCLES,\n EXPLOSING_SQUARES\n}\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n */\n\nimport { Injectable } from '@angular/core';\nimport { SidePreviewsConfig, SlideConfig } from '../model/slide-config.interface';\nimport { PlayConfig } from '../model/play-config.interface';\nimport { KS_DEFAULT_ACCESSIBILITY_CONFIG } from '../components/accessibility-default';\nimport { PreviewConfig } from '../model/preview-config.interface';\nimport { Size } from '../model/size.interface';\nimport { ButtonsConfig, ButtonsStrategy } from '../model/buttons-config.interface';\nimport { DotsConfig } from '../model/dots-config.interface';\nimport { GridLayout, LineLayout, PlainGalleryConfig, PlainGalleryStrategy } from '../model/plain-gallery-config.interface';\nimport { CurrentImageConfig } from '../model/current-image-config.interface';\nimport { LoadingConfig, LoadingType } from '../model/loading-config.interface';\nimport { Description, DescriptionStrategy, DescriptionStyle } from '../model/description.interface';\nimport { CarouselConfig } from '../model/carousel-config.interface';\nimport { CarouselImageConfig } from '../model/carousel-image-config.interface';\nimport { BreakpointsConfig, CarouselPreviewConfig } from '../model/carousel-preview-config.interface';\nimport { LibConfig } from '../model/lib-config.interface';\n\nexport const DEFAULT_PREVIEW_SIZE: Size = { height: '50px', width: 'auto' };\nexport const DEFAULT_LAYOUT: LineLayout = new LineLayout(DEFAULT_PREVIEW_SIZE, { length: -1, wrap: false }, 'flex-start');\nexport const DEFAULT_PLAIN_CONFIG: PlainGalleryConfig = {\n strategy: PlainGalleryStrategy.ROW,\n layout: DEFAULT_LAYOUT,\n advanced: { aTags: false, additionalBackground: '50% 50%/cover' }\n};\nexport const DEFAULT_LOADING: LoadingConfig = { enable: true, type: LoadingType.STANDARD };\nexport const DEFAULT_DESCRIPTION_STYLE: DescriptionStyle = {\n bgColor: 'rgba(0, 0, 0, .5)',\n textColor: 'white',\n marginTop: '0px',\n marginBottom: '0px',\n marginLeft: '0px',\n marginRight: '0px'\n};\nexport const DEFAULT_DESCRIPTION: Description = {\n strategy: DescriptionStrategy.ALWAYS_VISIBLE,\n imageText: 'Image ',\n numberSeparator: '/',\n beforeTextDescription: ' - ',\n style: DEFAULT_DESCRIPTION_STYLE\n};\nexport const DEFAULT_CAROUSEL_DESCRIPTION: Description = {\n strategy: DescriptionStrategy.ALWAYS_HIDDEN,\n imageText: 'Image ',\n numberSeparator: '/',\n beforeTextDescription: ' - ',\n style: DEFAULT_DESCRIPTION_STYLE\n};\nexport const DEFAULT_CURRENT_IMAGE_CONFIG: CurrentImageConfig = {\n navigateOnClick: true,\n loadingConfig: DEFAULT_LOADING,\n description: DEFAULT_DESCRIPTION,\n downloadable: false,\n invertSwipe: false\n};\nexport const DEFAULT_CAROUSEL_IMAGE_CONFIG: CarouselImageConfig = {\n description: DEFAULT_CAROUSEL_DESCRIPTION,\n invertSwipe: false\n};\nexport const DEFAULT_CURRENT_CAROUSEL_CONFIG: CarouselConfig = {\n maxWidth: '100%',\n maxHeight: '400px',\n showArrows: true,\n objectFit: 'cover',\n keyboardEnable: true,\n modalGalleryEnable: false\n};\nexport const DEFAULT_CURRENT_CAROUSEL_PLAY: PlayConfig = {\n autoPlay: true,\n interval: 5000,\n pauseOnHover: true\n};\n\nexport const DEFAULT_CAROUSEL_BREAKPOINTS: BreakpointsConfig = { xSmall: 100, small: 100, medium: 150, large: 200, xLarge: 200 };\nexport const DEFAULT_CAROUSEL_PREVIEWS_CONFIG: CarouselPreviewConfig = {\n visible: true,\n number: 4,\n arrows: true,\n clickable: true,\n width: 100 / 4 + '%',\n maxHeight: '200px',\n breakpoints: DEFAULT_CAROUSEL_BREAKPOINTS\n};\nexport const DEFAULT_SLIDE_CONFIG: SlideConfig = {\n infinite: false,\n playConfig: { autoPlay: false, interval: 5000, pauseOnHover: true } as PlayConfig,\n sidePreviews: { show: true, size: { width: '100px', height: 'auto' } } as SidePreviewsConfig\n};\nexport const DEFAULT_PREVIEW_CONFIG: PreviewConfig = {\n visible: true,\n number: 3,\n arrows: true,\n clickable: true,\n size: DEFAULT_PREVIEW_SIZE\n};\n\nconst DEFAULT_CONFIG: LibConfig = Object.freeze({\n slideConfig: DEFAULT_SLIDE_CONFIG,\n accessibilityConfig: KS_DEFAULT_ACCESSIBILITY_CONFIG,\n previewConfig: DEFAULT_PREVIEW_CONFIG,\n buttonsConfig: { visible: true, strategy: ButtonsStrategy.DEFAULT } as ButtonsConfig,\n dotsConfig: { visible: true } as DotsConfig,\n plainGalleryConfig: DEFAULT_PLAIN_CONFIG,\n currentImageConfig: DEFAULT_CURRENT_IMAGE_CONFIG,\n keyboardConfig: undefined, // by default nothing, because the library uses default buttons automatically\n carouselConfig: DEFAULT_CURRENT_CAROUSEL_CONFIG,\n carouselImageConfig: DEFAULT_CAROUSEL_IMAGE_CONFIG,\n carouselPreviewsConfig: DEFAULT_CAROUSEL_PREVIEWS_CONFIG,\n carouselPlayConfig: DEFAULT_CURRENT_CAROUSEL_PLAY,\n carouselDotsConfig: { visible: true } as DotsConfig,\n carouselSlideInfinite: true,\n enableCloseOutside: true\n});\n\n/**\n * Service to handle library configuration in a unique place\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfigService {\n configMap: Map<number, LibConfig> = new Map<number, LibConfig>();\n\n getConfig(id: number): LibConfig | undefined {\n this.initIfNotExists(id);\n return this.configMap.get(id);\n }\n\n setConfig(id: number, obj: LibConfig | undefined): void {\n this.initIfNotExists(id);\n if (!obj) {\n return;\n }\n\n if (\n !DEFAULT_CONFIG ||\n !DEFAULT_CONFIG.slideConfig ||\n !DEFAULT_CONFIG.slideConfig.sidePreviews ||\n !DEFAULT_CONFIG.previewConfig ||\n !DEFAULT_CONFIG.previewConfig.size ||\n !DEFAULT_CONFIG.previewConfig.number ||\n !DEFAULT_CONFIG.plainGalleryConfig ||\n !DEFAULT_CONFIG.currentImageConfig ||\n !DEFAULT_CONFIG.currentImageConfig ||\n !DEFAULT_CONFIG.currentImageConfig.description ||\n !DEFAULT_CONFIG.carouselImageConfig ||\n !DEFAULT_CONFIG.carouselImageConfig.description ||\n !DEFAULT_CONFIG.carouselPreviewsConfig ||\n !DEFAULT_CONFIG.carouselPreviewsConfig.breakpoints ||\n !DEFAULT_CAROUSEL_PREVIEWS_CONFIG.number\n ) {\n throw new Error('Internal library error - DEFAULT_CONFIG must be fully initialized!!!');\n }\n\n const newConfig: LibConfig = Object.assign({}, this.configMap.get(id));\n if (obj.slideConfig) {\n let playConfig;\n let sidePreviews;\n let size;\n if (obj.slideConfig.playConfig) {\n playConfig = Object.assign({}, DEFAULT_CONFIG.slideConfig.playConfig, obj.slideConfig.playConfig);\n } else {\n playConfig = DEFAULT_CONFIG.slideConfig.playConfig;\n }\n if (obj.slideConfig.sidePreviews) {\n if (obj.slideConfig.sidePreviews.size) {\n size = Object.assign({}, DEFAULT_CONFIG.slideConfig.sidePreviews.size, obj.slideConfig.sidePreviews.size);\n } else {\n size = DEFAULT_CONFIG.slideConfig.sidePreviews.size;\n }\n sidePreviews = Object.assign({}, DEFAULT_CONFIG.slideConfig.sidePreviews, obj.slideConfig.sidePreviews);\n } else {\n sidePreviews = DEFAULT_CONFIG.slideConfig.sidePreviews;\n size = DEFAULT_CONFIG.slideConfig.sidePreviews.size;\n }\n const newSlideConfig: SlideConfig = Object.assign({}, DEFAULT_CONFIG.slideConfig, obj.slideConfig);\n newSlideConfig.playConfig = playConfig;\n newSlideConfig.sidePreviews = sidePreviews;\n newSlideConfig.sidePreviews.size = size;\n newConfig.slideConfig = newSlideConfig;\n }\n if (obj.accessibilityConfig) {\n newConfig.accessibilityConfig = Object.assign({}, DEFAULT_CONFIG.accessibilityConfig, obj.accessibilityConfig);\n }\n if (obj.previewConfig) {\n let size: Size;\n let num: number;\n if (obj.previewConfig.size) {\n size = Object.assign({}, DEFAULT_CONFIG.previewConfig.size, obj.previewConfig.size);\n } else {\n size = DEFAULT_CONFIG.previewConfig.size;\n }\n if (obj.previewConfig.number) {\n if (obj.previewConfig.number <= 0) {\n // if number is <= 0 reset to default\n num = DEFAULT_CONFIG.previewConfig.number;\n } else {\n num = obj.previewConfig.number;\n }\n } else {\n num = DEFAULT_CONFIG.previewConfig.number;\n }\n const newPreviewConfig: PreviewConfig = Object.assign({}, DEFAULT_CONFIG.previewConfig, obj.previewConfig);\n newPreviewConfig.size = size;\n newPreviewConfig.number = num;\n newConfig.previewConfig = newPreviewConfig;\n }\n if (obj.buttonsConfig) {\n newConfig.buttonsConfig = Object.assign({}, DEFAULT_CONFIG.buttonsConfig, obj.buttonsConfig);\n }\n if (obj.dotsConfig) {\n newConfig.dotsConfig = Object.assign({}, DEFAULT_CONFIG.dotsConfig, obj.dotsConfig);\n }\n if (obj.plainGalleryConfig) {\n let advanced;\n let layout;\n if (obj.plainGalleryConfig.advanced) {\n advanced = Object.assign({}, DEFAULT_CONFIG.plainGalleryConfig.advanced, obj.plainGalleryConfig.advanced);\n } else {\n advanced = DEFAULT_CONFIG.plainGalleryConfig.advanced;\n }\n if (obj.plainGalleryConfig.layout) {\n // it isn't mandatory to use assign, because obj.plainGalleryConfig.layout is an instance of class (LineaLayout, GridLayout)\n layout = obj.plainGalleryConfig.layout;\n } else {\n layout = DEFAULT_CONFIG.plainGalleryConfig.layout;\n }\n const newPlainGalleryConfig: PlainGalleryConfig = Object.assign({}, DEFAULT_CONFIG.plainGalleryConfig, obj.plainGalleryConfig);\n newPlainGalleryConfig.layout = layout;\n newPlainGalleryConfig.advanced = advanced;\n newConfig.plainGalleryConfig = initPlainGalleryConfig(newPlainGalleryConfig);\n }\n if (obj.currentImageConfig) {\n let loading;\n let description;\n let descriptionStyle;\n if (obj.currentImageConfig.loadingConfig) {\n loading = Object.assign({}, DEFAULT_CONFIG.currentImageConfig.loadingConfig, obj.currentImageConfig.loadingConfig);\n } else {\n loading = DEFAULT_CONFIG.currentImageConfig.loadingConfig;\n }\n if (obj.currentImageConfig.description) {\n description = Object.assign({}, DEFAULT_CONFIG.currentImageConfig.description, obj.currentImageConfig.description);\n if (obj.currentImageConfig.description.style) {\n descriptionStyle = Object.assign({}, DEFAULT_CONFIG.currentImageConfig.description.style, obj.currentImageConfig.description.style);\n } else {\n descriptionStyle = DEFAULT_CONFIG.currentImageConfig.description.style;\n }\n } else {\n description = DEFAULT_CONFIG.currentImageConfig.description;\n descriptionStyle = DEFAULT_CONFIG.currentImageConfig.description.style;\n }\n const newCurrentImageConfig: CurrentImageConfig = Object.assign({}, DEFAULT_CONFIG.currentImageConfig, obj.currentImageConfig);\n newCurrentImageConfig.loadingConfig = loading;\n newCurrentImageConfig.description = description;\n newCurrentImageConfig.description.style = descriptionStyle;\n newConfig.currentImageConfig = newCurrentImageConfig;\n }\n if (obj.keyboardConfig) {\n newConfig.keyboardConfig = Object.assign({}, DEFAULT_CONFIG.keyboardConfig, obj.keyboardConfig);\n }\n\n // carousel\n if (obj.carouselConfig) {\n newConfig.carouselConfig = Object.assign({}, DEFAULT_CONFIG.carouselConfig, obj.carouselConfig);\n }\n if (obj.carouselImageConfig) {\n let description;\n let descriptionStyle;\n if (obj.carouselImageConfig.description) {\n description = Object.assign({}, DEFAULT_CONFIG.carouselImageConfig.description, obj.carouselImageConfig.description);\n if (obj.carouselImageConfig.description.style) {\n descriptionStyle = Object.assign({}, DEFAULT_CONFIG.carouselImageConfig.description.style, obj.carouselImageConfig.description.style);\n } else {\n descriptionStyle = DEFAULT_CONFIG.carouselImageConfig.description.style;\n }\n } else {\n description = DEFAULT_CONFIG.carouselImageConfig.description;\n descriptionStyle = DEFAULT_CONFIG.carouselImageConfig.description.style;\n }\n const newCarouselImageConfig: CarouselImageConfig = Object.assign({}, DEFAULT_CONFIG.carouselImageConfig, obj.carouselImageConfig);\n newCarouselImageConfig.description = description;\n newCarouselImageConfig.description.style = descriptionStyle;\n newConfig.carouselImageConfig = newCarouselImageConfig;\n }\n if (obj.carouselPlayConfig) {\n // check values\n if (obj.carouselPlayConfig.interval <= 0) {\n throw new Error(`Carousel's interval must be a number >= 0`);\n }\n newConfig.carouselPlayConfig = Object.assign({}, DEFAULT_CONFIG.carouselPlayConfig, obj.carouselPlayConfig);\n }\n if (obj.carouselPreviewsConfig) {\n // check values\n let num: number;\n let breakpoints: BreakpointsConfig;\n if (!obj.carouselPreviewsConfig.number || obj.carouselPreviewsConfig.number <= 0) {\n num = DEFAULT_CAROUSEL_PREVIEWS_CONFIG.number;\n } else {\n num = obj.carouselPreviewsConfig.number;\n }\n if (obj.carouselPreviewsConfig.breakpoints) {\n breakpoints = Object.assign({}, DEFAULT_CONFIG.carouselPreviewsConfig.breakpoints, obj.carouselPreviewsConfig.breakpoints);\n } else {\n breakpoints = DEFAULT_CONFIG.carouselPreviewsConfig.breakpoints;\n }\n newConfig.carouselPreviewsConfig = Object.assign({}, DEFAULT_CONFIG.carouselPreviewsConfig, obj.carouselPreviewsConfig);\n newConfig.carouselPreviewsConfig.number = num;\n newConfig.carouselPreviewsConfig.breakpoints = breakpoints;\n // Init preview image width based on the number of previews in PreviewConfig\n // Don't move this line above, because I need to be sure that both configPreview.number\n // and configPreview.size are initialized\n newConfig.carouselPreviewsConfig.width = 100 / newConfig.carouselPreviewsConfig.number + '%';\n }\n if (obj.carouselDotsConfig) {\n newConfig.carouselDotsConfig = Object.assign({}, DEFAULT_CONFIG.carouselDotsConfig, obj.carouselDotsConfig);\n }\n if (obj.carouselSlideInfinite === undefined) {\n newConfig.carouselSlideInfinite = DEFAULT_CONFIG.carouselSlideInfinite;\n } else {\n newConfig.carouselSlideInfinite = obj.carouselSlideInfinite;\n }\n if (obj.enableCloseOutside === undefined) {\n newConfig.enableCloseOutside = DEFAULT_CONFIG.enableCloseOutside;\n } else {\n newConfig.enableCloseOutside = obj.enableCloseOutside;\n }\n this.configMap.set(id, newConfig);\n }\n\n private initIfNotExists(id: number): void {\n if (!this.configMap.has(id)) {\n this.configMap.set(id, DEFAULT_CONFIG);\n }\n }\n}\n\n/**\n * Function to build and return a `PlainGalleryConfig` object, proving also default values and validating the input object.\n * @param plainGalleryConfig object with the config requested by user\n * @returns PlainGalleryConfig the plain gallery configuration\n * @throws an Error if layout and strategy aren't compatible\n */\nfunction initPlainGalleryConfig(plainGalleryConfig: PlainGalleryConfig): PlainGalleryConfig {\n const newPlayGalleryConfig: PlainGalleryConfig = Object.assign({}, DEFAULT_CONFIG.plainGalleryConfig, plainGalleryConfig);\n\n if (newPlayGalleryConfig.layout instanceof LineLayout) {\n if (newPlayGalleryConfig.strategy !== PlainGalleryStrategy.ROW && newPlayGalleryConfig.strategy !== PlainGalleryStrategy.COLUMN) {\n throw new Error('LineLayout requires either ROW or COLUMN strategy');\n }\n if (!newPlayGalleryConfig.layout || !newPlayGalleryConfig.layout.breakConfig) {\n throw new Error('Both layout and breakConfig must be valid');\n }\n }\n\n if (newPlayGalleryConfig.layout instanceof GridLayout) {\n if (newPlayGalleryConfig.strategy !== PlainGalleryStrategy.GRID) {\n throw new Error('GridLayout requires GRID strategy');\n }\n if (!newPlayGalleryConfig.layout || !newPlayGalleryConfig.layout.breakConfig) {\n throw new Error('Both layout and breakConfig must be valid');\n }\n // force wrap for grid layout\n newPlayGalleryConfig.layout.breakConfig.wrap = true;\n }\n return newPlayGalleryConfig;\n}\n","/*\n The MIT License (MIT)\n\n Copyright (c) 2017-2024 Stefano Cappa (Ks89)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN