Skip to content

Commit 5a49456

Browse files
Fixed "sub menu out of position #533 "
1 parent 8427585 commit 5a49456

8 files changed

+149
-40
lines changed

dist/jquery.contextMenu.css

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Licensed under
1313
* MIT License http://www.opensource.org/licenses/mit-license
1414
*
15-
* Date: 2017-08-30T12:16:04.938Z
15+
* Date: 2017-11-24T17:56:22.439Z
1616
*/
1717
@-webkit-keyframes cm-spin {
1818
0% {
@@ -54,8 +54,8 @@
5454
font-style: normal;
5555
font-weight: normal;
5656

57-
src: url("font/context-menu-icons.eot?1915n");
58-
src: url("font/context-menu-icons.eot?1915n#iefix") format("embedded-opentype"), url("font/context-menu-icons.woff2?1915n") format("woff2"), url("font/context-menu-icons.woff?1915n") format("woff"), url("font/context-menu-icons.ttf?1915n") format("truetype");
57+
src: url("font/context-menu-icons.eot?12di9");
58+
src: url("font/context-menu-icons.eot?12di9#iefix") format("embedded-opentype"), url("font/context-menu-icons.woff2?12di9") format("woff2"), url("font/context-menu-icons.woff?12di9") format("woff"), url("font/context-menu-icons.ttf?12di9") format("truetype");
5959
}
6060

6161
.context-menu-icon-add:before {
@@ -156,8 +156,12 @@
156156
color: #bbb;
157157
}
158158

159+
.context-menu-list.overBoundary, .context-menu-list.overBoundary ul.context-menu-list {
160+
position: fixed !important;
161+
}
162+
159163
.context-menu-list {
160-
position: fixed;
164+
position: absolute;
161165
display: inline-block;
162166
min-width: 13em;
163167
max-width: 26em;

dist/jquery.contextMenu.js

Lines changed: 104 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Licensed under
1212
* MIT License http://www.opensource.org/licenses/mit-license
1313
*
14-
* Date: 2017-08-30T12:16:04.336Z
14+
* Date: 2017-11-24T18:02:43.224Z
1515
*/
1616

1717
// jscs:disable
@@ -116,10 +116,16 @@
116116
// flag denoting if a second trigger should simply move (true) or rebuild (false) an open menu
117117
// as long as the trigger happened on one of the trigger-element's child nodes
118118
reposition: true,
119+
// Flag denoting if a second trigger should close the menu, as long as
120+
// the trigger happened on one of the trigger-element's child nodes.
121+
// This overrides the reposition option.
122+
hideOnSecondTrigger: false,
119123

120124
//ability to select submenu
121125
selectableSubMenu: false,
122126

127+
hasOverboundaryScroll: false,
128+
123129
// Default classname configuration to be able avoid conflicts in frameworks
124130
classNames: {
125131
hover: 'context-menu-hover', // Item hover
@@ -200,7 +206,7 @@
200206
opt.$menu.css(offset);
201207
},
202208
// position the sub-menu
203-
positionSubmenu: function ($menu) {
209+
positionSubmenu: function ($menu, $root) {
204210
if (typeof $menu === 'undefined') {
205211
// When user hovers over item (which has sub items) handle.focusItem will call this.
206212
// but the submenu does not exist yet if opt.items is a promise. just return, will
@@ -217,12 +223,23 @@
217223
collision: 'flipfit fit'
218224
}).css('display', '');
219225
} else {
220-
// determine contextMenu position
221-
var offset = {
222-
top: -9,
223-
left: this.outerWidth() - 5
224-
};
226+
var offset = {};
227+
if($root && $root.hasOverboundaryScroll){
228+
var parentOffset = this.offset();
229+
// determine contextMenu position
230+
offset = {
231+
top: parentOffset.top,
232+
left: parentOffset.left + this.outerWidth()
233+
};
234+
} else {
235+
offset = {
236+
top: -9,
237+
left: this.outerWidth() - 5
238+
};
239+
}
225240
$menu.css(offset);
241+
if ($root && $root.hasOverboundaryScroll)
242+
op.activated($root, $menu);
226243
}
227244
},
228245
// offset to add to zIndex
@@ -236,7 +253,8 @@
236253
// events
237254
events: {
238255
show: $.noop,
239-
hide: $.noop
256+
hide: $.noop,
257+
activated: $.noop
240258
},
241259
// default callback
242260
callback: null,
@@ -471,7 +489,12 @@
471489
$(target).trigger(e);
472490
root.$layer.show();
473491
}
474-
492+
493+
if (root.hideOnSecondTrigger && triggerAction && root.$menu !== null && typeof root.$menu !== 'undefined') {
494+
root.$menu.trigger('contextmenu:hide');
495+
return;
496+
}
497+
475498
if (root.reposition && triggerAction) {
476499
if (document.elementFromPoint) {
477500
if (root.$trigger.is(target)) {
@@ -936,7 +959,7 @@
936959

937960
// position sub-menu - do after show so dumb $.ui.position can keep up
938961
if (opt.$node) {
939-
root.positionSubmenu.call(opt.$node, opt.$menu);
962+
root.positionSubmenu.call(opt.$node, opt.$menu, root);
940963
}
941964
},
942965
// blur <command>
@@ -997,6 +1020,9 @@
9971020
// position and show context menu
9981021
opt.$menu.css(css)[opt.animation.show](opt.animation.duration, function () {
9991022
$trigger.trigger('contextmenu:visible');
1023+
1024+
op.activated(opt,opt.$menu);
1025+
opt.events.activated();
10001026
});
10011027
// make options available and set state
10021028
$trigger
@@ -1104,7 +1130,7 @@
11041130
}
11051131

11061132
// create contextMenu
1107-
opt.$menu = $('<ul class="context-menu-list"></ul>').addClass(opt.className || '').data({
1133+
opt.$menu = $('<ul class="context-menu-list ' + (opt.hasOverboundaryScroll ? 'overBoundary' : '') + '"></ul>').addClass(opt.className || '').data({
11081134
'contextMenu': opt,
11091135
'contextMenuRoot': root
11101136
});
@@ -1521,12 +1547,62 @@
15211547
opt.items = items;
15221548
op.create(opt, root, true); // Create submenu
15231549
op.update(opt, root); // Correctly update position if user is already hovered over menu item
1524-
root.positionSubmenu.call(opt.$node, opt.$menu); // positionSubmenu, will only do anything if user already hovered over menu item that just got new subitems.
1550+
root.positionSubmenu.call(opt.$node, opt.$menu, root); // positionSubmenu, will only do anything if user already hovered over menu item that just got new subitems.
15251551
}
15261552

15271553
// Wait for promise completion. .then(success, error, notify) (we don't track notify). Bind the opt
15281554
// and root to avoid scope problems
15291555
promise.then(completedPromise.bind(this, opt, root), errorPromise.bind(this, opt, root));
1556+
},
1557+
// operation that will run after contextMenu showed on screen
1558+
activated: function(opt,menu){
1559+
if(!opt.hasOverboundaryScroll)
1560+
return;
1561+
var $menu = menu;
1562+
var win = $(window);
1563+
var $menuOffset = $menu.offset();
1564+
var winHeight = win.height();
1565+
var winWidth = win.width();
1566+
var winScrollTop = win.scrollTop();
1567+
var menuHeight = $menu.outerHeight();
1568+
var menuWidth = $menu.outerWidth();
1569+
if(menuHeight > winHeight){
1570+
$menu.css({
1571+
'height': winHeight -
1572+
((parseInt($menu.css('padding-top'))*2)+(parseInt($menu.css('margin-top'))*2))+'px',
1573+
'overflow-x':'hidden',
1574+
'overflow-y':'auto',
1575+
'top':winScrollTop+'px'
1576+
});
1577+
} else if($menuOffset.top < winScrollTop){
1578+
$menu.css({
1579+
'top':'0px'
1580+
});
1581+
} else if($menuOffset.top+menuHeight > winScrollTop + winHeight){
1582+
$menu.css({
1583+
'top':$menuOffset.top - Math.abs((winScrollTop+winHeight)-($menuOffset.top+menuHeight)) -((parseInt($menu.css('padding-top'))*2)+(parseInt($menu.css('margin-top'))*2))+'px'
1584+
});
1585+
}
1586+
if($menuOffset.left + menuWidth > winWidth){
1587+
var newLeftPosition = $menuOffset.left - Math.abs(($menuOffset.left+menuWidth) - winWidth);
1588+
var parent = $menu.parents('ul.context-menu-list').first();
1589+
if(parent.length){
1590+
if(newLeftPosition <= parent.offset().left + parent.outerWidth()
1591+
&& newLeftPosition >= parent.offset().left){
1592+
$menu.css({
1593+
'left':parent.offset().left - $menu.outerWidth() + 'px'
1594+
});
1595+
}else{
1596+
$menu.css({
1597+
'left':$menuOffset.left-Math.abs(($menuOffset.left+menuWidth) - winWidth) + 'px'
1598+
});
1599+
}
1600+
}else{
1601+
$menu.css({
1602+
'left':$menuOffset.left-Math.abs(($menuOffset.left+menuWidth) - winWidth) + 'px'
1603+
});
1604+
}
1605+
}
15301606
}
15311607
};
15321608

@@ -1616,6 +1692,20 @@
16161692
}
16171693

16181694
switch (operation) {
1695+
1696+
case 'update':
1697+
// Updates visibility and such
1698+
if(_hasContext){
1699+
op.update($context);
1700+
} else {
1701+
for(var menu in menus){
1702+
if(menus.hasOwnProperty(menu)){
1703+
op.update(menus[menu]);
1704+
}
1705+
}
1706+
}
1707+
break;
1708+
16191709
case 'create':
16201710
// no selector no joy
16211711
if (!o.selector) {
@@ -1905,7 +1995,7 @@
19051995
disabled: !!$node.attr('disabled'),
19061996
callback: (function () {
19071997
return function () {
1908-
$node.get(0).click()
1998+
$node.get(0).click();
19091999
};
19102000
})()
19112001
};
@@ -1924,7 +2014,7 @@
19242014
icon: $node.attr('icon'),
19252015
callback: (function () {
19262016
return function () {
1927-
$node.get(0).click()
2017+
$node.get(0).click();
19282018
};
19292019
})()
19302020
};

0 commit comments

Comments
 (0)