/* Minification failed. Returning unminified contents.
(2568,21-22): run-time error JS1195: Expected expression: >
(2568,72-73): run-time error JS1004: Expected ';': )
(2575,6-7): run-time error JS1195: Expected expression: )
(2579,41-42): run-time error JS1195: Expected expression: >
(2584,1-2): run-time error JS1002: Syntax error: }
(2635,1-2): run-time error JS1002: Syntax error: }
(2638,72-73): run-time error JS1004: Expected ';': {
(3188,24-25): run-time error JS1195: Expected expression: )
(3188,27-28): run-time error JS1195: Expected expression: >
(3192,6-7): run-time error JS1195: Expected expression: ,
(3250,7-15): run-time error JS1004: Expected ';': function
(3253,36-41): run-time error JS1004: Expected ';': fetch
(3262,33-34): run-time error JS1014: Invalid character: `
(3262,39-44): run-time error JS1193: Expected ',' or ')': error
(3262,72-73): run-time error JS1014: Invalid character: `
(3262,73-74): run-time error JS1195: Expected expression: )
(3265,32-40): run-time error JS1004: Expected ';': response
(3267,24-25): run-time error JS1014: Invalid character: `
(3267,25-26): run-time error JS1195: Expected expression: <
(3267,33-34): run-time error JS1197: Too many errors. The file might not be a JavaScript file: =
(3250,7-49): run-time error JS1301: End of file encountered before function is properly closed: function thumbnailWithPreview(guid, label)
(3267,44-51): run-time error JS1004: Expected ';': onclick
(3267,120-121): run-time error JS1195: Expected expression: <
(3267,121-124): run-time error JS1197: Too many errors. The file might not be a JavaScript file: img
(2702,5-19): run-time error JS1018: 'return' statement outside of function: return methods
 */
/*         ______________________________________
  ________|                                      |_______
  \       |           SmartAdmin WebApp          |      /
   \      |      Copyright © 2014 MyOrange       |     /
   /      |______________________________________|     \
  /__________)                                (_________\

 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * =======================================================================
 * SmartAdmin is FULLY owned and LICENSED by MYORANGE INC.
 * This script may NOT be RESOLD or REDISTRUBUTED under any
 * circumstances, and is only to be used with this purchased
 * copy of SmartAdmin Template.
 * =======================================================================
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * =======================================================================
 * original filename: app.js
 * filesize: 50,499 bytes
 * author: Sunny (@bootstraphunt)
 * email: info@myorange.ca
 * =======================================================================
 * INDEX:
 * 
 * 1. APP CONFIGURATION.......................................[line: 80  ]
 * 2. APP DOM REFERENCES......................................[line: 131 ]
 * 3. DETECT MOBILE DEVICES...................................[line: 149 ]
 * 4. CHECK FOR MENU POSITION.................................[line: 176 ]
 * 5. DOCUMENT LOADED EVENT...................................[line: 187 ]
 * 6. SMART ACTIONS...........................................[line: 195 ]
 * --1a. LOGOUT MSG...........................................[line: 199 ]
 * --1b. RESET WIDGETS........................................[line: 220 ]
 * --1c. LAUNCH FULLSCREEN....................................[line: 237 ]
 * --1d. MINIFY MENU..........................................[line: 270 ]
 * --1e  TOGGLE MENU .........................................[line: 280 ]
 * --1f. TOGGLE SHORTCUT .....................................[line: 290 ]
 * 7. FIRE TOOLTIPS...........................................[line: 373 ]
 * 8. INITIALIZE LEFT NAV.....................................[line: 379 ]
 * 9. SHOW & HIDE MOBILE SEARCH FIELD.........................[line: 393 ]
 * 10.ACTIVITY................................................[line: 402 ]
 * 11.NOTIFICATION IS PRESENT.................................[line: 453 ]
 * 12.RESIZER WITH THROTTLE...................................[line: 469 ]
 * 13.ADD CLASS WHEN BELOW CERTAIN WIDTH (MOBILE MENU)........[line: 587 ]
 * 14.CUSTOM MENU PLUGIN......................................[line: 643 ]
 * 15.ELEMENT EXIST OR NOT....................................[line: 736 ]
 * 16.INITIALIZE FORMS........................................[line: 748 ]
 * --16a.BOOTSTRAP SLIDER PLUGIN..............................[line: 755 ]
 * --16b.SELECT2 PLUGIN.......................................[line: 764 ]
 * --16c.MASKING..............................................[line: 782 ]
 * --16d.AUTOCOMPLETE.........................................[line: 798 ]
 * --16e.JQUERY UI DATE.......................................[line: 814 ]
 * --16f.AJAX BUTTON LOADING TEXT.............................[line: 833 ]
 * 17.INITIALIZE CHARTS.......................................[line: 849 ]
 * --17a.SPARKLINES...........................................[line: 855 ]
 * --17b.BAR CHART............................................[line: 949 ]
 * --17c.LINE CHART...........................................[line: 972 ]
 * --17d.PIE CHART............................................[line: 1021]
 * --17e.BOX PLOT.............................................[line: 1042]
 * --17f.BULLET...............................................[line: 1086]
 * --17g.DISCRETE.............................................[line: 1108]
 * --17h.TRISTATE.............................................[line: 1131]
 * --17i.COMPOSITE:BAR........................................[line: 1157]
 * --17j.COMPOSITE:LINE.......................................[line: 1191]
 * 18.EASY PIE CHARTS........................................[line: 1269]
 * 19.INITIALIZE JARVIS WIDGETS...............................[line: 1308]
 * 20.GOOGLE MAPS.............................................[line: 1407]
 * 21.LOAD SCRIPTS............................................[line: 1432]
 * 22.APP AJAX REQUEST SETUP..................................[line: 1470]
 * 23.CHECK TO SEE IF URL EXISTS..............................[line: 1543]
 * 24.LOAD AJAX PAGES.........................................[line: 1599]
 * 25.UPDATE BREADCRUMB (AJAX ONLY)...........................[line: 1691]
 * 26.PAGE SETUP..............................................[line: 1713]
 * 
 */

/==========================================================================================================/

/*
 * APP CONFIGURATION (HTML/AJAX/PHP Versions ONLY)
 * Description: Enable / disable certain theme features here
 */

// Impacts the responce rate of some of the responsive elements (lower value affects CPU but improves speed)
$.throttle_delay = 350;

// The rate at which the menu expands revealing child elements on click
$.menu_speed = 235;

// Your left nav in your app will no longer fire ajax calls, set it to false for HTML version
$.navAsAjax = false;

// Turn on JarvisWidget functionality
// dependency: js/jarviswidget/jarvis.widget.min.js
$.enableJarvisWidgets = false;

// Warning: Enabling mobile widgets could potentially crash your webApp if you have too many 
// widgets running at once (must have $.enableJarvisWidgets = true)
$.enableMobileWidgets = false;

// Turn on fast click for mobile devices?
// Enable this to activate fastclick plugin
// dependency: js/plugin/fastclick/fastclick.js 
$.fastClick = false;

/==========================================================================================================/


// Calculate nav height
$.calc_navbar_height = function () {
    var height = null;

    if ($('#header').length)
        height = $('#header').height();

    if (height === null)
        height = $('<div id="header"></div>').height();

    if (height === null)
        return 49;
    // default
    return height;
};

$.navbar_height = $.calc_navbar_height();

/*
 * APP DOM REFERENCES
 * Description: Obj DOM reference, please try to avoid changing these
 */
$.root_ = $('body');
$.left_panel = $('#left-panel');
$.shortcut_dropdown = $('#shortcut');
$.bread_crumb = $('#ribbon ol.breadcrumb');

// interval array (to be used with jarviswidget in ajax and angular mode) to clear auto fetch interval
$.intervalArr = new Array();

// Top menu on/off	
var $topmenu = false;

// desktop or mobile
$.device = null;

/*
 * DETECT MOBILE DEVICES
 * Description: Detects mobile device - if any of the listed device is detected
 * a class is inserted to $.root_ and the variable $.device is decleard. 
 */

/* so far this is covering most hand held devices */
var ismobile = (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));

if (!ismobile) {
    // Desktop
    $.root_.addClass("desktop-detected");
    $.device = "desktop";
} else {
    // Mobile
    $.root_.addClass("mobile-detected");
    $.device = "mobile";

    if ($.fastClick) {
        // Removes the tap delay in idevices
        // dependency: js/plugin/fastclick/fastclick.js 
        $.root_.addClass("needsclick");
        FastClick.attach(document.body);
    }

}

/*
 * CHECK FOR MENU POSITION
 */

if ($('body').hasClass("menu-on-top") || localStorage.getItem('sm-setmenu') == 'top') {
    $topmenu = true;
    $('body').addClass("menu-on-top");
    $('body').removeClass('minified');
}

/* ~ END: CHECK MOBILE DEVICE */

/*
 * DOCUMENT LOADED EVENT
 * Description: Fire when DOM is ready
 */

jQuery(document).ready(function () {
    $.root_ = $.root_ || $('body');
    var leftPanelIsMinifiedKey = 'left-panel-is-minified';

    /*
	 * SMART ACTIONS
	 */
    var smartActions = {

        // LOGOUT MSG 
        userLogout: function ($this) {

            // ask verification
            $.SmartMessageBox({
                title: "<i class='fa fa-sign-out txt-color-orangeDark'></i> Logout <span class='txt-color-orangeDark'><strong>" + $('#show-shortcut').text() + "</strong></span> ?",
                content: $this.data('logout-msg') || "You can improve your security further after logging out by closing this opened browser",
                buttons: '[No][Yes]'

            }, function (ButtonPressed) {
                if (ButtonPressed == "Yes") {
                    $.root_.addClass('animated fadeOutUp');
                    setTimeout(logout, 1000);
                }
            });
            function logout() {
                window.location = $this.attr('href');
            }

        },

        // BASIC SETUP MSG
        basicSetup: function ($this) {
            $.SmartMessageBox({
                title: "<span><strong>" + $this.data('basic-setup-msg') + "</strong></span>",
                content: "",
                buttons: '[Cancel][Okay]'

            }, function (ButtonPressed) {
                if (ButtonPressed == "Okay") {
                    $.root_.addClass('animated fadeOutUp');
                    setTimeout(redirect, 1000);
                }
            });
            function redirect() {
                window.location = $this.attr('href');
            }
        },

        // RESET WIDGETS
        resetWidgets: function ($this) {
            $.widresetMSG = $this.data('reset-msg');

            $.SmartMessageBox({
                title: "<i class='fa fa-refresh' style='color:green'></i> Clear Local Storage",
                content: $.widresetMSG || "Would you like to RESET all your saved widgets and clear LocalStorage?",
                buttons: '[No][Yes]'
            }, function (ButtonPressed) {
                if (ButtonPressed == "Yes" && localStorage) {
                    localStorage.clear();
                    location.reload();
                }

            });
        },

        // LAUNCH FULLSCREEN 
        launchFullscreen: function (element) {

            if (!$.root_.hasClass("full-screen")) {

                $.root_.addClass("full-screen");

                if (element.requestFullscreen) {
                    element.requestFullscreen();
                } else if (element.mozRequestFullScreen) {
                    element.mozRequestFullScreen();
                } else if (element.webkitRequestFullscreen) {
                    element.webkitRequestFullscreen();
                } else if (element.msRequestFullscreen) {
                    element.msRequestFullscreen();
                }

            } else {

                $.root_.removeClass("full-screen");

                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.mozCancelFullScreen) {
                    document.mozCancelFullScreen();
                } else if (document.webkitExitFullscreen) {
                    document.webkitExitFullscreen();
                }

            }

        },

        // MINIFY MENU
        minifyMenu: function ($this) {
            if (!$.root_.hasClass("menu-on-top")) {
                $.root_.toggleClass("minified");
                $.root_.removeClass("hidden-menu");
                $('html').removeClass("hidden-menu-mobile-lock");
                $this && $this.effect("highlight", {}, 500);
            }
        },

        // TOGGLE MENU 
        toggleMenu: function () {
            if (!$.root_.hasClass("menu-on-top")) {
                $('html').toggleClass("hidden-menu-mobile-lock");
                $.root_.toggleClass("hidden-menu");
                $.root_.removeClass("minified");
            } else if ($.root_.hasClass("menu-on-top") && $.root_.hasClass("mobile-view-activated")) {
                $('html').toggleClass("hidden-menu-mobile-lock");
                $.root_.toggleClass("hidden-menu");
                $.root_.removeClass("minified");
            }
        },

        // TOGGLE SHORTCUT 
        toggleShortcut: function () {

            if ($.shortcut_dropdown.is(":visible")) {
                shortcut_buttons_hide();
            } else {
                shortcut_buttons_show();
            }

            // SHORT CUT (buttons that appear when clicked on user name)
            $.shortcut_dropdown.find('a').click(function (e) {
                e.preventDefault();
                window.location = $(this).attr('href');
                setTimeout(shortcut_buttons_hide, 300);

            });

            // SHORTCUT buttons goes away if mouse is clicked outside of the area
            $(document).mouseup(function (e) {
                if (!$.shortcut_dropdown.is(e.target) && $.shortcut_dropdown.has(e.target).length === 0) {
                    shortcut_buttons_hide();
                }
            });

            // SHORTCUT ANIMATE HIDE
            function shortcut_buttons_hide() {
                $.shortcut_dropdown.animate({
                    height: "hide"
                }, 300, "easeOutCirc");
                $.root_.removeClass('shortcut-on');

            }

            // SHORTCUT ANIMATE SHOW
            function shortcut_buttons_show() {
                $.shortcut_dropdown.animate({
                    height: "show"
                }, 200, "easeOutCirc");
                $.root_.addClass('shortcut-on');
            }

        }

    };

   
    $.root_.on('click', '[data-action="userLogout"]', function (e) {
        var $this = $(this);
        smartActions.userLogout($this);
        e.preventDefault();
    });

    $.root_.on('click', '[data-action="basicSetup"]', function (e) {
        var $this = $(this);
        smartActions.basicSetup($this);
        e.preventDefault();
    });

    $.root_.on('click', '[data-action="resetWidgets"]', function (e) {
        var $this = $(this);
        smartActions.resetWidgets($this);
        e.preventDefault();
    });

    $.root_.on('click', '[data-action="launchFullscreen"]', function (e) {
        smartActions.launchFullscreen(document.documentElement);
        e.preventDefault();
    });

    $.root_.on('click', '[data-action="minifyMenu"]', function (e) {
        var $this = $(this);
        smartActions.minifyMenu($this);
        jQuery(".onlyOnHide").toggleClass("hide");
        e.preventDefault();

        if ($.root_.hasClass('minified')) {
            document.cookie = leftPanelIsMinifiedKey + '=true; path=/; Expires=Fri, 31 Dec 9999 23:59:59 GMT;';
        } else {
            document.cookie = leftPanelIsMinifiedKey + '=; path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
        }
    });

    $.root_.on('click', '[data-action="toggleMenu"]', function (e) {
        smartActions.toggleMenu();
        e.preventDefault();
    });

    $.root_.on('click', '[data-action="toggleShortcut"]', function (e) {
        smartActions.toggleShortcut();
        e.preventDefault();
    });

    /*
	 * FIRE TOOLTIPS
	 */
    if ($("[rel=tooltip]").length) {
        $("[rel=tooltip]").tooltip();
    }

    // INITIALIZE LEFT NAV
    if (!$topmenu) {

        function stripTrailingSlash(str) {
            if (!str) {
                return str;
            }
            if (str.substr(-1) == '/') {
                return str.substr(0, str.length - 1);
            }
            return str;
        }

        var url = window.location.pathname;
        var activePage = stripTrailingSlash(url);

        $('nav li a').each(function () {
            var currentPage = stripTrailingSlash($(this).attr('href'));
            if (activePage == currentPage) {
                $(this).parent().addClass('active');
            }
        });

        if ($('nav ul').jarvismenu) {
            if (!null) {
                $('nav ul').jarvismenu({
                    accordion: true,
                    speed: $.menu_speed,
                    closedSign: '<em class="fa fa-plus-square-o"></em>',
                    openedSign: '<em class="fa fa-minus-square-o"></em>'
                });
            } else {
                alert("Error - menu anchor does not exist");
            }
        }
    }

    // SHOW & HIDE MOBILE SEARCH FIELD
    $('#search-mobile').click(function () {
        $.root_.addClass('search-mobile');
    });

    $('#cancel-search-js').click(function () {
        $.root_.removeClass('search-mobile');
    });

    // ACTIVITY
    // ajax drop
    $('#activity').click(function (e) {
        var $this = $(this);

        if ($this.find('.badge').hasClass('bg-color-red')) {
            $this.find('.badge').removeClassPrefix('bg-color-');
            $this.find('.badge').text("0");
            // console.log("Ajax call for activity")
        }

        if (!$this.next('.ajax-dropdown').is(':visible')) {
            $this.next('.ajax-dropdown').fadeIn(150);
            $this.addClass('active');
        } else {
            $this.next('.ajax-dropdown').fadeOut(150);
            $this.removeClass('active');
        }

        var mytest = $this.next('.ajax-dropdown').find('.btn-group > .active > input').attr('id');
        //console.log(mytest)

        e.preventDefault();
    });

    $('input[name="activity"]').change(function () {
        //alert($(this).val())
        var $this = $(this);

        url = $this.attr('id');
        container = $('.ajax-notifications');

        loadURL(url, container);

    });

    $(document).mouseup(function (e) {
        if (!$('.ajax-dropdown').is(e.target) && $('.ajax-dropdown').has(e.target).length === 0) {
            $('.ajax-dropdown').fadeOut(150);
            $('.ajax-dropdown').prev().removeClass("active");
        }
    });

    $('button[data-btn-loading]').on('click', function () {
        var btn = $(this);
        btn.button('loading');
        setTimeout(function () {
            btn.button('reset');
        }, 3000);
    });

    // NOTIFICATION IS PRESENT

    function notification_check() {
        $this = $('#activity > .badge');

        if (parseInt($this.text()) > 0) {
            $this.addClass("bg-color-red bounceIn animated");
        }
    }

    notification_check();

});


