coupdoeil
Version:
Javascript for Ruby on Rails Coupdoeil gem
90 lines (80 loc) • 3.58 kB
JavaScript
import {POPOVER_SELECTOR} from "../popover/config";
import {isAnyPopoverOpened} from "../popover/state_check";
import {notTriggeredOnHover} from "../popover/attributes";
import {
cancelCloseRequest,
closeChildrenNow,
closeOnHoverChildrenLater,
closeTriggeredOnHoverLater,
closeTriggeredOnHoverNowUnlessAncestor
} from "../popover/closing";
import {addToCurrents as addToCurrentPopovers} from "../popover/current";
export const onMouseOver = ({ target: hoveredElement }) => {
const coupdoeilElement = hoveredElement.closest('coup-doeil')
const popoverElement = hoveredElement.closest(POPOVER_SELECTOR)
if (coupdoeilElement && popoverElement) {
handleMouseOverCoupdoeilWithinPopover(coupdoeilElement, popoverElement, hoveredElement)
}
else if (coupdoeilElement) {
handleMouseOverCoupdoeilOutsidePopover(coupdoeilElement, hoveredElement)
}
else if (popoverElement) {
handleOverOutsideCoupdoeilButWithinPopover(popoverElement)
}
else {
handleOverOutsideCoupdoeilAndPopover()
}
}
function handleMouseOverCoupdoeilWithinPopover(coupdoeilElement, popoverElement, hoveredElement) {
const childPopover = coupdoeilElement.popoverController
const parentPopover = popoverElement.popoverController
if(notTriggeredOnHover(childPopover))
return;
if (childPopover.isOpen) {
// when the mouse goes back from child popover to its coupdoeil element within parent popover
// it means that this child popover was already open
closeChildrenNow(childPopover)
} else {
// ensures to close other children popovers before opening the one that current one
closeChildrenNow(parentPopover)
// should also close any open popover outside of parent
coupdoeilElement.openPopover(hoveredElement)
}
}
function handleMouseOverCoupdoeilOutsidePopover(coupdoeilElement, hoveredElement) {
const popover = coupdoeilElement.popoverController
if(notTriggeredOnHover(popover))
return;
if (popover.isClosed) {
// Close any other open popover before opening this one
coupdoeilElement.openPopover(hoveredElement, { beforeDisplay: closeTriggeredOnHoverNowUnlessAncestor })
} else if (popover.closingRequest) {
// popover is still open but was requested to close, then it clear this closing request
// and ensures the popovers stays in current popovers register
cancelCloseRequest(popover)
addToCurrentPopovers(coupdoeilElement)
}
}
function handleOverOutsideCoupdoeilAndPopover() {
// mouse is not within any popover and not over any coupdoeil element
// Therefore all popovers that trigger on hover should be closed if any is open.
if (isAnyPopoverOpened()) {
closeTriggeredOnHoverLater()
}
}
function handleOverOutsideCoupdoeilButWithinPopover(popoverElement) {
const popover = popoverElement.popoverController
if (popover.closingRequest) {
// popover is still open but was requested to close, then it clears this closing request
// and ensures the popovers stays in current popovers register
// This typically happens when mouse was on coupdoeil element, then it moves toward the popover
// but because of a small gap, it triggers the closing request, but when the mouse finally enters the popover
// this closing request must be aborted.
cancelCloseRequest(popover)
addToCurrentPopovers(popover.coupdoeilElement)
} else if (popover.children.size > 0) {
// Happens when a child popover was open but mouse moved outside of it or its coupdoeil element,
// but stays within the parent popover
closeOnHoverChildrenLater(popover)
}
}