com.sksamuel.jqm4gwt.JQMPopup Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jqm4gwt-standalone Show documentation
Show all versions of jqm4gwt-standalone Show documentation
jqm4gwt bundled with all of its dependencies
The newest version!
package com.sksamuel.jqm4gwt;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Widget;
import com.sksamuel.jqm4gwt.JQMPopupEvent.PopupState;
/**
* @author Stephen K Samuel [email protected] 16 Sep 2012 00:26:35
*
*
See Popup
*/
public class JQMPopup extends JQMContainer {
private static int counter = 1;
private String tolerance;
/**
* Creates a new {@link JQMPopup} with an automatically assigned id in the form popup-xx where XX is an incrementing number.
*/
public JQMPopup() {
this("popup-" + (counter++));
}
/**
* Creates a new {@link JQMPopup} with explicitly defined id.
*/
public JQMPopup(String popupId) {
super(popupId, "popup");
}
public JQMPopup(Widget... widgets) {
this();
add(widgets);
}
@Override
public void setContainerId(String containerId) {
super.setContainerId(containerId);
removeAttribute("data-url");
}
/**
* Automatically assigns an id in the form popup-xx where XX is an incrementing number.
*/
@Override
public JQMContainer withContainerId() {
setContainerId("popup-" + (counter++));
return this;
}
private static native void initialize(Element elt) /*-{
$wnd.$(elt).popup();
}-*/;
/**
* Initialize dynamically added popup with static content (for example added after page is loaded).
*
Also see {@link JQMPopup#waitInitOpen(String)} if you need to wait for images to be loaded.
*/
public void initDynamic() {
initialize(getElement());
}
private static native void waitInitOpen(String waitForSelector, Element elt) /*-{
// Wait with opening the popup until the popup image has been loaded in the DOM.
// This ensures the popup gets the correct size and position
var pop = $wnd.$(elt);
var saveDisp = pop.css("display");
if (saveDisp !== "none") pop.css("display", "none");
$wnd.$( waitForSelector, elt ).load(function() {
pop.css("display", saveDisp);
pop.popup();
pop.popup( "open" );
clearTimeout( fallback ); // Clear the fallback
});
// Fallback in case the browser doesn't fire a load event
var fallback = setTimeout(function() {
pop.css("display", saveDisp);
pop.popup();
pop.popup( "open" );
}, 2000);
}-*/;
/**
* First wait till some elements are loaded, then initialize and open dynamically added popup.
*
See Dynamic popup with images
*/
public void waitInitOpen(String waitForSelector) {
if (waitForSelector == null || waitForSelector.isEmpty()) {
initDynamic();
open();
return;
}
waitInitOpen(waitForSelector, getElement());
}
private static native void _close(Element elt) /*-{
$wnd.$(elt).popup("close");
}-*/;
private static native void _open(Element elt) /*-{
$wnd.$(elt).popup("open");
}-*/;
private static native void _open(Element popupElt, String positionToSelector) /*-{
$wnd.$(popupElt).popup("open", { positionTo: positionToSelector });
}-*/;
public static native void close(String popupSelector) /*-{
$wnd.$(popupSelector).popup("close");
}-*/;
public static native void open(String popupSelector) /*-{
$wnd.$(popupSelector).popup("open");
}-*/;
public static native void open(String popupSelector, String positionToSelector) /*-{
$wnd.$(popupSelector).popup("open", { positionTo: positionToSelector });
}-*/;
public JQMPopup close() {
_close(getElement());
return this;
}
public JQMPopup open() {
_open(getElement());
return this;
}
public JQMPopup openPosTo(String positionToSelector) {
_open(getElement(), positionToSelector);
return this;
}
@Override
public String getRelType() {
return "popup";
}
@Override
public String getTheme() {
String rslt = JQMCommon.getThemeEx(this, JQMCommon.STYLE_UI_BODY);
if (rslt == null || rslt.isEmpty()) rslt = super.getTheme();
return rslt;
}
@Override
public void setTheme(String theme) {
JQMCommon.setThemeEx(this, theme, JQMCommon.STYLE_UI_BODY);
}
public String getOverlayTheme() {
return getAttribute("data-overlay-theme");
}
public void setOverlayTheme(String theme) {
setAttribute("data-overlay-theme", theme);
}
public JQMPopup withOverlayTheme(String theme) {
setOverlayTheme(theme);
return this;
}
public boolean isPadding() {
return JQMCommon.hasStyle(this, "ui-content");
}
public void setPadding(boolean padding) {
if (padding) {
addStyleName("ui-content");
} else {
removeStyleName("ui-content");
}
}
public JQMPopup withPadding(boolean padding) {
setPadding(padding);
return this;
}
public String getPosition() {
return JQMCommon.getPopupPos(this);
}
/**
* @param pos - origin, window, or jQuery selector.
*
Element is searched by selector, and then popup is centered over it.
* The selector is filtered for elements that are visible with ":visible".
* If the result is empty, the popup will be centered in the window.
*/
public void setPosition(String pos) {
JQMCommon.setPopupPos(this, pos);
}
@Override
public String toString() {
return "JQMPopup [id=" + id + "]";
}
public boolean isDialog() {
String s = JQMCommon.getAttribute(this, "data-dismissible");
return "false".equals(s);
}
/**
* @param value - if true creates a modal style dialog, to prevent the click-outside-to-close
* behavior so people need to interact with popup buttons to close it.
*/
public void setDialog(boolean value) {
JQMCommon.setAttribute(this, "data-dismissible", value ? "false" : null);
}
public boolean isDismissible() {
return !isDialog();
}
/**
* Opposite to setDialog()
*
Sets whether clicking outside the popup or pressing Escape while the popup is
* open will close the popup.
*
Note: When history support is turned on, pressing the browser's "Back" button
* will dismiss the popup even if this option is set to false.
*/
public void setDismissible(boolean value) {
setDialog(!value);
}
public boolean isShadow() {
String s = JQMCommon.getAttribute(this, "data-shadow");
boolean noShadow = "false".equals(s);
return !noShadow;
}
public void setShadow(boolean value) {
JQMCommon.setAttribute(this, "data-shadow", value ? null : "false");
}
public String getArrows() {
return JQMCommon.getAttribute(this, "data-arrow");
}
/**
* @param arrows - possible values: true, false.
* Also comma-separated list of edge abbreviations: l t r b
*
"l" for left, "t" for top, "r" for right, and "b" for bottom.
*
*
The order in which the edges are given matters, see explanation below.
*
*
For each edge given in the list, the framework calculates:
*
1. the distance between the tip of the arrow and the center of the origin
*
2. and whether minimizing the above distance would cause the arrow to appear
* too close to one of the corners of the popup along the given edge.
*
*
If the second condition applies, the edge is discarded as a possible solution
* for placing the arrow. Otherwise, the calculated distance is examined.
* If it is 0, meaning that the popup can be placed exactly such that the tip of
* the arrow points at the center of the origin, no further edges are examined,
* and the popup is positioned along the last examined edge.
*
*/
public void setArrows(String arrows) {
JQMCommon.setAttribute(this, "data-arrow", arrows);
}
/** Triggered when a popup has completely closed */
protected void onAfterClose() {
}
protected void doAfterClose() {
onAfterClose();
JQMPopupEvent.fire(this, PopupState.AFTER_CLOSE);
}
/** Triggered after a popup has completely opened */
protected void onAfterOpen() {
}
protected void doAfterOpen() {
onAfterOpen();
JQMPopupEvent.fire(this, PopupState.AFTER_OPEN);
}
/**
* Triggered before a popup computes the coordinates where it will appear.
*
Handling this event gives an opportunity to modify the content of
* the popup before it appears on the screen. For example, the content can be
* scaled or parts of it can be hidden or removed if it is too wide or too tall.
* You can also modify the options parameter to affect the popup's placement.
*
* @param openOptions
**/
protected void onBeforePosition(PopupOptions openOptions) {
}
public static class PopupOptions {
private Double x;
private Double y;
private String positionTo;
public Double getX() {
return x;
}
public void setX(Double x) {
this.x = x;
}
public Double getY() {
return y;
}
public void setY(Double y) {
this.y = y;
}
public String getPositionTo() {
return positionTo;
}
public void setPositionTo(String positionTo) {
this.positionTo = positionTo;
}
@Override
public String toString() {
return "PopupOptions [x=" + JQMContext.round(x, 2)
+ ", y=" + JQMContext.round(y, 2) + ", positionTo=" + positionTo + "]";
}
}
/**
* @param openOptions = { x: 123, y: 456, positionTo: #xxx }
*/
protected void doBeforePosition(JavaScriptObject openOptions) {
String p = JsUtils.getObjValue(openOptions, "positionTo");
Double x = JsUtils.getObjDoubleValue(openOptions, "x");
Double y = JsUtils.getObjDoubleValue(openOptions, "y");
PopupOptions opts = new PopupOptions();
opts.setPositionTo(p);
opts.setX(x);
opts.setY(y);
onBeforePosition(opts);
JQMPopupEvent.fire(this, PopupState.BEFORE_POSITION, opts);
String newP = opts.getPositionTo();
if (newP == null) {
if (p != null && !p.isEmpty()) JsUtils.deleteObjProperty(openOptions, "positionTo");
} else {
JsUtils.setObjValue(openOptions, "positionTo", newP);
}
Double newX = opts.getX();
if (newX == null) {
if (x != null) JsUtils.deleteObjProperty(openOptions, "x");
} else {
JsUtils.setObjDoubleValue(openOptions, "x", newX);
}
Double newY = opts.getY();
if (newY == null) {
if (y != null) JsUtils.deleteObjProperty(openOptions, "y");
} else {
JsUtils.setObjDoubleValue(openOptions, "y", newY);
}
}
private static native void setTolerance(Element elt, String tolerance) /*-{
$wnd.$(elt).popup("option", "tolerance", tolerance);
}-*/;
private static native String getTolerance(Element elt) /*-{
return $wnd.$(elt).popup("option", "tolerance");
}-*/;
protected static native boolean isInitialized(Element elt) /*-{
if ($wnd.$ === undefined || $wnd.$ === null) return false; // jQuery is not loaded
var w = $wnd.$(elt);
return w.data('mobile-popup') !== undefined;
}-*/;
public String getTolerance() {
Element elt = getElement();
if (isInitialized(elt)) return getTolerance(elt);
else return tolerance;
}
/**
* @param tolerance - Default: "30,15,30,15"
*
Sets the minimum distance from the edge of the window for the corresponding edge
* of the popup. By default, the values above will be used for the distance from
* the top, right, bottom, and left edge of the window, respectively.
*
*
You can specify a value for this option in one of four ways:
*
1. Empty string, null, or some other falsy value. This will cause the popup to revert
* to the above default values.
*
*
2. A single number. This number will be used for all four edge tolerances.
*
*
3. Two numbers separated by a comma. The first number will be used for tolerances
* from the top and bottom edge of the window, and the second number will be used for tolerances
* from the left and right edge of the window.
*
*
4. Four comma-separated numbers. The first will be used for tolerance from the top edge,
* the second for tolerance from the right edge, the third for tolerance from the bottom edge,
* and the fourth for tolerance from the left edge.
*
*/
public void setTolerance(String tolerance) {
this.tolerance = tolerance;
Element elt = getElement();
if (isInitialized(elt)) setTolerance(elt, tolerance);
}
/**
* Based on mobile.popup _desiredCoords()
*
* @param positionTo - jQuery selector for finding element (must be visible)
* @return - { left: 111, top: 222, width: 333, height: 444 }
*/
private static native JavaScriptObject jsCalcEltCoords(String positionTo) /*-{
var dst = null;
try {
dst = $wnd.$(positionTo);
} catch(err) {
dst = null;
}
if (dst) {
dst.filter(":visible");
if (dst.length === 0) {
dst = null;
}
}
// If an element was found, preparing result
if (dst) {
var offset = dst.offset();
var rslt = { left: offset.left, top: offset.top, width: dst.outerWidth(), height: dst.outerHeight() };
return rslt;
} else {
return null;
}
}-*/;
public static class EltCoords {
public final double left;
public final double top;
public final double width;
public final double height;
public EltCoords(double left, double top, double width, double height) {
super();
this.left = left;
this.top = top;
this.width = width;
this.height = height;
}
@Override
public String toString() {
return "EltCoords [left=" + JQMContext.round(left, 2)
+ ", top=" + JQMContext.round(top, 2)
+ ", width=" + JQMContext.round(width, 2)
+ ", height=" + JQMContext.round(height, 2) + "]";
}
}
/**
* @param positionTo - jQuery selector for finding element (must be visible)
*/
public static EltCoords calcEltCoords(String positionTo) {
JavaScriptObject o = jsCalcEltCoords(positionTo);
if (o == null) return null;
Double left = JsUtils.getObjDoubleValue(o, "left");
Double top = JsUtils.getObjDoubleValue(o, "top");
Double width = JsUtils.getObjDoubleValue(o, "width");
Double height = JsUtils.getObjDoubleValue(o, "height");
return new EltCoords(left, top, width, height);
}
private static native void bindLifecycleEvents(JQMPopup p, Element elt) /*-{
if ($wnd.$ === undefined || $wnd.$ === null) return; // jQuery is not loaded
var popup = $wnd.$(elt);
popup.on("popupafterclose", function(event, ui) {
[email protected]::doAfterClose()();
});
popup.on("popupafteropen", function(event, ui) {
[email protected]::doAfterOpen()();
});
popup.on("popupbeforeposition", function(event, ui) {
//alert(JSON.stringify(ui));
[email protected]::doBeforePosition(Lcom/google/gwt/core/client/JavaScriptObject;)(ui);
});
}-*/;
private static native void unbindLifecycleEvents(Element elt) /*-{
if ($wnd.$ === undefined || $wnd.$ === null) return; // jQuery is not loaded
var popup = $wnd.$(elt);
popup.off("popupafterclose");
popup.off("popupafteropen");
popup.off("popupbeforeposition");
popup.off("popupcreate");
}-*/;
private static native void bindCreated(Element elt, JQMPopup pop) /*-{
$wnd.$(elt).on( 'popupcreate', function( event, ui ) {
[email protected]::created()();
});
}-*/;
private void created() {
setTolerance(getElement(), tolerance);
}
@Override
protected void onLoad() {
super.onLoad();
Element elt = getElement();
bindLifecycleEvents(this, elt);
if (tolerance != null) {
bindCreated(elt, this);
}
}
@Override
protected void onUnload() {
unbindLifecycleEvents(getElement());
super.onUnload();
}
public HandlerRegistration addPopupHandler(JQMPopupEvent.Handler handler) {
return addHandler(handler, JQMPopupEvent.getType());
}
public boolean isCloseThenClick() {
String s = JQMCommon.getAttribute(getElement(), "data-closeThenClick");
return "true".equals(s);
}
/**
* Works in conjunction with dismissible, will pass/re-route outside click to proper widget
* after popup is closed, so you don't have to tap widget one more time (i.e. prevents click event
* eating by popup).
*/
public void setCloseThenClick(boolean value) {
JQMCommon.setAttribute(getElement(), "data-closeThenClick", value ? "true" : null);
}
}