Source: site-navigation-admin-web/src/main/resources/META-INF/resources/js/SiteNavigationMenuItemDOMHandler.es.js

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

import {
	addClasses,
	closest,
	contains,
	hasClass,
	next,
	removeClasses,
	toElement
} from 'metal-dom';

const MENU_CONTAINER_CLASSNAME = 'site-navigation-menu-container';

const MENU_ITEM_CLASSNAME = 'site-navigation-menu-item';

const MENU_ITEM_CONTENT_CLASSNAME = `${MENU_ITEM_CLASSNAME}__content`;

const MENU_ITEM_DRAGGING_CLASSNAME = `${MENU_ITEM_CLASSNAME}--dragging`;

const MENU_ITEM_DRAG_ICON_CLASSNAME = `${MENU_ITEM_CLASSNAME}__drag-icon`;

const MENU_ITEM_SELECTED_CLASSNAME = `${MENU_ITEM_CLASSNAME}--selected`;

/**
 * Returns the menu item element's children.
 *
 * @param {HTMLElement} menuItem The menu item to return children for.
 * @return {Array<HTMLElement>}
 */
const getChildren = function(menuItem) {
	return Array.prototype.slice
		.call(menuItem.children)
		.filter(child => hasClass(child, MENU_ITEM_CLASSNAME));
};

/**
 * Returns the parent menu item element of the menu item content.
 *
 * @param {HTMLElement} menuItemContent The menu item content to return the
 * parent menu item for.
 * @return {HTMLElement|null}
 */
const getFromContentElement = function(menuItemContent) {
	return closest(menuItemContent, `.${MENU_ITEM_CLASSNAME}`);
};

/**
 * Returns the menu item element with the given ID.
 *
 * @param {number|string} menuItemId The menu item's ID.
 * @return {HTMLElement|null}
 */
const getFromId = function(menuItemId) {
	return document.querySelector(
		`.${MENU_ITEM_CLASSNAME}[data-site-navigation-menu-item-id="${menuItemId}"]`
	);
};

/**
 * Returns the given menu item element's ID.
 *
 * @param {HTMLElement} menuItem The menu item
 * @return {number}
 */
const getId = function(menuItem) {
	return parseInt(menuItem.dataset.siteNavigationMenuItemId, 10) || 0;
};

/**
 * Returns the next menu item sibling of the given menu item element.
 *
 * @param {HTMLElement} menuItem The menu item.
 * @return {HTMLElement|null}
 */
const getNextSibling = function(menuItem) {
	next(menuItem, `.${MENU_ITEM_CLASSNAME}`);
};

/**
 * Returns the menu item element's parent.
 *
 * @param {HTMLElement} menuItem The menu item.
 * @return {HTMLElement|null}
 */
const getParent = function(menuItem) {
	return menuItem.parentElement;
};

/**
 * Returns the menu item element's siblings.
 *
 * @param {HTMLElement} menuItem The menu item.
 * @return {Array<HTMLElement>}
 */
const getSiblings = function(menuItem) {
	const parentElement = menuItem.parentElement;
	let siblings = [];

	if (parentElement) {
		siblings = getChildren(parentElement);
	}

	return siblings;
};

/**
 * Returns <code>true</code> if the menu item is a child of the parent menu
 * item.
 *
 * @param {HTMLElement} menuItem The menu item to check.
 * @param {HTMLElement} parentMenuItem The parent menu item.
 * @return {boolean} Whether the menu item is a child of the parent menu item.
 */
const isChildOf = function(menuItem, parentMenuItem) {
	return contains(parentMenuItem, menuItem);
};

/**
 * Returns <code>true</code> if the given HTML element is a menu item.
 * @param {HTMLElement} htmlElement The HTML element to check.
 * @return {boolean} Whether the HTML element is a menu item.
 */
const isMenuItem = function(htmlElement) {
	return hasClass(htmlElement, MENU_ITEM_CLASSNAME);
};

/**
 * Returns <code>true</code> if the given menu item element is selected.
 *
 * @param {HTMLElement} menuItem The menu item to check.
 * @return {boolean} Whether the menu item is selected.
 */
const isSelected = function(menuItem) {
	return hasClass(menuItem, MENU_ITEM_SELECTED_CLASSNAME);
};

/**
 * Mutates the given menu item element by changing it's status to
 * dragging or not dragging.
 * @param {HTMLElement} menuItem The menu item.
 */
const setDragging = function(menuItem, dragging = false) {
	if (dragging) {
		addClasses(menuItem, MENU_ITEM_DRAGGING_CLASSNAME);
	} else {
		removeClasses(menuItem, MENU_ITEM_DRAGGING_CLASSNAME);
	}
};

/**
 * Mutates the given menu item by changing it's status to selected. Only a
 * single menu item can be selected, so any other selected menu item will be
 * unselected.
 *
 * @param {!HTMLElement} menuItem The menu item.
 */
const setSelected = function(menuItem) {
	unselectAll();
	addClasses(menuItem, MENU_ITEM_SELECTED_CLASSNAME);
};

/**
 * Mutates all selected menu items and sets their status to unselected.
 */
const unselectAll = function() {
	const selectedMenuItem = toElement(`.${MENU_ITEM_SELECTED_CLASSNAME}`);

	if (selectedMenuItem) {
		removeClasses(selectedMenuItem, MENU_ITEM_SELECTED_CLASSNAME);
	}
};

export {
	MENU_CONTAINER_CLASSNAME,
	MENU_ITEM_CONTENT_CLASSNAME,
	MENU_ITEM_CLASSNAME,
	MENU_ITEM_DRAG_ICON_CLASSNAME,
	MENU_ITEM_DRAGGING_CLASSNAME,
	getChildren,
	getFromContentElement,
	getFromId,
	getId,
	getNextSibling,
	getParent,
	getSiblings,
	isChildOf,
	isMenuItem,
	isSelected,
	setDragging,
	setSelected,
	unselectAll
};