So it turns out there were a couple of issues preventing the yui context
menu from working correctly after an ajax request.

Even though there was a call to clearContent on the context menu during the
on show event yui seemed to ignore this. This resulted in a doubling up of
some menu items especially sub menu items. I fixed this by calling
clearContent during the menu hide event.

The even worse problem was yui totally ignoring the menu updates if the menu
was not first destroyed. I fixed this by calling destroy on the menu before
calling all the javascript to create the menu. This really seems like
overkill to me but was the only way I could get it to work. I'm not sure why
calling clearContent after a destroy was necessary but this fixes all my
problems.

Also I did not see any reason to make the add method protected in
org.wicketstuff.yui.markup.html.menu2.contextMenu.Menu.
So I opened that up and made it public. This allows the caller to add menu
items and then refresh the panel via ajax and it all seems to work fine.

I have tested these changes in a simple app with one page and one panel. I
have also tested in a much more complicated app that contains a panel with
popup and over a dozen context menus each with two sub menus and so far I
have not found any problems.

I have attached a patch. Please let me know what you think. If you have any
suggestions please let me know.
I am happy to help out where I can...


On Mon, Jan 18, 2010 at 6:16 PM, Dave Kallstrom <dave.kallst...@gmail.com>wrote:

> Interesting... I'll give that a try.. Thanks...
>
>
> On Mon, Jan 18, 2010 at 6:06 PM, Alexander Elsholz <
> alexander.elsh...@widas.de> wrote:
>
>> for my problem with dojo this works:
>>
>> public void refreshMenu(AjaxRequestTarget pTarget) {
>>
>>       String js =  "dojo.addOnLoad(function(){\n + menu.generateJS()
>>                         + "\n});" ;
>>        pTarget.appendJavascript(sss);
>> }
>>
>>
>> and i know the same stuff works for jquery and yui. the problem is that
>> the
>> header javascript brokes after rerendering the component (i think its a
>> problem
>> with object references because most browsers replace the object by
>> creating a
>> new one and the javascript stuff bind on the dom-bject). What seems to
>> work is
>> to put the javascript stuff into the <body> tag using the
>> onComponentRendered()
>> to "reactivate" the behavior.
>>
>> the ugly is you have to reload the menu in every ajax-event reredering the
>> component with menu.
>>
>> hth
>> alex
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
>> For additional commands, e-mail: users-h...@wicket.apache.org
>>
>>
>
>
> --
> Dave Kallstrom
>



-- 
Dave Kallstrom
Index: src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/YuiContextMenuBehavior.java
===================================================================
--- src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/YuiContextMenuBehavior.java	(revision 5131)
+++ src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/YuiContextMenuBehavior.java	(working copy)
@@ -17,6 +17,8 @@
 
 public class YuiContextMenuBehavior extends AbstractDefaultAjaxBehavior {
 
+	private static final long serialVersionUID = -2453827056594475980L;
+	private static final String CONTEXT_MENU = "ContextMenu";
 	private List<YuiContextMenu> menus = new ArrayList<YuiContextMenu>();
 	private YuiContextMenu defaultMenu;
 
@@ -30,24 +32,24 @@
 		for (int i = 0; i < menus.length; i++) {
 			this.menus.add(menus[i]);
 		}
-		this.defaultMenu = this.menus.get( 0 );;
+		this.defaultMenu = this.menus.get(0);
 	}
