Author: vbaranov
Date: 2008-04-17 07:01:29 -0400 (Thu, 17 Apr 2008)
New Revision: 7886
Modified:
trunk/ui/contextMenu/src/main/config/component/contextMenu.xml
trunk/ui/contextMenu/src/main/java/org/richfaces/component/UIContextMenu.java
trunk/ui/contextMenu/src/main/java/org/richfaces/renderkit/html/ContextMenuRendererBase.java
trunk/ui/contextMenu/src/main/resources/org/richfaces/renderkit/html/scripts/context-menu.js
Log:
http://jira.jboss.com/jira/browse/RF-1653
Modified: trunk/ui/contextMenu/src/main/config/component/contextMenu.xml
===================================================================
--- trunk/ui/contextMenu/src/main/config/component/contextMenu.xml 2008-04-16 23:00:41 UTC
(rev 7885)
+++ trunk/ui/contextMenu/src/main/config/component/contextMenu.xml 2008-04-17 11:01:29 UTC
(rev 7886)
@@ -46,7 +46,7 @@
<name>attached</name>
<classname>boolean</classname>
<description>
- If the value of the "attached" attribute is true,
component is attached to parent component
+ DEPRECATED(use attachTo)If the value of the "attached"
attribute is true, component is attached to parent component
</description>
<defaultvalue>true</defaultvalue>
</property>
@@ -83,6 +83,28 @@
Set minimal width for the all of the lists that will appear
</description>
</property>
+
+ <property>
+ <name>attachTo</name>
+ <classname>java.lang.String</classname>
+ <description>
+ Client identifier of the component or id of the existing DOM element that is a
source
+ for given event. If attachTo is defined, the event is attached on the client
according
+ to the AttachTiming attribute.
+ If attachTo is not defined, the event is attached on the server to the closest in
the
+ component tree parent component (deprecated "attached" attribute is used).
+ </description>
+ <defaultvalue>""</defaultvalue>
+ </property>
+
+ <property>
+ <name>attachTiming</name>
+ <classname>java.lang.String</classname>
+ <description>
+ Defines the timing when the menu is attached to the target element
+ </description>
+ <defaultvalue>"onavailable"</defaultvalue>
+ </property>
<!--
Modified: trunk/ui/contextMenu/src/main/java/org/richfaces/component/UIContextMenu.java
===================================================================
---
trunk/ui/contextMenu/src/main/java/org/richfaces/component/UIContextMenu.java 2008-04-16
23:00:41 UTC (rev 7885)
+++
trunk/ui/contextMenu/src/main/java/org/richfaces/component/UIContextMenu.java 2008-04-17
11:01:29 UTC (rev 7886)
@@ -30,9 +30,19 @@
public abstract class UIContextMenu extends UIComponentBase implements MenuComponent {
public static final String COMPONENT_TYPE = "org.richfaces.ContextMenu";
+ @Deprecated
public abstract boolean isAttached();
+ @Deprecated
public abstract void setAttached(boolean b);
+
+ public abstract String getAttachTo();
+
+ public abstract void setAttachTo(String attachTo);
+
+ public abstract String getAttachTiming();
+
+ public abstract void setAttachTiming(String attachTo);
public abstract String getEvent();
Modified:
trunk/ui/contextMenu/src/main/java/org/richfaces/renderkit/html/ContextMenuRendererBase.java
===================================================================
---
trunk/ui/contextMenu/src/main/java/org/richfaces/renderkit/html/ContextMenuRendererBase.java 2008-04-16
23:00:41 UTC (rev 7885)
+++
trunk/ui/contextMenu/src/main/java/org/richfaces/renderkit/html/ContextMenuRendererBase.java 2008-04-17
11:01:29 UTC (rev 7886)
@@ -23,7 +23,7 @@
import java.io.IOException;
import java.io.Writer;
-import java.util.Iterator;
+import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -36,7 +36,9 @@
import org.ajax4jsf.component.JavaScriptParameter;
import org.ajax4jsf.javascript.JSFunction;
+import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.javascript.JSReference;
+import org.ajax4jsf.renderkit.RendererUtils;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.ajax4jsf.resource.InternetResource;
import org.richfaces.component.UIContextMenu;
@@ -47,17 +49,35 @@
* @author Maksim Kaszynski
*
*/
-public class ContextMenuRendererBase extends
- TemplateEncoderRendererBase {
+public class ContextMenuRendererBase extends TemplateEncoderRendererBase {
- private final ContextMenuRendererDelegate delegate =
+ /**
+ * Constant for "immediate" attach timing option
+ */
+ private static final String IMMEDIATE = "immediate";
+
+ /**
+ * Constant for "onAvailable" attach timing option
+ */
+ private static final String ON_AVAILABLE = "onavailable";
+
+ /**
+ * Constant for "onload" attach timing option
+ */
+ private static final String ON_LOAD = "onload";
+
+ private final ContextMenuRendererDelegate delegate =
new ContextMenuRendererDelegate();
private final InternetResource[] ownScripts = {
getResource("/org/richfaces/renderkit/html/scripts/json/json-dom.js"),
getResource("/org/richfaces/renderkit/html/scripts/utils.js"),
- getResource("/org/richfaces/renderkit/html/scripts/context-menu.js")
-
+ getResource("/org/richfaces/renderkit/html/scripts/context-menu.js"),
+ new org.ajax4jsf.javascript.PrototypeScript(),
+ new org.ajax4jsf.javascript.AjaxScript(),
+ getResource("/org/richfaces/renderkit/html/scripts/available.js"),
+ getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js")
+
};
private final InternetResource[] scripts;
@@ -89,6 +109,19 @@
writer.writeAttribute(HTML.id_ATTRIBUTE, component.getClientId(context),
"id");
}
+ /**
+ * Perform validation of the contextMenu configuration. Throws FacesException in case
validation fails.
+ * @param clientId - id of the component
+ * @param name - component name
+ * @param attachTiming - timing options
+ */
+ protected void checkValidity(String clientId, String name, String attachTiming) {
+ if (!ON_LOAD.equals(attachTiming) && !IMMEDIATE.equals(attachTiming)
&& !ON_AVAILABLE.equals(attachTiming)) {
+ throw new FacesException("The attachTiming attribute of the contextMenu
(id='" + clientId
+ + "') has an invalid value:'" + attachTiming + "'. It may
have only the following values: '"
+ + IMMEDIATE + "', '" + ON_LOAD + "', '" +
ON_AVAILABLE + "'");
+ }
+ }
public void renderChildren(FacesContext context, UIComponent component)
throws IOException {
@@ -108,14 +141,14 @@
}
writer.startElement("script", component);
- writer.writeText("new Richfaces.ContextMenu('", null);
+ writer.writeText("var contextMenu = new Richfaces.ContextMenu('", null);
writer.writeText(component.getClientId(context), null);
writer.writeText("', ", null);
writer.writeText(menu.getShowDelay() + ", ", null);
writeScriptBody(context, component, true);
writer.writeText(")", null);
+ writer.writeText(";", null);
writer.writeText(getClientAttachmentOptions(context, menu), null);
- writer.writeText(";", null);
if (menu.isDisableDefaultMenu()) {
writer.writeText("Richfaces.disableDefaultHandler('", null);
@@ -127,43 +160,90 @@
}
private String getClientAttachmentOptions(FacesContext context, UIContextMenu
contextMenu) {
- String result = "";
- if (contextMenu.isAttached()) {
- JSFunction function = new JSFunction(".attachToParent");
- UIComponent parent = contextMenu.getParent();
- String parentId = parent.getClientId(context);
-
- function.addParameter(parentId);
+ String attachTo = contextMenu.getAttachTo();
+ String attachTiming = contextMenu.getAttachTiming();
- String event = contextMenu.getEvent();
-
- function.addParameter(event);
-
- Map params = new LinkedHashMap();
- List children = contextMenu.getChildren();
-
- for (Iterator iterator = children.iterator(); iterator.hasNext();) {
- UIComponent kid = (UIComponent) iterator.next();
-
- if (kid instanceof UIParameter) {
- UIParameter parameter = (UIParameter) kid;
- String name = parameter.getName();
- Object value = parameter.getValue();
-
- if (parameter instanceof JavaScriptParameter &&
- ((JavaScriptParameter) parameter).isNoEscape()) {
- value = new JSReference(String.valueOf(value));
- }
-
- params.put(name, value);
- }
-
- }
-
- function.addParameter(params);
- result = function.toScript();
+ boolean isImmediate = attachTiming.equals(IMMEDIATE);
+ boolean isOnLoad = attachTiming.equals(ON_LOAD);
+ boolean isOnAvailable = attachTiming.equals(ON_AVAILABLE);
+
+ if (!(isImmediate || isOnLoad || isOnAvailable)) {
+ // unknown value of property "attachTiming"
+ return "";
+ }
+
+ String pattern = "\\s*,\\s*";
+ // "attachTo" attribute may contain several ids split by ","
+ List<String> attachToIds = new ArrayList<String>();
+ String[] splitAttachTo = attachTo.split(pattern);
+ for (String tempId : splitAttachTo) {
+ if(tempId.length() > 0) {
+ attachToIds.add(tempId);
}
- return result;
+ }
+
+ if((attachToIds.size() == 0) && !contextMenu.isAttached()) {
+ return "";
+ }
+
+ String baseJSFucntionName = "contextMenu.attachToElementById";
+
+ // compatibility with @Deprecated attribute "attached"
+ if(attachToIds.size() == 0) {
+ UIComponent parentComponent = contextMenu.getParent();
+ String clientId = parentComponent.getClientId(context);
+ if (clientId != null) {
+ attachToIds.add(clientId);
+ baseJSFucntionName = "contextMenu.attachToParent";
+ }
+ }
+
+ StringBuilder attachContextMenuBuffer = new StringBuilder();
+
+ // collect parameters
+ Map<String, Object> params = new LinkedHashMap<String, Object>();
+ for (UIComponent kid : contextMenu.getChildren()) {
+ if (kid instanceof UIParameter) {
+ UIParameter parameter = (UIParameter) kid;
+ String name = parameter.getName();
+ Object value = parameter.getValue();
+
+ if ((parameter instanceof JavaScriptParameter) && ((JavaScriptParameter)
parameter).isNoEscape()) {
+ value = new JSReference(String.valueOf(value));
+ }
+
+ params.put(name, value);
+ }
+ }
+
+ for (String attachToId : attachToIds) {
+ JSFunction attachContextMenuFunction = new JSFunction(baseJSFucntionName);
+ UIComponent target = RendererUtils.getInstance().findComponentFor(context, contextMenu,
attachToId);
+ String clientId = (target != null) ? target.getClientId(context) : attachToId;
+
+ attachContextMenuFunction.addParameter(clientId);
+ attachContextMenuFunction.addParameter(contextMenu.getEvent());
+ attachContextMenuFunction.addParameter(params);
+
+ if (isImmediate) {
+ attachContextMenuBuffer.append(attachContextMenuFunction.toScript());
+ } else if (isOnAvailable) {
+ JSFunction availableFunction = new JSFunction("Richfaces.onAvailable");
+ availableFunction.addParameter(clientId);
+ availableFunction.addParameter(new
JSFunctionDefinition().addToBody(attachContextMenuFunction));
+
+ attachContextMenuBuffer.append(availableFunction.toScript());
+ } else if (isOnLoad) {
+ JSFunction onloadFunction = new JSFunction("jQuery(document).ready");
+ onloadFunction.addParameter(new
JSFunctionDefinition().addToBody(attachContextMenuFunction));
+
+ attachContextMenuBuffer.append(onloadFunction.toScript());
+ }
+
+ attachContextMenuBuffer.append(";");
+ }
+
+ return attachContextMenuBuffer.toString();
}
protected void doEncodeEnd(ResponseWriter writer, FacesContext context,
Modified:
trunk/ui/contextMenu/src/main/resources/org/richfaces/renderkit/html/scripts/context-menu.js
===================================================================
---
trunk/ui/contextMenu/src/main/resources/org/richfaces/renderkit/html/scripts/context-menu.js 2008-04-16
23:00:41 UTC (rev 7885)
+++
trunk/ui/contextMenu/src/main/resources/org/richfaces/renderkit/html/scripts/context-menu.js 2008-04-17
11:01:29 UTC (rev 7886)
@@ -23,6 +23,15 @@
this.menuContent = null;
},
+ // attach contextMenu to element specified by id
+ attachToElementById : function(id, event, context) {
+ var element = $(id);
+
+ this.attachToElement(element, event, context);
+ },
+
+ // attach contextMenu to element specified by id
+ // or to the parent fo the current element
attachToParent : function(id, event, context) {
var element = $(id);
if (!element) {
@@ -32,15 +41,20 @@
}
}
+ this.attachToElement(element, event, context);
+ },
+
+ // attach contextMenu to specified element
+ attachToElement : function(element, event, context) {
if (element) {
this.applyDecoration(element);
+
+ //Strip 'on' here
+ var evnName = event.substr(2);
+ var listener = this.show.bindAsEventListener(this, context);
+
+ Event.observe(element, evnName, listener);
}
-
- //Strip 'on' here
- var evnName = event.substr(2);
- var listener = this.show.bindAsEventListener(this, context);
-
- Event.observe(element, evnName, listener);
},
hide: function() {