/*
 * RESIZER WITH THROTTLE
 * Source: http://benalman.com/code/projects/jquery-resize/examples/resize/
 */

(function ($, window, undefined) {

    var elems = $([]),
        jq_resize = $.resize = $.extend($.resize, {}),
        timeout_id, str_setTimeout = 'setTimeout',
        str_resize = 'resize',
        str_data = str_resize + '-special-event',
        str_delay = 'delay',
        str_throttle = 'throttleWindow';

    jq_resize[str_delay] = $.throttle_delay;

    jq_resize[str_throttle] = true;

    $.event.special[str_resize] = {

        setup: function () {
            if (!jq_resize[str_throttle] && this[str_setTimeout]) {
                return false;
            }

            var elem = $(this);
            elems = elems.add(elem);
            try {
                $.data(this, str_data, {
                    w: elem.width(),
                    h: elem.height()
                });
            } catch (e) {
                $.data(this, str_data, {
                    w: elem.width, // elem.width();
                    h: elem.height // elem.height();
                });
            }

            if (elems.length === 1) {
                loopy();
            }
        },
        teardown: function () {
            if (!jq_resize[str_throttle] && this[str_setTimeout]) {
                return false;
            }

            var elem = $(this);
            elems = elems.not(elem);
            elem.removeData(str_data);
            if (!elems.length) {
                clearTimeout(timeout_id);
            }
        },

        add: function (handleObj) {
            if (!jq_resize[str_throttle] && this[str_setTimeout]) {
                return false;
            }
            var old_handler;

            function new_handler(e, w, h) {
                var elem = $(this),
                    data = $.data(this, str_data);

                if (data !== undefined) {
                    data.w = w !== undefined ? w : elem.width();
                    data.h = h !== undefined ? h : elem.height();
                    old_handler.apply(this, arguments);
                }

            }
            if ($.isFunction(handleObj)) {
                old_handler = handleObj;
                return new_handler;
            } else {
                old_handler = handleObj.handler;
                handleObj.handler = new_handler;
            }
        }
    };

    function loopy() {
        timeout_id = window[str_setTimeout](function () {
            elems.each(function () {
                var width;
                var height;

                var elem = $(this),
                    data = $.data(this, str_data); //width = elem.width(), height = elem.height();

                // Highcharts fix
                try {
                    width = elem.width();
                } catch (e) {
                    width = elem.width;
                }

                try {
                    height = elem.height();
                } catch (e) {
                    height = elem.height;
                }
                //fixed bug


                if (width !== data.w || height !== data.h) {
                    elem.trigger(str_resize, [data.w = width, data.h = height]);
                }

            });
            loopy();

        }, jq_resize[str_delay]);

    }

})(jQuery, this);

/*
* ADD CLASS WHEN BELOW CERTAIN WIDTH (MOBILE MENU)
* Description: changes the page min-width of #CONTENT and NAV when navigation is resized.
* This is to counter bugs for min page width on many desktop and mobile devices.
* Note: This script uses JSthrottle technique so don't worry about memory/CPU usage
*/

$('#main').resize(function () {
    check_if_mobile_width();
});


function check_if_mobile_width() {
    $.root_ = $.root_ || $('body');
    if ($(window).width() < 979) {
        $.root_.addClass('mobile-view-activated');
        $.root_.removeClass('minified');
    } else if ($.root_.hasClass('mobile-view-activated')) {
        $.root_.removeClass('mobile-view-activated');
    }
}

/* ~ END: NAV OR #LEFT-BAR RESIZE DETECT */

/*
 * DETECT IE VERSION
 * Description: A short snippet for detecting versions of IE in JavaScript
 * without resorting to user-agent sniffing
 * RETURNS:
 * If you're not in IE (or IE version is less than 5) then:
 * //ie === undefined
 *
 * If you're in IE (>=5) then you can determine which version:
 * // ie === 7; // IE7
 *
 * Thus, to detect IE:
 * // if (ie) {}
 *
 * And to detect the version:
 * ie === 6 // IE6
 * ie > 7 // IE8, IE9 ...
 * ie < 9 // Anything less than IE9
 */

// TODO: delete this function later on - no longer needed (?)
var ie = (function () {

    var undef, v = 3, div = document.createElement('div'), all = div.getElementsByTagName('i');

    while (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]);

    return v > 4 ? v : undef;

}()); // do we need this? 

/* ~ END: DETECT IE VERSION */

/*
 * CUSTOM MENU PLUGIN
 */

$.fn.extend({

    //pass the options variable to the function
    jarvismenu: function (options) {

        var defaults = {
            accordion: 'true',
            speed: 200,
            closedSign: '[+]',
            openedSign: '[-]'
        };

        // Extend our default options with those provided.
        var opts = $.extend(defaults, options);
        //Assign current element to variable, in this case is UL element
        var $this = $(this);

        //add a mark [+] to a multilevel menu
        $this.find("li").each(function () {
            if ($(this).find("ul").length !== 0) {
                //add the multilevel sign next to the link
                $(this).find("a:first").append("<b class='collapse-sign'>" + opts.closedSign + "</b>");

                //avoid jumping to the top of the page when the href is an #
                if ($(this).find("a:first").attr('href') == "#") {
                    $(this).find("a:first").click(function () {
                        return false;
                    });
                }
            }
        });

        //open active level
        $this.find("li.active").each(function () {
            $(this).parents("ul").slideDown(opts.speed);
            $(this).parents("ul").parent("li").find("b:first").html(opts.openedSign);
            $(this).parents("ul").parent("li").addClass("open");
        });

        $this.find("li a").click(function () {

            if ($(this).parent().find("ul").length !== 0) {

                if (opts.accordion) {
                    //Do nothing when the list is open
                    if (!$(this).parent().find("ul").is(':visible')) {
                        parents = $(this).parent().parents("ul");
                        visible = $this.find("ul:visible");
                        visible.each(function (visibleIndex) {
                            var close = true;
                            parents.each(function (parentIndex) {
                                if (parents[parentIndex] == visible[visibleIndex]) {
                                    close = false;
                                    return false;
                                }
                            });
                            if (close) {
                                if ($(this).parent().find("ul") != visible[visibleIndex]) {
                                    $(visible[visibleIndex]).slideUp(opts.speed, function () {
                                        $(this).parent("li").find("b:first").html(opts.closedSign);
                                        $(this).parent("li").removeClass("open");
                                    });

                                }
                            }
                        });
                    }
                }// end if
                if ($(this).parent().find("ul:first").is(":visible") && !$(this).parent().find("ul:first").hasClass("active")) {
                    $(this).parent().find("ul:first").slideUp(opts.speed, function () {
                        $(this).parent("li").removeClass("open");
                        $(this).parent("li").find("b:first").delay(opts.speed).html(opts.closedSign);
                    });

                } else {
                    $(this).parent().find("ul:first").slideDown(opts.speed, function () {
                        /*$(this).effect("highlight", {color : '#616161'}, 500); - disabled due to CPU clocking on phones*/
                        $(this).parent("li").addClass("open");
                        $(this).parent("li").find("b:first").delay(opts.speed).html(opts.openedSign);
                    });
                } // end else
            } // end if
        });
    } // end function
});


/* ~ END: CUSTOM MENU PLUGIN */

/*
 * ELEMENT EXIST OR NOT
 * Description: returns true or false
 * Usage: $('#myDiv').doesExist();
 */

jQuery.fn.doesExist = function () {
    return jQuery(this).length > 0;
};

/* ~ END: ELEMENT EXIST OR NOT */

/*
 * INITIALIZE FORMS
 * Description: Select2, Masking, Datepicker, Autocomplete
 */

function runAllForms() {

    /*
	 * BOOTSTRAP SLIDER PLUGIN
	 * Usage:
	 * Dependency: js/plugin/bootstrap-slider
	 */
    if ($.fn.slider) {
        $('.slider').slider();
    }

    /*
	 * SELECT2 PLUGIN
	 * Usage:
	 * Dependency: js/plugin/select2/
	 */
    if ($.fn.select2) {
        $('.select2').each(function () {
            var $this = $(this);
            var width = $this.attr('data-select-width') || '100%';
            //, _showSearchInput = $this.attr('data-select-search') === 'true';
            $this.select2({
                //showSearchInput : _showSearchInput,
                allowClear: true,
                width: width
            });
        });
    }

    /*
	 * MASKING
	 * Dependency: js/plugin/masked-input/
	 */
    if ($.fn.mask) {
        $('[data-mask]').each(function () {

            var $this = $(this);
            var mask = $this.attr('data-mask') || 'error...', mask_placeholder = $this.attr('data-mask-placeholder') || 'X';

            $this.mask(mask, {
                placeholder: mask_placeholder
            });
        });
    }

    /*
	 * AUTOCOMPLETE
	 * Dependency: js/jqui
	 */
    if ($.fn.autocomplete) {
        $('[data-autocomplete]').each(function () {

            var $this = $(this);
            var availableTags = $this.data('autocomplete') || ["The", "Quick", "Brown", "Fox", "Jumps", "Over", "Three", "Lazy", "Dogs"];

            $this.autocomplete({
                source: availableTags
            });
        });
    }

    if ($.fn.datepicker) {
        $('.datepicker').each(function () {

            var $this = $(this);
            var dataDateFormat = $this.attr('data-dateformat') || 'mm.dd.yy';

            $this.datepicker({
                dateFormat: dataDateFormat,
                prevText: '<',
                nextText: '>',
            });
        });
    }

    /*
	 * AJAX BUTTON LOADING TEXT
	 * Usage: <button type="button" data-loading-text="Loading..." class="btn btn-xs btn-default ajax-refresh"> .. </button>
	 */
    $('button[data-loading-text]').on('click', function () {
        var btn = $(this);
        btn.button('loading');
        setTimeout(function () {
            btn.button('reset');
        }, 3000);
    });

}

