/**
*
*/
package org.richfaces.component;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UIParameter;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import org.ajax4jsf.Messages;
import org.ajax4jsf.component.AjaxSupport;
import org.ajax4jsf.component.EventValueBinding;
import org.ajax4jsf.component.JavaScriptParameter;
import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.javascript.ScriptUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.component.util.HtmlUtil;
/**
* JSF component class
*
*/
public abstract class UIComponentControl extends UIComponentBase implements AjaxSupport {
public static final String COMPONENT_TYPE = "org.richfaces.ComponentControl";
public static final String COMPONENT_FAMILY = "org.richfaces.ComponentControl";
private static final Log log = LogFactory.getLog(UIComponentControl.class);
private static final Pattern BACKSLASHES = Pattern.compile("\\\\", Pattern.LITERAL);
private static final String QUOTED_REPLACEMENT = "\\\\";
/**
* @return JavaScript eventString. Rebuild on every call, since
* can be in loop ( as in dataTable ) with different parameters.
*/
public String getEventString()
{
String targetId = HtmlUtil.idsToIdSelector(getFor());
targetId = HtmlUtil.expandIdSelector(targetId, this, FacesContext.getCurrentInstance());
JSFunction invocation = new JSFunction("Richfaces.componentControl.performOperation");
invocation.addParameter(new JSReference("event"));
//FIXME: Maksim
//Replacement looks ugly - move that functionality to HtmlUtil
invocation.addParameter(replaceBackSlashes(targetId));
invocation.addParameter(getOperation());
invocation.addParameter(new JSReference("{" + getEncodedParametersMap() + "}"));
invocation.addParameter(Boolean.valueOf(isDisableDefault()));
return invocation.toScript();
}
protected String replaceBackSlashes(String src) {
return BACKSLASHES.matcher(src).replaceAll(QUOTED_REPLACEMENT);
}
public String getEncodedParametersMap() {
StringBuffer result = new StringBuffer();
boolean shouldClose = false;
String params = this.getParams();
if (params != null && params.trim().length() != 0) {
result.append(params);
shouldClose = true;
}
for (Iterator it = this.getChildren().iterator(); it.hasNext();) {
UIComponent child = (UIComponent) it.next();
if (child instanceof UIParameter) {
String name = ((UIParameter) child).getName();
Object value = ((UIParameter) child).getValue();
if (null == name) {
FacesContext context = FacesContext.getCurrentInstance();
throw new IllegalArgumentException(Messages.getMessage(
Messages.UNNAMED_PARAMETER_ERROR, this
.getClientId(context)));
}
boolean escape = true;
if (child instanceof JavaScriptParameter) {
JavaScriptParameter actionParam = (JavaScriptParameter) child;
escape = !actionParam.isNoEscape();
}
if (shouldClose) {
result.append(", ");
}
ScriptUtils.addEncodedString(result, name);
result.append(": ");
result.append(ScriptUtils.toScript(escape ? value : new JSReference(value.toString())));
shouldClose = true;
}
}
return result.toString();
}
public abstract String getEvent();
public abstract void setEvent(String event);
public abstract String getFor();
public abstract void setFor(String value);
public abstract String getParams();
public abstract void setParams(String value);
public abstract String getOperation();
public abstract void setOperation(String value);
public abstract String getAttachTo();
public abstract void setAttachTo(String value);
protected String replaceClientIds(FacesContext context, UIComponent component, String selector) {
return HtmlUtil.expandIdSelector(selector, component, context);
}
/**
* After nornal setting <code>parent</code> property in case of
* created component set Ajax properties for parent.
* @see javax.faces.component.UIComponentBase#setParent(javax.faces.component.UIComponent)
*/
public void setParent(UIComponent parent)
{
super.setParent(parent);
if (null != parent && parent.getFamily() != null ) {
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage(Messages.CALLED_SET_PARENT, parent.getClass().getName()));
}
// TODO If this comopnent configured, set properties for parent component.
// NEW created component have parent, restored view - null in My faces.
// and SUN RI not call at restore saved view.
// In other case - set in restoreState method.
// if (parent.getParent() != null)
{
if (log.isDebugEnabled()) {
log.debug(Messages.getMessage(Messages.DETECT_NEW_COMPONENT));
}
setParentProperties(parent);
}
}
}
public void setParentProperties(UIComponent parent){
String event = getEvent();
String attachTo = getAttachTo();
if (event != null && event.length() != 0) {
if (attachTo == null || attachTo.length() == 0) {
parent.setValueBinding(event, new EventValueBinding(this));
} else {
ValueBinding vb = parent.getValueBinding(event);
if (vb instanceof EventValueBinding) {
//TODO check if that's EventValueBinding for us
parent.setValueBinding(event, null);
}
}
}
}
public abstract void setName(String name);
public abstract String getName();
public abstract void setAttachTiming( String attachTiming);
public abstract String getAttachTiming();
}