@nicobarbieri/quickctx
Version:
Fast & easy custom context menus for your web projects.
3 lines (2 loc) • 30.4 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).QuickCTX={})}(this,(function(e){"use strict";function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,i=Array(t);n<t;n++)i[n]=e[n];return i}function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,c(i.key),i)}}function o(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),Object.defineProperty(e,"prototype",{writable:!1}),e}function s(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=m(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var i=0,o=function(){};return{s:o,n:function(){return i>=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,r=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){r=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(r)throw s}}}}function a(e,t,n){return(t=c(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function u(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||m(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function c(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var i=n.call(e,t||"default");if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}function d(e){return d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},d(e)}function m(e,n){if(e){if("string"==typeof e)return t(e,n);var i={}.toString.call(e).slice(8,-1);return"Object"===i&&e.constructor&&(i=e.constructor.name),"Map"===i||"Set"===i?Array.from(e):"Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i)?t(e,n):void 0}}var h=function(){function e(t){var i,o=this,s=t.id,a=void 0===s?null!==(i=window.crypto)&&void 0!==i&&i.randomUUID?crypto.randomUUID():Date.now().toString(36)+Math.random().toString(36).substring(2):s,r=t.label,u=t.type,l=void 0===u?"action":u,c=t.action,d=t.targetTypes,m=void 0===d?["*"]:d,h=t.subCommands,v=void 0===h?[]:h,g=t.iconClass,f=void 0===g?null:g,p=t.disabled,b=void 0!==p&&p,y=t.visible,E=void 0===y||y,_=t.order,T=void 0===_?0:_,C=t.content,M=void 0===C?null:C;if(n(this,e),"separator"===this.type&&!r)throw new Error("MenuCommand (ID: ".concat(a,"): 'label' is required for types other than 'separator'."));this.id=a,this.label=r,this.type=l,this.action=c,this.targetTypes=Array.isArray(m)&&m.length>0?m:["*"],this.subCommands=v.map((function(t){var n=t instanceof e?t:new e(t);return n.parentCommand=o,n})),this.iconClass=f,this.disabled=b,this.visible=E,this.order=T,this.content=M}return o(e,null,[{key:"Separator",value:function(){return new e({type:"separator",content:arguments.length>0&&void 0!==arguments[0]?arguments[0]:null})}}])}();function v(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"",o=document.createElement(e);t&&(Array.isArray(t)?t.flatMap((function(e){return e.split(" ")})):l(t.split(" "))).forEach((function(e){return e&&o.classList.add(e)}));for(var s in n)Object.prototype.hasOwnProperty.call(n,s)&&o.setAttribute(s,n[s]);return i&&(o.textContent=i),o}var g=function(){return o((function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};n(this,e),this.isTouchDevice="ontouchstart"in window||navigator.maxTouchPoints>0;var i={defaultTrigger:"contextmenu",defaultMobileTrigger:"tap",defaultCloseTrigger:"auto",overlapStrategy:"closest",globalFilterStrategy:"hide",submenuArrow:'<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 16 16"><path fill="currentColor" d="M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L9.94 8L6.22 4.28a.75.75 0 0 1 0-1.06z"/></svg>',ignoreButtons:!0,ignoreLinks:!0,classes:{container:"quickctx-container",header:"quickctx-header",list:"quickctx-list",item:"quickctx-item",separator:"quickctx-separator",sublist:"quickctx-sublist",sublistCommand:"quickctx-sublist-command",disabled:"quickctx-item--disabled",hidden:"quickctx-item--hidden",icon:"quickctx-icon",opening:"quickctx--opening",open:"quickctx--open",closing:"quickctx--closing"},animations:{submenuOpenDelay:150,menuOpenDuration:200,menuCloseDuration:200,hoverMenuOpenDelay:450,hoverMenuCloseDelay:300,submenuCloseDelay:200,holdDuration:500}};this.options=u(u(u({},i),t),{},{classes:u(u({},i.classes),t.classes||{}),animations:u(u({},i.animations),t.animations||{})}),this.logger=console.log,this.loggerIsEnabled=!1,this.menuConfigurations={},this.registeredActions={},this.functionActionMap=new Map,this.activeMenuElement=null,this.currentTargetElement=null,this.activeSubmenus=[],this.menuHideTimeout=null,this.hoverHideTimeout=null,this.hoverOpenTimeout=null,this.submenuCloseTimeout=null,this.touchState={},this._boundHandleTrigger=this._handleTriggerEvent.bind(this),this._boundHandleKeydown=this._handleKeydown.bind(this),this._boundHandleScroll=this._handleScroll.bind(this),this._boundOutsideClick=this._handleOutsideClick.bind(this),this._boundScheduleAllSubmenusClose=this._scheduleAllSubmenusClose.bind(this),this._boundCancelAllSubmenusClose=this._cancelAllSubmenusClose.bind(this),this._boundHandleHoverEnter=this._cancelHoverHide.bind(this),this._boundHandleHoverLeave=this._scheduleHoverHide.bind(this),this._boundCancelHoverOpen=this._cancelHoverOpen.bind(this),this._boundHandleTouchStart=this._handleTouchStart.bind(this),this._boundHandleTouchMove=this._handleTouchMove.bind(this),this._boundHandleTouchEnd=this._handleTouchEnd.bind(this),this._init()}),[{key:"updateOptions",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this.options=u(u(u({},this.options),e),{},{classes:u(u({},this.options.classes),e.classes||{}),animations:u(u({},this.options.animations),e.animations||{})}),this._log({event:"updateOptions",message:"Updating options...",data:this.options}),this._setupEventListeners()}},{key:"_handleTouchStart",value:function(e){var t,n,i=this;if(!this.activeMenuElement){var o=e.target.closest("[data-custom-ctxmenu]");if(o){var s=o.getAttribute("data-custom-ctxmenu"),a=this.menuConfigurations[s];if(a){var r=null!==(t=a.ignoreLinks)&&void 0!==t?t:this.options.ignoreLinks,u=null!==(n=a.ignoreButtons)&&void 0!==n?n:this.options.ignoreButtons;if(!(r&&e.target.closest("a, [href]")||u&&e.target.closest('button, input[type="button"], input[type="submit"], input[type="reset"]'))){var l=a.mobileTriggerEvent||this.options.defaultMobileTrigger;"hold"===l&&e.preventDefault(),document.addEventListener("touchmove",this._boundHandleTouchMove,{passive:!0}),document.addEventListener("touchend",this._boundHandleTouchEnd);var c=e.touches[0];this.touchState={targetElement:o,config:a,startTime:Date.now(),startCoords:{x:c.clientX,y:c.clientY},isHolding:!1,timeout:null},"hold"===l&&(this.touchState.timeout=setTimeout((function(){i.touchState.isHolding=!0;var e={clientX:i.touchState.startCoords.x,clientY:i.touchState.startCoords.y,preventDefault:function(){},stopPropagation:function(){}};i._openMenu(i.touchState.config,i.touchState.targetElement,e)}),this.options.animations.holdDuration))}}}}}},{key:"_handleTouchMove",value:function(e){if(this.touchState&&this.touchState.timeout){var t=e.touches[0],n=Math.abs(t.clientX-this.touchState.startCoords.x),i=Math.abs(t.clientY-this.touchState.startCoords.y);(n>15||i>15)&&(clearTimeout(this.touchState.timeout),this.touchState=null,document.removeEventListener("touchmove",this._boundHandleTouchMove),document.removeEventListener("touchend",this._boundHandleTouchEnd))}}},{key:"_handleTouchEnd",value:function(e){if(this.touchState){clearTimeout(this.touchState.timeout);var t=Date.now()-this.touchState.startTime;if(document.removeEventListener("touchmove",this._boundHandleTouchMove),document.removeEventListener("touchend",this._boundHandleTouchEnd),this.touchState.isHolding)this.touchState=null;else{var n=this.touchState.config.mobileTriggerEvent||this.options.defaultMobileTrigger;if(t<300&&"tap"===n){var i={clientX:this.touchState.startCoords.x,clientY:this.touchState.startCoords.y,preventDefault:function(){},stopPropagation:function(){}};e.preventDefault(),this._openMenu(this.touchState.config,this.touchState.targetElement,i)}this.touchState=null}}}},{key:"setLogger",value:function(e){"function"==typeof e?this.logger=e:(console.warn("Logger must be a function. Default logging will be used."),this.logger=console.log)}},{key:"setLoggerIsEnabled",value:function(e){this.loggerIsEnabled=!!e}},{key:"_log",value:function(e){this.loggerIsEnabled&&this.logger(u(u({},e),{},{timestamp:new Date}))}},{key:"_init",value:function(){this._log({event:"init",message:"Initializing QuickCTX"}),this._setupEventListeners(),this._log({event:"init",message:"QuickCTX initialized"})}},{key:"_setupEventListeners",value:function(){var e=this,t=["contextmenu","click","dblclick","mouseover","mouseout"];t.forEach((function(t){document.removeEventListener(t,e._boundHandleTrigger)})),document.removeEventListener("touchstart",this._boundHandleTouchStart),this.isTouchDevice&&(document.addEventListener("touchstart",this._boundHandleTouchStart,{passive:!1}),this._log({event:"setupListeners",message:"Touch event listeners enabled."}));var n=new Set([this.options.defaultTrigger]);Object.values(this.menuConfigurations).forEach((function(e){e.triggerEvent&&("hover"===e.triggerEvent?["mouseover","mouseout"]:[e.triggerEvent]).forEach((function(e){return n.add(e)}))})),n.forEach((function(n){t.includes(n)&&document.addEventListener(n,e._boundHandleTrigger)})),this._log({event:"setupListeners",message:"Event listeners set up",data:{activeTriggers:Array.from(n)}})}},{key:"_handleTriggerEvent",value:function(e){var t,n,i=this;if(this.isTouchDevice&&"contextmenu"===e.type)e.preventDefault();else if(this._log({event:"handleTrigger",message:"Handling trigger event: ".concat(e.type),data:{target:e.target}}),"mouseout"!==e.type){var o="deepest"===this.options.overlapStrategy&&e.target.matches("[data-custom-ctxmenu]")?e.target:e.target.closest("[data-custom-ctxmenu]");if(o){var s=o.getAttribute("data-custom-ctxmenu");if(!s)throw this._log({event:"handleTrigger",message:"No menu ID found on target element: ".concat(o.tagName),data:{targetElementId:o.id||"unknown"},isError:!0}),new Error("No menu ID found on target element: ".concat(o.tagName));var a=this.menuConfigurations[s];if(!a)throw this._log({event:"handleTrigger",message:"No menu configuration found for ID: ".concat(s),data:{menuId:s},isError:!0}),new Error("No menu configuration found for ID: ".concat(s));var r=null!==(t=a.ignoreLinks)&&void 0!==t?t:this.options.ignoreLinks,u=null!==(n=a.ignoreButtons)&&void 0!==n?n:this.options.ignoreButtons;if(!(r&&e.target.closest("a, [href]")||u&&e.target.closest('button, input[type="button"], input[type="submit"], input[type="reset"]'))){var l="mouseover"===e.type?"hover":e.type,c=a.triggerEvent||this.options.defaultTrigger;l===c&&("hover"===c&&this.currentTargetElement===o||("hover"===l&&this.options.animations.hoverMenuOpenDelay>0?(this._cancelHoverOpen(),this.hoverOpenTimeout=setTimeout((function(){i._openMenu(a,o,e)}),this.options.animations.hoverMenuOpenDelay)):this._openMenu(a,o,e)))}}}else this._cancelHoverOpen()}},{key:"_handleKeydown",value:function(e){"Escape"===e.key&&this._hideMenu(this.activeMenuElement,!1)}},{key:"_handleScroll",value:function(){this.activeMenuElement&&this._hideMenu(this.activeMenuElement,!1)}},{key:"_handleOutsideClick",value:function(e){if(this.activeMenuElement&&!this.activeMenuElement.classList.contains(this.options.classes.opening)&&!this.activeMenuElement.contains(e.target)){var t,n=s(this.activeSubmenus);try{for(n.s();!(t=n.n()).done;){var i=t.value;if(i.element&&i.element.contains(e.target))return}}catch(e){n.e(e)}finally{n.f()}this._hideMenu(this.activeMenuElement,!1)}}},{key:"_setupHoverListeners",value:function(e,t){e.addEventListener("mouseleave",this._boundHandleHoverLeave),t.addEventListener("mouseleave",this._boundHandleHoverLeave),e.addEventListener("mouseenter",this._boundHandleHoverEnter),t.addEventListener("mouseenter",this._boundHandleHoverEnter)}},{key:"_openMenu",value:function(e,t,n){var i=this;this.activeMenuElement&&!this.activeMenuElement.classList.contains(this.options.classes.closing)&&this._hideMenu(this.activeMenuElement,!1),n.preventDefault(),n.stopPropagation(),this.currentTargetElement=t;var o=t.getAttribute("data-custom-ctxmenu-type")||"default",s=v("div",this.options.classes.container);Object.assign(s.style,{position:"fixed",zIndex:"10000",display:"none"}),document.body.appendChild(s),this.activeMenuElement=s,this._buildAndShowMenu(e,t,o,n.clientX,n.clientY),this._log({event:"_openMenu",message:"Opened menu ".concat(this.menuConfigurations.id," for target type: ").concat(o)});var a=this.isTouchDevice?e.mobileTriggerEvent||this.options.defaultMobileTrigger:e.triggerEvent||this.options.defaultTrigger,r=e.closeTriggerEvent||this.options.defaultCloseTrigger;"auto"===r&&(r="hover"===a?"mouseout":"click"),"mouseout"!==r||this.isTouchDevice?(setTimeout((function(){document.addEventListener("click",i._boundOutsideClick,!0),i.activeMenuElement}),0),this._log({event:"setupCloseListeners",message:"Using 'click' close trigger."})):(this._setupHoverListeners(t,this.activeMenuElement),this._log({event:"setupCloseListeners",message:"Using 'mouseout' close trigger."})),document.addEventListener("keydown",this._boundHandleKeydown),window.addEventListener("scroll",this._boundHandleScroll,!0)}},{key:"_scheduleHoverHide",value:function(){var e=this;this._cancelHoverHide(),this.hoverHideTimeout=setTimeout((function(){e._hideMenu(e.activeMenuElement)}),this.options.animations.hoverMenuCloseDelay)}},{key:"_cancelHoverHide",value:function(){this.hoverHideTimeout&&(clearTimeout(this.hoverHideTimeout),this.hoverHideTimeout=null)}},{key:"_cancelHoverOpen",value:function(){this.hoverOpenTimeout&&(clearTimeout(this.hoverOpenTimeout),this.hoverOpenTimeout=null)}},{key:"_scheduleSubmenuOpen",value:function(e,t,n){var i=this;this._cancelSubmenuOpen(e),e.openTimeout=setTimeout((function(){i._openSubmenu(e,t,n)}),this.options.animations.submenuOpenDelay)}},{key:"_cancelSubmenuOpen",value:function(e){e.openTimeout&&(clearTimeout(e.openTimeout),e.openTimeout=null)}},{key:"_openSubmenu",value:function(e,t,n){var i;if(null===(i=e.submenuElement)||void 0===i||!i.classList.contains(this.options.classes.open)){var o=e.submenuElement;o&&document.body.contains(o)||(o=v("div",[this.options.classes.container,this.options.classes.sublist]),Object.assign(o.style,{position:"fixed",zIndex:"10001",display:"none"}),document.body.appendChild(o),e.submenuElement=o),o.addEventListener("mousemove",this._boundCancelAllSubmenusClose),o.addEventListener("mouseleave",this._boundScheduleAllSubmenusClose);var s=t.getBoundingClientRect();this._buildAndShowMenu({commands:e.subCommands},n,n.dataset.customCtxmenuType||"default",s.right,s.top,o,e)}}},{key:"_scheduleAllSubmenusClose",value:function(){var e=this;this._cancelAllSubmenusClose(),this.submenuCloseTimeout=setTimeout((function(){e._closeSubmenus()}),this.options.animations.submenuCloseDelay)}},{key:"_cancelAllSubmenusClose",value:function(){clearTimeout(this.submenuCloseTimeout)}},{key:"_closeSiblingSubmenus",value:function(e){for(var t=new Set,n=e;n;)t.add(n),n=n.parentCommand;for(var i=this.activeSubmenus.length-1;i>=0;i--){var o=this.activeSubmenus[i];t.has(o.parentCommand)||(this._closeSingleSubmenu(o),this.activeSubmenus.splice(i,1))}}},{key:"_closeSingleSubmenu",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=e.element;n&&(n.removeEventListener("mousemove",this._cancelAllSubmenusClose),n.removeEventListener("mouseleave",this._scheduleAllSubmenusClose),t?n.parentElement&&document.body.removeChild(n):(n.classList.remove(this.options.classes.open),n.classList.add(this.options.classes.closing),setTimeout((function(){n.parentElement&&document.body.removeChild(n)}),this.options.animations.menuCloseDuration)))}},{key:"_closeSubmenus",value:function(){for(var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=function(){var t=e.activeSubmenus.pop();if(!t)return 1;var i=t.element,o=function(){i.style.display="none",i.classList.remove(e.options.classes.open,e.options.classes.opening,e.options.classes.closing),i.innerHTML="",i.parentElement===document.body&&document.body.removeChild(i)};n?o():(i.classList.remove(e.options.classes.open),i.classList.add(e.options.classes.closing),setTimeout(o,e.options.animations.menuCloseDuration))};this.activeSubmenus.length>t;)i()}},{key:"_hideMenu",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if(e){this._log({event:"hideMenu",message:"Hiding menu: ".concat(this.activeMenuElement?this.activeMenuElement.id:"none"),data:{activeMenuId:this.activeMenuElement?this.activeMenuElement.id:null}}),this._closeSubmenus(0,n);var i=function(){if(e.parentElement&&e.parentElement.removeChild(e),t.activeMenuElement===e){var n=t.currentTargetElement;t.activeMenuElement=null,t.currentTargetElement=null,document.removeEventListener("click",t._boundOutsideClick,!0),document.removeEventListener("keydown",t._boundHandleKeydown),window.removeEventListener("scroll",t._boundHandleScroll,!0),n&&(n.removeEventListener("mouseleave",t._boundHandleHoverLeave),n.removeEventListener("mouseenter",t._boundHandleHoverEnter)),e.removeEventListener("mouseleave",t._boundHandleHoverLeave),e.removeEventListener("mouseenter",t._boundHandleHoverEnter)}};n||0===this.options.animations.menuCloseDuration?i():(e.classList.remove(this.options.classes.open,this.options.classes.opening),e.classList.add(this.options.classes.closing),setTimeout(i,this.options.animations.menuCloseDuration)),this._log({event:"hideMenu",message:"Menu hidden successfully",data:{activeMenuId:this.activeMenuElement?this.activeMenuElement.id:null}})}}},{key:"openMenu",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:-1,i="string"==typeof e?document.querySelector(e):e;if(!(i&&i instanceof HTMLElement))return this._log({event:"openMenu",message:"Invalid target element provided.",isError:!0}),!1;var o=i.getAttribute("data-custom-ctxmenu");if(!o)return this._log({event:"openMenu",message:"Target element has no 'data-custom-ctxmenu' attribute.",isError:!0}),!1;var s=this.menuConfigurations[o];if(!s)return this._log({event:"openMenu",message:"No menu configuration found for ID: ".concat(o),isError:!0}),!1;var a=t,r=n;if(-1===t||-1===n){var u=i.getBoundingClientRect();a=u.left+u.width/2,r=u.top+u.height/2}var l={clientX:a,clientY:r,preventDefault:function(){},stopPropagation:function(){}};return this._openMenu(s,i,l),!0}},{key:"closeMenu",value:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this._hideMenu(this.activeMenuElement,e)}},{key:"_createMenuItemDOM",value:function(e,t,n,i){var o,s=this;this._log({event:"createMenuItemDOM",message:"Creating DOM for command: ".concat(e.label),data:{commandId:e.id,targetElementId:t.id||"unknown",isDisabled:n,isSubmenuItem:i}});var a=v("li",[this.options.classes.item]);if(a.style.position="relative","separator"===e.type)return a.classList.add(this.options.classes.separator),e.content&&(a.classList.add("quickctx-subheader"),"string"==typeof e.content?a.textContent=e.content:e.content instanceof HTMLElement&&a.appendChild(e.content)),a.addEventListener("mouseenter",(function(){s._boundCancelAllSubmenusClose(),s._closeSiblingSubmenus(e)})),a;if(n&&a.classList.add(this.options.classes.disabled),e.iconClass){var r=v("span",this.options.classes.icon);e.iconClass.split(" ").filter(Boolean).forEach((function(e){return r.classList.add(e,e.replace(".","_"))})),a.appendChild(r)}if(a.innerHTML=a.innerHTML+e.label,e.element=a,a.addEventListener("mouseenter",(function(){var i;s._boundCancelAllSubmenusClose(),n||(s._closeSiblingSubmenus(e),"sublist"===e.type&&(null===(i=e.subCommands)||void 0===i?void 0:i.length)>0&&s._scheduleSubmenuOpen(e,a,t))})),a.addEventListener("mouseleave",this._boundScheduleAllSubmenusClose),"sublist"===e.type&&(null===(o=e.subCommands)||void 0===o?void 0:o.length)>0){a.classList.add(this.options.classes.sublistCommand,"has-submenu-arrow");var u=v("span","submenu-arrow");u.innerHTML=this.options.submenuArrow,a.appendChild(u)}return"action"===e.type&&a.addEventListener("click",(function(t){var i,o,a;if(t.stopPropagation(),!n){var r=e.action;if("string"==typeof r&&(r=s.registeredActions[r]),"undefined"===r)throw s._log({event:"actionError",message:'No action registered for command "'.concat(e.label,'"'),data:{commandId:e.id,commandLabel:e.label},isError:!0}),new Error('No action registered for command "'.concat(e.label,'"'));if("function"==typeof r)try{r({target:s.currentTargetElement,command:e})}catch(t){throw s._log({event:"actionError",message:'Error executing action for command "'.concat(e.label,'"'),data:{commandId:e.id,commandLabel:e.label,error:t.message},isError:!0}),new Error('Error executing action for command "'.concat(e.label,'": ').concat(t.message))}null===(i=s.currentTargetElement)||void 0===i||i.dispatchEvent(new CustomEvent("QuickCTXActionSelected",{detail:{menuId:null===(o=s.currentTargetElement)||void 0===o?void 0:o.dataset.customCtxmenu,commandId:e.id,commandLabel:e.label,targetElement:s.currentTargetElement,targetType:null===(a=s.currentTargetElement)||void 0===a?void 0:a.dataset.customCtxmenuType},bubbles:!0,composed:!0})),s._hideMenu(s.activeMenuElement)}})),a}},{key:"_buildAndShowMenu",value:function(e,t,n,i,o){var s=this,a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:null,r=arguments.length>6&&void 0!==arguments[6]?arguments[6]:null;this._log({event:"buildMenu",message:"Building menu for target type: ".concat(n),data:{targetElementId:t.id||"unknown",parentMenuId:a?a.id:null}});var u=a||this.activeMenuElement,l=e.additionalClasses;a&&(this.activeSubmenus.push({element:u,parentCommand:r}),l=this.activeMenuElement.className),u.innerHTML="";var c=(e.headerText||e.headerTextTemplate||"").replace(/{type}/g,n);!a&&c&&u.appendChild(v("div",this.options.classes.header,{},c));var d=v("ul",this.options.classes.list),m=0;return e.commands.forEach((function(i){r&&(i.parentCommand=r);var o=i.targetTypes.includes("*")||i.targetTypes.includes(n);if(i.visible){var a=i.disabled;if(!o){if("hide"===(e.filterStrategy||s.options.globalFilterStrategy))return;a=!0}d.appendChild(s._createMenuItemDOM(i,t,a)),m++}})),m>0?(u.appendChild(d),this._showMenuDOM(u,i,o,t,null!==a,r,l)):this._hideMenu(this.activeMenuElement,!0),0===m?(a?null==r||r.element.classList.remove("has-submenu-arrow"):this._hideMenu(this.activeMenuElement,!0),null):(u.appendChild(d),a||(document.addEventListener("click",this._boundOutsideClick,!0),document.addEventListener("keydown",this._boundHandleKeydown)),u)}},{key:"_showMenuDOM",value:function(e,t,n,i,o,s,a){e.style.display="block",e.classList.remove(this.options.classes.closing),e.classList.add(this.options.classes.opening),null==a||a.split(" ").forEach((function(t){return e.classList.add(t)}));var r=e.getBoundingClientRect(),u=window.innerWidth,l=window.innerHeight;if(o&&null!=s&&s.element){var c=s.element.getBoundingClientRect();t=c.right-5,n=c.top}t+r.width>u&&(t=o?t-r.width-((null==s?void 0:s.element.getBoundingClientRect().width)||0)+10:u-r.width-10),t<10&&(t=10),n+r.height>l&&(n=l-r.height-10),n<10&&(n=10),e.style.left="".concat(t,"px"),e.style.top="".concat(n,"px"),e.offsetWidth,e.classList.remove(this.options.classes.opening),e.classList.add(this.options.classes.open)}},{key:"registerAction",value:function(e,t){"function"==typeof t||null===t?this.registeredActions[e]=t:console.error('Callback for action "'.concat(e,'" must be a function or null.'))}},{key:"addMenuConfiguration",value:function(e){if(!e.id)throw this._log({event:"addMenuConfiguration",message:"Failed to add menu configuration: ID is required.",isError:!0}),new Error("ID is required for menu configuration.");this.menuConfigurations[e.id]&&this._log({event:"addMenuConfiguration",message:"Overwriting existing menu configuration with ID: ".concat(e.id)});var t=Array.isArray(e.commands)?e.commands.map((function(e){return e instanceof h?e:new h(e)})).sort((function(e,t){return e.order-t.order})):[];this.menuConfigurations[e.id]=u(u({},e),{},{commands:t,triggerEvent:e.triggerEvent||this.options.defaultTrigger,mobileTriggerEvent:e.mobileTriggerEvent||this.options.defaultMobileTrigger,closeTriggerEvent:e.closeTriggerEvent||this.options.defaultCloseTrigger,filterStrategy:e.filterStrategy||this.options.globalFilterStrategy}),this._log({event:"addMenuConfiguration",message:"Menu configuration added for ID: ".concat(e.id),data:{commandsCount:t.length,filterStrategy:this.menuConfigurations[e.id].filterStrategy}}),this._setupEventListeners()}},{key:"updateMenuConfiguration",value:function(e,t){this.menuConfigurations[e]?(this.menuConfigurations[e]=u(u({},this.menuConfigurations[e]),t),this._setupEventListeners(),this._log({event:"updateMenuConfiguration",message:'Menu "'.concat(e,'" updated successfully.'),data:{newOptions:t}})):this._log({event:"updateMenuConfiguration",message:'Menu with ID "'.concat(e,'" not found.'),isError:!0})}},{key:"updateMenuCommand",value:function(e,t,n){var i,o=this.menuConfigurations[e];if(t="function"==typeof t?this.functionActionMap.get(t):t,!o)return this._log({event:"updateMenuCommand",message:'Menu with ID "'.concat(e,'" not found.'),isError:!0}),!1;var a=function(e){var o,r=s(e);try{for(r.s();!(o=r.n()).done;){var u=o.value;if(u.action===t)return Object.assign(u,n),i=u.label,!0;if(u.subCommands&&u.subCommands.length>0&&a(u.subCommands))return!0}}catch(e){r.e(e)}finally{r.f()}return!1},r=a(o.commands);return r?this._log({event:"updateMenuCommand",message:'Command "'.concat(i,'" in menu "').concat(e,'" was successfully updated.'),data:{updates:n}}):this._log({event:"updateMenuCommand",message:'Command not found in menu "'.concat(e,'".'),isError:!0}),r}},{key:"bindMenuToElements",value:function(e,t,n){var i="string"==typeof e?document.querySelectorAll(e):Array.isArray(e)?e:[e];i.forEach((function(e){e instanceof HTMLElement&&(e.dataset.customCtxmenu=t,e.dataset.customCtxmenuType=e.dataset.customCtxmenuType?e.dataset.customCtxmenuType:n)})),this._log({event:"bindMenuToElements",message:"Bound menu ".concat(t," to elements of type ").concat(n),data:{elementsCount:i.length,menuId:t,type:n}})}},{key:"unbindMenuFromElements",value:function(e){var t="string"==typeof e?document.querySelectorAll(e):Array.isArray(e)?e:[e];t.forEach((function(e){e instanceof HTMLElement&&(delete e.dataset.customCtxmenu,delete e.dataset.customCtxmenuType)})),this._log({event:"unbindMenuFromElements",message:"Unbound menu from elements",data:{elementsCount:t.length,selectorOrElements:e}})}},{key:"createAndBindMenu",value:function(e){var t=this,n=e.menuId,i=e.defaultTargetType,o=void 0===i?"*":i,s=e.selector,a=e.structure,r=e.headerText,l=e.triggerEvent,c=e.mobileTriggerEvent,m=e.closeTriggerEvent,v=e.filterStrategy,g=e.additionalClasses,f=e.ignoreButtons,p=e.ignoreLinks;if(!n||!a)throw this._log({event:"createAndBindMenu",message:"Failed to create and bind menu: missing required parameters.",isError:!0}),new Error("`menuId` and `structure` are required for createAndBindMenu.");var b=function(e,n){return e.map((function(e){var i=e instanceof h||"object"===d(e)&&null!==e?u({},e):null;if("object"!==d(i)||null===i)return null;if(i.subCommands&&Array.isArray(i.subCommands)&&i.subCommands.length>0&&(i.type="sublist",i.subCommands=b(i.subCommands,n)),"function"==typeof i.action){var o=i.action,s=t.functionActionMap.get(o);if(!s){var a,r=null!==(a=window.crypto)&&void 0!==a&&a.randomUUID?crypto.randomUUID():Date.now().toString(36)+Math.random().toString(36).substring(2);s="quickctx-action-".concat(r),t.registerAction(s,o),t.functionActionMap.set(o,s)}i.action=s}return!i.targetTypes&&n&&(i.targetTypes=[n]),new h(i)})).filter(Boolean)};this._log({event:"createAndBindMenu",message:"Creating and binding menu with ID: ".concat(n),data:{defaultTargetType:o,selector:s,structure:a,headerText:r,triggerEvent:l,filterStrategy:v}});var y=b(a,o);this._log({event:"createAndBindMenu",message:"Processed commands for menu ".concat(n)});var E={id:n,headerTextTemplate:r,commands:y,triggerEvent:l,mobileTriggerEvent:c,closeTriggerEvent:m,filterStrategy:v,additionalClasses:g,ignoreButtons:f,ignoreLinks:p};this.addMenuConfiguration(E),s&&o&&this.bindMenuToElements(s,n,o)}}])}();e.MenuCommand=h,e.QuickCTX=g,Object.defineProperty(e,"__esModule",{value:!0})}));
//# sourceMappingURL=quickctx.umd.min.min.js.map