View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.component;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Map.Entry;
24  import java.util.Queue;
25  
26  import org.apache.commons.lang.StringUtils;
27  import org.kuali.rice.krad.datadictionary.Copyable;
28  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
29  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
30  import org.kuali.rice.krad.datadictionary.uif.UifDictionaryBeanBase;
31  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
32  import org.kuali.rice.krad.datadictionary.validator.Validator;
33  import org.kuali.rice.krad.uif.CssConstants;
34  import org.kuali.rice.krad.uif.UifConstants;
35  import org.kuali.rice.krad.uif.UifConstants.ViewStatus;
36  import org.kuali.rice.krad.uif.control.ControlBase;
37  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
38  import org.kuali.rice.krad.uif.lifecycle.ViewLifecyclePhase;
39  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleRestriction;
40  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleTask;
41  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils;
42  import org.kuali.rice.krad.uif.modifier.ComponentModifier;
43  import org.kuali.rice.krad.uif.util.LifecycleAwareList;
44  import org.kuali.rice.krad.uif.util.LifecycleAwareMap;
45  import org.kuali.rice.krad.uif.util.LifecycleElement;
46  import org.kuali.rice.krad.uif.util.ScriptUtils;
47  import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
48  import org.kuali.rice.krad.uif.view.View;
49  import org.kuali.rice.krad.uif.view.ViewIndex;
50  import org.kuali.rice.krad.uif.widget.Tooltip;
51  import org.kuali.rice.krad.util.KRADUtils;
52  
53  /**
54   * Base implementation of <code>Component</code> which other component implementations should extend
55   *
56   * <p>
57   * Provides base component properties such as id and template. Also provides default implementation
58   * for the <code>ScriptEventSupport</code> and <code>Ordered</code> interfaces. By default no script
59   * events except the onDocumentReady are supported.
60   * </p>
61   *
62   * @author Kuali Rice Team (rice.collab@kuali.org)
63   */
64  @BeanTag(name = "componentBase-bean", parent = "Uif-ComponentBase")
65  public abstract class ComponentBase extends UifDictionaryBeanBase implements Component {
66      private static final long serialVersionUID = -4449335748129894350L;
67  
68      private String id;
69      private String viewPath;
70      private Map<String, String> phasePathMapping;
71  
72      private String template;
73      private String templateName;
74  
75      private String viewStatus;
76  
77      private String title;
78  
79      private boolean render;
80      private boolean retrieveViaAjax;
81  
82      @KeepExpression
83      private String progressiveRender;
84      private boolean progressiveRenderViaAJAX;
85      private boolean progressiveRenderAndRefresh;
86      private List<String> progressiveDisclosureControlNames;
87      private String progressiveDisclosureConditionJs;
88  
89      @KeepExpression
90      private String conditionalRefresh;
91      private String conditionalRefreshConditionJs;
92      private List<String> conditionalRefreshControlNames;
93  
94      private List<String> refreshWhenChangedPropertyNames;
95      private List<String> additionalComponentsToRefresh;
96      private String additionalComponentsToRefreshJs;
97      private boolean refreshedByAction;
98      private boolean disclosedByAction;
99  
100     private int refreshTimer;
101 
102     private boolean resetDataOnRefresh;
103     private String methodToCallOnRefresh;
104 
105     private boolean hidden;
106     private boolean readOnly;
107     private Boolean required;
108 
109     private String align;
110     private String valign;
111     private String width;
112 
113     // optional table-backed layout options
114     private int colSpan;
115     private int rowSpan;
116     private List<String> wrapperCssClasses;
117     private String wrapperStyle;
118     private String cellWidth;
119 
120     private String style;
121 
122     private List<String> libraryCssClasses;
123     private List<String> cssClasses;
124     private List<String> additionalCssClasses;
125 
126     private Tooltip toolTip;
127 
128     private int order;
129 
130     private boolean skipInTabOrder;
131 
132     private String finalizeMethodToCall;
133     private List<Object> finalizeMethodAdditionalArguments;
134     private MethodInvokerConfig finalizeMethodInvoker;
135 
136     private boolean selfRendered;
137     private String renderedHtmlOutput;
138 
139     private boolean disableSessionPersistence;
140     private boolean forceSessionPersistence;
141 
142     private ComponentSecurity componentSecurity;
143 
144     private String onLoadScript;
145     private String onUnloadScript;
146     private String onCloseScript;
147     private String onBlurScript;
148     private String onChangeScript;
149     private String onClickScript;
150     private String onDblClickScript;
151     private String onFocusScript;
152     private String onSubmitScript;
153     private String onInputScript;
154     private String onKeyPressScript;
155     private String onKeyUpScript;
156     private String onKeyDownScript;
157     private String onMouseOverScript;
158     private String onMouseOutScript;
159     private String onMouseUpScript;
160     private String onMouseDownScript;
161     private String onMouseMoveScript;
162     private String onDocumentReadyScript;
163 
164     private List<ComponentModifier> componentModifiers;
165 
166     protected Map<String, String> templateOptions;
167 
168     private String templateOptionsJSString;
169 
170     @ReferenceCopy(newCollectionInstance = true)
171     private transient Map<String, Object> context;
172 
173     private List<PropertyReplacer> propertyReplacers;
174 
175     private Map<String, String> dataAttributes;
176     private Map<String, String> scriptDataAttributes;
177 
178     @ReferenceCopy(referenceTransient = true)
179     private transient Map<String, Component> componentsForLifecycle;
180 
181     private String preRenderContent;
182     private String postRenderContent;
183 
184     public ComponentBase() {
185         super();
186 
187         order = 0;
188         colSpan = 1;
189         rowSpan = 1;
190 
191         viewStatus = ViewStatus.CREATED;
192 
193         render = true;
194         selfRendered = false;
195         progressiveRenderViaAJAX = false;
196         progressiveRenderAndRefresh = false;
197         refreshedByAction = false;
198         resetDataOnRefresh = false;
199         disableSessionPersistence = false;
200         forceSessionPersistence = false;
201 
202         phasePathMapping = new HashMap<String, String>();
203         context = Collections.emptyMap();
204         dataAttributes = Collections.emptyMap();
205         scriptDataAttributes = Collections.emptyMap();
206         templateOptions = Collections.emptyMap();
207 
208         cssClasses = Collections.emptyList();
209         libraryCssClasses = Collections.emptyList();
210         additionalCssClasses = Collections.emptyList();
211     }
212 
213     /**
214      * @see LifecycleElement#checkMutable(boolean)
215      */
216     public void checkMutable(boolean legalDuringInitialization) {
217         if (UifConstants.ViewStatus.CACHED.equals(viewStatus)) {
218             ViewLifecycle.reportIllegalState("Cached component "
219                     + getClass()
220                     + " "
221                     + getId()
222                     + " is immutable, use copy() to get a mutable instance");
223             return;
224         }
225 
226         if (ViewLifecycle.isActive()) {
227             return;
228         }
229 
230         if (UifConstants.ViewStatus.CREATED.equals(viewStatus)) {
231             if (!legalDuringInitialization) {
232                 ViewLifecycle.reportIllegalState("View has not been fully initialized, attempting to change component "
233                         + getClass()
234                         + " "
235                         + getId());
236                 return;
237             }
238         } else {
239 //            ViewLifecycle.reportIllegalState("Component "
240 //                    + getClass()
241 //                    + " "
242 //                    + getId()
243 //                    + " has been initialized, but the lifecycle is not active.");
244             return;
245         }
246     }
247 
248     /**
249      * @see LifecycleElement#isMutable(boolean)
250      */
251     public boolean isMutable(boolean legalDuringInitialization) {
252         return (UifConstants.ViewStatus.CREATED.equals(viewStatus) && legalDuringInitialization) || ViewLifecycle
253                 .isActive();
254     }
255 
256     /**
257      * Indicates what lifecycle phase the component instance is in
258      *
259      * <p>
260      * The view lifecycle begins with the CREATED status. In this status a new
261      * instance of the view has been retrieved from the dictionary, but no
262      * further processing has been done. After the initialize phase has been run
263      * the status changes to INITIALIZED. After the model has been applied and
264      * the view is ready for render the status changes to FINAL
265      * </p>
266      *
267      * @return view status
268      * @see org.kuali.rice.krad.uif.UifConstants.ViewStatus
269      */
270     public String getViewStatus() {
271         return this.viewStatus;
272     }
273 
274     /**
275      * Setter for the view status
276      *
277      * @param status view status
278      */
279     @Override
280     public void setViewStatus(String status) {
281         if (!UifConstants.ViewStatus.CREATED.equals(status)) {
282             checkMutable(true);
283         }
284 
285         this.viewStatus = status;
286     }
287 
288     /**
289      * Setter for the view status
290      *
291      * @param phase completed view lifecycle phase
292      */
293     @Override
294     public void setViewStatus(ViewLifecyclePhase phase) {
295         this.viewStatus = phase.getEndViewStatus();
296     }
297 
298     /**
299      * {@inheritDoc}
300      */
301     @Override
302     public void notifyCompleted(ViewLifecyclePhase phase) {
303         ViewIndex viewIndex = ViewLifecycle.getView().getViewIndex();
304         if (viewIndex != null) {
305             viewIndex.indexComponent(this);
306         }
307     }
308 
309     /**
310      * Indicates whether the component has been initialized.
311      *
312      * @return True if the component has been initialized, false if not.
313      */
314     public boolean isInitialized() {
315         return StringUtils.equals(viewStatus, ViewStatus.INITIALIZED) || isModelApplied();
316     }
317 
318     /**
319      * Indicates whether the component has been updated from the model.
320      *
321      * @return True if the component has been updated, false if not.
322      */
323     public boolean isModelApplied() {
324         return StringUtils.equals(viewStatus, ViewStatus.MODEL_APPLIED) || isFinal();
325     }
326 
327     /**
328      * Indicates whether the component has been updated from the model and final
329      * updates made.
330      *
331      * @return True if the component has been updated, false if not.
332      */
333     public boolean isFinal() {
334         return StringUtils.equals(viewStatus, ViewStatus.FINAL) || isRendered();
335     }
336 
337     /**
338      * Indicates whether the component has been fully rendered.
339      *
340      * @return True if the component has fully rendered, false if not.
341      */
342     public boolean isRendered() {
343         return StringUtils.equals(viewStatus, ViewStatus.RENDERED);
344     }
345 
346     /**
347      * {@inheritDoc}
348      */
349     @Override
350     public void performInitialization(Object model) {
351     }
352 
353     /**
354      * The following updates are done here:
355      * 
356      * <ul>
357      * <li>Evaluate the progressive render condition (if set) and combine with the current render
358      * status to set the render status</li>
359      * </ul>
360      * 
361      * {@inheritDoc}
362      */
363     @Override
364     public void performApplyModel(Object model, LifecycleElement parent) {
365         View view = ViewLifecycle.getView();
366 
367         if (this.render && StringUtils.isNotEmpty(progressiveRender)) {
368             // progressive anded with render, will not render at least one of the two are false
369             ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
370 
371             String adjustedProgressiveRender = expressionEvaluator.replaceBindingPrefixes(view, this,
372                     progressiveRender);
373 
374             Boolean progRenderEval = (Boolean) expressionEvaluator.evaluateExpression(context,
375                     adjustedProgressiveRender);
376 
377             this.setRender(progRenderEval);
378         }
379     }
380 
381     /**
382      * The following finalization is done here:
383      * 
384      * <ul>
385      * <li>progressiveRender and conditionalRefresh variables are processed if set</li>
386      * <li>If any of the style properties were given, sets the style string on the style property</li>
387      * <li>Set the skipInTabOrder flag for nested components</li>
388      * </ul>
389      * 
390      * {@inheritDoc}
391      */
392     @Override
393     public void performFinalize(Object model, LifecycleElement parent) {
394         View view = ViewLifecycle.getView();
395         ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
396         // progressiveRender expression setup
397         if (StringUtils.isNotEmpty(progressiveRender)) {
398             progressiveRender = expressionEvaluator.replaceBindingPrefixes(view, this, progressiveRender);
399             progressiveDisclosureControlNames = new ArrayList<String>();
400             progressiveDisclosureConditionJs = expressionEvaluator.parseExpression(progressiveRender,
401                     progressiveDisclosureControlNames, this.getContext());
402         }
403 
404         // conditional refresh expression setup
405         if (StringUtils.isNotEmpty(conditionalRefresh)) {
406             conditionalRefresh = expressionEvaluator.replaceBindingPrefixes(view, this, conditionalRefresh);
407             conditionalRefreshControlNames = new ArrayList<String>();
408             conditionalRefreshConditionJs = expressionEvaluator.parseExpression(conditionalRefresh,
409                     conditionalRefreshControlNames, this.getContext());
410         }
411 
412         if (refreshWhenChangedPropertyNames != null) {
413             List<String> adjustedRefreshPropertyNames = new ArrayList<String>(refreshWhenChangedPropertyNames.size());
414             for (String refreshPropertyName : refreshWhenChangedPropertyNames) {
415                 adjustedRefreshPropertyNames.add(expressionEvaluator.replaceBindingPrefixes(view, this,
416                         refreshPropertyName));
417             }
418             refreshWhenChangedPropertyNames = adjustedRefreshPropertyNames;
419         }
420 
421         // retrieveViaAjax forces session persistence because it assumes that this component will be retrieved by
422         // some ajax retrieval call
423         if (retrieveViaAjax) {
424             forceSessionPersistence = true;
425         }
426 
427         // add the align, valign, and width settings to style
428         if (StringUtils.isNotBlank(getAlign()) && !StringUtils.contains(getStyle(), CssConstants.TEXT_ALIGN)) {
429             appendToStyle(CssConstants.TEXT_ALIGN + getAlign() + ";");
430         }
431 
432         if (StringUtils.isNotBlank(getValign()) && !StringUtils.contains(getStyle(), CssConstants.VERTICAL_ALIGN)) {
433             appendToStyle(CssConstants.VERTICAL_ALIGN + getValign() + ";");
434         }
435 
436         if (StringUtils.isNotBlank(getWidth()) && !StringUtils.contains(getStyle(), CssConstants.WIDTH)) {
437             appendToStyle(CssConstants.WIDTH + getWidth() + ";");
438         }
439 
440         // Set the skipInTabOrder flag on all nested components
441         // Set the tabIndex on controls to -1 in order to be skipped on tabbing
442         if (skipInTabOrder) {
443             for (LifecycleElement component : ViewLifecycleUtils.getElementsForLifecycle(this).values()) {
444                 if (component != null && component instanceof ComponentBase) {
445                     ((ComponentBase) component).setSkipInTabOrder(skipInTabOrder);
446                     if (component instanceof ControlBase) {
447                         ((ControlBase) component).setTabIndex(-1);
448                     }
449                 }
450             }
451         }
452 
453         // if this is not rendering and it is not rendering via an ajax call, but still has a progressive render
454         // condition we still want to render the component, but hide it (in ajax cases, template creates a placeholder)
455         boolean hide = false;
456         if (!this.render && !this.progressiveRenderViaAJAX && !this.progressiveRenderAndRefresh && StringUtils
457                 .isNotBlank(progressiveRender)) {
458             hide = true;
459         } else if (this.isHidden()) {
460             hide = true;
461         }
462 
463         if (hide) {
464             if (StringUtils.isNotBlank(this.getStyle())) {
465                 if (this.getStyle().endsWith(";")) {
466                     this.setStyle(this.getStyle() + " display: none;");
467                 } else {
468                     this.setStyle(this.getStyle() + "; display: none;");
469                 }
470             } else {
471                 this.setStyle("display: none;");
472             }
473         }
474 
475         // setup refresh timer
476         // if the refreshTimer property has been set then pre-append the call to refreshComponetUsingTimer
477         // to the onDocumentReadyScript
478         if (refreshTimer > 0) {
479             String timerScript = getOnDocumentReadyScript();
480 
481             if (StringUtils.isBlank(this.methodToCallOnRefresh)) {
482                 this.methodToCallOnRefresh = "refresh";
483             }
484 
485             timerScript = (null == timerScript) ? "" : timerScript;
486             timerScript = "refreshComponentUsingTimer('"
487                     + this.id
488                     + "','"
489                     + this.methodToCallOnRefresh
490                     + "',"
491                     + refreshTimer
492                     + ");"
493                     + timerScript;
494 
495             setOnDocumentReadyScript(timerScript);
496         }
497 
498         // put together all css class names for this component, in order
499         List<String> finalCssClasses = new ArrayList<String>();
500 
501         if (this.libraryCssClasses != null && (!ViewLifecycle.isActive() || ViewLifecycle.getView()
502                 .isUseLibraryCssClasses())) {
503             finalCssClasses.addAll(libraryCssClasses);
504         }
505 
506         if (this.cssClasses != null) {
507             finalCssClasses.addAll(cssClasses);
508         }
509 
510         if (this.additionalCssClasses != null) {
511             finalCssClasses.addAll(additionalCssClasses);
512         }
513 
514         cssClasses = finalCssClasses;
515 
516         if ((isRender() || StringUtils.isNotBlank(getProgressiveRender())) && StringUtils.isNotBlank(
517                 methodToCallOnRefresh)) {
518             ViewLifecycle.getViewPostMetadata().addAccessibleMethodToCall(methodToCallOnRefresh);
519         }
520     }
521 
522     /**
523      * @see org.kuali.rice.krad.uif.util.LifecycleElement#initializePendingTasks(org.kuali.rice.krad.uif.lifecycle.ViewLifecyclePhase,
524      *      java.util.Queue)
525      */
526     @Override
527     public void initializePendingTasks(ViewLifecyclePhase phase, Queue<ViewLifecycleTask<?>> pendingTasks) {
528     }
529     
530     /**
531      * Returns list of components that are being held in property replacers configured for this
532      * component
533      *
534      * @return List<Component>
535      */
536     @ViewLifecycleRestriction
537     public List<Component> getPropertyReplacerComponents() {
538         if (propertyReplacers == null) {
539             return Collections.emptyList();
540         }
541 
542         List<Component> components = new ArrayList<Component>();
543         for (Object replacer : propertyReplacers) {
544             components.addAll(((PropertyReplacer) replacer).getNestedComponents());
545         }
546 
547         return components;
548     }
549 
550     /**
551      * {@inheritDoc}
552      */
553     @BeanTagAttribute(name = "id")
554     @Override
555     public String getId() {
556         return this.id;
557     }
558 
559     /**
560      * {@inheritDoc}
561      */
562     @Override
563     public void setId(String id) {
564         checkMutable(true);
565         this.id = id;
566     }
567 
568     /**
569      * {@inheritDoc}
570      */
571     @Override
572     public String getViewPath() {
573         return this.viewPath;
574     }
575     
576     /**
577      * {@inheritDoc}
578      */
579     @Override
580     public void setViewPath(String viewPath) {
581         checkMutable(true);
582         this.viewPath = viewPath;
583     }
584 
585     /**
586      * {@inheritDoc}
587      */
588     @Override
589     public Map<String, String> getPhasePathMapping() {
590         return phasePathMapping;
591     }
592 
593     /**
594      * {@inheritDoc}
595      */
596     @Override
597     public void setPhasePathMapping(Map<String, String> phasePathMapping) {
598         this.phasePathMapping = phasePathMapping;
599     }
600 
601     /**
602      * {@inheritDoc}
603      */
604     @BeanTagAttribute(name = "template")
605     @Override
606     public String getTemplate() {
607         return this.template;
608     }
609 
610     /**
611      * {@inheritDoc}
612      */
613     @Override
614     public void setTemplate(String template) {
615         checkMutable(true);
616         this.template = template;
617     }
618 
619     /**
620      * {@inheritDoc}
621      */
622     @Override
623     public List<String> getAdditionalTemplates() {
624         return Collections.emptyList();
625     }
626 
627     /**
628      * {@inheritDoc}
629      */
630     @BeanTagAttribute(name = "templateName")
631     @Override
632     public String getTemplateName() {
633         return templateName;
634     }
635 
636     /**
637      * {@inheritDoc}
638      */
639     @Override
640     public void setTemplateName(String templateName) {
641         checkMutable(true);
642         this.templateName = templateName;
643     }
644 
645     /**
646      * {@inheritDoc}
647      */
648     @BeanTagAttribute(name = "title")
649     @Override
650     public String getTitle() {
651         return this.title;
652     }
653 
654     /**
655      * {@inheritDoc}
656      */
657     @Override
658     public void setTitle(String title) {
659         checkMutable(true);
660         this.title = title;
661     }
662 
663     /**
664      * {@inheritDoc}
665      */
666     @BeanTagAttribute(name = "hidden")
667     @Override
668     public boolean isHidden() {
669         return this.hidden;
670     }
671 
672     /**
673      * {@inheritDoc}
674      */
675     @Override
676     public void setHidden(boolean hidden) {
677         checkMutable(true);
678         this.hidden = hidden;
679     }
680 
681     /**
682      * {@inheritDoc}
683      */
684     @BeanTagAttribute(name = "readOnly")
685     @Override
686     public boolean isReadOnly() {
687         return this.readOnly;
688     }
689 
690     /**
691      * {@inheritDoc}
692      */
693     @Override
694     public void setReadOnly(boolean readOnly) {
695         checkMutable(true);
696         this.readOnly = readOnly;
697     }
698 
699     /**
700      * {@inheritDoc}
701      */
702     @BeanTagAttribute(name = "required")
703     @Override
704     public Boolean getRequired() {
705         return this.required;
706     }
707 
708     /**
709      * {@inheritDoc}
710      */
711     @Override
712     public void setRequired(Boolean required) {
713         checkMutable(true);
714         this.required = required;
715     }
716 
717     /**
718      * {@inheritDoc}
719      */
720     @BeanTagAttribute(name = "render")
721     @Override
722     public boolean isRender() {
723         return this.render;
724     }
725 
726     /**
727      * {@inheritDoc}
728      */
729     @Override
730     public void setRender(boolean render) {
731         checkMutable(true);
732         this.render = render;
733     }
734 
735     /**
736      * {@inheritDoc}
737      */
738     @BeanTagAttribute(name = "retrieveViaAjax")
739     @Override
740     public boolean isRetrieveViaAjax() {
741         return retrieveViaAjax;
742     }
743 
744     /**
745      * {@inheritDoc}
746      */
747     @Override
748     public void setRetrieveViaAjax(boolean retrieveViaAjax) {
749         checkMutable(true);
750         this.retrieveViaAjax = retrieveViaAjax;
751     }
752 
753     /**
754      * {@inheritDoc}
755      */
756     @BeanTagAttribute(name = "ColSpan")
757     @Override
758     public int getColSpan() {
759         return this.colSpan;
760     }
761 
762     /**
763      * {@inheritDoc}
764      */
765     @Override
766     public void setColSpan(int colSpan) {
767         checkMutable(true);
768         this.colSpan = colSpan;
769     }
770 
771     /**
772      * {@inheritDoc}
773      */
774     @BeanTagAttribute(name = "rowSpan")
775     @Override
776     public int getRowSpan() {
777         return this.rowSpan;
778     }
779 
780     /**
781      * {@inheritDoc}
782      */
783     @Override
784     public void setRowSpan(int rowSpan) {
785         checkMutable(true);
786         this.rowSpan = rowSpan;
787     }
788 
789     /**
790      * {@inheritDoc}
791      */
792     @Override
793     public List<String> getWrapperCssClasses() {
794         return wrapperCssClasses;
795     }
796 
797     /**
798      * {@inheritDoc}
799      */
800     @Override
801     public void setWrapperCssClasses(List<String> wrapperCssClasses) {
802         checkMutable(true);
803         this.wrapperCssClasses = wrapperCssClasses;
804     }
805 
806     /**
807      * {@inheritDoc}
808      */
809     @Override
810     public void addWrapperCssClass(String cssClass) {
811         checkMutable(false);
812         if (this.wrapperCssClasses == null) {
813             this.wrapperCssClasses = new ArrayList<String>();
814         }
815 
816         if (cssClass != null) {
817             this.wrapperCssClasses.add(cssClass);
818         }
819     }
820 
821     /**
822      * Builds the HTML class attribute string by combining the cellStyleClasses list with a space
823      * delimiter.
824      *
825      * @return class attribute string
826      */
827     public String getWrapperCssClassesAsString() {
828         if (wrapperCssClasses != null) {
829             return StringUtils.join(wrapperCssClasses, " ").trim();
830         }
831 
832         return "";
833     }
834 
835     /**
836      * {@inheritDoc}
837      */
838     @Override
839     public String getWrapperStyle() {
840         return wrapperStyle;
841     }
842 
843     /**
844      * {@inheritDoc}
845      */
846     @Override
847     public void setWrapperStyle(String wrapperStyle) {
848         checkMutable(true);
849         this.wrapperStyle = wrapperStyle;
850     }
851 
852     /**
853      * {@inheritDoc}
854      */
855     @Override
856     public String getCellWidth() {
857         return cellWidth;
858     }
859 
860     /**
861      * {@inheritDoc}
862      */
863     @Override
864     public void setCellWidth(String cellWidth) {
865         checkMutable(true);
866         this.cellWidth = cellWidth;
867     }
868 
869     /**
870      * {@inheritDoc}
871      */
872     @BeanTagAttribute(name = "align")
873     @Override
874     public String getAlign() {
875         return this.align;
876     }
877 
878     /**
879      * {@inheritDoc}
880      */
881     @Override
882     public void setAlign(String align) {
883         checkMutable(true);
884         this.align = align;
885     }
886 
887     /**
888      * {@inheritDoc}
889      */
890     @BeanTagAttribute(name = "valign")
891     @Override
892     public String getValign() {
893         return this.valign;
894     }
895 
896     /**
897      * {@inheritDoc}
898      */
899     @Override
900     public void setValign(String valign) {
901         checkMutable(true);
902         this.valign = valign;
903     }
904 
905     /**
906      * {@inheritDoc}
907      */
908     @BeanTagAttribute(name = "width")
909     @Override
910     public String getWidth() {
911         return this.width;
912     }
913 
914     /**
915      * {@inheritDoc}
916      */
917     @Override
918     public void setWidth(String width) {
919         checkMutable(true);
920         this.width = width;
921     }
922 
923     /**
924      * {@inheritDoc}
925      */
926     @BeanTagAttribute(name = "style")
927     @Override
928     public String getStyle() {
929         return this.style;
930     }
931 
932     /**
933      * {@inheritDoc}
934      */
935     @Override
936     public void setStyle(String style) {
937         checkMutable(true);
938         this.style = style;
939     }
940 
941     /**
942      * Additional css classes that come before css classes listed in the cssClasses property
943      *
944      * <p>
945      * These are used by the framework for styling with a library (for example, bootstrap), and
946      * should normally not be overridden.
947      * </p>
948      *
949      * @return the library cssClasses
950      */
951     public List<String> getLibraryCssClasses() {
952         if (libraryCssClasses == Collections.EMPTY_LIST && isMutable(true)) {
953             libraryCssClasses = new LifecycleAwareList<String>(this);
954         }
955 
956         return libraryCssClasses;
957     }
958 
959     /**
960      * Set the libraryCssClasses
961      *
962      * @param libraryCssClasses
963      */
964     public void setLibraryCssClasses(List<String> libraryCssClasses) {
965         checkMutable(true);
966 
967         if (libraryCssClasses == null) {
968             this.libraryCssClasses = Collections.emptyList();
969         } else {
970             this.libraryCssClasses = new LifecycleAwareList<String>(this, libraryCssClasses);
971         }
972     }
973 
974     /**
975      * {@inheritDoc}
976      */
977     @BeanTagAttribute(name = "cssClasses", type = BeanTagAttribute.AttributeType.LISTVALUE)
978     @Override
979     public List<String> getCssClasses() {
980         if (cssClasses == Collections.EMPTY_LIST && isMutable(true)) {
981             cssClasses = new LifecycleAwareList<String>(this);
982         }
983 
984         return cssClasses;
985     }
986 
987     /**
988      * {@inheritDoc}
989      */
990     @Override
991     public void setCssClasses(List<String> cssClasses) {
992         checkMutable(true);
993         if (cssClasses == null) {
994             this.cssClasses = Collections.emptyList();
995         } else {
996             this.cssClasses = new LifecycleAwareList<String>(this, cssClasses);
997         }
998     }
999 
1000     /**
1001      * {@inheritDoc}
1002      */
1003     @BeanTagAttribute(name = "additionalCssClasses", type = BeanTagAttribute.AttributeType.LISTVALUE)
1004     @Override
1005     public List<String> getAdditionalCssClasses() {
1006         if (additionalCssClasses == Collections.EMPTY_LIST && isMutable(true)) {
1007             additionalCssClasses = new LifecycleAwareList<String>(this);
1008         }
1009 
1010         return additionalCssClasses;
1011     }
1012 
1013     /**
1014      * {@inheritDoc}
1015      */
1016     @Override
1017     public void setAdditionalCssClasses(List<String> additionalCssClasses) {
1018         checkMutable(true);
1019         if (additionalCssClasses == null) {
1020             this.additionalCssClasses = Collections.emptyList();
1021         } else {
1022             this.additionalCssClasses = new LifecycleAwareList<String>(this, additionalCssClasses);
1023         }
1024     }
1025 
1026     /**
1027      * Builds the HTML class attribute string by combining the styleClasses list with a space
1028      * delimiter
1029      *
1030      * @return class attribute string
1031      */
1032     public String getStyleClassesAsString() {
1033         if (cssClasses != null) {
1034             return StringUtils.join(cssClasses, " ").trim();
1035         }
1036 
1037         return "";
1038     }
1039 
1040     /**
1041      * {@inheritDoc}
1042      */
1043     @Override
1044     public void addStyleClass(String styleClass) {
1045         checkMutable(false);
1046         if (StringUtils.isEmpty(styleClass)) {
1047             return;
1048         }
1049 
1050         if (cssClasses.isEmpty()) {
1051             setCssClasses(new ArrayList<String>());
1052         }
1053 
1054         if (!cssClasses.contains(styleClass)) {
1055             cssClasses.add(styleClass);
1056         }
1057     }
1058 
1059     /**
1060      * {@inheritDoc}
1061      */
1062     @Override
1063     public void appendToStyle(String styleRules) {
1064         checkMutable(false);
1065         if (style == null) {
1066             style = "";
1067         }
1068         style = style + styleRules;
1069     }
1070 
1071     /**
1072      * {@inheritDoc}
1073      */
1074     @BeanTagAttribute(name = "finalizeMethodToCall")
1075     @Override
1076     public String getFinalizeMethodToCall() {
1077         return this.finalizeMethodToCall;
1078     }
1079 
1080     /**
1081      * Setter for the finalize method
1082      *
1083      * @param finalizeMethodToCall
1084      */
1085     public void setFinalizeMethodToCall(String finalizeMethodToCall) {
1086         checkMutable(true);
1087         this.finalizeMethodToCall = finalizeMethodToCall;
1088     }
1089 
1090     /**
1091      * {@inheritDoc}
1092      */
1093     @BeanTagAttribute(name = "finalizeMethodAdditionalArguments", type = BeanTagAttribute.AttributeType.LISTBEAN)
1094     @Override
1095     public List<Object> getFinalizeMethodAdditionalArguments() {
1096         return finalizeMethodAdditionalArguments;
1097     }
1098 
1099     /**
1100      * Setter for the finalize additional arguments list
1101      *
1102      * @param finalizeMethodAdditionalArguments
1103      */
1104     public void setFinalizeMethodAdditionalArguments(List<Object> finalizeMethodAdditionalArguments) {
1105         checkMutable(true);
1106         this.finalizeMethodAdditionalArguments = finalizeMethodAdditionalArguments;
1107     }
1108 
1109     /**
1110      * {@inheritDoc}
1111      */
1112     @BeanTagAttribute(name = "finalizeMethodInvoker", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1113     @Override
1114     public MethodInvokerConfig getFinalizeMethodInvoker() {
1115         return this.finalizeMethodInvoker;
1116     }
1117 
1118     /**
1119      * Setter for the method invoker instance
1120      *
1121      * @param finalizeMethodInvoker
1122      */
1123     public void setFinalizeMethodInvoker(MethodInvokerConfig finalizeMethodInvoker) {
1124         checkMutable(true);
1125         this.finalizeMethodInvoker = finalizeMethodInvoker;
1126     }
1127 
1128     /**
1129      * {@inheritDoc}
1130      */
1131     @BeanTagAttribute(name = "selfRendered")
1132     @Override
1133     public boolean isSelfRendered() {
1134         return this.selfRendered;
1135     }
1136 
1137     /**
1138      * {@inheritDoc}
1139      */
1140     @Override
1141     public void setSelfRendered(boolean selfRendered) {
1142         this.selfRendered = selfRendered;
1143     }
1144 
1145     /**
1146      * {@inheritDoc}
1147      */
1148     @BeanTagAttribute(name = "renderedHtmlOutput")
1149     @Override
1150     public String getRenderedHtmlOutput() {
1151         return this.renderedHtmlOutput;
1152     }
1153 
1154     /**
1155      * {@inheritDoc}
1156      */
1157     @Override
1158     public void setRenderedHtmlOutput(String renderedHtmlOutput) {
1159         this.renderedHtmlOutput = renderedHtmlOutput;
1160     }
1161 
1162     /**
1163      * {@inheritDoc}
1164      */
1165     @BeanTagAttribute(name = "disableSessionPersistence")
1166     @Override
1167     public boolean isDisableSessionPersistence() {
1168         return disableSessionPersistence;
1169     }
1170 
1171     /**
1172      * {@inheritDoc}
1173      */
1174     @Override
1175     public void setDisableSessionPersistence(boolean disableSessionPersistence) {
1176         checkMutable(true);
1177         this.disableSessionPersistence = disableSessionPersistence;
1178     }
1179 
1180     /**
1181      * {@inheritDoc}
1182      */
1183     @BeanTagAttribute(name = "forceSessionPersistence")
1184     @Override
1185     public boolean isForceSessionPersistence() {
1186         return forceSessionPersistence;
1187     }
1188 
1189     /**
1190      * {@inheritDoc}
1191      */
1192     @Override
1193     public void setForceSessionPersistence(boolean forceSessionPersistence) {
1194         checkMutable(true);
1195         this.forceSessionPersistence = forceSessionPersistence;
1196     }
1197 
1198     /**
1199      * {@inheritDoc}
1200      */
1201     @BeanTagAttribute(name = "componentSecurity", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1202     @Override
1203     public ComponentSecurity getComponentSecurity() {
1204         return componentSecurity;
1205     }
1206 
1207     /**
1208      * {@inheritDoc}
1209      */
1210     @Override
1211     public void setComponentSecurity(ComponentSecurity componentSecurity) {
1212         checkMutable(true);
1213         this.componentSecurity = componentSecurity;
1214     }
1215 
1216     /**
1217      * Initializes (if necessary) the component security instance for the component type
1218      */
1219     protected void initializeComponentSecurity() {
1220         if (this.componentSecurity == null) {
1221             this.componentSecurity = KRADUtils.createNewObjectFromClass(ComponentSecurity.class);
1222         }
1223     }
1224 
1225     /**
1226      * @see org.kuali.rice.krad.uif.component.ComponentSecurity#isEditAuthz()
1227      */
1228     public Boolean isEditAuthz() {
1229         initializeComponentSecurity();
1230 
1231         return this.componentSecurity.isEditAuthz();
1232     }
1233 
1234     /**
1235      * Setter for {@link #isEditAuthz()}
1236      * 
1237      * @param editAuthz property value
1238      */
1239     public void setEditAuthz(Boolean editAuthz) {
1240         checkMutable(true);
1241         initializeComponentSecurity();
1242 
1243         this.componentSecurity.setEditAuthz(editAuthz);
1244     }
1245 
1246     /**
1247      * @see org.kuali.rice.krad.uif.component.ComponentSecurity#isViewAuthz()
1248      */
1249     public Boolean isViewAuthz() {
1250         initializeComponentSecurity();
1251 
1252         return this.componentSecurity.isViewAuthz();
1253     }
1254 
1255     /**
1256      * Setter for {@link #isViewAuthz()}
1257      * 
1258      * @param viewAuthz property value
1259      */
1260     public void setViewAuthz(Boolean viewAuthz) {
1261         checkMutable(true);
1262         initializeComponentSecurity();
1263 
1264         this.componentSecurity.setViewAuthz(viewAuthz);
1265     }
1266 
1267     /**
1268      * {@inheritDoc}
1269      */
1270     @BeanTagAttribute(name = "componentModifiers", type = BeanTagAttribute.AttributeType.LISTBEAN)
1271     @Override
1272     public List<ComponentModifier> getComponentModifiers() {
1273         return this.componentModifiers;
1274     }
1275 
1276     /**
1277      * {@inheritDoc}
1278      */
1279     @Override
1280     public void setComponentModifiers(List<ComponentModifier> componentModifiers) {
1281         checkMutable(true);
1282         this.componentModifiers = componentModifiers == null ? Collections.<ComponentModifier>emptyList() :
1283                 Collections.<ComponentModifier>unmodifiableList(componentModifiers);
1284     }
1285 
1286     /**
1287      * {@inheritDoc}
1288      */
1289     @BeanTagAttribute(name = "context", type = BeanTagAttribute.AttributeType.MAPBEAN)
1290     @Override
1291     public Map<String, Object> getContext() {
1292         if (context == Collections.EMPTY_MAP && isMutable(true)) {
1293             context = new LifecycleAwareMap<String, Object>(this);
1294         }
1295 
1296         return context;
1297     }
1298 
1299     /**
1300      * {@inheritDoc}
1301      */
1302     @Override
1303     public void setContext(Map<String, Object> context) {
1304         checkMutable(true);
1305 
1306         if (context == null) {
1307             this.context = Collections.emptyMap();
1308         } else {
1309             this.context = new LifecycleAwareMap<String, Object>(this, context);
1310         }
1311     }
1312 
1313     /**
1314      * {@inheritDoc}
1315      */
1316     @Override
1317     public void pushObjectToContext(String objectName, Object object) {
1318         checkMutable(true);
1319         if (context == Collections.EMPTY_MAP && isMutable(true)) {
1320             context = new LifecycleAwareMap<String, Object>(this);
1321         }
1322 
1323         pushToPropertyReplacerContext(objectName, object);
1324         context.put(objectName, object);
1325     }
1326 
1327     /*
1328     * Adds the object to the context of the components in the
1329     * PropertyReplacer object. Only checks for a list, map or component.
1330     */
1331     protected void pushToPropertyReplacerContext(String objectName, Object object) {
1332         checkMutable(true);
1333         List<Component> propertyReplacerComponents = getPropertyReplacerComponents();
1334         if (propertyReplacerComponents != null) {
1335             for (Component replacerComponent : propertyReplacerComponents) {
1336                 replacerComponent.pushObjectToContext(objectName, object);
1337             }
1338         }
1339     }
1340 
1341     /**
1342      * {@inheritDoc}
1343      */
1344     @Override
1345     public void pushAllToContext(Map<String, Object> objects) {
1346         checkMutable(true);
1347         if (objects == null || objects.isEmpty()) {
1348             return;
1349         }
1350 
1351         if (context == Collections.EMPTY_MAP && isMutable(true)) {
1352             context = new LifecycleAwareMap<String, Object>(this);
1353         }
1354 
1355         context.putAll(objects);
1356 
1357         List<Component> propertyReplacerComponents = getPropertyReplacerComponents();
1358         if (propertyReplacerComponents != null) {
1359             for (Component replacerComponent : propertyReplacerComponents) {
1360                 replacerComponent.pushAllToContext(objects);
1361             }
1362         }
1363     }
1364 
1365     /**
1366      * {@inheritDoc}
1367      */
1368     @BeanTagAttribute(name = "propertyReplacers", type = BeanTagAttribute.AttributeType.LISTBEAN)
1369     @Override
1370     public List<PropertyReplacer> getPropertyReplacers() {
1371         return this.propertyReplacers;
1372     }
1373 
1374     /**
1375      * {@inheritDoc}
1376      */
1377     @Override
1378     public void setPropertyReplacers(List<PropertyReplacer> propertyReplacers) {
1379         checkMutable(true);
1380         this.propertyReplacers = propertyReplacers == null ? Collections.<PropertyReplacer>emptyList() :
1381                 Collections.<PropertyReplacer>unmodifiableList(propertyReplacers);
1382     }
1383 
1384     /**
1385      * @see org.springframework.core.Ordered#getOrder()
1386      */
1387     @BeanTagAttribute(name = "order")
1388     public int getOrder() {
1389         return this.order;
1390     }
1391 
1392     /**
1393      * Setter for the component's order
1394      *
1395      * @param order
1396      */
1397     public void setOrder(int order) {
1398         checkMutable(true);
1399         this.order = order;
1400     }
1401 
1402     /**
1403      * {@inheritDoc}
1404      */
1405     @BeanTagAttribute(name = "toolTip", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
1406     @Override
1407     public Tooltip getToolTip() {
1408         return toolTip;
1409     }
1410 
1411     /**
1412      * {@inheritDoc}
1413      */
1414     @Override
1415     public void setToolTip(Tooltip toolTip) {
1416         checkMutable(true);
1417         this.toolTip = toolTip;
1418     }
1419 
1420     /**
1421      * {@inheritDoc}
1422      */
1423     @Override
1424     public String getEventHandlerScript() {
1425         StringBuilder sb = new StringBuilder();
1426 
1427         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "load", getOnLoadScript()));
1428 
1429         // special handling for ready since it needs to bind to the document
1430         if (StringUtils.isNotBlank(getOnDocumentReadyScript())) {
1431             sb.append("jQuery(document).ready(function(e) {");
1432             sb.append(getOnDocumentReadyScript());
1433             sb.append("});");
1434         }
1435 
1436         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "unload", getOnUnloadScript()));
1437         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "blur", getOnBlurScript()));
1438         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "change", getOnChangeScript()));
1439         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "click", getOnClickScript()));
1440         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "dblclick", getOnDblClickScript()));
1441         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "focus", getOnFocusScript()));
1442         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "input", getOnInputScript()));
1443         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "keypress", getOnKeyPressScript()));
1444         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "keyup", getOnKeyUpScript()));
1445         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "keydown", getOnKeyDownScript()));
1446         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "mouseover", getOnMouseOverScript()));
1447         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "mouseout", getOnMouseOutScript()));
1448         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "mouseup", getOnMouseUpScript()));
1449         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "mousedown", getOnMouseDownScript()));
1450         sb.append(ScriptUtils.buildEventHandlerScript(getId(), "mousemove", getOnMouseMoveScript()));
1451 
1452         return sb.toString();
1453     }
1454 
1455     /**
1456      * {@inheritDoc}
1457      */
1458     @BeanTagAttribute(name = "onLoadScript")
1459     @Override
1460     public String getOnLoadScript() {
1461         return onLoadScript;
1462     }
1463 
1464     /**
1465      * @see ScriptEventSupport#setOnLoadScript(java.lang.String)
1466      */
1467     public void setOnLoadScript(String onLoadScript) {
1468         checkMutable(true);
1469         this.onLoadScript = onLoadScript;
1470     }
1471 
1472     /**
1473      * {@inheritDoc}
1474      */
1475     @BeanTagAttribute(name = "onDocumentReadyScript")
1476     @Override
1477     public String getOnDocumentReadyScript() {
1478         return this.onDocumentReadyScript;
1479     }
1480 
1481     /**
1482      * @see ScriptEventSupport#setOnDocumentReadyScript(java.lang.String)
1483      */
1484     public void setOnDocumentReadyScript(String onDocumentReadyScript) {
1485         checkMutable(true);
1486         this.onDocumentReadyScript = onDocumentReadyScript;
1487     }
1488 
1489     /**
1490      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnUnloadScript()
1491      */
1492     @BeanTagAttribute(name = "onUnloadScript")
1493     public String getOnUnloadScript() {
1494         return onUnloadScript;
1495     }
1496 
1497     /**
1498      * @see ScriptEventSupport#setOnUnloadScript(java.lang.String)
1499      */
1500     public void setOnUnloadScript(String onUnloadScript) {
1501         checkMutable(true);
1502         this.onUnloadScript = onUnloadScript;
1503     }
1504 
1505     /**
1506      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnCloseScript()
1507      */
1508     @BeanTagAttribute(name = "onCloseScript")
1509     public String getOnCloseScript() {
1510         return onCloseScript;
1511     }
1512 
1513     /**
1514      * @see ScriptEventSupport#setOnCloseScript(java.lang.String)
1515      */
1516     public void setOnCloseScript(String onCloseScript) {
1517         checkMutable(true);
1518         this.onCloseScript = onCloseScript;
1519     }
1520 
1521     /**
1522      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnBlurScript()
1523      */
1524     @BeanTagAttribute(name = "onBlurScript")
1525     public String getOnBlurScript() {
1526         return onBlurScript;
1527     }
1528 
1529     /**
1530      * @see ScriptEventSupport#setOnBlurScript(java.lang.String)
1531      */
1532     public void setOnBlurScript(String onBlurScript) {
1533         checkMutable(true);
1534         this.onBlurScript = onBlurScript;
1535     }
1536 
1537     /**
1538      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnChangeScript()
1539      */
1540     @BeanTagAttribute(name = "onChangeScript")
1541     public String getOnChangeScript() {
1542         return onChangeScript;
1543     }
1544 
1545     /**
1546      * @see ScriptEventSupport#setOnChangeScript(java.lang.String)
1547      */
1548     public void setOnChangeScript(String onChangeScript) {
1549         checkMutable(true);
1550         this.onChangeScript = onChangeScript;
1551     }
1552 
1553     /**
1554      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnClickScript()
1555      */
1556     @BeanTagAttribute(name = "onClickScript")
1557     public String getOnClickScript() {
1558         return onClickScript;
1559     }
1560 
1561     /**
1562      * @see ScriptEventSupport#setOnClickScript(java.lang.String)
1563      */
1564     public void setOnClickScript(String onClickScript) {
1565         checkMutable(true);
1566         this.onClickScript = onClickScript;
1567     }
1568 
1569     /**
1570      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnDblClickScript()
1571      */
1572     @BeanTagAttribute(name = "onDblClickScript")
1573     public String getOnDblClickScript() {
1574         return onDblClickScript;
1575     }
1576 
1577     /**
1578      * @see ScriptEventSupport#setOnDblClickScript(java.lang.String)
1579      */
1580     public void setOnDblClickScript(String onDblClickScript) {
1581         checkMutable(true);
1582         this.onDblClickScript = onDblClickScript;
1583     }
1584 
1585     /**
1586      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnFocusScript()
1587      */
1588     @BeanTagAttribute(name = "onFocusScript")
1589     public String getOnFocusScript() {
1590         return onFocusScript;
1591     }
1592 
1593     /**
1594      * @see ScriptEventSupport#setOnFocusScript(java.lang.String)
1595      */
1596     public void setOnFocusScript(String onFocusScript) {
1597         checkMutable(true);
1598         this.onFocusScript = onFocusScript;
1599     }
1600 
1601     /**
1602      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnSubmitScript()
1603      */
1604     @BeanTagAttribute(name = "onSubmitScript")
1605     public String getOnSubmitScript() {
1606         return onSubmitScript;
1607     }
1608 
1609     /**
1610      * @see ScriptEventSupport#setOnSubmitScript(java.lang.String)
1611      */
1612     public void setOnSubmitScript(String onSubmitScript) {
1613         checkMutable(true);
1614         this.onSubmitScript = onSubmitScript;
1615     }
1616 
1617     /**
1618      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnInputScript()
1619      */
1620     @BeanTagAttribute(name = "onInputScript")
1621     public String getOnInputScript() {
1622         return onInputScript;
1623     }
1624 
1625     /**
1626      * @see ScriptEventSupport#setOnInputScript(java.lang.String)
1627      */
1628     public void setOnInputScript(String onInputScript) {
1629         checkMutable(true);
1630         this.onInputScript = onInputScript;
1631     }
1632 
1633     /**
1634      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyPressScript()
1635      */
1636     @BeanTagAttribute(name = "onKeyPressScript")
1637     public String getOnKeyPressScript() {
1638         return onKeyPressScript;
1639     }
1640 
1641     /**
1642      * @see ScriptEventSupport#setOnKeyPressScript(java.lang.String)
1643      */
1644     public void setOnKeyPressScript(String onKeyPressScript) {
1645         checkMutable(true);
1646         this.onKeyPressScript = onKeyPressScript;
1647     }
1648 
1649     /**
1650      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyUpScript()
1651      */
1652     @BeanTagAttribute(name = "onKeyUpScript")
1653     public String getOnKeyUpScript() {
1654         return onKeyUpScript;
1655     }
1656 
1657     /**
1658      * @see ScriptEventSupport#setOnKeyUpScript(java.lang.String)
1659      */
1660     public void setOnKeyUpScript(String onKeyUpScript) {
1661         checkMutable(true);
1662         this.onKeyUpScript = onKeyUpScript;
1663     }
1664 
1665     /**
1666      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyDownScript()
1667      */
1668     @BeanTagAttribute(name = "onKeyDownScript")
1669     public String getOnKeyDownScript() {
1670         return onKeyDownScript;
1671     }
1672 
1673     /**
1674      * @see ScriptEventSupport#setOnKeyDownScript(java.lang.String)
1675      */
1676     public void setOnKeyDownScript(String onKeyDownScript) {
1677         checkMutable(true);
1678         this.onKeyDownScript = onKeyDownScript;
1679     }
1680 
1681     /**
1682      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseOverScript()
1683      */
1684     @BeanTagAttribute(name = "onMouseOverScript")
1685     public String getOnMouseOverScript() {
1686         return onMouseOverScript;
1687     }
1688 
1689     /**
1690      * @see ScriptEventSupport#setOnMouseOverScript(java.lang.String)
1691      */
1692     public void setOnMouseOverScript(String onMouseOverScript) {
1693         checkMutable(true);
1694         this.onMouseOverScript = onMouseOverScript;
1695     }
1696 
1697     /**
1698      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseOutScript()
1699      */
1700     @BeanTagAttribute(name = "onMouseOutScript")
1701     public String getOnMouseOutScript() {
1702         return onMouseOutScript;
1703     }
1704 
1705     /**
1706      * @see ScriptEventSupport#setOnMouseOutScript(java.lang.String)
1707      */
1708     public void setOnMouseOutScript(String onMouseOutScript) {
1709         checkMutable(true);
1710         this.onMouseOutScript = onMouseOutScript;
1711     }
1712 
1713     /**
1714      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseUpScript()
1715      */
1716     @BeanTagAttribute(name = "onMouseUpScript")
1717     public String getOnMouseUpScript() {
1718         return onMouseUpScript;
1719     }
1720 
1721     /**
1722      * @see ScriptEventSupport#setOnMouseUpScript(java.lang.String)
1723      */
1724     public void setOnMouseUpScript(String onMouseUpScript) {
1725         checkMutable(true);
1726         this.onMouseUpScript = onMouseUpScript;
1727     }
1728 
1729     /**
1730      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseDownScript()
1731      */
1732     @BeanTagAttribute(name = "onMouseDownScript")
1733     public String getOnMouseDownScript() {
1734         return onMouseDownScript;
1735     }
1736 
1737     /**
1738      * @see ScriptEventSupport#setOnMouseDownScript(java.lang.String)
1739      */
1740     public void setOnMouseDownScript(String onMouseDownScript) {
1741         checkMutable(true);
1742         this.onMouseDownScript = onMouseDownScript;
1743     }
1744 
1745     /**
1746      * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseMoveScript()
1747      */
1748     @BeanTagAttribute(name = "onMouseMoveScript")
1749     public String getOnMouseMoveScript() {
1750         return onMouseMoveScript;
1751     }
1752 
1753     /**
1754      * @see ScriptEventSupport#setOnMouseMoveScript(java.lang.String)
1755      */
1756     public void setOnMouseMoveScript(String onMouseMoveScript) {
1757         checkMutable(true);
1758         this.onMouseMoveScript = onMouseMoveScript;
1759     }
1760 
1761     /**
1762      * {@inheritDoc}
1763      */
1764     @BeanTagAttribute(name = "templateOptions", type = BeanTagAttribute.AttributeType.MAPVALUE)
1765     @Override
1766     public Map<String, String> getTemplateOptions() {
1767         if (templateOptions == Collections.EMPTY_MAP && isMutable(true)) {
1768             templateOptions = new LifecycleAwareMap<String, String>(this);
1769         }
1770 
1771         return templateOptions;
1772     }
1773 
1774     /**
1775      * {@inheritDoc}
1776      */
1777     @Override
1778     public void setTemplateOptions(Map<String, String> templateOptions) {
1779         checkMutable(true);
1780         if (templateOptions == null) {
1781             this.templateOptions = Collections.emptyMap();
1782         } else {
1783             this.templateOptions = new LifecycleAwareMap<String, String>(this, templateOptions);
1784         }
1785     }
1786 
1787     /**
1788      * Builds a string from the underlying <code>Map</code> of template options that will export
1789      * that options as a JavaScript Map for use in js and jQuery plugins
1790      *
1791      * @return String of widget options formatted as JS Map.
1792      */
1793     @Override
1794     @BeanTagAttribute(name = "templateOptionsJSString")
1795     public String getTemplateOptionsJSString() {
1796         if (templateOptionsJSString != null) {
1797             return templateOptionsJSString;
1798         }
1799 
1800         if (templateOptions == null) {
1801             return "{}";
1802         }
1803 
1804         StringBuilder sb = new StringBuilder();
1805         sb.append("{");
1806 
1807         for (Entry<String, String> option : templateOptions.entrySet()) {
1808 
1809             if (sb.length() > 1) {
1810                 sb.append(",");
1811             }
1812 
1813             sb.append(option.getKey());
1814             sb.append(":");
1815 
1816             sb.append(ScriptUtils.convertToJsValue(option.getValue()));
1817         }
1818 
1819         sb.append("}");
1820 
1821         return sb.toString();
1822     }
1823 
1824     @Override
1825     public void setTemplateOptionsJSString(String templateOptionsJSString) {
1826         checkMutable(true);
1827         this.templateOptionsJSString = templateOptionsJSString;
1828     }
1829 
1830     /**
1831      * When set if the condition is satisfied, the component will be displayed. The component MUST
1832      * BE a container or field type. progressiveRender is defined in a limited Spring EL syntax.
1833      * Only valid form property names, and, or, logical comparison operators (non-arithmetic),
1834      * #listContains, #emptyList, matches clause are allowed. String and regex values must use
1835      * single quotes ('), booleans must be either true or false, numbers must be a valid double,
1836      * either negative or positive.
1837      *
1838      * <p>
1839      * DO NOT use progressiveRender and a conditional refresh statement on the same component unless
1840      * it is known that the component will always be visible in all cases when a conditional refresh
1841      * happens (ie conditional refresh has progressiveRender's condition anded with its own
1842      * condition).
1843      * </p>
1844      *
1845      * <p>
1846      * <b>If a component should be refreshed every time it is shown, use the
1847      * progressiveRenderAndRefresh option with this property instead.</b>
1848      * </p>
1849      *
1850      * @return progressiveRender expression
1851      */
1852     @BeanTagAttribute(name = "progressiveRender")
1853     public String getProgressiveRender() {
1854         return this.progressiveRender;
1855     }
1856 
1857     /**
1858      * @param progressiveRender the progressiveRender to set.
1859      */
1860     public void setProgressiveRender(String progressiveRender) {
1861         checkMutable(true);
1862         this.progressiveRender = progressiveRender;
1863     }
1864 
1865     /**
1866      * When set if the condition is satisfied, the component will be refreshed.
1867      *
1868      * <p>
1869      * The component MUST BE a container or field type. conditionalRefresh is defined in a limited
1870      * Spring EL syntax. Only valid form property names, and, or, logical comparison operators
1871      * (non-arithmetic), #listContains, #emptyList, and the matches clause are allowed. String and
1872      * regex values must use single quotes ('), booleans must be either true or false, numbers must
1873      * be a valid double either negative or positive.
1874      *
1875      * <p>
1876      * DO NOT use progressiveRender and conditionalRefresh on the same component unless it is known
1877      * that the component will always be visible in all cases when a conditionalRefresh happens (ie
1878      * conditionalRefresh has progressiveRender's condition anded with its own condition). <b>If a
1879      * component should be refreshed every time it is shown, use the progressiveRenderAndRefresh
1880      * option with this property instead.</b>
1881      * </p>
1882      *
1883      * @return the conditionalRefresh
1884      */
1885     @BeanTagAttribute(name = "conditionalRefresh")
1886     public String getConditionalRefresh() {
1887         return this.conditionalRefresh;
1888     }
1889 
1890     /**
1891      * Set the conditional refresh condition
1892      *
1893      * @param conditionalRefresh the conditionalRefresh to set
1894      */
1895     public void setConditionalRefresh(String conditionalRefresh) {
1896         checkMutable(true);
1897         this.conditionalRefresh = conditionalRefresh;
1898     }
1899 
1900     /**
1901      * Control names used to control progressive disclosure, set internally cannot be set.
1902      *
1903      * @return the progressiveDisclosureControlNames
1904      */
1905     public List<String> getProgressiveDisclosureControlNames() {
1906         return this.progressiveDisclosureControlNames;
1907     }
1908 
1909     /**
1910      * The condition to show this component progressively converted to a js expression, set
1911      * internally cannot be set.
1912      *
1913      * @return the progressiveDisclosureConditionJs
1914      */
1915     public String getProgressiveDisclosureConditionJs() {
1916         return this.progressiveDisclosureConditionJs;
1917     }
1918 
1919     /**
1920      * The condition to refresh this component converted to a js expression, set internally cannot
1921      * be set.
1922      *
1923      * @return the conditionalRefreshConditionJs
1924      */
1925     public String getConditionalRefreshConditionJs() {
1926         return this.conditionalRefreshConditionJs;
1927     }
1928 
1929     /**
1930      * Control names used to control conditional refresh, set internally cannot be set.
1931      *
1932      * @return the conditionalRefreshControlNames
1933      */
1934     public List<String> getConditionalRefreshControlNames() {
1935         return this.conditionalRefreshControlNames;
1936     }
1937 
1938     /**
1939      * When progressiveRenderViaAJAX is true, this component will be retrieved from the server when
1940      * it first satisfies its progressive render condition.
1941      *
1942      * <p>
1943      * After the first retrieval, it is hidden/shown in the html by the js when its progressive
1944      * condition result changes. <b>By default, this is false, so components with progressive render
1945      * capabilities will always be already within the client html and toggled to be hidden or
1946      * visible.</b>
1947      * </p>
1948      *
1949      * @return the progressiveRenderViaAJAX
1950      */
1951     @BeanTagAttribute(name = "progressiveRenderViaAJAX")
1952     public boolean isProgressiveRenderViaAJAX() {
1953         return this.progressiveRenderViaAJAX;
1954     }
1955 
1956     /**
1957      * @param progressiveRenderViaAJAX the progressiveRenderViaAJAX to set.
1958      */
1959     public void setProgressiveRenderViaAJAX(boolean progressiveRenderViaAJAX) {
1960         checkMutable(true);
1961         this.progressiveRenderViaAJAX = progressiveRenderViaAJAX;
1962     }
1963 
1964     /**
1965      * If true, when the progressiveRender condition is satisfied, the component will always be
1966      * retrieved from the server and shown(as opposed to being stored on the client, but hidden,
1967      * after the first retrieval as is the case with the progressiveRenderViaAJAX option).
1968      *
1969      * <p>
1970      * <b>By default, this is false, so components with progressive render capabilities will always
1971      * be already within the client html and toggled to be hidden or visible.</b>
1972      * </p>
1973      *
1974      * @return the progressiveRenderAndRefresh
1975      */
1976     @BeanTagAttribute(name = "progressiveRenderAndRefresh")
1977     public boolean isProgressiveRenderAndRefresh() {
1978         return this.progressiveRenderAndRefresh;
1979     }
1980 
1981     /**
1982      * Set the progressive render and refresh option.
1983      *
1984      * @param progressiveRenderAndRefresh the progressiveRenderAndRefresh to set.
1985      */
1986     public void setProgressiveRenderAndRefresh(boolean progressiveRenderAndRefresh) {
1987         checkMutable(true);
1988         this.progressiveRenderAndRefresh = progressiveRenderAndRefresh;
1989     }
1990 
1991     /**
1992      * {@inheritDoc}
1993      */
1994     @BeanTagAttribute(name = "refreshWhenChangedPropertyNames", type = BeanTagAttribute.AttributeType.LISTVALUE)
1995     @Override
1996     public List<String> getRefreshWhenChangedPropertyNames() {
1997         return this.refreshWhenChangedPropertyNames;
1998     }
1999 
2000     /**
2001      * {@inheritDoc}
2002      */
2003     @Override
2004     public void setRefreshWhenChangedPropertyNames(List<String> refreshWhenChangedPropertyNames) {
2005         checkMutable(true);
2006         this.refreshWhenChangedPropertyNames =
2007                 refreshWhenChangedPropertyNames == null ? Collections.<String>emptyList() :
2008                         Collections.<String>unmodifiableList(refreshWhenChangedPropertyNames);
2009     }
2010 
2011     /**
2012      * {@inheritDoc}
2013      */
2014     @BeanTagAttribute(name = "additionalComponentsToRefresh", type = BeanTagAttribute.AttributeType.LISTVALUE)
2015     @Override
2016     public List<String> getAdditionalComponentsToRefresh() {
2017         return additionalComponentsToRefresh;
2018     }
2019 
2020     /**
2021      * {@inheritDoc}
2022      */
2023     @Override
2024     public void setAdditionalComponentsToRefresh(List<String> additionalComponentsToRefresh) {
2025         checkMutable(true);
2026         this.additionalComponentsToRefresh = additionalComponentsToRefresh == null ? Collections.<String>emptyList() :
2027                 Collections.<String>unmodifiableList(additionalComponentsToRefresh);
2028         this.additionalComponentsToRefreshJs = null;
2029     }
2030 
2031     /**
2032      * {@inheritDoc}
2033      */
2034     @Override
2035     public String getAdditionalComponentsToRefreshJs() {
2036         if (additionalComponentsToRefreshJs == null
2037                 && additionalComponentsToRefresh != null
2038                 && !additionalComponentsToRefresh.isEmpty()) {
2039             additionalComponentsToRefreshJs = ScriptUtils.convertStringListToJsArray(
2040                     this.getAdditionalComponentsToRefresh());
2041         }
2042 
2043         return additionalComponentsToRefreshJs;
2044     }
2045 
2046     /**
2047      * {@inheritDoc}
2048      */
2049     @Override
2050     public boolean isRefreshedByAction() {
2051         return refreshedByAction;
2052     }
2053 
2054     /**
2055      * {@inheritDoc}
2056      */
2057     @Override
2058     public void setRefreshedByAction(boolean refreshedByAction) {
2059         checkMutable(true);
2060         this.refreshedByAction = refreshedByAction;
2061     }
2062 
2063     /**
2064      * {@inheritDoc}
2065      */
2066     @Override
2067     public boolean isDisclosedByAction() {
2068         return disclosedByAction;
2069     }
2070 
2071     /**
2072      * {@inheritDoc}
2073      */
2074     @Override
2075     public void setDisclosedByAction(boolean disclosedByAction) {
2076         checkMutable(true);
2077         this.disclosedByAction = disclosedByAction;
2078     }
2079 
2080     /**
2081      * Time in seconds that the component will be automatically refreshed
2082      *
2083      * <p>
2084      * This will invoke the refresh process just like the conditionalRefresh and
2085      * refreshWhenChangedPropertyNames. When using this property methodToCallOnRefresh and id should
2086      * also be specified
2087      * </p>
2088      *
2089      * @return refreshTimer
2090      */
2091     @BeanTagAttribute(name = "refreshTimer")
2092     public int getRefreshTimer() {
2093         return refreshTimer;
2094     }
2095 
2096     /**
2097      * Setter for refreshTimer
2098      *
2099      * @param refreshTimer
2100      */
2101     public void setRefreshTimer(int refreshTimer) {
2102         checkMutable(true);
2103         this.refreshTimer = refreshTimer;
2104     }
2105 
2106     /**
2107      * {@inheritDoc}
2108      */
2109     @BeanTagAttribute(name = "resetDataOnRefresh")
2110     @Override
2111     public boolean isResetDataOnRefresh() {
2112         return resetDataOnRefresh;
2113     }
2114 
2115     /**
2116      * {@inheritDoc}
2117      */
2118     @Override
2119     public void setResetDataOnRefresh(boolean resetDataOnRefresh) {
2120         checkMutable(true);
2121         this.resetDataOnRefresh = resetDataOnRefresh;
2122     }
2123 
2124     /**
2125      * Name of a method on the controller that should be invoked as part of the component refresh
2126      * and disclosure process
2127      *
2128      * <p>
2129      * During the component refresh or disclosure process it might be necessary to perform other
2130      * operations, such as preparing data or executing a business process. This allows the
2131      * configuration of a method on the underlying controller that should be called for the
2132      * component refresh action. In this method, the necessary logic can be performed and then the
2133      * base component update method invoked to carry out the component refresh.
2134      * </p>
2135      *
2136      * <p>
2137      * Controller method to invoke must accept the form, binding result, request, and response
2138      * arguments
2139      * </p>
2140      *
2141      * @return valid controller method name
2142      */
2143     @BeanTagAttribute(name = "methodToCallOnRefresh")
2144     public String getMethodToCallOnRefresh() {
2145         return methodToCallOnRefresh;
2146     }
2147 
2148     /**
2149      * Setter for the controller method to call for a refresh or disclosure action on this component
2150      *
2151      * @param methodToCallOnRefresh
2152      */
2153     public void setMethodToCallOnRefresh(String methodToCallOnRefresh) {
2154         checkMutable(true);
2155         this.methodToCallOnRefresh = methodToCallOnRefresh;
2156     }
2157 
2158     /**
2159      * @param skipInTabOrder flag
2160      */
2161     public void setSkipInTabOrder(boolean skipInTabOrder) {
2162         checkMutable(true);
2163         this.skipInTabOrder = skipInTabOrder;
2164     }
2165 
2166     /**
2167      * Flag indicating that this component and its nested components must be skipped when keyboard
2168      * tabbing.
2169      *
2170      * @return the skipInTabOrder flag
2171      */
2172     @BeanTagAttribute(name = "skipInTabOrder")
2173     public boolean isSkipInTabOrder() {
2174         return skipInTabOrder;
2175     }
2176 
2177     /**
2178      * {@inheritDoc}
2179      */
2180     @Override
2181     @BeanTagAttribute(name = "dataAttributes", type = BeanTagAttribute.AttributeType.MAPVALUE)
2182     public Map<String, String> getDataAttributes() {
2183         if (dataAttributes == Collections.EMPTY_MAP) {
2184             dataAttributes = new LifecycleAwareMap<String, String>(this);
2185         }
2186 
2187         return dataAttributes;
2188     }
2189 
2190     /**
2191      * {@inheritDoc}
2192      */
2193     @Override
2194     public void setDataAttributes(Map<String, String> dataAttributes) {
2195         checkMutable(true);
2196         if (dataAttributes == null) {
2197             this.dataAttributes = Collections.emptyMap();
2198         } else {
2199             this.dataAttributes = new LifecycleAwareMap<String, String>(this, dataAttributes);
2200         }
2201     }
2202 
2203     /**
2204      * {@inheritDoc}
2205      */
2206     @Override
2207     @BeanTagAttribute(name = "scriptDataAttributes", type = BeanTagAttribute.AttributeType.MAPVALUE)
2208     public Map<String, String> getScriptDataAttributes() {
2209         if (scriptDataAttributes == Collections.EMPTY_MAP) {
2210             scriptDataAttributes = new LifecycleAwareMap<String, String>(this);
2211         }
2212 
2213         return scriptDataAttributes;
2214     }
2215 
2216     /**
2217      * {@inheritDoc}
2218      */
2219     @Override
2220     public void setScriptDataAttributes(Map<String, String> scriptDataAttributes) {
2221         this.scriptDataAttributes = scriptDataAttributes;
2222     }
2223 
2224     /**
2225      * {@inheritDoc}
2226      */
2227     @Override
2228     public void addDataAttribute(String key, String value) {
2229         checkMutable(true);
2230 
2231         if (dataAttributes == Collections.EMPTY_MAP) {
2232             dataAttributes = new LifecycleAwareMap<String, String>(this);
2233         }
2234 
2235         dataAttributes.put(key, value);
2236     }
2237 
2238     /**
2239      * {@inheritDoc}
2240      */
2241     @Override
2242     public void addScriptDataAttribute(String key, String value) {
2243         checkMutable(true);
2244 
2245         if (scriptDataAttributes == Collections.EMPTY_MAP) {
2246             scriptDataAttributes = new LifecycleAwareMap<String, String>(this);
2247         }
2248 
2249         scriptDataAttributes.put(key, value);
2250     }
2251 
2252     /**
2253      * {@inheritDoc}
2254      */
2255     @Override
2256     public String getSimpleDataAttributes() {
2257         String attributes = "";
2258 
2259         if (getDataAttributes() == null) {
2260             return attributes;
2261         }
2262 
2263         for (Map.Entry<String, String> data : getDataAttributes().entrySet()) {
2264             if (data != null && data.getValue() != null) {
2265                 attributes = attributes + " " + "data-" + data.getKey() + "=\"" +
2266                         KRADUtils.convertToHTMLAttributeSafeString(data.getValue()) + "\"";
2267             }
2268         }
2269 
2270         return attributes;
2271     }
2272 
2273 
2274     @Override
2275     public String getScriptDataAttributesJs() {
2276         String script = "";
2277 
2278         if (getScriptDataAttributes() == null || getScriptDataAttributes().isEmpty()) {
2279             return script;
2280         }
2281 
2282         String id = this.getId().replace(".", "\\\\.");
2283         String selector = "var dataComponent = jQuery('#" + id + "');";
2284         script = ScriptUtils.appendScript(script, selector);
2285 
2286         for (Map.Entry<String, String> data : getScriptDataAttributes().entrySet()) {
2287             if (data != null && data.getValue() != null) {
2288                 script = ScriptUtils.appendScript(script,
2289                         "dataComponent.data('" + data.getKey() + "'," + ScriptUtils.convertToJsValue(data.getValue())
2290                                 + ");");
2291             }
2292         }
2293 
2294         return script;
2295     }
2296 
2297     /**
2298      * {@inheritDoc}
2299      */
2300     @BeanTagAttribute(name = "preRenderContent")
2301     @Override
2302     public String getPreRenderContent() {
2303         return preRenderContent;
2304     }
2305 
2306     /**
2307      * {@inheritDoc}
2308      */
2309     @Override
2310     public void setPreRenderContent(String preRenderContent) {
2311         checkMutable(true);
2312         this.preRenderContent = preRenderContent;
2313     }
2314 
2315     /**
2316      * {@inheritDoc}
2317      */
2318     @BeanTagAttribute(name = "postRenderContent")
2319     @Override
2320     public String getPostRenderContent() {
2321         return postRenderContent;
2322     }
2323 
2324     /**
2325      * {@inheritDoc}
2326      */
2327     @Override
2328     public void setPostRenderContent(String postRenderContent) {
2329         checkMutable(true);
2330         this.postRenderContent = postRenderContent;
2331     }
2332 
2333     /**
2334      * {@inheritDoc}
2335      */
2336     @Override
2337     public ComponentBase clone() throws CloneNotSupportedException {
2338         ComponentBase copy = (ComponentBase) super.clone();
2339 
2340         // Copy initialized status, but reset to created for others.
2341         // This allows prototypes to bypass repeating the initialized phase.
2342         if (UifConstants.ViewStatus.INITIALIZED.equals(viewStatus)) {
2343             copy.viewStatus = UifConstants.ViewStatus.INITIALIZED;
2344         } else {
2345             copy.viewStatus = UifConstants.ViewStatus.CREATED;
2346         }
2347 
2348         return copy;
2349     }
2350 
2351     /**
2352      * Set view status to {@link org.kuali.rice.krad.uif.UifConstants.ViewStatus#CACHED} to prevent modification.
2353      *
2354      * @see Copyable#preventModification()
2355      */
2356     @Override
2357     public void preventModification() {
2358         if (!UifConstants.ViewStatus.CREATED.equals(viewStatus) && !UifConstants.ViewStatus.CACHED.equals(viewStatus)) {
2359             ViewLifecycle.reportIllegalState("View status is "
2360                     + viewStatus
2361                     + " prior to caching "
2362                     + getClass().getName()
2363                     + " "
2364                     + getId()
2365                     + ", expected C or X");
2366         }
2367 
2368         viewStatus = UifConstants.ViewStatus.CACHED;
2369     }
2370 
2371     /**
2372      * {@inheritDoc}
2373      */
2374     @Override
2375     public boolean skipLifecycle() {
2376             return this.isRetrieveViaAjax();
2377     }
2378 
2379     /**
2380      * {@inheritDoc}
2381      */
2382     @Override
2383     public void completeValidation(ValidationTrace tracer) {
2384         tracer.addBean(this);
2385 
2386         // Check for invalid characters in the components id
2387         if (getId() != null) {
2388             if (getId().contains("'")
2389                     || getId().contains("\"")
2390                     || getId().contains("[]")
2391                     || getId().contains(".")
2392                     || getId().contains("#")) {
2393                 String currentValues[] = {"id = " + getId()};
2394                 tracer.createError("Id contains invalid characters", currentValues);
2395             }
2396         }
2397 
2398         if (tracer.getValidationStage() == ValidationTrace.BUILD) {
2399             // Check for a render presence if the component is set to render
2400             if ((isProgressiveRenderViaAJAX() || isProgressiveRenderAndRefresh()) && (getProgressiveRender() == null)) {
2401                 String currentValues[] = {"progressiveRenderViaAJAX = " + isProgressiveRenderViaAJAX(),
2402                         "progressiveRenderAndRefresh = " + isProgressiveRenderAndRefresh(),
2403                         "progressiveRender = " + getProgressiveRender()};
2404                 tracer.createError(
2405                         "ProgressiveRender must be set if progressiveRenderViaAJAX or progressiveRenderAndRefresh are true",
2406                         currentValues);
2407             }
2408         }
2409 
2410         // Check for rendered html if the component is set to self render
2411         if (isSelfRendered() && getRenderedHtmlOutput() == null) {
2412             String currentValues[] =
2413                     {"selfRendered = " + isSelfRendered(), "renderedHtmlOutput = " + getRenderedHtmlOutput()};
2414             tracer.createError("RenderedHtmlOutput must be set if selfRendered is true", currentValues);
2415         }
2416 
2417         // Check to prevent over writing of session persistence status
2418         if (isDisableSessionPersistence() && isForceSessionPersistence()) {
2419             String currentValues[] = {"disableSessionPersistence = " + isDisableSessionPersistence(),
2420                     "forceSessionPersistence = " + isForceSessionPersistence()};
2421             tracer.createWarning("DisableSessionPersistence and forceSessionPersistence cannot be both true",
2422                     currentValues);
2423         }
2424 
2425         // Check for un-executable data resets when no refresh option is set
2426         if (getMethodToCallOnRefresh() != null || isResetDataOnRefresh()) {
2427             if (!isProgressiveRenderAndRefresh()
2428                     && !isRefreshedByAction()
2429                     && !isProgressiveRenderViaAJAX()
2430                     && !StringUtils.isNotEmpty(conditionalRefresh)
2431                     && !(refreshTimer > 0)) {
2432                 String currentValues[] = {"methodToCallONRefresh = " + getMethodToCallOnRefresh(),
2433                         "resetDataONRefresh = " + isResetDataOnRefresh(),
2434                         "progressiveRenderAndRefresh = " + isProgressiveRenderAndRefresh(),
2435                         "refreshedByAction = " + isRefreshedByAction(),
2436                         "progressiveRenderViaAJAX = " + isProgressiveRenderViaAJAX(),
2437                         "conditionalRefresh = " + getConditionalRefresh(), "refreshTimer = " + getRefreshTimer()};
2438                 tracer.createWarning(
2439                         "MethodToCallONRefresh and resetDataONRefresh should only be set when a trigger event is set",
2440                         currentValues);
2441             }
2442         }
2443 
2444         // Check to prevent complications with rendering and refreshing a component that is not always shown
2445         if (StringUtils.isNotEmpty(getProgressiveRender()) && StringUtils.isNotEmpty(conditionalRefresh)) {
2446             String currentValues[] = {"progressiveRender = " + getProgressiveRender(),
2447                     "conditionalRefresh = " + getConditionalRefresh()};
2448             tracer.createWarning("DO NOT use progressiveRender and conditionalRefresh on the same component unless "
2449                     + "it is known that the component will always be visible in all cases when a conditionalRefresh "
2450                     + "happens (ie conditionalRefresh has progressiveRender's condition anded with its own condition). "
2451                     + "If a component should be refreshed every time it is shown, use the progressiveRenderAndRefresh "
2452                     + "option with this property instead.", currentValues);
2453         }
2454 
2455         // Check for valid Spring EL format for progressiveRender
2456         if (!Validator.validateSpringEL(getProgressiveRender())) {
2457             String currentValues[] = {"progressiveRender =" + getProgressiveRender()};
2458             tracer.createError("ProgressiveRender must follow the Spring EL @{} format", currentValues);
2459         }
2460 
2461         // Check for valid Spring EL format for conditionalRefresh
2462         if (!Validator.validateSpringEL(getConditionalRefresh())) {
2463             String currentValues[] = {"conditionalRefresh =" + getConditionalRefresh()};
2464             tracer.createError("conditionalRefresh must follow the Spring EL @{} format", currentValues);
2465         }
2466     }
2467 }