1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.container;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.krad.datadictionary.parse.BeanTag;
20 import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
21 import org.kuali.rice.krad.datadictionary.parse.BeanTags;
22 import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
23 import org.kuali.rice.krad.datadictionary.validator.Validator;
24 import org.kuali.rice.krad.uif.UifConstants;
25 import org.kuali.rice.krad.uif.UifPropertyPaths;
26 import org.kuali.rice.krad.uif.component.Component;
27 import org.kuali.rice.krad.uif.component.DataBinding;
28 import org.kuali.rice.krad.uif.component.DelayedCopy;
29 import org.kuali.rice.krad.uif.element.Action;
30 import org.kuali.rice.krad.uif.field.Field;
31 import org.kuali.rice.krad.uif.field.FieldGroup;
32 import org.kuali.rice.krad.uif.field.InputField;
33 import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
34 import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils;
35 import org.kuali.rice.krad.uif.util.ExpressionUtils;
36 import org.kuali.rice.krad.uif.util.LifecycleElement;
37 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
38 import org.kuali.rice.krad.uif.util.ScriptUtils;
39 import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
40 import org.kuali.rice.krad.uif.view.View;
41 import org.kuali.rice.krad.uif.view.ViewModel;
42 import org.kuali.rice.krad.uif.widget.Disclosure;
43 import org.kuali.rice.krad.uif.widget.Inquiry;
44 import org.kuali.rice.krad.uif.widget.QuickFinder;
45 import org.kuali.rice.krad.uif.widget.Scrollpane;
46 import org.kuali.rice.krad.util.KRADUtils;
47
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collections;
51 import java.util.HashSet;
52 import java.util.Iterator;
53 import java.util.List;
54 import java.util.Set;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 @BeanTags({@BeanTag(name = "group", parent = "Uif-GroupBase"),
77 @BeanTag(name = "boxGroup", parent = "Uif-BoxGroupBase"),
78 @BeanTag(name = "verticalGroup", parent = "Uif-VerticalBoxGroup"),
79 @BeanTag(name = "verticalSection", parent = "Uif-VerticalBoxSection"),
80 @BeanTag(name = "verticalSubSection", parent = "Uif-VerticalBoxSubSection"),
81 @BeanTag(name = "disclosureVerticalSection", parent = "Uif-Disclosure-VerticalBoxSection"),
82 @BeanTag(name = "disclosureVerticalSubSection", parent = "Uif-Disclosure-VerticalBoxSubSection"),
83 @BeanTag(name = "horizontalGroup", parent = "Uif-HorizontalBoxGroup"),
84 @BeanTag(name = "horizontalSection", parent = "Uif-HorizontalBoxSection"),
85 @BeanTag(name = "horizontalSubSection", parent = "Uif-HorizontalBoxSubSection"),
86 @BeanTag(name = "disclosureHorizontalSection", parent = "Uif-Disclosure-HorizontalBoxSection"),
87 @BeanTag(name = "disclosureHorizontalSubSection", parent = "Uif-Disclosure-HorizontalBoxSubSection"),
88 @BeanTag(name = "grid", parent = "Uif-GridGroup"),
89 @BeanTag(name = "gridSection", parent = "Uif-GridSection"),
90 @BeanTag(name = "gridSubSection", parent = "Uif-GridSubSection"),
91 @BeanTag(name = "disclosureGridSection", parent = "Uif-Disclosure-GridSection"),
92 @BeanTag(name = "cssGrid", parent = "Uif-CssGridGroup"),
93 @BeanTag(name = "section", parent = "Uif-CssGridSection"),
94 @BeanTag(name = "subSection", parent = "Uif-CssGridSubSection"),
95 @BeanTag(name = "section1Col", parent = "Uif-CssGridSection-1FieldLabelColumn"),
96 @BeanTag(name = "section2Col", parent = "Uif-CssGridSection-2FieldLabelColumn"),
97 @BeanTag(name = "section3Col", parent = "Uif-CssGridSection-3FieldLabelColumn"),
98 @BeanTag(name = "subSection1Col", parent = "Uif-CssGridSubSection-1FieldLabelColumn"),
99 @BeanTag(name = "subSection2Col", parent = "Uif-CssGridSubSection-2FieldLabelColumn"),
100 @BeanTag(name = "subSection3Col", parent = "Uif-CssGridSubSection-3FieldLabelColumn"),
101 @BeanTag(name = "list", parent = "Uif-ListGroup"),
102 @BeanTag(name = "listSection", parent = "Uif-ListSection"),
103 @BeanTag(name = "listSubSection", parent = "Uif-ListSubSection"),
104 @BeanTag(name = "disclosureListSection", parent = "Uif-Disclosure-ListSection"),
105 @BeanTag(name = "disclosureListSubSection", parent = "Uif-Disclosure-ListSubSection"),
106 @BeanTag(name = "collectionGridItem", parent = "Uif-CollectionGridItem"),
107 @BeanTag(name = "collectionVerticalBoxItem", parent = "Uif-CollectionVerticalBoxItem"),
108 @BeanTag(name = "collectionHorizontalBoxItem", parent = "Uif-CollectionHorizontalBoxItem"),
109 @BeanTag(name = "headerUpperGroup", parent = "Uif-HeaderUpperGroup"),
110 @BeanTag(name = "headerRightGroup", parent = "Uif-HeaderRightGroup"),
111 @BeanTag(name = "headerLowerGroup", parent = "Uif-HeaderLowerGroup"),
112 @BeanTag(name = "footer", parent = "Uif-FooterBase"),
113 @BeanTag(name = "formFooter", parent = "Uif-FormFooter"),
114 @BeanTag(name = "maintenanceGrid", parent = "Uif-MaintenanceGridGroup"),
115 @BeanTag(name = "maintenanceHorizontalGroup", parent = "Uif-MaintenanceHorizontalBoxGroup"),
116 @BeanTag(name = "maintenanceVerticalGroup", parent = "Uif-MaintenanceVerticalBoxGroup"),
117 @BeanTag(name = "maintenanceGridSection", parent = "Uif-MaintenanceGridSection"),
118 @BeanTag(name = "maintenanceGridSubSection", parent = "Uif-MaintenanceGridSubSection"),
119 @BeanTag(name = "maintenanceHorizontalSection", parent = "Uif-MaintenanceHorizontalBoxSection"),
120 @BeanTag(name = "maintenanceVerticalSection", parent = "Uif-MaintenanceVerticalBoxSection"),
121 @BeanTag(name = "maintenanceHorizontalSubSection", parent = "Uif-MaintenanceHorizontalBoxSubSection"),
122 @BeanTag(name = "maintenanceVerticalSubSection", parent = "Uif-MaintenanceVerticalBoxSubSection")})
123 public class GroupBase extends ContainerBase implements Group {
124 private static final long serialVersionUID = 7953641325356535509L;
125
126 public static enum ACTION_VALIDATION_COMPONENTS {QUICKFINDER, INQUIRY, COLLECTION}
127
128 private String fieldBindByNamePrefix;
129 private String fieldBindingObjectPath;
130
131 @DelayedCopy
132 private Disclosure disclosure;
133 private Scrollpane scrollpane;
134
135 private List<? extends Component> items;
136
137 private String wrapperTag;
138
139
140
141
142 public GroupBase() {
143 items = Collections.emptyList();
144 }
145
146
147
148
149 @Override
150 public void performInitialization(Object model) {
151 if (isAjaxDisclosureGroup()) {
152 this.setItems(new ArrayList<Component>());
153 }
154
155 super.performInitialization(model);
156
157 Iterator<? extends Component> itemIterator = getItems().iterator();
158 while (itemIterator.hasNext()) {
159 Component component = itemIterator.next();
160
161 if (component == null) {
162 continue;
163 }
164
165 String excludeUnless = component.getExcludeUnless();
166 if (StringUtils.isNotBlank(excludeUnless) &&
167 !Boolean.TRUE.equals(ObjectPropertyUtils.getPropertyValue(model, excludeUnless))) {
168 itemIterator.remove();
169 continue;
170 }
171
172 String excludeIf = component.getExcludeIf();
173 if (StringUtils.isNotBlank(excludeIf) &&
174 Boolean.TRUE.equals(ObjectPropertyUtils.getPropertyValue(model, excludeIf))) {
175 itemIterator.remove();
176 continue;
177 }
178
179
180
181 if (component instanceof DataBinding) {
182 DataBinding dataBinding = (DataBinding) component;
183
184 if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
185 String bindByNamePrefixToSet = getFieldBindByNamePrefix();
186
187 if (StringUtils.isNotBlank(dataBinding.getBindingInfo().getBindByNamePrefix())) {
188 bindByNamePrefixToSet += "." + dataBinding.getBindingInfo().getBindByNamePrefix();
189 }
190 dataBinding.getBindingInfo().setBindByNamePrefix(bindByNamePrefixToSet);
191 }
192
193 if (StringUtils.isNotBlank(fieldBindingObjectPath) && StringUtils.isBlank(
194 dataBinding.getBindingInfo().getBindingObjectPath())) {
195 dataBinding.getBindingInfo().setBindingObjectPath(fieldBindingObjectPath);
196 }
197 }
198
199 else if (component instanceof FieldGroup) {
200 FieldGroup fieldGroup = (FieldGroup) component;
201
202 if (fieldGroup.getGroup() != null) {
203 if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindByNamePrefix())) {
204 fieldGroup.getGroup().setFieldBindByNamePrefix(fieldBindByNamePrefix);
205 }
206 if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindingObjectPath())) {
207 fieldGroup.getGroup().setFieldBindingObjectPath(fieldBindingObjectPath);
208 }
209 }
210 } else if (component instanceof Group) {
211 Group subGroup = (Group) component;
212 if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
213 if (StringUtils.isNotBlank(subGroup.getFieldBindByNamePrefix())) {
214 subGroup.setFieldBindByNamePrefix(
215 getFieldBindByNamePrefix() + "." + subGroup.getFieldBindByNamePrefix());
216 } else {
217 subGroup.setFieldBindByNamePrefix(getFieldBindByNamePrefix());
218 }
219 }
220 if (StringUtils.isNotBlank(getFieldBindingObjectPath())) {
221 if (StringUtils.isNotBlank(subGroup.getFieldBindingObjectPath())) {
222 subGroup.setFieldBindingObjectPath(
223 getFieldBindingObjectPath() + "." + subGroup.getFieldBindingObjectPath());
224 } else {
225 subGroup.setFieldBindingObjectPath(getFieldBindingObjectPath());
226 }
227 }
228 }
229 }
230 }
231
232
233
234
235 @Override
236 public void afterEvaluateExpression() {
237 super.afterEvaluateExpression();
238
239 if (getReadOnly() == null) {
240 Component parent = ViewLifecycle.getPhase().getParent();
241 setReadOnly(parent == null ? null : parent.getReadOnly());
242 }
243 }
244
245
246
247
248
249
250 @Override
251 public void performFinalize(Object model, LifecycleElement parent) {
252 super.performFinalize(model, parent);
253
254 if (StringUtils.isBlank(wrapperTag) && StringUtils.isNotBlank(this.getHeaderText()) && this.getHeader()
255 .isRender()) {
256 wrapperTag = UifConstants.WrapperTags.SECTION;
257 } else if (StringUtils.isBlank(wrapperTag)) {
258 wrapperTag = UifConstants.WrapperTags.DIV;
259 }
260
261 setNestedComponentId(getInstructionalMessage(), this.getId() + UifConstants.IdSuffixes.INSTRUCTIONAL);
262 setNestedComponentId(getHeader(), this.getId() + UifConstants.IdSuffixes.HEADER_WRAPPER);
263 setNestedComponentId(getHelp(), this.getId() + UifConstants.IdSuffixes.HELP_WRAPPER);
264
265 if (getHelp() != null && getHelp().getHelpAction() != null) {
266 setNestedComponentId(getHelp().getHelpAction(), this.getId() + UifConstants.IdSuffixes.HELP);
267 }
268
269
270 setupValidationScripts(ACTION_VALIDATION_COMPONENTS.QUICKFINDER, ACTION_VALIDATION_COMPONENTS.INQUIRY);
271
272
273 List<Field> fields = ViewLifecycleUtils.getElementsOfTypeDeep(getItems(), Field.class);
274 for (Field field : fields) {
275 field.setOmitFromFormPost(isOmitFromFormPost());
276 }
277 }
278
279
280
281
282
283
284
285 protected void setupValidationScripts(ACTION_VALIDATION_COMPONENTS... componentsToValidate) {
286 List<ACTION_VALIDATION_COMPONENTS> componentsList = Arrays.asList(componentsToValidate);
287 List<InputField> inputFieldsWithActionsToValidate = new ArrayList<InputField>();
288 List<InputField> allInputFields = new ArrayList<InputField>();
289
290
291
292 for (Component component : getItems()) {
293 if (component instanceof InputField) {
294 InputField inputField = (InputField) component;
295 QuickFinder quickFinder = inputField.getQuickfinder();
296 Inquiry inquiry = inputField.getInquiry();
297 if ((quickFinder != null && componentsList.contains(ACTION_VALIDATION_COMPONENTS.QUICKFINDER)) || (
298 inquiry != null && componentsList.contains(ACTION_VALIDATION_COMPONENTS.INQUIRY))) {
299 inputFieldsWithActionsToValidate.add(inputField);
300 }
301 allInputFields.add(inputField);
302 }
303 }
304
305
306
307 for (InputField widgetInputField : inputFieldsWithActionsToValidate) {
308 QuickFinder quickFinder = widgetInputField.getQuickfinder();
309 Inquiry inquiry = widgetInputField.getInquiry();
310 String script = buildInputFieldValidationActionScript(allInputFields, Arrays.asList(
311 widgetInputField.getId()));
312
313
314 if (componentsList.contains(ACTION_VALIDATION_COMPONENTS.QUICKFINDER) && quickFinder != null) {
315 Action quickFinderAction = quickFinder.getQuickfinderAction();
316 script = ScriptUtils.appendScript(script, quickFinderAction.getActionScript());
317 quickFinderAction.setActionScript(script);
318 }
319
320
321 if (componentsList.contains(ACTION_VALIDATION_COMPONENTS.INQUIRY) && inquiry != null) {
322 Action directInquiryAction = inquiry.getDirectInquiryAction();
323 script = ScriptUtils.appendScript(script, directInquiryAction.getActionScript());
324 directInquiryAction.setActionScript(script);
325 }
326 }
327 }
328
329
330
331
332
333
334
335
336
337 protected String buildInputFieldValidationActionScript(List<InputField> allInputFields,
338 List<String> excludedFields) {
339 List<String> controlsToValidate = new ArrayList<String>();
340
341 for (InputField inputField : allInputFields) {
342 if ((excludedFields == null || !excludedFields.contains(inputField.getId())) && validateInputField(
343 inputField)) {
344 controlsToValidate.add(inputField.getId() + UifConstants.IdSuffixes.CONTROL);
345
346
347 if (this instanceof CollectionGroup) {
348 controlsToValidate.add(
349 inputField.getId() + UifConstants.IdSuffixes.ADD_LINE + UifConstants.IdSuffixes.CONTROL);
350 }
351 }
352 }
353
354
355 String script = "";
356 if (!controlsToValidate.isEmpty()) {
357 script = "var control;var allValid=true;";
358 for (String controlToValidate : controlsToValidate) {
359 script += "control=jQuery('#" + controlToValidate
360 + "');if(jQuery(control).val()){allValid=allValid&&validateFieldValue(control);}";
361 }
362 script += "if(allValid == 0){return;}control = null;";
363 }
364 return script;
365 }
366
367
368
369
370
371
372
373 protected boolean validateInputField(InputField inputField) {
374 if (inputField.getValidCharactersConstraint() != null
375 && inputField.getValidCharactersConstraint().getApplyClientSide() != null
376 && inputField.getValidCharactersConstraint().getApplyClientSide() == Boolean.TRUE) {
377 return true;
378 }
379 return false;
380 }
381
382
383
384
385
386
387
388 protected void setNestedComponentId(Component component, String newId) {
389 if (component != null) {
390 component.setId(newId);
391 }
392 }
393
394
395
396
397 @Override
398 public Set<Class<? extends Component>> getSupportedComponents() {
399 Set<Class<? extends Component>> supportedComponents = new HashSet<Class<? extends Component>>();
400 supportedComponents.add(Field.class);
401 supportedComponents.add(Group.class);
402
403 return supportedComponents;
404 }
405
406
407
408
409 @Override
410 public String getComponentTypeName() {
411 return "group";
412 }
413
414
415
416
417 @Override
418 @BeanTagAttribute
419 public String getFieldBindByNamePrefix() {
420 return this.fieldBindByNamePrefix;
421 }
422
423
424
425
426 @Override
427 public void setFieldBindByNamePrefix(String fieldBindByNamePrefix) {
428 this.fieldBindByNamePrefix = fieldBindByNamePrefix;
429 }
430
431
432
433
434 @BeanTagAttribute
435 public String getFieldBindingObjectPath() {
436 return this.fieldBindingObjectPath;
437 }
438
439
440
441
442 @Override
443 public void setFieldBindingObjectPath(String fieldBindingObjectPath) {
444 this.fieldBindingObjectPath = fieldBindingObjectPath;
445 }
446
447
448
449
450 @BeanTagAttribute
451 public Disclosure getDisclosure() {
452 return this.disclosure;
453 }
454
455
456
457
458 @Override
459 public void setDisclosure(Disclosure disclosure) {
460 this.disclosure = disclosure;
461 }
462
463
464
465
466 @BeanTagAttribute
467 public Scrollpane getScrollpane() {
468 return this.scrollpane;
469 }
470
471
472
473
474 @Override
475 public void setScrollpane(Scrollpane scrollpane) {
476 this.scrollpane = scrollpane;
477 }
478
479
480
481
482 @Override
483 @BeanTagAttribute
484 public List<? extends Component> getItems() {
485 if (items == Collections.EMPTY_LIST && isMutable(true)) {
486 items = new ArrayList<Component>();
487 }
488
489 return this.items;
490 }
491
492
493
494
495 @Override
496 public void setItems(List<? extends Component> items) {
497 if (items == null) {
498 this.items = Collections.emptyList();
499 } else if (items.contains(this)) {
500 throw new IllegalArgumentException("Attempted to add group to itself");
501 } else {
502 this.items = items;
503 }
504 }
505
506
507
508
509
510
511
512 @BeanTagAttribute
513 public String getWrapperTag() {
514 return wrapperTag;
515 }
516
517
518
519
520 public void setWrapperTag(String wrapperTag) {
521 this.wrapperTag = wrapperTag;
522 }
523
524
525
526
527
528
529 protected boolean isAjaxDisclosureGroup() {
530 ViewModel model = (ViewModel) ViewLifecycle.getModel();
531 View view = ViewLifecycle.getView();
532
533 ExpressionUtils.populatePropertyExpressionsFromGraph(this);
534
535
536 if (this.getDisclosure() != null && StringUtils.isNotBlank(this.getDisclosure().getPropertyExpression(
537 UifPropertyPaths.DEFAULT_OPEN))){
538 ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
539
540 String expression = this.getDisclosure().getPropertyExpression(UifPropertyPaths.DEFAULT_OPEN);
541 expression = expressionEvaluator.replaceBindingPrefixes(view, this, expression);
542
543 expression = expressionEvaluator.evaluateExpressionTemplate(this.getDisclosure().getContext(), expression);
544 ObjectPropertyUtils.setPropertyValue(this.getDisclosure(), UifPropertyPaths.DEFAULT_OPEN, expression);
545 }
546
547
548 if (this.getDisclosure() != null) {
549 KRADUtils.syncClientSideStateForComponent(this.getDisclosure(), model.getClientStateForSyncing());
550 }
551
552
553
554 return !this.isRetrieveViaAjax() && this.getDisclosure() != null && this.getDisclosure()
555 .isAjaxRetrievalWhenOpened() && !this.getDisclosure().isDefaultOpen();
556 }
557
558
559
560
561 @Override
562 public void completeValidation(ValidationTrace tracer) {
563 tracer.addBean(this);
564
565
566 for (int i = 0; i < getItems().size(); i++) {
567 if (getItems().get(i).getClass() == PageGroup.class || getItems().get(i).getClass()
568 == TabNavigationGroup.class) {
569 String currentValues[] = {"item(" + i + ").class =" + getItems().get(i).getClass()};
570 tracer.createError("Items in Group cannot be PageGroup or NaviagtionGroup", currentValues);
571 }
572 }
573
574
575 if (getLayoutManager() == null) {
576 if (Validator.checkExpressions(this, "layoutManager")) {
577 String currentValues[] = {"layoutManager = " + getLayoutManager()};
578 tracer.createError("LayoutManager must be set", currentValues);
579 }
580 }
581
582 super.completeValidation(tracer.getCopy());
583 }
584
585
586
587
588 @Override
589 public boolean isRenderLoading() {
590 return disclosure != null && disclosure.isAjaxRetrievalWhenOpened() && (!disclosure.isRender() || !disclosure
591 .isDefaultOpen());
592 }
593 }