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.ui.form.field.factory;
35
36 import info.magnolia.annotation.deprecation.MgnlDeprecated;
37 import info.magnolia.config.registry.DefinitionProvider;
38 import info.magnolia.objectfactory.ComponentProvider;
39 import info.magnolia.objectfactory.Components;
40 import info.magnolia.ui.api.app.AppContext;
41 import info.magnolia.ui.api.app.AppController;
42 import info.magnolia.ui.api.app.AppDescriptor;
43 import info.magnolia.ui.api.app.ChooseDialogCallback;
44 import info.magnolia.ui.api.app.SubAppContext;
45 import info.magnolia.ui.api.app.contenttypes.ContentTypeAppDescriptor;
46 import info.magnolia.ui.api.app.registry.AppDescriptorRegistry;
47 import info.magnolia.ui.api.context.UiContext;
48 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
49 import info.magnolia.ui.form.field.LinkField;
50 import info.magnolia.ui.form.field.component.ContentPreviewComponent;
51 import info.magnolia.ui.form.field.converter.IdentifierToPathConverter;
52 import info.magnolia.ui.form.field.converter.Vaadin7FieldValueConverterAdapter;
53 import info.magnolia.ui.form.field.definition.LinkFieldDefinition;
54 import info.magnolia.ui.vaadin.integration.jcr.JcrItemId;
55 import info.magnolia.ui.vaadin.integration.jcr.JcrItemUtil;
56
57 import java.util.Objects;
58 import java.util.Optional;
59
60 import javax.inject.Inject;
61 import javax.jcr.Node;
62 import javax.jcr.RepositoryException;
63
64 import org.apache.commons.lang3.StringUtils;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 import com.vaadin.ui.Button;
69 import com.vaadin.v7.data.Item;
70 import com.vaadin.v7.data.Property;
71 import com.vaadin.v7.ui.Field;
72
73
74
75
76
77
78
79 @MgnlDeprecated(since = "6.0")
80 public class LinkFieldFactory<D extends LinkFieldDefinition> extends AbstractFieldFactory<D, String> {
81
82 private static final Logger log = LoggerFactory.getLogger(LinkFieldFactory.class);
83
84 public static final String PATH_PROPERTY_NAME = "transientPathProperty";
85 public static final String SELF_APP_REFERENCE = "self";
86 public static final String CONTENT_TYPE_REFERENCE_PREFIX = "ct:";
87
88 private final AppController appController;
89 private final UiContext uiContext;
90 private final AppDescriptorRegistry appRegistry;
91
92 private ComponentProvider componentProvider;
93 private LinkField linkField;
94
95
96 @Inject
97 public LinkFieldFactory(D definition, Item relatedFieldItem, UiContext uiContext, I18NAuthoringSupport i18nAuthoringSupport, AppController appController, ComponentProvider componentProvider, AppDescriptorRegistry appRegistry) {
98 super(definition, relatedFieldItem, uiContext, i18nAuthoringSupport);
99 this.appController = appController;
100 this.uiContext = uiContext;
101 this.componentProvider = componentProvider;
102 this.appRegistry = appRegistry;
103 }
104
105
106
107
108 @Deprecated
109 public LinkFieldFactory(D definition, Item relatedFieldItem, UiContext uiContext, I18NAuthoringSupport i18nAuthoringSupport, AppController appController, ComponentProvider componentProvider) {
110 this(definition, relatedFieldItem, uiContext, i18nAuthoringSupport, appController, componentProvider, Components.getComponent(AppDescriptorRegistry.class));
111 }
112
113 @Override
114 public void setComponentProvider(ComponentProvider componentProvider) {
115 super.setComponentProvider(componentProvider);
116 this.componentProvider = componentProvider;
117 }
118
119 @Override
120 protected Field<String> createFieldComponent() {
121 linkField = new LinkField();
122
123 linkField.setButtonCaptionNew(isMessageKey(definition.getButtonSelectNewLabel()) ? definition.getButtonSelectNewDefaultLabel() : definition.getButtonSelectNewLabel());
124 linkField.setButtonCaptionOther(isMessageKey(definition.getButtonSelectOtherLabel()) ? definition.getButtonSelectOtherDefaultLabel() : definition.getButtonSelectOtherLabel());
125 linkField.getSelectButton().setDisableOnClick(true);
126
127 linkField.getSelectButton().addClickListener(createButtonClickListener());
128 linkField.setFieldEditable(definition.isFieldEditable());
129
130 IdentifierToPathConverter converter = definition.getIdentifierToPathConverter();
131 if (converter != null) {
132 converter.setWorkspaceName(definition.getTargetWorkspace());
133 linkField.setTextFieldConverter(Vaadin7FieldValueConverterAdapter.wrap(converter));
134 }
135
136
137 if (definition.getContentPreviewDefinition() != null && definition.getContentPreviewDefinition().getContentPreviewClass() != null) {
138 final ContentPreviewComponent<?> contentPreviewComponent = componentProvider.newInstance(definition.getContentPreviewDefinition().getContentPreviewClass(), definition.getTargetWorkspace());
139 linkField.getTextField().addValueChangeListener((Property.ValueChangeListener) event -> {
140 String itemReference = Objects.toString(event.getProperty().getValue(), StringUtils.EMPTY);
141 contentPreviewComponent.onValueChange(itemReference);
142 contentPreviewComponent.setVisible(StringUtils.isNotBlank(itemReference));
143 });
144 contentPreviewComponent.onValueChange(linkField.getValue());
145 contentPreviewComponent.setVisible(StringUtils.isNotBlank(linkField.getValue()));
146 linkField.setContentPreview(contentPreviewComponent);
147 }
148
149 String placeholder = definition.getPlaceholder();
150 if (placeholder != null && !isMessageKey(placeholder)) {
151 linkField.getTextField().setInputPrompt(placeholder);
152 }
153
154 return linkField;
155 }
156
157
158
159
160
161 private Button.ClickListener createButtonClickListener() {
162 return (Button.ClickListener) event -> {
163 ChooseDialogCallback callback = createChooseDialogCallback();
164 String value = linkField.getTextField().getValue();
165
166 String appName = definition.getAppName();
167 if (SELF_APP_REFERENCE.equalsIgnoreCase(appName)) {
168 appName = resolveCurrentAppName().orElse(appName);
169 } else if (StringUtils.startsWith(appName, CONTENT_TYPE_REFERENCE_PREFIX)) {
170 appName = resolveContentTypeAppName(appName).orElse(appName);
171 }
172 if (StringUtils.isNotBlank(definition.getTargetTreeRootPath())) {
173 appController.openChooseDialog(appName, uiContext, definition.getTargetTreeRootPath(), value, callback);
174 } else {
175 appController.openChooseDialog(appName, uiContext, value, callback);
176 }
177 };
178 }
179
180 private Optional<String> resolveCurrentAppName() {
181 if (uiContext instanceof SubAppContext) {
182 return Optional.of(((SubAppContext) uiContext).getAppContext().getName());
183 } else if (uiContext instanceof AppContext) {
184 return Optional.ofNullable(((AppContext) uiContext).getName());
185 }
186
187 log.warn("Attempting to resolve linkField '{}' appName self-reference without actually being in an app", definition.getName());
188 return Optional.empty();
189 }
190
191 private Optional<String> resolveContentTypeAppName(String appName) {
192 String contentType = StringUtils.removeStart(appName, CONTENT_TYPE_REFERENCE_PREFIX);
193
194 return appRegistry.getAllProviders().stream()
195 .filter(DefinitionProvider::isValid)
196 .map(DefinitionProvider::get)
197 .filter(ContentTypeAppDescriptor.class::isInstance)
198 .map(ContentTypeAppDescriptor.class::cast)
199 .filter(appDescriptor -> StringUtils.equalsIgnoreCase(contentType, appDescriptor.getContentType()))
200 .findFirst()
201 .map(AppDescriptor::getName);
202 }
203
204
205
206
207 protected ChooseDialogCallback createChooseDialogCallback() {
208 return new ChooseDialogCallback() {
209
210 @Override
211 public void onItemChosen(String actionName, final Object chosenValue) {
212 String newValue = null;
213 if (chosenValue instanceof JcrItemId) {
214 String propertyName = definition.getTargetPropertyToPopulate();
215 try {
216 javax.jcr.Item jcrItem = JcrItemUtil.getJcrItem((JcrItemId) chosenValue);
217 if (jcrItem.isNode()) {
218 final Node selected = (Node) jcrItem;
219 boolean isPropertyExisting = StringUtils.isNotBlank(propertyName) && selected.hasProperty(propertyName);
220 newValue = isPropertyExisting ? selected.getProperty(propertyName).getString() : selected.getPath();
221 }
222 } catch (RepositoryException e) {
223 log.error("Not able to access the configured property. Value will not be set.", e);
224 }
225 } else {
226 newValue = String.valueOf(chosenValue);
227 }
228 linkField.setValue(newValue);
229 linkField.getSelectButton().setEnabled(true);
230 }
231
232 @Override
233 public void onCancel() {
234 linkField.getSelectButton().setEnabled(true);
235 }
236 };
237 }
238 }