/* ~ END: INITIALIZE FORMS */

/*
 * INITIALIZE CHARTS
 * Description: Sparklines, PieCharts
 */

function runAllCharts() {
    /*
	 * SPARKLINES
	 * DEPENDENCY: js/plugins/sparkline/jquery.sparkline.min.js
	 * See usage example below...
	 */

    /* Usage:
	 * 		<div class="sparkline-line txt-color-blue" data-fill-color="transparent" data-sparkline-height="26px">
	 *			5,6,7,9,9,5,9,6,5,6,6,7,7,6,7,8,9,7
	 *		</div>
	 */

    if ($.fn.sparkline) {

        // variable declearations:

        var barColor,
		    sparklineHeight,
		    sparklineBarWidth,
		    sparklineBarSpacing,
		    sparklineNegBarColor,
		    sparklineStackedColor,
		    thisLineColor,
		    thisLineWidth,
		    thisFill,
		    thisSpotColor,
		    thisMinSpotColor,
		    thisMaxSpotColor,
		    thishighlightSpotColor,
		    thisHighlightLineColor,
		    thisSpotRadius,
			pieColors,
		    pieWidthHeight,
		    pieBorderColor,
		    pieOffset,
		 	thisBoxWidth,
		    thisBoxHeight,
		    thisBoxRaw,
		    thisBoxTarget,
		    thisBoxMin,
		    thisBoxMax,
		    thisShowOutlier,
		    thisIQR,
		    thisBoxSpotRadius,
		    thisBoxLineColor,
		    thisBoxFillColor,
		    thisBoxWhisColor,
		    thisBoxOutlineColor,
		    thisBoxOutlineFill,
		    thisBoxMedianColor,
		    thisBoxTargetColor,
			thisBulletHeight,
		    thisBulletWidth,
		    thisBulletColor,
		    thisBulletPerformanceColor,
		    thisBulletRangeColors,
			thisDiscreteHeight,
		    thisDiscreteWidth,
		    thisDiscreteLineColor,
		    thisDiscreteLineHeight,
		    thisDiscreteThrushold,
		    thisDiscreteThrusholdColor,
			thisTristateHeight,
		    thisTristatePosBarColor,
		    thisTristateNegBarColor,
		    thisTristateZeroBarColor,
		    thisTristateBarWidth,
		    thisTristateBarSpacing,
		    thisZeroAxis,
		    thisBarColor,
		    sparklineWidth,
		    sparklineValue,
		    sparklineValueSpots1,
		    sparklineValueSpots2,
		    thisLineWidth1,
		    thisLineWidth2,
		    thisLineColor1,
		    thisLineColor2,
		    thisSpotRadius1,
		    thisSpotRadius2,
		    thisMinSpotColor1,
		    thisMaxSpotColor1,
		    thisMinSpotColor2,
		    thisMaxSpotColor2,
		    thishighlightSpotColor1,
		    thisHighlightLineColor1,
		    thishighlightSpotColor2,
		    thisFillColor1,
		    thisFillColor2;


        $('.sparkline').each(function () {
            var $this = $(this);
            var sparklineType = $this.data('sparkline-type') || 'bar';

            // BAR CHART
            if (sparklineType == 'bar') {

                barColor = $this.data('sparkline-bar-color') || $this.css('color') || '#0000f0';
                sparklineHeight = $this.data('sparkline-height') || '26px';
                sparklineBarWidth = $this.data('sparkline-barwidth') || 5;
                sparklineBarSpacing = $this.data('sparkline-barspacing') || 2;
                sparklineNegBarColor = $this.data('sparkline-negbar-color') || '#A90329';
                sparklineStackedColor = $this.data('sparkline-barstacked-color') || ["#A90329", "#0099c6", "#98AA56", "#da532c", "#4490B1", "#6E9461", "#990099", "#B4CAD3"];

                $this.sparkline('html', {
                    barColor: barColor,
                    type: sparklineType,
                    height: sparklineHeight,
                    barWidth: sparklineBarWidth,
                    barSpacing: sparklineBarSpacing,
                    stackedBarColor: sparklineStackedColor,
                    negBarColor: sparklineNegBarColor,
                    zeroAxis: 'false'
                });

            }

            // LINE CHART
            if (sparklineType == 'line') {

                sparklineHeight = $this.data('sparkline-height') || '20px';
                sparklineWidth = $this.data('sparkline-width') || '90px';
                thisLineColor = $this.data('sparkline-line-color') || $this.css('color') || '#0000f0';
                thisLineWidth = $this.data('sparkline-line-width') || 1;
                thisFill = $this.data('fill-color') || '#c0d0f0';
                thisSpotColor = $this.data('sparkline-spot-color') || '#f08000';
                thisMinSpotColor = $this.data('sparkline-minspot-color') || '#ed1c24';
                thisMaxSpotColor = $this.data('sparkline-maxspot-color') || '#f08000';
                thishighlightSpotColor = $this.data('sparkline-highlightspot-color') || '#50f050';
                thisHighlightLineColor = $this.data('sparkline-highlightline-color') || 'f02020';
                thisSpotRadius = $this.data('sparkline-spotradius') || 1.5;
                thisChartMinYRange = $this.data('sparkline-min-y') || 'undefined';
                thisChartMaxYRange = $this.data('sparkline-max-y') || 'undefined';
                thisChartMinXRange = $this.data('sparkline-min-x') || 'undefined';
                thisChartMaxXRange = $this.data('sparkline-max-x') || 'undefined';
                thisMinNormValue = $this.data('min-val') || 'undefined';
                thisMaxNormValue = $this.data('max-val') || 'undefined';
                thisNormColor = $this.data('norm-color') || '#c0c0c0';
                thisDrawNormalOnTop = $this.data('draw-normal') || false;

                $this.sparkline('html', {
                    type: 'line',
                    width: sparklineWidth,
                    height: sparklineHeight,
                    lineWidth: thisLineWidth,
                    lineColor: thisLineColor,
                    fillColor: thisFill,
                    spotColor: thisSpotColor,
                    minSpotColor: thisMinSpotColor,
                    maxSpotColor: thisMaxSpotColor,
                    highlightSpotColor: thishighlightSpotColor,
                    highlightLineColor: thisHighlightLineColor,
                    spotRadius: thisSpotRadius,
                    chartRangeMin: thisChartMinYRange,
                    chartRangeMax: thisChartMaxYRange,
                    chartRangeMinX: thisChartMinXRange,
                    chartRangeMaxX: thisChartMaxXRange,
                    normalRangeMin: thisMinNormValue,
                    normalRangeMax: thisMaxNormValue,
                    normalRangeColor: thisNormColor,
                    drawNormalOnTop: thisDrawNormalOnTop

                });

            }

            // PIE CHART
            if (sparklineType == 'pie') {

                pieColors = $this.data('sparkline-piecolor') || ["#B4CAD3", "#4490B1", "#98AA56", "#da532c", "#6E9461", "#0099c6", "#990099", "#717D8A"];
                pieWidthHeight = $this.data('sparkline-piesize') || 90;
                pieBorderColor = $this.data('border-color') || '#45494C';
                pieOffset = $this.data('sparkline-offset') || 0;

                $this.sparkline('html', {
                    type: 'pie',
                    width: pieWidthHeight,
                    height: pieWidthHeight,
                    tooltipFormat: '<span style="color: {{color}}">&#9679;</span> ({{percent.1}}%)',
                    sliceColors: pieColors,
                    borderWidth: 1,
                    offset: pieOffset,
                    borderColor: pieBorderColor
                });

            }

            // BOX PLOT
            if (sparklineType == 'box') {

                thisBoxWidth = $this.data('sparkline-width') || 'auto';
                thisBoxHeight = $this.data('sparkline-height') || 'auto';
                thisBoxRaw = $this.data('sparkline-boxraw') || false;
                thisBoxTarget = $this.data('sparkline-targetval') || 'undefined';
                thisBoxMin = $this.data('sparkline-min') || 'undefined';
                thisBoxMax = $this.data('sparkline-max') || 'undefined';
                thisShowOutlier = $this.data('sparkline-showoutlier') || true;
                thisIQR = $this.data('sparkline-outlier-iqr') || 1.5;
                thisBoxSpotRadius = $this.data('sparkline-spotradius') || 1.5;
                thisBoxLineColor = $this.css('color') || '#000000';
                thisBoxFillColor = $this.data('fill-color') || '#c0d0f0';
                thisBoxWhisColor = $this.data('sparkline-whis-color') || '#000000';
                thisBoxOutlineColor = $this.data('sparkline-outline-color') || '#303030';
                thisBoxOutlineFill = $this.data('sparkline-outlinefill-color') || '#f0f0f0';
                thisBoxMedianColor = $this.data('sparkline-outlinemedian-color') || '#f00000';
                thisBoxTargetColor = $this.data('sparkline-outlinetarget-color') || '#40a020';

                $this.sparkline('html', {
                    type: 'box',
                    width: thisBoxWidth,
                    height: thisBoxHeight,
                    raw: thisBoxRaw,
                    target: thisBoxTarget,
                    minValue: thisBoxMin,
                    maxValue: thisBoxMax,
                    showOutliers: thisShowOutlier,
                    outlierIQR: thisIQR,
                    spotRadius: thisBoxSpotRadius,
                    boxLineColor: thisBoxLineColor,
                    boxFillColor: thisBoxFillColor,
                    whiskerColor: thisBoxWhisColor,
                    outlierLineColor: thisBoxOutlineColor,
                    outlierFillColor: thisBoxOutlineFill,
                    medianColor: thisBoxMedianColor,
                    targetColor: thisBoxTargetColor

                });

            }

            // BULLET
            if (sparklineType == 'bullet') {

                var thisBulletHeight = $this.data('sparkline-height') || 'auto';
                thisBulletWidth = $this.data('sparkline-width') || 2;
                thisBulletColor = $this.data('sparkline-bullet-color') || '#ed1c24';
                thisBulletPerformanceColor = $this.data('sparkline-performance-color') || '#3030f0';
                thisBulletRangeColors = $this.data('sparkline-bulletrange-color') || ["#d3dafe", "#a8b6ff", "#7f94ff"];

                $this.sparkline('html', {

                    type: 'bullet',
                    height: thisBulletHeight,
                    targetWidth: thisBulletWidth,
                    targetColor: thisBulletColor,
                    performanceColor: thisBulletPerformanceColor,
                    rangeColors: thisBulletRangeColors

                });

            }

            // DISCRETE
            if (sparklineType == 'discrete') {

                thisDiscreteHeight = $this.data('sparkline-height') || 26;
                thisDiscreteWidth = $this.data('sparkline-width') || 50;
                thisDiscreteLineColor = $this.css('color');
                thisDiscreteLineHeight = $this.data('sparkline-line-height') || 5;
                thisDiscreteThrushold = $this.data('sparkline-threshold') || 'undefined';
                thisDiscreteThrusholdColor = $this.data('sparkline-threshold-color') || '#ed1c24';

                $this.sparkline('html', {

                    type: 'discrete',
                    width: thisDiscreteWidth,
                    height: thisDiscreteHeight,
                    lineColor: thisDiscreteLineColor,
                    lineHeight: thisDiscreteLineHeight,
                    thresholdValue: thisDiscreteThrushold,
                    thresholdColor: thisDiscreteThrusholdColor

                });

            }

            // TRISTATE
            if (sparklineType == 'tristate') {

                thisTristateHeight = $this.data('sparkline-height') || 26;
                thisTristatePosBarColor = $this.data('sparkline-posbar-color') || '#60f060';
                thisTristateNegBarColor = $this.data('sparkline-negbar-color') || '#f04040';
                thisTristateZeroBarColor = $this.data('sparkline-zerobar-color') || '#909090';
                thisTristateBarWidth = $this.data('sparkline-barwidth') || 5;
                thisTristateBarSpacing = $this.data('sparkline-barspacing') || 2;
                thisZeroAxis = $this.data('sparkline-zeroaxis') || false;

                $this.sparkline('html', {

                    type: 'tristate',
                    height: thisTristateHeight,
                    posBarColor: thisBarColor,
                    negBarColor: thisTristateNegBarColor,
                    zeroBarColor: thisTristateZeroBarColor,
                    barWidth: thisTristateBarWidth,
                    barSpacing: thisTristateBarSpacing,
                    zeroAxis: thisZeroAxis

                });

            }

            //COMPOSITE: BAR
            if (sparklineType == 'compositebar') {

                sparklineHeight = $this.data('sparkline-height') || '20px';
                sparklineWidth = $this.data('sparkline-width') || '100%';
                sparklineBarWidth = $this.data('sparkline-barwidth') || 3;
                thisLineWidth = $this.data('sparkline-line-width') || 1;
                thisLineColor = $this.data('sparkline-color-top') || '#ed1c24';
                thisBarColor = $this.data('sparkline-color-bottom') || '#333333';

                $this.sparkline($this.data('sparkline-bar-val'), {

                    type: 'bar',
                    width: sparklineWidth,
                    height: sparklineHeight,
                    barColor: thisBarColor,
                    barWidth: sparklineBarWidth
                    //barSpacing: 5

                });

                $this.sparkline($this.data('sparkline-line-val'), {

                    width: sparklineWidth,
                    height: sparklineHeight,
                    lineColor: thisLineColor,
                    lineWidth: thisLineWidth,
                    composite: true,
                    fillColor: false

                });

            }

            //COMPOSITE: LINE
            if (sparklineType == 'compositeline') {

                sparklineHeight = $this.data('sparkline-height') || '20px';
                sparklineWidth = $this.data('sparkline-width') || '90px';
                sparklineValue = $this.data('sparkline-bar-val');
                sparklineValueSpots1 = $this.data('sparkline-bar-val-spots-top') || null;
                sparklineValueSpots2 = $this.data('sparkline-bar-val-spots-bottom') || null;
                thisLineWidth1 = $this.data('sparkline-line-width-top') || 1;
                thisLineWidth2 = $this.data('sparkline-line-width-bottom') || 1;
                thisLineColor1 = $this.data('sparkline-color-top') || '#333333';
                thisLineColor2 = $this.data('sparkline-color-bottom') || '#ed1c24';
                thisSpotRadius1 = $this.data('sparkline-spotradius-top') || 1.5;
                thisSpotRadius2 = $this.data('sparkline-spotradius-bottom') || thisSpotRadius1;
                thisSpotColor = $this.data('sparkline-spot-color') || '#f08000';
                thisMinSpotColor1 = $this.data('sparkline-minspot-color-top') || '#ed1c24';
                thisMaxSpotColor1 = $this.data('sparkline-maxspot-color-top') || '#f08000';
                thisMinSpotColor2 = $this.data('sparkline-minspot-color-bottom') || thisMinSpotColor1;
                thisMaxSpotColor2 = $this.data('sparkline-maxspot-color-bottom') || thisMaxSpotColor1;
                thishighlightSpotColor1 = $this.data('sparkline-highlightspot-color-top') || '#50f050';
                thisHighlightLineColor1 = $this.data('sparkline-highlightline-color-top') || '#f02020';
                thishighlightSpotColor2 = $this.data('sparkline-highlightspot-color-bottom') ||
                    thishighlightSpotColor1;
                thisHighlightLineColor2 = $this.data('sparkline-highlightline-color-bottom') ||
                    thisHighlightLineColor1;
                thisFillColor1 = $this.data('sparkline-fillcolor-top') || 'transparent';
                thisFillColor2 = $this.data('sparkline-fillcolor-bottom') || 'transparent';

                $this.sparkline(sparklineValue, {

                    type: 'line',
                    spotRadius: thisSpotRadius1,

                    spotColor: thisSpotColor,
                    minSpotColor: thisMinSpotColor1,
                    maxSpotColor: thisMaxSpotColor1,
                    highlightSpotColor: thishighlightSpotColor1,
                    highlightLineColor: thisHighlightLineColor1,

                    valueSpots: sparklineValueSpots1,

                    lineWidth: thisLineWidth1,
                    width: sparklineWidth,
                    height: sparklineHeight,
                    lineColor: thisLineColor1,
                    fillColor: thisFillColor1

                });

                $this.sparkline($this.data('sparkline-line-val'), {

                    type: 'line',
                    spotRadius: thisSpotRadius2,

                    spotColor: thisSpotColor,
                    minSpotColor: thisMinSpotColor2,
                    maxSpotColor: thisMaxSpotColor2,
                    highlightSpotColor: thishighlightSpotColor2,
                    highlightLineColor: thisHighlightLineColor2,

                    valueSpots: sparklineValueSpots2,

                    lineWidth: thisLineWidth2,
                    width: sparklineWidth,
                    height: sparklineHeight,
                    lineColor: thisLineColor2,
                    composite: true,
                    fillColor: thisFillColor2

                });

            }

        });

    }// end if

    /*
	 * EASY PIE CHARTS
	 * DEPENDENCY: js/plugins/easy-pie-chart/jquery.easy-pie-chart.min.js
	 * Usage: <div class="easy-pie-chart txt-color-orangeDark" data-pie-percent="33" data-pie-size="72" data-size="72">
	 *			<span class="percent percent-sign">35</span>
	 * 	  	  </div>
	 */

    if ($.fn.easyPieChart) {

        $('.easy-pie-chart').each(function () {
            var $this = $(this);
            var barColor = $this.css('color') || $this.data('pie-color'),
			    trackColor = $this.data('pie-track-color') || '#eeeeee',
			    size = parseInt($this.data('pie-size')) || 25;

            $this.easyPieChart({

                barColor: barColor,
                trackColor: trackColor,
                scaleColor: false,
                lineCap: 'butt',
                lineWidth: parseInt(size / 8.5),
                animate: 1500,
                rotate: -90,
                size: size,
                onStep: function (value) {
                    this.$el.find('span').text(~~value);
                }

            });
        });

    } // end if

}

