Subversion-Projekte lars-tiefland.cienc

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
5 lars 1
/*!
2
 * Bootstrap Context Menu
3
 * Author: @sydcanem
4
 * https://github.com/sydcanem/bootstrap-contextmenu
5
 *
6
 * Inspired by Bootstrap's dropdown plugin.
7
 * Bootstrap (http://getbootstrap.com).
8
 *
9
 * Licensed under MIT
10
 * ========================================================= */
11
 
12
;(function($) {
13
 
14
	'use strict';
15
 
16
	/* CONTEXTMENU CLASS DEFINITION
17
	 * ============================ */
18
	var toggle = '[data-toggle="context"]';
19
 
20
	var ContextMenu = function (element, options) {
21
		this.$element = $(element);
22
 
23
		this.before = options.before || this.before;
24
		this.onItem = options.onItem || this.onItem;
25
		this.scopes = options.scopes || null;
26
 
27
		if (options.target) {
28
			this.$element.data('target', options.target);
29
		}
30
 
31
		this.listen();
32
	};
33
 
34
	ContextMenu.prototype = {
35
 
36
		constructor: ContextMenu
37
		,show: function(e) {
38
 
39
			var $menu
40
				, evt
41
				, tp
42
				, items
43
				, relatedTarget = { relatedTarget: this, target: e.currentTarget };
44
 
45
			if (this.isDisabled()) return;
46
 
47
			this.closemenu();
48
 
49
			if (!this.before.call(this,e,$(e.currentTarget))) return;
50
 
51
			$menu = this.getMenu();
52
			$menu.trigger(evt = $.Event('show.bs.context', relatedTarget));
53
 
54
			tp = this.getPosition(e, $menu);
55
			items = 'li:not(.divider)';
56
			$menu.attr('style', '')
57
				.css(tp)
58
				.addClass('open')
59
				.on('click.context.data-api', items, $.proxy(this.onItem, this, $(e.currentTarget)))
60
				.trigger('shown.bs.context', relatedTarget);
61
 
62
			// Delegating the `closemenu` only on the currently opened menu.
63
			// This prevents other opened menus from closing.
64
			$('html')
65
				.on('click.context.data-api', $menu.selector, $.proxy(this.closemenu, this));
66
 
67
			return false;
68
		}
69
 
70
		,closemenu: function(e) {
71
			var $menu
72
				, evt
73
				, items
74
				, relatedTarget;
75
 
76
			$menu = this.getMenu();
77
 
78
			if(!$menu.hasClass('open')) return;
79
 
80
			relatedTarget = { relatedTarget: this };
81
			$menu.trigger(evt = $.Event('hide.bs.context', relatedTarget));
82
 
83
			items = 'li:not(.divider)';
84
			$menu.removeClass('open')
85
				.off('click.context.data-api', items)
86
				.trigger('hidden.bs.context', relatedTarget);
87
 
88
			$('html')
89
				.off('click.context.data-api', $menu.selector);
90
			// Don't propagate click event so other currently
91
			// opened menus won't close.
92
			return false;
93
		}
94
 
95
		,keydown: function(e) {
96
			if (e.which == 27) this.closemenu(e);
97
		}
98
 
99
		,before: function(e) {
100
			return true;
101
		}
102
 
103
		,onItem: function(e) {
104
			return true;
105
		}
106
 
107
		,listen: function () {
108
			this.$element.on('contextmenu.context.data-api', this.scopes, $.proxy(this.show, this));
109
			$('html').on('click.context.data-api', $.proxy(this.closemenu, this));
110
			$('html').on('keydown.context.data-api', $.proxy(this.keydown, this));
111
		}
112
 
113
		,destroy: function() {
114
			this.$element.off('.context.data-api').removeData('context');
115
			$('html').off('.context.data-api');
116
		}
117
 
118
		,isDisabled: function() {
119
			return this.$element.hasClass('disabled') ||
120
					this.$element.attr('disabled');
121
		}
122
 
123
		,getMenu: function () {
124
			var selector = this.$element.data('target')
125
				, $menu;
126
 
127
			if (!selector) {
128
				selector = this.$element.attr('href');
129
				selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
130
			}
131
 
132
			$menu = $(selector);
133
 
134
			return $menu && $menu.length ? $menu : this.$element.find(selector);
135
		}
136
 
137
		,getPosition: function(e, $menu) {
138
			var mouseX = e.clientX
139
				, mouseY = e.clientY
140
				, boundsX = $(window).width()
141
				, boundsY = $(window).height()
142
				, menuWidth = $menu.find('.dropdown-menu').outerWidth()
143
				, menuHeight = $menu.find('.dropdown-menu').outerHeight()
144
				, tp = {"position":"absolute","z-index":9999}
145
				, Y, X, parentOffset;
146
 
147
			if (mouseY + menuHeight > boundsY) {
148
				Y = {"top": mouseY - menuHeight + $(window).scrollTop()};
149
			} else {
150
				Y = {"top": mouseY + $(window).scrollTop()};
151
			}
152
 
153
			if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {
154
				X = {"left": mouseX - menuWidth + $(window).scrollLeft()};
155
			} else {
156
				X = {"left": mouseX + $(window).scrollLeft()};
157
			}
158
 
159
			// If context-menu's parent is positioned using absolute or relative positioning,
160
			// the calculated mouse position will be incorrect.
161
			// Adjust the position of the menu by its offset parent position.
162
			parentOffset = $menu.offsetParent().offset();
163
			X.left = X.left - parentOffset.left;
164
			Y.top = Y.top - parentOffset.top;
165
 
166
			return $.extend(tp, Y, X);
167
		}
168
 
169
	};
170
 
171
	/* CONTEXT MENU PLUGIN DEFINITION
172
	 * ========================== */
173
 
174
	$.fn.contextmenu = function (option,e) {
175
		return this.each(function () {
176
			var $this = $(this)
177
				, data = $this.data('context')
178
				, options = (typeof option == 'object') && option;
179
 
180
			if (!data) $this.data('context', (data = new ContextMenu($this, options)));
181
			if (typeof option == 'string') data[option].call(data, e);
182
		});
183
	};
184
 
185
	$.fn.contextmenu.Constructor = ContextMenu;
186
 
187
	/* APPLY TO STANDARD CONTEXT MENU ELEMENTS
188
	 * =================================== */
189
 
190
	$(document)
191
	   .on('contextmenu.context.data-api', function() {
192
			$(toggle).each(function () {
193
				var data = $(this).data('context');
194
				if (!data) return;
195
				data.closemenu();
196
			});
197
		})
198
		.on('contextmenu.context.data-api', toggle, function(e) {
199
			$(this).contextmenu('show', e);
200
 
201
			e.preventDefault();
202
			e.stopPropagation();
203
		});
204
 
205
}(jQuery));