package lt.inventi.wicket.component.bootstrap; import java.util.HashMap; import java.util.Map; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxEventBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.behavior.Behavior; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; import org.apache.wicket.markup.head.OnDomReadyHeaderItem; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.request.cycle.RequestCycle; import de.agilecoders.wicket.core.util.Json; import lt.inventi.wicket.resource.ResourceSettings; public class ModalBehavior extends Behavior { private final WebMarkupContainer modalContainer; private final ModalBehaviorConfig modalConfig; private AjaxEventBehavior hideBehavior, showBehavior; public ModalBehavior(WebMarkupContainer modalContainer) { this(modalContainer, new ModalBehaviorConfig()); } public ModalBehavior(WebMarkupContainer modalContainer, ModalBehaviorConfig modalConfig) { this.modalContainer = modalContainer; this.modalConfig = modalConfig; } @Override public void bind(Component component) { component.setOutputMarkupId(true); modalContainer.setOutputMarkupId(true); modalContainer.add(new AttributeAppender("class", " modal hide")); modalContainer.add(new AttributeAppender("tabindex", "-1")); component.add(new AttributeModifier("data-toggle", "modal")); // markup Id might get modified after #bind (e.g. #onInitialize, #onBeforeRender) component.add(new AttributeModifier("data-target", new AbstractReadOnlyModel<String>() { @Override public String getObject() { return "#" + modalContainer.getMarkupId(); } })); if (modalConfig.hasVisibilityModel()) { hideBehavior = new AjaxEventBehavior("hidden") { @Override protected void onEvent(AjaxRequestTarget target) { modalConfig.onClose(); } }; showBehavior = new AjaxEventBehavior("shown") { @Override protected void onEvent(AjaxRequestTarget target) { modalConfig.onShow(); } }; modalContainer.add(hideBehavior, showBehavior); } } @Override public void onRemove(Component component) { AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class); if (target != null) { // Hide the modal if behavior is removed during an Ajax request StringBuilder js = new StringBuilder("var m = $('#%s').data('modal');"); js.append("if (m && m.isShown) { m.hide(); }"); target.prependJavaScript(String.format(js.toString(), modalContainer.getMarkupId())); } if (modalConfig.hasVisibilityModel()) { modalContainer.remove(hideBehavior, showBehavior); } } @Override public void renderHead(Component component, IHeaderResponse response) { super.renderHead(component, response); response.render(JavaScriptHeaderItem.forReference(ResourceSettings.get().js().bootstrapJs.bsModal)); String mId = modalContainer.getMarkupId(); response.render(OnDomReadyHeaderItem.forScript("$('#" + mId + "').modal(" + getOptionsJson() + ")")); if (modalConfig.hasVisibilityModel()) { response.render(OnDomReadyHeaderItem.forScript(callbackScript(mId, "hidden", hideBehavior))); response.render(OnDomReadyHeaderItem.forScript(callbackScript(mId, "shown", showBehavior))); } } private static String callbackScript(String mId, String event, AjaxEventBehavior behavior) { return String.format("$('#%s').on('%s',function(){Wicket.Ajax.ajax({'u':'%s','c':'%s'});})", mId, event, behavior.getCallbackUrl(), mId); } private String getOptionsJson() { Map<String, Object> params = new HashMap<String, Object>(); params.put("show", modalConfig.isShown()); params.put("backdrop", modalConfig.backdrop()); return Json.stringify(params); } }