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