/* ~ END: INITIALIZE CHARTS */

/*
 * INITIALIZE JARVIS WIDGETS
 */

// Setup Desktop Widgets
function setup_widgets_desktop() {

    if ($.fn.jarvisWidgets && $.enableJarvisWidgets) {

        $('#es-dashboard-widget-grid').jarvisWidgets({
            grid: 'article',
            widgets: '.jarviswidget',
            localStorage: true,
            deleteSettingsKey: '#deletesettingskey-options',
            settingsKeyLabel: 'Reset settings?',
            deletePositionKey: '#deletepositionkey-options',
            positionKeyLabel: 'Reset position?',
            sortable: true,
            buttonsHidden: false,
            // toggle button
            toggleButton: true,
            toggleClass: 'fa fa-minus | fa fa-plus',
            toggleSpeed: 200,
            onToggle: function () {
            },
            // delete btn
            deleteButton: true,
            deleteClass: 'fa fa-times',
            deleteSpeed: 200,
            onDelete: function () {
            },
            // edit btn
            editButton: true,
            editPlaceholder: '.jarviswidget-editbox',
            editClass: 'fa fa-cog | fa fa-save',
            editSpeed: 200,
            onEdit: function () {
            },
            // color button
            colorButton: true,
            // full screen
            fullscreenButton: true,
            fullscreenClass: 'fa fa-expand | fa fa-compress',
            fullscreenDiff: 3,
            onFullscreen: function () {
            },
            // custom btn
            customButton: false,
            customClass: 'folder-10 | next-10',
            customStart: function () {
                alert('Hello you, this is a custom button...');
            },
            customEnd: function () {
                alert('bye, till next time...');
            },
            // order
            buttonOrder: '%refresh% %custom% %edit% %toggle% %fullscreen% %delete%',
            opacity: 1.0,
            dragHandle: '> header',
            placeholderClass: 'jarviswidget-placeholder',
            indicator: true,
            indicatorTime: 600,
            ajax: true,
            timestampPlaceholder: '.jarviswidget-timestamp',
            timestampFormat: 'Last update: %m%/%d%/%y% %h%:%i%:%s%',
            refreshButton: true,
            refreshButtonClass: 'fa fa-refresh',
            labelError: 'Sorry but there was a error:',
            labelUpdated: 'Last Update:',
            labelRefresh: 'Refresh',
            labelDelete: 'Delete widget:',
            afterLoad: function () {
            },
            rtl: false, // best not to toggle this!
            onChange: function () {
            },
            onSave: function () {

            },
            ajaxnav: $.navAsAjax // declears how the localstorage should be saved (HTML or AJAX page)

        });

    }

}

// Setup Desktop Widgets
function setup_widgets_mobile() {

    if ($.enableMobileWidgets && $.enableJarvisWidgets) {
        setup_widgets_desktop();
    }

}

/* ~ END: INITIALIZE JARVIS WIDGETS */

/*
 * GOOGLE MAPS
 * description: Append google maps to head dynamically (only execute for ajax version)
 * Loads at the begining for ajax pages
 */

if ($.navAsAjax || $(".google_maps")) {
    var gMapsLoaded = false;
    window.gMapsCallback = function () {
        gMapsLoaded = true;
        $(window).trigger('gMapsLoaded');
    };
    window.loadGoogleMaps = function () {
        if (gMapsLoaded)
            return window.gMapsCallback();
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type", "text/javascript");
        script_tag.setAttribute("src", "http://maps.google.com/maps/api/js?sensor=false&callback=gMapsCallback");
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
    };
}

/* ~ END: GOOGLE MAPS */

/*
 * LOAD SCRIPTS
 * Usage:
 * Define function = myPrettyCode ()...
 * loadScript("js/my_lovely_script.js", myPrettyCode);
 */

var jsArray = {};

function loadScript(scriptName, callback) {

    if (!jsArray[scriptName]) {
        jsArray[scriptName] = true;

        // adding the script tag to the head as suggested before
        var body = document.getElementsByTagName('body')[0];
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = scriptName;

        // then bind the event to the callback function
        // there are several events for cross browser compatibility
        //script.onreadystatechange = callback;
        script.onload = callback;

        // fire the loading
        body.appendChild(script);

    } else if (callback) {// changed else to else if(callback)
        //console.log("JS file already added!");
        //execute function
        callback();
    }

}

/* ~ END: LOAD SCRIPTS */

/*
* APP AJAX REQUEST SETUP
* Description: Executes and fetches all ajax requests also
* updates naivgation elements to active
*/
if ($.navAsAjax) {
    // fire this on page load if nav exists
    if ($('nav').length) {
        checkURL();
    }

    $(document).on('click', 'nav a[href!="#"]', function (e) {
        e.preventDefault();
        var $this = $(e.currentTarget);

        // if parent is not active then get hash, or else page is assumed to be loaded
        if (!$this.parent().hasClass("active") && !$this.attr('target')) {

            // update window with hash
            // you could also do here:  $.device === "mobile" - and save a little more memory

            if ($.root_.hasClass('mobile-view-activated')) {
                $.root_.removeClass('hidden-menu');
                window.setTimeout(function () {
                    if (window.location.search) {
                        window.location.href =
							window.location.href.replace(window.location.search, '')
								.replace(window.location.hash, '') + '#' + $this.attr('href');
                    } else {
                        window.location.hash = $this.attr('href');
                    }
                }, 150);
                // it may not need this delay...
            } else {
                if (window.location.search) {
                    window.location.href =
						window.location.href.replace(window.location.search, '')
							.replace(window.location.hash, '') + '#' + $this.attr('href');
                } else {
                    window.location.hash = $this.attr('href');
                }
            }
        }

    });

    // fire links with targets on different window
    $(document).on('click', 'nav a[target="_blank"]', function (e) {
        e.preventDefault();
        var $this = $(e.currentTarget);

        window.open($this.attr('href'));
    });

    // fire links with targets on same window
    $(document).on('click', 'nav a[target="_top"]', function (e) {
        e.preventDefault();
        var $this = $(e.currentTarget);

        window.location = ($this.attr('href'));
    });

    // all links with hash tags are ignored
    $(document).on('click', 'nav a[href="#"]', function (e) {
        e.preventDefault();
    });

    // DO on hash change
    $(window).on('hashchange', function () {
        checkURL();
    });
}

