Index: main/plugin-blog/i18n/messages_en.xml =================================================================== --- main/plugin-blog/i18n/messages_en.xml (revision 31348) +++ main/plugin-blog/i18n/messages_en.xml (working copy) @@ -56,7 +56,8 @@ The displayed title. Display Service display - Default + Tree + Flat list Posts Posts Title Index: main/plugin-blog/i18n/messages_fr.xml =================================================================== --- main/plugin-blog/i18n/messages_fr.xml (revision 31348) +++ main/plugin-blog/i18n/messages_fr.xml (working copy) @@ -56,7 +56,8 @@ Titre Affichage Affichage - Defaut + Vue arborescence + Liste à plat Liste de billets Ce service affiche une liste de billets. Titre Index: main/plugin-blog/pages/services/tags/list_1.0.xml =================================================================== --- main/plugin-blog/pages/services/tags/list_1.0.xml (revision 0) +++ main/plugin-blog/pages/services/tags/list_1.0.xml (revision 0) @@ -0,0 +1,19 @@ + + + + + Index: main/plugin-blog/pages/services/tags/list_1.0.xsl =================================================================== --- main/plugin-blog/pages/services/tags/list_1.0.xsl (revision 0) +++ main/plugin-blog/pages/services/tags/list_1.0.xsl (revision 0) @@ -0,0 +1,102 @@ + + + + + + + + 1 + true + + + blog blog-tags blog-list + + service-blog-tags + + + + + + + + + + + + + + + + + + + + + + + +
    + + 1 + +
