/* ------------------------------------------------------------------------------
 *
 *  # Template JS core
 *
 *  Includes minimum required JS code for proper template functioning
 *
 * ---------------------------------------------------------------------------- */


// Setup module
// ------------------------------

const App = function () {


    // Utils
    // -------------------------

    //
    // Transitions
    //

    // Disable all transitions
    const transitionsDisabled = function() {
        document.body.classList.add('no-transitions');
    };

    // Enable all transitions
    const transitionsEnabled = function() {
        document.body.classList.remove('no-transitions');
    };


    //
    // Detect OS to apply custom scrollbars
    //

    // Custom scrollbar style is controlled by CSS. This function is needed to keep default
    // scrollbars on MacOS and avoid usage of extra JS libraries
    const detectOS = function() {
        const platform = window.navigator.platform,
              windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
              customScrollbarsClass = 'custom-scrollbars';

        // Add class if OS is windows
        windowsPlatforms.indexOf(platform) != -1 && document.documentElement.classList.add(customScrollbarsClass);
    };



    // Sidebars
    // -------------------------

    //
    // On desktop
    //

    // Resize main sidebar
    const sidebarMainResize = function() {

        document.querySelectorAll('.btn-light-theme').forEach(function(btn) {
            btn.addEventListener('click', function() {
                    // localStorage.removeItem('theme');
                // }
                // else {
                    localStorage.removeItem('theme');
            })
        })

        document.querySelectorAll('.btn-dark-theme').forEach(function(btn) {
            btn.addEventListener('click', function() {
                    // localStorage.removeItem('theme');
                // }
                // else {
                    localStorage.setItem('theme', 'dark');
            })
        })

        document.querySelectorAll('.btn-auto-theme').forEach(function(btn) {
            btn.addEventListener('click', function() {
                    // localStorage.removeItem('theme');
                // }
                // else {
                    window.matchMedia('(prefers-color-scheme: dark)').matches ? localStorage.setItem('theme', 'auto') : localStorage.removeItem('theme');
                    // ((localStorage.getItem('theme') == 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) || localStorage.getItem('theme') == 'dark') && document.documentElement.setAttribute('data-color-theme', 'dark');
            })
        })

        // Elements
        const sidebarMainElement = document.querySelector('.sidebar-main'),
              sidebarMainToggler = document.querySelectorAll('.sidebar-main-resize'),
              resizeClass = 'sidebar-main-resized',
              unfoldClass = 'sidebar-main-unfold';


        // Config
        if (sidebarMainElement) {

            // Define variables
            const unfoldDelay = 150;
            let timerStart,
                timerFinish;

            // Toggle classes on click
            sidebarMainToggler.forEach(function(toggler) {
                toggler.addEventListener('click', function(e) {
                    e.preventDefault();
                    sidebarMainElement.classList.toggle(resizeClass);
                    !sidebarMainElement.classList.contains(resizeClass) && sidebarMainElement.classList.remove(unfoldClass);
                });                
            });

            // Add class on mouse enter
            sidebarMainElement.addEventListener('mouseenter', function() {
                clearTimeout(timerFinish);
                timerStart = setTimeout(function() {
                    sidebarMainElement.classList.contains(resizeClass) && sidebarMainElement.classList.add(unfoldClass);
                }, unfoldDelay);
            });

            // Remove class on mouse leave
            sidebarMainElement.addEventListener('mouseleave', function() {
                clearTimeout(timerStart);
                timerFinish = setTimeout(function() {
                    sidebarMainElement.classList.remove(unfoldClass);
                }, unfoldDelay);
            });
        }
    };

    // Toggle main sidebar
    const sidebarMainToggle = function() {

        // Elements
        const sidebarMainElement = document.querySelector('.sidebar-main'),
              sidebarMainRestElements = document.querySelectorAll('.sidebar:not(.sidebar-main):not(.sidebar-component)'),
              sidebarMainDesktopToggler = document.querySelectorAll('.sidebar-main-toggle'),
              sidebarMainMobileToggler = document.querySelectorAll('.sidebar-mobile-main-toggle'),
              sidebarCollapsedClass = 'sidebar-collapsed',
              sidebarMobileExpandedClass = 'sidebar-mobile-expanded';

        // On desktop
        sidebarMainDesktopToggler.forEach(function(toggler) {
            toggler.addEventListener('click', function(e) {
                e.preventDefault();
                sidebarMainElement.classList.toggle(sidebarCollapsedClass);
            });                
        });

        // On mobile
        sidebarMainMobileToggler.forEach(function(toggler) {
            toggler.addEventListener('click', function(e) {
                e.preventDefault();
                sidebarMainElement.classList.toggle(sidebarMobileExpandedClass);

                sidebarMainRestElements.forEach(function(sidebars) {
                    sidebars.classList.remove(sidebarMobileExpandedClass);
                });
            });                
        });
    };

    // Toggle secondary sidebar
    const sidebarSecondaryToggle = function() {

        // Elements
        const sidebarSecondaryElement = document.querySelector('.sidebar-secondary'),
              sidebarSecondaryRestElements = document.querySelectorAll('.sidebar:not(.sidebar-secondary):not(.sidebar-component)'),
              sidebarSecondaryDesktopToggler = document.querySelectorAll('.sidebar-secondary-toggle'),
              sidebarSecondaryMobileToggler = document.querySelectorAll('.sidebar-mobile-secondary-toggle'),
              sidebarCollapsedClass = 'sidebar-collapsed',
              sidebarMobileExpandedClass = 'sidebar-mobile-expanded';

        // On desktop
        sidebarSecondaryDesktopToggler.forEach(function(toggler) {
            toggler.addEventListener('click', function(e) {
                e.preventDefault();
                sidebarSecondaryElement.classList.toggle(sidebarCollapsedClass);
            });                
        });

        // On mobile
        sidebarSecondaryMobileToggler.forEach(function(toggler) {
            toggler.addEventListener('click', function(e) {
                e.preventDefault();
                sidebarSecondaryElement.classList.toggle(sidebarMobileExpandedClass);

                sidebarSecondaryRestElements.forEach(function(sidebars) {
                    sidebars.classList.remove(sidebarMobileExpandedClass);
                });
            });                
        });
    };

    // Toggle right sidebar
    const sidebarRightToggle = function() {

        // Elements
        const sidebarRightElement = document.querySelector('.sidebar-end'),
              sidebarRightRestElements = document.querySelectorAll('.sidebar:not(.sidebar-end):not(.sidebar-component)'),
              sidebarRightDesktopToggler = document.querySelectorAll('.sidebar-end-toggle'),
              sidebarRightMobileToggler = document.querySelectorAll('.sidebar-mobile-end-toggle'),
              sidebarCollapsedClass = 'sidebar-collapsed',
              sidebarMobileExpandedClass = 'sidebar-mobile-expanded';

        // On desktop
        sidebarRightDesktopToggler.forEach(function(toggler) {
            toggler.addEventListener('click', function(e) {
                e.preventDefault();
                sidebarRightElement.classList.toggle(sidebarCollapsedClass);
            });                
        });

        // On mobile
        sidebarRightMobileToggler.forEach(function(toggler) {
            toggler.addEventListener('click', function(e) {
                e.preventDefault();
                sidebarRightElement.classList.toggle(sidebarMobileExpandedClass);

                sidebarRightRestElements.forEach(function(sidebars) {
                    sidebars.classList.remove(sidebarMobileExpandedClass);
                });
            });                
        });
    };

    // Toggle component sidebar
    const sidebarComponentToggle = function() {

        // Elements
        const sidebarComponentElement = document.querySelector('.sidebar-component'),
              sidebarComponentMobileToggler = document.querySelectorAll('.sidebar-mobile-component-toggle'),
              sidebarMobileExpandedClass = 'sidebar-mobile-expanded';

        // Toggle classes
        sidebarComponentMobileToggler.forEach(function(toggler) {
            toggler.addEventListener('click', function(e) {
                e.preventDefault();
                sidebarComponentElement.classList.toggle(sidebarMobileExpandedClass);
            });                
        });
    };


    // Navigations
    // -------------------------

    // Sidebar navigation
    const navigationSidebar = function() {

        // Elements
        const navContainerClass = 'nav-sidebar',
              navItemOpenClass = 'nav-item-open',
              navLinkClass = 'nav-link',
              navLinkDisabledClass = 'disabled',
              navSubmenuContainerClass = 'nav-item-submenu',
              navSubmenuClass = 'nav-group-sub',
              navScrollSpyClass = 'nav-scrollspy',
              sidebarNavElement = document.querySelectorAll(`.${navContainerClass}:not(.${navScrollSpyClass})`);

        // Setup
        sidebarNavElement.forEach(function(nav) {
            nav.querySelectorAll(`.${navSubmenuContainerClass} > .${navLinkClass}:not(.${navLinkDisabledClass})`).forEach(function(link) {
                link.addEventListener('click', function(e) {
                    e.preventDefault();
                    const submenuContainer = link.closest(`.${navSubmenuContainerClass}`);
                    const submenu = link.closest(`.${navSubmenuContainerClass}`).querySelector(`:scope > .${navSubmenuClass}`);

                    // Collapsible
                    if(submenuContainer.classList.contains(navItemOpenClass)) {
                        new bootstrap.Collapse(submenu).hide();
                        submenuContainer.classList.remove(navItemOpenClass);
                    }
                    else {
                        new bootstrap.Collapse(submenu).show();
                        submenuContainer.classList.add(navItemOpenClass);
                    }

                    // Accordion
                    if (link.closest(`.${navContainerClass}`).getAttribute('data-nav-type') == 'accordion') {
                        for (let sibling of link.parentNode.parentNode.children) {
                            if (sibling != link.parentNode && sibling.classList.contains(navItemOpenClass)) {
                                sibling.querySelectorAll(`:scope > .${navSubmenuClass}`).forEach(function(submenu) {
                                    new bootstrap.Collapse(submenu).hide();
                                    sibling.classList.remove(navItemOpenClass);
                                });
                            }
                        }
                    }
                });
            });
        });
    };



    const componentTooltip = function() {
        const tooltipSelector = document.querySelectorAll('[data-bs-popup="tooltip"]');

        tooltipSelector.forEach(function(popup) {
            new bootstrap.Tooltip(popup, {
                boundary: '.page-content'
            });
        });
    };

    // Popover
    const componentPopover = function() {
        const popoverSelector = document.querySelectorAll('[data-bs-popup="popover"]');

        popoverSelector.forEach(function(popup) {
            new bootstrap.Popover(popup, {
                boundary: '.page-content'
            });
        });
    };
    // Custom popover background color
    const componentPopoverCustomBackgroundColor = function() {
        const customPopoverElement = document.querySelectorAll('[data-bs-popup="popover-solid"]');
        if(customPopoverElement) {
            customPopoverElement.forEach(function (popup) {
                new bootstrap.Popover(popup, {
                    customClass: 'popover-custom',
                    // template: '<div class="popover bg-primary border-primary"><div class="popover-arrow border-primary"></div><h3 class="popover-header bg-primary text-white border-white border-opacity-25"></h3></div>'
                    template: '<div class="popover bg-primary border-primary"><div class="popover-arrow border-primary"></div><h3 class="popover-header bg-primary text-white border-white border-opacity-25"></h3><div class="popover-body text-white"></div></div>'

                });
            });
        }

        // if(customPopoverElement) {
        //     new bootstrap.Popover(customPopoverElement, {
        //         customClass: 'popover-custom',
        //         // template: '<div class="popover-arrow border-primary"><div class="popover-arrow border-primary"></div><h3 class="popover-header bg-primary text-white border-white border-opacity-25"></h3></div>'
        //         template: '<div class="popover bg-primary border-primary"><div class="popover-arrow border-primary"></div><h3 class="popover-header bg-primary text-white border-white border-opacity-25"></h3><div class="popover-body text-white"></div></div>'
        //     });
        // }
    };

    // "Go to top" button
    const componentToTopButton = function() {

        // Elements
        const toTopContainer = document.querySelector('.content-wrapper'),
              toTopElement = document.createElement('button'),
              toTopElementIcon = document.createElement('i'),
              toTopButtonContainer = document.createElement('div'),
              toTopButtonColorClass = 'btn-secondary',
              toTopButtonIconClass = 'ph-arrow-up',
              scrollableContainer = document.querySelector('.content-inner'),
              scrollableDistance = 250,
              footerContainer = document.querySelector('.navbar-footer');


        // Append only if container exists
        if (scrollableContainer) {

            // Create button container
            toTopContainer.appendChild(toTopButtonContainer);
            toTopButtonContainer.classList.add('btn-to-top');

            // Create button
            toTopElement.classList.add('btn', toTopButtonColorClass, 'btn-icon', 'rounded-pill');
            toTopElement.setAttribute('type', 'button');
            toTopButtonContainer.appendChild(toTopElement);
            toTopElementIcon.classList.add(toTopButtonIconClass);
            toTopElement.appendChild(toTopElementIcon);

            // Show and hide on scroll
            const to_top_button = document.querySelector('.btn-to-top'),
                  add_class_on_scroll = () => to_top_button.classList.add('btn-to-top-visible'),
                  remove_class_on_scroll = () => to_top_button.classList.remove('btn-to-top-visible');

            scrollableContainer.addEventListener('scroll', function() { 
                const scrollpos = scrollableContainer.scrollTop;
                scrollpos >= scrollableDistance ? add_class_on_scroll() : remove_class_on_scroll();
                if(footerContainer) {
                    if (this.scrollHeight - this.scrollTop - this.clientHeight <= footerContainer.clientHeight) {
                        to_top_button.style.bottom = footerContainer.clientHeight + 20 + 'px';
                    }
                    else {
                        to_top_button.removeAttribute('style');
                    }
                }
            });

            // Scroll to top on click
            document.querySelector('.btn-to-top .btn').addEventListener('click', function() {
                scrollableContainer.scrollTo(0, 0);
            });
        }
    };

    const componentDragula = function() {
        if (typeof dragula == 'undefined') {
            console.warn('Warning - dragula.min.js is not loaded.');
            return;
        }

        const containers = dragula(Array.from(document.querySelectorAll('.sortable')), {
                isContainer: function (el) {
                    return el.classList.contains('dragula-container');
                 //   return false; // во внимание будут приниматься только элементы в drake.containers
                },
                moves: function (el, source, handle, sibling) {
                    return true; // по умолчанию элементы всегда можно перетаскивать
                },
                accepts: function (el, target, source, sibling) {
                    return true; // по умолчанию элементы могут быть помещены в любой из "контейнеров"
                },
                invalid: function (el, handle) {
                    return false; //не запрещайте инициировать какие-либо перетаскивания по умолчанию
                },
                direction: 'vertical',             // Y ось учитывается при определении того, куда будет отброшен элемент
                copy: false,                       // элементы перемещаются по умолчанию, а не копируются
                copySortSource: false,             // элементы в контейнерах с копируемым исходным кодом могут быть переупорядочены
                revertOnSpill: false,              // перетекание вернет элемент туда, откуда он был перетащен, если это true
                removeOnSpill: false,              // разрыв приведет к `.удалению` элемента, если это true
                ignoreInputTextSelection: true,     // позволяет пользователям выбирать вводимый текст, подробности см. ниже
                // slideFactorX: 0,               // allows users to select the amount of movement on the X axis before it is considered a drag instead of a click
                slideFactorY: 50,               // allows users to select the amount of movement on the Y axis before it is considered a drag instead of a click
                mirrorContainer: document.querySelector('.sortable')
        });
        containers
            .on('drag', function (el) {
                el.className = el.className.replace('ex-moved', '');
            }).on('drop', function (el) {
                el.className += ' ex-moved';
                $('.sortable_footer_navbar').addClass('show');
            }).on('over', function (el, container) {
                container.className += ' ex-over';
            }).on('out', function (el, container) {
                container.className = container.className.replace('ex-over', '');
            });

        const songs = dragula(Array.from(document.querySelectorAll('.sortable-songs')), {
            isContainer: function (el) {
                return el.classList.contains('dragula-container');
                //   return false; // во внимание будут приниматься только элементы в drake.containers
            },
            moves: function (el, source, handle, sibling) {
                return true; // по умолчанию элементы всегда можно перетаскивать
            },
            accepts: function (el, target, source, sibling) {
                return true; // по умолчанию элементы могут быть помещены в любой из "контейнеров"
            },
            invalid: function (el, handle) {
                return false; //не запрещайте инициировать какие-либо перетаскивания по умолчанию
            },
            direction: 'vertical',             // Y ось учитывается при определении того, куда будет отброшен элемент
            copy: false,                       // элементы перемещаются по умолчанию, а не копируются
            copySortSource: false,             // элементы в контейнерах с копируемым исходным кодом могут быть переупорядочены
            revertOnSpill: false,              // перетекание вернет элемент туда, откуда он был перетащен, если это true
            removeOnSpill: false,              // разрыв приведет к `.удалению` элемента, если это true
            ignoreInputTextSelection: true,     // позволяет пользователям выбирать вводимый текст, подробности см. ниже
            // slideFactorX: 0,               // allows users to select the amount of movement on the X axis before it is considered a drag instead of a click
            slideFactorY: 50,               // allows users to select the amount of movement on the Y axis before it is considered a drag instead of a click
            mirrorContainer: document.querySelector('.sortable-songs')
        });
        songs
            .on('drag', function (el) {
                el.className = el.className.replace('ex-moved', '');
            }).on('drop', function (el) {
            el.className += ' ex-moved';
            $('.songs_footer_navbar').addClass('show');
        }).on('over', function (el, container) {
            container.className += ' ex-over';
        }).on('out', function (el, container) {
            container.className = container.className.replace('ex-over', '');
        });


        const tableContainers = dragula(Array.from(document.querySelectorAll('.sortable-table')), {
            isContainer: function (el) {
                return el.classList.contains('dragula-container');
            },
            moves: function (el, source, handle, sibling) {
                return true; // по умолчанию элементы всегда можно перетаскивать
            },
            accepts: function (el, target, source, sibling) {
                return true; // по умолчанию элементы могут быть помещены в любой из "контейнеров"
            },
            invalid: function (el, handle) {
                return false; //не запрещайте инициировать какие-либо перетаскивания по умолчанию
            },
            direction: 'vertical',             // Y ось учитывается при определении того, куда будет отброшен элемент
            copy: false,                       // элементы перемещаются по умолчанию, а не копируются
            copySortSource: false,             // элементы в контейнерах с копируемым исходным кодом могут быть переупорядочены
            revertOnSpill: false,              // перетекание вернет элемент туда, откуда он был перетащен, если это true
            removeOnSpill: false,              // разрыв приведет к `.удалению` элемента, если это true
            ignoreInputTextSelection: true,     // позволяет пользователям выбирать вводимый текст, подробности см. ниже
            // slideFactorX: 0,               // allows users to select the amount of movement on the X axis before it is considered a drag instead of a click
            slideFactorY: 50,               // allows users to select the amount of movement on the Y axis before it is considered a drag instead of a click
            mirrorContainer: document.querySelector('.sortable-table')
        });
        // tableContainers.on('drag', function (el) {
        //     el.className = el.className.replace('ex-moved', '');
        // }).on('drop', function (el) {
        //     el.className += ' ex-moved';
        // }).on('over', function (el, container) {
        //     container.className += ' ex-over';
        // }).on('out', function (el, container) {
        //     container.className = container.className.replace('ex-over', '');
        // });

    };

    // Lightbox
    const componentLightbox = function() {
        if (typeof GLightbox == 'undefined') {
            console.warn('Warning - glightbox.min.js is not loaded.');
            return;
        }

        const lightbox = GLightbox({
            selector: '[data-popup="lightbox"]',
            loop: true,
        });
    };
    // Select2 examples
    var componentSelect2 = function() {
        if (!$().select2) {
            console.warn('Warning - select2.min.js is not loaded.');
            return;
        }

        $('.select').select2({
            minimumResultsForSearch: Infinity,
            placeholder: 'Выберите...'
        });

        $('.select-search').select2({
            placeholder: 'Выберите...'
        });

        //
        // Single select with icons
        //

        // Format icon
        function iconFormat(icon) {
            var originalOption = icon.element;
            if (!icon.id) { return icon.text; }
            var $icon = '<i class="ph-' + $(icon.element).data('icon') + '"></i>' + icon.text;

            return $icon;
        }

        // Initialize with options
        $('.select-icons').select2({
            templateResult: iconFormat,
            minimumResultsForSearch: Infinity,
            templateSelection: iconFormat,
            escapeMarkup: function(m) { return m; }
        });


        //
        // Customize matched results
        //

        // Setup matcher
        function matchStart (term, text) {
            if (text.toUpperCase().indexOf(term.toUpperCase()) == 0) {
                return true;
            }

            return false;
        }

        // Initialize
        $.fn.select2.amd.require(['select2/compat/matcher'], function (oldMatcher) {
            $('.select-matched-customize').select2({
                minimumResultsForSearch: Infinity,
                placeholder: 'Select a State',
                matcher: oldMatcher(matchStart)
            });
        });


        // Format displayed data
        function formatRepo (repo) {
            if (repo.loading) return repo.text;

            var markup = '<div class="select2-result-repository clearfix">' +
                '<div class="select2-result-repository__avatar"><img src="' + repo.owner.avatar_url + '" /></div>' +
                '<div class="select2-result-repository__meta">' +
                '<div class="select2-result-repository__title">' + repo.full_name + '</div>';

            if (repo.description) {
                markup += '<div class="select2-result-repository__description">' + repo.description + '</div>';
            }

            markup += '<div class="select2-result-repository__statistics">' +
                '<div class="select2-result-repository__forks">' + repo.forks_count + ' Forks</div>' +
                '<div class="select2-result-repository__stargazers">' + repo.stargazers_count + ' Stars</div>' +
                '<div class="select2-result-repository__watchers">' + repo.watchers_count + ' Watchers</div>' +
                '</div>' +
                '</div></div>';

            return markup;
        }

        // Format selection
        function formatRepoSelection (repo) {
            return repo.full_name || repo.text;
        }

        // Initialize
        $('.select-remote-data').select2({
            ajax: {
                url: 'https://api.github.com/search/repositories',
                dataType: 'json',
                delay: 250,
                data: function (params) {
                    return {
                        q: params.term, // search term
                        page: params.page
                    };
                },
                processResults: function (data, params) {

                    // parse the results into the format expected by Select2
                    // since we are using custom formatting functions we do not need to
                    // alter the remote JSON data, except to indicate that infinite
                    // scrolling can be used
                    params.page = params.page || 1;

                    return {
                        results: data.items,
                        pagination: {
                            more: (params.page * 30) < data.total_count
                        }
                    };
                },
                cache: true
            },
            escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
            minimumInputLength: 1,
            templateResult: formatRepo, // omitted for brevity, see the source of this page
            templateSelection: formatRepoSelection // omitted for brevity, see the source of this page
        });


        //
        // Programmatic access (single)
        //

        // Set/get value
        $('.select-access-value').select2({
            minimumResultsForSearch: Infinity,
            placeholder: 'Select State...'
        });
        $('.access-get').on('click', function () { alert('Selected value is: '+$('.select-access-value').val()); });
        $('.access-set').on('click', function () { $('.select-access-value').val('CA').trigger('change'); });


        // Open/close menu
        $('.select-access-open').select2({
            minimumResultsForSearch: Infinity,
            placeholder: 'Select State...'
        });
        $('.access-open').on('click', function () { $('.select-access-open').select2('open'); });
        $('.access-close').on('click', function () { $('.select-access-open').select2('close'); });


        // Enable/disable menu
        $('.select-access-enable').select2({
            minimumResultsForSearch: Infinity,
            placeholder: 'Select State...'
        });
        $('.access-disable').on('click', function () { $('.select-access-enable').prop('disabled', true); });
        $('.access-enable').on('click', function () { $('.select-access-enable').prop('disabled', false); });


        // Destroy/create menu
        function create_menu() {
            $('.select-access-create').select2({
                minimumResultsForSearch: Infinity,
                placeholder: 'Select State...'
            });
        }
        create_menu();
        $('.access-create').on('click', function () { return create_menu()});
        $('.access-destroy').on('click', function () { $('.select-access-create').select2('destroy'); });


        //
        // Programmatic access (multiple)
        //

        // Reacting to external value changes
        $('.select-access-multiple-value').select2();
        $('.change-to-ca').on('click', function() { $('.select-access-multiple-value').val('CA').trigger('change'); });
        $('.change-to-ak-co').on('click', function() { $('.select-access-multiple-value').val(['AK','CO']).trigger('change'); });


        // Open/close menu
        $('.select-access-multiple-open').select2({
            minimumResultsForSearch: Infinity
        });
        $('.access-multiple-open').on('click', function () { $('.select-access-multiple-open').select2('open'); });
        $('.access-multiple-close').on('click', function () { $('.select-access-multiple-open').select2('close'); });


        // Enable/disable menu
        $('.select-access-multiple-enable').select2({
            minimumResultsForSearch: Infinity
        });
        $('.access-multiple-disable').on('click', function () { $('.select-access-multiple-enable').prop('disabled', true); });
        $('.access-multiple-enable').on('click', function () { $('.select-access-multiple-enable').prop('disabled', false); });


        // Destroy/create menu
        function create_menu_multiple() {
            $('.select-access-multiple-create').select2({
                minimumResultsForSearch: Infinity
            });
        }
        create_menu_multiple();
        $('.access-multiple-create').on('click', function () { return create_menu_multiple()});
        $('.access-multiple-destroy').on('click', function () { $('.select-access-multiple-create').select2('destroy'); });


        // Clear selection
        $('.select-access-multiple-clear').select2({
            minimumResultsForSearch: Infinity
        });
        $('.access-multiple-clear').on('click', function () { $('.select-access-multiple-clear').val(null).trigger('change'); });
    };

    var componentMultiselect = function() {
        if (!$().multiselect) {
            console.warn('Warning - bootstrap-multiselect.js is not loaded.');
            return;
        }


        // Basic examples
        // ------------------------------

        // Basic initialization
        $('.multiselect').multiselect({
            selectAllText: 'Выбрать все',
            nonSelectedText: "Выберите опцию",
            allSelectedText: "Выбраны все",
            nSelectedText  : "Выбрано",
            filterPlaceholder: 'Поиск...'
        });

        // Prevent deselect
        var $preventDeselectElement = $('.multiselect-prevent-deselect');
        $preventDeselectElement.multiselect({
            onChange: function(option, checked) {
                if (checked === false) {
                    $preventDeselectElement.multiselect('select', option.val());
                }
            }
        });

        //
        // Display values
        //

        // Initialize
        $('.multiselect-display-values').multiselect();

        // Select options
        $('.multiselect-display-values-select').on('click', function() {
            $('.multiselect-display-values').multiselect('select', 'cheese');
            $('.multiselect-display-values').multiselect('select', 'tomatoes');

            $('.values-area').addClass('alert alert-info').text('Selected: ' + $('.multiselect-display-values').val().join(', '));
        });

        // Deselect options
        $('.multiselect-display-values-deselect').on('click', function() {
            $('.multiselect-display-values').multiselect('deselect', 'cheese');
            $('.multiselect-display-values').multiselect('deselect', 'tomatoes');

            $('.values-area').addClass('alert alert-info').text('Selected: ' + $('.multiselect-display-values').val() > 0 ? $('.multiselect-display-values').val().join(', ') : 'Nothing selected');
        });


        //
        // Toggle selection
        //

        // Select all/Deselect all
        function multiselect_selected($el) {
            var ret = true;
            $('option', $el).each(function(element) {
                if (!!!$(this).prop('selected')) {
                    ret = false;
                }
            });
            return ret;
        }
        function multiselect_selectAll($el) {
            $('option', $el).each(function(element) {
                $el.multiselect('select', $(this).val());
            });
        }
        function multiselect_deselectAll($el) {
            $('option', $el).each(function(element) {
                $el.multiselect('deselect', $(this).val());
            });
        }
        function multiselect_toggle($el, $btn) {
            if (multiselect_selected($el)) {
                multiselect_deselectAll($el);
                $btn.text('Select All');
            }
            else {
                multiselect_selectAll($el);
                $btn.text('Deselect All');
            }
        }

        // Initialize
        $('.multiselect-toggle-selection').multiselect();

        // Toggle selection on button click
        $('.multiselect-toggle-selection-button').on('click', function(e) {
            e.preventDefault();
            multiselect_toggle($('.multiselect-toggle-selection'), $(this));
        });


        //
        // Order options
        //

        var orderCount = 0;

        // Initialize
        $('.multiselect-order-options').multiselect({
            buttonText: function(options) {
                if (options.length == 0) {
                    return 'None selected';
                }
                else if (options.length > 3) {
                    return options.length + ' selected';
                }
                else {
                    var selected = [];
                    options.each(function() {
                        selected.push([$(this).text(), $(this).data('order')]);
                    });

                    selected.sort(function(a, b) {
                        return a[1] - b[1];
                    });

                    var text = '';
                    for (var i = 0; i < selected.length; i++) {
                        text += selected[i][0] + ', ';
                    }

                    return text.substr(0, text.length -2);
                }
            },
            onChange: function(option, checked) {
                if (checked) {
                    orderCount++;
                    $(option).data('order', orderCount);
                }
                else {
                    $(option).data('order', '');
                }
            }
        });

        // Order selected options on button click
        $('.multiselect-order-options-button').on('click', function() {
            var selected = [];
            $('.multiselect-order-options option:selected').each(function() {
                selected.push([$(this).val(), $(this).data('order')]);
            });

            selected.sort(function(a, b) {
                return a[1] - b[1];
            });

            var text = '';
            for (var i = 0; i < selected.length; i++) {
                text += selected[i][0] + ', ';
            }
            text = text.substring(0, text.length - 2);

            alert(text);
        });


        //
        // Reset selections
        //

        // Initialize
        $('.multiselect-reset').multiselect();

        // Reset using reset button
        $('#multiselect-reset-form').on('reset', function() {
            $('.multiselect-reset option:selected').each(function() {
                $(this).prop('selected', false);
            })

            $('.multiselect-reset').multiselect('refresh');
        });
    };

    var componentTagField = function() {
        // if (typeof Tokenfield == 'undefined') {
        //     console.warn('Warning - tokenfield.min.js is not loaded.');
        //     return;
        // }
        // const items = [
        //     {id: 1, name: "Acura"},
        //     {id: 2, name: "Audi"},
        //     {id: 3, name: "BMW"},
        // ];
        // document.querySelectorAll('.keywords').forEach(function(element) {
        //     console.log(element)
        //     const tfBasic = new Tokenfield({
        //         el: element,
        //         items: items
        //     });
        // });

        // const tfBasic = new Tokenfield({
        //     el: document.querySelector('.keywords'),
        //     items: items,
        //     setItems: items,
        //     placeholder: 'Custom placeholder',
        //     addItemsOnPaste: true,
        // });
        //
        // console.log(tfBasic);
        //
        // tfBasic.renderSetItemLabel = function(item) {
        //     return item.name.toUpperCase();
        // }
    };

    const componentFormValidate = function() {
        if (!$().validate) {
            console.warn('Warning - validate.min.js is not loaded.');
            return;
        }

        const validationElement = $('.validation');

        validationElement.validate({
            ignore: 'input[type=hidden], .select2-search__field', // игнорировать скрытые поля
            errorClass: 'validation-invalid-label',
            highlight: function(element, errorClass) {
                $(element).removeClass(errorClass);
            },
            unhighlight: function(element, errorClass) {
                $(element).removeClass(errorClass);
            },

            // Различные компоненты требуют правильного размещения меток ошибок
            errorPlacement: function(error, element) {

                // Input with icons and Select2
                if (element.hasClass('select2-hidden-accessible')) {
                    error.appendTo(element.parent());
                }

                // Группа ввода, проверки форм и пользовательские элементы управления
                else if (element.parents().hasClass('form-control-feedback') || element.parents().hasClass('form-check') || element.parents().hasClass('input-group')) {
                    error.appendTo(element.parent().parent());
                }
                else {
                    error.insertAfter(element);
                }
            },
            submitHandler: function(form) {
                $.ajax({
                    url: form.action,
                    type: form.method,
                    data: $(form).serialize(),
                    success: function(response) {
                        $('#answers').html(response);
                    }
                });
            }
        });
    };

    // Noty.js examples
    const componentNoty = function() {
        if (typeof Noty == 'undefined') {
            console.warn('Warning - noty.min.js is not loaded.');
            return;
        }

        // Override Noty defaults
        Noty.overrideDefaults({
            theme: 'limitless',
            layout: 'topRight',
            type: 'alert',
            timeout: 2500
        });

        // Error
        const notyErrorElement = document.querySelector('#noty_error');
        if(notyErrorElement) {
            notyErrorElement.addEventListener('click', function() {
                new Noty({
                    text: 'Change a few things up and try submitting again.',
                    type: 'error'
                }).show();
            });
        }

        // Success
        const notySuccessElement = document.querySelector('#noty_success');
        if(notySuccessElement) {
            notySuccessElement.addEventListener('click', function() {
                new Noty({
                    text: 'You successfully read this important alert message.',
                    type: 'success'
                }).show();
            });
        }

        // Warning
        const notyWarningElement = document.querySelector('#noty_warning');
        if(notyWarningElement) {
            notyWarningElement.addEventListener('click', function() {
                new Noty({
                    text: 'Warning! Best check yo self, you\'re not looking too good.',
                    type: 'warning'
                }).show();
            });
        }

        // Info
        const notyInfoElement = document.querySelector('#noty_info');
        if(notyInfoElement) {
            notyInfoElement.addEventListener('click', function() {
                new Noty({
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info'
                }).show();
            });
        }

        // Alert
        const notyAlertElement = document.querySelector('#noty_alert');
        if(notyAlertElement) {
            notyAlertElement.addEventListener('click', function() {
                new Noty({
                    text: 'Best check yourself, you\'re not looking too good.',
                    type: 'alert'
                }).show();
            });
        }

        // Confirmation
        const notyConfirmElement = document.querySelector('#noty_confirm');
        if(notyConfirmElement) {
            notyConfirmElement.addEventListener('click', function() {
                var notyConfirm = new Noty({
                    text: '<h6 class="mb-3">Please confirm your action</h6><label class="form-label">Enter comment (optional)</label> <input type="text" class="form-control" placeholder="Enter comment">',
                    timeout: false,
                    modal: true,
                    layout: 'center',
                    closeWith: 'button',
                    type: 'confirm',
                    buttons: [
                        Noty.button('Cancel', 'btn btn-link', function () {
                            notyConfirm.close();
                        }),

                        Noty.button('Submit <i class="ph-paper-plane-tilt ms-2"></i>', 'btn btn-primary ms-1', function () {
                                alert('Submitted!');
                                notyConfirm.close();
                            },
                            {id: 'button1', 'data-status': 'ok'}
                        )
                    ]
                }).show();
            });
        }


        //
        // Top position
        //

        // Top
        const notyTopElement = document.querySelector('#noty_top');
        if(notyTopElement) {
            notyTopElement.addEventListener('click', function() {
                new Noty({
                    layout: 'top',
                    text: 'Best check yourself, you\'re not looking too good.',
                    type: 'alert'
                }).show();
            });
        }

        // Left
        const notyTopLeftElement = document.querySelector('#noty_top_left');
        if(notyTopLeftElement) {
            notyTopLeftElement.addEventListener('click', function() {
                new Noty({
                    layout: 'topLeft',
                    text: 'Best check yourself, you\'re not looking too good.',
                    type: 'alert'
                }).show();
            });
        }

        // Center
        const notyTopCenterElement = document.querySelector('#noty_top_center');
        if(notyTopCenterElement) {
            notyTopCenterElement.addEventListener('click', function() {
                new Noty({
                    layout: 'topCenter',
                    text: 'Best check yourself, you\'re not looking too good.',
                    type: 'alert'
                }).show();
            });
        }

        // Right (default)
        const notyTopRightElement = document.querySelector('#noty_top_right');
        if(notyTopRightElement) {
            notyTopRightElement.addEventListener('click', function() {
                new Noty({
                    text: 'Best check yourself, you\'re not looking too good.',
                    type: 'alert'
                }).show();
            });
        }


        //
        // Center position
        //

        // Left
        const notyCenterLeftElement = document.querySelector('#noty_center_left');
        if(notyCenterLeftElement) {
            notyCenterLeftElement.addEventListener('click', function() {
                new Noty({
                    layout: 'centerLeft',
                    text: 'You successfully read this important alert message.',
                    type: 'success'
                }).show();
            });
        }

        // Center
        const notyCenterElement = document.querySelector('#noty_center');
        if(notyCenterElement) {
            notyCenterElement.addEventListener('click', function() {
                new Noty({
                    layout: 'center',
                    text: 'You successfully read this important alert message.',
                    type: 'success'
                }).show();
            });
        }

        // Right
        const notyCenterRightElement = document.querySelector('#noty_center_right');
        if(notyCenterRightElement) {
            notyCenterRightElement.addEventListener('click', function() {
                new Noty({
                    layout: 'centerRight',
                    text: 'You successfully read this important alert message.',
                    type: 'success'
                }).show();
            });
        }


        //
        // Bottom position
        //

        // Bottom
        const notyBottomElement = document.querySelector('#noty_bottom');
        if(notyBottomElement) {
            notyBottomElement.addEventListener('click', function() {
                new Noty({
                    layout: 'bottom',
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info'
                }).show();
            });
        }

        // Left
        const notyBottomLeftElement = document.querySelector('#noty_bottom_left');
        if(notyBottomLeftElement) {
            notyBottomLeftElement.addEventListener('click', function() {
                new Noty({
                    layout: 'bottomLeft',
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info'
                }).show();
            });
        }

        // Center
        const notyBottomCenterElement = document.querySelector('#noty_bottom_center');
        if(notyBottomCenterElement) {
            notyBottomCenterElement.addEventListener('click', function() {
                new Noty({
                    layout: 'bottomCenter',
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info'
                }).show();
            });
        }

        // Right (default)
        const notyBottomRightElement = document.querySelector('#noty_bottom_right');
        if(notyBottomRightElement) {
            notyBottomRightElement.addEventListener('click', function() {
                new Noty({
                    layout: 'bottomRight',
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info'
                }).show();
            });
        }


        //
        // Other examples
        //

        // Overlay
        const notyOverlayElement = document.querySelector('#noty_overlay');
        if(notyOverlayElement) {
            notyOverlayElement.addEventListener('click', function() {
                new Noty({
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info',
                    modal: true
                }).show();
            });
        }

        // Sticky
        const notyStickyElement = document.querySelector('#noty_sticky');
        if(notyStickyElement) {
            notyStickyElement.addEventListener('click', function() {
                new Noty({
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info',
                    timeout: false
                }).show();
            });
        }

        // Close button
        const notyCloseElement = document.querySelector('#noty_close');
        if(notyCloseElement) {
            notyCloseElement.addEventListener('click', function() {
                new Noty({
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info',
                    closeWith: ['button']
                }).show();
            });
        }

        // No progress
        const notyProgressElement = document.querySelector('#noty_progress');
        if(notyProgressElement) {
            notyProgressElement.addEventListener('click', function() {
                new Noty({
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info',
                    progressBar: false
                }).show();
            });
        }

        // Custom color
        const notyCustomColorElement = document.querySelector('#noty_custom');
        if(notyCustomColorElement) {
            notyCustomColorElement.addEventListener('click', function() {
                new Noty({
                    theme: ' bg-teal',
                    text: 'This alert needs your attention, but it\'s not super important.',
                    type: 'info'
                }).show();
            });
        }
    };

    const componentPassy = function() {
        if (!$().passy) {
            console.warn('Warning - passy.js is not loaded.');
            return;
        }

        // Input badges
        const $inputGroup = $('.group-indicator');
        const $outputGroup = $('.password-indicator-group');
        // Min input length
        $.passy.requirements.length.min = 4;

        const feedbackGroup = [
            {color: 'bg-danger border-danger text-white', text: 'Weak'},
            {color: 'bg-secondary border-secondary text-white', text: 'Normal'},
            {color: 'bg-primary border-primary text-white', text: 'Good'},
            {color: 'bg-success border-success text-white', text: 'Strong'}
        ];

        $inputGroup.passy(function(strength) {
            $outputGroup.text(feedbackGroup[strength].text);
            $outputGroup.addClass(feedbackGroup[strength].color);
        });

        $('.generate-group').on('click', function() {
            $inputGroup.passy('generate', 12);
        });
    };


    const componentFileUpload = function() {
        if (!$().fileinput) {
            console.warn('Warning - fileinput.min.js is not loaded.');
            return;
        }

        //
        // Define variables
        //

        // Buttons inside zoom modal
        const previewZoomButtonClasses = {
            rotate: 'btn btn-light btn-icon btn-sm',
            toggleheader: 'btn btn-light btn-icon btn-header-toggle btn-sm',
            fullscreen: 'btn btn-light btn-icon btn-sm',
            borderless: 'btn btn-light btn-icon btn-sm',
            close: 'btn btn-light btn-icon btn-sm'
        };

        // Icons inside zoom modal classes
        const previewZoomButtonIcons = {
            prev: document.dir == 'rtl' ? '<i class="ph-arrow-right"></i>' : '<i class="ph-arrow-left"></i>',
            next: document.dir == 'rtl' ? '<i class="ph-arrow-left"></i>' : '<i class="ph-arrow-right"></i>',
            rotate: '<i class="ph-arrow-clockwise"></i>',
            toggleheader: '<i class="ph-arrows-down-up"></i>',
            fullscreen: '<i class="ph-corners-out"></i>',
            borderless: '<i class="ph-frame-corners"></i>',
            close: '<i class="ph-x"></i>'
        };

        // File actions
        const fileActionSettings = {
            zoomClass: '',
            zoomIcon: '<i class="ph-magnifying-glass-plus"></i>',
            dragClass: 'p-2',
            dragIcon: '<i class="ph-dots-six"></i>',
            removeClass: '',
            removeErrorClass: 'text-danger',
            removeIcon: '<i class="ph-trash"></i>',
            indicatorNew: '<i class="ph-file-plus text-success"></i>',
            indicatorSuccess: '<i class="ph-check file-icon-large text-success"></i>',
            indicatorError: '<i class="ph-x text-danger"></i>',
            indicatorLoading: '<i class="ph-spinner spinner text-muted"></i>'
        };


        //
        // Basic example
        //

        $('.file-input').fileinput({
            browseLabel: 'Browse',
            browseIcon: '<i class="ph-file-plus me-2"></i>',
            uploadIcon: '<i class="ph-file-arrow-up me-2"></i>',
            removeIcon: '<i class="ph-x fs-base me-2"></i>',
            layoutTemplates: {
                icon: '<i class="ph-check"></i>'
            },
            uploadClass: 'btn btn-light',
            removeClass: 'btn btn-light',
            initialCaption: "No file selected",
            previewZoomButtonClasses: previewZoomButtonClasses,
            previewZoomButtonIcons: previewZoomButtonIcons,
            fileActionSettings: fileActionSettings
        });


        //
        // Custom layout
        //

        $('.file-input-custom').fileinput({
            previewFileType: 'image',
            browseLabel: 'Select',
            browseClass: 'btn btn-secondary',
            browseIcon: '<i class="ph-image me-2"></i>',
            removeLabel: 'Remove',
            removeClass: 'btn btn-danger',
            removeIcon: '<i class="ph-x-square me-2"></i>',
            uploadClass: 'btn btn-teal',
            uploadIcon: '<i class="ph-upload-simple me-2"></i>',
            layoutTemplates: {
                icon: '<i class="ph-check"></i>'
            },
            initialCaption: "Please select image",
            mainClass: 'input-group',
            previewZoomButtonClasses: previewZoomButtonClasses,
            previewZoomButtonIcons: previewZoomButtonIcons,
            fileActionSettings: fileActionSettings
        });


        //
        // Hidden caption
        //

        $('.file-input-caption').fileinput({
            browseLabel: 'Browse',
            browseIcon: '<i class="ph-file-plus me-2"></i>',
            uploadIcon: '<i class="ph-file-arrow-up me-2"></i>',
            removeIcon: '<i class="ph-x fs-base me-2"></i>',
            layoutTemplates: {
                icon: '<i class="ph-check"></i>'
            },
            uploadClass: 'btn btn-light',
            removeClass: 'btn btn-light',
            initialCaption: "No file selected",
            previewZoomButtonClasses: previewZoomButtonClasses,
            previewZoomButtonIcons: previewZoomButtonIcons,
            fileActionSettings: fileActionSettings,
            showCaption: false,
            dropZoneEnabled: false
        });


        //
        // Template modifications
        //

        $('.file-input-advanced').fileinput({
            browseLabel: 'Browse',
            browseClass: 'btn btn-light',
            removeClass: 'btn btn-light',
            uploadClass: 'btn btn-success',
            browseIcon: '<i class="ph-file-plus me-2"></i>',
            uploadIcon: '<i class="ph-file-arrow-up me-2"></i>',
            removeIcon: '<i class="ph-x fs-base me-2"></i>',
            layoutTemplates: {
                icon: '<i class="ph-check"></i>',
                main1: "{preview}\n" +
                    "<div class='input-group {class}'>\n" +
                    "{browse}\n" +
                    "{caption}\n" +
                    "{upload}\n" +
                    "{remove}\n" +
                    "</div>"
            },
            initialCaption: "No file selected",
            previewZoomButtonClasses: previewZoomButtonClasses,
            previewZoomButtonIcons: previewZoomButtonIcons,
            fileActionSettings: fileActionSettings
        });



        //
        // AJAX upload
        //

        $('.file-input-ajax').fileinput({
            browseLabel: 'Browse',
            uploadUrl: "http://localhost", // server upload action
            uploadAsync: true,
            maxFileCount: 5,
            initialPreview: [],
            browseIcon: '<i class="ph-file-plus me-2"></i>',
            uploadIcon: '<i class="ph-file-arrow-up me-2"></i>',
            removeIcon: '<i class="ph-x fs-base me-2"></i>',
            fileActionSettings: {
                removeIcon: '<i class="ph-trash"></i>',
                removeClass: '',
                uploadIcon: '<i class="ph-upload-simple"></i>',
                uploadClass: '',
                zoomIcon: '<i class="ph-magnifying-glass-plus"></i>',
                zoomClass: '',
                indicatorNew: '<i class="ph-file-plus text-success"></i>',
                indicatorSuccess: '<i class="ph-check file-icon-large text-success"></i>',
                indicatorError: '<i class="ph-x text-danger"></i>',
                indicatorLoading: '<i class="ph-spinner spinner text-muted"></i>',
            },
            layoutTemplates: {
                icon: '<i class="ph-check"></i>'
            },
            uploadClass: 'btn btn-light',
            removeClass: 'btn btn-light',
            initialCaption: 'No file selected',
            previewZoomButtonClasses: previewZoomButtonClasses,
            previewZoomButtonIcons: previewZoomButtonIcons
        });


        //
        // Misc
        //

        // Disable/enable button
        $('#btn-modify').on('click', function() {
            $btn = $(this);
            if ($btn.text() == 'Disable file input') {
                $('#file-input-methods').fileinput('disable');
                $btn.html('Enable file input');
                alert('Hurray! I have disabled the input and hidden the upload button.');
            }
            else {
                $('#file-input-methods').fileinput('enable');
                $btn.html('Disable file input');
                alert('Hurray! I have reverted back the input to enabled with the upload button.');
            }
        });
    };


    // // Reload card (uses BlockUI extension)
    // const cardActionReload = function() {
    //
    //     // Elements
    //     const buttonClass = '[data-card-action=reload]', containerClass = 'card', overlayClass = 'card-overlay',
    //           spinnerClass = 'ph-circle-notch', overlayAnimationClass = 'card-overlay-fadeout';
    //
    //     // Configure
    //     document.querySelectorAll(buttonClass).forEach(function(button) {
    //         button.addEventListener('click', function(e) {
    //             e.preventDefault();
    //
    //             // Elements
    //             const parentContainer = button.closest(`.${containerClass}`),
    //                   overlayElement = document.createElement('div'),
    //                   overlayElementIcon = document.createElement('i');
    //
    //             // Append overlay with icon
    //             overlayElement.classList.add(overlayClass);
    //             parentContainer.appendChild(overlayElement);
    //             overlayElementIcon.classList.add(spinnerClass, 'spinner', 'text-body');
    //             overlayElement.appendChild(overlayElementIcon);
    //
    //             // Remove overlay after 2.5s, for demo only
    //             setTimeout(function() {
    //                 overlayElement.classList.add(overlayAnimationClass);
    //                 ['animationend', 'animationcancel'].forEach(function(e) {
    //                     overlayElement.addEventListener(e, function() {
    //                         overlayElement.remove();
    //                     });
    //                 });
    //             }, 2500);
    //         });
    //     });
    // };

    // Collapse card
    const cardActionCollapse = function() {
        const buttonClass = '[data-card-action=collapse]', cardCollapsedClass = 'card-collapsed';

        document.querySelectorAll(buttonClass).forEach(function(button) {
            button.addEventListener('click', function(e) {
                e.preventDefault();

                const parentContainer = button.closest('.card'),
                      collapsibleContainer = parentContainer.querySelectorAll(':scope > .collapse');

                if (parentContainer.classList.contains(cardCollapsedClass)) {
                    parentContainer.classList.remove(cardCollapsedClass);
                    collapsibleContainer.forEach(function(toggle) {
                        new bootstrap.Collapse(toggle, {
                            show: true
                        });
                    });
                }
                else {
                    parentContainer.classList.add(cardCollapsedClass);
                    collapsibleContainer.forEach(function(toggle) {
                        new bootstrap.Collapse(toggle, {
                            hide: true
                        });
                    });
                }
            });
        });
    };

    // Remove card
    const cardActionRemove = function() {

        const buttonClass = '[data-card-action=remove]', containerClass = 'card'
        // Config
        document.querySelectorAll(buttonClass).forEach(function(button) {
            button.addEventListener('click', function(e) {
                e.preventDefault();
                button.closest(`.${containerClass}`).remove();
            });
        });
    };

    // Card fullscreen mode
    const cardActionFullscreen = function() {

        // Elements
        const buttonAttribute = '[data-card-action=fullscreen]',
              buttonClass = 'text-body',
              buttonContainerClass = 'd-inline-flex',
              cardFullscreenClass = 'card-fullscreen',
              collapsedClass = 'collapsed-in-fullscreen',
              scrollableContainerClass = 'content-inner',
              fullscreenAttr = 'data-fullscreen';

        // Configure
        document.querySelectorAll(buttonAttribute).forEach(function(button) {
            button.addEventListener('click', function(e) {
                e.preventDefault();

                // Get closest card container
                const cardFullscreen = button.closest('.card');

                // Toggle required classes
                cardFullscreen.classList.toggle(cardFullscreenClass);

                // Toggle classes depending on state
                if (!cardFullscreen.classList.contains(cardFullscreenClass)) {
                    button.removeAttribute(fullscreenAttr);
                    cardFullscreen.querySelectorAll(`:scope > .${collapsedClass}`).forEach(function(collapsedElement) {
                        collapsedElement.classList.remove('show');
                    });
                    document.querySelector(`.${scrollableContainerClass}`).classList.remove('overflow-hidden');
                    button.closest(`.${buttonContainerClass}`).querySelectorAll(`:scope > .${buttonClass}:not(${buttonAttribute})`).forEach(function(actions) {
                        actions.classList.remove('d-none');
                    });
                }
                else {
                    button.setAttribute(fullscreenAttr, 'active');
                    cardFullscreen.removeAttribute('style');
                    cardFullscreen.querySelectorAll(`:scope > .collapse:not(.show)`).forEach(function(collapsedElement) {
                        collapsedElement.classList.add('show', `.${collapsedClass}`);
                    });
                    document.querySelector(`.${scrollableContainerClass}`).classList.add('overflow-hidden');
                    button.closest(`.${buttonContainerClass}`).querySelectorAll(`:scope > .${buttonClass}:not(${buttonAttribute})`).forEach(function(actions) {
                        actions.classList.add('d-none');
                    });
                }
            });
        });
    };

    const dropdownSubmenu = function() {

        const menuClass = 'dropdown-menu', submenuClass = 'dropdown-submenu', menuToggleClass = 'dropdown-toggle',
            disabledClass = 'disabled', showClass = 'show';

        if(submenuClass) {

            // Toggle submenus on all levels
            document.querySelectorAll(`.${menuClass} .${submenuClass}:not(.${disabledClass}) .${menuToggleClass}`).forEach(function(link) {
                link.addEventListener('click', function(e) {
                    e.stopPropagation();
                    e.preventDefault();

                    // Toggle classes
                    link.closest(`.${submenuClass}`).classList.toggle(showClass);
                    link.closest(`.${submenuClass}`).querySelectorAll(`:scope > .${menuClass}`).forEach(function(children) {
                        children.classList.toggle(showClass);
                    });

                    // When submenu is shown, hide others in all siblings
                    for (let sibling of link.parentNode.parentNode.children) {
                        if (sibling != link.parentNode) {
                            sibling.classList.remove(showClass);
                            sibling.querySelectorAll(`.${showClass}`).forEach(function(submenu) {
                                submenu.classList.remove(showClass);
                            });
                        }
                    }
                });
            });

            // Hide all levels when parent dropdown is closed
            document.querySelectorAll(`.${menuClass}`).forEach(function(link) {
                if(!link.parentElement.classList.contains(submenuClass)) {
                    link.parentElement.addEventListener('hidden.bs.dropdown', function(e) {
                        link.querySelectorAll(`.${menuClass}.${showClass}`).forEach(function(children) {
                            children.classList.remove(showClass);
                        });
                    });
                }
            });
        }
    };



    //
    // Return objects assigned to module
    //

    return {

        // Disable transitions before page is fully loaded
        initBeforeLoad: function() {
            detectOS();
            transitionsDisabled();
        },

        // Enable transitions when page is fully loaded
        initAfterLoad: function() {
            transitionsEnabled();
        },
        // Initialize all components
        initComponents: function() {
            componentTooltip();
            // componentPopover();
            // componentPopoverCustomBackgroundColor();
            componentToTopButton();
            componentDragula();
            componentLightbox();
            componentSelect2();
            componentMultiselect();
            componentTagField();
            componentFormValidate();
            componentNoty();
            componentPassy();
            componentFileUpload();
        },

        // Initialize all sidebars
        initSidebars: function() {
            sidebarMainResize();
            sidebarMainToggle();
            sidebarSecondaryToggle();
            sidebarRightToggle();
            sidebarComponentToggle();
        },

        // Initialize all navigations
        initNavigations: function() {
            navigationSidebar();
        },

        // Initialize all card actions
        initCardActions: function() {
            // cardActionReload();
            cardActionCollapse();
            cardActionRemove();
            cardActionFullscreen();
        },

        // Dropdown submenu
        initDropdowns: function() {
            dropdownSubmenu();
        },

        // Initialize core
        initCore: function() {
            App.initBeforeLoad();
            App.initSidebars();
            App.initNavigations();
            App.initComponents();
            App.initCardActions();
            App.initDropdowns();
        }
    };
}();


// Initialize module
// ------------------------------

// When content is loaded
document.addEventListener('DOMContentLoaded', function() {
    App.initCore();
});

// When page is fully loaded
window.addEventListener('load', function() {
    App.initAfterLoad();
});
