Author: nbelaevski
Date: 2009-08-24 21:02:04 -0400 (Mon, 24 Aug 2009)
New Revision: 15291
Added:
root/examples/trunk/components/core-demo/src/main/java/org/richfaces/demo/OutputPanelBean.java
Modified:
root/examples/trunk/components/core-demo/src/main/webapp/outputPanel.xhtml
root/examples/trunk/components/core-demo/src/main/webapp/push.xhtml
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.java
root/ui/trunk/components/core/src/main/java/org/richfaces/component/html/HtmlOutputPanel.java
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/AjaxCommandRendererBase.java
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxOutputPanelRenderer.java
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/MediaOutputRenderer.java
Log:
Added behaviors support for a4j:outputPanel
Added:
root/examples/trunk/components/core-demo/src/main/java/org/richfaces/demo/OutputPanelBean.java
===================================================================
---
root/examples/trunk/components/core-demo/src/main/java/org/richfaces/demo/OutputPanelBean.java
(rev 0)
+++
root/examples/trunk/components/core-demo/src/main/java/org/richfaces/demo/OutputPanelBean.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -0,0 +1,40 @@
+/**
+ * License Agreement.
+ *
+ * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.richfaces.demo;
+
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.RequestScoped;
+import javax.faces.event.AjaxBehaviorEvent;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+@ManagedBean(name = "outputPanelBean")
+@RequestScoped
+public class OutputPanelBean {
+
+ public void behaviorListener(AjaxBehaviorEvent event) {
+ System.out.println("OutputPanelBean.behaviorListener() " + event);
+ }
+}
Modified: root/examples/trunk/components/core-demo/src/main/webapp/outputPanel.xhtml
===================================================================
--- root/examples/trunk/components/core-demo/src/main/webapp/outputPanel.xhtml 2009-08-24
18:52:20 UTC (rev 15290)
+++ root/examples/trunk/components/core-demo/src/main/webapp/outputPanel.xhtml 2009-08-25
01:02:04 UTC (rev 15291)
@@ -9,9 +9,13 @@
<h:head>
</h:head>
<h:body>
- <a4j:outputPanel layout="block">
- Output panel
- </a4j:outputPanel>
+ <a4j:status startText="start..." /><br />
+ <h:form>
+ <a4j:outputPanel layout="block"
onclick="alert('clicked')">
+ <f:ajax event="mouseover"
listener="#{outputPanelBean.behaviorListener}" />
+ Output panel
+ </a4j:outputPanel>
+ </h:form>
</h:body>
</f:view>
</html>
\ No newline at end of file
Modified: root/examples/trunk/components/core-demo/src/main/webapp/push.xhtml
===================================================================
--- root/examples/trunk/components/core-demo/src/main/webapp/push.xhtml 2009-08-24
18:52:20 UTC (rev 15290)
+++ root/examples/trunk/components/core-demo/src/main/webapp/push.xhtml 2009-08-25
01:02:04 UTC (rev 15291)
@@ -21,7 +21,7 @@
</a4j:push>
<h:commandLink value="Generate push event"
action="#{pushBean.generateEvent}">
- <f:ajax render="#{'@this'}" />
+ <f:ajax render="@none" />
</h:commandLink>
</h:form>
</h:body>
Modified:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java 2009-08-24
18:52:20 UTC (rev 15290)
+++
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -1081,41 +1081,63 @@
private static final boolean isNonEmpty(String s) {
return s!= null && s.length() != 0;
}
+
+ public static String createBehaviorsChain(FacesContext facesContext, UIComponent
component, String eventHandlerAttribute,
+ String behaviorName, boolean needsSubmittingBehavior) {
- public static String createBehaviorsChain(FacesContext facesContext, UIComponent
component, String attributeName) {
+ List<ClientBehavior> behaviors = null;
+
+ String eventHandler = (String) component.getAttributes().get(eventHandlerAttribute);
+ if (component instanceof ClientBehaviorHolder) {
+ ClientBehaviorHolder clientBehaviorHolder = (ClientBehaviorHolder) component;
+ Map<String, List<ClientBehavior>> clientBehaviorsMap =
clientBehaviorHolder.getClientBehaviors();
+ if (clientBehaviorsMap != null) {
+ behaviors = clientBehaviorsMap.get(behaviorName);
+ }
+ }
+
+ ClientBehaviorContext behaviorContext = null;
+ if (behaviors != null) {
+ Collection<Parameter> parametersList =
AjaxRendererUtils.getBehaviorParametersList(facesContext, component);
+ behaviorContext = ClientBehaviorContext.createClientBehaviorContext(facesContext,
component,
+ behaviorName, null, parametersList);
+ }
+
+ if (isNonEmpty(eventHandler) || behaviors != null) {
+ return AjaxRendererUtils.createBehaviorsChain(facesContext, eventHandler, behaviors,
behaviorContext, needsSubmittingBehavior);
+ } else {
+ return null;
+ }
+ }
+
+ public static String createBehaviorsChain(FacesContext facesContext, String
eventHandlerValue, List<ClientBehavior> behaviors,
+ ClientBehaviorContext behaviorContext, boolean needsSubmittingBehavior) {
+
String result = null;
+ //TODO: performance optimizization
List<String> handlers = new ArrayList<String>(2);
- String eventHandler = (String) component.getAttributes().get(attributeName);
- if (isNonEmpty(eventHandler)) {
- handlers.add(eventHandler);
+ if (isNonEmpty(eventHandlerValue)) {
+ handlers.add(eventHandlerValue);
}
boolean hasSubmittingBehavior = false;
Map<String, Object> parametersMap = new LinkedHashMap<String, Object>();
- AjaxRendererUtils.appendParameters(facesContext, component, parametersMap);
- if (component instanceof ClientBehaviorHolder) {
- ClientBehaviorHolder clientBehaviorHolder = (ClientBehaviorHolder) component;
- List<ClientBehavior> behaviors =
clientBehaviorHolder.getClientBehaviors().get(attributeName);
- if (behaviors != null) {
- ClientBehaviorContext behaviorContext =
ClientBehaviorContext.createClientBehaviorContext(facesContext,
- component, attributeName, null, adaptParametersMap(parametersMap));
-
- for (ClientBehavior clientBehavior : behaviors) {
- String behaviorScript = clientBehavior.getScript(behaviorContext);
- if (isNonEmpty(behaviorScript)) {
- if (clientBehavior.getHints().contains(ClientBehaviorHint.SUBMITTING)) {
- hasSubmittingBehavior = true;
- }
-
- handlers.add(behaviorScript);
+ if (behaviors != null) {
+ for (ClientBehavior clientBehavior : behaviors) {
+ String behaviorScript = clientBehavior.getScript(behaviorContext);
+ if (isNonEmpty(behaviorScript)) {
+ if (clientBehavior.getHints().contains(ClientBehaviorHint.SUBMITTING)) {
+ hasSubmittingBehavior = true;
}
+
+ handlers.add(behaviorScript);
}
}
}
- if (!hasSubmittingBehavior) {
+ if (!hasSubmittingBehavior && needsSubmittingBehavior) {
JSFunction jsFunction = new JSFunction(AJAX_FUNCTION_NAME, JSReference.THIS,
JSReference.EVENT);
if (parametersMap != null && !parametersMap.isEmpty()) {
jsFunction.addParameter(parametersMap);
@@ -1138,7 +1160,11 @@
return result;
}
- private static Collection<ClientBehaviorContext.Parameter>
adaptParametersMap(Map<String, Object> parametersMap) {
+ public static Collection<ClientBehaviorContext.Parameter>
getBehaviorParametersList(FacesContext context, UIComponent component) {
+ Map<String, Object> parametersMap = new LinkedHashMap<String, Object>();
+ //TODO: merge to a single method
+ appendParameters(context, component, parametersMap);
+
List<Parameter> result = new
ArrayList<ClientBehaviorContext.Parameter>(parametersMap.size());
for (Map.Entry<String, Object> entry : parametersMap.entrySet()) {
result.add(new ClientBehaviorContext.Parameter(entry.getKey(), entry.getValue()));
Modified:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.java 2009-08-24
18:52:20 UTC (rev 15290)
+++
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -29,6 +29,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -40,6 +41,10 @@
import javax.faces.component.UIForm;
import javax.faces.component.UIViewRoot;
import javax.faces.component.ValueHolder;
+import javax.faces.component.behavior.ClientBehavior;
+import javax.faces.component.behavior.ClientBehaviorContext;
+import javax.faces.component.behavior.ClientBehaviorHolder;
+import javax.faces.component.behavior.ClientBehaviorContext.Parameter;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
@@ -74,6 +79,7 @@
substitutions.put(HTML.class_ATTRIBUTE, "styleClass");
requiredAttributes.add(HTML.alt_ATTRIBUTE);
Arrays.sort(HTML.PASS_THRU);
+ Arrays.sort(HTML.PASS_THRU_EVENTS);
Arrays.sort(HTML.PASS_THRU_BOOLEAN);
Arrays.sort(HTML.PASS_THRU_URI);
}
@@ -210,30 +216,33 @@
// public static final String onreset_ATTRIBUTE = "onreset";
// attributes sets.
public static final String[] PASS_THRU = {
- // DIR_ATTRIBUTE,
- // LANG_ATTRIBUTE,
- // STYLE_ATTRIBUTE,
- // TITLE_ATTRIBUTE
- "accesskey", "alt", "cols", "height",
"lang", "longdesc",
- "maxlength", "onblur", "onchange", "onclick",
"ondblclick",
- "onfocus", "onkeydown", "onkeypress",
"onkeyup", "onload",
- "onmousedown", "onmousemove", "onmouseout",
"onmouseover",
- "onmouseup", "onreset", "onselect",
"onsubmit", "onunload",
- "rows", "size", "tabindex", "title",
"width", "dir", "rules",
- "frame", "border", "cellspacing",
"cellpadding", "summary",
- "bgcolor", "usemap", "enctype",
"accept-charset", "accept",
- "target", "charset", "coords", "hreflang",
"rel", "rev",
- "shape", "disabled", "readonly", "ismap",
"align"
+ // DIR_ATTRIBUTE,
+ // LANG_ATTRIBUTE,
+ // STYLE_ATTRIBUTE,
+ // TITLE_ATTRIBUTE
+ "accesskey", "alt", "cols", "height",
"lang", "longdesc",
+ "maxlength", "rows", "size", "tabindex",
"title", "width",
+ "dir", "rules", "frame", "border",
"cellspacing", "cellpadding",
+ "summary", "bgcolor", "usemap", "enctype",
"accept-charset",
+ "accept", "target", "charset", "coords",
"hreflang", "rel",
+ "rev", "shape", "disabled", "readonly",
"ismap", "align"
+ };
+ public static final String[] PASS_THRU_EVENTS = {
+ "onblur", "onchange", "onclick",
"ondblclick",
+ "onfocus", "onkeydown", "onkeypress",
"onkeyup", "onload",
+ "onmousedown", "onmousemove", "onmouseout",
"onmouseover",
+ "onmouseup", "onreset", "onselect",
"onsubmit", "onunload"
};
-
+
/**
* HTML attributes allowed boolean-values only
*/
public static final String[] PASS_THRU_BOOLEAN = { "disabled",
- "declare", "readonly", "compact", "ismap",
"selected",
- "checked", "nowrap", "noresize", "nohref",
"noshade",
- "multiple" };
+ "declare", "readonly", "compact", "ismap",
"selected",
+ "checked", "nowrap", "noresize", "nohref",
"noshade",
+ "multiple"
+ };
/**
* all HTML attributes with URI value.
@@ -338,6 +347,53 @@
}
}
+ public void encodeBehaviors(FacesContext context, ClientBehaviorHolder behaviorHolder,
+ String defaultHtmlEventName, String[] attributesExclusions) throws IOException {
+
+ if (attributesExclusions != null && attributesExclusions.length != 0) {
+ assert false : "Not supported yet";
+ }
+
+ //TODO: disabled component check
+ String defaultEventName = behaviorHolder.getDefaultEventName();
+ Collection<String> eventNames = behaviorHolder.getEventNames();
+ if (eventNames != null) {
+ UIComponent component = (UIComponent) behaviorHolder;
+ ResponseWriter writer = context.getResponseWriter();
+ Map<String, List<ClientBehavior>> clientBehaviors =
behaviorHolder.getClientBehaviors();
+ Collection<Parameter> behaviorParametersList =
AjaxRendererUtils.getBehaviorParametersList(context, component);
+
+ for (String behaviorEventName : eventNames) {
+ if (behaviorEventName.equals(defaultEventName)) {
+ continue;
+ }
+
+ String htmlEventName = "on" + behaviorEventName;
+ List<ClientBehavior> behaviorsList = clientBehaviors.get(behaviorEventName);
+ if (behaviorsList == null && behaviorEventName.equals(defaultHtmlEventName)
&&
+ defaultEventName != null) {
+
+ behaviorEventName = defaultEventName;
+ behaviorsList = clientBehaviors.get(behaviorEventName);
+ }
+
+ ClientBehaviorContext clientBehaviorContext = null;
+ if (behaviorsList != null) {
+ clientBehaviorContext = ClientBehaviorContext.createClientBehaviorContext(context,
component, behaviorEventName,
+ null, behaviorParametersList);
+ }
+
+ String eventHandlerValue = (String) component.getAttributes().get(htmlEventName);
+ if (!isEmpty(eventHandlerValue) || behaviorsList != null) {
+ String behaviorsChain = AjaxRendererUtils.createBehaviorsChain(context,
eventHandlerValue,
+ behaviorsList, clientBehaviorContext, false);
+
+ writer.writeAttribute(htmlEventName, behaviorsChain, htmlEventName);
+ }
+ }
+ }
+ }
+
/**
* Encode common pass-thru html attributes.
*
@@ -345,9 +401,15 @@
* @param component
* @throws IOException
*/
- public void encodePassThru(FacesContext context, UIComponent component)
+ public void encodePassThru(FacesContext context, UIComponent component, String
defaultHtmlEvent)
throws IOException {
encodeAttributesFromArray(context, component, HTML.PASS_THRU);
+ if (component instanceof ClientBehaviorHolder) {
+ ClientBehaviorHolder clientBehaviorHolder = (ClientBehaviorHolder) component;
+ encodeBehaviors(context, clientBehaviorHolder, defaultHtmlEvent, null);
+ } else {
+ encodeAttributesFromArray(context, component, HTML.PASS_THRU_EVENTS);
+ }
}
/**
@@ -359,16 +421,16 @@
* @throws IOException
*/
public void encodePassThruWithExclusions(FacesContext context,
- UIComponent component, String exclusions) throws IOException {
+ UIComponent component, String exclusions, String defaultHtmlEvent) throws IOException
{
if (null != exclusions) {
String[] exclusionsArray = exclusions.split(",");
encodePassThruWithExclusionsArray(context, component,
- exclusionsArray);
+ exclusionsArray, defaultHtmlEvent);
}
}
public void encodePassThruWithExclusionsArray(FacesContext context,
- UIComponent component, Object[] exclusions) throws IOException {
+ UIComponent component, String[] exclusions, String defaultHtmlEvent) throws
IOException {
ResponseWriter writer = context.getResponseWriter();
Map<String, Object> attributes = component.getAttributes();
Arrays.sort(exclusions);
@@ -378,6 +440,18 @@
encodePassThruAttribute(context, attributes, writer, attribute);
}
}
+
+ if (component instanceof ClientBehaviorHolder) {
+ ClientBehaviorHolder clientBehaviorHolder = (ClientBehaviorHolder) component;
+ encodeBehaviors(context, clientBehaviorHolder, defaultHtmlEvent, exclusions);
+ } else {
+ for (int i = 0; i < HTML.PASS_THRU_EVENTS.length; i++) {
+ String attribute = HTML.PASS_THRU_EVENTS[i];
+ if (Arrays.binarySearch(exclusions, attribute) < 0) {
+ encodePassThruAttribute(context, attributes, writer, attribute);
+ }
+ }
+ }
}
/**
Modified:
root/ui/trunk/components/core/src/main/java/org/richfaces/component/html/HtmlOutputPanel.java
===================================================================
---
root/ui/trunk/components/core/src/main/java/org/richfaces/component/html/HtmlOutputPanel.java 2009-08-24
18:52:20 UTC (rev 15290)
+++
root/ui/trunk/components/core/src/main/java/org/richfaces/component/html/HtmlOutputPanel.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -1,8 +1,15 @@
package org.richfaces.component.html;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+
+import javax.faces.component.behavior.ClientBehaviorHolder;
+
import org.richfaces.component.UIAjaxOutputPanel;
-public class HtmlOutputPanel extends UIAjaxOutputPanel {
+public class HtmlOutputPanel extends UIAjaxOutputPanel implements ClientBehaviorHolder {
static final public String COMPONENT_FAMILY = "javax.faces.Panel";
@@ -13,6 +20,12 @@
onkeyup, onmousedown, title, style, onmouseout, onmouseover, onmouseup, styleClass
}
+ private static final Collection<String> EVENT_NAMES =
Collections.unmodifiableCollection(
+ new LinkedHashSet<String>(
+ Arrays.asList("click", "mousemove", "dblclick",
"keydown", "keypress",
+ "keyup", "mousedown", "mouseout",
"mouseover", "mouseup"))
+ );
+
public HtmlOutputPanel() {
super();
setRendererType("org.richfaces.OutputPanelRenderer");
@@ -150,4 +163,8 @@
return COMPONENT_FAMILY;
}
+ @Override
+ public Collection<String> getEventNames() {
+ return EVENT_NAMES;
+ }
}
Modified:
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/AjaxCommandRendererBase.java
===================================================================
---
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/AjaxCommandRendererBase.java 2009-08-24
18:52:20 UTC (rev 15290)
+++
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/AjaxCommandRendererBase.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -74,7 +74,7 @@
public String getOnClick(FacesContext context, UIComponent component) {
StringBuffer onClick = new StringBuffer();
if (!getUtils().isBooleanAttribute(component, "disabled")) {
- onClick.append(AjaxRendererUtils.createBehaviorsChain(context, component,
"onclick"));
+ onClick.append(AjaxRendererUtils.createBehaviorsChain(context, component,
"onclick", "click" , true));
if (!"reset".equals(component.getAttributes().get("type"))) {
onClick.append(";return false;");
}
Modified:
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxOutputPanelRenderer.java
===================================================================
---
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxOutputPanelRenderer.java 2009-08-24
18:52:20 UTC (rev 15290)
+++
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxOutputPanelRenderer.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -105,7 +105,7 @@
if (!hasNoneLayout(component)) {
writer.startElement(getTag(panel), panel);
getUtils().encodeId(context, component);
- getUtils().encodePassThru(context, component);
+ getUtils().encodePassThru(context, component, null);
getUtils().encodeAttributesFromArray(context,component,STYLE_ATTRIBUTES);
}
}
Modified:
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java
===================================================================
---
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java 2009-08-24
18:52:20 UTC (rev 15290)
+++
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -98,7 +98,9 @@
options.put("pushId", push.getListenerId(context));
options.put("clientId", component.getClientId(context));
- String behaviorsChain = AjaxRendererUtils.createBehaviorsChain(context, push,
push.getDefaultEventName());
+ String behaviorsChain = AjaxRendererUtils.createBehaviorsChain(context, push,
UIPush.ON_DATA_AVAILABLE,
+ UIPush.ON_DATA_AVAILABLE, true);
+
if (behaviorsChain != null) {
JSFunctionDefinition dataAvailableHandler = new
JSFunctionDefinition(JSReference.EVENT);
dataAvailableHandler.addToBody(behaviorsChain);
Modified:
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/MediaOutputRenderer.java
===================================================================
---
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/MediaOutputRenderer.java 2009-08-24
18:52:20 UTC (rev 15290)
+++
root/ui/trunk/components/core/src/main/java/org/richfaces/renderkit/html/MediaOutputRenderer.java 2009-08-25
01:02:04 UTC (rev 15291)
@@ -122,7 +122,7 @@
}
writer.writeURIAttribute(uriAttribute,uri,"uri");
getUtils().encodeAttributesFromArray(context,component,HTML.PASS_THRU_STYLES);
- getUtils().encodePassThru(context, mmedia);
+ getUtils().encodePassThru(context, mmedia, null);
}
}