text:
"use strict";
define(['ojs/ojcore', 'jquery', 'ojs/ojcomponentcore','ojs/ojbutton','ojs/ojmenu','ojs/ojlistview'],
       function(oj, $)
{

/**
 * Handler for Expanded Navigation List
 * @constructor
 * @ignore
 */
oj.DefaultNavListHandler = function (widget, root, component)
{
    this.m_widget = widget;
    this.m_root = root;
    this.m_component = component;
};
/**
 * Restore Listview element
 * @private
 */
oj.DefaultNavListHandler.prototype.Destroy = function ()
{
    this.m_root.removeClass('oj-navigationlist-expanded oj-navigationlist-vertical');
};
/**
 * Expand group Item
 * @param {jQuery} groupItem  Group Item
 * @param {boolean} animate true if animate the expand operation, false otherwise
 * @private
 */
oj.DefaultNavListHandler.prototype.Expand = function (groupItem, animate) {
    // Do nothing
};

/**
 * Collapse group Item
 * @param {jQuery} item  Group Item
 * @param {boolean} animate true if animate the collapse operation, false otherwise
 * @private
 */
oj.DefaultNavListHandler.prototype.Collapse = function (item, animate) {
    // Do nothing
};

/**
 * Handle keyboard events for expand and collapse
 * @private
 */
oj.DefaultNavListHandler.prototype.HandleExpandAndCollapseKeys = function (event, keyCode, current, currentItemKey) {
    return false;
};

/**
 * Mofify List item
 * @private
 */
oj.DefaultNavListHandler.prototype.ModifyListItem = function ($item, itemContent) {
   //Do nothing
};

/**
 * Update aria properties when an item is selected.
 * @private
 */
oj.DefaultNavListHandler.prototype.UpdateAriaPropertiesOnSelectedItem = function (elem, highlight) {
    elem.attr("aria-selected", highlight ? 'true' : 'false');
};

/**
 * Placeholder to override or update generated dom after completing rendering
 * @private
 */
oj.DefaultNavListHandler.prototype.BeforeRenderComplete = function () {

};
/**
 * Called by content handler once the content of an item is rendered triggered by an insert event
 * @param {Element} elem the item element
 * @param {Object} context the context object used for the item
 * @private
 */
oj.DefaultNavListHandler.prototype.ItemInsertComplete = function(elem, context)
{

};

/**
 * Called by content handler once the content of an item is removed triggered by an remove event
 * @param {Element} elem the item element
 * @private
 */
oj.DefaultNavListHandler.prototype.ItemRemoveComplete = function(elem)
{

};
/**
 * Handles arrow keys navigation on item
 * @param {number} keyCode description
 * @param {boolean} isExtend
 * @param {Event} event the DOM event causing the arrow keys
 * @private
 */
oj.DefaultNavListHandler.prototype.HandleArrowKeys = function (keyCode, isExtend, event) {
    return _ojNavigationListView.superclass.HandleArrowKeys.apply(this.m_widget, arguments);
};

/**
 * Determine whether the key code is an arrow key
 * @param {number} keyCode
 * @return {boolean} true if it's an arrow key, false otherwise
 * @private
 */
oj.DefaultNavListHandler.prototype.IsArrowKey = function (keyCode) {
    return _ojNavigationListView.superclass.IsArrowKey.apply(this.m_widget, arguments);
};
/**
 * Determines whether the specified item is expanded
 * @param {jQuery} item the item element
 * @return {number} 0 if item is expanded, 1 if item is collapsed, 2 if item cannot be expand or collapse.
 * @private
 */
oj.DefaultNavListHandler.prototype.GetState = function (item) {
    return _ojNavigationListView.superclass.GetState.apply(this.m_widget, arguments);
};
/**
 * Sets the disclosed state of the item
 * @param {jQuery} item the item element
 * @param {number} state 0 if item is expanded, 1 if item is collapsed, 2 if item cannot be expand or collapse.
 * @private
 */
oj.DefaultNavListHandler.prototype.SetState = function (item, state) {
    _ojNavigationListView.superclass.SetState.apply(this.m_widget, arguments);
};

oj.DefaultNavListHandler.prototype.Init = function (opts) {
    this.m_root.addClass('oj-navigationlist-expanded oj-navigationlist-vertical');
};

/**
 * Check whether the item is selectable
 * @param {Element} item the item element
 * @return {boolean} true if item is selectable
 * @private
 */
oj.DefaultNavListHandler.prototype.IsSelectable = function (item)
{
    return _ojNavigationListView.superclass.IsSelectable.apply(this.m_widget, arguments);
};

/**
 * Restore Item
 * @param {jQuery} item, List item
 * @param {jQuery} itemContent, Item contentelement
 * @param {jQuery} sublist, sub list when item is a group item.
 * @private
 */
oj.DefaultNavListHandler.prototype.RestoreItem = function (item, itemContent, sublist) {

};

/**
 * In case of sliding navigation List, Collapses the current visible list if it is not the top level list
 * @private
 */
oj.DefaultNavListHandler.prototype.CollapseCurrentList = function () {
    //DO Nothing
};

/**
 * Invoked when an option was updated after component initialization.
 * Note: This will be invoked only for specifc options. see setOptions method in NavigationList.js.
 * @private
 */
oj.DefaultNavListHandler.prototype.setOptions = function (options) {
    //DO Nothing
};

/**
 * Handler for Horizontal Navigation List
 * @constructor
 * @extends oj.DefaultNavListHandler
 * @ignore
 */

oj.HorizontalNavListHandler = function (widget, root, component)
{
    oj.HorizontalNavListHandler.superclass.constructor.call(this, widget, root, component);
};

// Subclass from oj.Object
oj.Object.createSubclass(oj.HorizontalNavListHandler, oj.DefaultNavListHandler, "oj.HorizontalNavListHandler");

oj.HorizontalNavListHandler.prototype.Destroy = function ()
{
    this.m_root.removeClass('oj-navigationlist-expanded oj-navigationlist-horizontal');
    this.m_root.find('.'+this.m_widget.DIVIDER_STYLE_CLASS).remove();
};

oj.HorizontalNavListHandler.prototype.UpdateAriaPropertiesOnSelectedItem = function (elem, highlight) {
    elem.attr('aria-pressed', highlight ? 'true' : 'false');
};

/**
 * Handles arrow keys navigation on item
 * @param {number} keyCode description
 * @param {boolean} isExtend
 * @param {Event} event the DOM event causing the arrow keys
 * @private
 */
oj.HorizontalNavListHandler.prototype.HandleArrowKeys = function (keyCode, isExtend, event) {
    //Change keyCode to reverse left/right arrow keys for rtl case.
    if (keyCode === $.ui.keyCode.LEFT)
        keyCode = this.m_widget.isRtl() ? $.ui.keyCode.DOWN : $.ui.keyCode.UP;
    else if (keyCode === $.ui.keyCode.RIGHT)
        keyCode = this.m_widget.isRtl() ? $.ui.keyCode.UP : $.ui.keyCode.DOWN;

    var processed = _ojNavigationListView.superclass.HandleArrowKeys.call(this.m_widget, keyCode, isExtend, event);
    if (this.m_widget.ojContext.options['edge'] === 'top') {
        var current = this.m_widget.m_active['elem'];
        current[0].scrollIntoView(false);
    }
    return processed;
};

/**
 *
 * @param {number} keyCode
 * @return {boolean}
 * @private
 */
oj.HorizontalNavListHandler.prototype.IsArrowKey = function (keyCode)
{
    return (keyCode === this.m_widget.UP_KEY || keyCode === this.m_widget.DOWN_KEY || keyCode === this.m_widget.LEFT_KEY || keyCode === this.m_widget.RIGHT_KEY);
};

oj.HorizontalNavListHandler.prototype.ModifyListItem = function ($item, itemContent) {
    var focusableElement = this.m_widget.getSingleFocusableElement($item);
    focusableElement.attr('role', 'button');
    if(focusableElement[0].hasAttribute('aria-selected')){
        focusableElement.attr('aria-pressed', 'false');
        focusableElement.removeAttr('aria-selected');
    }
};

oj.HorizontalNavListHandler.prototype.BeforeRenderComplete = function () {
    var self = this;
    this.m_widget.element.attr('role', 'toolbar');
    this.m_widget.element.find('.' + this.m_widget.getItemElementStyleClass()+':visible').each(function (index) {
        if (index > 0) {
            self._addSeparator(this, index);
        }
    });
};

oj.HorizontalNavListHandler.prototype._addSeparator = function(elem, index) {
    var $elem = $(elem);
    var previousElement = $elem.prev();
    if(index > 0
        && $elem.is(':visible')
        && previousElement.length
        && !previousElement.is("li."+ this.m_widget.DIVIDER_STYLE_CLASS))
    {
            $elem.before('

');//@HTMLUpdateOK
    }

};

oj.HorizontalNavListHandler.prototype.ItemInsertComplete = function(elem, context)
{
    this._addSeparator(elem, context.index);
};

oj.HorizontalNavListHandler.prototype.ItemRemoveComplete = function(elem)
{
    var $elem = $(elem), previousElement = $elem.prev();
    if( previousElement.length && previousElement.is("li."+this.m_widget.DIVIDER_STYLE_CLASS)){
        previousElement.remove();
    }else{
        // Means,this could be the first element,
        //so ensure that divider is not present on next element which is going to be the first one.
        //This is needed because when complete observable array is updated with new set of records, first new records will be added before removing old ones.
        var nextElement = $elem.next();
        if(nextElement.is("li."+ this.m_widget.DIVIDER_STYLE_CLASS)) {
            nextElement.remove();
        }
    }
};

oj.HorizontalNavListHandler.prototype.IsSelectable = function (item)
{
    return  this.m_widget.getFocusItem($(item))[0].hasAttribute("aria-pressed");
};

oj.HorizontalNavListHandler.prototype.Init = function (opts) {
    this.m_root.addClass('oj-navigationlist-expanded oj-navigationlist-horizontal');
};

oj.HorizontalNavListHandler.prototype.RestoreItem = function (item, itemContent, sublist) {

};

/**
 * Handler for Collapsible Navigation List
 * @constructor
 * @extends oj.DefaultNavListHandler
 * @ignore
 */
oj.CollapsibleNavListHandler = function (widget, root, component)
{
    oj.CollapsibleNavListHandler.superclass.constructor.call(this, widget, root, component);
};
// Subclass from oj.Object
oj.Object.createSubclass(oj.CollapsibleNavListHandler, oj.DefaultNavListHandler, "oj.CollapsibleNavListHandler");

oj.CollapsibleNavListHandler.prototype.Destroy = function ()
{
    this.m_root.removeClass('oj-navigationlist-collapsible oj-navigationlist-vertical');
};

oj.CollapsibleNavListHandler.prototype.Init = function (opts) {
    this.m_root.addClass('oj-navigationlist-collapsible oj-navigationlist-vertical');
};

oj.CollapsibleNavListHandler.prototype.Expand = function (groupItem, animate) {
    _ojNavigationListView.superclass.AnimateExpand.apply(this.m_widget, arguments);
};

oj.CollapsibleNavListHandler.prototype.Collapse = function (item, animate) {
    _ojNavigationListView.superclass.AnimateCollapse.apply(this.m_widget, arguments);
};

oj.CollapsibleNavListHandler.prototype.HandleExpandAndCollapseKeys = function (event, keyCode, current, currentItemKey) {
    var isGroupItem = current.children('.' + this.m_widget.getGroupStyleClass()).length > 0;
    if (keyCode === this.m_widget.LEFT_KEY || keyCode === this.m_widget.RIGHT_KEY)
    {
        //Need to reverse left/right functionality  in rtl case
        if ((keyCode === this.m_widget.LEFT_KEY && !this.m_widget.isRtl()) || (keyCode === this.m_widget.RIGHT_KEY && this.m_widget.isRtl()))
        {
            if (this.m_widget.GetState(current) === this.m_widget.STATE_EXPANDED)
            {
                this.m_widget.CollapseItem(current, event, true, currentItemKey, true, true);
            }
        }
        else
        {
            if (this.m_widget.GetState(current) === this.m_widget.STATE_COLLAPSED)
            {
                this.m_widget.ExpandItem(current, event, true, currentItemKey, true, true, true);
            }
        }
        return true;
    } else if (isGroupItem && (keyCode === $.ui.keyCode.ENTER || keyCode === $.ui.keyCode.SPACE)) {
        if (current.length <= 0)
            return;
        if (this.m_widget.GetState(current) === this.m_widget.STATE_COLLAPSED) {
            this.m_widget.ExpandItem(current, null, true, currentItemKey, true, true, true);
        } else if (this.m_widget.GetState(current) === this.m_widget.STATE_EXPANDED) {
            this.m_widget.CollapseItem(current, null, true, currentItemKey, true, true);
        }
        return true;
    }
    return false;
};

oj.CollapsibleNavListHandler.prototype.RestoreItem = function (item, itemContent, sublist) {

};
/**
 * Handler for Sliding Navigation List
 * @constructor
 * @extends oj.CollapsibleNavListHandler
 * @ignore
 */
oj.SlidingNavListHandler = function (widget, root, component)
{
    oj.SlidingNavListHandler.superclass.constructor.call(this, widget, root, component);
    this.m_expanded = [];
};

// Subclass from oj.Object
oj.Object.createSubclass(oj.SlidingNavListHandler, oj.CollapsibleNavListHandler, "oj.SlidingNavListHandler");

oj.SlidingNavListHandler.prototype.Destroy = function ()
{
    this.m_root.removeClass('oj-navigationlist-slider oj-navigationlist-vertical');
    this._toolbar.remove();
};
/**
 * Intiate Expand/collapse animation.
 *
 * @param {Object} item, item which is going to be expanded.
 * @param {boolean} isMovingNext true for expand animation and false for collapse animation.
 * @param {Object} focusableElement, focusable element after animation.
 */
oj.SlidingNavListHandler.prototype._slideAnimation = function (item, isMovingNext, focusableElement) {
    var self = this;
    var list_root = this.m_widget.getRootElement();
    var contentWidth = list_root.outerWidth() / 2;
    var isRtl = this.m_widget.isRtl();
    if (!isMovingNext) {
        contentWidth = contentWidth * -1;
    }
    if (isRtl) {
        list_root.css({
            "margin-right": contentWidth
        });
        list_root.animate({
            "margin-right": "0px"
        }, 400, 'swing', function () {
            self._slideAnimationComplete(item, isMovingNext, focusableElement);
        });
    } else {
        list_root.css({
            "margin-left": contentWidth
        });
        list_root.animate({
            "margin-left": "0px"
        }, 400, 'swing', function () {
            self._slideAnimationComplete(item, isMovingNext, focusableElement);
        });
    }
};

/**
 * Update ui after animation.
 *
 * @param {Object} item, item which is going to be expanded.
 * @param {boolean} isMovingNext true for expand animation and false for collapse animation
 * @param {Object|null} focusableElement, focusable element after animation.
 * @private
 */
oj.SlidingNavListHandler.prototype._slideAnimationComplete = function (item, isMovingNext, focusableElement) {
    if (this.m_widget.m_contentHandler === null)
        return;
    if(focusableElement)
    {
        var key = this.m_widget.GetKey(focusableElement[0]);
        this.m_widget.SetOption('currentItem', key);//Set current option on listview
    }
    if (!isMovingNext) {
        this.m_widget.AnimateCollapseComplete(item.children('.' + this.m_widget.getGroupStyleClass()));
    } else {
        this.m_widget.AnimateExpandComplete(item.children('.' + this.m_widget.getGroupStyleClass()));
    }
};

/**
 * Expand item in sliding navigation list
 * @param {Object} groupItem group item to be expanded
 * @param {boolean} animate flag to trigger animation or not
 * @private
 */
oj.SlidingNavListHandler.prototype.Expand = function (groupItem, animate) {
    var target = $(groupItem).parents('.oj-navigationlist-item-element:first');
    var sublist = target.children('.' + this.m_widget.getGroupStyleClass()),
            parentLabel,
            nextFocusableItem = null;

    var currentListRoot = target.closest('.' + this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS);
    if (currentListRoot.length > 0) {
        //Move marker style class to expanded node only when it is child of an already expanded node.
        //It is possible that child is expanded before parent, in which we need should not remove marker class from child.
        //Ref , During initialization, listview expands child before parent which is causing the issue.
        currentListRoot.removeClass(this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS);
        target.addClass(this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS);
        nextFocusableItem = sublist.find('.' + this.m_widget.getItemElementStyleClass() + ':eq(0)');
        var listOfParents = target.parentsUntil(currentListRoot, 'ul');
        if (currentListRoot.is(this.m_widget.element)){
            listOfParents = listOfParents.get().concat(currentListRoot.get());
        }else{
            listOfParents = listOfParents.get();
        }

        var self = this, itemNode;
        listOfParents = $(listOfParents.reverse());
        listOfParents.each(function (i, parentList) {
            if ($(parentList).is(self.m_widget.element)) {
                parentLabel = self.m_widget.getRootLabel();
            } else {
                parentLabel = self.m_widget.getItemLabel($(parentList).parent());
            }
            if (i === listOfParents.length - 1) {
                itemNode = target;
            } else {
                itemNode = $(listOfParents.get(i + 1)).parent();
            }
            self._addItemToHviewMenu(self.m_widget.GetKey(itemNode[0]), self.m_widget.getItemLabel(itemNode), parentLabel);
            // this var keeps a stack of expanded items
            self.m_expanded.push(itemNode);
        });
    }

    if (animate)
        this._slideAnimation(target, true, nextFocusableItem);
    else
        this._slideAnimationComplete(target, true, nextFocusableItem);

    this.m_widget.element.focus();
    //For ios, it is needed to set aria-hidden.
    target.siblings().attr('aria-hidden', 'true');
    target.children('.' + this.m_widget.getGroupItemStyleClass())
            .children('.' + this.m_widget.ITEM_CONTENT_STYLE_CLASS)
            .attr('aria-hidden', 'true');
    sublist.removeAttr('aria-hidden');

    // undo any display set by ListView
    groupItem.css("display", "");
    //Skip focus for group element
    target.addClass('oj-skipfocus');
};

/**
 * Collapse item in sliding navigation list
 * @param {Object} target target list root
 * @param {boolean} animate flag to trigger animation or not
 * @private
 */
oj.SlidingNavListHandler.prototype.Collapse = function (target, animate) {
    var currentList = target.children('.' + this.m_widget.getGroupStyleClass()),
            parentlist = target.parent();

    target.children('.' + this.m_widget.getGroupItemStyleClass())
            .children('.' + this.m_widget.ITEM_CONTENT_STYLE_CLASS)
            .removeAttr('aria-hidden');
    currentList.attr('aria-hidden', 'true');
    target.siblings().removeAttr('aria-hidden');

    //Enable focus for group element
    target.removeClass('oj-skipfocus');

    target.removeClass(this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS);
    //While collapsing node, if any of parent is already having current style class then don't add again
    if(target.closest('.'+this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS).length === 0){
            parentlist.closest('.' + this.m_widget.getItemElementStyleClass()).addClass(this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS);
            if (this.m_widget.element.is(parentlist)) {
                    this.m_widget.element.addClass(this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS);
            }
    }

    if (animate)
        this._slideAnimation(target, false, currentList.parent());
    else
        this._slideAnimationComplete(target, false, currentList.parent());

    this._removeItemFromHviewMenu();
    this.m_widget.element.focus();
};

oj.SlidingNavListHandler.prototype.UpdateAriaPropertiesOnSelectedItem = function (elem, highlight) {
    if (highlight)
        elem.attr('aria-describedby', 'selectedLabel');
    else
        elem.removeAttr('aria-describedby');
};
/**
 * Determines whether the specified item is expanded
 * @param {jQuery} item the item element
 * @return {number} 0 if item is expanded, 1 if item is collapsed, 2 if item cannot be expand or collapse.
 * @private
 */
oj.SlidingNavListHandler.prototype.GetState = function (item) {
    var expanded = this.m_widget.getFocusItem(item).attr("aria-expanded");
    if (expanded === "true")
    {
        return this.m_widget.STATE_EXPANDED;
    }
    else if (expanded === "false")
    {
        return this.m_widget.STATE_COLLAPSED;
    }
    else
    {
        return this.m_widget.STATE_NONE;
    }
};
/**
 * Sets the disclosed state of the item
 * @param {jQuery} item the item element
 * @param {number} state 0 if item is expanded, 1 if item is collapsed, 2 if item cannot be expand or collapse.
 * @private
 */
oj.SlidingNavListHandler.prototype.SetState = function (item, state)
{
    if (state === this.m_widget.STATE_EXPANDED)
    {
        this.m_widget.getFocusItem(item)
                .attr("aria-expanded", "true");
        item.removeClass(this.m_widget.COLLAPSED_STYLE_CLASS)
                .addClass(this.m_widget.EXPANDED_STYLE_CLASS);

    }
    else if (state === this.m_widget.STATE_COLLAPSED)
    {
        this.m_widget.getFocusItem(item)
                .attr("aria-expanded", "false");
        item.removeClass(this.m_widget.EXPANDED_STYLE_CLASS)
                .addClass(this.m_widget.COLLAPSED_STYLE_CLASS);
    }
};

oj.SlidingNavListHandler.prototype.ModifyListItem = function ($item, itemContent) {
    var focusableElement = this.m_widget.getFocusItem($item);

    focusableElement.attr('role', 'menuitem');
    if (!itemContent.attr('id'))
        itemContent.uniqueId();
    // Ensure that it collapses all nodes.
    var groupItems = $item.children('.' + this.m_widget.getGroupStyleClass());
    if (groupItems.length > 0) {
        focusableElement.attr('aria-haspopup', 'true');
        groupItems.attr('role', 'menu');
        groupItems.css("display", "");
        $item.removeAttr('aria-expanded');
        focusableElement.attr('aria-expanded', 'false');
    }
};

oj.SlidingNavListHandler.prototype.BeforeRenderComplete = function () {
    this.m_widget.element.attr('role', 'menu');
};

oj.SlidingNavListHandler.prototype.Init = function (opts) {
    this.m_root.addClass('oj-navigationlist-slider oj-navigationlist-vertical');
    opts.element.addClass('oj-navigationlist-current');
    this._buildSlidingNavListHeader(opts);
    this._initializeHierarchicalView();
};
/**
 * Initialize sliding navigation list header .
 * @private
 * @memberof! oj.ojNavigationList
 */
oj.SlidingNavListHandler.prototype._buildSlidingNavListHeader = function (opts)
{
    var self = this, vSeparator, selectedLabel;
    this._toolbar = $(document.createElement('div'));
    this._toolbar.addClass('oj-navigationlist-toolbar');
    this._previousLink = $(document.createElement('a'));
    this._prevIcon = $(document.createElement('span'));
    this._prevIcon.addClass('oj-navigationlist-previous-icon oj-component-icon oj-clickable-icon-nocontext')
            .attr('role', 'img')
            .attr('alt', this.m_component.getTranslatedString('previousIcon'));
    this._prevIcon.hide();
    this._previousLink.addClass('oj-navigationlist-previous-link')
            .attr('tabindex', '-1')
            .append(this._prevIcon);// @HTMLUpdateOK
    this._headerLabel = $(document.createElement('label'));
    this._headerLabel.addClass('oj-navigationlist-current-header')
            .text(this.m_widget.getRootLabel());
    this._vSeparator = $(document.createElement('span'));
    this._vSeparator.attr('role', 'separator')
            .attr('aria-orientation', 'vertical')
            .addClass('oj-navigationlist-toolbar-separator');
    this._hviewBtn = $(document.createElement('button'));
    this._hviewBtn.addClass('oj-navigationlist-hierarchical-button');
    this._hviewMenu = $(document.createElement('ul'));
    this._hviewMenu.addClass('oj-navigationlist-hierarchical-menu').hide();
    selectedLabel = $(document.createElement('label'));
    selectedLabel.addClass('oj-helper-hidden-accessible')
            .attr('aria-hidden', 'true')
            .attr('id', 'selectedLabel');
    selectedLabel.text(this.m_component.getTranslatedString('selectedLabel'));
    this._previousLink.append(this._headerLabel);// @HTMLUpdateOK
    this._toolbar.append(this._previousLink)// @HTMLUpdateOK
            .append(this._vSeparator)// @HTMLUpdateOK
            .append(this._hviewBtn)// @HTMLUpdateOK
            .append(this._hviewMenu)// @HTMLUpdateOK
            .append(selectedLabel);// @HTMLUpdateOK
    this.m_root.prepend(this._toolbar);// @HTMLUpdateOK
    this._showOrHideHierarchyMenu(opts.hierarchyMenuDisplayThresholdLevel);
};

/**
 * In case of sliding navigation List, Collapses the current visible list if it is not the top level list
 * @private
 */
oj.SlidingNavListHandler.prototype.CollapseCurrentList = function () {
    // pop the expanded item stack
    var current = this.m_expanded.pop();
    if(current) {
        this.m_widget.CollapseItem(current, null, true, null, true, true);
    }
};

/**
 * Initialize hierarchical view for sliding navlist.
 * @private
 * @memberof! oj.ojNavigationList
 */
oj.SlidingNavListHandler.prototype._initializeHierarchicalView = function () {
    var self = this,
            menuid = this._hviewMenu.uniqueId().attr('id');
    this._hviewMenu.ojMenu({
        openOptions: {
            position: {
                "my": "end top",
                "at": "end bottom"
            }
        },
        select: function (event, ui) {
            var itemsToRemove = ui.item.nextAll(),
                    currentKey, item,
                    expandedItems = self.m_expanded,
                    targetItemKey = ui.item.data('key');
            //collapse all child lists untill target list is visible
            while (expandedItems.length > 0) {
                item = expandedItems.pop();// remove item from list
                currentKey = self.m_widget.GetKey(item[0]);
                self.m_widget.CollapseItem($(item), null, true, currentKey, true, true);
                if (targetItemKey === currentKey) {
                    break;
                }
            }
            itemsToRemove.remove();
            ui.item.remove();
            self._hviewMenu.ojMenu('refresh');
        }
    });
    this._hviewBtn.ojButton({
        'label': this.m_component.getTranslatedString('hierMenuBtnLabel'),
        'display': 'icons',
        'icons': {
            start: 'oj-fwk-icon oj-hier-icon'
        },
        'menu': '#' + menuid,
        'disabled': true,
        'chroming': 'half'
    });
};

/**
 * Add current visible group item to hierarchical menu and update header text with new list's label.
 * @param {string} itemKey key of the group item whose list will be displayed
 * @param {string} label current list's label
 * @param {string} parentLabel parent list's label
 * @private
 */
oj.SlidingNavListHandler.prototype._addItemToHviewMenu = function (itemKey, label, parentLabel) {
    if (this._hviewBtn) {
        var itemsinTree = this._hviewMenu.find('li').length;
        var menuListItem = $(document.createElement('li'));
        var menuItem = $(document.createElement('a'));
        menuItem.attr('href', '#');
        menuListItem.append(menuItem);// @HTMLUpdateOK
        if (itemsinTree > 0) {
            for (var i = 0; i < itemsinTree; i++) {
                if (i > 0) {
                    menuItem.append($(document.createElement('span'))// @HTMLUpdateOK
                            .addClass('oj-navigationlist-hvitem-space'));
                }
            }
            menuItem.append($(document.createElement('span'))// @HTMLUpdateOK
                    .addClass('oj-menu-item-icon oj-icon oj-navigationlist-level-indicator'));
        }
        var menuItemLabel = $(document.createElement('span'))
                .addClass('oj-navigationlist-hierarchical-menu-label');
        menuItemLabel.text(parentLabel);
        menuItem.append(menuItemLabel);// @HTMLUpdateOK

        //Store item key reference to refresh the list when user clicks on  hiearchical menu item.
        menuListItem.data('key', itemKey);
        this._hviewMenu.append(menuListItem);// @HTMLUpdateOK

        this._hviewMenu.ojMenu('refresh');
        this._showOrHideHierarchyMenu(this.m_widget.GetOption('hierarchyMenuDisplayThresholdLevel'));
        this._hviewBtn.ojButton("option", "disabled", false);
        this._prevIcon.show();
        this._previousLink.attr('tabindex', '0');
        this._headerLabel.text(label);
    }
};
oj.SlidingNavListHandler.prototype.setOptions = function (options) {
    var currentHMenuDisplayThreshold =  this.m_widget.GetOption('hierarchyMenuDisplayThresholdLevel');
    if (currentHMenuDisplayThreshold !== options['hierarchyMenuDisplayThresholdLevel']) {
        this._showOrHideHierarchyMenu(options.hierarchyMenuDisplayThresholdLevel);
    }
};
oj.SlidingNavListHandler.prototype._showOrHideHierarchyMenu =  function (hierarchyMenuDisplayThresholdLevel) {
    var itemsinTree = this._hviewMenu.find('li').length;
    if(hierarchyMenuDisplayThresholdLevel === -1 || itemsinTree < hierarchyMenuDisplayThresholdLevel ){
        this._vSeparator.hide();
        this._hviewBtn.hide();
    }else if(itemsinTree >= hierarchyMenuDisplayThresholdLevel ) {
        this._vSeparator.show();
        this._hviewBtn.show();
    }
};
/**
 * Removes parent item of current list from hierarchical menu
 * otherwise return the emptyText set in the options
 * @private
 */
oj.SlidingNavListHandler.prototype._removeItemFromHviewMenu = function () {
    if (this._hviewBtn) {
        var removed = this._hviewMenu.find('li').last().remove();
        this._hviewMenu.ojMenu('refresh');
        this._showOrHideHierarchyMenu(this.m_widget.GetOption('hierarchyMenuDisplayThresholdLevel'));
        if (this._hviewMenu.children('li').length === 0) {
            this._hviewBtn.ojButton("option", "disabled", true);
            this._prevIcon.hide();
            this._previousLink.attr('tabindex', '-1');
            this._headerLabel.text(this.m_widget.getRootLabel());
        } else {
            this._headerLabel.text(removed.children('a').text());
        }
    }
};

oj.SlidingNavListHandler.prototype.RestoreItem = function (item, itemContent, sublist) {
    item.removeClass(this.m_widget.SLIDING_NAVLIST_CURRENT_STYLE_CLASS);
    itemContent.removeAttr('role')
        .removeAttr('aria-expanded')
        .removeAttr('aria-describedby')
        .removeAttr('aria-hidden');
};

/**
 * todo: create common utility class between combobox, listview and navlist
 * @private
 */
var _NavigationListUtils = {
    clazz: function (SuperClass, methods)
    {
        var constructor = function () {
        };
        oj.Object.createSubclass(constructor, SuperClass, '');
        $.extend(constructor.prototype, methods);
        return constructor;
    }
};
/**
 * @export
 * @class _ojNavigationListView
 * @classdesc NavigationList
 * @constructor
 * @ignore
 */
var _ojNavigationListView = _NavigationListUtils.clazz(oj._ojListView,
/** @lends _ojNavigationListView.prototype */
{

    ITEM_CONTENT_STYLE_CLASS: 'oj-navigationlist-item-content',
    EXPANDED_STYLE_CLASS: 'oj-expanded',
    COLLAPSED_STYLE_CLASS: 'oj-collapsed',
    SLIDING_NAVLIST_CURRENT_STYLE_CLASS: 'oj-navigationlist-current',
    DIVIDER_STYLE_CLASS: 'oj-navigationlist-divider',
    _CATEGORY_DIVIDER_STYLE_CLASS: 'oj-navigationlist-category-divider',
    _ITEM_LABEL_STYLE_CLASS: 'oj-navigationlist-item-label',
    _ICON_ONLY_STYLE_CLASS: 'oj-navigationlist-icon-only',
    _ITEM_ICON_STYLE_CLASS: 'oj-navigationlist-item-icon',
    _HORIZONTAL_NAVLIST_STYLE_CLASS: 'oj-navigationlist-horizontal',
    _NAVLIST_HAS_ICONS: 'oj-navigationlist-has-icons',
    _NAVLIST_ITEM_HAS_NO_ICON: 'oj-navigationlist-item-no-icon',
    _NAVLIST_ITEM_TITLE: 'oj-navigationlist-item-title',
    _NAVLIST_STYLE_CLASS: 'oj-navigationlist',
    _NAVLIST_TOUCH_STYLE_CLASS: 'oj-navigationlist-touch',
    _NAVLIST_LISTVIEW_CONTAINER_STYLE_CLASS: 'oj-navigationlist-listview-container',
    _IS_TITLE_ATTR_ADDED_DUE_TO_TRUNCATION: 'IsTitleAttrDueToTruncation',
    _APPLICATION_LEVEL_NAV_STYLE_CLASS: 'oj-navigationlist-app-level',
    _PAGE_LEVEL_NAV_STYLE_CLASS: 'oj-navigationlist-page-level',
    _NAVLIST_ITEM_ICON_HAS_TITLE: 'navigationListItemIconHastitle',
    _NAVLIST_NO_FOLLOW_LINK_CLASS: 'oj-navigationlist-nofollow-link',
    /**
     * Returns Item label text
     * @returns {string|null} Item label
     */
    getItemLabel: function (target) {
        var itemContent = this.getItemContentElement(target);
        if (itemContent.is('a')) { // When using simple  markup
            return $.trim(itemContent.text());
        } else {
            //When using arbitrary content, extract item title from element having marker class .oj-navigationlist-item-title.
            return $.trim(itemContent.find('.'+this._NAVLIST_ITEM_TITLE).text());
        }
    },
    /**
     * Returns Item content root element.
     * @returns {Object} Returns jquery object for item content root
     */
    getItemContentElement: function (item) {
        var itemContent = item.children('.' + this.ITEM_CONTENT_STYLE_CLASS);
        if (itemContent.length === 0) {
            itemContent = item.children('.' + this.getGroupItemStyleClass()).children('.' + this.ITEM_CONTENT_STYLE_CLASS);
            if (itemContent.length === 0) { //This case is when item label is invoked before complete initialization of listview
                itemContent = item.children('.' + this.getGroupItemStyleClass()).children(':not(.' + this.getExpandIconStyleClass() + '):not(.' + this.getCollapseIconStyleClass() + ')');
            }
        }
        return itemContent;
    },
    /**
     * Return true when page is in rtl mode otherwise false.
     * @returns {boolean} true if page is in rtl mode
     */
    isRtl: function () {
        return this.ojContext._GetReadingDirection() === "rtl";
    },
    /**
     * Called by content handler once content of all items are rendered
     * @override
     */
    renderComplete: function () {
        this.m_listHandler.BeforeRenderComplete();
        _ojNavigationListView.superclass.renderComplete.apply(this, arguments);
    },
    /**
     * Called by content handler once the content of an item is rendered triggered by an insert event
     * @param {Element} elem the item element
     * @param {Object} context the context object used for the item
     */
    itemInsertComplete: function(elem, context)
    {
        this.m_listHandler.ItemInsertComplete(elem, context);
    },

    /**
     * Called by content handler once the content of an item is removed triggered by an remove event
     * @param {Element} elem the item element
     */
    itemRemoveComplete: function(elem)
    {
        this.m_listHandler.ItemRemoveComplete(elem);
        _ojNavigationListView.superclass.itemRemoveComplete.apply(this, arguments);
    },
    /**
     * Restore content while restroying list
     * @private
     */
    _restoreContent: function (list) {
        var items = list.children();
        list.removeAttr('style')
            .removeClass(this._NAVLIST_HAS_ICONS)
            .removeAttr('aria-hidden');
        for (var i = 0; i < items.length; i++)
        {
            var item = items[i];
            item = $(item);
            if (item.hasClass(this.DIVIDER_STYLE_CLASS)) {
                item.remove();
                continue;
            }
            var itemContent = this.getItemContentElement(item);
            itemContent.removeClass(this.ITEM_CONTENT_STYLE_CLASS)
                       .removeClass(this._NAVLIST_ITEM_HAS_NO_ICON)
                       .removeAttr('aria-haspopup');
            var itemIcon = itemContent.children('.'+this._ITEM_ICON_STYLE_CLASS);
            if (itemIcon && itemIcon.length > 0) {
                itemIcon.removeAttr('role');
                itemIcon.removeAttr('aria-label');
                this._removeToolTipOnIcon(itemIcon);
            }

            item.removeClass('oj-default')
                    .removeAttr('role')
                    .removeAttr('aria-disabled')
                    .removeAttr('aria-expanded')
                    .removeAttr('aria-hidden')
                    .removeAttr('aria-pressed');
            var focusableItem = this.getFocusItem(item);
            focusableItem.removeAttr('role')
                    .removeAttr('aria-hidden')
                    .removeAttr('aria-pressed');
            itemContent.children('.' + this._ITEM_LABEL_STYLE_CLASS)
                    .contents().unwrap();
            if (focusableItem.data(this._IS_TITLE_ATTR_ADDED_DUE_TO_TRUNCATION)) {
                focusableItem.removeAttr('title');
            }
            var sublist = item.children('ul');
            if (sublist.length > 0) {
                this.m_listHandler.RestoreItem(item, itemContent, sublist);
                this._restoreContent(sublist);
            } else {
                this.m_listHandler.RestoreItem(item, itemContent);
            }
        }
    },
    /**
     * Overriding to exclude oj-navigationlist-item-content from clickable components.
     * @override
     * @protected
     */
    IsNodeEditableOrClickable: function (node) {
        if (node.hasClass(this.ITEM_CONTENT_STYLE_CLASS) || node.hasClass(this.getExpandIconStyleClass()) || node.hasClass(this.getCollapseIconStyleClass()))
            return false;
        return _ojNavigationListView.superclass.IsNodeEditableOrClickable.apply(this, arguments);
    },
    /**
    * checks for whether a node is editable or clickable.
    * @param {jQuery} node  Node
    * @return {boolean} true or false
    * @override
    * @protected
    */
    IsElementEditableOrClickable: function(node)
    {
        var nodeName = node.prop("nodeName");
        //Exclude navlist item content  tag from below list and also checking for oj-component class as it is needed for toggle button.
        return (nodeName.match(/^INPUT|SELECT|OPTION|BUTTON|^A\b|TEXTAREA/) && !node.hasClass(this.ITEM_CONTENT_STYLE_CLASS)) || node.hasClass('oj-component');
    },
    /**
     * Prepare options to initialize List
     * @private
     */
    _prepareListViewOptions: function (navlistOptions) {

        var opts = {
            drillMode: navlistOptions['drillMode'] !== 'none' ? 'collapsible' : 'none',
            selection: navlistOptions['selection'] !== null ? [navlistOptions['selection']] : [],
            item: navlistOptions['item'],
            data: navlistOptions['data'],
            selectionMode: 'single'
        };
        opts.element = this._list;
        opts.item.focusable = function (context) {
            if ($(context['data']).is('li')) {
                return !$(context['data']).hasClass('oj-disabled');
            }
            return !$(context['parentElement']).hasClass('oj-disabled');
        };
        opts = $.extend($.extend({}, navlistOptions), opts);
        return opts;
    },
    /**
     * Returns root label for navigation list.
     * otherwise return the emptyText set in the options
     * @return {string} Label for navigation list
     */
    getRootLabel: function () {
        if (this.ojContext.options['rootLabel'])
            return this.ojContext.options['rootLabel'];
        else
            return  this.ojContext.getTranslatedString('defaultRootLabel');
    },

    /**
     * Sets wai-aria properties on root element
     * @override
     * @protected
     */
    SetAriaProperties: function ()
    {
        //Set aria-labelledby or aria-label
        var ariaLabelId = this.ojContext.element.attr('aria-labelledby'), opts;
        if (ariaLabelId) {
            this.element.attr('aria-labelledby', ariaLabelId);
            this.ojContext.element.removeAttr('aria-labelledby');
        }
        else {
            this.element.attr('aria-label', this.getRootLabel());
        }
        _ojNavigationListView.superclass.SetAriaProperties.apply(this, arguments);
    },
    /**
     * Removes wai-aria properties on root element
     * @override
     * @protected
     */
    UnsetAriaProperties: function ()
    {
        //restore aria-labelledby on root element
        if (this.element.attr('aria-labelledby')) {
            this.ojContext.element.attr('aria-labelledby', this.element.attr('aria-labelledby'));
            this.element.removeAttr('aria-labelledby');
        }

        if (this.element.attr('aria-label')) {
            this.element.removeAttr('aria-label');
        }
        _ojNavigationListView.superclass.UnsetAriaProperties.apply(this, arguments);
    },
    /**
     * Overriding init to initialize list with respective List handler.
     * @override
     */
    init: function (navlistopts)
    {
        var opts,
            self = this,
            element = navlistopts.ojContext.element;
        element.addClass(this._NAVLIST_STYLE_CLASS);

        if (oj.DomUtils.isTouchSupported()) {
            element.addClass(this._NAVLIST_TOUCH_STYLE_CLASS);
        }

        this._list = element.children('ul:first');
        if (this._list.length === 0) {
            this._list = $(document.createElement("ul"))
            element.append(this._list);//@HTMLUpdateOK
        }
        var listViewContainer = $(document.createElement("div"));
        listViewContainer.addClass(this._NAVLIST_LISTVIEW_CONTAINER_STYLE_CLASS);
        this._list.wrap(listViewContainer);// @HTMLUpdateOK
        opts = this._prepareListViewOptions(navlistopts);

        _ojNavigationListView.superclass.init.call(this, opts);
        this.element.removeClass('oj-component-initnode');
        this.ojContext._on(this.ojContext.element, {
            "touchstart": function(event) {
                var item = self.FindItem($(event.target));
                if (item && !item.hasClass("oj-disabled"))
                    self.HighlightUnhighlightElem(item, "oj-active", true);
            },
            "touchend": function(event) {
                var item = self.FindItem($(event.target));
                self.HighlightUnhighlightElem(item, "oj-active", false);
            },
            "mousedown": function(event) {
                var item = self.FindItem($(event.target));
                if (item && !item.hasClass("oj-disabled"))
                    self.HighlightUnhighlightElem(item, "oj-active", true);
            },
            "mouseup": function(event) {
                var item = self.FindItem($(event.target));
                self.HighlightUnhighlightElem(item, "oj-active", false);
            },
            "click .oj-navigationlist-previous-link": function (event) {
                self._collapseCurrentList();
            },
            "keydown .oj-navigationlist-previous-link": function (event) {
                if (event.keyCode === $.ui.keyCode.ENTER) {
                    self._collapseCurrentList();
                }
            },
            "keydown .oj-navigationlist-element": function (event) {
                //check for default prevented as it might have already processed for quiting f2 mode
                if (event.keyCode === $.ui.keyCode.ESCAPE && !event.isDefaultPrevented())
                {
                    self._collapseCurrentList();
                }
            },
            "mouseenter a.oj-navigationlist-item-content": function(event) {
                var $itemLink = $(event.currentTarget);
                var $label = $itemLink.find('.'+ self._ITEM_LABEL_STYLE_CLASS);
                //Add title attribute only when the text is truncated.
                if ($label[0].offsetWidth < $label[0].scrollWidth && !$itemLink.attr('title')) {
                    $itemLink.attr('title', $label.text().trim());
                    $itemLink.data(self._IS_TITLE_ATTR_ADDED_DUE_TO_TRUNCATION,'true');
                }
            },
            "mouseleave a.oj-navigationlist-item-content": function(event) {
                //Remove title attribute on mouseleave.
                var $itemLink = $(event.currentTarget);
                if ($itemLink.data(self._IS_TITLE_ATTR_ADDED_DUE_TO_TRUNCATION)) {
                  $itemLink.removeData(self._IS_TITLE_ATTR_ADDED_DUE_TO_TRUNCATION);
                  $itemLink.removeAttr('title');
                }
            }
        });
    },
    _collapseCurrentList: function() {
        this.m_listHandler.CollapseCurrentList();
    },
    _initListHandler: function () {
        var drillMode = this.ojContext.options['drillMode'];
        var edge = this.ojContext.options['edge'];
        if (drillMode === 'sliding') {
            this.m_listHandler = new oj.SlidingNavListHandler(this, this.ojContext.element, this.ojContext);
        } else if (drillMode === 'collapsible') {
            this.m_listHandler = new oj.CollapsibleNavListHandler(this, this.ojContext.element, this.ojContext);
        } else if (drillMode === 'none' && edge === 'top') {
            this.m_listHandler = new oj.HorizontalNavListHandler(this, this.ojContext.element, this.ojContext);
        } else {
            this.m_listHandler = new oj.DefaultNavListHandler(this, this.ojContext.element, this.ojContext);
        }
        this.m_listHandler.Init(this.options);
        var navigationLevel = this.ojContext.options['navigationLevel'];
        this._setNavigationLevel(navigationLevel);
    },
    _setNavigationLevel: function(navigationLevel) {
        var drillMode = this.ojContext.options['drillMode'];
        if (drillMode === 'none' ) {
            if (navigationLevel === 'application') {
                this.ojContext.element.addClass(this._APPLICATION_LEVEL_NAV_STYLE_CLASS);
                this.ojContext.element.removeClass(this._PAGE_LEVEL_NAV_STYLE_CLASS);
            } else if (navigationLevel === 'page') {
                this.ojContext.element.addClass(this._PAGE_LEVEL_NAV_STYLE_CLASS);
                this.ojContext.element.removeClass(this._APPLICATION_LEVEL_NAV_STYLE_CLASS);
            }
        }
    },
    /**
     * Initialize the listview after creation
     * @override
     */
    afterCreate: function ()
    {
        this._initListHandler();
        _ojNavigationListView.superclass.afterCreate.apply(this, arguments);
    },
    /**
     * Returns Navlist specific container style class
     * @override
     * @protected
     */
    GetContainerStyleClass: function () {
        return "oj-navigationlist-listview";
    },
    /**
     * Returns Navlist specific root element style class
     * @override
     * @protected
     */
    GetStyleClass: function () {
        return "oj-navigationlist-element";
    },
    /**
     * Returns Navlist specific Item style class
     * @override
     */
    getItemStyleClass: function () {
        return "oj-navigationlist-item";
    },
    getFocusedElementStyleClass: function()
    {
        return "oj-navigationlist-focused-element";
    },
    /**
     * Returns Navlist specific Item element style class
     * @override
     */
    getItemElementStyleClass: function ()
    {
        return "oj-navigationlist-item-element";
    },
    /**
     * Returns Navlist specific collapse icon style class
     * @override
     */
    getCollapseIconStyleClass: function () {
        return "oj-navigationlist-collapse-icon";
    },
    /**
     * Returns Navlist specific expand icon style class
     * @override
     */
    getExpandIconStyleClass: function () {
        return "oj-navigationlist-expand-icon";
    },
    /**
     * Returns Navlist specific depth style class
     * @override
     */
    getDepthStyleClass: function (depth) {
        return "oj-navigationlist-depth-" + depth;
    },
    /**
     * Returns Navlist specific Group Item style class
     * @override
     */
    getGroupItemStyleClass: function ()
    {
        return "oj-navigationlist-group-item";
    },
    /**
     * Returns Navlist specific Group style class
     * @override
     */
    getGroupStyleClass: function () {
        return "oj-navigationlist-group";
    },
    /**
     * Returns Navlist specific group expand style class
     * @override
     */
    getGroupExpandStyleClass: function ()
    {
        return "oj-navigationlist-collapsible-transition";
    },
    /**
     * Returns Navlist specific group collapse style class
     * @override
     */
    getGroupCollapseStyleClass: function ()
    {
        return this.getGroupExpandStyleClass();
    },
    /**
     * Override expand animation behaviour to support differnet types of navlists.
     * @override
     * @protected
     */
    AnimateExpand: function (groupItem, animate) {
        this.m_listHandler.Expand(groupItem, animate);
    },
    /**
     * Override collapse animation behaviour to support differnet types of navlists.
     * @override
     * @protected
     */
    AnimateCollapse: function (item, animate) {
        this.m_listHandler.Collapse(item, animate);
    },
    /**
     * Handles arrow keys navigation on item
     * @param {number} keyCode description
     * @param {boolean} isExtend
     * @param {Event} event the DOM event causing the arrow keys
     * @override
     * @protected
     */
    HandleArrowKeys: function (keyCode, isExtend, event)
    {
        return this.m_listHandler.HandleArrowKeys(keyCode, isExtend, event);
    },
    /**
     * Determine whether the key code is an arrow key
     * @param {number} keyCode
     * @return {boolean} true if it's an arrow key, false otherwise
     * @override
     * @protected
     */
    IsArrowKey: function (keyCode)
    {
        return this.m_listHandler.IsArrowKey(keyCode);
    },
    /**
     * Determines whether the specified item is expanded
     * @param {jQuery} item the item element
     * @return {number} 0 if item is expanded, 1 if item is collapsed, 2 if item cannot be expand or collapse.
     * @override
     * @protected
     */
    GetState: function (item)
    {
        return this.m_listHandler.GetState(item);
    },
    /**
     * Sets the disclosed state of the item
     * @param {jQuery} item the item element
     * @param {number} state 0 if item is expanded, 1 if item is collapsed, 2 if item cannot be expand or collapse.
     * @override
     * @protected
     */
    SetState: function (item, state)
    {
        this.m_listHandler.SetState(item, state);
    },

    /**
     * Override to expand and collapse events on clicking item instead of icon. Also avoids expand/collapse when user click on arbitrary clickable elements.
     * @override
     * @protected
     */
    HandleMouseClick: function (event) {
        var item = this.FindItem($(event.target)), itemKey;
        if (item == null || item.length === 0)
        {
            // can't find item or if item cannot be focus
            return;
        }
        if (this.SkipFocus(item)) {
            event.preventDefault();
            return;
        }
        itemKey = this.GetKey(item[0]);

        //TODO , once it is fixd in listview probably don't need to override HandleMouseClick

        if (this.IsNodeEditableOrClickable($(event.target))) {
            return;
        }

        var itemContent = this.getItemContentElement(item);
        var url = itemContent.attr('href');
        if (url && url !== "#") {
            if (event.button === 0  && (event.shiftKey || event.ctrlKey)) {
                return; // Do nothing, as Browser will launch  target it in new tab or browser
            }
        }

        _ojNavigationListView.superclass.HandleMouseClick.apply(this, arguments);
        event.preventDefault();
    },
    /**
     * Override to support flip left/right arrows for expand and collapse actions.
     * @override
     * @protected
     */
    HandleKeyDown: function (event) {
        var keyCode, current, currentItemKey;

        keyCode = event.keyCode;
        current = this.m_active['elem'];
        currentItemKey = this.m_active['key'];

        if (keyCode === $.ui.keyCode.HOME || keyCode === $.ui.keyCode.END) {
            var item, key;
            if (keyCode === $.ui.keyCode.HOME)
            {
                item = this.element.find('.' + this.ITEM_CONTENT_STYLE_CLASS + ':visible').first().closest('.' + this.getItemElementStyleClass());
            } else {
                item = this.element.find('.' + this.ITEM_CONTENT_STYLE_CLASS + ':visible').last().closest('.' + this.getItemElementStyleClass());
            }
            key = this.GetKey(item[0]);
            this.SetOption('currentItem', key); //Set current option on listview
            event.preventDefault();
        } else {
            var processed = this.HandleSelectionOrActiveKeyDown(event);
            var processExpansion = this.m_listHandler.HandleExpandAndCollapseKeys(event, keyCode, current, currentItemKey);
            if (processed === true || processExpansion === true)
            {
                event.preventDefault();
            }
        }
    },
    /**
     * Override to trigger beforeSelect event when user selecets an item.
     * @override
     * @protected
     */
    ToggleSelection: function (event, keepCurrentSelection, skipIfNotSelected) {
        var item = this.m_active['elem'];

        if (!this.IsSelectable(item[0])) {
            return;
        }
        if (this._isSelected(item)) {
            return;
        }
        var shouldSelect = this._fireBeforeSelectEvent(event, item);
        if (shouldSelect) {
            _ojNavigationListView.superclass.ToggleSelection.apply(this, arguments);
            this._initiateNavigation(item);
        }
    },
    /**
     * Highlight or unhighlight an element
     * @param {jQuery|Element} elem the element the highlight or unhighlight
     * @param {string} style the style to add or remove
     * @param {boolean} highlight true if it's to highlight, false if it's to unhighlight
     * @override
     * @protected
     */
    HighlightUnhighlightElem: function (elem, style, highlight)
    {
        var group;

        elem = $(elem);

        if (style === "oj-selected") {
            this.m_listHandler.UpdateAriaPropertiesOnSelectedItem(this.getFocusItem(elem), highlight);
        }

        // if item is a group, the highlight should be apply to the group item element
        group = elem.children("." + this.getGroupItemStyleClass());
        if (group.length > 0)
        {
            elem = $(group[0]);
        }

        if (highlight)
        {
            elem.addClass(style);
        }
        else
        {
            elem.removeClass(style);
        }

        if (elem.hasClass('oj-selected') || elem.hasClass('oj-hover') || elem.hasClass('oj-active') || elem.hasClass('oj-disabled')) {
            elem.removeClass('oj-default');
        }
        else {
            elem.addClass('oj-default');
        }
    },
    /**
     * In Navlist,it is not gaurenteed that item will have aria-selected. So overriding it to make all items selectable.
     * @override
     * @protected
     */
    IsSelectable: function (item)
    {
        return !$(item).hasClass('oj-disabled') && this.m_listHandler.IsSelectable($(item));
    },
    /**
     * Override to skip firing events like ready which are not needed for navlist.
     * @override
     * @protected
     */
    Trigger: function (type, event, ui)
    {
        if (type !== 'ready')
            return this.ojContext._trigger(type, event, ui);
        else
            return true;
    },
    /**
     * Override to convert selection option value from array to string before setting on component.
     * @override
     * @protected
     */
    SetOption: function (key, value, flags)
    {
        if (key === 'selection') { // selection Data type is different for listview and navlist
            //change items to item as navlist does't allow multiple selection.
            var context = flags['_context'],
                selectedItem = context && context.extraData && context.extraData['items'];
            if (selectedItem) {
                //extraData['items'] is a jquery object(not an array) and in case of navlist it will always have single item.
                context.extraData['item'] = selectedItem;
                context.extraData['items'] = undefined;
            }
            if (value && value.length > 0)
                this.ojContext.option(key, value[0], flags);
            else
                this.ojContext.option(key, null, flags);

        } else {// Common options
            this.ojContext.option(key, value, flags);
        }
        this.options[key] = value;
    },
    /**
     * Whether ListView should refresh if certain option is updated
     * @param {Object} options the options to check
     * @return {boolean} true if should refresh, false otherwise
     * @override
     * @protected
     */
    ShouldRefresh: function (options)
    {
        return (options['data'] != null ||
                options['drillMode'] != null ||
                options['item'] != null ||
                options['display'] != null ||
                options['edge'] != null);
    },
    /**
     * Sets multiple options
     * @param {Object} options the options object
     * @param {Object} flags additional flags for option
     * @return {Object} result result object holding skipUpdate and needRefresh flags.
     * @override
     */
    setOptions: function (options, flags)
    {
        var result = { skipOptions: [] }, newSelectionValue;

        if ( options['hierarchyMenuDisplayThresholdLevel'] !== undefined) {
            this.m_listHandler.setOptions(options);
        }

        if (options['navigationLevel'] !== undefined) {
            this._setNavigationLevel(options['navigationLevel']);
        }

        if (options['selection'] !== undefined) {
            newSelectionValue = options['selection'];
            if (!!newSelectionValue) {
                var selection = this.GetOption('selection');
                if (!selection || selection.length === 0 || selection[0] !== newSelectionValue) {
                    var item = this.FindElementByKey(newSelectionValue);
                    if (item && this.IsSelectable(item)) {
                        var shouldSelect = this._fireBeforeSelectEvent(null, $(item));
                        if (shouldSelect) {
                           options['selection'] = [newSelectionValue];
                           this._initiateNavigation($(item));
                        } else {
                          delete options['selection'];
                          result.skipOptions.push('selection');
                        }
                    } else {
                      delete options['selection'];
                      result.skipOptions.push('selection');
                    }
                } else {
                  //When new value is same as existing one, no need to update it on listview.
                  delete options['selection'];
                }
            } else {
              options['selection'] = [];
            }
        }

        result.needRefresh = _ojNavigationListView.superclass.setOptions.call(this, options, flags);
        //Restore original user provided selection value
        if (newSelectionValue !== undefined) {
          options['selection'] = newSelectionValue;
        }
        return result;
    },
    /**
     * Override to convert selection option value from string to array before setting on component.
     * @override
     * @protected
     */
    GetOption: function (key)
    {
        var optionValue = this.ojContext.option(key);
        if (key === 'selection') { // selection Data type is different for listview and navlist
            if (optionValue) {
                return [optionValue];
            } else {
                return [];
            }
        }
        if (optionValue === null) { // if the option is only applicable to listview
            return this.options[key];
        }
        return optionValue;
    },
    /**
     * Override to return widget constructor
     * @override
     */
    getWidgetConstructor: function () {
        return oj.Components.getWidgetConstructor(this.ojContext.element);
    },
    /**
     * Override to skip intermediate nodes(only in case of collapsible) and disabled items from selection.
     * @override
     * @protected
     */
    SelectAndFocus: function (item, event) {
        //Disabled items are not selectable and focuable.
        if (item.hasClass('oj-disabled')) {
            return;
        }

        //Selectable items should gain focus on click
        if (this.IsSelectable(item[0])) {
            var key = this.GetKey(item[0]);
            this.SetOption('currentItem', key);
        } else {
            return;
        }

        //If item is already selected then return
        if (this._isSelected(item)) {
            return;
        }

        var shouldSelect = this._fireBeforeSelectEvent(event, item);
        if (shouldSelect) {
            _ojNavigationListView.superclass.SelectAndFocus.apply(this, arguments);
            this._initiateNavigation(item);
        }
    },
    _fireBeforeSelectEvent: function (event, item) {
        var key = this.GetKey(item[0]);
        return this.Trigger("beforeSelect", event, {item: item, key: key});
    },
    _initiateNavigation: function (item) {

        if (this.ojContext.element.hasClass(this._NAVLIST_NO_FOLLOW_LINK_CLASS)) {
            return false;
        }

        var itemContent = this.getItemContentElement(item);
        var url = itemContent.attr('href');
        if (url && url !== "#") {
            //In case of javascript uri, javascript will get executed on assigning it to href.
            //Ideally user can use beforeSelect/optionChange events to do this,Will there be any issue in supporting this?
            window.location.href = url;
            return true;
        }
        return false;
    },
    _isSelected: function (item) {
        var selection, key, index;

        selection = this.GetOption("selection");
        key = this.GetKey(item[0]);

        index = selection.indexOf(key);
        if (index > -1)
        {
            return true;
        }
        return false;
    },
    _setToolTipOnIcon: function (icon, itemLabel) {
        if (!icon.attr('title')) {
            icon.attr('title', itemLabel);
        }
    },
    _removeToolTipOnIcon: function (icon) {
        if (!icon.data(this._NAVLIST_ITEM_ICON_HAS_TITLE)) {
            icon.removeAttr('title');
        } else {
            icon.removeData(this._NAVLIST_ITEM_ICON_HAS_TITLE);
        }
    },
    /**
     * Called by content handler once the content of an item is rendered
     * @param {Element} elem the item element
     * @param {Object} context the context object used for the item
     */
    itemRenderComplete: function(elem, context)
    {
        var $item = $(elem);
        if ($item.hasClass(this._CATEGORY_DIVIDER_STYLE_CLASS)) {
            $item.removeClass(this.getItemElementStyleClass());
            $item.removeClass(this.getFocusedElementStyleClass());
            $item.removeClass(this.getItemStyleClass());
            $item.removeAttr('aria-selected');
            $item.children().remove();
            $item.attr('role', 'separator');
            return;
        }
        var groupItemClass = this.getGroupItemStyleClass();
        var collapseIconClass = this.getCollapseIconStyleClass();
        var expandIconClass = this.getExpandIconStyleClass();
        var itemIconClass = this._ITEM_ICON_STYLE_CLASS;
        var groupItem = $item.children('.' + groupItemClass);
        var itemContent;
        if (groupItem.length > 0) {
            //Adding oj-navigationlist-item class on group node. Listview does't add this any more.
            groupItem.addClass(this.getItemStyleClass());
            itemContent = groupItem.children(':not(.' + expandIconClass + '):not(.' + collapseIconClass + ')');
            var groupIcon = groupItem.children('.' + expandIconClass);
            if (groupIcon.length === 0) {
                groupIcon = groupItem.children('.' + collapseIconClass);
            }
            groupIcon.attr('role', 'presentation');
            groupIcon.removeAttr('aria-labelledby');
            if ($item.hasClass('oj-disabled')) {
                groupItem.addClass('oj-disabled');
            }
        } else {
            itemContent = $item.children().first();
        }
        itemContent.addClass(this.ITEM_CONTENT_STYLE_CLASS);
        var icon = itemContent.wrapInner('').find('.' + itemIconClass);//@HTMLUpdateOK
        if (icon.length > 0) {
            icon.insertBefore(icon.parent());// @HTMLUpdateOK

            if (icon.attr('title')) {// preserve the title to restore it after destroy.
                icon.data(this._NAVLIST_ITEM_ICON_HAS_TITLE, icon.attr('title'));
            }

            if (this.ojContext.options['display'] === 'icons') {
                this.ojContext.element.addClass(this._ICON_ONLY_STYLE_CLASS);
                var itemLabel = this.getItemLabel($item);
                icon.attr('aria-label', itemLabel);
                icon.attr('role','img');
                this._setToolTipOnIcon(icon, itemLabel);
            }

            $item.closest('ul').addClass(this._NAVLIST_HAS_ICONS);
        } else {
            itemContent.addClass(this._NAVLIST_ITEM_HAS_NO_ICON);
        }

        if ($item.hasClass('oj-disabled')) {
            this.getFocusItem($item).attr('aria-disabled', 'true');
        } else {
            if (groupItem.length > 0) {
                groupItem.addClass('oj-default');
            } else {
                $item.addClass('oj-default');
            }
        }
        this.m_listHandler.ModifyListItem($item, itemContent);
        _ojNavigationListView.superclass.itemRenderComplete.apply(this, arguments);

    },

    /**
     * Return node for given locator
     *
     * @override
     */
    getNodeBySubId: function (locator)
    {
        var subId, key, item;

        if (locator === null)
        {
            return this.element ? this.element[0] : null;
        }

        subId = locator['subId'];
        if (subId === 'oj-navigationlist-item')
        {
            key = locator['key'];
            item = this.FindElementByKey(key);
            return item;
        } else if (subId === 'oj-navigationlist-previous-link') {
            return this.m_listHandler._previousLink ? this.m_listHandler._previousLink[0] : null;
        } else if (subId === 'oj-navigationlist-hierarchical-button') {
            return this.m_listHandler._hviewBtn ? this.m_listHandler._hviewBtn[0] : null;
        } else if (subId === 'oj-navigationlist-hierarchical-menu') {
            return this.m_listHandler._hviewMenu ? this.m_listHandler._hviewMenu[0] : null;
        }

        // Non-null locators have to be handled by the component subclasses
        return null;
    },
    /**
     * Returns the subId locator for the given child DOM node.
     * Invoked by widget
     * @param {!Element} node - child DOM node
     * @return {Object|null} The locator for the DOM node, or null when none is found.
     */
    getSubIdByNode: function(node)
    {
          var item, key;
          if (this.m_listHandler._previousLink && this.m_listHandler._previousLink[0] === node) {
            return {'subId': 'oj-navigationlist-previous-link'};
          } else if (this.m_listHandler._hviewBtn && this.m_listHandler._hviewBtn[0] === node) {
            return {'subId': 'oj-navigationlist-hierarchical-button'};
          } else if (this.m_listHandler._hviewMenu && this.m_listHandler._hviewMenu[0] === node) {
            return {'subId': 'oj-navigationlist-hierarchical-menu'};
          } else {
              item = this.FindItem(node);
              if (item != null && item.length > 0)
              {
                  key = this.GetKey(item[0]);
                  if (key != null)
                  {
                      return {'subId': 'oj-navigationlist-item', 'key': key};
                  }
              }
          }
          return null;
    },
    /**
     * Returns an object with context for the given child DOM node.
     * This will always contain the subid for the node, defined as the 'subId' property on the context object.
     * Additional component specific information may also be included. For more details on returned objects, see context objects.
     * Invoked by widget
     *
     * @param {!Element} node the child DOM node
     * @returns {Object|null} the context for the DOM node, or null when none is found.
     */
    getContextByNode: function(node)
    {
        var context = _ojNavigationListView.superclass.getContextByNode.call(this,node);
        if (context && context['subId'] == 'oj-listview-item')
        {
            context['subId'] = 'oj-navigationlist-item';
            return context;
        }
        return null;
    },
    /**
     * Refresh navlist
     * @override
     */
    refresh: function () {
        this._resetNavlist();
        this._initListHandler();
        _ojNavigationListView.superclass.refresh.apply(this, arguments);
    },
    /**
     * Uninitialize dom.
     * @private
     */
    _resetNavlist: function () {
        this.ojContext.element.removeClass(this._ICON_ONLY_STYLE_CLASS);
        this.ojContext.element.removeClass(this._APPLICATION_LEVEL_NAV_STYLE_CLASS);
        this.ojContext.element.removeClass(this._PAGE_LEVEL_NAV_STYLE_CLASS);
        this._restoreContent(this.element);
        this.m_listHandler.Destroy();
    },
    /**
     * Destroy the Navigation List
     * @override
     */
    destroy: function () {
        this._resetNavlist();
        _ojNavigationListView.superclass.destroy.apply(this, arguments);
        this._list.unwrap();
        //for data source, this will be empty.
        if (this._list.is(':empty')) {
            this._list.remove();
        }
        this.ojContext.element.removeClass(this._NAVLIST_STYLE_CLASS+' '+this._NAVLIST_TOUCH_STYLE_CLASS);
        this.ojContext._off(this.element, "click");
        this.ojContext._off(this.element, "focus");
        this.ojContext._off(this.element, "blur");
        this.ojContext._off(this.element, "mouseover");
        this.ojContext._off(this.element, "mousein");
        this.ojContext._off(this.element, "mouseout");
        this.ojContext._off(this.element, "keydown");
    }

});

/**
 * Copyright (c) 2014, Oracle and/or its affiliates.
 * All rights reserved.
 */
(function () {
    /**
     * @ojcomponent oj.ojNavigationList
     * @augments oj.baseComponent
     * @since 1.1.0
     *
     * @classdesc
     *

     *   JET Navigation List Component
     *
     *

     *
     *
Description:  The JET Navigation List enhances a HTML list element into a themable, WAI-ARIA compliant, mobile friendly component with advance interactive features.
     *
     *
The JET Navigation List gets its data in following ways.

     *

     *
Using table datasource. This is typically used in case of flat list.There are several types of TableDataSource that
     * are available out of the box like oj.ArrayTableDataSource,oj.CollectionTableDataSource.NOTE: oj.PagingTableDataSource is not supported by navigation list.
     * For large amount of data, It is recommended to use hierarhcial navigation list with tree data source.

     *
Using TreeDataSource.  This is typically used to display hierarchical navigation list.  There are several types
     * of TreeDataSource that are available out of the box like oj.JsonTreeDataSource, oj.CollectionTreeDataSource

     *
Using static content . The structure of the content can be either flat or hierarhical.

     *

     *
Example of flat static content

     *

     *
     * <div id="navigationlist">
     *  <ul>
     *   <li><a href="#">Item 1</a></li>
     *   <li><a href="#">Item 2</a></li>
     *   <li><a href="#">Item 3</a></li>
     *  </ul>
     * </div>
     *

     *
     *
Example of hierarchical static content

     *

     *
     * <div id="navigationlist">
     *  <ul >
     *   <li><a href="#">Item 1</a></li>
     *   <li><a href="#">Item 2</a></li>
     *   <li><a href="#">Item 3</a>
     *     <ul>
     *       <li><a href="#">Item 3-1</a></li>
     *       <li><a href="#">Item 3-2</a></li>
     *       <li><a href="#">Item 3-3</a></li>
     *       <li><a href="#">Item 3-4</a></li>
     *       <li><a href="#">Item 3-5</a></li>
     *     </ul>
     *   </li>
     *   <li><a href="#">Item 4</a></li>
     *   <li><a href="#">Item 5</a></li>
     *  </ul>
     * </div>
     *

     *
 JSON Tree Node Format

     *

     * Each node object typically have an
     * attr property. This attr value will be provided as itemContext.data to renderer function. See itemContext section. Any node can be defined as a parent by supplying
     * a children property, which is an array of one or more node definitions.
     * (Note: lazy-loading is not supported in navigation list so children property should be a non empty array)
     *
Example: Basic JSON Tree definition
     *

     *
     *[
     *   {
     *     "attr": {
     *               "id": "home",
     *               "title": "Home"
     *             },
     *   },
     *   {
     *     "attr": {
     *               "id": "news",
     *               "title": "News"
     *             }
     *   },
     *   {
     *      "attr": {
     *                "id": "blogs",
     *                "title": "Blogs"
     *              },
     *      "children": [ {
     *
     *                       "attr": {
     *                                   "id": "today",
     *                                   "title": "Today"
     *                               }
     *                    },
     *                    {
     *                       "attr": {
     *                                   "id": "yesterday",
     *                                   "title": "Yesterday"
     *                               }
     *                    }
     *                  ]
     *   }
     *]
     *

     *

     *
Any list item can be disabled by adding the oj-disabled class to that element.  As with any DOM change, doing so post-init
     * requires a refresh() of the component.
     *
     *
     *

     *   Icons
     *
     *

     *
     *
Sublist icons are inserted automatically.  To add other icons to list items, include them in the markup and include the oj-navigationlist-item-icon class, as follows:
     *
     *

     * <ul id="navigationlist">
     *   <li id="foo"><a href="#"><span class="oj-navigationlist-item-icon demo-icon-font-24 demo-palette-icon-24"></span>Foo</a></li>
     * </ul>
     *

     *
     *

     *   Styling
     *
     *

     *
     *

     *

     *

     *       Class(es)
     *       Description
     *

     *

     *

     *

     *       oj-navigationlist-stack-icon-label
     *       Add this class to display Navigation List with Stacked icon and label. Applicable only when edge is top.
     *

     *

     *       oj-navigationlist-category-divider
     *       Use this class to add horizontal divider line between two categories of items.
     *

     *

     *       oj-navigationlist-item-icon
     *       Use this class to add icon to list item.
     *

     *

     *       oj-navigationlist-item-title
     *       When arbitrary content is placed in side item, mark item title using this marker class.
     *
Example of item markup with arbitrary content.
     *

     *
     *<li>
     *  <div>
     *      <span class="oj-navigationlist-item-title">Play</span>
     *      <button>Button</button>
     *  </div>
     *</li>
     *
     *

     *

     *
     *

     *

     *       oj-navigationlist-item-text-wrap
     *       Use this class to wrap item label text.
     *

     *

     *       oj-navigationlist-item-dividers
     *       Use this class to show dividers between horizontal navigation list items.
     *

     *

     *       oj-sm-condense
     *       Use this class to condense horizontal navigation list items on small and up screens.
     *
     *

     *

     *       oj-md-condense
     *       Use this class to condense horizontal navigation list items on medium and up screens.
     *
     *

     *

     *       oj-lg-condense
     *       Use this class to condense horizontal navigation list items on large and up screens.
     *
     *

     *

     *       oj-xl-condense
     *       Use this class to condense horizontal navigation list items on extra large and up screens.
     *
     *

     *

     *       oj-navigationlist-nofollow-link
     *        Use this class to prevent automatic navigation to the url specified on <a> tag's href attribute. In this case, navigation can be handled programmatically by using optionChange event.
     *
     *

     *

     *

     *

     *   Touch End User Information
     *
     *

     *
     * {@ojinclude "name":"touchDoc"}
     *
     *

     *   Keyboard End User Information
     *
     *

     * {@ojinclude "name":"keyboardDoc"}
     *
     *
Disabled items will not receive keyboard focus and do not allow any interaction.
     *
     *

     *   Item Context
     *
     *

     *
     *
For all item options, developers can specify a function as the return value.  The function takes a single argument, which is an object that contains contextual information about the particular item.  This gives developers the flexibility to return different value depending on the context.

     *
     *
The context paramter contains the following keys:

     *

     *

     *

     *       Key
     *       Description
     *

     *

     *

     *

     *       component
     *       A reference to the NavigationList widget constructor.
     *

     *

     *       datasource
     *       A reference to the data source object. (Not available for static content)
     *

     *

     *       index
     *       The index of the item, where 0 is the index of the first item.  In the hierarchical case the index is relative to its parent.
     *

     *

     *       key
     *       The key of the item.
     *

     *

     *       data
     *       The data object for the item.
     *

     *

     *       parentElement
     *       The list item element.  The renderer can use this to directly append content.
     *

     *

     *

     *
     *

     *
If the data is hierarchical, the following additional contextual information are available:

     *

     *

     *

     *       Key
     *       Description
     *

     *

     *

     *

     *       depth
     *       The depth of the item.  The depth of the first level children under the invisible root is 1.
     *

     *

     *       parentKey
     *       The key of the parent item.  The parent key is null for root node.
     *

     *

     *       leaf
     *       Whether the item is a leaf or a group item.
     *

     *

     *

     *

     *   Performance
     *
     *

     *
     *
Data Set Size

     *
As a rule of thumb, it's recommended that applications limit the amount of data to display.  Displaying large
     * number of items in Navigation List makes it hard for user to find what they are looking for, but affects the load time.
     * If displaying large number of items is neccessary, it is recommended to group the items in to hierarchial navigation list.
     *
     *
Item Content

     *
Navigation List allows developers to specify arbitrary content inside its item. In order to minimize any negative effect on
     * performance, you should avoid putting a large number of heavy-weight components inside because as you add more complexity
     * to the structure, the effect will be multiplied because there can be many items in the Navigation List.

     *
     *
Expand All

     *
While Navigation List provides a convenient way to initially expand all group items, it might have an impact
     * on the initial rendering performance since expanding each group item might cause a fetch from the server depending on
     * the TreeDataSource.  Other factors that could impact performance includes the depth of the tree, and the number of children
     * in each level.

     *
     *

     *   Accessibility
     *
     *

     *
     *
Disabled content: JET supports an accessible luminosity contrast ratio,
     * as specified in WCAG 2.0 - Section 1.4.3 "Contrast",
     * in the themes that are accessible.  (See the "Theming" chapter of the JET Developer Guide for more information on which
     * themes are accessible.)  Note that Section 1.4.3 says that text or images of text that are part of an inactive user
     * interface component have no contrast requirement.  Because disabled content may not meet the minimum contrast ratio
     * required of enabled content, it cannot be used to convey meaningful information.

     *
     *
     *

     *   Reading direction
     *
     *

     *
     *
The only supported way to set the reading direction (LTR or RTL) is to set the "dir" attribute on the
     * <html> element of the page.  As with any JET component, in the unusual case that the reading direction
     * is changed post-init, the navigation list must be refresh()ed, or the page must be reloaded.
     *
     *
     *

     *   Pseudo-selectors
     *
     *

     *
     *
The :oj-navigationlist pseudo-selector can be used in jQuery expressions to select JET Navigation Lists.  For example:
     *
     *

     * $( ":oj-navigationlist" ) // selects all JET Navigation lists on the page
     * $myEventTarget.closest( ":oj-navigationlist" ) // selects the closest ancestor that is a JET Navigation lists
     *

     *
     *
     *
     *
     * @desc Creates a JET Navigation List.
     *
     * @param {Object=} options a map of option-value pairs to set on the component
     *
     * @example
Initialize the Navigation list with no options specified:

     * $( ".selector" ).ojNavigationList();
     *
     * @example
Initialize the Navigation list with some options and callbacks specified:

     * $( ".selector" ).ojNavigationList( { "drillMode": "none", "beforeSelect": function( event, ui ) {} } );
     *
     * @example
Initialize the Navigation list via the JET ojComponent binding:

     * <div id="navigationlist" data-bind="ojComponent: { component: 'ojNavigationList',
     *                                         drillMode: 'none',
     *                                         beforeSelect: beforeSelectItem }">
     */
    oj.__registerWidget("oj.ojNavigationList", $['oj']['baseComponent'], {
        widgetEventPrefix: 'oj',
        options: {
            /**
             * Key of the current item.  Current item is the list item which is having active focus.  Note that if currentItem
             * is set to an item that is currently not available (not fetched or
             * inside a collapsed parent node), then the value is ignored.
             *
             * @expose
             * @public
             * @instance
             * @memberof! oj.ojNavigationList
             * @type {Object}
             * @default null
             *
             * @example
Get the current item:

             * $( ".selector" ).ojNavigationList("option", "currentItem");
             *
             * @example
Set the current item on the NavigationList during initialization:

             * $(".selector").ojNavigationList({"currentItem", "item2"});
             */
            currentItem: null,
            /**
             * Defines style of navigation used to drill down hierarchical list items.
             *

             *
none

             *
collapsible

             *
sliding

             *

             *
             * @expose
             * @memberof oj.ojNavigationList
             * @instance
             * @type {string}
             * @default "none"
             * @ojvalue {string} "none" All group items are expanded by default and user not allowed to collapse them.
             * @ojvalue {string} "collapsible" Allows user to expand and collapse group items. If there are more than two levels in hierarchy, sliding is preferered drill mode.
             * @ojvalue {string} "sliding" This is typically used for hierarchical lists. This allows user to view one level at a time.
             *
             * @example
Initialize the menu with the drillMode option specified:

             * $( ".selector" ).ojNavigationList({ drillMode: "collapsible" });
             *
             * @example
Get the drillMode option, after initialization:

             * // getter
             * var drillMode = $( ".selector" ).ojNavigationList( "option", "drillMode" );
             */
            drillMode: "none",
            /**
             * The position of the Navigation List. Valid Values: top and start.
             *
 NOTE: when value is top,"none" is the only supported drillMode and it also does't support hierarchical items.
             * @expose
             * @name edge
             * @memberof oj.ojNavigationList
             * @instance
             * @type {string|null}
             * @ojvalue {string} "top" This renders list items horizontally.
             * @ojvalue {string} "start" This renders list items vertically.
             * @default "start"
             */
            edge: "start",
            /**
            * Specifies the level at which user can see hiearchical menu button.This is only valid when drillMode set to sliding.
            * Default value is 0, shows hiearchical menu always. If value is -1, then it will never be shown.
            *
            *
The default value for hierarchyMenuDisplayThresholdLevel varies by theme.  Each theme can set its default by setting
            * $navigationListHierarchyMenuDisplayThresholdLevelOptionDefault as seen in the example below.
            *
            * @expose
            * @name hierarchyMenuDisplayThresholdLevel
            * @memberof oj.ojNavigationList
            * @instance
            * @type {number|null}
            * @default Varies by theme. "0" if not specified in theme.
            *
            * @example
Initialize the navigation list with the hierarchyMenuDisplayThresholdLevel option specified:

            * $( ".selector" ).ojNavigationList( { "hierarchyMenuDisplayThresholdLevel": "4" } );
            *
            * @example
Get or set the hierarchyMenuDisplayThresholdLevel option, after initialization:

            * // getter
            * var display = $( ".selector" ).ojNavigationList( "option", "hierarchyMenuDisplayThresholdLevel" );
            *
            * // setter
            * $( ".selector" ).ojNavigationList( "option", "hierarchyMenuDisplayThresholdLevel", "4" );
            *
            * @example
Set the default in the theme (SCSS) :

            * $navigationListHierarchyMenuDisplayThresholdLevelOptionDefault: -1 !default;
            */
            hierarchyMenuDisplayThresholdLevel: 0,
            /**
             * Label for top level list items.
             *
NOTE: This is needed only for sliding navigation list where
             * this will be used as title for the top level list elements.
             * @type {?string}
             * @default Navigation List
             * @expose
             * @instance
             * @memberof oj.ojNavigationList
             */
            rootLabel: null,
            /**
             * Item key of currently selected list item. If the value is modified
             * by an application, navigation list UI is modified to match the new value.
             * @type {string|null}
             * @default null
             * @expose
             * @instance
             * @memberof oj.ojNavigationList
             */
            selection: null,
            /**
             * Specifies which items in NavigationList should be expanded. Specifies "all" value to expand all items.  Specifies
             * an array of keys to expand specific items.
             *
             * The default value is "auto", which means that NavigationList will determine which items are expanded by default.
             * Specifically, if drillMode is set to "none", then all items are expanded, any other values for
             * drillMode will not cause any items to expand by default.
             *
             * Note that expanded does not return the currently expanded items.  This only returns what is specified
             * by default.  To retrieve the keys of currently expanded items, use the getExpanded
             * method.
             * @type {Array|string}
             * @default []
             * @expose
             * @instance
             * @memberof oj.ojNavigationList
             */
            expanded: "auto",
            /**
             * The data source for the NavigationList accepts either a oj.TableDataSource or oj.TreeDataSource.
             * See the data source section in the introduction for out of the box data source types.
             * If the data attribute is not specified, the child elements are used as content.  If there's no
             * content specified, then an empty list is rendered.
             *
             * @expose
             * @memberof! oj.ojNavigationList
             * @instance
             * @type {oj.TableDataSource|oj.TreeDataSource}
             * @default null
             *
             * @example
Initialize the NavigationList with a one-dimensional array:

             * $( ".selector" ).ojNavigationList({ "data": new oj.ArrayTableDataSource([1,2,3])});
             *
             * @example
Initialize the NavigationList with an oj.Collection:

             * $( ".selector" ).ojNavigationList({ "data": new oj.CollectionTableDataSource(collection)});
             */
            data: null,
            /**
             * Whether to display both the label and icons ("all") or just the icons ("icons").
             * In the latter case, the label is displayed in a tooltip instead, unless a tooltip was already supplied at create time.
             * Note: display="icons" is valid only when drillMode=none and navigation list is a flat list.
             * It is also mandatory to provide icons for each item as stated in icons section.
             *
             * @expose
             * @memberof oj.ojNavigationList
             * @instance
             * @type {string}
             * @ojvalue {string} "all" Display both the label and icons.
             * @ojvalue {string} "icons" Display only the icons.This option
             * @default "all"
             *
             * @example
Initialize the NavigationList with the display option specified:

             * $( ".selector" ).ojNavigationList( { "display": "icons" } );
             *
             * @example
Get or set the display option, after initialization:

             * // getter
             * var display = $( ".selector" ).ojNavigationList( "option", "display" );
             *
             * // setter
             * $( ".selector" ).ojNavigationList( "option", "display", "icons" );
             */
            display: "all",
            /**
             * Navigation List supports two different look-and-feel depends on its usage level, one is application level and other is page level.
             *
             * @expose
             * @memberof oj.ojNavigationList
             * @instance
             * @type {string}
             * @ojvalue {string} "application" Render Navigation List for application level navigation.
             * @ojvalue {string} "page" Render Navigation List for page level navigation.
             * @default "page"
             *
             * @example
Initialize the NavigationList with the navigationLevel option specified:

             * $( ".selector" ).ojNavigationList( { "navigationLevel": "application" } );
             *
             * @example
Get or set the navigationLevel option, after initialization:

             * // getter
             * var display = $( ".selector" ).ojNavigationList( "option", "navigationLevel" );
             *
             * // setter
             * $( ".selector" ).ojNavigationList( "option", "navigationLevel", "application" );
             */
            navigationLevel: "page",
            /**
             * The item option contains a subset of options for items.
             *
             * @expose
             * @memberof! oj.ojNavigationList
             * @instance
             */
            item: {
                /**
                 * The renderer function that renders the content of the item. See itemContext
                 * in the introduction to see the object passed into the renderer function.
                 * The function returns either a String or a DOM element of the content inside the item.
                 * If the developer chooses to manipulate the list element directly, the function should return
                 * nothing. If no renderer is specified, Navigation List will treat the data as a String.
                 *
                 * @expose
                 * @alias item.renderer
                 * @memberof! oj.ojNavigationList
                 * @instance
                 * @type {function(Object)|null}
                 * @default null
                 *
                 * @example
Initialize the NavigationList with a renderer:

                 * $( ".selector" ).ojNavigationList({ "data":data, "item": { "renderer": function(itemContext) {
                 *                                            return itemContext['data'].get('FIRST_NAME');}}});
                 *
                 * @example
Get or set the renderer option, after initialization:

                 * // set the renderer function
                 * $( ".selector" ).ojNavigationList( "option", "item.renderer", myFunction});
                 */
                renderer: null,
                /**
                 * Whether the item is selectable.
                 * See itemContext in the introduction to see the object passed into the selectable function.
                 *
                 * @expose
                 * @alias item.selectable
                 * @memberof! oj.ojNavigationList
                 * @instance
                 * @type {function(Object)|boolean}
                 * @default true
                 *
                 * @example
Initialize the NavigationList such that the first 3 items are not selectable:

                 * $( ".selector" ).ojNavigationList({ "data":data, "item": { "selectable": function(itemContext) {
                 *                                            return itemContext['index'] > 3;}}});
                 */
                selectable: true
                        /**
                         * The knockout template used to render the content of the item.
                         *
                         * This attribute is only exposed via the ojComponent binding, and is not a
                         * component option.
                         *
                         * @ojbindingonly
                         * @name item.template
                         * @memberof! oj.ojNavigationList
                         * @instance
                         * @type {string|null}
                         * @default null
                         *
                         * @example
Specify the template when initializing NavigationList:

                         * // set the template
                         * <div id="navlist" data-bind="ojComponent: {component: 'ojNavigationList', data: dataSource, template: 'my_template'}"></div>
                         */
            },
            //Events
            /**
             *
Triggered before this list item is selected.
             * To prevent the item selection, return false from event handler or invoke event.preventDefault().
             *
The ui.key contains item key which uniquely identifies the item.
             * ui.item payload field contains item element being selected.
             *
             * @expose
             * @event
             * @memberof! oj.ojNavigationList
             * @instance
             * @property {Event} event jQuery event object
             * @property {Object} ui Parameters
             * @property {Object} ui.key Selected list item key.
             * @property {jQuery} ui.item Selected list item.
             *
             * @example
Initialize the Navigation List with the beforeSelect callback specified:

             * $( ".selector" ).ojNavigationList({
             *     "beforeSelect": function( event, ui ) {}
             * });
             *
             * @example
Bind an event listener to the ojbeforeselect event:

             * $( ".selector" ).on( "ojbeforeselect", function( event, ui ) {} );
             */
            beforeSelect: null,
            /**
             * Triggered before an item is collapse via the expanded option,
             * the collapse method, or via the UI.
             * To prevent the item being collapsed, return false from event handler or invoke event.preventDefault().
             *
             * @expose
             * @event
             * @memberof! oj.ojNavigationList
             * @instance
             * @property {Event} event jQuery event object
             * @property {Object} ui Parameters
             * @property {Object} ui.key the key of the item to be collapse
             * @property {jQuery} ui.item the item to be collapse
             *
             * @example
Initialize the NavigationList with the beforeCollapse callback specified:

             * $( ".selector" ).ojNavigationList({
             *     "beforeCollapse": function( event, ui ) {
             *         // return false to veto the event, which prevents the item to collapse
             *     }
             * });
             *
             * @example
Bind an event listener to the ojbeforecollapse event:

             * $( ".selector" ).on( "ojbeforecollapse", function( event, ui ) {} );
             */
            beforeCollapse: null,
            /**
             * Triggered before the current item is changed via the currentItem option or via the UI.
             * To prevent the item being focused, return false from event handler or invoke event.preventDefault().
             * @expose
             * @event
             * @memberof! oj.ojNavigationList
             * @instance
             * @property {Event} event jQuery event object
             * @property {Object} ui Parameters
             * @property {Object} ui.previousKey the key of the previous item
             * @property {jQuery} ui.previousItem the previous item
             * @property {Object} ui.key the key of the new current item
             * @property {jQuery} ui.item the new current item
             *
             * @example
Initialize the NavigationList with the beforeCurrentItem callback specified:

             * $( ".selector" ).ojNavigationList({
             *     "beforeCurrentItem": function( event, ui ) {
             *         // return false to veto the event, which prevents the item to become focus
             *     }
             * });
             *
             * @example
Bind an event listener to the ojbeforecurrentitem event:

             * $( ".selector" ).on( "ojbeforecurrentitem", function( event, ui ) {} );
             */
            beforeCurrentItem: null,
            /**
             * Triggered after an item has been collapsed via the expanded option,
             * the collapse method, or via the UI.
             *
             * @expose
             * @event
             * @memberof! oj.ojNavigationList
             * @instance
             * @property {Event} event jQuery event object
             * @property {Object} ui Parameters
             * @property {Object} ui.key The key of the item that was just collapsed.
             * @property {jQuery} ui.item The list item that was just collapsed.
             *
             * @example
Initialize the NavigationList with the expand callback specified:

             * $( ".selector" ).ojNavigationList({
             *     "collapse": function( event, ui ) {}
             * });
             *
             * @example
Bind an event listener to the ojcollapse event:

             * $( ".selector" ).on( "ojcollapse", function( event, ui ) {} );
             */
            collapse: null,
            /**
             * Triggered before an item is expand via the expanded option,
             * the expand method, or via the UI.
             * To prevent the item being expanded, return false from event handler or invoke event.preventDefault().
             * @expose
             * @event
             * @memberof! oj.ojNavigationList
             * @instance
             * @property {Event} event jQuery event object
             * @property {Object} ui Parameters
             * @property {Object} ui.key the key of the item to be expand
             * @property {jQuery} ui.item the item to be expand
             *
             * @example
Initialize the NavigationList with the beforeExpand callback specified:

             * $( ".selector" ).ojNavigationList({
             *     "beforeExpand": function( event, ui ) {
             *         // return false to veto the event, which prevents the item to expand
             *     }
             * });
             *
             * @example
Bind an event listener to the ojbeforeexpand event:

             * $( ".selector" ).on( "ojbeforeexpand", function( event, ui ) {} );
             */
            beforeExpand: null,
            /**
             * Triggered after an item has been expanded via the expanded option,
             * the expand method, or via the UI.
             *
             * @expose
             * @event
             * @memberof! oj.ojNavigationList
             * @instance
             * @property {Event} event jQuery event object
             * @property {Object} ui Parameters
             * @property {Object} ui.key The key of the item that was just expanded.
             * @property {jQuery} ui.item The list item that was just expanded.
             *
             * @example
Initialize the NavigationList with the expand callback specified:

             * $( ".selector" ).ojNavigationList({
             *     "expand": function( event, ui ) {}
             * });
             *
             * @example
Bind an event listener to the ojexpand event:

             * $( ".selector" ).on( "ojexpand", function( event, ui ) {} );
             */
            expand: null,
            /**
             * Fired whenever a supported component option changes, whether due to user interaction or programmatic
             * intervention.  If the new value is the same as the previous value, no event will be fired.
             *
             * @expose
             * @event
             * @memberof! oj.ojNavigationList
             * @instance
             * @property {Event} event jQuery event object
             * @property {Object} ui Parameters
             * @property {string} ui.option the name of the option that is changing
             * @property {boolean} ui.previousValue the previous value of the option
             * @property {boolean} ui.value the current value of the option
             * @property {Object} ui.optionMetadata information about the option that is changing
             * @property {string} ui.optionMetadata.writeback "shouldWrite" or
             *           "shouldNotWrite".  For use by the JET writeback mechanism.
             * @property {jQuery} ui.item For selection option change, this will be the selected list item. Otherwise it is undefined.
             *
             * @example
Initialize component with the optionChange callback

             * $(".selector").ojNavigationList({
             *   'optionChange': function (event, data) {
             *        if (data['option'] === 'selection') { // handle selection change }
             *    }
             * });
             * @example
Bind an event listener to the ojoptionchange event

             * $(".selector").on({
             *   'ojoptionchange': function (event, data) {
             *       window.console.log("option that changed is: " + data['option']);
             *   };
             * });
             */
            optionChange: null
        },
        /**
         * Create the Navigation List
         * @override
         * @memberof! oj.ojNavigationList
         * @protected
         */
        _ComponentCreate: function () {
            this._super();
            this._setup();
        },
        /**
         * Initialize the NavigationList after creation
         * @protected
         * @override
         * @memberof! oj.ojNavigationList
         */
        _AfterCreate: function ()
        {
            this._super();
            this.navlist.afterCreate();
        },
        /**
         * When the contextMenu option is set, this method is called when the user invokes the context menu via
         * the default gestures: right-click, pressHold, and Shift-F10.  Components should not call this method directly.
         *
         * @param {!Object} menu The JET Menu to open as a context menu.  Always non-null.
         * @param {!Event} event What triggered the menu launch.  Always non-null.
         * @param {string} eventType "mouse", "touch", or "keyboard".  Never null.
         * @private
         */
        _NotifyContextMenuGesture: function (menu, event, eventType)
        {
            this.navlist.notifyContextMenuGesture(menu, event, eventType);
        },
        /**
         * Initialize DOM structure for navigation list.
         * @private
         * @memberof! oj.ojNavigationList
         */
        _setup: function () {
            for (var key in this.options) {
                this._validateOptionValues(key, this.options[key]);
            }
            this._validateOptionsForIconsOnlyAndHorizontalList(this.options['drillMode'], this.options['display'], this.options['edge']);

            this.navlist = new _ojNavigationListView();

            var opts = {};
            opts.ojContext = this;
            opts = $.extend(this.options, opts);
            this.navlist.init(opts);
        },

        getNodeBySubId: function (locator)
        {
            return this.navlist.getNodeBySubId(locator);
        },
        getSubIdByNode: function(node)
        {
            return this.navlist.getSubIdByNode(node);
        },
        /**
         * {@ojinclude "name":"nodeContextDoc"}
         * @param {!Element} node - {@ojinclude "name":"nodeContextParam"}
         * @returns {Object|null} {@ojinclude "name":"nodeContextReturn"}
         *
         * @example {@ojinclude "name":"nodeContextExample"}
         *
         * @expose
         * @instance
         * @memberof oj.ojNavigationList
         */
        getContextByNode: function(node)
        {
           return this.navlist.getContextByNode(node);
        },
        /**
         * Expand an item.

         * Note when vetoable is set to false, beforeExpand event will still be fired but the event cannot be veto.

         *
         * @expose
         * @memberof oj.ojNavigationList
         * @instance
         * @param {Object} key the key of the item to expand
         * @param {boolean} vetoable if event is vetoable
         */
        expand: function (key, vetoable)
        {
            this.navlist.expandKey(key, vetoable, true, true);
        },
        /**
         * Collapse an item.

         * Note when vetoable is set to false, beforeCollapse event will still be fired but the event cannot be veto.

         *
         * @expose
         * @memberof oj.ojNavigationList
         * @instance
         * @param {Object} key the key of the item to collapse
         * @param {boolean} vetoable if event is vetoable
         */
        collapse: function (key, vetoable)
        {
            this.navlist.collapseKey(key, vetoable, true);
        },
        /**
         * Gets the key of currently expanded items.
         *
         * @expose
         * @memberof oj.ojNavigationList
         * @instance
         * @return {Array} array of keys of currently expanded items
         */
        getExpanded: function ()
        {
            return this.navlist.getExpanded();
        },
        _validateOptionsForIconsOnlyAndHorizontalList: function (drillMode, display, edge) {
            if (drillMode !== 'none') {
                if (display === 'icons') {
                    throw "Icon only navigation list should have drillMode set to 'none'.";
                }
                if (edge === 'top') {
                    throw "Horizontal navigation list should have drillMode set to 'none'.";
                }
            }
        },
        _validateOptionValues: function (key, value) {
            var valid = true;
            if (key === "drillMode") {
                valid = (value === 'none' || value === 'collapsible' || value === 'sliding');
            } else if (key === "display") {
                valid = (value === 'all' || value === 'icons');
            } else if (key === "edge") {
                valid = (value === 'top' || value === 'start');
            }

            if (!valid) {
                throw "Invalid value: " + value + " for key: " + key;
            }

        },
        /**
         * Set single option
         * @param {string} key the option key
         * @param {Object} value value for option
         * @override
         * @memberof oj.ojNavigationList
         * @instance
         * @private
         */
        _setOption: function (key, value) {
            this._validateOptionValues(key, value);
            switch (key) {
                case "drillMode":
                    this._validateOptionsForIconsOnlyAndHorizontalList(value, this.options['display'], this.options['edge']);
                    break;
                case "display":
                    this._validateOptionsForIconsOnlyAndHorizontalList(this.options['drillMode'], value, this.options['edge']);
                    break;
                case "edge":
                    this._validateOptionsForIconsOnlyAndHorizontalList(this.options['drillMode'], this.options['display'], value);
                    break;
            }
            return this._super(key, value);
        },
        /**
         * Sets multiple options
         * @param {Object} options the options object
         * @param {Object} flags additional flags for option
         * @override
         * @private
         */
        _setOptions: function (options, flags)
        {
            var result = this.navlist.setOptions(options, flags);

            for (var key in options)
            {
              if( result.skipOptions.indexOf(key) < 0 ) {
                this._setOption(key, options[key], flags);
              }
            }

            if (result.needRefresh)
            {
                this.navlist.refresh();
            }
            return this;
        },
        /**
         * In browsers [Chrome v35, Firefox v24.5, IE9, Safari v6.1.4], blur and mouseleave events are generated for hidden content but not detached content,
         * so for detached content only, we must use this hook to remove the focus and hover classes.
         * @override
         * @private
         */
        _NotifyDetached: function ()
        {
            this.navlist.notifyDetached();
        },
        /**
         * Invoked when application calls oj.Components.subtreeShown.
         * @override
         * @private
         */
        _NotifyShown: function()
        {
             this.navlist.notifyShown();
        },
        /**
         * Refreshes the visual state of the Navigation List. JET components require a refresh() after the DOM is
         * programmatically changed underneath the component.
         *
This method does not accept any arguments.
         *
         * @expose
         * @memberof oj.ojNavigationList
         * @instance
         *
         * @example
Invoke the refresh method:

         * $( ".selector" ).ojNavigationList( "refresh" );
         */
        refresh: function () {
            this._super();
            this.navlist.refresh();

        },
        /**
         * Returns a Promise that resolves when the component is ready, i.e. after data fetching, rendering, and animations complete.
         * Note that in the highwatermark scrolling case, component is ready after data fetching, rendering, and associated animations of items fetched so far are complete.
         *
         *
This method does not accept any arguments.
         *
         * @expose
         * @memberof oj.ojNavigationList
         * @instance
         * @return {Promise} A Promise that resolves when the component is ready.
         */
        whenReady: function()
        {
            return this.navlist.whenReady();
        },
        /**
         * Destroy the Navigation List
         * @memberof! oj.ojNavigationList
         * @private
         */
        _destroy: function ()
        {
            this.navlist.destroy();
            this._super();
            delete this.navlist;
        }

        // Fragments:

        /**
         *

         *

         *

         *       Target
         *       Gesture
         *       Action
         *

         *

         *

         *

         *       List Item
         *       Tap
         *       Selects the item.
         *

         *

         *       Press & Hold
         *       Display context menu
         *

         *

         *       Group Item
         *       Tap
         *       Expand or collapse the group item if drillMode is set to collapsible.
         *       When drillMode is set to sliding, sublist will silde in.
         *       When drillMode is set to none, group item will be selecetd.
         *

         *

         *       Press & Hold
         *       Display context menu
         *

         *

         *       Hierarchical Menu button
         *       Tap
         *       Open menu. Refer menu button touch documentation. Note: This is applicable only for Sliding Navigation List.
         *

         *

         *       Previous Icon or List Header
         *       Tap
         *       Collapses the sublist and slides to parent list. Note: This is applicable only for Sliding Navigation List.
         *

         *

         *

         *
         * @ojfragment touchDoc - Used in touch gesture section of classdesc, and standalone gesture doc
         * @memberof oj.ojNavigationList
         */

        /**
         *

         *

         *

         *       Target
         *       Key
         *       Action
         *

         *

         *

         *

         *       List Item
         *       Enter or Space
         *       Selects list item.
         *

         *

         *       UpArrow
         *       Moves focus to the previous visible list item.
         *

         *

         *       DownArrow
         *       Moves focus to the next  visible list item
         *

         *

         *       RightArrow (LeftArrow in RTL)
         *       For horizontal navigation list,focus will be moved to next visible item.
         *
         *

         *

         *       LeftArrow (RightArrow in RTL)
         *       For horizontal navigation list,focus will be moved to previous visible item.
         *

         *

         *       Home
         *       Moves focus to the first visible list item.
         *

         *

         *       End
         *       Moves focus to the last visible list item.
         *

         *

         *       F2
         *       If focus is on a list item, pressing F2 will make its contents accessible using TAB.
         *

         *

         *       Esc
         *       When F2 mode is enabled, press Esc to exit F2 mode.
         *

         *

         *       Shift+Tab
         *       Move fous to hierarchical menu button.Only applicable for sliding navigation list and when hierarchial menu button is enabled.
         *

         *

         *       Group Item
         *       RightArrow (LeftArrow in RTL)
         *       If focus is on collapsed node, expands the sub list.
         *

         *

         *       LeftArrow (RightArrow in RTL)
         *       If focus is on expanded node, collapses the sub list.
         *

         *

         *       List Item in sublist
         *       Esc
         *       Applicable only for sliding navigation list. If focus is in a sub list, closes the sublist and moves focus to the parent list item.
         *

         *

         *       Hierarchical Menu button
         *       Enter
         *       Open menu. Refer menu button keyboard documentation. Note: This target is visible only for Sliding Navigation List.
         *

         *

         *       Tab
         *       Moves focus to current list item. Note: This target is visible only for Sliding Navigation List.
         *

         *

         *       Shift + Tab
         *       Moves focus to Previous Icon. Note: This target is visible only for Sliding Navigation List.
         *

         *

         *       Previous Icon or List Header
         *       Enter
         *       Collapses the sublist and slides to parent list.Note: This target is visible only for Sliding Navigation List.
         *

         *

         *       Tab
         *       Moves focus to Hierarchical Menu button. Note: This target is visible only for Sliding Navigation List.
         *

         *
         *

         *

         *
         *
         * @ojfragment keyboardDoc - Used in keyboard section of classdesc, and standalone gesture doc
         * @memberof oj.ojNavigationList
         */

         // SubId Locators *****************************************************

         /**
          *
Sub-ID for the ojNavigationList component's list item element.

          *
          *

          * To lookup the list items the locator object should have the following:
          *

          *
subId: 'oj-navigationlist-item'

          *
key: the key of the item

          *

          *
          * @ojsubid oj-navigationlist-item
          * @memberof oj.ojNavigationList
          *
          * @example
Get the list item element with key 'foo':

          * var node = $( ".selector" ).ojNavigationList( "getNodeBySubId", {'subId': 'oj-navigationlist-item', 'key': 'foo'} );
          */
          /**
           *
Sub-ID for the ojNavigationList component's previous link element.

           *
           * To lookup the previous link the locator object should have the following:
           *

           *
subId: 'oj-navigationlist-previous-link'

           *

           * @ojsubid
           * @memberof oj.ojNavigationList
           *
           * @example
Get the previous link element:

           * var node = $( ".selector" ).ojNavigationList( "getNodeBySubId", {'subId': 'oj-navigationlist-previous-link'} );
           */
           /**
            *
Sub-ID for the ojNavigationList component's hierarchical menu button element.
            * See the getNodeBySubId method for details.

            *
            * To lookup the hierarchical menu button the locator object should have the following:
            *

            *
subId: 'oj-navigationlist-hierarchical-button'

            *

            * @ojsubid
            * @name oj-navigationlist-hierarchical-button
            * @memberof oj.ojNavigationList
            *
            * @example
Get the hierarchical menu button element:

            * var node = $( ".selector" ).ojNavigationList( "getNodeBySubId", {'subId': 'oj-navigationlist-hierarchical-button'} );
            */
            /**
             *
Sub-ID for the ojNavigationList component's hierarchical menu element.

             *
             * To lookup the hierarchical menu the locator object should have the following:
             *

             *
subId: 'oj-navigationlist-hierarchical-menu'

             *

             * @ojsubid
             * @name oj-navigationlist-hierarchical-menu
             * @memberof oj.ojNavigationList
             *
             * @example
Get the hierarchical menu element:

             * var node = $( ".selector" ).ojNavigationList( "getNodeBySubId", {'subId': 'oj-navigationlist-hierarchical-menu'} );
             */

           // Node Context Objects *********************************************
            /**
             *
Context for the ojNavigationList component's items.

             *
             * @property {number} index the zero based item index relative to its parent
             * @property {Object} key the key of the item
             * @property {Element} parent the parent group item.  Only available if item has a parent.
             * @property {boolean} group whether the item is a group.
             *
             * @ojnodecontext oj-navigationlist-item
             * @memberof oj.ojNavigationList
             */
    });

    // Add custom getters for properties from theming file
    oj.Components.setDefaultOptions(
      {
        'ojNavigationList':
        {
          'hierarchyMenuDisplayThresholdLevel': oj.Components.createDynamicPropertyGetter(
            function()
            {
               return oj.ThemeUtils.getOptionDefaultMap("navigationList")["hierarchyMenuDisplayThresholdLevel"];
            })
        }
      }
    );
}());

});