// CHECK TO SEE IF URL EXISTS
function checkURL() {

    // bootstrap backdrop bug for ajax version
    if ($('.modal-backdrop')[0] && $.navAsAjax) {
        $('.modal-backdrop').remove();
        //console.log("backdrop removed");
    }

    //get the url by removing the hash
    var url = location.hash.replace(/^#/, '');

    //BEGIN: IE11 Work Around
    if (!url) {

        try {
            var documentUrl = window.document.URL;
            if (documentUrl) {
                if (documentUrl.indexOf('#', 0) > 0 && documentUrl.indexOf('#', 0) < (documentUrl.length + 1)) {
                    url = documentUrl.substring(documentUrl.indexOf('#', 0) + 1);

                }

            }

        } catch (err) { }
    }
    //END: IE11 Work Around

    container = $('#content');
    // Do this if url exists (for page refresh, etc...)
    if (url) {
        // remove all active class
        $('nav li.active').removeClass("active");
        // match the url and add the active class
        $('nav li:has(a[href="' + url + '"])').addClass("active");
        var title = ($('nav a[href="' + url + '"]').attr('title'));

        // change page title from global var
        document.title = (title || document.title);
        //console.log("page title: " + document.title);

        // parse url to jquery
        loadURL(url + location.search, container);
    } else {

        // grab the first URL from nav
        var $this = $('nav > ul > li:first-child > a[href!="#"]');

        //update hash
        window.location.hash = $this.attr('href');

    }

}

// LOAD AJAX PAGES
function loadURL(url, container) {
    //console.log(container)

    $.ajax({
        type: "GET",
        url: url,
        dataType: 'html',
        cache: true, // (warning: setting it to false will cause a timestamp and will call the request twice)
        beforeSend: function () {

            //IE11 bug fix for googlemaps
            //check if the page is ajax = true, has google map class and the container is #content
            if ($.navAsAjax && $(".google_maps")[0] && (container[0] == $("#content")[0])) {

                // target gmaps if any on page
                var collection = $(".google_maps"),
					i = 0;
                // run for each	map
                collection.each(function () {
                    i++;
                    // get map id from class elements
                    var divDealerMap = document.getElementById(this.id);

                    if (i == collection.length + 1) {
                        // "callback"
                        //console.log("all maps destroyed");
                    } else {
                        // destroy every map found
                        if (divDealerMap) divDealerMap.parentNode.removeChild(divDealerMap);
                        //console.log(this.id + " destroying maps...");
                    }
                });

                //console.log("google maps nuked!!!");

            }; //end fix

            // destroy all datatable instances
            if ($.navAsAjax && $('.dataTables_wrapper')[0] && (container[0] == $("#content")[0])) {

                var tables = $.fn.dataTable.fnTables(true);
                $(tables).each(function () {
                    $(this).dataTable().fnDestroy();
                });
                //console.log("datatable nuked!!!");
            }
            // end destroy

            // pop intervals 
            if ($.navAsAjax && $.intervalArr.length > 0 && (container[0] == $("#content")[0])) {

                while ($.intervalArr.length > 0)
                    clearInterval($.intervalArr.pop());
                //console.log("all intervals cleared..")

            }
            // end pop intervals

            // place cog
            container.html('<h1 class="ajax-loading-animation"><i class="fa fa-cog fa-spin"></i> Loading...</h1>');
            //console.log('cog replaced')

            // Only draw breadcrumb if it is main content material
            // TODO: see the framerate for the animation in touch devices

            if (container[0] == $("#content")[0]) {
                drawBreadCrumb();
                // scroll up
                $("html").animate({
                    scrollTop: 0
                }, "fast");
            }

            // end if
        },
        success: function (data) {
            container.css({
                opacity: '0.0'
            }).html(data).delay(50).animate({
                opacity: '1.0'
            }, 300);
        },
        error: function (xhr, ajaxOptions, thrownError) {
            container.html('<h4 class="ajax-loading-error"><i class="fa fa-warning txt-color-orangeDark"></i> Error 404! Page not found.</h4>');
        },
        async: true
    });

    //console.log("ajax request sent");
}

// UPDATE BREADCRUMB
function drawBreadCrumb() {
    var nav_elems = $('nav li.active > a'), count = nav_elems.length;

    //console.log("breadcrumb")
    $.bread_crumb.empty();
    $.bread_crumb.append($("<li>Home</li>"));
    nav_elems.each(function () {
        $.bread_crumb.append($("<li></li>").html($.trim($(this).clone().children(".badge").remove().end().text())));
        // update title when breadcrumb is finished...
        if (!--count) document.title = $.bread_crumb.find("li:last-child").text();
    });

}

/* ~ END: APP AJAX REQUEST SETUP */

/*
 * PAGE SETUP
 * Description: fire certain scripts that run through the page
 * to check for form elements, tooltip activation, popovers, etc...
 */
function pageSetUp() {

    if ($.device === "desktop") {
        // is desktop

        // activate tooltips
        $("[rel=tooltip]").tooltip();

        // activate popovers
        $("[rel=popover]").popover({
            html: true
        });

        // activate popovers with hover states
        $("[rel=popover-hover]").popover({
            trigger: "hover",
            html:true
        });

        // setup widgets
        setup_widgets_desktop();

        // activate inline charts
        //runAllCharts();

        // run form elements
        runAllForms();

    } else {

        // is mobile

        // activate popovers
        $("[rel=popover]").popover();

        // activate popovers with hover states
        $("[rel=popover-hover]").popover({
            trigger: "hover"
        });

        // setup widgets
        setup_widgets_mobile();

        // run form elements
        runAllForms();

    }

}

// Keep only 1 active popover per trigger - also check and hide active popover if user clicks on document
$('body').on('click', function (e) {
    $('[rel="popover"]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

// input validations
function onlyAlphabets(e, t) {
    try {
        var charCode = (e.keyCode ? e.keyCode : e.which);
        if ((charCode > 64 && charCode < 91) || (charCode > 96 && charCode < 123) || charCode == 32 || charCode == 39 || charCode == 64 || charCode == 46 || (charCode >= 48 && charCode < 58) || charCode == 45 || charCode == 58 || charCode == 8 || charCode == 46 || (e.keyCode >= 37 && e.keyCode <= 40))
            return true;
        else
            return false;
    }
    catch (err) {
        alert(err.Description);
    }
}

function fn_allowAlphabetspace(s, e) {
    var searchSpecial = '$Backspace$Del$Home$Tab$Left$Right$Up$Down$End$';
    if (searchSpecial.indexOf('$' + e.htmlEvent.key + '$') < 0) {
        var theEvent = e.htmlEvent || window.event;
        var key = theEvent.keyCode || theEvent.which;
        key = String.fromCharCode(key);
        var regex = /[a-zA-Z ]/;
        if (!regex.test(key)) {
            theEvent.returnValue = false;
            if (theEvent.preventDefault)
                theEvent.preventDefault();
        }
    }
}

// input validations
function preventGtLt(e, t) {
    try {
        if (window.event) {
            var charCode = window.event.keyCode;
        }
        else if (e) {
            var charCode = e.which;
        }
        else { return true; }
        if (charCode == 60 || charCode == 62)
            return false;
        else
            return true;
    }
    catch (err) {
        alert(err.Description);
    }
}

function alpha(e) {
    var k;
    document.all ? k = e.keyCode : k = e.which;
    return ((k > 64 && k < 91) || (k > 96 && k < 123) || k == 8 || k == 32 || (k >= 48 && k <= 57) || k == 58);
}

$(".numeric").keypress(function (event) {
    // Backspace, tab, enter, end, home, left, right
    // We don't support the del key in Opera because del == . == 46.
    var controlKeys = [8, 9, 13, 35, 36, 37, 39];
    // IE doesn't support indexOf
    var isControlKey = controlKeys.join(",").match(new RegExp(event.which));
    // Some browsers just don't raise events for control keys. Easy.
    // e.g. Safari backspace.
    if (!event.which || // Control keys in most browsers. e.g. Firefox tab is 0
        (48 <= event.which && event.which <= 57) || // Always 1 through 9
        (48 == event.which && $(this).attr("value")) || // No 0 first digit
        isControlKey) { // Opera assigns values for control keys.
        return;
    } else {
        event.preventDefault();
    }
});

function forcePostive(e) {
    var key = e.which || e.keyCode;

    if (!e.shiftKey && !e.altKey && !e.ctrlKey &&
        // numbers   
        key >= 48 && key <= 57 ||
        // Numeric keypad
        key >= 96 && key <= 105 ||
        // comma, period and minus, . on keypad
       key == 190 || key == 188 || key == 110 ||
        // Backspace and Tab and Enter
       key == 8 || key == 9 || key == 13 ||
        // Home and End
       key == 35 || key == 36 ||
        // left and right arrows
       key == 37 || key == 39 ||
        // Del and Ins
       key == 46 || key == 45)
        return true;

    return false;
}

function isNumber(evt) {
    evt = (evt) ? evt : window.event;
    var charCode = (evt.which) ? evt.which : evt.keyCode;
    if (charCode > 31 && (charCode < 48 || charCode > 57)) {
        return false;
    }
    return true;
}

$(".decimalonly").keydown(function (event) {
    if (event.shiftKey == true) {
        event.preventDefault();
    }

    if ((event.keyCode >= 48 && event.keyCode <= 57) || 
        (event.keyCode >= 96 && event.keyCode <= 105) || 
        event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 37 ||
        event.keyCode == 39 || event.keyCode == 46 || event.keyCode == 190 || event.keyCode == 110) {

    } else {
        event.preventDefault();
    }

    if($(this).val().indexOf('.') !== -1 && (event.keyCode == 190 || event.keyCode == 110))
        event.preventDefault(); 
    //if a decimal has been added, disable the "."-button

});


function isNormalInteger(str) {
    var n = ~~Number(str);
    return String(n) === str && n >= 0;
}

// end input validations


function showRedWarningBox(title, content, timeout) {
    $.smallBox({
        title: title,
        content: "<span style='padding:5px;font-size:16px;'><i class='fa fa-exclamation-circle'></i> <i>" + content + "</i></span>",
        color: "#C46A69",
        iconSmall: "fa fa-times fa-2x fadeInRight animated",
        timeout: timeout || 4000
    });
}

function showSuccessBox(title, content, timeout) {
    $.smallBox({
        title: title,
        content: "<i class='fa fa-check'></i>  <i> " + content + "</i>",
        color: "#659265",
        iconSmall: "fa fa-check fa-2x fadeInRight animated",
        timeout: timeout || 4000
    });
    return false;
}

function htmlEncode(str) {
    str = str.replace(/&/g, '&amp;');
    str = str.replace(/"/g, "&quot;");
    str = str.replace(/</g, '&lt;');
    str = str.replace(/>/g, '&gt;');
    return str;
}

function replaceQuotes(str) {
    if (str === null)
        return;

    return str.replace(/'/g, "\\'").replace(/"/g, '&quot;');
}

function replaceEncodedTicks(str) {
    var s = str.replace(/\\u0027/g, "'");
    s = s.replace(/\\u0026/g, "&");
    return s;
}

Date.prototype.formatMMDDYYYY = function () {
    return (this.getMonth() + 1) +
        "/" + this.getDate() +
        "/" + this.getFullYear();
};

Date.prototype.stdTimezoneOffset = function () {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);
    return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
};

Date.prototype.dst = function () {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
};

function htmlDecode(input) {
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

function rebindAjaxGrid(id) {
    if (document.getElementById(id)) {
       $("#" + id).data('kendoGrid').dataSource.read();
    }
}

function rebindKendoMultiSelect(id) {
    if (document.getElementById(id)) {
        $("#" + id).data('kendoMultiSelect').dataSource.read();
    }
}
function startGridBinding(id) {
    $("#" + id).data('kendoGrid').dataSource.read();
}
function displayUrlInModal(url, containerId) {
    if (containerId == null) {
        containerId = "action-modal-content-wrapper";
    }
    $('#action-modal').modal('show');
    jQuery.ajax({
        url: url,
        type: "GET",
        success: function (data) {
            $('#' + containerId).html(data);
        }
    });
}

function displayActionInModal(url, containerId) {
    displayUrlInModal(url, containerId);
}

function displayActionInCustomModal(url,id) {
    var modalId = "action-modal-" + id;
    var wrapperId = "action-modal-content-wrapper-" + id;
    $('#' + modalId).modal('show');
    jQuery.ajax({
        url: url,
        type: "GET",
        success: function (data) {
            $('#' + wrapperId).html(data);
        }
    });
}
function disableSubmitButton() {
    var id = jQuery(this).closest("form").attr("id");
    jQuery("#" + id).find(':submit').prop('disabled', true);
    jQuery("#" + id).find('.submit-btn').prop('disabled', true);
}
function enableSubmitButton(ref) {
    var id = jQuery(ref).attr("id");
    jQuery("#" + id).find(':submit').prop('disabled', false);
    jQuery("#" + id).find('.submit-btn').prop('disabled', false);
}

function closeModalDialog(id) {
    $('#' + id).modal('toggle');
}
jQuery(document).ready(function() {
    $("body").on("hidden.bs.modal", ".action-modal", function() {
        $(this).removeData('bs.modal');
        $(".action-modal .modal-dialog .modal-content").empty();
    });
});
function showToastrMessage(type, title, message, position) {
    toastr.options = {
        "closeButton": false,
        "debug": false,
        "newestOnTop": false,
        "progressBar": false,
        "positionClass": position || "toast-top-right",
        "preventDuplicates": false,
        "onclick": null,
        "showDuration": "300",
        "hideDuration": "1000",
        "timeOut": "3000",
        "extendedTimeOut": "1000",
        "showEasing": "swing",
        "hideEasing": "linear",
        "showMethod": "fadeIn",
        "hideMethod": "fadeOut"
    }

    toastr[type](message, title);
}

function showSuccessToastr() {
    return showToastrMessage('success', 'Success!', 'Save Successful.');
}

function showCustomSuccessToastr(title, content) {
    return showToastrMessage('success',title, content);
}
function showSuccessDeleteToastr() {
    return showToastrMessage('success', 'Success!', 'Delete Successful.');
}

function activeKendoTabName(tabId) {
    var id = jQuery("#" + tabId).first("ul").find(".k-state-active").attr("customId");
    return id;
}

function onKendoTabLoad(tabId) {
    var tabstrip = $("#" + tabId).data("kendoTabStrip");
    var index = jQuery.cookie(tabId);
    if (typeof index === 'undefined') {
        index = 0;
    };
    var myTab = tabstrip.tabGroup.children("li").eq(index);
    tabstrip.select(myTab);
}

function trySelectTabByIndex(tabId,index) {
    var t = $("#" + tabId).data("kendoTabStrip");

    if (t != null) {
        /*var myTab = t.tabGroup.children("li").eq(index);
        t.select(myTab);
        rebindActiveKendoTabStrip(tabId);*/

        /*var tab = $("#" + tabId).data("kendoTabStrip").select(index);
        jQuery(tab).trigger("click");*/
    }
}
function rebindActiveKendoTabStrip(tabId) {
    var tab = $("#" + tabId).data("kendoTabStrip").select();
    jQuery(tab).trigger("change");
}
function getUsingAjax(url,containerId) {
    jQuery.ajax({
        url: url,
        type: "GET",
        success: function (data) {
            jQuery("#" + containerId).html(data);
        }
    });
}
function toBoolean(val) {
    if (val == null) {
        return false;
    }
    switch (val.toLowerCase().trim()) {
        case "true": case "yes": case "1": return true;
        case "false": case "no": case "0": case null: return false;
        default: return false;
    }
}
function enableSubmitButtonByContainer(containerId) {
    var btn = jQuery("#" + containerId).find('.submit-btn');
    jQuery.each(btn, function (key, val) {
        jQuery(val).prop('disabled', false);
        var text = jQuery(val).attr("oldText");
        jQuery(val).html(text);
    });
}

function disableSubmitButtonByContainer(containerId) {
    var btn = jQuery("#" + containerId).find('.submit-btn');
    jQuery.each(btn, function (key, val) {
        jQuery(val).prop('disabled', true);
        var oldText = jQuery(val).text();
        jQuery(val).attr("oldText", oldText);
        jQuery(val).html('<i class="fa fa-gear fa-spin"></i>&nbsp;Saving');
    });

}
function disableSendButtonByContainer(containerId) {
    var btn = jQuery("#" + containerId).find('.submit-btn');
    jQuery.each(btn, function (key, val) {
        jQuery(val).prop('disabled', true);
        var oldText = jQuery(val).text();
        jQuery(val).attr("oldText", oldText);
        jQuery(val).html('<i class="fa fa-gear fa-spin"></i>&nbsp;Sending');
    });

}
function removeCookieById(cookieId) {
    var val = $.removeCookie(cookieId, { path: '/' });
}

function filterKendoGrid(gridId, filter, v) {
    var grid = $("#" + gridId).data("kendoGrid").dataSource;
    if (v) {
        grid.filter(filter);
    } else {
        grid.filter({});
    }
}
function startJarvisWidget(id) {
    $('#' + id).jarvisWidgets({
        grid: 'article',
        widgets: '.jarviswidget',
        localStorage: true,
        sortable: false,
        hidden: false,
        buttonsHidden: false,
        toggleButton: true,
        toggleClass: 'fa fa-minus | fa fa-plus',
        toggleSpeed: 100,
        onToggle: function () {
        },
        deleteButton: false,
        deleteClass: 'fa fa-times',
        deleteSpeed: 200,
        onDelete: function () {
        },
        editButton: false,
        editPlaceholder: '.jarviswidget-editbox',
        editClass: 'fa fa-cog | fa fa-save',
        editSpeed: 200,
        onEdit: function () {
        },
        colorButton: false,
        fullscreenButton: false,
        fullscreenClass: 'fa fa-expand | fa fa-compress',
        fullscreenDiff: 3,
        onFullscreen: function () {
        },
        customButton: false,
        customClass: 'folder-10 | next-10',
        customStart: function () {
        },
        customEnd: function () {
        },
        // order
        buttonOrder: '%refresh% %custom% %edit% %toggle% %fullscreen% %delete%',
        opacity: 1.0,
        /* dragHandle: '> header',*/
        /*placeholderClass: 'jarviswidget-placeholder',*/
        indicator: false,
        indicatorTime: 600,
        ajax: false,
        timestampPlaceholder: '.jarviswidget-timestamp',
        timestampFormat: 'Last update: %m%/%d%/%y% %h%:%i%:%s%',
        refreshButton: true,
        refreshButtonClass: 'fa fa-refresh',
        labelError: 'Sorry but there was a error:',
        labelUpdated: 'Last Update:',
        labelRefresh: 'Refresh',
        labelDelete: 'Delete widget:',
        afterLoad: function () {

        },
        rtl: false, // best not to toggle this!
        onChange: function () {

        },
        onSave: function () {

        },
        ajaxnav: $.navAsAjax // declears how the localstorage should be saved (HTML or AJAX page)

    });
}
function openPanel(id) {
    var $this = $("#" + id).find(".panel-heading").first().find(".clickable").first();
    if (!$this.hasClass('panel-collapsed')) {
    } else {
        $this.parent().parent().parent().find('.panel-body').first().slideDown();
        $this.removeClass('panel-collapsed');
        $this.find('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
    }
}
var entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": "\\'",
    "/": '&#x2F;'
};

function escapeHtml(string) {
    return String(string)
        .replace(/[&<>"'\/]/g,
            function(s) {
                return entityMap[s];
            });
}
var entityMapWithEmpty = {
    "&": "",
    "<": "",
    ">": "",
    '"': '',
    "'": "",
    "/": ';'
};

function escapeHtmlWithEmpty(string) {
    return String(string)
        .replace(/[&<>"'\/]/g,
            function (s) {
                return entityMapWithEmpty[s];
            });
}

function submitNonAjaxForm(formId) {
    var form = jQuery("#" + formId);
    if (form.valid()) {
        var btn = jQuery(document).find('.submit-btn');
        jQuery.each(btn, function(key, val) {
            jQuery(val).prop('disabled', true);
            var oldText = jQuery(val).text();
            jQuery(val).attr("oldText", oldText);
            jQuery(val).html('<i class="fa fa-gear fa-spin"></i>&nbsp;' + oldText);
        });
        form.submit();
    } else {
        showRedWarningBox("Validation Error", " Please make sure all required fields are filled out correctly!");
    }
}

var entityMapJsFunction = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": "\\'",
    "/": '&#x2F;'
};

function escapeJsFunctionHtml(string) {
    return String(string)
        .replace(/[&<>"'\/]/g,
            function (s) {
                return entityMapJsFunction[s];
            });
}
function disableButtonByClass(buttonClass) {
    var btn = jQuery(document).find('.' + buttonClass);
    jQuery.each(btn, function (key, val) {
        jQuery(val).prop('disabled', true);
        var oldText = jQuery(val).text();
        jQuery(val).attr("oldText", oldText);
        jQuery(val).html('<i class="fa fa-gear fa-spin"></i>&nbsp;' + oldText);
    });
}
function enableButtonByClass(buttonClass) {
    var btn = jQuery(document).find('.' + buttonClass);
    jQuery.each(btn, function (key, val) {
        jQuery(val).prop('disabled', false);
        var text = jQuery(val).attr("oldText");
        jQuery(val).html(text);
    });
}
function saveStateToCookie(gridId,state,minutes) {
    if (state) {
        var expirationDateTime = new Date();
        var expirationMinutes = minutes;
        expirationDateTime.setTime(expirationDateTime.getTime() + (expirationMinutes * 60 * 1000));
        state.dataSource.filter = null;
        $.cookie("state-" + gridId, gridId, { expires: expirationDateTime });
        localStorage[gridId] = kendo.stringify(state);
    }
}

function getSaveState(gridId) {
    var cookieVal = $.cookie("state-" + gridId);
    if (cookieVal) {
        var options = localStorage[gridId];
        if (options) {
            return JSON.parse(options);
        }
    }
    return null;
}

function clearStorageDataByName(name) {
    var pairs = document.cookie.split(";");
    var cookies = [];
    for (var i = 0; i < pairs.length; i++) {
        var pair = pairs[i].split("=");
        var cookieName = pair[0];
        if (cookieName.indexOf(name) > -1) {
            cookies.push(pair[0]);
        }
    }
    for (var i = 0; i < cookies.length; i++) {
        document.cookie = cookies[i] + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
    }
    for (var key in localStorage) {
        if (key.indexOf(name) > -1) {
            localStorage.removeItem(key);
        }
    }
    location.reload();
}
function getKendoTreeViewCheckedItems(id) {
    var result = [];
    if (document.getElementById(id)) {
        var treeView = jQuery("#" + id).data("kendoTreeView");
        if (treeView) {
            result = treeView.getCheckedItems();
        }
    }
    return result;
    
}
function rebindKendoDropdown(id) {
    var elem = $('#' + id).data('kendoDropDownList');
    if (elem) {
        elem.dataSource.read();
    }
}
function rebindKendoComboBox(id) {
    var elem = $('#' + id).data('kendoComboBox');
    if (elem) {
        elem.dataSource.read();
    }
}
function setFocus(id) {
    jQuery("#" + id).focus();
}

function setFocusWithTimeOut(id, time) {
    setTimeout(function () { setFocus(id); }, time);
}

function loadUsingAjax(url, containerId, showloader) {
    jQuery.ajax({
        url: url,
        type: "GET",
        beforeSend: function () {
            if (showloader) {
                jQuery("#" + containerId).html('<div class="k-loading-image"></div>');
            }
        },
        success: function (data) {
            jQuery("#" + containerId).html(data);
        }
    });
}

function saveToCookie(cookieId, val, minutes) {
    var date = new Date();
    date.setTime(date.getTime() + (minutes * 60 * 1000));
    $.cookie(cookieId, val, { expires: date, path: '/' });
}
function getCookieValue(cookieId) {
    var data = $.cookie(cookieId);
    if (data == null) {
        return null;
    }
    return data;
}
function getCookieArray(cookieId) {
    var data = $.cookie(cookieId);
    if (data == null) {
        return [];
    }
    var arr = JSON.parse(data);
    return arr;
}
function getCookieBoolean(cookieId) {
    var data = $.cookie(cookieId);
    if (data == null) {
        return false;
    }
    var val = JSON.parse(data);
    return toBoolean(val);
}
(function ($) {
    $.fn.focusTextToEnd = function () {
        this.focus();
        var $thisVal = this.val();
        this.val('').val($thisVal);
        return this;
    }
}(jQuery));
function refreshKendoTabWithGrid(containerId, gridId, url) {
    var container = $("#" + containerId);
    var hasClass = container.hasClass("loaded");
    container.addClass("loaded");
    if (hasClass) {
        rebindAjaxGrid(gridId);
    } else {
        $.ajax({
            url: url,
            type: "GET",
            success: function (data) {
                container.html(data);
                container.addClass("loaded");
            }
        });
    }
}
function refreshKendoTabWithTab(containerId, tabId, url) {
    var container = $("#" + containerId);
    if (container.hasClass("loaded")) {
        rebindActiveKendoTabStrip(tabId);
    } else {
        $.ajax({
            url: url,
            type: "GET",
            success: function (data) {
                container.html(data);
                container.addClass("loaded");
            }
        });
    }
}
function refreshKendoTabWithForm(containerId, url) {
    var container = $("#" + containerId);
    $.ajax({
        url: url,
        type: "GET",
        success: function (data) {
            container.html(data);
        }
    });
}
function initiatePopOver() {
    $("[rel=popover]").popover().popover({
        html: true
    });
    // activate popovers with hover states
    $("[rel=popover-hover]").popover({
        trigger: "hover",
        html:true
    });
    if ($("[rel=tooltip]").length) {
        $("[rel=tooltip]").tooltip();
    }
}
function getKendoMultiSelectAsString(id) {
    var val = jQuery("#" + id).val();
    if (val == null || val == '') {
        return '';
    } else {
        return val.join();
    }
}



;

const DESKTOP_EXPERIENCE_MIN_VIEWPORT_WIDTH = 980;
const FULLCALENDAR_MAX_RESULTS = 3000;

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js?_=v20200133')
        //.then(reg => console.log('service worker registered'))
        .catch(err => console.log('service worker not registered', err));

    navigator.serviceWorker.addEventListener('message', event => {
        // Not sure we are going to need to use this, but messages can be sent from the service worker to do things since it has no direct access to the DOM

        // console.log("got message!");
        // console.log(event);
    });
}

// Add event listeners for offline & online indicators
window.addEventListener('offline', evt => {
    //WP.showOfflineIndicator("offline");
    //WP.setState("offLine", true);
    // Kill off the online check
    window.online_check_dfd && window.online_check_dfd.reject();
});

window.addEventListener('online', evt => {
    // Try to connect
    //WP.showOfflineIndicator("trying");

    // pseudo-recursive function.  Will keep polling until we have either rejected because of going back offline (above)
    // or we receive a 200 back.
    var tryConnection = function (dfd) {
        if (dfd == null)
            dfd = window.online_check_dfd = new $.Deferred();

        $.ajax({
            url: "/xmlRequests/keepalive.cfm?_=" + ((new Date()).getTime()),
            timeout: 30000
        })
            .done(function () {
                window.online_check_dfd.resolve();
            })
            .fail(function (jqXHR, textStatus, errorThrown) {
                // If we have not resolved our online check deferred.
                if (window.online_check_dfd.state() == "pending") {
                    // only if we got a timeout back, we want to try the connection again.
                    // console.log(textStatus + " | " + errorThrown);
                    if (errorThrown == "timeout")
                        tryConnection(dfd);
                    else
                        window.online_check_dfd.reject();
                }
                else {
                    // clean up the check deferred, as we have either gone back offline or we are good.
                    delete window.online_check_dfd;
                }
            });

        return dfd;
    };

    tryConnection().done(function () {
        //WP.showOfflineIndicator("online");
        //WP.setState("offLine", false);
        delete window.online_check_dfd;
    })
        .fail(function () {
            // We should only get here if we manually failed the online_check,
            // meaning we didn't get a timeout, so there was some other sort of problem.
            //WP.showOfflineIndicator("error");
            //WP.setState("offLine", false);
            delete window.online_check_dfd;
        });

});


let InventoriedResourceHeper = function ($checkbox, treeview, saveQty) {
    let $node = $checkbox.closest('.k-item').children('div').eq(0);
    let $full_item = $node.children(0);
    let $quantity_input = $('input.quantity-input', $full_item);
    let $save_quantity_button = $('.save-quantity-button', $full_item);
    let $checkbox_wrapper = $('.k-checkbox-wrapper', $full_item);
    let $switch = $('.k-switch', $checkbox_wrapper);
    let item_id = $save_quantity_button.attr("data-item-id");
    let item_uid = $save_quantity_button.attr("data-item-uid");
    let methods = {};
    let kendo_switch_instance = $checkbox.data("kendoSwitch");

    let treeId = treeview.wrapper[0].id;
    let data = treeview.dataItem($node[0]);

    methods = {
        setupTooltip: function () {
            $checkbox_wrapper.kendoTooltip({
                position: "top",
                width: 250,
                content: "To add this inventoried resource, enter a quantity in the field to the right and click Save."
            });
        },

        destroyTooltip: function () {
            if ($checkbox_wrapper.data("kendoTooltip"))
                $checkbox_wrapper.kendoTooltip('destroy');
        },

        onCheckboxUncheck: function () {
            $quantity_input.val("");
            kendo_switch_instance.enable(false);
            removeItemFromSchedule(treeview.findByUid(data.uid), data, treeId);
            methods.setupTooltip();
        }
    };

    // Set up the event listeners
    $checkbox.on("change", function (e) {
        if ($checkbox.prop("checked")) {
            methods.destroyTooltip();
        }
    });

    $save_quantity_button.on("click", function (e) {
        let quantity = $quantity_input.val();
        saveQty(this, item_id, false, quantity, item_uid).done(function () {
            // If we have non-zero quantity here, check the switch and enable
            if (quantity != 0) {
                kendo_switch_instance.check(true);
                kendo_switch_instance.enable(true);
                methods.destroyTooltip();
            }
            else {
                kendo_switch_instance.check(false);
                methods.onCheckboxUncheck();
            }
        });
    });

    // Set the initial state
    if (!$checkbox.prop("checked"))
        methods.setupTooltip();

    return methods;
};

let PdfViewer = function () {
    let pdf_file_match = /.*\.pdf$/i;

    let methods = {
        init: function () {
            let self = this;
            // Set up listener for any link that is a pdf
            $("body", document).on("click", "a", function (e) {
                let $this = $(this);
                let baseUrl = this.href.split("?")[0];
                let downloadAttr = $this.attr("download");
                let isDownload = (typeof downloadAttr !== 'undefined' && downloadAttr !== false);
                // debugger;
                // Inspect the href, if it's a pdf, load up in the viewer
                // Inspect the href, if it's a pdf, load up in the viewer
                if (isDownload == false && ($this.hasClass("opens-pdf") || pdf_file_match.test(baseUrl))) {
                    let fileName = $this.attr("data-pdf-title") || $this.text().replace(/\.pdf$/i, "");
                    e.preventDefault();

                    var isApp = navigator.userAgent.toLowerCase().indexOf('canvas') > -1;

                    const HOSTED_VIEWER_ORIGINS = ["null", "http://espace.blob.core.windows.net", "https://espace.blob.core.windows.net"];
                    var viewerOrigin = new URL(this.href).origin || "null";

                    if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin) && isApp == false) {
                        // Open the PDF in our viewer
                        self.viewPdf(this.href, fileName);
                    }
                    else {
                        if (isApp == true) {
                            // Open the file and let the native app handle the PDF
                            window.open(this.href);
                        }
                        else {
                            // Open a new window with the PDF to avoid 
                            window.open(this.href, "_blank");
                        }
                    }
                }
                // Otherwise, let it walk like a duck
                return;
            });
            return this;
        },
        viewPdf: function (url, name) {

            var name = name == null ? url.replace(/\.pdf$/i, "") : name;
            let urlNoPDF = url.replace(/\.pdf$/i, "");
            window.location = "/public/viewPDF?fileName=" + encodeURIComponent(name) + "&fileUrl=" + encodeURIComponent(urlNoPDF);
            // window.open("/public/viewPDF?fileName=" + encodeURIComponent(name) + "&fileUrl=" + encodeURIComponent(url), "_blank");
        }
    };
    return methods;
};
// Initialize the pdf viewer to hijack links only on mobile...
var isMobile = false; //initiate as false
// device detection
if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
    || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4))) {
    isMobile = true;
}
//if (isMobile) {
window.pdfViewer = (new PdfViewer()).init();
//}

function setupInventoriedResourceHelpers(tree_id, saveQty) {
    let treeview = $("#" + tree_id).data('kendoTreeView');
    console.log(treeview);
    $("#" + tree_id + " input.inventoried-item-checkbox").each(function () {
        let $this = $(this);
        console.log($this);
        if (!$this.data('inventoriedResourceHelper'))
            $this.data('inventoriedResourceHelper', new InventoriedResourceHeper($this, treeview, saveQty));
    });
}

function renderCheckboxesAsSwitches(treeviewCascade) {
    let render_dfd = new $.Deferred();
    window.setTimeout(function () {
        renderCheckboxesAsSwitchesNow(treeviewCascade);
    }, 0);
    window.setTimeout(function () {
        renderCheckboxesAsSwitchesNow(treeviewCascade);
        render_dfd.resolve();
    }, 1000);
    return render_dfd;
}

function renderCheckboxesAsSwitchesNow(treeviewCascade) {
    $('input[type="checkbox"]:not([data-role="switch"]):not(.always-hidden)').off('change.switch').on('change.switch', function (e) {
        var checked = $(e.target).is(':checked');
        $(e.target).data('kendoSwitch').check(checked);
    });
    $('label>input[type="checkbox"]:not([data-role="switch"]):not(.always-hidden)').on('click', function (e) {
        return false;
    });
    if (treeviewCascade) {
        $('input[type="checkbox"]:not([data-role="switch"]):not(.always-hidden)').on('change', function (e) {
            var checked = $(e.target).is(':checked');
            $(e.target).closest('div').next().find('span:not(.k-state-disabled)>input[type="checkbox"]').each(function () {
                $(this).data('kendoSwitch').check(checked);
            });
        });
    }
    $('input[type="checkbox"]:not([data-role="switch"]):not(.always-hidden)').kendoSwitch({
        change: function (e) {
            $(e.sender.element[0]).trigger('change');
        }
    });
}

jQuery.fn.extend({
    propChecked: function (chk) {
        return this.each(function () {
            this.checked = chk;
            $(this).trigger('change.switch');
            var ksw = $(this).data('kendoSwitch');
            if (ksw && ksw.element.attr('isdisabled') != 'true') {
                ksw.check(chk);
            }
        });
    }
});
jQuery.fn.extend({
    propDisabled: function (disabled) {
        return this.each(function () {
            $(this).attr("disabled", "disabled");
            $(this).trigger('change.switch');
        });

    }
});

function HidePagerIfOnePage(e) {
    if (e.sender.dataSource.total() <= e.sender.dataSource.pageSize()) {
        e.sender.pager.element.hide();
    } else {
        e.sender.pager.element.show();
    }
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, '\\$&');
    var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, ' '));
}

