Refactoring of Assets Forms WARNING: Does not compile!

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@6151 8810af33-2d31-482b-a856-94f89814c4df
ccm-docs
jensp 2019-07-25 09:36:14 +00:00
parent 874c8d9543
commit e84d3283df
19 changed files with 1130 additions and 516 deletions

View File

@ -43,18 +43,15 @@ import com.arsdigita.kernel.KernelConfig;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.contentsection.Asset; import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetRepository;
import java.util.Optional;
import org.libreccm.core.UnexpectedErrorException; import org.libreccm.core.UnexpectedErrorException;
import org.librecms.assets.AssetL10NManager;
import org.librecms.contentsection.AssetManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Map;
import java.util.TooManyListenersException; import java.util.TooManyListenersException;
/** /**
@ -111,15 +108,15 @@ public abstract class AbstractAssetForm<T extends Asset>
@Override @Override
public void prepare(final PrintEvent event) { public void prepare(final PrintEvent event) {
final PageState state = event.getPageState(); final PageState state = event.getPageState();
final Optional<T> selectedAsset = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
final Label target = (Label) event.getTarget(); final Label target = (Label) event.getTarget();
if (selectedAsset.isPresent()) { if (selectedAssetId == null) {
target.setLabel(new GlobalizedMessage( target.setLabel(new GlobalizedMessage(
"cms.ui.asset.show_locale", "cms.ui.asset.initial_locale",
CmsConstants.CMS_BUNDLE)); CmsConstants.CMS_BUNDLE));
} else { } else {
target.setLabel(new GlobalizedMessage( target.setLabel(new GlobalizedMessage(
"cms.ui.asset.initial_locale", "cms.ui.asset.show_locale",
CmsConstants.CMS_BUNDLE)); CmsConstants.CMS_BUNDLE));
} }
} }
@ -133,26 +130,8 @@ public abstract class AbstractAssetForm<T extends Asset>
public void prepare(final PrintEvent event) { public void prepare(final PrintEvent event) {
final PageState state = event.getPageState(); final PageState state = event.getPageState();
final Optional<T> selectedAsset = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
if (selectedAsset.isPresent()) { if (selectedAssetId == null) {
final SingleSelect target = (SingleSelect) event
.getTarget();
target.clearOptions();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AbstractAssetFormController controller = cdiUtil
.findBean(AbstractAssetFormController.class);
final List<Locale> availableLocales = controller
.availableLocales(selectedAsset.get());
availableLocales.sort((locale1, locale2) -> {
return locale1.toString().compareTo(locale2
.toString());
});
availableLocales.forEach(locale -> target.addOption(
new Option(locale.toString(),
new Text(locale.toString()))));
} else {
final SingleSelect target = (SingleSelect) event final SingleSelect target = (SingleSelect) event
.getTarget(); .getTarget();
@ -165,6 +144,27 @@ public abstract class AbstractAssetForm<T extends Asset>
langs.forEach(lang -> { langs.forEach(lang -> {
target.addOption(new Option(lang, new Text(lang))); target.addOption(new Option(lang, new Text(lang)));
}); });
} else {
final SingleSelect target = (SingleSelect) event
.getTarget();
target.clearOptions();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
@SuppressWarnings("unchecked")
final AbstractAssetFormController<T> controller
= cdiUtil
.findBean(AbstractAssetFormController.class);
final List<Locale> availableLocales = controller
.availableLocales(selectedAssetId,
getAssetClass());
availableLocales.sort((locale1, locale2) -> {
return locale1.toString().compareTo(locale2
.toString());
});
availableLocales.forEach(locale -> target.addOption(
new Option(locale.toString(),
new Text(locale.toString()))));
} }
} }
@ -178,7 +178,7 @@ public abstract class AbstractAssetForm<T extends Asset>
@Override @Override
public boolean isVisible(final PageState state) { public boolean isVisible(final PageState state) {
return getSelectedAsset(state).isPresent(); return getSelectedAssetId(state) != null;
} }
}; };
@ -191,7 +191,7 @@ public abstract class AbstractAssetForm<T extends Asset>
@Override @Override
public boolean isVisible(final PageState state) { public boolean isVisible(final PageState state) {
return getSelectedAsset(state).isPresent(); return getSelectedAssetId(state) != null;
} }
}; };
@ -206,19 +206,22 @@ public abstract class AbstractAssetForm<T extends Asset>
public void prepare(final PrintEvent event) { public void prepare(final PrintEvent event) {
final PageState state = event.getPageState(); final PageState state = event.getPageState();
final Optional<T> selectedAsset = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
if (selectedAsset.isPresent()) { if (selectedAssetId != null) {
final SingleSelect target = (SingleSelect) event final SingleSelect target = (SingleSelect) event
.getTarget(); .getTarget();
target.clearOptions(); target.clearOptions();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AbstractAssetFormController controller = cdiUtil @SuppressWarnings("unchecked")
.findBean(AbstractAssetFormController.class); final AbstractAssetFormController<T> controller
= cdiUtil
.findBean(AbstractAssetFormController.class);
final List<Locale> creatableLocales = controller final List<Locale> creatableLocales = controller
.creatableLocales(selectedAsset.get()); .creatableLocales(selectedAssetId,
getAssetClass());
creatableLocales.sort((locale1, locale2) -> { creatableLocales.sort((locale1, locale2) -> {
return locale1 return locale1
.toString() .toString()
@ -270,31 +273,13 @@ public abstract class AbstractAssetForm<T extends Asset>
return (String) title.getValue(state); return (String) title.getValue(state);
} }
@SuppressWarnings("unchecked") protected Long getSelectedAssetId(final PageState state) {
protected Optional<T> getSelectedAsset(final PageState state) {
if (selectionModel.getSelectedKey(state) == null) { final Object key = selectionModel.getSelectedKey(state);
return Optional.empty(); if (key == null) {
return null;
} else { } else {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); return (Long) key;
final AssetRepository assetRepo = cdiUtil
.findBean(AssetRepository.class);
final Asset asset = assetRepo
.findById((long) selectionModel.getSelectedKey(state))
.orElseThrow(() -> new IllegalArgumentException(String.
format("No asset with ID %d in the database.",
selectionModel.getSelectedKey(state))));
if (getAssetClass().isAssignableFrom(asset.getClass())) {
return Optional.of((T) asset);
} else {
throw new UnexpectedErrorException(String
.format(
"The requested asset is not of the type expected by "
+ "this form. Expected type is \"%s\". "
+ "Type of asset: \"%s\".",
getAssetClass().getName(),
asset.getClass().getName()));
}
} }
} }
@ -303,28 +288,36 @@ public abstract class AbstractAssetForm<T extends Asset>
final PageState state = event.getPageState(); final PageState state = event.getPageState();
final Optional<T> selectedAsset = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
if (selectedAsset.isPresent()) { final Map<String, Object> data;
if (selectedAssetId == null) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AbstractAssetFormController controller = cdiUtil
.findBean(AbstractAssetFormController.class);
showLocaleSelect.setValue(state,
getSelectedLocale(state));
title.setValue(state,
controller.getTitle(selectedAsset.get(),
getSelectedLocale(state)));
} else {
showLocaleSelect.setValue(state, showLocaleSelect.setValue(state,
KernelConfig KernelConfig
.getConfig() .getConfig()
.getDefaultLocale() .getDefaultLocale()
.toString()); .toString());
data = Collections.emptyMap();
} else {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
@SuppressWarnings("unchecked")
final AbstractAssetFormController<T> controller = cdiUtil
.findBean(AbstractAssetFormController.class);
showLocaleSelect.setValue(state,
getSelectedLocale(state));
data = controller.getAssetData(selectedAssetId,
getAssetClass(),
getSelectedLocale(state));
title.setValue(state,
data.get(AbstractAssetFormController.TITLE));
} }
initForm(state, selectedAsset); initForm(state, data);
} }
protected Locale getSelectedLocale(final PageState state) { protected Locale getSelectedLocale(final PageState state) {
@ -346,22 +339,20 @@ public abstract class AbstractAssetForm<T extends Asset>
} }
protected void initForm(final PageState state, protected void initForm(final PageState state,
final Optional<T> selectedAsset) { final Map<String, Object> data) {
if (selectedAsset.isPresent()) { if (!data.isEmpty()) {
name.setValue(state, name.setValue(state,
selectedAsset data.get(AbstractAssetFormController.DISPLAY_NAME));
.get()
.getDisplayName());
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); // final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AbstractAssetFormController controller = cdiUtil // @SuppressWarnings("unchecked")
.findBean(AbstractAssetFormController.class); // final AbstractAssetFormController<T> controller = cdiUtil
// .findBean(AbstractAssetFormController.class);
title.setValue(state, title.setValue(state,
controller.getTitle(selectedAsset.get(), data.get(AbstractAssetFormController.TITLE));
getSelectedLocale(state)));
showLocale(state); showLocale(state);
} }
} }
@ -372,66 +363,41 @@ public abstract class AbstractAssetForm<T extends Asset>
final PageState state = event.getPageState(); final PageState state = event.getPageState();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); // final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
if (showLocaleSubmit.isSelected(state)) { if (showLocaleSubmit.isSelected(state)) {
final Optional<T> selectedAsset = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
initForm(state, selectedAsset);
initForm(state,
getController().getAssetData(selectedAssetId,
getAssetClass(),
getSelectedLocale(state)));
return; return;
} }
if (addLocaleSubmit.isSelected(state)) { if (addLocaleSubmit.isSelected(state)) {
final AssetL10NManager l10nManager = cdiUtil
.findBean(AssetL10NManager.class);
final Locale add = new Locale((String) addLocaleSelect final Locale add = new Locale((String) addLocaleSelect
.getValue(state)); .getValue(state));
final Optional<T> selectedAsset = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
l10nManager.addLanguage(selectedAsset.get(), add); getController().addLocale(selectedAssetId, add, getAssetClass());
} }
if (saveCancelSection.getSaveButton().isSelected(state)) { if (saveCancelSection.getSaveButton().isSelected(state)) {
final Optional<T> selectedAsset = getSelectedAsset(state);
final Asset asset;
if (selectedAsset.isPresent()) {
asset = selectedAsset.get();
// updateAsset(asset, event);
asset.setDisplayName((String) name.getValue(state)); final Long selectedAssetId = getSelectedAssetId(state);
asset.getTitle().addValue(getSelectedLocale(state), final Map<String, Object> data = new HashMap<>();
(String) title.getValue(state)); data.put(AbstractAssetFormController.DISPLAY_NAME,
name.getValue(state));
data.put(AbstractAssetFormController.TITLE,
title.getValue(state));
data.putAll(collectData(event));
// final AssetRepository assetRepo = cdiUtil getController().updateAsset(selectedAssetId,
// .findBean(AssetRepository.class); getSelectedLocale(state),
// assetRepo.save(asset); getAssetClass(),
} else { data);
asset = createAsset(event);
updateAsset(asset, event);
}
updateAsset(asset, event);
final AssetRepository assetRepo = cdiUtil
.findBean(AssetRepository.class);
assetRepo.save(asset);
// if (!selectedAsset.isPresent()) {
// //Set display name
// asset.setDisplayName((String) title.getValue(state));
// assetRepo.save(asset);
//
// //Add new asset to currently selected folder
// final Folder selectedFolder = assetPane
// .getFolderSelectionModel()
// .getSelectedObject(state);
// final CategoryManager categoryManager = cdiUtil
// .findBean(CategoryManager.class);
// categoryManager.addObjectToCategory(
// asset,
// selectedFolder,
// CmsConstants.CATEGORIZATION_TYPE_FOLDER);
// }
assetPane.browseMode(state); assetPane.browseMode(state);
} }
} }
@ -440,27 +406,8 @@ public abstract class AbstractAssetForm<T extends Asset>
protected abstract void showLocale(final PageState state); protected abstract void showLocale(final PageState state);
protected final T createAsset(final FormSectionEvent event) protected abstract Map<String, Object> collectData(
throws FormProcessException { final FormSectionEvent event)
Objects.requireNonNull(event);
final PageState state = event.getPageState();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AssetManager assetManager = cdiUtil.findBean(AssetManager.class);
return assetManager.createAsset((String) name.getValue(state),
(String) title.getValue(state),
getSelectedLocale(state),
assetPane
.getFolderSelectionModel()
.getSelectedObject(state),
getAssetClass());
}
protected abstract void updateAsset(final Asset asset,
final FormSectionEvent event)
throws FormProcessException; throws FormProcessException;
@Override @Override
@ -475,4 +422,13 @@ public abstract class AbstractAssetForm<T extends Asset>
} }
} }
protected AssetFormController<T> getController() {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AssetFormControllers controllers = cdiUtil
.findBean(AssetFormControllers.class);
return controllers.findController(getAssetClass());
}
} }

View File

@ -23,20 +23,26 @@ import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetRepository; import org.librecms.contentsection.AssetRepository;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.transaction.Transactional; import javax.transaction.Transactional;
/** /**
* An base class for implementations of {@link AssetFormController}.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <T>
*/ */
@RequestScoped public abstract class AbstractAssetFormController<T extends Asset> implements
public class AbstractAssetFormController { AssetFormController<T> {
protected static final String DISPLAY_NAME = "displayName";
protected static final String TITLE = "title";
@Inject @Inject
private AssetRepository assetRepository; private AssetRepository assetRepository;
@ -44,74 +50,186 @@ public class AbstractAssetFormController {
@Inject @Inject
private AssetL10NManager l10nManager; private AssetL10NManager l10nManager;
/**
* Retrieves the basic data of the provided asset. Subclasses should not
* overrride this method. Instead they should provided an implementation of
* {@link #getAssetData(org.librecms.contentsection.Asset, java.util.Locale)}.
*
* @param assetType The {@link Asset} from which the data is read.
* @param selectedLocale The locale for which the data is read.
*
* @return A map with the data of the basic properties of the provided
* asset.
*/
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String getTitle(final Asset asset, final Locale locale) { @Override
public Map<String, Object> getAssetData(final Long assetId,
final Class<T> assetType,
final Locale selectedLocale) {
Objects.requireNonNull(asset, "Can't get title from asset null."); Objects.requireNonNull(assetId, "Can't get data from asset null.");
Objects.requireNonNull(locale, Objects.requireNonNull(selectedLocale,
"Can't title from asset for locale null"); "Can't get data from asset for locale null.");
final Asset result = assetRepository final T asset = loadAsset(assetId, assetType);
.findById(asset.getObjectId())
.orElseThrow(
() -> new IllegalArgumentException(
String.format("No asset with ID %d found.",
asset.getObjectId())
)
);
return result.getTitle().getValue(locale); final Map<String, Object> data = new HashMap<>();
data.put(DISPLAY_NAME, asset.getDisplayName());
data.put(TITLE, asset.getTitle().getValue(selectedLocale));
data.putAll(getAssetData(asset, selectedLocale));
return data;
}
protected abstract Map<String, Object> getAssetData(
final T asset, final Locale selectedLocale);
/**
* Updates the provided asset with the provided data.
*
* This method is not intended to be overridden, but can't be {@code final}
* because of limitations of CDI. To update type specific properties
* implement
* {@link #updateAssetProperties(org.librecms.contentsection.Asset, java.util.Locale, java.util.Map)}.
*
* This method calls
* {@link AssetRepository#save(org.librecms.contentsection.Asset)} after the
* properties are set to save the changes to the database.
*
* @param assetId The ID of the asset to update.
* @param selectedLocale The locale for which the asset is updated.
* @param data The data used to update the asset.
*/
@Transactional(Transactional.TxType.REQUIRED)
@Override
public void updateAsset(final Long assetId,
final Locale selectedLocale,
final Class<T> assetType,
final Map<String, Object> data) {
Objects.requireNonNull(assetId, "Can't update asset null.");
Objects.requireNonNull(selectedLocale,
"Can't get update asset for locale null.");
Objects.requireNonNull(data, "Can't update asset without data.");
final T asset;
if (assetId == null) {
asset = createAsset();
} else {
asset = loadAsset(assetId, assetType);
}
if (data.containsKey(DISPLAY_NAME)) {
asset.setDisplayName((String) data.get(DISPLAY_NAME));
}
if (data.containsKey(TITLE)) {
final String title = (String) data.get(TITLE);
asset.getTitle().addValue(selectedLocale, title);
}
updateAssetProperties(asset, selectedLocale, data);
assetRepository.save(asset);
}
/**
* Override this method to process data for type specific properties.
*
* This method is called by
* {@link #updateAsset(org.librecms.contentsection.Asset, java.util.Locale, java.util.Map)}.
* Implementations should <strong>not</strong> call
* {@link AssetRepository#save}. Saving the update asset is done by
* {@link #updateAsset(org.librecms.contentsection.Asset, java.util.Locale, java.util.Map)}.
*
* An implementation should not assume that a value for each property is
* present in the provided map. Instead the overriding method should check
* if a value for a property is available by using
* {@link Map#containsKey(java.lang.Object)} first.
*
* @param asset The asset to update.
* @param selectedLocale The locale for which the asset is updated.
* @param data The data used to update the asset.
*/
public abstract void updateAssetProperties(final T asset,
final Locale selectedLocale,
final Map<String, Object> data);
/**
* Determines for which locales the provided asset has data.
*
* @param assetId The asset.
*
* @return A list of all locales for which the asset has data.
*/
@Transactional(Transactional.TxType.REQUIRED)
@Override
public List<Locale> availableLocales(final Long assetId,
final Class<T> assetType) {
Objects.requireNonNull(
assetId,
"Can't get available locales for asset with ID null.");
final T selectedAsset = loadAsset(assetId, assetType);
return new ArrayList<>(l10nManager.availableLocales(selectedAsset));
}
/**
* Determines for locales the asset has no data yet.
*
* @param assetId The asset.
*
* @return A list of all locales for which the provided asset has no data
* yet.
*/
@Transactional(Transactional.TxType.REQUIRED)
@Override
public List<Locale> creatableLocales(final Long assetId,
final Class<T> assetType) {
Objects.requireNonNull(
assetId,
"Can't get creatable locales for asset with ID null.");
final T selectedAsset = loadAsset(assetId, assetType);
return new ArrayList<>(l10nManager.creatableLocales(selectedAsset));
} }
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public List<Locale> availableLocales(final Asset asset) { @Override
public void addLocale(final Long assetId,
final Locale locale,
final Class<T> assetType) {
Objects.requireNonNull(asset, Objects.requireNonNull(assetId, "Can't add a locale to asset null.");
"Can't get available locales from asset null."); Objects.requireNonNull(locale, "Can't add locale null to an asset.");
final Asset result = assetRepository final T selectedAsset = loadAsset(assetId, assetType);
.findById(asset.getObjectId())
.orElseThrow(
() -> new IllegalArgumentException(
String.format("No asset with ID %d found.",
asset.getObjectId())
)
);
return new ArrayList<>(l10nManager.availableLocales(result)); l10nManager.addLanguage(selectedAsset, locale);
} }
@Transactional(Transactional.TxType.REQUIRED) /**
public List<Locale> creatableLocales(final Asset asset) { *
* @param assetId
* @param assetType
*
* @return
*/
protected T loadAsset(final Long assetId, final Class<T> assetType) {
Objects.requireNonNull(asset, Objects.requireNonNull(assetId, "null is not a valid assetId");
"Can't get creatable locales from asset null.");
final Asset result = assetRepository
.findById(asset.getObjectId())
.orElseThrow(
() -> new IllegalArgumentException(
String.format("No asset with ID %d found.",
asset.getObjectId())
)
);
return new ArrayList<>(l10nManager.creatableLocales(result));
}
@Transactional(Transactional.TxType.REQUIRED)
public void updateAsset(final Asset asset,
final String displayName,
final String title,
final Locale selectedLocale) {
Objects.requireNonNull(asset, "Can't update null");
final Asset selected = assetRepository
.findById(asset.getObjectId())
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No Asset with ID %d found.", asset.getObjectId())));
return assetRepository
.findById(assetId, assetType)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No asset with ID %d found.", assetId)));
} }
} }

