Compoments and resusable classes for subclasses of ContactableEntity, base structure for asset picker component

pull/10/head
Jens Pelzetter 2021-05-29 17:54:49 +02:00
parent 1bdddb5243
commit ca081f94df
26 changed files with 1625 additions and 78 deletions

View File

@ -161,25 +161,23 @@ public class PersonFormController
final String suffix = (String) data.get(SUFFIX); final String suffix = (String) data.get(SUFFIX);
if (asset.getPersonName() == null) { if (asset.getPersonName() == null) {
personManager.addPersonName(asset); final PersonName personName = new PersonName();
personName.setGivenName(givenName);
personName.setSuffix(suffix);
personName.setPrefix(prefix);
personName.setSurname(surname);
personManager.addPersonName(asset, personName);
} }
asset.getPersonName().setSurname(surname);
asset.getPersonName().setGivenName(givenName);
asset.getPersonName().setPrefix(prefix);
asset.getPersonName().setSuffix(suffix);
} }
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void addPersonName(final long personId) { public void addPersonName(final long personId) {
final Person person = personRepository final Person person = personRepository
.findById(personId) .findById(personId)
.orElseThrow(() -> new IllegalArgumentException(String.format( .orElseThrow(() -> new IllegalArgumentException(String.format(
"No Person with ID %d found.", personId))); "No Person with ID %d found.", personId)));
personManager.addPersonName(person); personManager.addPersonName(person, new PersonName());
} }
} }

View File

