UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

3,014 lines 117 kB
import './kendo.popup.js';
import './kendo.data.js';
import './kendo.icons.js';
import './kendo.core.js';
import './kendo.licensing.js';
import '@progress/kendo-licensing';
import './kendo.data.odata.js';
import './kendo.data.xml.js';
import './kendo.html.icon.js';
import './kendo.html.base.js';
import '@progress/kendo-svg-icons';

const __meta__ = {
    id: "menu",
    name: "Menu",
    category: "web",
    description: "The Menu widget displays hierarchical data as a multi-level menu.",
    depends: [ "popup", "data", "data.odata" ]
};

(function($, undefined$1) {
    var kendo = window.kendo,
        ui = kendo.ui,
        activeElement = kendo._activeElement,
        touch = (kendo.support.touch && kendo.support.mobileOS),
        isArray = Array.isArray,
        HierarchicalDataSource = kendo.data.HierarchicalDataSource,
        MOUSEDOWN = "mousedown",
        CLICK = "click",
        DELAY = 30,
        SCROLLSPEED = 50,
        extend = $.extend,
        each = $.each,
        encode = kendo.htmlEncode,
        template = kendo.template,
        keys = kendo.keys,
        Widget = ui.Widget,
        excludedNodesRegExp = /^(ul|a|div)$/i,
        NS = ".kendoMenu",
        IMG = "img",
        OPEN = "open",
        MENU = "k-menu",
        LINK = "k-link k-menu-link",
        LINK_SELECTOR = ".k-link",
        ICON_SELECTOR = ".k-menu-expand-arrow",
        LAST = "k-last",
        CLOSE = "close",
        TIMER = "timer",
        FIRST = "k-first",
        IMAGE = "k-image",
        SELECT = "select",
        ZINDEX = "zIndex",
        ACTIVATE = "activate",
        DEACTIVATE = "deactivate",
        POINTERDOWN = "touchstart" + NS + " MSPointerDown" + NS + " pointerdown" + NS,
        pointers = kendo.support.pointers,
        msPointers = kendo.support.msPointers,
        allPointers = msPointers || pointers,
        CHANGE = "change",
        ERROR = "error",
        TOUCHSTART = kendo.support.touch ? "touchstart" : "",
        MOUSEENTER = pointers ? "pointerover" : (msPointers ? "MSPointerOver" : "mouseenter"),
        MOUSELEAVE = pointers ? "pointerout" : (msPointers ? "MSPointerOut" : "mouseleave"),
        MOUSEWHEEL = "DOMMouseScroll" + NS + " mousewheel" + NS,
        RESIZE = kendo.support.resize + NS,
        POPUP_ID_ATTR = "group",
        POPUP_OPENER_ATTR = "groupparent",
        DOCUMENT_ELEMENT = $(document.documentElement),
        KENDOPOPUP = "kendoPopup",
        HOVERSTATE = "k-hover",
        FOCUSEDSTATE = "k-focus",
        DISABLEDSTATE = "k-disabled",
        SELECTEDSTATE = "k-selected",
        menuSelector = ".k-menu",
        groupSelector = ".k-menu-group",
        animationContainerSelector = ".k-animation-container",
        childAnimationContainerSelector = ".k-child-animation-container",
        popupSelector = ".k-menu-popup ," + animationContainerSelector,
        allItemsSelector = ":not(.k-list) > .k-item:not([role='treeitem'])",
        disabledSelector = ".k-item.k-disabled",
        itemSelector = ".k-item",
        availableItemsSelector = ".k-item:not(.k-disabled)",
        linkSelector = ".k-item:not(.k-disabled) > .k-link",
        exclusionSelector = ":not(.k-item.k-separator):visible",
        templateSelector = "div:not(.k-animation-container,.k-list-container)",
        scrollButtonSelector = ".k-menu-scroll-button",
        touchPointerTypes = { "2": 1, "touch": 1 },
        STRING = "string",
        DATABOUND = "dataBound",
        ARIA_EXPANDED = "aria-expanded",
        ROLE = "role",

        bindings = {
            text: "dataTextField",
            url: "dataUrlField",
            spriteCssClass: "dataSpriteCssClassField",
            icon: "dataIconField",
            iconClass: "dataIconClassField",
            imageUrl: "dataImageUrlField",
            imageAttr: "dataImageAttrField",
            content: "dataContentField"
        },

        rendering = {
            wrapperCssClass: function(group, item) {
                var result = "k-item k-menu-item",
                    index = item.index;

                if (item.separator) {
                    result += " k-separator";
                }

                if (item.enabled === false) {
                    result += " k-disabled";
                }

                if (group.firstLevel && index === 0) {
                    result += " k-first";
                }

                if (index == group.length - 1) {
                    result += " k-last";
                }

                if (item.cssClass) {
                    result += " " + item.cssClass;
                }

                if (item.attr && item.attr.hasOwnProperty("class")) {
                    result += " " + item.attr["class"];
                }

                if (item.selected) {
                    result += " " + SELECTEDSTATE;
                }

                return result;
            },

            itemCssAttributes: function(item) {
                var result = "";
                var attributes = item.attr || {};

                for (var attr in attributes) {
                    if (attributes.hasOwnProperty(attr) && attr !== "class") {
                        result += attr + "=\"" + attributes[attr] + "\" ";
                    }
                }

                return result;
            },

            imageCssAttributes: function(imgAttributes) {
                var result = "";
                var attributes = imgAttributes && imgAttributes.toJSON ? imgAttributes.toJSON() : {};

                if (!attributes['class']) {
                    attributes['class'] = IMAGE;
                } else {
                    attributes['class'] += " " + IMAGE;
                }

                for (var attr in attributes) {
                    if (attributes.hasOwnProperty(attr)) {
                        result += attr + "=\"" + attributes[attr] + "\" ";
                    }
                }

                return result;
            },

            contentCssAttributes: function(item) {
                var result = "";
                var attributes = item.contentAttr || {};
                var defaultClasses = "k-content k-menu-group k-menu-group-md";

                if (!attributes['class']) {
                    attributes['class'] = defaultClasses;
                } else {
                    attributes['class'] += " " + defaultClasses;
                }

                for (var attr in attributes) {
                    if (attributes.hasOwnProperty(attr)) {
                        result += attr + "=\"" + attributes[attr] + "\" ";
                    }
                }

                return result;
            },

            textClass: function() {
                return LINK;
            },

            groupAttributes: function(group) {
                return group.expanded !== true ? `${kendo.attr("style-display")}="none"` : "";
            },

            groupCssClass: function() {
                return "k-menu-group k-menu-group-md";
            },

            groupWrapperCssClass: function() {
                return "k-menu-popup";
            },

            content: function(item) {
                return item.content ? item.content : " ";
            }
    };

    function getEffectDirection(direction, root) {
        direction = direction.split(" ")[!root + 0] || direction;
        return direction.replace("top", "up").replace("bottom", "down");
    }

    function parseDirection(direction, root, isRtl) {
        direction = direction.split(" ")[!root + 0] || direction;
        var output = { origin: ["bottom", (isRtl ? "right" : "left")], position: ["top", (isRtl ? "right" : "left")] },
            horizontal = /left|right/.test(direction);

        if (horizontal) {
            output.origin = [ "top", direction ];
            output.position[1] = kendo.directions[direction].reverse;
        } else {
            output.origin[0] = direction;
            output.position[0] = kendo.directions[direction].reverse;
        }

        output.origin = output.origin.join(" ");
        output.position = output.position.join(" ");

        return output;
    }

    function contains(parent, child) {
        try {
            return $.contains(parent, child);
        } catch (e) {
            return false;
        }
    }

    function updateItemClasses(item) {
        item = $(item);
        var omitWrap = item.attr(kendo.attr("omit-wrap"));

        if (omitWrap) {
            return;
        }

        item.addClass("k-item k-menu-item")
            .children(IMG)
            .addClass(IMAGE);

        item
            .children("a")
            .addClass(LINK)
            .children(IMG)
            .addClass(IMAGE);

        item
            .filter(":not([disabled])");

        item
            .filter(".k-separator")
            .removeClass("k-menu-item")
            .addClass("k-separator-horizontal")
            .empty()
            .append(" ");

        item
            .filter("li[disabled]")
            .addClass(DISABLEDSTATE)
            .prop("disabled", false)
            .attr("aria-disabled", true);

        if (!item.filter("[role]").length) {
            item.attr(ROLE, "menuitem");
        }

        if (!item.children(LINK_SELECTOR).length) {
            item.contents() // exclude groups, real links, templates and empty text nodes
                .filter(function() { return (!this.nodeName.match(excludedNodesRegExp) && !(this.nodeType === 3 && !kendo.trim(this.nodeValue))); })
                // adding role=none to span elements inside li[role=menuitem]
                // to make screen readers announce submenus #telerik/kendo-ui-core/issues/6942
                .wrapAll("<span class='" + LINK + "' role='none'></span>")
                .filter(function(idx, elm) { return elm.nodeType === 3; })
                .wrap("<span class='k-menu-link-text' role='none'></span>");
        }

        updateArrow(item);
        updateFirstLast(item);
    }

    function updateArrow(item) {
        item = $(item);
        item.find("> .k-link > .k-menu-expand-arrow > [class*=k-i-caret]:not(.k-sprite),> .k-link > .k-menu-expand-arrow > [class*=k-svg-i-caret]:not(.k-sprite)").parent().remove();

        item.filter(":has(.k-menu-group)")
            .children(".k-link:not(:has([class*=k-i-caret]:not(.k-sprite))),.k-link:not(:has([class*=k-svg-i-caret]:not(.k-sprite)))")
            .each(function() {
                var item = $(this);

                item.append(`<span aria-hidden='true' class='k-menu-expand-arrow'>${kendo.ui.icon({ icon: getArrowIconName(item) })}</span>`);
            });
    }

    function getArrowIconName(item) {
        var arrowIconName,
            parent = item.parent().parent(),
            isRtl = kendo.support.isRtl(parent);

        if (parent.hasClass(MENU + "-horizontal")) {
            arrowIconName = "caret-alt-down";
        } else {
            if (isRtl) {
                arrowIconName = "caret-alt-left";
            }
            else {
                arrowIconName = "caret-alt-right";
            }
        }
        return arrowIconName;
    }

    function updateFirstLast(item) {
        item = $(item);

        item.filter(".k-first:not(:first-child)").removeClass(FIRST);
        item.filter(".k-last:not(:last-child)").removeClass(LAST);
        item.filter(":first-child").addClass(FIRST);
        item.filter(":last-child").addClass(LAST);
    }

    function updateHasAriaPopup(parents) {
        if (parents && parents.length) {
            for (var index in parents) {
                var parentLi = parents.eq(index);
                if (parentLi.find("ul").length) {
                    parentLi.attr("aria-haspopup", true);
                } else {
                    parentLi.removeAttr("aria-haspopup");
                }
            }
        }
    }

    function getParentLiItems(group) {
        if (!group.hasClass(MENU)) {
            return group.parentsUntil("." + MENU, "li");
        }
    }

    function storeItemSelectEventHandler(element, options) {
        var selectHandler = getItemSelectEventHandler(options);
        if (selectHandler) {
            setItemData(element, selectHandler);
        }

        if (options.items) {
            $(element).children("div").children("ul").children("li").each(function(i) {
                storeItemSelectEventHandler(this, options.items[i]);
            });
        }
    }

    function setItemData(element, selectHandler) {
        $(element).children(".k-link").data({
            selectHandler: selectHandler
        });
    }

    function getItemSelectEventHandler(options) {
        var selectHandler = options.select,
            isFunction = kendo.isFunction;

        if (selectHandler && isFunction(selectHandler)) {
            return selectHandler;
        }
        return null;
    }

    function popupOpenerSelector(id) {
        return id ? "li[data-groupparent='" + id + "']" : "li[data-groupparent]";
    }
    function popupGroupSelector(id) {
        var selector = id ? "[data-group='" + id + "']" : "[data-group]";
        return "ul" + selector + ",div" + selector;
    }
    function getChildPopups(currentPopup, overflowWrapper) {
        var childPopupOpener = currentPopup.find(popupOpenerSelector());
        var result = [];
        childPopupOpener.each(function(i, opener) {
            opener = $(opener);
            var popupId = opener.data(POPUP_OPENER_ATTR);
            var popup = currentPopup;
            while (popupId) {
                popup = overflowWrapper.find(popupGroupSelector(popupId) + ":visible");
                if (popup.length) {
                    result.push(popup);
                }
                opener = popup.find(popupOpenerSelector());
                popupId = opener.data(POPUP_OPENER_ATTR);
            }
        });

        return result;
    }

    function popupParentItem(popupElement, overflowWrapper) {
        var popupId = popupElement.data(POPUP_ID_ATTR);
        return popupId ? overflowWrapper.find(popupOpenerSelector(popupId)) : $([]);
    }

    function itemPopup(item, overflowWrapper) {
        var popupId = item.data(POPUP_OPENER_ATTR);
        return popupId ? overflowWrapper.children(animationContainerSelector).find(popupGroupSelector(popupId)) : $([]);
    }

    function overflowMenuParents(current, overflowWrapper) {
        var parents = [];
        var getParents = function(item) {
            while (item.parentNode && !overflowWrapper.is(item.parentNode)) {
                parents.push(item.parentNode);
                item = item.parentNode;
            }
        };
        var elem = current[0] || current;
        getParents(elem);
        var last = parents[parents.length - 1];
        while ($(last).is(animationContainerSelector)) {
            var popupElement = $(last).find(popupSelector);
            elem = popupParentItem(popupElement, overflowWrapper)[0];
            if (!elem) {
                break;
            }
            parents.push(elem);
            getParents(elem);
            last = parents[parents.length - 1];
        }
        return parents;
    }

    function mousewheelDelta(e) {
        var delta = 0;

        if (e.wheelDelta) {
            delta = -e.wheelDelta / 120;
            delta = delta > 0 ? Math.ceil(delta) : Math.floor(delta);
        }

        if (e.detail) {
            delta = Math.round(e.detail / 3);
        }

        return delta;
    }

    function parentsScroll(current, scrollDirection) {
        var scroll = 0;
        var parent = current.parentNode;
        while (parent && !isNaN(parent[scrollDirection])) {
            scroll += parent[scrollDirection];
            parent = parent.parentNode;
        }
        return scroll;
    }

    function isPointerTouch(e) {
        return allPointers && e.originalEvent && e.originalEvent.pointerType in touchPointerTypes;
    }

    function isTouch(e) {
        var ev = e.originalEvent;
        return touch && /touch/i.test(ev.type || "");
    }

    function removeSpacesBetweenItems(ul) {
        ul.contents().filter(function() { return this.nodeName != "LI"; }).remove();
    }

    var Menu = kendo.ui.DataBoundWidget.extend({
        init: function(element, options) {
            var that = this;

            Widget.fn.init.call(that, element, options);

            element = that.wrapper = that.element;
            options = that.options;
            that._accessors();
            that._templates();
            that._dataSource();

            that._updateClasses();
            that._wrapGroups();

            that._animations(options);

            that.nextItemZIndex = 100;

            that._tabindex();

            that._initOverflow(options);

            that._attachMenuEventsHandlers();

            if (options.openOnClick) {
                that.clicked = false;
            }

            element.attr(ROLE, "menubar");

            if (element[0].id) {
                that._ariaId = kendo.format("{0}_mn_active", element[0].id);
            } else {
                that._ariaId = kendo.format("{0}_mn_active", kendo.guid());
            }

            kendo.notify(that);
        },

        events: [
            OPEN,
            CLOSE,
            ACTIVATE,
            DEACTIVATE,
            SELECT,
            DATABOUND
        ],

        options: {
            name: "Menu",
            animation: {
                open: {
                    duration: 200
                },
                close: { // if close animation effects are defined, they will be used instead of open.reverse
                    duration: 100
                }
            },
            orientation: "horizontal",
            direction: "default",
            openOnClick: false,
            closeOnClick: true,
            hoverDelay: 100,
            scrollable: false,
            popupCollision: null,
            autoSize: false,
            iconPosition: "before", // "before" or "after" text content
        },

        _initData: function() {
            var that = this;

            if (that.dataSource) {
                that.element.empty();

                that.append(that.dataSource.view(), that.element);
            }
        },

        _attachMenuEventsHandlers: function() {
            var that = this;
            var element = that.element;
            var options = that.options;
            var overflowWrapper = that._overflowWrapper();

            that._checkActiveProxy = that._checkActiveElement.bind(that);

            (overflowWrapper || element).on(POINTERDOWN, itemSelector, that._focusHandler.bind(that))
                   .on(CLICK + NS, disabledSelector, false)
                   .on(CLICK + NS, itemSelector, that._click.bind(that))
                   .on(POINTERDOWN + " " + MOUSEDOWN + NS, ".k-content", that._preventClose.bind(that))
                   .on(MOUSEENTER + NS, availableItemsSelector, that._mouseenter.bind(that))
                   .on(MOUSELEAVE + NS, availableItemsSelector, that._mouseleave.bind(that))
                   .on(MOUSEDOWN + NS, availableItemsSelector, that._mousedown.bind(that))
                   .on(TOUCHSTART + NS + " " + MOUSEENTER + NS + " " + MOUSELEAVE + NS + " " +
                       MOUSEDOWN + NS + " " + CLICK + NS, linkSelector, that._toggleHover.bind(that));

            element.on("keydown" + NS, that._keydown.bind(that))
                   .on("focus" + NS, that._focus.bind(that))
                   .on("focus" + NS, ".k-content", that._focus.bind(that))
                   .on("blur" + NS, that._removeFocusItem.bind(that))
                   .on("blur" + NS, "[tabindex]", that._checkActiveProxy);

            if (overflowWrapper) {
                overflowWrapper
                    .on(MOUSELEAVE + NS, popupSelector, that._mouseleavePopup.bind(that))
                    .on(MOUSEENTER + NS, popupSelector, that._mouseenterPopup.bind(that));
            }

            if (options.openOnClick) {
                that._documentClickHandler = that._documentClick.bind(that);
                $(document).on("click", that._documentClickHandler);
            }
        },

        _detachMenuEventsHandlers: function() {
            var that = this;
            var overflowWrapper = that._overflowWrapper();

            if (overflowWrapper) {
                overflowWrapper.off(NS);
            }

            that.element.off(NS);

            if (that._documentClickHandler) {
                $(document).off("click", that._documentClickHandler);
            }
        },

        _getNeededSpaceForChildren: function(element, horizontal) {
            const children = element.children();
            let total = 0;

            if (children.length > 0) {
                children.each((_, element) => {
                    if (horizontal) {
                        total += kendo._outerWidth(element);
                    } else {
                        total += kendo._outerHeight(element);
                    }
                });
            }

            return total;
        },

        _initOverflow: function(options) {
            var that = this;
            var isHorizontal = options.orientation == "horizontal";
            var backwardBtn, forwardBtn;
            const isRtl = kendo.support.isRtl(that.wrapper);
            that._openedPopups = {};
            if (options.scrollable) {
                that._scrollWrapper = that.element.wrap(`<div class="k-menu-scroll-wrapper${options.orientation === 'vertical' ? " k-menu-scroll-wrapper-vertical" : ""}"></div>`).parent();
                if (isHorizontal) {
                    removeSpacesBetweenItems(that.element);
                }
                let backwardBtnIcon = isHorizontal ? (isRtl ? 'right' : 'left') : 'up';
                let forwardBtnIcon = isHorizontal ? (isRtl ? 'left' : 'right') : 'down';

                backwardBtn = $(that.templates.scrollButton({ direction: backwardBtnIcon }));
                forwardBtn = $(that.templates.scrollButton({ direction: forwardBtnIcon }));

                switch (options.scrollable.scrollButtonsPosition) {
                    case "start":
                        forwardBtn.prependTo(that._scrollWrapper);
                        backwardBtn.prependTo(that._scrollWrapper);
                        break;
                    case "end":
                        backwardBtn.appendTo(that._scrollWrapper);
                        forwardBtn.appendTo(that._scrollWrapper);
                        break;
                    default:
                        backwardBtn.prependTo(that._scrollWrapper);
                        forwardBtn.appendTo(that._scrollWrapper);
                }

                that._initScrolling(that.element, backwardBtn, forwardBtn, isHorizontal, isRtl);

                var initialWidth = that.element.outerWidth();
                var initialCssWidth = that.element[0].style.width;
                initialCssWidth = initialCssWidth === "auto" ? "" : initialCssWidth;

                if (isHorizontal) {
                    $(window).on(RESIZE, function() {
                        setTimeout(function() {
                            that._setOverflowWrapperWidth(initialWidth, initialCssWidth);
                            that._toggleScrollButtons(that.element, backwardBtn, forwardBtn, isHorizontal);
                        }, 300);
                    });
                }

                that._setOverflowWrapperWidth(initialWidth, initialCssWidth);
                that._toggleScrollButtons(that.element, backwardBtn, forwardBtn, isHorizontal);
            }
        },

        _overflowWrapper: function() {
            return this._scrollWrapper || this._popupsWrapper;
        },

        _setOverflowWrapperWidth: function(initialWidth, initialCssWidth) {
            var that = this;
            var wrapperCssWidth = that._scrollWrapper.css("width");

            that._scrollWrapper.css({ width: "" });
            var wrapperWidth = that._scrollWrapper.outerWidth();
            that._scrollWrapper.css({ width: wrapperCssWidth });

            var menuWidth = that.element.outerWidth();
            var borders = that.element[0].offsetWidth - that.element[0].clientWidth;

            if (menuWidth != wrapperWidth && wrapperWidth > 0) {
                var width = initialCssWidth ? Math.min(initialWidth, wrapperWidth) : wrapperWidth;
                that.element.width(width - borders);
                that._scrollWrapper.width(width);
            }
        },

        _reinitOverflow: function(options) {
            var that = this;
            var overflowChanged = ((options.scrollable && !that.options.scrollable) || (!options.scrollable && that.options.scrollable)) ||
                (options.scrollable && that.options.scrollable && (
                    options.scrollable.distance != that.options.scrollable.distance ||
                    options.scrollable.scrollButtonsPosition != that.options.scrollable.scrollButtonsPosition
                )) ||
                options.orientation != that.options.orientation;

            if (overflowChanged) {
                that._detachMenuEventsHandlers();
                that._destroyOverflow();
                that._initOverflow(options);
                that._attachMenuEventsHandlers();
            }
        },

        _destroyOverflow: function() {
            var that = this;
            var overflowWrapper = that._overflowWrapper();
            if (overflowWrapper) {
                overflowWrapper.off(NS);
                overflowWrapper.find(scrollButtonSelector).off(NS).remove();
                overflowWrapper.children(animationContainerSelector).each(function(i, popupWrapper) {
                    var ul = $(popupWrapper).find(".k-child-animation-container > .k-menu-popup");
                    ul.off(MOUSEWHEEL);
                    var popupParentLi = popupParentItem(ul, overflowWrapper);
                    if (popupParentLi.length) {
                        popupParentLi.append(popupWrapper);
                    }
                });

                overflowWrapper.find(popupOpenerSelector()).removeAttr("data-groupparent");
                overflowWrapper.find(popupGroupSelector()).removeAttr("data-group");
                that.element.off(MOUSEWHEEL);
                $(window).off(RESIZE);
                overflowWrapper.contents().unwrap();

                that._scrollWrapper = that._popupsWrapper = that._openedPopups = undefined$1;
            }
        },

        _initScrolling: function(scrollElement, backwardBtn, forwardBtn, isHorizontal, isRtl) {
            var that = this;
            var scrollable = that.options.scrollable;
            var distance = that.isNumeric(scrollable.distance) ? scrollable.distance : SCROLLSPEED;
            var mouseWheelDistance = distance / 2;
            var backward = "-=" + distance;
            var forward = "+=" + distance;
            var backwardDouble = "-=" + distance * 2;
            var forwardDouble = "+=" + distance * 2;
            var scrolling = false;
            var touchEvents = false;
            var scroll = function(value) {
                var scrollValue = isHorizontal ? { "scrollLeft": value } : { "scrollTop": value };
                scrollElement.finish().animate(scrollValue, "fast", "linear", function() {
                    if (scrolling) {
                        scroll(value);
                    }
                });
                that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal, isRtl);
            };

            var mouseenterHandler = function(e) {
                if (!scrolling && !touchEvents) {
                    scroll(e.data.direction);
                    scrolling = true;
                }
            };

            var mousedownHandler = function(e) {
                var scrollValue = isHorizontal ? { "scrollLeft": e.data.direction } : { "scrollTop": e.data.direction };
                touchEvents = isTouch(e) || isPointerTouch(e);
                scrollElement.stop().animate(scrollValue, "fast", "linear", function() {
                    if (!touchEvents) {
                        $(e.currentTarget).trigger(MOUSEENTER);
                    } else {
                         that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal, isRtl);
                         scrolling = true;
                    }
                });
                scrolling = false;

                e.stopPropagation();
                e.preventDefault();
            };

            backwardBtn.on(MOUSEENTER + NS, { direction: isRtl && isHorizontal ? forward : backward }, mouseenterHandler)
                .on(kendo.eventMap.down + NS, { direction: isRtl && isHorizontal ? forwardDouble : backwardDouble }, mousedownHandler);

            forwardBtn.on(MOUSEENTER + NS, { direction: isRtl && isHorizontal ? backward : forward }, mouseenterHandler)
                .on(kendo.eventMap.down + NS, { direction: isRtl && isHorizontal ? backwardDouble : forwardDouble }, mousedownHandler);

            backwardBtn.add(forwardBtn)
                .on(MOUSELEAVE + NS, function() {
                    scrollElement.stop();
                    scrolling = false;
                    that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal, isRtl);
                });

            scrollElement.on(MOUSEWHEEL, function(e) {
                if (!e.ctrlKey && !e.shiftKey && !e.altKey) {
                    var wheelDelta = mousewheelDelta(e.originalEvent);
                    var scrollSpeed = Math.abs(wheelDelta) * mouseWheelDistance;
                    var value = (wheelDelta > 0 ? "+=" : "-=") + scrollSpeed;
                    var scrollValue = isHorizontal ? { "scrollLeft": value } : { "scrollTop": value };

                    that._closeChildPopups(scrollElement);

                    scrollElement.finish().animate(scrollValue, "fast", "linear", function() {
                        that._toggleScrollButtons(scrollElement, backwardBtn, forwardBtn, isHorizontal);
                    });
                    e.preventDefault();
                }
            });
        },

        isNumeric: function(n) {
            return !isNaN(parseFloat(n)) && isFinite(n);
        },

        _toggleScrollButtons: function(scrollElement, backwardBtn, forwardBtn, horizontal) {
            const neededSpace = this._getNeededSpaceForChildren(scrollElement, horizontal);
            const elementSpace = horizontal ? kendo._outerWidth(this.element) : kendo._outerHeight(this.element);

            backwardBtn.toggle(neededSpace > elementSpace);
            forwardBtn.toggle(neededSpace > elementSpace);

            const currentScroll = horizontal ? kendo.scrollLeft(scrollElement) : scrollElement.scrollTop();
            const elementIsPopup = scrollElement.is(popupSelector) || scrollElement.parent().is(childAnimationContainerSelector);

            let disableNextButton = Math.abs(currentScroll - (scrollElement[0].scrollWidth - scrollElement[0].offsetWidth)) <= 1;

            if (!horizontal) {
                disableNextButton = Math.abs(currentScroll - (scrollElement[0].scrollHeight - scrollElement[0].offsetHeight)) <= 1;
            }

            if (elementIsPopup) {
                disableNextButton = Math.abs(currentScroll - (scrollElement[0].scrollHeight - scrollElement[0].offsetHeight) - 1) <= 1;
            }

            backwardBtn.toggleClass(DISABLEDSTATE, Math.floor(currentScroll) === 0);
            forwardBtn.toggleClass(DISABLEDSTATE, disableNextButton);
        },

        setOptions: function(options) {
            var animation = this.options.animation;

            this._animations(options);

            options.animation = extend(true, animation, options.animation);

            if ("dataSource" in options) {
                this._dataSource(options);
            }

            this._updateClasses();
            this._wrapGroups();
            this._reinitOverflow(options);

            Widget.fn.setOptions.call(this, options);
        },

        destroy: function() {
            var that = this;

            Widget.fn.destroy.call(that);

            that._detachMenuEventsHandlers();

            that._destroyOverflow();

            kendo.destroy(that.element);
        },

        enable: function(element, enable) {
            this._toggleDisabled(element, enable !== false);

            return this;
        },

        disable: function(element) {
            this._toggleDisabled(element, false);

            return this;
        },

        attemptGetItem: function(candidate) {
            candidate = candidate || this.element;
            var item = this.element.find(candidate);
            var overflowWrapper = this._overflowWrapper();

            if (item.length || candidate === this.element) {
                return item;
            } else if (overflowWrapper) {
                return overflowWrapper.find(candidate);
            } else {
                return $();
            }
        },

        append: function(item, referenceItem) {
            referenceItem = this.attemptGetItem(referenceItem);

            var inserted = this._insert(item, referenceItem, referenceItem.length ? this._childPopupElement(referenceItem).children().eq(0) : null);

            each(inserted.items, function(i) {
                inserted.group.append(this);
                updateArrow(this);
                storeItemSelectEventHandler(this, item[i] || item);
            });

            updateArrow(referenceItem);
            updateFirstLast(inserted.group.find(".k-first, .k-last").add(inserted.items));
            updateHasAriaPopup(getParentLiItems(inserted.group));

            return this;
        },

        insertBefore: function(item, referenceItem) {
            referenceItem = this.attemptGetItem(referenceItem);

            var inserted = this._insert(item, referenceItem, referenceItem.parent());

            each(inserted.items, function(i) {
                referenceItem.before(this);
                updateArrow(this);
                updateFirstLast(this);
                storeItemSelectEventHandler(this, item[i] || item);
            });

            updateFirstLast(referenceItem);

            return this;
        },

        insertAfter: function(item, referenceItem) {
            referenceItem = this.attemptGetItem(referenceItem);

            var inserted = this._insert(item, referenceItem, referenceItem.parent());

            each(inserted.items, function(i) {
                referenceItem.after(this);
                updateArrow(this);
                updateFirstLast(this);
                storeItemSelectEventHandler(this, item[i] || item);
            });

            updateFirstLast(referenceItem);

            return this;
        },

        _insert: function(item, referenceItem, parent) {
            var that = this,
                items, groups;

            if (!referenceItem || !referenceItem.length) {
                parent = that.element;
            }

            var plain = $.isPlainObject(item) || item instanceof kendo.data.ObservableObject,
                groupData = {
                    firstLevel: parent.hasClass(MENU),
                    horizontal: parent.hasClass(MENU + "-horizontal"),
                    expanded: true,
                    length: parent.children().length
                };

            if (referenceItem && !parent.length) {
                parent = $(that.renderGroup({ group: groupData, options: that.options })).css("display", "none").appendTo(referenceItem);
                kendo.applyStylesFromKendoAttributes(parent, ["display"]);
            }

            if (plain || isArray(item) || item instanceof kendo.data.ObservableArray) { // is JSON
                items = $($.map(plain ? [ item ] : item, function(value, idx) {
                            if (typeof value === "string") {
                                return $(value).get();
                            } else {
                                let itemElement = $(that.renderItem({
                                    group: groupData,
                                    item: extend(value, { index: idx })
                                }));

                                kendo.applyStylesFromKendoAttributes(itemElement, ["display"]);
                                return itemElement.get();
                            }
                        }));
            } else {
                if (typeof item == "string" && item.charAt(0) != "<") {
                    items = that.element.find(item);
                } else {
                    items = $(item);
                }

                groups = items.find("> ul")
                                .addClass("k-menu-group k-menu-group-md")
                                .attr(ROLE, "menu");

                items = items.filter("li");

                items.add(groups.find("> li")).each(function() {
                    updateItemClasses(this);
                });
            }

            parent = parent.is(popupSelector) ? parent.find(groupSelector).first() : parent;

            return { items: items, group: parent };
        },

        remove: function(element) {
            element = this.attemptGetItem(element);

            var that = this,
                parent = element.parentsUntil(that.element, allItemsSelector),
                group = element.parent("ul:not(.k-menu)");

            element.remove();

            if (group && !group.children(allItemsSelector).length) {
                var parentItems = getParentLiItems(group);

                var container = group.parent(animationContainerSelector);

                if (container.length) {
                    container.remove();
                } else {
                    group.remove();
                }

                updateHasAriaPopup(parentItems);
            }

            if (parent.length) {
                parent = parent.eq(0);

                updateArrow(parent);
                updateFirstLast(parent);
            }

            return that;
        },

        _openAfterLoad: function(element, dataItem) {
            var that = this;
            if (dataItem.loaded()) {
                that.open(element);
                that._loading = false;
            } else {
                dataItem.one(CHANGE, function() {
                    element.find(ICON_SELECTOR).children().removeClass("k-i-loading");
                    if (that._loading) {
                        that.open(element);
                        that._loading = false;
                    }
                });
            }
        },

        _createPopup: function(div, options) {
            let that = this;
            let overflowWrapper = that._overflowWrapper();
            return div.kendoPopup(extend({
                activate: function() { that._triggerEvent({ item: this.wrapper.parent(), type: ACTIVATE }); },
                deactivate: function(e) {
                    that._closing = false;
                    e.sender.element // Restore opacity after fade.
                        .removeData("targetTransform")
                        .css({ opacity: "" });
                    that._triggerEvent({ item: this.wrapper.parent(), type: DEACTIVATE });
                },
                open: that._popupOpen.bind(that),
                close: function(e) {
                    that._closing = e.sender.element;
                    var li = e.sender.wrapper.parent();

                    if (overflowWrapper) {
                        var popupId = e.sender.element.data(POPUP_ID_ATTR);
                        if (popupId) {
                            li = (overflowWrapper || that.element).find(popupOpenerSelector(popupId));
                        }
                        e.sender.wrapper.children(scrollButtonSelector).hide();
                    }

                    if (!that._triggerEvent({ item: li[0], type: CLOSE })) {
                        li.css(ZINDEX, li.data(ZINDEX));
                        li.removeData(ZINDEX);

                        if (that.options.scrollable) {
                            li.parent().siblings(scrollButtonSelector).css({ zIndex: "" });
                        }

                        if (touch || allPointers || kendo.support.mouseAndTouchPresent) {
                            li.removeClass(HOVERSTATE);
                        }
                    } else {
                        e.preventDefault();
                    }
                }
            }, options)).data(KENDOPOPUP);
        },

        open: function(element) {
            var that = this;
            var options = that.options;
            var horizontal = options.orientation == "horizontal";
            var direction = options.direction;
            var isRtl = kendo.support.isRtl(that.wrapper);
            var overflowWrapper = that._overflowWrapper();
            element = (overflowWrapper || that.element).find(element);

            var dataItem = that.dataSource && that.dataSource.getByUid(element.data(kendo.ns + "uid"));

            if (dataItem && dataItem.hasChildren && !dataItem.loaded() && !that._loading) {
                that._loading = true;
                element.find(ICON_SELECTOR).children().addClass("k-i-loading");
                dataItem.load();
                that._openAfterLoad(element, dataItem);
                return;
            }

            if (/^(top|bottom|default)$/.test(direction)) {
                if (isRtl) {
                    direction = horizontal ? (direction + " left").replace("default", "bottom") : "left";
                } else {
                    direction = horizontal ? (direction + " right").replace("default", "bottom") : "right";
                }
            }

            var visiblePopups = ">.k-popup:visible,>.k-animation-container > .k-child-animation-container > .k-menu-popup:visible";
            var closePopup = function() {
                var popup = $(this).data(KENDOPOPUP);
                if (popup) {
                    // Use the built-in close method to play the hoverDelay from the options
                    that.close($(this).closest("li.k-item"), true);
                }
            };

            element.siblings()
                   .find(visiblePopups)
                   .each(closePopup);

            if (overflowWrapper) {
                element.find(visiblePopups).each(closePopup);
            }

            if (that.options.openOnClick) {
                that.clicked = true;
            }

            element.each(function() {
                var li = $(this);

                clearTimeout(li.data(TIMER));
                clearTimeout(that._timerTimeout);
                that._timerTimeout = setTimeout(function() {
                    var div = li.find("> .k-menu-popup, > .k-animation-container > .k-child-animation-container > .k-menu-popup").filter(":hidden").first();
                    var popup;
                    var overflowPopup;

                    if (!div[0] && overflowWrapper) {
                        overflowPopup = that._getPopup(li);
                        div = overflowPopup && overflowPopup.element;
                    }
                    if (div.is(":visible")) {
                        return;
                    }

                    if (div[0] && that._triggerEvent({ item: li[0], type: OPEN }) === false) {
                        const menuParent = div.children('.k-menu-scroll-wrapper').length ? div.children('.k-menu-scroll-wrapper') : div;
                        const menu = that._groupElementsInitialSpace.find(({ element }) => menuParent.children('ul').is(element));

                        let maxHeight = "";
                        if (menu && Object.keys(menu).length > 0) {
                            if (menu.height > 0) {
                                maxHeight = menu.height;
                            }

                            that._popupToBeOpened = menu;

                            if (menu.inlineHeight) {
                                $(menu.element).css({ height: menu.inlineHeight });
                            } else {
                                $(menu.element).css({ height: "" });
                            }
                        }
                        const maxWidthNone = options.scrollable || options.autoSize;
                        const overflow = options.autoSize ? "auto" : "visible";
                        div.css({ maxHeight: maxWidthNone ? "" : maxHeight, overflow: overflow });

                        li.data(ZINDEX, li.css(ZINDEX));
                        var nextZindex = that.nextItemZIndex++;
                        li.css(ZINDEX, nextZindex);

                        if (that.options.scrollable) {
                            li.parent().siblings(scrollButtonSelector).css({ zIndex: ++nextZindex });
                        }

                        popup = div.data(KENDOPOPUP);
                        var root = li.parent().hasClass(MENU),
                            parentHorizontal = root && horizontal,
                            directions = parseDirection(direction, root, isRtl),
                            effects = options.animation.open.effects,
                            openEffects = effects !== undefined$1 ? effects : "slideIn:" + getEffectDirection(direction, root),
                            collision;

                        if (options.popupCollision !== null) {
                            collision = options.popupCollision;
                        } else if (parentHorizontal) {
                            collision = "fit";
                        } else {
                            collision = "fit flip";
                        }

                        if (!popup) {
                            popup = that._createPopup(div, {
                                origin: directions.origin,
                                position: directions.position,
                                collision: collision,
                                anchor: li,
                                appendTo: overflowWrapper || li,
                                animation: {
                                    open: extend(true, { effects: openEffects }, options.animation.open),
                                    close: options.animation.close
                                },
                            });

                            div.closest(animationContainerSelector).removeAttr(ROLE);
                        } else {
                            popup = div.data(KENDOPOPUP);
                            popup.options.origin = directions.origin;
                            popup.options.position = directions.position;
                            popup.options.animation.open.effects = openEffects;
                        }
                        div.removeAttr("aria-hidden");
                        li.attr(ARIA_EXPANDED, true);

                        that._configurePopupOverflow(popup, li);

                        popup._hovered = true;
                        popup.open();

                        that._initPopupScrolling(popup);
                    }

                }, that.options.hoverDelay);

                li.data(TIMER, that._timerTimeout);
            });

            return that;
        },

        _configurePopupOverflow: function(popup, popupOpener) {
            var that = this;
           if (that.options.scrollable) {
                that._wrapPopupElement(popup);
                if (!popupOpener.attr("data-groupparent")) {
                    var groupId = new Date().getTime();
                    popupOpener.attr("data-groupparent", groupId);
                    popup.element.attr("data-group", groupId);
                }
           }
        },

        _wrapPopupElement: function(popup) {
            if (!popup.element.parent().is(childAnimationContainerSelector)) {
                popup.wrapper = kendo.wrap(popup.element, popup.options.autosize)
                    .css({
                        overflow: "hidden",
                        display: "block",
                        position: "absolute"
                    });
            }
        },

        _initPopupScrolling: function(popup, isHorizontal, skipMouseEvents) {
            var that = this;
            const popupElement = popup.element;
            const scrollWrapper = popupElement.children('.k-menu-scroll-wrapper');
            const menu = scrollWrapper.length ? $(scrollWrapper.children('ul')) : $(popupElement.children('ul'));
            let childrenScrollSpace = that._getNeededSpaceForChildren(menu, isHorizontal);
            let initScrolling = false;

            if (isHorizontal) {
                initScrolling = (kendo._outerWidth(popupElement) < childrenScrollSpace);
            } else {
                initScrolling = (kendo._outerHeight(popupElement) < childrenScrollSpace);
            }


            if (that.options.scrollable && ((popupElement[0].scrollHeight > popupElement[0].offsetHeight) || initScrolling)) {
                that._initPopupScrollButtons(popup, isHorizontal, skipMouseEvents);
            } else {
                if (scrollWrapper.length) {
                    scrollWrapper.find(scrollButtonSelector).remove();
                    menu.unwrap();
                }
            }
        },

        _scrollButtonsMouseEnter: function() {
            let that = this;
            let popup = that.popup;
            let overflowWrapper = that._overflowWrapper();
            $(getChildPopups(popup.element, overflowWrapper)).each(function(i, p) {
                let popupOpener = overflowWrapper.find(popupOpenerSelector(p.data(POPUP_ID_ATTR)));
                that.close(popupOpener);
            });
        },

        _scrollButtonsMouseLeave: function() {
            let that = this;
            let popup = that.popup;
            setTimeout(function() {
                if ($.isEmptyObject(that._openedPopups)) {
                    that._closeParentPopups(popup.element);
                }
            }, DELAY);
        },

        _initPopupScrollButtons: function(popup, isHorizontal, skipMouseEvents) {
            let that = this,
                scrollButtons = popup.wrapper.find(scrollButtonSelector),
                element = popup.element,
                scrollWrapper = element.children('.k-menu-scroll-wrapper'),
                menu = element.children('ul');
                that._denyOpening = true;
                if (!menu.length && scrollWrapper.length) {
                    menu = scrollWrapper.children('ul');
                }

                if (!isHorizontal) {
                    menu.css({
                        overflow: 'hidden',
                    });
                }
                const wrapper = scrollWrapper.length > 0 ? scrollWrapper : menu.wrap(`<div class="k-menu-scroll-wrapper${!isHorizontal ? " k-menu-scroll-wrapper-vertical" : ""}"></div>`).parent();
                if (!scrollButtons.length) {
                    let backwardBtn = $(that.templates.scrollButton({ direction: isHorizontal ? "left" : "up" }));
                    let forwardBtn = $(that.templates.scrollButton({ direction: isHorizontal ? "right" : "down" }));

                    scrollButtons = backwardBtn.add(forwardBtn);
                    scrollButtons.css({
                        width: !isHorizontal && '100%',
                    });

                    backwardBtn.prependTo(wrapper);
                    forwardBtn.appendTo(wrapper);

                    that._initScrolling(menu, backwardBtn, forwardBtn, isHorizontal);
                    if (!skipMouseEvents) {
                        scrollButtons.on(MOUSEENTER + NS, function() {
                            let overflowWrapper = that._overflowWrapper();
                            $(getChildPopups(popup.element, overflowWrapper)).each(function(i, p) {
                                let popupOpener = overflowWrapper.find(popupOpenerSelector(p.data(POPUP_ID_ATTR)));
                                that.close(popupOpener);
                            });
                        })
                        .on(MOUSELEAVE + NS, function(e) {
                            setTimeout(function() {
                                if ($.isEmptyObject(that._openedPopups) && !popup.element.find(e.relatedTarget).length) {
                                    that._closeParentPopups(popup.element);
                                }
                            }, DELAY);
                        });
                    }
                } else {
                    if (scrollButtons.is(':hidden')) {
                        scrollButtons.show();
                    }
                }

                if (scrollButtons.length > 0 && !isHorizontal) {
                    const initialInlineHeight = that._popupToBeOpened ? that._popupToBeOpened.inlineHeight : "";

                    menu.css({ height: initialInlineHeight !== '' ? initialInlineHeight : `${kendo._outerHeight(popup.wrapper) - (kendo._outerHeight(scrollButtons) * 2)}px` });
                }

                that._toggleScrollButtons(menu, scrollButtons.first(), scrollButtons.last(), isHorizontal);
                that._denyOpening = false;
        },

        _popupOpen: function(e) {
            if (!this._keyTriggered) {
                e.sender.element.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
            }
            if (this.options.scrollable) {
                this._setPopupHeight(e.sender);
            }
        },

        _setPopupHeight: function(popup, isFixed) {
            let popupElement = popup.element,
                popups = popupElement.add(popupElement.parent(childAnimationContainerSelector));

            popups.height((popupElement.hasClass(MENU) && this._initialHeight) || "");

            let location = popup._location(isFixed),
                windowHeight = $(window).height(),
                popupOuterHeight = location.height,
                popupOffsetTop = isFixed ? 0 : Math.max(location.top, 0),
                scrollTop = isFixed ? 0 : parentsScroll(this._overflowWrapper()[0], "scrollTop"),
                bottomScrollbar = window.innerHeight - windowHeight,
                maxHeight = windowHeight + bottomScrollbar,
                canFit = maxHeight + scrollTop > popupOuterHeight + popupOffsetTop;

            if (!canFit) {
                let popupViewportGap = windowHeight * 0.05, // 5% gap from the viewport.
                height = Math.min(maxHeight, maxHeight - popupOffsetTop - popupViewportGap + scrollTop);
                popups.css({ height: height + "px" });
                popupElement.css({ overflow: 'hidden' });
            }
        },

        close: function(items, dontClearClose) {
            var that = this;
            var overflowWrapper = that._overflowWrapper();
            var element = (overflowWrapper || that.element);

            items = element.find(items);

            if (!items.length) {
                items = element.find(">.k-item");
            }

            var hasChildPopupsHovered = function(currentPopup) {
                var result = false;
                if ($.isEmptyObject(that._openedPopups)) {
                    return result;
                }
                $(getChildPopups(currentPopup, overflowWrapper)).each(function(i, popup) {
                    result = !!that._openedPopups[popup.data(POPUP_ID_ATTR).toString()];
                    return !result;
                });
                return result;
            };

            var isPopupMouseLeaved = function(opener) {
                var groupId = opener.data(POPUP_OPENER_ATTR);
                return (!overflowWrapper || !groupId || !that._openedPopups[groupId.toString()]);
            };

            items.each(function() {
                var li = $(this);

                li.attr(ARIA_EXPANDED, false);

                if (!dontClearClose && that._isRootItem(li)) {
                    that.clicked = false;
                }

                clearTimeout(li.data(TIMER));

                li.data(TIMER, setTimeout(function() {
                    var popup = that._getPopup(li);
                    if (popup && (isPopupMouseLeaved(li) || that._forceClose)) {
                        if (!that._forceClose && hasChildPopupsHovered(popup.element)) {
                            return;
                        }

                        popup.close();
                        popup.element.attr("aria-hidden", true);

                        if (overflowWrapper) {
                            if (that._forceClose && items.last().is(li[0])) {
                                delete that._forceClose;
                            }
                        }
                    }
                }, that.options.hoverDelay));
            });

            return that;
        },

        _getPopup: function(li) {
            var that = this;
            var popup = li.find(".k-menu-popup:not(.k-list-container):not(.k-calendar-container):visible").first().data(KENDOPOPUP);
            var overflowWrapper = that._overflowWrapper();

            if (!popup && overflowWrapper) {
                var groupId = li.data(POPUP_OPENER_ATTR);
                if (groupId) {
                    var popupElement = overflowWrapper.find(popupGroupSelector(groupId));
                    popup = popupElement.data(KENDOPOPUP);
                }
            }
            return popup;
        },

        _toggleDisabled: function(items, enable) {
            this.element.find(items).each(function() {
                $(this)
                    .toggleClass(DISABLEDSTATE, !enable)
                    .attr("aria-disabled", !enable);
            });
        },

        _toggleHover: function(e) {
            var target = $(kendo.eventTarget(e) || e.target).closest(allItemsSelector),
                isEnter = e.type == MOUSEENTER || MOUSEDOWN.indexOf(e.type) !== -1;

            target.siblings().removeClass(HOVERSTATE);

            if (!target.parents("li." + DISABLEDSTATE).length) {
                target.toggleClass(HOVERSTATE, isEnter || e.type == "mousedown" || e.type == "pointerover" || e.type == TOUCHSTART);
            }
        },

        _preventClose: function() {
            if (!this.options.closeOnClick) {
                this._closurePrevented = true;
            }
        },

        _checkActiveElement: function(e) {
            var that = this,
                focusedItem = $(e ? e.currentTarget : this._focusItem()),
                target = that._findRootParent(focusedItem)[0];

            if (!this._closurePrevented) {
                setTimeout(function() {
                    if (!document.hasFocus() || (!contains(target, kendo._activeElement()) && e && !contains(target, e.currentTarget))) {
                        that.close(target);
                    }
                }, 0);
            }

            this._closurePrevented = false;
        },

        _removeFocusItem: function() {
            var oldFocusedItem = this._focusItem();
            if (oldFocusedItem && oldFocusedItem.hasClass(FOCUSEDSTATE)) {
                oldFocusedItem.removeClass(FOCUSEDSTATE);
                this._oldFocusItem = null;
            }
        },

        _wrapGroups: function() {
            var that = this;
            const elements = that.element.find("li > ul");


            that._groupElementsInitialSpace = Array.from(elements).map(element => {
                let elementConfig;
                let forceShow = false;
                let parentPopup = element.closest(".k-animation-container") || element.closest(".k-popup");

                parentPopup = $(parentPopup);

                if (parentPopup && parentPopup.length && !parentPopup.is(":visible")) {
                    forceShow = true;
                    parentPopup.show();
                }

                elementConfig = {
                    element,
                    width: kendo._outerWidth(element),
                    height: kendo._outerHeight(element),
                    inlineHeight: element.style && element.style.height ? element.style.height : ""
                };

                if (forceShow) {
                    parentPopup.hide();
                }

                return elementConfig;
        });

            elements
                .filter(function() {
                    return !$(this).parent().hasClass("k-menu-popup");
                })
                .wrap("<div class='k-menu-popup k-popup'></div>")
                .parent("div")
                .attr("aria-hidden", that.element.is(":visible"))
                .hide();

            that.element.find("ul").each(function() {
                var group = $(this);
                var id = kendo.guid();
                group.attr("id", id)
                    .closest("li")
                    .attr("aria-controls", id);
            });
        },

        _updateClasses: function() {
            var element = this.element,
                nonContentGroupsSelector = ".k-menu-init div ul",
                items;

            element.removeClass("k-menu-horizontal k-menu-vertical");
            element.addClass("k-reset k-header k-menu-init " + MENU).addClass(MENU + "-" + this.options.orientation);

            if (this.options.orientation === "vertical") {
                element.attr("aria-orientation", "vertical");
            } else {
                element.attr("aria-orientation", "horizontal");
            }

            element.find("li > ul")
                   .filter(function() {
                       return !kendo.support.matchesSelector.call(this, nonContentGroupsSelector);
                   })
                   .addClass("k-menu-group k-menu-group-md")
                   .attr(ROLE, "menu")
                   .parent("li")
                   .attr("aria-haspopup", "true")
                   .end()
                   .find("li > div")
                   .addClass("k-content")
                   .attr("tabindex", "-1"); // Capture the focus before the Menu

            element.find("li[aria-haspopup]").attr(ARIA_EXPANDED, false);

            items = element.find("> li,.k-menu-group > li");

            element.removeClass("k-menu-init");

            items.each(function() {
                updateItemClasses(this);
            });
        },

        _mouseenter: function(e) {
            var that = this;
            var element = $(e.currentTarget);
            var hasChildren = that._itemHasChildren(element);
            var popupId = element.data(POPUP_OPENER_ATTR) || element.closest(popupSelector).data(POPUP_ID_ATTR);
            var pointerTouch = isPointerTouch(e);
            var isParentClosing = false;

            if (that._denyOpening) {
                return;
            }

            if (popupId) {
                that._openedPopups[popupId.toString()] = true;
            }

            if (that._closing) {
                isParentClosing = !!that._closing.find(element).length;
            }

            if (isParentClosing) {
                return;
            }

            that._keyTriggered = false;

            if ((that.options.openOnClick.rootMenuItems && that._isRootItem(element.closest(allItemsSelector))) ||
                (that.options.openOnClick.subMenuItems && !that._isRootItem(element.closest(allItemsSelector)))) {
                return;
            }

            if ((that.options.openOnClick === false ||
                (that.options.openOnClick.rootMenuItems === false && that._isRootItem(element.closest(allItemsSelector))) ||
                (that.options.openOnClick.subMenuItems === false && !that._isRootItem(element.closest(allItemsSelector))) || that.clicked) && !touch &&
                !(pointerTouch && that._isRootItem(element.closest(allItemsSelector)))) {

                if (!contains(e.currentTarget, e.relatedTarget) && hasChildren) {
                    that.open(element);
                }
            }

            if (that.options.openOnClick === true && that.clicked || touch) {
                element.siblings().each(function(_, sibling) {
                    that.close(sibling, true);
                });
            }
        },

        _mousedown: function(e) {
            var that = this;
            var element = $(e.currentTarget);
            // needs to close subMenuItems
            that._mousedownedElement = element;
            if (that.options.openOnClick.subMenuItems && !that._isRootItem(element) || touch) {
                element.siblings().each(function(_, sibling) {
                    that.close(sibling, true);
                });
            }
        },

        _mouseleave: function(e) {
            var that = this;
            var element = $(e.currentTarget);
            var popupOpener = element.data(POPUP_OPENER_ATTR);
            var hasChildren = element.children(popupSelector).length || popupOpener;
            var $window = $(window);

            if (popupOpener) {
                delete that._openedPopups[popupOpener.toString()];
            }

            if (element.parentsUntil(animationContainerSelector, ".k-list-container,.k-calendar-container")[0]) {
                e.stopImmediatePropagation();
                return;
            }

            if ((that.options.openOnClick === false || (!that.options.openOnClick.rootMenuItems && that._isRootItem(element)) ||
                (!that.options.openOnClick.subMenuItems && !that._isRootItem(element))) && !touch && !isPointerTouch(e) &&
                !contains(e.currentTarget, e.relatedTarget || e.target) && hasChildren &&
                !contains(e.currentTarget, kendo._activeElement())) {
                    that.close(element, true);
                    that._loading = false;
                    return;
            }

            // Detect if cursor goes outside the viewport of the browser
            if ( (kendo.support.browser.msie && !e.toElement && !e.relatedTarget && !isPointerTouch(e)) ||
                e.clientX < 0 || e.clientY < 0 ||
                e.clientY > $window.height() ||
                e.clientX > $window.width()) {
                that.close(element);
            }
        },

        _mouseenterPopup: function(e) {
            var that = this;
            var popupElement = $(e.currentTarget);

            if (popupElement.parent().is(childAnimationContainerSelector)) {
                 return;
            }

            popupElement = popupElement.find(popupSelector);
            var popupId = popupElement.data(POPUP_ID_ATTR);

            if (popupId) {
                that._openedPopups[popupId.toString()] = true;
            }
        },

        _mouseleavePopup: function(e) {
            var that = this;
            var popupElement = $(e.currentTarget);

            if (!isPointerTouch(e) && popupElement.is(animationContainerSelector)) {
                that._closePopups(popupElement.find(popupSelector));
            }
        },

        _closePopups: function(rootPopup) {
            var that = this;
            var overflowWrapper = that._overflowWrapper();
            var popupId = rootPopup.data(POPUP_ID_ATTR);

            if (popupId) {
                delete that._openedPopups[popupId.toString()];
                var groupParent = overflowWrapper.find(popupOpenerSelector(popupId));

                setTimeout(function() {
                    if (that.options.openOnClick) {
                        that._closeChildPopups(rootPopup);
                    } else {
                        if ($.isEmptyObject(that._openedPopups)) {
                            var innerPopup = that._innerPopup(rootPopup);
                            that._closeParentPopups(innerPopup);
                        } else {
                            that.close(groupParent, true);
                        }
                    }
                }, 0);
            }
        },

        _closeChildPopups: function(current) {
            var that = this;
            var overflowWrapper = that._overflowWrapper();
            $(getChildPopups(current, overflowWrapper)).each(function() {
                var popupOpener = overflowWrapper.find(popupOpenerSelector(this.data(POPUP_ID_ATTR)));
                that.close(popupOpener, true);
            });
        },

        _innerPopup: function(current) {
            var overflowWrapper = this._overflowWrapper();
            var popups = getChildPopups(current, overflowWrapper);
            return popups[popups.length - 1] || current;
        },

        _closeParentPopups: function(current) {
            var that = this;
            var overflowWrapper = that._overflowWrapper();
            var popupId = current.data(POPUP_ID_ATTR);
            const target = overflowWrapper ?? that.element;
            var popupOpener = target.find(popupOpenerSelector(popupId));
            popupId = popupOpener.closest(popupSelector).data(POPUP_ID_ATTR);
            that.close(popupOpener, true);
            while (popupId && !that._openedPopups[popupId]) {
                if (popupOpener.parent().is(menuSelector)) {
                    break;
                }
                popupOpener = overflowWrapper.find(popupOpenerSelector(popupId));
                that.close(popupOpener, true);
                popupId = popupOpener.closest(popupSelector).data(POPUP_ID_ATTR);
            }
        },

        _click: function(e) {
            var that = this, openHandle,
                options = that.options,
                target = $(kendo.eventTarget(e)),
                targetElement = target[0],
                nodeName = target[0] ? target[0].nodeName.toUpperCase() : "",
                formNode = (nodeName == "INPUT" || nodeName == "SELECT" || nodeName == "BUTTON" || nodeName == "LABEL"),
                link = target.closest(LINK_SELECTOR),
                element = target.closest(allItemsSelector),
                itemElement = element[0],
                href = link.attr("href"), childGroup, childGroupVisible,
                targetHref = target.attr("href"),
                sampleHref = $("<a href='#' />").attr("href"),
                isLink = (!!href && href !== sampleHref),
                isLocalLink = isLink && !!href.match(/^#/),
                isTargetLink = (!!targetHref && targetHref !== sampleHref),
                overflowWrapper = that._overflowWrapper(),
                shouldCloseTheRootItem;

            if (targetElement && (!targetElement.parentNode || !itemElement)) {
                return;
            }

            if ($(target).closest("span").parent().hasClass('k-menu-expand-arrow')) {
                this._lastClickedElement = itemElement;
            }

            while (targetElement && targetElement.parentNode != itemElement) {
                targetElement = targetElement.parentNode;
            }

            if ($(targetElement).is(templateSelector)) {
                return;
            }

            if (element.hasClass(DISABLEDSTATE)) {
                e.preventDefault();
                return;
            }

            if (!e.handled && that._triggerSelect(target, itemElement) && !formNode) { // We shouldn't stop propagation and shoudn't prevent form elements.
                e.preventDefault();
            }

            e.handled = true;

            childGroup = element.children(popupSelector);
            if (overflowWrapper) {
                var childPopupId = element.data(POPUP_OPENER_ATTR);
                if (childPopupId) {
                    childGroup = overflowWrapper.find(popupGroupSelector(childPopupId));
                }
            }
            childGroupVisible = childGroup.is(":visible");
            shouldCloseTheRootItem = options.openOnClick && childGroupVisible && that._isRootItem(element);

            if (options.closeOnClick && (!isLink || isLocalLink) && (!childGroup.length || shouldCloseTheRootItem)) {
                element.removeClass(HOVERSTATE).css("height"); // Force refresh for Chrome
                that._oldFocusItem = that._findRootParent(element);
                var item = that._parentsUntil(link, that.element, allItemsSelector);
                that._forceClose = !!overflowWrapper;
                that.close(item);
                that.clicked = false;
                return;
            }

            if (isLink && e.enterKey) {
                link[0].click();
            }

            if (((!that._isRootItem(element) || options.openOnClick === false) && !options.openOnClick.subMenuItems) && !kendo.support.touch && !(isPointerTouch(e) && that._isRootItem(element.closest(allItemsSelector)))) {
                return;
            }

            if (!isLink && !formNode && !isTargetLink) {
                e.preventDefault();
            }

            that.clicked = true;
            openHandle = childGroup.is(":visible") ? CLOSE : OPEN;
            if (!options.closeOnClick && openHandle == CLOSE) {
                return;
            }
            that[openHandle](element);
        },

        _parentsUntil: function(context, top, selector) {
            var overflowWrapper = this._overflowWrapper();
            if (!overflowWrapper) {
                return context.parentsUntil(top, selector);
            } else {
                var parents = overflowMenuParents(context, overflowWrapper);
                var result = [];
                $(parents).each(function() {
                    var parent = $(this);
                    if (parent.is(top)) {
                        return false;
                    }
                    if (parent.is(selector)) {
                        result.push(this);
                    }
                });
                return $(result);
            }
        },

        _triggerSelect: function(target, itemElement) {
            target = target.is(".k-link") ? target : target.closest(".k-link");

            var selectHandler = target.data("selectHandler"),
                itemSelectEventData;

            if (selectHandler) {
                itemSelectEventData = this._getEventData(target);
                selectHandler.call(this, itemSelectEventData);
            }

            var isSelectItemDefaultPrevented = itemSelectEventData && itemSelectEventData.isDefaultPrevented();
            var isSelectDefaultPrevented = this._triggerEvent({ item: itemElement, type: SELECT });
            return isSelectItemDefaultPrevented || isSelectDefaultPrevented;
        },

        _getEventData: function(target) {
            var eventData = {
                sender: this,
                target: target,
                _defaultPrevented: false,
                preventDefault: function() {
                    this._defaultPrevented = true;
                },
                isDefaultPrevented: function() {
                    return this._defaultPrevented;
                }
            };
            return eventData;
        },

        _documentClick: function(e) {
            var that = this;
            var target = $(e.target).closest("span").parent().hasClass('k-menu-expand-arrow') ? that._lastClickedElement : e.target;

            if (contains((that._overflowWrapper() || that.element)[0], target)) {
                that._lastClickedElement = undefined$1;
                return;
            }

            that.clicked = false;
        },

        _focus: function(e) {
            var that = this,
                target = e.target,
                focusItem = that._focusItem(),
                active = activeElement();

            if (that._mousedownedElement) {
                that._mousedownedElement = null;
                return;
            }

            if (target != that.wrapper[0] && !$(target).is(":kendoFocusable")) {
                e.stopPropagation();
                $(target).closest(".k-content").closest(".k-menu-popup").closest(".k-item").addClass(FOCUSEDSTATE);
                that.wrapper.trigger("focus");
                return;
            }
            if (active === e.currentTarget) {
                if (focusItem.length) {
                    that._moveFocus([], focusItem);
                } else if (!that._oldFocusItem) {
                    that._moveFocus([], that.wrapper.children().first());
                }
            }
        },

        _keydown: function(e) {
            var that = this,
                key = e.keyCode,
                focusItem = that._oldFocusItem,
                target,
                belongsToVertical,
                hasChildren,
                isRtl = kendo.support.isRtl(that.wrapper);

            if (e.target != e.currentTarget && key != keys.ESC) {
                return;
            }

            if (!focusItem) {
                focusItem = that._oldFocusItem = that._focusItem();
            }

            belongsToVertical = that._itemBelongsToVertival(focusItem);
            hasChildren = that._itemHasChildren(focusItem);
            that._keyTriggered = true;

            if (key == keys.RIGHT) {
                target = that[isRtl ? "_itemLeft" : "_itemRight"](focusItem, belongsToVertical, hasChildren);
            } else if (key == keys.LEFT) {
                target = that[isRtl ? "_itemRight" : "_itemLeft"](focusItem, belongsToVertical, hasChildren);
            } else if (key == keys.DOWN) {
                target = that._itemDown(focusItem, belongsToVertical, hasChildren);
            } else if (key == keys.UP) {
                target = that._itemUp(focusItem, belongsToVertical, hasChildren);
            } else if (key == keys.HOME) {
                that._moveFocus(focusItem, focusItem.parent().children(":visible").first());
                e.preventDefault();
            } else if (key == keys.END) {
                that._moveFocus(focusItem, focusItem.parent().children(":visible").last());
                e.preventDefault();
            } else if (key == keys.ESC) {
                target = that._itemEsc(focusItem, belongsToVertical);
            } else if (key == keys.ENTER || key == keys.SPACEBAR) {
                target = focusItem.children(".k-link");
                if (target.length > 0) {
                    that._click({ target: target[0], preventDefault: function() {}, enterKey: true });
                    if (hasChildren && !focusItem.hasClass(DISABLEDSTATE)) {
                        that.open(focusItem);
                        that._moveFocus(focusItem, that._childPopupElement(focusItem).children().find("li").first());
                    } else if (focusItem.is("li") && focusItem.attr("role") === "menuitemcheckbox") {
                        focusItem.find(".k-checkbox").attr("checked", true);
                    } else {
                        that._moveFocusToRoot(focusItem, that._findRootParent(focusItem));
                    }
                }
            } else if (key == keys.TAB) {
                target = that._findRootParent(focusItem);
                that._moveFocus(focusItem, target);
                that._checkActiveElement();
                return;
            }

            if (target && target[0]) {
                e.preventDefault();
                e.stopPropagation(); // needed to handle ESC in column menu only when a root item is focused
            }
        },

        _focusItem: function() {
            return this.wrapper.find(".k-item.k-focus").filter(":visible");
        },

        _itemBelongsToVertival: function(item) {
            var menuIsVertical = this.wrapper.hasClass("k-menu-vertical");

            if (!item.length) {
                return menuIsVertical;
            }
            return item.parent().hasClass("k-menu-group") || menuIsVertical;
        },

        _itemHasChildren: function(item) {
            if (!item || !item.length || !item[0].nodeType) {
                return false;
            }
            return item.children(".k-menu-group, .k-menu-popup, div.k-animation-container").length > 0 ||
                (!!item.data(POPUP_OPENER_ATTR) && !!this._overflowWrapper().children(popupGroupSelector(item.data(POPUP_OPENER_ATTR))));
        },

        _moveFocus: function(item, nextItem) {
            var that = this,
                id = that._ariaId;

            if (item.length && nextItem.length) {
                item.removeClass(FOCUSEDSTATE);
            }

            if (nextItem.length) {
                if (nextItem[0].id) {
                    id = nextItem[0].id;
                }

                that.wrapper.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                nextItem.addClass(FOCUSEDSTATE);
                that._oldFocusItem = nextItem;

                if (id) {
                    that.element.removeAttr("aria-activedescendant");
                    $("#" + id).removeAttr("id");
                    nextItem.attr("id", id);
                    that.element.attr("aria-activedescendant", id);
                }
                that._scrollToItem(nextItem);
            }
        },

        _moveFocusToRoot: function(item, nextItem) {
            this._moveFocus(item, nextItem);
        },

        _findRootParent: function(item) {
            if (this._isRootItem(item)) {
                return item;
            } else {
                return this._parentsUntil(item, menuSelector, "li.k-item").last();
            }
        },

        _isRootItem: function(item) {
            return item.parent().hasClass(MENU);
        },

        _itemRight: function(item, belongsToVertical, hasChildren) {
            var that = this,
                nextItem,
                parentItem,
                overflowWrapper;

            if (!belongsToVertical) {
                nextItem = item.nextAll(itemSelector + exclusionSelector).eq(0);
                if (!nextItem.length) {
                    nextItem = item.prevAll(itemSelector + exclusionSelector).last();
                }
                that.close(item);
            } else if (hasChildren && !item.hasClass(DISABLEDSTATE)) {
                that.open(item);
                nextItem = that._childPopupElement(item).children().find("li").first();
            } else if (that.options.orientation == "horizontal") {
                parentItem = that._findRootParent(item);
                overflowWrapper = that._overflowWrapper();
                if (overflowWrapper) {
                    var rootPopup = itemPopup(parentItem, overflowWrapper);
                    that._closeChildPopups(rootPopup);
                }
                that.close(parentItem);
                nextItem = parentItem.nextAll(itemSelector + exclusionSelector).eq(0);
            }

            if (nextItem && !nextItem.length) {
                nextItem = that.wrapper.children(".k-item").first();
            } else if (!nextItem) {
                nextItem = [];
            }

            that._moveFocus(item, nextItem);
            return nextItem;
        },

        _itemLeft: function(item, belongsToVertical) {
            var that = this,
                nextItem,
                overflowWrapper;

            if (!belongsToVertical) {
                nextItem = item.prevAll(itemSelector + exclusionSelector).eq(0);
                if (!nextItem.length) {
                    nextItem = item.nextAll(itemSelector + exclusionSelector).last();
                }
                that.close(item);
            } else {
                nextItem = item.parent().closest(".k-item");
                overflowWrapper = that._overflowWrapper();
                if (!nextItem.length && overflowWrapper) {
                    nextItem = popupParentItem(item.parent(), overflowWrapper);
                }
                that.close(nextItem);
                if (that._isRootItem(nextItem) && that.options.orientation == "horizontal") {
                    nextItem = nextItem.prevAll(itemSelector + exclusionSelector).eq(0);
                }
            }

            if (!nextItem.length) {
                nextItem = that.wrapper.children(".k-item").last();
            }

            that._moveFocus(item, nextItem);
            return nextItem;
        },

        _itemDown: function(item, belongsToVertical, hasChildren) {
            var that = this,
                nextItem;

            if (!belongsToVertical) {
                if (!hasChildren || item.hasClass(DISABLEDSTATE)) {
                    return;
                } else {
                    that.open(item);
                    nextItem = that._childPopupElement(item).children().find("li").first();
                }
            } else {
                nextItem = item.nextAll(itemSelector + exclusionSelector).eq(0);
            }

            if (!nextItem.length && item.length) {
                nextItem = item.parent().children(":visible").first();
            } else if (!item.length) {
                nextItem = that.wrapper.children(".k-item").first();
            }

            that._moveFocus(item, nextItem);
            return nextItem;
        },

        _itemUp: function(item, belongsToVertical) {
            var that = this,
                nextItem;

            if (!belongsToVertical) {
                return;
            } else {
                nextItem = item.prevAll(itemSelector + exclusionSelector).eq(0);
            }

            if (!nextItem.length && item.length) {
                nextItem = item.parent().children(":visible").last();
            } else if (!item.length) {
                nextItem = that.wrapper.children(".k-item").last();
            }

            that._moveFocus(item, nextItem);
            return nextItem;
        },

        _scrollToItem: function(item) {
            var that = this;
            if (that.options.scrollable && item && item.length) {
                var ul = item.parent();
                var isHorizontal = ul.hasClass(MENU) ? that.options.orientation == "horizontal" : false;
                var scrollDir = isHorizontal ? "scrollLeft" : "scrollTop";
                var getSize = isHorizontal ? kendo._outerWidth : kendo._outerHeight;
                var currentScrollOffset = ul[scrollDir]();
                var itemSize = getSize(item);
                var itemOffset = item[0][isHorizontal ? "offsetLeft" : "offsetTop"];
                var ulSize = getSize(ul);
                var scrollButtons = ul.siblings(scrollButtonSelector);
                var scrollButtonSize = scrollButtons.length ? getSize(scrollButtons.first()) : 0;
                var itemPosition;

                if (currentScrollOffset + ulSize < itemOffset + itemSize + scrollButtonSize) {
                    itemPosition = itemOffset + itemSize - ulSize + scrollButtonSize;
                } else if (currentScrollOffset > itemOffset - scrollButtonSize) {
                    itemPosition = itemOffset - scrollButtonSize;
                }

                if (!isNaN(itemPosition)) {
                    var scrolling = {};
                    scrolling[scrollDir] = itemPosition;
                    ul.finish().animate(scrolling, "fast", "linear", function() {
                        that._toggleScrollButtons(ul, scrollButtons.first(), scrollButtons.last(), isHorizontal);
                    });
                }
            }
        },

        _itemEsc: function(item, belongsToVertical) {
            var that = this,
                nextItem, groupId;

            if (!belongsToVertical) {
                return item;
            } else {
                nextItem = item.parent().closest(".k-item");

                if (nextItem.length === 0) {
                    groupId = item.closest(".k-menu-popup").data("group");
                    nextItem = that.wrapper.find(".k-item[data-groupparent='" + groupId + "']");
                }

                that.close(nextItem);
                that._moveFocus(item, nextItem);
            }

            return nextItem;
        },

        _childPopupElement: function(item) {
            var popupElement = item.find(".k-menu-popup");
            var wrapper = this._overflowWrapper();
            if (!popupElement.length && wrapper) {
                popupElement = itemPopup(item, wrapper);
            }
            return popupElement;
        },

        _triggerEvent: function(e) {
            var that = this;

            return that.trigger(e.type, { type: e.type, item: e.item });
        },

        _focusHandler: function(e) {
            var that = this,
                item = $(kendo.eventTarget(e)).closest(allItemsSelector);

            if (item.hasClass(DISABLEDSTATE)) {
                return;
            }

            setTimeout(function() {
                that._moveFocus([], item);
                if (item.children(".k-content")[0]) {
                    item.parent().closest(".k-item").removeClass(FOCUSEDSTATE);
                }
            }, 200);
        },

        _animations: function(options) {
            if (options && ("animation" in options) && !options.animation) {
                options.animation = { open: { effects: {} }, close: { hide: true, effects: {} } };
            }
        },
        _dataSource: function(options) {
            var that = this,
                dataSource = options ? options.dataSource : that.options.dataSource;

            if (!dataSource) {
                return;
            }

            dataSource = isArray(dataSource) ? { data: dataSource } : dataSource;

            that._unbindDataSource();

            if (!dataSource.fields) {
                dataSource.fields = [
                    { field: "uid" },
                    { field: "text" },
                    { field: "url" },
                    { field: "cssClass" },
                    { field: "spriteCssClass" },
                    { field: "icon" },
                    { field: "iconClass" },
                    { field: "imageUrl" },
                    { field: "imageAttr" },
                    { field: "attr" },
                    { field: "contentAttr" },
                    { field: "content" },
                    { field: "encoded" },
                    { field: "items" },
                    { field: "select" }
                ];
            }

            that.dataSource = HierarchicalDataSource.create(dataSource);

            that._bindDataSource();

            that.dataSource.fetch();
        },

        _bindDataSource: function() {
            this._refreshHandler = this.refresh.bind(this);
            this._errorHandler = this._error.bind(this);

            this.dataSource.bind(CHANGE, this._refreshHandler);
            this.dataSource.bind(ERROR, this._errorHandler);
        },

        _unbindDataSource: function() {
            var dataSource = this.dataSource;

            if (dataSource) {
                dataSource.unbind(CHANGE, this._refreshHandler);
                dataSource.unbind(ERROR, this._errorHandler);
            }
        },

        _error: function() {

        },

        findByUid: function(uid) {
            var wrapperElement = this._overflowWrapper() || this.element;
            return wrapperElement.find("[" + kendo.attr("uid") + "=" + uid + "]");
        },

        refresh: function(ev) {
            var that = this;
            var node = ev.node;
            var action = ev.action;
            var parentElement = node ? that.findByUid(node.uid) : that.element;
            var itemsToUpdate = ev.items;
            var index = ev.index;
            var updateProxy = that._updateItem.bind(that);
            var removeProxy = that._removeItem.bind(that);

            if (action == "add") {
                that._appendItems(itemsToUpdate, index, parentElement);
            } else if (action == "remove") {
                itemsToUpdate.forEach(removeProxy);
            } else if (action == "itemchange") {
                itemsToUpdate.forEach(updateProxy);
            } else if (action === "itemloaded") {
                that.append(ev.items, parentElement);
            } else {
                this._initData();
            }

            this.trigger(DATABOUND, { item: parentElement, dataItem: node });
        },

        _appendItems: function(items, index, parent) {
            var that = this;
            var referenceItem = parent.find(itemSelector).eq(index);

            if (referenceItem.length) {
                that.insertBefore(items, referenceItem);
            } else {
                that.append(items, parent);
            }
        },

        _removeItem: function(item) {
            var that = this;
            var element = that.findByUid(item.uid);
            that.remove(element);
        },

        _updateItem: function(item) {
            var that = this;
            var element = that.findByUid(item.uid);
            var nextElement = element.next();
            var parentNode = item.parentNode();

            that.remove(element);

            if (nextElement.length) {
                that.insertBefore(item, nextElement);
            } else {
                that.append(item, parentNode && that.findByUid(parentNode.uid));
            }
        },

        _accessors: function() {
            var that = this,
                options = that.options,
                i, field, textField,
                element = that.element;

            for (i in bindings) {
                field = options[bindings[i]];
                textField = element.attr(kendo.attr(i + "-field"));

                if (!field && textField) {
                    field = textField;
                }

                if (!field) {
                    field = i;
                }

                if (!isArray(field)) {
                    field = [field];
                }

                options[bindings[i]] = field;
            }
        },

        _fieldAccessor: function(fieldName) {
            var fieldBindings = this.options[bindings[fieldName]] || [],
                count = fieldBindings.length;

            if (count === 0) {
                return (function(item) { return item[fieldName]; });
            } else {
                return (function(item) {
                    var levels = $.map(fieldBindings, kendo.getter);
                    if (item.level) {
                        return levels[Math.min(item.level(), count - 1)](item);
                    } else {
                        return levels[count - 1](item);
                    }
                });
            }
        },

        _templates: function() {
            var that = this,
                options = that.options,
                fieldAccessor = that._fieldAccessor.bind(that);

            if (options.template && typeof options.template == STRING) {
                options.template = template(options.template);
            } else if (!options.template) {
                options.template = template((data) => {
                    var text = fieldAccessor("text")(data.item);
                    if (!(typeof data.item.encoded != 'undefined' && data.item.encoded === false)) {
                        text = encode(text);
                    }

                    return `<span class='k-menu-link-text' role='none'>${text}</span>`;
                });
            }

            that.templates = {
                content: template((data) => {
                    var item = data.item;
                    var contentHtml = fieldAccessor("content")(item);
                    var contCssAttributes = data.contentCssAttributes(item.toJSON ? item.toJSON() : item);
                    return `<div class='${data.groupWrapperCssClass(data.group)}' ${data.groupAttributes(data.group)}><div ${contCssAttributes} tabindex='-1'>${contentHtml || ''}</div></div>`;
                }),
                group: template((data) =>
                    `<div class='${data.groupWrapperCssClass(data.group)}' ${data.groupAttributes(data.group)}>` +
                    `<ul class='${data.groupCssClass(data.group)}' id='${data.groupId}' role='menu'>` +
                    `${data.renderItems(data)}` +
                    "</ul>" +
                    "</div>"
                ),
                itemWrapper: template((data) => {
                    var item = data.item;
                    var iconPosition = this.options.iconPosition;
                    var url = fieldAccessor("url")(item);
                    var imageUrl = fieldAccessor("imageUrl")(item);
                    var icon = fieldAccessor("icon")(item);
                    var iconClass = fieldAccessor("iconClass")(item);
                    var iconString = ((icon || iconClass) ? kendo.ui.icon({ icon: icon, iconClass: iconClass }) : '' );
                    var imgAttributes = fieldAccessor("imageAttr")(item);
                    var tag = url ? 'a' : 'span';

                    return `<${tag} class='${rendering.textClass(item)}' role='none' ${url ? `href='${kendo.sanitizeLink(url)}'` : ''} >` +
                        (imageUrl ? `<img ${rendering.imageCssAttributes(imgAttributes)}  alt='' src='${imageUrl}' />` : '') +
                        (iconPosition == "before" ? iconString : '') +
                        this.templates.sprite(item) +
                        this.options.template(data) +
                        (iconPosition == "after" ? iconString : '') +
                        data.arrow(data) +
                        `</${tag}>`;
                }),
                item: template((data) => {
                    var item = data.item,
                        menu = data.menu,
                        group = data.group,
                        subGroup = data.subGroup;
                    var contentHtml = fieldAccessor("content")(item);
                    var groupId = kendo.guid();
                    return `<li class='${rendering.wrapperCssClass(group, item)}' ${(item.hasChildren || item.items || item.content) ? 'aria-controls="' + groupId + '"' : '' } ${rendering.itemCssAttributes(item.toJSON ? item.toJSON() : item)} role='menuitem'  ${item.items || item.content ? "aria-haspopup='true'" : ''}` +
                        `${item.enabled === false ? "aria-disabled='true'" : ''}` +
                        kendo.attr("uid") + `='${item.uid}' ` +
                        ((item.items && item.items.length > 0) || item.content ?
                            (item.expanded ?
                                " aria-expanded='true'"
                                : " aria-expanded='false'")
                            : '') +
                        ">" +
                        `${!item.separator ? this.templates.itemWrapper(data) : ''}` +
                        ((item.hasChildren || item.items) ?
                            `${subGroup({ items: item.items, menu: menu, group: { expanded: item.expanded }, groupId: groupId })}`
                            : (item.content || item.contentUrl || contentHtml ?
                            `${data.renderContent($.extend({}, data, { group: { expanded: item.expanded } }))}`
                            : '')
                        ) +
                        "</li>";
                }),
                scrollButton: template(({ direction }) =>
                    `<span class='k-button k-button-md k-button-flat k-button-flat-base k-icon-button k-menu-scroll-button k-menu-scroll-button-${direction === 'left' || direction === 'up' ? 'prev' : 'next'}' unselectable='on'>` +
                        kendo.ui.icon({ icon: `caret-alt-${direction}`, iconClass: "k-button-icon" }) +
                    "</span>"
                ),
                arrow: template(({ item, group }) =>
                    `<span aria-hidden='true' class='k-menu-expand-arrow'>${kendo.ui.icon({ icon: group.horizontal ? "caret-alt-down" : "caret-alt-right" })}</span>`),
                sprite: template((data) => {
                    var spriteCssClass = fieldAccessor("spriteCssClass")(data);
                    if (spriteCssClass) {
                        return `<span class='k-sprite ${spriteCssClass}'></span>`;
                    }
                    return '';
                }),
                empty: template(() => "")
            };
        },

        renderItem: function(options) {
            var that = this;
            options = extend({ menu: that, group: {} }, options);

            var empty = that.templates.empty,
                item = options.item;

            return that.templates.item(extend(options, {
                separator: item.separator ? that.templates.separator : empty,
                sprite: that.templates.sprite,
                itemWrapper: that.templates.itemWrapper,
                renderContent: that.renderContent,
                arrow: item.items || item.content || item[that.options.dataContentField[0]] ? that.templates.arrow : empty,
                subGroup: that.renderGroup.bind(that)
            }, rendering));
        },

        renderGroup: function(options) {
            var that = this;
            var templates = that.templates || options.menu.templates;

            return templates.group(extend({
                renderItems: function(options) {
                    var html = "",
                        i = 0,
                        items = options.items,
                        len = items ? items.length : 0,
                        group = extend({ length: len }, options.group);

                    for (; i < len; i++) {
                        html += options.menu.renderItem(extend(options, {
                            group: group,
                            item: extend({ index: i }, items[i])
                        }));
                    }

                    return html;
                }
            }, options, rendering));
        },

        renderContent: function(options) {
            return options.menu.templates.content(extend(options, rendering));
        }
    });

    var ContextMenu = Menu.extend({
        init: function(element, options) {
            var that = this;

            Menu.fn.init.call(that, element, options);

            that.element.attr(ROLE, "menu");
            that._initialInlineHeight = that.element[0].style && that.element[0].style.height ? that.element[0].style.height : "";
            that._marker = kendo.guid().substring(0, 8);

            that.target = $(that.options.target);

            that._popup();
            that._wire();
        },

        _initOverflow: function(options) {
            var that = this;
            that._openedPopups = {};
            if (options.scrollable && !that._overflowWrapper()) {
                that._popupsWrapper = (that.element.parent().is(childAnimationContainerSelector) ? that.element.closes(animationContainerSelector) : that.element)
                    .wrap(`<div class="k-menu-scroll-wrapper${options.orientation === 'vertical' ? " k-menu-scroll-wrapper-vertical" : ""}"></div>`).parent();

                if (that.options.orientation == "horizontal") {
                    removeSpacesBetweenItems(that.element);
                }

                if (options.appendTo) {
                    options.appendTo = $(options.appendTo);
                    options.appendTo.append(that._popupsWrapper);
                }

                that._initialHeight = that.element[0].style.height;
                that._initialWidth = that.element[0].style.width;
            }
        },

        options: {
            name: "ContextMenu",
            filter: null,
            showOn: "contextmenu",
            orientation: "vertical",
            alignToAnchor: false,
            copyAnchorStyles: true,
            target: "body",
            origin: undefined$1,
            position: undefined$1
        },

        events: [
            OPEN,
            CLOSE,
            ACTIVATE,
            DEACTIVATE,
            SELECT
        ],

        setOptions: function(options) {
            var that = this;

            Menu.fn.setOptions.call(that, options);

            that.target.off(that.showOn + NS + that._marker, that._showProxy);

            if (that.userEvents) {
                that.userEvents.destroy();
            }

            that.target = $(that.options.target);
            if (options.orientation && that.popup.wrapper[0]) {
                that.popup.element.unwrap();
            }

            that._wire();

            Menu.fn.setOptions.call(this, options);
        },

        destroy: function() {
            var that = this;

            that.target.off(that.options.showOn + NS + that._marker);
            DOCUMENT_ELEMENT.off(kendo.support.mousedown + NS + that._marker, that._closeProxy);

            if (that.userEvents) {
                that.userEvents.destroy();
            }

            Menu.fn.destroy.call(that);

            if (that.popup) {
                that.popup.destroy();
            }
        },

        open: function(x, y) {
            var that = this;
            const isHorizontal = that.options.orientation === 'horizontal';
            x = $(x)[0];

            if (typeof x === "number") {
                if (that._initialInlineHeight) {
                    $(that.element).css({ height: that._initialInlineHeight });
                } else {
                    $(that.element).css({ height: "" });
                }
            }

            if (contains(that.element[0], $(x)[0]) || that._itemHasChildren($(x))) { // call parent open for children elements
                Menu.fn.open.call(that, x);
            } else {
                if (that._triggerEvent({ item: that.element, type: OPEN }) === false) {
                    if (that.popup.visible() && that.options.filter) {
                        that.popup.close(true);
                        that.popup.element.parent().kendoStop(true);
                    }

                    if (!that._triggerFocusOnActivate) {
                        that._triggerFocusOnActivate = that._focusMenu.bind(that);
                    }
                    that.bind(ACTIVATE, that._triggerFocusOnActivate);

                    if (y !== undefined$1) {
                        var overflowWrapper = that._overflowWrapper();
                        if (overflowWrapper) {
                            var offset = overflowWrapper.offset();
                            x -= offset.left;
                            y -= offset.top;
                        }
                        that.popup.wrapper.hide();
                        that._configurePopupScrolling(x, y);
                        that.popup.open(x, y);
                    } else {
                        that.popup.options.anchor = (x ? x : that.popup.anchor) || that.target;
                        that.popup.element.kendoStop(true);
                        that._configurePopupScrolling();
                        that.popup.open();
                    }

                    that._initPopupScrolling(that.popup, isHorizontal);
                    that.popup.element.siblings(scrollButtonSelector).hide();
                    DOCUMENT_ELEMENT.off(that.popup.downEvent, that.popup._mousedownProxy);
                    DOCUMENT_ELEMENT
                        .on(kendo.support.mousedown + NS + that._marker, that._closeProxy);
                }
            }

            return that;
        },

        _focusMenu: function() {
            var that = this;

            that.unbind(ACTIVATE, that._triggerFocusOnActivate);
            that.element.trigger("focus");
        },

        _configurePopupScrolling: function(x, y) {
            var that = this;
            var popup = that.popup;
            var isHorizontal = that.options.orientation == "horizontal";

            if (that.options.scrollable) {
                that._wrapPopupElement(popup);

                popup.element.parent().css({
                    position: "",
                    height: ""
                });

                popup.element.css({
                    visibility: "hidden",
                    display: "",
                    position: ""
                });

                if (isHorizontal) {
                    that._setPopupWidth(popup, isNaN(x) ? undefined$1 : { isFixed: true, x: x, y: y });
                } else {
                    that._setPopupHeight(popup, isNaN(x) ? undefined$1 : { isFixed: true, x: x, y: y });
                }

                popup.element.css({
                    visibility: "",
                    display: "none",
                    position: "absolute"
                });
            }
        },

        _setPopupWidth: function(popup, isFixed) {
            var popupElement = popup.element;
            var popups = popupElement.add(popupElement.parent(childAnimationContainerSelector));

            popups.width(this._initialWidth || "");

            var location = popup._location(isFixed);
            var windowWidth = $(window).width();
            var popupOuterWidth = location.width;
            var popupOffsetLeft = Math.max(location.left, 0);
            var scrollLeft = isFixed ? 0 : parentsScroll(this._overflowWrapper()[0], "scrollLeft");
            var shadow = kendo.getShadows(popupElement);
            var maxWidth = windowWidth - shadow.left - shadow.right;
            var canFit = maxWidth + scrollLeft > popupOuterWidth + popupOffsetLeft;

            if (!canFit) {
                popups.css({ overflow: "hidden", width: (maxWidth - popupOffsetLeft + scrollLeft) + "px" });
            }
        },

        close: function() {
            var that = this;

            if (contains(that.element[0], $(arguments[0])[0]) || that._itemHasChildren(arguments[0])) {
                Menu.fn.close.call(that, arguments[0]);
            } else {
                if (that.popup.visible()) {
                    if (that._triggerEvent({ item: that.element, type: CLOSE }) === false) {
                        that._removeFocusItem();
                        that.element.find("#" + that._ariaId).removeAttr("id");
                        that.popup.close();
                        DOCUMENT_ELEMENT.off(kendo.support.mousedown + NS + that._marker, that._closeProxy);
                        that.unbind(SELECT, that._closeTimeoutProxy);
                        that.popup.options.anchor.focus();
                    }
                }
            }
        },

        _showHandler: function(e) {
            var ev = e, offset,
                that = this,
                options = that.options,
                target = kendo.support.mobileOS ? $(ev.target) : $(ev.currentTarget);

            if (e.event) {
                ev = e.event;
                ev.pageX = e.x.location;
                ev.pageY = e.y.location;
            }

            if (contains(that.element[0], e.relatedTarget || e.target)) {
                return;
            }

            that._eventOrigin = ev;

            ev.preventDefault();
            ev.stopImmediatePropagation();

            that.element.find("." + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);

            if ((options.filter && target.is(options.filter)) || !options.filter) {
                if (options.alignToAnchor) {
                    that.popup.options.anchor = ev.currentTarget;
                    that.open(ev.currentTarget);
                } else {
                    that.popup.options.anchor = ev.currentTarget;

                    if (that._targetChild) {
                        offset = that.target.offset();
                        that.open(ev.pageX - offset.left, ev.pageY - offset.top);
                    } else {
                        that.open(ev.pageX, ev.pageY);
                    }
                }
            }
        },

        _closeHandler: function(e) {
            var that = this,
                target = $(e.relatedTarget || e.target),
                sameTarget = target.closest(that.target.selector)[0] == that.target[0],
                item = target.closest(itemSelector),
                children = that._itemHasChildren(item),
                overflowWrapper = that._overflowWrapper(),
                containment = contains(that.element[0], target[0]) || (overflowWrapper && contains(overflowWrapper[0], target[0]));

            that._eventOrigin = e;

            var normalClick = e.which !== 3;

            if (that.popup.visible() && ((normalClick && sameTarget) || !sameTarget) && ((that.options.closeOnClick && !children && containment) || !containment)) {
                if (containment) {
                    this.unbind(SELECT, this._closeTimeoutProxy);
                    that.bind(SELECT, that._closeTimeoutProxy);
                } else {
                    that.close();
                }
            }
        },

        _wire: function() {
            var that = this,
                options = that.options,
                target = that.target;

            that._preventProxy = null;
            that._showProxy = that._showHandler.bind(that);
            that._closeProxy = that._closeHandler.bind(that);
            that._closeTimeoutProxy = that.close.bind(that);

            if (target[0]) {
                if (kendo.support.mobileOS && options.showOn == "contextmenu") {
                    that.userEvents = new kendo.UserEvents(target, {
                        filter: options.filter,
                        allowSelection: false
                    });

                    that._preventProxy = function() { return false; };

                    that.userEvents.bind("hold", that._showProxy);
                }

                if (options.filter) {
                    target.on(options.showOn + NS + that._marker, options.filter, that._preventProxy || that._showProxy);
                } else {
                    target.on(options.showOn + NS + that._marker, that._preventProxy || that._showProxy);
                }

                target.on("keydown", (e) => {
                    if (e.keyCode === kendo.keys.F10 && e.shiftKey) {
                        e.preventDefault();
                        that.open(e.target);
                    }
                });
            }
        },

        _triggerEvent: function(e) {
            var that = this,
                anchor = $(that.popup.options.anchor)[0],
                origin = that._eventOrigin;

            that._eventOrigin = undefined$1;

            return that.trigger(e.type, extend({ type: e.type, item: e.item || this.element[0], target: anchor }, origin ? { event: origin } : {} ));
        },

        _popup: function() {
            var that = this;
            var overflowWrapper = that._overflowWrapper();
            var contextMenuElement = that.element
                .addClass("k-context-menu");

            that._triggerProxy = that._triggerEvent.bind(that);

            that.popup = $("<div></div>")
                            .append(contextMenuElement)
                            .kendoPopup({
                                origin: that.options.origin,
                                position: that.options.position,
                                autosize: that.options.orientation === "horizontal",
                                anchor: that.target || "body",
                                copyAnchorStyles: that.options.copyAnchorStyles,
                                collision: that.options.popupCollision || "fit",
                                animation: that.options.animation,
                                activate: that._triggerProxy,
                                deactivate: that._triggerProxy,
                                appendTo: overflowWrapper || that.options.appendTo,
                                close: !overflowWrapper ? $.noop : function(e) {
                                    $(getChildPopups(e.sender.element, overflowWrapper)).each(function(i, p) {
                                        var popup = p.data(KENDOPOPUP);
                                        if (popup) {
                                            popup.close(true);
                                        }
                                    });
                                }
                            }).data(KENDOPOPUP);

            that._targetChild = contains(that.target[0], that.popup.element[0]);
        },

        _moveFocusToRoot: function(item, nextItem) {
            this._moveFocus(item, nextItem);
            this.close();
        },

        _focus: function(e) {
            var focusItem = this._oldFocusItem = this._focusItem() || [];

            Menu.fn._focus.call(this, e);

            if (activeElement() === e.currentTarget) {
                this._moveFocus(focusItem, this.wrapper.children().filter(":visible").not(".k-separator").first());
            }
        }
    });

    ui.plugin(Menu);
    ui.plugin(ContextMenu);

})(window.kendo.jQuery);
var kendo$1 = kendo;

export { __meta__, kendo$1 as default };