001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.widgets; 029 030import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants; 031import org.opencms.file.CmsObject; 032import org.opencms.i18n.CmsEncoder; 033import org.opencms.i18n.CmsMessages; 034import org.opencms.json.JSONArray; 035import org.opencms.json.JSONException; 036import org.opencms.json.JSONObject; 037import org.opencms.loader.CmsImageScaler; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.util.CmsMacroResolver; 041import org.opencms.util.CmsStringUtil; 042import org.opencms.workplace.CmsDialog; 043import org.opencms.workplace.CmsWorkplace; 044import org.opencms.xml.types.CmsXmlVfsImageValue; 045 046import java.util.List; 047import java.util.Map; 048 049import org.apache.commons.logging.Log; 050 051/** 052 * Provides a widget for an extended image selection using the advanced gallery dialog.<p> 053 * 054 * @since 7.5.0 055 */ 056public class CmsVfsImageWidget extends CmsAdeImageGalleryWidget { 057 058 /** The static log object for this class. */ 059 private static final Log LOG = CmsLog.getLog(CmsVfsImageWidget.class); 060 061 /** Input field prefix for the description field. */ 062 private static final String PREFIX_DESCRIPTION = "desc."; 063 064 /** Input field prefix for the format field. */ 065 private static final String PREFIX_FORMAT = "format."; 066 067 /** Input field prefix for the hidden format value field. */ 068 private static final String PREFIX_FORMATVALUE = "fmtval."; 069 070 /** Input field prefix for the image field. */ 071 private static final String PREFIX_IMAGE = "img."; 072 073 /** Input field prefix for the image ratio field. */ 074 private static final String PREFIX_IMAGERATIO = "imgrat."; 075 076 /** Input field prefix for the hidden scale field. */ 077 private static final String PREFIX_SCALE = "scale."; 078 079 /** 080 * Creates a new image widget.<p> 081 */ 082 public CmsVfsImageWidget() { 083 084 // empty constructor is required for class registration 085 super(); 086 } 087 088 /** 089 * Creates an image widget with the specified configuration options.<p> 090 * 091 * @param configuration the configuration (possible options) for the image widget 092 */ 093 public CmsVfsImageWidget(String configuration) { 094 095 super(configuration); 096 } 097 098 /** 099 * @see org.opencms.widgets.I_CmsWidget#getDialogIncludes(org.opencms.file.CmsObject,org.opencms.widgets.I_CmsWidgetDialog) 100 */ 101 @Override 102 public String getDialogIncludes(CmsObject cms, I_CmsWidgetDialog widgetDialog) { 103 104 StringBuffer result = new StringBuffer(256); 105 // import the JavaScript for the image widget 106 result.append(getJSIncludeFile(CmsWorkplace.getSkinUri() + "components/widgets/vfsimage.js")); 107 return result.toString(); 108 } 109 110 /** 111 * @see org.opencms.widgets.I_CmsWidget#getDialogWidget(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 112 */ 113 @Override 114 public String getDialogWidget(CmsObject cms, I_CmsWidgetDialog widgetDialog, I_CmsWidgetParameter param) { 115 116 String id = param.getId(); 117 long idHash = id.hashCode(); 118 if (idHash < 0) { 119 // negative hash codes will not work as JS variable names, so convert them 120 idHash = -idHash; 121 // add 2^32 to the value to ensure that it is unique 122 idHash += 4294967296L; 123 } 124 // cast parameter to xml value to access the specific methods 125 CmsXmlVfsImageValue value = (CmsXmlVfsImageValue)param; 126 String imageLink = value.getRequestLink(cms); 127 if (imageLink == null) { 128 imageLink = ""; 129 } 130 131 StringBuffer result = new StringBuffer(4096); 132 133 result.append("<td class=\"xmlTd\" style=\"height: 25px;\">"); 134 135 result.append("<table class=\"xmlTableNested\">"); 136 result.append("<tr>"); 137 result.append("<td class=\"xmlLabel\">"); 138 result.append(widgetDialog.getMessages().key(Messages.GUI_EDITOR_LABEL_IMAGE_PATH_0)); 139 result.append(" </td>"); 140 result.append("<td>"); 141 result.append("<input class=\"xmlInputMedium\" value=\"").append(imageLink).append("\" name=\""); 142 result.append(PREFIX_IMAGE).append(id).append("\" id=\""); 143 result.append(PREFIX_IMAGE).append(id); 144 result.append("\" onkeyup=\"checkVfsImagePreview('"); 145 result.append(id); 146 result.append("');\" />"); 147 result.append("</td>"); 148 149 result.append(widgetDialog.dialogHorizontalSpacer(10)); 150 result.append( 151 "<td><table class=\"editorbuttonbackground\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>"); 152 153 result.append( 154 widgetDialog.button( 155 getOpenGalleryCall(cms, widgetDialog, param, idHash), 156 null, 157 getGalleryName() + "gallery", 158 Messages.getButtonName(getGalleryName()), 159 widgetDialog.getButtonStyle())); 160 161 // create preview button 162 String previewClass = "hide"; 163 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(imageLink)) { 164 // show button if preview is enabled 165 previewClass = "show"; 166 } 167 result.append("<td class=\""); 168 result.append(previewClass); 169 result.append("\" id=\"preview"); 170 result.append(id); 171 result.append("\">"); 172 result.append("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>"); 173 result.append( 174 widgetDialog.button( 175 getOpenPreviewCall(widgetDialog, PREFIX_IMAGE + param.getId()), 176 null, 177 "preview.png", 178 Messages.GUI_BUTTON_PREVIEW_0, 179 widgetDialog.getButtonStyle())); 180 result.append("</tr></table></td>"); 181 182 result.append("</tr></table></td>"); 183 result.append("</tr>"); 184 185 JSONObject additional = null; 186 try { 187 additional = getAdditionalGalleryInfo( 188 cms, 189 widgetDialog instanceof CmsDialog ? ((CmsDialog)widgetDialog).getParamResource() : null, 190 widgetDialog.getMessages(), 191 param); 192 } catch (JSONException e) { 193 LOG.error("Error parsing widget configuration", e); 194 } 195 if (additional != null) { 196 result.append("\n<script >\n"); 197 result.append("var cms_additional_").append(idHash).append("="); 198 result.append(additional.toString()).append(";\n"); 199 result.append("</script>"); 200 } 201 CmsVfsImageWidgetConfiguration configuration = getWidgetConfiguration(cms, widgetDialog.getMessages(), param); 202 String format = value.getFormat(cms); 203 if (configuration.isShowFormat()) { 204 // show the format select box, also create hidden format value field 205 result.append("<tr>"); 206 result.append("<td class=\"xmlLabel\">"); 207 result.append(widgetDialog.getMessages().key(Messages.GUI_EDITOR_LABEL_IMAGE_FORMAT_0)); 208 result.append(" </td>"); 209 result.append("<td class=\"xmlTd\">"); 210 result.append("<select class=\"xmlInput"); 211 if (param.hasError()) { 212 result.append(" xmlInputError"); 213 } 214 result.append("\" name=\""); 215 result.append(PREFIX_FORMAT).append(id); 216 result.append("\" id=\""); 217 result.append(PREFIX_FORMAT).append(id); 218 result.append("\""); 219 result.append(" onchange=\"setImageFormat(\'"); 220 result.append(id); 221 result.append("\', \'imgFmts"); 222 result.append(idHash); 223 result.append("\');\""); 224 result.append(">"); 225 226 // get select box options from default value String 227 List<CmsSelectWidgetOption> options = configuration.getSelectFormat(); 228 String selected = getSelectedValue(cms, options, format); 229 int selectedIndex = 0; 230 for (int i = 0; i < options.size(); i++) { 231 CmsSelectWidgetOption option = options.get(i); 232 // create the option 233 result.append("<option value=\""); 234 result.append(option.getValue()); 235 result.append("\""); 236 if ((selected != null) && selected.equals(option.getValue())) { 237 result.append(" selected=\"selected\""); 238 selectedIndex = i; 239 } 240 result.append(">"); 241 result.append(option.getOption()); 242 result.append("</option>"); 243 } 244 result.append("</select>"); 245 result.append("</td>"); 246 result.append("</tr>"); 247 List<String> formatValues = configuration.getFormatValues(); 248 String selectedFormat = ""; 249 try { 250 selectedFormat = formatValues.get(selectedIndex); 251 } catch (Exception e) { 252 // ignore, just didn't find a matching format value 253 } 254 // create hidden field to store the matching image format value 255 result.append("<input type=\"hidden\" value=\"").append(selectedFormat).append("\" name=\""); 256 result.append(PREFIX_FORMATVALUE).append(id).append("\" id=\""); 257 result.append(PREFIX_FORMATVALUE).append(id).append("\" />"); 258 // create hidden field to store image ratio 259 String ratio = ""; 260 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(imageLink)) { 261 // an image is specified, calculate ratio 262 try { 263 CmsImageScaler scaler = new CmsImageScaler(cms, cms.readResource(imageLink)); 264 float r = scaler.getWidth() / (float)scaler.getHeight(); 265 ratio = String.valueOf(r); 266 } catch (CmsException e) { 267 // ignore, image not found in VFS 268 } 269 } 270 result.append("<input type=\"hidden\" value=\"").append(ratio).append("\" name=\""); 271 result.append(PREFIX_IMAGERATIO).append(id).append("\" id=\""); 272 result.append(PREFIX_IMAGERATIO).append(id).append("\" />"); 273 // add possible format names and values as JS variables to access them from image gallery window 274 result.append("\n<script >"); 275 JSONArray formatsJson = new JSONArray(configuration.getFormatValues()); 276 result.append("\nvar imgFmts").append(idHash).append(" = ").append(formatsJson).append(";"); 277 result.append("\nvar imgFmtNames").append(idHash).append(" = \"").append( 278 CmsEncoder.escape(configuration.getSelectFormatString(), CmsEncoder.ENCODING_UTF_8)).append("\";"); 279 result.append("\nvar useFmts").append(idHash).append(" = true;"); 280 result.append("\n</script>"); 281 } else { 282 result.append("<input type=\"hidden\" value=\"\" name=\""); 283 result.append(PREFIX_IMAGERATIO).append(id).append("\" id=\""); 284 result.append(PREFIX_IMAGERATIO).append(id).append("\" />"); 285 result.append("<input type=\"hidden\" value=\"").append(format).append("\" name=\""); 286 result.append(PREFIX_FORMAT).append(id).append("\" id=\""); 287 result.append(PREFIX_FORMAT).append(id).append("\" />"); 288 result.append("\n<script >"); 289 result.append("\nvar useFmts").append(idHash).append(" = false;"); 290 result.append("\n</script>"); 291 } 292 293 String description = value.getDescription(cms); 294 if (description == null) { 295 description = ""; 296 } 297 298 if (configuration.isShowDescription()) { 299 result.append("<tr>"); 300 result.append("<td class=\"xmlLabel\">"); 301 result.append(widgetDialog.getMessages().key(Messages.GUI_EDITOR_LABEL_IMAGE_DESC_0)); 302 result.append("</td>"); 303 result.append("<td class=\"xmlTd\">"); 304 result.append("<textarea class=\"xmlInput maxwidth"); 305 if (param.hasError()) { 306 result.append(" xmlInputError"); 307 } 308 result.append("\" name=\""); 309 result.append(PREFIX_DESCRIPTION).append(id).append("\" id=\""); 310 result.append(PREFIX_DESCRIPTION).append(id); 311 result.append("\" rows=\""); 312 result.append(2); 313 result.append("\" cols=\"60\" style=\"height: 3em; overflow:auto;\">"); 314 result.append(CmsEncoder.escapeXml(description)); 315 result.append("</textarea>"); 316 result.append("</td>"); 317 result.append("</tr>"); 318 } else { 319 result.append("<input type=\"hidden\" value=\"").append(CmsEncoder.escapeXml(description)).append( 320 "\" name=\""); 321 result.append(PREFIX_DESCRIPTION).append(id).append("\" id=\""); 322 result.append(PREFIX_DESCRIPTION).append(id).append("\" />"); 323 324 } 325 result.append("</table>"); 326 327 String scale = value.getScaleOptions(cms); 328 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(configuration.getScaleParams()) 329 && (scale.indexOf(configuration.getScaleParams()) == -1)) { 330 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(scale)) { 331 scale += ","; 332 } 333 scale += configuration.getScaleParams(); 334 335 } 336 result.append("<input type=\"hidden\" value=\"").append(scale).append("\" name=\""); 337 result.append(PREFIX_SCALE).append(id).append("\" id=\""); 338 result.append(PREFIX_SCALE).append(id).append("\" />"); 339 340 result.append("</td>"); 341 342 return result.toString(); 343 } 344 345 /** 346 * @see org.opencms.widgets.I_CmsADEWidget#getWidgetName() 347 */ 348 @Override 349 public String getWidgetName() { 350 351 return CmsVfsImageWidget.class.getName(); 352 } 353 354 /** 355 * @see org.opencms.widgets.A_CmsWidget#getWidgetStringValue(org.opencms.file.CmsObject, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 356 */ 357 @Override 358 public String getWidgetStringValue(CmsObject cms, I_CmsWidgetDialog widgetDialog, I_CmsWidgetParameter param) { 359 360 String result = super.getWidgetStringValue(cms, widgetDialog, param); 361 String configuration = CmsMacroResolver.resolveMacros(getConfiguration(), cms, widgetDialog.getMessages()); 362 if (configuration == null) { 363 configuration = param.getDefault(cms); 364 } 365 List<CmsSelectWidgetOption> options = CmsSelectWidgetOption.parseOptions(configuration); 366 for (int m = 0; m < options.size(); m++) { 367 CmsSelectWidgetOption option = options.get(m); 368 if (result.equals(option.getValue())) { 369 result = option.getOption(); 370 break; 371 } 372 } 373 return result; 374 } 375 376 /** 377 * @see org.opencms.widgets.I_CmsWidget#newInstance() 378 */ 379 @Override 380 public I_CmsWidget newInstance() { 381 382 return new CmsVfsImageWidget(getConfiguration()); 383 } 384 385 /** 386 * @see org.opencms.widgets.I_CmsWidget#setEditorValue(org.opencms.file.CmsObject, java.util.Map, org.opencms.widgets.I_CmsWidgetDialog, org.opencms.widgets.I_CmsWidgetParameter) 387 */ 388 @Override 389 public void setEditorValue( 390 CmsObject cms, 391 Map<String, String[]> formParameters, 392 I_CmsWidgetDialog widgetDialog, 393 I_CmsWidgetParameter param) { 394 395 String[] imgValues = formParameters.get(PREFIX_IMAGE + param.getId()); 396 if ((imgValues != null) && (imgValues.length > 0)) { 397 param.setStringValue(cms, imgValues[0]); 398 } 399 400 CmsXmlVfsImageValue value = (CmsXmlVfsImageValue)param; 401 402 String[] descValues = formParameters.get(PREFIX_DESCRIPTION + param.getId()); 403 value.setDescription(cms, descValues[0]); 404 405 String[] formatValues = formParameters.get(PREFIX_FORMAT + param.getId()); 406 value.setFormat(cms, formatValues[0]); 407 408 String[] scaleValues = formParameters.get(PREFIX_SCALE + param.getId()); 409 value.setScaleOptions(cms, scaleValues[0]); 410 } 411 412 /** 413 * @see org.opencms.widgets.CmsAdeImageGalleryWidget#getAdditionalGalleryInfo(org.opencms.file.CmsObject, java.lang.String, org.opencms.i18n.CmsMessages, org.opencms.widgets.I_CmsWidgetParameter) 414 */ 415 @Override 416 protected JSONObject getAdditionalGalleryInfo( 417 CmsObject cms, 418 String resource, 419 CmsMessages messages, 420 I_CmsWidgetParameter param) throws JSONException { 421 422 JSONObject result = super.getAdditionalGalleryInfo(cms, resource, messages, param); 423 result.put("isAdvancedWidget", true); 424 return result; 425 } 426 427 /** 428 * @see org.opencms.widgets.A_CmsAdeGalleryWidget#getGalleryOpenParams(org.opencms.file.CmsObject, org.opencms.i18n.CmsMessages, org.opencms.widgets.I_CmsWidgetParameter, java.lang.String, long) 429 */ 430 @Override 431 protected Map<String, String> getGalleryOpenParams( 432 CmsObject cms, 433 CmsMessages widgetDialog, 434 I_CmsWidgetParameter param, 435 String resource, 436 long hashId) { 437 438 Map<String, String> result = super.getGalleryOpenParams(cms, widgetDialog, param, resource, hashId); 439 // the current element value will be read by java-script including the image input field and the scale input field 440 StringBuffer currentElement = new StringBuffer("'+document.getElementById('"); 441 if (param != null) { 442 currentElement.append(PREFIX_IMAGE).append(param.getId()); 443 } 444 currentElement.append("').getAttribute('value')+'"); 445 // only try reading scale and format info if formats are used 446 if (param != null) { 447 if (getWidgetConfiguration(cms, widgetDialog, param).isShowFormat()) { 448 currentElement.append("%3F__scale%3D'+document.getElementById('"); 449 currentElement.append(PREFIX_SCALE).append(param.getId()).append("').getAttribute('value')+'"); 450 currentElement.append("%26format%3D'+escape(document.getElementById('").append(PREFIX_FORMAT).append( 451 param.getId()).append("')[document.getElementById('").append(PREFIX_FORMAT).append( 452 param.getId()).append("').selectedIndex].value)+'"); 453 } 454 } 455 result.put(I_CmsGalleryProviderConstants.CONFIG_CURRENT_ELEMENT, currentElement.toString()); 456 return result; 457 } 458 459 /** 460 * Returns the currently selected value of the select widget.<p> 461 * 462 * If a value is found in the given parameter, this is used. Otherwise 463 * the default value of the select options are used. If there is neither a parameter value 464 * nor a default value, <code>null</code> is returned.<p> 465 * 466 * @param cms the current users OpenCms context 467 * @param selectOptions the available select options 468 * @param currentValue the current value that is selected 469 * 470 * @return the currently selected value of the select widget 471 */ 472 protected String getSelectedValue(CmsObject cms, List<CmsSelectWidgetOption> selectOptions, String currentValue) { 473 474 String paramValue = currentValue; 475 if (CmsStringUtil.isEmpty(paramValue)) { 476 CmsSelectWidgetOption option = CmsSelectWidgetOption.getDefaultOption(selectOptions); 477 if (option != null) { 478 paramValue = option.getValue(); 479 } 480 } 481 return paramValue; 482 } 483}