@ResourceDependencies({ @ResourceDependency(library="primefaces", name="jquery/jquery.js"), @ResourceDependency(library="primefaces", name="core/core.js"), @ResourceDependency(library = "css", name = "jquery.qtip.css"), @ResourceDependency(library = "js", name = "tooltip/jquery.qtip.js"), @ResourceDependency(library = "js", name = "tooltip/tooltip.js") }) public class Tooltip extends org.primefaces.component.tooltip.Tooltip { public java.lang.String getTargetPosition() { return (java.lang.String) getStateHelper().eval(PropertyKeys.targetPosition, "bottom right"); } public java.lang.String getPosition() { return (java.lang.String) getStateHelper().eval(PropertyKeys.position, "top left"); } public java.lang.String getShowEffect() { return (java.lang.String) getStateHelper().eval(PropertyKeys.showEffect, "fadeIn"); } public java.lang.String getHideEffect() { return (java.lang.String) getStateHelper().eval(PropertyKeys.hideEffect, "fadeOut"); } public java.lang.String getShowEvent() { return (java.lang.String) getStateHelper().eval(PropertyKeys.showEvent, "mouseenter"); } public java.lang.String getHideEvent() { return (java.lang.String) getStateHelper().eval(PropertyKeys.hideEvent, "mouseleave"); } }jquery.qtip.js is a new qTip script placed under the folder webapp/resources/js/tooltip and the tooltip.js is our one. In the tooltip.js I use the jQuery .live() method playing together with qTip2. This method allows us to easily add qTips to certain elements on a page, even when updating the DOM and adding new elements.
PrimeFaces.widget.Tooltip = function(cfg) { this.cfg = cfg; var _self = this; if (this.cfg.global) { // Bind the qTip within the event handler jQuery('*[title]').live(this.cfg.show.event, function(event) { var extCfg = _self.cfg; // Show the tooltip as soon as it's bound extCfg.show.ready = true; jQuery(this).qtip(extCfg, event); }); } else { jQuery(PrimeFaces.escapeClientId(this.cfg.forComponent)).qtip(this.cfg); } } // make tooltip theme aware jQuery.fn.qtip.defaults.style.widget = true; jQuery.fn.qtip.defaults.style.classes = "ui-tooltip-rounded ui-tooltip-shadow";jQuery ThemeRoller integration is done by the last two lines. The last step is to extend PrimeFaces's TooltipRenderer (because tooltip API has been changed) and register then all stuff in the faces-config.xml
public class TooltipRenderer extends org.primefaces.component.tooltip.TooltipRenderer { public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException { Tooltip tooltip = (Tooltip) component; // dummy markup for ajax update (not really necessary) ResponseWriter writer = facesContext.getResponseWriter(); writer.startElement("span", tooltip); writer.writeAttribute("id", tooltip.getClientId(facesContext), "id"); writer.endElement("span"); encodeScript(facesContext, tooltip); } protected void encodeScript(FacesContext facesContext, org.primefaces.component.tooltip.Tooltip tp) throws IOException { Tooltip tooltip = (Tooltip) tp; ResponseWriter writer = facesContext.getResponseWriter(); boolean global = tooltip.isGlobal(); String owner = getTarget(facesContext, tooltip); writer.startElement("script", null); writer.writeAttribute("type", "text/javascript", null); writer.write("jQuery(function() {"); writer.write(tooltip.resolveWidgetVar() + " = new PrimeFaces.widget.Tooltip({"); writer.write("global:" + global); if (!global) { writer.write(",forComponent:'" + owner + "'"); writer.write(",content:'"); if (tooltip.getValue() == null) { renderChildren(facesContext, tooltip); } else { writer.write(ComponentUtils.getStringValueToRender(facesContext, tooltip).replaceAll("'", "\\\\'")); } writer.write("'"); } writer.write(",show:{event:'" + tooltip.getShowEvent() + "',delay:" + tooltip.getShowDelay() + ",effect:function(){jQuery(this)." + tooltip.getShowEffect() + "(" + tooltip.getShowEffectLength() + ");}}"); writer.write(",hide:{event:'" + tooltip.getHideEvent() + "',delay:" + tooltip.getHideDelay() + ",effect:function(){jQuery(this)." + tooltip.getHideEffect() + "(" + tooltip.getHideEffectLength() + ");}}"); writer.write(",position: {"); String container = owner == null ? "jQuery(document.body)" : "jQuery(PrimeFaces.escapeClientId('" + owner + "')).parent()"; writer.write("container:" + container); writer.write(",at:'" + tooltip.getTargetPosition() + "'"); writer.write(",my:'" + tooltip.getPosition() + "'"); writer.write("}});});"); writer.endElement("script"); } }Have much fun! In one of my next post I will explain how to show a nice tooltip attached to the PrimeFaces Autocomplete component if user input disallowed characters.
Edit: I think a binding with namespace would be better to avoid collisions. Furthermore, a call of .die() before .live() is necessary in order to prevent miltiply binding of the same event if the tooltip gets updated via ajax. The same is for non global tooltips
jQuery('*[title]').die(this.cfg.show.event + ".tooltip").live(this.cfg.show.event + ".tooltip", ... ... }); ... in else ... // delete previous tooltip to support ajax updates and create a new one jQuery(PrimeFaces.escapeClientId(this.cfg.forComponent)).qtip('destroy').qtip(this.cfg);The container element which the tooltip is appended to should be always document.body in order to play nice with layout, datatable, etc. Changes in TooltipRenderer.java:
writer.write("container:jQuery(document.body)");