function StringIsUrl(str) {
    return str.toLowerCase().substring(0, 4) === 'http';
}

function GetOffsiteLabel(str) {
    //return StringIsUrl(str) ? "Virtual Meeting Link" : "Offsite Location";
    return "Offsite Location";
}

function GetOffsiteLabelStub(str) {
    //return StringIsUrl(str) ? "VIRTUAL" : "OFFSITE";
    return "Offsite";
}

jQuery.expr.filters.offscreenRight = function (el) {
    var rect = el.getBoundingClientRect();
    return rect.x + rect.width > window.innerWidth;
};

jQuery.expr.filters.offscreenBottom = function (el) {
    var rect = el.getBoundingClientRect();
    return rect.y + rect.height > window.innerHeight;
};

function initSelectionQuickGlance(treeId, narrowView) {
    if ($('#' + treeId + '.k-treeview div#quick-glance-' + treeId).length == 0) {
        if (narrowView || $(window).width() < DESKTOP_EXPERIENCE_MIN_VIEWPORT_WIDTH) {
            $('#' + treeId + 'k-treeview>ul').css('float', 'left');
            let el = '<div style="float: left; padding: 10px; width: 100%;">';
            el += '<div id="quick-glance-header-' + treeId + '"><a style="padding: 4px;display: block;cursor: pointer;" class="" onclick="expandCollapseQuickGlance(\'' + treeId + '\');"></a></div>';
            el += '<div style="display: none" id="quick-glance-' + treeId + '"></div>';
            el += '</div><div style="display: none" id="quick-glance-label-' + treeId + '">Show Selected</div>';
            $('#' + treeId + '.k-treeview').prepend(el);
        } else {
            $('#' + treeId + ' .k-group.k-treeview-lines').append('<div style="position: absolute; right: 10px; top: 10px; padding: 10px;" id="quick-glance-' + treeId + '"></div>');
        }
    }
}
function renderSelectionQuickGlance(treeId, prependLocationCode) {
    let selectedNodes = getQuickGlanceSelectedNodes(treeId);
    let allowRemoveAll = true;
    let htmlString = '';
    let children = '';
    let grandchildren = '';

    if (countQuickGlanceVisibleNodes(treeId) < 3) {
        $('#quick-glance-' + treeId).html('');
        return;
    }

    for (var i = 0; i < selectedNodes.length; i++) {
        let anchorTag = '<a style="margin-right: 10px;" class="k-button btn-sm mobile-padded btn-delete" title="Remove" onclick="deselectQuickGlance(\'' + treeId + '\',' + selectedNodes[i].ItemId + ',' + selectedNodes[i].ParentId + '); renderSelectionQuickGlance(\'' + treeId + '\', ' + prependLocationCode + ');"><i class="fa fa-trash"></i></a>';
        if (selectedNodes[i].DisableUpdate) {
            anchorTag = '<a style="margin-right: 10px;" class="k-button btn-sm mobile-padded btn-disabled" title="Required"><i class="fa fa-lock"></i></a>';
            allowRemoveAll = false;
        }
        const name = getNameForItem(selectedNodes[i], prependLocationCode);
        if (children.indexOf(',' + selectedNodes[i].ItemId + ',') >= 0) {
            if (selectedNodes[i].ChildrenIds !== null && selectedNodes[i].ChildrenIds.length > 0) {
                htmlString += '<div style="margin-bottom: 3px;">' + anchorTag + '<div title="' + name + '" style="display:inline;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;">- ' + name + '</div> <span style="color:#ccc;">(Parent)</span></div>';
                grandchildren = ',' + selectedNodes[i].ChildrenIds + ',';
            } else {
                htmlString += '<div style="margin-bottom: 3px;">' + anchorTag + '<div title="' + name + '" style="display:inline;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;">- ' + name + '</div></div>';
            }
        }
        else {
            if (selectedNodes[i].ChildrenIds !== null && selectedNodes[i].ChildrenIds.length > 0) {
                htmlString += '<div style="margin-bottom: 3px;">' + anchorTag + '<div title="' + name + '" style="display:inline;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;">' + name + '</div> <span style="color:#ccc;">(Parent)</span></div>';
                children = ',' + selectedNodes[i].ChildrenIds + ',';
            } else {
                htmlString += '<div style="margin-bottom: 3px;">' + anchorTag + '<div title="' + name + '" style="display:inline;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;">' + ((grandchildren.indexOf(',' + selectedNodes[i].ItemId + ',') >= 0) ? '-- ' : '') + name + '</div></div>';
            }
        }
    }
    const $header = $('#quick-glance-header-' + treeId + '>a');
    if ($header.length) {
        $header.html($('#quick-glance-label-' + treeId).html() + ' (' + selectedNodes.length + ')');
    }
    if (htmlString !== '' && allowRemoveAll) {
        htmlString = '<div><a title="Remove All" style="padding: 4px;display: block;cursor: pointer;" onclick="deselectAllQuickGlance(\'' + treeId + '\'); renderSelectionQuickGlance(\'' + treeId + '\', ' + prependLocationCode + ');">Remove All</a></div>' + htmlString;
    }
    else if ($header.length) {
        htmlString = '<div style="width: calc(100% - 35px); border: 1px solid gray; color: gray; padding: 10px; text-align: center;">No selections.</div>';
    }
    $('#quick-glance-' + treeId).html(htmlString);
}
function getNameForItem(node, prependLocationCode) {
    return (prependLocationCode && node.LocCode != null && node.LocCode.length > 0) ? node.LocCode + ' - ' + node.Name : node.Name;
}
function deselectQuickGlance(treeId, itemId, parentId) {
    $('#' + treeId + ' .k-checkbox-wrapper span:not(.k-state-disabled)>input[value="' + itemId + '"]').prop("checked", false).trigger("change");
    $('#' + treeId + ' .k-checkbox-wrapper span:not(.k-state-disabled)>input[value="' + itemId + '"]').propChecked(false);
    if (parentId) {
        $('#' + treeId + ' .k-checkbox-wrapper span:not(.k-state-disabled)>input[value="' + parentId + '"]').propChecked(false);
        var treeview = $("#" + treeId).data("kendoTreeView");
        treeview.dataItem($('#' + treeId + ' .k-checkbox-wrapper span:not(.k-state-disabled)>input[value="' + parentId + '"]')[0]).checked = false;
    }
}
function deselectAllQuickGlance(treeId) {
    $('#' + treeId + ' .k-checkbox-wrapper span:not(.k-state-disabled)>input[type="checkbox"]').prop("checked", false).trigger("change");
    $('#' + treeId + ' .k-checkbox-wrapper span:not(.k-state-disabled)>input[type="checkbox"]').propChecked(false);
    if (typeof deselectAllCallback === 'function') {
        deselectAllCallback(treeId);
    }
}
function expandCollapseQuickGlance(treeId) {
    const $quickGlance = $('#quick-glance-' + treeId);
    if ($quickGlance.css('display') == 'none') {
        $quickGlance.slideDown(150);
        $('#quick-glance-label-' + treeId).html('Hide Selected');
    }
    else {
        $quickGlance.slideUp(150);
        $('#quick-glance-label-' + treeId).html('Show Selected');
    }
    let selectedNodes = getQuickGlanceSelectedNodes(treeId);
    $('#quick-glance-header-' + treeId + '>a').html($('#quick-glance-label-' + treeId).html() + ' (' + selectedNodes.length + ')');
}
function getQuickGlanceSelectedNodes(treeId) {
    const treeView = $("#" + treeId).data("kendoTreeView");
    let selectedNodes = [];
    function buildSelectedNodesRecursive(nodes, selectedNodes) {
        for (var i = 0; i < nodes.length; i++) {
            if (nodes[i].checked) {
                selectedNodes.push(nodes[i]);
            }
            if (nodes[i].hasChildren) {
                buildSelectedNodesRecursive(nodes[i].children.view(), selectedNodes);
            }
        }
    }
    buildSelectedNodesRecursive(treeView.dataSource.view(), selectedNodes);
    return selectedNodes;
}
function countQuickGlanceVisibleNodes(treeId) {
    const treeView = $("#" + treeId).data("kendoTreeView");
    let visibleNodes = 0;
    function buildSelectedNodesRecursive(nodes) {
        for (var i = 0; i < nodes.length; i++) {
            visibleNodes++;
            if (nodes[i].hasChildren && nodes[i].expanded) {
                buildSelectedNodesRecursive(nodes[i].children.view());
            }
        }
    }
    buildSelectedNodesRecursive(treeView.dataSource.view());
    return visibleNodes;
}
function expandSwitchChildrenIfChecked(e, tree) {
    if (e) {
        var treeId = tree.wrapper[0].id;
        var treeview = $("#" + treeId).data("kendoTreeView");
        var data = treeview.dataItem(e.node);
        if (data.checked && data.hasChildren && !data.expanded) {
            treeview.expand(treeview.findByUid(data.uid));
        }
    }
}
function bindGridStandardEvents() {
    $('.k-grid.grid-standard .k-table-tbody tr.k-table-row').off('mouseenter.grid-standard');
    $('.k-grid.grid-standard .k-table-tbody tr.k-table-row').on('mouseenter.grid-standard', function () {
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row:nth-of-type(' + (this.rowIndex + 1) + ')').css('background-color', '#eee');
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row:nth-of-type(' + (this.rowIndex + 1) + ') .actions-button').css('color', '#555');
    });
    $('.k-grid.grid-standard .k-table-tbody tr.k-table-row').off('mouseleave.grid-standard');
    $('.k-grid.grid-standard .k-table-tbody tr.k-table-row').on('mouseleave.grid-standard', function () {
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row:nth-of-type(' + (this.rowIndex + 1) + ')').css('background-color', 'inherit');
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row:nth-of-type(' + (this.rowIndex + 1) + ') .actions-button').css('color', 'transparent');
    });
    $('.k-grid.grid-standard td.action-cell').off('click.grid-standard');
    $('.k-grid.grid-standard td.action-cell').on('click.grid-standard', function (e) {
        var $ix = $('.k-grid.grid-standard td.action-cell').index(this);
        var rct = $('.actions-button:eq(' + $ix + ')')[0].getBoundingClientRect();
        var alreadyVisible = $('.actions-container-gs:eq(' + $ix + ')').is(':visible');
        $('.actions-container-gs:eq(' + $ix + ')').css('top', rct.top + 27);
        $('.actions-container-gs:eq(' + $ix + ')').css('left', rct.left);
        $('.actions-container-gs').not(':eq(' + $ix + ')').fadeOut(100);
        $('.actions-container-gs:eq(' + $ix + ')').fadeToggle(100);
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row .actions-button i').css('color', 'inherit');
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row .actions-button').css('background-color', 'inherit');
        if (!alreadyVisible) {
            $('.k-grid.grid-standard .k-table-tbody tr.k-table-row .actions-button i:eq(' + $ix + ')').css('color', '#333');
            $('.k-grid.grid-standard .k-table-tbody tr.k-table-row .actions-button:eq(' + $ix + ')').css('background-color', '#ddd');
        }
        e.stopPropagation();
    });
}

