| /** | 
|  * jQuery Context Menu Plugin | 
|  * Cory S.N. LaViska | 
|  * A Beautiful Site ({@link https://abeautifulsite.net/}) | 
|  * Modified by Alexis Deveria | 
|  * | 
|  * More info: {@link https://abeautifulsite.net/2008/09/jquery-context-menu-plugin/} | 
|  * | 
|  * @module jQueryContextMenu | 
|  * @todo Update to latest version and adapt (and needs jQuery update as well): {@link https://github.com/swisnl/jQuery-contextMenu} | 
|  * @version 1.01 | 
|  * | 
|  * @license | 
|  * Terms of Use | 
|  * | 
|  * This plugin is dual-licensed under the GNU General Public License | 
|  *   and the MIT License and is copyright A Beautiful Site, LLC. | 
|  * | 
| */ | 
| import {isMac} from '../browser.js'; | 
|   | 
| /** | 
| * @callback module:jQueryContextMenu.jQueryContextMenuCallback | 
| * @param {string} href The `href` value after the first character (for bypassing an initial `#`) | 
| * @param {external:jQuery} srcElement The wrapped jQuery srcElement | 
| * @param {{x: Float, y: Float, docX: Float, docY: Float}} coords | 
| */ | 
|   | 
| /** | 
| * @typedef {PlainObject} module:jQueryContextMenu.jQueryContextMenuConfig | 
| * @property {string} menu | 
| * @property {Float} inSpeed | 
| * @property {Float} outSpeed | 
| * @property {boolean} allowLeft | 
| */ | 
|   | 
| /** | 
| * Adds {@link external:jQuery.fn.contextMenu}, | 
| * {@link external:jQuery.fn.disableContextMenuItems}, | 
| * {@link external:jQuery.fn.enableContextMenuItems}, | 
| * {@link external:jQuery.fn.disableContextMenu}, | 
| * {@link external:jQuery.fn.enableContextMenu}, | 
| * {@link external:jQuery.fn.destroyContextMenu}. | 
| * @function module:jQueryContextMenu.jQueryContextMenu | 
| * @param {external:jQuery} $ The jQuery object to wrap (with `contextMenu`, `disableContextMenuItems`, `enableContextMenuItems`, `disableContextMenu`, `enableContextMenu`, `destroyContextMenu`) | 
| * @returns {external:jQuery} | 
| */ | 
| function jQueryContextMenu ($) { | 
|   const win = $(window); | 
|   const doc = $(document); | 
|   | 
|   $.extend($.fn, { | 
|     /** | 
|     * @memberof external:jQuery.fn | 
|     * @param {module:jQueryContextMenu.jQueryContextMenuConfig} o | 
|     * @param {module:jQueryContextMenu.jQueryContextMenuCallback} callback | 
|     * @returns {external:jQuery} | 
|     */ | 
|     contextMenu (o, callback) { | 
|       // Defaults | 
|       if (o.menu === undefined) return false; | 
|       if (o.inSpeed === undefined) o.inSpeed = 150; | 
|       if (o.outSpeed === undefined) o.outSpeed = 75; | 
|       // 0 needs to be -1 for expected results (no fade) | 
|       if (o.inSpeed === 0) o.inSpeed = -1; | 
|       if (o.outSpeed === 0) o.outSpeed = -1; | 
|       // Loop each context menu | 
|       $(this).each(function () { | 
|         const el = $(this); | 
|         const offset = $(el).offset(); | 
|   | 
|         const menu = $('#' + o.menu); | 
|   | 
|         // Add contextMenu class | 
|         menu.addClass('contextMenu'); | 
|         // Simulate a true right click | 
|         $(this).bind('mousedown', function (e) { | 
|           const evt = e; | 
|           $(this).mouseup(function (e) { | 
|             const srcElement = $(this); | 
|             srcElement.unbind('mouseup'); | 
|             if (evt.button === 2 || o.allowLeft || | 
|               (evt.ctrlKey && isMac())) { | 
|               e.stopPropagation(); | 
|               // Hide context menus that may be showing | 
|               $('.contextMenu').hide(); | 
|               // Get this context menu | 
|   | 
|               if (el.hasClass('disabled')) return false; | 
|   | 
|               // Detect mouse position | 
|               let x = e.pageX, y = e.pageY; | 
|   | 
|               const xOff = win.width() - menu.width(), | 
|                 yOff = win.height() - menu.height(); | 
|   | 
|               if (x > xOff - 15) x = xOff - 15; | 
|               if (y > yOff - 30) y = yOff - 30; // 30 is needed to prevent scrollbars in FF | 
|   | 
|               // Show the menu | 
|               doc.unbind('click'); | 
|               menu.css({top: y, left: x}).fadeIn(o.inSpeed); | 
|               // Hover events | 
|               menu.find('A').mouseover(function () { | 
|                 menu.find('LI.hover').removeClass('hover'); | 
|                 $(this).parent().addClass('hover'); | 
|               }).mouseout(function () { | 
|                 menu.find('LI.hover').removeClass('hover'); | 
|               }); | 
|   | 
|               // Keyboard | 
|               doc.keypress(function (e) { | 
|                 switch (e.keyCode) { | 
|                 case 38: // up | 
|                   if (!menu.find('LI.hover').length) { | 
|                     menu.find('LI:last').addClass('hover'); | 
|                   } else { | 
|                     menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); | 
|                     if (!menu.find('LI.hover').length) menu.find('LI:last').addClass('hover'); | 
|                   } | 
|                   break; | 
|                 case 40: // down | 
|                   if (!menu.find('LI.hover').length) { | 
|                     menu.find('LI:first').addClass('hover'); | 
|                   } else { | 
|                     menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); | 
|                     if (!menu.find('LI.hover').length) menu.find('LI:first').addClass('hover'); | 
|                   } | 
|                   break; | 
|                 case 13: // enter | 
|                   menu.find('LI.hover A').trigger('click'); | 
|                   break; | 
|                 case 27: // esc | 
|                   doc.trigger('click'); | 
|                   break; | 
|                 } | 
|               }); | 
|   | 
|               // When items are selected | 
|               menu.find('A').unbind('mouseup'); | 
|               menu.find('LI:not(.disabled) A').mouseup(function () { | 
|                 doc.unbind('click').unbind('keypress'); | 
|                 $('.contextMenu').hide(); | 
|                 // Callback | 
|                 if (callback) { | 
|                   callback($(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y}); | 
|                 } | 
|                 return false; | 
|               }); | 
|   | 
|               // Hide bindings | 
|               setTimeout(function () { // Delay for Mozilla | 
|                 doc.click(function () { | 
|                   doc.unbind('click').unbind('keypress'); | 
|                   menu.fadeOut(o.outSpeed); | 
|                   return false; | 
|                 }); | 
|               }, 0); | 
|             } | 
|           }); | 
|         }); | 
|   | 
|         // Disable text selection | 
|         if ($.browser.mozilla) { | 
|           $('#' + o.menu).each(function () { $(this).css({MozUserSelect: 'none'}); }); | 
|         } else if ($.browser.msie) { | 
|           $('#' + o.menu).each(function () { $(this).bind('selectstart.disableTextSelect', function () { return false; }); }); | 
|         } else { | 
|           $('#' + o.menu).each(function () { $(this).bind('mousedown.disableTextSelect', function () { return false; }); }); | 
|         } | 
|         // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) | 
|         $(el).add($('UL.contextMenu')).bind('contextmenu', function () { return false; }); | 
|       }); | 
|       return $(this); | 
|     }, | 
|   | 
|     /** | 
|     * Disable context menu items on the fly. | 
|     * @memberof external:jQuery.fn | 
|     * @param {undefined|string} o Comma-separated | 
|     * @returns {external:jQuery} | 
|     */ | 
|     disableContextMenuItems (o) { | 
|       if (o === undefined) { | 
|         // Disable all | 
|         $(this).find('LI').addClass('disabled'); | 
|         return $(this); | 
|       } | 
|       $(this).each(function () { | 
|         if (o !== undefined) { | 
|           const d = o.split(','); | 
|           for (let i = 0; i < d.length; i++) { | 
|             $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); | 
|           } | 
|         } | 
|       }); | 
|       return $(this); | 
|     }, | 
|   | 
|     /** | 
|     * Enable context menu items on the fly. | 
|     * @memberof external:jQuery.fn | 
|     * @param {undefined|string} o Comma-separated | 
|     * @returns {external:jQuery} | 
|     */ | 
|     enableContextMenuItems (o) { | 
|       if (o === undefined) { | 
|         // Enable all | 
|         $(this).find('LI.disabled').removeClass('disabled'); | 
|         return $(this); | 
|       } | 
|       $(this).each(function () { | 
|         if (o !== undefined) { | 
|           const d = o.split(','); | 
|           for (let i = 0; i < d.length; i++) { | 
|             $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); | 
|           } | 
|         } | 
|       }); | 
|       return $(this); | 
|     }, | 
|   | 
|     /** | 
|     * Disable context menu(s). | 
|     * @memberof external:jQuery.fn | 
|     * @returns {external:jQuery} | 
|     */ | 
|     disableContextMenu () { | 
|       $(this).each(function () { | 
|         $(this).addClass('disabled'); | 
|       }); | 
|       return $(this); | 
|     }, | 
|   | 
|     /** | 
|     * Enable context menu(s). | 
|     * @memberof external:jQuery.fn | 
|     * @returns {external:jQuery} | 
|     */ | 
|     enableContextMenu () { | 
|       $(this).each(function () { | 
|         $(this).removeClass('disabled'); | 
|       }); | 
|       return $(this); | 
|     }, | 
|   | 
|     /** | 
|     * Destroy context menu(s). | 
|     * @memberof external:jQuery.fn | 
|     * @returns {external:jQuery} | 
|     */ | 
|     destroyContextMenu () { | 
|       // Destroy specified context menus | 
|       $(this).each(function () { | 
|         // Disable action | 
|         $(this).unbind('mousedown').unbind('mouseup'); | 
|       }); | 
|       return $(this); | 
|     } | 
|   }); | 
|   return $; | 
| } | 
|   | 
| export default jQueryContextMenu; |