001    /**
002     * Copyright 2005-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.uif.component;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
020    import org.kuali.rice.krad.datadictionary.uif.UifDictionaryBeanBase;
021    import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
022    import org.kuali.rice.krad.datadictionary.validator.Validator;
023    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
024    import org.kuali.rice.krad.uif.CssConstants;
025    import org.kuali.rice.krad.uif.control.ControlBase;
026    import org.kuali.rice.krad.uif.modifier.ComponentModifier;
027    import org.kuali.rice.krad.uif.service.ExpressionEvaluatorService;
028    import org.kuali.rice.krad.uif.util.ExpressionUtils;
029    import org.kuali.rice.krad.uif.util.ScriptUtils;
030    import org.kuali.rice.krad.uif.view.View;
031    import org.kuali.rice.krad.uif.widget.Tooltip;
032    import org.kuali.rice.krad.util.ObjectUtils;
033    
034    import java.util.ArrayList;
035    import java.util.HashMap;
036    import java.util.List;
037    import java.util.Map;
038    
039    /**
040     * Base implementation of <code>Component</code> which other component
041     * implementations should extend
042     *
043     * <p>
044     * Provides base component properties such as id and template. Also provides
045     * default implementation for the <code>ScriptEventSupport</code> and
046     * <code>Ordered</code> interfaces. By default no script events except the
047     * onDocumentReady are supported.
048     * </p>
049     *
050     * @author Kuali Rice Team (rice.collab@kuali.org)
051     */
052    public abstract class ComponentBase extends UifDictionaryBeanBase implements Component {
053        private static final long serialVersionUID = -4449335748129894350L;
054    
055        private String id;
056        private String baseId;
057        private String template;
058        private String templateName;
059    
060        private String title;
061    
062        private boolean render;
063    
064        @KeepExpression
065        private String progressiveRender;
066        private boolean progressiveRenderViaAJAX;
067        private boolean progressiveRenderAndRefresh;
068        private List<String> progressiveDisclosureControlNames;
069        private String progressiveDisclosureConditionJs;
070    
071        @KeepExpression
072        private String conditionalRefresh;
073        private String conditionalRefreshConditionJs;
074        private List<String> conditionalRefreshControlNames;
075    
076        private List<String> refreshWhenChangedPropertyNames;
077        private List<String> additionalComponentsToRefresh;
078        private String additionalComponentsToRefreshJs;
079        private boolean refreshedByAction;
080        private boolean disclosedByAction;
081    
082        private int refreshTimer;
083    
084        private boolean resetDataOnRefresh;
085        private String methodToCallOnRefresh;
086    
087        private boolean hidden;
088        private boolean readOnly;
089        private Boolean required;
090    
091        private String align;
092        private String valign;
093        private String width;
094    
095        //optional table-backed layout options
096        private int colSpan;
097        private int rowSpan;
098        private List<String> cellCssClasses;
099    
100        private String style;
101        private List<String> cssClasses;
102    
103        private Tooltip toolTip;
104    
105        private int order;
106    
107        private boolean skipInTabOrder;
108    
109        private String finalizeMethodToCall;
110        private List<Object> finalizeMethodAdditionalArguments;
111        private MethodInvokerConfig finalizeMethodInvoker;
112    
113        private boolean selfRendered;
114        private String renderedHtmlOutput;
115    
116        private boolean disableSessionPersistence;
117        private boolean forceSessionPersistence;
118    
119        private ComponentSecurity componentSecurity;
120    
121        private String onLoadScript;
122        private String onUnloadScript;
123        private String onCloseScript;
124        private String onBlurScript;
125        private String onChangeScript;
126        private String onClickScript;
127        private String onDblClickScript;
128        private String onFocusScript;
129        private String onSubmitScript;
130        private String onKeyPressScript;
131        private String onKeyUpScript;
132        private String onKeyDownScript;
133        private String onMouseOverScript;
134        private String onMouseOutScript;
135        private String onMouseUpScript;
136        private String onMouseDownScript;
137        private String onMouseMoveScript;
138        private String onDocumentReadyScript;
139    
140        private List<ComponentModifier> componentModifiers;
141    
142        private Map<String, String> templateOptions;
143        private String templateOptionsJSString;
144    
145        @ReferenceCopy(newCollectionInstance = true)
146        private transient Map<String, Object> context;
147    
148        private List<PropertyReplacer> propertyReplacers;
149    
150        private Map<String, String> dataAttributes;
151    
152        public ComponentBase() {
153            super();
154    
155            order = 0;
156            colSpan = 1;
157            rowSpan = 1;
158    
159            render = true;
160            selfRendered = false;
161            progressiveRenderViaAJAX = false;
162            progressiveRenderAndRefresh = false;
163            refreshedByAction = false;
164            resetDataOnRefresh = false;
165            disableSessionPersistence = false;
166            forceSessionPersistence = false;
167    
168            componentSecurity = ObjectUtils.newInstance(getComponentSecurityClass());
169    
170            refreshWhenChangedPropertyNames = new ArrayList<String>();
171            additionalComponentsToRefresh = new ArrayList<String>();
172            finalizeMethodAdditionalArguments = new ArrayList<Object>();
173            cssClasses = new ArrayList<String>();
174            componentModifiers = new ArrayList<ComponentModifier>();
175            templateOptions = new HashMap<String, String>();
176            context = new HashMap<String, Object>();
177            propertyReplacers = new ArrayList<PropertyReplacer>();
178            dataAttributes = new HashMap<String, String>();
179        }
180    
181        /**
182         * The following updates are done here:
183         *
184         * <ul>
185         * <li></li>
186         * </ul>
187         *
188         * @see Component#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
189         */
190        public void performInitialization(View view, Object model) {
191    
192        }
193    
194        /**
195         * The following updates are done here:
196         *
197         * <ul>
198         * <li>Evaluate the progressive render condition (if set) and combine with the current render status to set the
199         * render status</li>
200         * </ul>
201         *
202         * @see Component#performApplyModel(org.kuali.rice.krad.uif.view.View, java.lang.Object,
203         *      org.kuali.rice.krad.uif.component.Component)
204         */
205        public void performApplyModel(View view, Object model, Component parent) {
206            if (this.render && StringUtils.isNotEmpty(progressiveRender)) {
207                // progressive anded with render, will not render at least one of the two are false
208                ExpressionEvaluatorService expressionEvaluatorService =
209                        KRADServiceLocatorWeb.getExpressionEvaluatorService();
210                String adjustedProgressiveRender = expressionEvaluatorService.replaceBindingPrefixes(view, this,
211                        progressiveRender);
212                Boolean progRenderEval = (Boolean) expressionEvaluatorService.evaluateExpression(model, context,
213                        adjustedProgressiveRender);
214    
215                this.setRender(progRenderEval);
216            }
217        }
218    
219        /**
220         * The following finalization is done here:
221         *
222         * <ul>
223         * <li>progressiveRender and conditionalRefresh variables are processed if set</li>
224         * <li>If any of the style properties were given, sets the style string on
225         * the style property</li>
226         * <li>Set the skipInTabOrder flag for nested components</li>
227         * </ul>
228         *
229         * @see Component#performFinalize(org.kuali.rice.krad.uif.view.View, java.lang.Object,
230         *      org.kuali.rice.krad.uif.component.Component)
231         */
232        public void performFinalize(View view, Object model, Component parent) {
233            if (StringUtils.isNotEmpty(progressiveRender)) {
234                progressiveRender = KRADServiceLocatorWeb.getExpressionEvaluatorService().replaceBindingPrefixes(view, this,
235                        progressiveRender);
236                progressiveDisclosureControlNames = new ArrayList<String>();
237                progressiveDisclosureConditionJs = ExpressionUtils.parseExpression(progressiveRender,
238                        progressiveDisclosureControlNames);
239            }
240    
241            if (StringUtils.isNotEmpty(conditionalRefresh)) {
242                conditionalRefresh = KRADServiceLocatorWeb.getExpressionEvaluatorService().replaceBindingPrefixes(view,
243                        this, conditionalRefresh);
244                conditionalRefreshControlNames = new ArrayList<String>();
245                conditionalRefreshConditionJs = ExpressionUtils.parseExpression(conditionalRefresh,
246                        conditionalRefreshControlNames);
247            }
248    
249            List<String> adjustedRefreshPropertyNames = new ArrayList<String>();
250            for (String refreshPropertyName : refreshWhenChangedPropertyNames) {
251                adjustedRefreshPropertyNames.add(
252                        KRADServiceLocatorWeb.getExpressionEvaluatorService().replaceBindingPrefixes(view, this,
253                                refreshPropertyName));
254            }
255            refreshWhenChangedPropertyNames = adjustedRefreshPropertyNames;
256    
257            // add the align, valign, and width settings to style
258            if (StringUtils.isNotBlank(getAlign()) && !StringUtils.contains(getStyle(), CssConstants.TEXT_ALIGN)) {
259                appendToStyle(CssConstants.TEXT_ALIGN + getAlign() + ";");
260            }
261    
262            if (StringUtils.isNotBlank(getValign()) && !StringUtils.contains(getStyle(), CssConstants.VERTICAL_ALIGN)) {
263                appendToStyle(CssConstants.VERTICAL_ALIGN + getValign() + ";");
264            }
265    
266            if (StringUtils.isNotBlank(getWidth()) && !StringUtils.contains(getStyle(), CssConstants.WIDTH)) {
267                appendToStyle(CssConstants.WIDTH + getWidth() + ";");
268            }
269    
270            // Set the skipInTabOrder flag on all nested components
271            // Set the tabIndex on controls to -1 in order to be skipped on tabbing
272            for (Component component : getComponentsForLifecycle()) {
273                if (component != null && component instanceof ComponentBase && skipInTabOrder) {
274                    ((ComponentBase) component).setSkipInTabOrder(skipInTabOrder);
275                    if (component instanceof ControlBase) {
276                        ((ControlBase) component).setTabIndex(-1);
277                    }
278                }
279            }
280    
281            // if this is not rendering and it is not rendering via an ajax call, but still has a progressive render
282            // condition we still want to render the component, but hide it (in ajax cases, template creates a placeholder)
283            boolean hide = false;
284            if (!this.render && !this.progressiveRenderViaAJAX && !this.progressiveRenderAndRefresh && StringUtils
285                    .isNotBlank(progressiveRender)) {
286                hide = true;
287            } else if (this.isHidden()) {
288                hide = true;
289            }
290    
291            if (hide) {
292                if (StringUtils.isNotBlank(this.getStyle())) {
293                    if (this.getStyle().endsWith(";")) {
294                        this.setStyle(this.getStyle() + " display: none;");
295                    } else {
296                        this.setStyle(this.getStyle() + "; display: none;");
297                    }
298                } else {
299                    this.setStyle("display: none;");
300                }
301            }
302        }
303    
304        /**
305         * @see org.kuali.rice.krad.uif.component.Component#getComponentsForLifecycle()
306         */
307        public List<Component> getComponentsForLifecycle() {
308            List<Component> components = new ArrayList<Component>();
309    
310            components.add(toolTip);
311    
312            return components;
313        }
314    
315        /**
316         * @see org.kuali.rice.krad.uif.component.Component#getComponentPrototypes()
317         */
318        public List<Component> getComponentPrototypes() {
319            List<Component> components = new ArrayList<Component>();
320    
321            for (ComponentModifier modifier : componentModifiers) {
322                components.addAll(modifier.getComponentPrototypes());
323            }
324    
325            components.addAll(getPropertyReplacerComponents());
326    
327            return components;
328        }
329    
330        /**
331         * Returns list of components that are being held in property replacers configured for this component
332         *
333         * @return List<Component>
334         */
335        public List<Component> getPropertyReplacerComponents() {
336            List<Component> components = new ArrayList<Component>();
337            for (Object replacer : propertyReplacers) {
338                components.addAll(((PropertyReplacer) replacer).getNestedComponents());
339            }
340    
341            return components;
342        }
343    
344        /**
345         * @see org.kuali.rice.krad.uif.component.Component#getId()
346         */
347        @BeanTagAttribute(name = "id")
348        public String getId() {
349            return this.id;
350        }
351    
352        /**
353         * @see org.kuali.rice.krad.uif.component.Component#setId(java.lang.String)
354         */
355        public void setId(String id) {
356            this.id = id;
357        }
358    
359        /**
360         * @see org.kuali.rice.krad.uif.component.Component#getBaseId()
361         */
362        public String getBaseId() {
363            return this.baseId;
364        }
365    
366        /**
367         * @see org.kuali.rice.krad.uif.component.Component#setBaseId(java.lang.String)
368         */
369        public void setBaseId(String baseId) {
370            this.baseId = baseId;
371        }
372    
373        /**
374         * @see org.kuali.rice.krad.uif.component.Component#getTemplate()
375         */
376        @BeanTagAttribute(name = "template")
377        public String getTemplate() {
378            return this.template;
379        }
380    
381        /**
382         * @see org.kuali.rice.krad.uif.component.Component#setTemplate(java.lang.String)
383         */
384        public void setTemplate(String template) {
385            this.template = template;
386        }
387    
388        @BeanTagAttribute(name = "templateName")
389        public String getTemplateName() {
390            return templateName;
391        }
392    
393        public void setTemplateName(String templateName) {
394            this.templateName = templateName;
395        }
396    
397        /**
398         * @see org.kuali.rice.krad.uif.component.Component#getTitle()
399         */
400        @BeanTagAttribute(name = "title")
401        public String getTitle() {
402            return this.title;
403        }
404    
405        /**
406         * @see org.kuali.rice.krad.uif.component.Component#setTitle(java.lang.String)
407         */
408        public void setTitle(String title) {
409            this.title = title;
410        }
411    
412        /**
413         * @see org.kuali.rice.krad.uif.component.Component#isHidden()
414         */
415        @BeanTagAttribute(name = "hidden")
416        public boolean isHidden() {
417            return this.hidden;
418        }
419    
420        /**
421         * @see org.kuali.rice.krad.uif.component.Component#setHidden(boolean)
422         */
423        public void setHidden(boolean hidden) {
424            this.hidden = hidden;
425        }
426    
427        /**
428         * @see org.kuali.rice.krad.uif.component.Component#isReadOnly()
429         */
430        @BeanTagAttribute(name = "readOnly")
431        public boolean isReadOnly() {
432            return this.readOnly;
433        }
434    
435        /**
436         * @see org.kuali.rice.krad.uif.component.Component#setReadOnly(boolean)
437         */
438        public void setReadOnly(boolean readOnly) {
439            this.readOnly = readOnly;
440        }
441    
442        /**
443         * @see org.kuali.rice.krad.uif.component.Component#getRequired()
444         */
445        @BeanTagAttribute(name = "required")
446        public Boolean getRequired() {
447            return this.required;
448        }
449    
450        /**
451         * @see org.kuali.rice.krad.uif.component.Component#setRequired(java.lang.Boolean)
452         */
453        public void setRequired(Boolean required) {
454            this.required = required;
455        }
456    
457        /**
458         * @see org.kuali.rice.krad.uif.component.Component#isRender()
459         */
460        @BeanTagAttribute(name = "render")
461        public boolean isRender() {
462            return this.render;
463        }
464    
465        /**
466         * @see org.kuali.rice.krad.uif.component.Component#setRender(boolean)
467         */
468        public void setRender(boolean render) {
469            this.render = render;
470        }
471    
472        /**
473         * @see org.kuali.rice.krad.uif.component.Component#getColSpan()
474         */
475        @BeanTagAttribute(name = "ColSpan")
476        public int getColSpan() {
477            return this.colSpan;
478        }
479    
480        /**
481         * @see org.kuali.rice.krad.uif.component.Component#setColSpan(int)
482         */
483        public void setColSpan(int colSpan) {
484            this.colSpan = colSpan;
485        }
486    
487        /**
488         * @see org.kuali.rice.krad.uif.component.Component#getRowSpan()
489         */
490        @BeanTagAttribute(name = "rowSpan")
491        public int getRowSpan() {
492            return this.rowSpan;
493        }
494    
495        /**
496         * @see org.kuali.rice.krad.uif.component.Component#setRowSpan(int)
497         */
498        public void setRowSpan(int rowSpan) {
499            this.rowSpan = rowSpan;
500        }
501    
502        /**
503         * @see org.kuali.rice.krad.uif.component.Component#getCellCssClasses()
504         */
505        public List<String> getCellCssClasses() {
506            return cellCssClasses;
507        }
508    
509        /**
510         * @see Component#setCellCssClasses(java.util.List)
511         */
512        public void setCellCssClasses(List<String> cellCssClasses) {
513            this.cellCssClasses = cellCssClasses;
514        }
515    
516        /**
517         * @see Component#addCellCssClass(String)
518         */
519        public void addCellCssClass(String cssClass) {
520            if (this.cellCssClasses == null){
521                this.cellCssClasses = new ArrayList<String>();
522            }
523    
524            if(cssClass != null){
525                this.cellCssClasses.add(cssClass);
526            }
527        }
528    
529        /**
530         * Builds the HTML class attribute string by combining the cellStyleClasses list
531         * with a space delimiter
532         *
533         * @return String class attribute string
534         */
535        public String getCellStyleClassesAsString() {
536            if (cellCssClasses != null) {
537                return StringUtils.join(cellCssClasses, " ");
538            }
539    
540            return "";
541        }
542    
543        /**
544         * Horizontal alignment of the component within its container
545         * <p>
546         * All components belong to a <code>Container</code> and are placed using a
547         * <code>LayoutManager</code>. This property specifies how the component
548         * should be aligned horizontally within the container. During the finalize
549         * phase the CSS text-align style will be created for the align setting.
550         * </p>
551         *
552         * @return String horizontal align
553         * @see org.kuali.rice.krad.uif.CssConstants.TextAligns
554         */
555        @BeanTagAttribute(name = "align")
556        public String getAlign() {
557            return this.align;
558        }
559    
560        /**
561         * Sets the components horizontal alignment
562         *
563         * @param align
564         */
565        public void setAlign(String align) {
566            this.align = align;
567        }
568    
569        /**
570         * Vertical alignment of the component within its container
571         *
572         * <p>
573         * All components belong to a <code>Container</code> and are placed using a
574         * <code>LayoutManager</code>. This property specifies how the component
575         * should be aligned vertically within the container. During the finalize
576         * phase the CSS vertical-align style will be created for the valign
577         * setting.
578         * </p>
579         *
580         * @return String vertical align
581         * @see org.kuali.rice.krad.uif.CssConstants.VerticalAligns
582         */
583        @BeanTagAttribute(name = "valign")
584        public String getValign() {
585            return this.valign;
586        }
587    
588        /**
589         * Setter for the component's vertical align
590         *
591         * @param valign
592         */
593        public void setValign(String valign) {
594            this.valign = valign;
595        }
596    
597        /**
598         * Width the component should take up in the container
599         * <p>
600         * All components belong to a <code>Container</code> and are placed using a
601         * <code>LayoutManager</code>. This property specifies a width the component
602         * should take up in the Container. This is not applicable for all layout
603         * managers. During the finalize phase the CSS width style will be created
604         * for the width setting.
605         * </p>
606         * <p>
607         * e.g. '30%', '55px'
608         * </p>
609         *
610         * @return String width string
611         */
612        @BeanTagAttribute(name = "width")
613        public String getWidth() {
614            return this.width;
615        }
616    
617        /**
618         * Setter for the components width
619         *
620         * @param width
621         */
622        public void setWidth(String width) {
623            this.width = width;
624        }
625    
626        /**
627         * @see org.kuali.rice.krad.uif.component.Component#getStyle()
628         */
629        @BeanTagAttribute(name = "style")
630        public String getStyle() {
631            return this.style;
632        }
633    
634        /**
635         * @see org.kuali.rice.krad.uif.component.Component#setStyle(java.lang.String)
636         */
637        public void setStyle(String style) {
638            this.style = style;
639        }
640    
641        /**
642         * @see org.kuali.rice.krad.uif.component.Component#getCssClasses()
643         */
644        @BeanTagAttribute(name = "cssClasses", type = BeanTagAttribute.AttributeType.LISTVALUE)
645        public List<String> getCssClasses() {
646            return this.cssClasses;
647        }
648    
649        /**
650         * @see org.kuali.rice.krad.uif.component.Component#setCssClasses(java.util.List)
651         */
652        public void setCssClasses(List<String> cssClasses) {
653            this.cssClasses = cssClasses;
654        }
655    
656        /**
657         * Builds the HTML class attribute string by combining the styleClasses list
658         * with a space delimiter
659         *
660         * @return String class attribute string
661         */
662        public String getStyleClassesAsString() {
663            if (cssClasses != null) {
664                return StringUtils.join(cssClasses, " ");
665            }
666    
667            return "";
668        }
669    
670        /**
671         * @see org.kuali.rice.krad.uif.component.Component#addStyleClass(java.lang.String)
672         */
673        public void addStyleClass(String styleClass) {
674            if (!cssClasses.contains(styleClass)) {
675                cssClasses.add(styleClass);
676            }
677        }
678    
679        /**
680         * @see org.kuali.rice.krad.uif.component.Component#appendToStyle(java.lang.String)
681         */
682        public void appendToStyle(String styleRules) {
683            if (style == null) {
684                style = "";
685            }
686            style = style + styleRules;
687        }
688    
689        /**
690         * @see org.kuali.rice.krad.uif.component.Component#getFinalizeMethodToCall()
691         */
692        @BeanTagAttribute(name = "finalizeMethodToCall")
693        public String getFinalizeMethodToCall() {
694            return this.finalizeMethodToCall;
695        }
696    
697        /**
698         * Setter for the finalize method
699         *
700         * @param finalizeMethodToCall
701         */
702        public void setFinalizeMethodToCall(String finalizeMethodToCall) {
703            this.finalizeMethodToCall = finalizeMethodToCall;
704        }
705    
706        /**
707         * @see org.kuali.rice.krad.uif.component.Component#getFinalizeMethodAdditionalArguments()
708         */
709        @BeanTagAttribute(name = "finalizeMethodAdditionalArguments", type = BeanTagAttribute.AttributeType.LISTBEAN)
710        public List<Object> getFinalizeMethodAdditionalArguments() {
711            return finalizeMethodAdditionalArguments;
712        }
713    
714        /**
715         * Setter for the finalize additional arguments list
716         *
717         * @param finalizeMethodAdditionalArguments
718         */
719        public void setFinalizeMethodAdditionalArguments(List<Object> finalizeMethodAdditionalArguments) {
720            this.finalizeMethodAdditionalArguments = finalizeMethodAdditionalArguments;
721        }
722    
723        /**
724         * @see org.kuali.rice.krad.uif.component.Component#getFinalizeMethodInvoker()
725         */
726        @BeanTagAttribute(name = "finalizeMethodInvoker", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
727        public MethodInvokerConfig getFinalizeMethodInvoker() {
728            return this.finalizeMethodInvoker;
729        }
730    
731        /**
732         * Setter for the method invoker instance
733         *
734         * @param finalizeMethodInvoker
735         */
736        public void setFinalizeMethodInvoker(MethodInvokerConfig finalizeMethodInvoker) {
737            this.finalizeMethodInvoker = finalizeMethodInvoker;
738        }
739    
740        /**
741         * @see org.kuali.rice.krad.uif.component.Component#isSelfRendered()
742         */
743        @BeanTagAttribute(name = "selfRendered")
744        public boolean isSelfRendered() {
745            return this.selfRendered;
746        }
747    
748        /**
749         * @see org.kuali.rice.krad.uif.component.Component#setSelfRendered(boolean)
750         */
751        public void setSelfRendered(boolean selfRendered) {
752            this.selfRendered = selfRendered;
753        }
754    
755        /**
756         * @see org.kuali.rice.krad.uif.component.Component#getRenderedHtmlOutput()
757         */
758        @BeanTagAttribute(name = "renderedHtmlOutput")
759        public String getRenderedHtmlOutput() {
760            return this.renderedHtmlOutput;
761        }
762    
763        /**
764         * @see org.kuali.rice.krad.uif.component.Component#setRenderedHtmlOutput(java.lang.String)
765         */
766        public void setRenderedHtmlOutput(String renderedHtmlOutput) {
767            this.renderedHtmlOutput = renderedHtmlOutput;
768        }
769    
770        /**
771         * @see Component#isDisableSessionPersistence()
772         */
773        @BeanTagAttribute(name = "disableSessionPersistence")
774        public boolean isDisableSessionPersistence() {
775            return disableSessionPersistence;
776        }
777    
778        /**
779         * @see Component#setDisableSessionPersistence(boolean)
780         */
781        public void setDisableSessionPersistence(boolean disableSessionPersistence) {
782            this.disableSessionPersistence = disableSessionPersistence;
783        }
784    
785        /**
786         * @see Component#isForceSessionPersistence()
787         */
788        @BeanTagAttribute(name = "forceSessionPersistence")
789        public boolean isForceSessionPersistence() {
790            return forceSessionPersistence;
791        }
792    
793        /**
794         * @see Component#setForceSessionPersistence(boolean)
795         */
796        public void setForceSessionPersistence(boolean forceSessionPersistence) {
797            this.forceSessionPersistence = forceSessionPersistence;
798        }
799    
800        /**
801         * @see Component#getComponentSecurity()
802         */
803        @BeanTagAttribute(name = "componentSecurity", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
804        public ComponentSecurity getComponentSecurity() {
805            return componentSecurity;
806        }
807    
808        /**
809         * @see Component#setComponentSecurity(org.kuali.rice.krad.uif.component.ComponentSecurity)
810         */
811        public void setComponentSecurity(ComponentSecurity componentSecurity) {
812            this.componentSecurity = componentSecurity;
813        }
814    
815        /**
816         * Returns the security class that is associated with the component (used for initialization and validation)
817         *
818         * @return Class<? extends ComponentSecurity>
819         */
820        protected Class<? extends ComponentSecurity> getComponentSecurityClass() {
821            return ComponentSecurity.class;
822        }
823    
824        /**
825         * @see org.kuali.rice.krad.uif.component.Component#getComponentModifiers()
826         */
827        @BeanTagAttribute(name = "componentModifiers", type = BeanTagAttribute.AttributeType.LISTBEAN)
828        public List<ComponentModifier> getComponentModifiers() {
829            return this.componentModifiers;
830        }
831    
832        /**
833         * @see org.kuali.rice.krad.uif.component.Component#setComponentModifiers(java.util.List)
834         */
835        public void setComponentModifiers(List<ComponentModifier> componentModifiers) {
836            this.componentModifiers = componentModifiers;
837        }
838    
839        /**
840         * @see org.kuali.rice.krad.uif.component.Component#getContext()
841         */
842        @BeanTagAttribute(name = "context", type = BeanTagAttribute.AttributeType.MAPBEAN)
843        public Map<String, Object> getContext() {
844            return this.context;
845        }
846    
847        /**
848         * @see org.kuali.rice.krad.uif.component.Component#setContext(java.util.Map)
849         */
850        public void setContext(Map<String, Object> context) {
851            this.context = context;
852        }
853    
854        /**
855         * @see org.kuali.rice.krad.uif.component.Component#pushObjectToContext(java.lang.String,
856         *      java.lang.Object)
857         */
858        public void pushObjectToContext(String objectName, Object object) {
859            if (this.context == null) {
860                this.context = new HashMap<String, Object>();
861            }
862            pushToPropertyReplacerContext(objectName, object);
863            this.context.put(objectName, object);
864        }
865    
866        /*
867        * Adds the object to the context of the components in the
868        * PropertyReplacer object. Only checks for a list, map or component.
869        */
870        protected void pushToPropertyReplacerContext(String objectName, Object object) {
871            for (Component replacerComponent : getPropertyReplacerComponents()) {
872                replacerComponent.pushObjectToContext(objectName, object);
873            }
874        }
875    
876        /**
877         * @see org.kuali.rice.krad.uif.component.ComponentBase#pushAllToContext
878         */
879        public void pushAllToContext(Map<String, Object> objects) {
880            if (objects != null) {
881                for (Map.Entry<String, Object> objectEntry : objects.entrySet()) {
882                    pushObjectToContext(objectEntry.getKey(), objectEntry.getValue());
883                }
884            }
885        }
886    
887        /**
888         * @see org.kuali.rice.krad.uif.component.Component#getPropertyReplacers()
889         */
890        @BeanTagAttribute(name = "propertyReplacers", type = BeanTagAttribute.AttributeType.LISTBEAN)
891        public List<PropertyReplacer> getPropertyReplacers() {
892            return this.propertyReplacers;
893        }
894    
895        /**
896         * @see org.kuali.rice.krad.uif.component.Component#setPropertyReplacers(java.util.List)
897         */
898        public void setPropertyReplacers(List<PropertyReplacer> propertyReplacers) {
899            this.propertyReplacers = propertyReplacers;
900        }
901    
902        /**
903         * @see org.springframework.core.Ordered#getOrder()
904         */
905        @BeanTagAttribute(name = "order")
906        public int getOrder() {
907            return this.order;
908        }
909    
910        /**
911         * Setter for the component's order
912         *
913         * @param order
914         */
915        public void setOrder(int order) {
916            this.order = order;
917        }
918    
919        /**
920         * @see org.kuali.rice.krad.uif.component.Component#getToolTip()
921         */
922        @BeanTagAttribute(name = "toolTip", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
923        public Tooltip getToolTip() {
924            return toolTip;
925        }
926    
927        /**
928         * @see org.kuali.rice.krad.uif.component.Component#setToolTip(Tooltip)
929         */
930        public void setToolTip(Tooltip toolTip) {
931            this.toolTip = toolTip;
932        }
933    
934        /**
935         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnLoadScript()
936         */
937        @BeanTagAttribute(name = "onLoadScript")
938        public String getOnLoadScript() {
939            return onLoadScript;
940        }
941    
942        /**
943         * Setter for the components onLoad script
944         *
945         * @param onLoadScript
946         */
947        public void setOnLoadScript(String onLoadScript) {
948            this.onLoadScript = onLoadScript;
949        }
950    
951        /**
952         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnDocumentReadyScript()
953         */
954        @BeanTagAttribute(name = "onDocumentReadyScript")
955        public String getOnDocumentReadyScript() {
956            String onDocScript = this.onDocumentReadyScript;
957            // if the refreshTimer property has been set then pre-append the call to refreshComponetUsingTimer to the onDocumentReadyScript.
958            // if the refreshTimer property is set then the methodToCallOnRefresh should also be set.
959            if (refreshTimer > 0) {
960                onDocScript = (null == onDocScript) ? "" : onDocScript;
961                onDocScript = "refreshComponentUsingTimer('"
962                        + this.id
963                        + "','"
964                        + this.methodToCallOnRefresh
965                        + "',"
966                        + refreshTimer
967                        + ");"
968                        + onDocScript;
969            }
970            return onDocScript;
971        }
972    
973        /**
974         * Setter for the components onDocumentReady script
975         *
976         * @param onDocumentReadyScript
977         */
978        public void setOnDocumentReadyScript(String onDocumentReadyScript) {
979            this.onDocumentReadyScript = onDocumentReadyScript;
980        }
981    
982        /**
983         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnUnloadScript()
984         */
985        @BeanTagAttribute(name = "onUnloadScript")
986        public String getOnUnloadScript() {
987            return onUnloadScript;
988        }
989    
990        /**
991         * Setter for the components onUnload script
992         *
993         * @param onUnloadScript
994         */
995        public void setOnUnloadScript(String onUnloadScript) {
996            this.onUnloadScript = onUnloadScript;
997        }
998    
999        /**
1000         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnCloseScript()
1001         */
1002        @BeanTagAttribute(name = "onCloseScript")
1003        public String getOnCloseScript() {
1004            return onCloseScript;
1005        }
1006    
1007        /**
1008         * Setter for the components onClose script
1009         *
1010         * @param onCloseScript
1011         */
1012        public void setOnCloseScript(String onCloseScript) {
1013            this.onCloseScript = onCloseScript;
1014        }
1015    
1016        /**
1017         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnBlurScript()
1018         */
1019        @BeanTagAttribute(name = "onBlurScript")
1020        public String getOnBlurScript() {
1021            return onBlurScript;
1022        }
1023    
1024        /**
1025         * Setter for the components onBlur script
1026         *
1027         * @param onBlurScript
1028         */
1029        public void setOnBlurScript(String onBlurScript) {
1030            this.onBlurScript = onBlurScript;
1031        }
1032    
1033        /**
1034         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnChangeScript()
1035         */
1036        @BeanTagAttribute(name = "onChangeScript")
1037        public String getOnChangeScript() {
1038            return onChangeScript;
1039        }
1040    
1041        /**
1042         * Setter for the components onChange script
1043         *
1044         * @param onChangeScript
1045         */
1046        public void setOnChangeScript(String onChangeScript) {
1047            this.onChangeScript = onChangeScript;
1048        }
1049    
1050        /**
1051         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnClickScript()
1052         */
1053        @BeanTagAttribute(name = "onClickScript")
1054        public String getOnClickScript() {
1055            return onClickScript;
1056        }
1057    
1058        /**
1059         * Setter for the components onClick script
1060         *
1061         * @param onClickScript
1062         */
1063        public void setOnClickScript(String onClickScript) {
1064            this.onClickScript = onClickScript;
1065        }
1066    
1067        /**
1068         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnDblClickScript()
1069         */
1070        @BeanTagAttribute(name = "onDblClickScript")
1071        public String getOnDblClickScript() {
1072            return onDblClickScript;
1073        }
1074    
1075        /**
1076         * Setter for the components onDblClick script
1077         *
1078         * @param onDblClickScript
1079         */
1080        public void setOnDblClickScript(String onDblClickScript) {
1081            this.onDblClickScript = onDblClickScript;
1082        }
1083    
1084        /**
1085         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnFocusScript()
1086         */
1087        @BeanTagAttribute(name = "onFocusScript")
1088        public String getOnFocusScript() {
1089            return onFocusScript;
1090        }
1091    
1092        /**
1093         * Setter for the components onFocus script
1094         *
1095         * @param onFocusScript
1096         */
1097        public void setOnFocusScript(String onFocusScript) {
1098            this.onFocusScript = onFocusScript;
1099        }
1100    
1101        /**
1102         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnSubmitScript()
1103         */
1104        @BeanTagAttribute(name = "onSubmitScript")
1105        public String getOnSubmitScript() {
1106            return onSubmitScript;
1107        }
1108    
1109        /**
1110         * Setter for the components onSubmit script
1111         *
1112         * @param onSubmitScript
1113         */
1114        public void setOnSubmitScript(String onSubmitScript) {
1115            this.onSubmitScript = onSubmitScript;
1116        }
1117    
1118        /**
1119         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyPressScript()
1120         */
1121        @BeanTagAttribute(name = "onKeyPressScript")
1122        public String getOnKeyPressScript() {
1123            return onKeyPressScript;
1124        }
1125    
1126        /**
1127         * Setter for the components onKeyPress script
1128         *
1129         * @param onKeyPressScript
1130         */
1131        public void setOnKeyPressScript(String onKeyPressScript) {
1132            this.onKeyPressScript = onKeyPressScript;
1133        }
1134    
1135        /**
1136         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyUpScript()
1137         */
1138        @BeanTagAttribute(name = "onKeyUpScript")
1139        public String getOnKeyUpScript() {
1140            return onKeyUpScript;
1141        }
1142    
1143        /**
1144         * Setter for the components onKeyUp script
1145         *
1146         * @param onKeyUpScript
1147         */
1148        public void setOnKeyUpScript(String onKeyUpScript) {
1149            this.onKeyUpScript = onKeyUpScript;
1150        }
1151    
1152        /**
1153         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyDownScript()
1154         */
1155        @BeanTagAttribute(name = "onKeyDownScript")
1156        public String getOnKeyDownScript() {
1157            return onKeyDownScript;
1158        }
1159    
1160        /**
1161         * Setter for the components onKeyDown script
1162         *
1163         * @param onKeyDownScript
1164         */
1165        public void setOnKeyDownScript(String onKeyDownScript) {
1166            this.onKeyDownScript = onKeyDownScript;
1167        }
1168    
1169        /**
1170         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseOverScript()
1171         */
1172        @BeanTagAttribute(name = "onMouseOverScript")
1173        public String getOnMouseOverScript() {
1174            return onMouseOverScript;
1175        }
1176    
1177        /**
1178         * Setter for the components onMouseOver script
1179         *
1180         * @param onMouseOverScript
1181         */
1182        public void setOnMouseOverScript(String onMouseOverScript) {
1183            this.onMouseOverScript = onMouseOverScript;
1184        }
1185    
1186        /**
1187         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseOutScript()
1188         */
1189        @BeanTagAttribute(name = "onMouseOutScript")
1190        public String getOnMouseOutScript() {
1191            return onMouseOutScript;
1192        }
1193    
1194        /**
1195         * Setter for the components onMouseOut script
1196         *
1197         * @param onMouseOutScript
1198         */
1199        public void setOnMouseOutScript(String onMouseOutScript) {
1200            this.onMouseOutScript = onMouseOutScript;
1201        }
1202    
1203        /**
1204         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseUpScript()
1205         */
1206        @BeanTagAttribute(name = "onMouseUpScript")
1207        public String getOnMouseUpScript() {
1208            return onMouseUpScript;
1209        }
1210    
1211        /**
1212         * Setter for the components onMouseUp script
1213         *
1214         * @param onMouseUpScript
1215         */
1216        public void setOnMouseUpScript(String onMouseUpScript) {
1217            this.onMouseUpScript = onMouseUpScript;
1218        }
1219    
1220        /**
1221         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseDownScript()
1222         */
1223        @BeanTagAttribute(name = "onMouseDownScript")
1224        public String getOnMouseDownScript() {
1225            return onMouseDownScript;
1226        }
1227    
1228        /**
1229         * Setter for the components onMouseDown script
1230         *
1231         * @param onMouseDownScript
1232         */
1233        public void setOnMouseDownScript(String onMouseDownScript) {
1234            this.onMouseDownScript = onMouseDownScript;
1235        }
1236    
1237        /**
1238         * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseMoveScript()
1239         */
1240        @BeanTagAttribute(name = "onMouseMoveScript")
1241        public String getOnMouseMoveScript() {
1242            return onMouseMoveScript;
1243        }
1244    
1245        /**
1246         * Setter for the components onMouseMove script
1247         *
1248         * @param onMouseMoveScript
1249         */
1250        public void setOnMouseMoveScript(String onMouseMoveScript) {
1251            this.onMouseMoveScript = onMouseMoveScript;
1252        }
1253    
1254        /**
1255         * @see org.kuali.rice.krad.uif.component.Component#getTemplateOptions()
1256         */
1257        @BeanTagAttribute(name = "templateOptions", type = BeanTagAttribute.AttributeType.MAPVALUE)
1258        public Map<String, String> getTemplateOptions() {
1259            if (templateOptions == null) {
1260                templateOptions = new HashMap<String, String>();
1261            }
1262            return this.templateOptions;
1263        }
1264    
1265        /**
1266         * @see Component#setTemplateOptions(java.util.Map)
1267         */
1268        public void setTemplateOptions(Map<String, String> templateOptions) {
1269            this.templateOptions = templateOptions;
1270        }
1271    
1272        /**
1273         * Builds a string from the underlying <code>Map</code> of template options
1274         * that will export that options as a JavaScript Map for use in js and
1275         * jQuery plugins
1276         *
1277         * @return String of widget options formatted as JS Map
1278         */
1279        @Override
1280        @BeanTagAttribute(name = "templateOptionsJSString")
1281        public String getTemplateOptionsJSString() {
1282            if (templateOptionsJSString != null) {
1283                return templateOptionsJSString;
1284            }
1285    
1286            if (templateOptions == null) {
1287                templateOptions = new HashMap<String, String>();
1288            }
1289            StringBuilder sb = new StringBuilder();
1290    
1291            sb.append("{");
1292    
1293            for (String optionKey : templateOptions.keySet()) {
1294                String optionValue = templateOptions.get(optionKey);
1295    
1296                if (sb.length() > 1) {
1297                    sb.append(",");
1298                }
1299    
1300                sb.append(optionKey);
1301                sb.append(":");
1302    
1303                sb.append(ScriptUtils.convertToJsValue(optionValue));
1304            }
1305    
1306            sb.append("}");
1307    
1308            return sb.toString();
1309        }
1310    
1311        @Override
1312        public void setTemplateOptionsJSString(String templateOptionsJSString) {
1313            this.templateOptionsJSString = templateOptionsJSString;
1314        }
1315    
1316        /**
1317         * When set if the condition is satisfied, the component will be displayed. The component MUST BE a
1318         * container or field type. progressiveRender is defined in a limited Spring EL syntax. Only valid
1319         * form property names, and, or, logical comparison operators (non-arithmetic), and the matches
1320         * clause are allowed. String and regex values must use single quotes ('), booleans must be either true or false,
1321         * numbers must be a valid double, either negative or positive.
1322         *
1323         * <p>
1324         * DO NOT use progressiveRender and a conditional refresh statement on the same component
1325         * unless it is known that the component will always be visible in all cases when a conditional refresh happens
1326         * (ie conditional refresh has progressiveRender's condition anded with its own condition).
1327         * </p>
1328         *
1329         * <p>
1330         * <b>If a component should be refreshed every time it is shown, use the progressiveRenderAndRefresh option
1331         * with this property instead.</b>
1332         * </p>
1333         *
1334         * @return String progressiveRender expression
1335         */
1336        @BeanTagAttribute(name = "progressiveRender")
1337        public String getProgressiveRender() {
1338            return this.progressiveRender;
1339        }
1340    
1341        /**
1342         * @param progressiveRender the progressiveRender to set
1343         */
1344        public void setProgressiveRender(String progressiveRender) {
1345            this.progressiveRender = progressiveRender;
1346        }
1347    
1348        /**
1349         * When set if the condition is satisfied, the component will be refreshed.
1350         *
1351         * <p>The component MUST BE a container or field type. conditionalRefresh is
1352         * defined in a limited Spring EL syntax. Only valid form property names,
1353         * and, or, logical comparison operators (non-arithmetic), and the matches
1354         * clause are allowed. String and regex values must use single quotes ('),
1355         * booleans must be either true or false, numbers must be a valid double
1356         * either negative or positive.
1357         *
1358         * <p>DO NOT use progressiveRender and conditionalRefresh on the same component
1359         * unless it is known that the component will always be visible in all cases
1360         * when a conditionalRefresh happens (ie conditionalRefresh has
1361         * progressiveRender's condition anded with its own condition). <b>If a
1362         * component should be refreshed every time it is shown, use the
1363         * progressiveRenderAndRefresh option with this property instead.</b></p>
1364         *
1365         * @return the conditionalRefresh
1366         */
1367        @BeanTagAttribute(name = "conditionalRefresh")
1368        public String getConditionalRefresh() {
1369            return this.conditionalRefresh;
1370        }
1371    
1372        /**
1373         * Set the conditional refresh condition
1374         *
1375         * @param conditionalRefresh the conditionalRefresh to set
1376         */
1377        public void setConditionalRefresh(String conditionalRefresh) {
1378            this.conditionalRefresh = conditionalRefresh;
1379        }
1380    
1381        /**
1382         * Control names used to control progressive disclosure, set internally
1383         * cannot be set.
1384         *
1385         * @return the progressiveDisclosureControlNames
1386         */
1387        public List<String> getProgressiveDisclosureControlNames() {
1388            return this.progressiveDisclosureControlNames;
1389        }
1390    
1391        /**
1392         * The condition to show this component progressively converted to a js
1393         * expression, set internally cannot be set.
1394         *
1395         * @return the progressiveDisclosureConditionJs
1396         */
1397        public String getProgressiveDisclosureConditionJs() {
1398            return this.progressiveDisclosureConditionJs;
1399        }
1400    
1401        /**
1402         * The condition to refresh this component converted to a js expression, set
1403         * internally cannot be set.
1404         *
1405         * @return the conditionalRefreshConditionJs
1406         */
1407        public String getConditionalRefreshConditionJs() {
1408            return this.conditionalRefreshConditionJs;
1409        }
1410    
1411        /**
1412         * Control names used to control conditional refresh, set internally cannot
1413         * be set.
1414         *
1415         * @return the conditionalRefreshControlNames
1416         */
1417        public List<String> getConditionalRefreshControlNames() {
1418            return this.conditionalRefreshControlNames;
1419        }
1420    
1421        /**
1422         * When progressiveRenderViaAJAX is true, this component will be retrieved
1423         * from the server when it first satisfies its progressive render condition.
1424         *
1425         * <p>After the first retrieval, it is hidden/shown in the html by the js when
1426         * its progressive condition result changes. <b>By default, this is false,
1427         * so components with progressive render capabilities will always be already
1428         * within the client html and toggled to be hidden or visible.</b></p>
1429         *
1430         * @return the progressiveRenderViaAJAX
1431         */
1432        @BeanTagAttribute(name = "progressiveRenderViaAJAX")
1433        public boolean isProgressiveRenderViaAJAX() {
1434            return this.progressiveRenderViaAJAX;
1435        }
1436    
1437        /**
1438         * @param progressiveRenderViaAJAX the progressiveRenderViaAJAX to set
1439         */
1440        public void setProgressiveRenderViaAJAX(boolean progressiveRenderViaAJAX) {
1441            this.progressiveRenderViaAJAX = progressiveRenderViaAJAX;
1442        }
1443    
1444        /**
1445         * If true, when the progressiveRender condition is satisfied, the component
1446         * will always be retrieved from the server and shown(as opposed to being
1447         * stored on the client, but hidden, after the first retrieval as is the
1448         * case with the progressiveRenderViaAJAX option).
1449         *
1450         * <p><b>By default, this is
1451         * false, so components with progressive render capabilities will always be
1452         * already within the client html and toggled to be hidden or visible.</b></p>
1453         *
1454         * @return the progressiveRenderAndRefresh
1455         */
1456        @BeanTagAttribute(name = "progressiveRenderAndRefresh")
1457        public boolean isProgressiveRenderAndRefresh() {
1458            return this.progressiveRenderAndRefresh;
1459        }
1460    
1461        /**
1462         * Set the progressive render and refresh option.
1463         *
1464         * @param progressiveRenderAndRefresh the progressiveRenderAndRefresh to set
1465         */
1466        public void setProgressiveRenderAndRefresh(boolean progressiveRenderAndRefresh) {
1467            this.progressiveRenderAndRefresh = progressiveRenderAndRefresh;
1468        }
1469    
1470        /**
1471         * @see Component#getRefreshWhenChangedPropertyNames()
1472         */
1473        @BeanTagAttribute(name = "refreshWhenChangedPropertyNames", type = BeanTagAttribute.AttributeType.LISTVALUE)
1474        public List<String> getRefreshWhenChangedPropertyNames() {
1475            return this.refreshWhenChangedPropertyNames;
1476        }
1477    
1478        /**
1479         * @see Component#setRefreshWhenChangedPropertyNames(java.util.List<java.lang.String>)
1480         */
1481        public void setRefreshWhenChangedPropertyNames(List<String> refreshWhenChangedPropertyNames) {
1482            this.refreshWhenChangedPropertyNames = refreshWhenChangedPropertyNames;
1483        }
1484    
1485        /**
1486         * @see Component#getAdditionalComponentsToRefresh()
1487         */
1488        @BeanTagAttribute(name = "additionalComponentsToRefresh", type = BeanTagAttribute.AttributeType.LISTVALUE)
1489        public List<String> getAdditionalComponentsToRefresh() {
1490            return additionalComponentsToRefresh;
1491        }
1492    
1493        /**
1494         * @see Component#setAdditionalComponentsToRefresh(java.util.List<java.lang.String>)
1495         */
1496        public void setAdditionalComponentsToRefresh(List<String> additionalComponentsToRefresh) {
1497            this.additionalComponentsToRefresh = additionalComponentsToRefresh;
1498        }
1499    
1500        /**
1501         * @see Component#isRefreshedByAction()
1502         */
1503        public boolean isRefreshedByAction() {
1504            return refreshedByAction;
1505        }
1506    
1507        /**
1508         * @see Component#setRefreshedByAction(boolean)
1509         */
1510        public void setRefreshedByAction(boolean refreshedByAction) {
1511            this.refreshedByAction = refreshedByAction;
1512        }
1513    
1514        /**
1515         * @see org.kuali.rice.krad.uif.component.Component#isDisclosedByAction()
1516         */
1517        public boolean isDisclosedByAction() {
1518            return disclosedByAction;
1519        }
1520    
1521        /**
1522         * @see Component#setDisclosedByAction(boolean)
1523         */
1524        public void setDisclosedByAction(boolean disclosedByAction) {
1525            this.disclosedByAction = disclosedByAction;
1526        }
1527    
1528        /**
1529         * Time in seconds that the component will be automatically refreshed
1530         *
1531         * <p>
1532         * This will invoke the refresh process just like the conditionalRefresh and refreshWhenChangedPropertyNames.
1533         * When using this property methodToCallOnRefresh and id should also be specified
1534         * </p>
1535         *
1536         * @return refreshTimer
1537         */
1538        @BeanTagAttribute(name = "refreshTimer")
1539        public int getRefreshTimer() {
1540            return refreshTimer;
1541        }
1542    
1543        /**
1544         * Setter for refreshTimer
1545         *
1546         * @param refreshTimer
1547         */
1548        public void setRefreshTimer(int refreshTimer) {
1549            this.refreshTimer = refreshTimer;
1550        }
1551    
1552        /**
1553         * @see Component#isResetDataOnRefresh()
1554         */
1555        @BeanTagAttribute(name = "resetDataOnRefresh")
1556        public boolean isResetDataOnRefresh() {
1557            return resetDataOnRefresh;
1558        }
1559    
1560        /**
1561         * @see Component#setResetDataOnRefresh(boolean)
1562         */
1563        public void setResetDataOnRefresh(boolean resetDataOnRefresh) {
1564            this.resetDataOnRefresh = resetDataOnRefresh;
1565        }
1566    
1567        /**
1568         * Name of a method on the controller that should be invoked as part of the component refresh and disclosure
1569         * process
1570         *
1571         * <p>
1572         * During the component refresh or disclosure process it might be necessary to perform other operations, such as
1573         * preparing data or executing a business process. This allows the configuration of a method on the underlying
1574         * controller that should be called for the component refresh action. In this method, the necessary logic can be
1575         * performed and then the base component update method invoked to carry out the component refresh.
1576         * </p>
1577         *
1578         * <p>
1579         * Controller method to invoke must accept the form, binding result, request, and response arguments
1580         * </p>
1581         *
1582         * @return String valid controller method name
1583         */
1584        @BeanTagAttribute(name = "methodToCallOnRefresh")
1585        public String getMethodToCallOnRefresh() {
1586            return methodToCallOnRefresh;
1587        }
1588    
1589        /**
1590         * Setter for the controller method to call for a refresh or disclosure action on this component
1591         *
1592         * @param methodToCallOnRefresh
1593         */
1594        public void setMethodToCallOnRefresh(String methodToCallOnRefresh) {
1595            this.methodToCallOnRefresh = methodToCallOnRefresh;
1596        }
1597    
1598        /**
1599         * @param skipInTabOrder flag
1600         */
1601        public void setSkipInTabOrder(boolean skipInTabOrder) {
1602            this.skipInTabOrder = skipInTabOrder;
1603        }
1604    
1605        /**
1606         * Flag indicating that this component and its nested components must be
1607         * skipped when keyboard tabbing.
1608         *
1609         * @return the skipInTabOrder flag
1610         */
1611        @BeanTagAttribute(name = "skipInTabOrder")
1612        public boolean isSkipInTabOrder() {
1613            return skipInTabOrder;
1614        }
1615    
1616        /**
1617         * Get the dataAttributes setup for this component - to be written to the html/jQuery data
1618         *
1619         * <p>The attributes that are complex objects (contain {}) they will be written through script.
1620         * The attritubes that are simple (contain no objects) will be written directly to the html of the
1621         * component using standard data-.
1622         * Either way they can be access through .data() call in jQuery</p>
1623         *
1624         * @return map of dataAttributes
1625         */
1626        @BeanTagAttribute(name = "dataAttributes", type = BeanTagAttribute.AttributeType.MAPVALUE)
1627        public Map<String, String> getDataAttributes() {
1628            return dataAttributes;
1629        }
1630    
1631        /**
1632         * DataAttributes that will be written to the html and/or through script to be consumed by jQuery.
1633         *
1634         * @param dataAttributes the data attributes to set for this component
1635         */
1636        public void setDataAttributes(Map<String, String> dataAttributes) {
1637            this.dataAttributes = dataAttributes;
1638        }
1639    
1640        /**
1641         * Add a data attribute to the dataAttributes map - to be written to the html/jQuery data.
1642         *
1643         * @param key key of the data attribute
1644         * @param value value of the data attribute
1645         */
1646        public void addDataAttribute(String key, String value) {
1647            dataAttributes.put(key, value);
1648        }
1649    
1650        /**
1651         * Add a data attribute to the dataAttributes map if the given value is non null
1652         * or the empty string
1653         *
1654         * @param key - key for the data attribute entry
1655         * @param value - value for the data attribute
1656         */
1657        public void addDataAttributeIfNonEmpty(String key, String value) {
1658            if (StringUtils.isNotBlank(value)) {
1659                addDataAttribute(key, value);
1660            }
1661        }
1662    
1663        /**
1664         * Returns js that will add data to this component by the element which matches its id.
1665         * This will return script for only the complex data elements (containing {});
1666         *
1667         * @return jQuery data script for adding complex data attributes
1668         */
1669        public String getComplexDataAttributesJs() {
1670            String js = "";
1671            if (getDataAttributes() == null) {
1672                return js;
1673            } else {
1674                for (Map.Entry<String, String> data : getDataAttributes().entrySet()) {
1675                    if (data != null && data.getValue() != null &&
1676                            data.getValue().trim().startsWith("{") && data.getValue().trim().endsWith("}")) {
1677                        js = js + "jQuery('#" + this.getId() + "').data('" + data.getKey() + "', " + data.getValue() + ");";
1678                    }
1679                }
1680                return js;
1681            }
1682        }
1683    
1684        /**
1685         * Returns a string that can be put into a the tag of a component to add data attributes inline.
1686         * This does not include the complex attributes which contain {}
1687         *
1688         * @return html string for data attributes for the simple attributes
1689         */
1690        public String getSimpleDataAttributes() {
1691            String attributes = "";
1692            if (getDataAttributes() == null) {
1693                return attributes;
1694            } else {
1695                for (Map.Entry<String, String> data : getDataAttributes().entrySet()) {
1696                    if (data != null && data.getValue() != null && !data.getValue().trim().startsWith("{")) {
1697                        attributes = attributes + " " + "data-" + data.getKey() + "=\"" + data.getValue() + "\"";
1698                    }
1699                }
1700                return attributes;
1701            }
1702        }
1703    
1704        /**
1705         * @see org.kuali.rice.krad.uif.component.Component#getAllDataAttributesJs()
1706         */
1707        @Override
1708        public String getAllDataAttributesJs() {
1709            String js = "";
1710            if (getDataAttributes() == null) {
1711                return js;
1712            } else {
1713                for (Map.Entry<String, String> data : getDataAttributes().entrySet()) {
1714                    js = js + "jQuery('#" + this.getId() + "').data('" + data.getKey() + "', " + ScriptUtils
1715                            .convertToJsValue(data.getValue()) + ");";
1716                }
1717                return js;
1718            }
1719        }
1720    
1721        /**
1722         * @see org.kuali.rice.krad.uif.component.Component#getAdditionalComponentsToRefreshJs
1723         */
1724        public String getAdditionalComponentsToRefreshJs() {
1725            if (!(this.getAdditionalComponentsToRefresh().isEmpty())) {
1726                additionalComponentsToRefreshJs = ScriptUtils.convertStringListToJsArray(
1727                        this.getAdditionalComponentsToRefresh());
1728            }
1729            return additionalComponentsToRefreshJs;
1730        }
1731    
1732        /**
1733         * @see org.kuali.rice.krad.uif.component.Component#completeValidation
1734         */
1735        public void completeValidation(ValidationTrace tracer) {
1736            tracer.addBean(this);
1737    
1738            // Check for invalid characters in the components id
1739            if (getId() != null) {
1740                if (getId().contains("'")
1741                        || getId().contains("\"")
1742                        || getId().contains("[]")
1743                        || getId().contains(".")
1744                        || getId().contains("#")) {
1745                    String currentValues[] = {"id = " + getId()};
1746                    tracer.createError("Id contains invalid characters", currentValues);
1747                }
1748            }
1749    
1750            if (tracer.getValidationStage() == ValidationTrace.BUILD) {
1751                // Check for a render presence if the component is set to render
1752                if ((isProgressiveRenderViaAJAX() || isProgressiveRenderAndRefresh()) && (getProgressiveRender() == null)) {
1753                    String currentValues[] = {"progressiveRenderViaAJAX = " + isProgressiveRenderViaAJAX(),
1754                            "progressiveRenderAndRefresh = " + isProgressiveRenderAndRefresh(),
1755                            "progressiveRender = " + getProgressiveRender()};
1756                    tracer.createError(
1757                            "ProgressiveRender must be set if progressiveRenderViaAJAX or progressiveRenderAndRefresh are true",
1758                            currentValues);
1759                }
1760            }
1761    
1762            // Check for rendered html if the component is set to self render
1763            if (isSelfRendered() && getRenderedHtmlOutput() == null) {
1764                String currentValues[] =
1765                        {"selfRendered = " + isSelfRendered(), "renderedHtmlOutput = " + getRenderedHtmlOutput()};
1766                tracer.createError("RenderedHtmlOutput must be set if selfRendered is true", currentValues);
1767            }
1768    
1769            // Check to prevent over writing of session persistence status
1770            if (isDisableSessionPersistence() && isForceSessionPersistence()) {
1771                String currentValues[] = {"disableSessionPersistence = " + isDisableSessionPersistence(),
1772                        "forceSessionPersistence = " + isForceSessionPersistence()};
1773                tracer.createWarning("DisableSessionPersistence and forceSessionPersistence cannot be both true",
1774                        currentValues);
1775            }
1776    
1777            // Check for un-executable data resets when no refresh option is set
1778            if (getMethodToCallOnRefresh() != null || isResetDataOnRefresh()) {
1779                if (!isProgressiveRenderAndRefresh()
1780                        && !isRefreshedByAction()
1781                        && !isProgressiveRenderViaAJAX()
1782                        && !StringUtils.isNotEmpty(conditionalRefresh)
1783                        && !(refreshTimer > 0)) {
1784                    String currentValues[] = {"methodToCallONRefresh = " + getMethodToCallOnRefresh(),
1785                            "resetDataONRefresh = " + isResetDataOnRefresh(),
1786                            "progressiveRenderAndRefresh = " + isProgressiveRenderAndRefresh(),
1787                            "refreshedByAction = " + isRefreshedByAction(),
1788                            "progressiveRenderViaAJAX = " + isProgressiveRenderViaAJAX(),
1789                            "conditionalRefresh = " + getConditionalRefresh(), "refreshTimer = " + getRefreshTimer()};
1790                    tracer.createWarning(
1791                            "MethodToCallONRefresh and resetDataONRefresh should only be set when a trigger event is set",
1792                            currentValues);
1793                }
1794            }
1795    
1796            // Check to prevent complications with rendering and refreshing a component that is not always shown
1797            if (StringUtils.isNotEmpty(getProgressiveRender()) && StringUtils.isNotEmpty(conditionalRefresh)) {
1798                String currentValues[] = {"progressiveRender = " + getProgressiveRender(),
1799                        "conditionalRefresh = " + getConditionalRefresh()};
1800                tracer.createWarning("DO NOT use progressiveRender and conditionalRefresh on the same component unless "
1801                        + "it is known that the component will always be visible in all cases when a conditionalRefresh "
1802                        + "happens (ie conditionalRefresh has progressiveRender's condition and with its own condition). "
1803                        + "If a component should be refreshed every time it is shown, use the progressiveRenderAndRefresh "
1804                        + "option with this property instead.", currentValues);
1805            }
1806    
1807            // Check for valid Spring EL format for progressiveRender
1808            if (!Validator.validateSpringEL(getProgressiveRender())) {
1809                String currentValues[] = {"progressiveRender =" + getProgressiveRender()};
1810                tracer.createError("ProgressiveRender must follow the Spring EL @{} format", currentValues);
1811            }
1812    
1813            // Check for valid Spring EL format for conditionalRefresh
1814            if (!Validator.validateSpringEL(getConditionalRefresh())) {
1815                String currentValues[] = {"conditionalRefresh =" + getConditionalRefresh()};
1816                tracer.createError("conditionalRefresh must follow the Spring EL @{} format", currentValues);
1817                ;
1818            }
1819        }
1820    
1821    }