MYFACES-4301 create shortcut for jsf.ajax.request
diff --git a/api/src/main/javascript/META-INF/resources/myfaces/api/jsf.js b/api/src/main/javascript/META-INF/resources/myfaces/api/jsf.js
index 8eceb1f..efa761e 100644
--- a/api/src/main/javascript/META-INF/resources/myfaces/api/jsf.js
+++ b/api/src/main/javascript/META-INF/resources/myfaces/api/jsf.js
@@ -456,3 +456,28 @@
//return self;
}
}
+
+
+(!window.myfaces) ? window.myfaces = {} : null;
+if (!myfaces.ab) {
+ /*
+ * Shortcut of the jsf.ajax.request, to shorten the rendered JS.
+ */
+ myfaces.ab = function(source, event, eventName, execute, render, options) {
+ if (!options) {
+ options = {};
+ }
+
+ if (eventName) {
+ options["javax.faces.behavior.event"] = eventName;
+ }
+ if (execute) {
+ options["execute"] = execute;
+ }
+ if (render) {
+ options["render"] = render;
+ }
+
+ jsf.ajax.request(source, event, options);
+ };
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlAjaxBehaviorRenderer.java b/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlAjaxBehaviorRenderer.java
index 15610fb..305d937 100644
--- a/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlAjaxBehaviorRenderer.java
+++ b/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlAjaxBehaviorRenderer.java
@@ -18,12 +18,6 @@
*/
package org.apache.myfaces.renderkit.html;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.RandomAccess;
-
import javax.faces.FacesException;
import javax.faces.component.ActionSource;
import javax.faces.component.EditableValueHolder;
@@ -31,14 +25,11 @@
import javax.faces.component.behavior.AjaxBehavior;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorContext;
-import javax.faces.component.search.SearchExpressionContext;
-import javax.faces.component.search.SearchExpressionHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.event.PhaseId;
import javax.faces.render.ClientBehaviorRenderer;
-import org.apache.myfaces.component.search.MyFacesSearchExpressionHints;
-import org.apache.myfaces.util.lang.StringUtils;
+import org.apache.myfaces.renderkit.html.base.AjaxScriptBuilder;
import org.apache.myfaces.util.SharedStringBuilder;
/**
@@ -47,22 +38,9 @@
*/
public class HtmlAjaxBehaviorRenderer extends ClientBehaviorRenderer
{
-
- private static final String AJAX_KEY_ONERROR = "onerror";
- private static final String AJAX_KEY_ONEVENT = "onevent";
- private static final String AJAX_KEY_EXECUTE = "execute";
- private static final String AJAX_KEY_RENDER = "render";
- private static final String AJAX_KEY_DELAY = "delay";
- private static final String AJAX_KEY_RESETVALUES = "resetValues";
-
- private static final String AJAX_VAL_THIS = "this";
- private static final String AJAX_VAL_EVENT = "event";
- private static final String JS_AJAX_REQUEST = "jsf.ajax.request";
-
private static final String ERR_NO_AJAX_BEHAVIOR = "The behavior must be an instance of AjaxBehavior";
private static final String AJAX_SB = "oam.renderkit.AJAX_SB";
- private static final String AJAX_PARAM_SB = "oam.renderkit.AJAX_PARAM_SB";
@Override
public void decode(FacesContext context, UIComponent component, ClientBehavior behavior)
@@ -88,14 +66,29 @@
return null;
}
- return makeAjax(behaviorContext, ajaxBehavior).toString();
+ StringBuilder retVal = SharedStringBuilder.get(behaviorContext.getFacesContext(), AJAX_SB, 60);
+
+ AjaxScriptBuilder.build(behaviorContext.getFacesContext(),
+ retVal,
+ behaviorContext.getComponent(),
+ behaviorContext.getSourceId(),
+ behaviorContext.getEventName(),
+ ajaxBehavior.getExecute(),
+ ajaxBehavior.getRender(),
+ ajaxBehavior.getDelay(),
+ ajaxBehavior.isResetValues(),
+ ajaxBehavior.getOnerror(),
+ ajaxBehavior.getOnevent(),
+ behaviorContext.getParameters());
+
+ return retVal.toString();
}
private void dispatchBehaviorEvent(UIComponent component, AjaxBehavior ajaxBehavior)
{
AjaxBehaviorEvent event = new AjaxBehaviorEvent(component, ajaxBehavior);
- boolean isImmediate = false;
+ boolean isImmediate;
if (ajaxBehavior.isImmediateSet())
{
isImmediate = ajaxBehavior.isImmediate();
@@ -127,344 +120,6 @@
return isImmediate;
}
-
- /**
- * builds the generic ajax call depending upon
- * the ajax behavior parameters
- *
- * @param context the Client behavior context
- * @param behavior the behavior
- * @return a fully working javascript with calls into jsf.js
- */
- private StringBuilder makeAjax(ClientBehaviorContext context, AjaxBehavior behavior)
- {
- StringBuilder retVal = SharedStringBuilder.get(context.getFacesContext(), AJAX_SB, 60);
- StringBuilder paramBuffer = SharedStringBuilder.get(context.getFacesContext(), AJAX_PARAM_SB, 20);
-
- String executes = mapToString(context, paramBuffer, AJAX_KEY_EXECUTE, behavior.getExecute());
- String render = mapToString(context, paramBuffer, AJAX_KEY_RENDER, behavior.getRender());
-
- String onError = behavior.getOnerror();
- if (StringUtils.isNotBlank(onError))
- {
- paramBuffer.setLength(0);
- paramBuffer.append(AJAX_KEY_ONERROR);
- paramBuffer.append(':');
- paramBuffer.append(onError);
- onError = paramBuffer.toString();
- }
- else
- {
- onError = null;
- }
-
- String onEvent = behavior.getOnevent();
- if (StringUtils.isNotBlank(onEvent))
- {
- paramBuffer.setLength(0);
- paramBuffer.append(AJAX_KEY_ONEVENT);
- paramBuffer.append(':');
- paramBuffer.append(onEvent);
- onEvent = paramBuffer.toString();
- }
- else
- {
- onEvent = null;
- }
-
- String delay = behavior.getDelay();
- if (StringUtils.isNotBlank(delay))
- {
- paramBuffer.setLength(0);
- paramBuffer.append(AJAX_KEY_DELAY);
- paramBuffer.append(':');
- if ("none".equals(delay))
- {
- paramBuffer.append('\'');
- paramBuffer.append(delay);
- paramBuffer.append('\'');
- }
- else
- {
- paramBuffer.append(delay);
- }
- delay = paramBuffer.toString();
- }
- else
- {
- delay = null;
- }
-
- String resetValues = Boolean.toString(behavior.isResetValues());
- if (resetValues.equals("true"))
- {
- paramBuffer.setLength(0);
- paramBuffer.append(AJAX_KEY_RESETVALUES);
- paramBuffer.append(':');
- paramBuffer.append(resetValues);
- resetValues = paramBuffer.toString();
- }
- else
- {
- resetValues = null;
- }
-
- String sourceId;
- if (context.getSourceId() == null)
- {
- sourceId = AJAX_VAL_THIS;
- }
- else
- {
- paramBuffer.setLength(0);
- paramBuffer.append('\'');
- paramBuffer.append(context.getSourceId());
- paramBuffer.append('\'');
- sourceId = paramBuffer.toString();
-
- if (!context.getSourceId().trim().equals(
- context.getComponent().getClientId(context.getFacesContext())))
- {
- // Check if sourceId is not a clientId and there is no execute set
- UIComponent ref = context.getComponent();
- ref = (ref.getParent() == null) ? ref : ref.getParent();
- UIComponent instance = null;
- try
- {
- instance = ref.findComponent(context.getSourceId());
- }
- catch (IllegalArgumentException e)
- {
- // No Op
- }
- if (instance == null && executes == null)
- {
- // set the clientId of the component so the behavior can be decoded later,
- // otherwise the behavior will fail
- List<String> list = new ArrayList<>();
- list.add(context.getComponent().getClientId(context.getFacesContext()));
- executes = mapToString(context, paramBuffer, AJAX_KEY_EXECUTE, list);
- }
- }
- }
-
-
- String event = context.getEventName();
-
- retVal.append(JS_AJAX_REQUEST);
- retVal.append('(');
- retVal.append(sourceId);
- retVal.append(',');
- retVal.append(AJAX_VAL_EVENT);
- retVal.append(',');
-
- Collection<ClientBehaviorContext.Parameter> params = context.getParameters();
- int paramSize = (params != null) ? params.size() : 0;
-
- List<String> parameterList = new ArrayList<>(paramSize + 2);
- if (executes != null)
- {
- parameterList.add(executes);
- }
- if (render != null)
- {
- parameterList.add(render);
- }
- if (onError != null)
- {
- parameterList.add(onError);
- }
- if (onEvent != null)
- {
- parameterList.add(onEvent);
- }
- /*
- * since version 2.2
- */
- if (delay != null)
- {
- parameterList.add(delay);
- }
- /*
- * since version 2.2
- */
- if (resetValues != null)
- {
- parameterList.add(resetValues);
- }
- if (paramSize > 0)
- {
- /**
- * see ClientBehaviorContext.html of the spec
- * the param list has to be added in the post back
- */
- // params are in 99% RamdonAccess instace created in
- // HtmlRendererUtils.getClientBehaviorContextParameters(Map<String, String>)
- if (params instanceof RandomAccess)
- {
- List<ClientBehaviorContext.Parameter> list = (List<ClientBehaviorContext.Parameter>) params;
- for (int i = 0, size = list.size(); i < size; i++)
- {
- ClientBehaviorContext.Parameter param = list.get(i);
- append(paramBuffer, parameterList, param);
- }
- }
- else
- {
- for (ClientBehaviorContext.Parameter param : params)
- {
- append(paramBuffer, parameterList, param);
- }
- }
- }
-
- paramBuffer.setLength(0);
- paramBuffer.append('\'');
- paramBuffer.append(ClientBehaviorContext.BEHAVIOR_EVENT_PARAM_NAME);
- paramBuffer.append('\'');
- paramBuffer.append(':');
- paramBuffer.append('\'');
- paramBuffer.append(event);
- paramBuffer.append('\'');
- parameterList.add(paramBuffer.toString());
-
- /**
- * I assume here for now that the options are the same which also
- * can be sent via the options attribute to javax.faces.ajax
- * this still needs further clarifications but I assume so for now
- */
- retVal.append(buildOptions(paramBuffer, parameterList));
-
- retVal.append(')');
-
- return retVal;
- }
-
- private void append(StringBuilder paramBuffer, List<String> parameterList, ClientBehaviorContext.Parameter param)
- {
- // Both name and value should be quoted
- paramBuffer.setLength(0);
- paramBuffer.append('\'');
- paramBuffer.append(param.getName());
- paramBuffer.append('\'');
- paramBuffer.append(':');
- paramBuffer.append('\'');
- paramBuffer.append(param.getValue().toString());
- paramBuffer.append('\'');
- parameterList.add(paramBuffer.toString());
- }
-
-
- private StringBuilder buildOptions(StringBuilder retVal, List<String> options)
- {
- retVal.setLength(0);
-
- retVal.append('{');
-
- boolean first = true;
-
- for (int i = 0, size = options.size(); i < size; i++)
- {
- String option = options.get(i);
- if (StringUtils.isNotBlank(option))
- {
- if (!first)
- {
- retVal.append(',');
- }
- else
- {
- first = false;
- }
- retVal.append(option);
- }
- }
- retVal.append('}');
- return retVal;
- }
-
- private String mapToString(ClientBehaviorContext context, StringBuilder retVal,
- String target, Collection<String> dataHolder)
- {
- //Clear buffer
- retVal.setLength(0);
-
- if (dataHolder == null)
- {
- dataHolder = Collections.emptyList();
- }
-
- int executeSize = dataHolder.size();
- if (executeSize > 0)
- {
- retVal.append(target);
- retVal.append(':');
- retVal.append('\'');
-
- int cnt = 0;
-
- SearchExpressionContext searchExpressionContext = null;
-
- // perf: dataHolder is a Collection : ajaxBehaviour.getExecute()
- // and ajaxBehaviour.getRender() API
- // In most cases comes here a ArrayList, because
- // javax.faces.component.behavior.AjaxBehavior.getCollectionFromSpaceSplitString
- // creates it.
- if (dataHolder instanceof RandomAccess)
- {
- List<String> list = (List<String>) dataHolder;
- for (; cnt < executeSize; cnt++)
- {
- if (searchExpressionContext == null)
- {
- searchExpressionContext = SearchExpressionContext.createSearchExpressionContext(
- context.getFacesContext(), context.getComponent(),
- MyFacesSearchExpressionHints.SET_RESOLVE_CLIENT_SIDE_RESOLVE_SINGLE_COMPONENT, null);
- }
-
- String strVal = list.get(cnt);
- build(context, executeSize, retVal, cnt, strVal, searchExpressionContext);
- }
- }
- else
- {
- for (String strVal : dataHolder)
- {
- if (searchExpressionContext == null)
- {
- searchExpressionContext = SearchExpressionContext.createSearchExpressionContext(
- context.getFacesContext(), context.getComponent(),
- MyFacesSearchExpressionHints.SET_RESOLVE_CLIENT_SIDE_RESOLVE_SINGLE_COMPONENT, null);
- }
-
- cnt++;
- build(context, executeSize, retVal, cnt, strVal, searchExpressionContext);
- }
- }
-
- retVal.append('\'');
- return retVal.toString();
- }
- return null;
-
- }
-
- public void build(ClientBehaviorContext context,
- int size, StringBuilder retVal, int cnt,
- String strVal, SearchExpressionContext searchExpressionContext)
- {
- if (StringUtils.isNotBlank(strVal))
- {
- SearchExpressionHandler handler = context.getFacesContext().getApplication().getSearchExpressionHandler();
- String clientId = handler.resolveClientId(searchExpressionContext, strVal.trim());
- retVal.append(clientId);
- if (cnt < size)
- {
- retVal.append(' ');
- }
- }
- }
-
private void assertBehavior(ClientBehavior behavior)
{
if (!(behavior instanceof AjaxBehavior))
diff --git a/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlCommandScriptRenderer.java b/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlCommandScriptRenderer.java
index a8afb13..643be6b 100644
--- a/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlCommandScriptRenderer.java
+++ b/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlCommandScriptRenderer.java
@@ -20,24 +20,19 @@
package org.apache.myfaces.renderkit.html;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Map;
-import java.util.RandomAccess;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.UIParameter;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.component.behavior.ClientBehaviorHolder;
import javax.faces.component.html.HtmlCommandScript;
-import javax.faces.component.search.SearchExpressionContext;
-import javax.faces.component.search.SearchExpressionHandler;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.ActionEvent;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFRenderer;
-import org.apache.myfaces.component.search.MyFacesSearchExpressionHints;
+import org.apache.myfaces.renderkit.html.base.AjaxScriptBuilder;
import org.apache.myfaces.renderkit.html.base.ClientBehaviorRendererUtils;
import org.apache.myfaces.renderkit.html.util.HTML;
import org.apache.myfaces.renderkit.html.base.HtmlRenderer;
@@ -52,17 +47,7 @@
@JSFRenderer(renderKitId = "HTML_BASIC", family = "javax.faces.Command", type = "javax.faces.Script")
public class HtmlCommandScriptRenderer extends HtmlRenderer
{
- private static final String AJAX_KEY_ONERROR = "onerror";
- private static final String AJAX_KEY_ONEVENT = "onevent";
- private static final String AJAX_KEY_EXECUTE = "execute";
- private static final String AJAX_KEY_RENDER = "render";
- private static final String AJAX_KEY_RESETVALUES = "resetValues";
-
- private static final String AJAX_VAL_THIS = "this";
- private static final String JS_AJAX_REQUEST = "jsf.ajax.request";
-
private static final String AJAX_SB = "oam.renderkit.AJAX_SB";
- private static final String AJAX_PARAM_SB = "oam.renderkit.AJAX_PARAM_SB";
@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException
@@ -98,14 +83,24 @@
script.append("var "+name+" = function(o){var o=(typeof o==='object')&&o?o:{};");
script.prettyLine();
+ List<UIParameter> uiParams = HtmlRendererUtils.getValidUIParameterChildren(
+ context, getChildren(commandScript), false, false);
- Collection<ClientBehaviorContext.Parameter> eventParameters = null;
- //eventParameters.add(new ClientBehaviorContext.Parameter("params", "o"));
- ClientBehaviorContext ccc = ClientBehaviorContext.createClientBehaviorContext(
- context, component, "action",
- commandScript.getClientId(context), eventParameters);
-
- script.append(makeAjax(context, ccc, commandScript).toString());
+ StringBuilder ajax = SharedStringBuilder.get(context, AJAX_SB, 60);
+
+ AjaxScriptBuilder.build(context,
+ ajax,
+ commandScript,
+ commandScript.getClientId(context),
+ "action",
+ commandScript.getExecute(),
+ commandScript.getRender(),
+ commandScript.getResetValues(),
+ commandScript.getOnerror(),
+ commandScript.getOnevent(),
+ uiParams);
+
+ script.append(ajax.toString());
script.decreaseIndent();
script.append("}");
@@ -183,270 +178,4 @@
ClientBehaviorRendererUtils.decodeClientBehaviors(facesContext, component);
}
}
-
- /**
- * builds the generic ajax call depending upon
- * the ajax behavior parameters
- *
- * @param context the Client behavior context
- * @param behavior the behavior
- * @param commandScript the component
- * @return a fully working javascript with calls into jsf.js
- */
- private StringBuilder makeAjax(FacesContext facesContext, ClientBehaviorContext context,
- HtmlCommandScript commandScript)
- {
- StringBuilder retVal = SharedStringBuilder.get(context.getFacesContext(), AJAX_SB, 60);
- StringBuilder paramBuffer = SharedStringBuilder.get(context.getFacesContext(), AJAX_PARAM_SB, 20);
-
- SearchExpressionContext searchExpressionContext = SearchExpressionContext.createSearchExpressionContext(
- context.getFacesContext(), context.getComponent(),
- MyFacesSearchExpressionHints.SET_RESOLVE_CLIENT_SIDE_RESOLVE_SINGLE_COMPONENT, null);
-
- String executes = resolveExpressionsAsParameter(paramBuffer, AJAX_KEY_EXECUTE, commandScript.getExecute(),
- searchExpressionContext);
- String render = resolveExpressionsAsParameter(paramBuffer, AJAX_KEY_RENDER, commandScript.getRender(),
- searchExpressionContext);
-
- String onError = commandScript.getOnerror();
- if (StringUtils.isNotBlank(onError))
- {
- paramBuffer.setLength(0);
- paramBuffer.append(AJAX_KEY_ONERROR);
- paramBuffer.append(':');
- paramBuffer.append(onError);
- onError = paramBuffer.toString();
- }
- else
- {
- onError = null;
- }
-
- String onEvent = commandScript.getOnevent();
- if (StringUtils.isNotBlank(onEvent))
- {
- paramBuffer.setLength(0);
- paramBuffer.append(AJAX_KEY_ONEVENT);
- paramBuffer.append(':');
- paramBuffer.append(onEvent);
- onEvent = paramBuffer.toString();
- }
- else
- {
- onEvent = null;
- }
-
- String resetValues = null;
- if (Boolean.TRUE.equals(commandScript.getResetValues()))
- {
- paramBuffer.setLength(0);
- paramBuffer.append(AJAX_KEY_RESETVALUES);
- paramBuffer.append(':');
- paramBuffer.append("true");
- resetValues = paramBuffer.toString();
- }
-
- String sourceId = null;
- if (context.getSourceId() == null)
- {
- sourceId = AJAX_VAL_THIS;
- }
- else
- {
- paramBuffer.setLength(0);
- paramBuffer.append('\'');
- paramBuffer.append(context.getSourceId());
- paramBuffer.append('\'');
- sourceId = paramBuffer.toString();
-
- if (!context.getSourceId().trim().equals(
- context.getComponent().getClientId(context.getFacesContext())))
- {
- // Check if sourceId is not a clientId and there is no execute set
- UIComponent ref = context.getComponent();
- ref = (ref.getParent() == null) ? ref : ref.getParent();
- UIComponent instance = null;
- try
- {
- instance = ref.findComponent(context.getSourceId());
- }
- catch (IllegalArgumentException e)
- {
- // No Op
- }
- if (instance == null && executes == null)
- {
- // set the clientId of the component so the behavior can be decoded later,
- // otherwise the behavior will fail
- executes = resolveExpressionsAsParameter(paramBuffer, AJAX_KEY_EXECUTE,
- context.getComponent().getClientId(context.getFacesContext()), searchExpressionContext);
- }
- }
- }
-
- String event = context.getEventName();
-
- retVal.append(JS_AJAX_REQUEST);
- retVal.append('(');
- retVal.append(sourceId);
- retVal.append(",window.event,myfaces._impl._util._Lang.mixMaps(");
-
- Collection<ClientBehaviorContext.Parameter> params = context.getParameters();
- int paramSize = (params != null) ? params.size() : 0;
-
- List<String> parameterList = new ArrayList<>(paramSize + 2);
- if (executes != null)
- {
- parameterList.add(executes);
- }
- if (render != null)
- {
- parameterList.add(render);
- }
- if (onError != null)
- {
- parameterList.add(onError);
- }
- if (onEvent != null)
- {
- parameterList.add(onEvent);
- }
- if (resetValues != null)
- {
- parameterList.add(resetValues);
- }
- if (paramSize > 0)
- {
- /**
- * see ClientBehaviorContext.html of the spec
- * the param list has to be added in the post back
- */
- // params are in 99% RamdonAccess instace created in
- // HtmlRendererUtils.getClientBehaviorContextParameters(Map<String, String>)
- if (params instanceof RandomAccess)
- {
- List<ClientBehaviorContext.Parameter> list = (List<ClientBehaviorContext.Parameter>) params;
- for (int i = 0, size = list.size(); i < size; i++)
- {
- ClientBehaviorContext.Parameter param = list.get(i);
- append(paramBuffer, parameterList, param.getName(), param.getValue());
- }
- }
- else
- {
- for (ClientBehaviorContext.Parameter param : params)
- {
- append(paramBuffer, parameterList, param.getName(), param.getValue());
- }
- }
- }
-
- List<UIParameter> uiParams = HtmlRendererUtils.getValidUIParameterChildren(
- facesContext, getChildren(commandScript), false, false);
- if (uiParams != null && uiParams.size() > 0)
- {
- for (int i = 0, size = uiParams.size(); i < size; i++)
- {
- UIParameter param = uiParams.get(i);
- append(paramBuffer, parameterList, param.getName(), param.getValue());
- }
- }
-
- paramBuffer.setLength(0);
- paramBuffer.append('\'');
- paramBuffer.append(ClientBehaviorContext.BEHAVIOR_EVENT_PARAM_NAME);
- paramBuffer.append("\':\'");
- paramBuffer.append(event);
- paramBuffer.append('\'');
- parameterList.add(paramBuffer.toString());
-
- /**
- * I assume here for now that the options are the same which also
- * can be sent via the options attribute to javax.faces.ajax
- * this still needs further clarifications but I assume so for now
- */
- retVal.append(buildOptions(paramBuffer, parameterList));
-
- //mixMaps
- retVal.append(",o,false))");
-
- return retVal;
- }
-
- private void append(StringBuilder paramBuffer, List<String> parameterList, String paramName, Object paramValue)
- {
- //Both name and value should be quoted
- paramBuffer.setLength(0);
- paramBuffer.append('\'');
- paramBuffer.append(paramName);
- paramBuffer.append("\':\'");
- if (paramValue != null)
- {
- paramBuffer.append(paramValue.toString());
- }
- paramBuffer.append('\'');
- parameterList.add(paramBuffer.toString());
- }
-
- private StringBuilder buildOptions(StringBuilder retVal, List<String> options)
- {
- retVal.setLength(0);
-
- retVal.append('{');
-
- boolean first = true;
-
- for (int i = 0, size = options.size(); i < size; i++)
- {
- String option = options.get(i);
- if (StringUtils.isNotBlank(option))
- {
- if (!first)
- {
- retVal.append(',');
- }
- else
- {
- first = false;
- }
- retVal.append(option);
- }
- }
- retVal.append('}');
- return retVal;
- }
-
- private String resolveExpressionsAsParameter(StringBuilder retVal, String target, String expressions,
- SearchExpressionContext searchExpressionContext)
- {
- if (StringUtils.isNotBlank(expressions))
- {
- retVal.setLength(0);
- retVal.append(target);
- retVal.append(':');
- retVal.append('\'');
-
- SearchExpressionHandler handler =
- searchExpressionContext.getFacesContext().getApplication().getSearchExpressionHandler();
- List<String> clientIds =
- handler.resolveClientIds(searchExpressionContext, expressions);
-
- if (clientIds != null && !clientIds.isEmpty())
- {
- for (int i = 0; i < clientIds.size(); i++)
- {
- if (i > 0)
- {
- retVal.append(' ');
- }
- retVal.append(clientIds.get(i));
- }
- }
-
- retVal.append('\'');
- return retVal.toString();
- }
-
- return null;
- }
}
diff --git a/impl/src/main/java/org/apache/myfaces/renderkit/html/base/AjaxScriptBuilder.java b/impl/src/main/java/org/apache/myfaces/renderkit/html/base/AjaxScriptBuilder.java
new file mode 100644
index 0000000..6aba964
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/renderkit/html/base/AjaxScriptBuilder.java
@@ -0,0 +1,322 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.renderkit.html.base;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIParameter;
+import javax.faces.component.behavior.ClientBehaviorContext;
+import javax.faces.component.html.HtmlCommandScript;
+import javax.faces.component.search.SearchExpressionContext;
+import javax.faces.component.search.SearchExpressionHandler;
+import javax.faces.context.FacesContext;
+import org.apache.myfaces.component.search.MyFacesSearchExpressionHints;
+import org.apache.myfaces.util.lang.StringUtils;
+
+// CHECKSTYLE:OFF
+public class AjaxScriptBuilder
+{
+ public static void build(FacesContext context,
+ StringBuilder sb,
+ UIComponent component,
+ String sourceId,
+ String eventName,
+ String execute,
+ String render,
+ Boolean resetValues,
+ String onerror,
+ String onevent,
+ List<UIParameter> uiParams)
+ {
+ build(context,
+ sb,
+ component,
+ sourceId,
+ eventName,
+ execute,
+ render,
+ null,
+ Boolean.TRUE.equals(resetValues) ? Boolean.TRUE.toString() : null,
+ onerror,
+ onevent,
+ null,
+ uiParams);
+ }
+
+ public static void build(FacesContext context,
+ StringBuilder sb,
+ UIComponent component,
+ String sourceId,
+ String eventName,
+ Collection<String> executeList,
+ Collection<String> renderList,
+ String delay,
+ boolean resetValues,
+ String onerror,
+ String onevent,
+ Collection<ClientBehaviorContext.Parameter> params)
+ {
+ String execute = null;
+ if (executeList != null && !executeList.isEmpty())
+ {
+ execute = String.join(" ", executeList);
+ }
+
+ String render = null;
+ if (renderList != null && !renderList.isEmpty())
+ {
+ render = String.join(" ", renderList);
+ }
+
+ build(context,
+ sb,
+ component,
+ sourceId,
+ eventName,
+ execute,
+ render,
+ delay,
+ resetValues ? Boolean.TRUE.toString() : null,
+ onerror,
+ onevent,
+ params,
+ null);
+ }
+
+ public static void build(FacesContext context,
+ StringBuilder sb,
+ UIComponent component,
+ String sourceId,
+ String eventName,
+ String execute,
+ String render,
+ String delay,
+ String resetValues,
+ String onerror,
+ String onevent,
+ Collection<ClientBehaviorContext.Parameter> params,
+ List<UIParameter> uiParams)
+ {
+ // CHECKSTYLE:ON
+ HtmlCommandScript commandScript = (component instanceof HtmlCommandScript)
+ ? (HtmlCommandScript) component
+ : null;
+
+ sb.append("myfaces.ab(");
+
+ if (sourceId == null)
+ {
+ sb.append("this");
+ }
+ else
+ {
+ sb.append("'");
+ sb.append(sourceId);
+ sb.append("'");
+
+ if (!sourceId.trim().equals(component.getClientId(context)))
+ {
+ // Check if sourceId is not a clientId and there is no execute set
+ UIComponent ref = (component.getParent() == null) ? component : component.getParent();
+ UIComponent instance = null;
+ try
+ {
+ instance = ref.findComponent(sourceId);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // No Op
+ }
+ if (instance == null && execute == null)
+ {
+ // set the clientId of the component so the behavior can be decoded later,
+ // otherwise the behavior will fail
+ execute = component.getClientId(context);
+ }
+ }
+ }
+ sb.append(",");
+
+ sb.append(commandScript == null ? "event" : "null");
+ sb.append(",'");
+
+ sb.append(eventName);
+ sb.append("',");
+
+ SearchExpressionHandler seHandler = context.getApplication().getSearchExpressionHandler();
+ SearchExpressionContext seContext = SearchExpressionContext.createSearchExpressionContext(
+ context, component,
+ MyFacesSearchExpressionHints.SET_RESOLVE_CLIENT_SIDE_RESOLVE_SINGLE_COMPONENT, null);
+
+ appendIds(sb, execute, seHandler, seContext);
+ sb.append(",");
+
+ appendIds(sb, render, seHandler, seContext);
+
+ if (onevent != null || onerror != null || delay != null || resetValues != null
+ || (params != null && !params.isEmpty()) || (uiParams != null && !uiParams.isEmpty()))
+ {
+ sb.append(",{");
+ if (onevent != null)
+ {
+ appendProperty(sb, "onevent", onevent, false);
+ }
+ if (onerror != null)
+ {
+ appendProperty(sb, "onerror", onerror, false);
+ }
+ if (delay != null)
+ {
+ appendProperty(sb, "delay", delay, true);
+ }
+ if (resetValues != null)
+ {
+ appendProperty(sb, "resetValues", resetValues, false);
+ }
+ if (params != null && !params.isEmpty())
+ {
+ if (commandScript != null)
+ {
+ appendProperty(sb, "params", params.iterator().next().getName(), false);
+ }
+ else
+ {
+ appendProperty(sb, "params", "{", false);
+
+ if (params instanceof RandomAccess)
+ {
+ List<ClientBehaviorContext.Parameter> list = (List<ClientBehaviorContext.Parameter>) params;
+ for (int i = 0, size = list.size(); i < size; i++)
+ {
+ ClientBehaviorContext.Parameter param = list.get(i);
+ appendProperty(sb, param.getName(), param.getValue(), true);
+ }
+ }
+ else
+ {
+ for (ClientBehaviorContext.Parameter param : params)
+ {
+ appendProperty(sb, param.getName(), param.getValue(), true);
+ }
+ }
+
+ sb.append("}");
+ }
+ }
+ if (uiParams != null && uiParams.size() > 0)
+ {
+ for (int i = 0, size = uiParams.size(); i < size; i++)
+ {
+ UIParameter param = uiParams.get(i);
+ appendProperty(sb, param.getName(), param.getValue(), true);
+ }
+ }
+
+ sb.append("}");
+ }
+
+ sb.append(")");
+ }
+
+ private static void appendIds(StringBuilder sb, String expressions,
+ SearchExpressionHandler handler, SearchExpressionContext searchExpressionContext)
+ {
+ sb.append('\'');
+
+ if (StringUtils.isNotBlank(expressions))
+ {
+ List<String> clientIds =
+ handler.resolveClientIds(searchExpressionContext, expressions);
+
+ if (clientIds != null && !clientIds.isEmpty())
+ {
+ for (int i = 0; i < clientIds.size(); i++)
+ {
+ if (i > 0)
+ {
+ sb.append(' ');
+ }
+ sb.append(clientIds.get(i));
+ }
+ }
+ }
+
+ sb.append('\'');
+ }
+
+ // Appends an name/value property pair to a JSON object. Assumes
+ // object has already been opened by the caller.
+ public static void appendProperty(StringBuilder builder,
+ String name,
+ Object value,
+ boolean quoteValue)
+ {
+ if ((null == name) || (name.length() == 0))
+ {
+ throw new IllegalArgumentException();
+ }
+
+ char lastChar = builder.charAt(builder.length() - 1);
+ if ((lastChar != ',') && (lastChar != '{'))
+ {
+ builder.append(',');
+ }
+
+ appendQuotedValue(builder, name);
+ builder.append(":");
+
+ if (value == null)
+ {
+ builder.append("''");
+ }
+ else if (quoteValue)
+ {
+ appendQuotedValue(builder, value.toString());
+ }
+ else
+ {
+ builder.append(value.toString());
+ }
+ }
+
+ // Append a script to the chain, escaping any single quotes, since
+ // our script content is itself nested within single quotes.
+ public static void appendQuotedValue(StringBuilder builder, String script)
+ {
+ builder.append("'");
+
+ int length = script.length();
+
+ for (int i = 0; i < length; i++)
+ {
+ char c = script.charAt(i);
+
+ if (c == '\'' || c == '\\')
+ {
+ builder.append('\\');
+ }
+
+ builder.append(c);
+ }
+
+ builder.append("'");
+ }
+}