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.widget; 017 018import java.text.MessageFormat; 019 020import org.apache.commons.lang.StringUtils; 021import org.kuali.rice.core.api.CoreApiServiceLocator; 022import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator; 023import org.kuali.rice.coreservice.framework.parameter.ParameterService; 024import org.kuali.rice.krad.datadictionary.HelpDefinition; 025import org.kuali.rice.krad.datadictionary.parse.BeanTag; 026import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 027import org.kuali.rice.krad.datadictionary.uif.UifDictionaryBean; 028import org.kuali.rice.krad.uif.CssConstants; 029import org.kuali.rice.krad.uif.UifConstants; 030import org.kuali.rice.krad.uif.element.Action; 031import org.kuali.rice.krad.uif.field.InputField; 032import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle; 033import org.kuali.rice.krad.uif.util.ComponentFactory; 034import org.kuali.rice.krad.uif.util.LifecycleElement; 035import org.kuali.rice.krad.uif.view.ExpressionEvaluator; 036 037/** 038 * Widget that renders help on a component 039 * 040 * <p> 041 * If help URL is specified then display help icon and/or if help summary is specified then display help tooltip. 042 * </p> 043 * 044 * @author Kuali Rice Team (rice.collab@kuali.org) 045 */ 046@BeanTag(name = "help", parent = "Uif-Help") 047public class Help extends WidgetBase { 048 private static final long serialVersionUID = -1514436681476297241L; 049 050 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(Help.class); 051 052 private Action helpAction; 053 private HelpDefinition helpDefinition; 054 private String externalHelpUrl; 055 056 private String tooltipHelpContent; 057 058 /** 059 * The following initialization is performed: 060 * 061 * <ul> 062 * <li>If help action not initialized and external help is configured, get the default 063 * help action component</li> 064 * </ul> 065 * 066 * {@inheritDoc} 067 */ 068 @Override 069 public void performInitialization(Object model) { 070 super.performInitialization(model); 071 072 if (helpAction == null) { 073 if(hasValueOrPropertyExpression(externalHelpUrl, this, "externalHelpUrl") || ( 074 helpDefinition != null && 075 hasValueOrPropertyExpression(helpDefinition.getParameterName(), helpDefinition, "parameterName") && 076 hasValueOrPropertyExpression(helpDefinition.getParameterDetailType(), helpDefinition, "parameterDetailType") 077 )){ 078 helpAction = ComponentFactory.getHelpAction(); 079 helpAction.addDataAttribute(UifConstants.DataAttributes.ROLE, "help"); 080 } 081 } 082 else{ 083 helpAction.addDataAttribute(UifConstants.DataAttributes.ROLE, "help"); 084 } 085 } 086 087 /** 088 * Helper function to check if value or property expression exists 089 * 090 * @param defaultValue 091 * @param dictionaryBean 092 * @param expressionName 093 * @return 094 */ 095 private boolean hasValueOrPropertyExpression(String defaultValue, UifDictionaryBean dictionaryBean, String expressionName) { 096 return StringUtils.isNotBlank(defaultValue) || (dictionaryBean != null && dictionaryBean.getPropertyExpressions() != null && 097 StringUtils.isNotBlank(dictionaryBean.getPropertyExpression(expressionName))); 098 } 099 100 /** 101 * Finalize the help widget for usage 102 * 103 * <p> 104 * In addition to the standard finalization the following tasks are performed: 105 * <li>Build the external help Url</li> 106 * <li>Set the javascript action which opens the external help in window</li> 107 * <li>Set render to false if help not configured</li> 108 * </p> 109 * 110 * {@inheritDoc} 111 */ 112 @Override 113 public void performFinalize(Object model, LifecycleElement parent) { 114 super.performFinalize(model, parent); 115 116 buildExternalHelp(parent); 117 buildTooltipHelp(parent); 118 119 // if help is not configured don't render the component 120 if (StringUtils.isBlank(this.externalHelpUrl) && StringUtils.isBlank(this.tooltipHelpContent)) { 121 setRender(false); 122 } 123 124 // Change to icon only look and feel if not associated with an input 125 if (parent != null && !(parent instanceof InputField) && helpAction != null) { 126 helpAction.getLibraryCssClasses().remove(CssConstants.Classes.BTN); 127 helpAction.getLibraryCssClasses().remove(CssConstants.Classes.BTN_DEFAULT); 128 helpAction.getLibraryCssClasses().add(CssConstants.Classes.ICON_ONLY_BUTTON); 129 } 130 } 131 132 /** 133 * Build the external help 134 * 135 * <p> 136 * When the externalHelpUrl is blank and the helpDefinition is specified then the external help URL is 137 * looked up via the helpDefinition from the system parameters. The namespace in the helpDefinition 138 * does not need to be specified and will default to the namespace of the view. 139 * </p> 140 * 141 * <p> 142 * Set the javascript action to open the external help in a window. 143 * </p> 144 * 145 * <p> 146 * Set the html title attribute of the help icon. 147 * </p> 148 * 149 * @param parent used to get the help title text used in the html title attribute of the help icon 150 */ 151 protected void buildExternalHelp(LifecycleElement parent) { 152 if (StringUtils.isBlank(externalHelpUrl) && (helpDefinition != null)) { 153 if (StringUtils.isBlank(helpDefinition.getParameterNamespace())) { 154 helpDefinition.setParameterNamespace(ViewLifecycle.getView().getNamespaceCode()); 155 } 156 157 String parameterNamespace = helpDefinition.getParameterNamespace(); 158 String parameterDetailType = helpDefinition.getParameterDetailType(); 159 String parameterName = helpDefinition.getParameterName(); 160 161 ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator(); 162 if (parameterNamespace == null && helpDefinition.getPropertyExpression("parameterNamespace") != null) { 163 parameterNamespace = (String) expressionEvaluator.evaluateExpression(this.getContext(), 164 helpDefinition.getPropertyExpression("parameterNamespace")); 165 } 166 167 if (parameterDetailType == null && helpDefinition.getPropertyExpression("parameterDetailType") != null) { 168 parameterDetailType = (String) expressionEvaluator.evaluateExpression(this.getContext(), 169 helpDefinition.getPropertyExpression("parameterDetailType")); 170 } 171 172 if (parameterName == null && helpDefinition.getPropertyExpression("parameterName") != null) { 173 parameterName = (String) expressionEvaluator.evaluateExpression(this.getContext(), 174 helpDefinition.getPropertyExpression("parameterName")); 175 } 176 177 if (StringUtils.isNotBlank(parameterNamespace) 178 && StringUtils.isNotBlank(parameterDetailType) 179 && StringUtils.isNotBlank(parameterName)) { 180 externalHelpUrl = getParameterService().getParameterValueAsFilteredString( 181 parameterNamespace, parameterDetailType, parameterName); 182 } 183 } 184 185 if (StringUtils.isNotBlank(externalHelpUrl)) { 186 // set the javascript action for the external help 187 getHelpAction().setActionScript("openHelpWindow('" + externalHelpUrl + "')"); 188 189 // set the alt and title attribute of the image 190 String helpTitle; 191 192 // make sure that we are the component's native help and not a misconfigured standalone help bean. 193 if ((parent instanceof Helpable) && (((Helpable) parent).getHelp() == this)) { 194 helpTitle = MessageFormat.format( 195 CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString( 196 "help.icon.title.tag.with.field.label"), ((Helpable) parent).getHelpTitle()); 197 } else { 198 helpTitle = CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString( 199 "help.icon.title.tag"); 200 } 201 202 getHelpAction().setTitle(helpTitle); 203 } 204 } 205 206 /** 207 * Build the tooltip help 208 * 209 * <p> 210 * The help tooltip is set on the component. To use the help tooltip bean definition, the help's tooltip is used 211 * as and intermediary for setting up the tooltip widget and then copied to the component. 212 * </p> 213 * 214 * @param parent used for checking misconfigurations 215 */ 216 protected void buildTooltipHelp(LifecycleElement parent) { 217 if (StringUtils.isNotBlank(tooltipHelpContent) && this.isRender()) { 218 // make sure that we are the component's native help and not a misconfigured standalone help bean. 219 if (this.getToolTip() != null && (parent instanceof Helpable) 220 && (((Helpable) parent).getHelp() == this)) { 221 this.getToolTip().setTooltipContent(tooltipHelpContent); 222 ((Helpable) parent).setTooltipOfComponent(this.getToolTip()); 223 } 224 } 225 } 226 227 /** 228 * HelpActionField is used for rendering external help 229 * 230 * @return Action for external help 231 */ 232 @BeanTagAttribute 233 public Action getHelpAction() { 234 return helpAction; 235 } 236 237 /** 238 * Setter for helpAction 239 * 240 * @param helpAction 241 */ 242 public void setHelpAction(Action helpAction) { 243 this.helpAction = helpAction; 244 } 245 246 /** 247 * The help definition is used as the key to retrieve the external help Url from the parameter table of 248 * the database 249 * 250 * @return HelpDefinition 251 */ 252 @BeanTagAttribute(type= BeanTagAttribute.AttributeType.DIRECTORBYTYPE) 253 public HelpDefinition getHelpDefinition() { 254 return helpDefinition; 255 } 256 257 /** 258 * Setter for the help definition of the database. 259 * 260 * @param helpDefinition 261 */ 262 public void setHelpDefinition(HelpDefinition helpDefinition) { 263 this.helpDefinition = helpDefinition; 264 } 265 266 /** 267 * The external help Url 268 * 269 * <p> 270 * This should contain a valid URL. When specified this URL takes precedence over the external help URL from 271 * the system parameters. 272 * </p> 273 * 274 * @return Url of the external help 275 */ 276 @BeanTagAttribute 277 public String getExternalHelpUrl() { 278 return this.externalHelpUrl; 279 } 280 281 /** 282 * Setter for externalHelpUrl 283 * 284 * @param externalHelpUrl 285 */ 286 public void setExternalHelpUrl(String externalHelpUrl) { 287 this.externalHelpUrl = externalHelpUrl; 288 } 289 290 /** 291 * TooltipHelpContent 292 * 293 * @return TooltipHelpContent 294 */ 295 @BeanTagAttribute 296 public String getTooltipHelpContent() { 297 return this.tooltipHelpContent; 298 } 299 300 /** 301 * Setter for tooltipHelpContent 302 * 303 * @param tooltipHelpContent 304 */ 305 public void setTooltipHelpContent(String tooltipHelpContent) { 306 this.tooltipHelpContent = tooltipHelpContent; 307 } 308 309 /** 310 * Retrieve the parameter service 311 * 312 * @return ParameterService 313 */ 314 protected ParameterService getParameterService() { 315 return CoreFrameworkServiceLocator.getParameterService(); 316 } 317}