001package org.gwtbootstrap3.client.ui.base;
002
003/*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 2013 - 2015 GwtBootstrap3
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 * http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import java.util.Iterator;
024import java.util.NoSuchElementException;
025
026import org.gwtbootstrap3.client.shared.event.HiddenEvent;
027import org.gwtbootstrap3.client.shared.event.HiddenHandler;
028import org.gwtbootstrap3.client.shared.event.HideEvent;
029import org.gwtbootstrap3.client.shared.event.HideHandler;
030import org.gwtbootstrap3.client.shared.event.InsertedEvent;
031import org.gwtbootstrap3.client.shared.event.ShowEvent;
032import org.gwtbootstrap3.client.shared.event.ShowHandler;
033import org.gwtbootstrap3.client.shared.event.ShownEvent;
034import org.gwtbootstrap3.client.shared.event.ShownHandler;
035import org.gwtbootstrap3.client.ui.constants.Placement;
036import org.gwtbootstrap3.client.ui.constants.Trigger;
037
038import com.google.gwt.core.client.JavaScriptObject;
039import com.google.gwt.dom.client.Element;
040import com.google.gwt.event.logical.shared.AttachEvent;
041import com.google.gwt.safehtml.shared.SafeHtml;
042import com.google.gwt.user.client.Event;
043import com.google.gwt.user.client.Timer;
044import com.google.gwt.user.client.ui.HasOneWidget;
045import com.google.gwt.user.client.ui.HasWidgets;
046import com.google.gwt.user.client.ui.IsWidget;
047import com.google.gwt.user.client.ui.Widget;
048import com.google.web.bindery.event.shared.HandlerRegistration;
049
050/**
051 * Common implementation for the Bootstrap tooltip and popover.
052 *
053 * @author Joshua Godi
054 * @author Pontus Enmark
055 * @author Steven Jardine
056 */
057public abstract class AbstractTooltip implements IsWidget, HasWidgets, HasOneWidget, HasId, HasHover {
058    
059    private static final String TOGGLE = "toggle";
060    private static final String SHOW = "show";
061    private static final String HIDE = "hide";
062    private static final String DESTROY = "destroy";
063
064    // Defaults from http://getbootstrap.com/javascript/#tooltips
065    private boolean isAnimated = true;
066    private boolean isHTML = false;
067    private Placement placement = Placement.TOP;
068    private Trigger trigger = Trigger.HOVER;
069    private String title = "";
070    private int hideDelayMs = 0;
071    private int showDelayMs = 0;
072    private String container = null;
073    private String selector = null;
074    private String viewportSelector = "body";
075    private int viewportPadding = 0;
076
077    private String tooltipClassNames = "tooltip";
078    private String tooltipArrowClassNames = "tooltip-arrow";
079    private String tooltipInnerClassNames = "tooltip-inner";
080
081    private final static String DEFAULT_TEMPLATE = "<div class=\"{0}\"><div class=\"{1}\"></div><div class=\"{2}\"></div></div>";
082    private String alternateTemplate = null;
083
084    private Widget widget;
085    private String id;
086    private final String dataTarget;
087    private boolean initialized = false;
088    private boolean showing = false;
089
090    /**
091     * Creates the empty Tooltip
092     */
093    public AbstractTooltip(String dataTarget) {
094        this.dataTarget = dataTarget;
095    }
096
097    /**
098     * Creates the tooltip with given title. Remember to set the widget as well
099     *
100     * @param title title for the tooltip
101     */
102    public AbstractTooltip(String dataTarget, final String title) {
103        this(dataTarget);
104        setTitle(title);
105    }
106
107    /**
108     * Creates the tooltip around this widget
109     *
110     * @param w widget for the tooltip
111     */
112    public AbstractTooltip(String dataTarget, final Widget w) {
113        this(dataTarget);
114        setWidget(w);
115    }
116
117    /**
118     * Creates the tooltip around this widget with given title
119     *
120     * @param w widget for the tooltip
121     * @param title title for the tooltip
122     */
123    public AbstractTooltip(String dataTarget, final Widget w, final String title) {
124        this(dataTarget);
125        setWidget(w);
126        setTitle(title);
127    }
128
129    /**
130     * {@inheritDoc}
131     */
132    @Override
133    public void add(final Widget child) {
134        if (getWidget() != null) {
135            throw new IllegalStateException("Can only contain one child widget");
136        }
137        setWidget(child);
138    }
139
140    /**
141     * Adds a hidden handler to the Tooltip that will be fired when the Tooltip's hidden event is fired
142     *
143     * @param hiddenHandler HiddenHandler to handle the hidden event
144     * @return HandlerRegistration of the handler
145     */
146    public HandlerRegistration addHiddenHandler(final HiddenHandler hiddenHandler) {
147        return widget.addHandler(hiddenHandler, HiddenEvent.getType());
148    }
149
150    /**
151     * Adds a hide handler to the Tooltip that will be fired when the Tooltip's hide event is fired
152     *
153     * @param hideHandler HideHandler to handle the hide event
154     * @return HandlerRegistration of the handler
155     */
156    public HandlerRegistration addHideHandler(final HideHandler hideHandler) {
157        return widget.addHandler(hideHandler, HideEvent.getType());
158    }
159
160    /**
161     * Adds a show handler to the Tooltip that will be fired when the Tooltip's show event is fired
162     *
163     * @param showHandler ShowHandler to handle the show event
164     * @return HandlerRegistration of the handler
165     */
166    public HandlerRegistration addShowHandler(final ShowHandler showHandler) {
167        return widget.addHandler(showHandler, ShowEvent.getType());
168    }
169
170    /**
171     * Adds a shown handler to the Tooltip that will be fired when the Tooltip's shown event is fired
172     *
173     * @param shownHandler ShownHandler to handle the shown event
174     * @return HandlerRegistration of the handler
175     */
176    public HandlerRegistration addShownHandler(final ShownHandler shownHandler) {
177        return widget.addHandler(shownHandler, ShownEvent.getType());
178    }
179
180    /**
181     * Add a tooltip arrow div class name
182     *
183     * @param tooltipArrowClassName a tooltip arrow div class name
184     */
185    public void addTooltipArrowClassName(String tooltipArrowClassName) {
186        this.tooltipArrowClassNames += " " + tooltipArrowClassName;
187    }
188
189    /**
190     * Add a tooltip div class name
191     *
192     * @param tooltipClassName a tooltip div class name
193     */
194    public void addTooltipClassName(String tooltipClassName) {
195        this.tooltipClassNames += " " + tooltipClassName;
196    }
197
198    /**
199     * Add a tooltip inner div class name
200     *
201     * @param tooltipInnerClassName a tooltip inner div class name
202     */
203    public void addTooltipInnerClassName(String tooltipInnerClassName) {
204        this.tooltipInnerClassNames += " " + tooltipInnerClassName;
205    }
206
207    /** {@inheritDoc} */
208    @Override
209    public Widget asWidget() {
210        return widget;
211    }
212
213    // @formatter:off
214    protected native void bindJavaScriptEvents(final Element e) /*-{
215        var target = this;
216        var $tooltip = $wnd.jQuery(e);
217        var dataTarget = target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::dataTarget;
218        $tooltip.on('show.' + dataTarget, function (evt) {
219            target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::onShow(Lcom/google/gwt/user/client/Event;)(evt);
220        });
221        $tooltip.on('shown.' + dataTarget, function (evt) {
222            target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::onShown(Lcom/google/gwt/user/client/Event;)(evt);
223        });
224        $tooltip.on('hide.' + dataTarget, function (evt) {
225            target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::onHide(Lcom/google/gwt/user/client/Event;)(evt);
226        });
227        $tooltip.on('hidden.' + dataTarget, function (evt) {
228            target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::onHidden(Lcom/google/gwt/user/client/Event;)(evt);
229        });
230        $tooltip.on('inserted.' + dataTarget, function (evt) {
231            target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::onInserted(Lcom/google/gwt/user/client/Event;)(evt);
232        });
233    }-*/;
234    
235    protected abstract void call(final String arg);
236
237    /** {@inheritDoc} */
238    @Override
239    public void clear() {
240        widget = null;
241    }
242
243    /**
244     * Create the options for the tooltip.
245     */
246    protected native JavaScriptObject createOptions(Element e, boolean animation, boolean html, String selector,
247            String trigger, int showDelay, int hideDelay, String container, String template, String viewportSelector,
248            int viewportPadding) /*-{
249        var target = this;
250        var options = {
251            animation : animation,
252            delay : {
253                show : showDelay,
254                hide : hideDelay
255            },
256            html : html,
257            placement : function(tip, element) {
258                return target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::getPlacementCssName()();
259            },
260            template : template,
261            title : function() {
262                return target.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::getTitle()();
263            },
264            trigger : trigger,
265            viewport : {
266                selector: viewportSelector,
267                padding: viewportPadding
268            }
269        };
270        if (selector) {
271            options['selector'] = selector;
272        }
273        if (container) {
274            options['container'] = container;
275        }
276        return options;
277    }-*/;
278    
279    /**
280     * Force the Tooltip to be destroyed
281     */
282    public void destroy() {
283        call(DESTROY);
284        setInitialized(false);
285    }
286
287    /**
288     * Get the alternate template used to render the tooltip. If null,
289     * the default template will be used.
290     *
291     * @return String the alternate template used to render the tooltip
292     */
293    public String getAlternateTemplate() {
294        return alternateTemplate;
295    }
296
297    /** {@inheritDoc} */
298    @Override
299    public String getContainer() {
300        return container;
301    }
302
303    /** {@inheritDoc} */
304    @Override
305    public int getHideDelayMs() {
306        return hideDelayMs;
307    }
308
309    /** {@inheritDoc} */
310    @Override
311    public String getId() {
312        return (widget == null) ? id : widget.getElement().getId();
313    }
314
315    /** {@inheritDoc} */
316    @Override
317    public Placement getPlacement() {
318        return placement;
319    }
320
321    /**
322     * Gets the placement css name.
323     *
324     * @return the placement css name
325     */
326    private String getPlacementCssName() {
327        return placement == null ? Placement.TOP.getCssName() : placement.getCssName();
328    }
329
330    /**
331     * Get the tooltip's selector
332     *
333     * @return String the tooltip's selector
334     */
335    public String getSelector() {
336        return selector;
337    }
338
339    /** {@inheritDoc} */
340    @Override
341    public int getShowDelayMs() {
342        return showDelayMs;
343    }
344
345    /**
346     * Gets the tooltip's display string
347     *
348     * @return String tooltip display string
349     */
350    public String getTitle() {
351        return title;
352    }
353
354    /**
355     * Get the tooltip arrow div class names
356     *
357     * @return String Get the tooltip arrow div class names
358     */
359    public String getTooltipArrowClassNames() {
360        return tooltipArrowClassNames;
361    }
362
363    /**
364     * Get the tooltip div class names
365     *
366     * @return String the tooltip div class names
367     */
368    public String getTooltipClassNames() {
369        return tooltipClassNames;
370    }
371
372    /**
373     * Get the tooltip inner div class names
374     *
375     * @return String the tooltip inner div class names
376     */
377    public String getTooltipInnerClassNames() {
378        return tooltipInnerClassNames;
379    }
380
381    /** {@inheritDoc} */
382    @Override
383    public Trigger getTrigger() {
384        return trigger;
385    }
386
387    /**
388     * Gets the viewport.
389     *
390     * @param selector the selector
391     * @param padding the padding
392     * @return the viewport object for the tooltip options.
393     */
394    private native JavaScriptObject getViewport(String selector, int padding) /*-{
395        return {
396            selector: selector,
397            padding: padding
398        };
399    }-*/;
400
401    /**
402     * @return the viewportPadding
403     */
404    public int getViewportPadding() {
405        return viewportPadding;
406    }
407
408    /**
409     * @return the viewportSelector
410     */
411    public String getViewportSelector() {
412        return viewportSelector;
413    }
414
415    /** {@inheritDoc} */
416    @Override
417    public Widget getWidget() {
418        return widget;
419    }
420
421    /**
422     * Force hide the Tooltip
423     */
424    public void hide() {
425        call(HIDE);
426    }
427
428    /**
429     * Initializes the tooltip for use.
430     */
431    public abstract void init();
432
433    /** {@inheritDoc} */
434    @Override
435    public boolean isAnimated() {
436        return isAnimated;
437    }
438
439    /** {@inheritDoc} */
440    @Override
441    public boolean isHtml() {
442        return isHTML;
443    }
444
445    /**
446     * @return the initialized
447     */
448    public boolean isInitialized() {
449        return initialized;
450    }
451
452    /** {@inheritDoc} */
453    @Override
454    public Iterator<Widget> iterator() {
455        // Simple iterator for the widget
456        return new Iterator<Widget>() {
457
458            boolean hasElement = widget != null;
459
460            Widget returned = null;
461
462            /** {@inheritDoc} */
463            @Override
464            public boolean hasNext() {
465                return hasElement;
466            }
467
468            /** {@inheritDoc} */
469            @Override
470            public Widget next() {
471                if (!hasElement || (widget == null)) {
472                    throw new NoSuchElementException();
473                }
474                hasElement = false;
475                return (returned = widget);
476            }
477
478            /** {@inheritDoc} */
479            @Override
480            public void remove() {
481                if (returned != null) {
482                    AbstractTooltip.this.remove(returned);
483                }
484            }
485        };
486    }
487
488    /**
489     * Can be override by subclasses to handle Tooltip's "hidden" event however
490     * it's recommended to add an event handler to the tooltip.
491     *
492     * @param evt Event
493     * @see org.gwtbootstrap3.client.shared.event.HiddenEvent
494     */
495    protected void onHidden(final Event evt) {
496        showing = false;
497        widget.fireEvent(new HiddenEvent(evt));
498    }
499
500    /**
501     * Can be override by subclasses to handle Tooltip's "hide" event however
502     * it's recommended to add an event handler to the tooltip.
503     *
504     * @param evt Event
505     * @see org.gwtbootstrap3.client.shared.event.HideEvent
506     */
507    protected void onHide(final Event evt) {
508        widget.fireEvent(new HideEvent(evt));
509    }
510
511    /**
512     * Can be override by subclasses to handle Tooltip's "inserted" event however
513     * it's recommended to add an event handler to the tooltip.
514     *
515     * @param evt Event
516     * @see org.gwtbootstrap3.client.shared.event.InsertedEvent
517     */
518    protected void onInserted(final Event evt) {
519        widget.fireEvent(new InsertedEvent(evt));
520    }
521
522    /**
523     * Can be override by subclasses to handle Tooltip's "show" event however
524     * it's recommended to add an event handler to the tooltip.
525     *
526     * @param evt Event
527     * @see org.gwtbootstrap3.client.shared.event.ShowEvent
528     */
529    protected void onShow(final Event evt) {
530        widget.fireEvent(new ShowEvent(evt));
531    }
532
533    /**
534     * Can be override by subclasses to handle Tooltip's "shown" event however
535     * it's recommended to add an event handler to the tooltip.
536     *
537     * @param evt Event
538     * @see ShownEvent
539     */
540    protected void onShown(final Event evt) {
541        showing = true;
542        widget.fireEvent(new ShownEvent(evt));
543    }
544
545    protected String prepareTemplate() {
546        String template = null;
547        if (alternateTemplate == null) {
548            template = DEFAULT_TEMPLATE.replace("{0}", getTooltipClassNames());
549            template = template.replace("{1}", getTooltipArrowClassNames());
550            template = template.replace("{2}", getTooltipInnerClassNames());
551        } else {
552            template = alternateTemplate;
553        }
554        return template;
555    }
556
557    /**
558     * Reconfigures the tooltip.
559     * 
560     * @deprecated will be removed after the next release.
561     */
562    public void reconfigure() {
563        // Do nothing. No longer necessary.
564    }
565
566    /**
567     * Recreate the tooltip/popover with a default dealy of 300ms between the call to destroy and init.
568     */
569    public void recreate() {
570        recreate(300);
571    }
572
573    /**
574     * Recreate the tooltip/popover. The delay is necessary because the destroy of the tooltip needs to be complete
575     * prior to calling init.
576     *
577     * @param delay the delay in ms between the call to destroy and init.
578     */
579    public void recreate(int delay) {
580        destroy();
581        new Timer() {
582            @Override
583            public void run() {
584                init();
585            }
586        }.schedule(delay);
587    }
588
589    /** {@inheritDoc} */
590    @Override
591    public boolean remove(final Widget w) {
592        // Validate.
593        if (widget != w) {
594            return false;
595        }
596        // Logical detach.
597        clear();
598        return true;
599    }
600
601    /**
602     * Set the alternate template used to render the tooltip. The template should contain
603     * divs with classes 'tooltip', 'tooltip-inner', and 'tooltip-arrow'. If an alternate
604     * template is configured, the 'tooltipClassNames', 'tooltipArrowClassNames', and
605     * 'tooltipInnerClassNames' properties are not used.
606     *
607     * @param alternateTemplate the alternate template used to render the tooltip
608     */
609    public void setAlternateTemplate(String alternateTemplate) {
610        this.alternateTemplate = alternateTemplate;
611        if (initialized) {
612            updateString(widget.getElement(), "template", prepareTemplate());
613        }
614    }
615
616    /** {@inheritDoc} */
617    @Override
618    public void setContainer(final String container) {
619        this.container = container;
620        if (initialized) {
621            updateString(widget.getElement(), "container", container);
622        }
623    }
624
625    /** {@inheritDoc} */
626    @Override
627    public void setHideDelayMs(final int hideDelayMs) {
628        this.hideDelayMs = hideDelayMs;
629        if (initialized) {
630            updateDelay(widget.getElement(), showDelayMs, hideDelayMs);
631        }
632    }
633
634    /**
635     * Sets the tooltip's display string in HTML format
636     *
637     * @param text String display string in HTML format
638     */
639    public void setHtml(final SafeHtml html) {
640        setIsHtml(true);
641        if (html == null) {
642            setTitle("");
643        } else {
644            setTitle(html.asString());
645        }
646    }
647
648    /** {@inheritDoc} */
649    @Override
650    public void setId(final String id) {
651        this.id = id;
652        if (widget != null) {
653            widget.getElement().setId(id);
654        }
655    }
656
657    /**
658     * @param initialized the initialized to set
659     */
660    public void setInitialized(boolean initialized) {
661        this.initialized = initialized;
662    }
663
664    /** {@inheritDoc} */
665    @Override
666    public void setIsAnimated(final boolean isAnimated) {
667        this.isAnimated = isAnimated;
668        if (initialized) {
669            updateBool(widget.getElement(), "animation", isAnimated);
670        }
671    }
672
673    /** {@inheritDoc} */
674    @Override
675    public void setIsHtml(final boolean isHTML) {
676        this.isHTML = isHTML;
677        if (initialized) {
678            updateBool(widget.getElement(), "html", isHTML);
679        }
680
681    }
682
683    /** {@inheritDoc} */
684    @Override
685    public void setPlacement(final Placement placement) {
686        this.placement = placement;
687        if (initialized) {
688            updateString(widget.getElement(), "placement", getPlacementCssName());
689        }
690    }
691
692    /**
693     * Set the tooltip's selector
694     *
695     * @param selector the tooltip's selector
696     */
697    public void setSelector(String selector) {
698        this.selector = selector;
699        if (initialized) {
700            updateString(widget.getElement(), "selector", selector);
701        }
702    }
703
704    /** {@inheritDoc} */
705    @Override
706    public void setShowDelayMs(final int showDelayMs) {
707        this.showDelayMs = showDelayMs;
708        if (initialized) {
709            updateDelay(widget.getElement(), showDelayMs, hideDelayMs);
710        }
711    }
712
713    /**
714     * Convenience method. Sets the tooltop's display string.
715     * 
716     * @param text String display string.
717     * @deprecated use {@link #setTitle(String)}.
718     */
719    public void setText(String text) {
720        setTitle(text);
721    }
722
723    /**
724     * Sets the tooltip's display string
725     *
726     * @param title String display string
727     */
728    public void setTitle(final String title) {
729        this.title = title;
730        if (initialized) {
731            updateString(widget.getElement(), "title", this.title);
732            if (showing) {
733                updateTitleWhenShowing();
734            }
735        }
736    }
737
738    /**
739     * Set the tooltip arrow div class names
740     *
741     * @param tooltipArrowClassNames the tooltip arrow div class names
742     */
743    public void setTooltipArrowClassNames(String tooltipArrowClassNames) {
744        this.tooltipArrowClassNames = tooltipArrowClassNames;
745    }
746
747    /**
748     * Set the tooltip div class names
749     *
750     * @param tooltipClassNames the tooltip div class names
751     */
752    public void setTooltipClassNames(String tooltipClassNames) {
753        this.tooltipClassNames = tooltipClassNames;
754    }
755
756    /**
757     * Set the tooltip inner div class names
758     *
759     * @param tooltipInnerClassNames the tooltip inner div class names
760     */
761    public void setTooltipInnerClassNames(String tooltipInnerClassNames) {
762        this.tooltipInnerClassNames = tooltipInnerClassNames;
763    }
764
765    /** {@inheritDoc} */
766    @Override
767    public void setTrigger(final Trigger trigger) {
768        this.trigger = trigger;
769        if (initialized) {
770            updateString(widget.getElement(), "trigger",
771                    trigger == null ? Trigger.HOVER.getCssName() : trigger.getCssName());
772        }
773    }
774
775    /**
776     * @param viewportPadding the viewportPadding to set
777     */
778    public void setViewportPadding(int viewportPadding) {
779        this.viewportPadding = viewportPadding;
780        if (initialized) {
781            updateViewport(getWidget().getElement(), this.viewportSelector, this.viewportPadding);
782        }
783    }
784
785    /**
786     * @param viewportSelector the viewportSelector to set
787     */
788    public void setViewportSelector(String viewportSelector) {
789        this.viewportSelector = viewportSelector;
790        if (initialized) {
791            updateViewport(getWidget().getElement(), this.viewportSelector, this.viewportPadding);
792        }
793    }
794
795    /** {@inheritDoc} */
796    @Override
797    public void setWidget(final IsWidget w) {
798        setWidget(w.asWidget());
799    }
800
801    /** {@inheritDoc} */
802    @Override
803    public void setWidget(final Widget w) {
804        // Validate
805        if (w == widget) {
806            return;
807        }
808
809        // Detach new child
810        if (w != null) {
811            w.removeFromParent();
812        }
813
814        // Remove old child
815        if (widget != null) {
816            remove(widget);
817        }
818
819        // Logical attach, but don't physical attach; done by jquery.
820        widget = w;
821        if (widget == null) {
822            return;
823        }
824
825        // When we attach it, configure the tooltip
826        widget.addAttachHandler(new AttachEvent.Handler() {
827
828            @Override
829            public void onAttachOrDetach(final AttachEvent event) {
830                init();
831            }
832        });
833    }
834
835    /**
836     * Force show the Tooltip
837     */
838    public void show() {
839        call(SHOW);
840    }
841
842    /**
843     * Toggle the Tooltip to either show/hide
844     */
845    public void toggle() {
846        call(TOGGLE);
847    }
848
849    /** {@inheritDoc} */
850    @Override
851    public String toString() {
852        return asWidget().toString();
853    }
854
855    private native void updateBool(Element e, String option, boolean value) /*-{
856        var dataTarget = this.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::dataTarget;
857        $wnd.jQuery(e).data(dataTarget).options[option] = value;
858    }-*/;
859
860    private native void updateDelay(Element e, int showDelay, int hideDealy) /*-{
861        var dataTarget = this.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::dataTarget;
862        $wnd.jQuery(e).data(dataTarget).options['delay'] = {
863            show : showDelay,
864            hide : hideDelay
865        };
866    }-*/;
867
868    private native void updateString(Element e, String option, String value) /*-{
869        var dataTarget = this.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::dataTarget;
870        $wnd.jQuery(e).data(dataTarget).options[option] = value;
871    }-*/;
872
873    /**
874     * Update the title. This should only be called when the title is already showing. It causes a small flicker but
875     * updates the title immediately.
876     */
877    protected abstract void updateTitleWhenShowing();
878
879    private native void updateViewport(Element e, String selector, int padding) /*-{
880        var dataTarget = this.@org.gwtbootstrap3.client.ui.base.AbstractTooltip::dataTarget;
881        $wnd.jQuery(e).data(dataTarget).options['viewport'] = {
882            selector : selector,
883            padding : padding
884        };
885    }-*/;
886
887}