1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.pages.app.editor;
35
36 import info.magnolia.event.EventBus;
37 import info.magnolia.i18nsystem.SimpleTranslator;
38 import info.magnolia.objectfactory.Components;
39 import info.magnolia.pages.app.editor.event.NodeSelectedEvent;
40 import info.magnolia.pages.app.editor.pagebar.PageBarPresenter;
41 import info.magnolia.pages.app.editor.statusbar.StatusBarPresenter;
42 import info.magnolia.ui.actionbar.ActionbarPresenter;
43 import info.magnolia.ui.actionbar.ActionbarView;
44 import info.magnolia.ui.actionbar.definition.ActionbarDefinition;
45 import info.magnolia.ui.actionbar.definition.ActionbarGroupDefinition;
46 import info.magnolia.ui.actionbar.definition.ActionbarItemDefinition;
47 import info.magnolia.ui.actionbar.definition.ActionbarSectionDefinition;
48 import info.magnolia.ui.api.action.ActionDefinition;
49 import info.magnolia.ui.api.action.ActionExecutionException;
50 import info.magnolia.ui.api.action.ActionExecutor;
51 import info.magnolia.ui.api.app.AppContext;
52 import info.magnolia.ui.api.app.SubAppContext;
53 import info.magnolia.ui.api.app.SubAppEventBus;
54 import info.magnolia.ui.api.availability.AvailabilityChecker;
55 import info.magnolia.ui.api.availability.AvailabilityDefinition;
56 import info.magnolia.ui.api.event.AdmincentralEventBus;
57 import info.magnolia.ui.api.event.ContentChangedEvent;
58 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
59 import info.magnolia.ui.api.location.Location;
60 import info.magnolia.ui.api.message.Message;
61 import info.magnolia.ui.api.message.MessageType;
62 import info.magnolia.ui.contentapp.definition.ContentSubAppDescriptor;
63 import info.magnolia.ui.contentapp.detail.DetailLocation;
64 import info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor;
65 import info.magnolia.ui.contentapp.detail.DetailView;
66 import info.magnolia.ui.framework.app.BaseSubApp;
67 import info.magnolia.ui.framework.ioc.AdmincentralFlavour;
68 import info.magnolia.ui.vaadin.editor.PageEditorListener;
69 import info.magnolia.ui.vaadin.gwt.client.shared.AbstractElement;
70 import info.magnolia.ui.vaadin.gwt.client.shared.PageElement;
71
72 import java.util.Arrays;
73 import java.util.Collection;
74 import java.util.Collections;
75 import java.util.List;
76 import java.util.Locale;
77 import java.util.Map;
78 import java.util.Objects;
79
80 import javax.inject.Inject;
81 import javax.inject.Named;
82
83 import org.apache.commons.lang3.StringUtils;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
86
87 import com.vaadin.v7.data.Item;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public class PagesEditorSubApp extends BaseSubApp<PagesEditorSubAppView> implements PagesEditorSubAppView.Listener, ActionbarPresenter.Listener, PageEditorPresenter.Listener {
107
108 private static final Logger log = LoggerFactory.getLogger(PagesEditorSubApp.class);
109
110 private final ActionExecutor actionExecutor;
111 private final SubAppContext subAppContext;
112 private final PagesEditorSubAppView view;
113 private final EventBus subAppEventBus;
114 private final EventBus admincentralEventBus;
115 private final PageEditorPresenter pageEditorPresenter;
116 private final ActionbarPresenter actionbarPresenter;
117 private final PagesContentConnector contentConnector;
118 private final AvailabilityChecker availabilityChecker;
119 private final StatusBarPresenter statusBar;
120 private final PageBarPresenter pageBar;
121 private final AppContext appContext;
122 private final SimpleTranslator i18n;
123
124 private String caption;
125
126 @Inject
127 public PagesEditorSubApp(final ActionExecutor actionExecutor, final SubAppContext subAppContext, final PagesEditorSubAppView view,
128 final @Named(AdmincentralEventBus.NAME) EventBus admincentralEventBus, final @Named(SubAppEventBus.NAME) EventBus subAppEventBus,
129 final PageEditorPresenter pageEditorPresenter, final ActionbarPresenter actionbarPresenter,
130 final SimpleTranslator i18n, AvailabilityChecker availabilityChecker, final PagesContentConnector contentConnector,
131 final StatusBarPresenter statusBar, final PageBarPresenter pageBar) {
132 super(subAppContext, view);
133 this.actionExecutor = actionExecutor;
134 this.subAppContext = subAppContext;
135 this.view = view;
136 this.subAppEventBus = subAppEventBus;
137 this.admincentralEventBus = admincentralEventBus;
138 this.pageEditorPresenter = pageEditorPresenter;
139 this.actionbarPresenter = actionbarPresenter;
140 this.availabilityChecker = availabilityChecker;
141 this.statusBar = statusBar;
142 this.pageBar = pageBar;
143 this.contentConnector = contentConnector;
144 this.appContext = subAppContext.getAppContext();
145 this.i18n = i18n;
146 bindHandlers();
147 }
148
149 @Override
150 public String getCaption() {
151 return caption;
152 }
153
154 public void updateCaption(DetailLocation location) {
155 this.caption = contentConnector.getPageTitle(location.getNodePath(), location.getVersion());
156 if (AdmincentralFlavour.get().isM5()) {
157 pageBar.setPageName(caption, location.getNodePath());
158 } else {
159 statusBar.setPageName(caption, location.getNodePath());
160 }
161 }
162
163 @Override
164 public void updateCaptionForExternalPage(String title) {
165 this.caption = title;
166 if (AdmincentralFlavour.get().isM5()) {
167 pageBar.setPageName(caption);
168 } else {
169 statusBar.setPageName(caption);
170 }
171 }
172
173 @Override
174 public PagesEditorSubAppView start(Location location) {
175 view.setListener(this);
176
177 DetailLocation detailLocation = DetailLocation.wrap(location);
178 super.start(detailLocation);
179
180 ActionbarDefinition actionbarDefinition = ((ContentSubAppDescriptor) getSubAppContext().getSubAppDescriptor()).getActionbar();
181 Map<String, ActionDefinition> actionDefinitions = getSubAppContext().getSubAppDescriptor().getActions();
182 actionbarPresenter.setListener(this);
183 ActionbarView actionbar = actionbarPresenter.start(actionbarDefinition, actionDefinitions);
184 hideActionbarSections();
185
186 updateCaption(detailLocation);
187
188 pageEditorPresenter.setListener(this);
189 view.setActionbarView(actionbar);
190 if (AdmincentralFlavour.get().isM5()) {
191 view.setPageBarView(pageBar.start(detailLocation));
192 }
193
194 view.setStatusBarView(statusBar.start(detailLocation));
195 view.setPageEditorView(pageEditorPresenter.start(detailLocation));
196
197 return view;
198 }
199
200
201
202
203
204 protected void updateNodePath(String path) {
205 DetailLocation detailLocation = getCurrentLocation();
206 detailLocation.updateNodePath(path);
207 updateLocationDependentComponents(detailLocation);
208 getAppContext().updateSubAppLocation(getSubAppContext(), detailLocation);
209 pageEditorPresenter.getStatus().setNodePath(path);
210 pageEditorPresenter.updateParameters();
211 }
212
213 @Override
214 public boolean supportsLocation(Location location) {
215 return getCurrentLocation().getNodePath().equals(DetailLocation.wrap(location).getNodePath());
216 }
217
218
219
220
221 @Override
222 public DetailLocation getCurrentLocation() {
223 return DetailLocation.wrap(super.getCurrentLocation());
224 }
225
226 @Override
227 public void deactivateComponents() {
228 updateActionbar();
229 pageBar.deactivateExtensions();
230 statusBar.deactivateExtensions();
231 }
232
233 @Override
234 public void locationChanged(Location location) {
235 DetailLocation itemLocation = DetailLocation.wrap(location);
236 super.locationChanged(itemLocation);
237
238 if (pageEditorPresenter.getStatus().isLocationChanged(itemLocation)) {
239 pageEditorPresenter.reload(itemLocation);
240 updateLocationDependentComponents(itemLocation);
241 }
242 }
243
244 private void updateLocationDependentComponents(DetailLocation location) {
245 pageBar.onLocationUpdate(location);
246 statusBar.onLocationUpdate(location);
247 updateCaption(location);
248 }
249
250 private void bindHandlers() {
251
252 admincentralEventBus.addHandler(ContentChangedEvent.class, new ContentChangedEvent.Handler() {
253
254 @Override
255 public void onContentChanged(ContentChangedEvent event) {
256 if (contentConnector.canHandleItem(event.getItemId())) {
257 if (!contentConnector.itemExists(event.getItemId())) {
258 getSubAppContext().close();
259 }
260 }
261 }
262 });
263
264 subAppEventBus.addHandler(ContentChangedEvent.class, new ContentChangedEvent.Handler() {
265
266 @Override
267 public void onContentChanged(ContentChangedEvent event) {
268
269 AbstractElement element = contentConnector.getElementFrom(event.getItemId());
270 pageEditorPresenter.getStatus().setSelectedElement(element);
271
272
273 pageEditorPresenter.updateParameters();
274
275
276 Locale authoringLocale = subAppContext.getAuthoringLocale();
277
278
279
280 boolean i18nLikelyDisabled = getAvailableLocales(event.getItemId()).isEmpty();
281
282 if (pageEditorPresenter.getStatus().getParameters().isSpa()
283 || authoringLocale == null
284 || Objects.equals(authoringLocale, pageEditorPresenter.getStatus().getLocale())
285 || i18nLikelyDisabled) {
286 pageEditorPresenter.refresh();
287 } else {
288 updateLocationDependentComponents(getCurrentLocation());
289
290 pageEditorPresenter.loadPageEditor();
291 }
292 }
293 });
294
295 subAppEventBus.addHandler(NodeSelectedEvent.class, new NodeSelectedEvent.Handler() {
296
297 @Override
298 public void onItemSelected(NodeSelectedEvent event) {
299 AbstractElement element = event.getElement();
300 if (element instanceof PageElement) {
301 String path = element.getPath();
302 if (StringUtils.isEmpty(path)) {
303 path = "/";
304 }
305 if (!path.equals(getCurrentLocation().getNodePath())) {
306 updateNodePath(path);
307 }
308 }
309 updateActionbar();
310 }
311 });
312
313 }
314
315 @Override
316 public void onActionbarItemClicked(String actionName) {
317 prepareAndExecutePagesEditorAction(actionName);
318 }
319
320
321
322
323
324
325
326 protected void prepareAndExecutePagesEditorAction(String actionName) {
327 AbstractElement selectedElement = pageEditorPresenter.getSelectedElement();
328 if (selectedElement == null) {
329 log.warn("Trying to execute action [{}] but no element was selected. Was the page actually loaded?", actionName);
330 return;
331 }
332 try {
333 actionExecutor.execute(actionName, selectedElement, pageEditorPresenter);
334 } catch (ActionExecutionException e) {
335 Message error = new Message(MessageType.ERROR, i18n.translate("pages.pagesEditorSubapp.actionExecutionException.message"), e.getMessage());
336 log.error("An error occurred while executing action [{}]", actionName, e);
337 appContext.sendLocalMessage(error);
338 }
339 }
340
341 public void updateActionbar() {
342 Object itemId = contentConnector.getItemIdByElement(pageEditorPresenter.getSelectedElement());
343
344
345 List<ActionbarSectionDefinition> sections = getSections();
346 ActionbarSectionDefinition sectionDefinition = getVisibleSection(sections, itemId);
347
348
349 for (ActionbarSectionDefinition section : sections) {
350 actionbarPresenter.hideSection(section.getName());
351 }
352
353 if (sectionDefinition != null) {
354
355 actionbarPresenter.showSection(sectionDefinition.getName());
356
357
358 for (ActionbarGroupDefinition groupDefinition : sectionDefinition.getGroups()) {
359 for (ActionbarItemDefinition itemDefinition : groupDefinition.getItems()) {
360
361 String actionName = itemDefinition.getName();
362 ActionDefinition actionDefinition = actionExecutor.getActionDefinition(actionName);
363 if (actionDefinition != null) {
364 AvailabilityDefinition availability = actionDefinition.getAvailability();
365 if (availabilityChecker.isAvailable(availability, Arrays.asList(itemId))) {
366 actionbarPresenter.enable(actionName);
367 } else {
368 actionbarPresenter.disable(actionName);
369 }
370 }
371 }
372 }
373 }
374 }
375
376 private List<ActionbarSectionDefinition> getSections() {
377 DetailSubAppDescriptor subAppDescriptor = (DetailSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
378 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
379 if (actionbarDefinition == null) {
380 return Collections.emptyList();
381 }
382 return actionbarDefinition.getSections();
383 }
384
385 private void hideActionbarSections() {
386 for (ActionbarSectionDefinition sectionDefinition : getSections()) {
387 actionbarPresenter.hideSection(sectionDefinition.getName());
388 }
389 }
390
391 private ActionbarSectionDefinition getVisibleSection(List<ActionbarSectionDefinition> sections, Object itemId) {
392 for (ActionbarSectionDefinition section : sections) {
393 if (availabilityChecker.isAvailable(section.getAvailability(), Arrays.asList(itemId)))
394 return section;
395 }
396 return null;
397 }
398
399 @Override
400 public void onEscape() {
401 if (pageEditorPresenter.isMoving()) {
402 pageEditorPresenter.onAction(PageEditorListener.ACTION_CANCEL_MOVE_COMPONENT);
403 } else {
404
405 if (getCurrentLocation().getViewType().equals(DetailView.ViewType.EDIT)) {
406 prepareAndExecutePagesEditorAction(PageEditorListener.ACTION_VIEW_PREVIEW);
407 } else {
408 prepareAndExecutePagesEditorAction(PageEditorListener.ACTION_VIEW_EDIT);
409 }
410 }
411 }
412
413 @Override
414 public String getIcon(Location location) {
415 DetailLocation detailLocation = DetailLocation.wrap(location);
416 return detailLocation.getViewType().getIcon();
417 }
418
419 @Override
420 public void onMove() {
421 updateActionbar();
422 }
423
424 @Override
425 public void stop() {
426 pageBar.stop();
427 statusBar.stop();
428 }
429
430 private Collection<Locale> getAvailableLocales(Object itemId) {
431 Item item = contentConnector.getItem(itemId);
432 Collection<Locale> locales = Components.getComponent(I18NAuthoringSupport.class).getAvailableLocales(item);
433
434 return locales != null ? locales : Collections.emptyList();
435 }
436 }