This menu was designed to support 4 levels, and almost 900 different options items. One of the problems that I faced was that some options of the menu opens a af:popup with an af:dialog inside. That options needs to be opened when user clicks, and self-closed when user moves out of dialog.
In summary, I need the mix of "mouseHover" and "action" types on my <af:showPopupBehavior> tag.
Check the following video to see the menu in action.
To modify the expected behavior of <af:showPopupBehavior> type "action" I've created this simple JavaScript function to overwrite ADF JS library.
AdfShowPopupBehavior.prototype.fire = function (a) { a.cancel(); var b = AdfPage.PAGE, c = this._type, d = a.getSource(), e = d.getClientId(), f = d.findComponent(this._popupId); if (AdfPage.PAGE.isScreenReaderMode() && (c == "mouseHover" || c == "mouseMove" || c == "mouseOver" || c == "mouseOut")) AdfLogger.LOGGER.fine("showPopupBehavior trigger type " + c + " suppressed in screen reader mode for launch source id: " + e); else if (f) { var g = f._delayedActivationState; if (g) if (g.launchSourceId == e) return; else b.cancelTimer(g.timerId), delete f._delayedActivationState; if (f.isPopupVisible()) { var h = this._getPopupWindow(f); if (h == null) return; g = this._isInlinePopupSelector(h); h = this._wasOpendedFromSameSource(h, e); if (g) { if (f.hide(), h) return } else h || f.hide() } var k = this._align, h = this._alignId, g = { }; g[AdfRichPopup.HINT_LAUNCH_ID] = e; var l = this._type == AdfComponentEvent.CONTEXT_MENU_EVENT_TYPE; if (h || k || l) { k && (g[AdfRichPopup.HINT_ALIGN] = k, h || (h = d.getClientId(), k = h.lastIndexOf(":"), k != - 1 && (h = h.substring(k + 1)))); h && ((k = d.findComponent(h)) ? g[AdfRichPopup.HINT_ALIGN_ID] = k.getClientId() : AdfLogger.LOGGER.warning("Unable to find align component: ", h)); if (l) g[AdfDhtmlPopupWindow.HINT_TYPE] = AdfDhtmlPopupWindow.HINT_TYPE_MENU, g[AdfDhtmlPopupWindow.HINT_AUTODISMISS] = AdfDhtmlPopupWindow.HINT_AUTODISMISS_MENU, h || (h = AdfAgent.AGENT.getMousePosition(a.getNativeEvent()), g[AdfDhtmlPopupWindow.HINT_MOUSEPOSITION] = h); if (c == "mouseHover" || c == "action") g[AdfDhtmlPopupWindow.HINT_AUTODISMISS] = AdfDhtmlPopupWindow.HINT_AUTODISMISS_MOUSEOUT, g[AdfDhtmlPopupWindow.HINT_AUTODISMISS_MOUSEOUT_ID] = g[AdfRichPopup.HINT_ALIGN_ID] ? g[AdfRichPopup.HINT_ALIGN_ID] : g[AdfRichPopup.HINT_LAUNCH_ID] } a.getType() == AdfUIInputEvent.MOUSE_IN_EVENT_TYPE ? (a = b.scheduleTimer(this, this._onMouseOverTimeout, { hints : g, popup : f, source : d }, 500), f._delayedActivationState = { timerId : a, launchSourceId : e }, d.addEventListener(AdfUIInputEvent.MOUSE_OUT_EVENT_TYPE, this._fireCancel, this)) : f.show(g) } else AdfLogger.LOGGER.severe("Could not find popup ", this._popupId, " from component ", d) };
The line that changes the expected behavior is this one:
if (c == "mouseHover" || c == "action")
Include that JS fragment in a JS file and later import to your pageTemplate or JSPX page:
<af:resource type="javascript" source="../js/popbehavior.js"/>
Also, you can modify the delay time of mouse-out event modifiying the "500ms" value in the JS code.