001/** 002 * Copyright 2005-2018 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.element; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.apache.commons.lang.StringUtils; 020import org.kuali.rice.core.api.exception.RiceRuntimeException; 021import org.kuali.rice.krad.datadictionary.parse.BeanTag; 022import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 023import org.kuali.rice.krad.datadictionary.parse.BeanTags; 024import org.kuali.rice.krad.datadictionary.validator.ValidationTrace; 025import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 026import org.kuali.rice.krad.uif.UifConstants; 027import org.kuali.rice.krad.uif.UifParameters; 028import org.kuali.rice.krad.uif.UifPropertyPaths; 029import org.kuali.rice.krad.uif.component.Component; 030import org.kuali.rice.krad.uif.component.ComponentSecurity; 031import org.kuali.rice.krad.uif.container.DialogGroup; 032import org.kuali.rice.krad.uif.container.Group; 033import org.kuali.rice.krad.uif.field.DataField; 034import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle; 035import org.kuali.rice.krad.uif.util.ComponentFactory; 036import org.kuali.rice.krad.uif.util.LifecycleElement; 037import org.kuali.rice.krad.uif.util.ScriptUtils; 038import org.kuali.rice.krad.uif.util.UrlInfo; 039import org.kuali.rice.krad.uif.view.ExpressionEvaluator; 040import org.kuali.rice.krad.uif.view.FormView; 041import org.kuali.rice.krad.uif.view.View; 042import org.kuali.rice.krad.util.KRADUtils; 043 044import java.util.ArrayList; 045import java.util.HashMap; 046import java.util.List; 047import java.util.Map; 048 049/** 050 * Field that presents an action that can be taken on the UI such as submitting the form or invoking a script. 051 * 052 * @author Kuali Rice Team (rice.collab@kuali.org) 053 */ 054@BeanTags({@BeanTag(name = "action", parent = "Uif-Action"), 055 @BeanTag(name = "actionImage", parent = "Uif-ActionImage"), 056 @BeanTag(name = "button", parent = "Uif-PrimaryActionButton"), 057 @BeanTag(name = "secondaryButton", parent = "Uif-SecondaryActionButton"), 058 @BeanTag(name = "buttonLarge", parent = "Uif-PrimaryActionButton-Large"), 059 @BeanTag(name = "secondaryButtonLarge", parent = "Uif-SecondaryActionButton-Large"), 060 @BeanTag(name = "buttonSmall", parent = "Uif-PrimaryActionButton-Small"), 061 @BeanTag(name = "secondaryButtonSmall", parent = "Uif-SecondaryActionButton-Small"), 062 @BeanTag(name = "buttonMini", parent = "Uif-PrimaryActionButton-Mini"), 063 @BeanTag(name = "secondaryButtonMini", parent = "Uif-SecondaryActionButton-Mini"), 064 @BeanTag(name = "actionLink", parent = "Uif-ActionLink"), 065 @BeanTag(name = "navigationActionLink", parent = "Uif-NavigationActionLink"), 066 @BeanTag(name = "navigationButton", parent = "Uif-NavigationActionButton"), 067 @BeanTag(name = "secondaryNavigationActionButton", parent = "Uif-SecondaryNavigationActionButton")}) 068public class Action extends ContentElementBase { 069 private static final long serialVersionUID = 1025672792657238829L; 070 071 private String methodToCall; 072 private String actionEvent; 073 private String navigateToPageId; 074 private List<String> fieldsToSend; 075 076 private String actionScript; 077 private UrlInfo actionUrl; 078 079 private String actionLabel; 080 private boolean renderInnerTextSpan; 081 082 private Image actionImage; 083 private String actionImagePlacement; 084 085 private String iconClass; 086 private String actionIconPlacement; 087 088 private String jumpToIdAfterSubmit; 089 private String jumpToNameAfterSubmit; 090 private String focusOnIdAfterSubmit; 091 092 private boolean performClientSideValidation; 093 private boolean performDirtyValidation; 094 private boolean clearDirtyOnAction; 095 private boolean dirtyOnAction; 096 097 private String preSubmitCall; 098 private String confirmationPromptText; 099 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}