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.ade.containerpage.client.ui; 029 030import org.opencms.ade.containerpage.client.CmsContainerpageController; 031import org.opencms.ade.containerpage.client.Messages; 032import org.opencms.ade.containerpage.client.ui.css.I_CmsLayoutBundle; 033import org.opencms.ade.containerpage.shared.CmsCntPageData; 034import org.opencms.ade.containerpage.shared.CmsDialogOptions; 035import org.opencms.ade.containerpage.shared.CmsDialogOptionsAndInfo; 036import org.opencms.ade.contenteditor.client.CmsContentEditor; 037import org.opencms.ade.contenteditor.shared.CmsEditHandlerData; 038import org.opencms.ade.upload.client.I_CmsUploadContext; 039import org.opencms.ade.upload.client.lists.CmsUploadPopup; 040import org.opencms.gwt.client.CmsCoreProvider; 041import org.opencms.gwt.client.rpc.CmsRpcAction; 042import org.opencms.gwt.client.ui.A_CmsDirectEditButtons; 043import org.opencms.gwt.client.ui.CmsCreateModeSelectionDialog; 044import org.opencms.gwt.client.ui.CmsDeleteWarningDialog; 045import org.opencms.gwt.client.ui.CmsPushButton; 046import org.opencms.gwt.client.ui.I_CmsButton; 047import org.opencms.gwt.client.util.CmsDebugLog; 048import org.opencms.gwt.client.util.CmsDomUtil; 049import org.opencms.gwt.client.util.CmsPositionBean; 050import org.opencms.gwt.client.util.I_CmsSimpleCallback; 051import org.opencms.gwt.shared.CmsGwtConstants; 052import org.opencms.gwt.shared.CmsListInfoBean; 053import org.opencms.util.CmsStringUtil; 054import org.opencms.util.CmsUUID; 055 056import java.util.HashMap; 057import java.util.List; 058import java.util.Map; 059 060import com.google.common.collect.Maps; 061import com.google.gwt.dom.client.Element; 062import com.google.gwt.dom.client.Style; 063import com.google.gwt.dom.client.Style.Display; 064import com.google.gwt.dom.client.Style.Unit; 065import com.google.gwt.event.dom.client.ClickEvent; 066import com.google.gwt.event.dom.client.ClickHandler; 067import com.google.gwt.user.client.Command; 068import com.google.gwt.user.client.rpc.AsyncCallback; 069 070/** 071 * Class to provide direct edit buttons within list collector elements.<p> 072 * 073 * @since 8.0.0 074 */ 075public class CmsListCollectorEditor extends A_CmsDirectEditButtons { 076 077 /** True if the parent element has offset height or width. */ 078 private boolean m_parentHasDimensions; 079 080 /** The currently active upload popup. */ 081 private CmsUploadPopup m_uploadPopup; 082 083 /** 084 * Creates a new instance.<p> 085 * 086 * @param editable the editable element 087 * @param parentId the parent id 088 */ 089 public CmsListCollectorEditor(Element editable, String parentId) { 090 091 super(editable, parentId); 092 } 093 094 /** 095 * Creates the button to add an element to the user's favorites.<p> 096 * 097 * @return the created button 098 */ 099 public CmsPushButton createFavButton() { 100 101 CmsPushButton favButton = new CmsPushButton(); 102 favButton.setImageClass(I_CmsButton.ButtonData.ADD_TO_FAVORITES.getSmallIconClass()); 103 favButton.setTitle(I_CmsButton.ButtonData.ADD_TO_FAVORITES.getTitle()); 104 favButton.setButtonStyle(I_CmsButton.ButtonStyle.FONT_ICON, null); 105 add(favButton); 106 favButton.addClickHandler(new ClickHandler() { 107 108 public void onClick(ClickEvent event) { 109 110 CmsContainerpageController.get().getHandler().addToFavorites(getContentId().toString()); 111 } 112 }); 113 return favButton; 114 } 115 116 /** 117 * Returns true if the element view of the element is compatible with the currently set element view in the container page editor.<p> 118 * 119 * @return true if the element should be visible in the current mode 120 */ 121 public boolean isVisibleInCurrentView() { 122 123 return CmsContainerpageController.get().matchRootView(m_editableData.getElementView()); 124 } 125 126 /** 127 * Sets the 'parentHasDimensions' flag.<p> 128 * 129 * @param parentHasDimensions the new value of the flag 130 */ 131 public void setParentHasDimensions(boolean parentHasDimensions) { 132 133 m_parentHasDimensions = parentHasDimensions; 134 } 135 136 /** 137 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#setPosition(org.opencms.gwt.client.util.CmsPositionBean, com.google.gwt.dom.client.Element) 138 */ 139 @Override 140 public void setPosition(CmsPositionBean position, Element containerElement) { 141 142 m_position = position; 143 Element parent = CmsDomUtil.getPositioningParent(getElement()); 144 Style style = getElement().getStyle(); 145 int right = parent.getOffsetWidth() 146 - ((m_position.getLeft() + m_position.getWidth()) - parent.getAbsoluteLeft()); 147 148 int top = m_position.getTop() - parent.getAbsoluteTop(); 149 if (m_position.getHeight() < 24) { 150 // if the highlighted area has a lesser height than the buttons, center vertically 151 top -= (24 - m_position.getHeight()) / 2; 152 } 153 154 if (top < 25) { 155 // check if there is a parent option bar element present 156 Element parentOptionBar = CmsDomUtil.getFirstChildWithClass( 157 containerElement, 158 I_CmsLayoutBundle.INSTANCE.containerpageCss().optionBar()); 159 if ((parentOptionBar != null) && !getElement().equals(parentOptionBar)) { 160 int optBarTop = parentOptionBar.getAbsoluteTop(); 161 int optBarLeft = parentOptionBar.getAbsoluteLeft() + 22; 162 if ((Math.abs(optBarLeft - (m_position.getLeft() + m_position.getWidth())) < 25) 163 && (Math.abs(optBarTop - m_position.getTop()) < 25)) { 164 // in case the edit buttons overlap, move to the left 165 right = ((parent.getOffsetWidth() + parent.getAbsoluteLeft()) - optBarLeft) + 25; 166 } 167 } 168 } 169 style.setRight(right, Unit.PX); 170 style.setTop(top, Unit.PX); 171 updateExpiredOverlayPosition(parent); 172 } 173 174 /** 175 * Shows or hides the widget depending on the current view and whether the parent element has width or height.<p> 176 * 177 * @param editableContainer true if this list element is part of an element in an editable container 178 */ 179 public void updateVisibility(boolean editableContainer) { 180 181 boolean visible = m_parentHasDimensions && isVisibleInCurrentView() && editableContainer; 182 setDisplayNone(!visible); 183 184 } 185 186 /** 187 * Handles the 'default case' when using the new function on an editable element.<p> 188 */ 189 protected void defaultNew() { 190 191 CmsUUID referenceId = m_editableData.getStructureId(); 192 CmsCreateModeSelectionDialog.showDialog(referenceId, new AsyncCallback<String>() { 193 194 public void onFailure(Throwable caught) { 195 196 // is never called 197 } 198 199 public void onSuccess(String result) { 200 201 openEditDialog(true, result, null); 202 removeHighlighting(); 203 } 204 }); 205 } 206 207 /** 208 * Delete the editable element from page and VFS.<p> 209 */ 210 protected void deleteElement() { 211 212 CmsContainerpageController.get().deleteElement(m_editableData.getStructureId().toString(), m_parentResourceId); 213 } 214 215 /** 216 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#getAdditionalButtons() 217 */ 218 @Override 219 protected Map<Integer, CmsPushButton> getAdditionalButtons() { 220 221 Map<Integer, CmsPushButton> result = Maps.newHashMap(); 222 // only show add to favorites and info button, in case there actually is a resource and not in case of create new only 223 if (m_editableData.hasResource()) { 224 if (m_editableData.canFavorite()) { 225 result.put(Integer.valueOf(130), createFavButton()); 226 } 227 result.put(Integer.valueOf(160), createInfoButton()); 228 } 229 return result; 230 } 231 232 /** 233 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#getInfoContext() 234 */ 235 @Override 236 protected Map<String, String> getInfoContext() { 237 238 Map<String, String> result = new HashMap<>(); 239 String elementId = m_editableData.getElementId(); 240 if (elementId != null) { 241 result.put(CmsGwtConstants.ATTR_ELEMENT_ID, elementId); 242 } 243 String uri = CmsCoreProvider.get().getUri(); 244 String siteRoot = CmsCoreProvider.get().getSiteRoot(); 245 String pageRootPath = CmsStringUtil.joinPaths(siteRoot, uri); 246 result.put(CmsGwtConstants.ATTR_PAGE_ROOT_PATH, pageRootPath); 247 return result; 248 249 } 250 251 /** 252 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#getUploadButtonTitle(java.lang.String) 253 */ 254 @Override 255 protected String getUploadButtonTitle(String uploadFolder) { 256 257 return org.opencms.ade.galleries.client.Messages.get().key( 258 org.opencms.ade.galleries.client.Messages.GUI_GALLERY_UPLOAD_TITLE_1, 259 uploadFolder); 260 } 261 262 /** 263 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#onClickDelete() 264 */ 265 @Override 266 protected void onClickDelete() { 267 268 removeHighlighting(); 269 CmsDomUtil.ensureMouseOut(getElement()); 270 if (m_editableData.hasEditHandler()) { 271 final String elementId = CmsContentEditor.getClientIdForEditable(m_editableData); 272 final I_CmsSimpleCallback<String> deleteCallback = new I_CmsSimpleCallback<String>() { 273 274 public void execute(String arg) { 275 276 if (CmsDialogOptions.REGULAR_DELETE.equals(arg)) { 277 openWarningDialog(); 278 } else { 279 CmsContainerpageController.get().handleDelete(elementId, arg, new I_CmsSimpleCallback<Void>() { 280 281 public void execute(Void arg1) { 282 283 CmsContainerpageController.get().reloadElements( 284 new String[] {getParentResourceId()}, 285 () -> {/*do nothing*/}); 286 } 287 }); 288 } 289 } 290 }; 291 CmsContainerpageController.get().getDeleteOptions( 292 elementId, 293 new I_CmsSimpleCallback<CmsDialogOptionsAndInfo>() { 294 295 public void execute(CmsDialogOptionsAndInfo arg) { 296 297 if (arg == null) { 298 deleteCallback.execute(CmsDialogOptions.REGULAR_DELETE); 299 } else if (arg.getOptions().getOptions().size() == 1) { 300 String deleteOpt = arg.getOptions().getOptions().get(0).getValue(); 301 deleteCallback.execute(deleteOpt); 302 303 } else { 304 CmsOptionDialog dialog = new CmsOptionDialog( 305 Messages.get().key(Messages.GUI_EDIT_HANDLER_SELECT_DELETE_OPTION_0), 306 arg.getOptions(), 307 arg.getInfo(), 308 deleteCallback); 309 dialog.center(); 310 } 311 } 312 }); 313 } else { 314 openWarningDialog(); 315 } 316 m_delete.clearHoverState(); 317 } 318 319 /** 320 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#onClickEdit() 321 */ 322 @Override 323 protected void onClickEdit() { 324 325 openEditDialog(false, null, null); 326 removeHighlighting(); 327 } 328 329 /** 330 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#onClickNew(boolean) 331 */ 332 @Override 333 protected void onClickNew(boolean askCreateMode) { 334 335 if (!askCreateMode) { 336 openEditDialog(true, null, null); 337 removeHighlighting(); 338 } else { 339 if (m_editableData.hasEditHandler()) { 340 final String elementId = CmsContentEditor.getClientIdForEditable(m_editableData); 341 CmsCntPageData cntPageData = CmsContainerpageController.get().getData(); 342 final CmsUUID pageId = cntPageData.getRpcContext().getPageStructureId(); 343 final String requestParamStr = cntPageData.getRequestParams(); 344 345 final I_CmsSimpleCallback<String> newCallback = new I_CmsSimpleCallback<String>() { 346 347 public void execute(String choice) { 348 349 CmsEditHandlerData data = new CmsEditHandlerData(elementId, choice, pageId, requestParamStr); 350 openEditDialog(true, null, data); 351 removeHighlighting(); 352 353 } 354 }; 355 356 CmsContainerpageController.get().getNewOptions( 357 elementId, 358 new I_CmsSimpleCallback<CmsDialogOptionsAndInfo>() { 359 360 public void execute(CmsDialogOptionsAndInfo arg) { 361 362 if (arg == null) { 363 CmsDebugLog.consoleLog("dialog options null, using default behavior"); 364 defaultNew(); 365 } else { 366 CmsOptionDialog dialog = new CmsOptionDialog( 367 null, 368 arg.getOptions(), 369 arg.getInfo(), 370 newCallback); 371 dialog.center(); 372 } 373 374 } 375 }); 376 } else { 377 defaultNew(); 378 } 379 } 380 381 } 382 383 /** 384 * @see org.opencms.gwt.client.ui.A_CmsDirectEditButtons#onClickUpload() 385 */ 386 @Override 387 protected void onClickUpload() { 388 389 removeHighlighting(); 390 I_CmsUploadContext context = new I_CmsUploadContext() { 391 392 @SuppressWarnings("synthetic-access") 393 public void onUploadFinished(List<String> uploadedFiles) { 394 395 closeUploadPopup(); 396 CmsContainerpageController.get().reloadElements( 397 new String[] {getParentResourceId()}, 398 () -> {/*do nothing*/}); 399 } 400 }; 401 if (m_editableData.getStructureId() != null) { 402 CmsRpcAction<CmsListInfoBean> action = new CmsRpcAction<CmsListInfoBean>() { 403 404 @SuppressWarnings("synthetic-access") 405 @Override 406 public void execute() { 407 408 start(0, false); 409 CmsCoreProvider.get(); 410 CmsCoreProvider.getVfsService().getUploadFolderInfo( 411 m_editableData.getExtensions().getUploadFolder(), 412 this); 413 } 414 415 @SuppressWarnings("synthetic-access") 416 @Override 417 protected void onResponse(CmsListInfoBean result) { 418 419 stop(false); 420 setUploadPopup( 421 new CmsUploadPopup( 422 m_editableData.getExtensions().getUploadFolder(), 423 m_editableData.getPostCreateHandler(), 424 context, 425 result)); 426 m_uploadPopup.center(); 427 428 } 429 430 }; 431 action.execute(); 432 } else { 433 setUploadPopup( 434 new CmsUploadPopup( 435 m_editableData.getExtensions().getUploadFolder(), 436 m_editableData.getPostCreateHandler(), 437 context, 438 null)); 439 m_uploadPopup.center(); 440 441 } 442 443 } 444 445 /** 446 * Opens the content editor.<p> 447 * 448 * @param isNew <code>true</code> to create and edit a new resource 449 * @param mode the content creation mode 450 * @param handlerDataForNew the data for the edit handler if it is used for the 'new' function 451 */ 452 protected void openEditDialog(boolean isNew, String mode, CmsEditHandlerData handlerDataForNew) { 453 454 CmsContainerpageController.get().getContentEditorHandler().openDialog( 455 m_editableData, 456 isNew, 457 m_parentResourceId, 458 mode, 459 handlerDataForNew); 460 } 461 462 /** 463 * Shows the delete warning dialog.<p> 464 */ 465 protected void openWarningDialog() { 466 467 CmsDeleteWarningDialog dialog = new CmsDeleteWarningDialog(m_editableData.getSitePath()); 468 Command callback = new Command() { 469 470 /** 471 * @see com.google.gwt.user.client.Command#execute() 472 */ 473 public void execute() { 474 475 deleteElement(); 476 } 477 }; 478 dialog.loadAndShow(callback); 479 } 480 481 /** 482 * Returns the edit content id.<p> 483 * 484 * @return the content id 485 */ 486 CmsUUID getContentId() { 487 488 return m_editableData.getStructureId(); 489 } 490 491 /** 492 * Returns the parent resource id.<p> 493 * 494 * @return the parent resource id 495 */ 496 String getParentResourceId() { 497 498 return m_parentResourceId; 499 } 500 501 /** 502 * Sets the display CSS property to none, or clears it, depending on the given parameter.<p> 503 * 504 * @param displayNone true if the widget should not be displayed 505 */ 506 void setDisplayNone(boolean displayNone) { 507 508 if (displayNone) { 509 getElement().getStyle().setDisplay(Display.NONE); 510 } else { 511 getElement().getStyle().clearDisplay(); 512 } 513 } 514 515 /** 516 * Closes the currently active upload popup. 517 */ 518 private void closeUploadPopup() { 519 520 if (m_uploadPopup != null) { 521 m_uploadPopup.hide(); 522 m_uploadPopup = null; 523 } 524 } 525 526 /** 527 * Sets the upload popup, and closes the previous one if it exists. 528 * 529 * @param popup the upload popup 530 */ 531 private void setUploadPopup(CmsUploadPopup popup) { 532 533 closeUploadPopup(); 534 m_uploadPopup = popup; 535 } 536 537}