(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD define(['jquery'], factory); } else if (typeof module === 'object' && module.exports) { // CommonJS module.exports = factory(require('jquery')); } else { // Browser globals root.showPopupMenu = factory(root.$); } }(typeof self !== 'undefined' ? self : this, function ($) { 'use strict'; let showPopupMenu = (x, y, items, prop = {}) => { document.querySelectorAll('.vp-popup-menu').forEach(menu => { if(menu.parentNode) menu.parentNode.removeChild(menu); }); let container = prop.container || document.body; let menu = $('
').css({ position: 'absolute', left: (x|0) + 'px', top: (y|0) + 'px' })[0]; let elems = []; if(!items || !items.length) { $(menu).append(`
${prop.emptyText || 'No items'}
`); } else { items.forEach((it, idx) => { let label = typeof it === 'string' ? it : (it.label || it.screen || it.name || JSON.stringify(it)); let $item = $(`
${label}
`) .attr('data-idx', idx) .on('click', ev => { ev.stopPropagation(); try { (prop.onSelect || (()=>{}))(it); } catch(e){ console.error(e); } removeMenu(); }) .on('keydown', e => { if(e.key === 'Enter') { e.preventDefault(); $item[0].click(); } }); $(menu).append($item[0]); elems.push({el: $item[0], data: it}); }); } let focusedIndex = elems.length ? 0 : -1; let focusAt = i => { elems.forEach((it, idx) => { $(it.el).removeClass('focused'); if(idx === i) { $(it.el).addClass('focused'); try{ it.el.focus(); }catch(e){} } }); focusedIndex = i; }; let removeMenu = () => { if(menu.parentNode) menu.parentNode.removeChild(menu); $(document).off('mousedown', onDoc).off('keydown', onKey); $(window).off('resize', onResize); }; let onDoc = ev => { if(!menu.contains(ev.target)) removeMenu(); }; let onResize = () => reposition(); let onKey = ev => { if(!elems.length) { if(ev.key === 'Escape') removeMenu(); return; } if(ev.key === 'Escape') { ev.preventDefault(); removeMenu(); return; } if(ev.key === 'ArrowDown') { ev.preventDefault(); focusAt((focusedIndex + 1) % elems.length); return; } if(ev.key === 'ArrowUp') { ev.preventDefault(); focusAt((focusedIndex - 1 + elems.length) % elems.length); return; } if(ev.key === 'Home') { ev.preventDefault(); focusAt(0); return; } if(ev.key === 'End') { ev.preventDefault(); focusAt(elems.length - 1); return; } if(ev.key === 'Enter') { ev.preventDefault(); if(focusedIndex >= 0) elems[focusedIndex].el.click(); } }; container.appendChild(menu); let reposition = () => { let mRect = menu.getBoundingClientRect(); let winW = window.innerWidth, winH = window.innerHeight; let left = parseInt($(menu).css('left'),10) || 0, top = parseInt($(menu).css('top'),10) || 0; if(mRect.right > winW) left = Math.max(4, winW - Math.ceil(mRect.width) - 8); if(mRect.bottom > winH) top = Math.max(4, winH - Math.ceil(mRect.height) - 8); if(left < 4) left = 4; if(top < 4) top = 4; $(menu).css({left: left + 'px', top: top + 'px'}); }; $(document).on('mousedown', onDoc).on('keydown', onKey); $(window).on('resize', onResize); if(elems.length) { focusAt(0); } setTimeout(reposition, 0); return menu; }; return showPopupMenu; }));