Package: DefaultContentEditorPresentationControl
DefaultContentEditorPresentationControl
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DefaultContentEditorPresentationControl(EmbeddedServer, ContentEditorPresentation) |
|
|
|
|
|
||||||||||||||||||||
afterPropertiesSet() |
|
|
|
|
|
||||||||||||||||||||
bindProperties(ResourceProperties) |
|
|
|
|
|
||||||||||||||||||||
bindPropertiesAndLoadDocument(ResourceProperties) |
|
|
|
|
|
||||||||||||||||||||
destroy() |
|
|
|
|
|
||||||||||||||||||||
fix(ResourceProperties, String) |
|
|
|
|
|
||||||||||||||||||||
initialize() |
|
|
|
|
|
||||||||||||||||||||
lambda$new$0(ResourceProperties) |
|
|
|
|
|
||||||||||||||||||||
lambda$openExternalEditor$2(String, ResourceProperties) |
|
|
|
|
|
||||||||||||||||||||
lambda$openExternalEditor$3(String) |
|
|
|
|
|
||||||||||||||||||||
lambda$openExternalEditorBrowser$1() |
|
|
|
|
|
||||||||||||||||||||
onContentSelected(ContentSelectedEvent) |
|
|
|
|
|
||||||||||||||||||||
openExternalEditor() |
|
|
|
|
|
||||||||||||||||||||
openExternalEditorBrowser() |
|
|
|
|
|
||||||||||||||||||||
static {...} |
|
|
|
|
|
||||||||||||||||||||
unbindProperties() |
|
|
|
|
|
Coverage
1: /*
2: * #%L
3: * *********************************************************************************************************************
4: *
5: * NorthernWind - lightweight CMS
6: * http://northernwind.tidalwave.it - git clone git@bitbucket.org:tidalwave/northernwind-rca-src.git
7: * %%
8: * Copyright (C) 2013 - 2021 Tidalwave s.a.s. (http://tidalwave.it)
9: * %%
10: * *********************************************************************************************************************
11: *
12: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
13: * the License. You may obtain a copy of the License at
14: *
15: * http://www.apache.org/licenses/LICENSE-2.0
16: *
17: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
18: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
19: * specific language governing permissions and limitations under the License.
20: *
21: * *********************************************************************************************************************
22: *
23: *
24: * *********************************************************************************************************************
25: * #L%
26: */
27: package it.tidalwave.northernwind.rca.ui.contenteditor.spi;
28:
29: import javax.annotation.Nonnull;
30: import java.util.Optional;
31: import java.io.IOException;
32: import java.nio.file.Files;
33: import java.nio.file.Path;
34: import java.nio.file.Paths;
35: import it.tidalwave.role.ui.BoundProperty;
36: import it.tidalwave.role.ui.UserAction;
37: import it.tidalwave.messagebus.annotation.ListensTo;
38: import it.tidalwave.messagebus.annotation.SimpleMessageSubscriber;
39: import it.tidalwave.northernwind.core.model.Content;
40: import it.tidalwave.northernwind.core.model.ResourceProperties;
41: import it.tidalwave.northernwind.rca.embeddedserver.EmbeddedServer;
42: import it.tidalwave.northernwind.rca.embeddedserver.EmbeddedServer.Document;
43: import it.tidalwave.northernwind.rca.ui.event.ContentSelectedEvent;
44: import it.tidalwave.northernwind.rca.ui.contenteditor.ContentEditorPresentation;
45: import it.tidalwave.northernwind.rca.ui.contenteditor.ContentEditorPresentation.Bindings;
46: import it.tidalwave.northernwind.rca.ui.contenteditor.ContentEditorPresentationControl;
47: import it.tidalwave.northernwind.rca.ui.contenteditor.impl.JSoupXhtmlNormalizer;
48: import it.tidalwave.northernwind.rca.ui.contenteditor.impl.ProcessExecutor;
49: import it.tidalwave.util.annotation.VisibleForTesting;
50: import lombok.RequiredArgsConstructor;
51: import lombok.extern.slf4j.Slf4j;
52: import static it.tidalwave.northernwind.model.admin.Properties.*;
53: import static it.tidalwave.northernwind.model.admin.role.Saveable._Saveable_;
54: import static it.tidalwave.northernwind.rca.ui.contenteditor.spi.PropertyBinder.*;
55: import static it.tidalwave.role.ui.Presentable._Presentable_;
56: import static java.nio.charset.StandardCharsets.UTF_8;
57: import static java.util.Arrays.asList;
58: import static java.util.stream.Collectors.joining;
59:
60: /***********************************************************************************************************************
61: *
62: * A default implementation of the {@link ContentEditorPresentationControl}.
63: *
64: * @stereotype Control
65: *
66: * @author Fabrizio Giudici
67: *
68: **********************************************************************************************************************/
69:•@RequiredArgsConstructor @SimpleMessageSubscriber @Slf4j
70: public class DefaultContentEditorPresentationControl implements ContentEditorPresentationControl
71: {
72: @Nonnull
73: private final EmbeddedServer documentServer;
74:
75: @Nonnull
76: private final ContentEditorPresentation presentation;
77:
78: @Nonnull
79: private Optional<Content> content = Optional.empty();
80:
81: @Nonnull
82: private Optional<ResourceProperties> properties = Optional.empty();
83:
84: @VisibleForTesting final Bindings bindings = Bindings.builder()
85: .openExternalEditorAction(UserAction.of(this::openExternalEditor))
86: .openExternalEditorBrowserAction(UserAction.of(this::openExternalEditorBrowser))
87: .title(new BoundProperty<>(""))
88: .build();
89:
90: /*******************************************************************************************************************
91: *
92: *
93: *
94: ******************************************************************************************************************/
95: @VisibleForTesting final UpdateCallback propertyUpdateCallback = (updatedProperties) ->
96: {
97: updatedProperties.as(_Saveable_).saveIn(content.get().getFile());
98: unbindProperties();
99: properties = content.map(Content::getProperties); // reload them
100: // FIXME: properties have to be re-bound, since they have been reloaded - but this makes the HTML editor
101: // to flicker and the caret in text editor to reset at position 0 - and to loop forever
102: properties.ifPresent(this::bindProperties);
103: };
104:
105: /*******************************************************************************************************************
106: *
107: * {@inheritDoc}
108: *
109: ******************************************************************************************************************/
110: @Override
111: public void initialize()
112: {
113: presentation.bind(bindings);
114: }
115:
116: // FIXME: unbind at termination
117:
118: /*******************************************************************************************************************
119: *
120: * {@inheritDoc}
121: *
122: ******************************************************************************************************************/
123: @VisibleForTesting void onContentSelected (@ListensTo @Nonnull final ContentSelectedEvent selectionEvent)
124: {
125: log.debug("onContentSelected({})", selectionEvent);
126:
127: unbindProperties();
128: content = selectionEvent.getContent();
129: properties = content.map(Content::getProperties); // reload them
130:
131:• if (content.isEmpty())
132: {
133: presentation.clear();
134: }
135: else
136: {
137: presentation.showUp();
138: }
139:
140: properties.ifPresent(this::bindPropertiesAndLoadDocument);
141: }
142:
143: /*******************************************************************************************************************
144: *
145: *
146: *
147: ******************************************************************************************************************/
148: private void bindPropertiesAndLoadDocument (@Nonnull final ResourceProperties properties)
149: {
150: bindProperties(properties);
151: final PropertyBinder propertyBinder = properties.as(_PropertyBinder_);
152: final Document document = propertyBinder.createBoundDocument(PROPERTY_FULL_TEXT, propertyUpdateCallback);
153: presentation.populateDocument(documentServer.putDocument("/", document));
154: }
155:
156: /*******************************************************************************************************************
157: *
158: *
159: *
160: ******************************************************************************************************************/
161: private void bindProperties (@Nonnull final ResourceProperties properties)
162: {
163:• assert properties != null;
164: presentation.bind(bindings); // FIXME: needed because of unbindAll()
165: final PropertyBinder propertyBinder = properties.as(_PropertyBinder_);
166: propertyBinder.bind(PROPERTY_TITLE, bindings.title, propertyUpdateCallback);
167: presentation.populateProperties(properties.as(_Presentable_).createPresentationModel());
168: // presentation.populateProperties(PresentationModel.ofMaybePresentable(properties));
169: }
170:
171: /*******************************************************************************************************************
172: *
173: *
174: *
175: ******************************************************************************************************************/
176: private void unbindProperties()
177: {
178: bindings.title.unbindAll();
179: }
180:
181: /*******************************************************************************************************************
182: *
183: *
184: *
185: ******************************************************************************************************************/
186: private void openExternalEditorBrowser()
187: {
188: log.info("openExternalEditorBrowser");
189: // FIXME
190: final String url = "http://localhost:12345/";
191:
192: // Safari breaks Aloha editor
193: ProcessExecutor.forExecutable("Google Chrome.app")
194: .withArguments2(url)
195: .withPostMortemTask(() -> properties.ifPresent(this::bindPropertiesAndLoadDocument))
196: .execute();
197: }
198:
199: /*******************************************************************************************************************
200: *
201: *
202: *
203: ******************************************************************************************************************/
204: private void openExternalEditor()
205: {
206: log.info("openExternalEditor");
207: final String filePath = content.get().getFile().toFile().getAbsolutePath() + "/fullText_en.xhtml";
208:
209: ProcessExecutor.forExecutable("BlueGriffon.app")
210: // FIXME
211: // .withArguments2(content.get().getFile().getPath().asString())
212: .withArguments2(filePath)
213: .withPostMortemTask(() -> properties.ifPresent(p -> fix(p, filePath)))
214: .execute();
215: }
216:
217: /*******************************************************************************************************************
218: *
219: *
220: *
221: ******************************************************************************************************************/
222: private void fix (@Nonnull final ResourceProperties properties, @Nonnull final String filePath)
223: {
224: try
225: {
226: final Path path = Paths.get(filePath);
227: final String s = Files.lines(path, UTF_8).collect(joining("\n"))
228: .replace("%27", "'")
229: .replace("%28", "(")
230: .replace("%29", ")")
231: .replace("%7B", "{")
232: .replace("%7D", "}")
233: .replace("%20", " ");
234: final JSoupXhtmlNormalizer normalizer = new JSoupXhtmlNormalizer();
235: Files.write(path, asList(normalizer.asNormalizedString(s)), UTF_8);
236: bindPropertiesAndLoadDocument(properties);
237: }
238: catch (IOException e)
239: {
240: log.error("", e);
241: }
242: }
243: }