-	
-	public void applyAttributes( Component comp, String menuId, IModel targetId ) {
-		YuiContextMenu menu = getMenuById( menuId );
-		assert( menu != null);
-		applyAttributes( comp, menu, targetId );
+
+	public void applyAttributes(Component comp, String menuId, IModel<String> targetId) {
+		YuiContextMenu menu = getMenuById(menuId);
+		assert (menu != null);
+		applyAttributes(comp, menu, targetId);
 	}
-	
-	public void applyAttributes( Component comp, YuiContextMenu menu, IModel targetId ) {
+
+	public void applyAttributes(Component comp, YuiContextMenu menu, IModel<String> targetId) {
 		comp.add(new AttributeModifier("targetId", true, targetId));
-		comp.add(new AttributeModifier("contextMenuId", true, new Model( menu.getMenuId())));
+		comp.add(new AttributeModifier("contextMenuId", true, new Model<String>(menu.getMenuId())));
 	}
 
+	@Override
 	protected void respond(AjaxRequestTarget target) {
 		String action = RequestCycle.get().getRequest().getParameter("action");
-		String targetId = RequestCycle.get().getRequest().getParameter(
-				"targetId");
+		String targetId = RequestCycle.get().getRequest().getParameter("targetId");
 		String menuId = RequestCycle.get().getRequest().getParameter("contextMenuId");
 
 		YuiContextMenu menu = getMenuById(menuId);
@@ -79,43 +81,88 @@
 	}
 
 	public CharSequence getCallBackScriptForMenu(String action) {
-		return generateCallbackScript("wicketAjaxGet('" + getCallbackUrl()
-				+ "&action=" + action + "&targetId=' + targetId + '&contextMenuId=' + contextMenuId");
+		return generateCallbackScript("wicketAjaxGet('" + getCallbackUrl() + "&action=" + action + "&targetId=' + targetId + '&contextMenuId=' + contextMenuId");
 	}
 
+	@Override
 	public void renderHead(IHeaderResponse response) {
 		super.renderHead(response);
-		YuiHeaderContributor.forModule("menu", null, false, "2.5.2")
-				.renderHead(response);
 
-		response.renderJavascriptReference(new ResourceReference(
-				YuiContextMenuBehavior.class, "contextMenu.js"));
+		YuiHeaderContributor.forModule("menu", null, false, "2.5.2").renderHead(response);
+		response.renderJavascriptReference(new ResourceReference(YuiContextMenuBehavior.class, "contextMenu.js"));
+
+		String script = getMenuDestroyScript() + getMenuCreationScript() + getMenuInitializationScript();
+		response.renderOnDomReadyJavascript(script);
+	}
+
+	/**
+	 * Method to destroy the context menu item if it exists. This really helps yui rebuild the menu after an ajax
+	 * request
+	 * 
+	 * @return
+	 */
+	private String getMenuDestroyScript() {
 
 		StringBuffer buf = new StringBuffer();
-		
 
-		
-		buf.append( getMenuCreationScript() );
-		response.renderOnDomReadyJavascript(buf.toString() );
+		String menuGetter = getYuiMenuScript();
+
+		buf.append("if( " + menuGetter + "){ ");
+		buf.append(menuGetter).append(".destroy();  \n } \n");
+
+		return buf.toString();
+	}
+
+	/**
+	 * 
+	 * base start of scripts
+	 */
+	private String getYuiMenuScript() {
+		String menuName = getComponent().getMarkupId() + CONTEXT_MENU;
+		return "YAHOO.widget.MenuManager.getMenu(\"" + menuName + "\")";
 	}
-	
-	public String getMenuCreationScript() {
+
+	/**
+	 * Creates the menu initialization script.
+	 * 
+	 * @return
+	 */
+	private StringBuffer getMenuInitializationScript() {
 		StringBuffer buf = new StringBuffer();
-		
+
+		String menuGetter = getYuiMenuScript();
+
+		buf.append(menuGetter).append(".render( document.getElementById(\"").append(getComponent().getMarkupId()).append("\"));\n");
+		buf.append(menuGetter).append(".beforeShowEvent.subscribe(onContextMenuBeforeShow);\n");
+		buf.append(menuGetter).append(".hideEvent.subscribe(onContextMenuHideEvent);\n");
+
+		return buf;
+
+	}
+
+	/**
+	 * Creates the menu definition script
+	 * 
+	 * @return
+	 */
+	private String getMenuCreationScript() {
+
+		StringBuffer buf = new StringBuffer();
+
 		for (YuiContextMenu menu : menus) {
 			List<MenuItem> items = menu.getAllMenuItems();
 
 			for (MenuItem mi : items) {
 
-				buf.append("function ").append(mi.getPathToRoot()).append(
-						"() {\n");
+				buf.append("function ").append(mi.getPathToRoot()).append("() {\n");
 				buf.append(getCallBackScriptForMenu(mi.getMenuId()));
 				buf.append("\n}\n");
 			}
 
 		}
 		StringBuffer menuDefn = new StringBuffer();
-		menuDefn.append("var oContextMenuItems = {");
+		String contextMenuItems = " oContextMenuItems" + getComponent().getMarkupId();
+		menuDefn.append("var " + contextMenuItems + " = {");
 
 		Iterator<YuiContextMenu> menuIter = menus.iterator();
 		while (menuIter.hasNext()) {
@@ -124,8 +171,7 @@
 				defaultMenu = menu;
 			}
 
-			menuDefn.append("\"").append(menu.getMenuId()).append("\": [")
-					.append(menu.getItemData(this));
+			menuDefn.append("\"").append(menu.getMenuId()).append("\": [").append(menu.getItemData(this));
 			menuDefn.append("]");
 			if (menuIter.hasNext()) {
 				menuDefn.append(",\n");
@@ -135,26 +181,13 @@
 
 		buf.append(menuDefn.toString());
 
-		String menuName = getComponent().getMarkupId() + "ContextMenu";
-
-		buf.append("\nvar ").append(menuName).append(
-				" = new YAHOO.widget.ContextMenu(\"").append(menuName).append(
-				"\",\n").append("{ trigger: document.getElementById(\"").append(
-				getComponent().getMarkupId()).append("\"), lazyload: true }")
-				.append(");\n");
-
-		buf.append(menuName).append(".menus = ").append("oContextMenuItems;\n");
+		String menuName = getComponent().getMarkupId() + CONTEXT_MENU;
 
-		buf.append(menuName).append(".render( document.getElementById(\"").append(
-				getComponent().getMarkupId()).append("\"));\n");
+		buf.append("\nvar ").append(menuName).append(" = new YAHOO.widget.ContextMenu(\"").append(menuName).append("\",\n").append("{ trigger: document.getElementById(\"").append(getComponent().getMarkupId()).append("\"), lazyload: true }").append(");\n");
 
-		buf.append(menuName).append(
-				".beforeShowEvent.subscribe(onContextMenuBeforeShow);\n");
+		buf.append(menuName).append(".menus = ").append(contextMenuItems + ";\n");
 
-
-		
 		return buf.toString();
 
 	}
-
 }
Index: src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/contextMenu.js
===================================================================
--- src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/contextMenu.js	(revision 5131)
+++ src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/contextMenu.js	(working copy)
@@ -72,6 +72,16 @@
     return id == null ? null : menus[id];
 
 }
+ 
+/**
+ * Clearing the content on the hideEvent helps yui rebuild the menu
+ * correctly when it is displayed post ajax call.
+ */
+
+function onContextMenuHideEvent(p_sType, p_aArgs){
+	
+	this.clearContent();
+}
 
 function onContextMenuBeforeShow(p_sType, p_aArgs) {
 
@@ -79,7 +89,7 @@
     contextMenuId = GetMenuIdFromEventTarget(this.contextEventTarget);
 
     var aMenuItems = GetMenuFromEventTarget( this.contextEventTarget, this.menus );
-
+  
     this.clearContent();
     
     if ( aMenuItems != null ) {
Index: src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/Menu.java
===================================================================
--- src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/Menu.java	(revision 5131)
+++ src/main/java/org/wicketstuff/yui/markup/html/menu2/contextMenu/Menu.java	(working copy)
@@ -22,12 +22,12 @@
 	private String className;
 	private boolean clickToHide = true;
 	private boolean disabled;
-	
-	public Menu( String id ) {
-		this( id, id );
+
+	public Menu(String id) {
+		this(id, id);
 	}
 
-	public Menu(String id, String text ) {
+	public Menu(String id, String text) {
 		super(id, text);
 	}
 
@@ -127,10 +127,12 @@
 		this.clickToHide = clickToHide;
 	}
 
+	@Override
 	public boolean isDisabled() {
 		return disabled;
 	}
 
+	@Override
 	public void setDisabled(boolean disabled) {
 		this.disabled = disabled;
 	}
@@ -150,10 +152,9 @@
 	/**
 	 * Add an item to the menu
 	 * 
-	 * @param child
-	 *            menu Item
+	 * @param child menu Item
 	 */
-	protected void add(AbstractMenuItem child) {
+	public void add(AbstractMenuItem child) {
 		menuItems.add(child);
 		child.parent = this;
 	}
@@ -165,8 +166,7 @@
 	/**
 	 * Return the {...@link MenuItem} according to its action
 	 * 
-	 * @param action
-	 *            action of a {...@link MenuItem}
+	 * @param action action of a {...@link MenuItem}
 	 * @return the {...@link MenuItem} according to its action
 	 */
 	public MenuItem getMenuItem(String action) {
@@ -180,27 +180,26 @@
 				if (ret != null) {
 					break;
 				}
-			} else if (item instanceof MenuItem
-					&& item.getMenuId().equals(action)) {
+			} else if (item instanceof MenuItem && item.getMenuId().equals(action)) {
 				ret = (MenuItem) item;
 			}
 		}
 
 		return ret;
 	}
-	
+
 	public List<MenuItem> getAllMenuItems() {
 		List<MenuItem> items = new ArrayList<MenuItem>();
-		
-		for ( AbstractMenuItem item : menuItems ) {
+
+		for (AbstractMenuItem item : menuItems) {
 			if (item instanceof Menu) {
 				Menu menu = (Menu) item;
-				items.addAll( menu.getAllMenuItems() );
+				items.addAll(menu.getAllMenuItems());
 			} else if (item instanceof MenuItem) {
-				items.add((MenuItem)item );
+				items.add((MenuItem) item);
 			}
 		}
-		
+
 		return items;
 	}
 
@@ -217,10 +216,8 @@
 			props.put("y", y.toString());
 		}
 
-
 		props.put("fixedcenter", String.valueOf(fixedCenter));
 
-
 		if (width != null) {
 			props.put("width", width);
 		}
@@ -264,6 +261,7 @@
 		return props;
 	}
 
+	@Override
 	public String getItemData(YuiContextMenuBehavior behavior) {
 		StringBuffer buf = new StringBuffer();
 
@@ -276,9 +274,8 @@
 			buf.append("\"").append(props.get(key)).append("\"");
 			if (keys.hasNext()) {
 				buf.append(",\n");
-			}
-			else if ( menuItems.size() > 0 ) {
-				buf.append( ",\n" );
+			} else if (menuItems.size() > 0) {
+				buf.append(",\n");
 			}
 
 		}
@@ -291,8 +288,8 @@
 			while (miIter.hasNext()) {
 				AbstractMenuItem mi = miIter.next();
 				buf.append(mi.getItemData(behavior));
-				if ( miIter.hasNext() ) {
-					buf.append( ",\n" );
+				if (miIter.hasNext()) {
+					buf.append(",\n");
 				}
 
 			}
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@wicket.apache.org
For additional commands, e-mail: users-h...@wicket.apache.org

Reply via email to