View Javadoc
1   /**
2    * This file Copyright (c) 2013-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.pages.app.detail;
35  
36  import info.magnolia.pages.app.detail.context.MoveComponentContext;
37  import info.magnolia.pages.app.detail.context.NavigationContext;
38  import info.magnolia.ui.UIComponent;
39  import info.magnolia.ui.api.app.SubAppContext;
40  import info.magnolia.ui.api.location.Location;
41  import info.magnolia.ui.contentapp.browser.actions.ActionbarPresenter;
42  import info.magnolia.ui.contentapp.browser.actions.ActionbarView;
43  import info.magnolia.ui.contentapp.detail.AbstractDetailSubApp;
44  import info.magnolia.ui.contentapp.detail.ContentDetailSubApp;
45  import info.magnolia.ui.contentapp.detail.ContentDetailSubApp.DetailLocation;
46  import info.magnolia.ui.editor.LocaleContext;
47  import info.magnolia.ui.framework.WithImplementation;
48  import info.magnolia.ui.vaadin.editor.PageEditorListener;
49  import info.magnolia.ui.vaadin.editor.PageEditorView;
50  
51  import java.util.Optional;
52  
53  import javax.inject.Inject;
54  import javax.jcr.Node;
55  
56  import com.vaadin.event.ShortcutAction;
57  import com.vaadin.event.ShortcutListener;
58  import com.vaadin.shared.Registration;
59  import com.vaadin.ui.Component;
60  import com.vaadin.ui.ComponentContainer;
61  import com.vaadin.ui.CssLayout;
62  import com.vaadin.ui.Panel;
63  
64  /**
65   * Page detail subapp.
66   */
67  public class PageDetailSubApp extends AbstractDetailSubApp<PageDetailSubApp.View> {
68  
69      private final ContentDetailSubApp.LocationContext locationContext;
70      private final PageEditorStatus pageEditorStatus;
71  
72      @Inject
73      protected PageDetailSubApp(
74              SubAppContext subAppContext,
75              PageDetailDescriptor subAppDescriptor,
76              ContentDetailSubApp.LocationContext locationContext,
77              MoveComponentContext moveComponentContext,
78              PageEditorStatus pageEditorStatus,
79              PageEditorView pageEditorView
80      ) {
81          super(subAppContext, new View(subAppDescriptor, locationContext, moveComponentContext, pageEditorView));
82          this.locationContext = locationContext;
83          this.pageEditorStatus = pageEditorStatus;
84      }
85  
86      @Override
87      public View start(Location location) {
88          final View view = super.start(location);
89          bindInstance(UIComponent.class, getView());
90          locationContext.location().set(DetailLocation.wrap(location));
91          locationContext.location().observe(detailLocationOptional -> detailLocationOptional
92                  .ifPresent(detailLocation -> getSubAppContext().getAppContext().updateSubAppLocation(getSubAppContext(), detailLocation)));
93          return view;
94      }
95  
96      @Override
97      public void locationChanged(Location location) {
98          super.locationChanged(location);
99          locationContext.location().set(DetailLocation.wrap(location));
100     }
101 
102     @Override
103     public String getCaption() {
104         return pageEditorStatus.getPageTitle();
105     }
106 
107     /**
108      * Page detail view.
109      */
110     static class View extends CssLayout implements UIComponent {
111 
112         private final PageEditorPresenter pageEditorPresenter;
113         private final Panel panel = new Panel(this);
114 
115         private View(PageDetailDescriptor descriptor, ContentDetailSubApp.LocationContext locationContext, MoveComponentContext moveComponentContext, PageEditorView pageEditorView) {
116             ActionbarPresenter<Node> actionbarPresenter = create(ActionbarPresenter.class, descriptor.getActions(), descriptor.getActionbar());
117 
118             // make sure that the contexts are initialised on root sub-app level
119             // so that both underlying page editor view and status bar extensions
120             // can consume it
121             bindContext(LocaleContext.class);
122             bindContext(NavigationContext.class);
123             bindInstance(ActionbarPresenter.class, actionbarPresenter);
124             bindInstance(UIComponent.class, this);
125 
126             ActionbarView<Node> actionbarView = create("actionbar", ActionbarView.class, descriptor.getActionbar(), actionbarPresenter);
127 
128             CssLayout extensions = new CssLayout();
129             extensions.addStyleName("extensions");
130             descriptor.getExtensionViews()
131                     .stream()
132                     .map(WithImplementation::getImplementationClass)
133                     .map(this::createStatusBarExtension)
134                     .forEach(extensions::addComponent);
135 
136             CssLayout statusbar = new CssLayout();
137             statusbar.addStyleName("statusbar");
138 
139             statusbar.addComponent(extensions);
140 
141             addComponents(actionbarView.asVaadinComponent(), statusbar);
142             addStyleName("pageeditor");
143             setSizeFull();
144             panel.setSizeFull();
145 
146             addComponent(pageEditorView.asVaadinComponent());
147             this.pageEditorPresenter = create(PageEditorPresenter.class, create(descriptor.getItemProvider()));
148             addShortcutListener(new ShortcutListener(null, ShortcutAction.KeyCode.ESCAPE, (int[]) null) {
149                 @Override
150                 public void handleAction(Object sender, Object target) {
151                     if (moveComponentContext.isMoving()) {
152                         pageEditorPresenter.onAction(PageEditorListener.ACTION_STOP_MOVE_COMPONENT);
153                     } else {
154                         // Toggle preview and edit mode.
155                         if (locationContext.location().value().map(DetailLocation::getViewType).map("edit"::equals).orElse(false)) {
156                             pageEditorPresenter.onAction(PageEditorListener.ACTION_VIEW_PREVIEW);
157                         } else {
158                             pageEditorPresenter.onAction(PageEditorListener.ACTION_VIEW_EDIT);
159                         }
160                     }
161                 }
162             });
163         }
164 
165         private Component createStatusBarExtension(Class<? extends UIComponent> viewClass) {
166             UIComponent uiFrameworkView = create(viewClass);
167             Component component = uiFrameworkView.asVaadinComponent();
168             component.addStyleName("statusbar-extension");
169             return component;
170         }
171 
172         @Override
173         public Registration addShortcutListener(ShortcutListener shortcut) {
174             return panel.addShortcutListener(shortcut);
175         }
176 
177         @Override
178         public Component asVaadinComponent() {
179             return panel;
180         }
181 
182         @Override
183         public void destroy() {
184             if (asVaadinComponent().getParent() instanceof ComponentContainer) {
185                 ((ComponentContainer) asVaadinComponent().getParent()).removeComponent(this.asVaadinComponent());
186             }
187             Optional.ofNullable(pageEditorPresenter).ifPresent(PageEditorPresenter::destroy);
188         }
189     }
190 }