function initializeGridStandardEvents() {
    function deselectAction() {
        $('.actions-container-gs').fadeOut(100);
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row .actions-button i').css('color', 'inherit');
        $('.k-grid.grid-standard .k-table-tbody tr.k-table-row .actions-button').css('background-color', 'inherit');
    }

    $(document).on('click', function () {
        deselectAction();
    });

    bindGridStandardEvents();

    var grid = $("#treelist").data("kendoTreeList");
    var pageSizesDdl = $(grid.pager.element).find("[data-role='dropdownlist']").data("kendoDropDownList");
    pageSizesDdl.bind("change", function (e) {
        bindGridStandardEvents();
    });

    $('.grid-standard .k-auto-scrollable').on('scroll', function () {
        var $ix = $('.actions-container-gs').index($('.actions-container-gs:visible'));
        var rct = $('.actions-button:eq(' + $ix + ')')[0].getBoundingClientRect();
        var rctMin = $(this).closest('.grid-standard')[0].getBoundingClientRect();
        var rctMax = $(this).closest('.grid-standard').find('.k-grid-pager')[0].getBoundingClientRect();
        if (rct.top < rctMin.top || rct.top > rctMax.top) {
            deselectAction();
        }
        else {
            $('.actions-container-gs:eq(' + $ix + ')').css('top', rct.top + 27);
            $('.actions-container-gs:eq(' + $ix + ')').css('left', rct.left);
        }
    });

    var $otherButtons = $('.other-buttons');
    var $openOtherButtons = $('.other-buttons-arrow');

    $openOtherButtons.on('click', function () {
        $otherButtons.fadeToggle(100);
        document.activeElement.blur();
    });

    $(document).on('click', function (e) {
        if (!$otherButtons.is(e.target) &&
            !$otherButtons.has(e.target).length &&
            !$openOtherButtons.is(e.target) &&
            !$openOtherButtons.has(e.target).length) {
            $otherButtons.fadeOut(100);
        }
    });
}

