作者 开飞机的舒克

后台优化

  1 +{"files":["public\\assets\\addons\\bootstrapcontextmenu\\.bower.json","public\\assets\\addons\\bootstrapcontextmenu\\bootstrap-contextmenu.js","public\\assets\\addons\\bootstrapcontextmenu\\bower.json","public\\assets\\addons\\bootstrapcontextmenu\\gulpfile.js","public\\assets\\addons\\bootstrapcontextmenu\\index.html","public\\assets\\addons\\bootstrapcontextmenu\\js\\bootstrap-contextmenu.js","public\\assets\\addons\\bootstrapcontextmenu\\package.json","public\\assets\\addons\\bootstrapcontextmenu\\README.md"],"license":"regular","licenseto":"10789","licensekey":"ZzT6UH5x2GCK9XvS CJV3N5BiJJBv3LeD8j2FwfLarmcaM2RoTZdRqH6bB\/E=","domains":["campus.cn"],"licensecodes":[],"validations":["c51a74160ee0aa6a19729b33d4a9fcdc"]}
  1 +<?php
  2 +
  3 +namespace addons\bootstrapcontextmenu;
  4 +
  5 +use app\common\library\Menu;
  6 +use think\Addons;
  7 +
  8 +/**
  9 + * 插件
  10 + */
  11 +class Bootstrapcontextmenu extends Addons
  12 +{
  13 +
  14 + /**
  15 + * 插件安装方法
  16 + * @return bool
  17 + */
  18 + public function install()
  19 + {
  20 +
  21 + return true;
  22 + }
  23 +
  24 + /**
  25 + * 插件卸载方法
  26 + * @return bool
  27 + */
  28 + public function uninstall()
  29 + {
  30 +
  31 + return true;
  32 + }
  33 +
  34 + /**
  35 + * 插件启用方法
  36 + * @return bool
  37 + */
  38 + public function enable()
  39 + {
  40 +
  41 + return true;
  42 + }
  43 +
  44 + /**
  45 + * 插件禁用方法
  46 + * @return bool
  47 + */
  48 + public function disable()
  49 + {
  50 +
  51 + return true;
  52 + }
  53 +
  54 +}
  1 +require(['../addons/bootstrapcontextmenu/js/bootstrap-contextmenu'], function (undefined) {
  2 + if (Config.controllername == 'index' && Config.actionname == 'index') {
  3 + $("body").append(
  4 + '<div id="context-menu">' +
  5 + '<ul class="dropdown-menu" role="menu">' +
  6 + '<li><a tabindex="-1" data-operate="refresh"><i class="fa fa-refresh fa-fw"></i>刷新</a></li>' +
  7 + '<li><a tabindex="-1" data-operate="refreshTable"><i class="fa fa-table fa-fw"></i>刷新表格</a></li>' +
  8 + '<li><a tabindex="-1" data-operate="close"><i class="fa fa-close fa-fw"></i>关闭</a></li>' +
  9 + '<li><a tabindex="-1" data-operate="closeOther"><i class="fa fa-window-close-o fa-fw"></i>关闭其他</a></li>' +
  10 + '<li class="divider"></li>' +
  11 + '<li><a tabindex="-1" data-operate="closeAll"><i class="fa fa-power-off fa-fw"></i>关闭全部</a></li>' +
  12 + '</ul>' +
  13 + '</div>');
  14 +
  15 + $(".nav-addtabs").contextmenu({
  16 + target: "#context-menu",
  17 + scopes: 'li[role=presentation]',
  18 + onItem: function (e, event) {
  19 + var $element = $(event.target);
  20 + var tab_id = e.attr('id');
  21 + var id = tab_id.substr('tab_'.length);
  22 + var con_id = 'con_' + id;
  23 + switch ($element.data('operate')) {
  24 + case 'refresh':
  25 + $("#" + con_id + " iframe").attr('src', function (i, val) {
  26 + return val;
  27 + });
  28 + break;
  29 + case 'refreshTable':
  30 + try {
  31 + if ($("#" + con_id + " iframe").contents().find(".btn-refresh").size() > 0) {
  32 + $("#" + con_id + " iframe")[0].contentWindow.$(".btn-refresh").trigger("click");
  33 + }
  34 + } catch (e) {
  35 +
  36 + }
  37 + break;
  38 + case 'close':
  39 + if (e.find(".close-tab").length > 0) {
  40 + e.find(".close-tab").click();
  41 + }
  42 + break;
  43 + case 'closeOther':
  44 + e.parent().find("li[role='presentation']").each(function () {
  45 + if ($(this).attr('id') == tab_id) {
  46 + return;
  47 + }
  48 + if ($(this).find(".close-tab").length > 0) {
  49 + $(this).find(".close-tab").click();
  50 + }
  51 + });
  52 + break;
  53 + case 'closeAll':
  54 + e.parent().find("li[role='presentation']").each(function () {
  55 + if ($(this).find(".close-tab").length > 0) {
  56 + $(this).find(".close-tab").click();
  57 + }
  58 + });
  59 + break;
  60 + default:
  61 + break;
  62 + }
  63 + }
  64 + });
  65 + }
  66 + $(document).on('click', function () { // iframe内点击 隐藏菜单
  67 + try {
  68 + top.window.$(".nav-addtabs").contextmenu("closemenu");
  69 + } catch (e) {
  70 + }
  71 + });
  72 +
  73 +});
  1 +<?php
  2 +
  3 +return [];
  1 +<?php
  2 +
  3 +namespace addons\bootstrapcontextmenu\controller;
  4 +
  5 +use think\addons\Controller;
  6 +
  7 +class Index extends Controller
  8 +{
  9 +
  10 + public function index()
  11 + {
  12 + $this->error("当前插件暂无前台页面");
  13 + }
  14 +
  15 +}
  1 +name = bootstrapcontextmenu
  2 +title = 菜单栏右键菜单
  3 +intro = 菜单栏添加右键菜单关闭刷新功能
  4 +author = 张尧嵩
  5 +website = https://www.fastadmin.net
  6 +version = 1.0.1
  7 +state = 1
  8 +url = /addons/bootstrapcontextmenu
  9 +license = regular
  10 +licenseto = 10789
  1 +{
  2 + "name": "bootstrap-contextmenu",
  3 + "main": "bootstrap-contextmenu.js",
  4 + "version": "0.3.4",
  5 + "homepage": "https://github.com/sydcanem/bootstrap-contextmenu",
  6 + "authors": [
  7 + "sydcanem <icqhv.santos@gmail.com>"
  8 + ],
  9 + "description": "Context-menu extension for the Bootstrap framework",
  10 + "keywords": [
  11 + "boostrap",
  12 + "contextmenu"
  13 + ],
  14 + "license": "MIT",
  15 + "ignore": [
  16 + "**/.*",
  17 + "node_modules",
  18 + "bower_components",
  19 + "test",
  20 + "tests"
  21 + ],
  22 + "_release": "0.3.4",
  23 + "_resolution": {
  24 + "type": "version",
  25 + "tag": "0.3.4",
  26 + "commit": "78d4bfd46889c127e3770e00f477a697aa258229"
  27 + },
  28 + "_source": "https://github.com/sydcanem/bootstrap-contextmenu.git",
  29 + "_target": "0.3.4",
  30 + "_originalSource": "bootstrap-contextmenu"
  31 +}
  1 +Bootstrap Context Menu
  2 +======================
  3 +
  4 +A context menu extension of Bootstrap made for everyone's convenience.
  5 +
  6 +See a [demo page] [id].
  7 +[id]:http://sydcanem.github.io/bootstrap-contextmenu/
  8 +
  9 +Installation
  10 +------------
  11 +
  12 +`bower install bootstrap-contextmenu`
  13 +
  14 +Note: Requires bootstrap.css
  15 +
  16 +Usage
  17 +-----
  18 +
  19 +### Via data attributes
  20 +
  21 +Add `data-toggle="context"` to any element that needs a custom context menu and via CSS set `position: relative` to the element.
  22 +
  23 +Point `data-target` attribute to your custom context menu.
  24 +
  25 +`<div class="context" data-toggle="context" data-target="#context-menu"></div>`
  26 +
  27 +### Via Javascript
  28 +
  29 +Call the context menu via JavaScript:
  30 +
  31 +```js
  32 +$('.context').contextmenu({
  33 + target:'#context-menu',
  34 + before: function(e,context) {
  35 + // execute code before context menu if shown
  36 + },
  37 + onItem: function(context,e) {
  38 + // execute on menu item selection
  39 + }
  40 +})
  41 +```
  42 +
  43 +### Options
  44 +
  45 +`target` - is the equivalent of the `data-target` attribute. It identifies the html of the menu that will be displayed.
  46 +
  47 +`before` - is a function that is called before the context menu is displayed. If this function returns false, the context menu will not be displayed. It is passed two parameters,
  48 +
  49 + - `e` - the original event. (You can do an `e.preventDefault()` to cancel the browser event).
  50 + - `context` - the DOM element where right click occured.
  51 +
  52 +`onItem` - is a function that is called when a menu item is clicked. Useful when you want to execute a specific function when an item is clicked. It is passed two parameters,
  53 +
  54 + - `context` - the DOM element where right click occured.
  55 + - `e` - the click event of the menu item, $(e.target) is the item element.
  56 +
  57 +`scopes` - DOM selector for dynamically added context elements. See [issue](https://github.com/sydcanem/bootstrap-contextmenu/issues/56).
  58 +
  59 +### Events
  60 +
  61 +All events are fired at the context's menu. Check out `dropdown` plugin for
  62 +a complete description of events.
  63 +
  64 +- `show.bs.context` - This event fires immediately when the menu is opened.
  65 +- `shown.bs.context` - This event is fired when the dropdown has been made visible to the user.
  66 +- `hide.bs.context` - This event is fired immediately when the hide instance method has been called.
  67 +- `hidden.bs.context` - This event is fired when the dropdown has finished being hidden from the user (will wait for CSS transitions, to complete).
  68 +
  69 +Sample
  70 +
  71 +```js
  72 +$('#myMenu').on('show.bs.context',function () {
  73 + // do something...
  74 +});
  75 +```
  76 +
  77 +Example
  78 +-------
  79 +
  80 +Activate and specify selector for context menu
  81 +
  82 +```js
  83 +$('#main').contextmenu({'target':'#context-menu'});
  84 +```
  85 +
  86 +Activate within a div, but not on spans
  87 +
  88 +```js
  89 +$('#main').contextmenu({
  90 + target: '#context-menu2',
  91 + before: function (e, element, target) {
  92 + e.preventDefault();
  93 + if (e.target.tagName == 'SPAN') {
  94 + e.preventDefault();
  95 + this.closemenu();
  96 + return false;
  97 + }
  98 + return true;
  99 + }
  100 +});
  101 +```
  102 +
  103 +Modify the menu dynamically
  104 +
  105 +```js
  106 +$('#main').contextmenu({
  107 + target: "#myMenu",
  108 + before: function(e) {
  109 + this.getMenu().find("li").eq(2).find('a').html("This was dynamically changed");
  110 + }
  111 +});
  112 +```
  113 +
  114 +Show menu name on selection
  115 +
  116 +```js
  117 +$('#main').contextmenu({
  118 + onItem: function(context, e) {
  119 + alert($(e.target).text());
  120 + }
  121 +});
  122 +```
  123 +
  124 +### Nice to have features:
  125 +
  126 + - Close and open animations
  127 + - Keyboard shortcuts for menus
  128 +
  129 +### License
  130 +MIT
  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)) === false) 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 + if (e) {
  93 + e.stopPropagation();
  94 + }
  95 + }
  96 +
  97 + ,keydown: function(e) {
  98 + if (e.which == 27) this.closemenu(e);
  99 + }
  100 +
  101 + ,before: function(e) {
  102 + return true;
  103 + }
  104 +
  105 + ,onItem: function(e) {
  106 + return true;
  107 + }
  108 +
  109 + ,listen: function () {
  110 + this.$element.on('contextmenu.context.data-api', this.scopes, $.proxy(this.show, this));
  111 + $('html').on('click.context.data-api', $.proxy(this.closemenu, this));
  112 + $('html').on('keydown.context.data-api', $.proxy(this.keydown, this));
  113 + }
  114 +
  115 + ,destroy: function() {
  116 + this.$element.off('.context.data-api').removeData('context');
  117 + $('html').off('.context.data-api');
  118 + }
  119 +
  120 + ,isDisabled: function() {
  121 + return this.$element.hasClass('disabled') ||
  122 + this.$element.attr('disabled');
  123 + }
  124 +
  125 + ,getMenu: function () {
  126 + var selector = this.$element.data('target')
  127 + , $menu;
  128 +
  129 + if (!selector) {
  130 + selector = this.$element.attr('href');
  131 + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
  132 + }
  133 +
  134 + $menu = $(selector);
  135 +
  136 + return $menu && $menu.length ? $menu : this.$element.find(selector);
  137 + }
  138 +
  139 + ,getPosition: function(e, $menu) {
  140 + var mouseX = e.clientX
  141 + , mouseY = e.clientY
  142 + , boundsX = $(window).width()
  143 + , boundsY = $(window).height()
  144 + , menuWidth = $menu.find('.dropdown-menu').outerWidth()
  145 + , menuHeight = $menu.find('.dropdown-menu').outerHeight()
  146 + , tp = {"position":"absolute","z-index":9999}
  147 + , Y, X, parentOffset;
  148 +
  149 + if (mouseY + menuHeight > boundsY) {
  150 + Y = {"top": mouseY - menuHeight + $(window).scrollTop()};
  151 + } else {
  152 + Y = {"top": mouseY + $(window).scrollTop()};
  153 + }
  154 +
  155 + if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {
  156 + X = {"left": mouseX - menuWidth + $(window).scrollLeft()};
  157 + } else {
  158 + X = {"left": mouseX + $(window).scrollLeft()};
  159 + }
  160 +
  161 + // If context-menu's parent is positioned using absolute or relative positioning,
  162 + // the calculated mouse position will be incorrect.
  163 + // Adjust the position of the menu by its offset parent position.
  164 + parentOffset = $menu.offsetParent().offset();
  165 + X.left = X.left - parentOffset.left;
  166 + Y.top = Y.top - parentOffset.top;
  167 +
  168 + return $.extend(tp, Y, X);
  169 + }
  170 +
  171 + };
  172 +
  173 + /* CONTEXT MENU PLUGIN DEFINITION
  174 + * ========================== */
  175 +
  176 + $.fn.contextmenu = function (option,e) {
  177 + return this.each(function () {
  178 + var $this = $(this)
  179 + , data = $this.data('context')
  180 + , options = (typeof option == 'object') && option;
  181 +
  182 + if (!data) $this.data('context', (data = new ContextMenu($this, options)));
  183 + if (typeof option == 'string') data[option].call(data, e);
  184 + });
  185 + };
  186 +
  187 + $.fn.contextmenu.Constructor = ContextMenu;
  188 +
  189 + /* APPLY TO STANDARD CONTEXT MENU ELEMENTS
  190 + * =================================== */
  191 +
  192 + $(document)
  193 + .on('contextmenu.context.data-api', function() {
  194 + $(toggle).each(function () {
  195 + var data = $(this).data('context');
  196 + if (!data) return;
  197 + data.closemenu();
  198 + });
  199 + })
  200 + .on('contextmenu.context.data-api', toggle, function(e) {
  201 + $(this).contextmenu('show', e);
  202 +
  203 + e.preventDefault();
  204 + e.stopPropagation();
  205 + });
  206 +
  207 +}(jQuery));
  1 +{
  2 + "name": "bootstrap-contextmenu",
  3 + "main": "bootstrap-contextmenu.js",
  4 + "version": "0.3.3",
  5 + "homepage": "https://github.com/sydcanem/bootstrap-contextmenu",
  6 + "authors": [
  7 + "sydcanem <icqhv.santos@gmail.com>"
  8 + ],
  9 + "description": "Context-menu extension for the Bootstrap framework",
  10 + "keywords": [
  11 + "boostrap",
  12 + "contextmenu"
  13 + ],
  14 + "license": "MIT",
  15 + "ignore": [
  16 + "**/.*",
  17 + "node_modules",
  18 + "bower_components",
  19 + "test",
  20 + "tests"
  21 + ]
  22 +}
  1 +var gulp = require('gulp'),
  2 + qunit = require('gulp-qunit');
  3 +
  4 +gulp.task('test', function () {
  5 + return gulp.src('./test/qunit.html')
  6 + .pipe(qunit());
  7 +});
  1 +<!DOCTYPE html>
  2 +<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  3 + <meta charset="utf-8">
  4 + <title>Bootstrap</title>
  5 + <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6 + <meta name="description" content="">
  7 + <meta name="author" content="">
  8 +
  9 + <!-- Le styles -->
  10 + <link href="http://cdnjs.cloudflare.com/ajax/libs/prettify/r224/prettify.css" type="text/css">
  11 + <style>
  12 + body {
  13 + padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
  14 + }
  15 + </style>
  16 + <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
  17 +
  18 + <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
  19 + <!--[if lt IE 9]>
  20 + <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
  21 + <![endif]-->
  22 +
  23 + <!-- Le fav and touch icons -->
  24 + </head>
  25 +
  26 + <body onload="prettyPrint()">
  27 +
  28 + <div class="navbar navbar-inverse navbar-fixed-top">
  29 + <div class="navbar-inner">
  30 + <div class="container">
  31 + <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
  32 + <span class="icon-bar"></span>
  33 + <span class="icon-bar"></span>
  34 + <span class="icon-bar"></span>
  35 + </a>
  36 + <a class="brand" href="https://github.com/sydcanem/bootstrap-contextmenu">Context Menu Plugin Extension</a>
  37 + </div>
  38 + </div>
  39 + </div>
  40 +
  41 + <div class="container">
  42 + <div class="span7">
  43 + <h1>Demo</h1>
  44 + <p>Right click inside the box to trigger the menu</p>
  45 +
  46 + <h5>Demo 1</h5>
  47 + <p>Using <code>data-toggle="context"</code> to attach a context-menu</p>
  48 + <!-- Element div that needs a custom context menu -->
  49 + <div id="context" data-toggle="context" data-target="#context-menu" style="height:300px;width:650px;border:1px solid #ddd">
  50 + </div>
  51 +
  52 + <!-- Your custom menu with dropdown-menu as default styling -->
  53 + <div id="context-menu">
  54 + <ul class="dropdown-menu" role="menu">
  55 + <li><a tabindex="-1">Action</a></li>
  56 + <li><a tabindex="-1">Another action</a></li>
  57 + <li><a tabindex="-1">Something else here</a></li>
  58 + <li class="divider"></li>
  59 + <li><a tabindex="-1">Separated link</a></li>
  60 + </ul>
  61 + </div>
  62 +
  63 + <h5>Demo 2</h5>
  64 + <div id="main" data-toggle="context">This is an area where the context menu is active <span style="background-color: #cecece">However, we wont allow it here.</span> But anywhere else in this text should be perfectly fine. This one is started with only javascript</div>
  65 +
  66 + <div id="context-menu2">
  67 + <ul class="dropdown-menu" role="menu">
  68 + <li><a tabindex="-1">Action</a></li>
  69 + <li><a tabindex="-1">Another action</a></li>
  70 + <li><a tabindex="-1">Something else here</a></li>
  71 + <li class="divider"></li>
  72 + <li><a tabindex="-1">Separated link</a></li>
  73 + </ul>
  74 + </div>
  75 +
  76 + <h5>Demo 3</h5>
  77 + <p>Show the menu name of the item that was selected</p>
  78 + <!-- Element div that needs a custom context menu -->
  79 + <div id="context2" data-toggle="context" style="height:300px;width:650px;border:1px solid #ddd">
  80 + </div>
  81 +
  82 + <h2>Usage</h2>
  83 + <h3>Via data attributes</h3>
  84 + <p>Add <code>data-toggle="context"</code> to an element that needs a context menu.</p>
  85 + <pre class="prettyprint linenums">
  86 +&lt;div id="context" data-toggle="context" data-target="#context-menu"&gt;
  87 + ...
  88 +&lt;/div&gt;</pre>
  89 + <p>Your menu <code>&lt;ul&gt;</code> element must have a <code>dropdown-menu</code> class.
  90 + <pre class="prettyprint linenums">
  91 +&lt;div id="context-menu"&gt;
  92 + &lt;ul class="dropdown-menu" role="menu"&gt;
  93 + &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Action&lt;/a&gt;&lt;/li&gt;
  94 + ...
  95 + &lt;li&gt;&lt;a tabindex="-1" href="#"&gt;Separated link&lt;/a&gt;&lt;/li&gt;
  96 + &lt;/ul&gt;
  97 +&lt;/div&gt;</pre>
  98 + <h3>Via Javascript</h3>
  99 + <p>Call the context menus via Javascript:</p>
  100 + <pre class="prettyprint linenums">
  101 +$('.context').contextmenu();</pre>
  102 + </div> <!-- /container -->
  103 +
  104 +
  105 + <!-- Le javascript
  106 + ================================================== -->
  107 + <!-- Placed at the end of the document so the pages load faster -->
  108 + <script src="http://codeorigin.jquery.com/jquery-1.10.2.min.js"></script>
  109 + <script src="bootstrap-contextmenu.js"></script>
  110 + <script src="http://cdnjs.cloudflare.com/ajax/libs/prettify/r224/prettify.js"></script>
  111 + <script type="text/javascript">
  112 + // Demo 2
  113 + $('#main').contextmenu({
  114 + target: '#context-menu2',
  115 + before: function (e) {
  116 + // This function is optional.
  117 + // Here we use it to stop the event if the user clicks a span
  118 + e.preventDefault();
  119 + if (e.target.tagName == 'SPAN') {
  120 + e.preventDefault();
  121 + this.closemenu();
  122 + return false;
  123 + }
  124 + this.getMenu().find("li").eq(2).find('a').html("This was dynamically changed");
  125 + return true;
  126 + }
  127 + });
  128 + </script>
  129 + <script type="text/javascript">
  130 + // Demo 3
  131 + $('#context2').contextmenu({
  132 + target: '#context-menu2',
  133 + onItem: function (context, e) {
  134 + alert($(e.target).text());
  135 + }
  136 + });
  137 +
  138 + $('#context-menu2').on('show.bs.context', function (e) {
  139 + console.log('before show event');
  140 + });
  141 +
  142 + $('#context-menu2').on('shown.bs.context', function (e) {
  143 + console.log('after show event');
  144 + });
  145 +
  146 + $('#context-menu2').on('hide.bs.context', function (e) {
  147 + console.log('before hide event');
  148 + });
  149 +
  150 + $('#context-menu2').on('hidden.bs.context', function (e) {
  151 + console.log('after hide event');
  152 + });
  153 + </script>
  154 +</body></html>
  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)) === false) 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 + if (e) {
  93 + e.stopPropagation();
  94 + }
  95 + }
  96 +
  97 + ,keydown: function(e) {
  98 + if (e.which == 27) this.closemenu(e);
  99 + }
  100 +
  101 + ,before: function(e) {
  102 + return true;
  103 + }
  104 +
  105 + ,onItem: function(e) {
  106 + return true;
  107 + }
  108 +
  109 + ,listen: function () {
  110 + this.$element.on('contextmenu.context.data-api', this.scopes, $.proxy(this.show, this));
  111 + $('html').on('click.context.data-api', $.proxy(this.closemenu, this));
  112 + $('html').on('keydown.context.data-api', $.proxy(this.keydown, this));
  113 + }
  114 +
  115 + ,destroy: function() {
  116 + this.$element.off('.context.data-api').removeData('context');
  117 + $('html').off('.context.data-api');
  118 + }
  119 +
  120 + ,isDisabled: function() {
  121 + return this.$element.hasClass('disabled') ||
  122 + this.$element.attr('disabled');
  123 + }
  124 +
  125 + ,getMenu: function () {
  126 + var selector = this.$element.data('target')
  127 + , $menu;
  128 +
  129 + if (!selector) {
  130 + selector = this.$element.attr('href');
  131 + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
  132 + }
  133 +
  134 + $menu = $(selector);
  135 +
  136 + return $menu && $menu.length ? $menu : this.$element.find(selector);
  137 + }
  138 +
  139 + ,getPosition: function(e, $menu) {
  140 + var mouseX = e.clientX
  141 + , mouseY = e.clientY
  142 + , boundsX = $(window).width()
  143 + , boundsY = $(window).height()
  144 + , menuWidth = $menu.find('.dropdown-menu').outerWidth()
  145 + , menuHeight = $menu.find('.dropdown-menu').outerHeight()
  146 + , tp = {"position":"absolute","z-index":9999}
  147 + , Y, X, parentOffset;
  148 +
  149 + if (mouseY + menuHeight > boundsY) {
  150 + Y = {"top": mouseY - menuHeight + $(window).scrollTop()};
  151 + } else {
  152 + Y = {"top": mouseY + $(window).scrollTop()};
  153 + }
  154 +
  155 + if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {
  156 + X = {"left": mouseX - menuWidth + $(window).scrollLeft()};
  157 + } else {
  158 + X = {"left": mouseX + $(window).scrollLeft()};
  159 + }
  160 +
  161 + // If context-menu's parent is positioned using absolute or relative positioning,
  162 + // the calculated mouse position will be incorrect.
  163 + // Adjust the position of the menu by its offset parent position.
  164 + parentOffset = $menu.offsetParent().offset();
  165 + X.left = X.left - parentOffset.left;
  166 + Y.top = Y.top - parentOffset.top;
  167 +
  168 + return $.extend(tp, Y, X);
  169 + }
  170 +
  171 + };
  172 +
  173 + /* CONTEXT MENU PLUGIN DEFINITION
  174 + * ========================== */
  175 +
  176 + $.fn.contextmenu = function (option,e) {
  177 + return this.each(function () {
  178 + var $this = $(this)
  179 + , data = $this.data('context')
  180 + , options = (typeof option == 'object') && option;
  181 +
  182 + if (!data) $this.data('context', (data = new ContextMenu($this, options)));
  183 + if (typeof option == 'string') data[option].call(data, e);
  184 + });
  185 + };
  186 +
  187 + $.fn.contextmenu.Constructor = ContextMenu;
  188 +
  189 + /* APPLY TO STANDARD CONTEXT MENU ELEMENTS
  190 + * =================================== */
  191 +
  192 + $(document)
  193 + .on('contextmenu.context.data-api', function() {
  194 + $(toggle).each(function () {
  195 + var data = $(this).data('context');
  196 + if (!data) return;
  197 + data.closemenu();
  198 + });
  199 + })
  200 + .on('contextmenu.context.data-api', toggle, function(e) {
  201 + $(this).contextmenu('show', e);
  202 +
  203 + e.preventDefault();
  204 + e.stopPropagation();
  205 + });
  206 +
  207 +}(jQuery));
  1 +{
  2 + "name": "bootstrap-contextmenu",
  3 + "version": "0.3.4",
  4 + "description": "Context-menu extension for the Bootstrap framework",
  5 + "main": "bootstrap-contextmenu.js",
  6 + "directories": {
  7 + "test": "test"
  8 + },
  9 + "scripts": {
  10 + "test": "gulp test"
  11 + },
  12 + "repository": {
  13 + "type": "git",
  14 + "url": "git://github.com/sydcanem/bootstrap-contextmenu.git"
  15 + },
  16 + "keywords": [
  17 + "bootstrap"
  18 + ],
  19 + "author": "James Santos",
  20 + "license": "MIT",
  21 + "bugs": {
  22 + "url": "https://github.com/sydcanem/bootstrap-contextmenu/issues"
  23 + },
  24 + "homepage": "https://github.com/sydcanem/bootstrap-contextmenu",
  25 + "devDependencies": {
  26 + "gulp": "^3.6.0",
  27 + "gulp-qunit": "^0.3.3"
  28 + }
  29 +}