From 2e890bafb971b7f922f8a7d9627252b67a114d92 Mon Sep 17 00:00:00 2001 From: jensp Date: Mon, 17 Apr 2017 15:36:15 +0000 Subject: [PATCH] =?UTF-8?q?CCM=20NG/ccm-cms:=20-=20AssetSearchWidget=20-?= =?UTF-8?q?=20Form=20f=C3=BCr=20ExternalVideoAsset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4675 8810af33-2d31-482b-a856-94f89814c4df --- .../cms/dispatcher/CMSDispatcher.java | 8 +- .../arsdigita/cms/ui/assets/AssetPane.java | 49 +- .../cms/ui/assets/AssetSearchWidget.java | 126 +++++ .../assets/forms/ExternalVideoAssetForm.java | 100 ++-- ccm-cms/src/main/java/org/librecms/Cms.java | 7 +- .../librecms/assets/ExternalVideoAsset.java | 8 + .../org/librecms/contentsection/Asset.java | 38 +- .../contentsection/AssetRepository.java | 131 ++++- .../ContentSectionRepository.java | 8 +- .../contentsection/FolderRepository.java | 11 +- .../librecms/contentsection/rs/Assets.java | 278 ++++++++++ .../rs/AssetsOld.java} | 73 +-- .../ContentSections.java} | 7 +- .../org/librecms/CmsResources.properties | 3 +- .../org/librecms/CmsResources_de.properties | 3 +- .../org/librecms/CmsResources_fr.properties | 3 +- .../org/librecms/assets/Assets.properties | 2 + .../org/librecms/assets/Assets_de.properties | 2 + .../themes/foundry/foundry/lib/cms.xsl | 9 +- .../foundry/lib/cms/asset-search-widget.xsl | 489 ++++++++++++++++++ .../foundry/foundry/scripts/cms-admin.js | 156 ++++++ .../themes/foundry/foundry/styles/admin.css | 111 +++- .../foundry/templates/admin-layout.xml | 13 +- .../themes/foundry/foundry/texts/cms.xml | 60 ++- 24 files changed, 1530 insertions(+), 165 deletions(-) create mode 100644 ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetSearchWidget.java create mode 100644 ccm-cms/src/main/java/org/librecms/contentsection/rs/Assets.java rename ccm-cms/src/main/java/org/librecms/{assets/AssetSearchService.java => contentsection/rs/AssetsOld.java} (83%) rename ccm-cms/src/main/java/org/librecms/contentsection/{JaxRsContentSections.java => rs/ContentSections.java} (86%) create mode 100644 ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms/asset-search-widget.xsl create mode 100644 ccm-theme-foundry/src/main/resources/themes/foundry/foundry/scripts/cms-admin.js diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/dispatcher/CMSDispatcher.java b/ccm-cms/src/main/java/com/arsdigita/cms/dispatcher/CMSDispatcher.java index 3f3e7c1bc..d5a83e93d 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/dispatcher/CMSDispatcher.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/dispatcher/CMSDispatcher.java @@ -42,6 +42,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.shiro.authz.AuthorizationException; import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.core.UnexpectedErrorException; import org.libreccm.security.PermissionChecker; import org.libreccm.security.Shiro; import org.libreccm.security.User; @@ -456,10 +457,15 @@ public class CMSDispatcher implements Dispatcher, ChainedDispatcher { url = url.substring(debugXSLString.length()); } + final String sectionLabel = url; + // Fetch the current site node from the URL. final ContentSectionRepository sectionRepo = CdiUtil.createCdiUtil() .findBean(ContentSectionRepository.class); - ContentSection section = sectionRepo.findByLabel(url); + final ContentSection section = sectionRepo + .findByLabel(url) + .orElseThrow(() -> new UnexpectedErrorException( + String.format("No ContentSection '%s' found.", sectionLabel))); return section; } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetPane.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetPane.java index 9932b2d4b..a3d3eb8e5 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetPane.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetPane.java @@ -70,6 +70,7 @@ import com.arsdigita.cms.ui.folder.FolderTreeModelController; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.toolbox.ui.ActionGroup; import com.arsdigita.toolbox.ui.LayoutPanel; + import java.lang.reflect.InvocationTargetException; import org.apache.logging.log4j.LogManager; @@ -100,7 +101,6 @@ import java.util.Arrays; import java.util.Objects; import java.util.ResourceBundle; import java.util.TooManyListenersException; -import java.util.logging.Level; import static org.librecms.CmsConstants.*; @@ -137,7 +137,7 @@ public class AssetPane extends LayoutPanel implements Resettable { private TargetSelector targetSelector; private SegmentedPanel.Segment browseSegment; - private SegmentedPanel.Segment currentFolderSegment; +// private SegmentedPanel.Segment currentFolderSegment; private SegmentedPanel.Segment actionsSegment; private SegmentedPanel.Segment newFolderSegment; private SegmentedPanel.Segment editFolderSegment; @@ -315,28 +315,28 @@ public class AssetPane extends LayoutPanel implements Resettable { // browseSegment.add(folderBrowser); browseSegment.add(browserForm); - currentFolderSegment = panel.addSegment(); - currentFolderSegment.addHeader(new Text("Current folder")); - final Label currentFolderLabel = new Label(); - currentFolderLabel.addPrintListener(new PrintListener() { - - @Override - public void prepare(final PrintEvent event) { - final PageState state = event.getPageState(); - final Label target = (Label) event.getTarget(); - - final long selectedId = Long.parseLong(selectionModel - .getSelectedKey(state).toString()); - final long currentFolderId = folderSelectionModel - .getSelectedObject(state).getObjectId(); - target.setLabel(String.format( - "selectedId = %d; currentFolderId = %d", - selectedId, - currentFolderId)); - } - - }); - currentFolderSegment.add(currentFolderLabel); +// currentFolderSegment = panel.addSegment(); +// currentFolderSegment.addHeader(new Text("Current folder")); +// final Label currentFolderLabel = new Label(); +// currentFolderLabel.addPrintListener(new PrintListener() { +// +// @Override +// public void prepare(final PrintEvent event) { +// final PageState state = event.getPageState(); +// final Label target = (Label) event.getTarget(); +// +// final long selectedId = Long.parseLong(selectionModel +// .getSelectedKey(state).toString()); +// final long currentFolderId = folderSelectionModel +// .getSelectedObject(state).getObjectId(); +// target.setLabel(String.format( +// "selectedId = %d; currentFolderId = %d", +// selectedId, +// currentFolderId)); +// } +// +// }); +// currentFolderSegment.add(currentFolderLabel); actionsSegment = panel.addSegment(); actionsSegment.setIdAttr("folder-browse"); @@ -455,6 +455,7 @@ public class AssetPane extends LayoutPanel implements Resettable { final Form newAssetForm = new Form("new-asset-form", new BoxPanel(BoxPanel.HORIZONTAL)); + newAssetForm.setMethod("GET"); newAssetForm.add(new Label(new GlobalizedMessage( "cms.ui.assets.new", CmsConstants.CMS_BUNDLE))); final SingleSelect newAssetTypeSelect = new SingleSelect( diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetSearchWidget.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetSearchWidget.java new file mode 100644 index 000000000..c594b8862 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/AssetSearchWidget.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2017 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.cms.ui.assets; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.form.Widget; +import com.arsdigita.bebop.parameters.LongParameter; +import com.arsdigita.cms.CMS; +import com.arsdigita.xml.Element; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.l10n.GlobalizationHelper; +import org.librecms.assets.AssetTypeInfo; +import org.librecms.assets.AssetTypesManager; +import org.librecms.contentsection.Asset; +import org.librecms.contentsection.AssetRepository; +import org.librecms.contentsection.ContentSection; + +import java.util.ResourceBundle; + +/** + * A widget for selecting an asset. The widget does not contain any other + * widgets, only the information required to create an HTML/JavaScript dialog + * for selecting an asset. To get the dialog the + * {@link org.librecms.contentsection.rs.Assets} class can be used which + * provides several methods for getting the assets of an content section. + * + * @author Jens Pelzetter + */ +public class AssetSearchWidget extends Widget { + + private Class type; + + public AssetSearchWidget(final String name) { + super(new LongParameter(name)); + } + + public AssetSearchWidget(final String name, + final Class type) { + this(name); + this.type = type; + } + + @Override + public boolean isCompound() { + return true; + } + + @Override + protected String getType() { + return "asset-search-widget"; + } + + @Override + protected String getElementTag() { + return "cms:asset-search-widget"; + } + + @Override + public void generateWidget(final PageState state, + final Element parent) { + + final Element widget = parent.newChildElement(getElementTag(), + CMS.CMS_XML_NS); + + widget.addAttribute("name", getName()); + + if (type != null) { + widget.addAttribute("asset-type", type.getName()); + } + + final ContentSection section = CMS.getContext().getContentSection(); + widget.addAttribute("content-section", section.getLabel()); + + final Long value = (Long) getValue(state); + if (value != null) { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final AssetRepository assetRepo = cdiUtil + .findBean(AssetRepository.class); + final AssetTypesManager typesManager = cdiUtil + .findBean(AssetTypesManager.class); + final GlobalizationHelper globalizationHelper = cdiUtil + .findBean(GlobalizationHelper.class); + + final Asset asset = assetRepo + .findById(value) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No asset with ID %d in the database.", value))); + + final Element selected = widget.newChildElement( + "cms:selected-asset", CMS.CMS_XML_NS); + selected.addAttribute("assetId", + Long.toString(asset.getObjectId())); + selected.addAttribute( + "title", + globalizationHelper + .getValueFromLocalizedString(asset.getTitle())); + final AssetTypeInfo typeInfo = typesManager + .getAssetTypeInfo(asset.getClass().getName()); + final ResourceBundle bundle = ResourceBundle + .getBundle(typeInfo.getLabelBundle(), + globalizationHelper.getNegotiatedLocale()); + final String typeLabel = bundle.getString(typeInfo.getLabelKey()); + selected.addAttribute("type", typeLabel); + + exportAttributes(widget); + } + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalVideoAssetForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalVideoAssetForm.java index 4190de746..428af4523 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalVideoAssetForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/assets/forms/ExternalVideoAssetForm.java @@ -19,66 +19,104 @@ package com.arsdigita.cms.ui.assets.forms; import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; import com.arsdigita.bebop.PageState; import com.arsdigita.cms.ui.assets.AssetPane; +import com.arsdigita.cms.ui.assets.AssetSearchWidget; +import com.arsdigita.globalization.GlobalizedMessage; + +import org.libreccm.cdi.utils.CdiUtil; +import org.librecms.CmsConstants; +import org.librecms.assets.Bookmark; + import java.util.Objects; import java.util.Optional; + import org.librecms.assets.ExternalVideoAsset; +import org.librecms.assets.LegalMetadata; import org.librecms.contentsection.Asset; +import org.librecms.contentsection.AssetRepository; /** * * @author Jens Pelzetter */ public class ExternalVideoAssetForm extends BookmarkForm { - + + private AssetSearchWidget assetSearchWidget; + public ExternalVideoAssetForm(final AssetPane assetPane) { super(assetPane); } - + @Override public void addWidgets() { super.addWidgets(); - + + add(new Label(new GlobalizedMessage( + "cms.ui.assets.external_video_asset.legal_metadata.label", + CmsConstants.CMS_BUNDLE))); + assetSearchWidget = new AssetSearchWidget("legal-metadata", + LegalMetadata.class); + add(assetSearchWidget); + //ToDo } - - + @Override protected void initForm(final PageState state, final Optional selectedAsset) { super.initForm(state, selectedAsset); - - // ToDo + + if (selectedAsset.isPresent()) { + final ExternalVideoAsset externalVideoAsset + = (ExternalVideoAsset) selectedAsset + .get(); + + final LegalMetadata legalMetadata = externalVideoAsset + .getLegalMetadata(); + if (legalMetadata != null) { + assetSearchWidget.setValue(state, legalMetadata.getObjectId()); + } + } } - + @Override - protected void showLocale(final PageState state) { - - super.showLocale(state); - - //ToDo - } - - @Override protected Asset createAsset(final PageState state) throws FormProcessException { - - Objects.requireNonNull(state); - - final ExternalVideoAsset externalVideoAsset = new ExternalVideoAsset(); - - updateData(externalVideoAsset, state); - - // ToDo - - return externalVideoAsset; + + Objects.requireNonNull(state); + + final ExternalVideoAsset externalVideoAsset = new ExternalVideoAsset(); + + updateData((Bookmark) externalVideoAsset, state); + updateData(externalVideoAsset, state); + + return externalVideoAsset; } - + + protected void updateData(final ExternalVideoAsset externalVideoAsset, + final PageState state) { + + final Long legalMetadataId = (Long) assetSearchWidget.getValue(state); + if (legalMetadataId != null) { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final AssetRepository assetRepo = cdiUtil.findBean( + AssetRepository.class); + final LegalMetadata legalMetadata = (LegalMetadata) assetRepo + .findById(legalMetadataId) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No LegalMetadata asset with ID %d in the database.", + legalMetadataId))); + + externalVideoAsset.setLegalMetadata(legalMetadata); + } + } + @Override protected void updateAsset(final Asset asset, final PageState state) { - - Objects.requireNonNull(asset); + + Objects.requireNonNull(asset); Objects.requireNonNull(state); if (!(asset instanceof ExternalVideoAsset)) { @@ -91,8 +129,8 @@ public class ExternalVideoAssetForm extends BookmarkForm { final ExternalVideoAsset externalVideoAsset = (ExternalVideoAsset) asset; + updateData((Bookmark) externalVideoAsset, state); updateData(externalVideoAsset, state); - - // ToDo } + } diff --git a/ccm-cms/src/main/java/org/librecms/Cms.java b/ccm-cms/src/main/java/org/librecms/Cms.java index 6c0b524fc..88afe7762 100644 --- a/ccm-cms/src/main/java/org/librecms/Cms.java +++ b/ccm-cms/src/main/java/org/librecms/Cms.java @@ -21,6 +21,7 @@ import org.libreccm.web.ApplicationType; import org.libreccm.web.CcmApplication; import org.librecms.assets.AssetTypes; import org.librecms.assets.Bookmark; +import org.librecms.assets.ExternalVideoAsset; import org.librecms.assets.LegalMetadata; import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSectionCreator; @@ -35,6 +36,7 @@ import org.librecms.contenttypes.News; import java.io.IOException; import java.io.InputStream; import java.util.Properties; + import org.librecms.assets.SideNote; @Module(//packageName = "org.librecms.cms", @@ -61,7 +63,10 @@ import org.librecms.assets.SideNote; } ) @ContentTypes({Article.class, Event.class, MultiPartArticle.class, News.class}) -@AssetTypes({Bookmark.class, LegalMetadata.class, SideNote.class}) +@AssetTypes({Bookmark.class, + ExternalVideoAsset.class, + LegalMetadata.class, + SideNote.class}) public class Cms implements CcmModule { private static final Logger LOGGER = LogManager.getLogger(Cms.class); diff --git a/ccm-cms/src/main/java/org/librecms/assets/ExternalVideoAsset.java b/ccm-cms/src/main/java/org/librecms/assets/ExternalVideoAsset.java index bdff1cff6..aae470a54 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/ExternalVideoAsset.java +++ b/ccm-cms/src/main/java/org/librecms/assets/ExternalVideoAsset.java @@ -18,6 +18,8 @@ */ package org.librecms.assets; +import com.arsdigita.cms.ui.assets.forms.ExternalVideoAssetForm; + import org.hibernate.envers.Audited; import java.io.Serializable; @@ -29,6 +31,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import static org.librecms.CmsConstants.*; +import static org.librecms.assets.AssetConstants.*; /** * An asset for external videos, like videos from YouTube. @@ -38,6 +41,11 @@ import static org.librecms.CmsConstants.*; @Entity @Table(name = "EXTERNAL_VIDEO_ASSETS", schema = DB_SCHEMA) @Audited +@AssetType(assetForm = ExternalVideoAssetForm.class, + labelKey = "external_video_asset.label", + labelBundle = ASSETS_BUNDLE, + descriptionKey = "external_video_asset.description", + descriptionBundle = ASSETS_BUNDLE) public class ExternalVideoAsset extends Bookmark implements Serializable { private static final long serialVersionUID = -2927375812188779049L; diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/Asset.java b/ccm-cms/src/main/java/org/librecms/contentsection/Asset.java index 4e0584edf..629a28fc2 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/Asset.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/Asset.java @@ -61,22 +61,52 @@ import static org.librecms.CmsConstants.*; , @NamedQuery(name = "Asset.findByType", query = "SELECT a FROM Asset a " - + "WHERE TYPE(a) = :type") + + "WHERE TYPE(a) = :type " + + "AND a.categories IS NOT EMPTY") + , + @NamedQuery(name = "Asset.findByTypeAndContentSection", + query = "SELECT a FROM Asset a " + + "JOIN a.categories c " + + "WHERE TYPE(a) = :type " + + "AND c.category.section = :section") , @NamedQuery(name = "Asset.findByUuidAndType", query = "SELECT a FROM Asset a " + "WHERE a.uuid = :uuid " + "AND TYPE(a) = :type") , + @NamedQuery(name = "Asset.findByContentSection", + query = "SELECT a FROM Asset a " + + "JOIN a.categories c " + + "WHERE c.category.section = :section") + , @NamedQuery(name = "Asset.findByTitle'", - query = "SELECT a FROM Asset a JOIN a.title.values t " - + "WHERE LOWER(t) LIKE CONCAT('%', :title, '%')") + query = "SELECT a FROM Asset a " + + "JOIN a.title.values t " + + "WHERE LOWER(t) LIKE CONCAT('%', :title, '%') " + + "AND a.categories IS NOT EMPTY") + , + @NamedQuery(name = "Asset.findByTitleAndContentSection", + query = "SELECT a FROM Asset a " + + "JOIN a.title.values t " + + "JOIN a.categories c " + + "WHERE LOWER(t) LIKE CONCAT('%s', :title, '%s') " + + "AND c.category.section = :section") , @NamedQuery(name = "Asset.findByTitleAndType", - query = "SELECT a FROM Asset a JOIN a.title.values t " + query = "SELECT a FROM Asset a " + + "JOIN a.title.values t " + "WHERE LOWER(t) LIKE CONCAT('%', :title, '%') " + "AND TYPE(a) = :type") , + @NamedQuery(name = "Asset.findByTitleAndTypeAndContentSection", + query = "SELECT a FROM Asset a " + + "JOIN a.title.values t " + + "JOIN a.categories c " + + "WHERE LOWER(t) LIKE CONCAT('%', :title, '%') " + + "AND TYPE(a) = :type " + + "AND c.category.section = :section") + , @NamedQuery( name = "Asset.findByFolder", query = "SELECT a FROM Asset a " diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/AssetRepository.java b/ccm-cms/src/main/java/org/librecms/contentsection/AssetRepository.java index b4eb976ac..66d46538d 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/AssetRepository.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/AssetRepository.java @@ -18,7 +18,6 @@ */ package org.librecms.contentsection; - import org.libreccm.auditing.AbstractAuditedEntityRepository; import org.libreccm.categorization.Category; import org.libreccm.categorization.CategoryManager; @@ -97,7 +96,7 @@ public class AssetRepository public void save( @RequiresPrivilege(AssetPrivileges.EDIT) final Asset asset) { - + super.save(asset); } @@ -140,8 +139,8 @@ public class AssetRepository } /** - * Find an {@link Asset} by its UUID. This method does distinguish between - * shared and non shared assets. + * Find an {@link Asset} by its UUID. This method does not distinguish + * between shared and non shared assets. * * @param uuid The UUID of the {@link Asset}. * @@ -164,7 +163,7 @@ public class AssetRepository /** * Finds an {@link Asset} by its UUID and type. This method - * does distinguish between shared and non shared assets. + * does not distinguish between shared and non shared assets. * * @param uuid The UUID of the asset to retrieve. * @param type The type of the asset to retrieve. @@ -189,24 +188,58 @@ public class AssetRepository return Optional.empty(); } } - + @Transactional(Transactional.TxType.REQUIRED) - public List findByTitle(final String title) { - - final TypedQuery query = entityManager.createNamedQuery( - "Asset.findByTitle", Asset.class); - query.setParameter("title", title); - + public List findByContentSection(final ContentSection section) { + + final TypedQuery query = entityManager + .createNamedQuery("Asset.findByContentSection", Asset.class); + query.setParameter("section", section); + return query.getResultList(); } /** - * Finds all shared {@link Asset}s of the specified type. + * Finds all sharable {@link Asset}s where the title is like the provided + * one. This method does a {@code LIKE} query. Therefore it will find all + * assets where the title contains the string provided using the + * {@code title} parameter. + * + * @param title The title to search for. + * + * @return A list of all sharable assets (from all content sections) where + * the title contains the string provided by the {@code title} + * parameter. + */ + @Transactional(Transactional.TxType.REQUIRED) + public List findByTitle(final String title) { + + final TypedQuery query = entityManager + .createNamedQuery("Asset.findByTitle", Asset.class); + query.setParameter("title", title); + + return query.getResultList(); + } + + public List findByTitleAndContentSection( + final String title, final ContentSection section) { + + final TypedQuery query = entityManager.createNamedQuery( + "Asset.findByTitleAndContentSection", Asset.class); + query.setParameter("title", title); + query.setParameter("section", section); + + return query.getResultList(); + } + + /** + * Finds all sharable {@link Asset}s of the specified type from all content + * sections.. * * @param type The type of the assets to find. * - * @return A list containing all shared assets of the specified - * {@code type}. + * @return A list containing all sharable assets of the specified + * {@code type} from all content sections. */ @Transactional(Transactional.TxType.REQUIRED) public List findByType(final Class type) { @@ -217,15 +250,63 @@ public class AssetRepository return query.getResultList(); } - + + /** + * Finds all sharable {@link Asset}s of the specified type in the specified + * content section. + * + * @param type The type of the assets to find. + * @param section The section. + * + * @return A list containing all sharable assets of the specified + * {@code type} in the specified content section. + */ + @Transactional(Transactional.TxType.REQUIRED) + public List findByTypeAndContentSection( + final Class type, + final ContentSection section) { + + final TypedQuery query = entityManager.createNamedQuery( + "Asset.findByTypeAndContentSection", Asset.class); + query.setParameter("type", type); + query.setParameter("section", section); + + return query.getResultList(); + } + + /** + * Finds all assets of the provided type which contain the provided string + * in their title. + * + * @param title The title fragment used to filter the assets. + * @param type The type of the assets. + * + * @return A list of all assets from all content sections which are the + * specified type and which title matches the provided title. + */ @Transactional(Transactional.TxType.REQUIRED) public List findByTitleAndType(final String title, final Class type) { - - final TypedQuery query = entityManager.createNamedQuery( - "Asset.findByTitle", Asset.class); + + final TypedQuery query = entityManager + .createNamedQuery("Asset.findByTitle", Asset.class); query.setParameter("title", title); query.setParameter("type", type); + + return query.getResultList(); + } + + public List findByTitleAndTypeAndContentSection( + final String title, + final Class type, + final ContentSection section) { + + final TypedQuery query = entityManager + .createNamedQuery("Asset.findByTitleAndTypeAndContentSection", + Asset.class); + query.setParameter("title", title); + query.setParameter("type", type); + query.setParameter("section", section); return query.getResultList(); } @@ -268,7 +349,7 @@ public class AssetRepository * * @param folder The {@link Folder} which {@link Asset}s are filtered using * the provided {@code name}. - * @param title The string used to fiter the {@link Assets} in the provided + * @param title The string used to fiter the {@link Assets} in the provided * {@code folder}. * * @return A list with all {@link Asset}s in the provided {@link Folder} @@ -276,7 +357,7 @@ public class AssetRepository */ @Transactional(Transactional.TxType.REQUIRED) public List filterByFolderAndTitle(final Folder folder, - final String title) { + final String title) { final TypedQuery query = entityManager.createNamedQuery( "Asset.filterByFolderAndTitle", Asset.class); query.setParameter("folder", folder); @@ -291,7 +372,7 @@ public class AssetRepository * * @param folder The {@link Folder} which {@link Asset}s are filtered using * the provided {@code name}. - * @param title The string used to fiter the {@link Assets} in the provided + * @param title The string used to fiter the {@link Assets} in the provided * {@code folder}. * * @return The number of {@link Asset}s in the provided {@link Folder} which @@ -299,7 +380,7 @@ public class AssetRepository */ @Transactional(Transactional.TxType.REQUIRED) public long countFilterByFolderAndTitle(final Folder folder, - final String title) { + final String title) { final TypedQuery query = entityManager.createNamedQuery( "Asset.countFilterByFolderAndTitle", Long.class); query.setParameter("folder", folder); @@ -356,7 +437,7 @@ public class AssetRepository * * @param folder The {@link Folder} which contains the assets. * @param type The type of the {@link Asset}s. - * @param title The name to filter the {@link Asset}s for. + * @param title The name to filter the {@link Asset}s for. * * @return A list of all {@link Asset}s of the provided type which name * starts with the provided string in the provided folder. @@ -382,7 +463,7 @@ public class AssetRepository * * @param folder The {@link Folder} which contains the assets. * @param type The type of the {@link Asset}s. - * @param title The name to filter the {@link Asset}s for. + * @param title The name to filter the {@link Asset}s for. * * @return The number of {@link Asset}s of the provided type which name * starts with the provided string in the provided folder. diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionRepository.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionRepository.java index 5cf07f672..aaa78e8a0 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionRepository.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentSectionRepository.java @@ -39,7 +39,7 @@ import javax.transaction.Transactional; public class ContentSectionRepository extends AbstractEntityRepository { - public ContentSection findByLabel(final String label) { + public Optional findByLabel(final String label) { if (label == null || label.isEmpty()) { throw new IllegalArgumentException( "The label of a ContentSection can't be empty."); @@ -50,7 +50,11 @@ public class ContentSectionRepository ContentSection.class); query.setParameter("label", label); - return query.getSingleResult(); + try { + return Optional.of(query.getSingleResult()); + } catch(NoResultException ex) { + return Optional.empty(); + } } @Override diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java b/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java index 70c6ba508..7fe2dbfb0 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/FolderRepository.java @@ -104,12 +104,11 @@ public class FolderRepository extends AbstractEntityRepository { + "Valid path format: contentSection:path"); } - final ContentSection section = sectionRepo.findByLabel(tokens[0]); - if (section == null) { - throw new InvalidFolderPathException(String.format( - "No content section identified by label \"%s\" found.", - tokens[0])); - } + final ContentSection section = sectionRepo + .findByLabel(tokens[0]) + .orElseThrow(() -> new InvalidFolderPathException(String.format( + "No content section identified by label \"%s\" found.", + tokens[0]))); return findByPath(section, tokens[1], type); } diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/rs/Assets.java b/ccm-cms/src/main/java/org/librecms/contentsection/rs/Assets.java new file mode 100644 index 000000000..37ba59c9a --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/contentsection/rs/Assets.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2017 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.contentsection.rs; + +import com.arsdigita.kernel.KernelConfig; + +import org.libreccm.l10n.GlobalizationHelper; +import org.librecms.assets.AssetTypeInfo; +import org.librecms.assets.AssetTypesManager; +import org.librecms.contentsection.Asset; +import org.librecms.contentsection.AssetManager; +import org.librecms.contentsection.AssetRepository; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.ContentSectionRepository; +import org.librecms.contentsection.Folder; +import org.librecms.contentsection.FolderManager; +import org.librecms.contentsection.FolderRepository; +import org.librecms.contentsection.FolderType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.ResourceBundle; +import java.util.stream.Collectors; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; +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.QueryParam; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path("/{content-section}/assets/") +public class Assets { + + @Inject + private ContentSectionRepository sectionRepo; + + @Inject + private FolderRepository folderRepo; + + @Inject + private FolderManager folderManager; + + @Inject + private AssetRepository assetRepo; + + @Inject + private AssetManager assetManager; + + @Inject + private AssetTypesManager assetTypesManager; + + @Inject + private GlobalizationHelper globalizationHelper; + + private Class toAssetTypeClass(final String type) { + final Class clazz; + try { + clazz = Class.forName(type); + } catch (ClassNotFoundException ex) { + throw new IllegalArgumentException(String.format( + "Type '%s' is not a valid class.", + type)); + } + + if (Asset.class.isAssignableFrom(clazz)) { + @SuppressWarnings("unchecked") + final Class typeClass + = (Class) clazz; + return typeClass; + } else { + throw new IllegalArgumentException(String.format( + "Type '%s is not a subclass of '%s'.", + type, + Asset.class.getName())); + } + } + + private Map createAssetMapEntry(final Folder folder) { + final Map result = new HashMap<>(); + + result.put("title", + folder + .getTitle() + .getValue(KernelConfig.getConfig().getDefaultLocale())); + result.put("type", + Folder.class.getName()); + result.put("place", ""); + + return result; + } + + private Map createAssetMapEntry(final Asset asset) { + final Map result = new HashMap<>(); + + result.put("assetId", + Long.toString(asset.getObjectId())); + + result.put("title", + asset.getTitle().getValue(globalizationHelper + .getNegotiatedLocale())); + + result.put("type", + asset.getClass().getName()); + + final AssetTypeInfo typeInfo = assetTypesManager + .getAssetTypeInfo(asset.getClass()); + final ResourceBundle bundle = ResourceBundle + .getBundle(typeInfo.getLabelBundle(), + globalizationHelper.getNegotiatedLocale()); + result.put("typeLabel", bundle.getString(typeInfo.getLabelKey())); + + final Optional assetFolder = assetManager.getAssetFolder(asset); + if (assetFolder.isPresent()) { + result.put("place", + folderManager.getFolderPath(assetFolder.get())); + } else { + result.put("place", ""); + } + + return result; + } + + @GET + @Path("/") + @Produces("text/json; charset=utf-8") + @Transactional(Transactional.TxType.REQUIRED) + public List> findAssets( + @PathParam("content-section") final String section, + @QueryParam("query") final String query, + @QueryParam("type") final String type) { + + final ContentSection contentSection = sectionRepo + .findByLabel(section) + .orElseThrow(() -> new NotFoundException( + String.format("No content section '%s' found.", section))); + + final List assets; + if ((query == null || query.trim().isEmpty()) + && (type == null || type.trim().isEmpty())) { + assets = assetRepo.findByContentSection(contentSection); + } else if ((query != null && !query.trim().isEmpty()) + && (type == null || type.trim().isEmpty())) { + assets = assetRepo.findByTitleAndContentSection(query, + contentSection); + } else if ((query == null || query.trim().isEmpty()) + && (type != null && !type.trim().isEmpty())) { + final Class assetType = toAssetTypeClass(type); + assets = assetRepo.findByTypeAndContentSection(assetType, + contentSection); + } else { + final Class assetType = toAssetTypeClass(type); + assets = assetRepo.findByTitleAndTypeAndContentSection( + type, + assetType, + contentSection); + } + + return assets + .stream() + .map(asset -> createAssetMapEntry(asset)) + .collect(Collectors.toList()); + } + + @GET + @Path("/folders/") + @Produces("text/json; charset=utf-8") + @Transactional(Transactional.TxType.REQUIRED) + public List> findAssetsInRootFolder( + @PathParam("content-section") final String section, + @QueryParam("query") final String query, + @QueryParam("type") final String type) { + + final ContentSection contentSection = sectionRepo + .findByLabel(section) + .orElseThrow(() -> new NotFoundException( + String.format("No content section '%s' found.", section))); + + final Folder folder = contentSection.getRootAssetsFolder(); + + return findAssetsInFolder(folder, query, type); + } + + @GET + @Path("/folders/{folder}/") + @Produces("text/json; charset=utf-8") + @Transactional(Transactional.TxType.REQUIRED) + public List> findAssetsInFolder( + @PathParam("content-section") final String section, + @PathParam("folder") final String folderPath, + @QueryParam("query") final String query, + @QueryParam("type") final String type) { + + final ContentSection contentSection = sectionRepo + .findByLabel(section) + .orElseThrow(() -> new NotFoundException( + String.format("No content section '%s' found.", section))); + + final Folder folder = folderRepo.findByPath(contentSection, + folderPath, + FolderType.ASSETS_FOLDER) + .orElseThrow(() -> new NotFoundException(String.format( + "No assets folder with path '%s' in content section '%s'", + folderPath, + section))); + + return findAssetsInFolder(folder, query, type); + } + + private List> findAssetsInFolder(final Folder folder, + final String query, + final String type) { + + final List> subFolderEntries = folder + .getSubFolders() + .stream() + .map(subFolder -> createAssetMapEntry(subFolder)) + .collect(Collectors.toList()); + + final List assets; + if ((query == null || query.trim().isEmpty()) + && ((type == null) || type.trim().isEmpty())) { + assets = assetRepo.findByFolder(folder); + } else if ((query != null && !query.trim().isEmpty()) + && (type == null || type.trim().isEmpty())) { + + assets = assetRepo.filterByFolderAndTitle(folder, query); + } else if ((query == null || query.trim().isEmpty()) + && (type != null && !type.trim().isEmpty())) { + final Class assetType = toAssetTypeClass(type); + assets = assetRepo.filterByFolderAndType(folder, assetType); + } else { + final Class assetType = toAssetTypeClass(type); + assets = assetRepo.filterByFolderAndTypeAndTitle(folder, + assetType, + query); + } + + final List> assetEntries = assets + .stream() + .map(asset -> createAssetMapEntry(asset)) + .collect(Collectors.toList()); + + final List> result = new ArrayList<>(); + result.addAll(subFolderEntries); + result.addAll(assetEntries); + + return result; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/assets/AssetSearchService.java b/ccm-cms/src/main/java/org/librecms/contentsection/rs/AssetsOld.java similarity index 83% rename from ccm-cms/src/main/java/org/librecms/assets/AssetSearchService.java rename to ccm-cms/src/main/java/org/librecms/contentsection/rs/AssetsOld.java index 132a961f7..b18022b31 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/AssetSearchService.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/rs/AssetsOld.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package org.librecms.assets; +package org.librecms.contentsection.rs; import com.arsdigita.kernel.KernelConfig; @@ -48,13 +48,18 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import org.librecms.assets.AssetTypeInfo; +import org.librecms.assets.AssetTypesManager; + +import javax.ws.rs.NotFoundException; + /** * * @author Jens Pelzetter */ @RequestScoped @Path("/{content-section}/assets") -public class AssetSearchService { +public class AssetsOld { @Inject private AssetRepository assetRepo; @@ -94,57 +99,24 @@ public class AssetSearchService { } } - public List findAssetsByQuery(final String query) { - return assetRepo.findByTitle(query); - } - - public List findAssetsByType(final String type) { - return AssetSearchService.this.findAssets(toAssetClass(type)); - } - - public List findAssets(final Class type) { - return assetRepo.findByType(type); - } - - public List findAssets(final String query, final String type) { - - final Class clazz; - try { - clazz = Class.forName(type); - } catch (ClassNotFoundException ex) { - throw new IllegalArgumentException(String.format( - "Type '%s' is not a valid class.", - type)); - } - - if (clazz.isAssignableFrom(Asset.class)) { - @SuppressWarnings("unchecked") - final Class typeClass - = (Class) clazz; - return AssetSearchService.this.findAssets(query, typeClass); - } else { - throw new IllegalArgumentException(String.format( - "Type '%s is not a subclass of '%s'.", - type, - Asset.class.getName())); - } - - } - public List findAssets(final ContentSection section, final String path) { + final Optional folder = folderRepo .findByPath(section, path, FolderType.ASSETS_FOLDER); if (!folder.isPresent()) { - return Collections.emptyList(); + throw new NotFoundException(String.format( + "No asset folder with path '%s' found in content section '%s'.", + path, + section.getLabel())); } - + return assetRepo.findByFolder(folder.get()); } - + public List findAssets(final String query, final Class type) { return assetRepo.findByTitleAndType(query, type); @@ -153,8 +125,8 @@ public class AssetSearchService { @Transactional(Transactional.TxType.REQUIRED) public List findAssetsByType(final ContentSection section, - final String path, - final String type) { + final String path, + final String type) { final Optional folder = folderRepo .findByPath(section, @@ -168,11 +140,11 @@ public class AssetSearchService { return assetRepo.filterByFolderAndType(folder.get(), toAssetClass(type)); } - + @Transactional(Transactional.TxType.REQUIRED) public List findAssetsByQuery(final ContentSection section, - final String path, - final String query) { + final String path, + final String query) { final Optional folder = folderRepo .findByPath(section, @@ -229,7 +201,10 @@ public class AssetSearchService { @QueryParam("query") final String query, @QueryParam("type") final String type) { - final ContentSection contentSection = sectionRepo.findByLabel(section); + final ContentSection contentSection = sectionRepo + .findByLabel(section) + .orElseThrow(() -> new NotFoundException( + String.format("No content section '%s' found.", section))); final String folderPath; if (path == null || path.trim().isEmpty() || "/".equals(path.trim())) { @@ -269,7 +244,7 @@ public class AssetSearchService { assets = findAssetsByQuery(contentSection, folderPath, query); } else { assets - = findAssets(contentSection, folderPath, query, assetType); + = findAssets(contentSection, folderPath, query, assetType); } } diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/JaxRsContentSections.java b/ccm-cms/src/main/java/org/librecms/contentsection/rs/ContentSections.java similarity index 86% rename from ccm-cms/src/main/java/org/librecms/contentsection/JaxRsContentSections.java rename to ccm-cms/src/main/java/org/librecms/contentsection/rs/ContentSections.java index f1fdfb74c..bcfa9cff0 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/JaxRsContentSections.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/rs/ContentSections.java @@ -16,9 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package org.librecms.contentsection; +package org.librecms.contentsection.rs; -import org.librecms.assets.AssetSearchService; import java.util.HashSet; import java.util.Set; @@ -31,13 +30,13 @@ import javax.ws.rs.core.Application; * @author Jens Pelzetter */ @ApplicationPath("/content-sections") -public class JaxRsContentSections extends Application{ +public class ContentSections extends Application{ @Override public Set> getClasses() { final Set> classes = new HashSet<>(); - classes.add(AssetSearchService.class); + classes.add(Assets.class); return classes; } diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties index 9667ad3a9..7c82952cb 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources.properties @@ -249,7 +249,7 @@ cms.ui.folder.no_assets=No assets cms.ui.assets.new=Create new asset cms.ui.assets.new.create=Create asset cms.ui.asset.title=Title -cms.ui.admin.assets.create=Create new asset of type '{0}' +cms.ui.admin.assets.create=Create new asset of type ''{0}'' cms.ui.assets.bookmark.description=Description cms.ui.assets.bookmark.url=URL cms.ui.assets.bookmark.url.malformed=The provided URL is malformed. @@ -265,3 +265,4 @@ cms.ui.assets.sidenote.text=Text cms.ui.assets.search_page.title=Select an asset cms.ui.assets.search_page.query=Search for cms.ui.assets.search_page.query.submit=Find +cms.ui.assets.external_video_asset.legal_metadata.label=Legal metadata diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties index 8c23ad545..e6d988c9d 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_de.properties @@ -248,7 +248,7 @@ cms.ui.folder.no_assets=Keine Medien oder Datens\u00e4tze vorhanden cms.ui.assets.new=Neues Asset anlegen cms.ui.assets.new.create=Asset anlegen cms.ui.asset.title=Titel -cms.ui.admin.assets.create=Neues Asset vom Typ '{0}' anlegen +cms.ui.admin.assets.create=Neues Asset vom Typ ''{0}'' anlegen cms.ui.assets.bookmark.description=Beschreibung cms.ui.assets.bookmark.url=URL cms.ui.assets.bookmark.url.malformed=Die angegebene URL ist nicht wohlgeformt. @@ -264,3 +264,4 @@ cms.ui.assets.sidenote.text=Text cms.ui.assets.search_page.title=W\u00e4hlen Sie ein Asset cms.ui.assets.search_page.query=Suche nach cms.ui.assets.search_page.query.submit=Finden +cms.ui.assets.external_video_asset.legal_metadata.label=Rechtliche Informationen diff --git a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties index 174645e08..c24b9750d 100644 --- a/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties +++ b/ccm-cms/src/main/resources/org/librecms/CmsResources_fr.properties @@ -207,7 +207,7 @@ cms.ui.folder.no_assets=No assets cms.ui.assets.new=Create new asset cms.ui.assets.new.create=Create asset cms.ui.asset.title=Title -cms.ui.admin.assets.create=Create new asset of type '{0}' +cms.ui.admin.assets.create=Create new asset of type ''{0}'' cms.ui.assets.bookmark.description=Description cms.ui.assets.bookmark.url=URL cms.ui.assets.bookmark.url.malformed=The provided URL is malformed. @@ -223,3 +223,4 @@ cms.ui.assets.sidenote.text=Text cms.ui.assets.search_page.title=Select an asset cms.ui.assets.search_page.query=Search for cms.ui.assets.search_page.query.submit=Find +cms.ui.assets.external_video_asset.legal_metadata.label=Legal metadata diff --git a/ccm-cms/src/main/resources/org/librecms/assets/Assets.properties b/ccm-cms/src/main/resources/org/librecms/assets/Assets.properties index 03d5ccd24..880320ffb 100644 --- a/ccm-cms/src/main/resources/org/librecms/assets/Assets.properties +++ b/ccm-cms/src/main/resources/org/librecms/assets/Assets.properties @@ -5,3 +5,5 @@ legal_metadata.label=Legal metadata legal_metadata.description=Stores legal metadata like the informations about the creator of an image etc. sidenote.label=Side note sidenote.description=Additional information. Usually appears in the right or left column of an webpage. +external_video_asset.label=External Video +external_video_asset.description=An external video e.g. on YouTube. The presentation will either be a link or an embedded video. diff --git a/ccm-cms/src/main/resources/org/librecms/assets/Assets_de.properties b/ccm-cms/src/main/resources/org/librecms/assets/Assets_de.properties index c32b5530f..3af530d1f 100644 --- a/ccm-cms/src/main/resources/org/librecms/assets/Assets_de.properties +++ b/ccm-cms/src/main/resources/org/librecms/assets/Assets_de.properties @@ -5,3 +5,5 @@ legal_metadata.label=Rechtliche Informationen legal_metadata.description=Rechtliche Informationen, z.B. die Urheberschaft von Bildern etc. sidenote.label=Randbemerkung sidenote.description=Randbemerkung mit zus\u00e4tzlichen Informationen. Erscheint in der Regel in der rechten oder linken Spalte einer Webseite. +external_video_asset.label=Externes Video +external_video_asset.description=Externes Video z.B. auf YouTube. Wird entweder als Link oder eingebettet angezeigt. diff --git a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms.xsl b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms.xsl index 3779ce831..e7c03a45e 100644 --- a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms.xsl +++ b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms.xsl @@ -23,9 +23,10 @@ exclude-result-prefixes="xsl" version="2.0"> - - - - + + + + + \ No newline at end of file diff --git a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms/asset-search-widget.xsl b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms/asset-search-widget.xsl new file mode 100644 index 000000000..47b5c83b4 --- /dev/null +++ b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/lib/cms/asset-search-widget.xsl @@ -0,0 +1,489 @@ + + + + + + + +
+ + + +

