正在显示
14 个修改的文件
包含
943 行增加
和
0 行删除
addons/bootstrapcontextmenu/.addonrc
0 → 100644
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 | +} |
addons/bootstrapcontextmenu/bootstrap.js
0 → 100644
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 | +}); |
addons/bootstrapcontextmenu/config.php
0 → 100644
addons/bootstrapcontextmenu/info.ini
0 → 100644
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 | +<!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 | +<div id="context" data-toggle="context" data-target="#context-menu"> | ||
87 | + ... | ||
88 | +</div></pre> | ||
89 | + <p>Your menu <code><ul></code> element must have a <code>dropdown-menu</code> class. | ||
90 | + <pre class="prettyprint linenums"> | ||
91 | +<div id="context-menu"> | ||
92 | + <ul class="dropdown-menu" role="menu"> | ||
93 | + <li><a tabindex="-1" href="#">Action</a></li> | ||
94 | + ... | ||
95 | + <li><a tabindex="-1" href="#">Separated link</a></li> | ||
96 | + </ul> | ||
97 | +</div></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 | +} |
-
请 注册 或 登录 后发表评论