function savePersistentTreeList(elementId, cookieName) {
    var treeList = $('#' + elementId).data("kendoTreeList");
    var ids = $.map($('#' + elementId + " .k-svg-i-caret-alt-down").closest("tr"), function (val) {
        var data = treeList.dataItem(val);
        return data.id;
    });
    var widths = $.map(treeList.columns, function (val) {
        return val.width;
    });
    var json = JSON.stringify({ ids: ids, widths: widths });
    saveToCookie(cookieName, json, 30);
}

function loadPersistentTreeList(elementId, cookieName) {
    var json = getCookieValue(cookieName);
    if (json && json != null) {
        json = JSON.parse(json);
        var treeList = $('#' + elementId).data("kendoTreeList");
        var expandedIds = json.ids;
        $.each(expandedIds, function (idx, val) {
            var dataItem = treeList.dataSource.get(val);
            if (dataItem) {
                var row = treeList.content.find("tr[data-uid=" + dataItem.uid + "]");
                treeList.expand(row);
            }
        });
        var widths = json.widths;
        for (var i = 0; i < treeList.options.columns.length; i++) {
            if (widths[i]) {
                treeList.options.columns[i].width = widths[i];
            }
        }

        //this has a bug in kendo where the headerAttributes property is not retained on the columns.
        //This didnt seem to affect much in the treeLists I was working with so I left it.
        treeList.setOptions(treeList.options);
    }
}

function columnMenuHideColumns(container, titleArray) {
    for (var i = 0; i < titleArray.length; i++) {
        container.find('li[role="menuitemcheckbox"]').each(function () {
            if ($(this).find('[title="' + titleArray[i] + '"]').length > 0) {
                $(this).addClass("hide");
            }
        });

        //different layout in mobile view
        container.find('li.k-item.k-listgroup-item').each(function () {
            if ($(this).find('.k-switch>input[type="checkbox"][title="' + titleArray[i] + '"]').length > 0) {
                $(this).addClass("hide");
            }
        });
    }
}

function columnMenuHideEmptyHeaderColumns(container) {
    columnMenuHideColumns(container, ['', ' ', 'always-hidden']);
}

function columnMenuInitDefault(e) {
    if (kendo.support.mobileOS) {
        $('.k-grid-column-menu .k-header-cancel').on('click', function (evt) {
            $('.k-grid-column-menu .k-header-done').trigger('click');
            evt.preventDefault();
        });
        $('.k-grid-column-menu .k-header-done').hide();
    }

    columnMenuHideEmptyHeaderColumns(e.container);
}

function handleLeftPanelSize() {
    const list1 = document.querySelector('aside#left-panel > nav > ul:first-child');
    const list2 = document.querySelector('aside#left-panel > nav > ul:last-child');
    if (list2 && list1 !== list2) {
        const rect1 = list1.getBoundingClientRect();
        const rect2 = list2.getBoundingClientRect();

        if (rect1.top + rect1.height > window.innerHeight - rect2.height) {
            list2.classList.remove('pull-down');
        }
        else {
            list2.classList.add('pull-down');
        }
    }
}
handleLeftPanelSize();

if (document.querySelector('aside#left-panel > nav > ul:first-child')) {
    new ResizeObserver(handleLeftPanelSize).observe(document.querySelector('aside#left-panel > nav > ul:first-child'));
}
else {
    window.setTimeout(() => {
        if (document.querySelector('aside#left-panel > nav > ul:first-child')) {
            new ResizeObserver(handleLeftPanelSize).observe(document.querySelector('aside#left-panel > nav > ul:first-child'));
        }
    }, 500);
}

function formatNumber(num, decimals) {
    const result = num.toLocaleString(undefined, {
        minimumFractionDigits: decimals,
        maximumFractionDigits: decimals,
    });
    if (result.endsWith('.00')) {
        return result.slice(0, -3);
    }
    return result;
}

function parameterizeJs(str) {
    return encodeURIComponent(str)
        .replace(/'/g, '%27')
        .replace(/"/g, '%22')
        .replace(/\\/g, '%5C')
        .replace(/\(/g, '%28')
        .replace(/\)/g, '%29')
        .replace(/</g, '%3C')
        .replace(/>/g, '%3E')
        .replace(/`/g, '%60');
}

function deParameterizeJs(encodedStr) {
    return decodeURIComponent(encodedStr
        .replace(/%27/g, "'")
        .replace(/%22/g, '"')
        .replace(/%5C/g, '\\')
        .replace(/%28/g, '(')
        .replace(/%29/g, ')')
        .replace(/%3C/g, '<')
        .replace(/%3E/g, '>')
        .replace(/%60/g, '`'));
}

function returnTrue() { return true; }

function returnFalse() { return false; }

$(function () {
    kendoSafariHack();
});

function kendoSafariHack() {
    // Safari hack for kendo dropdowns
    if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
        $('body').addClass('safari');
    }
}

function displayBinaryFile(guid, label) {
    var url = '/BinaryFile/DisplayBinaryFile?guid=' + guid + "&label=" + deParameterizeJs(label);
    displayUrlInModal(url);
}

async function thumbnailWithPreview(guid, label) {
    if (guid != null) {
        try {
            const response = await fetch('/BinaryFile/GetBinaryFileThumbnailUrl', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ guid: guid, label: label })
            });

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            if (data.isWebDisplayable) {
                return `<a class="pointer" onclick="displayBinaryFile('${data.guid}','${parameterizeJs(data.label)}')"><img class="configuration-thumbnail" alt="${data.label}" src="${data.thumbnailUrl}" /></a>`;
            } else {
                return `<a class="pointer" onclick="displayBinaryFile('${data.guid}','${data.label}')">${deParameterizeJs(data.label)}</a>`;
            }
            
        } catch (error) {
            console.error("Error fetching thumbnail:", error);
            return ""; 
        }
    }
    return "";
}

async function thumbnailWithPreviewAndLink(guid, label) {
    if (guid != null) {
        try {
            const response = await fetch('/BinaryFile/GetBinaryFileThumbnailUrl', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ guid: guid, label: label })
            });

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            if (data.isWebDisplayable) {
                return `<a class="pointer" onclick="displayBinaryFile('${data.guid}','${data.label}')"><img class="configuration-thumbnail" alt="${deParameterizeJs(data.label)}" src="${data.thumbnailUrl}" /></a><br /><a class="pointer" onclick="displayBinaryFile('${data.guid}','${data.label}')">${deParameterizeJs(data.label)}</a>`;
            }
            else {
                return `<a class="pointer" onclick="displayBinaryFile('${data.guid}','${data.label}')">${deParameterizeJs(data.label)}</a>`;
            }
            
        } catch (error) {
            console.error("Error fetching thumbnail:", error);
            return ""; 
        }
    }
    return "";
}

async function thumbnailWithLink(guid, label) {
    if (guid != null) {
        try {
            const response = await fetch('/BinaryFile/GetBinaryFileThumbnailUrl', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ guid: guid, label: label })
            });

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            const returnVariable = `<a class="pointer" onclick="displayBinaryFile('${data.guid}','${data.label}')">${deParameterizeJs(data.label)}</a>`;

            return returnVariable;
        } catch (error) {
            console.error("Error fetching thumbnail:", error);
            return ""; 
        }
    }
    return "";
};

function initializeJarvisWidget(id) {
    $('#' + id).jarvisWidgets({
        grid: 'article',
        widgets: '.jarviswidget',
        localStorage: true,
        sortable: false,
        hidden: false,
        buttonsHidden: false,
        toggleButton: true,
        toggleClass: 'fa fa-minus | fa fa-plus',
        toggleSpeed: 100,
        onToggle: function () {
        },
        deleteButton: false,
        deleteClass: 'fa fa-times',
        deleteSpeed: 200,
        onDelete: function () {
        },
        editButton: false,
        editPlaceholder: '.jarviswidget-editbox',
        editClass: 'fa fa-cog | fa fa-save',
        editSpeed: 200,
        onEdit: function () {
        },
        colorButton: false,
        fullscreenButton: false,
        fullscreenClass: 'fa fa-expand | fa fa-compress',
        fullscreenDiff: 3,
        onFullscreen: function () {
        },
        customButton: false,
        customClass: 'folder-10 | next-10',
        customStart: function () {
            alert('Hello you, this is a custom button...');
        },
        customEnd: function () {
            alert('bye, till next time...');
        },
        // order
        buttonOrder: '%refresh% %custom% %edit% %toggle% %fullscreen% %delete%',
        opacity: 1.0,
        /* dragHandle: '> header',*/
        /*placeholderClass: 'jarviswidget-placeholder',*/
        indicator: false,
        indicatorTime: 600,
        ajax: false,
        timestampPlaceholder: '.jarviswidget-timestamp',
        timestampFormat: 'Last update: %m%/%d%/%y% %h%:%i%:%s%',
        refreshButton: true,
        refreshButtonClass: 'fa fa-refresh',
        labelError: 'Sorry but there was a error:',
        labelUpdated: 'Last Update:',
        labelRefresh: 'Refresh',
        labelDelete: 'Delete widget:',
        afterLoad: function () {
            jQuery('#' + id).show();
        },
        rtl: false, // best not to toggle this!
        onChange: function () {

        },
        onSave: function () {

        },
        ajaxnav: $.navAsAjax // declears how the localstorage should be saved (HTML or AJAX page)

    });
}

function remove_data_widget_collapsed(id) {
    var obj = localStorage.getItem("jarvisWidgets_settings_eSpace-_" + id);
    var json = $.parseJSON(obj);
    if (json != null) {
        var collapsed = json.widget[0].collapsed;
        if (collapsed == 0) {
            jQuery("#" + id + "-grid").removeAttr("data-widget-collapsed");
        }
    }
};
