package org.richfaces.renderkit;
import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.ajax4jsf.renderkit.ComponentVariables;
import org.ajax4jsf.renderkit.ComponentsVariableResolver;
import org.ajax4jsf.renderkit.HeaderResourcesRendererBase;
import org.ajax4jsf.renderkit.RendererUtils;
import org.ajax4jsf.resource.InternetResource;
import org.richfaces.component.UIComponentControl;
import org.richfaces.component.util.HtmlUtil;
public class ComponentControlRendererBase extends HeaderResourcesRendererBase {
/**
* 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";
protected Class<UIComponentControl> getComponentClass() {
return UIComponentControl.class;
}
/**
* Additional scripts.
*/
private final InternetResource[] additionalScripts = { new org.ajax4jsf.javascript.PrototypeScript(),
new org.ajax4jsf.javascript.AjaxScript(), getResource("/org/richfaces/renderkit/html/scripts/available.js") };
/**
* Perform validation of the component control configuration. Throws FacesException in case validation fails.
* @param clientId - id of the component
* @param name - component name
* @param attachTiming - timing options
* @param forAttr - client ids of target components
* @param operation - operation performed on target components
*/
protected void checkValidity(String clientId, String name, String attachTiming, String forAttr, String operation) {
if (!ON_LOAD.equals(attachTiming) && !IMMEDIATE.equals(attachTiming) && !ON_AVAILABLE.equals(attachTiming)) {
throw new FacesException("The attachTiming attribute of the controlComponent (id='" + clientId
+ "') has an invalid value:'" + attachTiming + "'. It may have only the following values: '"
+ IMMEDIATE + "', '" + ON_LOAD + "', '" + ON_AVAILABLE + "'");
}
if (operation == null || operation.trim().length() == 0) {
throw new FacesException("The operation attribute of the controlComponent (id='" + clientId
+ "') must be specified");
}
}
protected String replaceClientIds(FacesContext context, UIComponent component, String selector) {
return HtmlUtil.expandIdSelector(HtmlUtil.idsToIdSelector(selector), component, context);
}
/**
* Prepare Java script according to the timing option of the component control
* and write it to the ResponceWriter
* @param context - FacesContext
* @param component - component control
* @throws IOException - is thrown in case of writing to ResponceWriter exception
*/
protected void attachEventAccordingToTimingOption(FacesContext context, UIComponent component) throws IOException {
if (!(component instanceof UIComponentControl)) {
return;
}
UIComponentControl componentControl = (UIComponentControl) component;
String attachTo = componentControl.getAttachTo();
String attachTiming = componentControl.getAttachTiming();
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;
}
ResponseWriter writer = context.getResponseWriter();
ComponentVariables variables = ComponentsVariableResolver.getVariables(this, componentControl);
writer.startElement("script", componentControl);
getUtils().writeAttribute(writer, "type", "text/javascript");
writer.writeText("//", null);
writer.write("<![CDATA[");
String attachEventBodyStart = "\n{\n Richfaces.componentControl.attachEvent('";
StringBuilder attachEventBodyEnd = new StringBuilder();
attachEventBodyEnd.append("', '");
attachEventBodyEnd.append(convertToString(variables.getVariable("event")));
attachEventBodyEnd.append("', '");
attachEventBodyEnd.append(convertToString(variables.getVariable("forAttr")));
attachEventBodyEnd.append("', '");
attachEventBodyEnd.append(convertToString(variables.getVariable("operation")));
attachEventBodyEnd.append("', function() { return {");
attachEventBodyEnd.append(convertToString(variables.getVariable("params")));
attachEventBodyEnd.append("}; }, ");
attachEventBodyEnd.append(convertToString(componentControl.isDisableDefault()));
attachEventBodyEnd.append(");\n }");
String pattern = "\\s*,\\s*";
// "attachTo" attribute may contain several ids splitted by ","
String[] result = attachTo.split(pattern);
for (int i = 0; i < result.length; i++) {
if (isOnLoad) {
writer.write("\n jQuery(document).ready(function()");
} else if (isOnAvailable) {
UIComponent target = RendererUtils.getInstance().findComponentFor(context, component, result[i]);
String clientId = (target != null) ? target.getClientId(context) : result[i];
writer.write("\n Richfaces.onAvailable('" + clientId + "', function()");
} else if (isImmediate) {
}
writer.write(attachEventBodyStart);
writer.write(getUtils().escapeJavaScript(replaceClientIds(context, component, result[i])));
writer.write(attachEventBodyEnd.toString());
if (isOnLoad || isOnAvailable) {
writer.write(");");
}
}
writer.writeText("//", null);
writer.write("]]>");
writer.endElement("script");
}
/**
* Gets additional scripts.
*
* @return array of resources
*/
protected InternetResource[] getScripts() {
return additionalScripts;
}
/**
* Returns String representation of object. If object is null,
* returns empty String.
* @param obj - object
* @return String representation of object.
*/
private static String convertToString(Object obj ) {
return ( obj == null ? "" : obj.toString() );
}
}