001package gwt.material.design.client.ui;
002
003/*
004 * #%L
005 * GwtMaterial
006 * %%
007 * Copyright (C) 2015 GwtMaterialDesign
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 gwt.material.design.client.base.MaterialWidget;
024import gwt.material.design.client.base.HasDismissable;
025import gwt.material.design.client.base.HasTransition;
026import gwt.material.design.client.base.HasType;
027import gwt.material.design.client.base.mixin.CssTypeMixin;
028import gwt.material.design.client.constants.ModalType;
029
030import com.google.gwt.dom.client.Document;
031import com.google.gwt.dom.client.Element;
032import com.google.gwt.event.logical.shared.CloseEvent;
033import com.google.gwt.event.logical.shared.CloseHandler;
034import com.google.gwt.event.logical.shared.HasCloseHandlers;
035import com.google.gwt.event.shared.HandlerRegistration;
036
037//@formatter:off
038
039/**
040 * Dialogs are content that are not original visible on a page but show up with
041 * extra information if needed. The transitions should make the appearance of
042 * the dialog make sense and not jarring to the user.
043 *
044 *
045 * <p>
046 * <h3>UiBinder Usage:</h3>
047 *
048 * <pre>
049 * {@code
050 * <m:MaterialModal ui:field="modal" type="FIXED_FOOTER" dismissable="true" inDuration="500" outDuration="800">
051 *     <m:MaterialModalContent>
052 *         <m:MaterialTitle title="Title" description="Description" />
053 *     </m:MaterialModalContent>
054 *     <m:MaterialModalFooter>
055 *         <m:MaterialButton text="Close Modal" type="FLAT"/>
056 *     </m:MaterialModalFooter>
057 * </m:MaterialModal>
058 * }
059 * </pre>
060 *
061 * *
062 * <h3>Java Usage:</h3>
063 *
064 * <pre>
065 * {
066 *     &#064;code
067 *     &#064;UiField
068 *     MaterialModal modal;
069 *     modal.openModal();
070 * }
071 * </pre>
072 * 
073 * </p>
074 *
075 * @author kevzlou7979
076 * @author Ben Dol
077 * @see <a href="http://gwt-material-demo.herokuapp.com/#dialogs">Material
078 *      Modals</a>
079 */
080// @formatter:on
081public class MaterialModal extends MaterialWidget implements HasType<ModalType>, HasTransition,
082    HasDismissable, HasCloseHandlers<MaterialModal> {
083
084    private final CssTypeMixin<ModalType, MaterialModal> typeMixin = new CssTypeMixin<>(this);
085    private int inDuration = 300;
086    private int outDuration = 200;
087    private boolean dismissable = false;
088    private double opacity = 0.5;
089
090    public MaterialModal() {
091        super(Document.get().createDivElement(), "modal");
092    }
093
094    /**
095     * Open the modal programatically
096     * 
097     * <p>
098     * Note: the MaterialModal component must be added to the document before
099     * calling this method. When declaring this modal on a UiBinder file, the
100     * MaterialModal is already added, but if you call it using pure Java, you
101     * must add it to a container before opening the modal. You can do it by
102     * calling, for example:
103     * </p>
104     * 
105     * <pre>
106     * MaterialModal modal = new MaterialModal();
107     * RootPanel.get().add(modal);
108     * </pre>
109     * 
110     * @throws IllegalStateException
111     *             If the MaterialModal is not added to the document
112     */
113    public void openModal() {
114        // the modal must be added to the document before opening
115        if (this.getParent() == null) {
116            throw new IllegalStateException(
117                "The MaterialModal must be added to the document before calling openModal().");
118        }
119        openModal(getElement(), opacity, dismissable, inDuration, outDuration);
120    }
121
122    /**
123     * Open modal with additional properties
124     * 
125     * @param e
126     *            - Modal Component
127     * @param opacity
128     *            - Opacity of modal background
129     * @param dismissable
130     *            - Modal can be dismissed by clicking outside of the modal
131     * @param inDuration
132     *            - Transition in Duration
133     * @param outDuration
134     *            - Transition out Duration
135     */
136    protected native void openModal(Element e, double opacity, boolean dismissable, int inDuration, int outDuration) /*-{
137        var obj = this;
138        $wnd.jQuery(e).openModal({
139            opacity: opacity,
140            dismissible: dismissable,
141            in_duration: inDuration,
142            out_duration: outDuration,
143            complete: function () { obj.@gwt.material.design.client.ui.MaterialModal::onNativeClose(Z)(true); }
144        });
145    }-*/;
146
147    protected void onNativeClose(boolean autoClosed) {
148        CloseEvent.fire(this, this, autoClosed);
149    }
150
151    /**
152     * Close the modal programatically. It is the same as calling
153     * {@link #closeModal(boolean)} with <code>false</code> as parameter.
154     * <p>
155     * Note: you may need to remove it MaterialModal from the document if you
156     * are not using UiBinder. See {@link #openModal()}.
157     * </p>
158     * 
159     */
160    public void closeModal() {
161        closeModal(false);
162    }
163
164    /**
165     * Close the modal programatically.
166     * <p>
167     * Note: you may need to remove it MaterialModal from the document if you
168     * are not using UiBinder. See {@link #openModal()}.
169     * </p>
170     * 
171     * @param autoClosed
172     *            Flag indicating if the modal was automatically dismissed
173     * 
174     * @see CloseEvent
175     */
176    public void closeModal(boolean autoClosed) {
177        closeModal(getElement(), autoClosed);
178    }
179
180    protected native void closeModal(Element e, boolean autoClosed) /*-{
181        var obj = this;
182        $wnd.jQuery(e).closeModal({
183            complete: function () { obj.@gwt.material.design.client.ui.MaterialModal::onNativeClose(Z)(autoClosed); }
184        });
185    }-*/;
186
187    @Override
188    public void setType(ModalType type) {
189        typeMixin.setType(type);
190    }
191
192    @Override
193    public ModalType getType() {
194        return typeMixin.getType();
195    }
196
197    @Override
198    public void setInDuration(int inDuration) {
199        this.inDuration = inDuration;
200    }
201
202    @Override
203    public void setOutDuration(int outDuration) {
204        this.outDuration = outDuration;
205    }
206
207    @Override
208    public void setDismissable(boolean dismissable) {
209        this.dismissable = dismissable;
210    }
211
212    @Override
213    public boolean isDismissable() {
214        return dismissable;
215    }
216
217    @Override
218    public void setOpacity(double opacity) {
219        this.opacity = opacity;
220    }
221
222    @Override
223    public HandlerRegistration addCloseHandler(CloseHandler<MaterialModal> handler) {
224        return this.addHandler(handler, CloseEvent.getType());
225    }
226
227}