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                this.onDetach();
175    }
176
177    /**
178     * Sets the type of the Alert.
179     *
180     * @param type
181     */
182    public void setType(AlertType type) {
183        StyleHelper.changeStyle(this, type, AlertType.class);
184    }
185
186    /**
187     * Sets the text of an optional heading. The implementation depends on the
188     * subclass.
189     *
190     * @param text the new heading
191     */
192    public void setHeading(String text) {
193        headingContainer.clear();
194        headingContainer.add(new HTMLPanel("span", text));
195    }
196
197    /**
198     * Sets whether the Alert should be animated.
199     *
200     * @param animated <code>true</code> if the Alert should fade out. Default:
201     *                 <code>false</code>
202     */
203    public void setAnimation(boolean animated) {
204        this.fade = animated;
205        setFade();
206    }
207
208    /**
209     * {@inheritDoc}
210     */
211    public boolean getAnimation() {
212        return fade;
213    }
214
215    /**
216     * Delete the whole content of the Alert. This includes text, heading and
217     * close icon.
218     */
219    @Override
220    public void clear() {
221        container.clear();
222    }
223
224    /**
225     * Sets the classes that define whether the Alert fades or not.
226     */
227    private void setFade() {
228        if (fade) {
229            addStyleName("fade");
230            addStyleName("in");
231        } else {
232            removeStyleName("fade");
233            removeStyleName("in");
234        }
235    }
236
237    /**
238     * {@inheritDoc}
239     */
240    public String getText() {
241        return container.getElement().getInnerText();
242    }
243
244    /**
245     * {@inheritDoc}
246     */
247    public void setText(String text) {
248        setHTML(SafeHtmlUtils.htmlEscape(text));
249    }
250
251    /**
252     * {@inheritDoc}
253     */
254    public String getHTML() {
255        return container.getElement().getInnerHTML();
256    }
257
258    public void setHTML(String html) {
259        container.clear();
260        container.add(new HTMLPanel("span", html));
261    }
262
263    /**
264     * Close this alert.
265     */
266    public void close() {
267        close(getElement());
268    }
269
270    /**
271     * {@inheritDoc}
272     */
273    @Override
274    public HandlerRegistration addCloseHandler(CloseHandler<AlertBase> handler) {
275        return addHandler(handler, CloseEvent.getType());
276    }
277
278    /**
279     * {@inheritDoc}
280     */
281    @Override
282    public HandlerRegistration addClosedHandler(ClosedHandler<AlertBase> handler) {
283        return addHandler(handler, ClosedEvent.getType());
284    }
285
286    //@formatter:off
287
288    /**
289     * Adds the Java functions that fire the Events to document. It is a
290     * convenience method to have a cleaner code later on.
291     */
292    // TODO: Add autoTriggered feature in order to support autoClosed events. See {@link Modal}.
293    private native void setHandlerFunctions(Element e) /*-{
294        var that = this;
295        var $e = $wnd.jQuery(e);
296        $e.bind('close', function () {
297                that.@com.github.gwtbootstrap.client.ui.base.AlertBase::onClose()();
298        });
299        $e.bind('closed', function () {
300                that.@com.github.gwtbootstrap.client.ui.base.AlertBase::onClosed()();
301        });
302    }-*/;
303
304    private native void configure(Element e) /*-{
305        $wnd.jQuery(e).alert(e);
306    }-*/;
307
308    private native void close(Element e)/*-{
309        $wnd.jQuery(e).alert('close');
310    }-*/;
311    //@formatter:on
312
313}