gwt.material.design.client.ui.MaterialDialog Maven / Gradle / Ivy
/*
* #%L
* GwtMaterial
* %%
* Copyright (C) 2015 - 2017 GwtMaterialDesign
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package gwt.material.design.client.ui;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.*;
import com.google.gwt.event.shared.HandlerRegistration;
import gwt.material.design.client.base.*;
import gwt.material.design.client.base.mixin.CssTypeMixin;
import gwt.material.design.client.base.mixin.FullscreenMixin;
import gwt.material.design.client.base.mixin.OverlayStyleMixin;
import gwt.material.design.client.constants.*;
import gwt.material.design.client.js.JsModalOptions;
import gwt.material.design.jquery.client.api.JQueryElement;
import static gwt.material.design.client.js.JsMaterialElement.$;
//@formatter:off
/**
* Dialogs are content that are not original visible on a page but show up with
* extra information if needed. The transitions should make the appearance of
* the dialog make sense and not jarring to the user.
*
*
UiBinder Usage:
*
*
* {@code
*
*
*
*
*
*
*
*
* }
*
*
* *
*
Java Usage:
*
*
* {
* @code
* @UiField
* MaterialDialog modal;
* modal.open();
* }
*
*
*
*
* @author kevzlou7979
* @author Ben Dol
* @see Material Modals
* @see Material Design Specification
*/
// @formatter:on
public class MaterialDialog extends MaterialWidget implements HasType, HasInOutDurationTransition,
HasDismissible, HasCloseHandlers, HasOpenHandlers, HasFullscreen, HasOverlayStyle,
HasOpenClose {
private JsModalOptions options = new JsModalOptions();
private final String OVERLAY_ATTACHED = "modal-overlay-attached";
private final String HASH_CHANGE = "hashchange";
private CssTypeMixin typeMixin;
private FullscreenMixin fullscreenMixin;
private OverlayStyleMixin overlayStyleMixin;
private boolean open;
private boolean closeOnBrowserBackNavigation = true;
private JQueryElement overlayElement;
public MaterialDialog() {
super(Document.get().createDivElement(), CssName.MODAL);
}
@Override
protected void onLoad() {
super.onLoad();
setupOverlayStyles();
setupBackNavigation();
}
protected void setupOverlayStyles() {
if (getOverlayOption() != null) {
$(getElement()).on(OVERLAY_ATTACHED, (event, id) -> {
setOverlayElement($("#" + id));
applyOverlayStyle(overlayElement);
return true;
});
registerHandler(addOpenHandler(event -> applyOverlayStyle(overlayElement)));
registerHandler(addCloseHandler(event -> resetOverlayStyle()));
}
}
protected void setupBackNavigation() {
if (closeOnBrowserBackNavigation) {
window().on(HASH_CHANGE, (e, param1) -> {
e.preventDefault();
if (isOpen()) {
close();
}
return true;
});
} else {
window().off(HASH_CHANGE);
}
}
@Override
protected void onUnload() {
super.onUnload();
resetOverlayStyle();
window().off(HASH_CHANGE);
$(getElement()).off(OVERLAY_ATTACHED);
}
@Override
public void setType(DialogType type) {
getTypeMixin().setType(type);
}
@Override
public DialogType getType() {
return getTypeMixin().getType();
}
@Override
public void setInDuration(int inDuration) {
options.in_duration = inDuration;
}
@Override
public int getInDuration() {
return options.in_duration;
}
@Override
public void setOutDuration(int outDuration) {
options.out_duration = outDuration;
}
@Override
public int getOutDuration() {
return options.out_duration;
}
@Override
public void setDismissible(boolean dismissible) {
options.dismissible = dismissible;
}
@Override
public boolean isDismissible() {
return options.dismissible;
}
public boolean isCloseOnBrowserBackNavigation() {
return closeOnBrowserBackNavigation;
}
/**
* A property wherein if enabled - upon updating the browser url will automatically close the dialog
*/
public void setCloseOnBrowserBackNavigation(boolean closeOnBrowserBackNavigation) {
this.closeOnBrowserBackNavigation = closeOnBrowserBackNavigation;
}
@Override
public void setOpacity(double opacity) {
options.opacity = opacity;
}
@Override
public Double getOpacity() {
return options.opacity;
}
@Override
public void setEnabled(boolean enabled) {
getEnabledMixin().setEnabled(this, enabled);
}
@Override
public void setFullscreen(boolean value) {
if (getType() != DialogType.BOTTOM_SHEET) {
getFullscreenMixin().setFullscreen(value);
}
}
@Override
public boolean isFullscreen() {
return getFullscreenMixin().isFullscreen();
}
/**
* Open the modal programmatically
*
* Note: the MaterialDialog component must be added to the document before
* calling this method. When declaring this modal on a UiBinder file, the
* MaterialDialog is already added, but if you call it using pure Java, you
* must add it to a container before opening the modal. You can do it by
* calling, for example:
*
*
* MaterialDialog modal = new MaterialDialog();
* RootPanel.get().add(modal);
*
*
* @throws IllegalStateException If the MaterialDialog is not added to the document
*/
@Override
public void open() {
open(true);
}
/**
* Open the modal programmatically
*
* Note: the MaterialDialog component must be added to the document before
* calling this method. When declaring this modal on a UiBinder file, the
* MaterialDialog is already added, but if you call it using pure Java, you
* must add it to a container before opening the modal. You can do it by
* calling, for example:
*
*
* MaterialDialog modal = new MaterialDialog();
* RootPanel.get().add(modal);
*
* @param fireEvent - Flag whether this component fires Open Event
*
* @throws IllegalStateException If the MaterialDialog is not added to the document
*/
public void open(boolean fireEvent) {
// the modal must be added to the document before opening
if (this.getParent() == null) {
throw new IllegalStateException(
"The MaterialDialog must be added to the document before calling open().");
}
open(getElement(), fireEvent);
}
/**
* Open modal with additional properties
*
* @param e - Modal Component
* @param fireEvent - Flag whether this component fires Open Event
*/
protected void open(Element e, boolean fireEvent) {
this.open = true;
options.complete = () -> onNativeClose(true, true);
options.ready = () -> onNativeOpen(fireEvent);
$(e).openModal(options);
Scheduler.get().scheduleDeferred(() -> $(getElement()).focus());
}
protected void onNativeOpen(boolean fireEvent) {
if(fireEvent) {
OpenEvent.fire(this, this);
}
}
protected void onNativeClose(boolean autoClosed, boolean fireEvent) {
if (fireEvent) {
CloseEvent.fire(this, this, autoClosed);
}
}
/**
* Close the modal programmatically. It is the same as calling
* {@link #close(boolean)} with false
as parameter.
*
* Note: you may need to remove it MaterialDialog from the document if you
* are not using UiBinder. See {@link #open()}.
*
*/
@Override
public void close() {
close(false);
}
/**
* Close the modal programmatically.
*
* Note: you may need to remove it MaterialDialog from the document if you
* are not using UiBinder. See {@link #open()}.
*
*
* @param autoClosed Flag indicating if the modal was automatically dismissed
* @see CloseEvent
*/
public void close(boolean autoClosed) {
close(autoClosed, true);
}
/**
* Close the modal programmatically.
*
* Note: you may need to remove it MaterialDialog from the document if you
* are not using UiBinder. See {@link #open()}.
*
*
* @param autoClosed Flag indicating if the modal was automatically dismissed
* @param fireEvent Flag whether this component fires Close Event
* @see CloseEvent
*/
public void close(boolean autoClosed, boolean fireEvent) {
close(getElement(), autoClosed, fireEvent);
}
protected void close(Element e, boolean autoClosed, boolean fireEvent) {
this.open = false;
if (options != null) {
options.complete = () -> onNativeClose(autoClosed, fireEvent);
$(e).closeModal(options);
}
}
@Override
public boolean isOpen() {
return open;
}
public void setOverlayElement(JQueryElement overlayElement) {
this.overlayElement = overlayElement;
}
public JQueryElement getOverlayElement() {
return overlayElement;
}
@Override
public void setOverlayOption(OverlayOption overlayOption) {
getOverlayStyleMixin().setOverlayOption(overlayOption);
}
@Override
public OverlayOption getOverlayOption() {
return getOverlayStyleMixin().getOverlayOption();
}
@Override
public void applyOverlayStyle(JQueryElement overlayElement) {
getOverlayStyleMixin().applyOverlayStyle(overlayElement);
}
@Override
public void resetOverlayStyle() {
getOverlayStyleMixin().resetOverlayStyle();
}
@Override
public HandlerRegistration addCloseHandler(CloseHandler handler) {
return addHandler(handler, CloseEvent.getType());
}
@Override
public HandlerRegistration addOpenHandler(OpenHandler handler) {
return addHandler(handler, OpenEvent.getType());
}
protected CssTypeMixin getTypeMixin() {
if (typeMixin == null) {
typeMixin = new CssTypeMixin<>(this);
}
return typeMixin;
}
protected FullscreenMixin getFullscreenMixin() {
if (fullscreenMixin == null) {
fullscreenMixin = new FullscreenMixin(this);
}
return fullscreenMixin;
}
protected OverlayStyleMixin getOverlayStyleMixin() {
if (overlayStyleMixin == null) {
overlayStyleMixin = new OverlayStyleMixin<>(this);
}
return overlayStyleMixin;
}
}