View File

@ -34,8 +34,8 @@ import java.util.Map;
* create an implementation the {@link AbstractAssetFormController} class should * create an implementation the {@link AbstractAssetFormController} class should
* be used. This class provides basic implementations for most methods. * be used. This class provides basic implementations for most methods.
* *
* Implementations of the methods defined by this interface should annotated with * Implementations of the methods defined by this interface should annotated
* {@code @Transactional(Transactional.TxType.REQUIRED)}. * with {@code @Transactional(Transactional.TxType.REQUIRED)}.
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* *
@ -46,37 +46,56 @@ public interface AssetFormController<T extends Asset> {
/** /**
* Gets the data for the forms from the asset. * Gets the data for the forms from the asset.
* *
* @param asset The asset. * @param assetId The ID of the asset.
* @param assetType
* @param selectedLocale The selected locale * @param selectedLocale The selected locale
* *
* @return The values of the properties of the asset for the the selected * @return The values of the properties of the asset for the the selected
* locale. * locale.
*/ */
Map<String, Object> getData(T asset, Locale selectedLocale); Map<String, Object> getAssetData(Long assetId,
Class<T> assetType,
Locale selectedLocale);
/** /**
* Updates the asset with the provided data and saves the changes. * Updates the asset with the provided data and saves the changes.
* *
* @param asset * @param assetId
* @param selectedLocale * @param selectedLocale
* @param assetType
* @param data * @param data
*/ */
void setData(T asset, Locale selectedLocale, Map<String, Object> data); void updateAsset(Long assetId,
Locale selectedLocale,
Class<T> assetType,
Map<String, Object> data);
T createAsset();
/** /**
* Determines in which locales the provided asset is available. * Determines in which locales the provided asset is available.
* *
* @param asset The asset. *
* @param assetId
* @param assetType
*
* @return A list of the locales for which the asset has data. * @return A list of the locales for which the asset has data.
*/ */
List<Locale> availableLocales(T asset); List<Locale> availableLocales(Long assetId, Class<T> assetType);
/** /**
* Determines for which the provided asset has no data. * Determines for which the provided asset has no data.
* *
* @param asset The asset. *
* @param assetId
* @param assetType
*
* @return A list of the locales for which the asset has data yet. * @return A list of the locales for which the asset has data yet.
*/ */
List<Locale> creatableLocales(T asset); List<Locale> creatableLocales(Long assetId, Class<T> assetType);
void addLocale(final Long assetId,
final Locale locale,
final Class<T> assetType);
} }

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2019 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets;
import org.librecms.contentsection.Asset;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
public class AssetFormControllers {
@Inject
@Any
private Instance<AssetFormController<?>> controllers;
@SuppressWarnings("unchecked")
public <T extends Asset> AssetFormController<T> findController(
final Class<T> assetType) {
final IsControllerForAssetTypeLiteral literal
= new IsControllerForAssetTypeLiteral(
assetType);
final Instance<AssetFormController<?>> instance = controllers
.select(literal);
if (instance.isUnsatisfied()) {
throw new IllegalArgumentException(String.format(
"No controller for asset type \"%s\".",
assetType.getClass().getName()));
} else {
return (AssetFormController<T>) instance.iterator().next();
}
}
private class IsControllerForAssetTypeLiteral
extends AnnotationLiteral<IsControllerForAssetType>
implements IsControllerForAssetType {
private static final long serialVersionUID = 1L;
private final Class<? extends Asset> assetType;
public IsControllerForAssetTypeLiteral(
final Class<? extends Asset> assetType) {
this.assetType = assetType;
}
@Override
public Class<? extends Asset> value() {
return assetType;
}
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2019 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets;
import org.librecms.contentsection.Asset;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.METHOD,
ElementType.FIELD,
ElementType.PARAMETER,
ElementType.TYPE
})
public @interface IsControllerForAssetType {
Class<? extends Asset> value();
}

