mirror of
https://github.com/HeyPuter/puter
synced 2024-11-14 22:06:00 +00:00
We officially have one of the best web-based Context Menus
This commit is contained in:
parent
1904b92a9d
commit
1d083efb67
@ -17,6 +17,335 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* menu-aim is a jQuery plugin for dropdown menus that can differentiate
|
||||
* between a user trying hover over a dropdown item vs trying to navigate into
|
||||
* a submenu's contents.
|
||||
*
|
||||
* menu-aim assumes that you have are using a menu with submenus that expand
|
||||
* to the menu's right. It will fire events when the user's mouse enters a new
|
||||
* dropdown item *and* when that item is being intentionally hovered over.
|
||||
*
|
||||
* __________________________
|
||||
* | Monkeys >| Gorilla |
|
||||
* | Gorillas >| Content |
|
||||
* | Chimps >| Here |
|
||||
* |___________|____________|
|
||||
*
|
||||
* In the above example, "Gorillas" is selected and its submenu content is
|
||||
* being shown on the right. Imagine that the user's cursor is hovering over
|
||||
* "Gorillas." When they move their mouse into the "Gorilla Content" area, they
|
||||
* may briefly hover over "Chimps." This shouldn't close the "Gorilla Content"
|
||||
* area.
|
||||
*
|
||||
* This problem is normally solved using timeouts and delays. menu-aim tries to
|
||||
* solve this by detecting the direction of the user's mouse movement. This can
|
||||
* make for quicker transitions when navigating up and down the menu. The
|
||||
* experience is hopefully similar to amazon.com/'s "Shop by Department"
|
||||
* dropdown.
|
||||
*
|
||||
* Use like so:
|
||||
*
|
||||
* $("#menu").menuAim({
|
||||
* activate: $.noop, // fired on row activation
|
||||
* deactivate: $.noop // fired on row deactivation
|
||||
* });
|
||||
*
|
||||
* ...to receive events when a menu's row has been purposefully (de)activated.
|
||||
*
|
||||
* The following options can be passed to menuAim. All functions execute with
|
||||
* the relevant row's HTML element as the execution context ('this'):
|
||||
*
|
||||
* .menuAim({
|
||||
* // Function to call when a row is purposefully activated. Use this
|
||||
* // to show a submenu's content for the activated row.
|
||||
* activate: function() {},
|
||||
*
|
||||
* // Function to call when a row is deactivated.
|
||||
* deactivate: function() {},
|
||||
*
|
||||
* // Function to call when mouse enters a menu row. Entering a row
|
||||
* // does not mean the row has been activated, as the user may be
|
||||
* // mousing over to a submenu.
|
||||
* enter: function() {},
|
||||
*
|
||||
* // Function to call when mouse exits a menu row.
|
||||
* exit: function() {},
|
||||
*
|
||||
* // Selector for identifying which elements in the menu are rows
|
||||
* // that can trigger the above events. Defaults to "> li".
|
||||
* rowSelector: "> li",
|
||||
*
|
||||
* // You may have some menu rows that aren't submenus and therefore
|
||||
* // shouldn't ever need to "activate." If so, filter submenu rows w/
|
||||
* // this selector. Defaults to "*" (all elements).
|
||||
* submenuSelector: "*",
|
||||
*
|
||||
* // Direction the submenu opens relative to the main menu. Can be
|
||||
* // left, right, above, or below. Defaults to "right".
|
||||
* submenuDirection: "right"
|
||||
* });
|
||||
*
|
||||
* https://github.com/kamens/jQuery-menu-aim
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
$.fn.menuAim = function (opts) {
|
||||
// Initialize menu-aim for all elements in jQuery collection
|
||||
this.each(function () {
|
||||
init.call(this, opts);
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
function init(opts) {
|
||||
var $menu = $(this),
|
||||
activeRow = null,
|
||||
mouseLocs = [],
|
||||
lastDelayLoc = null,
|
||||
timeoutId = null,
|
||||
options = $.extend({
|
||||
rowSelector: "> li",
|
||||
submenuSelector: "*",
|
||||
submenuDirection: $.noop,
|
||||
tolerance: 75, // bigger = more forgivey when entering submenu
|
||||
enter: $.noop,
|
||||
exit: $.noop,
|
||||
activate: $.noop,
|
||||
deactivate: $.noop,
|
||||
exitMenu: $.noop
|
||||
}, opts);
|
||||
|
||||
var MOUSE_LOCS_TRACKED = 3, // number of past mouse locations to track
|
||||
DELAY = 300; // ms delay when user appears to be entering submenu
|
||||
|
||||
/**
|
||||
* Keep track of the last few locations of the mouse.
|
||||
*/
|
||||
var mousemoveDocument = function (e) {
|
||||
mouseLocs.push({ x: e.pageX, y: e.pageY });
|
||||
|
||||
if (mouseLocs.length > MOUSE_LOCS_TRACKED) {
|
||||
mouseLocs.shift();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel possible row activations when leaving the menu entirely
|
||||
*/
|
||||
var mouseleaveMenu = function () {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
// If exitMenu is supplied and returns true, deactivate the
|
||||
// currently active row on menu exit.
|
||||
if (options.exitMenu(this)) {
|
||||
if (activeRow) {
|
||||
options.deactivate(activeRow);
|
||||
}
|
||||
|
||||
activeRow = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger a possible row activation whenever entering a new row.
|
||||
*/
|
||||
var mouseenterRow = function () {
|
||||
if (timeoutId) {
|
||||
// Cancel any previous activation delays
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
options.enter(this);
|
||||
possiblyActivate(this);
|
||||
},
|
||||
mouseleaveRow = function () {
|
||||
options.exit(this);
|
||||
};
|
||||
|
||||
/*
|
||||
* Immediately activate a row if the user clicks on it.
|
||||
*/
|
||||
var clickRow = function () {
|
||||
activate(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Activate a menu row.
|
||||
*/
|
||||
var activate = function (row) {
|
||||
if (row == activeRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeRow) {
|
||||
options.deactivate(activeRow);
|
||||
}
|
||||
|
||||
|
||||
options.activate(row);
|
||||
activeRow = row;
|
||||
};
|
||||
|
||||
/**
|
||||
* Possibly activate a menu row. If mouse movement indicates that we
|
||||
* shouldn't activate yet because user may be trying to enter
|
||||
* a submenu's content, then delay and check again later.
|
||||
*/
|
||||
var possiblyActivate = function (row) {
|
||||
var delay = activationDelay();
|
||||
|
||||
if (delay) {
|
||||
timeoutId = setTimeout(function () {
|
||||
possiblyActivate(row);
|
||||
}, delay);
|
||||
} else {
|
||||
activate(row);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the amount of time that should be used as a delay before the
|
||||
* currently hovered row is activated.
|
||||
*
|
||||
* Returns 0 if the activation should happen immediately. Otherwise,
|
||||
* returns the number of milliseconds that should be delayed before
|
||||
* checking again to see if the row should be activated.
|
||||
*/
|
||||
var activationDelay = function () {
|
||||
if (!activeRow || !$(activeRow).is(options.submenuSelector)) {
|
||||
// If there is no other submenu row already active, then
|
||||
// go ahead and activate immediately.
|
||||
return 0;
|
||||
}
|
||||
|
||||
var offset = $menu.offset(),
|
||||
upperLeft = {
|
||||
x: offset.left,
|
||||
y: offset.top - options.tolerance
|
||||
},
|
||||
upperRight = {
|
||||
x: offset.left + $menu.outerWidth(),
|
||||
y: upperLeft.y
|
||||
},
|
||||
lowerLeft = {
|
||||
x: offset.left,
|
||||
y: offset.top + $menu.outerHeight() + options.tolerance
|
||||
},
|
||||
lowerRight = {
|
||||
x: offset.left + $menu.outerWidth(),
|
||||
y: lowerLeft.y
|
||||
},
|
||||
loc = mouseLocs[mouseLocs.length - 1],
|
||||
prevLoc = mouseLocs[0];
|
||||
|
||||
if (!loc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!prevLoc) {
|
||||
prevLoc = loc;
|
||||
}
|
||||
|
||||
if (prevLoc.x < offset.left || prevLoc.x > lowerRight.x ||
|
||||
prevLoc.y < offset.top || prevLoc.y > lowerRight.y) {
|
||||
// If the previous mouse location was outside of the entire
|
||||
// menu's bounds, immediately activate.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastDelayLoc &&
|
||||
loc.x == lastDelayLoc.x && loc.y == lastDelayLoc.y) {
|
||||
// If the mouse hasn't moved since the last time we checked
|
||||
// for activation status, immediately activate.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Detect if the user is moving towards the currently activated
|
||||
// submenu.
|
||||
//
|
||||
// If the mouse is heading relatively clearly towards
|
||||
// the submenu's content, we should wait and give the user more
|
||||
// time before activating a new row. If the mouse is heading
|
||||
// elsewhere, we can immediately activate a new row.
|
||||
//
|
||||
// We detect this by calculating the slope formed between the
|
||||
// current mouse location and the upper/lower right points of
|
||||
// the menu. We do the same for the previous mouse location.
|
||||
// If the current mouse location's slopes are
|
||||
// increasing/decreasing appropriately compared to the
|
||||
// previous's, we know the user is moving toward the submenu.
|
||||
//
|
||||
// Note that since the y-axis increases as the cursor moves
|
||||
// down the screen, we are looking for the slope between the
|
||||
// cursor and the upper right corner to decrease over time, not
|
||||
// increase (somewhat counterintuitively).
|
||||
function slope(a, b) {
|
||||
return (b.y - a.y) / (b.x - a.x);
|
||||
};
|
||||
|
||||
var decreasingCorner = upperRight,
|
||||
increasingCorner = lowerRight;
|
||||
|
||||
// Our expectations for decreasing or increasing slope values
|
||||
// depends on which direction the submenu opens relative to the
|
||||
// main menu. By default, if the menu opens on the right, we
|
||||
// expect the slope between the cursor and the upper right
|
||||
// corner to decrease over time, as explained above. If the
|
||||
// submenu opens in a different direction, we change our slope
|
||||
// expectations.
|
||||
if (options.submenuDirection() == "left") {
|
||||
decreasingCorner = lowerLeft;
|
||||
increasingCorner = upperLeft;
|
||||
} else if (options.submenuDirection() == "below") {
|
||||
decreasingCorner = lowerRight;
|
||||
increasingCorner = lowerLeft;
|
||||
} else if (options.submenuDirection() == "above") {
|
||||
decreasingCorner = upperLeft;
|
||||
increasingCorner = upperRight;
|
||||
}
|
||||
|
||||
var decreasingSlope = slope(loc, decreasingCorner),
|
||||
increasingSlope = slope(loc, increasingCorner),
|
||||
prevDecreasingSlope = slope(prevLoc, decreasingCorner),
|
||||
prevIncreasingSlope = slope(prevLoc, increasingCorner);
|
||||
|
||||
if (decreasingSlope < prevDecreasingSlope &&
|
||||
increasingSlope > prevIncreasingSlope) {
|
||||
// Mouse is moving from previous location towards the
|
||||
// currently activated submenu. Delay before activating a
|
||||
// new menu row, because user may be moving into submenu.
|
||||
lastDelayLoc = loc;
|
||||
return DELAY;
|
||||
}
|
||||
|
||||
lastDelayLoc = null;
|
||||
return 0;
|
||||
};
|
||||
|
||||
$menu.on('mouseenter', function(e) {
|
||||
if($menu.find('.context-menu-item-active').length === 0 && $menu.find('.has-open-context-menu-submenu').length === 0)
|
||||
activeRow = null;
|
||||
})
|
||||
/**
|
||||
* Hook up initial menu events
|
||||
*/
|
||||
$menu
|
||||
.mouseleave(mouseleaveMenu)
|
||||
.find(options.rowSelector)
|
||||
.mouseenter(mouseenterRow)
|
||||
.mouseleave(mouseleaveRow)
|
||||
.click(clickRow);
|
||||
|
||||
$(document).mousemove(mousemoveDocument);
|
||||
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
function UIContextMenu(options){
|
||||
$('.window-active .window-app-iframe').css('pointer-events', 'none');
|
||||
|
||||
@ -184,8 +513,9 @@ function UIContextMenu(options){
|
||||
// just passing over the item, the submenu doesn't open immediately.
|
||||
let submenu_delay_timer;
|
||||
|
||||
// Initialize the menuAim plugin (../libs/jquery.menu-aim.js)
|
||||
// Initialize the menuAim plugin
|
||||
$(contextMenu).menuAim({
|
||||
rowSelector: ".context-menu-item",
|
||||
submenuSelector: ".context-menu-item-submenu",
|
||||
submenuDirection: function(){
|
||||
// If not submenu
|
||||
@ -198,6 +528,10 @@ function UIContextMenu(options){
|
||||
}
|
||||
}
|
||||
},
|
||||
enter: function (e) {
|
||||
// activate items
|
||||
// this.activate(e);
|
||||
},
|
||||
// activates item when mouse enters depending on mouse position and direction
|
||||
activate: function (e) {
|
||||
// activate items
|
||||
@ -258,6 +592,7 @@ function UIContextMenu(options){
|
||||
// remove `has-open-context-menu-submenu` class from the parent menu item
|
||||
$(e).removeClass('has-open-context-menu-submenu');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@ -307,6 +642,14 @@ function UIContextMenu(options){
|
||||
return false;
|
||||
})
|
||||
|
||||
$(contextMenu).on("mouseleave", function (e) {
|
||||
$(contextMenu).find('.context-menu-item').removeClass('context-menu-item-active');
|
||||
clearTimeout(submenu_delay_timer);
|
||||
})
|
||||
|
||||
$(contextMenu).on("mouseenter", function (e) {
|
||||
})
|
||||
|
||||
return {
|
||||
cancel: (cancel_options) => {
|
||||
cancel_options_ = cancel_options;
|
||||
@ -344,7 +687,14 @@ $(document).on('mouseenter', '.context-menu', function(e){
|
||||
})
|
||||
|
||||
$(document).on('mouseenter', '.context-menu-item', function(e){
|
||||
select_ctxmenu_item(this);
|
||||
// select_ctxmenu_item(this);
|
||||
})
|
||||
|
||||
$(document).on('mouseenter', '.context-menu-divider', function(e){
|
||||
// unselect all items
|
||||
$(this).siblings('.context-menu-item:not(.has-open-context-menu-submenu)').removeClass('context-menu-item-active');
|
||||
})
|
||||
|
||||
$(document)
|
||||
|
||||
export default UIContextMenu;
|
@ -1,323 +0,0 @@
|
||||
/**
|
||||
* menu-aim is a jQuery plugin for dropdown menus that can differentiate
|
||||
* between a user trying hover over a dropdown item vs trying to navigate into
|
||||
* a submenu's contents.
|
||||
*
|
||||
* menu-aim assumes that you have are using a menu with submenus that expand
|
||||
* to the menu's right. It will fire events when the user's mouse enters a new
|
||||
* dropdown item *and* when that item is being intentionally hovered over.
|
||||
*
|
||||
* __________________________
|
||||
* | Monkeys >| Gorilla |
|
||||
* | Gorillas >| Content |
|
||||
* | Chimps >| Here |
|
||||
* |___________|____________|
|
||||
*
|
||||
* In the above example, "Gorillas" is selected and its submenu content is
|
||||
* being shown on the right. Imagine that the user's cursor is hovering over
|
||||
* "Gorillas." When they move their mouse into the "Gorilla Content" area, they
|
||||
* may briefly hover over "Chimps." This shouldn't close the "Gorilla Content"
|
||||
* area.
|
||||
*
|
||||
* This problem is normally solved using timeouts and delays. menu-aim tries to
|
||||
* solve this by detecting the direction of the user's mouse movement. This can
|
||||
* make for quicker transitions when navigating up and down the menu. The
|
||||
* experience is hopefully similar to amazon.com/'s "Shop by Department"
|
||||
* dropdown.
|
||||
*
|
||||
* Use like so:
|
||||
*
|
||||
* $("#menu").menuAim({
|
||||
* activate: $.noop, // fired on row activation
|
||||
* deactivate: $.noop // fired on row deactivation
|
||||
* });
|
||||
*
|
||||
* ...to receive events when a menu's row has been purposefully (de)activated.
|
||||
*
|
||||
* The following options can be passed to menuAim. All functions execute with
|
||||
* the relevant row's HTML element as the execution context ('this'):
|
||||
*
|
||||
* .menuAim({
|
||||
* // Function to call when a row is purposefully activated. Use this
|
||||
* // to show a submenu's content for the activated row.
|
||||
* activate: function() {},
|
||||
*
|
||||
* // Function to call when a row is deactivated.
|
||||
* deactivate: function() {},
|
||||
*
|
||||
* // Function to call when mouse enters a menu row. Entering a row
|
||||
* // does not mean the row has been activated, as the user may be
|
||||
* // mousing over to a submenu.
|
||||
* enter: function() {},
|
||||
*
|
||||
* // Function to call when mouse exits a menu row.
|
||||
* exit: function() {},
|
||||
*
|
||||
* // Selector for identifying which elements in the menu are rows
|
||||
* // that can trigger the above events. Defaults to "> li".
|
||||
* rowSelector: "> li",
|
||||
*
|
||||
* // You may have some menu rows that aren't submenus and therefore
|
||||
* // shouldn't ever need to "activate." If so, filter submenu rows w/
|
||||
* // this selector. Defaults to "*" (all elements).
|
||||
* submenuSelector: "*",
|
||||
*
|
||||
* // Direction the submenu opens relative to the main menu. Can be
|
||||
* // left, right, above, or below. Defaults to "right".
|
||||
* submenuDirection: "right"
|
||||
* });
|
||||
*
|
||||
* https://github.com/kamens/jQuery-menu-aim
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
$.fn.menuAim = function (opts) {
|
||||
// Initialize menu-aim for all elements in jQuery collection
|
||||
this.each(function () {
|
||||
init.call(this, opts);
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
function init(opts) {
|
||||
var $menu = $(this),
|
||||
activeRow = null,
|
||||
mouseLocs = [],
|
||||
lastDelayLoc = null,
|
||||
timeoutId = null,
|
||||
options = $.extend({
|
||||
rowSelector: "> li",
|
||||
submenuSelector: "*",
|
||||
submenuDirection: $.noop,
|
||||
tolerance: 75, // bigger = more forgivey when entering submenu
|
||||
enter: $.noop,
|
||||
exit: $.noop,
|
||||
activate: $.noop,
|
||||
deactivate: $.noop,
|
||||
exitMenu: $.noop
|
||||
}, opts);
|
||||
|
||||
var MOUSE_LOCS_TRACKED = 3, // number of past mouse locations to track
|
||||
DELAY = 300; // ms delay when user appears to be entering submenu
|
||||
|
||||
/**
|
||||
* Keep track of the last few locations of the mouse.
|
||||
*/
|
||||
var mousemoveDocument = function (e) {
|
||||
mouseLocs.push({ x: e.pageX, y: e.pageY });
|
||||
|
||||
if (mouseLocs.length > MOUSE_LOCS_TRACKED) {
|
||||
mouseLocs.shift();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel possible row activations when leaving the menu entirely
|
||||
*/
|
||||
var mouseleaveMenu = function () {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
// If exitMenu is supplied and returns true, deactivate the
|
||||
// currently active row on menu exit.
|
||||
if (options.exitMenu(this)) {
|
||||
if (activeRow) {
|
||||
options.deactivate(activeRow);
|
||||
}
|
||||
|
||||
activeRow = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger a possible row activation whenever entering a new row.
|
||||
*/
|
||||
var mouseenterRow = function () {
|
||||
if (timeoutId) {
|
||||
// Cancel any previous activation delays
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
options.enter(this);
|
||||
possiblyActivate(this);
|
||||
},
|
||||
mouseleaveRow = function () {
|
||||
options.exit(this);
|
||||
};
|
||||
|
||||
/*
|
||||
* Immediately activate a row if the user clicks on it.
|
||||
*/
|
||||
var clickRow = function () {
|
||||
activate(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Activate a menu row.
|
||||
*/
|
||||
var activate = function (row) {
|
||||
if (row == activeRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeRow) {
|
||||
options.deactivate(activeRow);
|
||||
}
|
||||
|
||||
|
||||
options.activate(row);
|
||||
activeRow = row;
|
||||
};
|
||||
|
||||
/**
|
||||
* Possibly activate a menu row. If mouse movement indicates that we
|
||||
* shouldn't activate yet because user may be trying to enter
|
||||
* a submenu's content, then delay and check again later.
|
||||
*/
|
||||
var possiblyActivate = function (row) {
|
||||
var delay = activationDelay();
|
||||
|
||||
if (delay) {
|
||||
timeoutId = setTimeout(function () {
|
||||
possiblyActivate(row);
|
||||
}, delay);
|
||||
} else {
|
||||
activate(row);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the amount of time that should be used as a delay before the
|
||||
* currently hovered row is activated.
|
||||
*
|
||||
* Returns 0 if the activation should happen immediately. Otherwise,
|
||||
* returns the number of milliseconds that should be delayed before
|
||||
* checking again to see if the row should be activated.
|
||||
*/
|
||||
var activationDelay = function () {
|
||||
if (!activeRow || !$(activeRow).is(options.submenuSelector)) {
|
||||
// If there is no other submenu row already active, then
|
||||
// go ahead and activate immediately.
|
||||
return 0;
|
||||
}
|
||||
|
||||
var offset = $menu.offset(),
|
||||
upperLeft = {
|
||||
x: offset.left,
|
||||
y: offset.top - options.tolerance
|
||||
},
|
||||
upperRight = {
|
||||
x: offset.left + $menu.outerWidth(),
|
||||
y: upperLeft.y
|
||||
},
|
||||
lowerLeft = {
|
||||
x: offset.left,
|
||||
y: offset.top + $menu.outerHeight() + options.tolerance
|
||||
},
|
||||
lowerRight = {
|
||||
x: offset.left + $menu.outerWidth(),
|
||||
y: lowerLeft.y
|
||||
},
|
||||
loc = mouseLocs[mouseLocs.length - 1],
|
||||
prevLoc = mouseLocs[0];
|
||||
|
||||
if (!loc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!prevLoc) {
|
||||
prevLoc = loc;
|
||||
}
|
||||
|
||||
if (prevLoc.x < offset.left || prevLoc.x > lowerRight.x ||
|
||||
prevLoc.y < offset.top || prevLoc.y > lowerRight.y) {
|
||||
// If the previous mouse location was outside of the entire
|
||||
// menu's bounds, immediately activate.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastDelayLoc &&
|
||||
loc.x == lastDelayLoc.x && loc.y == lastDelayLoc.y) {
|
||||
// If the mouse hasn't moved since the last time we checked
|
||||
// for activation status, immediately activate.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Detect if the user is moving towards the currently activated
|
||||
// submenu.
|
||||
//
|
||||
// If the mouse is heading relatively clearly towards
|
||||
// the submenu's content, we should wait and give the user more
|
||||
// time before activating a new row. If the mouse is heading
|
||||
// elsewhere, we can immediately activate a new row.
|
||||
//
|
||||
// We detect this by calculating the slope formed between the
|
||||
// current mouse location and the upper/lower right points of
|
||||
// the menu. We do the same for the previous mouse location.
|
||||
// If the current mouse location's slopes are
|
||||
// increasing/decreasing appropriately compared to the
|
||||
// previous's, we know the user is moving toward the submenu.
|
||||
//
|
||||
// Note that since the y-axis increases as the cursor moves
|
||||
// down the screen, we are looking for the slope between the
|
||||
// cursor and the upper right corner to decrease over time, not
|
||||
// increase (somewhat counterintuitively).
|
||||
function slope(a, b) {
|
||||
return (b.y - a.y) / (b.x - a.x);
|
||||
};
|
||||
|
||||
var decreasingCorner = upperRight,
|
||||
increasingCorner = lowerRight;
|
||||
|
||||
// Our expectations for decreasing or increasing slope values
|
||||
// depends on which direction the submenu opens relative to the
|
||||
// main menu. By default, if the menu opens on the right, we
|
||||
// expect the slope between the cursor and the upper right
|
||||
// corner to decrease over time, as explained above. If the
|
||||
// submenu opens in a different direction, we change our slope
|
||||
// expectations.
|
||||
if (options.submenuDirection() == "left") {
|
||||
decreasingCorner = lowerLeft;
|
||||
increasingCorner = upperLeft;
|
||||
} else if (options.submenuDirection() == "below") {
|
||||
decreasingCorner = lowerRight;
|
||||
increasingCorner = lowerLeft;
|
||||
} else if (options.submenuDirection() == "above") {
|
||||
decreasingCorner = upperLeft;
|
||||
increasingCorner = upperRight;
|
||||
}
|
||||
|
||||
var decreasingSlope = slope(loc, decreasingCorner),
|
||||
increasingSlope = slope(loc, increasingCorner),
|
||||
prevDecreasingSlope = slope(prevLoc, decreasingCorner),
|
||||
prevIncreasingSlope = slope(prevLoc, increasingCorner);
|
||||
|
||||
if (decreasingSlope < prevDecreasingSlope &&
|
||||
increasingSlope > prevIncreasingSlope) {
|
||||
// Mouse is moving from previous location towards the
|
||||
// currently activated submenu. Delay before activating a
|
||||
// new menu row, because user may be moving into submenu.
|
||||
lastDelayLoc = loc;
|
||||
return DELAY;
|
||||
}
|
||||
|
||||
lastDelayLoc = null;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook up initial menu events
|
||||
*/
|
||||
$menu
|
||||
.mouseleave(mouseleaveMenu)
|
||||
.find(options.rowSelector)
|
||||
.mouseenter(mouseenterRow)
|
||||
.mouseleave(mouseleaveRow)
|
||||
.click(clickRow);
|
||||
|
||||
$(document).mousemove(mousemoveDocument);
|
||||
|
||||
};
|
||||
})(jQuery);
|
@ -27,7 +27,6 @@ const lib_paths =[
|
||||
`/lib/jquery-ui-1.13.2/jquery-ui.min.js`,
|
||||
`/lib/lodash@4.17.21.min.js`,
|
||||
`/lib/jquery.dragster.js`,
|
||||
'/lib/jquery.menu-aim.js',
|
||||
`/lib/html-entities.js`,
|
||||
`/lib/timeago.min.js`,
|
||||
`/lib/iro.min.js`,
|
||||
|
Loading…
Reference in New Issue
Block a user