1/** 2 * Copyright (c)2005-2009 Matt Kruse (javascripttoolbox.com) 3 * 4 * Dual licensed under the MIT and GPL licenses. 5 * This basically means you can use this code however you want for 6 * free, but don't claim to have written it yourself! 7 * Donations always accepted: http://www.JavascriptToolbox.com/donate/ 8 * 9 * Please do not link to the .js files on javascripttoolbox.com from 10 * your site. Copy the files locally to your server instead. 11 * 12 */ 13/** 14 * jquery.contextmenu.js 15 * jQuery Plugin for Context Menus 16 * http://www.JavascriptToolbox.com/lib/contextmenu/ 17 * 18 * Copyright (c) 2008 Matt Kruse (javascripttoolbox.com) 19 * Dual licensed under the MIT and GPL licenses. 20 * 21 * @version 1.1 22 * @history 1.1 2010-01-25 Fixed a problem with 1.4 which caused undesired show/hide animations 23 * @history 1.0 2008-10-20 Initial Release 24 * @todo slideUp doesn't work in IE - because of iframe? 25 * @todo Hide all other menus when contextmenu is shown? 26 * @todo More themes 27 * @todo Nested context menus 28 */ 29; (function ($) { 30 $.contextMenu = { 31 shadow: true, 32 shadowOffset: 0, 33 shadowOffsetX: 5, 34 shadowOffsetY: 5, 35 shadowWidthAdjust: -3, 36 shadowHeightAdjust: -3, 37 shadowOpacity: .2, 38 shadowClass: 'context-menu-shadow', 39 shadowColor: 'black', 40 41 offsetX: 0, 42 offsetY: 0, 43 appendTo: 'body', 44 direction: 'down', 45 constrainToScreen: true, 46 47 showTransition: 'show', 48 hideTransition: 'hide', 49 showSpeed: null, 50 hideSpeed: null, 51 showCallback: null, 52 hideCallback: null, 53 54 className: 'context-menu', 55 itemClassName: 'context-menu-item', 56 itemHoverClassName: 'context-menu-item-hover', 57 disabledItemClassName: 'context-menu-item-disabled', 58 disabledItemHoverClassName: 'context-menu-item-disabled-hover', 59 separatorClassName: 'context-menu-separator', 60 innerDivClassName: 'context-menu-item-inner', 61 themePrefix: 'context-menu-theme-', 62 theme: 'default', 63 64 separator: 'context-menu-separator', // A specific key to identify a separator 65 target: null, // The target of the context click, to be populated when triggered 66 menu: null, // The jQuery object containing the HTML object that is the menu itself 67 shadowObj: null, // Shadow object 68 bgiframe: null, // The iframe object for IE6 69 shown: false, // Currently being shown? 70 useIframe:/*@cc_on @*//*@if (@_win32) true, @else @*/false,/*@end @*/ // This is a better check than looking at userAgent! 71 72 // Create the menu instance 73 create: function (menu, opts) { 74 var cmenu = $.extend({}, this, opts); // Clone all default properties to created object 75 76 // If a selector has been passed in, then use that as the menu 77 if (typeof menu == "string") { 78 cmenu.menu = $(menu); 79 } 80 // If a function has been passed in, call it each time the menu is shown to create the menu 81 else if (typeof menu == "function") { 82 cmenu.menuFunction = menu; 83 } 84 // Otherwise parse the Array passed in 85 else { 86 cmenu.menu = cmenu.createMenu(menu, cmenu); 87 } 88 if (cmenu.menu) { 89 cmenu.menu.css({ display: 'none' }); 90 $(cmenu.appendTo).append(cmenu.menu); 91 } 92 93 // Create the shadow object if shadow is enabled 94 if (cmenu.shadow) { 95 cmenu.createShadow(cmenu); // Extracted to method for extensibility 96 if (cmenu.shadowOffset) { cmenu.shadowOffsetX = cmenu.shadowOffsetY = cmenu.shadowOffset; } 97 } 98 $('body').bind('contextmenu', function () { cmenu.hide(); }); // If right-clicked somewhere else in the document, hide this menu 99 return cmenu; 100 }, 101 102 // Create an iframe object to go behind the menu 103 createIframe: function () { 104 return $('<iframe frameborder="0" tabindex="-1" src="javascript:false" style="display:block;position:absolute;z-index:-1;filter:Alpha(Opacity=0);"/>'); 105 }, 106 107 // Accept an Array representing a menu structure and turn it into HTML 108 createMenu: function (menu, cmenu) { 109 var className = cmenu.className; 110 $.each(cmenu.theme.split(","), function (i, n) { className += ' ' + cmenu.themePrefix + n }); 111 var $t = $('<table cellspacing=0 cellpadding=0></table>').click(function () { cmenu.hide(); return false; }); // We wrap a table around it so width can be flexible 112 var $tr = $('<tr></tr>'); 113 var $td = $('<td></td>');
114 var $div = $('<div class="' + className + '"></div>'); 115 116 // Each menu item is specified as either: 117 // title:function 118 // or title: { property:value ... } 119 for (var i = 0; i < menu.length; i++) { 120 var m = menu[i]; 121 if (m == $.contextMenu.separator) { 122 $div.append(cmenu.createSeparator()); 123 } 124 else { 125 for (var opt in menu[i]) { 126 $div.append(cmenu.createMenuItem(opt, menu[i][opt])); // Extracted to method for extensibility 127 } 128 } 129 } 130 if (cmenu.useIframe) { 131 $td.append(cmenu.createIframe()); 132 } 133 $t.append($tr.append($td.append($div))) 134 return $t; 135 }, 136 137 // Create an individual menu item 138 createMenuItem: function (label, obj) { 139 var cmenu = this; 140 if (typeof obj == "function") { obj = { onclick: obj }; } // If passed a simple function, turn it into a property of an object 141 // Default properties, extended in case properties are passed 142 var o = $.extend({ 143 onclick: function () { }, 144 className: '', 145 hoverClassName: cmenu.itemHoverClassName, 146 icon: '', 147 disabled: false, 148 title: '', 149 hoverItem: cmenu.hoverItem, 150 hoverItemOut: cmenu.hoverItemOut 151 }, obj); 152 // If an icon is specified, hard-code the background-image style. Themes that don't show images should take this into account in their CSS 153 var iconStyle = (o.icon) ? 'background-image:url(' + o.icon + ');' : ''; 154 var $div = $('<div class="' + cmenu.itemClassName + ' ' + o.className + ((o.disabled) ? ' ' + cmenu.disabledItemClassName : '') + '" title="' + o.title + '"></div>') 155 // If the item is disabled, don't do anything when it is clicked 156 .click(function (e) { if (cmenu.isItemDisabled(this)) { return false; } else { return o.onclick.call(cmenu.target, this, cmenu, e) } }) 157 // Change the class of the item when hovered over 158 .hover(function () { o.hoverItem.call(this, (cmenu.isItemDisabled(this)) ? cmenu.disabledItemHoverClassName : o.hoverClassName); } 159 , function () { o.hoverItemOut.call(this, (cmenu.isItemDisabled(this)) ? cmenu.disabledItemHoverClassName : o.hoverClassName); } 160 ); 161 var $idiv = $('<div class="' + cmenu.innerDivClassName + '" style="' + iconStyle + '">' + label + '</div>'); 162 $div.append($idiv); 163 return $div; 164 }, 165 166 // Create a separator row 167 createSeparator: function () { 168 return $('<div class="' + this.separatorClassName + '"></div>'); 169 }, 170 171 // Determine if an individual item is currently disabled. This is called each time the item is hovered or clicked because the disabled status may change at any time 172 isItemDisabled: function (item) { return $(item).is('.' + this.disabledItemClassName); }, 173 174 // Functions to fire on hover. Extracted to methods for extensibility 175 hoverItem: function (c) { $(this).addClass(c); }, 176 hoverItemOut: function (c) { $(this).removeClass(c); }, 177 178 // Create the shadow object 179 createShadow: function (cmenu) { 180 cmenu.shadowObj = $('<div class="' + cmenu.shadowClass + '"></div>').css({ display: 'none', position: "absolute", zIndex: 9998, opacity: cmenu.shadowOpacity, backgroundColor: cmenu.shadowColor }); 181 $(cmenu.appendTo).append(cmenu.shadowObj); 182 }, 183 184 // Display the shadow object, given the position of the menu itself 185 showShadow: function (x, y, e) { 186 var cmenu = this; 187 if (cmenu.shadow) { 188 cmenu.shadowObj.css({ 189 width: (cmenu.menu.width() + cmenu.shadowWidthAdjust) + "px", 190 height: (cmenu.menu.height() + cmenu.shadowHeightAdjust) + "px", 191 top: (y + cmenu.shadowOffsetY) + "px", 192 left: (x + cmenu.shadowOffsetX) + "px" 193 }).addClass(cmenu.shadowClass)[cmenu.showTransition](cmenu.showSpeed); 194 } 195 }, 196 197 // A hook to call before the menu is shown, in case special processing needs to be done. 198 // Return false to cancel the default show operation 199 beforeShow: function () { return true; }, 200 201 // Show the context menu 202 show: function (t, e) { 203 var cmenu = this, x = e.pageX, y = e.pageY; 204 cmenu.target = t; // Preserve the object that triggered this context menu so menu item click methods can see it 205 if (cmenu.beforeShow() !== false) { 206 // If the menu content is a function, call it to populate the menu each time it is displayed 207 if (cmenu.menuFunction) { 208 if (cmenu.menu) { $(cmenu.menu).remove(); } 209 cmenu.menu = cmenu.createMenu(cmenu.menuFunction(cmenu, t), cmenu); 210 cmenu.menu.css({ display: 'none' }); 211 $(cmenu.appendTo).append(cmenu.menu); 212 } 213 var $c = cmenu.menu; 214 x += cmenu.offsetX; y += cmenu.offsetY; 215 var pos = cmenu.getPosition(x, y, cmenu, e); // Extracted to method for extensibility 216 cmenu.showShadow(pos.x, pos.y, e); 217 // Resize the iframe if needed 218 if (cmenu.useIframe) { 219 $c.find('iframe').css({ width: $c.width() + cmenu.shadowOffsetX + cmenu.shadowWidthAdjust, height: $c.height() + cmenu.shadowOffsetY + cmenu.shadowHeightAdjust }); 220 } 221 $c.css({ top: pos.y + "px", left: pos.x + "px", position: "absolute", zIndex: 9999 })[cmenu.showTransition](cmenu.showSpeed, ((cmenu.showCallback) ? function () { cmenu.showCallback.call(cmenu); } : null)); 222 cmenu.shown = true; 223 $(document).one('click', null, function () { cmenu.hide() }); // Handle a single click to the document to hide the menu 224 } 225 }, 226 227 // Find the position where the menu should appear, given an x,y of the click event 228 getPosition: function (clickX, clickY, cmenu, e) { 229 var x = clickX + cmenu.offsetX; 230 var y = clickY + cmenu.offsetY 231 var h = $(cmenu.menu).height(); 232 var w = $(cmenu.menu).width(); 233 var dir = cmenu.direction; 234 if (cmenu.constrainToScreen) { 235 var $w = $(window); 236 var wh = $w.height(); 237 var ww = $w.width(); 238 if (dir == "down" && (y + h - $w.scrollTop() > wh)) { dir = "up"; } 239 var maxRight = x + w - $w.scrollLeft(); 240 if (maxRight > ww) { x -= (maxRight - ww); } 241 } 242 if (dir == "up") { y -= h; } 243 return { 'x': x, 'y': y }; 244 }, 245 246 // Hide the menu, of course 247 hide: function () { 248 var cmenu = this; 249 if (cmenu.shown) { 250 if (cmenu.iframe) { $(cmenu.iframe).hide(); } 251 if (cmenu.menu) { cmenu.menu[cmenu.hideTransition](cmenu.hideSpeed, ((cmenu.hideCallback) ? function () { cmenu.hideCallback.call(cmenu); } : null)); } 252 if (cmenu.shadow) { cmenu.shadowObj[cmenu.hideTransition](cmenu.hideSpeed); } 253 } 254 cmenu.shown = false; 255 } 256 }; 257 258 // This actually adds the .contextMenu() function to the jQuery namespace 259 $.fn.contextMenu = function (menu, options) { 260 var cmenu = $.contextMenu.create(menu, options); 261 return this.each(function () { 262 $(this).bind('contextmenu', function (e) { cmenu.show(this, e); return false; }); 263 }); 264 }; 265})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.