package org.richfaces.renderkit.html;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
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/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 buildEventOptions(FacesContext context, UIComponent component){
Map eventOptions = AjaxRendererUtils.buildEventOptions(context, component);
//after element is subsituted in DOM tree, we have to re-create
//it's JS-reference, cause old one is already invalid
String refreshTooltipInDOM = ";" + getJsVarName(context, component) + ".toolTip = $('" + component.getClientId(context) + "');" +
";" + getJsVarName(context, component) + ".toolTipContent = $('" + component.getClientId(context) + "content');";
String showNewToolTip = ";" + getJsVarName(context, component) + ".displayDiv();";
// before element will be substituted in DOM tree, we need to hide toolTipe to avoid blinking
String fireBeforeUpdateDOM = ";" + getJsVarName(context, component) + ".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(refreshTooltipInDOM + showNewToolTip);
eventOptions.put("oncomplete", onComplete);
} else {
JSFunctionDefinition onComplete = new JSFunctionDefinition();
onComplete.addParameter("request");
onComplete.addParameter("event");
onComplete.addParameter("data");
onComplete.addToBody(refreshTooltipInDOM + showNewToolTip);
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("event");
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 String constructJSVariable(FacesContext context, UIComponent component) {
UIToolTip toolTip = (UIToolTip)component;
String parentClientId = toolTip.getParent().getClientId(context);
StringBuffer ret = new StringBuffer();
String comma = ",";
String quot = "\"";
String event = toolTip.getEvent();
if(event.startsWith("on")){
event = event.substring(2);
}
Map eventsMap = new HashMap();
eventsMap.put(new JSReference("event"), event);
eventsMap.put(new JSReference("onshow"), toolTip.getOnshow());
eventsMap.put(new JSReference("oncomplete"), toolTip.getOncomplete());
eventsMap.put(new JSReference("onhide"), toolTip.getOnhide());
eventsMap.put(new JSReference("delay"), new Integer(toolTip.getDelay()));
JSFunction function = AjaxRendererUtils.buildAjaxFunction(component, context);
JSReference ref = new JSReference("ajaxOptions");
function.addParameter(ref);
String ajaxFunc = function.toScript();
Map ajaxOptions = buildEventOptions(context, toolTip);
ret.append("new ToolTip(" + ScriptUtils.toScript(eventsMap)).append(comma).append(quot).append( toolTip.getClientId(context)).append(quot).append(comma).
append(quot).append(parentClientId).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();
}
private String getJsVarName(FacesContext context, UIComponent component){
return "Richfaces.tooltips[\'" + component.getParent().getClientId(context) + "\']";
}
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();
}
}
}
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() : "");
super.renderChildren(context, component);
}
} else {
// client mode
responseWriter.write(component.getValue() != null ? component.getValue() : "");
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;
}
}