PageSourceSearch

https://hrweb.com/javascripts/jquery.contextmenu.js

js hrweb.com collected 2026-10-05 05:37:32 UTC 12,884 bytes, 265 lines download raw bytes

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.