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