coupdoeil
Version:
Javascript for Ruby on Rails Coupdoeil gem
103 lines (93 loc) • 4.3 kB
JavaScript
import {POPOVER_SELECTOR} from "../popover/config";
import {notTriggeredOnHover} from "../popover/attributes";
import {
cancelClosingRequest,
closeChildrenNow,
closeOnHoverChildrenLater,
closeOnHoverNotParentsLater,
closeTriggeredOnHoverLater,
closeTriggeredOnHoverNowUnlessAncestor
} from "../popover/closing";
import {addToCurrents as addToCurrentPopovers} from "../popover/current";
import {isAnyPopoverOpened} from "../popover/utils";
import {upgradeNativeElement} from "../elements/coupdoeil_element";
export const onMouseOver = ({ target: hoveredElement }) => {
const coupdoeilElement = hoveredElement.closest('coup-doeil, [data-popover-options]')
upgradeNativeElement(coupdoeilElement)
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)
// it should also prevent closing the child popover
cancelClosingRequest(childPopover)
addToCurrentPopovers(childPopover.coupdoeilElement)
} 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) {
// If popover is still open but was requested to close, then it must clear this closing request
// and ensures the popovers stays in current popovers register.
cancelClosingRequest(popover)
addToCurrentPopovers(popover.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) {
// If popover is still open but was requested to close, then it must clear this closing request
// and ensures the popovers stays in current popovers register.
// This typically happens when the mouse was on coupdoeil element and moved toward the popover.
// But because of a small gap, it triggered the closing request. When the mouse finally enters the popover
// the closing request must be aborted. Since it typically happens in a child popover, it means it should also
// prevent all parents of this popover to close.
let topMostParent = popover
while (topMostParent) {
cancelClosingRequest(topMostParent)
addToCurrentPopovers(topMostParent.coupdoeilElement)
topMostParent = topMostParent.parent
}
} 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)
}
// Closes all other on hover popovers that are not parents of the current popover nor children.
closeOnHoverNotParentsLater(popover)
}