blob: abdcdbc4e5712218b57751f440b26a893e470ad6 [file] [log] [blame]
/*
* 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.html5.renderkit.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.component.behavior.ClientBehaviorHint;
import javax.faces.component.behavior.ClientBehaviorHolder;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.myfaces.commons.util.DebugUtils;
/**
* @author Ali Ok
*/
public class Html5RendererUtils
{
private static final List<String> BOOLEAN_BUT_NOT_HTML5_BOOLEAN_ATTRS = Arrays.asList(HTML5.CONTENTEDITABLE_ATTR,
HTML5.DRAGGABLE_ATTR, HTML5.SPELLCHECK_ATTR);
private static final String HTML_EVENT_ATTR_PREFIX = "on";
private static final String DEFAULT_WIDGET_PREFIX = "widget_";
private static final String LINE_SEPARATOR = System.getProperty("line.separator", "\r\n");
private static final char TABULATOR = '\t';
public static final String NON_SUBMITTED_VALUE_WARNING
= "There should always be a submitted value for an input if it is rendered,"
+ " its form is submitted, and it was not originally rendered disabled or read-only."
+ " You cannot submit a form after disabling an input element via javascript."
+ " Consider setting read-only to true instead"
+ " or resetting the disabled value back to false prior to form submission.";
private static final Logger log = Logger.getLogger(Html5RendererUtils.class.getName());
/**
* Renders the pass through attributes of the component. Value of the JSF properties will be written with the
* matching Html attribute name.
*
* @param writer
* @param component
* @param passThruAttrs
* map that holds jsf property names as keys and html attribute names as values matched.
*
* @return true, if an attribute was written
* @throws java.io.IOException
*/
public static boolean renderPassThroughAttributes(ResponseWriter writer, UIComponent component,
Map<String, String> passThruAttrs) throws IOException
{
boolean somethingDone = false;
Set<String> passThruJsfProperties = passThruAttrs.keySet();
for (String passThruJsfPropertyName : passThruJsfProperties)
{
String passThruHtmlAttrName = passThruAttrs.get(passThruJsfPropertyName);
Object value = component.getAttributes().get(passThruJsfPropertyName);
if (renderHTMLAttribute(writer, passThruJsfPropertyName, passThruHtmlAttrName, value))
{
somethingDone = true;
}
}
return somethingDone;
}
/**
* Renders the attribute if the value is not the default value defined in the component. <br/>
* For three Html5 attributes (draggable, contenteditable and spellcheck), "true" will be written instead of the
* attribute's name as the value if the value is true. This behavior is necessary, since Html5 spec does not define
* those attributes as "Boolean Attribute"s. <br/>
* See related sections of Html5 spec for more:
* <ul>
* <li><a href="http://www.whatwg.org/specs/web-apps/current-work/#boolean-attribute">Boolean Attribute</a></li>
* <li><a
* href="http://www.whatwg.org/specs/web-apps/current-work/multipage/section-index.html#attributes-1">Attributes</a>
* </li>
* </ul>
*
* @return true, if the attribute was written
* @throws java.io.IOException
*/
public static boolean renderHTMLAttribute(ResponseWriter writer, String componentProperty, String attrName,
Object value) throws IOException
{
if (!RendererUtils.isDefaultAttributeValue(value))
{
if (BOOLEAN_BUT_NOT_HTML5_BOOLEAN_ATTRS.contains(attrName))
{
/*
* these attrs are not Html5 "Booolean Attribute"s : contenteditable draggable spellcheck
* http://www.whatwg.org/specs/web-apps/current-work/#boolean-attribute
* http://www.whatwg.org/specs/web-apps/current-work/multipage/section-index.html#attributes-1
*
* so draggable="draggable" is a syntax error. for these attrs, we need to render ="true" like
* draggable="true". so, to prevent writer.writeAttribute(...) render that, this is the workaround!
*
* XXX: file a ticket on JIRA for this issue
*/
if (value instanceof Boolean)
{
value = String.valueOf(((Boolean) value).booleanValue());
}
}
writer.writeAttribute(attrName, value, componentProperty);
return true;
}
return false;
}
/**
* Renders the client behavior event handlers for the component by investigating both client behaviors and values of
* the behaviorized attributes.
*/
public static void renderPassThroughClientBehaviorEventHandlers(FacesContext facesContext, UIComponent uiComponent,
Map<String, String> passThroughClientBehaviors, Map<String, List<ClientBehavior>> clientBehaviors)
throws IOException
{
Set<String> keySet = passThroughClientBehaviors.keySet();
for (String property : keySet)
{
String eventName = passThroughClientBehaviors.get(property);
String htmlAttrName = HTML_EVENT_ATTR_PREFIX + eventName;
renderBehaviorizedAttribute(facesContext,
facesContext.getResponseWriter(), property, uiComponent, eventName, clientBehaviors, htmlAttrName);
}
}
public static boolean renderBehaviorizedOnchangeEventHandler(
FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
Map<String, List<ClientBehavior>> clientBehaviors) throws IOException {
boolean hasChange = Html5RendererUtils.hasClientBehavior(ClientBehaviorEvents.CHANGE_EVENT, clientBehaviors, facesContext);
boolean hasValueChange = Html5RendererUtils.hasClientBehavior(ClientBehaviorEvents.VALUECHANGE_EVENT, clientBehaviors, facesContext);
if (hasChange && hasValueChange) {
String chain = Html5RendererUtils.buildBehaviorChain(facesContext,
uiComponent, ClientBehaviorEvents.CHANGE_EVENT, null, ClientBehaviorEvents.VALUECHANGE_EVENT, null, clientBehaviors,
(String) uiComponent.getAttributes().get(JsfProperties.ONCHANGE_PROP), null);
return Html5RendererUtils.renderHTMLAttribute(writer, JsfProperties.ONCHANGE_PROP, JsfProperties.ONCHANGE_PROP, chain);
} else if (hasChange) {
return Html5RendererUtils.renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONCHANGE_PROP, uiComponent,
ClientBehaviorEvents.CHANGE_EVENT, clientBehaviors, JsfProperties.ONCHANGE_PROP);
} else if (hasValueChange) {
return Html5RendererUtils.renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONCHANGE_PROP, uiComponent,
ClientBehaviorEvents.VALUECHANGE_EVENT, clientBehaviors, JsfProperties.ONCHANGE_PROP);
} else {
return Html5RendererUtils.renderHTMLAttribute(writer, JsfProperties.ONCHANGE_PROP, JsfProperties.ONCHANGE_PROP, uiComponent.getAttributes().get(JsfProperties.ONCHANGE_PROP));
}
}
public static void renderBehaviorizedEventHandlers(
FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
Map<String, List<ClientBehavior>> clientBehaviors) throws IOException {
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONCLICK_PROP, uiComponent,
ClientBehaviorEvents.CLICK_EVENT, clientBehaviors, JsfProperties.ONCLICK_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONDBLCLICK_PROP, uiComponent,
ClientBehaviorEvents.DBLCLICK_EVENT, clientBehaviors, JsfProperties.ONDBLCLICK_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONMOUSEDOWN_PROP, uiComponent,
ClientBehaviorEvents.MOUSEDOWN_EVENT, clientBehaviors, JsfProperties.ONMOUSEDOWN_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONMOUSEUP_PROP, uiComponent,
ClientBehaviorEvents.MOUSEUP_EVENT, clientBehaviors, JsfProperties.ONMOUSEUP_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONMOUSEOVER_PROP, uiComponent,
ClientBehaviorEvents.MOUSEOVER_EVENT, clientBehaviors, JsfProperties.ONMOUSEOVER_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONMOUSEMOVE_PROP, uiComponent,
ClientBehaviorEvents.MOUSEMOVE_EVENT, clientBehaviors, JsfProperties.ONMOUSEMOVE_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONMOUSEOUT_PROP, uiComponent,
ClientBehaviorEvents.MOUSEOUT_EVENT, clientBehaviors, JsfProperties.ONMOUSEOUT_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONKEYPRESS_PROP, uiComponent,
ClientBehaviorEvents.KEYPRESS_EVENT, clientBehaviors, JsfProperties.ONKEYPRESS_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONKEYDOWN_PROP, uiComponent,
ClientBehaviorEvents.KEYDOWN_EVENT, clientBehaviors, JsfProperties.ONKEYDOWN_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONKEYUP_PROP, uiComponent,
ClientBehaviorEvents.KEYUP_EVENT, clientBehaviors, JsfProperties.ONKEYUP_PROP);
}
public static void renderBehaviorizedFieldEventHandlersWithoutOnchange(
FacesContext facesContext, ResponseWriter writer, UIComponent uiComponent,
Map<String, List<ClientBehavior>> clientBehaviors) throws IOException {
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONFOCUS_PROP, uiComponent,
ClientBehaviorEvents.FOCUS_EVENT, clientBehaviors, JsfProperties.ONFOCUS_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONBLUR_PROP, uiComponent,
ClientBehaviorEvents.BLUR_EVENT, clientBehaviors, JsfProperties.ONBLUR_PROP);
renderBehaviorizedAttribute(facesContext, writer, JsfProperties.ONSELECT_PROP, uiComponent,
ClientBehaviorEvents.SELECT_EVENT, clientBehaviors, JsfProperties.ONSELECT_PROP);
}
public static boolean hasClientBehavior(String eventName,
Map<String, List<ClientBehavior>> behaviors,
FacesContext facesContext) {
if (behaviors == null) {
return false;
}
return (behaviors.get(eventName) != null);
}
/**
* Resolves string values from comma separated strings, string arrays or string collections.
*
* @param value
* @return null if value param is null or empty
* @throws IllegalArgumentException
* if value is not comma separated strings or String[] or Collection<String>.
* @see Html5RendererUtils#resolveStrings(Object, String[])
*/
public static String[] resolveStrings(Object value) throws IllegalArgumentException
{
return resolveStrings(value, null);
}
/**
* Resolves string values from comma separated strings, string arrays or string collections.
*
* @param value
* Object to resolve
* @param defaultValue
* Return value if value param is null or empty
* @throws IllegalArgumentException
* if value is not comma separated strings or String[] or Collection<String>.
*/
@SuppressWarnings("unchecked")
public static String[] resolveStrings(Object value, String[] defaultValue) throws IllegalArgumentException
{
if (value == null)
{
return defaultValue;
}
Collection<String> valuesCollection = null;
if (value instanceof String)
{
String strValues = (String) value;
if (strValues.length() == 0)
return defaultValue;
// if value is comma separated words, split it
String[] strValueElements = strValues.split(",");
valuesCollection = new ArrayList<String>(strValueElements.length);
for (String strValueElement : strValueElements)
{
strValueElement = strValueElement.trim();
if (strValueElement.length() > 0)
valuesCollection.add(strValueElement);
}
}
else if (value instanceof String[])
{
valuesCollection = Arrays.asList((String[]) value);
}
else if (value instanceof Collection<?>)
{
valuesCollection = (Collection<String>) value;
}
else
{
throw new IllegalArgumentException(
"Value should be one of comma separeted strings, String[] or Collection of \"String\"s");
}
try
{
if (valuesCollection.isEmpty())
return defaultValue;
else
return valuesCollection.toArray(new String[0]);
}
catch (ArrayStoreException e)
{
// if there is one non-String element in the collection, we'll fall in here during conversion to array.
throw new IllegalArgumentException("All elements of the value must be an instance of String.", e);
}
}
/**
* Escapes the given string for use as a CSS selector.
* @return Escaped selector
*/
public static String escapeCssSelector(String selector) {
if(selector==null)
return null;
return selector.replace(":", "\\:");
}
public static String getTimeValue(String s) {
if(StringUtils.isBlank(s))
return null;
else if(s.endsWith("s") || s.endsWith("ms"))
return s;
else
return s + "s";
}
public static String generateWidgetVar(String clientId){
return DEFAULT_WIDGET_PREFIX + escapeJavaScriptVariableName(clientId);
}
private static String escapeJavaScriptVariableName(String str) {
if(str==null)
return null;
return str.replace(":", "_");
}
/**
* @since 4.0.0
* @param facesContext
* @param component
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static void decodeClientBehaviors(FacesContext facesContext,
UIComponent component)
{
if (component instanceof ClientBehaviorHolder)
{
ClientBehaviorHolder clientBehaviorHolder = (ClientBehaviorHolder) component;
Map<String,List<ClientBehavior>> clientBehaviors =
clientBehaviorHolder.getClientBehaviors();
if (clientBehaviors != null && !clientBehaviors.isEmpty())
{
Map<String,String> paramMap = facesContext.getExternalContext().
getRequestParameterMap();
String behaviorEventName = paramMap.get("javax.faces.behavior.event");
if (behaviorEventName != null)
{
List<ClientBehavior> clientBehaviorList = clientBehaviors.get(behaviorEventName);
if (clientBehaviorList != null && !clientBehaviorList.isEmpty())
{
String clientId = paramMap.get("javax.faces.source");
if (component.getClientId().equals(clientId))
{
for (ClientBehavior clientBehavior : clientBehaviorList)
{
clientBehavior.decode(facesContext, component);
}
}
}
}
}
}
}
/**
* Render an attribute taking into account the passed event and
* the component property. The event will be rendered on the selected
* htmlAttrName
*
* @param facesContext
* @param writer
* @param component
* @param clientBehaviors
* @param eventName
* @param componentProperty
* @param htmlAttrName
* @return
* @throws IOException
* @since 4.0.1
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static boolean renderBehaviorizedAttribute(
FacesContext facesContext, ResponseWriter writer,
String componentProperty, UIComponent component,
String eventName, Map<String, List<ClientBehavior>> clientBehaviors,
String htmlAttrName) throws IOException {
return renderBehaviorizedAttribute(facesContext, writer,
componentProperty, component,
eventName, null, clientBehaviors,
htmlAttrName, (String) component.getAttributes().get(componentProperty));
}
/**
* Render an attribute taking into account the passed event,
* the component property and the passed attribute value for the component
* property. The event will be rendered on the selected htmlAttrName.
*
* @param facesContext
* @param writer
* @param componentProperty
* @param component
* @param eventName
* @param clientBehaviors
* @param htmlAttrName
* @param attributeValue
* @return
* @throws IOException
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static boolean renderBehaviorizedAttribute(
FacesContext facesContext, ResponseWriter writer,
String componentProperty, UIComponent component,
String eventName, Collection<ClientBehaviorContext.Parameter> eventParameters, Map<String, List<ClientBehavior>> clientBehaviors,
String htmlAttrName, String attributeValue) throws IOException {
List<ClientBehavior> cbl = (clientBehaviors != null) ? clientBehaviors.get(eventName) : null;
if (cbl == null || cbl.size() == 0) {
return renderHTMLAttribute(writer, componentProperty, htmlAttrName, attributeValue);
}
if (cbl.size() > 1 || (cbl.size() == 1 && attributeValue != null)) {
return renderHTMLAttribute(writer, componentProperty, htmlAttrName,
buildBehaviorChain(facesContext,
component, eventName, eventParameters, clientBehaviors,
attributeValue, StringUtils.EMPTY));
} else {
//Only 1 behavior and attrValue == null, so just render it directly
return renderHTMLAttribute(writer, componentProperty, htmlAttrName,
cbl.get(0).getScript(
ClientBehaviorContext
.createClientBehaviorContext(facesContext, component,
eventName, component.getClientId(facesContext),
eventParameters)));
}
}
/**
* @param facesContext
* @param uiComponent
* @param clientBehaviors
* @param eventName
* @param userEventCode
* @param serverEventCode
* @param params
* @return
* @since 4.0.0
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
//modified
public static String buildBehaviorChain(FacesContext facesContext,
UIComponent uiComponent,
String eventName, Collection<ClientBehaviorContext.Parameter> params,
Map<String, List<ClientBehavior>> clientBehaviors,
String userEventCode, String serverEventCode) {
ExternalContext externalContext = facesContext.getExternalContext();
List<String> finalParams = new ArrayList<String>(3);
if(StringUtils.isNotBlank(userEventCode)){
// escape every ' in the user event code since it will
// be a string attribute of jsf.util.chain
finalParams.add('\'' + escapeJavaScriptForChain(userEventCode) + '\'');
}
ScriptContext behaviorCode = new ScriptContext();
ScriptContext retVal = new ScriptContext();
getClientBehaviorScript(facesContext, uiComponent, eventName, clientBehaviors,
behaviorCode, params);
if (behaviorCode!=null && StringUtils.isNotBlank(behaviorCode.toString())) {
finalParams.add(behaviorCode.toString());
}
if (StringUtils.isNotBlank(serverEventCode)) {
finalParams.add('\'' + escapeJavaScriptForChain(serverEventCode) + '\'');
}
Iterator<String> it = finalParams.iterator();
// It's possible that there are no behaviors to render. For example, if we have
// <f:ajax disabled="true" /> as the only behavior.
if (it.hasNext()) {
//according to the spec jsf.util.chain has to be used to build up the behavior and scripts
retVal.append("jsf.util.chain(document.getElementById('"
+ uiComponent.getClientId(facesContext) + "'), event,");
while (it.hasNext()) {
retVal.append(it.next());
if (it.hasNext()) {
retVal.append(", ");
}
}
retVal.append(");");
}
return retVal.toString();
}
public static String buildBehaviorChain(FacesContext facesContext,
UIComponent uiComponent,
String eventName1, Collection<ClientBehaviorContext.Parameter> params,
String eventName2, Collection<ClientBehaviorContext.Parameter> params2,
Map<String, List<ClientBehavior>> clientBehaviors,
String userEventCode,
String serverEventCode) {
List<String> finalParams = new ArrayList<String>(3);
if (StringUtils.isNotBlank(userEventCode)) {
finalParams.add('\'' + escapeJavaScriptForChain(userEventCode) + '\'');
}
ScriptContext behaviorCode = new ScriptContext();
ScriptContext retVal = new ScriptContext();
boolean submitting1 = getClientBehaviorScript(facesContext, uiComponent, eventName1, clientBehaviors,
behaviorCode, params);
boolean submitting2 = getClientBehaviorScript(facesContext, uiComponent, eventName2, clientBehaviors,
behaviorCode, params2);
// ClientBehaviors for both events have to be checked for the Submitting hint
boolean submitting = submitting1 || submitting2;
if (StringUtils.isNotBlank(behaviorCode.toString())) {
finalParams.add(behaviorCode.toString());
}
if (StringUtils.isNotBlank(serverEventCode)) {
finalParams.add('\'' + escapeJavaScriptForChain(serverEventCode) + '\'');
}
Iterator<String> it = finalParams.iterator();
// It's possible that there are no behaviors to render. For example, if we have
// <f:ajax disabled="true" /> as the only behavior.
if (it.hasNext()) {
if (!submitting) {
retVal.append("return ");
}
//according to the spec jsf.util.chain has to be used to build up the behavior and scripts
retVal.append("jsf.util.chain(document.getElementById('"
+ uiComponent.getClientId(facesContext) + "'), event,");
while (it.hasNext()) {
retVal.append(it.next());
if (it.hasNext()) {
retVal.append(", ");
}
}
retVal.append(");");
if (submitting) {
retVal.append(" return false;");
}
}
return retVal.toString();
}
/**
* builds the chained behavior script which then can be reused
* in following order by the other script building parts
* <p/>
* user defined event handling script
* behavior script
* renderer default script
*
* @param eventName event name ("onclick" etc...)
* @param uiComponent the component which has the attachement (or should have)
* @param facesContext the facesContext
* @param params params map of params which have to be dragged into the request
* @return a string representation of the javascripts for the attached event behavior, an empty string if none is present
* @since 4.0.0
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
//modified
private static boolean getClientBehaviorScript(FacesContext facesContext,
UIComponent uiComponent, String eventName,
Map<String, List<ClientBehavior>> clientBehaviors,
ScriptContext target, Collection<ClientBehaviorContext.Parameter> params) {
if (!(uiComponent instanceof ClientBehaviorHolder)) {
target.append(StringUtils.EMPTY);
return false;
}
ExternalContext externalContext = facesContext.getExternalContext();
boolean renderClientBehavior = MapUtils.isNotEmpty(clientBehaviors);
if (!renderClientBehavior) {
target.append(StringUtils.EMPTY);
return false;
}
List<ClientBehavior> attachedEventBehaviors = clientBehaviors
.get(eventName);
if (attachedEventBehaviors == null
|| attachedEventBehaviors.size() == 0) {
target.append(StringUtils.EMPTY);
return false;
}
ClientBehaviorContext context = ClientBehaviorContext
.createClientBehaviorContext(facesContext, uiComponent,
eventName, uiComponent.getClientId(facesContext),
params);
boolean submitting = false;
Iterator<ClientBehavior> clientIterator = attachedEventBehaviors
.iterator();
while (clientIterator.hasNext()) {
ClientBehavior clientBehavior = clientIterator.next();
String script = clientBehavior.getScript(context);
// The script _can_ be null, and in fact is for <f:ajax disabled="true" />
if (script != null) {
//either strings or functions, but I assume string is more appropriate since it allows access to the
//origin as this!
target.append("'" + escapeJavaScriptForChain(script) + "'");
if (clientIterator.hasNext()) {
target.append(", ");
}
}
if (!submitting) {
submitting = clientBehavior.getHints().contains(ClientBehaviorHint.SUBMITTING);
}
}
return submitting;
}
/**
* This function correctly escapes the given JavaScript code
* for the use in the jsf.util.chain() JavaScript function.
* It also handles double-escaping correclty.
*
* @param javaScript
* @return
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static String escapeJavaScriptForChain(String javaScript)
{
// first replace \' with \\'
//String escaped = StringUtils.replace(javaScript, "\\'", "\\\\'");
// then replace ' with \'
// (this will replace every \' in the original to \\\')
//escaped = StringUtils.replace(escaped, '\'', "\\'");
//return escaped;
StringBuffer out = null;
for (int pos = 0; pos < javaScript.length(); pos++)
{
char c = javaScript.charAt(pos);
if (c == '\\' || c == '\'')
{
if (out == null)
{
out = new StringBuffer(javaScript.length() + 8);
if (pos > 0)
{
out.append(javaScript, 0, pos);
}
}
out.append('\\');
}
if (out != null)
{
out.append(c);
}
}
if (out == null)
{
return javaScript;
}
else
{
return out.toString();
}
}
/**
* Utility to set the submitted value of the provided component from the
* data in the current request object.
* <p/>
* Param component is required to be an EditableValueHolder. On return
* from this method, the component's submittedValue property will be
* set if the submitted form contained that component.
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static void decodeUIInput(FacesContext facesContext,
UIComponent component) {
if (!(component instanceof EditableValueHolder)) {
throw new IllegalArgumentException("Component "
+ component.getClientId(facesContext)
+ " is not an EditableValueHolder");
}
Map paramMap = facesContext.getExternalContext()
.getRequestParameterMap();
String clientId = component.getClientId(facesContext);
if (isDisabledOrReadOnly(component))
return;
if (paramMap.containsKey(clientId)) {
((EditableValueHolder) component).setSubmittedValue(paramMap
.get(clientId));
} else {
log.warning(NON_SUBMITTED_VALUE_WARNING +
" Component : " +
DebugUtils.getPathToComponent(component));
}
}
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static boolean isDisabled(UIComponent component) {
return isTrue(component.getAttributes().get("disabled"));
}
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static boolean isReadOnly(UIComponent component) {
return isTrue(component.getAttributes().get("readonly"));
}
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
private static boolean isTrue(Object obj) {
if (obj instanceof String) {
return new Boolean((String) obj);
}
if (!(obj instanceof Boolean))
return false;
return ((Boolean) obj).booleanValue();
}
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
//modified
public static boolean isDisabledOrReadOnly(UIComponent component) {
return isDisabled(component) ||
isReadOnly(component);
}
/**
* The ScriptContext offers methods and fields
* to help with rendering out a script and keeping a
* proper formatting.
*/
//copied from org.apache.myfaces.shared.renderkit.html.HtmlRendererUtils
public static class ScriptContext {
private long currentIndentationLevel;
private StringBuffer buffer = new StringBuffer();
private boolean prettyPrint = false;
/**
* automatic formatting will render
* new-lines and indents if blocks are opened
* and closed - attention: you need to append
* opening and closing brackets of blocks separately in this case!
*/
private boolean automaticFormatting = true;
public ScriptContext() {
}
public ScriptContext(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
}
public ScriptContext(StringBuffer buf, boolean prettyPrint) {
this.prettyPrint = prettyPrint;
this.buffer = buf;
}
public void increaseIndent() {
currentIndentationLevel++;
}
public void decreaseIndent() {
currentIndentationLevel--;
if (currentIndentationLevel < 0)
currentIndentationLevel = 0;
}
public void prettyLine() {
if (prettyPrint) {
append(LINE_SEPARATOR);
for (int i = 0; i < getCurrentIndentationLevel(); i++)
append(TABULATOR);
}
}
public void prettyLineIncreaseIndent() {
increaseIndent();
prettyLine();
}
public void prettyLineDecreaseIndent() {
decreaseIndent();
prettyLine();
}
public long getCurrentIndentationLevel() {
return currentIndentationLevel;
}
public void setCurrentIndentationLevel(long currentIndentationLevel) {
this.currentIndentationLevel = currentIndentationLevel;
}
public ScriptContext append(String str) {
if (automaticFormatting && str.length() == 1) {
boolean openBlock = str.equals("{");
boolean closeBlock = str.equals("}");
if (openBlock) {
prettyLine();
} else if (closeBlock) {
prettyLineDecreaseIndent();
}
buffer.append(str);
if (openBlock) {
prettyLineIncreaseIndent();
} else if (closeBlock) {
prettyLine();
}
} else {
buffer.append(str);
}
return this;
}
public ScriptContext append(char c) {
buffer.append(c);
return this;
}
public ScriptContext append(int i) {
buffer.append(i);
return this;
}
public String toString() {
return buffer.toString();
}
}
}