View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.element;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.api.exception.RiceRuntimeException;
21  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
22  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
23  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
24  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
25  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
26  import org.kuali.rice.krad.uif.UifConstants;
27  import org.kuali.rice.krad.uif.UifParameters;
28  import org.kuali.rice.krad.uif.UifPropertyPaths;
29  import org.kuali.rice.krad.uif.component.Component;
30  import org.kuali.rice.krad.uif.component.ComponentSecurity;
31  import org.kuali.rice.krad.uif.container.DialogGroup;
32  import org.kuali.rice.krad.uif.container.Group;
33  import org.kuali.rice.krad.uif.field.DataField;
34  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
35  import org.kuali.rice.krad.uif.util.ComponentFactory;
36  import org.kuali.rice.krad.uif.util.LifecycleElement;
37  import org.kuali.rice.krad.uif.util.ScriptUtils;
38  import org.kuali.rice.krad.uif.util.UrlInfo;
39  import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
40  import org.kuali.rice.krad.uif.view.FormView;
41  import org.kuali.rice.krad.uif.view.View;
42  import org.kuali.rice.krad.util.KRADUtils;
43  
44  import java.util.ArrayList;
45  import java.util.HashMap;
46  import java.util.List;
47  import java.util.Map;
48  
49  /**
50   * Field that presents an action that can be taken on the UI such as submitting the form or invoking a script.
51   *
52   * @author Kuali Rice Team (rice.collab@kuali.org)
53   */
54  @BeanTags({@BeanTag(name = "action", parent = "Uif-Action"),
55          @BeanTag(name = "actionImage", parent = "Uif-ActionImage"),
56          @BeanTag(name = "button", parent = "Uif-PrimaryActionButton"),
57          @BeanTag(name = "secondaryButton", parent = "Uif-SecondaryActionButton"),
58          @BeanTag(name = "buttonLarge", parent = "Uif-PrimaryActionButton-Large"),
59          @BeanTag(name = "secondaryButtonLarge", parent = "Uif-SecondaryActionButton-Large"),
60          @BeanTag(name = "buttonSmall", parent = "Uif-PrimaryActionButton-Small"),
61          @BeanTag(name = "secondaryButtonSmall", parent = "Uif-SecondaryActionButton-Small"),
62          @BeanTag(name = "buttonMini", parent = "Uif-PrimaryActionButton-Mini"),
63          @BeanTag(name = "secondaryButtonMini", parent = "Uif-SecondaryActionButton-Mini"),
64          @BeanTag(name = "actionLink", parent = "Uif-ActionLink"),
65          @BeanTag(name = "navigationActionLink", parent = "Uif-NavigationActionLink"),
66          @BeanTag(name = "navigationButton", parent = "Uif-NavigationActionButton"),
67          @BeanTag(name = "secondaryNavigationActionButton", parent = "Uif-SecondaryNavigationActionButton")})
68  public class Action extends ContentElementBase {
69      private static final long serialVersionUID = 1025672792657238829L;
70  
71      private String methodToCall;
72      private String actionEvent;
73      private String navigateToPageId;
74      private List<String> fieldsToSend;
75  
76      private String actionScript;
77      private UrlInfo actionUrl;
78  
79      private String actionLabel;
80      private boolean renderInnerTextSpan;
81  
82      private Image actionImage;
83      private String actionImagePlacement;
84  
85      private String iconClass;
86      private String actionIconPlacement;
87  
88      private String jumpToIdAfterSubmit;
89      private String jumpToNameAfterSubmit;
90      private String focusOnIdAfterSubmit;
91  
92      private boolean performClientSideValidation;
93      private boolean performDirtyValidation;
94      private boolean clearDirtyOnAction;
95      private boolean dirtyOnAction;
96  
97      private String preSubmitCall;
98      private String confirmationPromptText;
99      private DialogGroup confirmationDialog;
100 
101     private String dialogDismissOption;
102     private String dialogResponse;
103 
104     private boolean ajaxSubmit;
105     private String ajaxReturnType;
106     private String refreshId;
107     private String refreshPropertyName;
108 
109     private String successCallback;
110     private String errorCallback;
111 
112     private String loadingMessageText;
113     private boolean disableBlocking;
114 
115     private Map<String, String> additionalSubmitData;
116     private Map<String, String> actionParameters;
117 
118     private boolean evaluateDisabledOnKeyUp;
119 
120     private boolean defaultEnterKeyAction;
121 
122     private boolean disabled;
123     private String disabledReason;
124     private String disabledExpression;
125     private String disabledConditionJs;
126     private List<String> disabledConditionControlNames;
127 
128     private List<String> disabledWhenChangedPropertyNames;
129     private List<String> enabledWhenChangedPropertyNames;
130 
131     /**
132      * Sets initial field values and initializes collections.
133      */
134     public Action() {
135         super();
136 
137         actionImagePlacement = UifConstants.Position.LEFT.name();
138         actionIconPlacement = UifConstants.Position.LEFT.name();
139 
140         ajaxSubmit = true;
141 
142         successCallback = "";
143         errorCallback = "";
144         preSubmitCall = "";
145 
146         additionalSubmitData = new HashMap<String, String>();
147         actionParameters = new HashMap<String, String>();
148 
149         disabled = false;
150         disabledWhenChangedPropertyNames = new ArrayList<String>();
151         enabledWhenChangedPropertyNames = new ArrayList<String>();
152     }
153 
154     /**
155      * Sets the disabledExpression, if any, evaluates it and sets the disabled property.
156      *
157      * @param model top level object containing the data (could be the form or a
158      * @param parent parent component
159      */
160     public void performApplyModel(Object model, LifecycleElement parent) {
161         super.performApplyModel(model, parent);
162 
163         disabledExpression = this.getPropertyExpression("disabled");
164         if (disabledExpression != null) {
165             ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
166 
167             disabledExpression = expressionEvaluator.replaceBindingPrefixes(ViewLifecycle.getView(), this,
168                     disabledExpression);
169             disabled = (Boolean) expressionEvaluator.evaluateExpression(this.getContext(), disabledExpression);
170         }
171 
172         if (actionUrl != null) {
173             ViewLifecycle.getExpressionEvaluator().populatePropertyExpressionsFromGraph(actionUrl, false);
174             ViewLifecycle.getExpressionEvaluator().evaluateExpressionsOnConfigurable(ViewLifecycle.getView(),
175                     actionUrl, this.getContext());
176         }
177 
178         if (StringUtils.isNotBlank(confirmationPromptText) && (confirmationDialog != null) && StringUtils.isBlank(
179                 confirmationDialog.getPromptText())) {
180             confirmationDialog.setPromptText(confirmationPromptText);
181         }
182 
183         addConfirmDialogToView();
184     }
185 
186     /**
187      * For confirm text without a dialog, add instance of yes no dialog to view so it is already available
188      * on the client for dynamic dialog creation.
189      */
190     protected void addConfirmDialogToView() {
191         if (StringUtils.isBlank(confirmationPromptText) || (confirmationDialog != null)) {
192             return;
193         }
194 
195         boolean containsYesNoDialog = false;
196 
197         List<Group> viewDialogs = ViewLifecycle.getView().getDialogs();
198         if (viewDialogs == null) {
199             viewDialogs = new ArrayList<Group>();
200         } else {
201             for (Group dialogGroup : viewDialogs) {
202                 if (StringUtils.equals(ComponentFactory.YES_NO_DIALOG, dialogGroup.getId())) {
203                     containsYesNoDialog = true;
204                 }
205             }
206         }
207 
208         if (!containsYesNoDialog) {
209             Group confirmDialog = ComponentFactory.getYesNoDialog();
210             confirmDialog.setId(ComponentFactory.YES_NO_DIALOG);
211 
212             viewDialogs.add(confirmDialog);
213         }
214     }
215 
216     /**
217      * The following finalization is performed:
218      *
219      * <ul>
220      * <li>Add methodToCall action parameter if set and setup event code for
221      * setting action parameters</li>
222      * <li>Invoke method to build the data attributes and submit data for the action</li>
223      * <li>Compose the final onclick script for the action</li>
224      * <li>Parses the disabled expressions, if any, to equivalent javascript and evaluates the disable/enable when
225      * changed property names</li>
226      * </ul>
227      *
228      * {@inheritDoc}
229      */
230     @Override
231     public void performFinalize(Object model, LifecycleElement parent) {
232         super.performFinalize(model, parent);
233 
234         View view = ViewLifecycle.getView();
235         ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
236 
237         if (StringUtils.isNotEmpty(disabledExpression)
238                 && !disabledExpression.equalsIgnoreCase("true")
239                 && !disabledExpression.equalsIgnoreCase("false")) {
240             disabledConditionControlNames = new ArrayList<String>();
241             disabledConditionJs = ViewLifecycle.getExpressionEvaluator().parseExpression(disabledExpression,
242                     disabledConditionControlNames, this.getContext());
243         }
244 
245         List<String> adjustedDisablePropertyNames = new ArrayList<String>();
246         for (String propertyName : disabledWhenChangedPropertyNames) {
247             adjustedDisablePropertyNames.add(expressionEvaluator.replaceBindingPrefixes(view, this, propertyName));
248         }
249         disabledWhenChangedPropertyNames = adjustedDisablePropertyNames;
250 
251         List<String> adjustedEnablePropertyNames = new ArrayList<String>();
252         for (String propertyName : enabledWhenChangedPropertyNames) {
253             adjustedEnablePropertyNames.add(expressionEvaluator.replaceBindingPrefixes(view, this, propertyName));
254         }
255         enabledWhenChangedPropertyNames = adjustedEnablePropertyNames;
256 
257         // clear alt text to avoid screen reader confusion when using image in button with text
258         if (actionImage != null && StringUtils.isNotBlank(actionImagePlacement) && StringUtils.isNotBlank(actionLabel)) {
259             actionImage.setAltText("");
260         }
261 
262         // when icon only is set, add the icon class to the action
263         if (StringUtils.isNotBlank(iconClass) && (UifConstants.ICON_ONLY_PLACEMENT.equals(actionIconPlacement)
264                 || StringUtils.isBlank(actionLabel))) {
265             getCssClasses().add(iconClass);
266 
267             // force icon only placement
268             actionIconPlacement = UifConstants.ICON_ONLY_PLACEMENT;
269         }
270 
271         if (!actionParameters.containsKey(UifConstants.UrlParams.ACTION_EVENT) && StringUtils.isNotBlank(actionEvent)) {
272             actionParameters.put(UifConstants.UrlParams.ACTION_EVENT, actionEvent);
273         }
274 
275         if (StringUtils.isNotBlank(navigateToPageId)) {
276             actionParameters.put(UifParameters.NAVIGATE_TO_PAGE_ID, navigateToPageId);
277             if (StringUtils.isBlank(methodToCall)) {
278                 this.methodToCall = UifConstants.MethodToCallNames.NAVIGATE;
279             }
280         }
281 
282         if (!actionParameters.containsKey(UifConstants.CONTROLLER_METHOD_DISPATCH_PARAMETER_NAME) && StringUtils
283                 .isNotBlank(methodToCall)) {
284             actionParameters.put(UifConstants.CONTROLLER_METHOD_DISPATCH_PARAMETER_NAME, methodToCall);
285         }
286 
287         setupRefreshAction(view);
288 
289         // Apply dirty check if it is enabled for the view and the action requires it
290         if (view instanceof FormView) {
291             performDirtyValidation = performDirtyValidation && ((FormView) view).isApplyDirtyCheck();
292         }
293 
294         if (StringUtils.isBlank(getActionScript()) && (actionUrl != null) && actionUrl.isFullyConfigured()) {
295             String actionScript = ScriptUtils.buildFunctionCall(UifConstants.JsFunctions.REDIRECT, actionUrl.getHref());
296             setActionScript(actionScript);
297 
298             if (StringUtils.isNotBlank(actionUrl.getMethodToCall())) {
299                 ViewLifecycle.getViewPostMetadata().addAvailableMethodToCall(actionUrl.getMethodToCall());
300             }
301         }
302 
303         // add the method to call as an available method
304         if (StringUtils.isBlank(getActionScript()) && StringUtils.isNotBlank(methodToCall)) {
305             ViewLifecycle.getViewPostMetadata().addAvailableMethodToCall(methodToCall);
306         }
307 
308         // add additional submit data as accessible binding paths, and method to call as accessible method
309         if (isRender()) {
310             for (String additionalSubmitPath : additionalSubmitData.keySet()) {
311                 ViewLifecycle.getViewPostMetadata().addAccessibleBindingPath(additionalSubmitPath);
312             }
313 
314             if ((actionUrl != null) && actionUrl.isFullyConfigured() && StringUtils.isNotBlank(
315                     actionUrl.getMethodToCall())) {
316                 ViewLifecycle.getViewPostMetadata().addAccessibleMethodToCall(actionUrl.getMethodToCall());
317             } else if (StringUtils.isBlank(getActionScript()) && StringUtils.isNotBlank(methodToCall)) {
318                 ViewLifecycle.getViewPostMetadata().addAccessibleMethodToCall(methodToCall);
319             }
320         }
321 
322         buildActionData(view, model, parent);
323     }
324 
325     /**
326      * When the action is updating a component sets up the refresh script for the component (found by the
327      * given refresh id or refresh property name.
328      *
329      * @param view view instance the action belongs to
330      */
331     protected void setupRefreshAction(View view) {
332         // if refresh property or id is given, make return type update component
333         // TODO: what if the refresh id is the page id? we should set the return type as update page
334         if (StringUtils.isNotBlank(refreshPropertyName) || StringUtils.isNotBlank(refreshId)) {
335             ajaxReturnType = UifConstants.AjaxReturnTypes.UPDATECOMPONENT.getKey();
336         }
337 
338         // if refresh property name is given, adjust the binding and then attempt to find the
339         // component in the view index
340         Component refreshComponent = null;
341         if (StringUtils.isNotBlank(refreshPropertyName)) {
342             // TODO: does this support all binding prefixes?
343             if (refreshPropertyName.startsWith(UifConstants.NO_BIND_ADJUST_PREFIX)) {
344                 refreshPropertyName = StringUtils.removeStart(refreshPropertyName, UifConstants.NO_BIND_ADJUST_PREFIX);
345             } else if (StringUtils.isNotBlank(view.getDefaultBindingObjectPath())) {
346                 refreshPropertyName = view.getDefaultBindingObjectPath() + "." + refreshPropertyName;
347             }
348 
349             DataField dataField = view.getViewIndex().getDataFieldByPath(refreshPropertyName);
350             if (dataField != null) {
351                 refreshComponent = dataField;
352                 refreshId = refreshComponent.getId();
353             }
354         } else if (StringUtils.isNotBlank(refreshId)) {
355             Component component = view.getViewIndex().getComponentById(refreshId);
356             if (component != null) {
357                 refreshComponent = component;
358             }
359         }
360 
361         if (refreshComponent != null) {
362             refreshComponent.setRefreshedByAction(true);
363         }
364     }
365 
366     /**
367      * Builds the data attributes that will be read client side to determine how to
368      * handle the action and the additional data that should be submitted with the action
369      *
370      * <p>
371      * Note these data attributes will be exposed as a data map client side. The simple attributes (non object
372      * value) are also written out as attributes on the action element.
373      * </p>
374      *
375      * @param view view instance the action belongs to
376      * @param model model object containing the view data
377      * @param parent component the holds the action
378      */
379     protected void buildActionData(View view, Object model, LifecycleElement parent) {
380         HashMap<String, String> actionDataAttributes = new HashMap<String, String>();
381 
382         Map<String, String> dataDefaults =
383                 (Map<String, String>) (KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryBean(
384                         UifConstants.ACTION_DEFAULTS_MAP_ID));
385 
386         // map properties to data attributes
387         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.AJAX_SUBMIT,
388                 Boolean.toString(ajaxSubmit));
389         addActionDataSettingsValue(actionDataAttributes, dataDefaults,
390                 UifConstants.ActionDataAttributes.SUCCESS_CALLBACK, this.successCallback);
391         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.ERROR_CALLBACK,
392                 this.errorCallback);
393         addActionDataSettingsValue(actionDataAttributes, dataDefaults,
394                 UifConstants.ActionDataAttributes.PRE_SUBMIT_CALL, this.preSubmitCall);
395         addActionDataSettingsValue(actionDataAttributes, dataDefaults,
396                 UifConstants.ActionDataAttributes.LOADING_MESSAGE, this.loadingMessageText);
397         addActionDataSettingsValue(actionDataAttributes, dataDefaults,
398                 UifConstants.ActionDataAttributes.DISABLE_BLOCKING, Boolean.toString(this.disableBlocking));
399         addActionDataSettingsValue(actionDataAttributes, dataDefaults,
400                 UifConstants.ActionDataAttributes.AJAX_RETURN_TYPE, this.ajaxReturnType);
401         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.REFRESH_ID,
402                 this.refreshId);
403         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.VALIDATE,
404                 Boolean.toString(this.performClientSideValidation));
405         addActionDataSettingsValue(actionDataAttributes, dataDefaults,
406                 UifConstants.ActionDataAttributes.DIRTY_ON_ACTION, Boolean.toString(this.dirtyOnAction));
407         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.CLEAR_DIRTY,
408                 Boolean.toString(this.clearDirtyOnAction));
409         addActionDataSettingsValue(actionDataAttributes, dataDefaults,
410                 UifConstants.ActionDataAttributes.PERFORM_DIRTY_VALIDATION, Boolean.toString(
411                 this.performDirtyValidation));
412 
413         if (CollectionUtils.isNotEmpty(fieldsToSend)) {
414             addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.FIELDS_TO_SEND,
415                     ScriptUtils.translateValue(this.fieldsToSend));
416         }
417 
418         if (confirmationDialog != null) {
419             addDataAttribute(UifConstants.ActionDataAttributes.CONFIRM_DIALOG_ID, confirmationDialog.getId());
420         } else if (StringUtils.isNotBlank(confirmationPromptText)) {
421             addDataAttribute(UifConstants.ActionDataAttributes.CONFIRM_PROMPT_TEXT, confirmationPromptText);
422         }
423 
424         if (StringUtils.isNotBlank(dialogDismissOption)) {
425             addDataAttribute(UifConstants.DataAttributes.DISMISS_DIALOG_OPTION, dialogDismissOption);
426         }
427 
428         if (StringUtils.isNotBlank(dialogResponse)) {
429             addDataAttribute(UifConstants.DataAttributes.DISMISS_RESPONSE, dialogResponse);
430         }
431 
432         // all action parameters should be submitted with action
433         Map<String, String> submitData = new HashMap<String, String>();
434         for (String key : actionParameters.keySet()) {
435             String parameterPath = key;
436             if (!key.equals(UifConstants.CONTROLLER_METHOD_DISPATCH_PARAMETER_NAME)) {
437                 parameterPath = UifPropertyPaths.ACTION_PARAMETERS + "[" + key + "]";
438             }
439             submitData.put(parameterPath, actionParameters.get(key));
440         }
441 
442         for (String key : additionalSubmitData.keySet()) {
443             submitData.put(key, additionalSubmitData.get(key));
444         }
445 
446         // if focus id not set default to focus on action
447         if (focusOnIdAfterSubmit.equalsIgnoreCase(UifConstants.Order.NEXT_INPUT.toString())) {
448             focusOnIdAfterSubmit = UifConstants.Order.NEXT_INPUT.toString() + ":" + this.getId();
449         }
450 
451         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.FOCUS_ID,
452                 focusOnIdAfterSubmit);
453 
454         if (StringUtils.isNotBlank(jumpToIdAfterSubmit)) {
455             addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.ActionDataAttributes.JUMP_TO_ID,
456                     jumpToIdAfterSubmit);
457         } else if (StringUtils.isNotBlank(jumpToNameAfterSubmit)) {
458             addActionDataSettingsValue(actionDataAttributes, dataDefaults,
459                     UifConstants.ActionDataAttributes.JUMP_TO_NAME, jumpToNameAfterSubmit);
460         }
461 
462         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.DataAttributes.SUBMIT_DATA,
463                 ScriptUtils.toJSON(submitData));
464 
465         // build final onclick script
466         String onClickScript = this.getOnClickScript();
467         if (StringUtils.isNotBlank(actionScript)) {
468             onClickScript = ScriptUtils.appendScript(onClickScript, actionScript);
469         } else {
470             onClickScript = ScriptUtils.appendScript(onClickScript, "actionInvokeHandler(this);");
471         }
472 
473         //stop action if the action is disabled
474         if (disabled) {
475             this.addStyleClass("disabled");
476             this.setSkipInTabOrder(true);
477         }
478 
479         // on click script becomes a data attribute for use in a global handler on the client
480         addActionDataSettingsValue(actionDataAttributes, dataDefaults, UifConstants.DataAttributes.ONCLICK,
481                 KRADUtils.convertToHTMLAttributeSafeString(onClickScript));
482 
483         if (!actionDataAttributes.isEmpty()) {
484             this.getDataAttributes().putAll(actionDataAttributes);
485         }
486 
487         this.addDataAttribute(UifConstants.DataAttributes.ROLE, UifConstants.RoleTypes.ACTION);
488 
489         // add data attribute if this is the primary action
490         if (this.isDefaultEnterKeyAction()) {
491             this.addDataAttribute(UifConstants.DataAttributes.DEFAULT_ENTER_KEY_ACTION,
492                     Boolean.toString(this.isDefaultEnterKeyAction()));
493         }
494     }
495 
496     /**
497      * Adds the value passed to the valueMap with the key specified, if the value does not match the
498      * value which already exists in defaults (to avoid having to write out extra data that can later
499      * be derived from the defaults in the js client-side).
500      *
501      * @param valueMap the data map being constructed
502      * @param defaults defaults for validation messages
503      * @param key the variable name being added
504      * @param value the value set on this object as a String equivalent
505      */
506     protected void addActionDataSettingsValue(Map<String, String> valueMap, Map<String, String> defaults, String key,
507             String value) {
508         if (StringUtils.isBlank(value)) {
509             return;
510         }
511 
512         String defaultValue = defaults.get(key);
513         if (defaultValue == null || !value.equals(defaultValue)) {
514             valueMap.put(key, value);
515         }
516     }
517 
518     /**
519      * Name of the method that should be called when the action is selected
520      *
521      * <p>
522      * For a server side call (clientSideCall is false), gives the name of the
523      * method in the mapped controller that should be invoked when the action is
524      * selected. For client side calls gives the name of the script function
525      * that should be invoked when the action is selected
526      * </p>
527      *
528      * @return name of method to call
529      */
530     @BeanTagAttribute
531     public String getMethodToCall() {
532         return this.methodToCall;
533     }
534 
535     /**
536      * Setter for the actions method to call.
537      *
538      * @param methodToCall method to call
539      */
540     public void setMethodToCall(String methodToCall) {
541         this.methodToCall = methodToCall;
542     }
543 
544     /**
545      * Label text for the action
546      *
547      * <p>
548      * The label text is used by the template renderers to give a human readable
549      * label for the action. For buttons this generally is the button text,
550      * while for an action link it would be the links displayed text
551      * </p>
552      *
553      * @return label for action
554      */
555     @BeanTagAttribute
556     public String getActionLabel() {
557         return this.actionLabel;
558     }
559 
560     /**
561      * Setter for the actions label.
562      *
563      * @param actionLabel action label
564      */
565     public void setActionLabel(String actionLabel) {
566         this.actionLabel = actionLabel;
567     }
568 
569     /**
570      * When true, a span will be rendered around the actionLabel text.
571      *
572      * @return true if rendering a span around actionLabel, false otherwise
573      */
574     @BeanTagAttribute
575     public boolean isRenderInnerTextSpan() {
576         return renderInnerTextSpan;
577     }
578 
579     /**
580      * Setter for {@link org.kuali.rice.krad.uif.element.Action#isRenderInnerTextSpan()}.
581      *
582      * @param renderInnerTextSpan property value
583      */
584     public void setRenderInnerTextSpan(boolean renderInnerTextSpan) {
585         this.renderInnerTextSpan = renderInnerTextSpan;
586     }
587 
588     /**
589      * Image to use for the action
590      *
591      * <p>
592      * When the action image component is set (and render is true) the image will be
593      * used to present the action as opposed to the default (input submit). For
594      * action link templates the image is used for the link instead of the
595      * action link text
596      * </p>
597      *
598      * @return action image
599      */
600     @BeanTagAttribute
601     public Image getActionImage() {
602         return this.actionImage;
603     }
604 
605     /**
606      * Setter for the action image field.
607      *
608      * @param actionImage action image
609      */
610     public void setActionImage(Image actionImage) {
611         this.actionImage = actionImage;
612     }
613 
614     /**
615      * The css class (some which exist in bootstrap css) to use to render an icon for this action.
616      *
617      * @return the icon css class
618      */
619     @BeanTagAttribute
620     public String getIconClass() {
621         return iconClass;
622     }
623 
624     /**
625      * Setter for {@link org.kuali.rice.krad.uif.element.Action#getIconClass()}.
626      *
627      * @param iconClass property value
628      */
629     public void setIconClass(String iconClass) {
630         this.iconClass = iconClass;
631     }
632 
633     /**
634      * For an <code>Action</code> that is part of a
635      * <code>NavigationGroup</code>, the navigate to page id can be set to
636      * configure the page that should be navigated to when the action is
637      * selected.
638      *
639      * <p>
640      * Support exists in the <code>UifControllerBase</code> for handling
641      * navigation between pages.
642      * </p>
643      *
644      * @return id of page that should be rendered when the action item is
645      *         selected
646      */
647     @BeanTagAttribute
648     public String getNavigateToPageId() {
649         return this.navigateToPageId;
650     }
651 
652     /**
653      * Setter for {@link #getNavigateToPageId()}.
654      *
655      * @param navigateToPageId property value
656      */
657     public void setNavigateToPageId(String navigateToPageId) {
658         this.navigateToPageId = navigateToPageId;
659     }
660 
661     /**
662      * Limits the field data to send on a refresh methodToCall server call to the names/group id/field id
663      * specified in this list.
664      *
665      * <p>The names in the list should be the propertyNames of the fields sent with this request.  A wildcard("*")
666      * can be used at the END of a name to specify all fields with names that begin with the string
667      * before the wildcard.  If the array contains 1 item with the keyword "NONE", then no form fields are sent.
668      * In addition, A group id or field id with the "#" id selector prefix can be used to send all inputs which
669      * are nested within them. Note that this only limits the fields which exist on the form and data required
670      * by the KRAD framework is still sent (eg, methodToCall, formKey, sessionId, etc.)</p>
671      *
672      * @return the only input fields to send by name with the action request
673      */
674     @BeanTagAttribute
675     public List<String> getFieldsToSend() {
676         return fieldsToSend;
677     }
678 
679     /**
680      * @see Action#fieldsToSend
681      */
682     public void setFieldsToSend(List<String> fieldsToSend) {
683         this.fieldsToSend = fieldsToSend;
684     }
685 
686     /**
687      * Name of the event that will be set when the action is invoked
688      *
689      * <p>
690      * Action events can be looked at by the view or components in order to render differently depending on
691      * the action requested.
692      * </p>
693      *
694      * @return action event name
695      * @see org.kuali.rice.krad.uif.UifConstants.ActionEvents
696      */
697     @BeanTagAttribute
698     public String getActionEvent() {
699         return actionEvent;
700     }
701 
702     /**
703      * Setter for {@link #getActionEvent()}.
704      *
705      * @param actionEvent property value
706      */
707     public void setActionEvent(String actionEvent) {
708         this.actionEvent = actionEvent;
709     }
710 
711     /**
712      * Map of additional data that will be posted when the action is invoked.
713      *
714      * <p>
715      * Each entry in this map will be sent as a request parameter when the action is chosen. Note this in
716      * addition to the form data that is sent. For example, suppose the model contained a property named
717      * number and a boolean named showActive, we can send values for this properties by adding the following
718      * entries to this map:
719      * {'number':'a13', 'showActive', 'true'}
720      * </p>
721      *
722      * <p>
723      * The additionalSubmitData map is different from the actionParameters map. All name/value pairs given as
724      * actionParameters populated the form map actionParameters. While name/value pair given in additionalSubmitData
725      * populate different form (model) properties.
726      * </p>
727      *
728      * @return additional key/value pairs to submit
729      */
730     @BeanTagAttribute
731     public Map<String, String> getAdditionalSubmitData() {
732         return additionalSubmitData;
733     }
734 
735     /**
736      * Setter for map holding additional data to post.
737      *
738      * @param additionalSubmitData property value
739      */
740     public void setAdditionalSubmitData(Map<String, String> additionalSubmitData) {
741         this.additionalSubmitData = additionalSubmitData;
742     }
743 
744     /**
745      * Parameters that should be sent when the action is invoked
746      *
747      * <p>
748      * Action renderer will decide how the parameters are sent for the action
749      * (via script generated hiddens, or script parameters, ...)
750      * </p>
751      *
752      * <p>
753      * Can be set by other components such as the <code>CollectionGroup</code>
754      * to provide the context the action is in (such as the collection name and
755      * line the action applies to)
756      * </p>
757      *
758      * @return action parameters
759      */
760     @BeanTagAttribute
761     public Map<String, String> getActionParameters() {
762         return this.actionParameters;
763     }
764 
765     /**
766      * Setter for {@link #getActionParameters()}.
767      *
768      * @param actionParameters property value
769      */
770     public void setActionParameters(Map<String, String> actionParameters) {
771         this.actionParameters = actionParameters;
772     }
773 
774     /**
775      * Convenience method to add a parameter to the action parameters Map.
776      *
777      * @param parameterName name of parameter to add
778      * @param parameterValue value of parameter to add
779      */
780     public void addActionParameter(String parameterName, String parameterValue) {
781         if (actionParameters == null) {
782             this.actionParameters = new HashMap<String, String>();
783         }
784 
785         this.actionParameters.put(parameterName, parameterValue);
786     }
787 
788     /**
789      * Gets an action parameter by name.
790      *
791      * @param parameterName parameter name
792      * @return action parameter
793      */
794     public String getActionParameter(String parameterName) {
795         return this.actionParameters.get(parameterName);
796     }
797 
798     /**
799      * Action Security object that indicates what authorization (permissions) exist for the action.
800      *
801      * @return ActionSecurity instance
802      */
803     public ActionSecurity getActionSecurity() {
804         return (ActionSecurity) super.getComponentSecurity();
805     }
806 
807     /**
808      * Override to assert a {@link ActionSecurity} instance is set.
809      *
810      * @param componentSecurity instance of ActionSecurity
811      */
812     @Override
813     public void setComponentSecurity(ComponentSecurity componentSecurity) {
814         if ((componentSecurity != null) && !(componentSecurity instanceof ActionSecurity)) {
815             throw new RiceRuntimeException("Component security for Action should be instance of ActionSecurity");
816         }
817 
818         super.setComponentSecurity(componentSecurity);
819     }
820 
821     /**
822      * {@inheritDoc}
823      */
824     @Override
825     protected void initializeComponentSecurity() {
826         if (getComponentSecurity() == null) {
827             setComponentSecurity(KRADUtils.createNewObjectFromClass(ActionSecurity.class));
828         }
829     }
830 
831     /**
832      * Indicates whether or not to perform action auth.
833      *
834      * @return true to perform action auth
835      */
836     @BeanTagAttribute
837     public boolean isPerformActionAuthz() {
838         initializeComponentSecurity();
839 
840         return getActionSecurity().isPerformActionAuthz();
841     }
842 
843     /**
844      * Setter for {@link #isPerformActionAuthz()}.
845      *
846      * @param performActionAuthz property value
847      */
848     public void setPerformActionAuthz(boolean performActionAuthz) {
849         initializeComponentSecurity();
850 
851         getActionSecurity().setPerformActionAuthz(performActionAuthz);
852     }
853 
854     /**
855      * Indicates whether or not to perform line action auth.
856      *
857      * @return true to perform line action auth
858      */
859     @BeanTagAttribute
860     public boolean isPerformLineActionAuthz() {
861         initializeComponentSecurity();
862 
863         return getActionSecurity().isPerformLineActionAuthz();
864     }
865 
866     /**
867      * Setter for {@link #isPerformActionAuthz()}.
868      *
869      * @param performLineActionAuthz property value
870      */
871     public void setPerformLineActionAuthz(boolean performLineActionAuthz) {
872         initializeComponentSecurity();
873 
874         getActionSecurity().setPerformLineActionAuthz(performLineActionAuthz);
875     }
876 
877     /**
878      * Gets the id to jump to after submit.
879      *
880      * @return the jumpToIdAfterSubmit
881      */
882     @BeanTagAttribute
883     public String getJumpToIdAfterSubmit() {
884         return this.jumpToIdAfterSubmit;
885     }
886 
887     /**
888      * The id to jump to in the next page, the element with this id will be
889      * jumped to automatically when the new page is retrieved after a submit.
890      * Using "TOP" or "BOTTOM" will jump to the top or the bottom of the
891      * resulting page. Passing in nothing for both jumpToIdAfterSubmit and
892      * jumpToNameAfterSubmit will result in this Action being jumped to by
893      * default if it is present on the new page. WARNING: jumpToIdAfterSubmit
894      * always takes precedence over jumpToNameAfterSubmit, if set.
895      *
896      * @param jumpToIdAfterSubmit the jumpToIdAfterSubmit to set
897      */
898     public void setJumpToIdAfterSubmit(String jumpToIdAfterSubmit) {
899         this.jumpToIdAfterSubmit = jumpToIdAfterSubmit;
900     }
901 
902     /**
903      * The name to jump to in the next page, the element with this name will be
904      * jumped to automatically when the new page is retrieved after a submit.
905      * Passing in nothing for both jumpToIdAfterSubmit and jumpToNameAfterSubmit
906      * will result in this Action being jumped to by default if it is
907      * present on the new page. WARNING: jumpToIdAfterSubmit always takes
908      * precedence over jumpToNameAfterSubmit, if set.
909      *
910      * @return the jumpToNameAfterSubmit
911      */
912     @BeanTagAttribute
913     public String getJumpToNameAfterSubmit() {
914         return this.jumpToNameAfterSubmit;
915     }
916 
917     /**
918      * Setter for {@link #getJumpToIdAfterSubmit()}.
919      *
920      * @param jumpToNameAfterSubmit the jumpToNameAfterSubmit to set
921      */
922     public void setJumpToNameAfterSubmit(String jumpToNameAfterSubmit) {
923         this.jumpToNameAfterSubmit = jumpToNameAfterSubmit;
924     }
925 
926     /**
927      * The element to place focus on in the new page after the new page
928      * is retrieved.
929      *
930      * <p>The following are allowed:
931      * <ul>
932      * <li>A valid element id</li>
933      * <li>"FIRST" will focus on the first visible input element on the form</li>
934      * <li>"SELF" will result in this Action being focused (action bean defaults to "SELF")</li>
935      * <li>"LINE_FIRST" will result in the first input of the collection line to be focused (if available)</li>
936      * <li>"NEXT_INPUT" will result in the next available input that exists after this Action to be focused
937      * (only if this action still exists on the page)</li>
938      * </ul>
939      * </p>
940      *
941      * @return the focusOnAfterSubmit
942      */
943     @BeanTagAttribute
944     public String getFocusOnIdAfterSubmit() {
945         return this.focusOnIdAfterSubmit;
946     }
947 
948     /**
949      * Setter for {@link #getFocusOnIdAfterSubmit()}.
950      *
951      * @param focusOnIdAfterSubmit the focusOnAfterSubmit to set
952      */
953     public void setFocusOnIdAfterSubmit(String focusOnIdAfterSubmit) {
954         this.focusOnIdAfterSubmit = focusOnIdAfterSubmit;
955     }
956 
957     /**
958      * Indicates whether the form data should be validated on the client side.
959      *
960      * @return true if validation should occur, false otherwise
961      */
962     @BeanTagAttribute
963     public boolean isPerformClientSideValidation() {
964         return this.performClientSideValidation;
965     }
966 
967     /**
968      * Setter for the client side validation flag.
969      *
970      * @param performClientSideValidation property value
971      */
972     public void setPerformClientSideValidation(boolean performClientSideValidation) {
973         this.performClientSideValidation = performClientSideValidation;
974     }
975 
976     /**
977      * Client side javascript to be executed when this actionField is clicked.
978      *
979      * <p>
980      * This overrides the default action for this Action so the method
981      * called must explicitly submit, navigate, etc. through js, if necessary.
982      * In addition, this js occurs AFTER onClickScripts set on this field, it
983      * will be the last script executed by the click event. Sidenote: This js is
984      * always called after hidden actionParameters and methodToCall methods are
985      * written by the js to the html form.
986      * </p>
987      *
988      * @return the actionScript
989      */
990     @BeanTagAttribute
991     public String getActionScript() {
992         return this.actionScript;
993     }
994 
995     /**
996      * Setter for {@link #getActionScript()}.
997      *
998      * @param actionScript the actionScript to set
999      */
1000     public void setActionScript(String actionScript) {
1001         if (StringUtils.isNotBlank(actionScript) && !StringUtils.endsWith(actionScript, ";")) {
1002             actionScript = actionScript + ";";
1003         }
1004 
1005         this.actionScript = actionScript;
1006     }
1007 
1008     /**
1009      * Url to open when the action item is selected
1010      *
1011      * <p>
1012      * This makes the action behave like a standard link. Instead of posting the form, the configured URL will
1013      * simply be opened (using window.open). For using standard post actions these does not need to be configured.
1014      * </p>
1015      *
1016      * @return Url info instance for the configuration action link
1017      */
1018     @BeanTagAttribute
1019     public UrlInfo getActionUrl() {
1020         return actionUrl;
1021     }
1022 
1023     /**
1024      * Setter for {@link #getActionUrl()}.
1025      *
1026      * @param actionUrl property value
1027      */
1028     public void setActionUrl(UrlInfo actionUrl) {
1029         this.actionUrl = actionUrl;
1030     }
1031 
1032     /**
1033      * Setter for {@link #isPerformDirtyValidation()}.
1034      *
1035      * @param performDirtyValidation the blockValidateDirty to set
1036      */
1037     public void setPerformDirtyValidation(boolean performDirtyValidation) {
1038         this.performDirtyValidation = performDirtyValidation;
1039     }
1040 
1041     /**
1042      * Indicates whether or not to perform dirty validation.
1043      *
1044      * @return true to perform dirty validation
1045      */
1046     @BeanTagAttribute
1047     public boolean isPerformDirtyValidation() {
1048         return performDirtyValidation;
1049     }
1050 
1051     /**
1052      * True to make this action clear the dirty flag before submitting.
1053      *
1054      * <p>This will clear both the dirtyForm flag on the form and the count of fields considered dirty on the
1055      * client-side.  This will only be performed if this action is a request based action.</p>
1056      *
1057      * @return true if the dirty
1058      */
1059     @BeanTagAttribute
1060     public boolean isClearDirtyOnAction() {
1061         return clearDirtyOnAction;
1062     }
1063 
1064     /**
1065      * Setter for {@link #isClearDirtyOnAction()}.
1066      *
1067      * @param clearDirtyOnAction property value
1068      */
1069     public void setClearDirtyOnAction(boolean clearDirtyOnAction) {
1070         this.clearDirtyOnAction = clearDirtyOnAction;
1071     }
1072 
1073     /**
1074      * When true, this action will mark the form dirty by incrementing the dirty field count, but if this action
1075      * refreshes the entire view this will be lost (most actions only refresh the page)
1076      *
1077      * <p>This will increase count of fields considered dirty on the
1078      * client-side by 1.  This will only be performed if this action is a request based action.</p>
1079      *
1080      * @return true if this action is considered dirty, false otherwise
1081      */
1082     @BeanTagAttribute
1083     public boolean isDirtyOnAction() {
1084         return dirtyOnAction;
1085     }
1086 
1087     /**
1088      * Set to true, if this action is considered one that changes the form's data (makes the form dirty).
1089      *
1090      * @param dirtyOnAction property value
1091      */
1092     public void setDirtyOnAction(boolean dirtyOnAction) {
1093         this.dirtyOnAction = dirtyOnAction;
1094     }
1095 
1096     /**
1097      * Indicates whether the action (input or button) is disabled (doesn't allow interaction).
1098      *
1099      * @return true if the action field is disabled, false if not
1100      */
1101     @BeanTagAttribute
1102     public boolean isDisabled() {
1103         return disabled;
1104     }
1105 
1106     /**
1107      * Setter for the disabled indicator.
1108      *
1109      * @param disabled property value
1110      */
1111     public void setDisabled(boolean disabled) {
1112         this.disabled = disabled;
1113     }
1114 
1115     /**
1116      * If the action field is disabled, gives a reason for why which will be displayed as a tooltip
1117      * on the action field (button).
1118      *
1119      * @return disabled reason text
1120      * @see #isDisabled()
1121      */
1122     @BeanTagAttribute
1123     public String getDisabledReason() {
1124         return disabledReason;
1125     }
1126 
1127     /**
1128      * Setter for the disabled reason text.
1129      *
1130      * @param disabledReason property value
1131      */
1132     public void setDisabledReason(String disabledReason) {
1133         this.disabledReason = disabledReason;
1134     }
1135 
1136     /**
1137      * Gets the action image placement.
1138      *
1139      * @return action image placement
1140      */
1141     @BeanTagAttribute
1142     public String getActionImagePlacement() {
1143         return actionImagePlacement;
1144     }
1145 
1146     /**
1147      * Set to TOP, BOTTOM, LEFT, RIGHT to position image at that location within the button.
1148      * For the subclass ActionLinkField only LEFT and RIGHT are allowed.  When set to blank/null/IMAGE_ONLY, the image
1149      * itself will be the Action, if no value is set the default is ALWAYS LEFT, you must explicitly set
1150      * blank/null/IMAGE_ONLY to use ONLY the image as the Action.
1151      *
1152      * @param actionImagePlacement action image placement indicator
1153      */
1154     public void setActionImagePlacement(String actionImagePlacement) {
1155         this.actionImagePlacement = actionImagePlacement;
1156     }
1157 
1158     /**
1159      * Gets the action icon placement.
1160      *
1161      * @return action icon placement
1162      */
1163     @BeanTagAttribute
1164     public String getActionIconPlacement() {
1165         return actionIconPlacement;
1166     }
1167 
1168     /**
1169      * Setter for {@link #getActionIconPlacement()}.
1170      *
1171      * @param actionIconPlacement property value
1172      */
1173     public void setActionIconPlacement(String actionIconPlacement) {
1174         this.actionIconPlacement = actionIconPlacement;
1175     }
1176 
1177     /**
1178      * Gets the script which needs to be invoked before the form is submitted
1179      *
1180      * <p>
1181      * The preSubmitCall can carry out custom logic for the action before the submit occurs. The value should
1182      * be given as one or more lines of script and should return a boolean. If false is returned from the call,
1183      * the submit is not carried out. Furthermore, the preSubmitCall can refer to the request object through the
1184      * variable 'kradRequest' or 'this'. This gives full access over the request for doing such things as
1185      * adding additional data
1186      * </p>
1187      *
1188      * <p>
1189      * Examples 'return doFunction(kradRequest);', 'var valid=true;return valid;'
1190      * </p>
1191      *
1192      * <p>
1193      * The preSubmit call will be invoked both for ajax and non-ajax submits
1194      * </p>
1195      *
1196      * @return script text that will be invoked before form submission
1197      */
1198     @BeanTagAttribute
1199     public String getPreSubmitCall() {
1200         return preSubmitCall;
1201     }
1202 
1203     /**
1204      * Setter for {@link #getPreSubmitCall()}.
1205      *
1206      * @param preSubmitCall property value
1207      */
1208     public void setPreSubmitCall(String preSubmitCall) {
1209         this.preSubmitCall = preSubmitCall;
1210     }
1211 
1212     /**
1213      * Text to display as a confirmation of the action.
1214      *
1215      * <p>When this text is displayed the user will receive a confirmation when the action is taken. The user
1216      * can then cancel the action, or continue. If set, {@link Action#getConfirmationDialog()} will be used
1217      * to build the dialog. Otherwise, the dialog is created dynamically on the client.</p>
1218      *
1219      * @return text to display in a confirmation for the action
1220      */
1221     public String getConfirmationPromptText() {
1222         return confirmationPromptText;
1223     }
1224 
1225     /**
1226      * @see Action#getConfirmationPromptText()
1227      */
1228     public void setConfirmationPromptText(String confirmationPromptText) {
1229         this.confirmationPromptText = confirmationPromptText;
1230     }
1231 
1232     /**
1233      * Dialog to use an a confirmation for the action.
1234      *
1235      * <p>For custom confirmation dialogs this can be set to any valid dialog group. It is expected that the
1236      * dialog have at least one action with the dialog response of 'true' to continue the action.</p>
1237      *
1238      * @return dialog group instance to use an a confirmation
1239      */
1240     public DialogGroup getConfirmationDialog() {
1241         return confirmationDialog;
1242     }
1243 
1244     /**
1245      * @see Action#getConfirmationDialog()
1246      */
1247     public void setConfirmationDialog(DialogGroup confirmationDialog) {
1248         this.confirmationDialog = confirmationDialog;
1249     }
1250 
1251     /**
1252      * If the action is within a {@link org.kuali.rice.krad.uif.container.DialogGroup} it can be configured to
1253      * dismiss the dialog using this property.
1254      *
1255      * <p>A dialog can be dismissed at various points of the action using the values:
1256      *    IMMEDIATE - dismiss dialog right away (and do nothig further)
1257      *    PRESUBMIT - run the action presubmit (which can include validation), if successful close the dialog and
1258      *                do nothing further
1259      *    REQUEST - carry out the action request as usual and dismiss the dialog when the server request is made
1260      * </p>
1261      *
1262      * <p>Note the id for the dialog that will be dismissed is automatically associated with the action when
1263      * the dialog is shown.</p>
1264      *
1265      * @return String option for dismissing a dialog
1266      */
1267     public String getDialogDismissOption() {
1268         return dialogDismissOption;
1269     }
1270 
1271     /**
1272      * @see Action#getDialogDismissOption()
1273      */
1274     public void setDialogDismissOption(String dialogDismissOption) {
1275         this.dialogDismissOption = dialogDismissOption;
1276     }
1277 
1278     /**
1279      * If the action is within a {@link org.kuali.rice.krad.uif.container.DialogGroup} it can be configured to
1280      * return a response using this property.
1281      *
1282      * <p>Dialogs can be used to get a response from a user, either a simple confirmation (true or false), or to
1283      * choice from a list of options. The responses for the dialog are created with action components. The property
1284      * specifies the action value that should be returned (when chosen) to the dialog response handlers. For example,
1285      * in a simple confirmation one action will have a dialog response 'false', and the other will have a dialog
1286      * response 'true'.</p>
1287      *
1288      * @return String dialog response value
1289      */
1290     public String getDialogResponse() {
1291         return dialogResponse;
1292     }
1293 
1294     /**
1295      * @see Action#getDialogResponse()
1296      */
1297     public void setDialogResponse(String dialogResponse) {
1298         this.dialogResponse = dialogResponse;
1299     }
1300 
1301     /**
1302      * When this property is set to true it will submit the form using Ajax instead of the browser submit. Will default
1303      * to updating the page contents
1304      *
1305      * @return boolean
1306      */
1307     @BeanTagAttribute
1308     public boolean isAjaxSubmit() {
1309         return ajaxSubmit;
1310     }
1311 
1312     /**
1313      * Setter for {@link #isAjaxSubmit()}.
1314      *
1315      * @param ajaxSubmit property value
1316      */
1317     public void setAjaxSubmit(boolean ajaxSubmit) {
1318         this.ajaxSubmit = ajaxSubmit;
1319     }
1320 
1321     /**
1322      * Gets the return type for the ajax call
1323      *
1324      * <p>
1325      * The ajax return type indicates how the response content will be handled in the client. Typical
1326      * examples include updating a component, the page, or doing a redirect.
1327      * </p>
1328      *
1329      * @return return type
1330      * @see org.kuali.rice.krad.uif.UifConstants.AjaxReturnTypes
1331      */
1332     @BeanTagAttribute
1333     public String getAjaxReturnType() {
1334         return this.ajaxReturnType;
1335     }
1336 
1337     /**
1338      * Setter for the type of ajax return.
1339      *
1340      * @param ajaxReturnType property value
1341      */
1342     public void setAjaxReturnType(String ajaxReturnType) {
1343         this.ajaxReturnType = ajaxReturnType;
1344     }
1345 
1346     /**
1347      * Indicates if the action response should be displayed in a lightbox.
1348      *
1349      * @return true if response should be rendered in a lightbox, false if not
1350      */
1351     @BeanTagAttribute
1352     public boolean isDisplayResponseInLightBox() {
1353         return StringUtils.equals(this.ajaxReturnType, UifConstants.AjaxReturnTypes.DISPLAYLIGHTBOX.getKey());
1354     }
1355 
1356     /**
1357      * Setter for indicating the response should be rendered in a lightbox.
1358      *
1359      * @param displayResponseInLightBox property value
1360      */
1361     public void setDisplayResponseInLightBox(boolean displayResponseInLightBox) {
1362         if (displayResponseInLightBox) {
1363             this.ajaxReturnType = UifConstants.AjaxReturnTypes.DISPLAYLIGHTBOX.getKey();
1364         }
1365         // if display lightbox is false and it was previously true, set to default of update page
1366         else if (StringUtils.equals(this.ajaxReturnType, UifConstants.AjaxReturnTypes.DISPLAYLIGHTBOX.getKey())) {
1367             this.ajaxReturnType = UifConstants.AjaxReturnTypes.UPDATEPAGE.getKey();
1368         }
1369     }
1370 
1371     /**
1372      * Gets the script which will be invoked on a successful ajax call
1373      *
1374      * <p>
1375      * The successCallback can carry out custom logic after a successful ajax submission has been made. The
1376      * value can contain one or more script statements. In addition, the response contents can be accessed
1377      * through the variable 'responseContents'
1378      * </p>
1379      *
1380      * <p>
1381      * Examples 'handleSuccessfulUpdate(responseContents);'
1382      * </p>
1383      *
1384      * <p>
1385      * The successCallback may only be specified when {@link #isAjaxSubmit()} is true
1386      * </p>
1387      *
1388      * @return script to be executed when the action is successful
1389      */
1390     @BeanTagAttribute
1391     public String getSuccessCallback() {
1392         return successCallback;
1393     }
1394 
1395     /**
1396      * Setter for successCallback.
1397      *
1398      * @param successCallback property value
1399      */
1400     public void setSuccessCallback(String successCallback) {
1401         this.successCallback = successCallback;
1402     }
1403 
1404     /**
1405      * Gets the script which will be invoked when the action fails due to problems in the ajax call or
1406      * the return of an incident report
1407      *
1408      * <p>
1409      * The errorCallback can carry out custom logic after a failed ajax submission. The
1410      * value can contain one or more script statements. In addition, the response contents can be accessed
1411      * through the variable 'responseContents'
1412      * </p>
1413      *
1414      * <p>
1415      * Examples 'handleFailedUpdate(responseContents);'
1416      * </p>
1417      *
1418      * <p>
1419      * The errorCallback may only be specified when {@link #isAjaxSubmit()} is true
1420      * </p>
1421      *
1422      * @return script to be executed when the action is successful
1423      */
1424     @BeanTagAttribute
1425     public String getErrorCallback() {
1426         return errorCallback;
1427     }
1428 
1429     /**
1430      * Setter for {@link #getErrorCallback()}.
1431      *
1432      * @param errorCallback property value
1433      */
1434     public void setErrorCallback(String errorCallback) {
1435         this.errorCallback = errorCallback;
1436     }
1437 
1438     /**
1439      * Id for the component that should be refreshed after the action completes
1440      *
1441      * <p>
1442      * Either refresh id or refresh property name can be set to configure the component that should
1443      * be refreshed after the action completes. If both are blank, the page will be refreshed
1444      * </p>
1445      *
1446      * @return valid component id
1447      */
1448     @BeanTagAttribute
1449     public String getRefreshId() {
1450         return refreshId;
1451     }
1452 
1453     /**
1454      * Setter for the {@link #getRefreshId()}.
1455      *
1456      * @param refreshId property value
1457      */
1458     public void setRefreshId(String refreshId) {
1459         this.refreshId = refreshId;
1460     }
1461 
1462     /**
1463      * Property name for the {@link org.kuali.rice.krad.uif.field.DataField} that should be refreshed after the action
1464      * completes
1465      *
1466      * <p>
1467      * Either refresh id or refresh property name can be set to configure the component that should
1468      * be refreshed after the action completes. If both are blank, the page will be refreshed
1469      * </p>
1470      *
1471      * <p>
1472      * Property name will be adjusted to use the default binding path unless it contains the form prefix
1473      * </p>
1474      *
1475      * @return valid property name with an associated DataField
1476      * @see org.kuali.rice.krad.uif.UifConstants#NO_BIND_ADJUST_PREFIX
1477      */
1478     @BeanTagAttribute
1479     public String getRefreshPropertyName() {
1480         return refreshPropertyName;
1481     }
1482 
1483     /**
1484      * Setter for the property name of the DataField that should be refreshed.
1485      *
1486      * @param refreshPropertyName property value
1487      */
1488     public void setRefreshPropertyName(String refreshPropertyName) {
1489         this.refreshPropertyName = refreshPropertyName;
1490     }
1491 
1492     /**
1493      * Gets the loading message used by action's blockUI.
1494      *
1495      * @return String if String is not null, used in place of loading message
1496      */
1497     @BeanTagAttribute
1498     public String getLoadingMessageText() {
1499         return loadingMessageText;
1500     }
1501 
1502     /**
1503      * When this property is set, it is used in place of the loading message text used by the blockUI.
1504      *
1505      * @param loadingMessageText property value
1506      */
1507     public void setLoadingMessageText(String loadingMessageText) {
1508         this.loadingMessageText = loadingMessageText;
1509     }
1510 
1511     /**
1512      * Indicates whether blocking for the action should be disabled
1513      *
1514      * <p>
1515      * By default when an action is invoked part of the page or the entire window is blocked until
1516      * the action completes. If this property is set to true the blocking will not be displayed.
1517      * </p>
1518      *
1519      * <p>
1520      * Currently if an action returns a file download, this property should be set to true. If not, the blocking
1521      * will never get unblocked (because the page does not get notification a file was downloaded)
1522      * </p>
1523      *
1524      * @return true if blocking should be disabled, false if not
1525      */
1526     @BeanTagAttribute
1527     public boolean isDisableBlocking() {
1528         return disableBlocking;
1529     }
1530 
1531     /**
1532      * Setter for disabling blocking when the action is invoked.
1533      *
1534      * @param disableBlocking property value
1535      */
1536     public void setDisableBlocking(boolean disableBlocking) {
1537         this.disableBlocking = disableBlocking;
1538     }
1539 
1540     /**
1541      * Evaluate the disable condition on controls which disable it on each key up event.
1542      *
1543      * @return true if evaluate on key up, false otherwise
1544      */
1545     @BeanTagAttribute
1546     public boolean isEvaluateDisabledOnKeyUp() {
1547         return evaluateDisabledOnKeyUp;
1548     }
1549 
1550     /**
1551      * Setter for {@link #isEvaluateDisabledOnKeyUp()}.
1552      *
1553      * @param evaluateDisabledOnKeyUp property value
1554      */
1555     public void setEvaluateDisabledOnKeyUp(boolean evaluateDisabledOnKeyUp) {
1556         this.evaluateDisabledOnKeyUp = evaluateDisabledOnKeyUp;
1557     }
1558 
1559     /**
1560      * Evaluate if this action is the default action for a page, view, group, or section.
1561      *
1562      * @return true if this action is default, false otherwise
1563      */
1564     @BeanTagAttribute(name = "defaultEnterKeyAction")
1565     public boolean isDefaultEnterKeyAction() {
1566         return this.defaultEnterKeyAction;
1567     }
1568 
1569     /**
1570      * @see  #isDefaultEnterKeyAction()
1571      */
1572     public void setDefaultEnterKeyAction(boolean defaultEnterKeyAction) {
1573         this.defaultEnterKeyAction = defaultEnterKeyAction;
1574     }
1575 
1576     /**
1577      * Get the disable condition js derived from the springEL, cannot be set.
1578      *
1579      * @return the disableConditionJs javascript to be evaluated
1580      */
1581     public String getDisabledConditionJs() {
1582         return disabledConditionJs;
1583     }
1584 
1585     /**
1586      * Sets the disabled condition javascript.
1587      *
1588      * @param disabledConditionJs property value
1589      */
1590     protected void setDisabledConditionJs(String disabledConditionJs) {
1591         this.disabledConditionJs = disabledConditionJs;
1592     }
1593 
1594     /**
1595      * Gets a list of control names to add handlers to for disable functionality, cannot be set.
1596      *
1597      * @return control names to add handlers to for disable
1598      */
1599     public List<String> getDisabledConditionControlNames() {
1600         return disabledConditionControlNames;
1601     }
1602 
1603     /**
1604      * Set disabled condition control names.
1605      *
1606      * @param disabledConditionControlNames property value
1607      */
1608     public void setDisabledConditionControlNames(List<String> disabledConditionControlNames) {
1609         this.disabledConditionControlNames = disabledConditionControlNames;
1610     }
1611 
1612     /**
1613      * Gets the property names of fields that when changed, will disable this component.
1614      *
1615      * @return the property names to monitor for change to disable this component
1616      */
1617     @BeanTagAttribute
1618     public List<String> getDisabledWhenChangedPropertyNames() {
1619         return disabledWhenChangedPropertyNames;
1620     }
1621 
1622     /**
1623      * Sets the property names of fields that when changed, will disable this component.
1624      *
1625      * @param disabledWhenChangedPropertyNames property value
1626      */
1627     public void setDisabledWhenChangedPropertyNames(List<String> disabledWhenChangedPropertyNames) {
1628         this.disabledWhenChangedPropertyNames = disabledWhenChangedPropertyNames;
1629     }
1630 
1631     /**
1632      * Gets the property names of fields that when changed, will enable this component.
1633      *
1634      * @return the property names to monitor for change to enable this component
1635      */
1636     @BeanTagAttribute
1637     public List<String> getEnabledWhenChangedPropertyNames() {
1638         return enabledWhenChangedPropertyNames;
1639     }
1640 
1641     /**
1642      * Sets the property names of fields that when changed, will enable this component.
1643      *
1644      * @param enabledWhenChangedPropertyNames property value
1645      */
1646     public void setEnabledWhenChangedPropertyNames(List<String> enabledWhenChangedPropertyNames) {
1647         this.enabledWhenChangedPropertyNames = enabledWhenChangedPropertyNames;
1648     }
1649 
1650     /**
1651      * Sets the disabled expression.
1652      *
1653      * @param disabledExpression property value
1654      */
1655     protected void setDisabledExpression(String disabledExpression) {
1656         this.disabledExpression = disabledExpression;
1657     }
1658 
1659     /**
1660      * {@inheritDoc}
1661      */
1662     @Override
1663     public void completeValidation(ValidationTrace tracer) {
1664         tracer.addBean(this);
1665 
1666         // Checks that an action is set
1667         if (getJumpToIdAfterSubmit() != null && getJumpToNameAfterSubmit() != null) {
1668             String currentValues[] = {"jumpToIdAfterSubmit =" + getJumpToIdAfterSubmit(),
1669                     "jumpToNameAfterSubmit =" + getJumpToNameAfterSubmit()};
1670             tracer.createWarning("Only 1 jumpTo property should be set", currentValues);
1671         }
1672         super.completeValidation(tracer.getCopy());
1673     }
1674 }