View File

@ -34,12 +34,13 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.assets.BinaryAsset; import org.librecms.assets.BinaryAsset;
import org.librecms.contentsection.Asset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/** /**
* Base form for assets which extend {@link BinaryAsset}. * Base form for assets which extend {@link BinaryAsset}.
@ -51,9 +52,13 @@ public abstract class AbstractBinaryAssetForm<T extends BinaryAsset>
extends AbstractAssetForm<T> { extends AbstractAssetForm<T> {
private TextArea description; private TextArea description;
private Text fileName; private Text fileName;
private Text mimeType; private Text mimeType;
private Text size; private Text size;
private FileUploadSection fileUpload; private FileUploadSection fileUpload;
public AbstractBinaryAssetForm(final AssetPane assetPane) { public AbstractBinaryAssetForm(final AssetPane assetPane) {
@ -103,119 +108,70 @@ public abstract class AbstractBinaryAssetForm<T extends BinaryAsset>
@Override @Override
protected void initForm(final PageState state, protected void initForm(final PageState state,
final Optional<T> selectedAsset) { final Map<String, Object> data) {
super.initForm(state, selectedAsset); super.initForm(state, data);
if (selectedAsset.isPresent()) { if (!data.isEmpty()) {
if (!(selectedAsset.get() instanceof BinaryAsset)) {
throw new IllegalArgumentException(String.format(
"The provided asset must be an instanceof of class '%s' or "
+ "an subclass but is na instanceof class '%s'.",
BinaryAsset.class.getName(),
selectedAsset.get().getClass().getName()));
}
final BinaryAsset binaryAsset = (BinaryAsset) selectedAsset.get();
description.setValue(state, description.setValue(state,
binaryAsset data.get("description"));
.getDescription()
.getValue(getSelectedLocale(state)));
if (binaryAsset.getData() == null if (data.containsKey("data")) {
|| binaryAsset.getData().length == 0) {
final byte[] binaryData = (byte[]) data.get("data");
if (binaryData.length == 0) {
fileName.setText("-");
mimeType.setText("-");
size.setText("-");
} else {
fileName.setText((String) data.get("fileName"));
mimeType.setText((String) data.get("mimeType"));
size.setText(Long.toString((long) data.get("size")));
}
} else {
fileName.setText("-"); fileName.setText("-");
mimeType.setText("-"); mimeType.setText("-");
size.setText("-"); size.setText("-");
} else {
fileName.setText(binaryAsset.getFileName());
mimeType.setText(binaryAsset.getMimeType().toString());
size.setText(Long.toString(binaryAsset.getSize()));
} }
} }
} }
@Override @Override
protected void showLocale(final PageState state) { protected void showLocale(final PageState state) {
final Optional<T> selectedAsset = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
if (selectedAsset.isPresent()) { if (selectedAssetId != null) {
if (!(getSelectedAsset(state).get() instanceof BinaryAsset)) {
throw new IllegalArgumentException(
"Selected asset is not a binary asset.");
}
final BinaryAsset binaryAsset = (BinaryAsset) selectedAsset.get(); final Map<String, Object> data = getController()
.getAssetData(selectedAssetId,
getAssetClass(),
getSelectedLocale(state));
description.setValue(state, description
binaryAsset .setValue(
.getDescription() state,
.getValue(getSelectedLocale(state))); data
.get(AbstractBinaryAssetFormController.DESCRIPTION));
} }
} }
// @Override
// protected Asset createAsset(final FormSectionEvent event)
// throws FormProcessException {
//
// Objects.requireNonNull(event);
//
// final PageState state = event.getPageState();
//
// final BinaryAsset binaryAsset = createBinaryAsset(state);
//
// binaryAsset
// .getDescription()
// .addValue(getSelectedLocale(state),
// (String) description.getValue(state));
//
// setFileData(event, binaryAsset);
//
// return binaryAsset;
// }
// protected abstract BinaryAsset createBinaryAsset(final PageState state);
@Override @Override
protected void updateAsset(final Asset asset, protected Map<String, Object> collectData(final FormSectionEvent event)
final FormSectionEvent event)
throws FormProcessException { throws FormProcessException {
Objects.requireNonNull(asset); return getFileData(event);
Objects.requireNonNull(event);
final PageState state = event.getPageState();
if (!(asset instanceof BinaryAsset)) {
throw new IllegalArgumentException(String.format(
"Provided asset is not an instance of '%s' (or a sub class) "
+ "but is an instance of class '%s'.",
BinaryAsset.class.getName(),
asset.getClass().getName()));
}
final BinaryAsset binaryAsset = (BinaryAsset) asset;
binaryAsset
.getDescription()
.addValue(getSelectedLocale(state),
(String) description.getValue(state));
setFileData(event, binaryAsset);
} }
private void setFileData(final FormSectionEvent event, private Map<String, Object> getFileData(final FormSectionEvent event)
final BinaryAsset binaryAsset)
throws FormProcessException { throws FormProcessException {
final File file = fileUpload.getFile(event); final File file = fileUpload.getFile(event);
if (file != null) { if (file == null) {
return Collections.emptyMap();
} else {
final Path path = file.toPath(); final Path path = file.toPath();
final byte[] data; final byte[] data;
try { try {
@ -223,11 +179,19 @@ public abstract class AbstractBinaryAssetForm<T extends BinaryAsset>
} catch (IOException ex) { } catch (IOException ex) {
throw new FormProcessException(ex); throw new FormProcessException(ex);
} }
binaryAsset.setData(data);
binaryAsset.setFileName(fileUpload.getFileName(event));
binaryAsset.setSize(data.length);
binaryAsset.setMimeType(fileUpload.getMimeType(event)); final Map<String, Object> assetData = new HashMap<>();
assetData.put(AbstractBinaryAssetFormController.DATA,
data);
assetData.put(AbstractBinaryAssetFormController.FILE_NAME,
fileUpload.getFileName(event));
assetData.put(AbstractBinaryAssetFormController.SIZE,
data.length);
assetData.put(AbstractBinaryAssetFormController.MIME_TYPE,
fileUpload.getMimeType(event));
return assetData;
} }
} }

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2019 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets.forms;
import com.arsdigita.cms.ui.assets.AbstractAssetFormController;
import org.librecms.assets.BinaryAsset;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.activation.MimeType;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <T>
*/
public abstract class AbstractBinaryAssetFormController<T extends BinaryAsset>
extends AbstractAssetFormController<T> {
protected static final String DESCRIPTION = "description";
protected static final String FILE_NAME = "fileName";
protected static final String MIME_TYPE = "mimeType";
protected static final String DATA = "data";
protected static final String SIZE = "size";
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected Map<String, Object> getAssetData(final T asset,
final Locale selectedLocale) {
final Map<String, Object> data = new HashMap<>();
final String description = asset
.getDescription()
.getValue(selectedLocale);
data.put(DESCRIPTION, description);
data.put(FILE_NAME, asset.getFileName());
data.put(MIME_TYPE, asset.getMimeType());
data.put(DATA, asset.getData());
data.put(SIZE, asset.getSize());
return data;
}
@Override
@Transactional(Transactional.TxType.REQUIRED)
public void updateAssetProperties(final T asset,
final Locale selectedLocale,
final Map<String, Object> data) {
if (data.containsKey(DESCRIPTION)) {
asset.getDescription().addValue(selectedLocale,
(String) data.get(DESCRIPTION));
}
if (data.containsKey(FILE_NAME)) {
asset.setFileName((String) data.get(FILE_NAME));
}
if (data.containsKey(MIME_TYPE)) {
asset.setMimeType((MimeType) data.get(MIME_TYPE));
}
if (data.containsKey(DATA)) {
asset.setData((byte[]) data.get(DATA));
}
if (data.containsKey(SIZE)) {
asset.setSize((long) data.get(SIZE));
}
}
}

