b0y-101 Mini Shell


Current Path : E:/www/risk/media/com_pagebuilderck/assets/
File Upload :
Current File : E:/www/risk/media/com_pagebuilderck/assets/ckcontextmenu.js

/**
 * @name		Context Menu CK
 * @copyright	Copyright (C) 2020. All rights reserved.
 * @license		GNU General Public License version 2 or later; see LICENSE.txt
 * @author		Cedric Keiflin - https://www.template-creator.com - https://www.joomlack.fr
 * Original script © 2015 Context Menu Madness! Demo by Nick Salloum
 */

(function () {

	"use strict";

	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//
	// H E L P E R    F U N C T I O N S
	//
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////

	/**
	 * Function to check if we clicked inside an element with a particular class
	 * name.
	 * 
	 * @param {Object} e The event
	 * @param {String} className The class name to check against
	 * @return {Boolean}
	 */
	function clickInsideElement(e, className) {
		var el = e.srcElement || e.target;
		if (el.classList.contains(className)) {
			return el;
		} else {
			while (el = el.parentNode) {
				if (el.classList && el.classList.contains(className)) {
					return el;
				}
			}
		}

		return false;
	}

	/**
	 * Get's exact position of event.
	 * 
	 * @param {Object} e The event passed in
	 * @return {Object} Returns the x and y position
	 */
	function getPosition(e) {
		var posx = 0;
		var posy = 0;

		if (!e)
			var e = window.event;
			parentPos = document.getElementById('workspaceparentck').getBoundingClientRect();

		if (e.pageX || e.pageY) {
			posx = e.pageX - parentPos.x - window.scrollX;
			posy = e.pageY - parentPos.y - window.scrollY;
		} else if (e.clientX || e.clientY) {
			posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - parentPos.x - window.scrollX;
			posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop - parentPos.y - window.scrollY;
		}

		return {
			x: posx,
			y: posy
		}
	}

	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//
	// C O R E    F U N C T I O N S
	//
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////

	/**
	 * Variables.
	 */
//	var contextMenuClassName = "context-menu-ck";
//	var contextMenuItemClassName = "context-menu-ck__item";
	var contextMenuLinkClassName = "context-menu-ck__link";
	var contextMenuActive = "context-menu-ck--active";

//	var taskItemClassName = "rowck";
	var taskItemInContext;
	var taskColumnInContext;
	var taskRowInContext;

	var clickCoords;
	var clickCoordsX;
	var clickCoordsY;
	var parentPos;

	var menu = document.querySelector("#context-menu-ck");
	var menuItems = menu.querySelectorAll(".context-menu-ck__item");
	var menuState = 0;
	var menuWidth;
	var menuHeight;
//	var menuPosition;
//	var menuPositionX;
//	var menuPositionY;

	var windowWidth;
	var windowHeight;

	/**
	 * Initialise our application's code.
	 */
	function init() {
		contextListener();
		eventListener();
		keyupListener();
		resizeListener();
	}

	/**
	 * Listens for contextmenu events.
	 */
	function contextListener() {
		document.addEventListener("contextmenu", function (e) {
			taskRowInContext = clickInsideElement(e, 'rowck');
			taskColumnInContext = clickInsideElement(e, 'blockck');
			taskItemInContext = clickInsideElement(e, 'cktype');

			if (taskRowInContext) {
				// disable if ACL not allow
				var el = e.srcElement || e.target;
				if (el.classList.contains('cknoacl')) return false;

				e.preventDefault();
				fillMenu();
				toggleMenuOn();
				positionMenu(e);
			} else {
				taskRowInContext = null;
				toggleMenuOff();
			}
		});
	}

	/**
	 * Listens for click events.
	 */
	function eventListener() {
		document.addEventListener("click", function (e) {
			var clickeElIsLink = clickInsideElement(e, contextMenuLinkClassName);

			if (clickeElIsLink) {
				e.preventDefault();
				menuItemListener(clickeElIsLink);
			} else {
				var button = e.which || e.button;
				if (button === 1) {
					toggleMenuOff();
				}
			}
		});
		// position the submenu
		menu.querySelectorAll('.context-menu-ck__item.parent').forEach(listItem => listItem.addEventListener("mouseover", function (e) {
			positionSubmenu(listItem);
			highlightNode(listItem);
		}));
		menu.querySelectorAll('.context-menu-ck__item.parent').forEach(listItem => listItem.addEventListener("mouseleave", function (e) {
			removeHighlights();
		}));
		menu.querySelectorAll('.context-menu-ck__item.parent').forEach(listItem => listItem.addEventListener("click", function (e) {
			menu.classList.add('context-menu-ck__submenuopened');
			var submenu = listItem.querySelector('ul');
			if (! submenu.classList.contains('context-menu-ck__submenushow')) {
				if (menu.querySelector('.context-menu-ck__submenushow')) {
					var prevsubmenu = menu.querySelector('.context-menu-ck__submenushow');
					prevsubmenu.classList.remove('context-menu-ck__submenushow');
					prevsubmenu.style.display = "";
				}
				if (menu.querySelector('.context-menu-ck__item.active')) menu.querySelector('.context-menu-ck__item.active').classList.remove('active');
				submenu.classList.add('context-menu-ck__submenushow');
				listItem.classList.add('active');
				submenu.style.display = "block";
				positionSubmenu(listItem);
				highlightNode(listItem);
			} else {
				submenu.classList.remove('context-menu-ck__submenushow');
				listItem.classList.remove('active');
				submenu.style.display = "";
				removeHighlights();
				menu.classList.remove('context-menu-ck__submenuopened');
			}
		}));
	}

	/**
	 * Calculate the correct position for the submenu
	 * 
	 * @param node listItem
	 * @returns void
	 */
	function positionSubmenu(listItem) {
		var submenu = listItem.querySelector('ul');
		windowWidth = window.innerWidth;
		windowHeight = window.innerHeight;

		if ((windowWidth - parseInt(menu.style.left) - parentPos.x) < 480) {
			submenu.style.left = - 240 + "px";
		} else {
			submenu.style.left = 230 + "px";
		}

		// reset submenu position
		submenu.style.top = -25 + "px";
		var submenuHeight = submenu.offsetHeight + 4;
		var overflowH = (windowHeight - parseInt(submenu.getBoundingClientRect().top)) - submenuHeight;

		if ((windowHeight - 55 - parseInt(submenu.getBoundingClientRect().top)) < submenuHeight) {
			submenu.style.top = overflowH - 25 - 55 + "px";
		} else {
			submenu.style.top = -25 + "px";
		}
	}

	/**
	 * Visual help to target the focus
	 * 
	 * @param node listItem
	 * @returns void
	 */
	function highlightNode(listItem) {
		if (listItem.classList.contains('context-menu-ck_row')) {
			taskRowInContext.classList.add('ckhighlight');
		} else if (listItem.classList.contains('context-menu-ck_column')) {
			taskColumnInContext.classList.add('ckhighlight');
		} else if (listItem.classList.contains('context-menu-ck_item')) {
			taskItemInContext.classList.add('ckhighlight');
		} 
	}

	/**
	 * Remove the hightlight
	 * 
	 * @returns void
	 */
	function removeHighlights() {
		if(document.querySelector('.ckhighlight')) document.querySelector('.ckhighlight').classList.remove('ckhighlight');
	}

	/**
	 * Listens for keyup events.
	 */
	function keyupListener() {
		window.onkeyup = function (e) {
			if (e.keyCode === 27) {
				toggleMenuOff();
			}
		}
	}

	/**
	 * Window resize event listener
	 */
	function resizeListener() {
		window.onresize = function (e) {
			toggleMenuOff();
		};
	}

	/**
	 * Turns the custom context menu on.
	 */
	function toggleMenuOn() {
		if (menuState !== 1) {
			menuState = 1;
			menu.classList.add(contextMenuActive);
		}
	}

	/**
	 * 
	 * @param node taskItemInContext
	 * @returns void
	 */
	function fillMenu() {
		var rowEnabled = taskRowInContext ? 'list-item' : 'none';
		var columnEnabled = taskColumnInContext ? 'list-item' : 'none';
		var itemEnabled = taskItemInContext ? 'list-item' : 'none';
		menu.querySelector('.context-menu-ck_row').style.display = rowEnabled;
		menu.querySelector('.context-menu-ck_column').style.display = columnEnabled;
		menu.querySelector('.context-menu-ck_item').style.display = itemEnabled;
	}

	/**
	 * Turns the custom context menu off.
	 */
	function toggleMenuOff() {
		if (menuState !== 0) {
			menuState = 0;
			menu.classList.remove(contextMenuActive);
			menu.classList.remove('context-menu-ck__submenuopened');
			menu.querySelectorAll('ul').forEach(submenu => submenu.style.display = '');
			menu.querySelectorAll('li').forEach(listItem => listItem.classList.remove('active'));
		}
	}

	/**
	 * Positions the menu properly.
	 * 
	 * @param {Object} e The event
	 */
	function positionMenu(e) {
		clickCoords = getPosition(e);
		clickCoordsX = clickCoords.x;
		clickCoordsY = clickCoords.y;

		menuWidth = menu.offsetWidth + 4;
		menuHeight = menu.offsetHeight + 4;

		windowWidth = window.innerWidth;
		windowHeight = window.innerHeight;

		if ((windowWidth - clickCoordsX - parentPos.x) < menuWidth) {
			menu.style.left = windowWidth - menuWidth - parentPos.x + "px";
		} else {
			menu.style.left = clickCoordsX + "px";
		}

//		if ((windowHeight - clickCoordsY) < menuHeight) {
//			menu.style.top = windowHeight - menuHeight + "px";
//		} else {
			menu.style.top = clickCoordsY + "px";
//		}
	}

	/**
	 * Dummy action function that logs an action when a menu item link is clicked
	 * 
	 * @param {HTMLElement} link The link that was clicked
	 */
	function menuItemListener(link) {
		var action = link.getAttribute("data-action");
		if (action == 'parentItem') return;
		var actions = action.split('.');
		var target = actions[0];
		var task = actions[1];

		switch (target) {
			case 'row' :
				var targetEl = taskRowInContext;
				var listOfTasks = {
						'columns' : 'ckShowColumnsEdition',
						'fullwidth' : 'ckShowFullwidthRowEdition',
						'save' : 'ckSaveItem',
						'remove' : 'ckRemoveRow',
						'duplicate' : 'ckDuplicateRow',
						'edit' : 'ckShowCssPopup',
						'favorite' : 'ckShowFavoritePopup',
						'stylecopy' : 'ckCopyStyles',
						'stylepaste' : 'ckPasteStyles'
				};
				break;
			case 'column' :
				var targetEl = taskColumnInContext;
				var listOfTasks = {
						'remove' : 'ckRemoveBlock',
						'duplicate' : 'ckDuplicateColumn',
						'edit' : 'ckShowCssPopup',
						'favorite' : 'ckShowFavoritePopup',
						'stylecopy' : 'ckCopyStyles',
						'stylepaste' : 'ckPasteStyles'
				};
				break;
			case 'item' :
				var targetEl = taskItemInContext;
				var listOfTasks = {
						'save' : 'ckSaveItem',
						'remove' : 'ckRemoveItem',
						'clearstyles' : 'ckClearStyles',
						'duplicate' : 'ckDuplicateItem',
						'edit' : 'ckShowEditionPopup',
						'favorite' : 'ckShowFavoritePopup',
						'stylecopy' : 'ckCopyStyles',
						'stylepaste' : 'ckPasteStyles'
				};
				break;
			default :
				console.error('No target element found');
				return;
				break;
		}
		var targetId = targetEl.getAttribute("id");
		var targetTask = listOfTasks[task];
		toggleMenuOff();
		window[targetTask](targetId);
	}

	/**
	 * Run the app.
	 */
	init();

})();

Copyright © 2019 by b0y-101