From 6d170b94c3be72c81e5fc95052fd89a13cf079ec Mon Sep 17 00:00:00 2001 From: jensp Date: Thu, 25 Jul 2019 09:36:14 +0000 Subject: [PATCH] Refactoring of Assets Forms WARNING: Does not compile! git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@6151 8810af33-2d31-482b-a856-94f89814c4df --- .../cms/ui/assets/AbstractAssetForm.java | 258 ++++++++---------- .../assets/AbstractAssetFormController.java | 242 +++++++++++----- .../cms/ui/assets/AssetFormController.java | 55 ++-- .../cms/ui/assets/AssetFormControllers.java | 82 ++++++ .../ui/assets/IsControllerForAssetType.java | 46 ++++ .../assets/forms/AbstractBinaryAssetForm.java | 148 ++++------ .../AbstractBinaryAssetFormController.java | 98 +++++++ .../ui/assets/forms/AbstractBookmarkForm.java | 70 ++--- .../forms/AbstractBookmarkFormController.java | 77 ++++++ .../forms/AbstractContactableEntityForm.java | 106 +++---- ...stractContactableEntityFormController.java | 138 ++++++++-- .../cms/ui/assets/forms/AudioForm.java | 91 +++--- .../ui/assets/forms/AudioFormController.java | 86 ++++++ .../cms/ui/assets/forms/BookmarkForm.java | 16 +- .../assets/forms/BookmarkFormController.java | 41 +++ .../ExternalAudioAssetFormController.java | 86 ++++++ .../org/librecms/CmsResources.properties | 2 +- .../org/librecms/CmsResources_de.properties | 2 +- .../org/librecms/CmsResources_fr.properties | 2 +- 19 files changed, 1130 insertions(+), 516 deletions(-) create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormControllers.java create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/IsControllerForAssetType.java create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetFormController.java create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkFormController.java create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioFormController.java create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkFormController.java create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalAudioAssetFormController.java diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetForm.java index dba2e5243..4d4dc8b38 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetForm.java @@ -43,18 +43,15 @@ import com.arsdigita.kernel.KernelConfig; import org.libreccm.cdi.utils.CdiUtil; import org.librecms.CmsConstants; import org.librecms.contentsection.Asset; -import org.librecms.contentsection.AssetRepository; - -import java.util.Optional; import org.libreccm.core.UnexpectedErrorException; -import org.librecms.assets.AssetL10NManager; -import org.librecms.contentsection.AssetManager; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; -import java.util.Objects; +import java.util.Map; import java.util.TooManyListenersException; /** @@ -111,15 +108,15 @@ public abstract class AbstractAssetForm @Override public void prepare(final PrintEvent event) { final PageState state = event.getPageState(); - final Optional selectedAsset = getSelectedAsset(state); + final Long selectedAssetId = getSelectedAssetId(state); final Label target = (Label) event.getTarget(); - if (selectedAsset.isPresent()) { + if (selectedAssetId == null) { target.setLabel(new GlobalizedMessage( - "cms.ui.asset.show_locale", + "cms.ui.asset.initial_locale", CmsConstants.CMS_BUNDLE)); } else { target.setLabel(new GlobalizedMessage( - "cms.ui.asset.initial_locale", + "cms.ui.asset.show_locale", CmsConstants.CMS_BUNDLE)); } } @@ -133,26 +130,8 @@ public abstract class AbstractAssetForm public void prepare(final PrintEvent event) { final PageState state = event.getPageState(); - final Optional selectedAsset = getSelectedAsset(state); - if (selectedAsset.isPresent()) { - final SingleSelect target = (SingleSelect) event - .getTarget(); - - target.clearOptions(); - - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final AbstractAssetFormController controller = cdiUtil - .findBean(AbstractAssetFormController.class); - final List 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 Long selectedAssetId = getSelectedAssetId(state); + if (selectedAssetId == null) { final SingleSelect target = (SingleSelect) event .getTarget(); @@ -165,6 +144,27 @@ public abstract class AbstractAssetForm langs.forEach(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 controller + = cdiUtil + .findBean(AbstractAssetFormController.class); + final List 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 @Override public boolean isVisible(final PageState state) { - return getSelectedAsset(state).isPresent(); + return getSelectedAssetId(state) != null; } }; @@ -191,7 +191,7 @@ public abstract class AbstractAssetForm @Override public boolean isVisible(final PageState state) { - return getSelectedAsset(state).isPresent(); + return getSelectedAssetId(state) != null; } }; @@ -206,19 +206,22 @@ public abstract class AbstractAssetForm public void prepare(final PrintEvent event) { final PageState state = event.getPageState(); - final Optional selectedAsset = getSelectedAsset(state); - if (selectedAsset.isPresent()) { + final Long selectedAssetId = getSelectedAssetId(state); + if (selectedAssetId != null) { final SingleSelect target = (SingleSelect) event .getTarget(); target.clearOptions(); final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final AbstractAssetFormController controller = cdiUtil - .findBean(AbstractAssetFormController.class); + @SuppressWarnings("unchecked") + final AbstractAssetFormController controller + = cdiUtil + .findBean(AbstractAssetFormController.class); final List creatableLocales = controller - .creatableLocales(selectedAsset.get()); + .creatableLocales(selectedAssetId, + getAssetClass()); creatableLocales.sort((locale1, locale2) -> { return locale1 .toString() @@ -270,31 +273,13 @@ public abstract class AbstractAssetForm return (String) title.getValue(state); } - @SuppressWarnings("unchecked") - protected Optional getSelectedAsset(final PageState state) { + protected Long getSelectedAssetId(final PageState state) { - if (selectionModel.getSelectedKey(state) == null) { - return Optional.empty(); + final Object key = selectionModel.getSelectedKey(state); + if (key == null) { + return null; } else { - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - 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())); - } + return (Long) key; } } @@ -303,28 +288,36 @@ public abstract class AbstractAssetForm final PageState state = event.getPageState(); - final Optional selectedAsset = getSelectedAsset(state); + final Long selectedAssetId = getSelectedAssetId(state); - if (selectedAsset.isPresent()) { - - 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 { + final Map data; + if (selectedAssetId == null) { showLocaleSelect.setValue(state, KernelConfig .getConfig() .getDefaultLocale() .toString()); + + data = Collections.emptyMap(); + + } else { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + @SuppressWarnings("unchecked") + final AbstractAssetFormController 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) { @@ -346,22 +339,20 @@ public abstract class AbstractAssetForm } protected void initForm(final PageState state, - final Optional selectedAsset) { + final Map data) { - if (selectedAsset.isPresent()) { + if (!data.isEmpty()) { - name.setValue(state, - selectedAsset - .get() - .getDisplayName()); + name.setValue(state, + data.get(AbstractAssetFormController.DISPLAY_NAME)); - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final AbstractAssetFormController controller = cdiUtil - .findBean(AbstractAssetFormController.class); +// final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); +// @SuppressWarnings("unchecked") +// final AbstractAssetFormController controller = cdiUtil +// .findBean(AbstractAssetFormController.class); title.setValue(state, - controller.getTitle(selectedAsset.get(), - getSelectedLocale(state))); + data.get(AbstractAssetFormController.TITLE)); showLocale(state); } } @@ -372,66 +363,41 @@ public abstract class AbstractAssetForm final PageState state = event.getPageState(); - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - +// final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); if (showLocaleSubmit.isSelected(state)) { - final Optional selectedAsset = getSelectedAsset(state); - initForm(state, selectedAsset); + final Long selectedAssetId = getSelectedAssetId(state); + + initForm(state, + getController().getAssetData(selectedAssetId, + getAssetClass(), + getSelectedLocale(state))); return; } if (addLocaleSubmit.isSelected(state)) { - final AssetL10NManager l10nManager = cdiUtil - .findBean(AssetL10NManager.class); final Locale add = new Locale((String) addLocaleSelect .getValue(state)); - final Optional selectedAsset = getSelectedAsset(state); - l10nManager.addLanguage(selectedAsset.get(), add); + final Long selectedAssetId = getSelectedAssetId(state); + getController().addLocale(selectedAssetId, add, getAssetClass()); } if (saveCancelSection.getSaveButton().isSelected(state)) { - final Optional selectedAsset = getSelectedAsset(state); - final Asset asset; - if (selectedAsset.isPresent()) { - asset = selectedAsset.get(); -// updateAsset(asset, event); - asset.setDisplayName((String) name.getValue(state)); - asset.getTitle().addValue(getSelectedLocale(state), - (String) title.getValue(state)); + final Long selectedAssetId = getSelectedAssetId(state); + final Map data = new HashMap<>(); + data.put(AbstractAssetFormController.DISPLAY_NAME, + name.getValue(state)); + data.put(AbstractAssetFormController.TITLE, + title.getValue(state)); + data.putAll(collectData(event)); -// final AssetRepository assetRepo = cdiUtil -// .findBean(AssetRepository.class); -// assetRepo.save(asset); - } else { - asset = createAsset(event); - updateAsset(asset, event); - } + getController().updateAsset(selectedAssetId, + getSelectedLocale(state), + getAssetClass(), + data); - 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); } } @@ -440,27 +406,8 @@ public abstract class AbstractAssetForm protected abstract void showLocale(final PageState state); - protected final T createAsset(final FormSectionEvent event) - throws FormProcessException { - - 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) + protected abstract Map collectData( + final FormSectionEvent event) throws FormProcessException; @Override @@ -475,4 +422,13 @@ public abstract class AbstractAssetForm } } + protected AssetFormController getController() { + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final AssetFormControllers controllers = cdiUtil + .findBean(AssetFormControllers.class); + + return controllers.findController(getAssetClass()); + } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetFormController.java index bfc75ce83..a6581ef63 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetFormController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AbstractAssetFormController.java @@ -23,95 +23,213 @@ import org.librecms.contentsection.Asset; import org.librecms.contentsection.AssetRepository; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; -import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.transaction.Transactional; /** + * An base class for implementations of {@link AssetFormController}. * * @author Jens Pelzetter + * @param */ -@RequestScoped -public class AbstractAssetFormController { +public abstract class AbstractAssetFormController implements + AssetFormController { + + protected static final String DISPLAY_NAME = "displayName"; + protected static final String TITLE = "title"; @Inject private AssetRepository assetRepository; - + @Inject 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) - public String getTitle(final Asset asset, final Locale locale) { + @Override + public Map getAssetData(final Long assetId, + final Class assetType, + final Locale selectedLocale) { - Objects.requireNonNull(asset, "Can't get title from asset null."); - Objects.requireNonNull(locale, - "Can't title from asset for locale null"); + Objects.requireNonNull(assetId, "Can't get data from asset null."); + Objects.requireNonNull(selectedLocale, + "Can't get data from asset for locale null."); - final Asset result = assetRepository - .findById(asset.getObjectId()) - .orElseThrow( - () -> new IllegalArgumentException( - String.format("No asset with ID %d found.", - asset.getObjectId()) - ) - ); + final T asset = loadAsset(assetId, assetType); - return result.getTitle().getValue(locale); + final Map 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 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) - public List availableLocales(final Asset asset) { - - Objects.requireNonNull(asset, - "Can't get available 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.availableLocales(result)); + @Override + public void updateAsset(final Long assetId, + final Locale selectedLocale, + final Class assetType, + final Map 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 not 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 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) - public List creatableLocales(final Asset asset) { - - Objects.requireNonNull(asset, - "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)); + @Override + public List availableLocales(final Long assetId, + final Class 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 creatableLocales(final Long assetId, + final Class 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) - 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()))); - + @Override + public void addLocale(final Long assetId, + final Locale locale, + final Class assetType) { + + Objects.requireNonNull(assetId, "Can't add a locale to asset null."); + Objects.requireNonNull(locale, "Can't add locale null to an asset."); + + final T selectedAsset = loadAsset(assetId, assetType); + + l10nManager.addLanguage(selectedAsset, locale); } - + + /** + * + * @param assetId + * @param assetType + * + * @return + */ + protected T loadAsset(final Long assetId, final Class assetType) { + + Objects.requireNonNull(assetId, "null is not a valid assetId"); + + return assetRepository + .findById(assetId, assetType) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No asset with ID %d found.", assetId))); + } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormController.java index cfa78c933..c63e3e502 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormController.java @@ -33,9 +33,9 @@ import java.util.Map; * approbriate implementation of this interface. To minimize the efford to * create an implementation the {@link AbstractAssetFormController} class should * be used. This class provides basic implementations for most methods. - * - * Implementations of the methods defined by this interface should annotated with - * {@code @Transactional(Transactional.TxType.REQUIRED)}. + * + * Implementations of the methods defined by this interface should annotated + * with {@code @Transactional(Transactional.TxType.REQUIRED)}. * * @author Jens Pelzetter * @@ -46,37 +46,56 @@ public interface AssetFormController { /** * 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 * * @return The values of the properties of the asset for the the selected * locale. */ - Map getData(T asset, Locale selectedLocale); + Map getAssetData(Long assetId, + Class assetType, + Locale selectedLocale); /** * Updates the asset with the provided data and saves the changes. - * - * @param asset + * + * @param assetId * @param selectedLocale - * @param data + * @param assetType + * @param data */ - void setData(T asset, Locale selectedLocale, Map data); - + void updateAsset(Long assetId, + Locale selectedLocale, + Class assetType, + Map data); + + T createAsset(); + /** * 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. */ - List availableLocales(T asset); - + List availableLocales(Long assetId, Class assetType); + /** - * Determines for which the provided asset has no data. - * - * @param asset The asset. + * Determines for which the provided asset has no data. + * + * + * @param assetId + * @param assetType + * * @return A list of the locales for which the asset has data yet. */ - List creatableLocales(T asset); + List creatableLocales(Long assetId, Class assetType); + + void addLocale(final Long assetId, + final Locale locale, + final Class assetType); } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormControllers.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormControllers.java new file mode 100644 index 000000000..8fa79557f --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetFormControllers.java @@ -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 Jens Pelzetter + */ +@RequestScoped +public class AssetFormControllers { + + @Inject + @Any + private Instance> controllers; + + @SuppressWarnings("unchecked") + public AssetFormController findController( + final Class assetType) { + + final IsControllerForAssetTypeLiteral literal + = new IsControllerForAssetTypeLiteral( + assetType); + + final Instance> instance = controllers + .select(literal); + + if (instance.isUnsatisfied()) { + throw new IllegalArgumentException(String.format( + "No controller for asset type \"%s\".", + assetType.getClass().getName())); + } else { + return (AssetFormController) instance.iterator().next(); + } + } + + private class IsControllerForAssetTypeLiteral + extends AnnotationLiteral + implements IsControllerForAssetType { + + private static final long serialVersionUID = 1L; + + private final Class assetType; + + public IsControllerForAssetTypeLiteral( + final Class assetType) { + + this.assetType = assetType; + } + + @Override + public Class value() { + + return assetType; + } + + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/IsControllerForAssetType.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/IsControllerForAssetType.java new file mode 100644 index 000000000..9962cf2fa --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/IsControllerForAssetType.java @@ -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 Jens Pelzetter + */ +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +@Target({ + ElementType.METHOD, + ElementType.FIELD, + ElementType.PARAMETER, + ElementType.TYPE +}) +public @interface IsControllerForAssetType { + + Class value(); + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetForm.java index 69df27c11..58cf71b42 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetForm.java @@ -34,12 +34,13 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Objects; -import java.util.Optional; import org.librecms.CmsConstants; 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}. @@ -47,13 +48,17 @@ import org.librecms.contentsection.Asset; * @author Jens Pelzetter * @param Type of binary asset */ -public abstract class AbstractBinaryAssetForm +public abstract class AbstractBinaryAssetForm extends AbstractAssetForm { private TextArea description; + private Text fileName; + private Text mimeType; + private Text size; + private FileUploadSection fileUpload; public AbstractBinaryAssetForm(final AssetPane assetPane) { @@ -103,119 +108,70 @@ public abstract class AbstractBinaryAssetForm @Override protected void initForm(final PageState state, - final Optional selectedAsset) { + final Map data) { - super.initForm(state, selectedAsset); + super.initForm(state, data); - if (selectedAsset.isPresent()) { - - 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(); + if (!data.isEmpty()) { description.setValue(state, - binaryAsset - .getDescription() - .getValue(getSelectedLocale(state))); + data.get("description")); - if (binaryAsset.getData() == null - || binaryAsset.getData().length == 0) { + if (data.containsKey("data")) { + + 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("-"); mimeType.setText("-"); size.setText("-"); - } else { - - fileName.setText(binaryAsset.getFileName()); - mimeType.setText(binaryAsset.getMimeType().toString()); - size.setText(Long.toString(binaryAsset.getSize())); } } - } @Override protected void showLocale(final PageState state) { - final Optional selectedAsset = getSelectedAsset(state); + final Long selectedAssetId = getSelectedAssetId(state); - if (selectedAsset.isPresent()) { - if (!(getSelectedAsset(state).get() instanceof BinaryAsset)) { - throw new IllegalArgumentException( - "Selected asset is not a binary asset."); - } + if (selectedAssetId != null) { - final BinaryAsset binaryAsset = (BinaryAsset) selectedAsset.get(); + final Map data = getController() + .getAssetData(selectedAssetId, + getAssetClass(), + getSelectedLocale(state)); - description.setValue(state, - binaryAsset - .getDescription() - .getValue(getSelectedLocale(state))); + description + .setValue( + 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 - protected void updateAsset(final Asset asset, - final FormSectionEvent event) + protected Map collectData(final FormSectionEvent event) throws FormProcessException { - Objects.requireNonNull(asset); - 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); + return getFileData(event); } - private void setFileData(final FormSectionEvent event, - final BinaryAsset binaryAsset) + private Map getFileData(final FormSectionEvent event) throws FormProcessException { final File file = fileUpload.getFile(event); - if (file != null) { + if (file == null) { + return Collections.emptyMap(); + } else { final Path path = file.toPath(); final byte[] data; try { @@ -223,11 +179,19 @@ public abstract class AbstractBinaryAssetForm } catch (IOException ex) { throw new FormProcessException(ex); } - binaryAsset.setData(data); - binaryAsset.setFileName(fileUpload.getFileName(event)); - binaryAsset.setSize(data.length); - binaryAsset.setMimeType(fileUpload.getMimeType(event)); + final Map 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; } } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetFormController.java new file mode 100644 index 000000000..54845725c --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBinaryAssetFormController.java @@ -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 Jens Pelzetter + * @param + */ +public abstract class AbstractBinaryAssetFormController + extends AbstractAssetFormController { + + 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 getAssetData(final T asset, + final Locale selectedLocale) { + + final Map 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 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)); + } + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkForm.java index d8e8a1cb0..413e7c83d 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkForm.java @@ -36,6 +36,7 @@ import org.librecms.contentsection.Asset; import java.net.MalformedURLException; import java.net.URL; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -49,6 +50,7 @@ public abstract class AbstractBookmarkForm extends AbstractAssetForm { private TextArea description; + private TextField url; public AbstractBookmarkForm(final AssetPane assetPane) { @@ -93,45 +95,34 @@ public abstract class AbstractBookmarkForm @Override protected void initForm(final PageState state, - final Optional selectedAsset) { + final Map data) { - if (selectedAsset.isPresent()) { + if (!data.isEmpty()) { - if (!(selectedAsset.get() instanceof Bookmark)) { - throw new IllegalArgumentException(String.format( - "The provided asset must be an instanceof of class '%s' or " - + "an subclass but is an instanceof of class '%s'.", - Bookmark.class.getName(), - selectedAsset.get().getClass().getName())); - } - - final Bookmark bookmark = selectedAsset.get(); - - description.setValue(state, - bookmark - .getDescription() - .getValue(getSelectedLocale(state))); - url.setValue(state, bookmark.getUrl()); + description + .setValue( + state, + data.get(AbstractBookmarkFormController.DESCRIPTION)); + url.setValue(state, data.get(AbstractBookmarkFormController.URL)); } } @Override protected void showLocale(final PageState state) { - final Optional selectedAsset = getSelectedAsset(state); - if (selectedAsset.isPresent()) { - if (!(getSelectedAsset(state).get() instanceof Bookmark)) { - throw new IllegalArgumentException( - "Selected asset is not a bookmark"); - } + final Long selectedAssetId = getSelectedAssetId(state); - final Bookmark bookmark = selectedAsset.get(); + if (selectedAssetId != null) { - description.setValue(state, - bookmark - .getDescription() - .getValue(getSelectedLocale(state))); + final Map data = getController() + .getAssetData(selectedAssetId, + getAssetClass(), + getSelectedLocale(state)); + + description.setValue( + state, + data.get(AbstractBinaryAssetFormController.DESCRIPTION)); } } @@ -145,27 +136,4 @@ public abstract class AbstractBookmarkForm 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); - } - } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkFormController.java new file mode 100644 index 000000000..26d2c1cdf --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractBookmarkFormController.java @@ -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 Jens Pelzetter + * @param + */ +public abstract class AbstractBookmarkFormController + extends AbstractAssetFormController { + + protected static final String DESCRIPTION = "description"; + + protected static final String URL = "url"; + + @Override + protected Map getAssetData(final T asset, + final Locale selectedLocale) { + + final String description = asset + .getDescription() + .getValue(selectedLocale); + + final String url = asset.getUrl(); + + final Map 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 data) { + + if (data.containsKey(DESCRIPTION)) { + + asset.getDescription().addValue(selectedLocale, + (String) data.get(DESCRIPTION)); + + } + + if (data.containsKey(URL)) { + + asset.setUrl((String) data.get(URL)); + } + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityForm.java index 5fc395e45..daadea223 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityForm.java @@ -65,6 +65,7 @@ import org.librecms.assets.PostalAddress; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Optional; import java.util.TooManyListenersException; import java.util.stream.Collectors; @@ -115,7 +116,7 @@ public abstract class AbstractContactableEntityForm @Override public boolean isVisible(final PageState state) { - return getSelectedAsset(state) != null; + return getSelectedAssetId(state) != null; } }; @@ -173,9 +174,9 @@ public abstract class AbstractContactableEntityForm final PageState state = event.getPageState(); - final Optional selected = getSelectedAsset(state); + final Long selectedAssetId = getSelectedAssetId(state); - if (selected.isPresent()) { + if (selectedAssetId != null) { // ToDo } } @@ -184,54 +185,35 @@ public abstract class AbstractContactableEntityForm public void process(final FormSectionEvent event) throws FormProcessException { + final PageState state = event.getPageState(); + 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) - .orElseThrow(() -> new FormProcessException( - new GlobalizedMessage( - "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); + @SuppressWarnings("unchecked") + final AbstractContactableEntityFormController controller + = (AbstractContactableEntityFormController) getController(); final String key = (String) contactEntryKeySelect .getValue(state); final String value = (String) contactEntryValueField.getValue(state); - final ContactEntryKey entryKey = keyRepository - .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, ""); + controller.addContactEntry(key, value, selectedAssetId); } else { 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(); private Table buildContactEntriesTable() { @@ -296,14 +278,13 @@ public abstract class AbstractContactableEntityForm final Integer rowKey = (Integer) event.getRowKey(); - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final AbstractContactableEntityFormController controller - = cdiUtil - .findBean(AbstractContactableEntityFormController.class); - final Optional selected = getSelectedAsset(event - .getPageState()); - if (selected.isPresent()) { - controller.removeContactEntry(selected.get(), rowKey); + @SuppressWarnings("unchecked") + final AbstractContactableEntityFormController controller + = (AbstractContactableEntityFormController) getController(); + final PageState state = event.getPageState(); + final Long selectedId = getSelectedAssetId(state); + if (selectedId != null) { + controller.removeContactEntry(rowKey, selectedId); } } @@ -325,15 +306,17 @@ public abstract class AbstractContactableEntityForm public TableModel makeModel(final Table table, final PageState state) { - final ContactableEntity selected = getSelectedAsset(state) - .orElseThrow( - () -> new IllegalStateException("No asset selected") - ); - final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); - final AbstractContactableEntityFormController controller = cdiUtil - .findBean(AbstractContactableEntityFormController.class); - final List contactEntries = controller - .getContactEntries(selected); + final Long selectedId = getSelectedAssetId(state); + if (selectedId == null) { + throw new RuntimeException("No asset selected."); + } + + @SuppressWarnings("unchecked") + final AbstractContactableEntityFormController controller + = (AbstractContactableEntityFormController) getController(); + final List contactEntries = controller + .getContactEntries(selectedId, getSelectedLocale(state)); + return new ContactEntriesTableModel(contactEntries); } @@ -341,12 +324,12 @@ public abstract class AbstractContactableEntityForm private class ContactEntriesTableModel implements TableModel { - private final Iterator contactEntries; + private final Iterator contactEntries; - private ContactEntry currentContactEntry; + private String[] currentContactEntry; public ContactEntriesTableModel( - final List contactEntries) { + final List contactEntries) { this.contactEntries = contactEntries.iterator(); } @@ -372,9 +355,9 @@ public abstract class AbstractContactableEntityForm switch (columnIndex) { case COL_CONTACT_ENTRIES_KEY: - return currentContactEntry.getKey(); + return currentContactEntry[1]; case COL_CONTACT_ENTRIES_VALUE: - return currentContactEntry.getValue(); + return currentContactEntry[2]; case COL_CONTACT_ENTRIES_REMOVE: return new Label( new GlobalizedMessage( @@ -392,7 +375,7 @@ public abstract class AbstractContactableEntityForm @Override 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 return new ControlLink((Component) value); } - } private class ContactEntryKeySelectPrintListener implements PrintListener { diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityFormController.java index 589401485..819850088 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityFormController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AbstractContactableEntityFormController.java @@ -18,6 +18,8 @@ */ package com.arsdigita.cms.ui.assets.forms; +import com.arsdigita.cms.ui.assets.AbstractAssetFormController; + import org.libreccm.l10n.GlobalizationHelper; import org.librecms.assets.ContactEntry; import org.librecms.assets.ContactEntryKey; @@ -26,23 +28,32 @@ import org.librecms.assets.ContactEntryKeyRepository; import org.librecms.assets.ContactableEntity; import org.librecms.assets.ContactableEntityManager; import org.librecms.assets.ContactableEntityRepository; +import org.librecms.assets.PostalAddress; +import org.librecms.contentsection.AssetRepository; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; -import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.transaction.Transactional; /** * * @author Jens Pelzetter + * @param */ -@RequestScoped -public class AbstractContactableEntityFormController { +public abstract class AbstractContactableEntityFormController + extends AbstractAssetFormController { + + protected static final String POSTAL_ADDRESS = "postalAddress"; + + @Inject + private AssetRepository assetRepository; @Inject private ContactableEntityRepository contactableEntityRepository; @@ -57,48 +68,123 @@ public class AbstractContactableEntityFormController { private GlobalizationHelper globalizationHelper; @Transactional(Transactional.TxType.REQUIRED) - public List getContactEntries( - final ContactableEntity contactable) { + @Override + protected Map getAssetData(final T asset, + final Locale selectedLocale) { - Objects.requireNonNull(contactable, + final Map 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 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 getContactEntries( + final Long contactableId, final Locale selectedLocale) { + + Objects.requireNonNull(contactableId, "Can't get contact entries from null."); final ContactableEntity entity = contactableEntityRepository - .findById(contactable.getObjectId()) + .findById(contactableId) .orElseThrow(() -> new IllegalArgumentException(String.format( - "No ContactEntity with ID %d found.", - contactable.getObjectId()))); + "No ContactEntity with ID %d found.", contactableId))); - final List entries = new ArrayList<>(); - for (final ContactEntry entry : entity.getContactEntries()) { + entity + .getContactEntries() + .stream() + .map(contactEntry -> toContactEntryArray(contactEntry, + selectedLocale)) + .collect(Collectors.toList()); - entries.add(entry); - } + final List entries = new ArrayList<>(); return entries; } - @Transactional(Transactional.TxType.REQUIRED) - public void addContactEntry(final ContactEntry contactEntry, - final ContactableEntity toContactableEntity) { + private String[] toContactEntryArray(final ContactEntry entry, + final Locale selectedLocale) { - contactableEntityManager - .addContactEntryToContactableEntity(contactEntry, - toContactableEntity); + final String key = entry.getKey().getEntryKey(); + final String label = entry.getKey().getLabel().getValue(selectedLocale); + final String value = entry.getValue(); + return new String[]{key, label, value}; } @Transactional(Transactional.TxType.REQUIRED) - public void removeContactEntry(final ContactableEntity contactableEntity, - final int index) { + public void addContactEntry(final String contactEntryKey, + 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() - .get(index); + .get(withIndex); contactableEntityManager.removeContactEntryFromContactableEntity( - contactEntry, contactableEntity); + contactEntry, contactable + ); } } @@ -106,7 +192,7 @@ public class AbstractContactableEntityFormController { public List findAvailableContactEntryKeys() { final Locale locale = globalizationHelper.getNegotiatedLocale(); - + return keyRepository .findAll() .stream() diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioForm.java index ac09ac21f..403cd9da9 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioForm.java @@ -29,12 +29,11 @@ import com.arsdigita.globalization.GlobalizedMessage; import org.libreccm.cdi.utils.CdiUtil; import org.librecms.CmsConstants; import org.librecms.assets.AudioAsset; -import org.librecms.assets.BinaryAsset; import org.librecms.assets.LegalMetadata; import org.librecms.contentsection.Asset; import org.librecms.contentsection.AssetRepository; -import java.util.Optional; +import java.util.Map; /** * @@ -52,29 +51,28 @@ public class AudioForm extends AbstractBinaryAssetForm { @Override protected void addWidgets() { - assetSearchWidget = new AssetSearchWidget("legal-metadata", LegalMetadata.class); + assetSearchWidget = new AssetSearchWidget("legal-metadata", + LegalMetadata.class); add(new Label(new GlobalizedMessage( - "cms.ui.assets.audio.legal_metadata.label", - CmsConstants.CMS_BUNDLE + "cms.ui.assets.audio.legal_metadata.label", + CmsConstants.CMS_BUNDLE ))); add(assetSearchWidget); } @Override - protected void initForm(final PageState state, - final Optional selectedAsset) { + protected void initForm(final PageState state, + final Map 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 LegalMetadata legalMetadata = audioAsset - .getLegalMetadata(); - if (legalMetadata != null) { - assetSearchWidget.setValue(state, legalMetadata.getObjectId()); + final Long legalMetadataId = (Long) data + .get(AudioFormController.LEGAL_METADATA_ID); + if (legalMetadataId != null) { + assetSearchWidget.setValue(state, legalMetadataId); } } } @@ -83,7 +81,7 @@ public class AudioForm extends AbstractBinaryAssetForm { protected Class getAssetClass() { return AudioAsset.class; } - + // @Override // protected Asset createAsset(final FormSectionEvent event) // throws FormProcessException { @@ -96,38 +94,37 @@ public class AudioForm extends AbstractBinaryAssetForm { // // 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 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); - } - - protected void updateData(final AudioAsset audioAsset, - 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); - } - } +// protected void updateData(final AudioAsset audioAsset, +// 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 // protected BinaryAsset createBinaryAsset(final PageState state) { diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioFormController.java new file mode 100644 index 000000000..d9de53782 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/AudioFormController.java @@ -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 Jens Pelzetter + */ +@RequestScoped +@IsControllerForAssetType(AudioAsset.class) +public class AudioFormController extends AbstractBinaryAssetFormController { + + protected static final String LEGAL_METADATA_ID = "legalMetadataId"; + + @Inject + private AssetRepository assetRepository; + + @Override + public AudioAsset createAsset() { + return new AudioAsset(); + } + + @Override + protected Map getAssetData(final AudioAsset asset, + final Locale selectedLocale) { + + final Map 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 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); + } + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkForm.java index 9b785f547..124e89df2 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkForm.java @@ -18,10 +18,15 @@ */ 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 org.librecms.assets.Bookmark; +import java.util.Collections; +import java.util.Map; + /** * * @author Jens Pelzetter @@ -30,7 +35,6 @@ public class BookmarkForm extends AbstractBookmarkForm { // private TextArea description; // private TextField url; - public BookmarkForm(final AssetPane assetPane) { super(assetPane); } @@ -115,13 +119,12 @@ public class BookmarkForm extends AbstractBookmarkForm { // .getValue(getSelectedLocale(state))); // } // } - @Override @SuppressWarnings("unchecked") protected Class getAssetClass() { return Bookmark.class; } - + // @Override // protected Asset createAsset(final FormSectionEvent event) // throws FormProcessException { @@ -136,7 +139,6 @@ public class BookmarkForm extends AbstractBookmarkForm { // // return bookmark; // } - // protected void updateData(final Bookmark bookmark, // final PageState state) { // bookmark @@ -170,5 +172,11 @@ public class BookmarkForm extends AbstractBookmarkForm { // // updateData(bookmark, state); // } + @Override + protected Map collectData(final FormSectionEvent event) + throws FormProcessException { + + return Collections.emptyMap(); + } } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkFormController.java new file mode 100644 index 000000000..28eea567e --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/BookmarkFormController.java @@ -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 Jens Pelzetter + */ +@RequestScoped +@IsControllerForAssetType(Bookmark.class) +public class BookmarkFormController + extends AbstractBookmarkFormController { + + @Override + public Bookmark createAsset() { + return new Bookmark(); + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalAudioAssetFormController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalAudioAssetFormController.java new file mode 100644 index 000000000..4605c232a --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalAudioAssetFormController.java @@ -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 Jens Pelzetter + */ +@RequestScoped +@IsControllerForAssetType(ExternalAudioAsset.class) +public class ExternalAudioAssetFormController + extends AbstractBookmarkFormController { + + protected static final String LEGAL_METADATA_ID = "legalMetadataId"; + + @Inject + private AssetRepository assetRepository; + + @Override + public ExternalAudioAsset createAsset() { + return new ExternalAudioAsset(); + } + + @Override + protected Map getAssetData(final ExternalAudioAsset asset, + final Locale selectedLocale) { + + final Map 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 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); + } + } + +} diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties index 1b9e64da4..18db26708 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties @@ -543,9 +543,9 @@ cms.ui.pages.tab.page_models=Page Models 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.value=Value -cms.ui.authoring.assets.contactable.postaladdress\ =Postal address cms.ui.assets.none_selected=No assets selected 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.key=Type cms.ui.authoring.assets.contactable.contactentries.add=Add +cms.ui.authoring.assets.contactable.postaladdress=Postal address diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties index 172c4934a..c3c00ab10 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties @@ -540,9 +540,9 @@ cms.ui.pages.tab.page_models=Page Models 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.value=Wert -cms.ui.authoring.assets.contactable.postaladdress\ =Post Adresse cms.ui.assets.none_selected=Kein aktives Asset 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.key=Typ cms.ui.authoring.assets.contactable.contactentries.add=Hinzuf\u00fcgen +cms.ui.authoring.assets.contactable.postaladdress=Post Adresse diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties index 3df8ba180..38afee458 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties @@ -502,9 +502,9 @@ cms.ui.pages.tab.page_models=Page Models 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.value=Value -cms.ui.authoring.assets.contactable.postaladdress\ =Postal address cms.ui.assets.none_selected=No assets selected 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.key=Type cms.ui.authoring.assets.contactable.contactentries.add=Add +cms.ui.authoring.assets.contactable.postaladdress=Postal address