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.Close;
019import com.github.gwtbootstrap.client.ui.constants.AlertType;
020import com.github.gwtbootstrap.client.ui.constants.Constants;
021import com.github.gwtbootstrap.client.ui.constants.DismissType;
022import com.github.gwtbootstrap.client.ui.event.ClosedEvent;
023import com.github.gwtbootstrap.client.ui.event.ClosedHandler;
024import com.github.gwtbootstrap.client.ui.event.HasCloseHandlers;
025import com.google.gwt.dom.client.Element;
026import com.google.gwt.event.logical.shared.CloseEvent;
027import com.google.gwt.event.logical.shared.CloseHandler;
028import com.google.gwt.event.shared.HandlerRegistration;
029import com.google.gwt.safehtml.shared.SafeHtmlUtils;
030import com.google.gwt.user.client.ui.HTMLPanel;
031import com.google.gwt.user.client.ui.HasWidgets;
032
033/**
034 * Base class for Alert widgets.
035 *
036 * @author Dominik Mayer
037 * @author Carlos Alexandro Becker
038 *
039 * @see <a
040 *      href="http://getbootstrap.com/2.3.2/components.html#alerts">Bootstrap
041 *      documentation</a>
042 *
043 * @since 2.0.4.0
044 */
045public abstract class AlertBase extends HtmlWidget implements IsAnimated,
046        HasCloseHandlers<AlertBase>, HasType<AlertType> {
047
048    private Close close;
049
050    private HTMLPanel closeReplacement = new HTMLPanel("span", "");
051
052    private HTMLPanel headingContainer = new HTMLPanel("span", "");
053
054    private HTMLPanel container;
055
056    private boolean fade;
057
058    private boolean hasClose;
059
060    /**
061     * Initializes an Alert with a close icon.
062     */
063    public AlertBase() {
064        this("", true);
065    }
066
067    /**
068     * Initializes an Alert with a inner HTML.
069     *
070     * @param html inner HTML
071     */
072    public AlertBase(String html) {
073        this(html, true);
074    }
075
076    /**
077     * Initializes an Alert with an optional close icon.
078     *
079     * @param html     inner HTML
080     * @param hasClose whether the Alert should have a close icon.
081     */
082    public AlertBase(String html, boolean hasClose) {
083        super("div", "");
084
085        super.add(closeReplacement);
086        super.add(headingContainer);
087        container = new HTMLPanel("span", html);
088        super.add(container);
089        super.setStyleName(Constants.ALERT);
090        setClose(hasClose);
091    }
092
093    /**
094     * Initializes an Alert of given Type with a close icon.
095     *
096     * @param type of the Alert
097     */
098    public AlertBase(AlertType type) {
099        this();
100        setType(type);
101    }
102
103    /**
104     * Sets whether the Alert has a close icon or not.
105     *
106     * @param hasClose <code>false</code> if you don't want to have a close icon.
107     *                 Default: <code>true</code>
108     */
109    public void setClose(boolean hasClose) {
110
111        this.hasClose = hasClose;
112
113        if (!isAttached()) {
114            return;
115        }
116
117        if (hasClose) {
118            if (close == null) {
119                close = new Close(DismissType.ALERT);
120                getElement().replaceChild(close.getElement(), closeReplacement.getElement());
121            }
122        } else {
123            if (close != null) {
124                getElement().replaceChild(closeReplacement.getElement(), close.getElement());
125                close = null;
126            }
127        }
128    }
129
130    /**
131     * {@inheritDoc}
132     */
133    @Override
134    protected void onAttach() {
135        super.onAttach();
136        setClose(hasClose);
137        configure(getElement());
138        setHandlerFunctions(getElement());
139    }
140
141    /**
142     * has Close
143     *
144     * @return true:has close false:does not has close
145     */
146    public boolean hasClose() {
147        return hasClose;
148    }
149
150    /**
151     * Gets heading's container widget
152     *
153     * @return heading's container
154     */
155    protected HasWidgets getHeadingContainer() {
156        return headingContainer;
157    }
158
159    /**
160     * This method is called immediately when the widget's close method is
161     * executed.
162     */
163    // TODO: Get the source element from javascript
164    protected void onClose() {
165        CloseEvent.fire(this, this);
166    }
167
168    /**
169     * This method is called once the widget is completely closed.
170     */
171    // TODO: Get the source element from javascript
172    protected void onClosed() {
173        ClosedEvent.fire(this, this);
174    }
175
176    /**
177     * Sets the type of the Alert.
178     *
179     * @param type
180     */
181    public void setType(AlertType type) {
182        StyleHelper.changeStyle(this, type, AlertType.class);
183    }
184
185    /**
186     * Sets the text of an optional heading. The implementation depends on the
187     * subclass.
188     *
189     * @param text the new heading
190     */
191    public void setHeading(String text) {
192        headingContainer.clear();
193        headingContainer.add(new HTMLPanel("span", text));
194    }
195
196    /**
197     * Sets whether the Alert should be animated.
198     *
199     * @param animated <code>true</code> if the Alert should fade out. Default:
200     *                 <code>false</code>
201     */
202    public void setAnimation(boolean animated) {
203        this.fade = animated;
204        setFade();
205    }
206
207    /**
208     * {@inheritDoc}
209     */
210    public boolean getAnimation() {
211        return fade;
212    }
213
214    /**
215     * Delete the whole content of the Alert. This includes text, heading and
216     * close icon.
217     */
218    @Override
219    public void clear() {
220        container.clear();
221    }
222
223    /**
224     * Sets the classes that define whether the Alert fades or not.
225     */
226    private void setFade() {
227        if (fade) {
228            addStyleName("fade");
229            addStyleName("in");
230        } else {
231            removeStyleName("fade");
232            removeStyleName("in");
233        }
234    }
235
236    /**
237     * {@inheritDoc}
238     */
239    public String getText() {
240        return container.getElement().getInnerText();
241    }
242
243    /**
244     * {@inheritDoc}
245     */
246    public void setText(String text) {
247        setHTML(SafeHtmlUtils.htmlEscape(text));
248    }
249
250    /**
251     * {@inheritDoc}
252     */
253    public String getHTML() {
254        return container.getElement().getInnerHTML();
255    }
256
257    public void setHTML(String html) {
258        container.clear();
259        container.add(new HTMLPanel("span", html));
260    }
261
262    /**
263     * Close this alert.
264     */
265    public void close() {
266        close(getElement());
267    }
268
269    /**
270     * {@inheritDoc}
271     */
272    @Override
273    public HandlerRegistration addCloseHandler(CloseHandler<AlertBase> handler) {
274        return addHandler(handler, CloseEvent.getType());
275    }
276
277    /**
278     * {@inheritDoc}
279     */
280    @Override
281    public HandlerRegistration addClosedHandler(ClosedHandler<AlertBase> handler) {
282        return addHandler(handler, ClosedEvent.getType());
283    }
284
285    //@formatter:off
286
287    /**
288     * Adds the Java functions that fire the Events to document. It is a
289     * convenience method to have a cleaner code later on.
290     */
291    // TODO: Add autoTriggered feature in order to support autoClosed events. See {@link Modal}.
292    private native void setHandlerFunctions(Element e) /*-{
293        var that = this;
294        var $e = $wnd.jQuery(e);
295        $e.bind('close', function () {
296                [email protected]::onClose()();
297        });
298        $e.bind('closed', function () {
299                [email protected]::onClosed()();
300        });
301    }-*/;
302
303    private native void configure(Element e) /*-{
304        $wnd.jQuery(e).alert(e);
305    }-*/;
306
307    private native void close(Element e)/*-{
308        $wnd.jQuery(e).alert('close');
309    }-*/;
310    //@formatter:on
311
312}