1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog;
20
21 import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
22 import de.agilecoders.wicket.extensions.markup.html.bootstrap.behavior.Draggable;
23 import de.agilecoders.wicket.extensions.markup.html.bootstrap.behavior.DraggableConfig;
24 import java.io.Serializable;
25 import java.util.ArrayList;
26 import java.util.List;
27 import org.apache.syncope.client.console.panels.AbstractModalPanel;
28 import org.apache.syncope.client.console.wicket.ajax.form.IndicatorModalCloseBehavior;
29 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.buttons.DefaultModalCloseButton;
30 import org.apache.syncope.client.ui.commons.panels.ModalPanel;
31 import org.apache.syncope.client.ui.commons.panels.NotificationPanel;
32 import org.apache.syncope.client.ui.commons.panels.SubmitableModalPanel;
33 import org.apache.wicket.Component;
34 import org.apache.wicket.WicketRuntimeException;
35 import org.apache.wicket.ajax.AjaxEventBehavior;
36 import org.apache.wicket.ajax.AjaxRequestTarget;
37 import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
38 import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
39 import org.apache.wicket.event.IEvent;
40 import org.apache.wicket.markup.head.IHeaderResponse;
41 import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
42 import org.apache.wicket.markup.html.WebMarkupContainer;
43 import org.apache.wicket.markup.html.form.Form;
44 import org.apache.wicket.markup.html.list.ListItem;
45 import org.apache.wicket.markup.html.list.ListView;
46 import org.apache.wicket.markup.html.panel.Panel;
47 import org.apache.wicket.model.CompoundPropertyModel;
48 import org.apache.wicket.model.IModel;
49 import org.apache.wicket.util.io.IClusterable;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 public class BaseModal<T extends Serializable> extends Modal<T> {
54
55 private static final long serialVersionUID = -6142277554912316095L;
56
57 protected static final Logger LOG = LoggerFactory.getLogger(BaseModal.class);
58
59
60 public static final String CONTENT_ID = "content";
61
62 private static final String SUBMIT = "submit";
63
64 private static final String FORM = "form";
65
66 protected NotificationPanel notificationPanel;
67
68 private final List<Component> components;
69
70 private WindowClosedCallback windowClosedCallback;
71
72 private Panel content;
73
74 private AjaxSubmitLink submitButton;
75
76 private final Form<T> form;
77
78 private final DefaultModalCloseButton defaultModalCloseButton;
79
80 private AjaxEventBehavior closeBehavior;
81
82 private WebMarkupContainer footer;
83
84 public BaseModal(final String id) {
85 super(id);
86
87 form = new Form<>(FORM);
88 form.setOutputMarkupId(true);
89 add(form);
90
91 content = new AbstractModalPanel<>(this, null) {
92
93 private static final long serialVersionUID = -6142277554912316095L;
94
95 };
96
97 content.setOutputMarkupId(true);
98
99 form.add(content);
100
101 useCloseHandler(true);
102 this.windowClosedCallback = null;
103 components = new ArrayList<>();
104
105
106 add(new Draggable(new DraggableConfig().withHandle(".modal-header").withCursor("move")));
107
108 defaultModalCloseButton = new DefaultModalCloseButton();
109 addButton(defaultModalCloseButton);
110 setUseKeyboard(true);
111 setFadeIn(true);
112 }
113
114 public Form<T> getForm() {
115 return form;
116 }
117
118 public BaseModal<T> setFormModel(final T modelObject) {
119 form.setModel(new CompoundPropertyModel<>(modelObject));
120 return this;
121 }
122
123 public BaseModal<T> setFormModel(final IModel<T> model) {
124 form.setModel(model);
125 return this;
126 }
127
128 public BaseModal<T> setFormAsMultipart(final boolean multipart) {
129 form.setMultiPart(multipart);
130 return this;
131 }
132
133 public T getFormModel() {
134 return form.getModelObject();
135 }
136
137 public ModalPanel getContent() {
138 if (content instanceof ModalPanel) {
139 return (ModalPanel) content;
140 }
141 throw new IllegalStateException();
142 }
143
144 public BaseModal<T> setContent(final ModalPanel component) {
145 if (component instanceof Panel) {
146 return setInternalContent(Panel.class.cast(component));
147 }
148 throw new IllegalArgumentException("Panel instance is required");
149 }
150
151 public BaseModal<T> setContent(final ModalPanel component, final AjaxRequestTarget target) {
152 setContent(component);
153 target.add(content);
154 return this;
155 }
156
157 public BaseModal<T> changeCloseButtonLabel(final String label) {
158 defaultModalCloseButton.getModel().setObject(label);
159 return this;
160 }
161
162 public BaseModal<T> changeCloseButtonLabel(final String label, final AjaxRequestTarget target) {
163 changeCloseButtonLabel(label);
164 target.add(defaultModalCloseButton);
165 return this;
166 }
167
168 private BaseModal<T> setInternalContent(final Panel component) {
169 if (!component.getId().equals(CONTENT_ID)) {
170 throw new WicketRuntimeException("Modal content id is wrong. "
171 + "Component ID: " + component.getId() + "; content ID: " + CONTENT_ID);
172 }
173
174 content.replaceWith(component);
175 content = component;
176
177 return this;
178 }
179
180 public BaseModal<T> setWindowClosedCallback(final WindowClosedCallback callback) {
181 windowClosedCallback = callback;
182 return this;
183 }
184
185 @Override
186 protected void onClose(final IPartialPageRequestHandler target) {
187 if (windowClosedCallback != null) {
188 windowClosedCallback.onClose((AjaxRequestTarget) target);
189 }
190 }
191
192 public AjaxSubmitLink addSubmitButton() {
193 if (!(BaseModal.this.getContent() instanceof SubmitableModalPanel)) {
194 throw new IllegalStateException();
195 }
196
197 AjaxSubmitLink submit = new AjaxSubmitLink(SUBMIT, form) {
198
199 private static final long serialVersionUID = -5783994974426198290L;
200
201 @Override
202 protected void onSubmit(final AjaxRequestTarget target) {
203 SubmitableModalPanel.class.cast(BaseModal.this.getContent()).onSubmit(target);
204 }
205
206 @Override
207 protected void onError(final AjaxRequestTarget target) {
208 SubmitableModalPanel.class.cast(BaseModal.this.getContent()).onError(target);
209 }
210 };
211
212 submit.setOutputMarkupId(true);
213
214 if (submitButton == null) {
215 submitButton = submit;
216 components.add(submitButton);
217 } else {
218 submitButton.replaceWith(submit);
219 submitButton = submit;
220 }
221
222 return submit;
223 }
224
225 public void removeSubmitButton() {
226 if (!(BaseModal.this.getContent() instanceof SubmitableModalPanel)) {
227 throw new IllegalStateException();
228 }
229
230 components.stream().
231 filter(component -> SUBMIT.equals(component.getId())).
232 findFirst().
233 ifPresent(components::remove);
234
235 submitButton = null;
236 }
237
238 @Override
239 protected void onInitialize() {
240 super.onInitialize();
241
242 final WebMarkupContainer dialog = (WebMarkupContainer) this.get("dialog");
243 dialog.setMarkupId(this.getId());
244
245 footer = (WebMarkupContainer) this.get("dialog:footer");
246 footer.addOrReplace(new ListView<>("inputs", components) {
247
248 private static final long serialVersionUID = 4949588177564901031L;
249
250 @Override
251 protected void populateItem(final ListItem<Component> item) {
252 item.add(item.getModelObject());
253 }
254 }.setOutputMarkupId(true)).setOutputMarkupId(true);
255 }
256
257
258
259
260 public static class ModalEvent implements Serializable {
261
262 private static final long serialVersionUID = 2668922412196063559L;
263
264
265
266
267 private final AjaxRequestTarget target;
268
269
270
271
272
273
274 public ModalEvent(final AjaxRequestTarget target) {
275 this.target = target;
276 }
277
278
279
280
281
282
283 public AjaxRequestTarget getTarget() {
284 return target;
285 }
286 }
287
288 public static class ChangeFooterVisibilityEvent extends ModalEvent {
289
290 private static final long serialVersionUID = -6157576856659866343L;
291
292 public ChangeFooterVisibilityEvent(final AjaxRequestTarget target) {
293 super(target);
294 }
295 }
296
297 @Override
298 public void onEvent(final IEvent<?> event) {
299 if (event.getPayload() instanceof ChangeFooterVisibilityEvent) {
300 if (BaseModal.this.footer != null) {
301 final AjaxRequestTarget target = ChangeFooterVisibilityEvent.class.cast(event.getPayload()).getTarget();
302 target.add(BaseModal.this.footer.setEnabled(!BaseModal.this.footer.isEnabled()));
303 }
304 }
305 }
306
307
308
309
310
311
312
313
314
315
316 public final Modal<T> useCloseHandler(final boolean useCloseHandler) {
317 if (useCloseHandler) {
318 if (closeBehavior == null) {
319 closeBehavior = new IndicatorModalCloseBehavior() {
320
321 private static final long serialVersionUID = -4955472558917915340L;
322
323 @Override
324 protected void onEvent(final AjaxRequestTarget target) {
325 if (isVisible()) {
326 onClose(target);
327 appendCloseDialogJavaScript(target);
328 }
329 }
330 };
331 add(closeBehavior);
332 }
333 } else if (closeBehavior != null) {
334 remove(closeBehavior);
335 closeBehavior = null;
336 }
337 return this;
338 }
339
340 @Override
341 public void renderHead(final IHeaderResponse response) {
342 super.renderHead(response);
343 response.render(OnDomReadyHeaderItem.forScript(createInitializerScript(getMarkupId(true))));
344 }
345
346
347
348
349
350
351
352 private String createInitializerScript(final String markupId) {
353 return addCloseHandlerScript(markupId, createBasicInitializerScript(markupId));
354 }
355
356
357
358
359
360
361
362
363 private String addCloseHandlerScript(final String markupId, final String script) {
364 if (closeBehavior != null) {
365 return script + ";$('#" + markupId + "').on('hidden', function () { "
366 + " Wicket.Ajax.ajax({'u':'" + closeBehavior.getCallbackUrl() + "','c':'" + markupId + "'});"
367 + "})";
368 }
369
370 return script;
371 }
372
373
374
375
376
377
378
379 @FunctionalInterface
380 public interface WindowClosedCallback extends IClusterable {
381
382
383
384
385
386
387 void onClose(AjaxRequestTarget target);
388 }
389 }