Views for creating and editing SciDepartment items.

pull/1/head
Jens Pelzetter 2022-10-03 13:37:34 +02:00
parent c094c8aa58
commit 1c21f2a898
20 changed files with 5419 additions and 14 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
{
"name": "sci-types-department",
"version": "7.0.0",
"description": "JavaScript parts of the UI of sci-types-department",
"main": "index.js",
"scripts": {
"build": "npm-run-all build:*",
"build:js": "webpack"
},
"author": "Jens Pelzetter",
"license": "LGPL-3.0-or-later",
"devDependencies": {
"@types/sortablejs": "^1.10.7",
"npm-run-all": "^4.1.5",
"ts-loader": "^9.2.6",
"typescript": "^4.4.3",
"webpack": "^5.55.1",
"webpack-cli": "^4.8.0"
},
"dependencies": {
"sortablejs": "^1.14.0"
},
"targets": {
"main": false
}
}

View File

@ -166,7 +166,7 @@
</configuration> </configuration>
</plugin> </plugin>
<!-- <plugin> <plugin>
<groupId>com.github.eirslett</groupId> <groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId> <artifactId>frontend-maven-plugin</artifactId>
<configuration> <configuration>
@ -188,7 +188,7 @@
<goal>npm</goal> <goal>npm</goal>
</goals> </goals>
<configuration> <configuration>
<arguments> - -userconfig ../libreccm.npmrc install</arguments> <arguments>--userconfig ../libreccm.npmrc install</arguments>
</configuration> </configuration>
</execution> </execution>
<execution> <execution>
@ -201,7 +201,7 @@
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin>--> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View File

