(function () {

    pageLoadingComplete = false;
    pageLoadingShowOnUnload = true;

    function initPageLoadingPanel() {

        // show loading panel if takes more than 1000ms to load page (i.e. client-side processing)
        window.setTimeout(function () {
            if (!pageLoadingComplete) {
                pageLoading.Show();
            }
        }, 1000);

        //// show loading panel if takes more than 1000ms to unload page (i.e. server-side processing)
        //window.onbeforeunload = function () {
        //    if (pageLoadingShowOnUnload) {
        //        window.setTimeout(function () {
        //            pageLoading.Show();
        //        }, 1000);
        //    } else {
        //        pageLoadingShowOnUnload = true;
        //    }
        //};

    }

    //function initPageLoadingAnchors() {

    //    // suppress specific anchors from showing loading panel, i.e. mailto and handlers
    //    $('a[href^="mailto"]').click(function () { pageLoadingShowOnUnload = false; });
    //    $('a[href*=".ashx"]').click(function () { pageLoadingShowOnUnload = false; });

    //}


    var adjustmentDelegates = [];

    function AddAdjustmentDelegate(adjustmentDelegate) {
        adjustmentDelegates.push(adjustmentDelegate);
    }

    function onControlsInitialized(s, e) {

        // adjust page controls once controls initialised
        adjustPageControls();
 
        // show root invisible panels in order (this may not be required)
        if (ASPx.GetControlCollection().GetByName("headerPanel")) { headerPanel.SetVisible(true) };
        if (ASPx.GetControlCollection().GetByName("leftPanel")) { leftPanel.SetVisible(true) };
        if (ASPx.GetControlCollection().GetByName("rightPanel")) { rightPanel.SetVisible(true) };
        if (ASPx.GetControlCollection().GetByName("pageToolbarPanel")) { pageToolbarPanel.SetVisible(true) };
        if (ASPx.GetControlCollection().GetByName("contentPanel")) { contentPanel.SetVisible(true) };

        // show any other invisible panels
        if (ASPx.GetControlCollection().GetByName("detailsFormLayout")) { detailsFormLayout.SetVisible(true) };
        
        // show root invisible elements in order
        if ($('#headerPanelDiv').length) { $('#headerPanelDiv').css('visibility', 'visible') };
        if ($('#leftPanelDiv').length) { $('#leftPanelDiv').css('visibility', 'visible') };
        if ($('#rightPanelDiv').length) { $('#rightPanelDiv').css('visibility', 'visible') };
        if ($('#pageToolbarDiv').length) { $('#pageToolbarDiv').css('visibility', 'visible') };
        if ($('#pageContentDiv').length) { $('#pageContentDiv').css('visibility', 'visible') };

        // show any other invisible elements not covered above
        if ($('.start-hidden').length) { $('.start-hidden').css('visibility', 'visible') };

        // hide loading panel if applicable with a 500ms delay
        if (ASPx.GetControlCollection().GetByName("pageLoading")) {
            pageLoadingComplete = true;
            setTimeout(function () {
                pageLoading.Hide()
            }, 500);
        };

        // re-adjust page controls again (mainly for gridview)
        adjustPageControls();

        //// append keep alive worker frame if not yet added
        //if ($('#keepAliveWorker').length && !$('#keepAliveFrame').length) {
        //    $('#workerWrapper').append('<iframe id="keepAliveFrame" src="/Workers/KeepSessionAlive.aspx?interval=60" class="worker-frame" scrolling="no"></iframe>');
        //};

        //// append message alert worker frame if not yet added
        //if ($('#messageAlertWorker').length && !$('#messageAlertFrame').length) {
        //    $('#workerWrapper').append('<iframe id="messageAlertFrame" src="/Workers/RefreshMessageAlert.aspx?interval=15" class="worker-frame" scrolling="no"></iframe>');
        //};

        // update the help and placeholder content if available
        updateUserContent();

    }

    function onBrowserWindowResized(s, e) {
        adjustPageControls();
    }

    function adjustPageControls() {
        for(var i = 0; i < adjustmentDelegates.length; i++) {
            adjustmentDelegates[i]();
        }
    }


    function onLeftMenuItemClick(s, e) {
        if(e.item.name === "ToggleLeftPanel")
            toggleLeftPanel();
        if(e.item.name === "Back")
            //window.history.back();
            if (leftAreaMenu && leftAreaMenu.cpBackButtonLink)
                window.location.href = leftAreaMenu.cpBackButtonLink;
            else
                window.history.back();
    }

    function onRightMenuItemClick(s, e) {
        if(e.item.name === "ToggleRightPanel") {
            toggleRightPanel();
            e.processOnServer = false;
        }

        if(e.item.name === "AccountItem")
            e.processOnServer = false;
    }

    function HideLeftPanelIfRequired() {
        if (leftPanel.IsExpandable() && leftPanel.IsExpanded())
            leftPanel.Collapse();
    }

    var initToggleLeftPanel = false;

    function toggleLeftPanel() {
        if(leftPanel.IsExpandable()) {
            leftPanel.Toggle();

            // on first toggle on mobile, automatically scroll to selected menu item
            if (!initToggleLeftPanel) {
                scrollIntoViewforLeftMenu();
                initToggleLeftPanel = true;
            }

        } else {
            leftPanel.SetVisible(!leftPanel.GetVisible());

            adjustPageControls();
        }

        //auto adjust main page when panel toggled
        //necessary to adjust grid if filter shown
        setTimeout(function () {
            adjustPageControls();
        }, 0);

    }
    
    // automatically scroll to selected menu item if applicable
    function scrollIntoViewforLeftMenu() {

        //var selectedItem = document.getElementsByClassName("dxnb-itemSelected");
        var selectedItem = $(".navbar-menu-item.dxnb-itemSelected");

        if (selectedItem && selectedItem.length > 0) {
            scrollIntoViewIfOutOfView(selectedItem[0]);
        }

    }

    function toggleRightPanel() {
        rightPanel.Toggle();
    }
    
    function expandRightPanel() {
        rightAreaMenu.GetItemByName("ToggleRightPanel").SetChecked(true);
        rightPanel.Expand();
    }

    function onRightPanelCollapsed(s, e) {
        rightAreaMenu.GetItemByName("ToggleRightPanel").SetChecked(false);
    }

    function onRightPanelInit(s, e) {

        var adjustmentMethod = function () {

            // auto adjust right panel width
            adjustRightPanel(s, e);

        };

        AddAdjustmentDelegate(adjustmentMethod);

    }

    function onRightPanelExpanded(s, e) {

        //// auto adjust right panel width
        //adjustRightPanel(s, e);

    }

    function adjustRightPanel(s, e) {
        
        // change help panel width based on document width
        var containerWidth = ASPxClientUtils.GetDocumentClientWidth();
        var panelWidth = (containerWidth < 500 ? 300 : 420)
        s.SetWidth(panelWidth);

    }

    function onPageToolbarInit(s, e) {
        var adjustmentMethod = function() {
            document.getElementById("pageContent").style.paddingTop = s.GetHeight() + "px"; 
        };
        AddAdjustmentDelegate(adjustmentMethod);
    }

    function onLeftPanelCollapsed(s, e) {
        leftAreaMenu.GetItemByName("ToggleLeftPanel").SetChecked(false);
    }

    function onLeftPanelInit(s, e) {

        var adjustmentMethod = function () {

            // auto adjust left panel width
            adjustLeftPanel(s, e);

            // change panel properties based on whether adaptive
            var pageToolbarPanel = ASPx.GetControlCollection().GetByName("pageToolbarPanel");
            if (pageToolbarPanel)
                pageToolbarPanel.GetMainElement().style.left = s.GetWidth() + "px";

            var toggleButton = leftAreaMenu.GetItemByName("ToggleLeftPanel");
            if (s.IsExpandable())
                toggleButton.SetChecked(leftPanel.IsExpanded());
            else {
                if (leftPanel.GetVisible())
                    document.body.style.marginLeft = "1px";
                else
                    document.body.style.marginLeft = 0;
                toggleButton.SetChecked(leftPanel.GetVisible());
            }
        };

        AddAdjustmentDelegate(adjustmentMethod);

    }

    function onLeftPanelExpanded(s, e) {

        //// auto adjust left panel width
        //adjustLeftPanel(s, e);

    }

    function adjustLeftPanel(s, e) {

        // change left panel width based on document width
        var containerWidth = ASPxClientUtils.GetDocumentClientWidth();
        var panelWidth = (containerWidth < 500 ? 300 : 335);

        leftPanel.SetWidth(panelWidth);
        leftPanel.AdjustControl();
        tableOfContentsNavBar.AdjustControl();
        $('.left-panel .dxpnl-acc').css('width', panelWidth + 'px');
        $('.navbar-menu-item span').css('max-width', 'calc(' + panelWidth + 'px - 60px)');

    }

    ////Allow adding multiple load functions
    ////https://www.htmlgoodies.com/beyond/javascript/article.php/3724571/using-multiple-javascript-onload-functions.htm
    //function addLoadEvent(func) {
    //    var oldonload = window.onload;
    //    if (typeof window.onload != 'function') {
    //        window.onload = func;
    //    } else {
    //        window.onload = function () {
    //            if (oldonload) {
    //                oldonload();
    //            }
    //            func();
    //        }
    //    }
    //}

    //Updates the unread message count in Application Menu
    function updateMessageAlert(unreadCount) {
        var messageMenu = document.getElementsByClassName("message-menu");

        if (messageMenu && messageMenu.length > 0) {

            //format as appropriate
            if (unreadCount == null || unreadCount.trim() == "" || isNaN(unreadCount)) {
                unreadCount = "&nbsp;";
            } else if (parseInt(unreadCount) == 0) {
                unreadCount = "0";
            } else if (parseInt(unreadCount) > 99) {
                unreadCount = "99+"
            } else {
                unreadCount = unreadCount.toString();
            }

            //create element in menu if required
            unreadAlert = document.getElementById("unread-alert");
            if (!unreadAlert)
                $(".message-menu .dxm-contentText").after("<span id='unread-alert'></span>");

            //update count in element
            unreadAlert = document.getElementById("unread-alert");
            unreadAlert.innerHTML = unreadCount;

            //change class if count is zero or null
            if (unreadCount == "&nbsp;" || unreadCount == "0") {
                $("#unread-alert").addClass("all-read");
                unreadAlert.setAttribute("title", "No unread messages");
            } else {
                $("#unread-alert").removeClass("all-read");
                unreadAlert.setAttribute("title", unreadCount + " unread message(s)");
            }

        }
    }

    //scroll the element into view if outside viewport:
    //https://stackoverflow.com/a/33681714
    function scrollIntoViewIfOutOfView(el) {
        var topOfPage = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
        var heightOfPage = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
        var elY = 0;
        var elH = 0;
        if (document.layers) { // NS4
            elY = el.y;
            elH = el.height;
        }
        else {
            for (var p = el; p && p.tagName != 'BODY'; p = p.offsetParent) {
                elY += p.offsetTop;
            }
            elH = el.offsetHeight;
        }
        if ((topOfPage + heightOfPage) < (elY + elH)) {
            el.scrollIntoView(true); // set to false to stick to footer
        }
        else if (elY < topOfPage) {
            el.scrollIntoView(true);
        }
    }

    //automatically add file icons based on file extension
    function initFileIcons() {
        $("a.file:contains('.pdf')").addClass("file-pdf");
        $("a.file:contains('.doc')").addClass("file-doc"); // matches ".doc" and ".docx"
        $("a.file:contains('.xls')").addClass("file-xls"); // matches ".xls" and ".xlsx"
        $("a.file:contains('.csv')").addClass("file-csv");
        $("a.file:contains('.zip')").addClass("file-zip");
    }

    // disable auto complete for editor, typically called in got focus event
    function disableAutoComplete(s, e) {
        ASPx.Attr.SetAttribute(s.GetInputElement(), 'autocomplete', 'chrome-off');
    }

    // notifications
    function createNotifyStack(element) {

        PNotify.defaultModules.set(PNotifyMobile, {});

        return new PNotify.Stack({
            dir1: 'down',
            //dir1: 'up',
            //dir2: 'left',
            firstpos1: 0,
            //firstpos2: 20,
            spacing1: 0,
            modal: false,
            maxOpen: Infinity,
            //context: document.getElementById('HeaderPanel') //top of page header (good)
            //context: document.getElementById('pageContent') //top of content header (disappears when scrolling down)
            //context: document.getElementById('PageToolbarPanel') //top of content header (better?, stays with content)
            //context: document.getElementById('windowBottom') // bottom of page (good, use dir1: 'up')
            context: element // under grid toolbar
        });

    }

    function showNotify(stack, type, text, close) {

        PNotify.defaultModules.set(PNotifyMobile, {});

        // if auto close, then close after 2 seconds
        var delay = (close ? 2000 : Infinity);

        const notify = PNotify.alert({
            type: type,
            text: text,
            textTrusted: true, // allows markup in text
            maxTextHeight: null,
            //width: "450px",
            //width: "500px",
            sticker: false,
            delay: delay,
            stack: stack
        });

        notify.on('click', () => {
            notify.close();
        });

    }

    function showPageNotify(type, text, close) {

        // top of compose popup
        var element = document.getElementById('notifyStack');
        //var element = document.getElementsByClassName('title')[0];

        // create stack if required
        if (typeof window.pageNotifyStack === 'undefined')
            window.pageNotifyStack = createNotifyStack(element);

        showNotify(window.pageNotifyStack, type, text, close);

    }

    function printContentFromUrl(contentUrl, newTab) {

        // print content from specific url
        // .https://stackoverflow.com/a/59777513
        // .https://seegatesite.com/trick-how-to-print-report-without-open-new-tab-page-with-javascript/

        var printWindow;

        // open in new browser tab, otherwise hidden iframe
        if (newTab) {
            printWindow = window.open(contentUrl, "_blank");
        } else {
            $("<iframe id='printWindow' name='printWindow' scrollbars='no'>")
                //.hide()
                //.css('visibility', 'hidden')
                .attr("src", contentUrl)
                .appendTo("body");
            printWindow = frames["printWindow"];
        }

        // once window loaded, then attempt to print
        printWindow.onload = function () {

            var printEventAdded = false;

            //wait an extra 100ms before printing to ensure controls fully loaded
            setTimeout(function () {

                // pre-emptively close document
                printWindow.document.close();
                printWindow.focus();

                // remove superfluous text in document title
                var printName = printWindow.document.title;
                if (printName.includes(" | ")) {
                    printName = printName.split(" | ")[0];
                }
                printWindow.document.title = printName;

                // attempt to print document
                printWindow.print();

                // queue close window (firefox only)
                if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
                    printWindow.close();
                }

                // remove iframe if used
                $("#printWindow").remove();

            }, 100);
        };

        //originally used "addEventListener", but this causes issues with firefox calling the "load" event twice;
        //.https://support.mozilla.org/en-US/questions/1290085
        //.https://stackoverflow.com/questions/2153579/page-load-fires-twice-on-firefox/2160741
        //.https://stackoverflow.com/questions/60410013/addeventlistener-load-fires-twice-on-firefox
        //.https://stackoverflow.com/questions/38499989/what-is-the-difference-between-window-onload-and-document-addeventlistenerlo
        //.https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
        //.https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
        //
        //printWindow.addEventListener('load', function () {
        //   ...
        //}, true);

        // close window only after printing (doesn't work in firefox)
        printWindow.onafterprint = function () {
            printWindow.close(); 
        };

    }

    // add password show / hide icon
    function onPasswordButtonEditButtonClick(s, e) {
        var inputType = s.GetInputElement().type;
        var turnOnPasswordMode = inputType !== "password";

        s.GetInputElement().type = turnOnPasswordMode ? "password" : "text";

        var eyeButton = s.GetMainElement().getElementsByClassName("eye-button")[0];
        if (turnOnPasswordMode)
            ASPxClientUtils.RemoveClassNameFromElement(eyeButton, "show-password");
        else
            ASPxClientUtils.AddClassNameToElement(eyeButton, "show-password");
    }


    // override enter key for custom popup editors which have a key down event
    function onCustomPopupEditorKeyDown(s, e, button) {
        switch (e.htmlEvent.keyCode) {
            case 13:
                //e.htmlEvent.preventDefault();
                button.DoClick();
                //ASPxClientUtils.PreventEventAndBubble(e.htmlEvent);
                e.htmlEvent.preventDefault();
                break;
        }
    }

    // override enter key for custom popup checkboxes which don't have a key down event
    function onCustomPopupEditorInit(s, e, button) {
        ASPxClientUtils.AttachEventToElement(s.GetMainElement(), 'keydown', function (event) {
            switch (event.keyCode) {
                case 13:
                    //event.preventDefault();
                    button.DoClick();
                    event.preventDefault();
                    break;

            }
        });
    }

    // show popup details
    function showPopupDetails(element, key, title, contentUrl) {

        popupDetails.SetContentUrl(contentUrl);
        if (title && title !== '')
            popupDetails.SetHeaderText(title);
        if (!popupDetails.IsVisible())
            popupDetails.ShowAtElement(element);

    }

    // popup toolbar item click, including print, popout and close
    function onPopupToolbarItemClick(s, e) {

        switch (e.item.name) {

            case "Print":
                var dialogUrl = popupDetails.GetContentUrl();
                var printUrl = dialogUrl.replace(/mode=dialog/gi, "mode=print");
                printContentFromUrl(printUrl, true); // don't open new browser tab
                break;

            case "Popout": // pop out the dialog window in new browser tab
                var dialogUrl = popupDetails.GetContentUrl();
                var popoutUrl = dialogUrl.replace(/mode=dialog/gi, "");
                popoutWindow = window.open(popoutUrl, "_blank");
                break;

            case "Close":
                popupDetails.Hide();
                break;

        }
    }

    // clear details after closing popup, stops flickering of previous details
    function closeUpPopupDetails() {
        popupDetails.SetContentUrl(null);
    }
    
    // update the help and placeholder content based on user
    function updateUserContent() {

        // obtain current user group and roles from user state hidden field
        var currentUserGroupKey = userState.Get("userGroupKey");
        var currentUserRoleKeys = userState.Get("userRoleKeys");

        // hide initially, then show if specific user group
        // e.g. <p class="show-if admin auditor">...</p>
        $('.settings-content .show-if, .text-content .show-if').hide()
            .each(function () { 
                if (isUserInElement($(this), currentUserGroupKey, currentUserRoleKeys))
                    $(this).show();
            });

        // show initially, then hide if specific user group
        // e.g. <p class="hide-if business">...</p>
        $('.settings-content .hide-if, .text-content .hide-if').show()
            .each(function () {
                if (isUserInElement($(this), currentUserGroupKey, currentUserRoleKeys))
                    $(this).hide();
            });

        // replace help tags with appropriate javascript to load help content
        $('help')
            .each(function () {
                var name = $(this).attr("name");
                var title = $(this).attr("title");
                var text = $(this).text();
                if (isNull(title))
                    title = "Show help for " + text;
                $(this).replaceWith("<a href=\"javascript:void(0)\" title=\"" + title + "\" onclick=\"loadHelpContent('" + name + "');\">" + text + "</a>");
            });

        // add link to page for h2 tags with link specified
        $('h2[href]')
            .each(function () {
                var url = $(this).attr("href");
                var title = $(this).attr("title");
                var text = $(this).text();
                var html = $(this).html();
                if (isNull(title))
                    title = "Go to " + text;
                $(this).replaceWith("<h2>" + html + "<a class=\"help-link\" href=\"" + url + "\" title=\"" + title + "\"></a></h2>");
            });

        //// replace page tags with appropriate javascript to redirect to page
        //$('page')
        //    .each(function () {
        //        var name = $(this).attr("name");
        //        var text = $(this).text();
        //        $(this).replaceWith("<a href=\"\\" + name + ".aspx\" title=\"Go to " + text + "\">" + text + "</a>");
        //    });

    }

    function isUserInElement(element, userGroupKey, userRoleKeys) {

        // determine type of user group
        var isExec = (userGroupKey == 'nationalExec');
        var isAdmin = (userGroupKey == 'nationalAdmin' || userGroupKey == 'asstNationalAdmin' || userGroupKey == 'systemAdmin');
        var isAuditor = (userGroupKey == 'auditor');
        var isBusiness = (userGroupKey == 'business' || userGroupKey == 'businessStaff');
        var isGovernment = (userGroupKey == 'government' || userGroupKey == 'govtInspector');

        // determine type of user roles (NOT YET IMPLEMENTED)

        // return result
        return ((element.hasClass('exec') && isExec)
                || (element.hasClass('admin') && isAdmin)
                || (element.hasClass('auditor') && isAuditor)
                || (element.hasClass('business') && isBusiness)
                || (element.hasClass('government') && isGovernment));

    }

    // load content in help
    function loadHelpContent(page) {

        // if no page specified, then load self if available
        if (isNullOrEmpty(page))
            page = "";
        
        // load help page via callback
        helpContentPanel.PerformCallback("load|" + page);

        // when loading new help page, close search
        if (helpSearchPanel.IsExpanded())
            helpSearchPanel.Collapse();

    }


    // load and show content in help
    function showHelpContent(page) {
        expandRightPanel();
        window.setTimeout(function () {
            loadHelpContent(null);
        }, 150);
    }


    // scroll to top of help content
    function scrollTopHelpContent() {
        window.setTimeout(function () {
            var toolbarTop = $(".help-toolbar")[0];
            toolbarTop.scrollIntoView(true);
        }, 0);
    }


    // .https://stackoverflow.com/a/34290167
    function formatIsoDate(date) {

        result = [
            date.getFullYear(),
            ('0' + (date.getMonth() + 1)).slice(-2),
            ('0' + date.getDate()).slice(-2)
        ].join('-');

        return result;

    }


    function formatFriendlyDate(date, trimZero) {

        result = date.toLocaleString('en-AU').split(',')[0]
        if (trimZero && result.startsWith('0')) { result = result.substring(1); }

        return result;

    }


    // common functions
    function isNull(value) {
        // .https://stackoverflow.com/a/19323555
        return (typeof (value) === 'undefined' || value === null);
    }
    
    function isNullOrEmpty(value) {
        return (isNull(value) || value == '');
    }
    
    function isNullOrWhiteSpace(value) {
        return (isNullOrEmpty(value) || (/^\s+$/).test(value));
    }
    
    function padLeft(value, size) {
        var result = value + "";
        while (result.length < size) result = "0" + result;
        return result;
    }

    function parseInteger(value) {
        var result = (isNaN(value) ? 0 : parseInt(value));
        return result;
    }

    function millisecondsToTimeSpan(value, verbose) {
        var totalMins = Math.floor(value / (60 * 1000));
        var hourPortion = Math.floor(totalMins / 60);
        var minsPortion = padLeft(totalMins % 60, 2);
        var result = (verbose ? hourPortion + ' hr ' + minsPortion + ' min' : hourPortion + ':' + minsPortion);
        return result;
    }

    function timeSpanToMilliseconds(value) {
        if ((/^\d+ hr \d+ min$/).test(value)) {
            value = value.replace(" hr ", ":").replace(" min", "");
        }
        var hourPortion = parseInteger(value.substr(0, value.indexOf(':')));
        var minsPortion = parseInteger(value.substr(value.indexOf(':') + 1));
        var totalMins = ((hourPortion * 60) + minsPortion) * (60 * 1000);
        var result = totalMins;
        return result;
    }

    function decodeHtml(html) {
        return $('<div>').html(html).text();
    }


    //.https://stackoverflow.com/a/54626214
    //e.g. downloadUrl("/EccpFileHandler.ashx?id=1");
    //e.g. downloadUrl("/Content/Images/add.svg");
    //e.g. downloadUrl("/Content/Images/add.svg", "test.svg"); //

    function downloadUrl(url, name) {

        // create temporary download link
        var downloadLink = document.createElement("a");
        downloadLink.href = url;

        // use file name if no download name
        if (isNullOrWhiteSpace(name))
            name = getFileFromUrl(url);

        // use placeholder if no download name
        if (isNullOrWhiteSpace(name))
            name = "{download}";

        // download the file
        downloadLink.download = name;
        downloadLink.click();

    }


    //.https://stackoverflow.com/a/423385
    // e.g. getFileFromUrl("/Content/Images/add.svg")  ==>  "add.svg"

    function getFileFromUrl(url) {
        var fileName = url.replace(/^.*[\\\/]/, '');
        return fileName;
    }

    
    function disableBrowserSpellCheck(s, e) {
        if (navigator.userAgent.indexOf('Edg/') > -1)
            s.core.setSpellCheckAttributeValue(false);
    }


    //image slider functions

    function initImageSliderLightbox() {

        // initialise lightbox
        // .https://lokeshdhakar.com/projects/lightbox2/#options
        lightbox.option({
            'fadeDuration': 200,
            'imageFadeDuration': 200,
            'resizeDuration': 200,
            'wrapAround': true,
            'showImageNumberLabel': true,
            'alwaysShowNavOnTouchDevices': true,
            'disableScrolling': true
        })

        // now initially update lightbox
        updateImageSliderLightbox();

    }

    function updateImageSliderLightbox() {

        //console.clear();

        var shownIndex = imageSlider.GetActiveItemIndex();

        // populate shown index details
        var shownItem = imageSlider.GetItem(shownIndex);
        $(".gallery-slider .image-area a").attr("data-lightbox", "slider-lightbox");
        $(".gallery-slider .image-area a").attr("data-title", shownItem.text);

        //console.log('' + shownItem.index + ': ' + shownItem.imageUrl + ' ... ' + shownItem.text);

        // populate remaining items in order (create or clear first)
        if ($(".gallery-slider .remaining-images").length)
            $(".gallery-slider .remaining-images").empty();
        else
            $(".gallery-slider").append("<div class='remaining-images' style='display: none'></div>");

        for (let currentIndex = shownIndex + 1; currentIndex <= shownIndex + imageSlider.GetItemCount() - 1; currentIndex++) {
            var currentItem = imageSlider.GetItem(currentIndex % imageSlider.GetItemCount());
            $(".gallery-slider .remaining-images").append("<a href='" + currentItem.imageUrl + "' data-lightbox='slider-lightbox' data-title='" + currentItem.text + "'></a>");

            //console.log('' + currentItem.index + ': ' + currentUrl + ' ... ' + currentText);
        }

    }

    function initSearchViewLightbox() {

        // initialise lightbox
        // .https://lokeshdhakar.com/projects/lightbox2/#options
        lightbox.option({
            'fadeDuration': 200,
            'imageFadeDuration': 200,
            'resizeDuration': 200,
            'wrapAround': true,
            'showImageNumberLabel': true,
            'alwaysShowNavOnTouchDevices': true,
            'disableScrolling': true
        })

    }

    function getUrlWithParams(baseUrl, params) {

        // remove null params
        for (key in params)
            if (isNullOrWhiteSpace(params[key]))
                delete params[key];

        // generate query string
        var queryString = jQuery.param(params);

        // generate full url from base url and query string
        var url = baseUrl + (isNullOrWhiteSpace(queryString) ? '' : '?' + queryString);

        // return generated url
        return url;

    }

    function getCurrentUrlWithParams(params) {

        var baseUrl = window.location.pathname;
        return getUrlWithParams(baseUrl, params);

    }

    function pushHistoryUrl(url, replace) {
        if (typeof (history.pushState) != "undefined") {
            var stateData = {};
            if (replace)
                history.replaceState(stateData, "", url);
            else
                history.pushState(stateData, "", url);
        }
    }



    window.initPageLoadingPanel = initPageLoadingPanel;
    //window.initPageLoadingAnchors = initPageLoadingAnchors;

    window.onControlsInitialized = onControlsInitialized;
    window.onBrowserWindowResized = onBrowserWindowResized;

    window.onLeftMenuItemClick = onLeftMenuItemClick;
    window.onRightMenuItemClick = onRightMenuItemClick;
    window.onRightPanelCollapsed = onRightPanelCollapsed;
    window.onRightPanelInit = onRightPanelInit;
    window.onRightPanelExpanded = onRightPanelExpanded;
    window.onPageToolbarInit = onPageToolbarInit;
    window.onLeftPanelCollapsed = onLeftPanelCollapsed;
    window.onLeftPanelInit = onLeftPanelInit;
    window.onLeftPanelExpanded = onLeftPanelExpanded;
    window.adjustPageControls = adjustPageControls;

    window.toggleLeftPanel = toggleLeftPanel;
    window.scrollIntoViewforLeftMenu = scrollIntoViewforLeftMenu;

    window.toggleRightPanel = toggleRightPanel;
    window.expandRightPanel = expandRightPanel;

    window.HideLeftPanelIfRequired = HideLeftPanelIfRequired;
    window.AddAdjustmentDelegate = AddAdjustmentDelegate;

    //wind.addLoadEvent = addLoadEvent;

    window.updateMessageAlert = updateMessageAlert
    window.scrollIntoViewIfOutOfView = scrollIntoViewIfOutOfView

    window.initFileIcons = initFileIcons;
    window.disableAutoComplete = disableAutoComplete;

    window.createNotifyStack = createNotifyStack;
    window.showNotify = showNotify;
    window.showPageNotify = showPageNotify;

    window.printContentFromUrl = printContentFromUrl;

    window.onPasswordButtonEditButtonClick = onPasswordButtonEditButtonClick;

    window.onCustomPopupEditorKeyDown = onCustomPopupEditorKeyDown;
    window.onCustomPopupEditorInit = onCustomPopupEditorInit;

    window.showPopupDetails = showPopupDetails;
    window.onPopupToolbarItemClick = onPopupToolbarItemClick;
    window.closeUpPopupDetails = closeUpPopupDetails;

    window.updateUserContent = updateUserContent;
    window.loadHelpContent = loadHelpContent;
    window.showHelpContent = showHelpContent;
    window.scrollTopHelpContent = scrollTopHelpContent;

    window.formatIsoDate = formatIsoDate;
    window.formatFriendlyDate = formatFriendlyDate;

    window.isNull = isNull;
    window.isNullOrEmpty = isNullOrEmpty;
    window.isNullOrWhiteSpace = isNullOrWhiteSpace;
    window.padLeft = padLeft;
    window.parseInteger = parseInteger;
    window.millisecondsToTimeSpan = millisecondsToTimeSpan;
    window.timeSpanToMilliseconds = timeSpanToMilliseconds;

    window.decodeHtml = decodeHtml;

    window.downloadUrl = downloadUrl;

    window.disableBrowserSpellCheck = disableBrowserSpellCheck;

    window.initImageSliderLightbox = initImageSliderLightbox;
    window.updateImageSliderLightbox = updateImageSliderLightbox;
    window.initSearchViewLightbox = initSearchViewLightbox;

    window.getUrlWithParams = getUrlWithParams;
    window.getCurrentUrlWithParams = getCurrentUrlWithParams;
    window.pushHistoryUrl = pushHistoryUrl;

})();

$(document).ready(function () {
    initFileIcons();
    //initPageLoadingAnchors();
});
