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