@Override
  protected void doEncodeBegin(ResponseWriter writer, FacesContext context, UIComponent component)
      throws IOException {
    AbstractTooltip tooltip = (AbstractTooltip) component;

    writer.startElement(getMarkupElement(tooltip), component);
    writer.writeAttribute(ID_ATTRIBUTE, component.getClientId(context), "clientId");

    writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, "display: none;", null);
    writer.startElement(getMarkupElement(tooltip), component);
    writer.writeAttribute(ID_ATTRIBUTE, component.getClientId(context) + ":wrp", null);
    writer.writeAttribute(CLASS_ATTRIBUTE, getStyleClass(component), null);

    int zindex = tooltip.getZindex();
    if (zindex == Integer.MIN_VALUE) {
      zindex = DEFAULT_ZINDEX_VALUE;
    }

    String style = concatStyles("z-index:" + zindex, getStyle(component));
    if (style != null && style.trim().length() > 0) {
      writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, style, null);
    }

    renderPassThroughAttributes(context, component, getPassThroughAttributes());

    writer.startElement(getMarkupElement(tooltip), component);
    writer.writeAttribute(ID_ATTRIBUTE, component.getClientId(context) + ":cntr", null);
    writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tt-cntr", null);

    if (tooltip.getMode() == TooltipMode.ajax) {
      encodeLoading(writer, context, tooltip);
    }

    encodeContentBegin(writer, context, tooltip);
  }
 private void encodeContentBegin(
     ResponseWriter writer, FacesContext context, AbstractTooltip tooltip) throws IOException {
   writer.startElement(getMarkupElement(tooltip), tooltip);
   writer.writeAttribute(ID_ATTRIBUTE, tooltip.getClientId(context) + ":content", null);
   writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tt-cnt", null);
   if (tooltip.getChildCount() == 0) {
     writer.write(tooltip.getValue().toString());
   }
 }
 public Integer[] getOffset(AbstractTooltip tooltip) {
   int horizontalOffset = tooltip.getHorizontalOffset();
   int verticalOffset = tooltip.getVerticalOffset();
   if (horizontalOffset == Integer.MIN_VALUE) {
     horizontalOffset = 10;
   }
   if (verticalOffset == Integer.MIN_VALUE) {
     verticalOffset = 10;
   }
   return new Integer[] {horizontalOffset, verticalOffset};
 }
  private String getMarkupElement(AbstractTooltip component) {
    switch (component.getLayout()) {
      case block:
        return HtmlConstants.DIV_ELEM;

      case inline:
        return HtmlConstants.SPAN_ELEM;

      default:
        throw new IllegalStateException("Unknown tooltip layout (=" + component.getLayout() + ")");
    }
  }
 private void encodeLoading(ResponseWriter writer, FacesContext context, AbstractTooltip tooltip)
     throws IOException {
   writer.startElement(getMarkupElement(tooltip), tooltip);
   writer.writeAttribute(ID_ATTRIBUTE, tooltip.getClientId(context) + ":loading", null);
   writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tt-loading", null);
   UIComponent loading = tooltip.getFacet("loading");
   if (loading != null && loading.isRendered()) {
     loading.encodeAll(context);
   } else {
     writer.writeText("Loading...", null);
   }
   writer.endElement(getMarkupElement(tooltip));
 }
  @Override
  protected void doEncodeChildren(
      ResponseWriter writer, FacesContext context, UIComponent component) throws IOException {

    AbstractTooltip tooltip = (AbstractTooltip) component;

    if (tooltip.getMode() == TooltipMode.client) {
      if (tooltip.getChildCount() > 0) {
        for (UIComponent kid : tooltip.getChildren()) {
          kid.encodeAll(context);
        }
      }
    }
  }
  @Override
  protected void doDecode(FacesContext context, UIComponent component) {
    AbstractTooltip tooltip = (AbstractTooltip) component;

    Map<String, String> requestMap = context.getExternalContext().getRequestParameterMap();

    String compClientId = component.getClientId(context);
    String clientId = requestMap.get(compClientId);
    if (clientId != null && clientId.equals(compClientId)) {
      context.getPartialViewContext().getRenderIds().add(tooltip.getContentClientId(context));

      // TODO nick - this should be done on encode, not on decode
      addOnCompleteParam(context, tooltip.getClientId(context));
      context.renderResponse();
    }
  }
  public void encodeMetaComponent(
      FacesContext context, UIComponent component, String metaComponentId) throws IOException {
    if (AbstractTooltip.CONTENT_META_COMPONENT_ID.equals(metaComponentId)) {
      AbstractTooltip tooltip = (AbstractTooltip) component;
      PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();
      writer.startUpdate(
          tooltip.getClientId(context) + ":" + AbstractTooltip.CONTENT_META_COMPONENT_ID);

      encodeContentBegin(writer, context, tooltip);
      for (UIComponent child : tooltip.getChildren()) {
        child.encodeAll(context);
      }
      encodeContentEnd(writer, context, tooltip);

      writer.endUpdate();
    }
  }
  @Override
  protected Map<String, Object> getScriptObjectOptions(
      FacesContext context, UIComponent component) {
    AbstractTooltip tooltip = (AbstractTooltip) component;

    Map<String, Object> options = new HashMap<String, Object>();

    RenderKitUtils.addToScriptHash(
        options, "ajax", getAjaxOptions(context, tooltip), TooltipMode.DEFAULT);

    Positioning jointPoint = tooltip.getJointPoint();
    if (jointPoint == null) {
      jointPoint = org.richfaces.component.Positioning.DEFAULT;
    }
    Positioning direction = tooltip.getDirection();
    if (direction == null) {
      direction = org.richfaces.component.Positioning.DEFAULT;
    }

    RenderKitUtils.addToScriptHash(
        options, "jointPoint", jointPoint.getValue(), Positioning.DEFAULT.getValue());
    RenderKitUtils.addToScriptHash(
        options, "direction", direction.getValue(), Positioning.DEFAULT.getValue());
    RenderKitUtils.addToScriptHash(options, "attached", tooltip.isAttached(), true);
    RenderKitUtils.addToScriptHash(options, "offset", getOffset(tooltip));
    RenderKitUtils.addToScriptHash(options, "mode", tooltip.getMode(), TooltipMode.DEFAULT);
    RenderKitUtils.addToScriptHash(options, "hideDelay", tooltip.getHideDelay(), 0);
    RenderKitUtils.addToScriptHash(options, "hideEvent", tooltip.getHideEvent(), "mouseleave");
    RenderKitUtils.addToScriptHash(options, "showDelay", tooltip.getShowDelay(), 0);
    RenderKitUtils.addToScriptHash(options, "showEvent", tooltip.getShowEvent(), "mouseenter");
    RenderKitUtils.addToScriptHash(options, "followMouse", tooltip.isFollowMouse(), true);
    RenderKitUtils.addToScriptHash(
        options,
        "target",
        RENDERER_UTILS.findComponentFor(component, tooltip.getTarget()).getClientId(context));

    addEventOption(context, tooltip, options, HIDE);
    addEventOption(context, tooltip, options, SHOW);
    addEventOption(context, tooltip, options, BEFORE_HIDE);
    addEventOption(context, tooltip, options, BEFORE_SHOW);

    return options;
  }