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; 029 030import org.opencms.ade.containerpage.client.CmsContainerpageEvent.EventType; 031import org.opencms.ade.containerpage.client.ui.CmsConfirmRemoveDialog; 032import org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer; 033import org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel; 034import org.opencms.ade.containerpage.client.ui.CmsGroupContainerElementPanel; 035import org.opencms.ade.containerpage.client.ui.CmsRemovedElementDeletionDialog; 036import org.opencms.ade.containerpage.client.ui.CmsReuseInfoDialog; 037import org.opencms.ade.containerpage.client.ui.CmsSmallElementsHandler; 038import org.opencms.ade.containerpage.client.ui.I_CmsDropContainer; 039import org.opencms.ade.containerpage.client.ui.css.I_CmsLayoutBundle; 040import org.opencms.ade.containerpage.client.ui.groupeditor.A_CmsGroupEditor; 041import org.opencms.ade.containerpage.client.ui.groupeditor.CmsGroupContainerEditor; 042import org.opencms.ade.containerpage.client.ui.groupeditor.CmsInheritanceContainerEditor; 043import org.opencms.ade.containerpage.shared.CmsCntPageData; 044import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode; 045import org.opencms.ade.containerpage.shared.CmsContainer; 046import org.opencms.ade.containerpage.shared.CmsContainerElement; 047import org.opencms.ade.containerpage.shared.CmsContainerElementData; 048import org.opencms.ade.containerpage.shared.CmsContainerPageGalleryData; 049import org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext; 050import org.opencms.ade.containerpage.shared.CmsCreateElementData; 051import org.opencms.ade.containerpage.shared.CmsDialogOptionsAndInfo; 052import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig; 053import org.opencms.ade.containerpage.shared.CmsElementViewInfo; 054import org.opencms.ade.containerpage.shared.CmsGroupContainer; 055import org.opencms.ade.containerpage.shared.CmsGroupContainerSaveResult; 056import org.opencms.ade.containerpage.shared.CmsInheritanceContainer; 057import org.opencms.ade.containerpage.shared.CmsPageSaveStatus; 058import org.opencms.ade.containerpage.shared.CmsRemovedElementStatus; 059import org.opencms.ade.containerpage.shared.CmsReuseInfo; 060import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService; 061import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageServiceAsync; 062import org.opencms.ade.contenteditor.client.CmsContentEditor; 063import org.opencms.gwt.client.CmsCoreProvider; 064import org.opencms.gwt.client.I_CmsElementToolbarContext; 065import org.opencms.gwt.client.dnd.CmsCompositeDNDController; 066import org.opencms.gwt.client.dnd.CmsDNDHandler; 067import org.opencms.gwt.client.dnd.I_CmsDNDController; 068import org.opencms.gwt.client.rpc.CmsRpcAction; 069import org.opencms.gwt.client.rpc.CmsRpcPrefetcher; 070import org.opencms.gwt.client.ui.CmsErrorDialog; 071import org.opencms.gwt.client.ui.CmsNotification; 072import org.opencms.gwt.client.ui.CmsNotification.Type; 073import org.opencms.gwt.client.ui.contextmenu.CmsEmbeddedAction; 074import org.opencms.gwt.client.util.CmsDebugLog; 075import org.opencms.gwt.client.util.CmsDomUtil; 076import org.opencms.gwt.client.util.I_CmsSimpleCallback; 077import org.opencms.gwt.shared.CmsContextMenuEntryBean; 078import org.opencms.gwt.shared.CmsCoreData.AdeContext; 079import org.opencms.gwt.shared.CmsGalleryContainerInfo; 080import org.opencms.gwt.shared.CmsGwtConstants; 081import org.opencms.gwt.shared.CmsGwtLog; 082import org.opencms.gwt.shared.CmsListInfoBean; 083import org.opencms.gwt.shared.CmsTemplateContextInfo; 084import org.opencms.gwt.shared.I_CmsAutoBeanFactory; 085import org.opencms.gwt.shared.I_CmsUnlockData; 086import org.opencms.gwt.shared.rpc.I_CmsCoreServiceAsync; 087import org.opencms.util.CmsDefaultSet; 088import org.opencms.util.CmsStringUtil; 089import org.opencms.util.CmsUUID; 090 091import java.util.ArrayList; 092import java.util.Collection; 093import java.util.HashMap; 094import java.util.HashSet; 095import java.util.Iterator; 096import java.util.List; 097import java.util.Map; 098import java.util.Map.Entry; 099import java.util.Set; 100 101import com.google.common.base.Optional; 102import com.google.common.collect.Lists; 103import com.google.gwt.core.client.GWT; 104import com.google.gwt.dom.client.AnchorElement; 105import com.google.gwt.dom.client.Element; 106import com.google.gwt.dom.client.EventTarget; 107import com.google.gwt.event.dom.client.KeyCodes; 108import com.google.gwt.event.logical.shared.ResizeEvent; 109import com.google.gwt.event.logical.shared.ResizeHandler; 110import com.google.gwt.event.logical.shared.ValueChangeEvent; 111import com.google.gwt.event.logical.shared.ValueChangeHandler; 112import com.google.gwt.user.client.Command; 113import com.google.gwt.user.client.Event; 114import com.google.gwt.user.client.Event.NativePreviewEvent; 115import com.google.gwt.user.client.Event.NativePreviewHandler; 116import com.google.gwt.user.client.History; 117import com.google.gwt.user.client.Timer; 118import com.google.gwt.user.client.Window; 119import com.google.gwt.user.client.rpc.AsyncCallback; 120import com.google.gwt.user.client.rpc.SerializationException; 121import com.google.gwt.user.client.rpc.ServiceDefTarget; 122import com.google.gwt.user.client.ui.RootPanel; 123import com.google.gwt.user.client.ui.Widget; 124import com.google.web.bindery.autobean.shared.AutoBean; 125import com.google.web.bindery.autobean.shared.AutoBeanCodex; 126 127import elemental2.core.JsObject; 128import elemental2.dom.CustomEvent; 129import elemental2.dom.CustomEventInit; 130import elemental2.dom.DomGlobal; 131import elemental2.webstorage.WebStorageWindow; 132import jsinterop.annotations.JsPackage; 133import jsinterop.annotations.JsProperty; 134import jsinterop.annotations.JsType; 135import jsinterop.base.Js; 136import jsinterop.base.JsPropertyMap; 137 138/** 139 * Data provider for the container-page editor. All data concerning the container-page is requested and maintained by this provider.<p> 140 * 141 * @since 8.0.0 142 */ 143public final class CmsContainerpageController { 144 145 /** 146 * Enum which is used to control how elements are removed from the page.<p> 147 */ 148 public enum ElementRemoveMode { 149 /** Reference checks are performed and the user is asked for confirmation whether they really want to remove the element before the page is saved. */ 150 confirmRemove, 151 152 /** Reference checks are only performed after the page or group has been saved. */ 153 saveAndCheckReferences, 154 155 /** Element is just removed, no checks are performed. */ 156 silent; 157 } 158 159 /** 160 * Wrapper for the event details object for custom page editor events. 161 */ 162 @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "?") 163 public interface I_EventDetails { 164 165 /** 166 * Gets the HTML element for the container itself. 167 * 168 * @return the HTML element for the container 169 */ 170 @JsProperty 171 elemental2.dom.Element getContainer(); 172 173 /** 174 * Gets the HTML element for the page element. 175 * 176 * @return the HTML element for the page element 177 */ 178 @JsProperty 179 elemental2.dom.Element getElement(); 180 181 /** 182 * The 'placeholder' state of the element. 183 * 184 * @return the 'placedholder' state 185 */ 186 @JsProperty 187 boolean getIsPlaceholder(); 188 189 /** 190 * Gets the replaced element. 191 * 192 * @return the replaced element 193 */ 194 @JsProperty 195 elemental2.dom.Element getReplacedElement(); 196 197 /** 198 * Gets the type. 199 * 200 * @return the type 201 */ 202 @JsProperty 203 String getType(); 204 205 /** 206 * Sets the HTML element for the container. 207 * 208 * @param container the HTML element for the container 209 */ 210 @JsProperty 211 void setContainer(elemental2.dom.Element container); 212 213 /** 214 * Sets the HTML element for the page element. 215 * @param element the HTML element for the page element 216 */ 217 @JsProperty 218 void setElement(elemental2.dom.Element element); 219 220 /** 221 * Sets the 'placeholder' (i.e. 'new') state 222 * 223 * @param isPlaceholder true if the element was new 224 */ 225 @JsProperty 226 void setIsPlaceholder(boolean isPlaceholder); 227 228 /** 229 * Sets the replaced element. 230 * 231 * @param element the replaced element 232 */ 233 @JsProperty 234 void setReplacedElement(elemental2.dom.Element element); 235 236 /** 237 * Sets the type. 238 * 239 * @param type the type 240 */ 241 @JsProperty 242 void setType(String type); 243 244 } 245 246 /** 247 * Visitor interface used to process the current container content on the page.<p> 248 */ 249 public static interface I_PageContentVisitor { 250 251 /** 252 * This method is called before a container is processed.<p> 253 * 254 * If the method returns false, the container will be skipped.<p> 255 * 256 * @param name the container name 257 * @param container the container data object 258 * 259 * @return true if the container should be processed, true if it should be skipped 260 */ 261 boolean beginContainer(String name, CmsContainer container); 262 263 /** 264 * This method is called after all elements of a container have been processed.<p> 265 */ 266 void endContainer(); 267 268 /** 269 * This method is called for each element of a container.<p> 270 * 271 * @param element the container element 272 */ 273 void handleElement(CmsContainerPageElementPanel element); 274 } 275 276 /** 277 * Interface for classes that should be notified when container page elements are reloaded. 278 */ 279 public interface I_ReloadHandler { 280 281 /** 282 * Called after all other onReload calls for the current operation. 283 * */ 284 void finish(); 285 286 /** 287 * Is called when an element has been replaced on the page. 288 * 289 * @param oldElement the old element 290 * @param newElement the replacement element that is currently on the page 291 */ 292 void onReload(CmsContainerPageElementPanel oldElement, CmsContainerPageElementPanel newElement); 293 } 294 295 /** 296 * This visitor implementation checks whether there are other elements in the current page 297 * which correspond to the same VFS resource as a given container element. 298 */ 299 public static class ReferenceCheckVisitor implements I_PageContentVisitor { 300 301 /** The element for which we want to check whether there are other references to the same resource. */ 302 private CmsContainerPageElementPanel m_elementPanel; 303 304 /** True if other references have been found. */ 305 private boolean m_hasReferences; 306 307 /** The structure id of the element. */ 308 private String m_structureId; 309 310 /** 311 * Creates a new instance.<p> 312 * 313 * @param elementPanel the element for which we want to check if there are other references 314 */ 315 public ReferenceCheckVisitor(CmsContainerPageElementPanel elementPanel) { 316 317 m_elementPanel = elementPanel; 318 m_structureId = getServerId(elementPanel.getId()); 319 } 320 321 /** 322 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#beginContainer(java.lang.String, org.opencms.ade.containerpage.shared.CmsContainer) 323 */ 324 public boolean beginContainer(String name, CmsContainer container) { 325 326 return !container.isDetailView(); 327 } 328 329 /** 330 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#endContainer() 331 */ 332 public void endContainer() { 333 334 // do nothing 335 } 336 337 /** 338 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#handleElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) 339 */ 340 public void handleElement(CmsContainerPageElementPanel element) { 341 342 if (element != m_elementPanel) { 343 String id = getServerId(element.getId()); 344 if (m_structureId.equals(id)) { 345 m_hasReferences = true; 346 } 347 } 348 } 349 350 /** 351 * Checks if other references have been found.<p> 352 * 353 * @return true if other references have been found 354 */ 355 public boolean hasReferences() { 356 357 return m_hasReferences; 358 } 359 360 } 361 362 /** 363 * Visitor implementation which is used to gather the container contents for saving.<p> 364 */ 365 protected class PageStateVisitor implements I_PageContentVisitor { 366 367 /** The current container name. */ 368 protected String m_containerName; 369 370 /** The contaienr which is currently being processed. */ 371 protected CmsContainer m_currentContainer; 372 373 /** The list of collected containers. */ 374 protected List<CmsContainer> m_resultContainers = new ArrayList<CmsContainer>(); 375 376 /** The list of elements of the currently processed container which have already been processed. */ 377 List<CmsContainerElement> m_currentElements; 378 379 /** 380 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#beginContainer(java.lang.String, org.opencms.ade.containerpage.shared.CmsContainer) 381 */ 382 public boolean beginContainer(String name, CmsContainer container) { 383 384 m_currentContainer = container; 385 m_containerName = name; 386 m_currentElements = new ArrayList<CmsContainerElement>(); 387 return true; 388 } 389 390 /** 391 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#endContainer() 392 */ 393 public void endContainer() { 394 395 CmsContainer container = new CmsContainer( 396 m_containerName, 397 m_currentContainer.getType(), 398 null, 399 m_currentContainer.getWidth(), 400 m_currentContainer.getMaxElements(), 401 m_currentContainer.isDetailViewContainer(), 402 m_currentContainer.isDetailView(), 403 true, 404 m_currentElements, 405 m_currentContainer.getParentContainerName(), 406 m_currentContainer.getParentInstanceId(), 407 m_currentContainer.getSettingPresets()); 408 container.setDetailOnly(m_currentContainer.isDetailOnly()); 409 container.setRootContainer(isRootContainer(m_currentContainer)); 410 m_resultContainers.add(container); 411 } 412 413 /** 414 * Gets the list of collected containers.<p> 415 * 416 * @return the list of containers 417 */ 418 public List<CmsContainer> getContainers() { 419 420 return m_resultContainers; 421 } 422 423 /** 424 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#handleElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) 425 */ 426 public void handleElement(CmsContainerPageElementPanel elementWidget) { 427 428 CmsContainerElement element = new CmsContainerElement(); 429 element.setClientId(elementWidget.getId()); 430 element.setResourceType(elementWidget.getNewType()); 431 element.setCreateNew(elementWidget.isCreateNew()); 432 element.setModelGroupId(elementWidget.getModelGroupId()); 433 element.setSitePath(elementWidget.getSitePath()); 434 element.setNewEditorDisabled(elementWidget.isNewEditorDisabled()); 435 m_currentElements.add(element); 436 } 437 438 } 439 440 /** 441 * Visitor implementation which is used to gather the container contents for saving.<p> 442 */ 443 protected class SaveDataVisitor implements I_PageContentVisitor { 444 445 /** The current container name. */ 446 protected String m_containerName; 447 448 /** The contaienr which is currently being processed. */ 449 protected CmsContainer m_currentContainer; 450 451 /** The list of collected containers. */ 452 protected List<CmsContainer> m_resultContainers = new ArrayList<CmsContainer>(); 453 454 /** The list of elements of the currently processed container which have already been processed. */ 455 List<CmsContainerElement> m_currentElements; 456 457 /** 458 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#beginContainer(java.lang.String, org.opencms.ade.containerpage.shared.CmsContainer) 459 */ 460 public boolean beginContainer(String name, CmsContainer container) { 461 462 if (container.isDetailView() || ((getData().getDetailId() != null) && !container.isDetailOnly())) { 463 m_currentContainer = null; 464 return false; 465 466 } else { 467 m_currentContainer = container; 468 m_containerName = name; 469 m_currentElements = new ArrayList<CmsContainerElement>(); 470 return true; 471 } 472 } 473 474 /** 475 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#endContainer() 476 */ 477 public void endContainer() { 478 479 CmsContainer container = new CmsContainer( 480 m_containerName, 481 m_currentContainer.getType(), 482 null, 483 m_currentContainer.getWidth(), 484 m_currentContainer.getMaxElements(), 485 m_currentContainer.isDetailViewContainer(), 486 m_currentContainer.isDetailView(), 487 true, 488 m_currentElements, 489 m_currentContainer.getParentContainerName(), 490 m_currentContainer.getParentInstanceId(), 491 m_currentContainer.getSettingPresets()); 492 493 container.setRootContainer(isRootContainer(m_currentContainer)); 494 m_resultContainers.add(container); 495 } 496 497 /** 498 * Gets the list of collected containers.<p> 499 * 500 * @return the list of containers 501 */ 502 public List<CmsContainer> getContainers() { 503 504 return m_resultContainers; 505 } 506 507 /** 508 * @see org.opencms.ade.containerpage.client.CmsContainerpageController.I_PageContentVisitor#handleElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) 509 */ 510 public void handleElement(CmsContainerPageElementPanel elementWidget) { 511 512 CmsContainerElement element = new CmsContainerElement(); 513 element.setClientId(elementWidget.getId()); 514 element.setResourceType(elementWidget.getNewType()); 515 element.setCreateNew(elementWidget.isCreateNew()); 516 element.setModelGroupId(elementWidget.getModelGroupId()); 517 element.setSitePath(elementWidget.getSitePath()); 518 element.setNewEditorDisabled(elementWidget.isNewEditorDisabled()); 519 m_currentElements.add(element); 520 } 521 522 } 523 524 /** 525 * A type which indicates the locking status of the currently edited container page.<p> 526 */ 527 enum LockStatus { 528 /** Locking the resource failed. */ 529 failed, 530 531 /** The resource could be successfully locked. */ 532 locked, 533 534 /** Locking the resource has not been tried. */ 535 unknown 536 } 537 538 /** 539 * A RPC action implementation used to request the data for container-page elements.<p> 540 */ 541 private class MultiElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> { 542 543 /** Call-back executed on response. */ 544 private I_CmsSimpleCallback<Map<String, CmsContainerElementData>> m_callback; 545 546 /** The requested client id's. */ 547 private Set<String> m_clientIds; 548 549 /** 550 " * Constructor.<p> 551 * 552 * @param clientIds the client id's 553 * @param callback the call-back 554 */ 555 public MultiElementAction( 556 Set<String> clientIds, 557 I_CmsSimpleCallback<Map<String, CmsContainerElementData>> callback) { 558 559 super(); 560 m_clientIds = clientIds; 561 m_callback = callback; 562 } 563 564 /** 565 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 566 */ 567 @Override 568 public void execute() { 569 570 Map<String, CmsContainerElementData> result = new HashMap<String, CmsContainerElementData>(); 571 List<String> neededIds = new ArrayList<String>(); 572 Iterator<String> it = m_clientIds.iterator(); 573 while (it.hasNext()) { 574 String clientId = it.next(); 575 if (m_elements.containsKey(clientId)) { 576 result.put(clientId, m_elements.get(clientId)); 577 } else { 578 neededIds.add(clientId); 579 } 580 } 581 if (neededIds.size() == 0) { 582 m_callback.execute(result); 583 } else { 584 getContainerpageService().getElementsData( 585 getData().getRpcContext(), 586 getData().getDetailId(), 587 getRequestParams(), 588 m_clientIds, 589 getPageState(), 590 false, 591 null, 592 getLocale(), 593 this); 594 } 595 596 } 597 598 /** 599 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 600 */ 601 @Override 602 protected void onResponse(Map<String, CmsContainerElementData> result) { 603 604 if (result != null) { 605 addElements(result); 606 Map<String, CmsContainerElementData> elements = new HashMap<String, CmsContainerElementData>(); 607 Iterator<String> it = m_clientIds.iterator(); 608 while (it.hasNext()) { 609 String clientId = it.next(); 610 elements.put(clientId, m_elements.get(clientId)); 611 } 612 m_callback.execute(elements); 613 } 614 } 615 616 } 617 618 /** 619 * A RPC action implementation used to reload the data for a container-page element.<p> 620 */ 621 private class ReloadElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> { 622 623 /** The requested client id's. */ 624 private Set<String> m_clientIds; 625 626 /** The callback to execute after the reload. */ 627 private I_ReloadHandler m_reloadHandler; 628 629 /** 630 * Constructor.<p> 631 * 632 * @param clientIds the client id's to reload 633 * @param reloadHandler the callback to call after the elements have been replaced 634 */ 635 public ReloadElementAction(Set<String> clientIds, I_ReloadHandler reloadHandler) { 636 637 super(); 638 m_clientIds = clientIds; 639 m_reloadHandler = reloadHandler; 640 } 641 642 /** 643 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 644 */ 645 @Override 646 public void execute() { 647 648 getContainerpageService().getElementsData( 649 getData().getRpcContext(), 650 getData().getDetailId(), 651 getRequestParams(), 652 m_clientIds, 653 getPageState(), 654 false, 655 null, 656 getLocale(), 657 this); 658 } 659 660 /** 661 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 662 */ 663 @Override 664 protected void onResponse(Map<String, CmsContainerElementData> result) { 665 666 if (result == null) { 667 return; 668 } 669 addElements(result); 670 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> it = getAllDragElements().iterator(); 671 boolean reloadMarkerFound = false; 672 while (it.hasNext()) { 673 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel containerElement = it.next(); 674 if (!m_clientIds.contains(containerElement.getId())) { 675 continue; 676 } 677 try { 678 CmsContainerPageElementPanel replacer = replaceContainerElement( 679 containerElement, 680 result.get(containerElement.getId())); 681 if (replacer.getElement().getInnerHTML().contains(CmsGwtConstants.FORMATTER_RELOAD_MARKER)) { 682 reloadMarkerFound = true; 683 } 684 m_reloadHandler.onReload(containerElement, replacer); 685 } catch (Exception e) { 686 CmsDebugLog.getInstance().printLine("trying to replace"); 687 CmsDebugLog.getInstance().printLine(e.getLocalizedMessage()); 688 } 689 690 } 691 if (isGroupcontainerEditing()) { 692 getGroupEditor().updateBackupElements(result); 693 getGroupcontainer().refreshHighlighting(); 694 } else { 695 if (reloadMarkerFound) { 696 CmsContainerpageController.get().reloadPage(); 697 } else { 698 long loadTime = result.values().iterator().next().getLoadTime(); 699 setLoadTime(Long.valueOf(loadTime)); 700 } 701 } 702 m_handler.updateClipboard(result); 703 resetEditButtons(); 704 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.elementEdited)); 705 if (m_reloadHandler != null) { 706 m_reloadHandler.finish(); 707 } 708 } 709 } 710 711 /** 712 * A RPC action implementation used to request the data for a single container-page element.<p> 713 */ 714 private class SingleElementAction extends CmsRpcAction<Map<String, CmsContainerElementData>> { 715 716 /** Always copy createNew elements in case reading data for a clipboard element used as a copy group. */ 717 private boolean m_alwaysCopy; 718 719 /** Call-back executed on response. */ 720 private I_CmsSimpleCallback<CmsContainerElementData> m_callback; 721 /** The requested client id. */ 722 private String m_clientId; 723 724 /** If this action was triggered by drag and drop from a container, this should contain the id of the origin container. */ 725 private String m_dndContainer; 726 727 /** 728 * Constructor.<p> 729 * 730 * @param clientId the client id 731 * @param callback the call-back 732 * @param alwaysCopy <code>true</code> in case reading data for a clipboard element used as a copy group 733 */ 734 public SingleElementAction( 735 String clientId, 736 boolean alwaysCopy, 737 I_CmsSimpleCallback<CmsContainerElementData> callback) { 738 739 super(); 740 m_clientId = clientId; 741 m_callback = callback; 742 m_alwaysCopy = alwaysCopy; 743 } 744 745 /** 746 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 747 */ 748 @Override 749 public void execute() { 750 751 List<String> clientIds = new ArrayList<String>(); 752 clientIds.add(m_clientId); 753 getContainerpageService().getElementsData( 754 getData().getRpcContext(), 755 getData().getDetailId(), 756 getRequestParams(), 757 clientIds, 758 getPageState(), 759 m_alwaysCopy, 760 m_dndContainer, 761 getLocale(), 762 this); 763 } 764 765 /** 766 * Sets the origin container for the drag and drop case.<p> 767 * 768 * @param containerId the origin container name 769 */ 770 public void setDndContainer(String containerId) { 771 772 m_dndContainer = containerId; 773 } 774 775 /** 776 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 777 */ 778 @Override 779 protected void onResponse(Map<String, CmsContainerElementData> result) { 780 781 if (result != null) { 782 addElements(result); 783 long loadTime = result.get(m_clientId).getLoadTime(); 784 setLoadTime(Long.valueOf(loadTime)); 785 m_callback.execute(result.get(m_clientId)); 786 } 787 } 788 } 789 790 /** The client side id/setting-hash seperator. */ 791 public static final String CLIENT_ID_SEPERATOR = "#"; 792 793 /** Custom event name. */ 794 public static final String EVENT_DRAG = "ocDrag"; 795 796 /** Custom event name. */ 797 public static final String EVENT_DRAG_FINISHED = "ocDragFinished"; 798 799 /** Custom event name. */ 800 public static final String EVENT_DRAG_STARTED = "ocDragStarted"; 801 802 /** Custom event name. */ 803 public static final String EVENT_ELEMENT_ADDED = "ocElementAdded"; 804 805 /** Custom event name. */ 806 public static final String EVENT_ELEMENT_DELETED = "ocElementDeleted"; 807 808 /** Custom event name. */ 809 public static final String EVENT_ELEMENT_EDITED = "ocElementEdited"; 810 811 /** Custom event name. */ 812 public static final String EVENT_ELEMENT_EDITED_CONTENT = "ocElementEditedContent"; 813 814 /** Custom event name. */ 815 public static final String EVENT_ELEMENT_EDITED_SETTINGS = "ocElementEditedSettings"; 816 817 /** Custom event name. */ 818 public static final String EVENT_ELEMENT_MODIFIED = "ocElementModified"; 819 820 /** Custom event name. */ 821 public static final String EVENT_ELEMENT_MOVED = "ocElementMoved"; 822 823 /** CSS class on the body to signal whether we are currently editing a group container. */ 824 public static final String OC_EDITING_GROUPCONTAINER = "oc-editing-groupcontainer"; 825 826 /** Parameter name. */ 827 public static final String PARAM_REMOVEMODE = "removemode"; 828 829 /** Instance of the data provider. */ 830 private static CmsContainerpageController INSTANCE; 831 832 /** The container element data. All requested elements will be cached here.*/ 833 protected Map<String, CmsContainerElementData> m_elements; 834 835 /** The new element data by resource type name. */ 836 protected Map<String, CmsContainerElementData> m_newElements; 837 838 /** The gallery data update timer. */ 839 Timer m_galleryUpdateTimer; 840 841 /** The currently editing group-container editor. */ 842 A_CmsGroupEditor m_groupEditor; 843 844 /** The container-page handler. */ 845 CmsContainerpageHandler m_handler; 846 847 /** The drag targets within this page. */ 848 Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> m_targetContainers; 849 850 /** The UUIDs for which reuse status has already been checked. */ 851 private Set<CmsUUID> m_checkedReuse = new HashSet<>(); 852 853 /** The container page drag and drop controller. */ 854 private I_CmsDNDController m_cntDndController; 855 856 /** The container-page RPC service. */ 857 private I_CmsContainerpageServiceAsync m_containerpageService; 858 859 /** The container-page util instance. */ 860 private CmsContainerpageUtil m_containerpageUtil; 861 862 /** The container data. */ 863 private Map<String, CmsContainer> m_containers; 864 865 /** The XML content editor handler. */ 866 private CmsContentEditorHandler m_contentEditorHandler; 867 868 /** The core RPC service instance. */ 869 private I_CmsCoreServiceAsync m_coreSvc; 870 871 /** The current edit container level. */ 872 private int m_currentEditLevel = -1; 873 874 /** The prefetched data. */ 875 private CmsCntPageData m_data; 876 877 /** The DND controller. */ 878 private CmsCompositeDNDController m_dndController; 879 880 /** The drag and drop handler. */ 881 private CmsDNDHandler m_dndHandler; 882 883 /** Edit button position timer. */ 884 private Timer m_editButtonsPositionTimer; 885 886 /** The current element view. */ 887 private CmsElementViewInfo m_elementView; 888 889 /** Flag indicating that a content element is being edited. */ 890 private boolean m_isContentEditing; 891 892 /** The container page load time. */ 893 private long m_loadTime; 894 895 /** The lock error message. */ 896 private String m_lockErrorMessage; 897 898 /** The current lock status for the page. */ 899 private LockStatus m_lockStatus = LockStatus.unknown; 900 901 /** The max container level. */ 902 private int m_maxContainerLevel; 903 904 /** The model group base element id. */ 905 private String m_modelGroupElementId; 906 907 /** The browser location at the time the containerpage controller was initialized. */ 908 private String m_originalUrl; 909 910 /** Flag if the container-page has changed. */ 911 private boolean m_pageChanged; 912 913 /** The publish lock checker. */ 914 private CmsPublishLockChecker m_publishLockChecker = new CmsPublishLockChecker(this); 915 916 /** Timer to handle window resize. */ 917 private Timer m_resizeTimer; 918 919 /** Handler for small elements. */ 920 private CmsSmallElementsHandler m_smallElementsHandler; 921 922 /** Alternative preview handler for events. */ 923 private NativePreviewHandler m_previewHandler; 924 925 /** 926 * Constructor.<p> 927 */ 928 public CmsContainerpageController() { 929 930 m_originalUrl = Window.Location.getHref(); 931 INSTANCE = this; 932 try { 933 m_data = (CmsCntPageData)CmsRpcPrefetcher.getSerializedObjectFromDictionary( 934 getContainerpageService(), 935 CmsCntPageData.DICT_NAME); 936 m_elementView = m_data.getElementView(); 937 m_modelGroupElementId = m_data.getModelGroupElementId(); 938 m_loadTime = m_data.getLoadTime(); 939 try { 940 WebStorageWindow window = WebStorageWindow.of(DomGlobal.window); 941 for (Map.Entry<String, String> entry : m_data.getSessionStorageData().entrySet()) { 942 window.sessionStorage.setItem(entry.getKey(), entry.getValue()); 943 } 944 } catch (Exception e) { 945 CmsGwtLog.log("can't use webstorage API"); 946 } 947 } catch (SerializationException e) { 948 CmsErrorDialog.handleException( 949 new Exception( 950 "Deserialization of page data failed. This may be caused by expired java-script resources, please clear your browser cache and try again.", 951 e)); 952 } 953 m_smallElementsHandler = new CmsSmallElementsHandler(getContainerpageService()); 954 if (m_data != null) { 955 m_smallElementsHandler.setEditSmallElements(m_data.isEditSmallElementsInitially(), false); 956 957 m_data.setRpcContext( 958 new CmsContainerPageRpcContext( 959 CmsCoreProvider.get().getStructureId(), 960 m_data.getTemplateContextInfo().getCurrentContext())); 961 } 962 963 } 964 965 /** 966 * Returns the data provider instance.<p> 967 * 968 * @return the data provider 969 */ 970 public static CmsContainerpageController get() { 971 972 if (INSTANCE == null) { 973 CmsDebugLog.getInstance().printLine("WARNING: The data provider has not been initialized!"); 974 return null; 975 } 976 return INSTANCE; 977 } 978 979 /** 980 * Returns the current URI.<p> 981 * 982 * @return the current URI 983 */ 984 public static String getCurrentUri() { 985 986 return CmsCoreProvider.get().getUri(); 987 988 } 989 990 /** 991 * Returns the server id for a given client element id.<p> 992 * 993 * @param clientId the client id including an optional element settings hash 994 * 995 * @return the server id 996 */ 997 public static String getServerId(String clientId) { 998 999 String serverId = clientId; 1000 if (clientId.contains(CLIENT_ID_SEPERATOR)) { 1001 serverId = clientId.substring(0, clientId.lastIndexOf(CLIENT_ID_SEPERATOR)); 1002 } 1003 return serverId; 1004 } 1005 1006 /** 1007 * Checks whether element removal should be confirmed.<p> 1008 * 1009 * @return true if element removal should be confirmed 1010 */ 1011 public static boolean isConfirmRemove() { 1012 1013 Map<String, String> params = CmsCoreProvider.get().getAdeParameters(); 1014 String removeMode = params.get(PARAM_REMOVEMODE); 1015 return (removeMode == null) || removeMode.equals("confirm"); 1016 } 1017 1018 /** 1019 * Adds a handler for container page events.<p> 1020 * 1021 * @param handler the handler to add 1022 */ 1023 public void addContainerpageEventHandler(I_CmsContainerpageEventHandler handler) { 1024 1025 CmsCoreProvider.get().getEventBus().addHandler(CmsContainerpageEvent.TYPE, handler); 1026 } 1027 1028 /** 1029 * Adds an element specified by it's id to the favorite list.<p> 1030 * 1031 * @param clientId the element id 1032 */ 1033 public void addToFavoriteList(final String clientId) { 1034 1035 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 1036 1037 /** 1038 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1039 */ 1040 @Override 1041 public void execute() { 1042 1043 getContainerpageService().addToFavoriteList(getData().getRpcContext(), clientId, this); 1044 } 1045 1046 /** 1047 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1048 */ 1049 @Override 1050 protected void onResponse(Void result) { 1051 1052 CmsNotification.get().send( 1053 Type.NORMAL, 1054 Messages.get().key(Messages.GUI_NOTIFICATION_ADD_TO_FAVORITES_0)); 1055 } 1056 }; 1057 action.execute(); 1058 } 1059 1060 /** 1061 * Adds an element specified by it's id to the recent list.<p> 1062 * 1063 * @param clientId the element id 1064 * @param nextAction the action to execute after the element has been added 1065 */ 1066 public void addToRecentList(final String clientId, final Runnable nextAction) { 1067 1068 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 1069 1070 /** 1071 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1072 */ 1073 @Override 1074 public void execute() { 1075 1076 getContainerpageService().addToRecentList(getData().getRpcContext(), clientId, this); 1077 } 1078 1079 /** 1080 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1081 */ 1082 @Override 1083 protected void onResponse(Void result) { 1084 1085 if (nextAction != null) { 1086 nextAction.run(); 1087 } 1088 } 1089 }; 1090 action.execute(); 1091 } 1092 1093 /** 1094 * Checks whether GWT widgets are available for all fields of a content.<p> 1095 * 1096 * @param structureId the structure id of the content 1097 * @param resultCallback the callback for the result 1098 */ 1099 public void checkNewWidgetsAvailable(final CmsUUID structureId, final AsyncCallback<Boolean> resultCallback) { 1100 1101 CmsRpcAction<Boolean> action = new CmsRpcAction<Boolean>() { 1102 1103 @Override 1104 public void execute() { 1105 1106 start(200, false); 1107 getContainerpageService().checkNewWidgetsAvailable(structureId, this); 1108 } 1109 1110 @Override 1111 protected void onResponse(Boolean result) { 1112 1113 stop(false); 1114 resultCallback.onSuccess(result); 1115 } 1116 1117 // empty 1118 }; 1119 action.execute(); 1120 1121 } 1122 1123 /** 1124 * Checks reuse status of a container element, then shows a warning dialog if it is reused, and finally executes an action. 1125 * 1126 * @param elementWidget the container element for which to check the reuse status 1127 * @param action the action to execute after the reuse warning dialog is closed 1128 */ 1129 public void checkReuse(CmsContainerPageElementPanel elementWidget, Runnable action) { 1130 1131 Runnable wrappedAction = () -> { 1132 m_checkedReuse.add(elementWidget.getStructureId()); 1133 action.run(); 1134 }; 1135 if (elementWidget.isReused() 1136 && CmsCoreProvider.get().isWarnWhenEditingReusedElement() 1137 && !m_checkedReuse.contains(elementWidget.getStructureId())) { 1138 CmsUUID id = elementWidget.getStructureId(); 1139 CmsUUID detailId = CmsContainerpageController.get().getData().getDetailId(); 1140 CmsUUID pageId = CmsCoreProvider.get().getStructureId(); 1141 CmsRpcAction<CmsReuseInfo> rpc = new CmsRpcAction<CmsReuseInfo>() { 1142 1143 @Override 1144 public void execute() { 1145 1146 start(0, true); 1147 getContainerpageService().getReuseInfo(pageId, detailId, id, this); 1148 } 1149 1150 @Override 1151 protected void onResponse(CmsReuseInfo result) { 1152 1153 stop(false); 1154 if (result.getCount() == 0) { 1155 wrappedAction.run(); 1156 } else { 1157 CmsReuseInfoDialog dialog = new CmsReuseInfoDialog(result, status -> { 1158 if (status.booleanValue()) { 1159 wrappedAction.run(); 1160 } 1161 }); 1162 dialog.show(); 1163 // without delayed center(), positioning is inconsistent 1164 Timer timer = new Timer() { 1165 1166 @Override 1167 public void run() { 1168 1169 dialog.center(); 1170 } 1171 }; 1172 timer.schedule(100); 1173 } 1174 } 1175 }; 1176 rpc.execute(); 1177 } else { 1178 action.run(); 1179 } 1180 } 1181 1182 /** 1183 * Checks for container elements that are no longer present within the DOM.<p> 1184 */ 1185 public void cleanUpContainers() { 1186 1187 List<String> removed = new ArrayList<String>(); 1188 for (Entry<String, CmsContainerPageContainer> entry : m_targetContainers.entrySet()) { 1189 if (!RootPanel.getBodyElement().isOrHasChild(entry.getValue().getElement())) { 1190 removed.add(entry.getKey()); 1191 } 1192 } 1193 for (String containerId : removed) { 1194 m_targetContainers.remove(containerId); 1195 m_containers.remove(containerId); 1196 } 1197 if (removed.size() > 0) { 1198 scheduleGalleryUpdate(); 1199 } 1200 } 1201 1202 /** 1203 * Copies an element and asynchronously returns the structure id of the copy.<p> 1204 * 1205 * @param id the element id 1206 * @param callback the callback for the result 1207 */ 1208 public void copyElement(final String id, final I_CmsSimpleCallback<CmsUUID> callback) { 1209 1210 CmsRpcAction<CmsUUID> action = new CmsRpcAction<CmsUUID>() { 1211 1212 @Override 1213 public void execute() { 1214 1215 start(200, false); 1216 getContainerpageService().copyElement( 1217 CmsCoreProvider.get().getStructureId(), 1218 new CmsUUID(id), 1219 getData().getLocale(), 1220 this); 1221 } 1222 1223 @Override 1224 protected void onResponse(CmsUUID result) { 1225 1226 stop(false); 1227 callback.execute(result); 1228 } 1229 1230 }; 1231 action.execute(); 1232 } 1233 1234 /** 1235 * Creates a new resource for crag container elements with the status new and opens the content editor.<p> 1236 * 1237 * @param element the container element 1238 * @param inline <code>true</code> to open the inline editor for the given element if available 1239 */ 1240 public void createAndEditNewElement( 1241 final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element, 1242 final boolean inline) { 1243 1244 if (!element.isNew()) { 1245 return; 1246 } 1247 1248 final CmsContainer container = m_containers.get(element.getParentTarget().getContainerId()); 1249 1250 m_handler.showPageOverlay(); 1251 CmsRpcAction<CmsCreateElementData> action = new CmsRpcAction<CmsCreateElementData>() { 1252 1253 /** 1254 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1255 */ 1256 @Override 1257 public void execute() { 1258 1259 getContainerpageService().checkCreateNewElement( 1260 CmsCoreProvider.get().getStructureId(), 1261 getData().getDetailId(), 1262 element.getId(), 1263 element.getNewType(), 1264 container, 1265 getLocale(), 1266 this); 1267 1268 } 1269 1270 /** 1271 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1272 */ 1273 @Override 1274 protected void onResponse(CmsCreateElementData result) { 1275 1276 if (result.needsModelSelection()) { 1277 getHandler().openModelResourceSelect(element, result.getModelResources()); 1278 } else { 1279 openEditorForNewElement(element, result.getCreatedElement(), inline); 1280 } 1281 } 1282 }; 1283 action.execute(); 1284 } 1285 1286 /** 1287 * Creates a new resource for drag container elements with the status new and opens the content editor.<p> 1288 * 1289 * @param element the container element 1290 * @param modelResourceStructureId the model resource structure id 1291 */ 1292 public void createAndEditNewElement( 1293 final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element, 1294 final CmsUUID modelResourceStructureId) { 1295 1296 CmsRpcAction<CmsContainerElement> action = new CmsRpcAction<CmsContainerElement>() { 1297 1298 @Override 1299 public void execute() { 1300 1301 getContainerpageService().createNewElement( 1302 CmsCoreProvider.get().getStructureId(), 1303 getData().getDetailId(), 1304 element.getId(), 1305 element.getNewType(), 1306 modelResourceStructureId, 1307 getLocale(), 1308 this); 1309 1310 } 1311 1312 @Override 1313 protected void onResponse(CmsContainerElement result) { 1314 1315 openEditorForNewElement(element, result, false); 1316 1317 } 1318 }; 1319 action.execute(); 1320 } 1321 1322 /** 1323 * Creates the details object for a custom page editor event based on the given container page element. 1324 * 1325 * @param widget a container page element 1326 * @return the event details object 1327 */ 1328 public I_EventDetails createEventDetails(CmsContainerPageElementPanel widget) { 1329 1330 final Element parentContainerElement = CmsDomUtil.getAncestor( 1331 widget.getElement(), 1332 CmsContainerElement.CLASS_CONTAINER); 1333 1334 I_EventDetails details = Js.cast(new JsObject()); 1335 details.setIsPlaceholder(widget.isNew()); 1336 details.setElement(Js.cast(widget.getElement())); 1337 details.setContainer(Js.cast(parentContainerElement)); 1338 return details; 1339 } 1340 1341 /** 1342 * Creates a new element.<p> 1343 * 1344 * @param element the widget belonging to the element which is currently in memory only 1345 * @param callback the callback to call with the result 1346 */ 1347 public void createNewElement( 1348 final CmsContainerPageElementPanel element, 1349 final AsyncCallback<CmsContainerElement> callback) { 1350 1351 CmsRpcAction<CmsContainerElement> action = new CmsRpcAction<CmsContainerElement>() { 1352 1353 @Override 1354 public void execute() { 1355 1356 getContainerpageService().createNewElement( 1357 CmsCoreProvider.get().getStructureId(), 1358 getData().getDetailId(), 1359 element.getId(), 1360 element.getNewType(), 1361 null, 1362 getLocale(), 1363 this); 1364 1365 } 1366 1367 @Override 1368 protected void onResponse(CmsContainerElement result) { 1369 1370 callback.onSuccess(result); 1371 } 1372 }; 1373 action.execute(); 1374 } 1375 1376 /** 1377 * Deletes an element from the VFS, removes it from all containers and the client side cache.<p> 1378 * 1379 * @param elementId the element to delete 1380 * @param relatedElementId related element to reload after the element has been deleted 1381 */ 1382 public void deleteElement(String elementId, final String relatedElementId) { 1383 1384 elementId = getServerId(elementId); 1385 removeContainerElements(elementId); 1386 addToRecentList(elementId, null); 1387 reloadElements(new String[] {relatedElementId}, () -> {/*do nothing*/}); 1388 } 1389 1390 /** 1391 * Disables the inline editing for all content elements but the given one.<p> 1392 * 1393 * @param notThisOne the content element not to disable 1394 */ 1395 public void disableInlineEditing(CmsContainerPageElementPanel notThisOne) { 1396 1397 removeEditButtonsPositionTimer(); 1398 if (isGroupcontainerEditing()) { 1399 for (Widget element : m_groupEditor.getGroupContainerWidget()) { 1400 if ((element instanceof CmsContainerPageElementPanel) && (element != notThisOne)) { 1401 ((CmsContainerPageElementPanel)element).removeInlineEditor(); 1402 } 1403 } 1404 } else { 1405 for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers.values()) { 1406 for (Widget element : container) { 1407 if ((element instanceof CmsContainerPageElementPanel) && (element != notThisOne)) { 1408 ((CmsContainerPageElementPanel)element).removeInlineEditor(); 1409 } 1410 } 1411 } 1412 } 1413 } 1414 1415 /** 1416 * Enables the favorites editing drag and drop controller.<p> 1417 * 1418 * @param enable if <code>true</code> favorites editing will enabled, otherwise disabled 1419 * @param dndController the favorites editing drag and drop controller 1420 */ 1421 public void enableFavoriteEditing(boolean enable, I_CmsDNDController dndController) { 1422 1423 if (m_dndHandler.isDragging()) { 1424 // never switch drag and drop controllers while dragging 1425 return; 1426 } 1427 if (enable) { 1428 m_dndHandler.setController(dndController); 1429 } else { 1430 m_dndHandler.setController(m_cntDndController); 1431 } 1432 1433 } 1434 1435 /** 1436 * Replaces all element instances of the original element with the new element within the former copy model.<p> 1437 * 1438 * @param originalElementId the original element id 1439 * @param modelGroupParent the model group parent element 1440 * @param elementData the replace element data 1441 */ 1442 public void executeCopyModelReplace( 1443 String originalElementId, 1444 Element modelGroupParent, 1445 CmsContainerElementData elementData) { 1446 1447 String serverId = getServerId(originalElementId); 1448 for (CmsContainerPageContainer cont : m_targetContainers.values()) { 1449 if (modelGroupParent.isOrHasChild(cont.getElement())) { 1450 // look for instances of the original element 1451 for (Widget child : cont) { 1452 if ((child instanceof CmsContainerPageElementPanel) 1453 && ((CmsContainerPageElementPanel)child).getId().startsWith(serverId)) { 1454 CmsContainerPageElementPanel replacer = null; 1455 String elementContent = elementData.getContents().get(cont.getContainerId()); 1456 if ((elementContent != null) && (elementContent.trim().length() > 0)) { 1457 try { 1458 replacer = getContainerpageUtil().createElement(elementData, cont, false); 1459 cont.insert(replacer, cont.getWidgetIndex(child)); 1460 child.removeFromParent(); 1461 initializeSubContainers(replacer); 1462 } catch (Exception e) { 1463 //ignore 1464 } 1465 } 1466 } 1467 } 1468 } 1469 } 1470 } 1471 1472 /** 1473 * Fires an event on the core event bus.<p> 1474 * 1475 * @param event the event to fire 1476 */ 1477 public void fireEvent(CmsContainerpageEvent event) { 1478 1479 CmsCoreProvider.get().getEventBus().fireEvent(event); 1480 1481 } 1482 1483 /** 1484 * Returns all drag elements of the page.<p> 1485 * 1486 * @return the drag elements 1487 */ 1488 public List<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> getAllDragElements() { 1489 1490 List<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> result = new ArrayList<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel>(); 1491 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> it = m_targetContainers.values().iterator(); 1492 while (it.hasNext()) { 1493 result.addAll(it.next().getAllDragElements()); 1494 } 1495 if (isGroupcontainerEditing()) { 1496 Iterator<Widget> itSub = m_groupEditor.getGroupContainerWidget().iterator(); 1497 while (itSub.hasNext()) { 1498 Widget w = itSub.next(); 1499 if (w instanceof org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel) { 1500 result.add((org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel)w); 1501 } 1502 } 1503 } 1504 return result; 1505 } 1506 1507 /** 1508 * Returns the data for the requested element, or <code>null</code> if the element has not been cached yet.<p> 1509 * 1510 * @param clientId the element id 1511 * 1512 * @return the element data 1513 */ 1514 public CmsContainerElementData getCachedElement(String clientId) { 1515 1516 if (m_elements.containsKey(clientId)) { 1517 return m_elements.get(clientId); 1518 } 1519 return null; 1520 } 1521 1522 /** 1523 * Returns the data for the requested element, or <code>null</code> if the element has not been cached yet.<p> 1524 * 1525 * @param resourceTypeName the element resource type 1526 * 1527 * @return the element data 1528 */ 1529 public CmsContainerElementData getCachedNewElement(String resourceTypeName) { 1530 1531 if (m_newElements.containsKey(resourceTypeName)) { 1532 return m_newElements.get(resourceTypeName); 1533 } 1534 return null; 1535 } 1536 1537 /** 1538 * Returns the container data of container with the given name. 1539 * 1540 * @param containerName the container name 1541 * 1542 * @return the container data 1543 */ 1544 public CmsContainer getContainer(String containerName) { 1545 1546 return m_containers.get(containerName); 1547 } 1548 1549 /** 1550 * Gets the container element widget to which the given element belongs, or Optional.absent if none could be found.<p> 1551 * 1552 * @param element the element for which the container element widget should be found 1553 * 1554 * @return the container element widget, or Optional.absent if none can be found 1555 */ 1556 public Optional<CmsContainerPageElementPanel> getContainerElementWidgetForElement(Element element) { 1557 1558 final Element parentContainerElement = CmsDomUtil.getAncestor( 1559 element, 1560 I_CmsLayoutBundle.INSTANCE.dragdropCss().dragElement()); 1561 if (parentContainerElement == null) { 1562 return Optional.absent(); 1563 } 1564 final List<CmsContainerPageElementPanel> result = Lists.newArrayList(); 1565 processPageContent(new I_PageContentVisitor() { 1566 1567 public boolean beginContainer(String name, CmsContainer container) { 1568 1569 // we don't need to look into the container if we have already found our container element 1570 return result.isEmpty(); 1571 } 1572 1573 public void endContainer() { 1574 1575 // do nothing 1576 } 1577 1578 public void handleElement(CmsContainerPageElementPanel current) { 1579 1580 if ((current.getElement() == parentContainerElement) && result.isEmpty()) { 1581 result.add(current); 1582 } 1583 } 1584 }); 1585 if (result.isEmpty()) { 1586 return Optional.absent(); 1587 } else { 1588 return Optional.fromNullable(result.get(0)); 1589 } 1590 } 1591 1592 /** 1593 * Gets the container info to send to the gallery service. 1594 * 1595 * @return the container info to send to the gallery service 1596 */ 1597 public CmsGalleryContainerInfo getContainerInfoForGalleries() { 1598 1599 if (m_targetContainers != null) { 1600 HashSet<CmsGalleryContainerInfo.Item> items = new HashSet<>(); 1601 for (CmsContainerPageContainer cont : m_targetContainers.values()) { 1602 items.add(new CmsGalleryContainerInfo.Item(cont.getContainerType(), cont.getConfiguredWidth())); 1603 } 1604 return new CmsGalleryContainerInfo(items); 1605 } 1606 return null; 1607 } 1608 1609 /** 1610 * Returns the container-page RPC service.<p> 1611 * 1612 * @return the container-page service 1613 */ 1614 public I_CmsContainerpageServiceAsync getContainerpageService() { 1615 1616 if (m_containerpageService == null) { 1617 m_containerpageService = GWT.create(I_CmsContainerpageService.class); 1618 String serviceUrl = CmsCoreProvider.get().link("org.opencms.ade.containerpage.CmsContainerpageService.gwt"); 1619 ((ServiceDefTarget)m_containerpageService).setServiceEntryPoint(serviceUrl); 1620 } 1621 return m_containerpageService; 1622 } 1623 1624 /** 1625 * Returns the {@link org.opencms.ade.containerpage.client.CmsContainerpageUtil}.<p> 1626 * 1627 * @return the containerpage-util 1628 */ 1629 public CmsContainerpageUtil getContainerpageUtil() { 1630 1631 return m_containerpageUtil; 1632 } 1633 1634 /** 1635 * Returns the containers.<p> 1636 * 1637 * @return the containers 1638 */ 1639 public Map<String, CmsContainer> getContainers() { 1640 1641 return m_containers; 1642 } 1643 1644 /** 1645 * Returns the container drag target by name (HTML id attribute).<p> 1646 * 1647 * @param containerName the container name 1648 * @return the drag target 1649 */ 1650 public org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer getContainerTarget(String containerName) { 1651 1652 return m_targetContainers.get(containerName); 1653 } 1654 1655 /** 1656 * Returns a map of the container drag targets.<p> 1657 * 1658 * @return the drag targets 1659 */ 1660 public Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> getContainerTargets() { 1661 1662 Map<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> result = new HashMap<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer>(); 1663 for (Entry<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> entry : m_targetContainers.entrySet()) { 1664 if (entry.getValue().isEditable() 1665 && (!isDetailPage() || (entry.getValue().isDetailOnly() || entry.getValue().isDetailView()))) { 1666 result.put(entry.getKey(), entry.getValue()); 1667 } 1668 } 1669 return result; 1670 } 1671 1672 /** 1673 * Returns the type of container with the given name.<p> 1674 * 1675 * @param containerName the container name 1676 * 1677 * @return the container type 1678 */ 1679 public String getContainerType(String containerName) { 1680 1681 return getContainer(containerName).getType(); 1682 } 1683 1684 /** 1685 * Returns the XML content editor handler.<p> 1686 * 1687 * @return the XML content editor handler 1688 */ 1689 public CmsContentEditorHandler getContentEditorHandler() { 1690 1691 return m_contentEditorHandler; 1692 } 1693 1694 /** 1695 * Returns the prefetched data.<p> 1696 * 1697 * @return the prefetched data 1698 */ 1699 public CmsCntPageData getData() { 1700 1701 return m_data; 1702 } 1703 1704 /** 1705 * Returns the delete options for the given content element.<p> 1706 * 1707 * @param clientId the content id 1708 * @param callback the callback to execute 1709 */ 1710 public void getDeleteOptions(final String clientId, final I_CmsSimpleCallback<CmsDialogOptionsAndInfo> callback) { 1711 1712 CmsRpcAction<CmsDialogOptionsAndInfo> action = new CmsRpcAction<CmsDialogOptionsAndInfo>() { 1713 1714 @Override 1715 public void execute() { 1716 1717 getContainerpageService().getDeleteOptions( 1718 clientId, 1719 getData().getRpcContext().getPageStructureId(), 1720 getData().getRequestParams(), 1721 this); 1722 } 1723 1724 @Override 1725 protected void onResponse(CmsDialogOptionsAndInfo result) { 1726 1727 callback.execute(result); 1728 } 1729 }; 1730 action.execute(); 1731 } 1732 1733 /** 1734 * Gets the DND controller.<p> 1735 * 1736 * @return the DND controller 1737 */ 1738 public CmsCompositeDNDController getDndController() { 1739 1740 return m_dndController; 1741 } 1742 1743 /** 1744 * Returns the drag and drop handler.<p> 1745 * 1746 * @return the drag and drop handler 1747 */ 1748 public CmsDNDHandler getDndHandler() { 1749 1750 return m_dndHandler; 1751 } 1752 1753 /** 1754 * Returns the edit options for the given content element.<p> 1755 * 1756 * @param clientId the content id 1757 * @param isListElement in case a list element, not a container element is about to be edited 1758 * @param callback the callback to execute 1759 */ 1760 public void getEditOptions( 1761 final String clientId, 1762 final boolean isListElement, 1763 final I_CmsSimpleCallback<CmsDialogOptionsAndInfo> callback) { 1764 1765 CmsRpcAction<CmsDialogOptionsAndInfo> action = new CmsRpcAction<CmsDialogOptionsAndInfo>() { 1766 1767 @Override 1768 public void execute() { 1769 1770 getContainerpageService().getEditOptions( 1771 clientId, 1772 getData().getRpcContext().getPageStructureId(), 1773 getData().getRequestParams(), 1774 isListElement, 1775 this); 1776 } 1777 1778 @Override 1779 protected void onResponse(CmsDialogOptionsAndInfo result) { 1780 1781 callback.execute(result); 1782 } 1783 }; 1784 action.execute(); 1785 } 1786 1787 /** 1788 * Requests the data for a container element specified by the client id for drag and drop from a container. The data will be provided to the given call-back function.<p> 1789 * 1790 * @param clientId the element id 1791 * @param containerId the id of the container from which the element is being dragged 1792 * @param alwaysCopy <code>true</code> in case reading data for a clipboard element used as a copy group 1793 * @param callback the call-back to execute with the requested data 1794 */ 1795 public void getElementForDragAndDropFromContainer( 1796 final String clientId, 1797 final String containerId, 1798 boolean alwaysCopy, 1799 final I_CmsSimpleCallback<CmsContainerElementData> callback) { 1800 1801 SingleElementAction action = new SingleElementAction(clientId, alwaysCopy, callback); 1802 action.setDndContainer(containerId); 1803 action.execute(); 1804 } 1805 1806 /** 1807 * Requests the data for container elements specified by the client id. The data will be provided to the given call-back function.<p> 1808 * 1809 * @param clientIds the element id's 1810 * @param callback the call-back to execute with the requested data 1811 */ 1812 public void getElements(Set<String> clientIds, I_CmsSimpleCallback<Map<String, CmsContainerElementData>> callback) { 1813 1814 MultiElementAction action = new MultiElementAction(clientIds, callback); 1815 action.execute(); 1816 } 1817 1818 /** 1819 * Requests the element settings config data for a container element specified by the client id. The data will be provided to the given call-back function.<p> 1820 * 1821 * @param clientId the element id 1822 * @param containerId the parent container id 1823 * @param callback the call-back to execute with the requested data 1824 */ 1825 public void getElementSettingsConfig( 1826 final String clientId, 1827 final String containerId, 1828 final I_CmsSimpleCallback<CmsElementSettingsConfig> callback) { 1829 1830 CmsRpcAction<CmsElementSettingsConfig> action = new CmsRpcAction<CmsElementSettingsConfig>() { 1831 1832 /** 1833 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1834 */ 1835 @Override 1836 public void execute() { 1837 1838 start(100, true); 1839 getContainerpageService().getElementSettingsConfig( 1840 getData().getRpcContext(), 1841 clientId, 1842 containerId, 1843 getPageState(), 1844 getLocale(), 1845 this); 1846 1847 } 1848 1849 /** 1850 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1851 */ 1852 @Override 1853 protected void onResponse(CmsElementSettingsConfig result) { 1854 1855 if (result != null) { 1856 callback.execute(result); 1857 } 1858 stop(false); 1859 } 1860 }; 1861 action.execute(); 1862 } 1863 1864 /** 1865 * Returns the current element view.<p> 1866 * 1867 * @return the current element view 1868 */ 1869 public CmsElementViewInfo getElementView() { 1870 1871 return m_elementView; 1872 } 1873 1874 /** 1875 * Retrieves a container element with a given set of settings.<p> 1876 * 1877 * @param clientId the id of the container element 1878 * @param settings the set of settings 1879 * 1880 * @param callback the callback which should be executed when the element has been loaded 1881 */ 1882 public void getElementWithSettings( 1883 final String clientId, 1884 final Map<String, String> settings, 1885 final I_CmsSimpleCallback<CmsContainerElementData> callback) { 1886 1887 CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 1888 1889 /** 1890 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 1891 */ 1892 @Override 1893 public void execute() { 1894 1895 start(200, false); 1896 getContainerpageService().getElementWithSettings( 1897 getData().getRpcContext(), 1898 getData().getDetailId(), 1899 getRequestParams(), 1900 clientId, 1901 settings, 1902 getPageState(), 1903 getLocale(), 1904 this); 1905 1906 } 1907 1908 /** 1909 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 1910 */ 1911 @Override 1912 protected void onResponse(CmsContainerElementData result) { 1913 1914 stop(false); 1915 if (result != null) { 1916 // cache the loaded element 1917 m_elements.put(result.getClientId(), result); 1918 } 1919 callback.execute(result); 1920 } 1921 1922 }; 1923 action.execute(); 1924 1925 } 1926 1927 /** 1928 * Returns the group-container element being edited.<p> 1929 * 1930 * @return the group-container 1931 */ 1932 public CmsGroupContainerElementPanel getGroupcontainer() { 1933 1934 return m_groupEditor.getGroupContainerWidget(); 1935 } 1936 1937 /** 1938 * Returns the id of the currently edited group-container.<p> 1939 * 1940 * @return the group-container id, or <code>null</code> if no editing is taking place 1941 */ 1942 public String getGroupcontainerId() { 1943 1944 if (m_groupEditor != null) { 1945 return m_groupEditor.getGroupContainerWidget().getContainerId(); 1946 } 1947 return null; 1948 } 1949 1950 /** 1951 * Returns the container-page handler.<p> 1952 * 1953 * @return the container-page handler 1954 */ 1955 public CmsContainerpageHandler getHandler() { 1956 1957 return m_handler; 1958 } 1959 1960 /** 1961 * Returns the time off page load.<p> 1962 * 1963 * @return the time stamp 1964 */ 1965 public long getLoadTime() { 1966 1967 return m_loadTime; 1968 } 1969 1970 /** 1971 * Gets the lock error message.<p> 1972 * 1973 * @return the lock error message 1974 */ 1975 public String getLockErrorMessage() { 1976 1977 return m_lockErrorMessage; 1978 } 1979 1980 /** 1981 * Returns the model group base element id.<p> 1982 * 1983 * @return the model group base element id 1984 */ 1985 public String getModelGroupElementId() { 1986 1987 return m_modelGroupElementId; 1988 } 1989 1990 /** 1991 * Collects all container elements which are model groups.<p> 1992 * 1993 * @return the list of model group container elements 1994 */ 1995 public List<CmsContainerPageElementPanel> getModelGroups() { 1996 1997 final List<CmsContainerPageElementPanel> result = Lists.newArrayList(); 1998 1999 processPageContent(new I_PageContentVisitor() { 2000 2001 public boolean beginContainer(String name, CmsContainer container) { 2002 2003 return true; 2004 } 2005 2006 public void endContainer() { 2007 2008 // do nothing 2009 } 2010 2011 public void handleElement(CmsContainerPageElementPanel element) { 2012 2013 if (element.isModelGroup()) { 2014 result.add(element); 2015 } 2016 } 2017 }); 2018 return result; 2019 } 2020 2021 /** 2022 * Returns the element data for a resource type representing a new element.<p> 2023 * 2024 * @param resourceType the resource type name 2025 * @param callback the callback to execute with the new element data 2026 */ 2027 public void getNewElement(final String resourceType, final I_CmsSimpleCallback<CmsContainerElementData> callback) { 2028 2029 CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 2030 2031 @Override 2032 public void execute() { 2033 2034 getContainerpageService().getNewElementData( 2035 getData().getRpcContext(), 2036 getData().getDetailId(), 2037 getRequestParams(), 2038 resourceType, 2039 getPageState(), 2040 getLocale(), 2041 this); 2042 } 2043 2044 @Override 2045 protected void onResponse(CmsContainerElementData result) { 2046 2047 m_elements.put(result.getClientId(), result); 2048 callback.execute(result); 2049 } 2050 }; 2051 action.execute(); 2052 } 2053 2054 /** 2055 * Fetches the options for creating a new element from the edit handler.<p> 2056 * 2057 * @param clientId the client id of the element 2058 * @param callback the callback which is called with the result 2059 */ 2060 public void getNewOptions(final String clientId, final I_CmsSimpleCallback<CmsDialogOptionsAndInfo> callback) { 2061 2062 CmsRpcAction<CmsDialogOptionsAndInfo> action = new CmsRpcAction<CmsDialogOptionsAndInfo>() { 2063 2064 @Override 2065 public void execute() { 2066 2067 getContainerpageService().getNewOptions( 2068 clientId, 2069 getData().getRpcContext().getPageStructureId(), 2070 getData().getRequestParams(), 2071 this); 2072 } 2073 2074 @Override 2075 protected void onResponse(CmsDialogOptionsAndInfo result) { 2076 2077 callback.execute(result); 2078 } 2079 }; 2080 2081 action.execute(); 2082 } 2083 2084 /** 2085 * Produces the "return code", which is needed to return to the current page from the sitemap.<p> 2086 * 2087 * @return the return code 2088 */ 2089 public String getReturnCode() { 2090 2091 CmsUUID ownId = CmsCoreProvider.get().getStructureId(); 2092 CmsUUID detailId = m_data.getDetailId(); 2093 if (detailId != null) { 2094 return "" + ownId + ":" + detailId; 2095 } else { 2096 return "" + ownId; 2097 } 2098 } 2099 2100 /** 2101 * Returns the deserialized element data.<p> 2102 * 2103 * @param data the data to deserialize 2104 * 2105 * @return the container element 2106 * @throws SerializationException if deserialization fails 2107 */ 2108 public CmsContainer getSerializedContainer(String data) throws SerializationException { 2109 2110 return (CmsContainer)CmsRpcPrefetcher.getSerializedObjectFromString(getContainerpageService(), data); 2111 } 2112 2113 /** 2114 * Returns the deserialized element data.<p> 2115 * 2116 * @param data the data to deserialize 2117 * 2118 * @return the container element 2119 * @throws SerializationException if deserialization fails 2120 */ 2121 public CmsContainerElement getSerializedElement(String data) throws SerializationException { 2122 2123 return (CmsContainerElement)CmsRpcPrefetcher.getSerializedObjectFromString(getContainerpageService(), data); 2124 } 2125 2126 /** 2127 * Gets the handler for small elements.<p> 2128 * 2129 * @return the small elements handler 2130 */ 2131 public CmsSmallElementsHandler getSmallElementsHandler() { 2132 2133 return m_smallElementsHandler; 2134 } 2135 2136 /** 2137 * Gets the view with the given id.<p> 2138 * 2139 * @param value the view id as a string 2140 * 2141 * @return the view with the given id, or null if no such view is available 2142 */ 2143 public CmsElementViewInfo getView(String value) { 2144 2145 for (CmsElementViewInfo info : m_data.getElementViews()) { 2146 if (info.getElementViewId().toString().equals(value)) { 2147 return info; 2148 } 2149 } 2150 return null; 2151 } 2152 2153 /** 2154 * Handler that gets called when the template context setting of an element was changed by the user.<p> 2155 * 2156 * @param element the element whose template context setting was changed 2157 * 2158 * @param newValue the new value of the setting 2159 */ 2160 public void handleChangeTemplateContext(final CmsContainerPageElementPanel element, final String newValue) { 2161 2162 if (CmsStringUtil.isEmptyOrWhitespaceOnly(newValue) || CmsTemplateContextInfo.EMPTY_VALUE.equals(newValue)) { 2163 if (CmsInheritanceContainerEditor.getInstance() != null) { 2164 CmsInheritanceContainerEditor.getInstance().removeElement(element); 2165 } else { 2166 removeElement(element, ElementRemoveMode.silent); 2167 } 2168 } 2169 } 2170 2171 /** 2172 * Asks the user for confirmation before removing a container page element.<p> 2173 * 2174 * @param element the element for which the user should confirm the removal 2175 */ 2176 public void handleConfirmRemove(final CmsContainerPageElementPanel element) { 2177 2178 if (element.isNew()) { 2179 I_EventDetails details = createEventDetails(element); 2180 element.removeFromParent(); 2181 cleanUpContainers(); 2182 setPageChanged(); 2183 sendElementDeleted(details); 2184 return; 2185 } 2186 checkElementReferences(element, new AsyncCallback<CmsRemovedElementStatus>() { 2187 2188 public void onFailure(Throwable caught) { 2189 2190 // ignore, will never be executed 2191 2192 } 2193 2194 public void onSuccess(CmsRemovedElementStatus status) { 2195 2196 boolean showDeleteCheckbox = status.isDeletionCandidate(); 2197 ElementDeleteMode deleteMode = status.getElementDeleteMode(); 2198 if (deleteMode == null) { 2199 deleteMode = getData().getDeleteMode(); 2200 } 2201 CmsConfirmRemoveDialog removeDialog = new CmsConfirmRemoveDialog( 2202 status.getElementInfo(), 2203 showDeleteCheckbox, 2204 deleteMode, 2205 new AsyncCallback<Boolean>() { 2206 2207 public void onFailure(Throwable caught) { 2208 2209 element.removeHighlighting(); 2210 } 2211 2212 public void onSuccess(Boolean shouldDeleteResource) { 2213 2214 Runnable[] nextActions = new Runnable[] {}; 2215 2216 if (shouldDeleteResource.booleanValue()) { 2217 final CmsRpcAction<Void> deleteAction = new CmsRpcAction<Void>() { 2218 2219 @Override 2220 public void execute() { 2221 2222 start(200, true); 2223 2224 CmsUUID id = new CmsUUID(getServerId(element.getId())); 2225 CmsCoreProvider.getVfsService().deleteResource(id, this); 2226 } 2227 2228 @Override 2229 public void onResponse(Void result) { 2230 2231 stop(true); 2232 } 2233 }; 2234 nextActions = new Runnable[] {new Runnable() { 2235 2236 public void run() { 2237 2238 deleteAction.execute(); 2239 } 2240 }}; 2241 } 2242 I_CmsDropContainer container = element.getParentTarget(); 2243 I_EventDetails details = createEventDetails(element); 2244 element.removeFromParent(); 2245 if (container instanceof CmsContainerPageContainer) { 2246 ((CmsContainerPageContainer)container).checkEmptyContainers(); 2247 } 2248 cleanUpContainers(); 2249 sendElementDeleted(details); 2250 setPageChanged(nextActions); 2251 } 2252 }); 2253 removeDialog.center(); 2254 } 2255 2256 }); 2257 } 2258 2259 /** 2260 * Calls the edit handler to handle the delete action.<p> 2261 * 2262 * @param clientId the content client id 2263 * @param deleteOption the selected delete option 2264 * @param callback the callback to execute after the delete 2265 */ 2266 public void handleDelete( 2267 final String clientId, 2268 final String deleteOption, 2269 final I_CmsSimpleCallback<Void> callback) { 2270 2271 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 2272 2273 @Override 2274 public void execute() { 2275 2276 getContainerpageService().handleDelete( 2277 clientId, 2278 deleteOption, 2279 getData().getRpcContext().getPageStructureId(), 2280 getData().getRequestParams(), 2281 this); 2282 } 2283 2284 @Override 2285 protected void onResponse(Void result) { 2286 2287 if (callback != null) { 2288 callback.execute(result); 2289 } 2290 } 2291 }; 2292 action.execute(); 2293 } 2294 2295 /** 2296 * Returns if the selection button is active.<p> 2297 * 2298 * @return <code>true</code> if the selection button is active 2299 */ 2300 public boolean hasActiveSelection() { 2301 2302 return m_handler.hasActiveSelection(); 2303 } 2304 2305 /** 2306 * Returns if the page has changed.<p> 2307 * 2308 * @return <code>true</code> if the page has changed 2309 */ 2310 public boolean hasPageChanged() { 2311 2312 return m_pageChanged; 2313 } 2314 2315 /** 2316 * Hides list collector direct edit buttons, if present.<p> 2317 */ 2318 public void hideEditableListButtons() { 2319 2320 removeEditButtonsPositionTimer(); 2321 for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers.values()) { 2322 container.hideEditableListButtons(); 2323 } 2324 } 2325 2326 /** 2327 * Initializes the controller.<p> 2328 * 2329 * @param handler the container-page handler 2330 * @param dndHandler the drag and drop handler 2331 * @param contentEditorHandler the XML content editor handler 2332 * @param containerpageUtil the container-page utility 2333 */ 2334 public void init( 2335 CmsContainerpageHandler handler, 2336 CmsDNDHandler dndHandler, 2337 CmsContentEditorHandler contentEditorHandler, 2338 CmsContainerpageUtil containerpageUtil) { 2339 2340 if (getData().getDetailId() != null) { 2341 CmsEmbeddedAction.PARAMS.put(CmsGwtConstants.PARAM_ADE_DETAIL_ID, "" + getData().getDetailId()); 2342 } 2343 2344 Window.addResizeHandler(new ResizeHandler() { 2345 2346 public void onResize(ResizeEvent event) { 2347 2348 CmsContainerpageController.this.onResize(); 2349 } 2350 }); 2351 m_containerpageUtil = containerpageUtil; 2352 m_handler = handler; 2353 m_contentEditorHandler = contentEditorHandler; 2354 m_dndHandler = dndHandler; 2355 m_cntDndController = m_dndHandler.getController(); 2356 2357 m_elements = new HashMap<String, CmsContainerElementData>(); 2358 m_newElements = new HashMap<String, CmsContainerElementData>(); 2359 m_containers = new HashMap<String, CmsContainer>(); 2360 if (m_data == null) { 2361 m_handler.m_editor.disableEditing(Messages.get().key(Messages.ERR_READING_CONTAINER_PAGE_DATA_0)); 2362 CmsErrorDialog dialog = new CmsErrorDialog( 2363 Messages.get().key(Messages.ERR_READING_CONTAINER_PAGE_DATA_0), 2364 null); 2365 dialog.center(); 2366 return; 2367 } 2368 // ensure any embedded flash players are set opaque so UI elements may be placed above them 2369 CmsDomUtil.fixFlashZindex(RootPanel.getBodyElement()); 2370 m_targetContainers = m_containerpageUtil.consumeContainers(m_containers, RootPanel.getBodyElement()); 2371 updateContainerLevelInfo(); 2372 resetEditButtons(); 2373 Event.addNativePreviewHandler(new NativePreviewHandler() { 2374 2375 public void onPreviewNativeEvent(NativePreviewEvent event) { 2376 2377 previewNativeEvent(event); 2378 } 2379 }); 2380 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_data.getNoEditReason())) { 2381 m_handler.m_editor.disableEditing(m_data.getNoEditReason()); 2382 } else { 2383 checkLockInfo(); 2384 } 2385 2386 // initialize the browser history handler 2387 History.addValueChangeHandler(new ValueChangeHandler<String>() { 2388 2389 public void onValueChange(ValueChangeEvent<String> event) { 2390 2391 String historyToken = event.getValue(); 2392 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(historyToken)) { 2393 getContentEditorHandler().openEditorForHistory(historyToken); 2394 } else { 2395 getContentEditorHandler().closeContentEditor(); 2396 } 2397 } 2398 }); 2399 AsyncCallback<Void> doNothing = new AsyncCallback<Void>() { 2400 2401 public void onFailure(Throwable caught) { 2402 2403 // nothing to do 2404 } 2405 2406 public void onSuccess(Void result) { 2407 2408 // nothing to do 2409 } 2410 }; 2411 getContainerpageService().setLastPage(CmsCoreProvider.get().getStructureId(), m_data.getDetailId(), doNothing); 2412 2413 // check if there is already a history item available 2414 String historyToken = History.getToken(); 2415 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(historyToken)) { 2416 m_contentEditorHandler.openEditorForHistory(historyToken); 2417 } 2418 2419 updateGalleryData(false, null); 2420 addContainerpageEventHandler(event -> { 2421 updateDetailPreviewStyles(); 2422 }); 2423 updateDetailPreviewStyles(); 2424 updateButtonsForCurrentView(); 2425 startPublishLockCheck(); 2426 } 2427 2428 /** 2429 * Checks for element sub containers.<p> 2430 * 2431 * @param containerElement the container element 2432 */ 2433 public void initializeSubContainers(CmsContainerPageElementPanel containerElement) { 2434 2435 int containerCount = m_targetContainers.size(); 2436 m_targetContainers.putAll(m_containerpageUtil.consumeContainers(m_containers, containerElement.getElement())); 2437 updateContainerLevelInfo(); 2438 if (m_targetContainers.size() > containerCount) { 2439 // in case new containers have been added, the gallery data needs to be updated 2440 scheduleGalleryUpdate(); 2441 } 2442 } 2443 2444 /** 2445 * Returns if the given container is editable.<p> 2446 * 2447 * @param dragParent the parent container 2448 * 2449 * @return <code>true</code> if the given container is editable 2450 */ 2451 public boolean isContainerEditable(I_CmsDropContainer dragParent) { 2452 2453 boolean isSubElement = dragParent instanceof CmsGroupContainerElementPanel; 2454 boolean isContainerEditable = dragParent.isEditable() 2455 && (isSubElement || !isDetailPage() || dragParent.isDetailView() || dragParent.isDetailOnly()); 2456 return isContainerEditable; 2457 } 2458 2459 /** 2460 * Returns the flag indicating that a content element is being edited.<p> 2461 * 2462 * @return the flag indicating that a content element is being edited 2463 */ 2464 public boolean isContentEditing() { 2465 2466 return m_isContentEditing; 2467 } 2468 2469 /** 2470 * Returns if this page displays a detail view.<p> 2471 * 2472 * @return <code>true</code> if this page displays a detail view 2473 */ 2474 public boolean isDetailPage() { 2475 2476 return m_data.getDetailId() != null; 2477 } 2478 2479 /** 2480 * Checks if the page editing features should be disabled.<p> 2481 * 2482 * @return true if the page editing features should be disabled 2483 */ 2484 public boolean isEditingDisabled() { 2485 2486 return (m_data == null) 2487 || CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_data.getNoEditReason()) 2488 || (m_lockStatus == LockStatus.failed); 2489 } 2490 2491 /** 2492 * Returns if a group-container is currently being edited.<p> 2493 * 2494 * @return <code>true</code> if a group-container is being edited 2495 */ 2496 public boolean isGroupcontainerEditing() { 2497 2498 return m_groupEditor != null; 2499 } 2500 2501 /** 2502 * Checks whether the given element should be inline editable.<p> 2503 * 2504 * @param element the element 2505 * @param dragParent the element parent 2506 * 2507 * @return <code>true</code> if the element should be inline editable 2508 */ 2509 public boolean isInlineEditable(CmsContainerPageElementPanel element, I_CmsDropContainer dragParent) { 2510 2511 CmsUUID elemView = element.getElementView(); 2512 return !getData().isUseClassicEditor() 2513 && CmsStringUtil.isEmptyOrWhitespaceOnly(element.getNoEditReason()) 2514 && hasActiveSelection() 2515 && matchRootView(elemView) 2516 && isContainerEditable(dragParent) 2517 && matchesCurrentEditLevel(dragParent) 2518 && (getData().isModelGroup() || !element.hasModelGroupParent()) 2519 && (!(dragParent instanceof CmsGroupContainerElementPanel) || isGroupcontainerEditing()); 2520 } 2521 2522 /** 2523 * Method to leave the page without saving.<p> 2524 * 2525 * @param targetUri the new URI to call 2526 */ 2527 public void leaveUnsaved(String targetUri) { 2528 2529 setPageChanged(false, true); 2530 Window.Location.assign(targetUri); 2531 } 2532 2533 /** 2534 * Loads the context menu entries.<p> 2535 * 2536 * @param structureId the structure id of the resource to get the context menu entries for 2537 * @param context the ade context (sitemap or containerpae) 2538 */ 2539 public void loadContextMenu(final CmsUUID structureId, final AdeContext context) { 2540 2541 /** The RPC menu action for the container page dialog. */ 2542 CmsRpcAction<List<CmsContextMenuEntryBean>> menuAction = new CmsRpcAction<List<CmsContextMenuEntryBean>>() { 2543 2544 /** 2545 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2546 */ 2547 @Override 2548 public void execute() { 2549 2550 Map<String, String> params = new HashMap<>(); 2551 if (getData().getDetailId() != null) { 2552 params.put(CmsGwtConstants.PARAM_ADE_DETAIL_ID, "" + getData().getDetailId()); 2553 } 2554 getCoreService().getContextMenuEntries(structureId, context, params, this); 2555 } 2556 2557 /** 2558 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 2559 */ 2560 @Override 2561 public void onResponse(List<CmsContextMenuEntryBean> menuBeans) { 2562 2563 m_handler.insertContextMenu(menuBeans, structureId); 2564 } 2565 }; 2566 menuAction.execute(); 2567 2568 } 2569 2570 /** 2571 * Loads the favorite list and adds the elements to the favorite list widget of the tool-bar menu.<p> 2572 * 2573 * @param callback the call-back to execute with the result data 2574 */ 2575 public void loadFavorites(final I_CmsSimpleCallback<List<CmsContainerElementData>> callback) { 2576 2577 CmsRpcAction<List<CmsContainerElementData>> action = new CmsRpcAction<List<CmsContainerElementData>>() { 2578 2579 /** 2580 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2581 */ 2582 @Override 2583 public void execute() { 2584 2585 start(200, true); 2586 getContainerpageService().getFavoriteList( 2587 CmsCoreProvider.get().getStructureId(), 2588 getData().getDetailId(), 2589 getPageState(), 2590 getLocale(), 2591 this); 2592 } 2593 2594 /** 2595 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 2596 */ 2597 @Override 2598 protected void onResponse(List<CmsContainerElementData> result) { 2599 2600 stop(false); 2601 addElements(result); 2602 callback.execute(result); 2603 } 2604 }; 2605 action.execute(); 2606 } 2607 2608 /** 2609 * Loads the recent list and adds the elements to the recent list widget of the tool-bar menu.<p> 2610 * 2611 * @param callback the call-back to execute with the result data 2612 */ 2613 public void loadRecent(final I_CmsSimpleCallback<List<CmsContainerElementData>> callback) { 2614 2615 CmsRpcAction<List<CmsContainerElementData>> action = new CmsRpcAction<List<CmsContainerElementData>>() { 2616 2617 /** 2618 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 2619 */ 2620 @Override 2621 public void execute() { 2622 2623 start(200, true); 2624 getContainerpageService().getRecentList( 2625 CmsCoreProvider.get().getStructureId(), 2626 getData().getDetailId(), 2627 getPageState(), 2628 getLocale(), 2629 this); 2630 } 2631 2632 /** 2633 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 2634 */ 2635 @Override 2636 protected void onResponse(List<CmsContainerElementData> result) { 2637 2638 stop(false); 2639 addElements(result); 2640 callback.execute(result); 2641 } 2642 }; 2643 action.execute(); 2644 } 2645 2646 /** 2647 * Locks the container-page.<p> 2648 * 2649 * @param callback the callback to execute 2650 */ 2651 public void lockContainerpage(final I_CmsSimpleCallback<Boolean> callback) { 2652 2653 if (m_lockStatus == LockStatus.locked) { 2654 callback.execute(Boolean.TRUE); 2655 } else if (m_lockStatus == LockStatus.failed) { 2656 callback.execute(Boolean.FALSE); 2657 } else { 2658 I_CmsSimpleCallback<String> call = new I_CmsSimpleCallback<String>() { 2659 2660 public void execute(String lockError) { 2661 2662 if (lockError == null) { 2663 onLockSuccess(); 2664 callback.execute(Boolean.TRUE); 2665 } else { 2666 onLockFail(lockError); 2667 callback.execute(Boolean.FALSE); 2668 } 2669 } 2670 }; 2671 2672 if (getData().getDetailContainerPage() != null) { 2673 CmsCoreProvider.get().lockOrReturnError(getData().getDetailContainerPage(), getLoadTime(), call); 2674 } else { 2675 CmsCoreProvider.get().lockOrReturnError(CmsCoreProvider.get().getStructureId(), getLoadTime(), call); 2676 } 2677 } 2678 } 2679 2680 /** 2681 * Returns true if the view with the given view id and the current view have the same root view.<p> 2682 * 2683 * @param viewIdFromElement the id of a view 2684 * @return true if the root view of the id matches the root view of the current view 2685 */ 2686 public boolean matchRootView(CmsUUID viewIdFromElement) { 2687 2688 if (viewIdFromElement == null) { 2689 viewIdFromElement = CmsUUID.getNullUUID(); 2690 } 2691 CmsElementViewInfo viewFromElement = getView(viewIdFromElement.toString()); 2692 return (viewFromElement != null) && viewFromElement.getRootViewId().equals(m_elementView.getRootViewId()); 2693 } 2694 2695 /** 2696 * This method should be called when locking the page has failed.<p> 2697 * 2698 * @param lockError the locking information 2699 */ 2700 public void onLockFail(String lockError) { 2701 2702 m_lockStatus = LockStatus.failed; 2703 m_handler.onLockFail(lockError); 2704 } 2705 2706 /** 2707 * This method should be called when locking the page has succeeded.<p> 2708 * 2709 */ 2710 public void onLockSuccess() { 2711 2712 assert m_lockStatus == LockStatus.unknown; 2713 m_lockStatus = LockStatus.locked; 2714 } 2715 2716 /** 2717 * Handler which is executed when the window closes.<p> 2718 */ 2719 public void onWindowClose() { 2720 2721 // causes synchronous RPC call 2722 unlockContainerpage(); 2723 } 2724 2725 /** 2726 * Calls the edit handler to prepare the given content element for editing.<p> 2727 * 2728 * @param clientId the element id 2729 * @param editOption the selected edit option 2730 * @param callback the callback to execute 2731 */ 2732 public void prepareForEdit( 2733 final String clientId, 2734 final String editOption, 2735 final I_CmsSimpleCallback<CmsUUID> callback) { 2736 2737 CmsRpcAction<CmsUUID> action = new CmsRpcAction<CmsUUID>() { 2738 2739 @Override 2740 public void execute() { 2741 2742 getContainerpageService().prepareForEdit( 2743 clientId, 2744 editOption, 2745 getData().getRpcContext().getPageStructureId(), 2746 getData().getRequestParams(), 2747 this); 2748 } 2749 2750 @Override 2751 protected void onResponse(CmsUUID result) { 2752 2753 callback.execute(result); 2754 } 2755 }; 2756 action.execute(); 2757 } 2758 2759 /** 2760 * Reinitializes the buttons in the container element menus.<p> 2761 */ 2762 public void reinitializeButtons() { 2763 2764 if (isGroupcontainerEditing()) { 2765 m_groupEditor.reinitializeButtons(); 2766 } else { 2767 List<CmsContainerPageElementPanel> elemWidgets = getAllContainerPageElements(true); 2768 2769 for (CmsContainerPageElementPanel elemWidget : elemWidgets) { 2770 if (requiresOptionBar(elemWidget, elemWidget.getParentTarget())) { 2771 getContainerpageUtil().addOptionBar(elemWidget); 2772 } else { 2773 // otherwise remove any present option bar 2774 elemWidget.setElementOptionBar(null); 2775 } 2776 elemWidget.showEditableListButtons(); 2777 } 2778 } 2779 } 2780 2781 /** 2782 * Re-initializes the inline editing.<p> 2783 */ 2784 public void reInitInlineEditing() { 2785 2786 removeEditButtonsPositionTimer(); 2787 if ((m_targetContainers == null) || getData().isUseClassicEditor()) { 2788 // if the target containers are not initialized yet or classic editor is set, don't do anything 2789 return; 2790 } 2791 if (isGroupcontainerEditing()) { 2792 for (Widget element : m_groupEditor.getGroupContainerWidget()) { 2793 if (((element instanceof CmsContainerPageElementPanel) 2794 && isInlineEditable( 2795 (CmsContainerPageElementPanel)element, 2796 m_groupEditor.getGroupContainerWidget()))) { 2797 ((CmsContainerPageElementPanel)element).initInlineEditor(this); 2798 } 2799 } 2800 } else { 2801 for (CmsContainerPageContainer container : m_targetContainers.values()) { 2802 // first remove inline editors 2803 for (Widget element : container) { 2804 if ((element instanceof CmsContainerPageElementPanel)) { 2805 ((CmsContainerPageElementPanel)element).removeInlineEditor(); 2806 } 2807 } 2808 2809 // add inline editors only on suitable elements 2810 if (isContainerEditable(container) && matchesCurrentEditLevel(container)) { 2811 for (Widget element : container) { 2812 if ((element instanceof CmsContainerPageElementPanel) 2813 && isInlineEditable((CmsContainerPageElementPanel)element, container)) { 2814 ((CmsContainerPageElementPanel)element).initInlineEditor(this); 2815 } 2816 } 2817 } 2818 } 2819 } 2820 } 2821 2822 /** 2823 * Reloads the content for the given elements and related elements. 2824 * 2825 * @param ids the element ids 2826 * @param callback the callback to execute after the reload 2827 */ 2828 public void reloadElements(Collection<String> ids, I_ReloadHandler callback) { 2829 2830 Set<String> related = new HashSet<String>(); 2831 for (String id : ids) { 2832 related.addAll(getRelatedElementIds(id)); 2833 } 2834 if (!related.isEmpty()) { 2835 ReloadElementAction action = new ReloadElementAction(related, callback); 2836 action.execute(); 2837 } 2838 } 2839 2840 /** 2841 * Reloads the content for the given elements and related elements. 2842 * 2843 * @param ids the element ids 2844 * @param callback the callback to execute after the reload 2845 */ 2846 public void reloadElements(Collection<String> ids, Runnable callback) { 2847 2848 reloadElements(ids, new I_ReloadHandler() { 2849 2850 public void finish() { 2851 2852 if (callback != null) { 2853 callback.run(); 2854 } 2855 } 2856 2857 public void onReload(CmsContainerPageElementPanel a, CmsContainerPageElementPanel b) { 2858 2859 // ignore 2860 } 2861 }); 2862 2863 } 2864 2865 /** 2866 * Reloads the content for the given element and all related elements.<p> 2867 * 2868 * Call this if the element content has changed.<p> 2869 * 2870 * @param ids the element ids 2871 * @param callback the callback to execute after the reload 2872 */ 2873 public void reloadElements(String[] ids, I_ReloadHandler callback) { 2874 2875 Set<String> related = new HashSet<String>(); 2876 for (int i = 0; i < ids.length; i++) { 2877 related.addAll(getRelatedElementIds(ids[i])); 2878 } 2879 if (!related.isEmpty()) { 2880 ReloadElementAction action = new ReloadElementAction(related, callback); 2881 action.execute(); 2882 } else { 2883 callback.finish(); 2884 } 2885 } 2886 2887 /** 2888 * Reloads the content for the given element and all related elements.<p> 2889 * 2890 * Call this if the element content has changed.<p> 2891 * 2892 * @param ids the element ids 2893 * @param callback the callback to execute after the reload 2894 */ 2895 public void reloadElements(String[] ids, Runnable callback) { 2896 2897 reloadElements(ids, new I_ReloadHandler() { 2898 2899 @Override 2900 public void finish() { 2901 2902 if (callback != null) { 2903 callback.run(); 2904 } 2905 } 2906 2907 @Override 2908 public void onReload(CmsContainerPageElementPanel oldElement, CmsContainerPageElementPanel newElement) { 2909 2910 } 2911 }); 2912 2913 } 2914 2915 /** 2916 * Reloads a container page element with a new set of settings.<p> 2917 * 2918 * @param elementWidget the widget of the container page element which should be reloaded 2919 * @param clientId the id of the container page element which should be reloaded 2920 * @param settings the new set of settings 2921 * @param reloadHandler the handler to call with the reloaded element 2922 */ 2923 public void reloadElementWithSettings( 2924 final org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel elementWidget, 2925 final String clientId, 2926 final Map<String, String> settings, 2927 final I_ReloadHandler reloadHandler) { 2928 2929 final I_CmsSimpleCallback<CmsContainerElementData> callback = new I_CmsSimpleCallback<CmsContainerElementData>() { 2930 2931 public void execute(CmsContainerElementData newElement) { 2932 2933 try { 2934 final CmsContainerPageElementPanel replacement = replaceContainerElement(elementWidget, newElement); 2935 resetEditButtons(); 2936 addToRecentList(newElement.getClientId(), null); 2937 reloadHandler.onReload(elementWidget, replacement); 2938 reloadHandler.finish(); 2939 } catch (Exception e) { 2940 // should never happen 2941 CmsDebugLog.getInstance().printLine(e.getLocalizedMessage()); 2942 } 2943 } 2944 }; 2945 2946 if (!isGroupcontainerEditing()) { 2947 2948 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 2949 2950 public void execute(Boolean arg) { 2951 2952 if (arg.booleanValue()) { 2953 CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 2954 2955 @Override 2956 public void execute() { 2957 2958 start(500, true); 2959 getContainerpageService().saveElementSettings( 2960 getData().getRpcContext(), 2961 getData().getDetailId(), 2962 getRequestParams(), 2963 clientId, 2964 settings, 2965 getPageState(), 2966 getLocale(), 2967 this); 2968 } 2969 2970 @Override 2971 protected void onResponse(CmsContainerElementData result) { 2972 2973 stop(false); 2974 CmsContainerpageController.get().fireEvent( 2975 new CmsContainerpageEvent(EventType.pageSaved)); 2976 setPageChanged(false, false); 2977 if (result != null) { 2978 // cache the loaded element 2979 m_elements.put(result.getClientId(), result); 2980 setLoadTime(Long.valueOf(result.getLoadTime())); 2981 } 2982 callback.execute(result); 2983 } 2984 }; 2985 action.execute(); 2986 } 2987 } 2988 }); 2989 2990 } else { 2991 getElementWithSettings(clientId, settings, callback); 2992 } 2993 } 2994 2995 /** 2996 * Reloads the page.<p> 2997 */ 2998 public void reloadPage() { 2999 3000 Timer timer = new Timer() { 3001 3002 @Override 3003 public void run() { 3004 3005 Window.Location.reload(); 3006 } 3007 }; 3008 3009 timer.schedule(150); 3010 3011 } 3012 3013 /** 3014 * Removes the given container element from its parent container.<p> 3015 * 3016 * @param dragElement the element to remove 3017 */ 3018 public void removeElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel dragElement) { 3019 3020 ElementRemoveMode removeMode = isConfirmRemove() 3021 ? ElementRemoveMode.confirmRemove 3022 : ElementRemoveMode.saveAndCheckReferences; 3023 removeElement(dragElement, removeMode); 3024 } 3025 3026 /** 3027 * Removes the given container element from its parent container.<p> 3028 * 3029 * @param dragElement the element to remove 3030 * @param removeMode the remove mode 3031 */ 3032 public void removeElement( 3033 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel dragElement, 3034 ElementRemoveMode removeMode) { 3035 3036 if (isGroupcontainerEditing()) { 3037 dragElement.removeFromParent(); 3038 if (!getGroupcontainer().iterator().hasNext()) { 3039 // group-container is empty, mark it 3040 getGroupcontainer().addStyleName(I_CmsLayoutBundle.INSTANCE.containerpageCss().emptyGroupContainer()); 3041 } 3042 getGroupcontainer().refreshHighlighting(); 3043 } else { 3044 final String id = dragElement.getId(); 3045 if (id != null) { 3046 addToRecentList(id, null); 3047 } 3048 3049 I_CmsDropContainer container = dragElement.getParentTarget(); 3050 switch (removeMode) { 3051 case saveAndCheckReferences: 3052 I_EventDetails details = createEventDetails(dragElement); 3053 dragElement.removeFromParent(); 3054 if (container instanceof CmsContainerPageContainer) { 3055 ((CmsContainerPageContainer)container).checkEmptyContainers(); 3056 } 3057 cleanUpContainers(); 3058 Runnable checkReferencesAction = new Runnable() { 3059 3060 public void run() { 3061 3062 checkReferencesToRemovedElement(id); 3063 } 3064 }; 3065 sendElementDeleted(details); 3066 setPageChanged(checkReferencesAction); 3067 break; 3068 case confirmRemove: 3069 handleConfirmRemove(dragElement); 3070 break; 3071 case silent: 3072 default: 3073 I_EventDetails details2 = createEventDetails(dragElement); 3074 dragElement.removeFromParent(); 3075 if (container instanceof CmsContainerPageContainer) { 3076 ((CmsContainerPageContainer)container).checkEmptyContainers(); 3077 } 3078 cleanUpContainers(); 3079 sendElementDeleted(details2); 3080 setPageChanged(); 3081 break; 3082 } 3083 } 3084 } 3085 3086 /** 3087 * Replaces the given drag-element with the given container element.<p> 3088 * 3089 * @param containerElement the container element to replace 3090 * @param elementData the new element data 3091 * 3092 * @return the container element which replaced the old one 3093 * 3094 * @throws Exception if something goes wrong 3095 */ 3096 public CmsContainerPageElementPanel replaceContainerElement( 3097 CmsContainerPageElementPanel containerElement, 3098 CmsContainerElementData elementData) 3099 throws Exception { 3100 3101 I_CmsDropContainer parentContainer = containerElement.getParentTarget(); 3102 String containerId = parentContainer.getContainerId(); 3103 CmsContainerPageElementPanel replacer = null; 3104 String elementContent = elementData.getContents().get(containerId); 3105 if ((elementContent != null) && (elementContent.trim().length() > 0)) { 3106 replacer = getContainerpageUtil().createElement(elementData, parentContainer, false); 3107 3108 if (containerElement.isNew()) { 3109 // if replacing element data has the same structure id, keep the 'new' state by setting the new type property 3110 // this should only be the case when editing settings of a new element that has not been created in the VFS yet 3111 String id = getServerId(containerElement.getId()); 3112 if (elementData.getClientId().startsWith(id)) { 3113 replacer.setNewType(containerElement.getNewType()); 3114 } 3115 } 3116 replacer.setCreateNew(containerElement.isCreateNew()); 3117 // replacer.setModelGroup(containerElement.isModelGroup()); 3118 if (isGroupcontainerEditing() && (containerElement.getInheritanceInfo() != null)) { 3119 // in case of inheritance container editing, keep the inheritance info 3120 replacer.setInheritanceInfo(containerElement.getInheritanceInfo()); 3121 // set the proper element options 3122 CmsInheritanceContainerEditor.getInstance().setOptionBar(replacer); 3123 } 3124 parentContainer.insert(replacer, parentContainer.getWidgetIndex(containerElement)); 3125 containerElement.removeFromParent(); 3126 initializeSubContainers(replacer); 3127 } 3128 cleanUpContainers(); 3129 return replacer; 3130 } 3131 3132 /** 3133 * Replaces the given element with another content while keeping it's settings.<p> 3134 * 3135 * @param elementWidget the element to replace 3136 * @param elementId the id of the replacing content 3137 * @param callback the callback to execute after the element is replaced 3138 */ 3139 public void replaceElement( 3140 final CmsContainerPageElementPanel elementWidget, 3141 final String elementId, 3142 I_ReloadHandler handler) { 3143 3144 final CmsRpcAction<CmsContainerElementData> action = new CmsRpcAction<CmsContainerElementData>() { 3145 3146 @Override 3147 public void execute() { 3148 3149 start(500, true); 3150 getContainerpageService().replaceElement( 3151 getData().getRpcContext(), 3152 getData().getDetailId(), 3153 getRequestParams(), 3154 elementWidget.getId(), 3155 elementId, 3156 getPageState(), 3157 getLocale(), 3158 this); 3159 } 3160 3161 @Override 3162 protected void onResponse(CmsContainerElementData result) { 3163 3164 stop(false); 3165 3166 if (result != null) { 3167 // cache the loaded element 3168 m_elements.put(result.getClientId(), result); 3169 try { 3170 CmsContainerPageElementPanel replacer = replaceContainerElement(elementWidget, result); 3171 resetEditButtons(); 3172 addToRecentList(result.getClientId(), null); 3173 setPageChanged(new Runnable() { 3174 3175 public void run() { 3176 3177 if (handler != null) { 3178 handler.onReload(elementWidget, replacer); 3179 handler.finish(); 3180 } 3181 } 3182 }); 3183 } catch (Exception e) { 3184 // should never happen 3185 CmsDebugLog.getInstance().printLine(e.getLocalizedMessage()); 3186 } 3187 } 3188 } 3189 }; 3190 3191 if (!isGroupcontainerEditing()) { 3192 3193 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 3194 3195 public void execute(Boolean arg) { 3196 3197 if (arg.booleanValue()) { 3198 action.execute(); 3199 } 3200 } 3201 }); 3202 3203 } else { 3204 action.execute(); 3205 } 3206 } 3207 3208 /** 3209 * Replaces the given element with another content while keeping it's settings.<p> 3210 * 3211 * @param elementWidget the element to replace 3212 * @param elementId the id of the replacing content 3213 * @param callback the callback to execute after the element is replaced 3214 */ 3215 public void replaceElement( 3216 final CmsContainerPageElementPanel elementWidget, 3217 final String elementId, 3218 Runnable callback) { 3219 3220 replaceElement(elementWidget, elementId, new I_ReloadHandler() { 3221 3222 @Override 3223 public void finish() { 3224 3225 if (callback != null) { 3226 callback.run(); 3227 } 3228 } 3229 3230 @Override 3231 public void onReload(CmsContainerPageElementPanel oldElement, CmsContainerPageElementPanel newElement) { 3232 3233 // do nothing 3234 } 3235 }); 3236 3237 } 3238 3239 /** 3240 * Checks whether the given element should display the option bar.<p> 3241 * 3242 * @param element the element 3243 * @param dragParent the element parent 3244 * 3245 * @return <code>true</code> if the given element should display the option bar 3246 */ 3247 public boolean requiresOptionBar(CmsContainerPageElementPanel element, I_CmsDropContainer dragParent) { 3248 3249 return element.hasViewPermission() 3250 && (!element.hasModelGroupParent() || getData().isModelGroup()) 3251 && (matchRootView(element.getElementView()) 3252 || isGroupcontainerEditing() 3253 || shouldShowModelgroupOptionBar(element)) 3254 && isContainerEditable(dragParent) 3255 && matchesCurrentEditLevel(dragParent); 3256 } 3257 3258 /** 3259 * Resets all edit buttons an there positions.<p> 3260 */ 3261 public void resetEditButtons() { 3262 3263 removeEditButtonsPositionTimer(); 3264 m_editButtonsPositionTimer = new Timer() { 3265 3266 /** Timer run counter. */ 3267 private int m_timerRuns; 3268 3269 @Override 3270 public void run() { 3271 3272 for (org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer container : m_targetContainers.values()) { 3273 container.showEditableListButtons(); 3274 container.updateOptionBars(); 3275 } 3276 if (m_timerRuns > 3) { 3277 cancel(); 3278 } 3279 m_timerRuns++; 3280 } 3281 }; 3282 m_editButtonsPositionTimer.scheduleRepeating(100); 3283 } 3284 3285 /** 3286 * Resets the container-page.<p> 3287 */ 3288 public void resetPage() { 3289 3290 setPageChanged(false, true); 3291 Window.Location.reload(); 3292 } 3293 3294 /** 3295 * Method to save and leave the page.<p> 3296 * 3297 * @param leaveCommand the command to execute to leave the page 3298 */ 3299 public void saveAndLeave(final Command leaveCommand) { 3300 3301 if (hasPageChanged()) { 3302 CmsRpcAction<CmsPageSaveStatus> action = new CmsRpcAction<CmsPageSaveStatus>() { 3303 3304 /** 3305 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3306 */ 3307 @Override 3308 public void execute() { 3309 3310 if (getData().getDetailContainerPage() != null) { 3311 getContainerpageService().saveDetailContainers( 3312 getData().getDetailId(), 3313 getData().getDetailContainerPage(), 3314 getPageContent(), 3315 this); 3316 } else { 3317 getContainerpageService().saveContainerpage( 3318 CmsCoreProvider.get().getStructureId(), 3319 getPageContent(), 3320 this); 3321 } 3322 } 3323 3324 /** 3325 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3326 */ 3327 @Override 3328 protected void onResponse(CmsPageSaveStatus result) { 3329 3330 setLoadTime(result.getTimestamp()); 3331 if (getData().getDetailContainerPage() != null) { 3332 getData().setDetailContainerPageId(result.getPageId()); 3333 } 3334 CmsNotification.get().send(Type.NORMAL, Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_SAVED_0)); 3335 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.pageSaved)); 3336 setPageChanged(false, true); 3337 leaveCommand.execute(); 3338 } 3339 }; 3340 action.execute(); 3341 } 3342 } 3343 3344 /** 3345 * Method to save and leave the page.<p> 3346 * 3347 * @param targetUri the new URI to call 3348 */ 3349 public void saveAndLeave(final String targetUri) { 3350 3351 if (hasPageChanged()) { 3352 CmsRpcAction<CmsPageSaveStatus> action = new CmsRpcAction<CmsPageSaveStatus>() { 3353 3354 /** 3355 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3356 */ 3357 @Override 3358 public void execute() { 3359 3360 if (getData().getDetailContainerPage() != null) { 3361 getContainerpageService().saveDetailContainers( 3362 getData().getDetailId(), 3363 getData().getDetailContainerPage(), 3364 getPageContent(), 3365 this); 3366 } else { 3367 getContainerpageService().saveContainerpage( 3368 CmsCoreProvider.get().getStructureId(), 3369 getPageContent(), 3370 this); 3371 } 3372 } 3373 3374 /** 3375 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3376 */ 3377 @Override 3378 protected void onResponse(CmsPageSaveStatus result) { 3379 3380 setLoadTime(result.getTimestamp()); 3381 if (getData().getDetailContainerPage() != null) { 3382 getData().setDetailContainerPageId(result.getPageId()); 3383 } 3384 CmsNotification.get().send(Type.NORMAL, Messages.get().key(Messages.GUI_NOTIFICATION_PAGE_SAVED_0)); 3385 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.pageSaved)); 3386 setPageChanged(false, true); 3387 Window.Location.assign(targetUri); 3388 } 3389 }; 3390 action.execute(); 3391 } 3392 } 3393 3394 /** 3395 * Saves the clipboard tab index selected by the user.<p> 3396 * 3397 * @param tabIndex the tab index 3398 */ 3399 public void saveClipboardTab(final int tabIndex) { 3400 3401 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 3402 3403 @Override 3404 public void execute() { 3405 3406 start(1, false); 3407 getContainerpageService().saveClipboardTab(tabIndex, this); 3408 } 3409 3410 @Override 3411 protected void onResponse(Void result) { 3412 3413 stop(false); 3414 } 3415 }; 3416 action.execute(); 3417 } 3418 3419 /** 3420 * Saves the current state of the container-page.<p> 3421 * 3422 * @param afterSaveActions the actions to execute after saving 3423 */ 3424 public void saveContainerpage(final Runnable... afterSaveActions) { 3425 3426 if (hasPageChanged()) { 3427 final CmsRpcAction<CmsPageSaveStatus> action = new CmsRpcAction<CmsPageSaveStatus>() { 3428 3429 /** 3430 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3431 */ 3432 @Override 3433 public void execute() { 3434 3435 start(500, true); 3436 if (getData().getDetailContainerPage() != null) { 3437 getContainerpageService().saveDetailContainers( 3438 getData().getDetailId(), 3439 getData().getDetailContainerPage(), 3440 getPageContent(), 3441 this); 3442 } else { 3443 getContainerpageService().saveContainerpage( 3444 CmsCoreProvider.get().getStructureId(), 3445 getPageContent(), 3446 this); 3447 } 3448 } 3449 3450 /** 3451 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3452 */ 3453 @Override 3454 protected void onResponse(CmsPageSaveStatus result) { 3455 3456 setLoadTime(result.getTimestamp()); 3457 if (getData().getDetailContainerPage() != null) { 3458 getData().setDetailContainerPageId(result.getPageId()); 3459 } 3460 stop(false); 3461 setPageChanged(false, false); 3462 CmsContainerpageController.get().fireEvent(new CmsContainerpageEvent(EventType.pageSaved)); 3463 for (Runnable afterSaveAction : afterSaveActions) { 3464 afterSaveAction.run(); 3465 } 3466 } 3467 }; 3468 if (getData().getDetailContainerPage() != null) { 3469 action.execute(); 3470 } else { 3471 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 3472 3473 public void execute(Boolean arg) { 3474 3475 if (arg.booleanValue()) { 3476 action.execute(); 3477 } 3478 } 3479 }); 3480 } 3481 } 3482 } 3483 3484 /** 3485 * Saves the favorite list.<p> 3486 * 3487 * @param clientIds the client id's of the list's elements 3488 */ 3489 public void saveFavoriteList(final List<String> clientIds) { 3490 3491 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 3492 3493 /** 3494 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3495 */ 3496 @Override 3497 public void execute() { 3498 3499 getContainerpageService().saveFavoriteList(clientIds, CmsCoreProvider.get().getUri(), this); 3500 } 3501 3502 /** 3503 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3504 */ 3505 @Override 3506 protected void onResponse(Void result) { 3507 3508 CmsNotification.get().send( 3509 Type.NORMAL, 3510 Messages.get().key(Messages.GUI_NOTIFICATION_FAVORITES_SAVED_0)); 3511 } 3512 }; 3513 action.execute(); 3514 } 3515 3516 /** 3517 * Saves the group-container.<p> 3518 * 3519 * @param groupContainer the group-container data to save 3520 * @param groupContainerElement the group-container widget 3521 */ 3522 public void saveGroupcontainer( 3523 final CmsGroupContainer groupContainer, 3524 final CmsGroupContainerElementPanel groupContainerElement) { 3525 3526 if (getGroupcontainer() != null) { 3527 CmsRpcAction<CmsGroupContainerSaveResult> action = new CmsRpcAction<CmsGroupContainerSaveResult>() { 3528 3529 /** 3530 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3531 */ 3532 @Override 3533 public void execute() { 3534 3535 start(0, true); 3536 getContainerpageService().saveGroupContainer( 3537 getData().getRpcContext(), 3538 getData().getDetailId(), 3539 getRequestParams(), 3540 groupContainer, 3541 getPageState(), 3542 getLocale(), 3543 this); 3544 } 3545 3546 /** 3547 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3548 */ 3549 @Override 3550 protected void onResponse(CmsGroupContainerSaveResult saveResult) { 3551 3552 stop(false); 3553 Map<String, CmsContainerElementData> elementData = saveResult.getElementData(); 3554 m_elements.putAll(elementData); 3555 try { 3556 replaceContainerElement(groupContainerElement, elementData.get(groupContainerElement.getId())); 3557 } catch (Exception e) { 3558 CmsDebugLog.getInstance().printLine("Error replacing group container element"); 3559 } 3560 addToRecentList(groupContainerElement.getId(), null); 3561 CmsNotification.get().send( 3562 Type.NORMAL, 3563 Messages.get().key(Messages.GUI_NOTIFICATION_GROUP_CONTAINER_SAVED_0)); 3564 List<CmsRemovedElementStatus> removedElements = saveResult.getRemovedElements(); 3565 for (CmsRemovedElementStatus removedElement : removedElements) { 3566 askWhetherRemovedElementShouldBeDeleted(removedElement); 3567 } 3568 3569 } 3570 }; 3571 action.execute(); 3572 3573 } 3574 } 3575 3576 /** 3577 * Saves the inheritance container.<p> 3578 * 3579 * @param inheritanceContainer the inheritance container data to save 3580 * @param groupContainerElement the group container widget 3581 */ 3582 public void saveInheritContainer( 3583 final CmsInheritanceContainer inheritanceContainer, 3584 final CmsGroupContainerElementPanel groupContainerElement) { 3585 3586 if (getGroupcontainer() != null) { 3587 CmsRpcAction<Map<String, CmsContainerElementData>> action = new CmsRpcAction<Map<String, CmsContainerElementData>>() { 3588 3589 /** 3590 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 3591 */ 3592 @Override 3593 public void execute() { 3594 3595 start(0, true); 3596 getContainerpageService().saveInheritanceContainer( 3597 CmsCoreProvider.get().getStructureId(), 3598 getData().getDetailId(), 3599 inheritanceContainer, 3600 getPageState(), 3601 getLocale(), 3602 this); 3603 } 3604 3605 /** 3606 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 3607 */ 3608 @Override 3609 protected void onResponse(Map<String, CmsContainerElementData> result) { 3610 3611 stop(false); 3612 m_elements.putAll(result); 3613 try { 3614 replaceContainerElement(groupContainerElement, result.get(groupContainerElement.getId())); 3615 } catch (Exception e) { 3616 CmsDebugLog.getInstance().printLine("Error replacing group container element"); 3617 } 3618 addToRecentList(groupContainerElement.getId(), null); 3619 CmsNotification.get().send( 3620 Type.NORMAL, 3621 Messages.get().key(Messages.GUI_NOTIFICATION_INHERITANCE_CONTAINER_SAVED_0)); 3622 3623 } 3624 }; 3625 action.execute(); 3626 3627 } 3628 } 3629 3630 /** 3631 * Sends the ocDragFinished event. 3632 * 3633 * @param dragElement the drag element 3634 * @param target the target element 3635 * @param isNew true if the dragged element is new 3636 */ 3637 public void sendDragFinished(Element dragElement, Element target, boolean isNew) { 3638 3639 I_EventDetails details = Js.cast(new JsObject()); 3640 if (dragElement != null) { 3641 details.setElement(Js.cast(dragElement)); 3642 } 3643 if (target != null) { 3644 final Element parentContainerElement = CmsDomUtil.getAncestor(target, CmsContainerElement.CLASS_CONTAINER); 3645 details.setContainer(Js.cast(parentContainerElement)); 3646 } 3647 if (isNew) { 3648 details.setIsPlaceholder(isNew); 3649 } 3650 sendEvent(EVENT_DRAG_FINISHED, details); 3651 I_EventDetails details2 = copyEventDetails(details); 3652 details2.setType("finish"); 3653 sendEvent(EVENT_DRAG, details2); 3654 } 3655 3656 /** 3657 * Sends the ocDragStarted event. 3658 * 3659 * @param isNew true if the user started dragging a new element 3660 */ 3661 public void sendDragStarted(boolean isNew) { 3662 3663 I_EventDetails details = Js.cast(new JsObject()); 3664 details.setIsPlaceholder(isNew); 3665 sendEvent(EVENT_DRAG_STARTED, details); 3666 I_EventDetails details2 = copyEventDetails(details); 3667 details2.setType("start"); 3668 sendEvent(EVENT_DRAG, details2); 3669 } 3670 3671 /** 3672 * Sends the custom 'ocElementAdded' event for added container elements. 3673 * 3674 * @param widget the container element 3675 */ 3676 public void sendElementAdded(CmsContainerPageElementPanel widget) { 3677 3678 if (widget != null) { 3679 I_EventDetails details = createEventDetails(widget); 3680 sendEvent(EVENT_ELEMENT_ADDED, details); 3681 sendEvent(EVENT_ELEMENT_MODIFIED, addTypeToDetails(details, "add")); 3682 } 3683 } 3684 3685 /** 3686 * Sends the custom 'ocElementDeleted' event for a deleted container element. 3687 * 3688 * @param details the event details 3689 */ 3690 public void sendElementDeleted(I_EventDetails details) { 3691 3692 sendEvent(EVENT_ELEMENT_DELETED, details); 3693 sendEvent(EVENT_ELEMENT_MODIFIED, addTypeToDetails(details, "delete")); 3694 } 3695 3696 /** 3697 * Sends the custom 'ocElementEditedContent' event for an edited container element. 3698 * 3699 * @param widget the container element 3700 * @param replacedElement the element that was formerly on the page before the user edited it 3701 * @param wasNew true if the element was a new element before editing 3702 */ 3703 public void sendElementEditedContent( 3704 CmsContainerPageElementPanel widget, 3705 elemental2.dom.Element replacedElement, 3706 boolean wasNew) { 3707 3708 if (widget != null) { 3709 I_EventDetails details = createEventDetails(widget); 3710 details.setReplacedElement(replacedElement); 3711 details.setIsPlaceholder(wasNew); 3712 sendEvent(EVENT_ELEMENT_EDITED_CONTENT, details); 3713 sendEvent(EVENT_ELEMENT_EDITED, details); 3714 sendEvent(EVENT_ELEMENT_MODIFIED, addTypeToDetails(details, "editContent")); 3715 } 3716 } 3717 3718 /** 3719 * Sends the custom 'ocElementEditedSettings' event for an edited container element. 3720 * 3721 * @param widget the container element 3722 * @param replacedWidget the former container element that has now been replaced with 'widget' 3723 */ 3724 public void sendElementEditedSettings( 3725 CmsContainerPageElementPanel widget, 3726 CmsContainerPageElementPanel replacedWidget) { 3727 3728 if (widget != null) { 3729 I_EventDetails details = createEventDetails(widget); 3730 details.setReplacedElement(Js.cast(replacedWidget.getElement())); 3731 sendEvent(EVENT_ELEMENT_EDITED_SETTINGS, details); 3732 sendEvent(EVENT_ELEMENT_EDITED, details); 3733 sendEvent(EVENT_ELEMENT_MODIFIED, addTypeToDetails(details, "editSettings")); 3734 } 3735 } 3736 3737 /** 3738 * Sends the custom 'ocElementMoved' event for a moved container element. 3739 * 3740 * @param widget the container element 3741 */ 3742 public void sendElementMoved(CmsContainerPageElementPanel widget) { 3743 3744 if (widget != null) { 3745 I_EventDetails details = createEventDetails(widget); 3746 sendEvent(EVENT_ELEMENT_MOVED, details); 3747 sendEvent(EVENT_ELEMENT_MODIFIED, addTypeToDetails(details, "move")); 3748 } 3749 } 3750 3751 /** 3752 * Sets the flag indicating that a content element is being edited.<p> 3753 * 3754 * @param isContentEditing the flag indicating that a content element is being edited 3755 */ 3756 public void setContentEditing(boolean isContentEditing) { 3757 3758 if (m_groupEditor != null) { 3759 if (isContentEditing) { 3760 m_groupEditor.hidePopup(); 3761 } else { 3762 m_groupEditor.showPopup(); 3763 } 3764 } 3765 m_isContentEditing = isContentEditing; 3766 } 3767 3768 /** 3769 * Sets the DND controller.<p> 3770 * 3771 * @param dnd the new DND controller 3772 */ 3773 public void setDndController(CmsCompositeDNDController dnd) { 3774 3775 m_dndController = dnd; 3776 } 3777 3778 /** 3779 * Sets the element view.<p> 3780 * 3781 * @param viewInfo the element view 3782 * @param nextAction the action to execute after setting the view 3783 */ 3784 public void setElementView(CmsElementViewInfo viewInfo, Runnable nextAction) { 3785 3786 if (viewInfo != null) { 3787 m_elementView = viewInfo; 3788 3789 CmsRpcAction<Void> action = new CmsRpcAction<Void>() { 3790 3791 @SuppressWarnings("synthetic-access") 3792 @Override 3793 public void execute() { 3794 3795 getContainerpageService().setElementView(m_elementView.getElementViewId(), this); 3796 } 3797 3798 @Override 3799 protected void onResponse(Void result) { 3800 3801 // nothing to do 3802 } 3803 }; 3804 action.execute(); 3805 3806 m_currentEditLevel = -1; 3807 reinitializeButtons(); 3808 updateButtonsForCurrentView(); 3809 reInitInlineEditing(); 3810 updateGalleryData(true, nextAction); 3811 } 3812 } 3813 3814 /** 3815 * Sets the model group base element id.<p> 3816 * 3817 * @param modelGroupElementId the model group base element id 3818 */ 3819 public void setModelGroupElementId(String modelGroupElementId) { 3820 3821 m_modelGroupElementId = modelGroupElementId; 3822 } 3823 3824 /** 3825 * Marks the page as changed.<p> 3826 * 3827 * @param nextActions the actions to perform after the page has been marked as changed 3828 */ 3829 public void setPageChanged(Runnable... nextActions) { 3830 3831 if (!isGroupcontainerEditing()) { 3832 // the container page will be saved immediately 3833 m_pageChanged = true; 3834 saveContainerpage(nextActions); 3835 } 3836 } 3837 3838 /** 3839 * Sets an alternative event preview handler. 3840 * 3841 * @param handler the alternative preview handler to use 3842 */ 3843 public void setPreviewHandler(NativePreviewHandler handler) { 3844 3845 m_previewHandler = handler; 3846 } 3847 3848 /** 3849 * Method to determine whether a container element should be shown in the current template context.<p> 3850 * 3851 * @param elementData the element data 3852 * 3853 * @return true if the element should be shown 3854 */ 3855 public boolean shouldShowInContext(CmsContainerElementData elementData) { 3856 3857 CmsTemplateContextInfo contextInfo = getData().getTemplateContextInfo(); 3858 if (contextInfo.getCurrentContext() == null) { 3859 return true; 3860 } 3861 CmsDefaultSet<String> allowedContexts = contextInfo.getAllowedContexts().get(elementData.getResourceType()); 3862 if ((allowedContexts != null) && !allowedContexts.contains(contextInfo.getCurrentContext())) { 3863 return false; 3864 } 3865 3866 String settingValue = elementData.getSettings().get(CmsTemplateContextInfo.SETTING); 3867 return (settingValue == null) || settingValue.contains(contextInfo.getCurrentContext()); 3868 } 3869 3870 /** 3871 * Tells the controller that group-container editing has started.<p> 3872 * 3873 * @param groupContainer the group container 3874 * @param isElementGroup <code>true</code> if the group container is an element group and not an inheritance group 3875 */ 3876 public void startEditingGroupcontainer( 3877 final CmsGroupContainerElementPanel groupContainer, 3878 final boolean isElementGroup) { 3879 3880 removeEditButtonsPositionTimer(); 3881 I_CmsSimpleCallback<Boolean> callback = new I_CmsSimpleCallback<Boolean>() { 3882 3883 public void execute(Boolean arg) { 3884 3885 if (arg.booleanValue()) { 3886 if (isElementGroup) { 3887 m_groupEditor = CmsGroupContainerEditor.openGroupcontainerEditor( 3888 groupContainer, 3889 CmsContainerpageController.this, 3890 m_handler); 3891 } else { 3892 m_groupEditor = CmsInheritanceContainerEditor.openInheritanceContainerEditor( 3893 groupContainer, 3894 CmsContainerpageController.this, 3895 m_handler); 3896 } 3897 } else { 3898 CmsNotification.get().send( 3899 Type.WARNING, 3900 Messages.get().key(Messages.GUI_NOTIFICATION_UNABLE_TO_LOCK_0)); 3901 } 3902 } 3903 }; 3904 RootPanel.get().addStyleName(OC_EDITING_GROUPCONTAINER); 3905 if ((m_groupEditor == null) && (groupContainer.isNew())) { 3906 callback.execute(Boolean.TRUE); 3907 } else { 3908 lockContainerpage(callback); 3909 } 3910 3911 } 3912 3913 /** 3914 * Starts the publish lock check. 3915 */ 3916 public void startPublishLockCheck() { 3917 3918 Set<CmsUUID> elementIds = new HashSet<>(); 3919 processPageContent(new I_PageContentVisitor() { 3920 3921 public boolean beginContainer(String name, CmsContainer container) { 3922 3923 return true; 3924 } 3925 3926 public void endContainer() { 3927 3928 // do nothing 3929 } 3930 3931 public void handleElement(CmsContainerPageElementPanel element) { 3932 3933 if (element.hasWritePermission() && element.getLockInfo().isPublishLock()) { 3934 CmsUUID structureId = element.getStructureId(); 3935 if (structureId != null) { 3936 elementIds.add(structureId); 3937 } 3938 } 3939 } 3940 }); 3941 3942 m_publishLockChecker.addIdsToCheck(elementIds); 3943 } 3944 3945 /** 3946 * Tells the controller that group-container editing has stopped.<p> 3947 */ 3948 public void stopEditingGroupcontainer() { 3949 3950 m_groupEditor = null; 3951 RootPanel.get().removeStyleName(OC_EDITING_GROUPCONTAINER); 3952 } 3953 3954 /** 3955 * Unlocks the given resource.<p> 3956 * 3957 * @param structureId the structure id of the resource to unlock 3958 * 3959 * @return <code>true</code> if the resource was unlocked successfully 3960 */ 3961 public boolean unlockResource(CmsUUID structureId) { 3962 3963 return CmsCoreProvider.get().unlock(structureId); 3964 } 3965 3966 /** 3967 * Updates he 3968 */ 3969 public void updateButtonsForCurrentView() { 3970 3971 String nonDefaultViewClass = I_CmsLayoutBundle.INSTANCE.containerpageCss().nonDefaultView(); 3972 CmsUUID viewId = getElementView().getRootViewId(); 3973 if (viewId.isNullUUID()) { 3974 RootPanel.get().removeStyleName(nonDefaultViewClass); 3975 } else { 3976 RootPanel.get().addStyleName(nonDefaultViewClass); 3977 } 3978 } 3979 3980 /** 3981 * Adds the given element data to the element cache.<p> 3982 * 3983 * @param elements the element data 3984 */ 3985 protected void addElements(List<CmsContainerElementData> elements) { 3986 3987 for (CmsContainerElementData element : elements) { 3988 m_elements.put(element.getClientId(), element); 3989 } 3990 } 3991 3992 /** 3993 * Adds the given element data to the element cache.<p> 3994 * 3995 * @param elements the element data 3996 */ 3997 protected void addElements(Map<String, CmsContainerElementData> elements) { 3998 3999 for (CmsContainerElementData element : elements.values()) { 4000 m_elements.put(element.getClientId(), element); 4001 } 4002 } 4003 4004 /** 4005 * Asks the user whether an element which has been removed should be deleted.<p> 4006 * 4007 * @param status the status of the removed element 4008 */ 4009 protected void askWhetherRemovedElementShouldBeDeleted(final CmsRemovedElementStatus status) { 4010 4011 CmsRemovedElementDeletionDialog dialog = new CmsRemovedElementDeletionDialog(status); 4012 dialog.center(); 4013 } 4014 4015 /** 4016 * Checks that a removed can be possibly deleted and if so, asks the user if it should be deleted.<p> 4017 * 4018 * @param id the client id of the element 4019 */ 4020 protected void checkReferencesToRemovedElement(final String id) { 4021 4022 if (id != null) { 4023 //NOTE: We only use an RPC call here to check for references on the server side. If, at a later point, we decide 4024 //to add a save button again, this will have to be changed, because then we have to consider client-side state. 4025 CmsRpcAction<CmsRemovedElementStatus> getStatusAction = new CmsRpcAction<CmsRemovedElementStatus>() { 4026 4027 @Override 4028 public void execute() { 4029 4030 start(200, true); 4031 getContainerpageService().getRemovedElementStatus(id, null, null, this); 4032 } 4033 4034 @Override 4035 public void onResponse(final CmsRemovedElementStatus status) { 4036 4037 stop(false); 4038 if (status.isDeletionCandidate()) { 4039 askWhetherRemovedElementShouldBeDeleted(status); 4040 4041 } 4042 } 4043 4044 }; 4045 getStatusAction.execute(); 4046 4047 } 4048 } 4049 4050 /** 4051 * Disables option and toolbar buttons.<p> 4052 */ 4053 protected void deactivateOnClosing() { 4054 4055 removeEditButtonsPositionTimer(); 4056 m_handler.deactivateCurrentButton(); 4057 m_handler.disableToolbarButtons(); 4058 } 4059 4060 /** 4061 * Helper method to get all current container page elements.<p> 4062 * 4063 * @param includeGroupContents true if the contents of group containers should also be included 4064 * 4065 * @return the list of current container page elements 4066 */ 4067 protected List<CmsContainerPageElementPanel> getAllContainerPageElements(boolean includeGroupContents) { 4068 4069 List<CmsContainerPageElementPanel> elemWidgets = new ArrayList<CmsContainerPageElementPanel>(); 4070 for (Entry<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> entry : CmsContainerpageController.get().getContainerTargets().entrySet()) { 4071 Iterator<Widget> elIt = entry.getValue().iterator(); 4072 while (elIt.hasNext()) { 4073 try { 4074 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel elementWidget = (org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel)elIt.next(); 4075 elemWidgets.add(elementWidget); 4076 if (includeGroupContents && (elementWidget instanceof CmsGroupContainerElementPanel)) { 4077 List<CmsContainerPageElementPanel> groupChildren = ((CmsGroupContainerElementPanel)elementWidget).getGroupChildren(); 4078 elemWidgets.addAll(groupChildren); 4079 } 4080 } catch (ClassCastException e) { 4081 // no proper container element, skip it (this should never happen!) 4082 CmsDebugLog.getInstance().printLine( 4083 "WARNING: there is an inappropriate element within a container"); 4084 } 4085 } 4086 } 4087 return elemWidgets; 4088 } 4089 4090 /** 4091 * Returns the core RPC service.<p> 4092 * 4093 * @return the core service 4094 */ 4095 protected I_CmsCoreServiceAsync getCoreService() { 4096 4097 if (m_coreSvc == null) { 4098 m_coreSvc = CmsCoreProvider.getService(); 4099 } 4100 return m_coreSvc; 4101 } 4102 4103 /** 4104 * Returns the currently active group editor.<p> 4105 * 4106 * @return the currently active group editor 4107 */ 4108 protected A_CmsGroupEditor getGroupEditor() { 4109 4110 return m_groupEditor; 4111 } 4112 4113 /** 4114 * Returns the content locale.<p> 4115 * 4116 * @return the content locale 4117 */ 4118 protected String getLocale() { 4119 4120 return m_data.getLocale(); 4121 } 4122 4123 /** 4124 * Gets the page content for purposes of saving.<p> 4125 * 4126 * @return the page content 4127 */ 4128 protected List<CmsContainer> getPageContent() { 4129 4130 SaveDataVisitor visitor = new SaveDataVisitor(); 4131 processPageContent(visitor); 4132 return visitor.getContainers(); 4133 4134 } 4135 4136 /** 4137 * Returns the containers of the page in their current state.<p> 4138 * 4139 * @return the containers of the page 4140 */ 4141 protected List<CmsContainer> getPageState() { 4142 4143 PageStateVisitor visitor = new PageStateVisitor(); 4144 processPageContent(visitor); 4145 return visitor.getContainers(); 4146 } 4147 4148 /** 4149 * Returns the request parameters of the displayed container-page.<p> 4150 * 4151 * @return the request parameters 4152 */ 4153 protected String getRequestParams() { 4154 4155 return m_data.getRequestParams(); 4156 } 4157 4158 /** 4159 * Checks if any of the containers are nested containers.<p> 4160 * 4161 * @return true if there are nested containers 4162 */ 4163 protected boolean hasNestedContainers() { 4164 4165 boolean hasNestedContainers = false; 4166 for (CmsContainer container : m_containers.values()) { 4167 if (container.getParentContainerName() != null) { 4168 hasNestedContainers = true; 4169 break; 4170 } 4171 } 4172 return hasNestedContainers; 4173 } 4174 4175 /** 4176 * Returns whether the given container is considered a root container.<p> 4177 * 4178 * @param container the container to check 4179 * 4180 * @return <code>true</code> if the given container is a root container 4181 */ 4182 protected boolean isRootContainer(CmsContainer container) { 4183 4184 boolean isRoot = false; 4185 if (!container.isSubContainer()) { 4186 isRoot = true; 4187 } else if (container.isDetailOnly()) { 4188 CmsContainer parent = getContainer(container.getParentContainerName()); 4189 isRoot = (parent != null) && !parent.isDetailOnly(); 4190 } 4191 return isRoot; 4192 } 4193 4194 /** 4195 * Opens the editor for the newly created element.<p> 4196 * 4197 * @param element the container element 4198 * @param newElementData the new element data 4199 * @param inline <code>true</code> to open the inline editor for the given element if available 4200 */ 4201 protected void openEditorForNewElement( 4202 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element, 4203 CmsContainerElement newElementData, 4204 boolean inline) { 4205 4206 String oldId = element.getNewType(); 4207 element.setNewType(null); 4208 if (inline) { 4209 String newId = getServerId(newElementData.getClientId()); 4210 CmsContentEditor.replaceResourceIds(element.getElement(), oldId, newId); 4211 } 4212 element.setId(newElementData.getClientId()); 4213 element.setSitePath(newElementData.getSitePath()); 4214 if (!isGroupcontainerEditing()) { 4215 setPageChanged(); 4216 } 4217 getHandler().hidePageOverlay(); 4218 getHandler().openEditorForElement(element, inline, true); 4219 } 4220 4221 /** 4222 * Previews events. Shows the leaving page dialog, if the page has changed and an anchor has been clicked.<p> 4223 * Also triggers an element view change on 'Ctrl+E'.<p> 4224 * 4225 * @param event the native event 4226 */ 4227 protected void previewNativeEvent(NativePreviewEvent event) { 4228 4229 if (m_previewHandler != null) { 4230 m_previewHandler.onPreviewNativeEvent(event); 4231 return; 4232 } 4233 4234 Event nativeEvent = Event.as(event.getNativeEvent()); 4235 4236 if ((nativeEvent.getTypeInt() == Event.ONCLICK) && hasPageChanged()) { 4237 EventTarget target = nativeEvent.getEventTarget(); 4238 if (!Element.is(target)) { 4239 return; 4240 } 4241 Element element = Element.as(target); 4242 element = CmsDomUtil.getAncestor(element, CmsDomUtil.Tag.a); 4243 if (element == null) { 4244 return; 4245 } 4246 AnchorElement anc = AnchorElement.as(element); 4247 final String uri = anc.getHref(); 4248 4249 // avoid to abort events for date-picker widgets 4250 if (CmsStringUtil.isEmptyOrWhitespaceOnly(uri) 4251 || (CmsDomUtil.getAncestor(element, "x-date-picker") != null)) { 4252 return; 4253 } 4254 nativeEvent.preventDefault(); 4255 nativeEvent.stopPropagation(); 4256 m_handler.leavePage(uri); 4257 } 4258 if (event.getTypeInt() == Event.ONKEYDOWN) { 4259 int keyCode = nativeEvent.getKeyCode(); 4260 if ((keyCode == KeyCodes.KEY_F5) && hasPageChanged()) { 4261 // user pressed F5 4262 nativeEvent.preventDefault(); 4263 nativeEvent.stopPropagation(); 4264 m_handler.leavePage(Window.Location.getHref()); 4265 } 4266 if (nativeEvent.getCtrlKey() || nativeEvent.getMetaKey()) { 4267 // look for short cuts 4268 if (keyCode == KeyCodes.KEY_E) { 4269 if (nativeEvent.getShiftKey()) { 4270 circleContainerEditLayers(); 4271 } else { 4272 openNextElementView(); 4273 } 4274 nativeEvent.preventDefault(); 4275 nativeEvent.stopPropagation(); 4276 } 4277 } 4278 } 4279 } 4280 4281 /** 4282 * Iterates over all the container contents and calls a visitor object with the visited containers/elements as parameters. 4283 * 4284 * @param visitor the visitor which the container elements should be passed to 4285 */ 4286 protected void processPageContent(I_PageContentVisitor visitor) { 4287 4288 for (Entry<String, org.opencms.ade.containerpage.client.ui.CmsContainerPageContainer> entry : m_targetContainers.entrySet()) { 4289 4290 CmsContainer cnt = m_containers.get(entry.getKey()); 4291 if (visitor.beginContainer(entry.getKey(), cnt)) { 4292 Iterator<Widget> elIt = entry.getValue().iterator(); 4293 while (elIt.hasNext()) { 4294 try { 4295 CmsContainerPageElementPanel elementWidget = (CmsContainerPageElementPanel)elIt.next(); 4296 visitor.handleElement(elementWidget); 4297 } catch (ClassCastException e) { 4298 // no proper container element, skip it (this should never happen!) 4299 CmsDebugLog.getInstance().printLine( 4300 "WARNING: there is an inappropriate element within a container"); 4301 } 4302 } 4303 visitor.endContainer(); 4304 } 4305 } 4306 } 4307 4308 /** 4309 * Removes all container elements with the given id from all containers and the client side cache.<p> 4310 * 4311 * @param resourceId the resource id 4312 */ 4313 protected void removeContainerElements(String resourceId) { 4314 4315 boolean changed = false; 4316 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> it = getAllDragElements().iterator(); 4317 while (it.hasNext()) { 4318 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel containerElement = it.next(); 4319 if (resourceId.startsWith(containerElement.getId())) { 4320 containerElement.removeFromParent(); 4321 changed = true; 4322 } 4323 } 4324 for (String elementId : m_elements.keySet()) { 4325 if (elementId.startsWith(resourceId)) { 4326 m_elements.remove(elementId); 4327 } 4328 } 4329 if (changed) { 4330 setPageChanged(); 4331 } 4332 } 4333 4334 /** 4335 * Schedules an update of the gallery data according to the current element view and the editable containers.<p> 4336 */ 4337 protected void scheduleGalleryUpdate() { 4338 4339 // only if not already scheduled 4340 if (m_galleryUpdateTimer == null) { 4341 m_galleryUpdateTimer = new Timer() { 4342 4343 @Override 4344 public void run() { 4345 4346 m_galleryUpdateTimer = null; 4347 updateGalleryData(false, null); 4348 } 4349 }; 4350 m_galleryUpdateTimer.schedule(50); 4351 } 4352 } 4353 4354 /** 4355 * Sets the page changed flag and initializes the window closing handler if necessary.<p> 4356 * 4357 * @param changed if <code>true</code> the page has changed 4358 * @param unlock if <code>true</code> the page will be unlocked for unchanged pages 4359 */ 4360 protected void setPageChanged(boolean changed, boolean unlock) { 4361 4362 if (changed) { 4363 if (!m_pageChanged) { 4364 m_pageChanged = changed; 4365 lockContainerpage(new I_CmsSimpleCallback<Boolean>() { 4366 4367 public void execute(Boolean arg) { 4368 4369 // nothing to do 4370 } 4371 }); 4372 } 4373 } else { 4374 m_pageChanged = changed; 4375 if (unlock) { 4376 unlockContainerpage(); 4377 } 4378 } 4379 } 4380 4381 /** 4382 * Asynchronously unlocks the container page. 4383 */ 4384 protected void unlockContainerpage() { 4385 4386 I_CmsAutoBeanFactory factory = CmsCoreProvider.AUTO_BEAN_FACTORY; 4387 AutoBean<I_CmsUnlockData> unlockParams = factory.unlockData(); 4388 unlockParams.as().setPageId("" + CmsCoreProvider.get().getStructureId()); 4389 if (getData().getDetailId() != null) { 4390 unlockParams.as().setDetailId("" + getData().getDetailId()); 4391 } 4392 unlockParams.as().setLocale(CmsCoreProvider.get().getLocale()); 4393 String url = CmsCoreProvider.get().link("/handleBuiltinService" + CmsGwtConstants.HANDLER_UNLOCK_PAGE); 4394 sendBeacon(url, AutoBeanCodex.encode(unlockParams).getPayload()); 4395 } 4396 4397 /** 4398 * Returns the pages of editable containers.<p> 4399 * 4400 * @return the containers 4401 */ 4402 List<CmsContainer> getEditableContainers() { 4403 4404 List<CmsContainer> containers = new ArrayList<CmsContainer>(); 4405 for (CmsContainer container : m_containers.values()) { 4406 if ((m_targetContainers.get(container.getName()) != null) 4407 && isContainerEditable(m_targetContainers.get(container.getName()))) { 4408 containers.add(container); 4409 } 4410 } 4411 return containers; 4412 } 4413 4414 /** 4415 * Handles a window resize to reset highlighting and the edit button positions.<p> 4416 */ 4417 void handleResize() { 4418 4419 m_resizeTimer = null; 4420 resetEditButtons(); 4421 } 4422 4423 /** 4424 * Call on window resize.<p> 4425 */ 4426 void onResize() { 4427 4428 if (!isGroupcontainerEditing() && (m_resizeTimer == null)) { 4429 m_resizeTimer = new Timer() { 4430 4431 @Override 4432 public void run() { 4433 4434 handleResize(); 4435 } 4436 }; 4437 m_resizeTimer.schedule(300); 4438 } 4439 } 4440 4441 /** 4442 * Sets the load time.<p> 4443 * 4444 * @param time the time to set 4445 */ 4446 void setLoadTime(Long time) { 4447 4448 if (time != null) { 4449 m_loadTime = time.longValue(); 4450 } 4451 } 4452 4453 /** 4454 * Updates the gallery data according to the current element view and the editable containers.<p> 4455 * This method should only be called from the gallery update timer to avoid unnecessary requests.<p> 4456 * 4457 * @param viewChanged <code>true</code> in case the element view changed 4458 * @param nextAction the action to execute after updating the gallery data 4459 */ 4460 void updateGalleryData(final boolean viewChanged, final Runnable nextAction) { 4461 4462 CmsRpcAction<CmsContainerPageGalleryData> dataAction = new CmsRpcAction<CmsContainerPageGalleryData>() { 4463 4464 @Override 4465 public void execute() { 4466 4467 getContainerpageService().getGalleryDataForPage( 4468 getEditableContainers(), 4469 getElementView().getElementViewId(), 4470 CmsCoreProvider.get().getUri(), 4471 getData().getDetailId(), 4472 getData().getLocale(), 4473 CmsContainerpageController.get().getData().getTemplateContextInfo(), 4474 this); 4475 } 4476 4477 @Override 4478 protected void onResponse(CmsContainerPageGalleryData result) { 4479 4480 m_handler.m_editor.getAdd().updateGalleryData(result, viewChanged); 4481 if (nextAction != null) { 4482 nextAction.run(); 4483 } 4484 } 4485 }; 4486 dataAction.execute(); 4487 } 4488 4489 /** 4490 * Creates a copy of the event details and adds a 'type' field with the specified value to the result. 4491 * 4492 * @param details the details to copy 4493 * @param type the type to add 4494 * @return the copy with the added type 4495 */ 4496 private I_EventDetails addTypeToDetails(I_EventDetails details, String type) { 4497 4498 I_EventDetails result = copyEventDetails(details); 4499 result.setType(type); 4500 return result; 4501 } 4502 4503 /** 4504 * Checks whether there are other references to a given container page element.<p> 4505 * 4506 * @param element the element to check 4507 * @param callback the callback which will be called with the result of the check (true if there are other references) 4508 */ 4509 private void checkElementReferences( 4510 final CmsContainerPageElementPanel element, 4511 final AsyncCallback<CmsRemovedElementStatus> callback) { 4512 4513 ReferenceCheckVisitor visitor = new ReferenceCheckVisitor(element); 4514 processPageContent(visitor); 4515 if (visitor.hasReferences()) { 4516 // Don't need to ask the server because we already know we have other references in the same page 4517 CmsRpcAction<CmsListInfoBean> infoAction = new CmsRpcAction<CmsListInfoBean>() { 4518 4519 @Override 4520 public void execute() { 4521 4522 start(200, true); 4523 CmsCoreProvider.getVfsService().getPageInfo(new CmsUUID(getServerId(element.getId())), this); 4524 } 4525 4526 @Override 4527 protected void onResponse(CmsListInfoBean result) { 4528 4529 stop(false); 4530 callback.onSuccess(new CmsRemovedElementStatus(null, result, false, null)); 4531 } 4532 }; 4533 infoAction.execute(); 4534 } else { 4535 CmsRpcAction<CmsRemovedElementStatus> getStatusAction = new CmsRpcAction<CmsRemovedElementStatus>() { 4536 4537 @Override 4538 public void execute() { 4539 4540 start(200, true); 4541 CmsUUID detailOnlyId = CmsContainerpageController.get().getData().getDetailContainerPageId(); 4542 CmsUUID pageId = detailOnlyId != null ? detailOnlyId : CmsCoreProvider.get().getStructureId(); 4543 4544 getContainerpageService().getRemovedElementStatus( 4545 element.getId(), 4546 CmsCoreProvider.get().getStructureId(), 4547 pageId, 4548 this); 4549 } 4550 4551 @Override 4552 public void onResponse(final CmsRemovedElementStatus status) { 4553 4554 stop(false); 4555 callback.onSuccess(status); 4556 } 4557 4558 }; 4559 getStatusAction.execute(); 4560 4561 } 4562 } 4563 4564 /** 4565 * Checks if the page was locked by another user at load time.<p> 4566 */ 4567 private void checkLockInfo() { 4568 4569 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getData().getLockInfo())) { 4570 CmsNotification.get().send(Type.ERROR, getData().getLockInfo()); 4571 m_lockStatus = LockStatus.failed; 4572 m_handler.m_editor.disableEditing(getData().getLockInfo()); 4573 } 4574 } 4575 4576 /** 4577 * Selects the next container edit level.<p> 4578 */ 4579 private void circleContainerEditLayers() { 4580 4581 if (m_isContentEditing || isGroupcontainerEditing() || (m_maxContainerLevel == 0)) { 4582 return; 4583 } 4584 boolean hasEditables = false; 4585 int previousLevel = m_currentEditLevel; 4586 String message = ""; 4587 while (!hasEditables) { 4588 if (m_currentEditLevel == m_maxContainerLevel) { 4589 m_currentEditLevel = -1; 4590 message = Messages.get().key(Messages.GUI_SWITCH_EDIT_LEVEL_ALL_1, m_elementView.getTitle()); 4591 } else { 4592 m_currentEditLevel++; 4593 message = Messages.get().key(Messages.GUI_SWITCH_EDIT_LEVEL_1, Integer.valueOf(m_currentEditLevel)); 4594 } 4595 reinitializeButtons(); 4596 hasEditables = !CmsDomUtil.getElementsByClass( 4597 I_CmsElementToolbarContext.ELEMENT_OPTION_BAR_CSS_CLASS).isEmpty(); 4598 } 4599 if (previousLevel != m_currentEditLevel) { 4600 CmsNotification.get().send(Type.NORMAL, message); 4601 } 4602 } 4603 4604 /** 4605 * Copies an event details object. 4606 * 4607 * @param original the original event details 4608 * @return the copied object 4609 */ 4610 private I_EventDetails copyEventDetails(I_EventDetails original) { 4611 4612 JsPropertyMap<Object> originalMap = Js.cast(original); 4613 JsPropertyMap<Object> result = Js.cast(new JsObject()); 4614 originalMap.forEach(key -> { 4615 result.set(key, originalMap.get(key)); 4616 }); 4617 return Js.cast(result); 4618 } 4619 4620 /** 4621 * Returns all element id's related to the given one.<p> 4622 * 4623 * @param id the element id 4624 * @return the related id's 4625 */ 4626 private Set<String> getRelatedElementIds(String id) { 4627 4628 Set<String> result = new HashSet<String>(); 4629 if (id != null) { 4630 result.add(id); 4631 String serverId = getServerId(id); 4632 4633 Iterator<String> it = m_elements.keySet().iterator(); 4634 while (it.hasNext()) { 4635 String elId = it.next(); 4636 if (elId.startsWith(serverId)) { 4637 result.add(elId); 4638 } 4639 } 4640 4641 Iterator<org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel> itEl = getAllDragElements().iterator(); 4642 while (itEl.hasNext()) { 4643 org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel element = itEl.next(); 4644 if (element.getId().startsWith(serverId)) { 4645 result.add(element.getId()); 4646 } 4647 } 4648 } 4649 return result; 4650 } 4651 4652 /** 4653 * Checks whether the given container matches the current edit level.<p> 4654 * 4655 * @param container the container to check 4656 * 4657 * @return <code>true</code> if the given container matches the current edit level 4658 */ 4659 private boolean matchesCurrentEditLevel(I_CmsDropContainer container) { 4660 4661 boolean result = !(container instanceof CmsContainerPageContainer) 4662 || (m_currentEditLevel == -1) 4663 || (m_currentEditLevel == ((CmsContainerPageContainer)container).getContainerLevel()); 4664 return result; 4665 } 4666 4667 /** 4668 * Opens the next available root element view.<p> 4669 */ 4670 private void openNextElementView() { 4671 4672 List<CmsElementViewInfo> views = getData().getElementViews(); 4673 if (views.size() > 1) { 4674 CmsUUID current = m_elementView.getRootViewId(); 4675 4676 // look for the current view index 4677 int currentIndex = -1; 4678 for (int i = 0; i < views.size(); i++) { 4679 CmsElementViewInfo view = views.get(i); 4680 if (view.isRoot() && current.equals(view.getElementViewId())) { 4681 currentIndex = i; 4682 break; 4683 } 4684 } 4685 if (currentIndex != -1) { 4686 CmsElementViewInfo target = null; 4687 // look for the next root view 4688 for (int i = currentIndex + 1; i < views.size(); i++) { 4689 CmsElementViewInfo view = views.get(i); 4690 if (view.isRoot()) { 4691 target = view; 4692 break; 4693 } 4694 } 4695 if (target == null) { 4696 // start at the beginning 4697 for (int i = 0; i < currentIndex; i++) { 4698 CmsElementViewInfo view = views.get(i); 4699 if (view.isRoot()) { 4700 target = view; 4701 break; 4702 } 4703 } 4704 } 4705 if (target != null) { 4706 final String viewName = target.getTitle(); 4707 Runnable action = new Runnable() { 4708 4709 public void run() { 4710 4711 CmsNotification.get().send( 4712 Type.NORMAL, 4713 Messages.get().key(Messages.GUI_SWITCH_ELEMENT_VIEW_NOTIFICATION_1, viewName)); 4714 } 4715 }; 4716 setElementView(target, action); 4717 } 4718 } 4719 } 4720 } 4721 4722 /** 4723 * Removes the edit buttons position timer.<p> 4724 */ 4725 private void removeEditButtonsPositionTimer() { 4726 4727 if (m_editButtonsPositionTimer != null) { 4728 m_editButtonsPositionTimer.cancel(); 4729 m_editButtonsPositionTimer = null; 4730 } 4731 } 4732 4733 /** 4734 * Calls the browser's sendBeacon function. 4735 * 4736 * @param url the URL to send the data to 4737 * @param data the data to send 4738 */ 4739 private native void sendBeacon(String url, String data) /*-{ 4740 $wnd.navigator.sendBeacon(url, data); 4741 }-*/; 4742 4743 /** 4744 * Creates a custom event and dispatches it to the document. 4745 * 4746 * @param type the event type 4747 * @param details the event details 4748 */ 4749 private void sendEvent(String type, I_EventDetails details) { 4750 4751 CustomEventInit<I_EventDetails> init = Js.cast(CustomEventInit.create()); 4752 init.setBubbles(false); 4753 init.setCancelable(false); 4754 init.setDetail(details); 4755 CustomEvent<I_EventDetails> event1 = new elemental2.dom.CustomEvent<I_EventDetails>(type, init); 4756 CustomEvent<I_EventDetails> event = event1; 4757 // fire event in a timer so the page editor is not blocked by the event handler reacting to it 4758 Timer timer = new Timer() { 4759 4760 @Override 4761 public void run() { 4762 4763 DomGlobal.document.documentElement.dispatchEvent(event); 4764 } 4765 }; 4766 timer.schedule(0); 4767 } 4768 4769 /** 4770 * Checks whether given element is a model group and it's option bar edit points should be visible.<p> 4771 * 4772 * @param element the element to check 4773 * 4774 * @return <code>true</code> in case the current page is not a model group page, 4775 * the given element is a model group and it is inside a view visible to the current user 4776 */ 4777 private boolean shouldShowModelgroupOptionBar(CmsContainerPageElementPanel element) { 4778 4779 if (!getData().isModelGroup() && element.isModelGroup()) { 4780 for (CmsElementViewInfo info : getData().getElementViews()) { 4781 if (info.getElementViewId().equals(element.getElementView())) { 4782 return true; 4783 } 4784 } 4785 } 4786 4787 return false; 4788 } 4789 4790 /** 4791 * Updates the container level info on the present containers.<p> 4792 */ 4793 private void updateContainerLevelInfo() { 4794 4795 Map<String, CmsContainerPageContainer> containers = new HashMap<String, CmsContainerPageContainer>(); 4796 List<CmsContainerPageContainer> temp = new ArrayList<CmsContainerPageContainer>(m_targetContainers.values()); 4797 m_maxContainerLevel = 0; 4798 boolean progress = true; 4799 while (!temp.isEmpty() && progress) { 4800 int size = containers.size(); 4801 Iterator<CmsContainerPageContainer> it = temp.iterator(); 4802 while (it.hasNext()) { 4803 CmsContainerPageContainer container = it.next(); 4804 int level = -1; 4805 if (CmsStringUtil.isEmptyOrWhitespaceOnly(container.getParentContainerId())) { 4806 level = 0; 4807 } else if (containers.containsKey(container.getParentContainerId())) { 4808 level = containers.get(container.getParentContainerId()).getContainerLevel() + 1; 4809 } 4810 if (level > -1) { 4811 container.setContainerLevel(level); 4812 containers.put(container.getContainerId(), container); 4813 it.remove(); 4814 if (level > m_maxContainerLevel) { 4815 m_maxContainerLevel = level; 4816 } 4817 } 4818 } 4819 progress = containers.size() > size; 4820 } 4821 } 4822 4823 /** 4824 * Sets the oc-detail-preview class on first container elements of an appropriate type in detail containers, 4825 * if we are currently not showing a detail content. 4826 */ 4827 private void updateDetailPreviewStyles() { 4828 4829 Set<String> detailTypes = getData().getDetailTypes(); 4830 if ((getData().getDetailId() != null) || detailTypes.isEmpty()) { 4831 return; 4832 } 4833 for (Element elem : CmsDomUtil.getElementsByClass(CmsGwtConstants.CLASS_DETAIL_PREVIEW)) { 4834 elem.removeClassName(CmsGwtConstants.CLASS_DETAIL_PREVIEW); 4835 } 4836 boolean defaultDetailPage = detailTypes.contains(CmsGwtConstants.DEFAULT_DETAILPAGE_TYPE); 4837 4838 processPageContent(new I_PageContentVisitor() { 4839 4840 boolean m_isdetail = false; 4841 4842 public boolean beginContainer(String name, CmsContainer container) { 4843 4844 m_isdetail = container.isDetailViewContainer(); 4845 return true; 4846 } 4847 4848 public void endContainer() { 4849 4850 // do nothing 4851 } 4852 4853 public void handleElement(CmsContainerPageElementPanel element) { 4854 4855 if (m_isdetail && (defaultDetailPage || detailTypes.contains(element.getResourceType()))) { 4856 element.addStyleName(CmsGwtConstants.CLASS_DETAIL_PREVIEW); 4857 } 4858 } 4859 }); 4860 4861 } 4862}