/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ package org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; import de.agilecoders.wicket.extensions.markup.html.bootstrap.behavior.Draggable; import de.agilecoders.wicket.extensions.markup.html.bootstrap.behavior.DraggableConfig; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.apache.syncope.client.console.panels.AbstractModalPanel; import org.apache.syncope.client.console.panels.ModalPanel; import org.apache.syncope.client.console.panels.NotificationPanel; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.buttons.DefaultModalCloseButton; import org.apache.wicket.Component; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; import org.apache.wicket.core.request.handler.IPartialPageRequestHandler; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.WindowClosedCallback; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.syncope.client.console.panels.SubmitableModalPanel; import org.apache.syncope.client.console.wicket.ajax.form.IndicatorModalCloseBehavior; import org.apache.wicket.ajax.AjaxEventBehavior; import org.apache.wicket.event.IEvent; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.OnDomReadyHeaderItem; public class BaseModal<T extends Serializable> extends Modal<T> { private static final long serialVersionUID = -6142277554912316095L; protected static final Logger LOG = LoggerFactory.getLogger(BaseModal.class); /** the default id of the content component */ public static final String CONTENT_ID = "content"; private static final String SUBMIT = "submit"; private static final String FORM = "form"; protected NotificationPanel notificationPanel; private final List<Component> components; private WindowClosedCallback windowClosedCallback; private Panel content; private AjaxSubmitLink submitButton; private final Form<T> form; private final DefaultModalCloseButton defaultModalCloseButton; private AjaxEventBehavior closeBehavior; private WebMarkupContainer footer; public BaseModal(final String id) { super(id); form = new Form<>(FORM); form.setOutputMarkupId(true); add(form); content = new AbstractModalPanel<T>(this, null) { private static final long serialVersionUID = 1L; }; content.setOutputMarkupId(true); form.add(content); useCloseHandler(true); this.windowClosedCallback = null; components = new ArrayList<>(); // Note: not adding this would imply adding WebjarsJavaScriptResourceReference about JQuery resizable and mouse // add(new Resizable().withChildSelector(".modal-content")); // Note: not adding this would imply adding of WebjarsJavaScriptResourceReference about JQuery draggable add(new Draggable(new DraggableConfig().withHandle(".modal-header").withCursor("move"))); defaultModalCloseButton = new DefaultModalCloseButton(); addButton(defaultModalCloseButton); setUseKeyboard(true); setFadeIn(true); } public Form<T> getForm() { return form; } public BaseModal<T> setFormModel(final T modelObject) { form.setModel(new CompoundPropertyModel<>(modelObject)); return this; } public BaseModal<T> setFormModel(final IModel<T> model) { form.setModel(model); return this; } public T getFormModel() { return form.getModelObject(); } public ModalPanel getContent() { if (content instanceof ModalPanel) { return (ModalPanel) content; } throw new IllegalStateException(); } public BaseModal<T> setContent(final ModalPanel component) { if (component instanceof Panel) { return setInternalContent(Panel.class.cast(component)); } throw new IllegalArgumentException("Panel instance is required"); } public BaseModal<T> setContent(final ModalPanel component, final AjaxRequestTarget target) { setContent(component); target.add(content); return this; } public BaseModal<T> changeCloseButtonLabel(final String label) { defaultModalCloseButton.getModel().setObject(label); return this; } public BaseModal<T> changeCloseButtonLabel(final String label, final AjaxRequestTarget target) { changeCloseButtonLabel(label); target.add(defaultModalCloseButton); return this; } private BaseModal<T> setInternalContent(final Panel component) { if (!component.getId().equals(getContentId())) { throw new WicketRuntimeException( "Modal content id is wrong. Component ID:" + component.getId() + "; content ID: " + getContentId()); } content.replaceWith(component); content = component; return this; } public static String getContentId() { return CONTENT_ID; } public BaseModal<T> setWindowClosedCallback(final WindowClosedCallback callback) { windowClosedCallback = callback; return this; } @Override protected void onClose(final IPartialPageRequestHandler target) { if (windowClosedCallback != null) { windowClosedCallback.onClose((AjaxRequestTarget) target); } } public AjaxSubmitLink addSubmitButton() { if (!(BaseModal.this.getContent() instanceof SubmitableModalPanel)) { throw new IllegalStateException(); } AjaxSubmitLink submit = new AjaxSubmitLink(SUBMIT, form) { private static final long serialVersionUID = -5783994974426198290L; @Override protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) { SubmitableModalPanel.class.cast(BaseModal.this.getContent()).onSubmit(target, form); } @Override protected void onError(final AjaxRequestTarget target, final Form<?> form) { SubmitableModalPanel.class.cast(BaseModal.this.getContent()).onError(target, form); } }; submit.setOutputMarkupId(true); if (submitButton == null) { submitButton = submit; this.components.add(submitButton); } else { submitButton.replaceWith(submit); submitButton = submit; } return submit; } @Override protected void onInitialize() { super.onInitialize(); final WebMarkupContainer dialog = (WebMarkupContainer) this.get("dialog"); dialog.setMarkupId(this.getId()); footer = (WebMarkupContainer) this.get("dialog:footer"); footer.addOrReplace(new ListView<Component>("inputs", components) { private static final long serialVersionUID = 4949588177564901031L; @Override protected void populateItem(final ListItem<Component> item) { item.add(item.getModelObject()); } }.setOutputMarkupId(true)).setOutputMarkupId(true); } /** * Generic modal event. */ public static class ModalEvent implements Serializable { private static final long serialVersionUID = 2668922412196063559L; /** * Request target. */ private final AjaxRequestTarget target; /** * Constructor. * * @param target request target. */ public ModalEvent(final AjaxRequestTarget target) { this.target = target; } /** * Target getter. * * @return request target. */ public AjaxRequestTarget getTarget() { return target; } } public static class ChangeFooterVisibilityEvent extends ModalEvent { private static final long serialVersionUID = -6157576856659866343L; public ChangeFooterVisibilityEvent(final AjaxRequestTarget target) { super(target); } } @Override public void onEvent(final IEvent<?> event) { if (event.getPayload() instanceof ChangeFooterVisibilityEvent) { if (BaseModal.this.footer != null) { final AjaxRequestTarget target = ChangeFooterVisibilityEvent.class.cast(event.getPayload()).getTarget(); target.add(BaseModal.this.footer.setEnabled(!BaseModal.this.footer.isEnabled())); } } } //-------------------------------------------------------- // Reqired for SYNCOPE-846 //-------------------------------------------------------- /** * Sets whether the close handler is used or not. Default is false. * * @param useCloseHandler True if close handler should be used * @return This */ public final Modal<T> useCloseHandler(final boolean useCloseHandler) { if (useCloseHandler) { if (closeBehavior == null) { closeBehavior = new IndicatorModalCloseBehavior() { private static final long serialVersionUID = -4955472558917915340L; @Override protected void onEvent(final AjaxRequestTarget target) { if (isVisible()) { onClose(target); appendCloseDialogJavaScript(target); } } }; add(closeBehavior); } } else if (closeBehavior != null) { remove(closeBehavior); closeBehavior = null; } return this; } @Override public void renderHead(final IHeaderResponse response) { super.renderHead(response); response.render(OnDomReadyHeaderItem.forScript(createInitializerScript(getMarkupId(true)))); } /** * creates the initializer script of the modal dialog. * * @param markupId The component's markup id * @return initializer script */ private String createInitializerScript(final String markupId) { return addCloseHandlerScript(markupId, createBasicInitializerScript(markupId)); } /** * adds close handler to initializer script, if use of close handler has been defined. * * @param markupId markup id * @param script base script to prepend * @return close handler script */ private String addCloseHandlerScript(final String markupId, final String script) { if (closeBehavior != null) { return script + ";$('#" + markupId + "').on('hidden', function () { " + " Wicket.Ajax.ajax({'u':'" + closeBehavior.getCallbackUrl() + "','c':'" + markupId + "'});" + "})"; } return script; } //-------------------------------------------------------- }