View File

@ -36,6 +36,7 @@ import org.librecms.contentsection.Asset;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@ -49,6 +50,7 @@ public abstract class AbstractBookmarkForm<T extends Bookmark>
extends AbstractAssetForm<T> { extends AbstractAssetForm<T> {
private TextArea description; private TextArea description;
private TextField url; private TextField url;
public AbstractBookmarkForm(final AssetPane assetPane) { public AbstractBookmarkForm(final AssetPane assetPane) {
@ -93,45 +95,34 @@ public abstract class AbstractBookmarkForm<T extends Bookmark>
@Override @Override
protected void initForm(final PageState state, protected void initForm(final PageState state,
final Optional<T> selectedAsset) { final Map<String, Object> data) {
if (selectedAsset.isPresent()) { if (!data.isEmpty()) {
if (!(selectedAsset.get() instanceof Bookmark)) { description
throw new IllegalArgumentException(String.format( .setValue(
"The provided asset must be an instanceof of class '%s' or " state,
+ "an subclass but is an instanceof of class '%s'.", data.get(AbstractBookmarkFormController.DESCRIPTION));
Bookmark.class.getName(), url.setValue(state, data.get(AbstractBookmarkFormController.URL));
selectedAsset.get().getClass().getName()));
}
final Bookmark bookmark = selectedAsset.get();
description.setValue(state,
bookmark
.getDescription()
.getValue(getSelectedLocale(state)));
url.setValue(state, bookmark.getUrl());
} }
} }
@Override @Override
protected void showLocale(final PageState state) { protected void showLocale(final PageState state) {
final Optional<T> selectedAsset = getSelectedAsset(state);
if (selectedAsset.isPresent()) { final Long selectedAssetId = getSelectedAssetId(state);
if (!(getSelectedAsset(state).get() instanceof Bookmark)) {
throw new IllegalArgumentException(
"Selected asset is not a bookmark");
}
final Bookmark bookmark = selectedAsset.get(); if (selectedAssetId != null) {
description.setValue(state, final Map<String, Object> data = getController()
bookmark .getAssetData(selectedAssetId,
.getDescription() getAssetClass(),
.getValue(getSelectedLocale(state))); getSelectedLocale(state));
description.setValue(
state,
data.get(AbstractBinaryAssetFormController.DESCRIPTION));
} }
} }
@ -145,27 +136,4 @@ public abstract class AbstractBookmarkForm<T extends Bookmark>
bookmark.setUrl((String) url.getValue(state)); bookmark.setUrl((String) url.getValue(state));
} }
@Override
protected void updateAsset(final Asset asset,
final FormSectionEvent event)
throws FormProcessException {
Objects.requireNonNull(asset);
Objects.requireNonNull(event);
final PageState state = event.getPageState();
if (!(asset instanceof Bookmark)) {
throw new IllegalArgumentException(String.format(
"Provided asset is not an instance of class (or sub class of) "
+ "'%s' but is an instance of class '%s'",
Bookmark.class.getName(),
asset.getClass().getName()));
}
final Bookmark bookmark = (Bookmark) asset;
updateData(bookmark, state);
}
} }

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2019 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets.forms;
import com.arsdigita.cms.ui.assets.AbstractAssetFormController;
import org.librecms.assets.Bookmark;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <T>
*/
public abstract class AbstractBookmarkFormController<T extends Bookmark>
extends AbstractAssetFormController<T> {
protected static final String DESCRIPTION = "description";
protected static final String URL = "url";
@Override
protected Map<String, Object> getAssetData(final T asset,
final Locale selectedLocale) {
final String description = asset
.getDescription()
.getValue(selectedLocale);
final String url = asset.getUrl();
final Map<String, Object> data = new HashMap<>();
data.put("description", description);
data.put("url", url);
return data;
}
@Override
public void updateAssetProperties(final T asset,
final Locale selectedLocale,
final Map<String, Object> data) {
if (data.containsKey(DESCRIPTION)) {
asset.getDescription().addValue(selectedLocale,
(String) data.get(DESCRIPTION));
}
if (data.containsKey(URL)) {
asset.setUrl((String) data.get(URL));
}
}
}

