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.cms.core.Path;
37 import info.magnolia.cms.core.version.VersionManager;
38 import info.magnolia.cms.i18n.I18nContentSupport;
39 import info.magnolia.context.MgnlContext;
40 import info.magnolia.event.EventBus;
41 import info.magnolia.i18nsystem.SimpleTranslator;
42 import info.magnolia.jcr.util.NodeTypes;
43 import info.magnolia.jcr.util.PropertyUtil;
44 import info.magnolia.objectfactory.Components;
45 import info.magnolia.pages.app.editor.event.NodeSelectedEvent;
46 import info.magnolia.pages.app.editor.pagebar.PageBarPresenter;
47 import info.magnolia.pages.app.editor.statusbar.StatusBarPresenter;
48 import info.magnolia.repository.RepositoryConstants;
49 import info.magnolia.ui.actionbar.ActionbarPresenter;
50 import info.magnolia.ui.actionbar.ActionbarView;
51 import info.magnolia.ui.actionbar.definition.ActionbarDefinition;
52 import info.magnolia.ui.actionbar.definition.ActionbarGroupDefinition;
53 import info.magnolia.ui.actionbar.definition.ActionbarItemDefinition;
54 import info.magnolia.ui.actionbar.definition.ActionbarSectionDefinition;
55 import info.magnolia.ui.api.action.ActionDefinition;
56 import info.magnolia.ui.api.action.ActionExecutionException;
57 import info.magnolia.ui.api.action.ActionExecutor;
58 import info.magnolia.ui.api.app.AppContext;
59 import info.magnolia.ui.api.app.SubAppContext;
60 import info.magnolia.ui.api.app.SubAppEventBus;
61 import info.magnolia.ui.api.availability.AvailabilityChecker;
62 import info.magnolia.ui.api.availability.AvailabilityDefinition;
63 import info.magnolia.ui.api.event.AdmincentralEventBus;
64 import info.magnolia.ui.api.event.ContentChangedEvent;
65 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
66 import info.magnolia.ui.api.location.Location;
67 import info.magnolia.ui.api.message.Message;
68 import info.magnolia.ui.api.message.MessageType;
69 import info.magnolia.ui.contentapp.definition.ContentSubAppDescriptor;
70 import info.magnolia.ui.contentapp.detail.DetailLocation;
71 import info.magnolia.ui.contentapp.detail.DetailSubAppDescriptor;
72 import info.magnolia.ui.contentapp.detail.DetailView;
73 import info.magnolia.ui.framework.app.BaseSubApp;
74 import info.magnolia.ui.vaadin.editor.PageEditorListener;
75 import info.magnolia.ui.vaadin.editor.pagebar.PageBarView;
76 import info.magnolia.ui.vaadin.gwt.client.shared.AbstractElement;
77 import info.magnolia.ui.vaadin.gwt.client.shared.AreaElement;
78 import info.magnolia.ui.vaadin.gwt.client.shared.PageElement;
79 import info.magnolia.ui.vaadin.integration.contentconnector.ContentConnector;
80 import info.magnolia.ui.vaadin.integration.contentconnector.JcrContentConnector;
81 import info.magnolia.ui.vaadin.integration.jcr.JcrNewNodeItemId;
82 import info.magnolia.ui.workbench.StatusBarView;
83
84 import java.util.Arrays;
85 import java.util.Collections;
86 import java.util.List;
87 import java.util.Locale;
88 import java.util.Map;
89
90 import javax.inject.Inject;
91 import javax.inject.Named;
92 import javax.jcr.Node;
93 import javax.jcr.RepositoryException;
94 import javax.jcr.Session;
95
96 import org.apache.commons.lang3.ObjectUtils;
97 import org.apache.commons.lang3.StringUtils;
98 import org.slf4j.Logger;
99 import org.slf4j.LoggerFactory;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 public class PagesEditorSubApp extends BaseSubApp<PagesEditorSubAppView> implements PagesEditorSubAppView.Listener, ActionbarPresenter.Listener, PageEditorPresenter.Listener {
119
120 private static final Logger log = LoggerFactory.getLogger(PagesEditorSubApp.class);
121
122 protected static final String PROPERTY_TITLE = "title";
123
124 private final ActionExecutor actionExecutor;
125 private final SubAppContext subAppContext;
126 private final PagesEditorSubAppView view;
127 private final EventBus subAppEventBus;
128 private final EventBus admincentralEventBus;
129 private final PageEditorPresenter pageEditorPresenter;
130 private final ActionbarPresenter actionbarPresenter;
131 private final JcrContentConnector contentConnector;
132 private final AvailabilityChecker availabilityChecker;
133 private final StatusBarPresenter statusBar;
134 private final PageBarPresenter pageBar;
135 private final String workspace;
136 private final AppContext appContext;
137 private final VersionManager versionManager;
138 private final SimpleTranslator i18n;
139
140 private String caption;
141
142 @Inject
143 public PagesEditorSubApp(final ActionExecutor actionExecutor, final SubAppContext subAppContext, final PagesEditorSubAppView view, @Named(AdmincentralEventBus.NAME) EventBus admincentralEventBus,
144 final @Named(SubAppEventBus.NAME) EventBus subAppEventBus, final PageEditorPresenter pageEditorPresenter, final ActionbarPresenter actionbarPresenter, VersionManager versionManager, final SimpleTranslator i18n, AvailabilityChecker availabilityChecker,
145 ContentConnector contentConnector, StatusBarPresenter statusBar, PageBarPresenter pageBar) {
146 super(subAppContext, view);
147 this.actionExecutor = actionExecutor;
148 this.subAppContext = subAppContext;
149 this.view = view;
150 this.subAppEventBus = subAppEventBus;
151 this.admincentralEventBus = admincentralEventBus;
152 this.pageEditorPresenter = pageEditorPresenter;
153 this.actionbarPresenter = actionbarPresenter;
154 this.availabilityChecker = availabilityChecker;
155 this.statusBar = statusBar;
156 this.pageBar = pageBar;
157 this.contentConnector = (JcrContentConnector) contentConnector;
158 this.workspace = this.contentConnector.getContentConnectorDefinition().getWorkspace();
159 this.appContext = subAppContext.getAppContext();
160 this.versionManager = versionManager;
161 this.i18n = i18n;
162 bindHandlers();
163 }
164
165
166
167
168 @Deprecated
169 public PagesEditorSubApp(final ActionExecutor actionExecutor, final SubAppContext subAppContext, final PagesEditorSubAppView view, @Named(AdmincentralEventBus.NAME) EventBus admincentralEventBus,
170 final @Named(SubAppEventBus.NAME) EventBus subAppEventBus, final PageEditorPresenter pageEditorPresenter, final ActionbarPresenter actionbarPresenter, final PageBarView pageBarView,
171 I18NAuthoringSupport i18NAuthoringSupport, I18nContentSupport i18nContentSupport, VersionManager versionManager, final SimpleTranslator i18n, AvailabilityChecker availabilityChecker,
172 ContentConnector contentConnector, StatusBarView statusBarView) {
173 this(actionExecutor, subAppContext, view, admincentralEventBus, subAppEventBus, pageEditorPresenter, actionbarPresenter, versionManager, i18n, availabilityChecker, contentConnector, Components.getComponent(StatusBarPresenter.class), Components.getComponent(PageBarPresenter.class));
174 }
175
176 @Override
177 public String getCaption() {
178 return caption;
179 }
180
181 public void updateCaption(DetailLocation location) {
182 this.caption = getPageTitle(location);
183 pageBar.setPageName(caption, location.getNodePath());
184 }
185
186 @Override
187 public void updateCaptionForExternalPage(String title) {
188 this.caption = title;
189 pageBar.setPageName(caption);
190 }
191
192 @Override
193 public PagesEditorSubAppView start(Location location) {
194 view.setListener(this);
195
196 DetailLocation detailLocation = DetailLocation.wrap(location);
197 super.start(detailLocation);
198
199 ActionbarDefinition actionbarDefinition = ((ContentSubAppDescriptor) getSubAppContext().getSubAppDescriptor()).getActionbar();
200 Map<String, ActionDefinition> actionDefinitions = getSubAppContext().getSubAppDescriptor().getActions();
201 actionbarPresenter.setListener(this);
202 ActionbarView actionbar = actionbarPresenter.start(actionbarDefinition, actionDefinitions);
203 hideActionbarSections();
204
205 updateCaption(detailLocation);
206
207 pageEditorPresenter.setListener(this);
208 view.setActionbarView(actionbar);
209 view.setPageBarView(pageBar.start(detailLocation));
210 view.setPageEditorView(pageEditorPresenter.start(detailLocation));
211 view.setStatusBarView(statusBar.start(detailLocation));
212
213 return view;
214 }
215
216
217
218
219
220 protected void updateNodePath(String path) {
221 DetailLocation detailLocation = getCurrentLocation();
222 detailLocation.updateNodePath(path);
223 updateLocationDependentComponents(detailLocation);
224 getAppContext().updateSubAppLocation(getSubAppContext(), detailLocation);
225 pageEditorPresenter.getStatus().setNodePath(path);
226 pageEditorPresenter.updateParameters();
227 }
228
229 @Override
230 public boolean supportsLocation(Location location) {
231 return getCurrentLocation().getNodePath().equals(DetailLocation.wrap(location).getNodePath());
232 }
233
234
235
236
237 @Override
238 public DetailLocation getCurrentLocation() {
239 return DetailLocation.wrap(super.getCurrentLocation());
240 }
241
242 @Override
243 public void deactivateComponents() {
244 updateActionbar();
245 pageBar.deactivateExtensions();
246 statusBar.deactivateExtensions();
247 }
248
249 @Override
250 public void locationChanged(Location location) {
251 DetailLocation itemLocation = DetailLocation.wrap(location);
252 super.locationChanged(itemLocation);
253
254 if (pageEditorPresenter.getStatus().isLocationChanged(itemLocation)) {
255 pageEditorPresenter.reload(itemLocation);
256 updateLocationDependentComponents(itemLocation);
257 }
258 }
259
260 private void updateLocationDependentComponents(DetailLocation location) {
261 pageBar.onLocationUpdate(location);
262 statusBar.onLocationUpdate(location);
263 updateCaption(location);
264 }
265
266 private String getPageTitle(DetailLocation location) {
267 String caption = StringUtils.EMPTY;
268 try {
269 Session session = MgnlContext.getJCRSession(workspace);
270 Node node = session.getNode(location.getNodePath());
271 if (StringUtils.isNotBlank(location.getVersion())) {
272 node = versionManager.getVersion(node, location.getVersion());
273 caption = i18n.translate("subapp.versioned_page", PropertyUtil.getString(node, PROPERTY_TITLE, node.getName()), location.getVersion());
274 } else {
275 caption = PropertyUtil.getString(node, PROPERTY_TITLE, node.getName());
276 }
277
278 } catch (RepositoryException e) {
279 log.warn("Could not set page Tab Title for item : {}", location.getNodePath(), e);
280 }
281 return caption;
282 }
283
284 private void bindHandlers() {
285
286 admincentralEventBus.addHandler(ContentChangedEvent.class, new ContentChangedEvent.Handler() {
287
288 @Override
289 public void onContentChanged(ContentChangedEvent event) {
290 if (contentConnector.canHandleItem(event.getItemId())) {
291
292 try {
293 String currentNodePath = getCurrentLocation().getNodePath();
294 if (!MgnlContext.getJCRSession(RepositoryConstants.WEBSITE).nodeExists(currentNodePath)) {
295 getSubAppContext().close();
296 }
297 } catch (RepositoryException e) {
298 log.warn("Could not determine if currently edited page exists", e);
299 }
300 }
301 }
302 });
303
304 subAppEventBus.addHandler(ContentChangedEvent.class, new ContentChangedEvent.Handler() {
305
306 @Override
307 public void onContentChanged(ContentChangedEvent event) {
308
309 Locale authoringLocale = subAppContext.getAuthoringLocale();
310 if (authoringLocale != null && ObjectUtils.notEqual(authoringLocale, pageEditorPresenter.getStatus().getLocale())) {
311 updateLocationDependentComponents(getCurrentLocation());
312
313 pageEditorPresenter.loadPageEditor();
314 } else {
315 pageEditorPresenter.refresh();
316 }
317 }
318 });
319
320 subAppEventBus.addHandler(NodeSelectedEvent.class, new NodeSelectedEvent.Handler() {
321
322 @Override
323 public void onItemSelected(NodeSelectedEvent event) {
324 AbstractElement element = event.getElement();
325 if (element instanceof PageElement) {
326 String path = element.getPath();
327 if (StringUtils.isEmpty(path)) {
328 path = "/";
329 }
330 if (!path.equals(getCurrentLocation().getNodePath())) {
331 updateNodePath(path);
332 }
333 }
334 updateActionbar();
335 }
336 });
337
338 }
339
340 @Override
341 public void onActionbarItemClicked(String actionName) {
342 prepareAndExecutePagesEditorAction(actionName);
343 }
344
345 protected void prepareAndExecutePagesEditorAction(String actionName) {
346 AbstractElement selectedElement = pageEditorPresenter.getSelectedElement();
347 if (selectedElement == null) {
348 log.warn("Trying to execute action [{}] but no element was selected. Was the page actually loaded?", actionName);
349 return;
350 }
351 try {
352 Object itemId = getItemId(selectedElement);
353 actionExecutor.execute(actionName, contentConnector.getItem(itemId), selectedElement, pageEditorPresenter);
354 } catch (ActionExecutionException e) {
355 Message error = new Message(MessageType.ERROR, i18n.translate("pages.pagesEditorSubapp.actionExecutionException.message"), e.getMessage());
356 log.error("An error occurred while executing action [{}]", actionName, e);
357 appContext.sendLocalMessage(error);
358 }
359 }
360
361 public void updateActionbar() {
362 Object itemId = getItemId(pageEditorPresenter.getSelectedElement());
363
364
365
366 List<ActionbarSectionDefinition> sections = getSections();
367 ActionbarSectionDefinition sectionDefinition = getVisibleSection(sections, itemId);
368
369
370 for (ActionbarSectionDefinition section : sections) {
371 actionbarPresenter.hideSection(section.getName());
372 }
373
374 if (sectionDefinition != null) {
375
376 actionbarPresenter.showSection(sectionDefinition.getName());
377
378
379 for (ActionbarGroupDefinition groupDefinition : sectionDefinition.getGroups()) {
380 for (ActionbarItemDefinition itemDefinition : groupDefinition.getItems()) {
381
382 String actionName = itemDefinition.getName();
383 ActionDefinition actionDefinition = actionExecutor.getActionDefinition(actionName);
384 if (actionDefinition != null) {
385 AvailabilityDefinition availability = actionDefinition.getAvailability();
386 if (availabilityChecker.isAvailable(availability, Arrays.asList(itemId))) {
387 actionbarPresenter.enable(actionName);
388 } else {
389 actionbarPresenter.disable(actionName);
390 }
391 }
392 }
393 }
394 }
395 }
396
397 private Object getItemId(AbstractElement element) {
398 if (element == null) {
399 return null;
400 }
401 else if (element instanceof AreaElement && ((AreaElement) element).isOptional() && !((AreaElement) element).isCreated()) {
402
403 try {
404 int index = element.getPath().lastIndexOf("/");
405 String parentPath = element.getPath().substring(0, index);
406 String relPath = element.getPath().substring(index + 1);
407
408 Node parent = MgnlContext.getJCRSession(getWorkspace()).getNode(parentPath);
409
410 JcrNewNodeItemId jcrNewNodeItemId = new JcrNewNodeItemId(parent.getIdentifier(), getWorkspace(), NodeTypes.Area.NAME);
411 jcrNewNodeItemId.setName(Path.getUniqueLabel(parent, relPath));
412 return jcrNewNodeItemId;
413 } catch (RepositoryException e) {
414 log.error("Failed to create new jcr node item id: " + e.getMessage(), e);
415 }
416 return null;
417 }
418 else {
419 return contentConnector.getItemIdByUrlFragment(element.getPath());
420 }
421 }
422
423 private List<ActionbarSectionDefinition> getSections() {
424 DetailSubAppDescriptor subAppDescriptor = (DetailSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
425 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
426 if (actionbarDefinition == null) {
427 return Collections.emptyList();
428 }
429 return actionbarDefinition.getSections();
430 }
431
432 private void hideActionbarSections() {
433 for (ActionbarSectionDefinition sectionDefinition : getSections()) {
434 actionbarPresenter.hideSection(sectionDefinition.getName());
435 }
436 }
437
438 private ActionbarSectionDefinition getVisibleSection(List<ActionbarSectionDefinition> sections, Object itemId) {
439 for (ActionbarSectionDefinition section : sections) {
440 if (availabilityChecker.isAvailable(section.getAvailability(), Arrays.asList(itemId)))
441 return section;
442 }
443 return null;
444 }
445
446 @Override
447 public void onEscape() {
448 if (pageEditorPresenter.isMoving()) {
449 pageEditorPresenter.onAction(PageEditorListener.ACTION_CANCEL_MOVE_COMPONENT);
450 } else {
451
452 if (getCurrentLocation().getViewType().equals(DetailView.ViewType.EDIT)) {
453 prepareAndExecutePagesEditorAction(PageEditorListener.ACTION_VIEW_PREVIEW);
454 } else {
455 prepareAndExecutePagesEditorAction(PageEditorListener.ACTION_VIEW_EDIT);
456 }
457 }
458 }
459
460 protected String getWorkspace() {
461 return workspace;
462 }
463
464 @Override
465 public void onMove() {
466 updateActionbar();
467 }
468
469 @Override
470 public void stop() {
471 pageBar.stop();
472 statusBar.stop();
473 }
474 }