| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 | /*! * Bootstrap Context Menu * Author: @sydcanem * https://github.com/sydcanem/bootstrap-contextmenu * * Inspired by Bootstrap's dropdown plugin. * Bootstrap (http://getbootstrap.com). * * Licensed under MIT * ========================================================= */;(function($) {	'use strict';	/* CONTEXTMENU CLASS DEFINITION	 * ============================ */	var toggle = '[data-toggle="context"]';	var ContextMenu = function (element, options) {		this.$element = $(element);		this.before = options.before || this.before;		this.onItem = options.onItem || this.onItem;		this.scopes = options.scopes || null;		if (options.target) {			this.$element.data('target', options.target);		}		this.listen();	};	ContextMenu.prototype = {		constructor: ContextMenu		,show: function(e) {			var $menu				, evt				, tp				, items				, relatedTarget = { relatedTarget: this, target: e.currentTarget };			if (this.isDisabled()) return;			this.closemenu();			if (this.before.call(this,e,$(e.currentTarget)) === false) return;			$menu = this.getMenu();			$menu.trigger(evt = $.Event('show.bs.context', relatedTarget));			tp = this.getPosition(e, $menu);			items = 'li:not(.divider)';			$menu.attr('style', '')				.css(tp)				.addClass('open')				.on('click.context.data-api', items, $.proxy(this.onItem, this, $(e.currentTarget)))				.trigger('shown.bs.context', relatedTarget);			// Delegating the `closemenu` only on the currently opened menu.			// This prevents other opened menus from closing.			$('html')				.on('click.context.data-api', $menu.selector, $.proxy(this.closemenu, this));			return false;		}		,closemenu: function(e) {			var $menu				, evt				, items				, relatedTarget;			$menu = this.getMenu();			if(!$menu.hasClass('open')) return;			relatedTarget = { relatedTarget: this };			$menu.trigger(evt = $.Event('hide.bs.context', relatedTarget));			items = 'li:not(.divider)';			$menu.removeClass('open')				.off('click.context.data-api', items)				.trigger('hidden.bs.context', relatedTarget);			$('html')				.off('click.context.data-api', $menu.selector);			// Don't propagate click event so other currently			// opened menus won't close.			if (e) {				e.stopPropagation();			}		}		,keydown: function(e) {			if (e.which == 27) this.closemenu(e);		}		,before: function(e) {			return true;		}		,onItem: function(e) {			return true;		}		,listen: function () {			this.$element.on('contextmenu.context.data-api', this.scopes, $.proxy(this.show, this));			$('html').on('click.context.data-api', $.proxy(this.closemenu, this));			$('html').on('keydown.context.data-api', $.proxy(this.keydown, this));		}		,destroy: function() {			this.$element.off('.context.data-api').removeData('context');			$('html').off('.context.data-api');		}		,isDisabled: function() {			return this.$element.hasClass('disabled') || 					this.$element.attr('disabled');		}		,getMenu: function () {			var selector = this.$element.data('target')				, $menu;			if (!selector) {				selector = this.$element.attr('href');				selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7			}			$menu = $(selector);			return $menu && $menu.length ? $menu : this.$element.find(selector);		}		,getPosition: function(e, $menu) {			var mouseX = e.clientX				, mouseY = e.clientY				, boundsX = $(window).width()				, boundsY = $(window).height()				, menuWidth = $menu.find('.dropdown-menu').outerWidth()				, menuHeight = $menu.find('.dropdown-menu').outerHeight()				, tp = {"position":"absolute","z-index":9999}				, Y, X, parentOffset;			if (mouseY + menuHeight > boundsY) {				Y = {"top": mouseY - menuHeight + $(window).scrollTop()};			} else {				Y = {"top": mouseY + $(window).scrollTop()};			}			if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {				X = {"left": mouseX - menuWidth + $(window).scrollLeft()};			} else {				X = {"left": mouseX + $(window).scrollLeft()};			}			// If context-menu's parent is positioned using absolute or relative positioning,			// the calculated mouse position will be incorrect.			// Adjust the position of the menu by its offset parent position.			parentOffset = $menu.offsetParent().offset();			X.left = X.left - parentOffset.left;			Y.top = Y.top - parentOffset.top; 			return $.extend(tp, Y, X);		}	};	/* CONTEXT MENU PLUGIN DEFINITION	 * ========================== */	$.fn.contextmenu = function (option,e) {		return this.each(function () {			var $this = $(this)				, data = $this.data('context')				, options = (typeof option == 'object') && option;			if (!data) $this.data('context', (data = new ContextMenu($this, options)));			if (typeof option == 'string') data[option].call(data, e);		});	};	$.fn.contextmenu.Constructor = ContextMenu;	/* APPLY TO STANDARD CONTEXT MENU ELEMENTS	 * =================================== */	$(document)	   .on('contextmenu.context.data-api', function() {			$(toggle).each(function () {				var data = $(this).data('context');				if (!data) return;				data.closemenu();			});		})		.on('contextmenu.context.data-api', toggle, function(e) {			$(this).contextmenu('show', e);			e.preventDefault();			e.stopPropagation();		});		}(jQuery));
 |