001/**
002 * Copyright 2005-2016 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.service.KRADServiceLocatorWeb;
020import org.kuali.rice.krad.uif.CssConstants;
021import org.kuali.rice.krad.uif.UifConstants.ViewStatus;
022import org.kuali.rice.krad.uif.control.ControlBase;
023import org.kuali.rice.krad.uif.modifier.ComponentModifier;
024import org.kuali.rice.krad.uif.util.ExpressionUtils;
025import org.kuali.rice.krad.uif.view.View;
026import org.kuali.rice.krad.util.ObjectUtils;
027
028import java.util.ArrayList;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033/**
034 * Base implementation of <code>Component</code> which other component
035 * implementations should extend
036 *
037 * <p>
038 * Provides base component properties such as id and template. Also provides
039 * default implementation for the <code>ScriptEventSupport</code> and
040 * <code>Ordered</code> interfaces. By default no script events except the
041 * onDocumentReady are supported.
042 * </p>
043 *
044 * @author Kuali Rice Team (rice.collab@kuali.org)
045 */
046public abstract class ComponentBase extends ConfigurableBase implements Component {
047    private static final long serialVersionUID = -4449335748129894350L;
048
049    private String id;
050    private String factoryId;
051    private String template;
052    private String title;
053
054    private boolean render;
055    private boolean refresh;
056
057    @KeepExpression
058    private String progressiveRender;
059    private boolean progressiveRenderViaAJAX;
060    private boolean progressiveRenderAndRefresh;
061    private List<String> progressiveDisclosureControlNames;
062    private String progressiveDisclosureConditionJs;
063
064    @KeepExpression
065    private String conditionalRefresh;
066    private String conditionalRefreshConditionJs;
067    private List<String> conditionalRefreshControlNames;
068
069    private String refreshWhenChanged;
070    private List<String> refreshWhenChangedControlNames;
071    private boolean refreshedByAction;
072
073    private boolean resetDataOnRefresh;
074    private String refreshDiscloseMethodToCall;
075
076    private boolean hidden;
077    private boolean readOnly;
078    private Boolean required;
079
080    private String align;
081    private String valign;
082    private String width;
083
084    private int colSpan;
085    private int rowSpan;
086
087    private String style;
088    private List<String> styleClasses;
089
090    private int order;
091
092    private boolean skipInTabOrder;
093
094    private String finalizeMethodToCall;
095    private List<Object> finalizeMethodAdditionalArguments;
096    private MethodInvokerConfig finalizeMethodInvoker;
097    private boolean selfRendered;
098    private String renderOutput;
099
100    private boolean persistInSession;
101
102    private ComponentSecurity componentSecurity;
103
104    private String onLoadScript;
105    private String onUnloadScript;
106    private String onCloseScript;
107    private String onBlurScript;
108    private String onChangeScript;
109    private String onClickScript;
110    private String onDblClickScript;
111    private String onFocusScript;
112    private String onSubmitScript;
113    private String onKeyPressScript;
114    private String onKeyUpScript;
115    private String onKeyDownScript;
116    private String onMouseOverScript;
117    private String onMouseOutScript;
118    private String onMouseUpScript;
119    private String onMouseDownScript;
120    private String onMouseMoveScript;
121    private String onDocumentReadyScript;
122
123    private List<ComponentModifier> componentModifiers;
124
125    private Map<String, String> componentOptions;
126    private String componentOptionsJSString;
127
128    @ReferenceCopy(newCollectionInstance = true)
129    private transient Map<String, Object> context;
130
131    private List<PropertyReplacer> propertyReplacers;
132
133    public ComponentBase() {
134        super();
135
136        order = 0;
137        colSpan = 1;
138        rowSpan = 1;
139
140        render = true;
141        selfRendered = false;
142        progressiveRenderViaAJAX = false;
143        progressiveRenderAndRefresh = false;
144        refreshedByAction = false;
145        resetDataOnRefresh = false;
146        persistInSession = false;
147
148        componentSecurity = ObjectUtils.newInstance(getComponentSecurityClass());
149
150        finalizeMethodAdditionalArguments = new ArrayList<Object>();
151        styleClasses = new ArrayList<String>();
152        componentModifiers = new ArrayList<ComponentModifier>();
153        componentOptions = new HashMap<String, String>();
154        context = new HashMap<String, Object>();
155        propertyReplacers = new ArrayList<PropertyReplacer>();
156    }
157
158    /**
159     * The following updates are done here:
160     *
161     * <ul>
162     * <li></li>
163     * </ul>
164     *
165     * @see Component#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
166     */
167    public void performInitialization(View view, Object model) {
168
169    }
170
171    /**
172     * The following updates are done here:
173     *
174     * <ul>
175     * <li>Evaluate the progressive render condition (if set) and combine with the current render status to set the
176     * render status</li>
177     * </ul>
178     *
179     * @see Component#performApplyModel(org.kuali.rice.krad.uif.view.View, java.lang.Object, org.kuali.rice.krad.uif.component.Component)
180     */
181    public void performApplyModel(View view, Object model, Component parent) {
182        if (StringUtils.isNotEmpty(progressiveRender)) {
183            // progressive anded with conditional render, will not render at least one of the two are false
184            Boolean progRenderEval = (Boolean) KRADServiceLocatorWeb.getExpressionEvaluatorService().evaluateExpression(
185                    model, context, progressiveRender);
186
187            this.setRender(progRenderEval && this.render);
188        }
189    }
190
191    /**
192     * The following finalization is done here:
193     *
194     * <ul>
195     * <li>progressiveRender and conditionalRefresh variables are processed if set</li>
196     * <li>If any of the style properties were given, sets the style string on
197     * the style property</li>
198     * <li>Set the skipInTabOrder flag for nested components</li>
199     * </ul>
200     *
201     * @see Component#performFinalize(org.kuali.rice.krad.uif.view.View, java.lang.Object, org.kuali.rice.krad.uif.component.Component)
202     */
203    public void performFinalize(View view, Object model, Component parent) {
204        if (StringUtils.isNotEmpty(progressiveRender)) {
205            progressiveRender = ExpressionUtils.replaceBindingPrefixes(view, this, progressiveRender);
206            progressiveDisclosureControlNames = new ArrayList<String>();
207            progressiveDisclosureConditionJs = ExpressionUtils.parseExpression(progressiveRender,
208                    progressiveDisclosureControlNames);
209        }
210
211        if (StringUtils.isNotEmpty(conditionalRefresh)) {
212            conditionalRefresh = ExpressionUtils.replaceBindingPrefixes(view, this, conditionalRefresh);
213            conditionalRefreshControlNames = new ArrayList<String>();
214            conditionalRefreshConditionJs = ExpressionUtils.parseExpression(conditionalRefresh,
215                    conditionalRefreshControlNames);
216        }
217
218        if (StringUtils.isNotEmpty(refreshWhenChanged)) {
219            refreshWhenChanged = ExpressionUtils.replaceBindingPrefixes(view, this, refreshWhenChanged);
220            refreshWhenChangedControlNames = new ArrayList<String>();
221            String[] names = StringUtils.split(refreshWhenChanged, ",");
222            for (String name : names) {
223                refreshWhenChangedControlNames.add(name.trim());
224            }
225        }
226
227        // TODO: does this check on final status need to be here?
228        if (!ViewStatus.FINAL.equals(view.getViewStatus())) {
229            // add the align, valign, and width settings to style
230            if (StringUtils.isNotBlank(getAlign()) && !StringUtils.contains(getStyle(), CssConstants.TEXT_ALIGN)) {
231                appendToStyle(CssConstants.TEXT_ALIGN + getAlign() + ";");
232            }
233
234            if (StringUtils.isNotBlank(getValign()) && !StringUtils.contains(getStyle(), CssConstants.VERTICAL_ALIGN)) {
235                appendToStyle(CssConstants.VERTICAL_ALIGN + getValign() + ";");
236            }
237
238            if (StringUtils.isNotBlank(getWidth()) && !StringUtils.contains(getStyle(), CssConstants.WIDTH)) {
239                appendToStyle(CssConstants.WIDTH + getWidth() + ";");
240            }
241        }
242
243        // Set the skipInTabOrder flag on all nested components
244        // Set the tabIndex on controls to -1 in order to be skipped on tabbing
245        for (Component component : getComponentsForLifecycle()) {
246            if (component != null && component instanceof ComponentBase && skipInTabOrder) {
247                ((ComponentBase) component).setSkipInTabOrder(skipInTabOrder);
248                if (component instanceof ControlBase) {
249                    ((ControlBase) component).setTabIndex(-1);
250                }
251            }
252        }
253    }
254
255    /**
256     * @see org.kuali.rice.krad.uif.component.Component#getComponentsForLifecycle()
257     */
258    public List<Component> getComponentsForLifecycle() {
259        List<Component> components = new ArrayList<Component>();
260
261        return components;
262    }
263
264    /**
265     * @see org.kuali.rice.krad.uif.component.Component#getComponentPrototypes()
266     */
267    public List<Component> getComponentPrototypes() {
268        List<Component> components = new ArrayList<Component>();
269
270        for (ComponentModifier modifier : componentModifiers) {
271            components.addAll(modifier.getComponentPrototypes());
272        }
273
274        components.addAll(getPropertyReplacerComponents());
275
276        return components;
277    }
278
279    /**
280     * Returns list of components that are being held in property replacers configured for this component
281     *
282     * @return List<Component>
283     */
284    public List<Component> getPropertyReplacerComponents() {
285        List<Component> components = new ArrayList<Component>();
286        for (Object replacer : propertyReplacers) {
287            components.addAll(((PropertyReplacer) replacer).getNestedComponents());
288        }
289
290        return components;
291    }
292
293    /**
294     * @see org.kuali.rice.krad.uif.component.Component#getId()
295     */
296    public String getId() {
297        return this.id;
298    }
299
300    /**
301     * @see org.kuali.rice.krad.uif.component.Component#setId(java.lang.String)
302     */
303    public void setId(String id) {
304        this.id = id;
305    }
306
307    /**
308     * @see org.kuali.rice.krad.uif.component.Component#getFactoryId()
309     */
310    public String getFactoryId() {
311        return this.factoryId;
312    }
313
314    /**
315     * @see org.kuali.rice.krad.uif.component.Component#setFactoryId(java.lang.String)
316     */
317    public void setFactoryId(String factoryId) {
318        this.factoryId = factoryId;
319    }
320
321    /**
322     * @see org.kuali.rice.krad.uif.component.Component#getTemplate()
323     */
324    public String getTemplate() {
325        return this.template;
326    }
327
328    /**
329     * @see org.kuali.rice.krad.uif.component.Component#setTemplate(java.lang.String)
330     */
331    public void setTemplate(String template) {
332        this.template = template;
333    }
334
335    /**
336     * @see org.kuali.rice.krad.uif.component.Component#getTitle()
337     */
338    public String getTitle() {
339        return this.title;
340    }
341
342    /**
343     * @see org.kuali.rice.krad.uif.component.Component#setTitle(java.lang.String)
344     */
345    public void setTitle(String title) {
346        this.title = title;
347    }
348
349    /**
350     * @see org.kuali.rice.krad.uif.component.Component#isHidden()
351     */
352    public boolean isHidden() {
353        return this.hidden;
354    }
355
356    /**
357     * @see org.kuali.rice.krad.uif.component.Component#setHidden(boolean)
358     */
359    public void setHidden(boolean hidden) {
360        this.hidden = hidden;
361    }
362
363    /**
364     * @see org.kuali.rice.krad.uif.component.Component#isReadOnly()
365     */
366    public boolean isReadOnly() {
367        return this.readOnly;
368    }
369
370    /**
371     * @see org.kuali.rice.krad.uif.component.Component#setReadOnly(boolean)
372     */
373    public void setReadOnly(boolean readOnly) {
374        this.readOnly = readOnly;
375    }
376
377    /**
378     * @see org.kuali.rice.krad.uif.component.Component#getRequired()
379     */
380    public Boolean getRequired() {
381        return this.required;
382    }
383
384    /**
385     * @see org.kuali.rice.krad.uif.component.Component#setRequired(java.lang.Boolean)
386     */
387    public void setRequired(Boolean required) {
388        this.required = required;
389    }
390
391    /**
392     * @see org.kuali.rice.krad.uif.component.Component#isRender()
393     */
394    public boolean isRender() {
395        return this.render;
396    }
397
398    /**
399     * @see org.kuali.rice.krad.uif.component.Component#setRender(boolean)
400     */
401    public void setRender(boolean render) {
402        this.render = render;
403    }
404
405    /**
406     * @see org.kuali.rice.krad.uif.component.Component#getColSpan()
407     */
408    public int getColSpan() {
409        return this.colSpan;
410    }
411
412    /**
413     * @see org.kuali.rice.krad.uif.component.Component#setColSpan(int)
414     */
415    public void setColSpan(int colSpan) {
416        this.colSpan = colSpan;
417    }
418
419    /**
420     * @see org.kuali.rice.krad.uif.component.Component#getRowSpan()
421     */
422    public int getRowSpan() {
423        return this.rowSpan;
424    }
425
426    /**
427     * @see org.kuali.rice.krad.uif.component.Component#setRowSpan(int)
428     */
429    public void setRowSpan(int rowSpan) {
430        this.rowSpan = rowSpan;
431    }
432
433    /**
434     * Horizontal alignment of the component within its container
435     * <p>
436     * All components belong to a <code>Container</code> and are placed using a
437     * <code>LayoutManager</code>. This property specifies how the component
438     * should be aligned horizontally within the container. During the finalize
439     * phase the CSS text-align style will be created for the align setting.
440     * </p>
441     *
442     * @return String horizontal align
443     * @see org.kuali.rice.krad.uif.CssConstants.TextAligns
444     */
445    public String getAlign() {
446        return this.align;
447    }
448
449    /**
450     * Sets the components horizontal alignment
451     *
452     * @param align
453     */
454    public void setAlign(String align) {
455        this.align = align;
456    }
457
458    /**
459     * Vertical alignment of the component within its container
460     * <p>
461     * All components belong to a <code>Container</code> and are placed using a
462     * <code>LayoutManager</code>. This property specifies how the component
463     * should be aligned vertically within the container. During the finalize
464     * phase the CSS vertical-align style will be created for the valign
465     * setting.
466     * </p>
467     *
468     * @return String vertical align
469     * @see org.kuali.rice.krad.uif.CssConstants.VerticalAligns
470     */
471    public String getValign() {
472        return this.valign;
473    }
474
475    /**
476     * Setter for the component's vertical align
477     *
478     * @param valign
479     */
480    public void setValign(String valign) {
481        this.valign = valign;
482    }
483
484    /**
485     * Width the component should take up in the container
486     * <p>
487     * All components belong to a <code>Container</code> and are placed using a
488     * <code>LayoutManager</code>. This property specifies a width the component
489     * should take up in the Container. This is not applicable for all layout
490     * managers. During the finalize phase the CSS width style will be created
491     * for the width setting.
492     * </p>
493     * <p>
494     * e.g. '30%', '55px'
495     * </p>
496     *
497     * @return String width string
498     */
499    public String getWidth() {
500        return this.width;
501    }
502
503    /**
504     * Setter for the components width
505     *
506     * @param width
507     */
508    public void setWidth(String width) {
509        this.width = width;
510    }
511
512    /**
513     * @see org.kuali.rice.krad.uif.component.Component#getStyle()
514     */
515    public String getStyle() {
516        return this.style;
517    }
518
519    /**
520     * @see org.kuali.rice.krad.uif.component.Component#setStyle(java.lang.String)
521     */
522    public void setStyle(String style) {
523        this.style = style;
524    }
525
526    /**
527     * @see org.kuali.rice.krad.uif.component.Component#getStyleClasses()
528     */
529    public List<String> getStyleClasses() {
530        return this.styleClasses;
531    }
532
533    /**
534     * @see org.kuali.rice.krad.uif.component.Component#setStyleClasses(java.util.List)
535     */
536    public void setStyleClasses(List<String> styleClasses) {
537        this.styleClasses = styleClasses;
538    }
539
540    /**
541     * Builds the HTML class attribute string by combining the styleClasses list
542     * with a space delimiter
543     *
544     * @return String class attribute string
545     */
546    public String getStyleClassesAsString() {
547        if (styleClasses != null) {
548            return StringUtils.join(styleClasses, " ");
549        }
550
551        return "";
552    }
553
554    /**
555     * @see org.kuali.rice.krad.uif.component.Component#addStyleClass(java.lang.String)
556     */
557    public void addStyleClass(String styleClass) {
558        if (!styleClasses.contains(styleClass)) {
559            styleClasses.add(styleClass);
560        }
561    }
562
563    /**
564     * @see org.kuali.rice.krad.uif.component.Component#appendToStyle(java.lang.String)
565     */
566    public void appendToStyle(String styleRules) {
567        if (style == null) {
568            style = "";
569        }
570        style = style + styleRules;
571    }
572
573    /**
574     * @see org.kuali.rice.krad.uif.component.Component#getFinalizeMethodToCall()
575     */
576    public String getFinalizeMethodToCall() {
577        return this.finalizeMethodToCall;
578    }
579
580    /**
581     * Setter for the finalize method
582     *
583     * @param finalizeMethodToCall
584     */
585    public void setFinalizeMethodToCall(String finalizeMethodToCall) {
586        this.finalizeMethodToCall = finalizeMethodToCall;
587    }
588
589    /**
590     * @see org.kuali.rice.krad.uif.component.Component#getFinalizeMethodAdditionalArguments()
591     */
592    public List<Object> getFinalizeMethodAdditionalArguments() {
593        return finalizeMethodAdditionalArguments;
594    }
595
596    /**
597     * Setter for the finalize additional arguments list
598     *
599     * @param finalizeMethodAdditionalArguments
600     */
601    public void setFinalizeMethodAdditionalArguments(List<Object> finalizeMethodAdditionalArguments) {
602        this.finalizeMethodAdditionalArguments = finalizeMethodAdditionalArguments;
603    }
604
605    /**
606     * @see org.kuali.rice.krad.uif.component.Component#getFinalizeMethodInvoker()
607     */
608    public MethodInvokerConfig getFinalizeMethodInvoker() {
609        return this.finalizeMethodInvoker;
610    }
611
612    /**
613     * Setter for the method invoker instance
614     *
615     * @param finalizeMethodInvoker
616     */
617    public void setFinalizeMethodInvoker(MethodInvokerConfig finalizeMethodInvoker) {
618        this.finalizeMethodInvoker = finalizeMethodInvoker;
619    }
620
621    /**
622     * @see org.kuali.rice.krad.uif.component.Component#isSelfRendered()
623     */
624    public boolean isSelfRendered() {
625        return this.selfRendered;
626    }
627
628    /**
629     * @see org.kuali.rice.krad.uif.component.Component#setSelfRendered(boolean)
630     */
631    public void setSelfRendered(boolean selfRendered) {
632        this.selfRendered = selfRendered;
633    }
634
635    /**
636     * @see org.kuali.rice.krad.uif.component.Component#getRenderOutput()
637     */
638    public String getRenderOutput() {
639        return this.renderOutput;
640    }
641
642    /**
643     * @see org.kuali.rice.krad.uif.component.Component#setRenderOutput(java.lang.String)
644     */
645    public void setRenderOutput(String renderOutput) {
646        this.renderOutput = renderOutput;
647    }
648
649    /**
650     * @see Component#isPersistInSession()
651     */
652    public boolean isPersistInSession() {
653        return persistInSession;
654    }
655
656    /**
657     * @see Component#setPersistInSession(boolean)
658     */
659    public void setPersistInSession(boolean persistInSession) {
660        this.persistInSession = persistInSession;
661    }
662
663    /**
664     * @see Component#getComponentSecurity()
665     */
666    public ComponentSecurity getComponentSecurity() {
667        return componentSecurity;
668    }
669
670    /**
671     * @see Component#setComponentSecurity(org.kuali.rice.krad.uif.component.ComponentSecurity)
672     */
673    public void setComponentSecurity(ComponentSecurity componentSecurity) {
674        this.componentSecurity = componentSecurity;
675    }
676
677    /**
678     * Returns the security class that is associated with the component (used for initialization and validation)
679     *
680     * @return Class<? extends ComponentSecurity>
681     */
682    protected Class<? extends ComponentSecurity> getComponentSecurityClass() {
683        return ComponentSecurity.class;
684    }
685
686    /**
687     * @see org.kuali.rice.krad.uif.component.Component#getComponentModifiers()
688     */
689    public List<ComponentModifier> getComponentModifiers() {
690        return this.componentModifiers;
691    }
692
693    /**
694     * @see org.kuali.rice.krad.uif.component.Component#setComponentModifiers(java.util.List)
695     */
696    public void setComponentModifiers(List<ComponentModifier> componentModifiers) {
697        this.componentModifiers = componentModifiers;
698    }
699
700    /**
701     * @see org.kuali.rice.krad.uif.component.Component#getContext()
702     */
703    public Map<String, Object> getContext() {
704        return this.context;
705    }
706
707    /**
708     * @see org.kuali.rice.krad.uif.component.Component#setContext(java.util.Map)
709     */
710    public void setContext(Map<String, Object> context) {
711        this.context = context;
712    }
713
714    /**
715     * @see org.kuali.rice.krad.uif.component.Component#pushObjectToContext(java.lang.String,
716     *      java.lang.Object)
717     */
718    public void pushObjectToContext(String objectName, Object object) {
719        if (this.context == null) {
720            this.context = new HashMap<String, Object>();
721        }
722        pushToPropertyReplacerContext(objectName, object);
723        this.context.put(objectName, object);
724    }
725
726    /*
727    * Adds the object to the context of the components in the
728    * PropertyReplacer object. Only checks for a list, map or component.
729    */
730    protected void pushToPropertyReplacerContext(String objectName, Object object) {
731        for (Component replacerComponent : getPropertyReplacerComponents()) {
732            replacerComponent.pushObjectToContext(objectName, object);
733        }
734    }
735
736    /**
737     * @see org.kuali.rice.krad.uif.component.ComponentBase#pushAllToContext
738     */
739    public void pushAllToContext(Map<String, Object> objects) {
740        if (objects != null) {
741            for (Map.Entry<String, Object> objectEntry : objects.entrySet()) {
742                pushObjectToContext(objectEntry.getKey(), objectEntry.getValue());
743            }
744        }
745    }
746
747    /**
748     * @see org.kuali.rice.krad.uif.component.Component#getPropertyReplacers()
749     */
750    public List<PropertyReplacer> getPropertyReplacers() {
751        return this.propertyReplacers;
752    }
753
754    /**
755     * @see org.kuali.rice.krad.uif.component.Component#setPropertyReplacers(java.util.List)
756     */
757    public void setPropertyReplacers(List<PropertyReplacer> propertyReplacers) {
758        this.propertyReplacers = propertyReplacers;
759    }
760
761    /**
762     * @see org.springframework.core.Ordered#getOrder()
763     */
764    public int getOrder() {
765        return this.order;
766    }
767
768    /**
769     * Setter for the component's order
770     *
771     * @param order
772     */
773    public void setOrder(int order) {
774        this.order = order;
775    }
776
777    /**
778     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnLoad()
779     */
780    public boolean getSupportsOnLoad() {
781        return false;
782    }
783
784    /**
785     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnLoadScript()
786     */
787    public String getOnLoadScript() {
788        return onLoadScript;
789    }
790
791    /**
792     * Setter for the components onLoad script
793     *
794     * @param onLoadScript
795     */
796    public void setOnLoadScript(String onLoadScript) {
797        this.onLoadScript = onLoadScript;
798    }
799
800    /**
801     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnDocumentReady()
802     */
803    public boolean getSupportsOnDocumentReady() {
804        return true;
805    }
806
807    /**
808     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnDocumentReadyScript()
809     */
810    public String getOnDocumentReadyScript() {
811        return onDocumentReadyScript;
812    }
813
814    /**
815     * Setter for the components onDocumentReady script
816     *
817     * @param onDocumentReadyScript
818     */
819    public void setOnDocumentReadyScript(String onDocumentReadyScript) {
820        this.onDocumentReadyScript = onDocumentReadyScript;
821    }
822
823    /**
824     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnUnload()
825     */
826    public boolean getSupportsOnUnload() {
827        return false;
828    }
829
830    /**
831     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnUnloadScript()
832     */
833    public String getOnUnloadScript() {
834        return onUnloadScript;
835    }
836
837    /**
838     * Setter for the components onUnload script
839     *
840     * @param onUnloadScript
841     */
842    public void setOnUnloadScript(String onUnloadScript) {
843        this.onUnloadScript = onUnloadScript;
844    }
845
846    /**
847     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnClose()
848     */
849    public boolean getSupportsOnClose() {
850        return false;
851    }
852
853    /**
854     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnCloseScript()
855     */
856    public String getOnCloseScript() {
857        return onCloseScript;
858    }
859
860    /**
861     * Setter for the components onClose script
862     *
863     * @param onCloseScript
864     */
865    public void setOnCloseScript(String onCloseScript) {
866        this.onCloseScript = onCloseScript;
867    }
868
869    /**
870     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnBlur()
871     */
872    public boolean getSupportsOnBlur() {
873        return false;
874    }
875
876    /**
877     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnBlurScript()
878     */
879    public String getOnBlurScript() {
880        return onBlurScript;
881    }
882
883    /**
884     * Setter for the components onBlur script
885     *
886     * @param onBlurScript
887     */
888    public void setOnBlurScript(String onBlurScript) {
889        this.onBlurScript = onBlurScript;
890    }
891
892    /**
893     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnChange()
894     */
895    public boolean getSupportsOnChange() {
896        return false;
897    }
898
899    /**
900     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnChangeScript()
901     */
902    public String getOnChangeScript() {
903        return onChangeScript;
904    }
905
906    /**
907     * Setter for the components onChange script
908     *
909     * @param onChangeScript
910     */
911    public void setOnChangeScript(String onChangeScript) {
912        this.onChangeScript = onChangeScript;
913    }
914
915    /**
916     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnClick()
917     */
918    public boolean getSupportsOnClick() {
919        return false;
920    }
921
922    /**
923     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnClickScript()
924     */
925    public String getOnClickScript() {
926        return onClickScript;
927    }
928
929    /**
930     * Setter for the components onClick script
931     *
932     * @param onClickScript
933     */
934    public void setOnClickScript(String onClickScript) {
935        this.onClickScript = onClickScript;
936    }
937
938    /**
939     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnDblClick()
940     */
941    public boolean getSupportsOnDblClick() {
942        return false;
943    }
944
945    /**
946     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnDblClickScript()
947     */
948    public String getOnDblClickScript() {
949        return onDblClickScript;
950    }
951
952    /**
953     * Setter for the components onDblClick script
954     *
955     * @param onDblClickScript
956     */
957    public void setOnDblClickScript(String onDblClickScript) {
958        this.onDblClickScript = onDblClickScript;
959    }
960
961    /**
962     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnFocus()
963     */
964    public boolean getSupportsOnFocus() {
965        return false;
966    }
967
968    /**
969     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnFocusScript()
970     */
971    public String getOnFocusScript() {
972        return onFocusScript;
973    }
974
975    /**
976     * Setter for the components onFocus script
977     *
978     * @param onFocusScript
979     */
980    public void setOnFocusScript(String onFocusScript) {
981        this.onFocusScript = onFocusScript;
982    }
983
984    /**
985     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnSubmit()
986     */
987    public boolean getSupportsOnSubmit() {
988        return false;
989    }
990
991    /**
992     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnSubmitScript()
993     */
994    public String getOnSubmitScript() {
995        return onSubmitScript;
996    }
997
998    /**
999     * Setter for the components onSubmit script
1000     *
1001     * @param onSubmitScript
1002     */
1003    public void setOnSubmitScript(String onSubmitScript) {
1004        this.onSubmitScript = onSubmitScript;
1005    }
1006
1007    /**
1008     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnKeyPress()
1009     */
1010    public boolean getSupportsOnKeyPress() {
1011        return false;
1012    }
1013
1014    /**
1015     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyPressScript()
1016     */
1017    public String getOnKeyPressScript() {
1018        return onKeyPressScript;
1019    }
1020
1021    /**
1022     * Setter for the components onKeyPress script
1023     *
1024     * @param onKeyPressScript
1025     */
1026    public void setOnKeyPressScript(String onKeyPressScript) {
1027        this.onKeyPressScript = onKeyPressScript;
1028    }
1029
1030    /**
1031     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnKeyUp()
1032     */
1033    public boolean getSupportsOnKeyUp() {
1034        return false;
1035    }
1036
1037    /**
1038     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyUpScript()
1039     */
1040    public String getOnKeyUpScript() {
1041        return onKeyUpScript;
1042    }
1043
1044    /**
1045     * Setter for the components onKeyUp script
1046     *
1047     * @param onKeyUpScript
1048     */
1049    public void setOnKeyUpScript(String onKeyUpScript) {
1050        this.onKeyUpScript = onKeyUpScript;
1051    }
1052
1053    /**
1054     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnKeyDown()
1055     */
1056    public boolean getSupportsOnKeyDown() {
1057        return false;
1058    }
1059
1060    /**
1061     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnKeyDownScript()
1062     */
1063    public String getOnKeyDownScript() {
1064        return onKeyDownScript;
1065    }
1066
1067    /**
1068     * Setter for the components onKeyDown script
1069     *
1070     * @param onKeyDownScript
1071     */
1072    public void setOnKeyDownScript(String onKeyDownScript) {
1073        this.onKeyDownScript = onKeyDownScript;
1074    }
1075
1076    /**
1077     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnMouseOver()
1078     */
1079    public boolean getSupportsOnMouseOver() {
1080        return false;
1081    }
1082
1083    /**
1084     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseOverScript()
1085     */
1086    public String getOnMouseOverScript() {
1087        return onMouseOverScript;
1088    }
1089
1090    /**
1091     * Setter for the components onMouseOver script
1092     *
1093     * @param onMouseOverScript
1094     */
1095    public void setOnMouseOverScript(String onMouseOverScript) {
1096        this.onMouseOverScript = onMouseOverScript;
1097    }
1098
1099    /**
1100     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnMouseOut()
1101     */
1102    public boolean getSupportsOnMouseOut() {
1103        return false;
1104    }
1105
1106    /**
1107     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseOutScript()
1108     */
1109    public String getOnMouseOutScript() {
1110        return onMouseOutScript;
1111    }
1112
1113    /**
1114     * Setter for the components onMouseOut script
1115     *
1116     * @param onMouseOutScript
1117     */
1118    public void setOnMouseOutScript(String onMouseOutScript) {
1119        this.onMouseOutScript = onMouseOutScript;
1120    }
1121
1122    /**
1123     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnMouseUp()
1124     */
1125    public boolean getSupportsOnMouseUp() {
1126        return false;
1127    }
1128
1129    /**
1130     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseUpScript()
1131     */
1132    public String getOnMouseUpScript() {
1133        return onMouseUpScript;
1134    }
1135
1136    /**
1137     * Setter for the components onMouseUp script
1138     *
1139     * @param onMouseUpScript
1140     */
1141    public void setOnMouseUpScript(String onMouseUpScript) {
1142        this.onMouseUpScript = onMouseUpScript;
1143    }
1144
1145    /**
1146     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnMouseDown()
1147     */
1148    public boolean getSupportsOnMouseDown() {
1149        return false;
1150    }
1151
1152    /**
1153     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseDownScript()
1154     */
1155    public String getOnMouseDownScript() {
1156        return onMouseDownScript;
1157    }
1158
1159    /**
1160     * Setter for the components onMouseDown script
1161     *
1162     * @param onMouseDownScript
1163     */
1164    public void setOnMouseDownScript(String onMouseDownScript) {
1165        this.onMouseDownScript = onMouseDownScript;
1166    }
1167
1168    /**
1169     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getSupportsOnMouseMove()
1170     */
1171    public boolean getSupportsOnMouseMove() {
1172        return false;
1173    }
1174
1175    /**
1176     * @see org.kuali.rice.krad.uif.component.ScriptEventSupport#getOnMouseMoveScript()
1177     */
1178    public String getOnMouseMoveScript() {
1179        return onMouseMoveScript;
1180    }
1181
1182    /**
1183     * Setter for the components onMouseMove script
1184     *
1185     * @param onMouseMoveScript
1186     */
1187    public void setOnMouseMoveScript(String onMouseMoveScript) {
1188        this.onMouseMoveScript = onMouseMoveScript;
1189    }
1190
1191    public Map<String, String> getComponentOptions() {
1192        if (componentOptions == null) {
1193            componentOptions = new HashMap<String, String>();
1194        }
1195        return this.componentOptions;
1196    }
1197
1198    public void setComponentOptions(Map<String, String> componentOptions) {
1199        this.componentOptions = componentOptions;
1200    }
1201
1202    /**
1203     * Builds a string from the underlying <code>Map</code> of component options
1204     * that will export that options as a JavaScript Map for use in js and
1205     * jQuery plugins
1206     *
1207     * @return String of widget options formatted as JS Map
1208     */
1209    @Override
1210    public String getComponentOptionsJSString() {
1211        if (componentOptionsJSString != null) {
1212            return componentOptionsJSString;
1213        }
1214
1215        if (componentOptions == null) {
1216            componentOptions = new HashMap<String, String>();
1217        }
1218        StringBuilder sb = new StringBuilder();
1219
1220        sb.append("{");
1221
1222        for (String optionKey : componentOptions.keySet()) {
1223            String optionValue = componentOptions.get(optionKey);
1224
1225            if (sb.length() > 1) {
1226                sb.append(",");
1227            }
1228
1229            sb.append(optionKey);
1230            sb.append(":");
1231
1232            boolean isNumber = false;
1233            if (StringUtils.isNotBlank(optionValue) && (StringUtils.isNumeric(optionValue.trim().substring(0, 1))
1234                    || optionValue.trim().substring(0, 1).equals("-"))) {
1235                try {
1236                    Double.parseDouble(optionValue.trim());
1237                    isNumber = true;
1238                } catch (NumberFormatException e) {
1239                    isNumber = false;
1240                }
1241            }
1242            // If an option value starts with { or [, it would be a nested value
1243            // and it should not use quotes around it
1244            if (StringUtils.startsWith(optionValue, "{") || StringUtils.startsWith(optionValue, "[")) {
1245                sb.append(optionValue);
1246            }
1247            // need to be the base boolean value "false" is true in js - a non
1248            // empty string
1249            else if (optionValue.equalsIgnoreCase("false") || optionValue.equalsIgnoreCase("true")) {
1250                sb.append(optionValue);
1251            }
1252            // if it is a call back function, do not add the quotes
1253            else if (StringUtils.startsWith(optionValue, "function") && StringUtils.endsWith(optionValue, "}")) {
1254                sb.append(optionValue);
1255            }
1256            // for numerics
1257            else if (isNumber) {
1258                sb.append(optionValue);
1259            } else {
1260                sb.append("\"" + optionValue + "\"");
1261            }
1262        }
1263
1264        sb.append("}");
1265
1266        return sb.toString();
1267    }
1268
1269    @Override
1270    public void setComponentOptionsJSString(String componentOptionsJSString) {
1271        this.componentOptionsJSString = componentOptionsJSString;
1272    }
1273
1274    public String getEventCode() {
1275        String eventCode = "";
1276
1277        return eventCode;
1278    }
1279
1280    /**
1281     * When set if the condition is satisfied, the component will be displayed. The component MUST BE a
1282     * container or field type. progressiveRender is defined in a limited Spring EL syntax. Only valid
1283     * form property names, and, or, logical comparison operators (non-arithmetic), and the matches
1284     * clause are allowed. String and regex values must use single quotes ('), booleans must be either true or false,
1285     * numbers must be a valid double, either negative or positive.
1286     *
1287     * <p>
1288     * DO NOT use progressiveRender and a conditional refresh statement on the same component
1289     * unless it is known that the component will always be visible in all cases when a conditional refresh happens
1290     * (ie conditional refresh has progressiveRender's condition anded with its own condition).
1291     * </p>
1292     *
1293     * <p>
1294     * <b>If a component should be refreshed every time it is shown, use the progressiveRenderAndRefresh option
1295     * with this property instead.</b>
1296     * </p>
1297     *
1298     * @return String progressiveRender expression
1299     */
1300    public String getProgressiveRender() {
1301        return this.progressiveRender;
1302    }
1303
1304    /**
1305     * @param progressiveRender the progressiveRender to set
1306     */
1307    public void setProgressiveRender(String progressiveRender) {
1308        this.progressiveRender = progressiveRender;
1309    }
1310
1311    /**
1312     * When set if the condition is satisfied, the component will be refreshed.
1313     * The component MUST BE a container or field type. conditionalRefresh is
1314     * defined in a limited Spring EL syntax. Only valid form property names,
1315     * and, or, logical comparison operators (non-arithmetic), and the matches
1316     * clause are allowed. String and regex values must use single quotes ('),
1317     * booleans must be either true or false, numbers must be a valid double
1318     * either negative or positive. <br>
1319     * DO NOT use progressiveRender and conditionalRefresh on the same component
1320     * unless it is known that the component will always be visible in all cases
1321     * when a conditionalRefresh happens (ie conditionalRefresh has
1322     * progressiveRender's condition anded with its own condition). <b>If a
1323     * component should be refreshed every time it is shown, use the
1324     * progressiveRenderAndRefresh option with this property instead.</b>
1325     *
1326     * @return the conditionalRefresh
1327     */
1328    public String getConditionalRefresh() {
1329        return this.conditionalRefresh;
1330    }
1331
1332    /**
1333     * @param conditionalRefresh the conditionalRefresh to set
1334     */
1335    public void setConditionalRefresh(String conditionalRefresh) {
1336        this.conditionalRefresh = conditionalRefresh;
1337    }
1338
1339    /**
1340     * Control names used to control progressive disclosure, set internally
1341     * cannot be set.
1342     *
1343     * @return the progressiveDisclosureControlNames
1344     */
1345    public List<String> getProgressiveDisclosureControlNames() {
1346        return this.progressiveDisclosureControlNames;
1347    }
1348
1349    /**
1350     * The condition to show this component progressively converted to a js
1351     * expression, set internally cannot be set.
1352     *
1353     * @return the progressiveDisclosureConditionJs
1354     */
1355    public String getProgressiveDisclosureConditionJs() {
1356        return this.progressiveDisclosureConditionJs;
1357    }
1358
1359    /**
1360     * The condition to refresh this component converted to a js expression, set
1361     * internally cannot be set.
1362     *
1363     * @return the conditionalRefreshConditionJs
1364     */
1365    public String getConditionalRefreshConditionJs() {
1366        return this.conditionalRefreshConditionJs;
1367    }
1368
1369    /**
1370     * Control names used to control conditional refresh, set internally cannot
1371     * be set.
1372     *
1373     * @return the conditionalRefreshControlNames
1374     */
1375    public List<String> getConditionalRefreshControlNames() {
1376        return this.conditionalRefreshControlNames;
1377    }
1378
1379    /**
1380     * When progressiveRenderViaAJAX is true, this component will be retrieved
1381     * from the server when it first satisfies its progressive render condition.
1382     * After the first retrieval, it is hidden/shown in the html by the js when
1383     * its progressive condition result changes. <b>By default, this is false,
1384     * so components with progressive render capabilities will always be already
1385     * within the client html and toggled to be hidden or visible.</b>
1386     *
1387     * @return the progressiveRenderViaAJAX
1388     */
1389    public boolean isProgressiveRenderViaAJAX() {
1390        return this.progressiveRenderViaAJAX;
1391    }
1392
1393    /**
1394     * @param progressiveRenderViaAJAX the progressiveRenderViaAJAX to set
1395     */
1396    public void setProgressiveRenderViaAJAX(boolean progressiveRenderViaAJAX) {
1397        this.progressiveRenderViaAJAX = progressiveRenderViaAJAX;
1398    }
1399
1400    /**
1401     * If true, when the progressiveRender condition is satisfied, the component
1402     * will always be retrieved from the server and shown(as opposed to being
1403     * stored on the client, but hidden, after the first retrieval as is the
1404     * case with the progressiveRenderViaAJAX option). <b>By default, this is
1405     * false, so components with progressive render capabilities will always be
1406     * already within the client html and toggled to be hidden or visible.</b>
1407     *
1408     * @return the progressiveRenderAndRefresh
1409     */
1410    public boolean isProgressiveRenderAndRefresh() {
1411        return this.progressiveRenderAndRefresh;
1412    }
1413
1414    /**
1415     * @param progressiveRenderAndRefresh the progressiveRenderAndRefresh to set
1416     */
1417    public void setProgressiveRenderAndRefresh(boolean progressiveRenderAndRefresh) {
1418        this.progressiveRenderAndRefresh = progressiveRenderAndRefresh;
1419    }
1420
1421    /**
1422     * Specifies a property by name that when it value changes will
1423     * automatically perform a refresh on this component. This can be a comma
1424     * separated list of multiple properties that require this component to be
1425     * refreshed when any of them change. <Br>DO NOT use with progressiveRender
1426     * unless it is know that progressiveRender condition will always be
1427     * satisfied before one of these fields can be changed.
1428     *
1429     * @return the refreshWhenChanged
1430     */
1431    public String getRefreshWhenChanged() {
1432        return this.refreshWhenChanged;
1433    }
1434
1435    /**
1436     * @param refreshWhenChanged the refreshWhenChanged to set
1437     */
1438    public void setRefreshWhenChanged(String refreshWhenChanged) {
1439        this.refreshWhenChanged = refreshWhenChanged;
1440    }
1441
1442    /**
1443     * Control names which will refresh this component when they are changed, added
1444     * internally
1445     *
1446     * @return the refreshWhenChangedControlNames
1447     */
1448    public List<String> getRefreshWhenChangedControlNames() {
1449        return this.refreshWhenChangedControlNames;
1450    }
1451
1452    /**
1453     * @see Component#isRefreshedByAction()
1454     */
1455    public boolean isRefreshedByAction() {
1456        return refreshedByAction;
1457    }
1458
1459    /**
1460     * @see Component#setRefreshedByAction(boolean)
1461     */
1462    public void setRefreshedByAction(boolean refreshedByAction) {
1463        this.refreshedByAction = refreshedByAction;
1464    }
1465
1466    /**
1467     * @see Component#isResetDataOnRefresh()
1468     */
1469    public boolean isResetDataOnRefresh() {
1470        return resetDataOnRefresh;
1471    }
1472
1473    /**
1474     * @see Component#setResetDataOnRefresh(boolean)
1475     */
1476    public void setResetDataOnRefresh(boolean resetDataOnRefresh) {
1477        this.resetDataOnRefresh = resetDataOnRefresh;
1478    }
1479
1480    /**
1481     * @return the refresh
1482     */
1483    public boolean isRefresh() {
1484        return this.refresh;
1485    }
1486
1487    /**
1488     * @param refresh the refresh to set
1489     */
1490    public void setRefresh(boolean refresh) {
1491        this.refresh = refresh;
1492    }
1493
1494    /**
1495     * Name of a method on the controller that should be invoked as part of the component refresh and disclosure process
1496     *
1497     * <p>
1498     * During the component refresh or disclosure process it might be necessary to perform other operations, such as
1499     * preparing data or executing a business process. This allows the configuration of a method on the underlying
1500     * controller that should be called for the component refresh action. In this method, the necessary logic can be
1501     * performed and then the base component update method invoked to carry out the component refresh.
1502     * </p>
1503     *
1504     * <p>
1505     * Controller method to invoke must accept the form, binding result, request, and response arguments
1506     * </p>
1507     *
1508     * @return String valid controller method name
1509     */
1510    public String getRefreshDiscloseMethodToCall() {
1511        return refreshDiscloseMethodToCall;
1512    }
1513
1514    /**
1515     * Setter for the controller method to call for a refresh or disclosure action on this component
1516     *
1517     * @param refreshDiscloseMethodToCall
1518     */
1519    public void setRefreshDiscloseMethodToCall(String refreshDiscloseMethodToCall) {
1520        this.refreshDiscloseMethodToCall = refreshDiscloseMethodToCall;
1521    }
1522
1523    /**
1524     * @param skipInTabOrder flag
1525     */
1526    public void setSkipInTabOrder(boolean skipInTabOrder) {
1527        this.skipInTabOrder = skipInTabOrder;
1528    }
1529
1530    /**
1531     * Flag indicating that this component and its nested components must be
1532     * skipped when keyboard tabbing.
1533     *
1534     * @return the skipInTabOrder flag
1535     */
1536    public boolean isSkipInTabOrder() {
1537        return skipInTabOrder;
1538    }
1539
1540}