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