Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
875 lars 1
/**
2
 * ### Contextmenu plugin
3
 *
4
 * Shows a context menu when a node is right-clicked.
5
 */
6
/*globals jQuery, define, exports, require, document */
7
(function (factory) {
8
	"use strict";
9
	if (typeof define === 'function' && define.amd) {
10
		define('jstree.contextmenu', ['jquery','jstree'], factory);
11
	}
12
	else if(typeof exports === 'object') {
13
		factory(require('jquery'), require('jstree'));
14
	}
15
	else {
16
		factory(jQuery, jQuery.jstree);
17
	}
18
}(function ($, jstree, undefined) {
19
	"use strict";
20
 
21
	if($.jstree.plugins.contextmenu) { return; }
22
 
23
	/**
24
	 * stores all defaults for the contextmenu plugin
25
	 * @name $.jstree.defaults.contextmenu
26
	 * @plugin contextmenu
27
	 */
28
	$.jstree.defaults.contextmenu = {
29
		/**
30
		 * a boolean indicating if the node should be selected when the context menu is invoked on it. Defaults to `true`.
31
		 * @name $.jstree.defaults.contextmenu.select_node
32
		 * @plugin contextmenu
33
		 */
34
		select_node : true,
35
		/**
36
		 * a boolean indicating if the menu should be shown aligned with the node. Defaults to `true`, otherwise the mouse coordinates are used.
37
		 * @name $.jstree.defaults.contextmenu.show_at_node
38
		 * @plugin contextmenu
39
		 */
40
		show_at_node : true,
41
		/**
42
		 * an object of actions, or a function that accepts a node and a callback function and calls the callback function with an object of actions available for that node (you can also return the items too).
43
		 *
44
		 * Each action consists of a key (a unique name) and a value which is an object with the following properties (only label and action are required):
45
		 *
46
		 * * `separator_before` - a boolean indicating if there should be a separator before this item
47
		 * * `separator_after` - a boolean indicating if there should be a separator after this item
48
		 * * `_disabled` - a boolean indicating if this action should be disabled
49
		 * * `label` - a string - the name of the action (could be a function returning a string)
50
		 * * `action` - a function to be executed if this item is chosen
51
		 * * `icon` - a string, can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class
52
		 * * `shortcut` - keyCode which will trigger the action if the menu is open (for example `113` for rename, which equals F2)
53
		 * * `shortcut_label` - shortcut label (like for example `F2` for rename)
54
		 *
55
		 * @name $.jstree.defaults.contextmenu.items
56
		 * @plugin contextmenu
57
		 */
58
		items : function (o, cb) { // Could be an object directly
59
			return {
60
				"create" : {
61
					"separator_before"	: false,
62
					"separator_after"	: true,
63
					"_disabled"			: false, //(this.check("create_node", data.reference, {}, "last")),
64
					"label"				: "Create",
65
					"action"			: function (data) {
66
						var inst = $.jstree.reference(data.reference),
67
							obj = inst.get_node(data.reference);
68
						inst.create_node(obj, {}, "last", function (new_node) {
69
							setTimeout(function () { inst.edit(new_node); },0);
70
						});
71
					}
72
				},
73
				"rename" : {
74
					"separator_before"	: false,
75
					"separator_after"	: false,
76
					"_disabled"			: false, //(this.check("rename_node", data.reference, this.get_parent(data.reference), "")),
77
					"label"				: "Rename",
78
					/*!
79
					"shortcut"			: 113,
80
					"shortcut_label"	: 'F2',
81
					"icon"				: "glyphicon glyphicon-leaf",
82
					*/
83
					"action"			: function (data) {
84
						var inst = $.jstree.reference(data.reference),
85
							obj = inst.get_node(data.reference);
86
						inst.edit(obj);
87
					}
88
				},
89
				"remove" : {
90
					"separator_before"	: false,
91
					"icon"				: false,
92
					"separator_after"	: false,
93
					"_disabled"			: false, //(this.check("delete_node", data.reference, this.get_parent(data.reference), "")),
94
					"label"				: "Delete",
95
					"action"			: function (data) {
96
						var inst = $.jstree.reference(data.reference),
97
							obj = inst.get_node(data.reference);
98
						if(inst.is_selected(obj)) {
99
							inst.delete_node(inst.get_selected());
100
						}
101
						else {
102
							inst.delete_node(obj);
103
						}
104
					}
105
				},
106
				"ccp" : {
107
					"separator_before"	: true,
108
					"icon"				: false,
109
					"separator_after"	: false,
110
					"label"				: "Edit",
111
					"action"			: false,
112
					"submenu" : {
113
						"cut" : {
114
							"separator_before"	: false,
115
							"separator_after"	: false,
116
							"label"				: "Cut",
117
							"action"			: function (data) {
118
								var inst = $.jstree.reference(data.reference),
119
									obj = inst.get_node(data.reference);
120
								if(inst.is_selected(obj)) {
121
									inst.cut(inst.get_top_selected());
122
								}
123
								else {
124
									inst.cut(obj);
125
								}
126
							}
127
						},
128
						"copy" : {
129
							"separator_before"	: false,
130
							"icon"				: false,
131
							"separator_after"	: false,
132
							"label"				: "Copy",
133
							"action"			: function (data) {
134
								var inst = $.jstree.reference(data.reference),
135
									obj = inst.get_node(data.reference);
136
								if(inst.is_selected(obj)) {
137
									inst.copy(inst.get_top_selected());
138
								}
139
								else {
140
									inst.copy(obj);
141
								}
142
							}
143
						},
144
						"paste" : {
145
							"separator_before"	: false,
146
							"icon"				: false,
147
							"_disabled"			: function (data) {
148
								return !$.jstree.reference(data.reference).can_paste();
149
							},
150
							"separator_after"	: false,
151
							"label"				: "Paste",
152
							"action"			: function (data) {
153
								var inst = $.jstree.reference(data.reference),
154
									obj = inst.get_node(data.reference);
155
								inst.paste(obj);
156
							}
157
						}
158
					}
159
				}
160
			};
161
		}
162
	};
163
 
164
	$.jstree.plugins.contextmenu = function (options, parent) {
165
		this.bind = function () {
166
			parent.bind.call(this);
167
 
168
			var last_ts = 0, cto = null, ex, ey;
169
			this.element
170
				.on("contextmenu.jstree", ".jstree-anchor", $.proxy(function (e, data) {
171
						e.preventDefault();
172
						last_ts = e.ctrlKey ? +new Date() : 0;
173
						if(data || cto) {
174
							last_ts = (+new Date()) + 10000;
175
						}
176
						if(cto) {
177
							clearTimeout(cto);
178
						}
179
						if(!this.is_loading(e.currentTarget)) {
180
							this.show_contextmenu(e.currentTarget, e.pageX, e.pageY, e);
181
						}
182
					}, this))
183
				.on("click.jstree", ".jstree-anchor", $.proxy(function (e) {
184
						if(this._data.contextmenu.visible && (!last_ts || (+new Date()) - last_ts > 250)) { // work around safari & macOS ctrl+click
185
							$.vakata.context.hide();
186
						}
187
						last_ts = 0;
188
					}, this))
189
				.on("touchstart.jstree", ".jstree-anchor", function (e) {
190
						if(!e.originalEvent || !e.originalEvent.changedTouches || !e.originalEvent.changedTouches[0]) {
191
							return;
192
						}
193
						ex = e.pageX;
194
						ey = e.pageY;
195
						cto = setTimeout(function () {
196
							$(e.currentTarget).trigger('contextmenu', true);
197
						}, 750);
198
					})
199
				.on('touchmove.vakata.jstree', function (e) {
200
						if(cto && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && (Math.abs(ex - e.pageX) > 50 || Math.abs(ey - e.pageY) > 50)) {
201
							clearTimeout(cto);
202
						}
203
					})
204
				.on('touchend.vakata.jstree', function (e) {
205
						if(cto) {
206
							clearTimeout(cto);
207
						}
208
					});
209
 
210
			/*!
211
			if(!('oncontextmenu' in document.body) && ('ontouchstart' in document.body)) {
212
				var el = null, tm = null;
213
				this.element
214
					.on("touchstart", ".jstree-anchor", function (e) {
215
						el = e.currentTarget;
216
						tm = +new Date();
217
						$(document).one("touchend", function (e) {
218
							e.target = document.elementFromPoint(e.originalEvent.targetTouches[0].pageX - window.pageXOffset, e.originalEvent.targetTouches[0].pageY - window.pageYOffset);
219
							e.currentTarget = e.target;
220
							tm = ((+(new Date())) - tm);
221
							if(e.target === el && tm > 600 && tm < 1000) {
222
								e.preventDefault();
223
								$(el).trigger('contextmenu', e);
224
							}
225
							el = null;
226
							tm = null;
227
						});
228
					});
229
			}
230
			*/
231
			$(document).on("context_hide.vakata.jstree", $.proxy(function () { this._data.contextmenu.visible = false; }, this));
232
		};
233
		this.teardown = function () {
234
			if(this._data.contextmenu.visible) {
235
				$.vakata.context.hide();
236
			}
237
			parent.teardown.call(this);
238
		};
239
 
240
		/**
241
		 * prepare and show the context menu for a node
242
		 * @name show_contextmenu(obj [, x, y])
243
		 * @param {mixed} obj the node
244
		 * @param {Number} x the x-coordinate relative to the document to show the menu at
245
		 * @param {Number} y the y-coordinate relative to the document to show the menu at
246
		 * @param {Object} e the event if available that triggered the contextmenu
247
		 * @plugin contextmenu
248
		 * @trigger show_contextmenu.jstree
249
		 */
250
		this.show_contextmenu = function (obj, x, y, e) {
251
			obj = this.get_node(obj);
252
			if(!obj || obj.id === $.jstree.root) { return false; }
253
			var s = this.settings.contextmenu,
254
				d = this.get_node(obj, true),
255
				a = d.children(".jstree-anchor"),
256
				o = false,
257
				i = false;
258
			if(s.show_at_node || x === undefined || y === undefined) {
259
				o = a.offset();
260
				x = o.left;
261
				y = o.top + this._data.core.li_height;
262
			}
263
			if(this.settings.contextmenu.select_node && !this.is_selected(obj)) {
264
				this.activate_node(obj, e);
265
			}
266
 
267
			i = s.items;
268
			if($.isFunction(i)) {
269
				i = i.call(this, obj, $.proxy(function (i) {
270
					this._show_contextmenu(obj, x, y, i);
271
				}, this));
272
			}
273
			if($.isPlainObject(i)) {
274
				this._show_contextmenu(obj, x, y, i);
275
			}
276
		};
277
		/**
278
		 * show the prepared context menu for a node
279
		 * @name _show_contextmenu(obj, x, y, i)
280
		 * @param {mixed} obj the node
281
		 * @param {Number} x the x-coordinate relative to the document to show the menu at
282
		 * @param {Number} y the y-coordinate relative to the document to show the menu at
283
		 * @param {Number} i the object of items to show
284
		 * @plugin contextmenu
285
		 * @trigger show_contextmenu.jstree
286
		 * @private
287
		 */
288
		this._show_contextmenu = function (obj, x, y, i) {
289
			var d = this.get_node(obj, true),
290
				a = d.children(".jstree-anchor");
291
			$(document).one("context_show.vakata.jstree", $.proxy(function (e, data) {
292
				var cls = 'jstree-contextmenu jstree-' + this.get_theme() + '-contextmenu';
293
				$(data.element).addClass(cls);
294
			}, this));
295
			this._data.contextmenu.visible = true;
296
			$.vakata.context.show(a, { 'x' : x, 'y' : y }, i);
297
			/**
298
			 * triggered when the contextmenu is shown for a node
299
			 * @event
300
			 * @name show_contextmenu.jstree
301
			 * @param {Object} node the node
302
			 * @param {Number} x the x-coordinate of the menu relative to the document
303
			 * @param {Number} y the y-coordinate of the menu relative to the document
304
			 * @plugin contextmenu
305
			 */
306
			this.trigger('show_contextmenu', { "node" : obj, "x" : x, "y" : y });
307
		};
308
	};
309
 
310
	// contextmenu helper
311
	(function ($) {
312
		var right_to_left = false,
313
			vakata_context = {
314
				element		: false,
315
				reference	: false,
316
				position_x	: 0,
317
				position_y	: 0,
318
				items		: [],
319
				html		: "",
320
				is_visible	: false
321
			};
322
 
323
		$.vakata.context = {
324
			settings : {
325
				hide_onmouseleave	: 0,
326
				icons				: true
327
			},
328
			_trigger : function (event_name) {
329
				$(document).triggerHandler("context_" + event_name + ".vakata", {
330
					"reference"	: vakata_context.reference,
331
					"element"	: vakata_context.element,
332
					"position"	: {
333
						"x" : vakata_context.position_x,
334
						"y" : vakata_context.position_y
335
					}
336
				});
337
			},
338
			_execute : function (i) {
339
				i = vakata_context.items[i];
340
				return i && (!i._disabled || ($.isFunction(i._disabled) && !i._disabled({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }))) && i.action ? i.action.call(null, {
341
							"item"		: i,
342
							"reference"	: vakata_context.reference,
343
							"element"	: vakata_context.element,
344
							"position"	: {
345
								"x" : vakata_context.position_x,
346
								"y" : vakata_context.position_y
347
							}
348
						}) : false;
349
			},
350
			_parse : function (o, is_callback) {
351
				if(!o) { return false; }
352
				if(!is_callback) {
353
					vakata_context.html		= "";
354
					vakata_context.items	= [];
355
				}
356
				var str = "",
357
					sep = false,
358
					tmp;
359
 
360
				if(is_callback) { str += "<"+"ul>"; }
361
				$.each(o, function (i, val) {
362
					if(!val) { return true; }
363
					vakata_context.items.push(val);
364
					if(!sep && val.separator_before) {
365
						str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;<"+"/a><"+"/li>";
366
					}
367
					sep = false;
368
					str += "<"+"li class='" + (val._class || "") + (val._disabled === true || ($.isFunction(val._disabled) && val._disabled({ "item" : val, "reference" : vakata_context.reference, "element" : vakata_context.element })) ? " vakata-contextmenu-disabled " : "") + "' "+(val.shortcut?" data-shortcut='"+val.shortcut+"' ":'')+">";
369
					str += "<"+"a href='#' rel='" + (vakata_context.items.length - 1) + "'>";
370
					if($.vakata.context.settings.icons) {
371
						str += "<"+"i ";
372
						if(val.icon) {
373
							if(val.icon.indexOf("/") !== -1 || val.icon.indexOf(".") !== -1) { str += " style='background:url(\"" + val.icon + "\") center center no-repeat' "; }
374
							else { str += " class='" + val.icon + "' "; }
375
						}
376
						str += "><"+"/i><"+"span class='vakata-contextmenu-sep'>&#160;<"+"/span>";
377
					}
378
					str += ($.isFunction(val.label) ? val.label({ "item" : i, "reference" : vakata_context.reference, "element" : vakata_context.element }) : val.label) + (val.shortcut?' <span class="vakata-contextmenu-shortcut vakata-contextmenu-shortcut-'+val.shortcut+'">'+ (val.shortcut_label || '') +'</span>':'') + "<"+"/a>";
379
					if(val.submenu) {
380
						tmp = $.vakata.context._parse(val.submenu, true);
381
						if(tmp) { str += tmp; }
382
					}
383
					str += "<"+"/li>";
384
					if(val.separator_after) {
385
						str += "<"+"li class='vakata-context-separator'><"+"a href='#' " + ($.vakata.context.settings.icons ? '' : 'style="margin-left:0px;"') + ">&#160;<"+"/a><"+"/li>";
386
						sep = true;
387
					}
388
				});
389
				str  = str.replace(/<li class\='vakata-context-separator'\><\/li\>$/,"");
390
				if(is_callback) { str += "</ul>"; }
391
				/**
392
				 * triggered on the document when the contextmenu is parsed (HTML is built)
393
				 * @event
394
				 * @plugin contextmenu
395
				 * @name context_parse.vakata
396
				 * @param {jQuery} reference the element that was right clicked
397
				 * @param {jQuery} element the DOM element of the menu itself
398
				 * @param {Object} position the x & y coordinates of the menu
399
				 */
400
				if(!is_callback) { vakata_context.html = str; $.vakata.context._trigger("parse"); }
401
				return str.length > 10 ? str : false;
402
			},
403
			_show_submenu : function (o) {
404
				o = $(o);
405
				if(!o.length || !o.children("ul").length) { return; }
406
				var e = o.children("ul"),
407
					x = o.offset().left + o.outerWidth(),
408
					y = o.offset().top,
409
					w = e.width(),
410
					h = e.height(),
411
					dw = $(window).width() + $(window).scrollLeft(),
412
					dh = $(window).height() + $(window).scrollTop();
413
				// може да се спести е една проверка - дали няма някой от класовете вече нагоре
414
				if(right_to_left) {
415
					o[x - (w + 10 + o.outerWidth()) < 0 ? "addClass" : "removeClass"]("vakata-context-left");
416
				}
417
				else {
418
					o[x + w + 10 > dw ? "addClass" : "removeClass"]("vakata-context-right");
419
				}
420
				if(y + h + 10 > dh) {
421
					e.css("bottom","-1px");
422
				}
423
				e.show();
424
			},
425
			show : function (reference, position, data) {
426
				var o, e, x, y, w, h, dw, dh, cond = true;
427
				if(vakata_context.element && vakata_context.element.length) {
428
					vakata_context.element.width('');
429
				}
430
				switch(cond) {
431
					case (!position && !reference):
432
						return false;
433
					case (!!position && !!reference):
434
						vakata_context.reference	= reference;
435
						vakata_context.position_x	= position.x;
436
						vakata_context.position_y	= position.y;
437
						break;
438
					case (!position && !!reference):
439
						vakata_context.reference	= reference;
440
						o = reference.offset();
441
						vakata_context.position_x	= o.left + reference.outerHeight();
442
						vakata_context.position_y	= o.top;
443
						break;
444
					case (!!position && !reference):
445
						vakata_context.position_x	= position.x;
446
						vakata_context.position_y	= position.y;
447
						break;
448
				}
449
				if(!!reference && !data && $(reference).data('vakata_contextmenu')) {
450
					data = $(reference).data('vakata_contextmenu');
451
				}
452
				if($.vakata.context._parse(data)) {
453
					vakata_context.element.html(vakata_context.html);
454
				}
455
				if(vakata_context.items.length) {
456
					vakata_context.element.appendTo("body");
457
					e = vakata_context.element;
458
					x = vakata_context.position_x;
459
					y = vakata_context.position_y;
460
					w = e.width();
461
					h = e.height();
462
					dw = $(window).width() + $(window).scrollLeft();
463
					dh = $(window).height() + $(window).scrollTop();
464
					if(right_to_left) {
465
						x -= (e.outerWidth() - $(reference).outerWidth());
466
						if(x < $(window).scrollLeft() + 20) {
467
							x = $(window).scrollLeft() + 20;
468
						}
469
					}
470
					if(x + w + 20 > dw) {
471
						x = dw - (w + 20);
472
					}
473
					if(y + h + 20 > dh) {
474
						y = dh - (h + 20);
475
					}
476
 
477
					vakata_context.element
478
						.css({ "left" : x, "top" : y })
479
						.show()
480
						.find('a').first().focus().parent().addClass("vakata-context-hover");
481
					vakata_context.is_visible = true;
482
					/**
483
					 * triggered on the document when the contextmenu is shown
484
					 * @event
485
					 * @plugin contextmenu
486
					 * @name context_show.vakata
487
					 * @param {jQuery} reference the element that was right clicked
488
					 * @param {jQuery} element the DOM element of the menu itself
489
					 * @param {Object} position the x & y coordinates of the menu
490
					 */
491
					$.vakata.context._trigger("show");
492
				}
493
			},
494
			hide : function () {
495
				if(vakata_context.is_visible) {
496
					vakata_context.element.hide().find("ul").hide().end().find(':focus').blur().end().detach();
497
					vakata_context.is_visible = false;
498
					/**
499
					 * triggered on the document when the contextmenu is hidden
500
					 * @event
501
					 * @plugin contextmenu
502
					 * @name context_hide.vakata
503
					 * @param {jQuery} reference the element that was right clicked
504
					 * @param {jQuery} element the DOM element of the menu itself
505
					 * @param {Object} position the x & y coordinates of the menu
506
					 */
507
					$.vakata.context._trigger("hide");
508
				}
509
			}
510
		};
511
		$(function () {
512
			right_to_left = $("body").css("direction") === "rtl";
513
			var to = false;
514
 
515
			vakata_context.element = $("<ul class='vakata-context'></ul>");
516
			vakata_context.element
517
				.on("mouseenter", "li", function (e) {
518
					e.stopImmediatePropagation();
519
 
520
					if($.contains(this, e.relatedTarget)) {
521
						// премахнато заради delegate mouseleave по-долу
522
						// $(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
523
						return;
524
					}
525
 
526
					if(to) { clearTimeout(to); }
527
					vakata_context.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end();
528
 
529
					$(this)
530
						.siblings().find("ul").hide().end().end()
531
						.parentsUntil(".vakata-context", "li").addBack().addClass("vakata-context-hover");
532
					$.vakata.context._show_submenu(this);
533
				})
534
				// тестово - дали не натоварва?
535
				.on("mouseleave", "li", function (e) {
536
					if($.contains(this, e.relatedTarget)) { return; }
537
					$(this).find(".vakata-context-hover").addBack().removeClass("vakata-context-hover");
538
				})
539
				.on("mouseleave", function (e) {
540
					$(this).find(".vakata-context-hover").removeClass("vakata-context-hover");
541
					if($.vakata.context.settings.hide_onmouseleave) {
542
						to = setTimeout(
543
							(function (t) {
544
								return function () { $.vakata.context.hide(); };
545
							}(this)), $.vakata.context.settings.hide_onmouseleave);
546
					}
547
				})
548
				.on("click", "a", function (e) {
549
					e.preventDefault();
550
				//})
551
				//.on("mouseup", "a", function (e) {
552
					if(!$(this).blur().parent().hasClass("vakata-context-disabled") && $.vakata.context._execute($(this).attr("rel")) !== false) {
553
						$.vakata.context.hide();
554
					}
555
				})
556
				.on('keydown', 'a', function (e) {
557
						var o = null;
558
						switch(e.which) {
559
							case 13:
560
							case 32:
561
								e.type = "mouseup";
562
								e.preventDefault();
563
								$(e.currentTarget).trigger(e);
564
								break;
565
							case 37:
566
								if(vakata_context.is_visible) {
567
									vakata_context.element.find(".vakata-context-hover").last().closest("li").first().find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover").end().end().children('a').focus();
568
									e.stopImmediatePropagation();
569
									e.preventDefault();
570
								}
571
								break;
572
							case 38:
573
								if(vakata_context.is_visible) {
574
									o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first();
575
									if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").last(); }
576
									o.addClass("vakata-context-hover").children('a').focus();
577
									e.stopImmediatePropagation();
578
									e.preventDefault();
579
								}
580
								break;
581
							case 39:
582
								if(vakata_context.is_visible) {
583
									vakata_context.element.find(".vakata-context-hover").last().children("ul").show().children("li:not(.vakata-context-separator)").removeClass("vakata-context-hover").first().addClass("vakata-context-hover").children('a').focus();
584
									e.stopImmediatePropagation();
585
									e.preventDefault();
586
								}
587
								break;
588
							case 40:
589
								if(vakata_context.is_visible) {
590
									o = vakata_context.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first();
591
									if(!o.length) { o = vakata_context.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").first(); }
592
									o.addClass("vakata-context-hover").children('a').focus();
593
									e.stopImmediatePropagation();
594
									e.preventDefault();
595
								}
596
								break;
597
							case 27:
598
								$.vakata.context.hide();
599
								e.preventDefault();
600
								break;
601
							default:
602
								//console.log(e.which);
603
								break;
604
						}
605
					})
606
				.on('keydown', function (e) {
607
					e.preventDefault();
608
					var a = vakata_context.element.find('.vakata-contextmenu-shortcut-' + e.which).parent();
609
					if(a.parent().not('.vakata-context-disabled')) {
610
						a.click();
611
					}
612
				});
613
 
614
			$(document)
615
				.on("mousedown.vakata.jstree", function (e) {
616
					if(vakata_context.is_visible && !$.contains(vakata_context.element[0], e.target)) {
617
						$.vakata.context.hide();
618
					}
619
				})
620
				.on("context_show.vakata.jstree", function (e, data) {
621
					vakata_context.element.find("li:has(ul)").children("a").addClass("vakata-context-parent");
622
					if(right_to_left) {
623
						vakata_context.element.addClass("vakata-context-rtl").css("direction", "rtl");
624
					}
625
					// also apply a RTL class?
626
					vakata_context.element.find("ul").hide().end();
627
				});
628
		});
629
	}($));
630
	// $.jstree.defaults.plugins.push("contextmenu");
631
}));