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, 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.workplace.editors.directedit; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsResourceTypeConfig; 032import org.opencms.ade.contenteditor.shared.CmsEditorConstants; 033import org.opencms.file.CmsResource; 034import org.opencms.file.CmsResourceFilter; 035import org.opencms.file.types.CmsResourceTypeXmlContent; 036import org.opencms.file.types.I_CmsResourceType; 037import org.opencms.gwt.shared.CmsGwtConstants; 038import org.opencms.gwt.shared.I_CmsCollectorInfoFactory; 039import org.opencms.gwt.shared.I_CmsContentLoadCollectorInfo; 040import org.opencms.i18n.CmsEncoder; 041import org.opencms.json.JSONException; 042import org.opencms.json.JSONObject; 043import org.opencms.jsp.util.CmsJspStandardContextBean; 044import org.opencms.lock.CmsLock; 045import org.opencms.main.CmsException; 046import org.opencms.main.CmsLog; 047import org.opencms.main.OpenCms; 048import org.opencms.security.CmsPermissionSet; 049import org.opencms.util.CmsStringUtil; 050import org.opencms.util.CmsUUID; 051import org.opencms.workplace.editors.Messages; 052import org.opencms.workplace.explorer.CmsResourceUtil; 053import org.opencms.xml.containerpage.CmsContainerElementBean; 054 055import java.util.Random; 056 057import javax.servlet.jsp.JspException; 058import javax.servlet.jsp.PageContext; 059 060import org.apache.commons.logging.Log; 061 062import com.google.web.bindery.autobean.shared.AutoBean; 063import com.google.web.bindery.autobean.shared.AutoBeanCodex; 064import com.google.web.bindery.autobean.vm.AutoBeanFactorySource; 065 066/** 067 * Provider for the OpenCms AdvancedDirectEdit.<p> 068 * 069 * Since OpenCms version 8.0.0.<p> 070 * 071 * This provider DOES NOT support {@link CmsDirectEditMode#MANUAL} mode.<p> 072 * 073 * @since 8.0.0 074 */ 075public class CmsAdvancedDirectEditProvider extends A_CmsDirectEditProvider { 076 077 /** The log object for this class. */ 078 private static final Log LOG = CmsLog.getLog(CmsAdvancedDirectEditProvider.class); 079 080 /** Indicates the permissions for the last element the was opened. */ 081 protected int m_lastPermissionMode; 082 083 /** True if the elements should be assigned randomly generated ids. */ 084 protected boolean m_useIds; 085 086 /** The random number generator used for element ids. */ 087 private Random m_random = new Random(); 088 089 /** 090 * Returns the end HTML for a disabled direct edit button.<p> 091 * 092 * @return the end HTML for a disabled direct edit button 093 */ 094 public String endDirectEditDisabled() { 095 096 return ""; 097 } 098 099 /** 100 * Returns the end HTML for an enabled direct edit button.<p> 101 * 102 * @return the end HTML for an enabled direct edit button 103 */ 104 public String endDirectEditEnabled() { 105 106 return "<div class=\"" + CmsGwtConstants.CLASS_EDITABLE_END + "\"></div>\n"; 107 } 108 109 /** 110 * Generates a random element id.<p> 111 * 112 * @return a random element id 113 */ 114 public synchronized String getRandomId() { 115 116 return "editable_" + Math.abs(m_random.nextLong()); 117 } 118 119 /** 120 * @see org.opencms.workplace.editors.directedit.A_CmsDirectEditProvider#getResourceInfo(java.lang.String) 121 * 122 * Similar to the method in the superclass, but removes the write permission check, as this is handled differently. 123 */ 124 @Override 125 public CmsDirectEditResourceInfo getResourceInfo(String resourceName) { 126 127 try { 128 // first check some simple preconditions for direct edit 129 if (m_cms.getRequestContext().getCurrentProject().isOnlineProject()) { 130 // don't show direct edit button in online project 131 return CmsDirectEditResourceInfo.INACTIVE; 132 } 133 if (CmsResource.isTemporaryFileName(resourceName)) { 134 // don't show direct edit button on a temporary file 135 return CmsDirectEditResourceInfo.INACTIVE; 136 } 137 if (!m_cms.isInsideCurrentProject(resourceName)) { 138 // don't show direct edit button on files not belonging to the current project 139 return CmsDirectEditResourceInfo.INACTIVE; 140 } 141 // read the target resource 142 CmsResource resource = m_cms.readResource(resourceName, CmsResourceFilter.ALL); 143 if (!OpenCms.getResourceManager().getResourceType(resource.getTypeId()).isDirectEditable() 144 && !resource.isFolder()) { 145 // don't show direct edit button for non-editable resources 146 return CmsDirectEditResourceInfo.INACTIVE; 147 } 148 // check the resource lock 149 CmsLock lock = m_cms.getLock(resource); 150 boolean locked = !(lock.isUnlocked() 151 || lock.isOwnedInProjectBy( 152 m_cms.getRequestContext().getCurrentUser(), 153 m_cms.getRequestContext().getCurrentProject())); 154 // check the users permissions on the resource 155 // only if write permissions are granted the resource may be direct editable 156 if (locked) { 157 // a locked resource must be shown as "disabled" 158 return new CmsDirectEditResourceInfo(CmsDirectEditPermissions.DISABLED, resource, lock); 159 } 160 // if we have write permission and the resource is not locked then direct edit is enabled 161 return new CmsDirectEditResourceInfo(CmsDirectEditPermissions.ENABLED, resource, lock); 162 163 } catch (Exception e) { 164 // all exceptions: don't mix up the result HTML, always return INACTIVE mode 165 if (LOG.isWarnEnabled()) { 166 LOG.warn( 167 org.opencms.workplace.editors.Messages.get().getBundle().key( 168 org.opencms.workplace.editors.Messages.LOG_CALC_EDIT_MODE_FAILED_1, 169 resourceName), 170 e); 171 } 172 } 173 // otherwise the resource is not direct editable 174 return CmsDirectEditResourceInfo.INACTIVE; 175 } 176 177 /** 178 * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditEnd(javax.servlet.jsp.PageContext) 179 */ 180 public void insertDirectEditEnd(PageContext context) throws JspException { 181 182 String content; 183 switch (m_lastPermissionMode) { 184 185 case 1: // disabled 186 // content = endDirectEditDisabled(); 187 // break; 188 case 2: // enabled 189 content = endDirectEditEnabled(); 190 break; 191 default: // inactive or undefined 192 content = null; 193 } 194 m_lastPermissionMode = 0; 195 print(context, content); 196 } 197 198 /** 199 * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditIncludes(javax.servlet.jsp.PageContext, org.opencms.workplace.editors.directedit.CmsDirectEditParams) 200 */ 201 @SuppressWarnings("unused") 202 public void insertDirectEditIncludes(PageContext context, CmsDirectEditParams params) throws JspException { 203 204 // For Advanced Direct Edit all necessary js and css-code is included by the enableADE tag. Further includes in the head are not needed. 205 206 } 207 208 /** 209 * @see org.opencms.workplace.editors.directedit.A_CmsDirectEditProvider#insertDirectEditListMetadata(javax.servlet.jsp.PageContext, org.opencms.gwt.shared.I_CmsContentLoadCollectorInfo) 210 */ 211 @Override 212 public void insertDirectEditListMetadata(PageContext context, I_CmsContentLoadCollectorInfo info) 213 throws JspException { 214 215 if (m_cms.getRequestContext().getCurrentProject().isOnlineProject()) { 216 // the metadata is only needed for editing 217 return; 218 } 219 I_CmsCollectorInfoFactory collectorInfoFactory = AutoBeanFactorySource.create(I_CmsCollectorInfoFactory.class); 220 AutoBean<I_CmsContentLoadCollectorInfo> collectorInfoAutoBean = collectorInfoFactory.wrapCollectorInfo(info); 221 String serializedCollectorInfo = AutoBeanCodex.encode(collectorInfoAutoBean).getPayload(); 222 223 String marker = "<div class='" 224 + CmsGwtConstants.CLASS_COLLECTOR_INFO 225 + "' style='display: none !important;' " 226 + CmsGwtConstants.ATTR_DATA_COLLECTOR 227 + "='" 228 + CmsEncoder.escapeXml(serializedCollectorInfo) 229 + "'></div>"; 230 print(context, marker); 231 } 232 233 /** 234 * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#insertDirectEditStart(javax.servlet.jsp.PageContext, org.opencms.workplace.editors.directedit.CmsDirectEditParams) 235 */ 236 public boolean insertDirectEditStart(PageContext context, CmsDirectEditParams params) throws JspException { 237 238 String content; 239 // check the direct edit permissions of the current user 240 CmsDirectEditResourceInfo resourceInfo = getResourceInfo(params.getResourceName()); 241 242 // check the permission mode 243 m_lastPermissionMode = resourceInfo.getPermissions().getPermission(); 244 switch (m_lastPermissionMode) { 245 case 1: // disabled 246 // content = startDirectEditDisabled(params, resourceInfo); 247 // break; 248 case 2: // enabled 249 try { 250 CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(context.getRequest()); 251 CmsContainerElementBean element = contextBean.getElement(); 252 if ((element != null) && element.getId().equals(resourceInfo.getResource().getStructureId())) { 253 params.m_element = element.editorHash(); 254 params.setContainerElement(element); 255 } 256 content = startDirectEditEnabled(params, resourceInfo); 257 } catch (JSONException e) { 258 throw new JspException(e); 259 } 260 break; 261 default: // inactive or undefined 262 content = null; 263 } 264 print(context, content); 265 return content != null; 266 } 267 268 /** 269 * Returns <code>false</code> because the default provider does not support manual button placement.<p> 270 * 271 * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#isManual(org.opencms.workplace.editors.directedit.CmsDirectEditMode) 272 */ 273 @Override 274 public boolean isManual(CmsDirectEditMode mode) { 275 276 return false; 277 } 278 279 /** 280 * @see org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider#newInstance() 281 */ 282 public I_CmsDirectEditProvider newInstance() { 283 284 CmsAdvancedDirectEditProvider result = new CmsAdvancedDirectEditProvider(); 285 result.m_configurationParameters = m_configurationParameters; 286 return result; 287 } 288 289 /** 290 * Returns the start HTML for a disabled direct edit button.<p> 291 * 292 * @param params the direct edit parameters 293 * @param resourceInfo contains information about the resource to edit 294 * 295 * @return the start HTML for a disabled direct edit button 296 */ 297 public String startDirectEditDisabled(CmsDirectEditParams params, CmsDirectEditResourceInfo resourceInfo) { 298 299 StringBuffer result = new StringBuffer(256); 300 301 result.append("<!-- EDIT BLOCK START (DISABLED): "); 302 result.append(params.m_resourceName); 303 result.append(" ["); 304 result.append(resourceInfo.getResource().getState()); 305 result.append("] "); 306 if (!resourceInfo.getLock().isUnlocked()) { 307 result.append(" locked "); 308 result.append(resourceInfo.getLock().getProject().getName()); 309 } 310 result.append(" -->\n"); 311 return result.toString(); 312 } 313 314 /** 315 * Returns the start HTML for an enabled direct edit button.<p> 316 * 317 * @param params the direct edit parameters 318 * @param resourceInfo contains information about the resource to edit 319 * 320 * @return the start HTML for an enabled direct edit button 321 * @throws JSONException if a JSON handling error occurs 322 */ 323 public String startDirectEditEnabled(CmsDirectEditParams params, CmsDirectEditResourceInfo resourceInfo) 324 throws JSONException { 325 326 String editLocale = m_cms.getRequestContext().getLocale().toString(); 327 String editId = getNextDirectEditId(); 328 String editNewLink = CmsEncoder.encode(params.getLinkForNew()); 329 // putting together all needed data 330 JSONObject editableData = new JSONObject(); 331 CmsResource resource = resourceInfo.getResource(); 332 boolean writable = false; 333 if (resource != null) { 334 try { 335 writable = m_cms.hasPermissions( 336 resource, 337 CmsPermissionSet.ACCESS_WRITE, 338 false, 339 CmsResourceFilter.IGNORE_EXPIRATION); 340 } catch (CmsException e) { 341 LOG.error(e.getLocalizedMessage(), e); 342 } 343 } 344 editableData.put("editId", editId); 345 CmsContainerElementBean containerElement = params.getContainerElement(); 346 if (containerElement != null) { 347 editableData.put(CmsGwtConstants.ATTR_ELEMENT_ID, containerElement.editorHash()); 348 } 349 350 editableData.put("structureId", resourceInfo.getResource().getStructureId()); 351 editableData.put("sitePath", params.getResourceName()); 352 editableData.put("elementlanguage", editLocale); 353 editableData.put("elementname", params.getElement()); 354 editableData.put("newlink", editNewLink); 355 editableData.put("hasResource", resource != null); 356 editableData.put("hasEdit", params.getButtonSelection().isShowEdit() && writable); 357 editableData.put("hasDelete", params.getButtonSelection().isShowDelete() && writable); 358 editableData.put("hasNew", params.getButtonSelection().isShowNew()); 359 editableData.put("newtitle", m_messages.key(Messages.GUI_EDITOR_TITLE_NEW_0)); 360 editableData.put( 361 "unreleaseOrExpired", 362 !resourceInfo.getResource().isReleasedAndNotExpired(System.currentTimeMillis())); 363 if (params.getId() != null) { 364 editableData.put(CmsEditorConstants.ATTR_CONTEXT_ID, params.getId().toString()); 365 } 366 editableData.put(CmsEditorConstants.ATTR_POST_CREATE_HANDLER, params.getPostCreateHandler()); 367 CmsUUID viewId = CmsUUID.getNullUUID(); 368 boolean hasEditHandler = false; 369 if ((resourceInfo.getResource() != null) && resourceInfo.getResource().isFile()) { 370 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resourceInfo.getResource()); 371 if (type instanceof CmsResourceTypeXmlContent) { 372 hasEditHandler = ((CmsResourceTypeXmlContent)type).getEditHandler(m_cms) != null; 373 } 374 CmsADEConfigData configData = OpenCms.getADEManager().lookupConfiguration( 375 m_cms, 376 resourceInfo.getResource().getRootPath()); 377 CmsResourceTypeConfig typeConfig = configData.getResourceType( 378 OpenCms.getResourceManager().getResourceType(resourceInfo.getResource()).getTypeName()); 379 if (typeConfig != null) { 380 viewId = typeConfig.getElementView(); 381 } 382 } 383 editableData.put(CmsEditorConstants.ATTR_ELEMENT_VIEW, viewId); 384 editableData.put("hasEditHandler", hasEditHandler); 385 if (m_lastPermissionMode == 1) { 386 387 try { 388 String noEditReason = new CmsResourceUtil(m_cms, resourceInfo.getResource()).getNoEditReason( 389 OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms), 390 true); 391 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(noEditReason)) { 392 editableData.put("noEditReason", noEditReason); 393 } 394 } catch (CmsException e) { 395 LOG.error(e.getLocalizedMessage(), e); 396 } 397 } 398 StringBuffer result = new StringBuffer(512); 399 if (m_useIds) { 400 result.append( 401 "<div id=\"" 402 + getRandomId() 403 + "\" class='" 404 + CmsGwtConstants.CLASS_EDITABLE 405 + "' " 406 + CmsGwtConstants.ATTR_DATA_EDITABLE 407 + "='").append(editableData.toString()).append("'></div>\n"); 408 } else { 409 result.append( 410 "<div class='" 411 + CmsGwtConstants.CLASS_EDITABLE 412 + "' " 413 + CmsGwtConstants.ATTR_DATA_EDITABLE 414 + "='").append(editableData.toString()).append("'></div>\n"); 415 } 416 return result.toString(); 417 } 418}