View File

@ -65,6 +65,7 @@ import org.librecms.assets.PostalAddress;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Optional; import java.util.Optional;
import java.util.TooManyListenersException; import java.util.TooManyListenersException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -115,7 +116,7 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
@Override @Override
public boolean isVisible(final PageState state) { public boolean isVisible(final PageState state) {
return getSelectedAsset(state) != null; return getSelectedAssetId(state) != null;
} }
}; };
@ -173,9 +174,9 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
final PageState state = event.getPageState(); final PageState state = event.getPageState();
final Optional<T> selected = getSelectedAsset(state); final Long selectedAssetId = getSelectedAssetId(state);
if (selected.isPresent()) { if (selectedAssetId != null) {
// ToDo // ToDo
} }
} }
@ -184,54 +185,35 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
public void process(final FormSectionEvent event) public void process(final FormSectionEvent event)
throws FormProcessException { throws FormProcessException {
final PageState state = event.getPageState();
if (addContactEntryLink.equals(event.getSource())) { if (addContactEntryLink.equals(event.getSource())) {
final PageState state = event.getPageState(); final Long selectedAssetId = getSelectedAssetId(state);
if (selectedAssetId == null) {
throw new FormProcessException(
new GlobalizedMessage(
"cms.ui.assets.none_selected", CMS_BUNDLE)
);
}
final ContactableEntity selected = getSelectedAsset(state) @SuppressWarnings("unchecked")
.orElseThrow(() -> new FormProcessException( final AbstractContactableEntityFormController<ContactableEntity> controller
new GlobalizedMessage( = (AbstractContactableEntityFormController<ContactableEntity>) getController();
"cms.ui.assets.none_selected", CMS_BUNDLE)));
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final ContactableEntityManager contactableEntityManager = cdiUtil
.findBean(ContactableEntityManager.class);
final ContactEntryKeyRepository keyRepository = cdiUtil
.findBean(ContactEntryKeyRepository.class);
final String key = (String) contactEntryKeySelect final String key = (String) contactEntryKeySelect
.getValue(state); .getValue(state);
final String value = (String) contactEntryValueField.getValue(state); final String value = (String) contactEntryValueField.getValue(state);
final ContactEntryKey entryKey = keyRepository controller.addContactEntry(key, value, selectedAssetId);
.findByEntryKey(key)
.orElseThrow(() -> new FormProcessException(
new GlobalizedMessage(
"cms.ui.assets.contactable.illegal_entry_key", CMS_BUNDLE)));
final ContactEntry entry = new ContactEntry();
entry.setKey(entryKey);
entry.setValue(value);
entry.setOrder(selected.getContactEntries().size());
contactableEntityManager
.addContactEntryToContactableEntity(entry, selected);
contactEntryKeySelect.setValue(state, null);
contactEntryValueField.setValue(state, "");
} else { } else {
super.process(event); super.process(event);
final Object selectedPostal = postalAddressSearchWidget
.getValue(state);
} }
} }
@Override
public void register(final Page page) {
super.register(page);
// page.addComponent(addContactEntryLink);
}
protected abstract void addPropertyWidgets(); protected abstract void addPropertyWidgets();
private Table buildContactEntriesTable() { private Table buildContactEntriesTable() {
@ -296,14 +278,13 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
final Integer rowKey = (Integer) event.getRowKey(); final Integer rowKey = (Integer) event.getRowKey();
final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); @SuppressWarnings("unchecked")
final AbstractContactableEntityFormController controller final AbstractContactableEntityFormController<ContactableEntity> controller
= cdiUtil = (AbstractContactableEntityFormController<ContactableEntity>) getController();
.findBean(AbstractContactableEntityFormController.class); final PageState state = event.getPageState();
final Optional<T> selected = getSelectedAsset(event final Long selectedId = getSelectedAssetId(state);
.getPageState()); if (selectedId != null) {
if (selected.isPresent()) { controller.removeContactEntry(rowKey, selectedId);
controller.removeContactEntry(selected.get(), rowKey);
} }
} }
@ -325,15 +306,17 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
public TableModel makeModel(final Table table, public TableModel makeModel(final Table table,
final PageState state) { final PageState state) {
final ContactableEntity selected = getSelectedAsset(state) final Long selectedId = getSelectedAssetId(state);
.orElseThrow( if (selectedId == null) {
() -> new IllegalStateException("No asset selected") throw new RuntimeException("No asset selected.");
); }
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AbstractContactableEntityFormController controller = cdiUtil @SuppressWarnings("unchecked")
.findBean(AbstractContactableEntityFormController.class); final AbstractContactableEntityFormController<ContactableEntity> controller
final List<ContactEntry> contactEntries = controller = (AbstractContactableEntityFormController<ContactableEntity>) getController();
.getContactEntries(selected); final List<String[]> contactEntries = controller
.getContactEntries(selectedId, getSelectedLocale(state));
return new ContactEntriesTableModel(contactEntries); return new ContactEntriesTableModel(contactEntries);
} }
@ -341,12 +324,12 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
private class ContactEntriesTableModel implements TableModel { private class ContactEntriesTableModel implements TableModel {
private final Iterator<ContactEntry> contactEntries; private final Iterator<String[]> contactEntries;
private ContactEntry currentContactEntry; private String[] currentContactEntry;
public ContactEntriesTableModel( public ContactEntriesTableModel(
final List<ContactEntry> contactEntries) { final List<String[]> contactEntries) {
this.contactEntries = contactEntries.iterator(); this.contactEntries = contactEntries.iterator();
} }
@ -372,9 +355,9 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
switch (columnIndex) { switch (columnIndex) {
case COL_CONTACT_ENTRIES_KEY: case COL_CONTACT_ENTRIES_KEY:
return currentContactEntry.getKey(); return currentContactEntry[1];
case COL_CONTACT_ENTRIES_VALUE: case COL_CONTACT_ENTRIES_VALUE:
return currentContactEntry.getValue(); return currentContactEntry[2];
case COL_CONTACT_ENTRIES_REMOVE: case COL_CONTACT_ENTRIES_REMOVE:
return new Label( return new Label(
new GlobalizedMessage( new GlobalizedMessage(
@ -392,7 +375,7 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
@Override @Override
public Object getKeyAt(int columnIndex) { public Object getKeyAt(int columnIndex) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. return currentContactEntry[0];
} }
} }
@ -410,7 +393,6 @@ public abstract class AbstractContactableEntityForm<T extends ContactableEntity>
return new ControlLink((Component) value); return new ControlLink((Component) value);
} }
} }
private class ContactEntryKeySelectPrintListener implements PrintListener { private class ContactEntryKeySelectPrintListener implements PrintListener {

View File

@ -18,6 +18,8 @@
*/ */
package com.arsdigita.cms.ui.assets.forms; package com.arsdigita.cms.ui.assets.forms;
import com.arsdigita.cms.ui.assets.AbstractAssetFormController;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.librecms.assets.ContactEntry; import org.librecms.assets.ContactEntry;
import org.librecms.assets.ContactEntryKey; import org.librecms.assets.ContactEntryKey;
@ -26,23 +28,32 @@ import org.librecms.assets.ContactEntryKeyRepository;
import org.librecms.assets.ContactableEntity; import org.librecms.assets.ContactableEntity;
import org.librecms.assets.ContactableEntityManager; import org.librecms.assets.ContactableEntityManager;
import org.librecms.assets.ContactableEntityRepository; import org.librecms.assets.ContactableEntityRepository;
import org.librecms.assets.PostalAddress;
import org.librecms.contentsection.AssetRepository;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.transaction.Transactional; import javax.transaction.Transactional;
/** /**
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <T>
*/ */
@RequestScoped public abstract class AbstractContactableEntityFormController<T extends ContactableEntity>
public class AbstractContactableEntityFormController { extends AbstractAssetFormController<T> {
protected static final String POSTAL_ADDRESS = "postalAddress";
@Inject
private AssetRepository assetRepository;
@Inject @Inject
private ContactableEntityRepository contactableEntityRepository; private ContactableEntityRepository contactableEntityRepository;
@ -57,48 +68,123 @@ public class AbstractContactableEntityFormController {
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public List<ContactEntry> getContactEntries( @Override
final ContactableEntity contactable) { protected Map<String, Object> getAssetData(final T asset,
final Locale selectedLocale) {
Objects.requireNonNull(contactable, final Map<String, Object> data = new HashMap<>();
final PostalAddress postalAddress = asset.getPostalAddress();
if (postalAddress != null) {
data.put(POSTAL_ADDRESS, postalAddress.getObjectId());
}
return data;
}
@Override
public void updateAssetProperties(final T asset,
final Locale selectedLocale,
final Map<String, Object> data) {
if (data.containsKey(POSTAL_ADDRESS)) {
final long addressId = (long) data.get(POSTAL_ADDRESS);
final PostalAddress postalAddress = assetRepository
.findById(addressId, PostalAddress.class)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No PostalAddress with ID %d found.", addressId)));
contactableEntityManager
.addPostalAddressToContactableEntity(postalAddress, asset);
}
}
/**
* Returns the contact entries of the provided contentable entity for the
* provided language.
*
* @param contactableId The ID of the contactable entity.
* @param selectedLocale The selected locale.
*
* @return An list of the contact entires
*/
@Transactional(Transactional.TxType.REQUIRED)
public List<String[]> getContactEntries(
final Long contactableId, final Locale selectedLocale) {
Objects.requireNonNull(contactableId,
"Can't get contact entries from null."); "Can't get contact entries from null.");
final ContactableEntity entity = contactableEntityRepository final ContactableEntity entity = contactableEntityRepository
.findById(contactable.getObjectId()) .findById(contactableId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No ContactEntity with ID %d found.", "No ContactEntity with ID %d found.", contactableId)));
contactable.getObjectId())));
final List<ContactEntry> entries = new ArrayList<>(); entity
for (final ContactEntry entry : entity.getContactEntries()) { .getContactEntries()
.stream()
.map(contactEntry -> toContactEntryArray(contactEntry,
selectedLocale))
.collect(Collectors.toList());
entries.add(entry); final List<String[]> entries = new ArrayList<>();
}
return entries; return entries;
} }
@Transactional(Transactional.TxType.REQUIRED) private String[] toContactEntryArray(final ContactEntry entry,
public void addContactEntry(final ContactEntry contactEntry, final Locale selectedLocale) {
final ContactableEntity toContactableEntity) {
contactableEntityManager final String key = entry.getKey().getEntryKey();
.addContactEntryToContactableEntity(contactEntry, final String label = entry.getKey().getLabel().getValue(selectedLocale);
toContactableEntity); final String value = entry.getValue();
return new String[]{key, label, value};
} }
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void removeContactEntry(final ContactableEntity contactableEntity, public void addContactEntry(final String contactEntryKey,
final int index) { final String contactEntryValue,
final Long toContactableEntityWithId) {
if (contactableEntity.getContactEntries().size() > index) { final ContactableEntity contactable = contactableEntityRepository
.findById(toContactableEntityWithId)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No ContactableEntity with ID %d found",
toContactableEntityWithId)));
final ContactEntry contactEntry = contactableEntity final ContactEntryKey key = keyRepository
.findByEntryKey(contactEntryKey)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No ContactEntryKey with key \"%s\" found.", contactEntryKey)));
final ContactEntry entry = new ContactEntry();
entry.setKey(key);
entry.setValue(contactEntryValue);
entry.setOrder(contactable.getContactEntries().size());
contactableEntityManager
.addContactEntryToContactableEntity(entry, contactable);
}
@Transactional(Transactional.TxType.REQUIRED)
public void removeContactEntry(final int withIndex,
final Long fromContactableEntityWithId) {
final ContactableEntity contactable = contactableEntityRepository
.findById(fromContactableEntityWithId)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No ContactableEntity with ID %d found",
fromContactableEntityWithId)));
if (contactable.getContactEntries().size() > withIndex) {
final ContactEntry contactEntry = contactable
.getContactEntries() .getContactEntries()
.get(index); .get(withIndex);
contactableEntityManager.removeContactEntryFromContactableEntity( contactableEntityManager.removeContactEntryFromContactableEntity(
contactEntry, contactableEntity); contactEntry, contactable
);
} }
} }