+ +

+ +
+ +

+ + + +

+ +
+
+ + +

+ + +

+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+ $title + + $type + + $place +
+
+
+
+
+ +
diff --git a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/scripts/cms-admin.js b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/scripts/cms-admin.js new file mode 100644 index 000000000..d128b7d26 --- /dev/null +++ b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/scripts/cms-admin.js @@ -0,0 +1,156 @@ +'use strict'; + +/*function selectAsset(button) { + + var assetType = button.getAttribute('data-assettype'); + var contentSection = button.getAttribute('data-contentsection'); + var target = button.getAttribute('data-target'); + + alert("AssetSelection assetType = " + assetType + + "; contentSection = " + contentSection + + "; target = " + target + "; "); + + return false; + }*/ + +function getAssetsForSelectAssetDialog(dialogId) { + + var dialog = document.querySelector('#' + dialogId); + var type = dialog.getAttribute('data-assettype'); + var contentSection = dialog.getAttribute('data-contentsection'); + var targetId = dialog.getAttribute('data-targetId'); + var filter = document.querySelector('#' + dialogId + '-asset-filter'); + var query = filter.value; + var dispatcherPrefix = dialog.getAttribute('data-dispatcherPrefix'); + + var request = new XMLHttpRequest(); + var url = dispatcherPrefix.substring(0, dispatcherPrefix.length - "/ccm".length) + "/content-sections/" + contentSection + "/assets/"; + if (type !== null && type.length > 0) { + url = url + "?type=" + type; + } + + if ((type !== null && type.length > 0) + && (query !== null && query.length > 0)) { + url = url + "&query=" + query; + } else if (query !== null && query.length > 0) { + url = url + "?query=" + query; + } + + request.open("GET", url); +// request.setRequestHeader(); + request.addEventListener('load', function (event) { + if (request.status >= 200 && request.status < 300) { + var assets = JSON.parse(request.responseText); + var tableRows = ""; + var i; + for (i = 0; i < assets.length; ++i) { + var asset = assets[i]; + tableRows = tableRows + + "" + + "" + + "" + + asset['title'] + "" + + "" + + "" + + asset['typeLabel'] + + "" + + "" + asset['place'] + "" + + ""; + } + document + .querySelector("#" + dialogId + " tbody") + .innerHTML = tableRows; + } else { + alert("Error while retrieving assets. " + + "Response code: " + request.status + " " + + "Message: " + request.statusText); + } + }); + request.send(); +} + +function setSelectedAsset(assetId, assetTitle, targetId, dialogId) { + var target = document.querySelector("#" + targetId); + var targetText = document.querySelector("#" + targetId + "-selected"); + + target.value = assetId; + targetText.textContent = assetTitle; + + toggleSelectAssetDialog('hide', dialogId); + +} + +function toggleSelectAssetDialog(mode, dialogId) { + + var dialog = document.querySelector("#" + dialogId); + + if ('show' === mode) { + dialog.setAttribute('open', 'open'); + getAssetsForSelectAssetDialog(dialogId) + } else { + dialog.setAttribute('open', 'false'); + } +} + +document.addEventListener('DOMContentLoaded', function () { + + var i; + + var buttons = document.querySelectorAll('.select-asset-button'); + for (i = 0; i < buttons.length; ++i) { + + buttons[i].addEventListener('click', function (event) { + + var button = event.currentTarget; + var dialogId = button.getAttribute('data-dialogId'); + + toggleSelectAssetDialog('show', dialogId); + + +// var assetType = button.getAttribute('data-assettype'); +// var contentSection = button.getAttribute('data-contentsection'); +// var target = button.getAttribute('data-target'); +// +// alert("AssetSelection assetType = " + assetType +// + "; contentSection = " + contentSection +// + "; target = " + target + "; "); + + event.stopPropagation(); + return false; + }); + } + + var closeButtons = document.querySelectorAll('.asset-search-widget-dialog .close-button'); + for (i = 0; i < closeButtons.length; ++i) { + + closeButtons[i].addEventListener('click', function (event) { + + var button = event.currentTarget; + var dialogId = button.getAttribute('data-dialogId'); + + toggleSelectAssetDialog('hide', dialogId); + + event.stopPropagation(); + return false; + }); + + } + + var applyButtons = document.querySelectorAll('.asset-search-widget-dialog .apply-filter'); + for (i = 0; i < applyButtons.length; ++i) { + + applyButtons[i].addEventListener('click', function (event) { + + var button = event.currentTarget; + var dialogId = button.getAttribute('data-dialogId'); + + getAssetsForSelectAssetDialog(dialogId); + + event.stopPropagation(); + return false; + }); + + + } +}); + diff --git a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/styles/admin.css b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/styles/admin.css index 959b9ab9d..3e93fdaae 100644 --- a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/styles/admin.css +++ b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/styles/admin.css @@ -1425,13 +1425,120 @@ dl dd a:hover { .tile div + div { height: auto; } -s + img.cmsImageDisplay { float: left; max-height: 200px; width: auto; } +div.asset-search-widget dialog { + background-color: #e6e4f2; + + border: 1px solid #555; + border-radius: 0.75em; + + box-shadow: 5px 5px #aaa; + + display: none; + + padding: 0; + + position: absolute; + top: 5%; + left: 2%; + + width: 96%; + height: 90%; + + z-index: 999; +} + +div.asset-search-widget dialog[open="open"] { + display: block; +} + +div.asset-search-widget dialog .controls { + padding: 0.5em; +} + +div.asset-search-widget dialog .controls label { + + font-weight: bold; + + margin-right: 0.5em; +} + +div.asset-search-widget dialog .dialogarea controls button { + + margin-left: 0.5em; + +} +div .asset-search-widget dialog .selectable-assets { + + padding: 0; + + position: absolute; + bottom: 0; + left: 0; + + width: 100%; + height: 80%; + overflow: scroll; +} + +div.asset-search-widget dialog .dialogarea table { + + margin-top: 1em; + margin-left: 0.5em; + margin-right: 0.5em; +} + +div.asset-search-widget dialog .selectable-assets table thead tr th { + + background-color: transparent; + + color: #000; + + font-weight: bold; + +} + +div.asset-search-widget dialog .titlebar { + + border-bottom: 1px solid #555; + + margin-top: 0; + + padding: 0.5em 1em; +} + +div.asset-search-widget dialog .titlebar .close-button { + + background-color: transparent; + + border: none; + + font-size: 18px; + + position: absolute; + right: 5px; +} + +div.asset-search-widget dialog .titlebar .close-button:after { + content: '\2715'; +} + +div.asset-search-widget dialog .titlebar .close-button span { + + position: absolute; + top: -999px; + + width: 1px; + height: 1px; + overflow:hidden; +} + div.cmsImageInfoOverlay { float: left; margin-left: 2em; @@ -1796,7 +1903,7 @@ span#quickLinksCascade { .static-new-item-form select { max-width: 12em; - + } .static-new-item-form input { diff --git a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/templates/admin-layout.xml b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/templates/admin-layout.xml index 015bb5111..bda585123 100644 --- a/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/templates/admin-layout.xml +++ b/ccm-theme-foundry/src/main/resources/themes/foundry/foundry/templates/admin-layout.xml @@ -8,15 +8,16 @@ -