@ -65,7 +65,8 @@ public class ContactEntryKey
@Embedded @Embedded
@AssociationOverride( @AssociationOverride(
name = "values", name = "values",
joinTable = @JoinTable(name = "CONTACT_ENTRY_KEY_LABELS", joinTable = @JoinTable(
name = "CONTACT_ENTRY_KEY_LABELS",
schema = DB_SCHEMA, schema = DB_SCHEMA,
joinColumns = { joinColumns = {
@JoinColumn(name = "KEY_ID") @JoinColumn(name = "KEY_ID")

View File

@ -65,6 +65,7 @@ public class ContactableEntityManager {
contactableEntity.setPostalAddress(postalAddress); contactableEntity.setPostalAddress(postalAddress);
assetRepository.save(postalAddress); assetRepository.save(postalAddress);
assetRepository.save(contactableEntity);
} }
public void removePostalAddressFromContactableEntity( public void removePostalAddressFromContactableEntity(
@ -73,6 +74,7 @@ public class ContactableEntityManager {
contactableEntity.setPostalAddress(null); contactableEntity.setPostalAddress(null);
assetRepository.save(postalAddress); assetRepository.save(postalAddress);
assetRepository.save(contactableEntity);
} }
} }

View File

@ -21,6 +21,9 @@ package org.librecms.assets;
import com.arsdigita.cms.ui.assets.forms.PersonForm; import com.arsdigita.cms.ui.assets.forms.PersonForm;
import org.hibernate.envers.Audited; import org.hibernate.envers.Audited;
import org.librecms.ui.contentsections.assets.MvcAssetEditKit;
import org.librecms.ui.contentsections.assets.PersonCreateStep;
import org.librecms.ui.contentsections.assets.PersonEditStep;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
@ -46,11 +49,17 @@ import static org.librecms.assets.AssetConstants.*;
@Entity @Entity
@Table(name = "PERSONS", schema = DB_SCHEMA) @Table(name = "PERSONS", schema = DB_SCHEMA)
@Audited @Audited
@AssetType(assetForm = PersonForm.class, @AssetType(
assetForm = PersonForm.class,
labelBundle = ASSETS_BUNDLE, labelBundle = ASSETS_BUNDLE,
labelKey = "person.label", labelKey = "person.label",
descriptionBundle = ASSETS_BUNDLE, descriptionBundle = ASSETS_BUNDLE,
descriptionKey = "person.description") descriptionKey = "person.description"
)
@MvcAssetEditKit(
createStep = PersonCreateStep.class,
editStep = PersonEditStep.class
)
public class Person extends ContactableEntity { public class Person extends ContactableEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -18,7 +18,6 @@
*/ */
package org.librecms.assets; package org.librecms.assets;
import java.util.Objects;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
@ -35,17 +34,19 @@ public class PersonManager {
private PersonRepository personRepository; private PersonRepository personRepository;
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public void addPersonName(final Person toPerson) { public void addPersonName(
final Person toPerson, final PersonName personName
final PersonName current = Objects ) {
.requireNonNull(toPerson, "Can't add a name to Person null.") // final PersonName current = Objects
.getPersonName(); // .requireNonNull(toPerson, "Can't add a name to Person null.")
// .getPersonName();
if (current == null) { //
toPerson.addPersonName(new PersonName()); // if (current == null) {
} else { // toPerson.addPersonName(new PersonName());
toPerson.addPersonName(current); // } else {
} // toPerson.addPersonName(current);
// }
toPerson.addPersonName(personName);
personRepository.save(toPerson); personRepository.save(toPerson);
} }

View File

@ -263,8 +263,9 @@ public class AssetRepository
/** /**
* Finds an {@link Asset} by its UUID <strong>and</strong> type.This method * Finds an {@link Asset} by its UUID <strong>and</strong> type.This method
* does not distinguish between shared and non shared assets. does not distinguish between shared and non shared assets.
* *
* @param <T> Type of the asset
* @param uuid The UUID of the asset to retrieve. * @param uuid The UUID of the asset to retrieve.
* @param type The type of the asset to retrieve. * @param type The type of the asset to retrieve.
* *
@ -274,8 +275,9 @@ public class AssetRepository
* {@link Optional} is returned. * {@link Optional} is returned.
*/ */
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public Optional<Asset> findByUuidAndType( @SuppressWarnings("unchecked")
final String uuid, final Class<? extends Asset> type) { public <T extends Asset> Optional<T> findByUuidAndType(
final String uuid, final Class<T> type) {
final TypedQuery<Asset> query = entityManager.createNamedQuery( final TypedQuery<Asset> query = entityManager.createNamedQuery(
"Asset.findByUuidAndType", Asset.class); "Asset.findByUuidAndType", Asset.class);
@ -284,7 +286,11 @@ public class AssetRepository
setAuthorizationParameters(query); setAuthorizationParameters(query);
try { try {
return Optional.of(query.getSingleResult()); final Asset result = query.getSingleResult();
if (result.getClass().isAssignableFrom(type)) {
return Optional.of((T) result);
}
return Optional.empty();
} catch (NoResultException ex) { } catch (NoResultException ex) {
return Optional.empty(); return Optional.empty();
} }

View File

@ -53,6 +53,7 @@ import javax.json.JsonObject;
import javax.json.JsonObjectBuilder; import javax.json.JsonObjectBuilder;
import javax.json.JsonWriter; import javax.json.JsonWriter;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException; import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@ -115,7 +116,7 @@ public class Assets {
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String findAssets( public String findAssets(
@PathParam("content-section") final String section, @PathParam("content-section") final String section,
@QueryParam("query") final String query, @QueryParam("query") @DefaultValue("") final String query,
@QueryParam("type") final String type) { @QueryParam("type") final String type) {
final ContentSection contentSection = sectionRepo final ContentSection contentSection = sectionRepo

View File

@ -76,21 +76,11 @@ public class Images {
@DefaultValue("-1") @DefaultValue("-1")
final String heightParam) { final String heightParam) {
final Optional<Asset> asset = assetRepo final Optional<Image> asset = assetRepo
.findByUuidAndType(uuid, Image.class); .findByUuidAndType(uuid, Image.class);
if (asset.isPresent()) { if (asset.isPresent()) {
if (asset.get() instanceof Image) { return loadImage(asset.get(), widthParam, heightParam);
return loadImage((Image) asset.get(), widthParam, heightParam);
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(String
.format("The asset with the requested UUID \"%s\" "
+ "is not an image.",
uuid))
.build();
}
} else { } else {
return Response return Response
.status(Response.Status.NOT_FOUND) .status(Response.Status.NOT_FOUND)
@ -107,21 +97,12 @@ public class Images {
@PathParam("content-section") final String sectionName, @PathParam("content-section") final String sectionName,
@PathParam("uuid") final String uuid) { @PathParam("uuid") final String uuid) {
final Optional<Asset> asset = assetRepo.findByUuidAndType(uuid, final Optional<Image> asset = assetRepo.findByUuidAndType(
Image.class); uuid, Image.class
);
if (asset.isPresent()) { if (asset.isPresent()) {
if (asset.get() instanceof Image) { return readImageProperties(asset.get());
return readImageProperties((Image) asset.get());
} else {
return Response
.status(Response.Status.NOT_FOUND)
.entity(String
.format("The asset with the requested UUID \"%s\" "
+ "is not an image.",
uuid))
.build();
}
} else { } else {
return Response return Response
.status(Response.Status.NOT_FOUND) .status(Response.Status.NOT_FOUND)

View File

@ -0,0 +1,305 @@
/*
* Copyright (C) 2021 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 org.librecms.ui.contentsections.assets;
import org.libreccm.api.Identifier;
import org.libreccm.api.IdentifierParser;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.AuthorizationRequired;
import org.librecms.assets.ContactEntry;
import org.librecms.assets.ContactEntryKey;
import org.librecms.assets.ContactEntryKeyRepository;
import org.librecms.assets.ContactEntryRepository;
import org.librecms.assets.ContactableEntity;
import org.librecms.assets.ContactableEntityManager;
import org.librecms.assets.PostalAddress;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetRepository;
import org.librecms.ui.contentsections.ContentSectionNotFoundException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.mvc.Models;
import javax.transaction.Transactional;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public abstract class AbstractContactableEntityEditStep
extends AbstractMvcAssetEditStep {
@Inject
private AssetRepository assetRepo;
@Inject
private AssetUi assetUi;
@Inject
private ContactEntryRepository entryRepo;
@Inject
private ContactEntryKeyRepository entryKeyRepo;
@Inject
private ContactableEntityManager contactableManager;
@Inject
private ContactableEntityEditStepModel editStepModel;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private IdentifierParser identifierParser;
@Inject
private Models models;
@Override
@Transactional(Transactional.TxType.REQUIRED)
protected void init() throws ContentSectionNotFoundException,
AssetNotFoundException {
super.init();
if (getAsset() instanceof ContactableEntity) {
editStepModel
.setAvailableContactEntryKeys(
entryKeyRepo
.findAll()
.stream()
.map(this::buildContactEntryKeyListItemModel)
.collect(
Collectors.toMap(
item -> item.getEntryKey(),
item -> item.getLabel()
)
)
);
editStepModel
.setContactEntries(
getContactableEntity()
.getContactEntries()
.stream()
.map(this::buildContactEntryListItemModel)
.collect(Collectors.toList())
);
editStepModel.setPostalAddress(
getContactableEntity().getPostalAddress()
);
} else {
throw new AssetNotFoundException(
assetUi.showAssetNotFound(
getContentSection(), getAssetPath()
),
String.format(
"No ContactableEntity for path %s found in section %s.",
getAssetPath(),
getContentSection().getLabel()
)
);
}
}
protected ContactableEntity getContactableEntity() {
return (ContactableEntity) getAsset();
}
@POST
@Path("/contactentries")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String addContactEntry(
@FormParam("entryKey") final String entryKeyParam,
@FormParam("entryValue") final String entryValue
) {
final Optional<ContactEntryKey> entryKeyResult = entryKeyRepo
.findByEntryKey(entryKeyParam);
if (!entryKeyResult.isPresent()) {
return showContactEntryKeyNoFound(entryKeyParam);
}
final ContactEntryKey entryKey = entryKeyResult.get();
final ContactableEntity contactable = getContactableEntity();
final ContactEntry contactEntry = new ContactEntry();
contactEntry.setKey(entryKey);
contactEntry.setValue(entryValue);
contactableManager.addContactEntryToContactableEntity(
contactEntry, contactable
);
return buildRedirectPathForStep();
}
@POST
@Path("/contactentries/{index}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String updateContactEntry(
@PathParam("index") final int index,
@FormParam("entryValue") final String entryValue
) {
final List<ContactEntry> entries = getContactableEntity()
.getContactEntries();
if (index >= entries.size()) {
return showContactEntryNotFound(index);
}
final ContactEntry entry = entries.get(index);
entry.setValue(entryValue);
entryRepo.save(entry);
return buildRedirectPathForStep();
}
@POST
@Path("/contactentries/{index}/@remove")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String removeContactEntry(
@PathParam("index") final int index
) {
final List<ContactEntry> entries = getContactableEntity()
.getContactEntries();
if (index >= entries.size()) {
return showContactEntryNotFound(index);
}
final ContactEntry entry = entries.get(index);
contactableManager.removeContactEntryFromContactableEntity(
entry, getContactableEntity()
);
return buildRedirectPathForStep();
}
@POST
@Path("/postaladdress")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String setPostalAddress(
final String postalAddressIdentifier
) {
final Identifier identifier = identifierParser
.parseIdentifier(postalAddressIdentifier);
final Optional<PostalAddress> postalAddressResult;
switch (identifier.getType()) {
case ID:
postalAddressResult = assetRepo.findById(
Long.parseLong(identifier.getIdentifier()),
PostalAddress.class
);
break;
case UUID:
postalAddressResult = assetRepo.findByUuidAndType(
identifier.getIdentifier(),
PostalAddress.class
);
break;
default:
postalAddressResult = assetRepo
.findByPath(identifier.getIdentifier())
.map(result -> (PostalAddress) result);
break;
}
if (!postalAddressResult.isPresent()) {
return showPostalAddressNotFound(postalAddressIdentifier);
}
final PostalAddress postalAddress = postalAddressResult.get();
contactableManager.addPostalAddressToContactableEntity(
postalAddress, getContactableEntity()
);
return buildRedirectPathForStep();
}
@POST
@Path("/postaladdress/@remove")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String removePostalAddress() {
contactableManager.removePostalAddressFromContactableEntity(
getContactableEntity().getPostalAddress(), getContactableEntity()
);
return buildRedirectPathForStep();
}
private String showContactEntryNotFound(
final int index
) {
models.put("entryIndex", index);
return "org/librecms/ui/contentsection/assets/contactable/entry-not-found.xhtml";
}
private String showContactEntryKeyNoFound(final String entryKeyParam) {
models.put("entryKeyParam", entryKeyParam);
return "org/librecms/ui/contentsection/assets/contactable/entry-key-not-found.xhtml";
}
private String showPostalAddressNotFound(
final String postalAddressIdentifier
) {
models.put("postalAddressIdentifier", postalAddressIdentifier);
return "org/librecms/ui/contentsection/assets/contactable/postal-address-not-found.xhtml";
}
private ContactEntryKeyListItemModel buildContactEntryKeyListItemModel(
final ContactEntryKey entryKey
) {
final ContactEntryKeyListItemModel model
= new ContactEntryKeyListItemModel();
model.setKeyId(entryKey.getKeyId());
model.setEntryKey(entryKey.getEntryKey());
model.setLabel(
globalizationHelper.getValueFromLocalizedString(
entryKey.getLabel())
);
return model;
}
private ContactEntryListItemModel buildContactEntryListItemModel(
final ContactEntry entry
) {
final ContactEntryListItemModel model = new ContactEntryListItemModel();
model.setContactEntryId(entry.getContactEntryId());
model.setEntryKey(entry.getKey().getEntryKey());
model.setEntryKeyId(entry.getKey().getKeyId());
model.setEntryKeyLabel(
globalizationHelper.getValueFromLocalizedString(
entry.getKey().getLabel()
)
);
model.setOrder(entry.getOrder());
model.setValue(entry.getValue());
return model;
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 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 org.librecms.ui.contentsections.assets;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ContactEntryKeyListItemModel {
private long keyId;
private String entryKey;
private String label;
public long getKeyId() {
return keyId;
}
protected void setKeyId(final long keyId) {
this.keyId = keyId;
}
public String getEntryKey() {
return entryKey;
}
protected void setEntryKey(final String entryKey) {
this.entryKey = entryKey;
}
public String getLabel() {
return label;
}
protected void setLabel(final String label) {
this.label = label;
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2021 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 org.librecms.ui.contentsections.assets;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class ContactEntryListItemModel {
private long contactEntryId;
private long order;
private long entryKeyId;
private String entryKey;
private String entryKeyLabel;
private String value;
public long getContactEntryId() {
return contactEntryId;
}
protected void setContactEntryId(final long contactEntryId) {
this.contactEntryId = contactEntryId;
}
public long getOrder() {
return order;
}
protected void setOrder(final long order) {
this.order = order;
}
public long getEntryKeyId() {
return entryKeyId;
}
protected void setEntryKeyId(final long entryKeyId) {
this.entryKeyId = entryKeyId;
}
public String getEntryKey() {
return entryKey;
}
protected void setEntryKey(final String entryKey) {
this.entryKey = entryKey;
}
public String getEntryKeyLabel() {
return entryKeyLabel;
}
protected void setEntryKeyLabel(final String entryKeyLabel) {
this.entryKeyLabel = entryKeyLabel;
}
public String getValue() {
return value;
}
protected void setValue(final String value) {
this.value = value;
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2021 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 org.librecms.ui.contentsections.assets;
import org.librecms.assets.PostalAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsContactableEditStepModel")
public class ContactableEntityEditStepModel {
private Map<String, String> availableContactEntryKeys;
private List<ContactEntryListItemModel> contactEntries;
private PostalAddress postalAddress;
public Map<String, String> getAvailableContactEntryKeys() {
return Collections.unmodifiableMap(availableContactEntryKeys);
}
public void setAvailableContactEntryKeys(
final Map<String, String> availableContactEntryKeys
) {
this.availableContactEntryKeys = new HashMap<>(
availableContactEntryKeys
);
}
public List<ContactEntryListItemModel> getContactEntries() {
return Collections.unmodifiableList(contactEntries);
}
protected void setContactEntries(
final List<ContactEntryListItemModel> contactEntries
) {
this.contactEntries = new ArrayList<>(contactEntries);
}
public PostalAddress getPostalAddress() {
return postalAddress;
}
protected void setPostalAddress(final PostalAddress postalAddress) {
this.postalAddress = postalAddress;
}
}

View File

@ -29,18 +29,14 @@ import org.librecms.contentsection.AssetRepository;
import org.librecms.ui.contentsections.AssetPermissionsChecker; import org.librecms.ui.contentsections.AssetPermissionsChecker;
import org.librecms.ui.contentsections.ContentSectionNotFoundException; import org.librecms.ui.contentsections.ContentSectionNotFoundException;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URLConnection;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.activation.MimeType; import javax.activation.MimeType;

View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2021 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 org.librecms.ui.contentsections.assets;
import org.libreccm.l10n.GlobalizationHelper;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import org.librecms.assets.Person;
import org.librecms.contentsection.AssetRepository;
import java.util.Map;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPersonCreateStep")
public class PersonCreateStep extends AbstractMvcAssetCreateStep<Person> {
@Inject
private AssetRepository assetRepo;
@Inject
private GlobalizationHelper globalizationHelper;
@Override
public String showCreateStep() {
return "org/librecms/ui/contentsection/assets/person/create-person.xhtml";
}
@Override
public String getLabel() {
return globalizationHelper
.getLocalizedTextsUtil(getBundle())
.getText("person.label");
}
@Override
public String getDescription() {
return globalizationHelper
.getLocalizedTextsUtil(getBundle())
.getText("person.description");
}
@Override
public String getBundle() {
return MvcAssetStepsConstants.BUNDLE;
}
@Override
protected Class<Person> getAssetClass() {
return Person.class;
}
@Override
protected String setAssetProperties(
final Person person, final Map<String, String[]> formParams
) {
return String.format(
"redirect:/%s/assets/%s/%s/@person-edit",
getContentSectionLabel(),
getFolderPath(),
getName()
);
}
}

View File

@ -0,0 +1,265 @@
/*
* Copyright (C) 2021 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 org.librecms.ui.contentsections.assets;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.AuthorizationRequired;
import org.librecms.assets.Person;
import org.librecms.assets.PersonManager;
import org.librecms.assets.PersonName;
import org.librecms.contentsection.AssetRepository;
import org.librecms.ui.contentsections.AssetPermissionsChecker;
import org.librecms.ui.contentsections.ContentSectionNotFoundException;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.transaction.Transactional;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Path(MvcAssetEditSteps.PATH_PREFIX + "person-edit")
@Controller
@MvcAssetEditStepDef(
bundle = MvcAssetStepsConstants.BUNDLE,
descriptionKey = "person.editstep.description",
labelKey = "person.editstep.lable",
supportedAssetType = Person.class
)
public class PersonEditStep extends AbstractContactableEntityEditStep {
@Inject
private AssetStepsDefaultMessagesBundle messageBundle;
@Inject
private AssetPermissionsChecker assetPermissionsChecker;
@Inject
private AssetRepository assetRepo;
@Inject
private AssetUi assetUi;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private PersonEditStepModel editStepModel;
@Inject
private PersonManager personManager;
@Override
public Class<? extends MvcAssetEditStep> getStepClass() {
return PersonEditStep.class;
}
protected Person getPerson() {
return (Person) getAsset();
}
@Override
protected void init() throws ContentSectionNotFoundException,
AssetNotFoundException {
super.init();
if (getAsset() instanceof Person) {
editStepModel.setBirthdate(
DateTimeFormatter
.ofLocalizedDate(FormatStyle.SHORT)
.withLocale(globalizationHelper.getNegotiatedLocale())
.format(getPerson().getBirthdate())
);
editStepModel.setPersonNames(getPerson().getPersonNames());
} else {
throw new AssetNotFoundException(
assetUi.showAssetNotFound(
getContentSection(), getAssetPath()
),
String.format(
"No Person for path %s found in section %s.",
getAssetPath(),
getContentSection().getLabel()
)
);
}
}
@GET
@Path("/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
@Override
public String showStep(
@PathParam(MvcAssetEditSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAssetEditSteps.ASSET_PATH_PATH_PARAM_NAME)
final String assetPath
) {
try {
init();
} catch (ContentSectionNotFoundException ex) {
return ex.showErrorMessage();
} catch (AssetNotFoundException ex) {
return ex.showErrorMessage();
}
if (assetPermissionsChecker.canEditAsset(getAsset())) {
return "org/librecms/ui/contentsection/assets/person/edit-person.xhtml";
} else {
return assetUi.showAccessDenied(
getContentSection(),
getAsset(),
messageBundle.get("asset.edit.denied"));
}
}
@POST
@Path("/personnames/@add")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String addPersonName(
@PathParam(MvcAssetEditSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAssetEditSteps.ASSET_PATH_PATH_PARAM_NAME)
final String assetPath,
@FormParam("surname") final String surname,
@FormParam("givenName") final String givenName,
@FormParam("prefix") final String prefix,
@FormParam("suffix") final String suffix
) {
try {
init();
} catch (ContentSectionNotFoundException ex) {
return ex.showErrorMessage();
} catch (AssetNotFoundException ex) {
return ex.showErrorMessage();
}
if (assetPermissionsChecker.canEditAsset(getAsset())) {
final PersonName personName = new PersonName();
personName.setGivenName(givenName);
personName.setPrefix(prefix);
personName.setSuffix(suffix);
personName.setSurname(surname);
personManager.addPersonName(getPerson(), personName);
return buildRedirectPathForStep();
} else {
return assetUi.showAccessDenied(
getContentSection(),
getAsset(),
messageBundle.get("asset.edit.denied"));
}
}
@POST
@Path("/personnames/{index}/@edit")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String updatePersonName(
@PathParam(MvcAssetEditSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAssetEditSteps.ASSET_PATH_PATH_PARAM_NAME)
final String assetPath,
@PathParam("index") final int index,
@FormParam("surname") final String surname,
@FormParam("givenName") final String givenName,
@FormParam("prefix") final String prefix,
@FormParam("suffix") final String suffix
) {
try {
init();
} catch (ContentSectionNotFoundException ex) {
return ex.showErrorMessage();
} catch (AssetNotFoundException ex) {
return ex.showErrorMessage();
}
if (assetPermissionsChecker.canEditAsset(getAsset())) {
if (index < getPerson().getPersonNames().size()) {
final PersonName personName = getPerson()
.getPersonNames()
.get(index);
personName.setGivenName(givenName);
personName.setPrefix(prefix);
personName.setSuffix(suffix);
personName.setSurname(surname);
assetRepo.save(getPerson());
}
return buildRedirectPathForStep();
} else {
return assetUi.showAccessDenied(
getContentSection(),
getAsset(),
messageBundle.get("asset.edit.denied"));
}
}
@POST
@Path("/personnames/{index}/@remove")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String removePersonName(
@PathParam(MvcAssetEditSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAssetEditSteps.ASSET_PATH_PATH_PARAM_NAME)
final String assetPath,
@PathParam("index") final int index
) {
try {
init();
} catch (ContentSectionNotFoundException ex) {
return ex.showErrorMessage();
} catch (AssetNotFoundException ex) {
return ex.showErrorMessage();
}
if (assetPermissionsChecker.canEditAsset(getAsset())) {
if (index < getPerson().getPersonNames().size()) {
final PersonName personName = getPerson()
.getPersonNames()
.get(index);
personManager.removePersonName(getPerson(), personName);
}
return buildRedirectPathForStep();
} else {
return assetUi.showAccessDenied(
getContentSection(),
getAsset(),
messageBundle.get("asset.edit.denied"));
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2021 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 org.librecms.ui.contentsections.assets;
import org.librecms.assets.PersonName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("CmsPersonEditStepModel")
public class PersonEditStepModel {
private List<PersonName> personName;
private String birthdate;
public List<PersonName> getPersonNames() {
return Collections.unmodifiableList(personName);
}
protected void setPersonNames(final List<PersonName> personNames) {
this.personName = new ArrayList<>(personNames);
}
public String getBirthdate() {
return birthdate;
}
protected void setBirthdate(final String birthdate) {
this.birthdate = birthdate;
}
}

View File

@ -0,0 +1,145 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<cc:interface shortDescription="An component for selecting assets.">
<cc:attribute name="action"
required="true"
shortDescription="Action to trigger when an asset has been selected."
type="String" />
<cc:attribute name="assetType"
required="false"
shortDescription="Type of assets to show."
type="String"
default="org.librecms.assets.Asset" />
<cc:attribute name="assetPickerId"
required="true"
shortDescription="ID of the asset picker"
type="String" />
<cc:attribute name="contentSection"
required="true"
shortDescription="The current content section."
type="String" />
<cc:attribute name="dialogTitle"
required="false"
shortDescription="Title of the asset picker dialog"
default="#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.title']}"
type="String"
/>
<cc:attribute name="formParamName"
required="true"
shortDescription="The name of the form parameter that will contain the UUID of the selected asset."
type="String"
/>
<cc:attribute name="headingLevel"
required="false"
shortDescription="The level of the heading used as title of the asset picker dialog."
default="3"
type="int" />
</cc:interface>
<cc:implementation>
<div class="ccm-cms-asset-picker"
data-assettype="#{cc.attrs.assetType}"
data-contentsection="#{cc.attrs.contentSection}">
<div aria-hidden="true"
aria-labelledby="#{cc.attrs.assetPickerId}-dialog-title"
class="modal fade"
id="#{cc.attrs.assetPickerId}-dialog"
tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<c:choose>
<c:when test="#{cc.attrs.headingLevel == 1}">
<h1 class="modal-title"
id="#{cc.attrs.assetPickerId}-dialog-title">#{cc.attrs.dialogTitle}</h1>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 2}">
<h2 class="modal-title"
id="#{cc.attrs.assetPickerId}-dialog-title">#{cc.attrs.dialogTitle}</h2>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 3}">
<h3 class="modal-title"
id="#{cc.attrs.assetPickerId}-dialog-title">#{cc.attrs.dialogTitle}</h3>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 4}">
<h4 class="modal-title"
id="#{cc.attrs.assetPickerId}-dialog-title">#{cc.attrs.dialogTitle}</h4>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 5}">
<h5 class="modal-title"
id="#{cc.attrs.assetPickerId}-dialog-title">#{cc.attrs.dialogTitle}</h5>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 6}">
<h6 class="modal-title"
id="#{cc.attrs.assetPickerId}-dialog-title">#{cc.attrs.dialogTitle}</h6>
</c:when>
<c:otherwise>
<div><strong>#{cc.attrs.dialogTitle}</strong></div>
</c:otherwise>
</c:choose>
<button
aria-label="#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.close']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x" />
</button>
</div>
<form action="#{cc.attrs.action}"
class="modal-content"
method="post">
<input class="assetpicker-param"
id="#{cc.attrs.assetPickerId}-param-input"
name="#{cc.attrs.formParamName}"
type="hidden" />
<bootstrap:formGroupText
class="assetpicker-filter"
help="#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.filter.help']}"
inputId="#{cc.attrs.assetPickerId}-filter"
label="#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.filter.label']}"
name="" />
<template id="#{cc.attrs.assetPickerId}-row">
<tr>
<td class="col-name"></td>
<td class="col-type"></td>
<td class="col-action">
<button class="btn btn-primary"
data-assetuuid=""
type="button">
#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.select']}
</button>
</td>
</tr>
</template>
<table>
<thead>
<tr>
<th>#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.column.name']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.column.type']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.column.action']}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</form>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{CmsAssetsStepsDefaultMessagesBundle['assetpicker.close']}
</button>
</div>
</div>
</div>
</div>
</div>
</cc:implementation>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<cc:interface shortDescription="An component for selecting assets.">
<cc:attribute name="assetPickerId"
required="true"
shortDescription="ID of the asset picker"
type="String" />
</cc:interface>
<cc:implementation>
<button class="btn btn-primary"
data-toggle="modal"
data-target="##{cc.attrs.assetPickerId}-dialog"
type="button" />
</cc:implementation>
</html>

View File

@ -0,0 +1,43 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition>
<h3>#{CmsAssetsStepsDefaultMessagesBundle['contactable.contactentries.title']}</h3>
<table>
<thead>
<tr>
<th>#{CmsAssetsStepsDefaultMessagesBundle['contactable.contactentries.cols.key']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['contactable.contactentries.cols.value']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['contactable.contactentries.cols.actions']}</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{CmsContactableEditStepModel.contactEntries}"
var="entry">
<tr data-entrykey="#{entry.entryKey}">
<td>#{entry.entryKeyLabel}</td>
<td>#{entry.value}</td>
<td>
<button class="btn btn-primary"
type="button">
<bootstrap:svgIcon icon="pen" />
<span class="sr-only">#{CmsAssetsStepsDefaultMessagesBundle['contactable.contactentries.edit']}</span>
</button>
<button class="btn btn-danger"
type="button">
<bootstrap:svgIcon icon="x-circle" />
<span class="sr-only">#{CmsAssetsStepsDefaultMessagesBundle['contactable.contactentries.remove']}</span>
</button>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</ui:composition>
</html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/contentsection.xhtml">
<ui:define name="main">
<div class="container">
<h1>#{CmsAssetsStepsDefaultMessagesBundle["person.createform.title"]}</h1>
<c:forEach items="#{CmsBookmarkCreateStep.messages.entrySet()}"
var="message">
<div class="alert alert-#{message.key}" role="alert">
#{message.value}
</div>
</c:forEach>
<form action="#{mvc.basePath}/#{CmsPersonCreateStep.contentSectionLabel}/assets/#{CmsPersonCreateStep.folderPath}@create/#{CmsPersonCreateStep.assetType}"
method="post">
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['createform.name.help']}"
inputId="name"
label="#{CmsAssetsStepsDefaultMessagesBundle['createform.name.label']}"
name="name"
pattern="^([a-zA-Z0-9_-]*)$"
required="true"
value="#{CmsBookmarkCreateStep.name}"
/>
<bootstrap:formGroupSelect
help="#{CmsAssetsStepsDefaultMessagesBundle['createform.initial_locale.help']}"
inputId="locale"
label="#{CmsAssetsStepsDefaultMessagesBundle['createform.initial_locale.label']}"
name="locale"
options="#{CmsBookmarkCreateStep.availableLocales}"
required="true"
selectedOptions="#{[CmsBookmarkCreateStep.initialLocale]}"
/>
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['createform.title.help']}"
inputId="title"
label="#{CmsAssetsStepsDefaultMessagesBundle['createform.title.label']}"
name="title"
required="true"
/>
<a class="btn btn-warning"
href="#{mvc.basePath}/#{CmsBookmarkCreateStep.contentSectionLabel}/assetfolders/#{CmsBookmarkCreateStep.folderPath}">
#{CmsAssetsStepsDefaultMessagesBundle['createform.cancel']}
</a>
<button class="btn btn-success"
type="submit">
#{CmsAssetsStepsDefaultMessagesBundle['createform.submit']}
</button>
</form>
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,255 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/assets/editstep.xhtml">
<ui:param name="stepControllerUrl"
value="@person-edit"
/>
<ui:param name="title"
value="#{CmsAssetsStepsDefaultMessagesBundle.getMessage('person.editstep.header', [MvcAssetEditStepModel.name])}"
/>
<ui:define name="editStep">
<h3>#{CmsAssetsStepsDefaultMessagesBundle['person.personnames']}</h3>
<div class="text-right">
<button class="btn btn-primary"
data-toggle="modal"
data-target="#add-personname-dialog"
type="button">
<bootstrap:svgIcon icon="plus-circle" />
<span class="sr-only">#{CmsAssetsStepsDefaultMessagesBundle['person.personname.add']}</span>
</button>
</div>
<div aria-hidden="true"
aria-labelledby="add-personname-dialog-title"
class="modal fade"
id="add-personname-dialog"
tab accesskey="-1"
>
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/asset/#{CmsSelectedAssetModel.assetPath}/@person-edit/personnames/@add"
class="modal-content"
method="post">
<div class="modal-header">
<h4 id="add-personname-dialog-title">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.add.dialog.title']}
</h4>
<button
aria-label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.add.dialog.close']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x" />
</button>
</div>
<div class="modal-body">
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.prefix.help']}"
inputId="prefix"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.prefix.label']}"
name="prefix" />
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.surname.help']}"
inputId="surname"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.surname.label']}"
name="surname" />
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.givenname.help']}"
inputId="givenName"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.givenname.label']}"
name="givenName" />
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.suffix.help']}"
inputId="suffix"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.suffix.label']}"
name="suffix" />
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.add.dialog.close']}
</button>
<button class="btn btn-success"
type="submit">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.add.dialog.submit']}
</button>
</div>
</form>
</div>
</div>
<table>
<thead>
<tr>
<th>#{CmsAssetsStepsDefaultMessagesBundle['person.personnames.col.prefix']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['person.personnames.col.surname']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['person.personnames.col.givenname']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['person.personnames.col.suffix']}</th>
<th>#{CmsAssetsStepsDefaultMessagesBundle['person.personnames.col.actions']}</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{CmsPersonEditStepModel.personNames}"
var="personName">
<tr>
<td>#{personName.prefix}</td>
<td>#{personName.surname}</td>
<td>#{personName.givenName}</td>
<td>#{personName.suffix}</td>
<td>
<button class="btn btn-primary"
data-toggle="modal"
data-target="#personname-edit-dialog-#{personName.hashCode()}"
type="button">
<bootstrap:svgIcon icon="pen" />
<span class="sr-only">#{CmsAssetsStepsDefaultMessagesBundle['person.personname.edit']}</span>
</button>
<div aria-hidden="true"
aria-lablledby="personname-edit-dialog-#{personName.hashCode()}-title"
class="modal fade"
id="personname-edit-dialog-#{personName.hashCode()}"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/asset/#{CmsSelectedAssetModel.assetPath}/@person-edit/personnames/@edit"
class="modal-content"
method="post">
<div class="modal-header">
<h4 id="personname-edit-dialog-#{personName.hashCode()}-title">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.edit.dialog.title']}
</h4>
<button
aria-label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.edit.dialog.close']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x" />
</button>
</div>
<div class="modal-body">
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.prefix.help']}"
inputId="prefix"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.prefix.label']}"
name="prefix"
value="#{personName.prefix}" />
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.surname.help']}"
inputId="surname"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.surname.label']}"
name="surname"
value="#{personName.surname}" />
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.givenname.help']}"
inputId="givenName"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.givenname.label']}"
name="givenName"
value="#{personName.givenName}" />
<bootstrap:formGroupText
help="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.suffix.help']}"
inputId="suffix"
label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.suffix.label']}"
name="suffix"
value="#{personName.suffix}" />
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.edit.dialog.close']}
</button>
<button class="btn btn-success"
type="submit">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.edit.dialog.submit']}
</button>
</div>
</form>
</div>
</div>
<button class="btn btn-danger"
data-toggle="modal"
data-target="#personname-remove-dialog-#{personName.hashCode()}"
type="button">
<bootstrap:svgIcon icon="x-circle" />
<span class="sr-only">#{CmsAssetsStepsDefaultMessagesBundle['person.personname.remove']}</span>
</button>
<div aria-hidden="true"
aria-lablledby="personname-remove-dialog-#{personName.hashCode()}-title"
class="modal fade"
id="personname-remove-dialog-#{personName.hashCode()}"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/asset/#{CmsSelectedAssetModel.assetPath}/@person-edit/personnames/@remove"
class="modal-content"
method="post">
<div class="modal-header">
<h4 id="personname-edit-dialog-#{personName.hashCode()}-title">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.remove.dialog.title']}
</h4>
<button
aria-label="#{CmsAssetsStepsDefaultMessagesBundle['person.personname.remove.dialog.close']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x" />
</button>
</div>
<div class="modal-body">
<input name="confirmed"
type="hidden"
value="true"/>
<p>
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.remove.dialog.message']}
</p>
<dl>
<div>
<dt>person.personname.prefix.label</dt>
<dd>#{personName.prefix}</dd>
</div>
<div>
<dt>person.personname.surname.label</dt>
<dd>#{personName.surname}</dd>
</div>
<div>
<dt>person.personname.givename.label</dt>
<dd>#{personName.givenName}</dd>
</div>
<div>
<dt>person.personname.suffix.label</dt>
<dd>#{personName.suffix}</dd>
</div>
</dl>
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.remove.dialog.close']}
</button>
<button class="btn btn-success"
type="submit">
#{CmsAssetsStepsDefaultMessagesBundle['person.personname.remove.dialog.submit']}
</button>
</div>
</form>
</div>
</div>
</td>
</tr>
</c:forEach>
</tbody>
</table>
<ui:include src="../edit-contactable.xhtml" />
</ui:define>
</ui:composition>
</html>

View File

@ -88,3 +88,10 @@ relatedinfo.attachmentlists.attachment.remove.cancel=Cancel
relatedinfo.attachmentlists.attachment.remove.confirm=Remove attachment from list relatedinfo.attachmentlists.attachment.remove.confirm=Remove attachment from list
relatedinfo.attachmentlists.attachment.remove.title=Remove Attachment from List relatedinfo.attachmentlists.attachment.remove.title=Remove Attachment from List
relatedinfo.attachmentlists.attachment.remove.message=Are you sure to remove the attachment {0} from the list? relatedinfo.attachmentlists.attachment.remove.message=Are you sure to remove the attachment {0} from the list?
assetpicker.title=Select asset to use
assetpicker.close=Cancel
assetpicker.select=Use this asset
assetpicker.column.name=Name
assetpicker.column.type=Typ
assetpicker.column.action=Action
person.createform.title=Create new Person

View File

@ -88,3 +88,10 @@ relatedinfo.attachmentlists.attachment.remove.cancel=Abbrechen
relatedinfo.attachmentlists.attachment.remove.confirm=Anhang aus Liste entfernen relatedinfo.attachmentlists.attachment.remove.confirm=Anhang aus Liste entfernen
relatedinfo.attachmentlists.attachment.remove.title=Anhang aus Liste entfernen relatedinfo.attachmentlists.attachment.remove.title=Anhang aus Liste entfernen
relatedinfo.attachmentlists.attachment.remove.message=Sind Sie sicher, dass Sie den Anhang {0} aus der Listen entfernen wollen? relatedinfo.attachmentlists.attachment.remove.message=Sind Sie sicher, dass Sie den Anhang {0} aus der Listen entfernen wollen?
assetpicker.title=Asset ausw\u00e4hlen
assetpicker.close=Abbrechen
assetpicker.select=Dieses Asset verwenden
assetpicker.column.name=Name
assetpicker.column.type=Typ
assetpicker.column.action=Aktion
person.createform.title=Neue Person erstellen

View File

@ -1,2 +1,3 @@
import "bootstrap"; import "bootstrap";
import "./cms-assetpicker";

View File

@ -0,0 +1,70 @@
import * as $ from "jquery";
document.addEventListener("DOMContentLoaded", function (event) {
const assetPickers = document.querySelectorAll("ccm-cms-asset-picker");
for (let i = 0; i < assetPickers.length; i++) {
initAssetPicker(assetPickers[i]);
}
});
async function initAssetPicker(assetPickerElem: Element) {
const assetPickerId = assetPickerElem.getAttribute("id");
const assetType = getAssetType(assetPickerElem);
const contentSection = assetPickerElem.getAttribute("data-contentsection");
try {
const response = await fetch(
`/content-sections/${contentSection}/assets/?type=${assetType}`
);
if (response.ok) {
const assets = (await response.json()) as [];
const rowTemplate = assetPickerElem.querySelector(
`#${assetPickerId}-row`
);
const tbody = assetPickerElem.querySelector("tbody");
for (const asset of assets) {
const row = rowTemplate.cloneNode(true) as Element;
const colName = row.querySelector(".col-name");
const colType = row.querySelector(".col-type");
const selectButton = row.querySelector(".col-action button");
colName.textContent = asset["name"];
colType.textContent = asset["type"];
selectButton.setAttribute("data-assetuuid", asset["uuid"]);
selectButton.addEventListener("click", event =>
selectAsset(event, assetPickerElem)
);
tbody.appendChild(row);
}
} else {
}
} catch (error) {}
}
function getAssetType(assetPickerElem: Element) {
if (assetPickerElem.hasAttribute("data-assettype")) {
return assetPickerElem.getAttribute("data-assettype");
} else {
return "org.librecms.assets.Asset";
}
}
async function selectAsset(event: Event, assetPickerElem: Element) {
const selectButton = event.currentTarget as Element;
const assetUuid = selectButton.getAttribute("data-assetuuid");
const assetPickerParam = assetPickerElem.querySelector(
".assetpicker-param"
) as HTMLInputElement;
assetPickerParam.value = assetUuid;
const form = assetPickerElem.querySelector("form") as HTMLFormElement;
form.submit();
}