From c86ebba60d1357de817f89d2a6a962c598b169ad Mon Sep 17 00:00:00 2001 From: Molkobain Date: Fri, 22 Mar 2024 16:40:50 +0100 Subject: [PATCH] =?UTF-8?q?N=C2=B07355=20-=20Update=20jQuery-contextmenu?= =?UTF-8?q?=20to=202.9.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node_modules/.package-lock.json | 11 +- node_modules/jquery-contextmenu/CHANGELOG.md | 552 +++++ node_modules/jquery-contextmenu/LICENSE | 21 + node_modules/jquery-contextmenu/README.md | 283 +-- .../dist/font/context-menu-icons.eot | Bin 0 -> 3528 bytes .../dist/font/context-menu-icons.ttf | Bin 0 -> 3320 bytes .../dist/font/context-menu-icons.woff | Bin 0 -> 2180 bytes .../dist/font/context-menu-icons.woff2 | Bin 0 -> 1684 bytes .../dist/jquery.contextMenu.css | 309 +++ .../dist/jquery.contextMenu.js | 2134 +++++++++++++++++ .../dist/jquery.contextMenu.min.css | 16 + .../dist/jquery.contextMenu.min.css.map | 1 + .../dist/jquery.contextMenu.min.js | 2 + .../dist/jquery.contextMenu.min.js.map | 1 + .../dist/jquery.ui.position.js | 513 ++++ .../dist/jquery.ui.position.min.js | 6 + node_modules/jquery-contextmenu/package.json | 97 +- .../src/jquery.contextMenu.css | 142 -- .../src/jquery.contextMenu.js | 1692 ------------- .../src/jquery.ui.position.js | 497 ---- package-lock.json | 21 +- package.json | 2 +- .../Application/Helper/WebResourcesHelper.php | 4 +- sources/Dependencies/NPM/iTopNPM.php | 1 + 24 files changed, 3673 insertions(+), 2632 deletions(-) create mode 100644 node_modules/jquery-contextmenu/CHANGELOG.md create mode 100644 node_modules/jquery-contextmenu/LICENSE create mode 100644 node_modules/jquery-contextmenu/dist/font/context-menu-icons.eot create mode 100644 node_modules/jquery-contextmenu/dist/font/context-menu-icons.ttf create mode 100644 node_modules/jquery-contextmenu/dist/font/context-menu-icons.woff create mode 100644 node_modules/jquery-contextmenu/dist/font/context-menu-icons.woff2 create mode 100644 node_modules/jquery-contextmenu/dist/jquery.contextMenu.css create mode 100644 node_modules/jquery-contextmenu/dist/jquery.contextMenu.js create mode 100644 node_modules/jquery-contextmenu/dist/jquery.contextMenu.min.css create mode 100644 node_modules/jquery-contextmenu/dist/jquery.contextMenu.min.css.map create mode 100644 node_modules/jquery-contextmenu/dist/jquery.contextMenu.min.js create mode 100644 node_modules/jquery-contextmenu/dist/jquery.contextMenu.min.js.map create mode 100644 node_modules/jquery-contextmenu/dist/jquery.ui.position.js create mode 100644 node_modules/jquery-contextmenu/dist/jquery.ui.position.min.js delete mode 100644 node_modules/jquery-contextmenu/src/jquery.contextMenu.css delete mode 100644 node_modules/jquery-contextmenu/src/jquery.contextMenu.js delete mode 100644 node_modules/jquery-contextmenu/src/jquery.ui.position.js diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index b9e0eced4..d1c2a5a1c 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -155,11 +155,14 @@ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" }, "node_modules/jquery-contextmenu": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/jquery-contextmenu/-/jquery-contextmenu-1.6.7.tgz", - "integrity": "sha512-6qPEpiquUCE3iMbChPOHReQSKRus8VdPoDrJJMRYHBKSj577cAllLqMfp2pBzxax6m2ASTSt+YY++DWxt5yxGA==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/jquery-contextmenu/-/jquery-contextmenu-2.9.2.tgz", + "integrity": "sha512-6S6sH/08owDStC/7zNwcN366yR0ydX6PmMB0RnjLRQOp7Nc/rqwEHglshfHrrw2kdTev97GXwRXrayDUmToIOw==", "dependencies": { - "jquery": ">=1.7.0" + "jquery": "^3.5.0" + }, + "peerDependencies": { + "jquery": ">=1.8.2" } }, "node_modules/jquery-migrate": { diff --git a/node_modules/jquery-contextmenu/CHANGELOG.md b/node_modules/jquery-contextmenu/CHANGELOG.md new file mode 100644 index 000000000..3974dbd17 --- /dev/null +++ b/node_modules/jquery-contextmenu/CHANGELOG.md @@ -0,0 +1,552 @@ +## Changelog ## + +### 2.9.2 + +* Fix reflow when adding click layer to page (fixed #721, thanks @Rhain) + +### 2.9.1 + +* Fix error when closing the menu by clicking on the page without any element under that click point. (fixes #717) +* Upgrades dependencies + +### 2.9.0 + +#### Added + +* Added `dataAttr` option to add arbitrary data attributes to menu items. + +#### Changed + +* Updated dev dependencies. + +### 2.8.1 + +#### Fixed + +* Added FontAwesome `fab` class to known classes. + +#### Documentation + +* Updated documentation for `callback` (thanks @arashdalir) + + +### 2.8.0 + +#### Added + +* Added support for `events.preShow` so you can enable default browser menu if needed (thanks @terwarf) + +### 2.7.1 + +#### Fixed + +* A context menu appears outside the screen Under certain conditions (thanks @so-susa) +* No font-awesome icons visible in submenu ([Issue #659](https://github.com/swisnl/jQuery-contextMenu/issues/659)) thanks @betafritz and @klues + +### 2.7.0 + +#### Documentation + +* Add `getting started` to the documentation. +* Fixed typo in documentation which breaks the `callback` demo. +* Fixed typo `promis` => `promise` ([Issue #633](https://github.com/swisnl/jQuery-contextMenu/issues/633)). +* Fixed arguments for callback option in documentation ([Issue #571](https://github.com/swisnl/jQuery-contextMenu/issues/571)). + + +#### Added + +* Added support for Font Awesome 5 ([Issue #593](https://github.com/swisnl/jQuery-contextMenu/issues/593)), ([Issue #593](https://github.com/swisnl/jQuery-contextMenu/issues/593)) + +### 2.6.4 + +#### Fixed + +* `events.activated` is called without `options`as argument ([Issue #580](https://github.com/swisnl/jQuery-contextMenu/issues/580)). +* LayerClick sometimes breaks when the source is not a mouseevent ([Issue #132](https://github.com/swisnl/jQuery-contextMenu/issues/132)). +* The contextmenu now checks `visible` on items once instead of twice. Fixes [issue 612](https://github.com/swisnl/jQuery-contextMenu/issues/612). +* Font awesome li height is now consistent again ([Issue #610](https://github.com/swisnl/jQuery-contextMenu/issues/610)). + + +### 2.6.3 + +#### Fixed + +* Broke build script after 2.5.0 which ment no updates to dist folder ([Issue #578](https://github.com/swisnl/jQuery-contextMenu/issues/578)). + +### 2.6.2 + +#### Fixed + +* Dev dependency ended up in normal dependencies. + +### 2.6.1 + +#### Added + +* Ability to define touchstart as trigger (thanks @npuser) +* Extra event `activated` that triggers after the menu is activated (thanks @AliShahrivarian) +* Flag denoting if a second trigger should close the menu (thanks @OliverColeman) +* Added update call to update visibility, disabled, icon and form value stats for items. Fixes issue ([Issue #555](https://github.com/swisnl/jQuery-contextMenu/issues/555)). + +```javascript + $('.context-menu-one').contextMenu('update'); // update single menu + $.contextMenu('update') // update all open menus +``` + +#### Fixed + +* Fix for out of bounds problem on window edges (thanks @AliShahrivarian) + +### 2.5.0 + +#### Added + +* Callback function now supplies original event ([Issue #211](https://github.com/swisnl/jQuery-contextMenu/issues/211)) thanks @wizzard0 + +### 2.4.5 + +#### Fixed + +* ContextMenu appears with wrong position ([Issue #502](https://github.com/swisnl/jQuery-contextMenu/issues/502) thanks @apptaro +* Check if given selected value is a 0, if it is a zero so return it as is. Thanks @Falseee +* Events are never trigger when opening a contextMenu right after the other ([Issue #454](https://github.com/swisnl/jQuery-contextMenu/issues/454) thanks @kagant15 +* Accesskey jQuery Modal Dialog not working ([Issue #506](https://github.com/swisnl/jQuery-contextMenu/issues/506) thanks @CiTRO33 +* Fix submenu hover not always staying active if hovering over a submenu item. ([Issue #523](https://github.com/swisnl/jQuery-contextMenu/issues/523) thanks @tim-nz +* Change $node.click() to $node.get(0).click() to allow native event in HTML5 ([Issue #517](https://github.com/swisnl/jQuery-contextMenu/issues/517) + +### 2.4.4 + +#### Fixed + +* trigger is sometimes called on undefined objects because of typecheck on null. thanks @andreasrosdal + +### 2.4.3 + +#### Changed + +* The inline style causes a Content Security Policy violation if style-src 'unsafe-inline' is not defined in the policy. [PR 498](https://github.com/swisnl/jQuery-contextMenu/pull/498) thanks @StealthDuck + +* Removed GPL license from the comment in the plugin. Was already removed everywhere else. Only MIT applies now. + +#### Added + +* Added SauceLabs tests for common browsers. + +### 2.4.2 ### + +### Fixed + +* Focus not set on content editable element when right clicking the second time ([Issue #482](https://github.com/swisnl/jQuery-contextMenu/issues/482)) + +* `selectableSubMenu` broke disabling click menu (fixes ([Issue #493](https://github.com/swisnl/jQuery-contextMenu/issues/493)) + +### 2.4.1 ### + +#### Fixed + +* Quick fix for error in visible check ([Issue #484](https://github.com/swisnl/jQuery-contextMenu/issues/484)) + +#### Updated + +* Tweaked positioning of submenu ([Issue #387](https://github.com/swisnl/jQuery-contextMenu/issues/387)) + +### 2.4.0 ### + +#### Added + +* Selectable Sub Menus ([Issue #483](https://github.com/swisnl/jQuery-contextMenu/issues/483)) thanks @zyuhel + +#### Fixed + +* The contextmenu shows even if all items are set to visible:false ([Issue #473](https://github.com/swisnlhttps://github.com/swisnl/jQuery-contextMenu/issues/482/jQuery-contextMenu/issues/473)) + +#### Documentation + +* Update documentation to include demo for async promise fixes ([Issue #470](https://github.com/swisnl/jQuery-contextMenu/issues/470)) + +### 2.3.0 ### + +#### Added + +* Asynchronous promise support for submenu's ([Issue #429](https://github.com/swisnl/jQuery-contextMenu/issues/429)) thanks @Ruud-cb for the hard work. +* Include dist and src in package.json to easily use SCSS files ([PR #467](https://github.com/swisnl/jQuery-contextMenu/pull/467)) thanks @RoachMech + + +#### Fixed + +* Font family when using font awesome ([Issue #433](https://github.com/swisnl/jQuery-contextMenu/issues/433)) +* Add check for `opt.$menu` is null when handling callbacks. ([Issue #462](https://github.com/swisnl/jQuery-contextMenu/issues/462)) thanks @andreasrosdal + +#### Changed + +* Make `` and `') + .attr('name', 'context-menu-input-' + key) + .val(item.value || '') + .appendTo($label); + break; + + case 'textarea': + $input = $('') + .attr('name', 'context-menu-input-' + key) + .val(item.value || '') + .appendTo($label); + + if (item.height) { + $input.height(item.height); + } + break; + + case 'checkbox': + $input = $('') + .attr('name', 'context-menu-input-' + key) + .val(item.value || '') + .prop('checked', !!item.selected) + .prependTo($label); + break; + + case 'radio': + $input = $('') + .attr('name', 'context-menu-input-' + item.radio) + .val(item.value || '') + .prop('checked', !!item.selected) + .prependTo($label); + break; + + case 'select': + $input = $('') + .attr('name', 'context-menu-input-' + key) + .appendTo($label); + if (item.options) { + $.each(item.options, function (value, text) { + $('').val(value).text(text).appendTo($input); + }); + $input.val(item.selected); + } + break; + + case 'sub': + createNameNode(item).appendTo($t); + item.appendTo = item.$node; + $t.data('contextMenu', item).addClass('context-menu-submenu'); + item.callback = null; + + // If item contains items, and this is a promise, we should create it later + // check if subitems is of type promise. If it is a promise we need to create + // it later, after promise has been resolved. + if ('function' === typeof item.items.then) { + // probably a promise, process it, when completed it will create the sub menu's. + op.processPromises(item, root, item.items); + } else { + // normal submenu. + op.create(item, root); + } + break; + + case 'html': + $(item.html).appendTo($t); + break; + + default: + $.each([opt, root], function (i, k) { + k.commands[key] = item; + // Overwrite only if undefined or the item is appended to the root. This so it + // doesn't overwrite callbacks of root elements if the name is the same. + if ($.isFunction(item.callback) && (typeof k.callbacks[key] === 'undefined' || typeof opt.type === 'undefined')) { + k.callbacks[key] = item.callback; + } + }); + createNameNode(item).appendTo($t); + break; + } + + // disable key listener in + if (item.type && item.type !== 'sub' && item.type !== 'html' && item.type !== 'cm_seperator') { + $input + .on('focus', handle.focusInput) + .on('blur', handle.blurInput); + + if (item.events) { + $input.on(item.events, opt); + } + } + + // add icons + if (item.icon) { + if ($.isFunction(item.icon)) { + item._icon = item.icon.call(this, this, $t, key, item); + } else { + if (typeof(item.icon) === 'string' && ( + item.icon.substring(0, 4) === 'fab ' + || item.icon.substring(0, 4) === 'fas ' + || item.icon.substring(0, 4) === 'fad ' + || item.icon.substring(0, 4) === 'far ' + || item.icon.substring(0, 4) === 'fal ') + ) { + // to enable font awesome + $t.addClass(root.classNames.icon + ' ' + root.classNames.icon + '--fa5'); + item._icon = $(''); + } else if (typeof(item.icon) === 'string' && item.icon.substring(0, 3) === 'fa-') { + item._icon = root.classNames.icon + ' ' + root.classNames.icon + '--fa fa ' + item.icon; + } else { + item._icon = root.classNames.icon + ' ' + root.classNames.icon + '-' + item.icon; + } + } + + if(typeof(item._icon) === "string"){ + $t.addClass(item._icon); + } else { + $t.prepend(item._icon); + } + } + } + + // cache contained elements + item.$input = $input; + item.$label = $label; + + // attach item to menu + $t.appendTo(opt.$menu); + + // Disable text selection + if (!opt.hasTypes && $.support.eventSelectstart) { + // browsers support user-select: none, + // IE has a special event for text-selection + // browsers supporting neither will not be preventing text-selection + $t.on('selectstart.disableTextSelect', handle.abortevent); + } + }); + // attach contextMenu to (to bypass any possible overflow:hidden issues on parents of the trigger element) + if (!opt.$node) { + opt.$menu.css('display', 'none').addClass('context-menu-root'); + } + opt.$menu.appendTo(opt.appendTo || document.body); + }, + resize: function ($menu, nested) { + var domMenu; + // determine widths of submenus, as CSS won't grow them automatically + // position:absolute within position:absolute; min-width:100; max-width:200; results in width: 100; + // kinda sucks hard... + + // determine width of absolutely positioned element + $menu.css({position: 'absolute', display: 'block'}); + // don't apply yet, because that would break nested elements' widths + $menu.data('width', + (domMenu = $menu.get(0)).getBoundingClientRect ? + Math.ceil(domMenu.getBoundingClientRect().width) : + $menu.outerWidth() + 1); // outerWidth() returns rounded pixels + // reset styles so they allow nested elements to grow/shrink naturally + $menu.css({ + position: 'static', + minWidth: '0px', + maxWidth: '100000px' + }); + // identify width of nested menus + $menu.find('> li > ul').each(function () { + op.resize($(this), true); + }); + // reset and apply changes in the end because nested + // elements' widths wouldn't be calculatable otherwise + if (!nested) { + $menu.find('ul').addBack().css({ + position: '', + display: '', + minWidth: '', + maxWidth: '' + }).outerWidth(function () { + return $(this).data('width'); + }); + } + }, + update: function (opt, root) { + var $trigger = this; + if (typeof root === 'undefined') { + root = opt; + op.resize(opt.$menu); + } + + var hasVisibleItems = false; + + // re-check disabled for each item + opt.$menu.children().each(function () { + var $item = $(this), + key = $item.data('contextMenuKey'), + item = opt.items[key], + disabled = ($.isFunction(item.disabled) && item.disabled.call($trigger, key, root)) || item.disabled === true, + visible; + if ($.isFunction(item.visible)) { + visible = item.visible.call($trigger, key, root); + } else if (typeof item.visible !== 'undefined') { + visible = item.visible === true; + } else { + visible = true; + } + + if (visible) { + hasVisibleItems = true; + } + + $item[visible ? 'show' : 'hide'](); + + // dis- / enable item + $item[disabled ? 'addClass' : 'removeClass'](root.classNames.disabled); + + if ($.isFunction(item.icon)) { + $item.removeClass(item._icon); + var iconResult = item.icon.call(this, $trigger, $item, key, item); + if(typeof(iconResult) === "string"){ + $item.addClass(iconResult); + } else { + $item.prepend(iconResult); + } + } + + if (item.type) { + // dis- / enable input elements + $item.find('input, select, textarea').prop('disabled', disabled); + + // update input states + switch (item.type) { + case 'text': + case 'textarea': + item.$input.val(item.value || ''); + break; + + case 'checkbox': + case 'radio': + item.$input.val(item.value || '').prop('checked', !!item.selected); + break; + + case 'select': + item.$input.val((item.selected === 0 ? "0" : item.selected) || ''); + break; + } + } + + if (item.$menu) { + // update sub-menu + var subMenuHasVisibleItems = op.update.call($trigger, item, root); + if (subMenuHasVisibleItems) { + hasVisibleItems = true; + } + } + }); + return hasVisibleItems; + }, + layer: function (opt, zIndex) { + // add transparent layer for click area + // filter and background for Internet Explorer, Issue #23 + var $layer = opt.$layer = $('
') + .css({ + height: $win.height(), + width: $win.width(), + display: 'block', + position: 'fixed', + 'z-index': zIndex - 1, + top: 0, + left: 0, + opacity: 0, + filter: 'alpha(opacity=0)', + 'background-color': '#000' + }) + .data('contextMenuRoot', opt) + .appendTo(document.body) + .on('contextmenu', handle.abortevent) + .on('mousedown', handle.layerClick); + + // IE6 doesn't know position:fixed; + if (typeof document.body.style.maxWidth === 'undefined') { // IE6 doesn't support maxWidth + $layer.css({ + 'position': 'absolute', + 'height': $(document).height() + }); + } + + return $layer; + }, + processPromises: function (opt, root, promise) { + // Start + opt.$node.addClass(root.classNames.iconLoadingClass); + + function completedPromise(opt, root, items) { + // Completed promise (dev called promise.resolve). We now have a list of items which can + // be used to create the rest of the context menu. + if (typeof items === 'undefined') { + // Null result, dev should have checked + errorPromise(undefined);//own error object + } + finishPromiseProcess(opt, root, items); + } + + function errorPromise(opt, root, errorItem) { + // User called promise.reject() with an error item, if not, provide own error item. + if (typeof errorItem === 'undefined') { + errorItem = { + "error": { + name: "No items and no error item", + icon: "context-menu-icon context-menu-icon-quit" + } + }; + if (window.console) { + (console.error || console.log).call(console, 'When you reject a promise, provide an "items" object, equal to normal sub-menu items'); + } + } else if (typeof errorItem === 'string') { + errorItem = {"error": {name: errorItem}}; + } + finishPromiseProcess(opt, root, errorItem); + } + + function finishPromiseProcess(opt, root, items) { + if (typeof root.$menu === 'undefined' || !root.$menu.is(':visible')) { + return; + } + opt.$node.removeClass(root.classNames.iconLoadingClass); + opt.items = items; + op.create(opt, root, true); // Create submenu + op.update(opt, root); // Correctly update position if user is already hovered over menu item + root.positionSubmenu.call(opt.$node, opt.$menu); // positionSubmenu, will only do anything if user already hovered over menu item that just got new subitems. + } + + // Wait for promise completion. .then(success, error, notify) (we don't track notify). Bind the opt + // and root to avoid scope problems + promise.then(completedPromise.bind(this, opt, root), errorPromise.bind(this, opt, root)); + }, + // operation that will run after contextMenu showed on screen + activated: function(opt){ + var $menu = opt.$menu; + var $menuOffset = $menu.offset(); + var winHeight = $(window).height(); + var winScrollTop = $(window).scrollTop(); + var menuHeight = $menu.height(); + if(menuHeight > winHeight){ + $menu.css({ + 'height' : winHeight + 'px', + 'overflow-x': 'hidden', + 'overflow-y': 'auto', + 'top': winScrollTop + 'px' + }); + } else if(($menuOffset.top < winScrollTop) || ($menuOffset.top + menuHeight > winScrollTop + winHeight)){ + $menu.css({ + 'top': winScrollTop + 'px' + }); + } + } + }; + + // split accesskey according to http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#assigned-access-key + function splitAccesskey(val) { + var t = val.split(/\s+/); + var keys = []; + + for (var i = 0, k; k = t[i]; i++) { + k = k.charAt(0).toUpperCase(); // first character only + // theoretically non-accessible characters should be ignored, but different systems, different keyboard layouts, ... screw it. + // a map to look up already used access keys would be nice + keys.push(k); + } + + return keys; + } + +// handle contextMenu triggers + $.fn.contextMenu = function (operation) { + var $t = this, $o = operation; + if (this.length > 0) { // this is not a build on demand menu + if (typeof operation === 'undefined') { + this.first().trigger('contextmenu'); + } else if (typeof operation.x !== 'undefined' && typeof operation.y !== 'undefined') { + this.first().trigger($.Event('contextmenu', { + pageX: operation.x, + pageY: operation.y, + mouseButton: operation.button + })); + } else if (operation === 'hide') { + var $menu = this.first().data('contextMenu') ? this.first().data('contextMenu').$menu : null; + if ($menu) { + $menu.trigger('contextmenu:hide'); + } + } else if (operation === 'destroy') { + $.contextMenu('destroy', {context: this}); + } else if ($.isPlainObject(operation)) { + operation.context = this; + $.contextMenu('create', operation); + } else if (operation) { + this.removeClass('context-menu-disabled'); + } else if (!operation) { + this.addClass('context-menu-disabled'); + } + } else { + $.each(menus, function () { + if (this.selector === $t.selector) { + $o.data = this; + + $.extend($o.data, {trigger: 'demand'}); + } + }); + + handle.contextmenu.call($o.target, $o); + } + + return this; + }; + + // manage contextMenu instances + $.contextMenu = function (operation, options) { + if (typeof operation !== 'string') { + options = operation; + operation = 'create'; + } + + if (typeof options === 'string') { + options = {selector: options}; + } else if (typeof options === 'undefined') { + options = {}; + } + + // merge with default options + var o = $.extend(true, {}, defaults, options || {}); + var $document = $(document); + var $context = $document; + var _hasContext = false; + + if (!o.context || !o.context.length) { + o.context = document; + } else { + // you never know what they throw at you... + $context = $(o.context).first(); + o.context = $context.get(0); + _hasContext = !$(o.context).is(document); + } + + switch (operation) { + + case 'update': + // Updates visibility and such + if(_hasContext){ + op.update($context); + } else { + for(var menu in menus){ + if(menus.hasOwnProperty(menu)){ + op.update(menus[menu]); + } + } + } + break; + + case 'create': + // no selector no joy + if (!o.selector) { + throw new Error('No selector specified'); + } + // make sure internal classes are not bound to + if (o.selector.match(/.context-menu-(list|item|input)($|\s)/)) { + throw new Error('Cannot bind to selector "' + o.selector + '" as it contains a reserved className'); + } + if (!o.build && (!o.items || $.isEmptyObject(o.items))) { + throw new Error('No Items specified'); + } + counter++; + o.ns = '.contextMenu' + counter; + if (!_hasContext) { + namespaces[o.selector] = o.ns; + } + menus[o.ns] = o; + + // default to right click + if (!o.trigger) { + o.trigger = 'right'; + } + + if (!initialized) { + var itemClick = o.itemClickEvent === 'click' ? 'click.contextMenu' : 'mouseup.contextMenu'; + var contextMenuItemObj = { + // 'mouseup.contextMenu': handle.itemClick, + // 'click.contextMenu': handle.itemClick, + 'contextmenu:focus.contextMenu': handle.focusItem, + 'contextmenu:blur.contextMenu': handle.blurItem, + 'contextmenu.contextMenu': handle.abortevent, + 'mouseenter.contextMenu': handle.itemMouseenter, + 'mouseleave.contextMenu': handle.itemMouseleave + }; + contextMenuItemObj[itemClick] = handle.itemClick; + // make sure item click is registered first + $document + .on({ + 'contextmenu:hide.contextMenu': handle.hideMenu, + 'prevcommand.contextMenu': handle.prevItem, + 'nextcommand.contextMenu': handle.nextItem, + 'contextmenu.contextMenu': handle.abortevent, + 'mouseenter.contextMenu': handle.menuMouseenter, + 'mouseleave.contextMenu': handle.menuMouseleave + }, '.context-menu-list') + .on('mouseup.contextMenu', '.context-menu-input', handle.inputClick) + .on(contextMenuItemObj, '.context-menu-item'); + + initialized = true; + } + + // engage native contextmenu event + $context + .on('contextmenu' + o.ns, o.selector, o, handle.contextmenu); + + if (_hasContext) { + // add remove hook, just in case + $context.on('remove' + o.ns, function () { + $(this).contextMenu('destroy'); + }); + } + + switch (o.trigger) { + case 'hover': + $context + .on('mouseenter' + o.ns, o.selector, o, handle.mouseenter) + .on('mouseleave' + o.ns, o.selector, o, handle.mouseleave); + break; + + case 'left': + $context.on('click' + o.ns, o.selector, o, handle.click); + break; + case 'touchstart': + $context.on('touchstart' + o.ns, o.selector, o, handle.click); + break; + /* + default: + // http://www.quirksmode.org/dom/events/contextmenu.html + $document + .on('mousedown' + o.ns, o.selector, o, handle.mousedown) + .on('mouseup' + o.ns, o.selector, o, handle.mouseup); + break; + */ + } + + // create menu + if (!o.build) { + op.create(o); + } + break; + + case 'destroy': + var $visibleMenu; + if (_hasContext) { + // get proper options + var context = o.context; + $.each(menus, function (ns, o) { + + if (!o) { + return true; + } + + // Is this menu equest to the context called from + if (!$(context).is(o.selector)) { + return true; + } + + $visibleMenu = $('.context-menu-list').filter(':visible'); + if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is($(o.context).find(o.selector))) { + $visibleMenu.trigger('contextmenu:hide', {force: true}); + } + + try { + if (menus[o.ns].$menu) { + menus[o.ns].$menu.remove(); + } + + delete menus[o.ns]; + } catch (e) { + menus[o.ns] = null; + } + + $(o.context).off(o.ns); + + return true; + }); + } else if (!o.selector) { + $document.off('.contextMenu .contextMenuAutoHide'); + $.each(menus, function (ns, o) { + $(o.context).off(o.ns); + }); + + namespaces = {}; + menus = {}; + counter = 0; + initialized = false; + + $('#context-menu-layer, .context-menu-list').remove(); + } else if (namespaces[o.selector]) { + $visibleMenu = $('.context-menu-list').filter(':visible'); + if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is(o.selector)) { + $visibleMenu.trigger('contextmenu:hide', {force: true}); + } + + try { + if (menus[namespaces[o.selector]].$menu) { + menus[namespaces[o.selector]].$menu.remove(); + } + + delete menus[namespaces[o.selector]]; + } catch (e) { + menus[namespaces[o.selector]] = null; + } + + $document.off(namespaces[o.selector]); + } + break; + + case 'html5': + // if and are not handled by the browser, + // or options was a bool true, + // initialize $.contextMenu for them + if ((!$.support.htmlCommand && !$.support.htmlMenuitem) || (typeof options === 'boolean' && options)) { + $('menu[type="context"]').each(function () { + if (this.id) { + $.contextMenu({ + selector: '[contextmenu=' + this.id + ']', + items: $.contextMenu.fromMenu(this) + }); + } + }).css('display', 'none'); + } + break; + + default: + throw new Error('Unknown operation "' + operation + '"'); + } + + return this; + }; + +// import values into commands + $.contextMenu.setInputValues = function (opt, data) { + if (typeof data === 'undefined') { + data = {}; + } + + $.each(opt.inputs, function (key, item) { + switch (item.type) { + case 'text': + case 'textarea': + item.value = data[key] || ''; + break; + + case 'checkbox': + item.selected = data[key] ? true : false; + break; + + case 'radio': + item.selected = (data[item.radio] || '') === item.value; + break; + + case 'select': + item.selected = data[key] || ''; + break; + } + }); + }; + +// export values from commands + $.contextMenu.getInputValues = function (opt, data) { + if (typeof data === 'undefined') { + data = {}; + } + + $.each(opt.inputs, function (key, item) { + switch (item.type) { + case 'text': + case 'textarea': + case 'select': + data[key] = item.$input.val(); + break; + + case 'checkbox': + data[key] = item.$input.prop('checked'); + break; + + case 'radio': + if (item.$input.prop('checked')) { + data[item.radio] = item.value; + } + break; + } + }); + + return data; + }; + +// find