View File

@ -29,12 +29,11 @@ import com.arsdigita.globalization.GlobalizedMessage;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import org.librecms.CmsConstants; import org.librecms.CmsConstants;
import org.librecms.assets.AudioAsset; import org.librecms.assets.AudioAsset;
import org.librecms.assets.BinaryAsset;
import org.librecms.assets.LegalMetadata; import org.librecms.assets.LegalMetadata;
import org.librecms.contentsection.Asset; import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetRepository; import org.librecms.contentsection.AssetRepository;
import java.util.Optional; import java.util.Map;
/** /**
* *
@ -52,29 +51,28 @@ public class AudioForm extends AbstractBinaryAssetForm<AudioAsset> {
@Override @Override
protected void addWidgets() { protected void addWidgets() {
assetSearchWidget = new AssetSearchWidget("legal-metadata", LegalMetadata.class); assetSearchWidget = new AssetSearchWidget("legal-metadata",
LegalMetadata.class);
add(new Label(new GlobalizedMessage( add(new Label(new GlobalizedMessage(
"cms.ui.assets.audio.legal_metadata.label", "cms.ui.assets.audio.legal_metadata.label",
CmsConstants.CMS_BUNDLE CmsConstants.CMS_BUNDLE
))); )));
add(assetSearchWidget); add(assetSearchWidget);
} }
@Override @Override
protected void initForm(final PageState state, protected void initForm(final PageState state,
final Optional<AudioAsset> selectedAsset) { final Map<String, Object> data) {
super.initForm(state, selectedAsset); super.initForm(state, data);
if (selectedAsset.isPresent()) { if (data.containsKey(AudioFormController.LEGAL_METADATA_ID)) {
final AudioAsset audioAsset = selectedAsset.get(); final Long legalMetadataId = (Long) data
.get(AudioFormController.LEGAL_METADATA_ID);
final LegalMetadata legalMetadata = audioAsset if (legalMetadataId != null) {
.getLegalMetadata(); assetSearchWidget.setValue(state, legalMetadataId);
if (legalMetadata != null) {
assetSearchWidget.setValue(state, legalMetadata.getObjectId());
} }
} }
} }
@ -96,38 +94,37 @@ public class AudioForm extends AbstractBinaryAssetForm<AudioAsset> {
// //
// return audioAsset; // return audioAsset;
// } // }
// @Override
// protected void updateAsset(final Asset asset,
// final FormSectionEvent event)
// throws FormProcessException {
//
// super.updateAsset(asset, event);
//
// final PageState state = event.getPageState();
//
// final AudioAsset audioAsset = (AudioAsset) asset;
//
// updateData(audioAsset, state);
// }
@Override // protected void updateData(final AudioAsset audioAsset,
protected void updateAsset(final Asset asset, // final PageState state) {
final FormSectionEvent event) //
throws FormProcessException { // final Long legalMetadataId = (Long) assetSearchWidget.getValue(state);
// if (legalMetadataId != null) {
super.updateAsset(asset, event); // final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
// final AssetRepository assetRepo = cdiUtil.findBean(
final PageState state = event.getPageState(); // AssetRepository.class);
// final LegalMetadata legalMetadata = (LegalMetadata) assetRepo
final AudioAsset audioAsset = (AudioAsset) asset; // .findById(legalMetadataId)
// .orElseThrow(() -> new IllegalArgumentException(String.format(
updateData(audioAsset, state); // "No LegalMetadata asset with ID %d in the database.",
} // legalMetadataId)));
//
protected void updateData(final AudioAsset audioAsset, // audioAsset.setLegalMetadata(legalMetadata);
final PageState state) { // }
// }
final Long legalMetadataId = (Long) assetSearchWidget.getValue(state);
if (legalMetadataId != null) {
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
final AssetRepository assetRepo = cdiUtil.findBean(
AssetRepository.class);
final LegalMetadata legalMetadata = (LegalMetadata) assetRepo
.findById(legalMetadataId)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No LegalMetadata asset with ID %d in the database.",
legalMetadataId)));
audioAsset.setLegalMetadata(legalMetadata);
}
}
// @Override // @Override
// protected BinaryAsset createBinaryAsset(final PageState state) { // protected BinaryAsset createBinaryAsset(final PageState state) {

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2019 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets.forms;
import com.arsdigita.cms.ui.assets.IsControllerForAssetType;
import org.librecms.assets.AudioAsset;
import org.librecms.assets.LegalMetadata;
import org.librecms.contentsection.AssetRepository;
import java.util.Locale;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@IsControllerForAssetType(AudioAsset.class)
public class AudioFormController extends AbstractBinaryAssetFormController<AudioAsset> {
protected static final String LEGAL_METADATA_ID = "legalMetadataId";
@Inject
private AssetRepository assetRepository;
@Override
public AudioAsset createAsset() {
return new AudioAsset();
}
@Override
protected Map<String, Object> getAssetData(final AudioAsset asset,
final Locale selectedLocale) {
final Map<String, Object> data = super.getAssetData(asset,
selectedLocale);
final LegalMetadata legalMetadata = asset.getLegalMetadata();
if (legalMetadata != null) {
data.put(LEGAL_METADATA_ID, legalMetadata.getObjectId());
}
return data;
}
@Override
public void updateAssetProperties(final AudioAsset asset,
final Locale selectedLocale,
final Map<String, Object> data) {
super.updateAssetProperties(asset, selectedLocale, data);
if (data.containsKey(LEGAL_METADATA_ID)) {
final long legalMetadataId = (long) data.get(LEGAL_METADATA_ID);
final LegalMetadata legalMetadata = assetRepository
.findById(legalMetadataId, LegalMetadata.class)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No LegalMetadata with ID %d found.", legalMetadataId)));
asset.setLegalMetadata(legalMetadata);
}
}
}

View File

@ -18,10 +18,15 @@
*/ */
package com.arsdigita.cms.ui.assets.forms; package com.arsdigita.cms.ui.assets.forms;
import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.cms.ui.assets.AssetPane; import com.arsdigita.cms.ui.assets.AssetPane;
import org.librecms.assets.Bookmark; import org.librecms.assets.Bookmark;
import java.util.Collections;
import java.util.Map;
/** /**
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
@ -30,7 +35,6 @@ public class BookmarkForm extends AbstractBookmarkForm<Bookmark> {
// private TextArea description; // private TextArea description;
// private TextField url; // private TextField url;
public BookmarkForm(final AssetPane assetPane) { public BookmarkForm(final AssetPane assetPane) {
super(assetPane); super(assetPane);
} }
@ -115,7 +119,6 @@ public class BookmarkForm extends AbstractBookmarkForm<Bookmark> {
// .getValue(getSelectedLocale(state))); // .getValue(getSelectedLocale(state)));
// } // }
// } // }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected Class<Bookmark> getAssetClass() { protected Class<Bookmark> getAssetClass() {
@ -136,7 +139,6 @@ public class BookmarkForm extends AbstractBookmarkForm<Bookmark> {
// //
// return bookmark; // return bookmark;
// } // }
// protected void updateData(final Bookmark bookmark, // protected void updateData(final Bookmark bookmark,
// final PageState state) { // final PageState state) {
// bookmark // bookmark
@ -170,5 +172,11 @@ public class BookmarkForm extends AbstractBookmarkForm<Bookmark> {
// //
// updateData(bookmark, state); // updateData(bookmark, state);
// } // }
@Override
protected Map<String, Object> collectData(final FormSectionEvent event)
throws FormProcessException {
return Collections.emptyMap();
}
} }

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2019 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets.forms;
import com.arsdigita.cms.ui.assets.IsControllerForAssetType;
import org.librecms.assets.Bookmark;
import javax.enterprise.context.RequestScoped;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@IsControllerForAssetType(Bookmark.class)
public class BookmarkFormController
extends AbstractBookmarkFormController<Bookmark> {
@Override
public Bookmark createAsset() {
return new Bookmark();
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2019 LibreCCM Foundation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package com.arsdigita.cms.ui.assets.forms;
import com.arsdigita.cms.ui.assets.IsControllerForAssetType;
import org.librecms.assets.ExternalAudioAsset;
import org.librecms.assets.LegalMetadata;
import org.librecms.contentsection.AssetRepository;
import java.util.Locale;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@IsControllerForAssetType(ExternalAudioAsset.class)
public class ExternalAudioAssetFormController
extends AbstractBookmarkFormController<ExternalAudioAsset> {
protected static final String LEGAL_METADATA_ID = "legalMetadataId";
@Inject
private AssetRepository assetRepository;
@Override
public ExternalAudioAsset createAsset() {
return new ExternalAudioAsset();
}
@Override
protected Map<String, Object> getAssetData(final ExternalAudioAsset asset,
final Locale selectedLocale) {
final Map<String, Object> data = super.getAssetData(asset,
selectedLocale);
final LegalMetadata legalMetadata = asset.getLegalMetadata();
if (legalMetadata != null) {
data.put(LEGAL_METADATA_ID, legalMetadata.getObjectId());
}
return data;
}
@Override
public void updateAssetProperties(final ExternalAudioAsset asset,
final Locale selectedLocale,
final Map<String, Object> data) {
super.updateAssetProperties(asset, selectedLocale, data);
if (data.containsKey(LEGAL_METADATA_ID)) {
final long legalMetadataId = (long) data.get(LEGAL_METADATA_ID);
final LegalMetadata legalMetadata = assetRepository
.findById(legalMetadataId, LegalMetadata.class)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"No LegalMetadata with ID %d found.", legalMetadataId)));
asset.setLegalMetadata(legalMetadata);
}
}
}

View File

@ -543,9 +543,9 @@ cms.ui.pages.tab.page_models=Page Models
cms.ui.assets.organization.name=Name of the organization cms.ui.assets.organization.name=Name of the organization
cms.ui.authoring.assets.contactable.contactentries.nonecms.ui.authoring.assets.contactable.contactentries.key=Type cms.ui.authoring.assets.contactable.contactentries.nonecms.ui.authoring.assets.contactable.contactentries.key=Type
cms.ui.authoring.assets.contactable.contactentries.value=Value cms.ui.authoring.assets.contactable.contactentries.value=Value
cms.ui.authoring.assets.contactable.postaladdress\ =Postal address
cms.ui.assets.none_selected=No assets selected cms.ui.assets.none_selected=No assets selected
cms.ui.assets.contactable.illegal_entry_key=Illegal value for contact entry key. cms.ui.assets.contactable.illegal_entry_key=Illegal value for contact entry key.
cms.ui.authoring.assets.contactable.contactentries.none=No contact entries cms.ui.authoring.assets.contactable.contactentries.none=No contact entries
cms.ui.authoring.assets.contactable.contactentries.key=Type cms.ui.authoring.assets.contactable.contactentries.key=Type
cms.ui.authoring.assets.contactable.contactentries.add=Add cms.ui.authoring.assets.contactable.contactentries.add=Add
cms.ui.authoring.assets.contactable.postaladdress=Postal address

View File

@ -540,9 +540,9 @@ cms.ui.pages.tab.page_models=Page Models
cms.ui.assets.organization.name=Name der Organization cms.ui.assets.organization.name=Name der Organization
cms.ui.authoring.assets.contactable.contactentries.nonecms.ui.authoring.assets.contactable.contactentries.key=Typ cms.ui.authoring.assets.contactable.contactentries.nonecms.ui.authoring.assets.contactable.contactentries.key=Typ
cms.ui.authoring.assets.contactable.contactentries.value=Wert cms.ui.authoring.assets.contactable.contactentries.value=Wert
cms.ui.authoring.assets.contactable.postaladdress\ =Post Adresse
cms.ui.assets.none_selected=Kein aktives Asset cms.ui.assets.none_selected=Kein aktives Asset
cms.ui.assets.contactable.illegal_entry_key=Unzul\u00e4ssiger Eintragsschl\u00fcssel cms.ui.assets.contactable.illegal_entry_key=Unzul\u00e4ssiger Eintragsschl\u00fcssel
cms.ui.authoring.assets.contactable.contactentries.none=Keine Eintr\u00e4ge cms.ui.authoring.assets.contactable.contactentries.none=Keine Eintr\u00e4ge
cms.ui.authoring.assets.contactable.contactentries.key=Typ cms.ui.authoring.assets.contactable.contactentries.key=Typ
cms.ui.authoring.assets.contactable.contactentries.add=Hinzuf\u00fcgen cms.ui.authoring.assets.contactable.contactentries.add=Hinzuf\u00fcgen
cms.ui.authoring.assets.contactable.postaladdress=Post Adresse

View File

@ -502,9 +502,9 @@ cms.ui.pages.tab.page_models=Page Models
cms.ui.assets.organization.name=Name of the organization cms.ui.assets.organization.name=Name of the organization
cms.ui.authoring.assets.contactable.contactentries.nonecms.ui.authoring.assets.contactable.contactentries.key=Type cms.ui.authoring.assets.contactable.contactentries.nonecms.ui.authoring.assets.contactable.contactentries.key=Type
cms.ui.authoring.assets.contactable.contactentries.value=Value cms.ui.authoring.assets.contactable.contactentries.value=Value
cms.ui.authoring.assets.contactable.postaladdress\ =Postal address
cms.ui.assets.none_selected=No assets selected cms.ui.assets.none_selected=No assets selected
cms.ui.assets.contactable.illegal_entry_key=Illegal value for contact entry key. cms.ui.assets.contactable.illegal_entry_key=Illegal value for contact entry key.
cms.ui.authoring.assets.contactable.contactentries.none=No contact entries cms.ui.authoring.assets.contactable.contactentries.none=No contact entries
cms.ui.authoring.assets.contactable.contactentries.key=Type cms.ui.authoring.assets.contactable.contactentries.key=Type
cms.ui.authoring.assets.contactable.contactentries.add=Add cms.ui.authoring.assets.contactable.contactentries.add=Add
cms.ui.authoring.assets.contactable.postaladdress=Postal address