-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmenubox2.min.js
1 lines (1 loc) · 6.97 KB
/
menubox2.min.js
1
class Menubox2Item{key;menubox;element;submenu;constructor(e,t){if(this.menubox=t,this.key=e.key,this.element=t.itemRenderer.create(e),"string"==typeof e.key&&""!==e.key)if(this.element.dataset.key=e.key,e.submenu instanceof Object){let s=t.id+"."+this.key,n=Object.assign({},e.submenu,{adjustment:{horizontal:"after",vertical:"submenu-top"},css:"submenubox",callback:t.callback});this.submenu=new Menubox2(s,n,t),this.element.classList.add("submenuitem")}else"function"==typeof e.callback&&(this.element.onclick=t=>{t.stopPropagation(),!1!==this.enabled&&(e.callback(this),this.menubox.close())});this.element.onmouseenter=e=>{this.menubox.closeSubmenus(),this.submenu instanceof Menubox2&&(Menubox2.currentSubmenuTimerId=setTimeout((()=>{this.submenu.popup(e,this.menubox.context,this.element)}),t.submenuDelay))},t.isMultiselect&&this.element.classList.add("multiselect"),!0===e.checked&&this.element.classList.add("checked"),!1===e.enabled&&this.element.classList.add("disabled")}get checked(){return this.element.classList.contains("checked")}set checked(e){if("boolean"!=typeof e)throw new TypeError("Boolean value expected.");this.element.classList.toggle("checked",!0===e)}get enabled(){return!1===this.element.classList.contains("disabled")}set enabled(e){if("boolean"!=typeof e)throw new TypeError("Boolean value expected.");this.element.classList.toggle("disabled",!1===e)}get label(){return this.element.textContent}}class Menubox2ItemRenderer{create(e){let t=document.createElement("div");return t.classList.add(e.key?"menubox-item":"menubox-label"),e.cssClasses instanceof Array&&e.cssClasses.length>0&&t.classList.add(...e.cssClasses),t.textContent=e.label??e.key??null,t}}class Menubox2{static SELECT_MODE={normal:"normal",persistent:"persistent",multiselect:"multiselect",multiselect_interactive:"multiselect_interactive"};static instances=new Map;static closeAll(){for(let e of Menubox2.instances.values())e.close()}static onMenuItemClick(e,t){let s=t.items.get(e.target.closest(".menubox-item")?.dataset?.key);s&&s.enabled&&(t.isMultiselect&&(s.checked=!s.checked),[Menubox2.SELECT_MODE.normal,Menubox2.SELECT_MODE.multiselect_interactive].includes(t.selectMode)&&!s.submenu&&"function"==typeof t.callback&&t.callback(s),s.submenu instanceof Menubox2?s.submenu.popup(e,t.context,s.element):t.selectMode===Menubox2.SELECT_MODE.normal&&t.close())}element;items;itemRenderer;adjustment;submenuDelay;context;callback;constructor(e,t,s){function n(e,t,s){let n=document.createElement(e);if(n.classList.add(t),s){for(let e of s.matchAll(/&#x([0-9a-f]+);/gi))s=s.replace(e[0],JSON.parse('"\\u'+e[1]+'"'));n.appendChild(document.createTextNode(s))}return n}Menubox2.instances.has(e)&&(console.info('Menubox "'+e+'" already existed, has been replaced.'),document.body.querySelector('[data-menubox="'+e+'"]')?.remove()),this.id=e,this.parentMenubox=s,this.selectMode=t.selectMode??Menubox2.SELECT_MODE.normal,this.callback=t.callback,this.itemRenderer=t.itemRenderer instanceof Menubox2ItemRenderer?t.itemRenderer:new Menubox2ItemRenderer,this.adjustment=Object.assign({horizontal:"left",vertical:"below"},t.adjustment),this.transistions=Object.assign({visibility:["hidden","visible"]},t.transistions),this.submenuDelay=Math.max(t.submenuDelay||300,0),this.element=n("div","menubox"),this.element.dataset.menubox=e,this.element.appendChild(n("div","menubox-wrapper")),this.isMultiselect&&this.element.classList.add("menubox-multiselect"),this.element.style.position=t.position??"absolute",this.element.style.top="0px",this.element.style.left="0px","string"==typeof t.css&&this.element.classList.add(...t.css.split(" ")),document.body.appendChild(this.element),this.element.onclick=e=>Menubox2.onMenuItemClick(e,this),this.element.onmouseleave=()=>{Menubox2.currentSubmenuTimerId&&clearTimeout(Menubox2.currentSubmenuTimerId)},function(e,t){e.items=new Map;let s=n("div","menubox-items");for(let l of t){let t;if(l.separator)t=n("hr","menubox-separator");else{let s=new Menubox2Item(l,e);t=s.element,l.key&&e.items.set(l.key,s)}s.appendChild(t)}e.element.querySelector("div.menubox-wrapper").appendChild(s)}(this,t.items??[]),Menubox2.instances.set(this.id,this),Menubox2.closeAll()}_setVisibility(e){let t=e?1:0;for(let e of Object.entries(this.transistions)){let s=e[0],n=e[1][t];"height"===s&&"auto"===n?n=this.element.firstElementChild.offsetHeight+"px":"width"===s&&"auto"===n&&(n=this.element.firstElementChild.offsetWidth+"px"),this.element.style[s]=n}}get rootMenubox(){return this.parentMenubox?.rootMenubox||this}get isMultiselect(){return[Menubox2.SELECT_MODE.multiselect,Menubox2.SELECT_MODE.multiselect_interactive].includes(this.selectMode)}popup(e,t,s){this.parentMenubox||Menubox2.closeAll();let n=this.element.querySelector("div.menubox-items"),l="fixed"===this.element.style.position?{top:0,left:0}:{top:document.documentElement.scrollTop,left:document.documentElement.scrollLeft};n.scrollTo({top:0}),n.style.height=null,n.style.overflowY=null,e instanceof MouseEvent&&(e.stopPropagation(),s instanceof HTMLElement==!1&&(this.element.style.top=e.clientY+l.top+"px",this.element.style.left=e.clientX+l.left+"px")),s instanceof HTMLElement&&function(e,t){let s=t.getBoundingClientRect(),n={x:0,y:0};switch(e.adjustment.horizontal){case"before":n.x=s.left-e.element.offsetWidth;break;case"right":n.x=s.right-e.element.offsetWidth;break;case"after":n.x=s.right;break;case"left":default:n.x=s.left;break}switch(e.adjustment.vertical){case"submenu-top":let t=window.getComputedStyle(e.element);n.y=s.top-Number.parseFloat(t.paddingTop)-Number.parseFloat(t.borderTopWidth);break;case"above":n.y=s.top-e.element.offsetHeight;break;case"top":n.y=s.top;break;case"bottom":n.y=s.bottom-e.element.offsetHeight;break;case"below":default:n.y=s.bottom;break}"fixed"!==window.getComputedStyle(e.element).position&&(n.y+=window.scrollY,n.x+=window.scrollX),e.element.style.top=Math.round(n.y)+"px",e.element.style.left=Math.round(n.x)+"px"}(this,s);let i=this.element.getBoundingClientRect();i.right>visualViewport.width&&(this.element.style.left=Math.round(Math.max(l.left,l.left+visualViewport.width-i.width))+"px"),i.bottom>visualViewport.height&&(this.element.style.top=Math.round(Math.max(l.top,l.top+visualViewport.height-i.height))+"px",i.height>visualViewport.height&&(n.style.height=n.offsetHeight-(i.height-visualViewport.height)+"px",n.style.overflowY="scroll")),this.context=t,this._setVisibility(!0)}close(e){this._setVisibility(!1),!0===e?this.closeSubmenus():this.parentMenubox?.close()}toggle(e,t=null,s=null){e.stopPropagation();let n="visible"!==this.element.style.visibility;return!0===n?this.popup(e,t,s):this.close(!0),n}closeSubmenus(){Menubox2.currentSubmenuTimerId&&clearTimeout(Menubox2.currentSubmenuTimerId);for(let e of this.items.values())e.submenu instanceof Menubox2&&(e.submenu.closeSubmenus(),e.submenu.close(!0))}getCheckedItems(){let e=[];for(let t of this.items.values())t.checked&&e.push(t);return e}}window.addEventListener("click",(e=>{null===e.target.closest("[data-menubox]")&&Menubox2.closeAll()})),window.addEventListener("keydown",(e=>{["Escape"].includes(e.code)&&Menubox2.closeAll()}));