@ -18,7 +18,7 @@ public class SciDepartmentConfig {
@Setting @Setting
private String memberRolesBundleName private String memberRolesBundleName
= "org.scientificcms.contenttypes.scidepartment.MemberRoles"; = "org.scientificcms.contenttypes.scidepartment.DefaultMemberRoles";
@Setting @Setting
private String textKeysBundleName private String textKeysBundleName

View File

@ -0,0 +1,29 @@
package org.scientificcms.contenttypes.scidepartment.ui;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.ui.AbstractMessagesBean;
import org.scientificcms.contenttypes.scidepartment.SciDepartmentConfig;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("SciDepartmentContactTypes")
public class SciDepartmentContactTypes extends AbstractMessagesBean {
@Inject
private ConfigurationManager confManager;
@Override
protected String getMessageBundle() {
return confManager
.findConfiguration(SciDepartmentConfig.class)
.getContactTypesBundleName();
}
}

View File

@ -18,8 +18,11 @@
*/ */
package org.scientificcms.contenttypes.scidepartment.ui; package org.scientificcms.contenttypes.scidepartment.ui;
import com.arsdigita.kernel.KernelConfig;
import org.libreccm.api.Identifier; import org.libreccm.api.Identifier;
import org.libreccm.api.IdentifierParser; import org.libreccm.api.IdentifierParser;
import org.libreccm.configuration.ConfigurationManager;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
@ -90,6 +93,10 @@ public class SciDepartmentDescriptionStep extends AbstractMvcAuthoringStep {
@Inject @Inject
private BaseUrl baseUrl; private BaseUrl baseUrl;
@Inject
private ConfigurationManager confManager;
@Inject @Inject
private ContentItemRepository itemRepo; private ContentItemRepository itemRepo;
@ -137,6 +144,9 @@ public class SciDepartmentDescriptionStep extends AbstractMvcAuthoringStep {
@Inject @Inject
private SciDepartmentTextsModel textsModel; private SciDepartmentTextsModel textsModel;
@Inject
private SciDepartmentTexts texts;
@Override @Override
public Class<SciDepartmentDescriptionStep> getStepClass() { public Class<SciDepartmentDescriptionStep> getStepClass() {
@ -428,9 +438,7 @@ public class SciDepartmentDescriptionStep extends AbstractMvcAuthoringStep {
final String sectionIdentifier, final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPath, final String documentPath,
@FormParam("textKey") final String textKey, @FormParam("textKey") final String textKey
@FormParam("locale") final String localeParam,
@FormParam("textValue") final String textValue
) { ) {
try { try {
init(); init();
@ -441,9 +449,11 @@ public class SciDepartmentDescriptionStep extends AbstractMvcAuthoringStep {
} }
if (itemPermissionChecker.canEditItem(getDepartment())) { if (itemPermissionChecker.canEditItem(getDepartment())) {
final Locale locale = new Locale(localeParam); final Locale locale = confManager
.findConfiguration(KernelConfig.class)
.getDefaultLocale();
final LocalizedString text = new LocalizedString(); final LocalizedString text = new LocalizedString();
text.putValue(locale, textValue); text.putValue(locale, "");
departmentManager.addText(text, getDepartment(), textKey); departmentManager.addText(text, getDepartment(), textKey);
itemRepo.save(getDepartment()); itemRepo.save(getDepartment());
@ -644,7 +654,7 @@ public class SciDepartmentDescriptionStep extends AbstractMvcAuthoringStep {
@Path("/texts/remove/{textKey}") @Path("/texts/remove/{textKey}")
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@AuthorizationRequired @AuthorizationRequired
public String removeTextValue( public String removeText(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM) @PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier, final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME) @PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
@ -1074,6 +1084,13 @@ public class SciDepartmentDescriptionStep extends AbstractMvcAuthoringStep {
) )
) )
); );
textsModel.setAvailableTextKeys(
texts
.keySet()
.stream()
.filter(key -> !textsModel.getTexts().containsKey(key))
.collect(Collectors.toList())
);
contactsModel.setCanEdit(canEdit); contactsModel.setCanEdit(canEdit);
contactsModel.setContacts( contactsModel.setContacts(

View File

@ -1,16 +1,25 @@
package org.scientificcms.contenttypes.scidepartment.ui; package org.scientificcms.contenttypes.scidepartment.ui;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/** /**
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
@RequestScoped
@Named("SciDepartmentTextsModel")
public class SciDepartmentTextsModel { public class SciDepartmentTextsModel {
private boolean canEdit; private boolean canEdit;
private List<String> availableTextKeys;
private Map<String, SciDepartmentTextModel> texts; private Map<String, SciDepartmentTextModel> texts;
@ -25,6 +34,14 @@ public class SciDepartmentTextsModel {
protected void setCanEdit(final boolean canEdit) { protected void setCanEdit(final boolean canEdit) {
this.canEdit = canEdit; this.canEdit = canEdit;
} }
public List<String> getAvailableTextKeys() {
return Collections.unmodifiableList(availableTextKeys);
}
protected void setAvailableTextKeys(final List<String> availableTextKeys) {
this.availableTextKeys = new ArrayList<>(availableTextKeys);
}
public Map<String, SciDepartmentTextModel> getTexts() { public Map<String, SciDepartmentTextModel> getTexts() {
return Collections.unmodifiableMap(texts); return Collections.unmodifiableMap(texts);

View File

@ -0,0 +1,125 @@
package org.scientificcms.contenttypes.scidepartment.ui;
import org.jsoup.Jsoup;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentSection;
import org.librecms.ui.contentsections.ContentSectionsUi;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import org.librecms.ui.contentsections.documents.MvcAuthoringSteps;
import org.scientificcms.contenttypes.scidepartment.SciDepartment;
import java.util.Locale;
import java.util.Optional;
import java.util.StringTokenizer;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Path(MvcAuthoringSteps.PATH_PREFIX + "scidepartment-texts-resources")
public class SciDepartmentTextsResources {
@Inject
private ContentItemRepository itemRepo;
@Inject
private ContentSectionsUi sectionsUi;
@Inject
private ItemPermissionChecker itemPermissionChecker;
@GET
@Path("/department-texts/{textKey}/wordcount/{locale}")
@Produces(MediaType.TEXT_HTML)
@Transactional(Transactional.TxType.REQUIRED)
public String getDepartmentDescriptionWordCount(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPathParam,
@PathParam("textKey") final String textKey,
@PathParam("locale") final String localeParam
) {
final ContentSection contentSection = sectionsUi
.findContentSection(sectionIdentifier)
.orElseThrow(
() -> new NotFoundException()
);
final ContentItem document = itemRepo
.findByPath(contentSection, documentPathParam)
.orElseThrow(
() -> new NotFoundException()
);
if (!(document instanceof SciDepartment)) {
throw new NotFoundException();
}
final SciDepartment department = (SciDepartment) document;
if (itemPermissionChecker.canEditItem(department)) {
return Optional
.ofNullable(department.getAdditionalTexts().get(textKey))
.map(text -> text.getText().getValue(new Locale(localeParam)))
.map(text -> Jsoup.parseBodyFragment(text))
.map(jsoupDoc -> jsoupDoc.body().text())
.map(text -> new StringTokenizer(text).countTokens())
.map(Long::toString)
.orElseThrow(() -> new NotFoundException());
} else {
throw new ForbiddenException();
}
}
@GET
@Path("/department-texts/{textKey}/{locale}")
@Produces(MediaType.TEXT_HTML)
@Transactional(Transactional.TxType.REQUIRED)
public String viewDepartmentDescriptionValue(
@PathParam(MvcAuthoringSteps.SECTION_IDENTIFIER_PATH_PARAM)
final String sectionIdentifier,
@PathParam(MvcAuthoringSteps.DOCUMENT_PATH_PATH_PARAM_NAME)
final String documentPathParam,
@PathParam("textKey") final String textKey,
@PathParam("locale") final String localeParam
) {
final ContentSection contentSection = sectionsUi
.findContentSection(sectionIdentifier)
.orElseThrow(
() -> new NotFoundException()
);
final ContentItem document = itemRepo
.findByPath(contentSection, documentPathParam)
.orElseThrow(
() -> new NotFoundException()
);
if (!(document instanceof SciDepartment)) {
throw new NotFoundException();
}
final SciDepartment department = (SciDepartment) document;
if (itemPermissionChecker.canEditItem(department)) {
return Optional
.ofNullable(department.getAdditionalTexts().get(textKey))
.map(text -> text.getText().getValue(new Locale(localeParam)))
.orElseThrow(() -> new NotFoundException());
} else {
throw new ForbiddenException();
}
}
}

View File

@ -0,0 +1,39 @@
<!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:librecms="http://xmlns.jcp.org/jsf/composite/components/librecms"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml">
<ui:define name="authoringStep">
<div class="d-flex">
<a class="btn btn-secondary btn-sm align-self-center mr-2"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description">
<bootstrap:svgIcon icon="caret-left-fill" />
<span class="sr-only">#{SciDepartmentMessageBundle['description_step.back']}</span>
</a>
<h2>#{SciDepartmentMessageBundle['description_step.description.header.edit']}</h2>
</div>
<c:if test="#{SciDepartmentDescriptionModel.canEdit}">
<librecms:cmsEditor
backUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description"
baseUrl="#{mvc.basePath}"
canEdit="#{SciDepartmentDescriptionModel.canEdit}"
contentSection="#{ContentSectionModel.sectionName}"
editMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/description/edit"
editorId="scidepartment-description-editor"
objectIdentifier="#{CmsSelectedDocumentModel.itemPath}"
selectedLocale="#{SciDepartmentDescriptionModel.selectedLocale}"
title="#{SciDepartmentMessageBundle['description.editor.header']}"
variantUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description-resources/department-description"
/>
</c:if>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,39 @@
<!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:h="http://xmlns.jcp.org/jsf/html"
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/documents/authoringstep.xhtml">
<ui:define name="authoringStep">
<div class="d-flex">
<a class="btn btn-secondary btn-sm align-self-center mr-2"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemName}/@scidepartment-description">
<bootstrap:svgIcon icon="caret-left-fill" />
<span class="sr-only">#{SciDepartmentMessageBundle['description_step.back']}</span>
</a>
<h2>#{SciDepartmentMessageBundle['description_step.description.header.view']}</h2>
</div>
<c:if test="#{SciDepartmentDescriptionModel.canEdit}">
<div class="text-right">
<a class="btn btn-secondary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/description/edit">
<bootstrap:svgIcon icon="pen" />
<span class="sr-only">#{SciDepartmentMessageBundle['description_step.edit']}</span>
</a>
</div>
</c:if>
<div class="cms-text-preview article-text border p-2">
<h:outputText escape="false"
value="#{SciDepartmentDescriptionModel.descriptionValues.get(SciDepartmentDescriptionModel.selectedLocale)}" />
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,454 @@
<!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:librecms="http://xmlns.jcp.org/jsf/composite/components/librecms"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml">
<ui:param name="authoringStep"
value="/libreccm/@contentsections/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/scidepartment-description" />
<ui:define name="authoringStep">
<h2>#{SciDepartmentMessageBundle['description_step.header']}</h2>
<c:if test="#{contactableNotFound != null}">
<div class="alert alert-warning" role="alert">
#{SciDepartmentMessageBundle.getMessage('description_step.errors.contactable_not_found', [contactableNotFound])}
</div>
</c:if>
<c:if test="#{personNotFound != null}">
<div class="alert alert-warning" role="alert">
#{SciDepartmentMessageBundle.getMessage('description_step.errors.person_not_found', [personNotFound])}
</div>
</c:if>
<c:if test="#{illegalStatusValue != null}">
<div class="alert alert-warning" role="alert">
#{SciDepartmentMessageBundle.getMessage('description_step.errors.illegal_member_status_value', [illegalStatusValue])}
</div>
</c:if>
<template id="scidepartment-contacts-sort-error-general">
<div class="alert alert-danger mt-3" role="alert">
#{SciDepartmentMessageBundle['contacts.sort.errors.general']}
</div>
</template>
<template id="scidepartment-contacts-sort-error-save">
<div class="alert alert-danger mt-3" role="alert">
#{SciDepartmentMessageBundle['contacts.sort.errors.save']}
</div>
</template>
<div id="messages"></div>
<librecms:cmsEditorVariants
addButtonLabel="#{SciDepartmentMessageBundle['description.editor.add_variant']}"
addDialogLocaleSelectHelp="#{SciDepartmentMessageBundle['description.editor.add.locale.help']}"
addMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/description/add"
canEdit="#{SciDepartmentDescriptionModel.canEdit}"
editorPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/description/edit"
hasUnusedLocales="#{!SciDepartmentDescriptionModel.unusedLocales.isEmpty()}"
headingLevel="3"
removeMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/description/remove"
sourceEditorPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/docuements/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/description/edit-source"
title="#{SciDepartmentMessageBundle['description.editor.header']}"
unusedLocales="#{SciDepartmentDescriptionModel.unusedLocales}"
variants="#{SciDepartmentDescriptionModel.variants}"
variantsId="description"
viewPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/description/view"
/>
<h3>#{SciDepartmentMessageBundle['contacts.header']}</h3>
<div class="mb-2">
<div class="text-right">
<librecms:assetPickerButton
assetPickerId="contacts-picker"
buttonIcon="plus-circle"
buttonText="#{SciDepartmentMessageBundle['contacts.add_button.label']}"
/>
</div>
</div>
<librecms:assetPicker
actionUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/contacts/add"
assetType="#{SciDepartmentDescriptionContacts.contactableTypes}"
assetPickerId="contacts-picker"
baseUrl="#{SciDepartmentDescriptionContacts.baseUrl}"
contentSection="#{ContentSectionModel.sectionName}"
dialogTitle="#{SciDepartmentMessageBundle['contact.add.title']}"
formParamName="contactableUuid">
<bootstrap:formGroupSelect
help="#{SciDepartmentMessageBundle['contacts.type.help']}"
inputId="type"
label="#{SciDepartmentMessageBundle['contacts.type.label']}"
name="type"
options="#{SciDepartmentContactTypes}"
/>
</librecms:assetPicker>
<button class="btn btn-secondary contacts-save-order-button"
disabled="disable"
type="button">
<span class="save-icon">
<bootstrap:svgIcon icon="save" />
</span>
<span class="save-spinner d-none">
<span aria-hidden="true"
class="spinner-border spinner-border-sm"
role="status"></span>
<span class="sr-only">#{SciDepartmentMessageBundle['contacts.order.save.inprogress']}</span>
</span>
<span>#{SciDepartmentMessageBundle['contacts.order.save']}</span>
</button>
<c:choose>
<c:when test="#{SciDepartmentDescriptionContacts.contacts.isEmpty()}">
<p>#{SciDepartmentMessageBundle['contacts.none']}</p>
</c:when>
<c:otherwise>
<table id="scidepartment-contacts-table"
data-saveUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description-contacts/save-order">
<thead>
<tr>
<th scope="col">#{SciDepartmentMessageBundle['contacts.cols.contactable']}</th>
<th scope="col">#{SciDepartmentMessageBundle['contacts.cols.type']}</th>
<th colspan="2"
scope="col"
>#{SciDepartmentMessageBundle['contacts.cols.actions']}</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{SciDepartmentDescriptionContacts.contacts}"
var="contact">
<tr class="scidepartment-contact"
id="#{contact.contactId}"
data-id="#{contact.contactId}">
<td>
<c:if test="#{CmsSelectedDocumentModel.canEdit}">
<button class="btn btn-secondary cms-sort-handle mr-2"
type="button">
<bootstrap:svgIcon icon="arrows-move" />
<span class="sr-only">#{SciDepartmentMessageBundle['contacts.move.button']}</span>
</button>
</c:if>
#{contact.contactable}
</td>
<td>#{contact.contactType}</td>
<td>
<button class="btn btn-secondary"
data-toggle="modal"
data-target="#contact-edit-dialog-#{contact.contactId}"
type="button">
<bootstrap:svgIcon icon="pen" />
<span>#{SciDepartmentMessageBundle['contacts.edit.label']}</span>
</button>
<div aria-hidden="true"
aria-labelledby="contact-edit-dialog-#{contact.contactId}-title"
class="modal fade"
id="contact-edit-dialog-#{contact.contactId}"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/contacts/edit/#{contact.contactId}"
method="post">
<div class="modal-header">
<h4 class="modal-title"
id="contact-edit-dialog-#{contact.contactId}-title">
#{SciDepartmentMessageBundle['contacts.edit.title']}
</h4>
<button
aria-label="#{SciDepartmentMessageBundle['contacts.edit.cancel']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x"/>
</button>
</div>
<div class="modal-body">
<bootstrap:formGroupSelect
help="#{SciDepartmentMessageBundle['contacts.edit.type.help']}"
inputId="type-edit"
label="#{SciDepartmentMessageBundle['contacts.edit.type.label']}"
name="type"
options="#{SciDepartmentContactTypes}"
selectedOptions="#{[contact.contactType]}"
/>
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{SciDepartmentMessageBundle['contacts.edit.cancel']}
</button>
<button class="btn btn-success"
type="submit">
#{SciDepartmentMessageBundle['contacts.edit.submit']}
</button>
</div>
</form>
</div>
</div>
</td>
<td>
<libreccm:deleteDialog
actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/contacts/#{contact.contactId}/remove"
buttonText="#{SciDepartmentMessageBundle['contacts.delete.label']}"
cancelLabel="#{SciDepartmentMessageBundle['contacts.delete.cancel']}"
confirmLabel="#{SciDepartmentMessageBundle['contacts.delete.confirm']}"
dialogId="contact-delete-dialog-#{contact.contactId}"
dialogTitle="#{SciDepartmentMessageBundle['contacts.delete.title']}"
message="#{SciDepartmentMessageBundle.getMessage('contacts.delete.message', [contact.contactable, contact.contactType])}"
/>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:otherwise>
</c:choose>
<h3>#{SciDepartmentMessageBundle['memberships.header']}</h3>
<div class="mb-2">
<div class="text-right">
<librecms:assetPickerButton
assetPickerId="members-picker"
buttonIcon="plus-circle"
buttonText="#{SciDepartmentMessageBundle['memberships.add_button.label']}"
/>
</div>
</div>
<librecms:assetPicker
actionUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/members/add"
assetPickerId="members-picker"
assetType="#{SciDepartmentDescriptionMembers.memberType}"
baseUrl="#{SciDepartmentDescriptionContacts.baseUrl}"
contentSection="#{ContentSectionModel.sectionName}"
dialogTitle="#{SciDepartmentMessageBundle['memberships.add.title']}"
formParamName="personUuid">
<bootstrap:formGroupSelect
help="#{SciDepartmentMessageBundle['memberships.role.help']}"
inputId="type"
label="#{SciDepartmentMessageBundle['memberships.role.label']}"
name="role"
options="#{SciDepartmentRoles}"
/>
<bootstrap:formGroupSelect
help="#{SciDepartmentMessageBundle['memberships.status.help']}"
inputId="status"
label="#{SciDepartmentMessageBundle['memberships.status.label']}"
name="status"
options="#{SciDepartmentDescriptionMembers.statusValues}"
/>
</librecms:assetPicker>
<c:choose>
<c:when test="#{SciDepartmentDescriptionMembers.members.isEmpty()}">
<p>#{SciDepartmentMessageBundle['memberships.none']}</p>
</c:when>
<c:otherwise>
<table>
<thead>
<tr>
<th scope="col">#{SciDepartmentMessageBundle['memberships.cols.name']}</th>
<th scope="col">#{SciDepartmentMessageBundle['memberships.cols.role']}</th>
<th scope="col">#{SciDepartmentMessageBundle['memberships.cols.status']}</th>
<th colspan="2"
scope="col">#{SciDepartmentMessageBundle['memberships.cols.actions']}</th>
</tr>
</thead>
<tbody id="members-list">
<c:forEach items="#{SciDepartmentDescriptionMembers.members}"
var="member">
<tr>
<td>
#{member.name}
</td>
<td>
#{SciDepartmentRoles[member.role]}
</td>
<td>
#{member.status}
</td>
<td>
<button class="btn btn-secondary"
data-toggle="modal"
data-target="#membership-edit-dialog"
type="button">
<bootstrap:svgIcon icon="pen"/>
<span class="sr-only">#{SciDepartmentMessageBundle['memberships.edit.label']}</span>
</button>
<div aria-hidden="true"
aria-labelledby="membership-edit-dialog-title"
class="modal fade"
id="membership-edit-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/members/edit/#{member.membershipId}"
class="modal-content"
method="post">
<div class="modal-header">
<h4 class="modal-title"
id="membership-edit-dialog-title">
</h4>
<button
aria-label="#{SciDepartmentMessageBundle['memberships.edit.cancel']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x"/>
</button>
</div>
<div class="modal-body">
<bootstrap:formGroupSelect
help="#{SciDepartmentMessageBundle['memberships.edit.role.help']}"
inputId="role"
label="#{SciDepartmentMessageBundle['memberships.edit.role.label']}"
name="role"
options="#{SciDepartmentRoles}"
selectedOptions="#{[member.role]}"
/>
<bootstrap:formGroupSelect
help="#{SciDepartmentMessageBundle['memberships.edit.status.help']}"
inputId="status"
label="#{SciDepartmentMessageBundle['memberships.edit.status.label']}"
name="status"
options="#{SciDepartmentDescriptionMembers.statusValues}"
selectedOptions="#{[member.status]}"
/>
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{SciDepartmentMessageBundle['members.edit.cancel']}
</button>
<button class="btn btn-success"
type="submit">
#{SciDepartmentMessageBundle['members.edit.submit']}
</button>
</div>
</form>
</div>
</div>
</td>
<td>
<libreccm:deleteDialog
actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/members/remove/#{member.membershipId}"
buttonText="#{SciDepartmentMessageBundle['>memberships.delete.label']}"
cancelLabel="#{SciDepartmentMessageBundle['memberships.delete.cancel']}"
confirmLabel="#{SciDepartmentMessageBundle['memberships.delete.confirm']}"
dialogId="membership-delete-dialog"
dialogTitle="#{SciDepartmentMessageBundle['memberships.delete.title']}"
message="#{SciDepartmentMessageBundle.getMessage('memberships.delete.message', [member.name])}"
/>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:otherwise>
</c:choose>
<h3>
#{SciDepartmentMessageBundle['texts.header']}
<button class="btn btn-secondary"
data-toggle="modal"
data-target="#department-text-add-dialog"
type="button">
<bootstrap:svgIcon icon="plus-circle" />
<span class="sr-only">#{SciDepartmentMessageBundle['texts.add.label']}</span>
</button>
<div aria-hidden="true"
aria-labelledby="department-text-add-dialog-title"
class="modal fade"
id="department-text-add-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/texts/add"
method="post">
<div class="modal-header">
<h4 class="modal-title"
id="department-text-add-dialog-title">
#{SciDepartmentMessageBundle['texts.add.dialog.title']}
</h4>
<button aria-label="#{SciDepartmentMessageBundle['texts.add.cancel']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x" />
</button>
</div>
<div class="modal-body">
<bootstrap:formGroupSelect
help="#{SciDepartmentMessageBundle['texts.add.key.help']}"
inputId="text-key"
label="#{SciDepartmentMessageBundle['texts.add.key.label']}"
name="textKey"
options="#{SciDepartmentTextsModel.availableTextKeys}"
/>
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{SciDepartmentMessageBundle['texts.add.cancel']}
</button>
<button class="btn btn-success"
type="submit">
#{SciDepartmentMessageBundle['texts.add.submit']}
</button>
</div>
</form>
</div>
</div>
</h3>
<c:choose>
<c:when test="#{SciDepartmentTextsModel.texts.isEmpty()}">
<p>#{SciDepartmentMessageBundle['texts.none']}</p>
</c:when>
<c:otherwise>
<c:forEach items="#{SciDepartmentTextsModel.texts.entrySet()}"
var="text">
<h4>
#{SciDepartmentTexts[text.key]}
<libreccm:deleteDialog
actionTarget="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/texts/remove/#{text.key}"
buttonText="#{SciDepartmentMessageBundle['texts.delete.label']}"
cancelLabel="#{SciDepartmentMessageBundle['texts.delete.cancel']}"
confirmLabel="#{SciDepartmentMessageBundle['texts.delete.confirm']}"
dialogId="text-#{text.key}-delete-dialog"
dialogTitle="#{SciDepartmentMessageBundle['texts.delete.title']}"
message="#{SciDepartmentMessageBundle.getMessage('texts.delete.message', [text.key])}"
/>
</h4>
<librecms:cmsEditorVariants
addButtonLabel="#{SciDepartmentMessageBundle['texts.editor.add_variant']}"
addDialogLocaleSelectHelp="#{SciDepartmentMessageBundle['texts.editor.add.locale.help']}"
addMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/texts/add/#{text.eky}"
canEdit="#{SciDepartmentDescriptionModel.canEdit}"
editorPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/texts/edit/#{text.key}"
hasUnusedLocales="#{text.value.unusedLocales.isEmpty()}"
headingLevel="5"
removeMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidpartment-description-texts/remove/#{text.key}"
sourceEditorPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidpartment-description-texts/edit-source/#{text.key}"
title="#{SciDepartmentMessageBundle.getMessage('texts.editor.header', [text.key])}"
unusedLocales="#{text.value.unusedLocales}"
variants="#{text.value.variants}"
variantsId="text-#{text.key}"
viewPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidpartment-description-texts/view/#{text.key}"
/>
</c:forEach>
</c:otherwise>
</c:choose>
</ui:define>
<ui:define name="scripts">
<script src="#{request.contextPath}/assets/@scidepartment/scidepartment-contacts.js" />
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,40 @@
<!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:librecms="http://xmlns.jcp.org/jsf/composite/components/librecms"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml">
<ui:define name="authoringStep">
<div class="d-flex">
<a class="btn btn-secondary btn-sm align-self-center mr-2"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description">
<bootstrap:svgIcon icon="caret-left-fill" />
<span class="sr-only">#{SciDepartmentMessageBundle['description_step.back']}</span>
</a>
<h2>#{SciDepartmentMessageBundle.getMessage('description_step.text.header.edit', [SciDepartmentTextsModel.selectedText])}</h2>
</div>
<c:if test="#{SciDepartmentDescriptionModel.canEdit}">
<librecms:cmsEditor
backUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description"
baseUrl="#{mvc.basePath}"
canEdit="#{SciDepartmentDescriptionModel.canEdit}"
contentSection="#{ContentSectionModel.sectionName}"
editMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-description/texts/edit/#{SciDepartmentTextsModel.selectedText}"
editorId="scidepartment-texts-editor"
objectIdentifier="#{CmsSelectedDocumentModel.itemPath}"
selectedLocale="#{SciDepartmentTextsModel.selectedLocale}"
title="#{SciDepartmentMessageBundle['texts.editor.header']}"
variantUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@scidepartment-texts-resources/department-texts"
/>
</c:if>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,37 @@
<!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:h="http://xmlns.jcp.org/jsf/html"
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/documents/authoringstep.xhtml">
<ui:define name="authoringStep">
<div class="d-flex">
<a class="btn btn-secondary btn-sm align-self-center mr-2"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemName}/@department-description">
<bootstrap:svgIcon icon="caret-left-fill" />
<span class="sr-only">#{SciDepartmentMessageBundle['description_step.back']}</span>
</a>
<h2>#{SciDepartmentMessageBundle.getMessage('description_step.texts.header.view', [SciDepartmentTextsModel.selectedText])}</h2>
</div>
<c:if test="#{SciDepartmentDescriptionModel.canEdit}">
<div class="text-right">
<a class="btn btn-secondary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@sciproject-description/texts/edit/#{SciDepartmentTextsModel.selectedText}">
<bootstrap:svgIcon icon="pen" />
<span class="sr-only">#{SciDepartmentMessageBundle['description_step.edit']}</span>
</a>
</div>
</c:if>
<div class="cms-text-preview article-text border p-2">
<h:outputText escape="false"
value="#{SciDepartmentTextsModel.texts.get(SciDepartmentTextsModel.selectedText).get(SciDepartmentTextsModel.selectedLocale)}" />
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -0,0 +1,5 @@
member=Member
head=Department head
deputy_head=Deputy department head
associated_member=Associated member

View File

@ -0,0 +1,5 @@
member=Mitglied
head=Abteilungsleitung
deputy_head=Stellvertretende Abteilungsleitung
associated_member=Assoziertes Mitglied

View File

@ -65,3 +65,81 @@ basicproperties.shortdescription.remove.submit=Remove
basicproperties.shortdescription.remove.text=Are you sure to remove this localized short description? basicproperties.shortdescription.remove.text=Are you sure to remove this localized short description?
basicproperties.shortdescription.remove.header=Confirm removal of localized short description basicproperties.shortdescription.remove.header=Confirm removal of localized short description
basicproperties.shortdescription.header=Short description basicproperties.shortdescription.header=Short description
description_step.header=Department Description
description_step.errors.contactable_not_found=The selected contactable entity {0} was not found.
description_step.errors.person_not_found=The selected person was not found.
description_step.errors.illegal_member_status_value=Illegal member status.
contacts.sort.errors.general=Error while sorting contacts.
contacts.sort.errors.save=Error while saving contact order.
description.editor.add_variant=Add localized description
description.editor.add.locale.help=The locale of the localized description.
description.editor.header=Description
contacts.header=Contacts
contacts.add_button.label=Add contact
contact.add.title=Add contact
contacts.type.help=The type of the contact.
contacts.type.label=Type
contacts.order.save.inprogress=Saving contacts order...
contacts.none=No contacts have been added yet.
contacts.cols.contactable=Contact
contacts.cols.type=Type
contacts.cols.actions=Actions
contacts.move.button=Move
contacts.edit.label=Edit
contacts.edit.title=Edit contact
contacts.edit.cancel=Cancel
contacts.edit.type.help=The type of the contact.
contacts.edit.type.label=Type
contacts.edit.submit=Save
contacts.delete.label=Remove
contacts.delete.cancel=Cancel
contacts.delete.confirm=Remove
contacts.delete.title=Confirm Removeal of Contact
contacts.delete.message=Are you sure to remove the contact {0} with type {1}?
memberships.header=Members
memberships.add_button.label=Add member
memberships.add.title=Add member
memberships.role.help=The role of the member.
memberships.role.label=Role
memberships.status.help=The status of the member.
memberships.status.label=Status
memberships.none=No member have been added yet.
memberships.cols.name=Name
memberships.cols.role=Role
memberships.cols.status=Status
memberships.cols.actions=Actions
memberships.edit.label=Edit
memberships.edit.cancel=Cancel
memberships.edit.role.help=The role of the member.
memberships.edit.role.label=Role
memberships.edit.status.help=The status of the member.
memberships.edit.status.label=Status
members.edit.cancel=Cancel
members.edit.submit=Save
memberships.delete.label=Remove
memberships.delete.cancel=Cancel
memberships.delete.confirm=Remove
memberships.delete.title=Confirm Removal of Member
memberships.delete.message=Are you sure to remove the member {0}?
texts.header=Additional texts
texts.add.label=Add text
texts.add.dialog.title=Add text
texts.add.cancel=Cancel
texts.add.key.help=The identifier of the text.
texts.add.key.label=Identifier
texts.add.submit=Add text
texts.none=No texts have been added yet.
texts.delete.label=Remove text
texts.delete.cancel=Cancel
texts.delete.confirm=Remove text
texts.delete.title=Confirm Removal of Text
texts.delete.message=Are you sure to remove the text {0}?
texts.editor.add_variant=Add localization
texts.editor.add.locale.help=The locale of the localized text.
texts.editor.header=Edit text {0}
description_step.back=Back
description_step.description.header.edit=Edit description
description_step.text.header.edit=Edit text {0}
description_step.texts.header.view=View text {0}
description_step.edit=Edit
description_step.description.header.view=Description

View File

@ -65,3 +65,81 @@ basicproperties.shortdescription.remove.submit=Entfernen
basicproperties.shortdescription.remove.text=Sind Sie sicher, dass Sie diese lokaliserte Kurzbeschreibung entfernen wollen? basicproperties.shortdescription.remove.text=Sind Sie sicher, dass Sie diese lokaliserte Kurzbeschreibung entfernen wollen?
basicproperties.shortdescription.remove.header=Entfernen einer lokalisierten Kurzbeschreibung best\u00e4tigen basicproperties.shortdescription.remove.header=Entfernen einer lokalisierten Kurzbeschreibung best\u00e4tigen
basicproperties.shortdescription.header=Kurzbeschreibung basicproperties.shortdescription.header=Kurzbeschreibung
description_step.header=Beschreibung der Abteilung
description_step.errors.contactable_not_found=Die ausgew\u00e4hlte Person oder Organisation {0} konnte nicht gefunden werden.
description_step.errors.person_not_found=Die ausgew\u00e4hlte Person konnte nicht gefunden werden.
description_step.errors.illegal_member_status_value=Fehlerhafter Status f\u00fcr Mitglied.
contacts.sort.errors.general=Fehler beim Sortieren der Kontakte.
contacts.sort.errors.save=Die Sortierung der Kontakte konnte nicht gespeichert werden.
description.editor.add_variant=Lokalisierte Beschreibung hinzuf\u00fcgen
description.editor.add.locale.help=Die Sprache der lokalisierten Beschreibung.
description.editor.header=Beschreibung
contacts.header=Kontakte
contacts.add_button.label=Kontakt hinzuf\u00fcgen
contact.add.title=Kontakt hinzuf\u00fcgen
contacts.type.help=Der Typ des Kontakts.
contacts.type.label=Typ
contacts.order.save.inprogress=Speichere Sortierung der Kontakte...
contacts.none=Es wurden noch keine Kontakte hinzugef\u00fcgt.
contacts.cols.contactable=Kontakt
contacts.cols.type=Typ
contacts.cols.actions=Aktionen
contacts.move.button=Verschieben
contacts.edit.label=Bearbeiten
contacts.edit.title=Kontakt bearbeiten
contacts.edit.cancel=Abbrechen
contacts.edit.type.help=Der Typ des Kontakts.
contacts.edit.type.label=Typ
contacts.edit.submit=Speichern
contacts.delete.label=Entfernen
contacts.delete.cancel=Abbrechen
contacts.delete.confirm=Entfernen
contacts.delete.title=Entfernen des Kontaktes best\u00e4tigen
contacts.delete.message=Sind Sie sicher das Sie den Kontakt {0} (Typ: {1}) entfernen wollen?
memberships.header=Mitglieder
memberships.add_button.label=Mitglied hinzuf\u00fcgen
memberships.add.title=Mitglied hinzuf\u00fcgen
memberships.role.help=Die Rolle des Mitglieds.
memberships.role.label=Rolle
memberships.status.help=Der Status des Mitglieds.
memberships.status.label=Status
memberships.none=Es wurden noch keine Mitglieder hinzugef\u00fcgt.
memberships.cols.name=Name
memberships.cols.role=Rolle
memberships.cols.status=Status
memberships.cols.actions=Aktionen
memberships.edit.label=Bearbeiten
memberships.edit.cancel=Abbrechen
memberships.edit.role.help=Die Rolle des Mitglieds.
memberships.edit.role.label=Rolle
memberships.edit.status.help=Der Status des Mitglieds.
memberships.edit.status.label=Status
members.edit.cancel=Abbrechen
members.edit.submit=Speichern
memberships.delete.label=Entfernen
memberships.delete.cancel=Abbrechen
memberships.delete.confirm=Entfernen
memberships.delete.title=Entfernen des Mitglieds best\u00e4tigen
memberships.delete.message=Sind Sie sicher, dass Sie das Mitglied {0} entfernen wollen?
texts.header=Weitere Texte
texts.add.label=Text hinzuf\u00fcgen
texts.add.dialog.title=Text hinzuf\u00fcgen
texts.add.cancel=Abbrechen
texts.add.key.help=Bezeichner des Textes.
texts.add.key.label=Bezeichner
texts.add.submit=Text hinzuf\u00fcgen
texts.none=Es wurden noch keine Texte hinzugef\u00fcgt.
texts.delete.label=Text entfernen
texts.delete.cancel=Abbrechen
texts.delete.confirm=Text entfernen
texts.delete.title=Entfernen des Textes best\u00e4tigen
texts.delete.message=Sind Sie sicher, dass Sie den Text {0} entfernen wollen?
texts.editor.add_variant=\u00dcbersetzung hinzuf\u00fcgen
texts.editor.add.locale.help=Die Sprache der \u00dcbersetzung.
texts.editor.header=Text {0} bearbeiten
description_step.back=Zur\u00fcck
description_step.description.header.edit=Beschreibung bearbeiten
description_step.text.header.edit=Text {0} bearbeiten
description_step.texts.header.view=Text {0}
description_step.edit=Bearbeiten
description_step.description.header.view=Beschreibung

View File

@ -0,0 +1,152 @@
import Sortable, { SortableEvent } from "sortablejs";
let contactsSortable: Sortable;
document.addEventListener("DOMContentLoaded", function (event) {
const contactsTable = document.querySelector(
"#scidepartment-contacts-table tbody"
);
if (contactsTable) {
contactsSortable = initContactsTable(contactsTable as HTMLElement);
}
const saveOrderButtons = document.querySelectorAll(
".contacts-save-order-button"
);
for (let i = 0; i < saveOrderButtons.length; i++) {
saveOrderButtons[i].addEventListener("click", saveOrder);
}
});
function initContactsTable(contactsTable: HTMLElement): Sortable {
return new Sortable(contactsTable, {
animation: 150,
group: "scidepartment-contact",
handle: ".cms-sort-handle",
onEnd: enableSaveButton,
});
}
function enableSaveButton(event: SortableEvent) {
const saveOrderButtons = document.querySelectorAll(
".contacts-save-order-button"
);
for (let i = 0; i < saveOrderButtons.length; i++) {
const saveOrderButton: HTMLButtonElement = saveOrderButtons[
i
] as HTMLButtonElement;
saveOrderButton.disabled = false;
}
}
function saveOrder() {
const contactsTable = document.querySelector("#scidepartment-contacts-table");
if (!contactsTable) {
showGeneralError();
throw Error("scidepartment-contacts-table not found");
}
const saveUrl = contactsTable.getAttribute("data-saveUrl");
if (!saveUrl) {
showGeneralError();
throw Error(
"data-saveUrl on scidepartment-contacts-table container is missing or empty"
);
}
const saveOrderButtons = document.querySelectorAll(
".contacts-save-order-button"
);
for (let i = 0; i < saveOrderButtons.length; i++) {
const saveOrderButton: HTMLButtonElement = saveOrderButtons[
i
] as HTMLButtonElement;
saveOrderButton.disabled = true;
const saveIcon = saveOrderButton.querySelector(".save-icon");
const spinner = saveOrderButton.querySelector(".save-spinner");
saveIcon?.classList.toggle("d-none");
spinner?.classList.toggle("d-none");
}
const headers = new Headers();
headers.append("Content-Type", "application/json");
fetch(saveUrl, {
credentials: "include",
body: JSON.stringify(contactsSortable.toArray()),
headers,
method: "POST",
})
.then((response) => {
if (response.ok) {
for (let i = 0; i < saveOrderButtons.length; i++) {
const saveOrderButton: HTMLButtonElement = saveOrderButtons[
i
] as HTMLButtonElement;
const saveIcon =
saveOrderButton.querySelector(".save-icon");
const spinner =
saveOrderButton.querySelector(".save-spinner");
saveIcon?.classList.toggle("d-none");
spinner?.classList.toggle("d-none");
}
} else {
showSaveError();
for (let i = 0; i < saveOrderButtons.length; i++) {
const saveOrderButton: HTMLButtonElement = saveOrderButtons[
i
] as HTMLButtonElement;
saveOrderButton.disabled = false;
const saveIcon =
saveOrderButton.querySelector(".save-icon");
const spinner =
saveOrderButton.querySelector(".save-spinner");
saveIcon?.classList.toggle("d-none");
spinner?.classList.toggle("d-none");
}
throw Error(
`Failed to save contacts order. Response status: ${response.status}, statusText: ${response.statusText}`
);
}
})
.catch((error) => {
showSaveError();
for (let i = 0; i < saveOrderButtons.length; i++) {
const saveOrderButton: HTMLButtonElement = saveOrderButtons[
i
] as HTMLButtonElement;
saveOrderButton.disabled = false;
const saveIcon = saveOrderButton.querySelector(".save-icon");
const spinner = saveOrderButton.querySelector(".save-spinner");
saveIcon?.classList.toggle("d-none");
spinner?.classList.toggle("d-none");
}
throw new Error(`Failed to save contacts order: ${error}`);
});
}
function showGeneralError(): void {
const alertTemplate = document.querySelector(
"#scidepartment-contacts-sort-error-general"
) as HTMLTemplateElement;
const alert = alertTemplate.content.cloneNode(true) as Element;
const container = document.querySelector("#messages");
if (container) {
container.appendChild(alert);
}
}
function showSaveError(): void {
const alertTemplate = document.querySelector(
"#scidepartment-contacts-sort-error-save"
) as HTMLTemplateElement;
const alert = alertTemplate.content.cloneNode(true) as Element;
const container = document.querySelector("#messages");
if (container) {
container.appendChild(alert);
}
}

View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"declaration": true,
"lib": [
"DOM",
"ES2016"
],
"module": "commonjs",
"moduleResolution": "node",
"outDir": "target/generated-resources/assets/@scidepartment",
"sourceMap": true,
"strict": true,
"target": "ES6"
},
"include": [
"src/main/typescript/**/*"
]
}

View File

@ -0,0 +1,23 @@
module.exports = {
mode: "development",
devtool: "source-map",
optimization: {
chunkIds: false
},
entry: {
"scidepartment-contacts": "./src/main/typescript/scidepartment-contacts.ts"
},
output: {
filename: "[name].js",
path: __dirname + "/target/generated-resources/assets/@scidepartment"
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".json"]
},
module: {
rules: [
// all files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'
{ test: /\.tsx?$/, use: ["ts-loader"], exclude: /node_modules/ }
]
}
}