001/* 002 * #%L 003 * GwtMaterial 004 * %% 005 * Copyright (C) 2015 - 2017 GwtMaterialDesign 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package gwt.material.design.client.ui; 021 022import com.google.gwt.dom.client.Document; 023import com.google.gwt.dom.client.Element; 024import com.google.gwt.event.logical.shared.*; 025import com.google.gwt.event.shared.HandlerRegistration; 026import gwt.material.design.client.base.*; 027import gwt.material.design.client.base.mixin.CssTypeMixin; 028import gwt.material.design.client.base.mixin.FullscreenMixin; 029import gwt.material.design.client.constants.CssName; 030import gwt.material.design.client.constants.ModalType; 031import gwt.material.design.client.js.JsModalOptions; 032 033import static gwt.material.design.client.js.JsMaterialElement.$; 034 035//@formatter:off 036 037/** 038 * Dialogs are content that are not original visible on a page but show up with 039 * extra information if needed. The transitions should make the appearance of 040 * the dialog make sense and not jarring to the user. 041 * <p> 042 * <h3>UiBinder Usage:</h3> 043 * <p> 044 * <pre> 045 * {@code 046 * <m:MaterialModal ui:field="modal" type="FIXED_FOOTER" dismissible="true" inDuration="500" outDuration="800"> 047 * <m:MaterialModalContent> 048 * <m:MaterialTitle title="Title" description="Description" /> 049 * </m:MaterialModalContent> 050 * <m:MaterialModalFooter> 051 * <m:MaterialButton text="Close Modal" type="FLAT"/> 052 * </m:MaterialModalFooter> 053 * </m:MaterialModal> 054 * } 055 * </pre> 056 * <p> 057 * * 058 * <h3>Java Usage:</h3> 059 * <p> 060 * <pre> 061 * { 062 * @code 063 * @UiField 064 * MaterialModal modal; 065 * modal.open(); 066 * } 067 * </pre> 068 * <p> 069 * </p> 070 * 071 * @author kevzlou7979 072 * @author Ben Dol 073 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#dialogs">Material Modals</a> 074 * @see <a href="https://material.io/guidelines/components/dialogs.html#">Material Design Specification</a> 075 */ 076// @formatter:on 077public class MaterialModal extends MaterialWidget implements HasType<ModalType>, HasInOutDurationTransition, 078 HasDismissible, HasCloseHandlers<MaterialModal>, HasOpenHandlers<MaterialModal>, HasFullscreen { 079 080 private JsModalOptions options = new JsModalOptions(); 081 082 private CssTypeMixin<ModalType, MaterialModal> typeMixin; 083 private FullscreenMixin fullscreenMixin; 084 085 public MaterialModal() { 086 super(Document.get().createDivElement(), CssName.MODAL); 087 } 088 089 090 @Override 091 public void setType(ModalType type) { 092 getTypeMixin().setType(type); 093 } 094 095 @Override 096 public ModalType getType() { 097 return getTypeMixin().getType(); 098 } 099 100 @Override 101 public void setInDuration(int inDuration) { 102 options.in_duration = inDuration; 103 } 104 105 @Override 106 public int getInDuration() { 107 return options.in_duration; 108 } 109 110 @Override 111 public void setOutDuration(int outDuration) { 112 options.out_duration = outDuration; 113 } 114 115 @Override 116 public int getOutDuration() { 117 return options.out_duration; 118 } 119 120 @Override 121 public void setDismissible(boolean dismissible) { 122 options.dismissible = dismissible; 123 } 124 125 @Override 126 public boolean isDismissible() { 127 return options.dismissible; 128 } 129 130 @Override 131 public void setOpacity(double opacity) { 132 options.opacity = opacity; 133 } 134 135 @Override 136 public double getOpacity() { 137 return options.opacity; 138 } 139 140 @Override 141 public void setEnabled(boolean enabled) { 142 getEnabledMixin().setEnabled(this, enabled); 143 } 144 145 @Override 146 public void setFullscreen(boolean value) { 147 if (getType() != ModalType.BOTTOM_SHEET) { 148 getFullscreenMixin().setFullscreen(value); 149 } 150 } 151 152 @Override 153 public boolean isFullscreen() { 154 return getFullscreenMixin().isFullscreen(); 155 } 156 157 /** 158 * Open the modal programmatically 159 * <p> 160 * Note: the MaterialModal component must be added to the document before 161 * calling this method. When declaring this modal on a UiBinder file, the 162 * MaterialModal is already added, but if you call it using pure Java, you 163 * must add it to a container before opening the modal. You can do it by 164 * calling, for example: 165 * </p> 166 * <pre> 167 * MaterialModal modal = new MaterialModal(); 168 * RootPanel.get().add(modal); 169 * </pre> 170 * 171 * @throws IllegalStateException If the MaterialModal is not added to the document 172 */ 173 public void open() { 174 open(true); 175 } 176 177 /** 178 * Open the modal programmatically 179 * <p> 180 * Note: the MaterialModal component must be added to the document before 181 * calling this method. When declaring this modal on a UiBinder file, the 182 * MaterialModal is already added, but if you call it using pure Java, you 183 * must add it to a container before opening the modal. You can do it by 184 * calling, for example: 185 * </p> 186 * <pre> 187 * MaterialModal modal = new MaterialModal(); 188 * RootPanel.get().add(modal); 189 * </pre> 190 * @param fireEvent - Flag whether this component fires Open Event 191 * 192 * @throws IllegalStateException If the MaterialModal is not added to the document 193 */ 194 public void open(boolean fireEvent) { 195 // the modal must be added to the document before opening 196 if (this.getParent() == null) { 197 throw new IllegalStateException( 198 "The MaterialModal must be added to the document before calling open()."); 199 } 200 open(getElement(), fireEvent); 201 } 202 203 /** 204 * Open modal with additional properties 205 * 206 * @param e - Modal Component 207 * @param fireEvent - Flag whether this component fires Open Event 208 */ 209 protected void open(Element e, boolean fireEvent) { 210 options.complete = () -> onNativeClose(true, true); 211 options.ready = () -> onNativeOpen(fireEvent); 212 $(e).openModal(options); 213 } 214 215 protected void onNativeOpen(boolean fireEvent) { 216 if(fireEvent) { 217 OpenEvent.fire(this, this); 218 } 219 } 220 221 protected void onNativeClose(boolean autoClosed, boolean fireEvent) { 222 if (fireEvent) { 223 CloseEvent.fire(this, this, autoClosed); 224 } 225 } 226 227 /** 228 * Close the modal programmatically. It is the same as calling 229 * {@link #close(boolean)} with <code>false</code> as parameter. 230 * <p> 231 * Note: you may need to remove it MaterialModal from the document if you 232 * are not using UiBinder. See {@link #open()}. 233 * </p> 234 */ 235 public void close() { 236 close(false); 237 } 238 239 /** 240 * Close the modal programmatically. 241 * <p> 242 * Note: you may need to remove it MaterialModal from the document if you 243 * are not using UiBinder. See {@link #open()}. 244 * </p> 245 * 246 * @param autoClosed Flag indicating if the modal was automatically dismissed 247 * @see CloseEvent 248 */ 249 public void close(boolean autoClosed) { 250 close(autoClosed, true); 251 } 252 253 /** 254 * Close the modal programmatically. 255 * <p> 256 * Note: you may need to remove it MaterialModal from the document if you 257 * are not using UiBinder. See {@link #open()}. 258 * </p> 259 * 260 * @param autoClosed Flag indicating if the modal was automatically dismissed 261 * @param fireEvent Flag whether this component fires Close Event 262 * @see CloseEvent 263 */ 264 public void close(boolean autoClosed, boolean fireEvent) { 265 close(getElement(), autoClosed, fireEvent); 266 } 267 268 protected void close(Element e, boolean autoClosed, boolean fireEvent) { 269 if (options != null) { 270 options.complete = () -> onNativeClose(autoClosed, fireEvent); 271 $(e).closeModal(options); 272 } 273 } 274 275 @Override 276 public HandlerRegistration addCloseHandler(CloseHandler<MaterialModal> handler) { 277 return addHandler(handler, CloseEvent.getType()); 278 } 279 280 @Override 281 public HandlerRegistration addOpenHandler(OpenHandler<MaterialModal> handler) { 282 return addHandler(handler, OpenEvent.getType()); 283 } 284 285 protected CssTypeMixin<ModalType, MaterialModal> getTypeMixin() { 286 if (typeMixin == null) { 287 typeMixin = new CssTypeMixin<>(this); 288 } 289 return typeMixin; 290 } 291 292 protected FullscreenMixin getFullscreenMixin() { 293 if (fullscreenMixin == null) { 294 fullscreenMixin = new FullscreenMixin(this); 295 } 296 return fullscreenMixin; 297 } 298}