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