001/*
002 *  Copyright 2012 GWT-Bootstrap
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.github.gwtbootstrap.client.ui.base;
017
018import com.github.gwtbootstrap.client.ui.constants.Placement;
019import com.github.gwtbootstrap.client.ui.constants.Trigger;
020import com.github.gwtbootstrap.client.ui.constants.VisibilityChange;
021import com.google.gwt.core.client.Scheduler;
022import com.google.gwt.core.client.Scheduler.ScheduledCommand;
023import com.google.gwt.dom.client.Element;
024import com.google.gwt.event.logical.shared.AttachEvent;
025import com.google.gwt.user.client.ui.HasOneWidget;
026import com.google.gwt.user.client.ui.HasText;
027import com.google.gwt.user.client.ui.HasWidgets;
028import com.google.gwt.user.client.ui.IsWidget;
029import com.google.gwt.user.client.ui.Widget;
030
031//@formatter:off
032/**
033* Base class for widgets that hover above other widgets.
034* 
035* @since 2.0.4.0
036* 
037* @author Dominik Mayer
038* 
039* @see <a href="http://twitter.github.com/bootstrap/javascript.html#popovers">Bootstrap documentation</a>
040*/
041//@formatter:on
042public abstract class HoverBase extends MarkupWidget  implements IsWidget, HasWidgets, HasOneWidget, IsAnimated, HasTrigger, HasPlacement, HasText, HasShowDelay, HasVisibility {
043
044        /**
045         * Whether the widget is animated or not.
046         */
047        protected boolean animated = true;
048
049        /**
050         * The placement of the widget relative to its trigger element.
051         */
052        protected Placement placement = Placement.TOP;
053
054        /**
055         * The action that triggers the widget.
056         */
057        protected Trigger trigger = Trigger.HOVER;
058
059        /**
060         * The delay until the widget is shown.
061         */
062        protected int showDelayInMilliseconds = 0;
063
064        /**
065         * The delay until the widget is hidden.
066         */
067        protected int hideDelayInMilliseconds = 0;
068
069    /**
070     * Appends the popover to a specific element.
071     */
072    protected String container;
073
074        /**
075         * Creates a new widget based on the provided HTML tag.
076         */
077        public HoverBase() {
078        }
079
080        /**
081         * {@inheritDoc}
082         */
083        @Override
084        public Widget asWidget() {
085                
086            if(getWidget() != null) {
087                Scheduler.get().scheduleDeferred(new ScheduledCommand() {
088                
089                @Override
090                public void execute() {
091                    removeDataIfExists();
092                    
093                    reconfigure();
094                    
095                    getWidget().addAttachHandler(new AttachEvent.Handler() {
096                        
097                        @Override
098                        public void onAttachOrDetach(AttachEvent event) {
099                            if (!event.isAttached()) {
100                                changeVisibility(VisibilityChange.HIDE);
101                            }
102                        }
103                    });
104                }
105            });
106                }
107                
108                return getWidget();
109
110        }
111        
112        protected void removeDataIfExists() {
113            hide();
114                removeDataIfExists(getWidget().getElement(), getDataName());
115        }
116        
117        protected abstract void removeDataIfExists(Element e, String dataName);
118
119        /**
120         * Adds an HTML data attribute to the widget's tag.
121         * 
122         * @param e target element
123         * 
124         * @param attribute
125         *            the name of the attribute without leading <code>"data-"</code>
126         * @param value
127         *            the value to be stored
128         */
129        protected void setDataAttribute(Element e , String attribute, String value) {
130                e.setAttribute("data-" + attribute, value);
131        }
132
133        /**
134         * {@inheritDoc}
135         */
136        public void setAnimation(boolean animated) {
137                this.animated = animated;
138        }
139
140        /**
141         * Redraws the widget with the currently set options. This must <b>not</b>
142         * be called when a parameter is updated because it would deactivate all
143         * other parameters. No idea why...
144         */
145        public abstract void reconfigure();
146
147        /**
148         * {@inheritDoc}
149         */
150        public boolean getAnimation() {
151                return animated;
152        }
153
154        /**
155         * {@inheritDoc} Relative to its trigger element.
156         */
157        public void setPlacement(Placement placement) {
158                this.placement = placement;
159        }
160
161        /**
162         * {@inheritDoc}
163         */
164        public Placement getPlacement() {
165                return placement;
166        }
167
168        /**
169         * {@inheritDoc}
170         */
171        public void setTrigger(Trigger trigger) {
172                this.trigger = trigger;
173        }
174
175        /**
176         * {@inheritDoc}
177         */
178        public Trigger getTrigger() {
179                return trigger;
180        }
181
182        /**
183         * {@inheritDoc}
184         */
185        public void setShowDelay(int delayInMilliseconds) {
186                showDelayInMilliseconds = delayInMilliseconds;
187        }
188
189        /**
190         * {@inheritDoc}
191         */
192        public int getShowDelay() {
193                return showDelayInMilliseconds;
194        }
195
196        /**
197         * {@inheritDoc}
198         */
199        public void setHideDelay(int delayInMilliseconds) {
200                hideDelayInMilliseconds = delayInMilliseconds;
201        }
202
203        /**
204         * {@inheritDoc}
205         */
206        public int getHideDelay() {
207                return hideDelayInMilliseconds;
208        }
209
210        /**
211         * {@inheritDoc}
212         */
213        public void show() {
214                changeVisibility(VisibilityChange.SHOW);
215        }
216
217        /**
218         * {@inheritDoc}
219         */
220        public void hide() {
221                changeVisibility(VisibilityChange.HIDE);
222        }
223
224        /**
225         * {@inheritDoc}
226         */
227        public void toggle() {
228                changeVisibility(VisibilityChange.TOGGLE);
229        }
230
231        /**
232         * Changes the visibility of the widget.
233         * 
234         * @param visibilityChange
235         *            the action to be performed
236         */
237        protected abstract void changeVisibility(VisibilityChange visibilityChange);
238
239        /**
240         * Get data name of JS Data API.
241         * @return data name
242         */
243        protected abstract String getDataName();
244
245    /**
246     * @return Specific element the Popover/Tooltip is appended to
247     */
248    public String getContainer() {
249        return container;
250    }
251
252    /**
253     * Set specific element the Popover/Tooltip is appended to
254     * @param container  Specific element the Popover/Tooltip is appended to. E.g. 'body' or null.
255     */
256    public void setContainer(String container) {
257        this.container = container;
258    }
259}