diff --git a/README.md b/README.md index f1be9420..b3b340ec 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,6 @@ --- -__IMPORTANT: The Next version (2.0.0) will change the default names of the icon classes in order to stop CSS conflicts with frameworks which define the class 'icon'.__ - - [![Travis Build Status](https://travis-ci.org/swisnl/jQuery-contextMenu.svg?branch=master)](https://travis-ci.org/swisnl/jQuery-contextMenu) $.contextMenu is a management facility for - you guessed it - context menus. It was designed for an application where there are hundreds of elements that may show a context menu - so intialization speed and memory usage are kept fairly small. It also allows to register context menus without providing actual markup, as $.contextMenu generates DOMElements as needed. @@ -100,10 +97,28 @@ $.contextMenu is published under the [MIT license](http://www.opensource.org/lic ## Changelog ## -### Unreleased ### +### 1.11.0 (Januari 8th 2016) ### + +* Added support for providing a function as zIndex value in options object (thanks @eivindga) +* Fixed a switch to use the correct type for separators (thanks @RareDevil) +* Fixed the problem with submenus size wrongly (Issue #308) (thanks @RareDevil) +* Incorrect entry on package.json (Issue #336) (thanks @Dijir) +* Positioning of contextmenu when using appendTo (thanks @mrMarco) +* Check to see if target have a higher zIndex than the contextmenu in the key event handler (thanks @RareDevil) + +### 1.10.3 (December 3rd 2015) ### + +* Remove executable bit from jquery.contextMenu.js (thanks @jacknagel) +* Fixed a problem there was when using a function for icons (thanks @RareDevil) +* Fixed a problem where submenus resized wrong (thanks @RareDevil) +* Fixed a problem where the contextmenu would open another menu (thanks @RareDevil) - ([Issue #252](https://github.com/swisnl/jQuery-contextMenu/issues/252) and [Issue #293](https://github.com/swisnl/jQuery-contextMenu/issues/293)) +* Fixed regression of node name's not being appended to the label of input elements. (thanks @RareDevil) +* Add check that root.$layer exists, to prevent calling hide() on an defined object. (thanks @andreasrosdal) -* __The Next version will change the default names of the icon classes in order to stop CSS conflicts with frameworks which define the class 'icon'.__ In order to keep the icon names the same as before this change you can change the defaults on the classnames for the icons ([docs on classNames option](http://swisnl.github.io/jQuery-contextMenu/docs.html#options-classNames)). The classnames will probably be "context-menu-icon-*" as proposed earlier by @rodneyrehm. +### 1.10.2 (October 28th 2015) ### +* Reverted the change from 1.7.0: .html() changed back to .text() since it is an security issue (thanks @arai-a) + ### 1.10.1 (October 25th 2015) ### * Last release before 2.0 diff --git a/bower.json b/bower.json index b0e38b42..1b5d96ba 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "jQuery-contextMenu", - "version": "1.10.1", + "version": "1.11.0", "main": [ "dist/jquery.contextMenu.js", "dist/jquery.contextMenu.min.js", diff --git a/dist/jquery.contextMenu.css b/dist/jquery.contextMenu.css index eee4f8a0..a8da112c 100755 --- a/dist/jquery.contextMenu.css +++ b/dist/jquery.contextMenu.css @@ -1,7 +1,7 @@ /*! * jQuery contextMenu - Plugin for simple contextMenu handling * - * Version: v1.10.1 + * Version: v1.10.3 * * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF) * Web: http://swisnl.github.io/jQuery-contextMenu/ @@ -11,7 +11,7 @@ * Licensed under * MIT License http://www.opensource.org/licenses/mit-license - * Date: 2015-10-26T19:58:28.706Z + * Date: 2015-12-03T20:12:18.263Z */ .context-menu-list { diff --git a/dist/jquery.contextMenu.js b/dist/jquery.contextMenu.js old mode 100755 new mode 100644 index d7db799d..98cd7713 --- a/dist/jquery.contextMenu.js +++ b/dist/jquery.contextMenu.js @@ -1,7 +1,7 @@ /*! - * jQuery contextMenu v1.10.1 - Plugin for simple contextMenu handling + * jQuery contextMenu v1.10.3 - Plugin for simple contextMenu handling * - * Version: v1.10.1 + * Version: v1.10.3 * * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF) * Web: http://swisnl.github.io/jQuery-contextMenu/ @@ -12,7 +12,7 @@ * MIT License http://www.opensource.org/licenses/mit-license * GPL v3 http://opensource.org/licenses/GPL-3.0 * - * Date: 2015-10-26T19:58:29.704Z + * Date: 2015-12-03T20:12:18.918Z */ (function (factory) { @@ -269,6 +269,14 @@ return; } + // Let the current contextmenu decide if it should show or not based on its own trigger settings + if (e.mouseButton !== undefined && e.data) { + if (!(e.data.trigger == 'left' && e.mouseButton === 0) && !(e.data.trigger == 'right' && e.mouseButton === 2)) { + // Mouse click is not valid. + return; + } + } + // abort event if menu is visible for this trigger if ($this.hasClass('context-menu-active')) { return; @@ -431,7 +439,7 @@ var triggerAction = ((root.trigger === 'left' && button === 0) || (root.trigger === 'right' && button === 2)); // find the element that would've been clicked, wasn't the layer in the way - if (document.elementFromPoint) { + if (document.elementFromPoint && root.$layer) { root.$layer.hide(); target = document.elementFromPoint(x - $win.scrollLeft(), y - $win.scrollTop()); root.$layer.show(); @@ -468,7 +476,7 @@ if (target && triggerAction) { root.$trigger.one('contextmenu:hidden', function () { - $(target).contextMenu({x: x, y: y}); + $(target).contextMenu({ x: x, y: y, button: button }); }); } @@ -1013,6 +1021,25 @@ root.accesskeys || (root.accesskeys = {}); + function createNameNode(item) { + var $name = $(''); + if (item._accesskey) { + if (item._beforeAccesskey) { + $name.append(document.createTextNode(item._beforeAccesskey)); + } + $('') + .addClass('context-menu-accesskey') + .text(item._accesskey) + .appendTo($name); + if (item._afterAccesskey) { + $name.append(document.createTextNode(item._afterAccesskey)); + } + } else { + $name.text(item.name); + } + return $name; + } + // create contextMenu items $.each(opt.items, function (key, item) { var $t = $('
  • ').addClass(item.className || ''), @@ -1042,7 +1069,12 @@ for (var i = 0, ak; ak = aks[i]; i++) { if (!root.accesskeys[ak]) { root.accesskeys[ak] = item; - item._name = item.name.replace(new RegExp('(' + ak + ')', 'i'), '$1'); + var matched = item.name.match(new RegExp('^(.*?)(' + ak + ')(.*)$', 'i')); + if (matched) { + item._beforeAccesskey = matched[1]; + item._accesskey = matched[2]; + item._afterAccesskey = matched[3]; + } break; } } @@ -1066,7 +1098,8 @@ $t.addClass('context-menu-html ' + root.classNames.notSelectable); } else if (item.type) { $label = $('').appendTo($t); - $('').html(item._name || item.name).appendTo($label); + createNameNode(item).appendTo($label); + $t.addClass('context-menu-input'); opt.hasTypes = true; $.each([opt, root], function (i, k) { @@ -1128,7 +1161,8 @@ break; case 'sub': - $('').html(item._name || item.name).appendTo($t); + createNameNode(item).appendTo($t); + item.appendTo = item.$node; op.create(item, root); $t.data('contextMenu', item).addClass('context-menu-submenu'); @@ -1146,7 +1180,7 @@ k.callbacks[key] = item.callback; } }); - $('').html(item._name || item.name || '').appendTo($t); + createNameNode(item).appendTo($t); break; } @@ -1164,7 +1198,7 @@ // add icons if (item.icon) { if ($.isFunction(item.icon)) { - item._icon = item.icon.call(this, $t, key, item); + item._icon = item.icon.call(this, this, $t, key, item); } else { item._icon = root.classNames.icon + ' ' + root.classNames.icon + '-' + item.icon; @@ -1253,7 +1287,7 @@ if ($.isFunction(item.icon)) { $item.removeClass(item._icon); - item._icon = item.icon.call(this, $trigger, key, item); + item._icon = item.icon.call(this, $trigger, $item, key, item); $item.addClass(item._icon); } @@ -1329,7 +1363,7 @@ if (operation === undefined) { this.first().trigger('contextmenu'); } else if (operation.x !== undefined && operation.y !== undefined) { - this.first().trigger($.Event('contextmenu', {pageX: operation.x, pageY: operation.y})); + 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; $menu && $menu.trigger('contextmenu:hide'); diff --git a/dist/jquery.contextMenu.min.css b/dist/jquery.contextMenu.min.css index d4c700d7..5707462d 100755 --- a/dist/jquery.contextMenu.min.css +++ b/dist/jquery.contextMenu.min.css @@ -1,7 +1,7 @@ /*! * jQuery contextMenu - Plugin for simple contextMenu handling * - * Version: v1.10.1 + * Version: v1.10.3 * * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF) * Web: http://swisnl.github.io/jQuery-contextMenu/ @@ -11,6 +11,6 @@ * Licensed under * MIT License http://www.opensource.org/licenses/mit-license - * Date: 2015-10-26T19:58:28.706Z + * Date: 2015-12-03T20:12:18.263Z */.context-menu-list{position:absolute;display:inline-block;min-width:120px;max-width:250px;padding:0;margin:0;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;list-style-type:none;background:#eee;border:1px solid #ddd;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.5);box-shadow:0 2px 5px rgba(0,0,0,.5)}.context-menu-item{position:relative;padding:2px 2px 2px 24px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#eee}.context-menu-separator{padding-bottom:0;border-bottom:1px solid #ddd}.context-menu-item>label>input,.context-menu-item>label>textarea{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.context-menu-item.hover{cursor:pointer;background-color:#39f}.context-menu-item.disabled{color:#666}.context-menu-input.hover,.context-menu-item.disabled.hover{cursor:default;background-color:#eee}.context-menu-submenu:after{position:absolute;top:0;right:3px;z-index:1;color:#666;content:">"}.context-menu-item.icon{min-height:18px;list-style-type:none;background-repeat:no-repeat;background-position:4px 2px}.context-menu-item.icon-edit{background-image:url(images/page_white_edit.png)}.context-menu-item.icon-cut{background-image:url(images/cut.png)}.context-menu-item.icon-copy{background-image:url(images/page_white_copy.png)}.context-menu-item.icon-paste{background-image:url(images/page_white_paste.png)}.context-menu-item.icon-delete{background-image:url(images/page_white_delete.png)}.context-menu-item.icon-add{background-image:url(images/page_white_add.png)}.context-menu-item.icon-quit{background-image:url(images/door.png)}.context-menu-input>label>*{vertical-align:top}.context-menu-input>label>input[type=checkbox],.context-menu-input>label>input[type=radio]{margin-left:-17px}.context-menu-input>label>span{margin-left:5px}.context-menu-input>label,.context-menu-input>label>input[type=text],.context-menu-input>label>select,.context-menu-input>label>textarea{display:block;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.context-menu-input>label>textarea{height:100px}.context-menu-item>.context-menu-list{top:5px;right:-5px;display:none}.context-menu-item.visible>.context-menu-list{display:block}.context-menu-accesskey{text-decoration:underline} /*# sourceMappingURL=jquery.contextMenu.min.css.map */ diff --git a/dist/jquery.contextMenu.min.css.map b/dist/jquery.contextMenu.min.css.map index 5d9e7dcc..8f03dfa4 100644 --- a/dist/jquery.contextMenu.min.css.map +++ b/dist/jquery.contextMenu.min.css.map @@ -1 +1 @@ -{"version":3,"sources":["jquery.contextMenu.css","jquery.contextMenu.min.css"],"names":[],"mappings":";;;;;;;;;;;;;;AAgBA,mBCCE,SDAE,SCCF,QDAE,aCCF,UAAW,MACX,UDAE,MCCF,QDAE,ECCF,ODAE,ECCF,YDAE,QAAmB,MAAA,UAAA,WCCrB,UDAE,KCCF,gBAAiB,KACjB,WDAE,KCCF,ODAE,IAAA,MAAA,KCCF,mBAAoB,EAAE,IAAI,IAAI,eDC5B,WAAA,EAAA,IAAA,IAAA,eCGJ,mBACE,SDFE,SCGF,QDFE,IAAA,IAAA,IAAgB,KACnB,oBAAA,KCGI,iBAAkB,KDDvB,gBAAA,KACI,YAAA,KCGF,iBDFE,KCKJ,wBACE,eDJE,ECKF,cDLE,IAAA,MAAA,KAGJ,+BCMA,kCACE,oBDLE,KACH,iBAAA,KCMK,gBAAiB,KDJvB,YAAA,KCQA,yBACE,ODPE,QCQF,iBDRE,KAGJ,4BCSE,MDRE,KCWJ,0BDPA,kCCSE,ODRE,QACH,iBAAA,KCWD,4BACE,SDRE,SCSF,IDRE,EACH,MAAA,ICSC,QAAS,EDPX,MAAA,KCSE,QDRE,ICiBJ,wBACE,WAAY,KACZ,gBAAiB,KACjB,kBAAmB,UACnB,oBDRC,IAAA,IAEH,6BACA,iBAAA,gCAEA,4BACA,iBAAA,oBAEA,6BCSE,iBAAkB,gCDNpB,8BCSE,iBAAkB,iCDNpB,+BCSE,iBAAkB,kCAEpB,4BDPA,iBAAA,+BCUA,6BACE,iBAAkB,qBAIpB,4BACE,eDRE,ICYJ,+CACA,4CACE,YAAa,MAEf,+BDTC,YAAA,ICaD,0BACA,2CAEA,iCADA,mCAEE,QAAS,MDTX,MAAA,KCWE,mBDViB,WAClB,gBAAA,WCWS,WAAY,WAGtB,mCACE,OAAQ,MAEV,sCACE,IAAK,IAEL,MAAuH,KACvH,QAAS,KAGX,8CACE,QAAS,MAGX,wBACE,gBAAiB","file":"jquery.contextMenu.min.css","sourcesContent":["/*!\n * jQuery contextMenu - Plugin for simple contextMenu handling\n *\n * Version: v@VERSION\n *\n * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)\n * Web: http://swisnl.github.io/jQuery-contextMenu/\n *\n * Copyright (c) 2011-@YEAR SWIS BV and contributors\n *\n * Licensed under\n * MIT License http://www.opensource.org/licenses/mit-license\n\n * Date: @DATE\n */\n\n.context-menu-list {\n margin:0; \n padding:0;\n \n min-width: 120px;\n max-width: 250px;\n display: inline-block;\n position: absolute;\n list-style-type: none;\n \n border: 1px solid #DDD;\n background: #EEE;\n \n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);\n \n font-family: Verdana, Arial, Helvetica, sans-serif;\n font-size: 11px;\n}\n\n.context-menu-item {\n padding: 2px 2px 2px 24px;\n background-color: #EEE;\n position: relative;\n user-select: none;\n}\n\n.context-menu-separator {\n padding-bottom:0;\n border-bottom: 1px solid #DDD;\n}\n\n.context-menu-item > label > input,\n.context-menu-item > label > textarea {\n user-select: text;\n}\n\n.context-menu-item.hover {\n cursor: pointer;\n background-color: #39F;\n}\n\n.context-menu-item.disabled {\n color: #666;\n}\n\n.context-menu-input.hover,\n.context-menu-item.disabled.hover {\n cursor: default;\n background-color: #EEE;\n}\n\n.context-menu-submenu:after {\n content: \">\";\n color: #666;\n position: absolute;\n top: 0;\n right: 3px;\n z-index: 1;\n}\n\n/* icons\n #protip:\n In case you want to use sprites for icons (which I would suggest you do) have a look at\n http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement \n .context-menu-item.icon:before {}\n */\n.context-menu-item.icon { min-height: 18px; background-repeat: no-repeat; background-position: 4px 2px; list-style-type: none;}\n.context-menu-item.icon-edit { background-image: url(images/page_white_edit.png); }\n.context-menu-item.icon-cut { background-image: url(images/cut.png); }\n.context-menu-item.icon-copy { background-image: url(images/page_white_copy.png); }\n.context-menu-item.icon-paste { background-image: url(images/page_white_paste.png); }\n.context-menu-item.icon-delete { background-image: url(images/page_white_delete.png); }\n.context-menu-item.icon-add { background-image: url(images/page_white_add.png); }\n.context-menu-item.icon-quit { background-image: url(images/door.png); }\n\n/* vertically align inside labels */\n.context-menu-input > label > * { vertical-align: top; }\n\n/* position checkboxes and radios as icons */\n.context-menu-input > label > input[type=\"checkbox\"],\n.context-menu-input > label > input[type=\"radio\"] {\n margin-left: -17px;\n}\n.context-menu-input > label > span {\n margin-left: 5px;\n}\n\n.context-menu-input > label,\n.context-menu-input > label > input[type=\"text\"],\n.context-menu-input > label > textarea,\n.context-menu-input > label > select {\n display: block;\n width: 100%;\n box-sizing: border-box;\n}\n\n.context-menu-input > label > textarea {\n height: 100px;\n}\n.context-menu-item > .context-menu-list {\n display: none;\n /* re-positioned by js */\n right: -5px;\n top: 5px;\n}\n\n.context-menu-item.visible > .context-menu-list {\n display: block;\n}\n\n.context-menu-accesskey {\n text-decoration: underline;\n}\n","/*!\n * jQuery contextMenu - Plugin for simple contextMenu handling\n *\n * Version: v1.10.1\n *\n * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)\n * Web: http://swisnl.github.io/jQuery-contextMenu/\n *\n * Copyright (c) 2011-2015 SWIS BV and contributors\n *\n * Licensed under\n * MIT License http://www.opensource.org/licenses/mit-license\n\n * Date: 2015-10-25T14:40:09.810Z\n */.context-menu-list{position:absolute;display:inline-block;min-width:120px;max-width:250px;padding:0;margin:0;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;list-style-type:none;background:#eee;border:1px solid #ddd;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.5);box-shadow:0 2px 5px rgba(0,0,0,.5)}.context-menu-item{position:relative;padding:2px 2px 2px 24px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#eee}.context-menu-separator{padding-bottom:0;border-bottom:1px solid #ddd}.context-menu-item>label>input,.context-menu-item>label>textarea{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.context-menu-item.hover{cursor:pointer;background-color:#39f}.context-menu-item.disabled{color:#666}.context-menu-input.hover,.context-menu-item.disabled.hover{cursor:default;background-color:#eee}.context-menu-submenu:after{position:absolute;top:0;right:3px;z-index:1;color:#666;content:\">\"}.context-menu-item.icon{min-height:18px;list-style-type:none;background-repeat:no-repeat;background-position:4px 2px}.context-menu-item.icon-edit{background-image:url(images/page_white_edit.png)}.context-menu-item.icon-cut{background-image:url(images/cut.png)}.context-menu-item.icon-copy{background-image:url(images/page_white_copy.png)}.context-menu-item.icon-paste{background-image:url(images/page_white_paste.png)}.context-menu-item.icon-delete{background-image:url(images/page_white_delete.png)}.context-menu-item.icon-add{background-image:url(images/page_white_add.png)}.context-menu-item.icon-quit{background-image:url(images/door.png)}.context-menu-input>label>*{vertical-align:top}.context-menu-input>label>input[type=checkbox],.context-menu-input>label>input[type=radio]{margin-left:-17px}.context-menu-input>label>span{margin-left:5px}.context-menu-input>label,.context-menu-input>label>input[type=text],.context-menu-input>label>select,.context-menu-input>label>textarea{display:block;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.context-menu-input>label>textarea{height:100px}.context-menu-item>.context-menu-list{top:5px;right:-5px;display:none}.context-menu-item.visible>.context-menu-list{display:block}.context-menu-accesskey{text-decoration:underline}\n/*# sourceMappingURL=jquery.contextMenu.min.css.map */\n"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["jquery.contextMenu.css","jquery.contextMenu.min.css"],"names":[],"mappings":";;;;;;;;;;;;;;AAgBA,mBCCE,SDAE,SCCF,QDAE,aCCF,UAAW,MACX,UDAE,MCCF,QDAE,ECCF,ODAE,ECCF,YDAE,QAAmB,MAAA,UAAA,WCCrB,UDAE,KCCF,gBAAiB,KACjB,WDAE,KCCF,ODAE,IAAA,MAAA,KCCF,mBAAoB,EAAE,IAAI,IAAI,eDC5B,WAAA,EAAA,IAAA,IAAA,eCGJ,mBACE,SDFE,SCGF,QDFE,IAAA,IAAA,IAAgB,KACnB,oBAAA,KCGI,iBAAkB,KDDvB,gBAAA,KACI,YAAA,KCGF,iBDFE,KCKJ,wBACE,eDJE,ECKF,cDLE,IAAA,MAAA,KAGJ,+BCMA,kCACE,oBDLE,KACH,iBAAA,KCMK,gBAAiB,KDJvB,YAAA,KCQA,yBACE,ODPE,QCQF,iBDRE,KAGJ,4BCSE,MDRE,KCWJ,0BDPA,kCCSE,ODRE,QACH,iBAAA,KCWD,4BACE,SDRE,SCSF,IDRE,EACH,MAAA,ICSC,QAAS,EDPX,MAAA,KCSE,QDRE,ICiBJ,wBACE,WAAY,KACZ,gBAAiB,KACjB,kBAAmB,UACnB,oBDRC,IAAA,IAEH,6BACA,iBAAA,gCAEA,4BACA,iBAAA,oBAEA,6BCSE,iBAAkB,gCDNpB,8BCSE,iBAAkB,iCDNpB,+BCSE,iBAAkB,kCAEpB,4BDPA,iBAAA,+BCUA,6BACE,iBAAkB,qBAIpB,4BACE,eDRE,ICYJ,+CACA,4CACE,YAAa,MAEf,+BDTC,YAAA,ICaD,0BACA,2CAEA,iCADA,mCAEE,QAAS,MDTX,MAAA,KCWE,mBDViB,WAClB,gBAAA,WCWS,WAAY,WAGtB,mCACE,OAAQ,MAEV,sCACE,IAAK,IAEL,MAAuH,KACvH,QAAS,KAGX,8CACE,QAAS,MAGX,wBACE,gBAAiB","file":"jquery.contextMenu.min.css","sourcesContent":["/*!\r\n * jQuery contextMenu - Plugin for simple contextMenu handling\r\n *\r\n * Version: v@VERSION\r\n *\r\n * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)\r\n * Web: http://swisnl.github.io/jQuery-contextMenu/\r\n *\r\n * Copyright (c) 2011-@YEAR SWIS BV and contributors\r\n *\r\n * Licensed under\r\n * MIT License http://www.opensource.org/licenses/mit-license\r\n\r\n * Date: @DATE\r\n */\r\n\r\n.context-menu-list {\r\n margin:0; \r\n padding:0;\r\n \r\n min-width: 120px;\r\n max-width: 250px;\r\n display: inline-block;\r\n position: absolute;\r\n list-style-type: none;\r\n \r\n border: 1px solid #DDD;\r\n background: #EEE;\r\n \r\n box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);\r\n \r\n font-family: Verdana, Arial, Helvetica, sans-serif;\r\n font-size: 11px;\r\n}\r\n\r\n.context-menu-item {\r\n padding: 2px 2px 2px 24px;\r\n background-color: #EEE;\r\n position: relative;\r\n user-select: none;\r\n}\r\n\r\n.context-menu-separator {\r\n padding-bottom:0;\r\n border-bottom: 1px solid #DDD;\r\n}\r\n\r\n.context-menu-item > label > input,\r\n.context-menu-item > label > textarea {\r\n user-select: text;\r\n}\r\n\r\n.context-menu-item.hover {\r\n cursor: pointer;\r\n background-color: #39F;\r\n}\r\n\r\n.context-menu-item.disabled {\r\n color: #666;\r\n}\r\n\r\n.context-menu-input.hover,\r\n.context-menu-item.disabled.hover {\r\n cursor: default;\r\n background-color: #EEE;\r\n}\r\n\r\n.context-menu-submenu:after {\r\n content: \">\";\r\n color: #666;\r\n position: absolute;\r\n top: 0;\r\n right: 3px;\r\n z-index: 1;\r\n}\r\n\r\n/* icons\r\n #protip:\r\n In case you want to use sprites for icons (which I would suggest you do) have a look at\r\n http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement \r\n .context-menu-item.icon:before {}\r\n */\r\n.context-menu-item.icon { min-height: 18px; background-repeat: no-repeat; background-position: 4px 2px; list-style-type: none;}\r\n.context-menu-item.icon-edit { background-image: url(images/page_white_edit.png); }\r\n.context-menu-item.icon-cut { background-image: url(images/cut.png); }\r\n.context-menu-item.icon-copy { background-image: url(images/page_white_copy.png); }\r\n.context-menu-item.icon-paste { background-image: url(images/page_white_paste.png); }\r\n.context-menu-item.icon-delete { background-image: url(images/page_white_delete.png); }\r\n.context-menu-item.icon-add { background-image: url(images/page_white_add.png); }\r\n.context-menu-item.icon-quit { background-image: url(images/door.png); }\r\n\r\n/* vertically align inside labels */\r\n.context-menu-input > label > * { vertical-align: top; }\r\n\r\n/* position checkboxes and radios as icons */\r\n.context-menu-input > label > input[type=\"checkbox\"],\r\n.context-menu-input > label > input[type=\"radio\"] {\r\n margin-left: -17px;\r\n}\r\n.context-menu-input > label > span {\r\n margin-left: 5px;\r\n}\r\n\r\n.context-menu-input > label,\r\n.context-menu-input > label > input[type=\"text\"],\r\n.context-menu-input > label > textarea,\r\n.context-menu-input > label > select {\r\n display: block;\r\n width: 100%;\r\n box-sizing: border-box;\r\n}\r\n\r\n.context-menu-input > label > textarea {\r\n height: 100px;\r\n}\r\n.context-menu-item > .context-menu-list {\r\n display: none;\r\n /* re-positioned by js */\r\n right: -5px;\r\n top: 5px;\r\n}\r\n\r\n.context-menu-item.visible > .context-menu-list {\r\n display: block;\r\n}\r\n\r\n.context-menu-accesskey {\r\n text-decoration: underline;\r\n}\r\n","/*!\r\n * jQuery contextMenu - Plugin for simple contextMenu handling\r\n *\r\n * Version: v1.10.2\r\n *\r\n * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF)\r\n * Web: http://swisnl.github.io/jQuery-contextMenu/\r\n *\r\n * Copyright (c) 2011-2015 SWIS BV and contributors\r\n *\r\n * Licensed under\r\n * MIT License http://www.opensource.org/licenses/mit-license\r\n\r\n * Date: 2015-10-28T15:14:59.323Z\r\n */.context-menu-list{position:absolute;display:inline-block;min-width:120px;max-width:250px;padding:0;margin:0;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;list-style-type:none;background:#eee;border:1px solid #ddd;-webkit-box-shadow:0 2px 5px rgba(0,0,0,.5);box-shadow:0 2px 5px rgba(0,0,0,.5)}.context-menu-item{position:relative;padding:2px 2px 2px 24px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#eee}.context-menu-separator{padding-bottom:0;border-bottom:1px solid #ddd}.context-menu-item>label>input,.context-menu-item>label>textarea{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.context-menu-item.hover{cursor:pointer;background-color:#39f}.context-menu-item.disabled{color:#666}.context-menu-input.hover,.context-menu-item.disabled.hover{cursor:default;background-color:#eee}.context-menu-submenu:after{position:absolute;top:0;right:3px;z-index:1;color:#666;content:\">\"}.context-menu-item.icon{min-height:18px;list-style-type:none;background-repeat:no-repeat;background-position:4px 2px}.context-menu-item.icon-edit{background-image:url(images/page_white_edit.png)}.context-menu-item.icon-cut{background-image:url(images/cut.png)}.context-menu-item.icon-copy{background-image:url(images/page_white_copy.png)}.context-menu-item.icon-paste{background-image:url(images/page_white_paste.png)}.context-menu-item.icon-delete{background-image:url(images/page_white_delete.png)}.context-menu-item.icon-add{background-image:url(images/page_white_add.png)}.context-menu-item.icon-quit{background-image:url(images/door.png)}.context-menu-input>label>*{vertical-align:top}.context-menu-input>label>input[type=checkbox],.context-menu-input>label>input[type=radio]{margin-left:-17px}.context-menu-input>label>span{margin-left:5px}.context-menu-input>label,.context-menu-input>label>input[type=text],.context-menu-input>label>select,.context-menu-input>label>textarea{display:block;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.context-menu-input>label>textarea{height:100px}.context-menu-item>.context-menu-list{top:5px;right:-5px;display:none}.context-menu-item.visible>.context-menu-list{display:block}.context-menu-accesskey{text-decoration:underline}\r\n/*# sourceMappingURL=jquery.contextMenu.min.css.map */\r\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/jquery.contextMenu.min.js b/dist/jquery.contextMenu.min.js old mode 100755 new mode 100644 index bbd088f6..8214bfd6 --- a/dist/jquery.contextMenu.min.js +++ b/dist/jquery.contextMenu.min.js @@ -1,7 +1,7 @@ /*! - * jQuery contextMenu v1.10.1 - Plugin for simple contextMenu handling + * jQuery contextMenu v1.10.3 - Plugin for simple contextMenu handling * - * Version: v1.10.1 + * Version: v1.10.3 * * Authors: Björn Brala (SWIS.nl), Rodney Rehm, Addy Osmani (patches for FF) * Web: http://swisnl.github.io/jQuery-contextMenu/ @@ -12,7 +12,7 @@ * MIT License http://www.opensource.org/licenses/mit-license * GPL v3 http://opensource.org/licenses/GPL-3.0 * - * Date: 2015-10-26T19:58:29.704Z + * Date: 2015-12-03T20:12:18.918Z */ -!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e("object"==typeof exports?require("jquery"):jQuery)}(function(e){"use strict";function t(e){for(var t,n=e.split(/\s+/),a=[],o=0;t=n[o];o++)t=t.charAt(0).toUpperCase(),a.push(t);return a}function n(t){return t.id&&e('label[for="'+t.id+'"]').val()||t.name}function a(t,o,i){return i||(i=0),o.each(function(){var o,s,c=e(this),r=this,l=this.nodeName.toLowerCase();switch("label"===l&&c.find("input, textarea, select").length&&(o=c.text(),c=c.children().first(),r=c.get(0),l=r.nodeName.toLowerCase()),l){case"menu":s={name:c.attr("label"),items:{}},i=a(s.items,c.children(),i);break;case"a":case"button":s={name:c.text(),disabled:!!c.attr("disabled"),callback:function(){return function(){c.click()}}()};break;case"menuitem":case"command":switch(c.attr("type")){case void 0:case"command":case"menuitem":s={name:c.attr("label"),disabled:!!c.attr("disabled"),icon:c.attr("icon"),callback:function(){return function(){c.click()}}()};break;case"checkbox":s={type:"checkbox",disabled:!!c.attr("disabled"),name:c.attr("label"),selected:!!c.attr("checked")};break;case"radio":s={type:"radio",disabled:!!c.attr("disabled"),name:c.attr("label"),radio:c.attr("radiogroup"),value:c.attr("id"),selected:!!c.attr("checked")};break;default:s=void 0}break;case"hr":s="-------";break;case"input":switch(c.attr("type")){case"text":s={type:"text",name:o||n(r),disabled:!!c.attr("disabled"),value:c.val()};break;case"checkbox":s={type:"checkbox",name:o||n(r),disabled:!!c.attr("disabled"),selected:!!c.attr("checked")};break;case"radio":s={type:"radio",name:o||n(r),disabled:!!c.attr("disabled"),radio:!!c.attr("name"),value:c.val(),selected:!!c.attr("checked")};break;default:s=void 0}break;case"select":s={type:"select",name:o||n(r),disabled:!!c.attr("disabled"),selected:c.val(),options:{}},c.children().each(function(){s.options[this.value]=e(this).text()});break;case"textarea":s={type:"textarea",name:o||n(r),disabled:!!c.attr("disabled"),value:c.val()};break;case"label":break;default:s={type:"html",html:c.clone(!0)}}s&&(i++,t["key"+i]=s)}),i}e.support.htmlMenuitem="HTMLMenuItemElement"in window,e.support.htmlCommand="HTMLCommandElement"in window,e.support.eventSelectstart="onselectstart"in document.documentElement,e.ui&&e.widget||(e.cleanData=function(t){return function(n){var a,o,i;for(i=0;null!=(o=n[i]);i++)try{a=e._data(o,"events"),a&&a.remove&&e(o).triggerHandler("remove")}catch(s){}t(n)}}(e.cleanData));var o=null,i=!1,s=e(window),c=0,r={},l={},u={},d={selector:null,appendTo:null,trigger:"right",autoHide:!1,delay:200,reposition:!0,classNames:{hover:"hover",disabled:"disabled",visible:"visible",notSelectable:"not-selectable",icon:"icon",iconEdit:"icon-edit",iconCut:"icon-cut",iconCopy:"icon-copy",iconPaste:"icon-paste",iconDelete:"icon-delete",iconAdd:"icon-add",iconQuit:"icon-quit"},determinePosition:function(t){if(e.ui&&e.ui.position)t.css("display","block").position({my:"center top",at:"center bottom",of:this,offset:"0 5",collision:"fit"}).css("display","none");else{var n=this.offset();n.top+=this.outerHeight(),n.left+=this.outerWidth()/2-t.outerWidth()/2,t.css(n)}},position:function(e,t,n){var a;if(!t&&!n)return void e.determinePosition.call(this,e.$menu);a="maintain"===t&&"maintain"===n?e.$menu.position():{top:n,left:t};var o=s.scrollTop()+s.height(),i=s.scrollLeft()+s.width(),c=e.$menu.outerHeight(),r=e.$menu.outerWidth();a.top+c>o&&(a.top-=c),a.top<0&&(a.top=0),a.left+r>i&&(a.left-=r),a.left<0&&(a.left=0),e.$menu.css(a)},positionSubmenu:function(t){if(e.ui&&e.ui.position)t.css("display","block").position({my:"left top",at:"right top",of:this,collision:"flipfit fit"}).css("display","");else{var n={top:0,left:this.outerWidth()};t.css(n)}},zIndex:1,animation:{duration:50,show:"slideDown",hide:"slideUp"},events:{show:e.noop,hide:e.noop},callback:null,items:{}},m={timer:null,pageX:null,pageY:null},p=function(e){for(var t=0,n=e;;)if(t=Math.max(t,parseInt(n.css("z-index"),10)||0),n=n.parent(),!n||!n.length||"html body".indexOf(n.prop("nodeName").toLowerCase())>-1)break;return t},f={abortevent:function(e){e.preventDefault(),e.stopImmediatePropagation()},contextmenu:function(t){var n=e(this);if("right"===t.data.trigger&&(t.preventDefault(),t.stopImmediatePropagation()),!("right"!==t.data.trigger&&"demand"!==t.data.trigger&&t.originalEvent||n.hasClass("context-menu-active")||n.hasClass("context-menu-disabled"))){if(o=n,t.data.build){var a=t.data.build(o,t);if(a===!1)return;if(t.data=e.extend(!0,{},d,t.data,a||{}),!t.data.items||e.isEmptyObject(t.data.items))throw window.console&&(console.error||console.log).call(console,"No items specified to show in contextMenu"),new Error("No Items specified");t.data.$trigger=o,h.create(t.data)}var i=!1;for(var s in t.data.items)if(t.data.items.hasOwnProperty(s)){var c;c=e.isFunction(t.data.items[s].visible)?t.data.items[s].visible.call(e(t.currentTarget),s,t.data):"undefined"!=typeof s.visible?t.data.items[s].visible===!0:!0,c&&(i=!0)}i&&h.show.call(n,t.data,t.pageX,t.pageY)}},click:function(t){t.preventDefault(),t.stopImmediatePropagation(),e(this).trigger(e.Event("contextmenu",{data:t.data,pageX:t.pageX,pageY:t.pageY}))},mousedown:function(t){var n=e(this);o&&o.length&&!o.is(n)&&o.data("contextMenu").$menu.trigger("contextmenu:hide"),2===t.button&&(o=n.data("contextMenuActive",!0))},mouseup:function(t){var n=e(this);n.data("contextMenuActive")&&o&&o.length&&o.is(n)&&!n.hasClass("context-menu-disabled")&&(t.preventDefault(),t.stopImmediatePropagation(),o=n,n.trigger(e.Event("contextmenu",{data:t.data,pageX:t.pageX,pageY:t.pageY}))),n.removeData("contextMenuActive")},mouseenter:function(t){var n=e(this),a=e(t.relatedTarget),i=e(document);a.is(".context-menu-list")||a.closest(".context-menu-list").length||o&&o.length||(m.pageX=t.pageX,m.pageY=t.pageY,m.data=t.data,i.on("mousemove.contextMenuShow",f.mousemove),m.timer=setTimeout(function(){m.timer=null,i.off("mousemove.contextMenuShow"),o=n,n.trigger(e.Event("contextmenu",{data:m.data,pageX:m.pageX,pageY:m.pageY}))},t.data.delay))},mousemove:function(e){m.pageX=e.pageX,m.pageY=e.pageY},mouseleave:function(t){var n=e(t.relatedTarget);if(!n.is(".context-menu-list")&&!n.closest(".context-menu-list").length){try{clearTimeout(m.timer)}catch(t){}m.timer=null}},layerClick:function(t){var n,a,o=e(this),i=o.data("contextMenuRoot"),c=t.button,r=t.pageX,l=t.pageY;t.preventDefault(),t.stopImmediatePropagation(),setTimeout(function(){var o,u="left"===i.trigger&&0===c||"right"===i.trigger&&2===c;if(document.elementFromPoint&&(i.$layer.hide(),n=document.elementFromPoint(r-s.scrollLeft(),l-s.scrollTop()),i.$layer.show()),i.reposition&&u)if(document.elementFromPoint){if(i.$trigger.is(n)||i.$trigger.has(n).length)return void i.position.call(i.$trigger,i,r,l)}else if(a=i.$trigger.offset(),o=e(window),a.top+=o.scrollTop(),a.top<=t.pageY&&(a.left+=o.scrollLeft(),a.left<=t.pageX&&(a.bottom=a.top+i.$trigger.outerHeight(),a.bottom>=t.pageY&&(a.right=a.left+i.$trigger.outerWidth(),a.right>=t.pageX))))return void i.position.call(i.$trigger,i,r,l);n&&u&&i.$trigger.one("contextmenu:hidden",function(){e(n).contextMenu({x:r,y:l})}),i.$menu.trigger("contextmenu:hide")},50)},keyStop:function(e,t){t.isInput||e.preventDefault(),e.stopPropagation()},key:function(e){var t={};switch(o&&(t=o.data("contextMenu")||{}),e.keyCode){case 9:case 38:if(f.keyStop(e,t),t.isInput){if(9===e.keyCode&&e.shiftKey)return e.preventDefault(),t.$selected&&t.$selected.find("input, textarea, select").blur(),void t.$menu.trigger("prevcommand");if(38===e.keyCode&&"checkbox"===t.$selected.find("input, textarea, select").prop("type"))return void e.preventDefault()}else if(9!==e.keyCode||e.shiftKey)return void t.$menu.trigger("prevcommand");case 40:if(f.keyStop(e,t),!t.isInput)return void t.$menu.trigger("nextcommand");if(9===e.keyCode)return e.preventDefault(),t.$selected&&t.$selected.find("input, textarea, select").blur(),void t.$menu.trigger("nextcommand");if(40===e.keyCode&&"checkbox"===t.$selected.find("input, textarea, select").prop("type"))return void e.preventDefault();break;case 37:if(f.keyStop(e,t),t.isInput||!t.$selected||!t.$selected.length)break;if(!t.$selected.parent().hasClass("context-menu-root")){var n=t.$selected.parent().parent();return t.$selected.trigger("contextmenu:blur"),void(t.$selected=n)}break;case 39:if(f.keyStop(e,t),t.isInput||!t.$selected||!t.$selected.length)break;var a=t.$selected.data("contextMenu")||{};if(a.$menu&&t.$selected.hasClass("context-menu-submenu"))return t.$selected=null,a.$selected=null,void a.$menu.trigger("nextcommand");break;case 35:case 36:return t.$selected&&t.$selected.find("input, textarea, select").length?void 0:((t.$selected&&t.$selected.parent()||t.$menu).children(":not(."+t.classNames.disabled+", ."+t.classNames.notSelectable+")")[36===e.keyCode?"first":"last"]().trigger("contextmenu:focus"),void e.preventDefault());case 13:if(f.keyStop(e,t),t.isInput){if(t.$selected&&!t.$selected.is("textarea, select"))return void e.preventDefault();break}return void("undefined"!=typeof t.$selected&&null!==t.$selected&&t.$selected.trigger("mouseup"));case 32:case 33:case 34:return void f.keyStop(e,t);case 27:return f.keyStop(e,t),void t.$menu.trigger("contextmenu:hide");default:var i=String.fromCharCode(e.keyCode).toUpperCase();if(t.accesskeys&&t.accesskeys[i])return void t.accesskeys[i].$node.trigger(t.accesskeys[i].$menu?"contextmenu:focus":"mouseup")}e.stopPropagation(),"undefined"!=typeof t.$selected&&null!==t.$selected&&t.$selected.trigger(e)},prevItem:function(t){t.stopPropagation();var n=e(this).data("contextMenu")||{},a=e(this).data("contextMenuRoot")||{};if(n.$selected){var o=n.$selected;n=n.$selected.parent().data("contextMenu")||{},n.$selected=o}for(var i=n.$menu.children(),s=n.$selected&&n.$selected.prev().length?n.$selected.prev():i.last(),c=s;s.hasClass(a.classNames.disabled)||s.hasClass(a.classNames.notSelectable);)if(s=s.prev().length?s.prev():i.last(),s.is(c))return;n.$selected&&f.itemMouseleave.call(n.$selected.get(0),t),f.itemMouseenter.call(s.get(0),t);var r=s.find("input, textarea, select");r.length&&r.focus()},nextItem:function(t){t.stopPropagation();var n=e(this).data("contextMenu")||{},a=e(this).data("contextMenuRoot")||{};if(n.$selected){var o=n.$selected;n=n.$selected.parent().data("contextMenu")||{},n.$selected=o}for(var i=n.$menu.children(),s=n.$selected&&n.$selected.next().length?n.$selected.next():i.first(),c=s;s.hasClass(a.classNames.disabled)||s.hasClass(a.classNames.notSelectable);)if(s=s.next().length?s.next():i.first(),s.is(c))return;n.$selected&&f.itemMouseleave.call(n.$selected.get(0),t),f.itemMouseenter.call(s.get(0),t);var r=s.find("input, textarea, select");r.length&&r.focus()},focusInput:function(){var t=e(this).closest(".context-menu-item"),n=t.data(),a=n.contextMenu,o=n.contextMenuRoot;o.$selected=a.$selected=t,o.isInput=a.isInput=!0},blurInput:function(){var t=e(this).closest(".context-menu-item"),n=t.data(),a=n.contextMenu,o=n.contextMenuRoot;o.isInput=a.isInput=!1},menuMouseenter:function(){var t=e(this).data().contextMenuRoot;t.hovering=!0},menuMouseleave:function(t){var n=e(this).data().contextMenuRoot;n.$layer&&n.$layer.is(t.relatedTarget)&&(n.hovering=!1)},itemMouseenter:function(t){var n=e(this),a=n.data(),o=a.contextMenu,i=a.contextMenuRoot;return i.hovering=!0,t&&i.$layer&&i.$layer.is(t.relatedTarget)&&(t.preventDefault(),t.stopImmediatePropagation()),(o.$menu?o:i).$menu.children(".hover").trigger("contextmenu:blur"),n.hasClass(i.classNames.disabled)||n.hasClass(i.classNames.notSelectable)?void(o.$selected=null):void n.trigger("contextmenu:focus")},itemMouseleave:function(t){var n=e(this),a=n.data(),o=a.contextMenu,i=a.contextMenuRoot;return i!==o&&i.$layer&&i.$layer.is(t.relatedTarget)?("undefined"!=typeof i.$selected&&null!==i.$selected&&i.$selected.trigger("contextmenu:blur"),t.preventDefault(),t.stopImmediatePropagation(),void(i.$selected=o.$selected=o.$node)):void n.trigger("contextmenu:blur")},itemClick:function(t){var n,a=e(this),o=a.data(),i=o.contextMenu,s=o.contextMenuRoot,c=o.contextMenuKey;if(i.items[c]&&!a.is("."+s.classNames.disabled+", .context-menu-submenu, .context-menu-separator, ."+s.classNames.notSelectable)){if(t.preventDefault(),t.stopImmediatePropagation(),e.isFunction(s.callbacks[c])&&Object.prototype.hasOwnProperty.call(s.callbacks,c))n=s.callbacks[c];else{if(!e.isFunction(s.callback))return;n=s.callback}n.call(s.$trigger,c,s)!==!1?s.$menu.trigger("contextmenu:hide"):s.$menu.parent().length&&h.update.call(s.$trigger,s)}},inputClick:function(e){e.stopImmediatePropagation()},hideMenu:function(t,n){var a=e(this).data("contextMenuRoot");h.hide.call(a.$trigger,a,n&&n.force)},focusItem:function(t){t.stopPropagation();var n=e(this),a=n.data(),o=a.contextMenu,i=a.contextMenuRoot;n.addClass([i.classNames.hover,i.classNames.visible].join(" ")).siblings().removeClass(i.classNames.visible).filter(i.classNames.hover).trigger("contextmenu:blur"),o.$selected=i.$selected=n,o.$node&&i.positionSubmenu.call(o.$node,o.$menu)},blurItem:function(t){t.stopPropagation();var n=e(this),a=n.data(),o=a.contextMenu,i=a.contextMenuRoot;o.autoHide&&n.removeClass(i.classNames.visible),n.removeClass(i.classNames.hover),o.$selected=null}},h={show:function(t,n,a){var i=e(this),s={};return e("#context-menu-layer").trigger("mousedown"),t.$trigger=i,t.events.show.call(i,t)===!1?void(o=null):(h.update.call(i,t),t.position.call(i,t,n,a),t.zIndex&&(s.zIndex=p(i)+t.zIndex),h.layer.call(t.$menu,t,s.zIndex),t.$menu.find("ul").css("zIndex",s.zIndex+1),t.$menu.css(s)[t.animation.show](t.animation.duration,function(){i.trigger("contextmenu:visible")}),i.data("contextMenu",t).addClass("context-menu-active"),e(document).off("keydown.contextMenu").on("keydown.contextMenu",f.key),void(t.autoHide&&e(document).on("mousemove.contextMenuAutoHide",function(e){var n=i.offset();n.right=n.left+i.outerWidth(),n.bottom=n.top+i.outerHeight(),!t.$layer||t.hovering||e.pageX>=n.left&&e.pageX<=n.right&&e.pageY>=n.top&&e.pageY<=n.bottom||t.$menu.trigger("contextmenu:hide")})))},hide:function(t,n){var a=e(this);if(t||(t=a.data("contextMenu")||{}),n||!t.events||t.events.hide.call(a,t)!==!1){if(a.removeData("contextMenu").removeClass("context-menu-active"),t.$layer){setTimeout(function(e){return function(){e.remove()}}(t.$layer),10);try{delete t.$layer}catch(i){t.$layer=null}}o=null,t.$menu.find("."+t.classNames.hover).trigger("contextmenu:blur"),t.$selected=null,e(document).off(".contextMenuAutoHide").off("keydown.contextMenu"),t.$menu&&t.$menu[t.animation.hide](t.animation.duration,function(){t.build&&(t.$menu.remove(),e.each(t,function(e){switch(e){case"ns":case"selector":case"build":case"trigger":return!0;default:t[e]=void 0;try{delete t[e]}catch(n){}return!0}})),setTimeout(function(){a.trigger("contextmenu:hidden")},10)})}},create:function(n,a){void 0===a&&(a=n),n.$menu=e('').addClass(n.className||"").data({contextMenu:n,contextMenuRoot:a}),e.each(["callbacks","commands","inputs"],function(e,t){n[t]={},a[t]||(a[t]={})}),a.accesskeys||(a.accesskeys={}),e.each(n.items,function(o,i){var s=e('
  • ').addClass(i.className||""),c=null,r=null;if(s.on("click",e.noop),"string"==typeof i&&(i={type:"cm_seperator"}),i.$node=s.data({contextMenu:n,contextMenuRoot:a,contextMenuKey:o}),"undefined"!=typeof i.accesskey)for(var l,d=t(i.accesskey),m=0;l=d[m];m++)if(!a.accesskeys[l]){a.accesskeys[l]=i,i._name=i.name.replace(new RegExp("("+l+")","i"),'$1');break}if(i.type&&u[i.type])u[i.type].call(s,i,n,a),e.each([n,a],function(t,n){n.commands[o]=i,e.isFunction(i.callback)&&(n.callbacks[o]=i.callback)});else{switch("cm_seperator"===i.type?s.addClass("context-menu-separator "+a.classNames.notSelectable):"html"===i.type?s.addClass("context-menu-html "+a.classNames.notSelectable):i.type?(c=e("").appendTo(s),e("").html(i._name||i.name).appendTo(c),s.addClass("context-menu-input"),n.hasTypes=!0,e.each([n,a],function(e,t){t.commands[o]=i,t.inputs[o]=i})):i.items&&(i.type="sub"),i.type){case"seperator":break;case"text":r=e('').attr("name","context-menu-input-"+o).val(i.value||"").appendTo(c);break;case"textarea":r=e('').attr("name","context-menu-input-"+o).val(i.value||"").appendTo(c),i.height&&r.height(i.height);break;case"checkbox":r=e('').attr("name","context-menu-input-"+o).val(i.value||"").prop("checked",!!i.selected).prependTo(c);break;case"radio":r=e('').attr("name","context-menu-input-"+i.radio).val(i.value||"").prop("checked",!!i.selected).prependTo(c);break;case"select":r=e('').attr("name","context-menu-input-"+s).val(i.value||"").appendTo(r);break;case"textarea":l=e('').attr("name","context-menu-input-"+s).val(i.value||"").appendTo(r),i.height&&l.height(i.height);break;case"checkbox":l=e('').attr("name","context-menu-input-"+s).val(i.value||"").prop("checked",!!i.selected).prependTo(r);break;case"radio":l=e('').attr("name","context-menu-input-"+i.radio).val(i.value||"").prop("checked",!!i.selected).prependTo(r);break;case"select":l=e('').attr(\"name\",\"context-menu-input-\"+o).val(i.value||\"\").appendTo(c);break;case\"textarea\":r=e('').attr(\"name\",\"context-menu-input-\"+o).val(i.value||\"\").appendTo(c),i.height&&r.height(i.height);break;case\"checkbox\":r=e('').attr(\"name\",\"context-menu-input-\"+o).val(i.value||\"\").prop(\"checked\",!!i.selected).prependTo(c);break;case\"radio\":r=e('').attr(\"name\",\"context-menu-input-\"+i.radio).val(i.value||\"\").prop(\"checked\",!!i.selected).prependTo(c);break;case\"select\":r=e('')\r\n .attr('name', 'context-menu-input-' + key)\r\n .val(item.value || '')\r\n .appendTo($label);\r\n break;\r\n\r\n case 'textarea':\r\n $input = $('')\r\n .attr('name', 'context-menu-input-' + key)\r\n .val(item.value || '')\r\n .appendTo($label);\r\n\r\n if (item.height) {\r\n $input.height(item.height);\r\n }\r\n break;\r\n\r\n case 'checkbox':\r\n $input = $('')\r\n .attr('name', 'context-menu-input-' + key)\r\n .val(item.value || '')\r\n .prop('checked', !!item.selected)\r\n .prependTo($label);\r\n break;\r\n\r\n case 'radio':\r\n $input = $('')\r\n .attr('name', 'context-menu-input-' + item.radio)\r\n .val(item.value || '')\r\n .prop('checked', !!item.selected)\r\n .prependTo($label);\r\n break;\r\n\r\n case 'select':\r\n $input = $('\r\n if (item.type && item.type !== 'sub' && item.type !== 'html' && item.type !== 'cm_seperator') {\r\n $input\r\n .on('focus', handle.focusInput)\r\n .on('blur', handle.blurInput);\r\n\r\n if (item.events) {\r\n $input.on(item.events, opt);\r\n }\r\n }\r\n\r\n // add icons\r\n if (item.icon) {\r\n if ($.isFunction(item.icon)) {\r\n item._icon = item.icon.call(this, this, $t, key, item);\r\n } else {\r\n item._icon = root.classNames.icon + ' ' + root.classNames.icon + '-' + item.icon;\r\n\r\n }\r\n $t.addClass(item._icon);\r\n }\r\n }\r\n\r\n // cache contained elements\r\n item.$input = $input;\r\n item.$label = $label;\r\n\r\n // attach item to menu\r\n $t.appendTo(opt.$menu);\r\n\r\n // Disable text selection\r\n if (!opt.hasTypes && $.support.eventSelectstart) {\r\n // browsers support user-select: none,\r\n // IE has a special event for text-selection\r\n // browsers supporting neither will not be preventing text-selection\r\n $t.on('selectstart.disableTextSelect', handle.abortevent);\r\n }\r\n });\r\n // attach contextMenu to (to bypass any possible overflow:hidden issues on parents of the trigger element)\r\n if (!opt.$node) {\r\n opt.$menu.css('display', 'none').addClass('context-menu-root');\r\n }\r\n opt.$menu.appendTo(opt.appendTo || document.body);\r\n },\r\n resize: function ($menu, nested) {\r\n // determine widths of submenus, as CSS won't grow them automatically\r\n // position:absolute within position:absolute; min-width:100; max-width:200; results in width: 100;\r\n // kinda sucks hard...\r\n\r\n // determine width of absolutely positioned element\r\n $menu.css({position: 'absolute', display: 'block'});\r\n // don't apply yet, because that would break nested elements' widths\r\n $menu.data('width', Math.ceil($menu.width()));\r\n // reset styles so they allow nested elements to grow/shrink naturally\r\n $menu.css({\r\n position: 'static',\r\n minWidth: '0px',\r\n maxWidth: '100000px'\r\n });\r\n // identify width of nested menus\r\n $menu.find('> li > ul').each(function () {\r\n op.resize($(this), true);\r\n });\r\n // reset and apply changes in the end because nested\r\n // elements' widths wouldn't be calculatable otherwise\r\n if (!nested) {\r\n $menu.find('ul').addBack().css({\r\n position: '',\r\n display: '',\r\n minWidth: '',\r\n maxWidth: ''\r\n }).width(function () {\r\n return $(this).data('width');\r\n });\r\n }\r\n },\r\n update: function (opt, root) {\r\n var $trigger = this;\r\n if (root === undefined) {\r\n root = opt;\r\n op.resize(opt.$menu);\r\n }\r\n // re-check disabled for each item\r\n opt.$menu.children().each(function () {\r\n var $item = $(this),\r\n key = $item.data('contextMenuKey'),\r\n item = opt.items[key],\r\n disabled = ($.isFunction(item.disabled) && item.disabled.call($trigger, key, root)) || item.disabled === true,\r\n visible;\r\n if ($.isFunction(item.visible)) {\r\n visible = item.visible.call($trigger, key, root);\r\n } else if (typeof item.visible !== 'undefined') {\r\n visible = item.visible === true;\r\n } else {\r\n visible = true;\r\n }\r\n $item[visible ? 'show' : 'hide']();\r\n\r\n // dis- / enable item\r\n $item[disabled ? 'addClass' : 'removeClass'](root.classNames.disabled);\r\n\r\n if ($.isFunction(item.icon)) {\r\n $item.removeClass(item._icon);\r\n item._icon = item.icon.call(this, $trigger, $item, key, item);\r\n $item.addClass(item._icon);\r\n }\r\n\r\n if (item.type) {\r\n // dis- / enable input elements\r\n $item.find('input, select, textarea').prop('disabled', disabled);\r\n\r\n // update input states\r\n switch (item.type) {\r\n case 'text':\r\n case 'textarea':\r\n item.$input.val(item.value || '');\r\n break;\r\n\r\n case 'checkbox':\r\n case 'radio':\r\n item.$input.val(item.value || '').prop('checked', !!item.selected);\r\n break;\r\n\r\n case 'select':\r\n item.$input.val(item.selected || '');\r\n break;\r\n }\r\n }\r\n\r\n if (item.$menu) {\r\n // update sub-menu\r\n op.update.call($trigger, item, root);\r\n }\r\n });\r\n },\r\n layer: function (opt, zIndex) {\r\n // add transparent layer for click area\r\n // filter and background for Internet Explorer, Issue #23\r\n var $layer = opt.$layer = $('
    ')\r\n .css({height: $win.height(), width: $win.width(), display: 'block'})\r\n .data('contextMenuRoot', opt)\r\n .insertBefore(this)\r\n .on('contextmenu', handle.abortevent)\r\n .on('mousedown', handle.layerClick);\r\n\r\n // IE6 doesn't know position:fixed;\r\n if (document.body.style.maxWidth === undefined) { // IE6 doesn't support maxWidth\r\n $layer.css({\r\n 'position': 'absolute',\r\n 'height': $(document).height()\r\n });\r\n }\r\n\r\n return $layer;\r\n }\r\n };\r\n\r\n // split accesskey according to http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#assigned-access-key\r\n function splitAccesskey(val) {\r\n var t = val.split(/\\s+/),\r\n keys = [];\r\n\r\n for (var i = 0, k; k = t[i]; i++) {\r\n k = k.charAt(0).toUpperCase(); // first character only\r\n // theoretically non-accessible characters should be ignored, but different systems, different keyboard layouts, ... screw it.\r\n // a map to look up already used access keys would be nice\r\n keys.push(k);\r\n }\r\n\r\n return keys;\r\n }\r\n\r\n// handle contextMenu triggers\r\n $.fn.contextMenu = function (operation) {\r\n var $t = this, $o = operation;\r\n if (this.length > 0) { // this is not a build on demand menu\r\n if (operation === undefined) {\r\n this.first().trigger('contextmenu');\r\n } else if (operation.x !== undefined && operation.y !== undefined) {\r\n this.first().trigger($.Event('contextmenu', { pageX: operation.x, pageY: operation.y, mouseButton: operation.button }));\r\n } else if (operation === 'hide') {\r\n var $menu = this.first().data('contextMenu') ? this.first().data('contextMenu').$menu : null;\r\n $menu && $menu.trigger('contextmenu:hide');\r\n } else if (operation === 'destroy') {\r\n $.contextMenu('destroy', {context: this});\r\n } else if ($.isPlainObject(operation)) {\r\n operation.context = this;\r\n $.contextMenu('create', operation);\r\n } else if (operation) {\r\n this.removeClass('context-menu-disabled');\r\n } else if (!operation) {\r\n this.addClass('context-menu-disabled');\r\n }\r\n } else {\r\n $.each(menus, function () {\r\n if (this.selector === $t.selector) {\r\n $o.data = this;\r\n\r\n $.extend($o.data, {trigger: 'demand'});\r\n }\r\n });\r\n\r\n handle.contextmenu.call($o.target, $o);\r\n }\r\n\r\n return this;\r\n };\r\n\r\n // manage contextMenu instances\r\n $.contextMenu = function (operation, options) {\r\n if (typeof operation !== 'string') {\r\n options = operation;\r\n operation = 'create';\r\n }\r\n\r\n if (typeof options === 'string') {\r\n options = {selector: options};\r\n } else if (options === undefined) {\r\n options = {};\r\n }\r\n\r\n // merge with default options\r\n var o = $.extend(true, {}, defaults, options || {});\r\n var $document = $(document);\r\n var $context = $document;\r\n var _hasContext = false;\r\n\r\n if (!o.context || !o.context.length) {\r\n o.context = document;\r\n } else {\r\n // you never know what they throw at you...\r\n $context = $(o.context).first();\r\n o.context = $context.get(0);\r\n _hasContext = o.context !== document;\r\n }\r\n\r\n switch (operation) {\r\n case 'create':\r\n // no selector no joy\r\n if (!o.selector) {\r\n throw new Error('No selector specified');\r\n }\r\n // make sure internal classes are not bound to\r\n if (o.selector.match(/.context-menu-(list|item|input)($|\\s)/)) {\r\n throw new Error('Cannot bind to selector \"' + o.selector + '\" as it contains a reserved className');\r\n }\r\n if (!o.build && (!o.items || $.isEmptyObject(o.items))) {\r\n throw new Error('No Items specified');\r\n }\r\n counter++;\r\n o.ns = '.contextMenu' + counter;\r\n if (!_hasContext) {\r\n namespaces[o.selector] = o.ns;\r\n }\r\n menus[o.ns] = o;\r\n\r\n // default to right click\r\n if (!o.trigger) {\r\n o.trigger = 'right';\r\n }\r\n\r\n if (!initialized) {\r\n // make sure item click is registered first\r\n $document\r\n .on({\r\n 'contextmenu:hide.contextMenu': handle.hideMenu,\r\n 'prevcommand.contextMenu': handle.prevItem,\r\n 'nextcommand.contextMenu': handle.nextItem,\r\n 'contextmenu.contextMenu': handle.abortevent,\r\n 'mouseenter.contextMenu': handle.menuMouseenter,\r\n 'mouseleave.contextMenu': handle.menuMouseleave\r\n }, '.context-menu-list')\r\n .on('mouseup.contextMenu', '.context-menu-input', handle.inputClick)\r\n .on({\r\n 'mouseup.contextMenu': handle.itemClick,\r\n 'contextmenu:focus.contextMenu': handle.focusItem,\r\n 'contextmenu:blur.contextMenu': handle.blurItem,\r\n 'contextmenu.contextMenu': handle.abortevent,\r\n 'mouseenter.contextMenu': handle.itemMouseenter,\r\n 'mouseleave.contextMenu': handle.itemMouseleave\r\n }, '.context-menu-item');\r\n\r\n initialized = true;\r\n }\r\n\r\n // engage native contextmenu event\r\n $context\r\n .on('contextmenu' + o.ns, o.selector, o, handle.contextmenu);\r\n\r\n if (_hasContext) {\r\n // add remove hook, just in case\r\n $context.on('remove' + o.ns, function () {\r\n $(this).contextMenu('destroy');\r\n });\r\n }\r\n\r\n switch (o.trigger) {\r\n case 'hover':\r\n $context\r\n .on('mouseenter' + o.ns, o.selector, o, handle.mouseenter)\r\n .on('mouseleave' + o.ns, o.selector, o, handle.mouseleave);\r\n break;\r\n\r\n case 'left':\r\n $context.on('click' + o.ns, o.selector, o, handle.click);\r\n break;\r\n /*\r\n default:\r\n // http://www.quirksmode.org/dom/events/contextmenu.html\r\n $document\r\n .on('mousedown' + o.ns, o.selector, o, handle.mousedown)\r\n .on('mouseup' + o.ns, o.selector, o, handle.mouseup);\r\n break;\r\n */\r\n }\r\n\r\n // create menu\r\n if (!o.build) {\r\n op.create(o);\r\n }\r\n break;\r\n\r\n case 'destroy':\r\n var $visibleMenu;\r\n if (_hasContext) {\r\n // get proper options\r\n var context = o.context;\r\n $.each(menus, function (ns, o) {\r\n if (o.context !== context) {\r\n return true;\r\n }\r\n\r\n $visibleMenu = $('.context-menu-list').filter(':visible');\r\n if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is($(o.context).find(o.selector))) {\r\n $visibleMenu.trigger('contextmenu:hide', {force: true});\r\n }\r\n\r\n try {\r\n if (menus[o.ns].$menu) {\r\n menus[o.ns].$menu.remove();\r\n }\r\n\r\n delete menus[o.ns];\r\n } catch (e) {\r\n menus[o.ns] = null;\r\n }\r\n\r\n $(o.context).off(o.ns);\r\n\r\n return true;\r\n });\r\n } else if (!o.selector) {\r\n $document.off('.contextMenu .contextMenuAutoHide');\r\n $.each(menus, function (ns, o) {\r\n $(o.context).off(o.ns);\r\n });\r\n\r\n namespaces = {};\r\n menus = {};\r\n counter = 0;\r\n initialized = false;\r\n\r\n $('#context-menu-layer, .context-menu-list').remove();\r\n } else if (namespaces[o.selector]) {\r\n $visibleMenu = $('.context-menu-list').filter(':visible');\r\n if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is(o.selector)) {\r\n $visibleMenu.trigger('contextmenu:hide', {force: true});\r\n }\r\n\r\n try {\r\n if (menus[namespaces[o.selector]].$menu) {\r\n menus[namespaces[o.selector]].$menu.remove();\r\n }\r\n\r\n delete menus[namespaces[o.selector]];\r\n } catch (e) {\r\n menus[namespaces[o.selector]] = null;\r\n }\r\n\r\n $document.off(namespaces[o.selector]);\r\n }\r\n break;\r\n\r\n case 'html5':\r\n // if or are not handled by the browser,\r\n // or options was a bool true,\r\n // initialize $.contextMenu for them\r\n if ((!$.support.htmlCommand && !$.support.htmlMenuitem) || (typeof options === 'boolean' && options)) {\r\n $('menu[type=\"context\"]').each(function () {\r\n if (this.id) {\r\n $.contextMenu({\r\n selector: '[contextmenu=' + this.id + ']',\r\n items: $.contextMenu.fromMenu(this)\r\n });\r\n }\r\n }).css('display', 'none');\r\n }\r\n break;\r\n\r\n default:\r\n throw new Error('Unknown operation \"' + operation + '\"');\r\n }\r\n\r\n return this;\r\n };\r\n\r\n// import values into commands\r\n $.contextMenu.setInputValues = function (opt, data) {\r\n if (data === undefined) {\r\n data = {};\r\n }\r\n\r\n $.each(opt.inputs, function (key, item) {\r\n switch (item.type) {\r\n case 'text':\r\n case 'textarea':\r\n item.value = data[key] || '';\r\n break;\r\n\r\n case 'checkbox':\r\n item.selected = data[key] ? true : false;\r\n break;\r\n\r\n case 'radio':\r\n item.selected = (data[item.radio] || '') === item.value;\r\n break;\r\n\r\n case 'select':\r\n item.selected = data[key] || '';\r\n break;\r\n }\r\n });\r\n };\r\n\r\n// export values from commands\r\n $.contextMenu.getInputValues = function (opt, data) {\r\n if (data === undefined) {\r\n data = {};\r\n }\r\n\r\n $.each(opt.inputs, function (key, item) {\r\n switch (item.type) {\r\n case 'text':\r\n case 'textarea':\r\n case 'select':\r\n data[key] = item.$input.val();\r\n break;\r\n\r\n case 'checkbox':\r\n data[key] = item.$input.prop('checked');\r\n break;\r\n\r\n case 'radio':\r\n if (item.$input.prop('checked')) {\r\n data[item.radio] = item.value;\r\n }\r\n break;\r\n }\r\n });\r\n\r\n return data;\r\n };\r\n\r\n// find