+
+
+ + + 1 + +
  • + + + + + +
      + + + +
    +
    +
  • +
    + + + + ( + + + + + + + + + ) + + + +
    Index: main/plugin-blog/pages/services/tags/tree_1.0.xsl =================================================================== --- main/plugin-blog/pages/services/tags/tree_1.0.xsl (revision 31348) +++ main/plugin-blog/pages/services/tags/tree_1.0.xsl (working copy) @@ -24,7 +24,7 @@ - 1 + 4 true @@ -59,7 +59,7 @@
      - + 1
    @@ -76,7 +76,7 @@
      - +
    Index: main/plugin-blog/plugin.xml =================================================================== --- main/plugin-blog/plugin.xml (revision 31348) +++ main/plugin-blog/plugin.xml (working copy) @@ -1000,6 +1000,7 @@ pages/services/tags pages/services/tags/tree_1.0.xsl + pages/services/tags/list_1.0.xsl Index: main/plugin-blog/src/org/ametys/plugins/blog/BlogCacheManager.java =================================================================== --- main/plugin-blog/src/org/ametys/plugins/blog/BlogCacheManager.java (revision 31348) +++ main/plugin-blog/src/org/ametys/plugins/blog/BlogCacheManager.java (working copy) @@ -57,6 +57,9 @@ import org.ametys.web.repository.content.jcr.DefaultWebContent; import org.ametys.web.repository.site.SiteManager; import org.ametys.web.site.SiteConfigurationExtensionPoint; +import org.ametys.web.tags.Tag; +import org.ametys.web.tags.TagHelper; +import org.ametys.web.tags.TagProviderExtensionPoint; /** * Blog cache manager. @@ -72,6 +75,9 @@ /** The ametys object resolver. */ protected AmetysObjectResolver _ametysResolver; + /** Th tag provider */ + protected TagProviderExtensionPoint _tagProviderEP; + /** The Site manager. */ protected SiteManager _siteManager; @@ -104,6 +110,7 @@ _siteConf = (SiteConfigurationExtensionPoint) serviceManager.lookup(SiteConfigurationExtensionPoint.ROLE); _blogRootHandler = (BlogPageHandler) serviceManager.lookup(BlogPageHandler.ROLE); _workspaceSelector = (WorkspaceSelector) serviceManager.lookup(WorkspaceSelector.ROLE); + _tagProviderEP = (TagProviderExtensionPoint) serviceManager.lookup(TagProviderExtensionPoint.ROLE); } @Override @@ -451,10 +458,35 @@ */ public Collection getSortedPostsByTag(String siteName, String language, String tagName) { + return getSortedPostsByTag (siteName, language, tagName, false); + } + + /** + * Get the posts for a given tag. + * @param siteName + * @param language + * @param tagName + * @return the tag posts, indexed by ID. + */ + public Collection getSortedPostsByTag(String siteName, String language, String tagName, boolean deepSearch) + { PostTagCache cache = getPostTagCache(siteName, language); List sortedPosts = new ArrayList(cache.getPosts(tagName).values()); + if (deepSearch) + { + Tag tag = _tagProviderEP.getTag(siteName, tagName); + if (tag != null) + { + Set descendantsNames = TagHelper.getDescendantNames(tag, false); + for (String descendantsName : descendantsNames) + { + sortedPosts.addAll(cache.getPosts(descendantsName).values()); + } + } + } + Collections.sort(sortedPosts, new ReverseDatePostComparator()); return sortedPosts; Index: main/plugin-blog/src/org/ametys/plugins/blog/posts/BlogPagesGenerator.java =================================================================== --- main/plugin-blog/src/org/ametys/plugins/blog/posts/BlogPagesGenerator.java (revision 31348) +++ main/plugin-blog/src/org/ametys/plugins/blog/posts/BlogPagesGenerator.java (working copy) @@ -29,6 +29,10 @@ import org.xml.sax.SAXException; import org.ametys.plugins.blog.BlogPageHandler; +import org.ametys.plugins.blog.repository.VirtualMonthPage; +import org.ametys.plugins.blog.repository.VirtualPostPage; +import org.ametys.plugins.blog.repository.VirtualTagPage; +import org.ametys.plugins.blog.repository.VirtualYearPage; import org.ametys.plugins.repository.AmetysObjectResolver; import org.ametys.web.repository.page.Page; import org.ametys.web.repository.page.PagesContainer; @@ -107,6 +111,23 @@ attrs.addCDATAAttribute("path", page.getPathInSitemap()); attrs.addCDATAAttribute("id", page.getId()); + if (page instanceof VirtualPostPage) + { + attrs.addCDATAAttribute("type", "post"); + } + else if (page instanceof VirtualTagPage) + { + attrs.addCDATAAttribute("type", "tag"); + } + else if (page instanceof VirtualYearPage) + { + attrs.addCDATAAttribute("type", "year"); + } + else if (page instanceof VirtualMonthPage) + { + attrs.addCDATAAttribute("type", "month"); + } + for (String tag : page.getTags()) { attrs.addCDATAAttribute("PLUGIN_TAGS_" + tag, "empty"); Index: main/plugin-blog/src/org/ametys/plugins/blog/posts/PostsGenerator.java =================================================================== --- main/plugin-blog/src/org/ametys/plugins/blog/posts/PostsGenerator.java (revision 31348) +++ main/plugin-blog/src/org/ametys/plugins/blog/posts/PostsGenerator.java (working copy) @@ -194,7 +194,7 @@ } else if ("tag".equals(type)) { - postIt = _blogCache.getSortedPostsByTag(siteName, language, tagName).iterator(); + postIt = _blogCache.getSortedPostsByTag(siteName, language, tagName, true).iterator(); } if (postIt != null) Index: main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagPage.java =================================================================== --- main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagPage.java (revision 31349) +++ main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagPage.java (working copy) @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Map; import java.util.Set; import org.ametys.cms.repository.Content; @@ -32,6 +33,7 @@ import org.ametys.plugins.repository.CollectionIterable; import org.ametys.plugins.repository.UnknownAmetysObjectException; import org.ametys.plugins.repository.metadata.CompositeMetadata; +import org.ametys.runtime.util.I18nUtils; import org.ametys.web.repository.page.Page; import org.ametys.web.repository.page.PagesContainer; import org.ametys.web.repository.page.Zone; @@ -40,9 +42,13 @@ import org.ametys.web.site.SiteConfigurationExtensionPoint; import org.ametys.web.skin.Skin; import org.ametys.web.skin.SkinsManager; +import org.ametys.web.tags.Tag; +import org.ametys.web.tags.TagHelper; +import org.ametys.web.tags.TagProviderExtensionPoint; /** - * Virtual page representing a year page. + * Virtual page representing a tag page. + * A tag page can contains {@link VirtualTagPage}s or {@link VirtualPostPage} */ public class VirtualTagPage extends AbstractBlogPage { @@ -53,22 +59,28 @@ private PagesContainer _root; private String _tagName; private String _title; + private TagProviderExtensionPoint _tagProviderEP; + private I18nUtils _i18nUtils; /** * Constructor. * @param resolver the {@link AmetysObjectResolver}. * @param cacheManager the {@link AmetysObjectResolver}. * @param skinsManager the {@link SkinsManager} - * @param siteConf - * @param tagName + * @param tagProviderEP the tag provider + * @param i18nUtils the i18n utils + * @param siteConf the site configuration + * @param tagName The tag name * @param title the page's title. * @param root the blog root page. */ - public VirtualTagPage(AmetysObjectResolver resolver, BlogCacheManager cacheManager, SkinsManager skinsManager, SiteConfigurationExtensionPoint siteConf, String tagName, String title, PagesContainer root) + public VirtualTagPage(AmetysObjectResolver resolver, BlogCacheManager cacheManager, SkinsManager skinsManager, TagProviderExtensionPoint tagProviderEP, I18nUtils i18nUtils, SiteConfigurationExtensionPoint siteConf, String tagName, String title, PagesContainer root) { _resolver = resolver; _cacheManager = cacheManager; _skinsManager = skinsManager; + _tagProviderEP = tagProviderEP; + _i18nUtils = i18nUtils; _siteConf = siteConf; _root = root; _tagName = tagName; @@ -146,6 +158,23 @@ { ArrayList childrenPages = new ArrayList(); + Tag tag = _tagProviderEP.getTag(getSiteName(), _tagName); + + Set tagNames = _cacheManager.getTags(getSiteName(), getSitemapName()); + + Map childTags = tag.getTags(); + for (Tag childTag : childTags.values()) + { + Set descendantAndItSelfNames = TagHelper.getDescendantNames(childTag, true); + + if (!Collections.disjoint(tagNames, descendantAndItSelfNames)) + { + String title = _i18nUtils.translate(childTag.getTitle(), getSitemapName()); + VirtualTagPage page = new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _tagProviderEP, _i18nUtils, _siteConf, childTag.getName(), title, _root); + childrenPages.add(page); + } + } + // Map posts = _cacheManager.getPostsByTag(getSiteName(), getSitemapName(), _tagName); Collection posts = _cacheManager.getSortedPostsByTag(getSiteName(), getSitemapName(), _tagName); for (Post post : posts) @@ -165,14 +194,24 @@ { String rootPath = _root.getPathInSitemap(); - StringBuilder buff = new StringBuilder(rootPath); + String path = _tagName; + + Tag tag = _tagProviderEP.getTag(getSiteName(), _tagName); + Tag parentTag = tag.getParent(); + while (parentTag != null) + { + path = parentTag.getName() + "/" + path; + parentTag = parentTag.getParent(); + } + + path = VirtualTagsPage.NAME + "/" + path; + if (!rootPath.isEmpty()) { - buff.append('/'); + path = "/" + path; } - buff.append(VirtualTagsPage.NAME).append('/').append(_tagName); - return buff.toString(); + return path; } @Override @@ -208,27 +247,35 @@ throw new AmetysRepositoryException("Path must be non empty"); } -// int slashPos = path.indexOf('/'); -// int questionPos = path.indexOf('?', slashPos); -// int ampPos = path.indexOf('&', questionPos); - -// String childName = slashPos == -1 ? path : path.substring(0, slashPos); -// String rootId = path.substring(questionPos + "?rootId=".length(), ampPos); -// String postId = path.substring(ampPos + "&postId=".length()); - + // TAG_1/TAG_2/TAG_3 int slashPos = path.indexOf('/'); String childName = slashPos == -1 ? path : path.substring(0, slashPos); - Post post = _cacheManager.getPostByName(getSiteName(), getSitemapName(), _tagName, childName); - if (post == null) + AbstractBlogPage page = null; + if (_cacheManager.hasTag(getSiteName(), getSitemapName(), childName)) { - throw new UnknownAmetysObjectException(path + " is not a valid post page."); + Tag tag = _tagProviderEP.getTag(getSiteName(), childName); + if (tag == null) + { + throw new UnknownAmetysObjectException("No child named " + childName + " exists in parent " + getId()); + } + + String title = _i18nUtils.translate(tag.getTitle(), getSitemapName()); + + page = new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _tagProviderEP, _i18nUtils, _siteConf, childName, title, _root); } - - Content postContent = _resolver.resolveById(post.getId()); - - VirtualPostPage page = new VirtualPostPage(_resolver, _skinsManager, _root, postContent, VirtualTagsPage.NAME + "/" + _tagName); + else + { + Post post = _cacheManager.getPostByName(getSiteName(), getSitemapName(), _tagName, childName); + if (post == null) + { + throw new UnknownAmetysObjectException(path + " is not a valid post page."); + } + + Content postContent = _resolver.resolveById(post.getId()); + page = new VirtualPostPage(_resolver, _skinsManager, _root, postContent, VirtualTagsPage.NAME + "/" + _tagName); + } if (slashPos == -1) { Index: main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagPageFactory.java =================================================================== --- main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagPageFactory.java (revision 31349) +++ main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagPageFactory.java (working copy) @@ -16,6 +16,9 @@ package org.ametys.plugins.blog.repository; +import java.util.Collections; +import java.util.Set; + import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; @@ -33,6 +36,7 @@ import org.ametys.web.site.SiteConfigurationExtensionPoint; import org.ametys.web.skin.SkinsManager; import org.ametys.web.tags.Tag; +import org.ametys.web.tags.TagHelper; import org.ametys.web.tags.TagProviderExtensionPoint; /** @@ -89,20 +93,24 @@ PagesContainer root = _resolver.resolveById(rootId); - if (!_cacheManager.hasTag(root.getSiteName(), root.getSitemapName(), tagName)) - { - throw new UnknownAmetysObjectException("There's no virtual child page named " + tagName + " for parent " + rootId); - } - Tag tag = _tagProviderEP.getTag(root.getSiteName(), tagName); + if (tag == null) { throw new UnknownAmetysObjectException("There's no virtual child page named " + tagName + " for parent " + rootId); } + Set descendantOrItSelfNames = TagHelper.getDescendantNames(tag, true); + Set tagNames = _cacheManager.getTags(root.getSiteName(), root.getSitemapName()); + + if (Collections.disjoint(tagNames, descendantOrItSelfNames)) + { + throw new UnknownAmetysObjectException("There's no virtual child page named " + tagName + " for parent " + rootId); + } + String title = _i18nUtils.translate(tag.getTitle(), root.getSitemapName()); - return new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _siteConf, tagName, title, root); + return new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _tagProviderEP, _i18nUtils, _siteConf, tagName, title, root); } @Override @@ -113,17 +121,28 @@ String tagName = id.substring(getScheme().length() + 3, rootPos); String rootId = id.substring(rootPos + "?rootId=".length()); - Page root = null; + PagesContainer root = _resolver.resolveById(rootId); try { root = _resolver.resolveById(rootId); - } + + Tag tag = _tagProviderEP.getTag(root.getSiteName(), tagName); + if (tag == null) + { + return false; + } + + Set descendantOrItSelfNames = TagHelper.getDescendantNames(tag, true); + Set tagNames = _cacheManager.getTags(root.getSiteName(), root.getSitemapName()); + + return !Collections.disjoint(tagNames, descendantOrItSelfNames); + } catch (UnknownAmetysObjectException e) { // Ignore. } - return root != null && _cacheManager.hasTag(root.getSiteName(), root.getSitemapName(), tagName); + return false; } /** Index: main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagsPage.java =================================================================== --- main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagsPage.java (revision 31349) +++ main/plugin-blog/src/org/ametys/plugins/blog/repository/VirtualTagsPage.java (working copy) @@ -19,6 +19,8 @@ import java.util.Collections; import java.util.Set; +import javax.jcr.RepositoryException; + import org.ametys.plugins.blog.BlogCacheManager; import org.ametys.plugins.explorer.resources.ResourceCollection; import org.ametys.plugins.repository.AmetysObject; @@ -27,6 +29,7 @@ import org.ametys.plugins.repository.AmetysRepositoryException; import org.ametys.plugins.repository.CollectionIterable; import org.ametys.plugins.repository.EmptyIterable; +import org.ametys.plugins.repository.TraversableAmetysObject; import org.ametys.plugins.repository.UnknownAmetysObjectException; import org.ametys.plugins.repository.metadata.CompositeMetadata; import org.ametys.runtime.util.I18nUtils; @@ -39,7 +42,10 @@ import org.ametys.web.site.SiteConfigurationExtensionPoint; import org.ametys.web.skin.SkinsManager; import org.ametys.web.tags.Tag; +import org.ametys.web.tags.TagHelper; import org.ametys.web.tags.TagProviderExtensionPoint; +import org.ametys.web.tags.jcr.JCRTag; +import org.ametys.web.tags.jcr.JCRTagProvider; /** * Virtual page representing the Post list page. @@ -146,13 +152,6 @@ public Zone getZone(String name) throws UnknownZoneException, AmetysRepositoryException { throw new UnknownZoneException("There is no zone on the blog tags page."); -// return null; -// if (!"default".equals(name)) -// { -// throw new IllegalArgumentException("Only the zone named 'default' is actually supported on virtual program pages."); -// } -// -// return new DomainZone(this); } @Override @@ -174,6 +173,40 @@ Set tagNames = _cacheManager.getTags(getSiteName(), getSitemapName()); + JCRTagProvider provider = (JCRTagProvider) _tagProviderEP.getExtension(JCRTagProvider.class.getName()); + try + { + TraversableAmetysObject rootNode = provider.getRootNode(getSiteName()); + AmetysObjectIterable it = rootNode.getChildren(); + for (AmetysObject object : it) + { + if (object instanceof JCRTag) + { + String tagName = object.getName(); + Tag tag = _tagProviderEP.getTag(getSiteName(), object.getName()); + + Set descendantAndItSelfNames = TagHelper.getDescendantNames(tag, true); + + if (!Collections.disjoint(tagNames, descendantAndItSelfNames)) + { + String title = _i18nUtils.translate(tag.getTitle(), getSitemapName()); + + VirtualTagPage page = new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _tagProviderEP, _i18nUtils, _siteConf, tagName, title, _root); + + children.add(page); + } + } + } + } + catch (RepositoryException e) + { + throw new AmetysRepositoryException("Unable to get tags pages", e); + } + + /*ArrayList children = new ArrayList(); + + Set tagNames = _cacheManager.getTags(getSiteName(), getSitemapName()); + for (String tagName : tagNames) { Tag tag = _tagProviderEP.getTag(getSiteName(), tagName); @@ -185,7 +218,7 @@ children.add(page); } - } + }*/ return new CollectionIterable(children); } @@ -240,20 +273,23 @@ String childName = slashPos == -1 ? path : path.substring(0, slashPos); - if (!_cacheManager.hasTag(getSiteName(), getSitemapName(), childName)) + Set tagNames = _cacheManager.getTags(getSiteName(), getSitemapName()); + + Tag tag = _tagProviderEP.getTag(getSiteName(), childName); + if (tag == null) { throw new UnknownAmetysObjectException("No child named " + childName + " exists in parent " + getId()); } - Tag tag = _tagProviderEP.getTag(getSiteName(), childName); - if (tag == null) + Set descendantAndItSelfNames = TagHelper.getDescendantNames(tag, true); + if (Collections.disjoint(tagNames, descendantAndItSelfNames)) { throw new UnknownAmetysObjectException("No child named " + childName + " exists in parent " + getId()); } String title = _i18nUtils.translate(tag.getTitle(), getSitemapName()); - VirtualTagPage page = new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _siteConf, childName, title, _root); + VirtualTagPage page = new VirtualTagPage(_resolver, _cacheManager, _skinsManager, _tagProviderEP, _i18nUtils, _siteConf, childName, title, _root); if (slashPos == -1) { Index: main/plugin-blog/stylesheets/content/post/post.xsl =================================================================== --- main/plugin-blog/stylesheets/content/post/post.xsl (revision 31348) +++ main/plugin-blog/stylesheets/content/post/post.xsl (working copy) @@ -80,8 +80,8 @@
  • - - + + ,