001 package org.gwtbootstrap3.client.ui;
002
003 /*
004 * #%L
005 * GwtBootstrap3
006 * %%
007 * Copyright (C) 2013 GwtBootstrap3
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
023 import org.gwtbootstrap3.client.shared.event.ModalHiddenEvent;
024 import org.gwtbootstrap3.client.shared.event.ModalHiddenHandler;
025 import org.gwtbootstrap3.client.shared.event.ModalHideEvent;
026 import org.gwtbootstrap3.client.shared.event.ModalHideHandler;
027 import org.gwtbootstrap3.client.shared.event.ModalShowEvent;
028 import org.gwtbootstrap3.client.shared.event.ModalShowHandler;
029 import org.gwtbootstrap3.client.shared.event.ModalShownEvent;
030 import org.gwtbootstrap3.client.shared.event.ModalShownHandler;
031 import org.gwtbootstrap3.client.ui.base.helper.StyleHelper;
032 import org.gwtbootstrap3.client.ui.base.modal.ModalContent;
033 import org.gwtbootstrap3.client.ui.base.modal.ModalDialog;
034 import org.gwtbootstrap3.client.ui.constants.Attributes;
035 import org.gwtbootstrap3.client.ui.constants.ModalBackdrop;
036 import org.gwtbootstrap3.client.ui.constants.Styles;
037 import org.gwtbootstrap3.client.ui.html.Div;
038
039 import com.google.gwt.dom.client.Element;
040 import com.google.gwt.user.client.Event;
041 import com.google.gwt.user.client.ui.RootPanel;
042 import com.google.gwt.user.client.ui.Widget;
043 import com.google.web.bindery.event.shared.HandlerRegistration;
044
045 /**
046 * Modal dialog.
047 * <p/>
048 * <h3>UiBinder example</h3>
049 * <p/>
050 * <pre>
051 * {@code
052 * <b:Modal title="Important information" b:id="modal1">
053 * <b:ModalBody>
054 * <g:HTML>Lorem ipsum...</g:HTML>
055 * </b:ModalBody>
056 * <b:ModalFooter>
057 * <b:Button type="PRIMARY">Do something</b:Button>
058 * <b:Button type="DANGER" dismiss="MODAL">Close</b:Button>
059 * </b:ModalFooter>
060 * </b:Modal>
061 * <b:Button target="#modal1" toggle="MODAL">Show modal</b:Button>
062 * }
063 * </pre>
064 * <p/>
065 * It's also possible to specify a custom modal header:
066 * <p/>
067 * <pre>
068 * {@code
069 * <b:Modal>
070 * <b:ModalHeader>
071 * <g:HTML>
072 * <h4>Custom header</h4>
073 * </g:HTML>
074 * </b:ModalHeader>
075 * ...
076 * </b:Modal>
077 * }
078 * </pre>
079 *
080 * @author Sven Jacobs
081 * @author Joshua Godi
082 * @see ModalHeader
083 * @see ModalBody
084 * @see ModalFooter
085 * @see org.gwtbootstrap3.client.shared.event.ModalShowEvent
086 * @see org.gwtbootstrap3.client.shared.event.ModalShownEvent
087 * @see org.gwtbootstrap3.client.shared.event.ModalHideEvent
088 * @see org.gwtbootstrap3.client.shared.event.ModalHiddenEvent
089 */
090 public class Modal extends Div implements IsClosable {
091
092 private final static String TOGGLE = "toggle";
093 private final static String HIDE = "hide";
094 private final static String SHOW = "show";
095
096 private final ModalContent content = new ModalContent();
097 private final ModalDialog dialog = new ModalDialog();
098 private ModalHeader header = new ModalHeader();
099
100 private boolean hideOtherModals = false;
101
102 public Modal() {
103 setStyleName(Styles.MODAL);
104
105 content.add(header);
106 dialog.add(content);
107
108 add(dialog);
109 }
110
111 @Override
112 public void setWidth(final String width) {
113 dialog.setWidth(width);
114 }
115
116 public void setSize(ModalSize size) {
117 StyleHelper.addUniqueEnumStyleName(dialog, ModalSize.class, size);
118 }
119
120 @Override
121 protected void onLoad() {
122 super.onLoad();
123 bindJavaScriptEvents(getElement());
124 }
125
126 @Override
127 public void add(final Widget w) {
128 // User can supply own ModalHeader
129 if (w instanceof ModalHeader) {
130 header.removeFromParent();
131 header = (ModalHeader) w;
132 }
133
134 if (w instanceof ModalComponent) {
135 content.add(w);
136 } else {
137 super.add(w);
138 }
139 }
140
141 @Override
142 public void setTitle(final String title) {
143 header.setTitle(title);
144 }
145
146 @Override
147 public void setClosable(final boolean closable) {
148 header.setClosable(closable);
149 }
150
151 @Override
152 public boolean isClosable() {
153 return header.isClosable();
154 }
155
156 /**
157 * If set to true, when the modal is shown it will force hide all other modals
158 *
159 * @param hideOtherModals - true to force hide other modals, false to keep them shown
160 */
161 public void setHideOtherModals(final boolean hideOtherModals) {
162 this.hideOtherModals = hideOtherModals;
163 }
164
165 /**
166 * If set to true, will remove the modal from the DOM completely and unbind any events to the modal
167 *
168 * @param removeOnHide - true to remove modal and unbind events on hide, false to keep it in the DOM
169 */
170 public void setRemoveOnHide(final boolean removeOnHide) {
171 if (removeOnHide) {
172 addHiddenHandler(new ModalHiddenHandler() {
173 @Override
174 public void onHidden(final ModalHiddenEvent evt) {
175 unbindAllHandlers(getElement());
176 removeFromParent();
177 }
178 });
179 }
180 }
181
182 /**
183 * If set Modal will fade in/out.
184 *
185 * @param fade If {@code true} modal will fade in/out
186 */
187 public void setFade(final boolean fade) {
188 if (fade) {
189 addStyleName(Styles.FADE);
190 } else {
191 removeStyleName(Styles.FADE);
192 }
193 }
194
195 /**
196 * Sets backdrop of modal.
197 *
198 * @param backdrop Backdrop of modal
199 * @see org.gwtbootstrap3.client.ui.constants.ModalBackdrop
200 */
201 public void setDataBackdrop(final ModalBackdrop backdrop) {
202 if (backdrop != null) {
203 getElement().setAttribute(Attributes.DATA_BACKDROP, backdrop.getBackdrop());
204 } else {
205 getElement().removeAttribute(Attributes.DATA_BACKDROP);
206 }
207 }
208
209 public void setDataKeyboard(final boolean keyboard) {
210 getElement().setAttribute(Attributes.DATA_KEYBOARD, Boolean.toString(keyboard));
211
212 // tabindex must be set to -1 for ESC key to work
213 if (keyboard) {
214 getElement().setAttribute(Attributes.TABINDEX, "-1");
215 }
216 }
217
218 public void toggle() {
219 modal(getElement(), TOGGLE);
220 }
221
222 public void show() {
223 checkIsAttached();
224 modal(getElement(), SHOW);
225 }
226
227 public void hide() {
228 modal(getElement(), HIDE);
229 }
230
231 public HandlerRegistration addShowHandler(final ModalShowHandler modalShowHandler) {
232 return addHandler(modalShowHandler, ModalShowEvent.getType());
233 }
234
235 public HandlerRegistration addShownHandler(final ModalShownHandler modalShownHandler) {
236 return addHandler(modalShownHandler, ModalShownEvent.getType());
237 }
238
239 public HandlerRegistration addHideHandler(final ModalHideHandler modalHideHandler) {
240 return addHandler(modalHideHandler, ModalHideEvent.getType());
241 }
242
243 public HandlerRegistration addHiddenHandler(final ModalHiddenHandler modalHiddenHandler) {
244 return addHandler(modalHiddenHandler, ModalHiddenEvent.getType());
245 }
246
247 /**
248 * Can be override by subclasses to handle Modal's "show" event however it's
249 * recommended to add an event handler to the modal.
250 *
251 * @param evt Event
252 * @see org.gwtbootstrap3.client.shared.event.ModalShowEvent
253 */
254 protected void onShow(final Event evt) {
255 if (hideOtherModals) {
256 hideOtherModals();
257 }
258 fireEvent(new ModalShowEvent(this, evt));
259 }
260
261 /**
262 * Can be override by subclasses to handle Modal's "shown" event however
263 * it's recommended to add an event handler to the modal.
264 *
265 * @param evt Event
266 * @see org.gwtbootstrap3.client.shared.event.ModalShownEvent
267 */
268 protected void onShown(final Event evt) {
269 fireEvent(new ModalShownEvent(this, evt));
270 }
271
272 /**
273 * Can be override by subclasses to handle Modal's "hide" event however it's
274 * recommended to add an event handler to the modal.
275 *
276 * @param evt Event
277 * @see org.gwtbootstrap3.client.shared.event.ModalHideEvent
278 */
279 protected void onHide(final Event evt) {
280 fireEvent(new ModalHideEvent(this, evt));
281 }
282
283 /**
284 * Can be override by subclasses to handle Modal's "hidden" event however
285 * it's recommended to add an event handler to the modal.
286 *
287 * @param evt Event
288 * @see org.gwtbootstrap3.client.shared.event.ModalHiddenEvent
289 */
290 protected void onHidden(final Event evt) {
291 fireEvent(new ModalHiddenEvent(this, evt));
292 }
293
294 private void checkIsAttached() {
295 if (!this.isAttached()) {
296 RootPanel.get().add(this);
297 }
298 }
299
300 private native void bindJavaScriptEvents(final Element e) /*-{
301 var target = this;
302 var $modal = $wnd.jQuery(e);
303
304 $modal.on('show.bs.modal', function (evt) {
305 target.@org.gwtbootstrap3.client.ui.Modal::onShow(Lcom/google/gwt/user/client/Event;)(evt);
306 });
307
308 $modal.on('shown.bs.modal', function (evt) {
309 target.@org.gwtbootstrap3.client.ui.Modal::onShown(Lcom/google/gwt/user/client/Event;)(evt);
310 });
311
312 $modal.on('hide.bs.modal', function (evt) {
313 target.@org.gwtbootstrap3.client.ui.Modal::onHide(Lcom/google/gwt/user/client/Event;)(evt);
314 });
315
316 $modal.on('hidden.bs.modal', function (evt) {
317 target.@org.gwtbootstrap3.client.ui.Modal::onHidden(Lcom/google/gwt/user/client/Event;)(evt);
318 });
319 }-*/;
320
321 private native void modal(final Element e, final String arg) /*-{
322 $wnd.jQuery(e).modal(arg);
323 }-*/;
324
325 // Will iterate over all the modals, if they are visible it will hide them
326 private native void hideOtherModals() /*-{
327 $wnd.jQuery('.modal.in').modal('hide');
328 }-*/;
329
330 // Unbinds all the handlers
331 private native void unbindAllHandlers(final Element e) /*-{
332 var $e = $wnd.jQuery(e);
333 $e.off('show.bs.modal');
334 $e.off('shown.bs.modal');
335 $e.off('hide.bs.modal');
336 $e.off('hidden.bs.modal');
337 }-*/;
338 }