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