package org.richfaces.renderkit.html;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIParameter;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.ActionEvent;
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.javascript.ScriptUtils;
import org.ajax4jsf.renderkit.AjaxComponentRendererBase;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.resource.InternetResource;
import org.richfaces.component.UIToolTip;
import org.richfaces.skin.Skin;
//import com.gargoylesoftware.htmlunit.protocol.javascript.JavaScriptURLConnection;
//import com.sun.el.lang.FunctionMapperImpl.Function;
public class ToolTipRenderer extends AjaxComponentRendererBase{
//
// Declarations
//
private final InternetResource[] styles = {
getResource("/org/richfaces/renderkit/html/css/tooltip.xcss")
};
private InternetResource[] stylesAll = null;
protected InternetResource[] getStyles() {
synchronized (this) {
if (stylesAll == null) {
InternetResource[] rsrcs = super.getStyles();
boolean ignoreSuper = rsrcs == null || rsrcs.length == 0;
boolean ignoreThis = styles == null || styles.length == 0;
if (ignoreSuper) {
if (ignoreThis) {
stylesAll = new InternetResource[0];
} else {
stylesAll = styles;
}
} else {
if (ignoreThis) {
stylesAll = rsrcs;
} else {
java.util.Set rsrcsSet = new java.util.LinkedHashSet();
for (int i = 0; i < rsrcs.length; i++ ) {
rsrcsSet.add(rsrcs[i]);
}
for (int i = 0; i < styles.length; i++ ) {
rsrcsSet.add(styles[i]);
}
stylesAll = (InternetResource[]) rsrcsSet.toArray(new InternetResource[rsrcsSet.size()]);
}
}
}
}
return stylesAll;
}
private final InternetResource[] scripts = {
new org.ajax4jsf.javascript.PrototypeScript(),
new org.ajax4jsf.javascript.AjaxScript(),
getResource("/org/richfaces/renderkit/html/scripts/jquery/jquery.js"),
getResource("/org/richfaces/renderkit/html/scripts/utils.js"),
getResource("/org/richfaces/renderkit/html/scripts/tooltip.js")
};
private InternetResource[] scriptsAll = null;
protected InternetResource[] getScripts() {
synchronized (this) {
if (scriptsAll == null) {
InternetResource[] rsrcs = super.getScripts();
boolean ignoreSuper = rsrcs == null || rsrcs.length == 0;
boolean ignoreThis = scripts == null || scripts.length == 0;
if (ignoreSuper) {
if (ignoreThis) {
scriptsAll = new InternetResource[0];
} else {
scriptsAll = scripts;
}
} else {
if (ignoreThis) {
scriptsAll = rsrcs;
} else {
java.util.Set rsrcsSet = new java.util.LinkedHashSet();
for (int i = 0; i < rsrcs.length; i++ ) {
rsrcsSet.add(rsrcs[i]);
}
for (int i = 0; i < scripts.length; i++ ) {
rsrcsSet.add(scripts[i]);
}
scriptsAll = (InternetResource[]) rsrcsSet.toArray(new InternetResource[rsrcsSet.size()]);
}
}
}
}
return scriptsAll;
}
protected Class getComponentClass() {
return org.richfaces.component.UIToolTip.class;
}
public String getBgColor(FacesContext context, UIComponent component){
Skin skin = getSkin(context);
String color = (String) skin.getParameter(context,"headerBackgroundColor");
return color;
}
public String getColor(FacesContext context, UIComponent component){
Skin skin = getSkin(context);
String color = (String) skin.getParameter(context,"headerTextColor");
return color;
}
public Map<String, Object> buildEventOptions(FacesContext context, UIComponent component, String targetId){
Map<String, Object> eventOptions = AjaxRendererUtils.buildEventOptions(context, component);
String jsVarName = "_toolTip";
//after element is subsituted in DOM tree, we have to re-create
//it's JS-reference, cause old one is already invalid
String clientId = component.getClientId(context);
String oncompleteTooltip = ";" + "{" +
"var " + jsVarName + " = $('" + clientId + "').component;" +
jsVarName + ".toolTipContent = $('" + clientId + "content');" +
jsVarName + ".displayDiv();" +
"}";
// before element will be substituted in DOM tree, we need to hide toolTipe to avoid blinking
String fireBeforeUpdateDOM = ";" + "{ var " + jsVarName + " = $('" + clientId + "').component;" + jsVarName + ".toolTip.style.display = 'none'; }";
//enable ajaxSingle mode, i.e. we do not need to submit all form controls to get tooltip content
eventOptions.put("control", JSReference.THIS);
if(eventOptions.containsKey("oncomplete")){
JSFunctionDefinition onComplete = (JSFunctionDefinition)eventOptions.get("oncomplete");
onComplete.addToBody(oncompleteTooltip);
eventOptions.put("oncomplete", onComplete);
} else {
JSFunctionDefinition onComplete = new JSFunctionDefinition();
onComplete.addParameter("request");
onComplete.addParameter("showEvent");
onComplete.addParameter("data");
onComplete.addToBody(oncompleteTooltip);
eventOptions.put("oncomplete", onComplete);
}
if(eventOptions.containsKey(AjaxRendererUtils.ONBEFOREDOMUPDATE_ATTR_NAME)){
JSFunctionDefinition beforeUpdate = (JSFunctionDefinition)eventOptions.get(AjaxRendererUtils.ONBEFOREDOMUPDATE_ATTR_NAME);
beforeUpdate.addToBody(fireBeforeUpdateDOM);
eventOptions.put(AjaxRendererUtils.ONBEFOREDOMUPDATE_ATTR_NAME, beforeUpdate);
} else {
JSFunctionDefinition beforeUpdate = new JSFunctionDefinition();
beforeUpdate.addParameter("request");
beforeUpdate.addParameter("showEvent");
beforeUpdate.addParameter("data");
beforeUpdate.addToBody(fireBeforeUpdateDOM);
eventOptions.put(AjaxRendererUtils.ONBEFOREDOMUPDATE_ATTR_NAME, beforeUpdate);
}
return eventOptions;
}
public void insertScript(FacesContext context, UIComponent component) throws IOException{
UIToolTip toolTip = (UIToolTip)component;
StringBuffer ret = new StringBuffer();
ret.append("<script ");
ret.append("type=\"text/javascript\" ");
ret.append("id =\"script" + component.getClientId(context)+"\">\n");
StringBuffer script = new StringBuffer();
//
String jsVar = constructJSVariable(context, component);
script.append(jsVar).append(";\n");
ret.append(script.toString());
ret.append("\n</script>");
ResponseWriter writer = context.getResponseWriter();
writer.write(ret.toString());
}
public Map <String, Object> getParamsMap(FacesContext context, UIToolTip toolTip) {
List <UIComponent> children = toolTip.getChildren();
Map <String, Object> paramsMap = new HashMap<String, Object>();
for(UIComponent child: children ) {
if(child instanceof UIParameter) {
UIParameter param = (UIParameter)child;
paramsMap.put(param.getName(),param.getValue());
}
}
return paramsMap;
}
private String getTargetId(FacesContext context, UIComponent component) {
UIToolTip toolTip = (UIToolTip) component;
String forValue = toolTip.getFor();
if (forValue != null && forValue.length() != 0) {
UIComponent targetComponent = getUtils().findComponentFor(component, forValue);
if (targetComponent != null) {
return targetComponent.getClientId(context);
} else {
return forValue;
}
} else {
return component.getParent().getClientId(context);
}
}
public String constructJSVariable(FacesContext context, UIComponent component) {
UIToolTip toolTip = (UIToolTip)component;
String targetClientId = getTargetId(context, component);
StringBuffer ret = new StringBuffer();
String comma = ",";
String quot = "\"";
String eventShow = (toolTip.isAttached()) ? toolTip.getShowEvent() : "";
String eventHide = (toolTip.isAttached()) ? toolTip.getHideEvent() : "";
if(eventShow.startsWith("on")){
eventShow = eventShow.substring(2);
}
if(eventHide.startsWith("on")){
eventHide = eventHide.substring(2);
}
Map<JSReference, Object> eventsMap = new HashMap<JSReference, Object>();
eventsMap.put(new JSReference("showEvent"), eventShow);
eventsMap.put(new JSReference("hideEvent"), eventHide);
eventsMap.put(new JSReference("delay"), new Integer(toolTip.getShowDelay()));
eventsMap.put(new JSReference("hideDelay"), new Integer(toolTip.getHideDelay()));
JSFunction function = AjaxRendererUtils.buildAjaxFunction(component, context);
JSReference ref = new JSReference("ajaxOptions");
function.addParameter(ref);
String ajaxFunc = function.toScript();
Map<String, Object> ajaxOptions = buildEventOptions(context, toolTip, targetClientId);
ajaxOptions.putAll(getParamsMap(context, toolTip));
JSFunctionDefinition completeFunc = getUtils().getAsEventHandler(context, component, "oncomplete", "; return true;");
JSFunctionDefinition hideFunc = getUtils().getAsEventHandler(context, component,"onhide", "; return true;");
JSFunctionDefinition showFunc = getUtils().getAsEventHandler(context, component,"onshow", "; return true;");
Map<JSReference, Object> funcMap = new HashMap<JSReference, Object>();
funcMap.put(new JSReference("oncomplete"), completeFunc);
funcMap.put(new JSReference("onhide"), hideFunc);
funcMap.put(new JSReference("onshow"), showFunc);
ret.append("new ToolTip(" + ScriptUtils.toScript(eventsMap)).append(comma).append(ScriptUtils.toScript(funcMap))
.append(comma).append(quot).append( toolTip.getClientId(context)).append(quot).append(comma).
append(quot).append(targetClientId).append(quot).append(comma).
append(quot).append(toolTip.getMode()).append(quot).append(comma).
append(toolTip.isDisabled()).append(comma).
append(quot).append(toolTip.getDirection()).append(quot).append(comma).
append(toolTip.isFollowMouse()).append(comma).
append(toolTip.getHorizontalOffset()).append(comma).
append(toolTip.getVerticalOffset()).append(comma).
append("\"").append(ajaxFunc).append("\"").append(comma).append(ScriptUtils.toScript(ajaxOptions)).append(");");
return ret.toString();
}
protected void doDecode(FacesContext context, UIComponent component) {
UIToolTip tooltip = (UIToolTip)component;
String clientId = tooltip.getClientId(context);
if(context.getExternalContext().getRequestParameterMap().containsKey(clientId)){
if("ajax".equals(tooltip.getMode())){
new AjaxEvent(component).queue();
new ActionEvent(component).queue();
}
}
}
public void encodeTooltipText(FacesContext context, UIToolTip component) throws IOException {
ResponseWriter responseWriter = context.getResponseWriter();
responseWriter.startElement(component.getUsedElementType(), component);
responseWriter.writeAttribute("id", component.getClientId(context) + "content", null);
if("ajax".equals(component.getMode())){
// we want to avoid rendering toolTip content during initialy page displaying
AjaxContext ajaxContext = AjaxContext.getCurrentInstance();
if(ajaxContext != null && ajaxContext.getAjaxAreasToRender().contains(component.getClientId(context) + "content")){
responseWriter.write(component.getValue() != null ? component.getValue().toString() : "");
super.renderChildren(context, component);
}
} else {
// client mode
responseWriter.write(component.getValue() != null ? component.getValue().toString() : "");
super.renderChildren(context, component);
}
responseWriter.endElement(component.getUsedElementType());
}
protected void doEncodeBegin(ResponseWriter writer, FacesContext context,
UIComponent component) throws IOException {
UIToolTip toolTip = (UIToolTip)component;
Class rendererClass = null;
try{
if("block".equals(toolTip.getLayout())){
rendererClass = Class.forName("org.richfaces.renderkit.html.HtmlToolTipRendererBlock");
} else if("inline".equals(toolTip.getLayout())){
rendererClass = Class.forName("org.richfaces.renderkit.html.HtmlToolTipRenderer");
} else {
throw new FacesException("Only \"block\" or \"inline\" values can be established to attribute \"layout\".");
}
ToolTipRenderer renderer = (ToolTipRenderer)rendererClass.newInstance();
renderer.doEncodeBegin(writer, context, component);
} catch(Exception e){
throw new FacesException(e.getMessage(), e);
}
}
protected void doEncodeChildren(ResponseWriter writer,
FacesContext context, UIComponent component) throws IOException {
UIToolTip toolTip = (UIToolTip)component;
Class rendererClass = null;
try{
if("block".equals(toolTip.getLayout())){
rendererClass = Class.forName("org.richfaces.renderkit.html.HtmlToolTipRendererBlock");
} else {
rendererClass = Class.forName("org.richfaces.renderkit.html.HtmlToolTipRenderer");
}
ToolTipRenderer renderer = null;
renderer = (ToolTipRenderer)rendererClass.newInstance();
renderer.doEncodeChildren(writer, context, component);
} catch(Exception e){
throw new FacesException(e.getMessage(), e);
}
}
protected void doEncodeEnd(ResponseWriter writer, FacesContext context,
UIComponent component) throws IOException {
UIToolTip toolTip = (UIToolTip)component;
Class rendererClass = null;
try{
if("block".equals(toolTip.getLayout())){
rendererClass = Class.forName("org.richfaces.renderkit.html.HtmlToolTipRendererBlock");
} else {
rendererClass = Class.forName("org.richfaces.renderkit.html.HtmlToolTipRenderer");
}
ToolTipRenderer renderer = (ToolTipRenderer)rendererClass.newInstance();
renderer.doEncodeEnd(writer, context, component);
} catch (Exception e) {
throw new FacesException(e.getMessage(), e);
}
}
/* (non-Javadoc)
* @see javax.faces.render.Renderer#getRendersChildren()
*/
public boolean getRendersChildren() {
return true;
}
}