Index: main/plugin-web/i18n/messages_en.xml =================================================================== --- main/plugin-web/i18n/messages_en.xml (revision 26702) +++ main/plugin-web/i18n/messages_en.xml (working copy) @@ -25,8 +25,6 @@ Access to custom tags Tags management Add, update or delete tags - Tag categories management - Add, update or delete tag categories Import tags Import tags from a XML file Rights on sitemap @@ -694,7 +692,6 @@ Tag Description - Category Type Select tag for more details An error occurred: impossible to set a tag on page or content @@ -709,7 +706,7 @@ <i>PAGE</i> tag Add tag - Add tag on selected category + Add tag as a child of the selected tag See Help for details Edit tag Edit selected tag @@ -717,22 +714,12 @@ Delete tag Delete selected tag See Help for details - Add category - Add category on selected node - See Help for details - Edit category - Edit selected category - See Help for details - Delete category - Delete selected category - See Help for details Tags An error occurred. Tool cannot display Import a file Import tags from a CSV file. - This button is disabled because no category is selected. Import tags from a XML file - Please select a XML file from your local storage containing the tags and categories to import. + Please select a XML file from your local storage containing the tags to import. File XML file containing the tags to import Please select a XML file @@ -750,7 +737,6 @@ 1 tag was not imported. tags were not imported. Error importing the tags - The tags could not be imported: the selected category does not exist anyware. You must select a file with .xml extension. The file is too large. The tags were not imported. An unexpected error has occurred : The tags were not imported. @@ -759,8 +745,6 @@ New tag Edit tag - New category - Edit category Title New Tag's title.<br/>The internal key, automatically created, will be based on this title. @@ -778,8 +762,7 @@ OK Cancel - Unable to create tag: parent category no longer exists. - Key already used for current website. + Unable to create tag: parent tag no longer exists. An error occurred : unable to create tag. An error occurred : unable to update tag. Unable to update tag: unknown tag. @@ -787,19 +770,13 @@ Do you really want to delete this tag? Unable to delete tag: unknown tag. An error occurred : unable to delete tag. - Unable to create category : unknown parent category. - Category name already used in current website - An error occurred : unable to create category. - An error occurred : unable to update category. - Unable to update category: unknown category. An error occurred : unable to collect tag data. - An error occured : unable to collect category data. - Delete - Do you really want to delete this category and its sub-categories? Note that tags belonging to these categories will also be deleted ? - Unable to delete category : unkown category. - An error occurred: unable to delete category. Invalid key : please type a key without space or special characters. Autrorized characters are A to Z, 0 to 9 and _. + Tags + Autoposting + Enable the autoposting feature for full text search. + @@ -1323,6 +1300,8 @@ Check this option to filter contents according to access rights of the connected user.<br/><b>Be careful!</b> Enabling this feature disables this page's cache and degrades its performance: it should not be checked on high traffic pages like the home page.<br/>If this option is disabled the resulting contents will be identical for all visitors having access to the page. Tags Service will only display contents tagged with specific tags.<br/>You can leave that field empty. + Strict search on tags + If strict search is disabled, the service will also display contents tagged with child tags of the selected tags. RSS feed See the RSS feed for these contents Check box to display an RSS feed on contents digest @@ -1421,11 +1400,13 @@ With checkboxes then by filter on results None (visitor has no choice) Search by tag - Add criterias on tags by selecting tag categories.<br/>The criteria will be the name of category and display a list of tags.<br/>Select several categories to display several criterias on tags.<br/>Leave empty if you don't want that kind of criteria. + Add criterias on tags by selecting a set of tags.<br/>The criteria will be the name of tag and display the list of child tags.<br/>There will be a distinct criterion for each selected tag, with every criterion displaying its own list of child tags.<br/>Leave empty if you do not want to use that kind of criteria. Search by section Select several pages of website to add a section criteria for search engine.<br/>If you choose only one section, search will only apply to pages of the selected section and visitor will have no criteria.<br/>If you select several sections, user will choose a section in a list.<br/>Leave empty to search on every sections. Multisite Check box if you want to propose search on all sites for visitors + Strict search on tags + If strict search is disabled, the service will also display contents tagged with child tags of the selected tags. The search field can not begin with character ? or *. Service identifier Optional, this field allows to give two instances of the same service (in different zones) the same identifier, to make it communicate.<br/>This allows, for instance, to display the results in a zone different of the search form. @@ -1927,16 +1908,11 @@ Collapse all Filter Select tags ... - Add a new tag to the selected category. + Add a new tag to the current selection. You are not allowed to add a tag here. - Please select a custom tag category to add a new tag. + Please select a custom tag to be able to add a new child tag. Ok Cancel - Click here to select tag category - Select tag category ... - Filter - Ok - Cancel No tag match the chosen context. Select content ... Search content ... @@ -2309,7 +2285,6 @@ Tags Tags - Categories Tags Index: main/plugin-web/i18n/messages_fr.xml =================================================================== --- main/plugin-web/i18n/messages_fr.xml (revision 26702) +++ main/plugin-web/i18n/messages_fr.xml (working copy) @@ -20,13 +20,11 @@ Redirection d'URLs Redirection d'URLs Autorise l'accès et la gestion des alias de page (ou redirection d'url) - Droits sur les étiquettes + Droits sur les étiquettes Etiquettes personnalisées Autorise l'accès à la liste des étiquettes personnalisées Gestion des étiquettes Autorise à ajouter, modifier ou supprimer des étiquettes - Gestion des catégories d'étiquette - Autorise à ajouter, modifier ou supprimer des catégories d'étiquette Importer des étiquettes Importer des étiquettes à partir d'un fichier xml Droits sur le plan du site @@ -694,7 +692,6 @@ Etiquette Description - Catégorie Type Sélectionner une étiquette pour plus d'information Une erreur est survenue : impossible d'étiqueter la page / le contenu @@ -709,7 +706,7 @@ Etiquette de <i>PAGE</i> Ajouter une étiquette - Ajoute une étiquette au niveau de la catégorie sélectionnée + Ajoute une étiquette en tant qu'enfant de l'étiquette sélectionnée Voir l'aide pour plus de détails Modifier l'étiquette Modifie l'étiquette sélectionnée @@ -717,22 +714,12 @@ Supprimer l'étiquette Supprime l'étiquette sélectionnée Voir l'aide pour plus de détails - Ajouter une catégorie - Ajoute une catégorie d'étiquette au niveau de la catégorie sélectionnée - Voir l'aide pour plus de détails - Modifier la catégorie - Modifie la catégorie d'étiquette sélectionnée - Voir l'aide pour plus de détails - Supprimer la catégorie - Supprime la catégorie d'étiquette sélectionnée - Voir l'aide pour plus de détails Etiquettes Une erreur survenue empêchant l'affichage de l'outil Importer des étiquettes Importer des étiquettes depuis un fichier xml. - Ce bouton est désactivé car aucune catégorie n'est sélectionnée. Importer des étiquettes depuis un fichier xml - Veuillez sélectionner un fichier .xml de votre disque dur contenant les étiquettes et catégories d'étiquettes à importer. + Veuillez sélectionner un fichier .xml de votre disque dur contenant les étiquettes à importer. Fichier Fichier XML contenant les étiquettes à importer Veuillez sélectionner un fichier XML @@ -750,7 +737,6 @@ 1 étiquette n'a pu être importée. étiquettes n'ont pu être importées. Importer des étiquettes - Les étiquettes n'ont pas pu être importées : la catégorie d'étiquettes sélectionnée n'existe plus. Vous devez sélectionner un fichier XML Le fichier est trop volumineux. Les étiquettes n'ont pas pu être importées. Une erreur inattendue est survenue : les étiquettes n'ont pas pu être importées. @@ -759,8 +745,6 @@ Nouvelle étiquette Modifier l'étiquette - Nouvelle catégorie - Modifier la catégorie Titre Nouveau Titre de l'étiquette.<br/>La clé interne sera calculée automatiquement en fonction de ce titre. @@ -778,8 +762,7 @@ OK Annuler - Impossible de créer l'étiquette: la catégorie parente n'existe plus. - La clef de cette étiquette est déjà utilisée pour ce site. + Impossible de créer l'étiquette: l'étiquette parente n'existe plus. Une erreur inattendue est survenue : l'étiquette n'a pu être créée. Une erreur inattendue est survenue : l'étiquette n'a pu être modifiée. Impossible de modifier l'étiquette: l'étiquette n'existe plus. @@ -787,19 +770,13 @@ Etes-vous sûr de vouloir supprimer cette étiquette ? Impossible de supprimer l'étiquette: l'étiquette n'existe plus. Une erreur inattendue est survenue : l'étiquette n'a pu être supprimée. - Impossible de créer la catégorie : la catégorie parente n'existe plus. - La nom de cette catégorie est déjà utilisée pour ce site - Une erreur inattendue est survenue : la catégorie n'a pu être créée. - Une erreur inattendue est survenue : la catégorie n'a pu être modifiée. - Impossible de modifier la catégorie: la catégorie n'existe plus. Une erreur est survenue : impossible de récupérer les informations sur l'étiquette. - Une erreur est survenue : impossible de récupérer les informations sur la catégorie d'étiquette. - Suppression - Etes-vous sûr de vouloir supprimer cette catégorie d'étiquette et ses sous-catégories et/ou étiquettes ? - Impossible de supprimer la catégorie : la catégorie n'existe plus. - Une erreur inattendue est survenue : la catégorie n'a pu être supprimée. La clé est invalide : veuillez choisir une clé sans espace ni accent, composée uniquement des caractères A à Z, 0 à 9 et _. + Etiquettes + Autopostage + Activer l'autopostage pour prendre en compte la hiérarchie des étiquettes dans les recherches plein texte. + @@ -1321,9 +1298,11 @@ Masquer les contenus orphelins Cochez cette case si vous ne voulez pas que les contenus orphelins soient remontés.<br/>Un contenu est orphelin si il n'est pas rattaché à une page ou si sa page n'est pas publiée. Prendre en compte les droits de l'utilisateur - Cochez cette option pour que la remontée de contenus soit personnalisées en fonction des droits d'accès de l'utilisateur connecté.<br/><b>Attention !</b> Ceci désactive la mise en cache de la page et en dégrade donc les performances : il est déconseillé d'activer cette option sur des pages à fort trafic, telle que la page d'accueil du site.<br/>Si cette option est désactivée la remontée de contenus est identique pour tous les visiteurs ayant accès à la page. + Cochez cette option pour que seuls les contenus auxquels l'utilisateur a accès soient remontés.<br/><b>Attention !</b> Cocher cette option désactive la mise en cache de la page et en dégrade donc les performances : il est déconseillé de l'activer sur des pages à fort trafic, comme la page d'accueil. Etiquettes Le service remontera uniquement les contenus étant étiquetés avec les étiquettes sélectionnées.<br/>Ce champ peut être vide. + Recherche stricte sur les étiquettes + Si la recherche stricte n'est pas activée, le service remontera également les contenus étant étiquetés avec des étiquettes filles de celles sélectionnées. Fils RSS Voir le flux RSS de ces contenus Cocher la case pour afficher l'icone de flux RSS @@ -1422,7 +1401,9 @@ Par des cases à cocher puis par filtre sur les résultats Aucun (choix imposé au visiteur) Recherche par étiquette - Vous pouvez ajouter le critère de recherche par étiquette en sélectionnant une catégorie d'étiquette.<br/>Le critère portera le nom de la catégorie et prendra la forme d'une liste déroulante avec la liste des d'étiquettes de cette catégorie.<br/>Chaque catégorie sélectionnée donne lieu à un critère de ce type.<br/>Laissez ce paramètre vide pour que ce critère n'apparaissse pas. + Vous pouvez ajouter le critère de recherche par étiquette en sélectionnant un ensemble d'étiquette.<br/>Le critère portera le nom de l'étiquette et prendra la forme d'une liste déroulante avec la liste des étiquettes filles.<br/>Chaque étiquette sélectionnée donne lieu à un critère de ce type.<br/>Laissez ce paramètre vide pour que ce critère n'apparaissse pas. + Recherche stricte sur les étiquettes + Si la recherche stricte n'est pas activée, le service remontera également les contenus étant étiquetés avec des étiquettes filles de celles sélectionnées. Recherche par rubrique Vous pouvez ajouter le critère de recherche par rubrique en sélectionnant une ou plusieurs pages de votre site.<br/>Si vous ne sélectionnez qu'une seule rubrique, la recherche ne portera que sur les pages de cette rubrique sans donner le choix aux utilisateurs.<br/>Si vous sélectionnez plus d'une rubrique, l'utilisateur pourra choisir une rubrique dans une liste déroulante.<br/>Laissez ce paramètre vide pour que ce critère n'apparaisse pas et que la recherche s'effectue dans toutes les rubriques du site. Recherche multisite @@ -1928,17 +1909,12 @@ Fermer tout Supprimer l'étiquette Sélectionnez des étiquettes ... - Cliquez ici pour ajouter une étiquette à la catégorie sélectionnée. + Cliquez ici pour ajouter une étiquette fille à la sélection. Vos droits sont insuffisants pour ajouter une étiquette ici. - Sélectionnez une catégorie d'étiquettes personnalisées pour en ajouter une. + Sélectionnez une étiquette personnalisée pour pouvoir ajouter une étiquette fille. Ok Annuler Aucune étiquette ne correspond dans le contexte choisi. - Cliquez ci-après pour sélectionner une catégorie d'étiquette - Sélectionnez des catégories d'étiquettes ... - Filtre - Ok - Annuler Sélectionner un contenu ... Rechercher un contenu ... Pour sélectionner le contenu d'une page, choisissez d'abord le site, la langue et la page dans l'arbre ci-dessous. Sélectionnez ensuite un contenu de la page sélectionnée dans la liste déroulante. @@ -2310,7 +2286,6 @@ Etiquettes Etiquettes - Catégories Etiquettes Index: main/plugin-web/ribbon/cms-ribbon-tags.xml =================================================================== --- main/plugin-web/ribbon/cms-ribbon-tags.xml (revision 26702) +++ main/plugin-web/ribbon/cms-ribbon-tags.xml (working copy) @@ -20,32 +20,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -53,6 +27,7 @@ + @@ -60,6 +35,7 @@ + @@ -67,6 +43,7 @@ + Index: main/plugin-web/resources/js/org/ametys/web/tool/tag/TagsTool.i18n.js =================================================================== --- main/plugin-web/resources/js/org/ametys/web/tool/tag/TagsTool.i18n.js (revision 26702) +++ main/plugin-web/resources/js/org/ametys/web/tool/tag/TagsTool.i18n.js (working copy) @@ -57,8 +57,8 @@ // Alphabetical sort this._treeSorter = new Ext.tree.TreeSorter(this._tree, { - folderSort: true, - leafAttr: 'leafSort' +// folderSort: true, +// leafAttr: 'leafSort' }); //tree.render(); @@ -158,9 +158,11 @@ { this.outOfDate(true); } - - // The node is out of date - this._updateNode (target.getParameters().id) + else + { + // The node is out of date + this._updateNode (target.getParameters().id) + } } } } @@ -280,7 +282,7 @@ if (!this._tree.rendered) return; - treeLoader.baseParams.categoryID = node.id; + treeLoader.baseParams.tagID = node.id; } org.ametys.web.tool.tag.TagsTool.prototype._onLoad = function (treeLoader, node) Index: main/plugin-web/resources/js/org/ametys/web/widgets/TagsWidget.i18n.js =================================================================== --- main/plugin-web/resources/js/org/ametys/web/widgets/TagsWidget.i18n.js (revision 26702) +++ main/plugin-web/resources/js/org/ametys/web/widgets/TagsWidget.i18n.js (working copy) @@ -39,6 +39,10 @@ if (!config.width) config.width = 470 // default width + + // string to boolean + config.onlyTagsWithChildren = config.onlyTagsWithChildren === true || config.onlyTagsWithChildren === 'true'; + config.allowProviders = config.allowProviders === true || config.allowProviders === 'true'; org.ametys.web.widget.TagsWidget.superclass.constructor.call(this, config); @@ -88,6 +92,14 @@ */ onlyCustomTags: false, /** + * @cfg {Boolean} onlyTagsWithChildren If true, only tags with children will be checkable. + */ + onlyTagsWithChildren: false, + /** + * @cfg {Boolean} allowProviders If true, tag providers will also be checkable. + */ + allowProviders: false, + /** * @cfg {Boolean} allowCreation If true, a link at the dialog bottom proposes to add a new page (defaults to false). */ allowCreation: false, @@ -150,7 +162,7 @@ var params = {'siteName': siteName, 'tags': typeof(values) == 'string' ? values.split(",") : values}; // Necessary synchronous mode to get _rawDisplayValue - var serverMessage = new org.ametys.servercomm.ServerMessage("web", 'tags.xml', params, org.ametys.servercomm.ServerComm.PRIORITY_SYNCHRONOUS, null, this, null, "xml"); + var serverMessage = new org.ametys.servercomm.ServerMessage("web", 'tags/list.xml', params, org.ametys.servercomm.ServerComm.PRIORITY_SYNCHRONOUS, null, this, null, "xml"); var response = org.ametys.servercomm.ServerComm.getInstance().send(serverMessage); var displayValue = ''; @@ -406,7 +418,7 @@ for (var i=0; i < tags.length; i++) { var node = this._findChildRecursively (this._tree.getRootNode(), 'name', tags[i]); - if (node != null) + if (node != null && !node.disabled) { if (this.multiple) { @@ -477,9 +489,11 @@ } var loader = new org.ametys.web.tree.TagXmlLoader ({ - dataUrl: getPluginDirectUrl("web") + '/tags/list.xml', + dataUrl: getPluginDirectUrl("web") + '/tags.xml', baseParams: baseParams, checkMode: this.multiple, // to display checkboxes + allowProviders: this.allowProviders, + onlyTagsWithChildren: this.onlyTagsWithChildren, syncMode: true // synchronous mode for filters }); loader.addListener("beforeload", this._onBeforeLoad, this); @@ -751,7 +765,7 @@ if (this.allowCreation) { - if (node == null || node.attributes.type != 'category') + if (node == null) { this._creationLink.enable(); this._creationLink.update(""); @@ -812,7 +826,7 @@ } -org.ametys.web.widget.TagsWidget.prototype._createTagCb = function(tagId, categoryId, parentNodeId) +org.ametys.web.widget.TagsWidget.prototype._createTagCb = function(tagId, parentId, parentNodeId) { this._tree.getRootNode().reload(); } Index: main/plugin-web/resources/js/org/ametys/web/widgets/TagCategoriesWidget.i18n.js =================================================================== --- main/plugin-web/resources/js/org/ametys/web/widgets/TagCategoriesWidget.i18n.js (revision 26702) +++ main/plugin-web/resources/js/org/ametys/web/widgets/TagCategoriesWidget.i18n.js (working copy) @@ -1,490 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ext.namespace('org.ametys.web.widget'); - -//Register widget -org.ametys.utils.Widgets.registerWidget ('string', 'tag-categories', 'org.ametys.web.widget.TagCategoriesWidget'); -org.ametys.utils.Widgets.registerWidget ('string', 'content-tag-categories', 'org.ametys.web.widget.ContentTagCategoriesWidget'); -org.ametys.utils.Widgets.registerWidget ('string', 'page-tag-categories', 'org.ametys.web.widget.PageTagCategoriesWidget'); - -/** - * @class This class provides a widget input for selecting tag categories.<br/> - * Use the {@link org.ametys.web.TagCategoriesWidget#multiple} configuration option to allow multi-selection.<br/> - * @extends Ext.form.TextField - * Creates a tag category widget field. - * @xtype tagcategoryfield - */ -org.ametys.web.widget.TagCategoriesWidget = function(config) -{ - config.itemCls = "ametys-input"; - config.labelSeparator = ''; - // private - config.readOnly = true; - config.name = config.name; - config.msgTarget = 'side'; - - if (!config.width) - config.width = 470 // default width - - org.ametys.web.widget.TagCategoriesWidget.superclass.constructor.call(this, config); -}; - -Ext.extend(org.ametys.web.widget.TagCategoriesWidget, Ext.form.TextField, { - /** - * @cfg {String} buttonText The button text to display on the select button (defaults to - * ''). Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text - * value will be used instead if available. - */ - buttonText: '', - /** - * @cfg {String} buttonIcon The button icon for the select button. - * Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.icon - * value will be used instead if available. - */ - buttonIcon: getPluginResourcesUrl('web') + '/img/tag/category_16.png', - /** - * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible - * text field (defaults to false). If true, all inherited TextField members will still be available. - */ - buttonOnly: false, - /** - * @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field - * (defaults to 5). Note that this only applies if {@link #buttonOnly} = false. - */ - buttonOffset: 5, - /** - * @cfg {String} siteName The site name of tags - * (defaults to current site). - */ - siteName: context.parameters.siteName, - /** - * @cfg {Boolean} multiple True to allow multi-selection and display checkboxes (defaults to false). - */ - multiple: false, - /** - * @cfg {Number} width The text field width in pixel(defaults to 470) - */ - /*width: 470,*/ - - targetType: null, - xtype: 'tagcategoryfield' - -}); - -org.ametys.web.widget.TagCategoriesWidget.prototype._rawDisplayValue = ""; -org.ametys.web.widget.TagCategoriesWidget.prototype.getDisplayValue = function () -{ - return this._rawDisplayValue; -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.setValue = function (values) -{ - org.ametys.web.widget.TagCategoriesWidget.superclass.setValue.call(this, values); - - if ((Ext.isArray(values) && values.length == 0) || (!Ext.isArray(values) && values == '')) - { - this._rawDisplayValue = ""; - - if (this.rendered) - { - var text = '<span class="empty">' + "" + '</span>'; - text = org.ametys.utils.Utils.getTruncatedText (this.displayField.el, text, this.displayField.getWidth()); - this.displayField.el.update (text); - } - } - else - { - var params = {'siteName': this.siteName, 'categories': typeof(values) == 'string' ? values.split(",") : values}; - var serverMessage = new org.ametys.servercomm.ServerMessage("web", 'tag-categories.xml', params, org.ametys.servercomm.ServerComm.PRIORITY_SYNCHRONOUS, null, this, null, "xml"); - var response = org.ametys.servercomm.ServerComm.getInstance().send(serverMessage); - - var displayValue = ''; - if (response != null) - { - var nodes = response.selectNodes("TagCategories/*") - for (var i=0; i < nodes.length; i++) - { - if (i != 0) - { - displayValue += ", "; - } - displayValue += nodes[i].selectSingleNode('title')[org.ametys.servercomm.ServerComm.xmlTextContent]; - } - } - - this._rawDisplayValue = displayValue; - - if (this.rendered) - { - displayValue = org.ametys.utils.Utils.getTruncatedText (this.displayField.el, displayValue, this.displayField.getWidth()); - this.displayField.el.update(displayValue); - } - } - -} - -/** - * Set the site name of the tag categories - * @param {String} The site name or constants among OTHER_SITES, ALL_SITES - */ -org.ametys.web.widget.TagCategoriesWidget.prototype.setSite = function (siteName) -{ - this.siteName = siteName; -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.reload = function (siteName) -{ - this._tree.getRootNode().reload(); - this._tree.collapseAll(); -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.onRender = function(ct, position) -{ - org.ametys.web.widget.TagCategoriesWidget.superclass.onRender.call(this, ct, position); - - this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-tag-wrap'}); - this.el.addClass('x-form-tag-text'); - - this.displayField = new org.ametys.HtmlContainer ({ - id: this.name + '-display', - html: '<span class="empty">' + "" + '</span>', - cls: 'x-form-widget-display-field', - hidden: false, - renderTo: this.wrap, - width: (this.width - 17) - }); - - var btnCfg = Ext.applyIf(this.buttonCfg || {}, { - text: this.buttonText, - icon: this.buttonIcon - }); - - this.button = new Ext.Button(Ext.apply(btnCfg, { - renderTo: this.wrap, - disabled: this.disabled, - widget: this, - cls: 'x-form-tag-btn' + (btnCfg.iconCls ? ' x-btn-icon' : ''), - handler: this._selectTagCategories, - tooltip: "" - })); - - if(this.buttonOnly){ - this.el.hide(); - this.wrap.setWidth(this.button.getEl().getWidth()); - } - - if (this.desc) - { - this.itemCt.child('div.x-form-element div.x-form-field-wrap').insertSibling({ - id: this.id + '-img', - tag:'img', - style: 'padding-left: 20px; padding-top : 7px;', - src: getPluginResourcesUrl('core') + '/img/administrator/config/help.gif'}, 'after'); - - var tooltip = new Ext.ToolTip({ - target: this.id + '-img', - html: this.desc - }); - } - - if (this.width != null && this.width > 0) - { - this.setWidth(this.width); - } -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.markInvalid = function (msg) -{ - org.ametys.web.widget.TagCategoriesWidget.superclass.markInvalid.call(this, msg); - - if(!this.rendered || this.preventMark){ // not rendered - return; - } - - this.wrap.addClass('x-widget-invalid'); - this.displayField.el.dom.qtip = msg; - this.displayField.el.dom.qclass = 'x-form-invalid-tip'; -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.clearInvalid = function () -{ - org.ametys.web.widget.TagCategoriesWidget.superclass.clearInvalid.call(this); - - if(!this.rendered || this.preventMark){ // not rendered - return; - } - - this.wrap.removeClass('x-widget-invalid'); - this.displayField.el.dom.qtip = ''; -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.setWidth = function (width) -{ - org.ametys.web.widget.TagCategoriesWidget.superclass.setWidth.call(this, width); - // width - btn width - padding left - padding right - this.displayField.setWidth (width - 22 - 5 - 10); - - var text = this.displayField.el.dom.innerHTML; - text = org.ametys.utils.Utils.getTruncatedText (this.displayField.el, text, width - 22 - 5 - 10); - this.displayField.el.update (text); -} - - -/** - * Display window to select tags - * @private - */ -org.ametys.web.widget.TagCategoriesWidget.prototype._selectTagCategories = function () -{ - if (!this.widget.delayedInitialize()) - return; - - this.widget.box.show(); - - this.widget._tree.getRootNode().reload(this.widget._fill, this.widget); - this.widget._tree.collapseAll(); -} - -/** - * Select the tree nodes according to the input field value - * @private - */ -org.ametys.web.widget.TagCategoriesWidget.prototype._fill = function () -{ - var tags = this.getValue().split(','); - - for (var i=0; i < tags.length; i++) - { - var node = this._tree.getNodeById(tags[i]); - if (node != null) - { - if (this.multiple) - { - node.attributes.checked = true; - node.getUI().toggleCheck(true); - } - else - { - node.select(); - } - } - } - - this._tree.getRootNode().childNodes[0].select(); -} - -/** - * @private - */ -org.ametys.web.widget.TagCategoriesWidget.prototype.delayedInitialize = function () -{ - if (this._initialized) - return true; - - var filterField = new org.ametys.form.TextField ({ - id: 'filter', - - width: 200, - emptyText: "", - - enableKeyEvents:true - }); - filterField.addListener ('keyup', this._filter, this); - - var loader = new org.ametys.web.tree.TagXmlLoader ({ - dataUrl: getPluginDirectUrl("web") + '/tags/list.xml', - baseParams: {siteName: this.siteName, all: 'true'}, - checkMode: this.multiple, // to display checkboxes - selectCategory: true, - syncMode: true // synchronous mode for filters - }); - loader.addListener("beforeload", this._onBeforeLoad, this); - - this._tree = new Ext.tree.TreePanel({ - region: 'center', - - tool: this, - autoScroll:true, - animate:true, - enableDD:false, - containerScroll: true, - border: false, - - rootVisible: false, - root: new Ext.tree.AsyncTreeNode({id: 'root'}), - - loader: loader - }); - - // Filter - this._tree.filter = new Ext.tree.TreeFilter (this._tree, { - clearBlank: true, - autoClear: true - }); - this._tree.getSelectionModel().addListener ("selectionchange", this._selectNode, this); - - // Alphabetical sort - this._treeSorter = new Ext.tree.TreeSorter(this._tree, { - }); - - this.box = new org.ametys.DialogBox({ - layout: 'border', - title : "", - icon : getPluginResourcesUrl('web') + "/img/tag/category_16.png", - - width :300, - height :410, - autoScroll: true, - - items : [ this._tree], - - defaultButton: this._tree, - closeAction: 'hide', - buttons : [ - { - text : '', - widget: this, - handler : this.ok, - disabled: !this.multiple - }, { - text : '', - widget: this, - handler : this.cancel - }], - // filter - tbar: [ filterField] - }); - - - this._initialized = true; - return true; -} - -/** - * @private - */ -org.ametys.web.widget.TagCategoriesWidget.prototype._filter = function (field, event) -{ - this._tree.filter.clear(); - - var val = field.getRawValue() - var re = new RegExp('.*' + val + '.*', 'i'); - - this._tree.filter.filterBy(function (node) - {return re.test(node.text) || (!node.isLeaf() && this._filterChildNodesByRe (node, re)); - }, this); -} -/** - * @private - */ -org.ametys.web.widget.TagCategoriesWidget.prototype._filterChildNodesByRe = function (node, re) -{ - var childNodes = node.childNodes; - for (var i=0; i < childNodes.length; i++) - { - if (re.test(childNodes[i].text)) - { - return true; - } - else - { - return this._filterChildNodesByRe (childNodes[i], re); - } - } - return false; -} - -/** - * @private - */ -org.ametys.web.widget.TagCategoriesWidget.prototype._onBeforeLoad = function (treeLoader, node) -{ - if (!this._tree.rendered) - return; - - treeLoader.baseParams.target = this.targetType; - treeLoader.baseParams.parentID = node.id != 'root' ? node.id : ''; -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.ok = function () -{ - this.widget.box.hide (); - - var categories = {}; - if (this.widget.multiple) - { - var selNodes = this.widget._tree.getChecked(); - for (var i=0; i < selNodes.length; i++) - { - categories[selNodes[i].id] = selNodes[i].attributes.title; - } - } - else - { - var node = this.widget._tree.getSelectionModel().getSelectedNode(); - categories[node.id] = node.attributes.title; - } - - this.widget._updateField (categories); - -} - -org.ametys.web.widget.TagCategoriesWidget.prototype.cancel = function () -{ - this.widget.box.hide (); -} - -org.ametys.web.widget.TagCategoriesWidget.prototype._updateField = function (tags) -{ - var values = []; - for (var i in tags) - { - values.push(i); - } - - this.setValue (values); -} - -org.ametys.web.widget.TagCategoriesWidget.prototype._selectNode = function (sm, node) -{ - if (!this.multiple) - { - // No selection or tag category selected - var catSelected = node == null || node.attributes["type"] == 'category' || node.attributes["type"] == 'tagprovider'; - this.box.buttons[0].setDisabled(!catSelected); - } -} - -// -------------------------------------------------------------- -org.ametys.web.widget.ContentTagCategoriesWidget = function(config) -{ - org.ametys.web.widget.ContentTagCategoriesWidget.superclass.constructor.call(this, config); -}; - -Ext.extend(org.ametys.web.widget.ContentTagCategoriesWidget, org.ametys.web.widget.TagCategoriesWidget, { - targetType: 'CONTENT' -}); - -//-------------------------------------------------------------- -org.ametys.web.widget.PageTagCategoriesWidget = function(config) -{ - org.ametys.web.widget.PageTagCategoriesWidget.superclass.constructor.call(this, config); -}; - -Ext.extend(org.ametys.web.widget.PageTagCategoriesWidget, org.ametys.web.widget.TagCategoriesWidget, { - targetType: 'PAGE' -}); Index: main/plugin-web/resources/js/org/ametys/web/tree/TagXmlLoader.js =================================================================== --- main/plugin-web/resources/js/org/ametys/web/tree/TagXmlLoader.js (revision 26702) +++ main/plugin-web/resources/js/org/ametys/web/tree/TagXmlLoader.js (working copy) @@ -33,7 +33,7 @@ { org.ametys.web.tree.TagXmlLoader.superclass.processAttributes.call(this, attr); - if (attr.tagName == "category" || attr.tagName == "tagprovider") + if (attr.tagName == "tagprovider") { // This is a category node attr.text = attr.title; @@ -47,25 +47,25 @@ { attr.leaf = true; } - if (this.checkMode && this.selectCategory) + if (this.checkMode && this.allowProviders) { attr.checked = false; } if (this.syncMode) { - // Override these values for our folder nodes because we are loading all data at once. If we were + // Override these values for our folder nodes because we are loading all data at once. If we were // loading each node asynchronously (the default) we would not want to do this: attr.expanded = true; attr.loaded = true; } } else - { // this is it a tag node - + { + // this is it a tag node attr.text = attr.title; attr.type = "tag"; - attr.leafSort = true; // attribute for sorting + attr.leafSort = false; // attribute for sorting if (attr.target == this.filterTarget) { @@ -90,10 +90,22 @@ // Tell the tree this is a leaf node. This could also be passed as an attribute in the original XML, // but this example demonstrates that you can control this even when you cannot dictate the format of // the incoming source XML: - attr.leaf = true; - if (this.checkMode && !this.selectCategory) + attr.leaf = !attr.hasChild ? true : false; + + if (this.checkMode) { - attr.checked = false; + // empty check box. + // nb. Do not show an empty check box for disabled node, or node without children in mode "only tags with children". + var dontCheck = !attr.hasChild && this.onlyTagsWithChildren || attr.disabled; + attr.checked = dontCheck ? null : false; + } + + if (this.syncMode) + { + // Override these values for our folder nodes because we are loading all data at once. If we were + // loading each node asynchronously (the default) we would not want to do this: + attr.expanded = true; + attr.loaded = true; } } } @@ -125,12 +137,5 @@ attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider); } - if (attr.tagName == "category" || attr.tagName == "tagprovider") - { - return new Ext.tree.AsyncTreeNode(attr); - } - else - { - return new Ext.tree.TreeNode(attr); - } + return new Ext.tree.AsyncTreeNode(attr); } Index: main/plugin-web/resources/js/org/ametys/web/tag/Actions.i18n.js =================================================================== --- main/plugin-web/resources/js/org/ametys/web/tag/Actions.i18n.js (revision 26702) +++ main/plugin-web/resources/js/org/ametys/web/tag/Actions.i18n.js (working copy) @@ -16,8 +16,6 @@ Ext.namespace('org.ametys.web.tag.Edit'); Ext.namespace('org.ametys.web.tag.Delete'); -Ext.namespace('org.ametys.web.tag.EditCategory'); -Ext.namespace('org.ametys.web.tag.DeleteCategory'); Ext.namespace('org.ametys.web.tag.Tag'); /** @@ -209,7 +207,7 @@ org.ametys.web.tag.Edit.callback = function (response, args) { var tagID = null; - var categoryID = null; + var parentID = null; if (args[0] == 'new') { @@ -220,22 +218,11 @@ } var msg = response.selectSingleNode("ActionResult/message") != null ? response.selectSingleNode("ActionResult/message")[org.ametys.servercomm.ServerComm.xmlTextContent] : ''; - if (msg == "unknown-category") - { - Ext.Msg.show({ - title: "", - msg: "", - buttons: Ext.Msg.OK, - icon: Ext.MessageBox.ERROR - }); - org.ametys.web.tag.Edit.box.hideWaitMsg(); - return; - } - else if (msg == "already-exist") + if (msg == "unknown-parent-tag") { Ext.Msg.show({ title: "", - msg: "", + msg: "", buttons: Ext.Msg.OK, icon: Ext.MessageBox.ERROR }); @@ -247,10 +234,10 @@ org.ametys.web.tag.Edit.box.hide(); tagID = response.selectSingleNode("ActionResult/id")[org.ametys.servercomm.ServerComm.xmlTextContent]; - categoryID = response.selectSingleNode("ActionResult/categoryID")[org.ametys.servercomm.ServerComm.xmlTextContent]; + parentID = response.selectSingleNode("ActionResult/parentID")[org.ametys.servercomm.ServerComm.xmlTextContent]; var tagName = response.selectSingleNode('ActionResult/name')[org.ametys.servercomm.ServerComm.xmlTextContent]; - var target = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("tag", {'id': tagID, 'parentID': categoryID, 'name': tagName, 'type': 'tag'}); + var target = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("tag", {'id': tagID, 'parentID': parentID, 'name': tagName, 'type': 'tag'}); var event = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_CREATED, null, [target]); org.ametys.messagebus.MessageBus.getInstance().fireMessages([event]); } @@ -288,7 +275,7 @@ if (org.ametys.web.tag.Edit._actionCallback != null) { - org.ametys.web.tag.Edit._actionCallback(tagID, categoryID); + org.ametys.web.tag.Edit._actionCallback(tagID, parentID); } } @@ -352,7 +339,7 @@ * @private * Initialize the form */ -org.ametys.web.tag.Edit._initForm = function (categoryId) +org.ametys.web.tag.Edit._initForm = function () { if (org.ametys.web.tag.Edit._mode == 'new') { @@ -360,11 +347,11 @@ if (org.ametys.web.tag.Edit._parentID == null) { - // Get the selected category + // Get the selected tag var targets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets(); var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function(target) { return target.getType() == "tag" }); - if (target == null || target.getParameters().type == 'tag') + if (target == null) return; parentID = target.getParameters().id; @@ -499,332 +486,6 @@ /** ------------------------------------ */ /** ------------------------------------ */ -org.ametys.web.tag.EditCategory.add = function(id, config, pluginName) -{ - org.ametys.web.tag.EditCategory.pluginName = pluginName; - org.ametys.web.tag.EditCategory._mode = 'new'; - org.ametys.web.tag.EditCategory.act (); -} - -org.ametys.web.tag.EditCategory.edit = function(id, config, pluginName) -{ - org.ametys.web.tag.EditCategory.pluginName = pluginName; - org.ametys.web.tag.EditCategory._mode = 'edit'; - org.ametys.web.tag.EditCategory.act (); -} - -/** - * @private - * @property {String} _mode Can be 'new' or 'edit' - */ -org.ametys.web.tag.EditCategory._mode; - -org.ametys.web.tag.EditCategory.act = function () -{ - if (!org.ametys.web.tag.EditCategory.delayedInitialize()) - return; - - if (org.ametys.web.tag.EditCategory._mode == 'new') - { - org.ametys.web.tag.EditCategory.box.setTitle(""); - org.ametys.web.tag.EditCategory.box.setIconPath(getPluginResourcesUrl(org.ametys.web.tag.EditCategory.pluginName) + "/img/tag/category_add_16.png"); - } - else - { - org.ametys.web.tag.EditCategory.box.setTitle(""); - org.ametys.web.tag.EditCategory.box.setIconPath(getPluginResourcesUrl(org.ametys.web.tag.EditCategory.pluginName) + "/img/tag/category_edit_16.png"); - } - org.ametys.web.tag.EditCategory.box.show(); - org.ametys.web.tag.EditCategory._initForm(); -} - -/** - * @private - */ -org.ametys.web.tag.EditCategory.delayedInitialize = function() -{ - if (org.ametys.web.tag.EditCategory.initialized) - return true; - - Ext.form.Field.prototype.msgTarget = 'side'; - var formPanel = new Ext.FormPanel( { - labelWidth :80, - bodyStyle: 'padding:10px', - - defaultType :'textfield', - - autoScroll: true, - items: [ new Ext.form.Hidden ({ - name: 'id' - }), - new Ext.form.Hidden ({ - name: 'parentID' - }), - new org.ametys.form.TextField ({ - name: 'title', - fieldLabel: "", - allowBlank: false, - width: 200 - }), - new org.ametys.form.TextAreaField ({ - name: 'description', - fieldLabel: "", - width: 200, - height: 70 - }) - ] - }); - - org.ametys.web.tag.EditCategory._form = formPanel.getForm(); - - org.ametys.web.tag.EditCategory.box = new org.ametys.DialogBox({ - title :"", - icon : getPluginResourcesUrl(org.ametys.web.tag.EditCategory.pluginName) + "/img/tag/category_add_16.png", - - layout :'fit', - width :370, - height : 220, - - items : [ formPanel ], - - defaultButton: org.ametys.web.tag.EditCategory._form.findField('title'), - closeAction: 'hide', - buttons : [ { - text :"", - handler : org.ametys.web.tag.EditCategory.ok - }, { - text :"", - handler : org.ametys.web.tag.EditCategory.cancel - } ] - }); - - org.ametys.web.tag.EditCategory.initialized = true; - - return true; -} - - -org.ametys.web.tag.EditCategory.ok = function () -{ - var form = org.ametys.web.tag.EditCategory._form; - if (form.isValid()) - { - org.ametys.web.tag.EditCategory.box.showWaitMsg(); - - // Parameters - var params = form.getValues(); - params.siteName = context.parameters.siteName; - if (org.ametys.web.tag.EditCategory._mode == 'new') - { - var serverMessage = new org.ametys.servercomm.ServerMessage(org.ametys.web.tag.EditCategory.pluginName, '/tag-category/add', params, org.ametys.servercomm.ServerComm.PRIORITY_MAJOR, org.ametys.web.tag.EditCategory.callback, this, ['new']); - org.ametys.servercomm.ServerComm.getInstance().send(serverMessage); - } - else - { - var serverMessage = new org.ametys.servercomm.ServerMessage(org.ametys.web.tag.EditCategory.pluginName, '/tag-category/update', params, org.ametys.servercomm.ServerComm.PRIORITY_MAJOR, org.ametys.web.tag.EditCategory.callback, this, ['edit']); - org.ametys.servercomm.ServerComm.getInstance().send(serverMessage); - } - } -} - -org.ametys.web.tag.EditCategory.cancel = function () -{ - org.ametys.web.tag.EditCategory.box.hide(); -} - -org.ametys.web.tag.EditCategory.callback = function (response, args) -{ - if (args[0] == 'new') - { - if (org.ametys.servercomm.ServerComm.handleBadResponse("", response, "org.ametys.web.tag.EditCategory")) - { - org.ametys.web.tag.EditCategory.box.hideWaitMsg(); - return; - } - - var msg = response.selectSingleNode("ActionResult/message") != null ? response.selectSingleNode("ActionResult/message")[org.ametys.servercomm.ServerComm.xmlTextContent] : ''; - if (msg == "unknown-category") - { - Ext.Msg.show({ - title: "", - msg: "", - buttons: Ext.Msg.OK, - icon: Ext.MessageBox.ERROR - }); - org.ametys.web.tag.EditCategory.box.hideWaitMsg(); - return; - } - else if (msg == "already-exist") - { - Ext.Msg.show({ - title: "", - msg: "", - buttons: Ext.Msg.OK, - icon: Ext.MessageBox.ERROR - }); - org.ametys.web.tag.EditCategory.box.hideWaitMsg(); - return; - } - - org.ametys.web.tag.EditCategory.box.hideWaitMsg(); - org.ametys.web.tag.EditCategory.box.hide(); - - var id = response.selectSingleNode("ActionResult/id")[org.ametys.servercomm.ServerComm.xmlTextContent]; - var parentID = response.selectSingleNode("ActionResult/parentID")[org.ametys.servercomm.ServerComm.xmlTextContent]; - var target = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("tag", {'id': id, 'parentID': parentID, 'type': 'tag-category'}); - var event = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_CREATED, null, [target]); - org.ametys.messagebus.MessageBus.getInstance().fireMessages([event]); - } - else - { - if (org.ametys.servercomm.ServerComm.handleBadResponse("", response, "org.ametys.web.tag.EditCategory")) - { - org.ametys.web.tag.EditCategory.box.hideWaitMsg(); - return; - } - - var msg = response.selectSingleNode("ActionResult/message") != null ? response.selectSingleNode("ActionResult/message")[org.ametys.servercomm.ServerComm.xmlTextContent] : ''; - if (msg == "unknown-tag") - { - Ext.Msg.show({ - title: "", - msg: "", - buttons: Ext.Msg.OK, - icon: Ext.MessageBox.ERROR - }); - org.ametys.web.tag.EditCategory.box.hideWaitMsg(); - return; - } - - org.ametys.web.tag.EditCategory.box.hideWaitMsg(); - org.ametys.web.tag.EditCategory.box.hide(); - - var categoryID = response.selectSingleNode("ActionResult/id")[org.ametys.servercomm.ServerComm.xmlTextContent]; - var title = response.selectSingleNode("ActionResult/title")[org.ametys.servercomm.ServerComm.xmlTextContent]; - var target = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("tag", {'id': categoryID, 'title': title, 'type': 'category'}); - var event = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_METADATACHANGED, null, [target]); - org.ametys.messagebus.MessageBus.getInstance().fireMessages([event]); - } - -} - -/** - * @private - * Initialize the form - */ -org.ametys.web.tag.EditCategory._initForm = function () -{ - if (org.ametys.web.tag.EditCategory._mode == 'new') - { - // Get the selected category - var targets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets(); - var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function(target) { return target.getType() == "tag" }); - - if (target == null || target.getParameters().type == 'tag') - return; - - var categoryID = target.getParameters().id; - - var form = org.ametys.web.tag.EditCategory._form; - form.findField('id').setValue(''); - form.findField('title').setValue(''); - form.findField('title').setValue(""); - form.findField('title').clearInvalid(); - form.findField('description').setValue(''); - form.findField('parentID').setValue(categoryID); - - form.findField('title').focus(true); - } - else - { - var targets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets(); - var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function(target) { return target.getType() == "tag" }); - - if (target == null || target.getParameters().type != 'category') - return; - - var id = target.getParameters().id; - - var serverMessage = new org.ametys.servercomm.ServerMessage(org.ametys.web.tag.EditCategory.pluginName, '/tags/jcr-tag.xml', {'id': id}, org.ametys.servercomm.ServerComm.PRIORITY_SYNCHRONOUS, null, this, null); - var response = org.ametys.servercomm.ServerComm.getInstance().send(serverMessage); - - if (org.ametys.servercomm.ServerComm.handleBadResponse("", response, "org.ametys.web.tag.EditCategory")) - { - return; - } - - var id = response.selectSingleNode('category').getAttribute('id'); - var title = response.selectSingleNode('category/title')[org.ametys.servercomm.ServerComm.xmlTextContent]; - var description = response.selectSingleNode('category/description')[org.ametys.servercomm.ServerComm.xmlTextContent]; - - var form = org.ametys.web.tag.EditCategory._form; - form.findField('id').setValue(id); - form.findField('title').setValue(title); - form.findField('description').setValue(description); - - form.findField('title').focus(true); - } -} - -/** ------------------------------------ */ -/** ------------------------------------ */ -/** ------------------------------------ */ - -org.ametys.web.tag.DeleteCategory.act = function (id, config, pluginName) -{ - org.ametys.web.tag.DeleteCategory.pluginName = pluginName; - - Ext.Msg.confirm("", - "", - org.ametys.web.tag.DeleteCategory._doAction, - this - ); -} - -org.ametys.web.tag.DeleteCategory._doAction = function(button) -{ - if (button == 'yes') - { - var targets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets(); - var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function(target) { return target.getType() == "tag" }); - - if (target == null || target.getParameters().type != 'category') - return; - - var params = {'id': target.getParameters().id}; - params.siteName = context.parameters.siteName; - var serverMessage = new org.ametys.servercomm.ServerMessage(org.ametys.web.tag.DeleteCategory.pluginName, '/tag-category/delete', params, org.ametys.servercomm.ServerComm.PRIORITY_MAJOR, org.ametys.web.tag.DeleteCategory.callback, this, [target.getParameters().id]); - org.ametys.servercomm.ServerComm.getInstance().send(serverMessage); - } -} -org.ametys.web.tag.DeleteCategory.callback = function (response, args) -{ - if (org.ametys.servercomm.ServerComm.handleBadResponse("", response, "org.ametys.web.tag.DeleteCategory")) - { - return; - } - - var msg = response.selectSingleNode("ActionResult/message") != null ? response.selectSingleNode("ActionResult/message")[org.ametys.servercomm.ServerComm.xmlTextContent] : ''; - if (msg == "unknown-category") - { - Ext.Msg.show({ - title: "", - msg: "", - buttons: Ext.Msg.OK, - icon: Ext.MessageBox.ERROR - }); - return; - } - - var target = org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("tag", {'id': args[0], 'type': 'category'}); - var event = org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage(org.ametys.ribbon.RibbonManager.EVENTTYPE_DELETED, null, [target]); - org.ametys.messagebus.MessageBus.getInstance().fireMessages([event]); -} - -/** ------------------------------------ */ -/** ------------------------------------ */ -/** ------------------------------------ */ - /** * Affect a tag */ @@ -918,7 +579,7 @@ org.ametys.web.tag.Tag._filterField.addListener ('keyup', org.ametys.web.tag.Tag._filterTree, true); var loader = new org.ametys.web.tree.TagXmlLoader ({ - dataUrl: getPluginDirectUrl(org.ametys.web.tag.Tag.pluginName) + '/tags/list.xml', + dataUrl: getPluginDirectUrl(org.ametys.web.tag.Tag.pluginName) + '/tags.xml', baseParams: {siteName: context.parameters.siteName, all: 'true'}, // FIXME checkMode: true, // to display checkboxes syncMode: true, // synchronous mode for filters, @@ -1384,10 +1045,10 @@ var targets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets(); var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function(target) { return target.getType() == "tag" }); - if (target == null || target.getParameters().type == 'tag') + if (target == null) return; - var categoryId = target.getParameters().id; + var tagId = target.getParameters().id; org.ametys.web.tag.Tag.ImportXml._pluginName = pluginName; @@ -1397,13 +1058,13 @@ } org.ametys.web.tag.Tag.ImportXml._dialog.show(); - org.ametys.web.tag.Tag.ImportXml._initForm (categoryId); + org.ametys.web.tag.Tag.ImportXml._initForm (tagId); } -org.ametys.web.tag.Tag.ImportXml._initForm = function (categoryId) +org.ametys.web.tag.Tag.ImportXml._initForm = function (tagId) { var form = org.ametys.web.tag.Tag.ImportXml._dialog.items.itemAt(0).getForm(); - form.findField('categoryId').setValue(categoryId); + form.findField('tagId').setValue(tagId); form.findField('importFile').reset(); } @@ -1426,8 +1087,8 @@ cls: 'dialog-text-hint' }), new Ext.form.Hidden({ - id: 'categoryId', - name: 'categoryId', + id: 'tagId', + name: 'tagId', value: '' }), new org.ametys.form.FileUploadField({ @@ -1553,11 +1214,7 @@ var message = ''; var error = action.result.error; - if (error == 'unknown-category') - { - message = ""; - } - else if (error == 'invalid-extension') + if (error == 'invalid-extension') { message = ""; } Index: main/plugin-web/resources/js/org/ametys/ribbon/control/button/TagCategoryActionButton.js =================================================================== --- main/plugin-web/resources/js/org/ametys/ribbon/control/button/TagCategoryActionButton.js (revision 26702) +++ main/plugin-web/resources/js/org/ametys/ribbon/control/button/TagCategoryActionButton.js (working copy) @@ -1,65 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ext.namespace('org.ametys.ribbon.control.button'); - -/** - * Create the control instance. - * @param {String} id The unique identifier - * @param {Map} configuration The configuration of the control instance. - * @param {String} pluginName The name of the declaring plugin - * @class This class implements the behavior for an action. - * @extends org.ametys.ribbon.control.RibbonControl - */ -org.ametys.ribbon.control.button.TagCategoryActionButton = function(id, configuration, pluginName) -{ - org.ametys.ribbon.control.button.TagCategoryActionButton.superclass.constructor.call(this, id, configuration, pluginName); -} - -Ext.extend(org.ametys.ribbon.control.button.TagCategoryActionButton, org.ametys.ribbon.control.button.ActionButton, {}); - -org.ametys.ribbon.control.button.TagCategoryActionButton.prototype.createControl = function(colspan) -{ - var elmt = org.ametys.ribbon.control.button.TagCategoryActionButton.superclass.createControl.call(this, colspan); - elmt.disable(); - return elmt; -} - -/** - * Creates the toggle button - * @param {integer} colspan The configured colspan. Must be transmited to the control. - * @return {Ext.form.field} The toggle button created. - */ -org.ametys.ribbon.control.button.TagCategoryActionButton.prototype.onMessage = function(messages) -{ - for (var i=0; i < messages.length; i++) - { - if (messages[i].getType().getName() == org.ametys.ribbon.RibbonManager.EVENTTYPE_SELECTIONCHANGED) - { - var targets = messages[i].getTargets(); - var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(targets, function(target) { return target.getType() == "tag";}); - - if (target != null && target.getParameters().type == 'category') - { - this.getElements().each(function(element) { element.enable(); }) - } - else - { - this.getElements().each(function(element) { element.disable(); }) - } - } - } -} Index: main/plugin-web/resources/img/tag/category_add_50.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_edit_32.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_add_16.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_delete_50.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_delete_32.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_edit_50.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_delete_16.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_add_32.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/resources/img/tag/category_edit_16.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = image/png Index: main/plugin-web/nodetypes/web_nodetypes.xml =================================================================== --- main/plugin-web/nodetypes/web_nodetypes.xml (revision 26702) +++ main/plugin-web/nodetypes/web_nodetypes.xml (working copy) @@ -211,17 +211,26 @@ ametys:unstructured - + - ametys:tag-category + ametys:tag + + + + ametys:unstructured + + + + ametys:tag + Index: main/plugin-web/plugin.xml =================================================================== --- main/plugin-web/plugin.xml (revision 26702) +++ main/plugin-web/plugin.xml (working copy) @@ -1263,13 +1263,6 @@ ametys:tags - - tag-category - ametys:tag-category - - @@ -1279,14 +1272,14 @@ - + pageAlias ametys:pageAlias - + alias ametys:alias @@ -1374,7 +1367,7 @@ PLUGINS_WEB_RIGHTS_TAGS_ACCESS_DESCRIPTION - PLUGINS_WEB_RIGHTS_TAGS_CATEGORY + PLUGINS_WEB_RIGHTS_TAGS @@ -1383,16 +1376,7 @@ PLUGINS_WEB_RIGHTS_TAGS_HANDLE_TAG_DESCRIPTION - PLUGINS_WEB_RIGHTS_TAGS_CATEGORY - - - - - - - PLUGINS_WEB_RIGHTS_TAGS_HANDLE_TAGCATEGORY_DESCRIPTION - PLUGINS_WEB_RIGHTS_TAGS_CATEGORY + PLUGINS_WEB_RIGHTS_TAGS @@ -1401,7 +1385,7 @@ PLUGINS_WEB_RIGHTS_TAGS_IMPORT_XML_DESCRIPTION - PLUGINS_WEB_RIGHTS_TAGS_CATEGORY + PLUGINS_WEB_RIGHTS_TAGS @@ -1803,7 +1787,6 @@ js/org/ametys/cms/widgets/ExternalSoundWidget.i18n.js js/org/ametys/web/widgets/WidgetHelper.i18n.js js/org/ametys/web/widgets/TagsWidget.i18n.js - js/org/ametys/web/widgets/TagCategoriesWidget.i18n.js js/org/ametys/web/widgets/ContentTagsWidget.js js/org/ametys/web/widgets/PageTagsWidget.js js/org/ametys/web/tree/SitesXmlLoader.i18n.js @@ -2480,7 +2463,7 @@ org.ametys.web.tag.Edit.add uitool-add-tag - category|root + tag|root PLUGINS_WEB_UITOOL_TAGS_ADD_TAG_LABEL PLUGINS_WEB_UITOOL_TAGS_ADD_TAG_DESC PLUGINS_WEB_UITOOL_TAGS_ADD_TAG_FOOTER @@ -2543,7 +2526,7 @@ org.ametys.web.tag.Tag.ImportXml uitool-import-tag - category|root + tag|root PLUGINS_WEB_UITOOL_TAGS_IMPORT_XML_LABEL PLUGINS_WEB_UITOOL_TAGS_IMPORT_XML_DESC @@ -2557,69 +2540,6 @@ Web_Rights_Tags_ImportXml - - - - org.ametys.web.tag.EditCategory.add - uitool-add-tagcategory - category|root - PLUGINS_WEB_UITOOL_TAGS_ADD_TAG_CATEGORY_LABEL - PLUGINS_WEB_UITOOL_TAGS_ADD_TAG_CATEGORY_DESC - PLUGINS_WEB_UITOOL_TAGS_ADD_TAG_CATEGORY_FOOTER - img/tag/category_add_16.png - img/tag/category_add_32.png - img/tag/category_add_50.png - - - js/org/ametys/web/tag/Actions.i18n.js - js/org/ametys/ribbon/control/button/TagActionButton.js - - Web_Rights_Tags_HandleTagCategory - - - - - org.ametys.web.tag.EditCategory.edit - uitool-edit-tagcategory - category - PLUGINS_WEB_UITOOL_TAGS_EDIT_TAG_CATEGORY_LABEL - PLUGINS_WEB_UITOOL_TAGS_EDIT_TAG_CATEGORY_DESC - PLUGINS_WEB_UITOOL_TAGS_EDIT_TAG_CATEGORY_FOOTER - img/tag/category_edit_16.png - img/tag/category_edit_32.png - img/tag/category_edit_50.png - - - js/org/ametys/web/tag/Actions.i18n.js - js/org/ametys/ribbon/control/button/TagActionButton.js - - Web_Rights_Tags_HandleTagCategory - - - - - org.ametys.web.tag.DeleteCategory.act - uitool-delete-tagcategory - category - PLUGINS_WEB_UITOOL_TAGS_DELETE_TAG_CATEGORY_LABEL - PLUGINS_WEB_UITOOL_TAGS_DELETE_TAG_CATEGORY_DESC - PLUGINS_WEB_UITOOL_TAGS_DELETE_TAG_CATEGORY_FOOTER - img/tag/category_delete_16.png - img/tag/category_delete_32.png - img/tag/category_delete_50.png - - - js/org/ametys/web/tag/Actions.i18n.js - js/org/ametys/ribbon/control/button/TagActionButton.js - - Web_Rights_Tags_HandleTagCategory - @@ -4033,7 +3953,15 @@ PLUGINS_WEB_SERVICE_FRONT_SEARCH_BY_TAG_CATEGORY_DESC - content-tag-categories + content-tags + + true + true + + + + + PLUGINS_WEB_SERVICE_FRONT_SEARCH_STRICT_SEARCH_ON_TAGS_DESC @@ -4104,7 +4032,15 @@ - + + + + + + + @@ -4426,6 +4362,10 @@ PLUGINS_WEB_SERVICE_FILTERED_CONTENTS_TAGS_DESC content-tags + + + PLUGINS_WEB_SERVICE_FILTERED_CONTENTS_STRICT_SEARCH_ON_TAGS_DESC + @@ -8943,4 +8883,47 @@ logger="org.ametys.web.cache.monitoring.process.CacheMonitoringScheduler" /> + + + + + + + + PLUGINS_WEB_TAGS_SITE_CONFIG_AUTOPOSTING_ENABLED_DESC + false + plugin.repository:PLUGINS_REPOSITORY_CONFIG_CATEGORY + PLUGINS_WEB_TAGS_SITE_CONFIG_GROUP + + + + + + + + + + + + + + + + + + + + + Index: main/plugin-web/sitemap-front.xmap =================================================================== --- main/plugin-web/sitemap-front.xmap (revision 26702) +++ main/plugin-web/sitemap-front.xmap (working copy) @@ -167,6 +167,7 @@ + @@ -275,6 +276,7 @@ + Index: main/plugin-web/pages/tags/filter.xsl =================================================================== --- main/plugin-web/pages/tags/filter.xsl (revision 26702) +++ main/plugin-web/pages/tags/filter.xsl (working copy) @@ -24,47 +24,49 @@ - + - + - + - + - + - + - + - + + - + + - + Index: main/plugin-web/pages/services/search/search_3.3.xsl =================================================================== --- main/plugin-web/pages/services/search/search_3.3.xsl (revision 26702) +++ main/plugin-web/pages/services/search/search_3.3.xsl (working copy) @@ -289,10 +289,10 @@ - - + + - + , @@ -388,7 +388,7 @@ - + @@ -397,8 +397,8 @@ - - + + Index: main/plugin-web/pages/services/search/search.xsl =================================================================== --- main/plugin-web/pages/services/search/search.xsl (revision 26702) +++ main/plugin-web/pages/services/search/search.xsl (working copy) @@ -422,7 +422,7 @@ - + @@ -431,8 +431,8 @@ - - + + Index: main/plugin-web/pages/services/search/search-criteria/search-criteria_3.3.xsl =================================================================== --- main/plugin-web/pages/services/search/search-criteria/search-criteria_3.3.xsl (revision 26702) +++ main/plugin-web/pages/services/search/search-criteria/search-criteria_3.3.xsl (working copy) @@ -166,7 +166,7 @@ - + @@ -325,8 +325,8 @@ - - + +
@@ -346,7 +346,7 @@ selected - + @@ -354,8 +354,8 @@
- - + +
Index: main/plugin-web/pages/services/search/search-criteria/search-criteria.xsl =================================================================== --- main/plugin-web/pages/services/search/search-criteria/search-criteria.xsl (revision 26702) +++ main/plugin-web/pages/services/search/search-criteria/search-criteria.xsl (working copy) @@ -236,7 +236,7 @@ - +
@@ -254,7 +254,7 @@ selected - + @@ -262,8 +262,8 @@
- -
+ +
Index: main/plugin-web/src/org/ametys/web/content/ContentGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/content/ContentGenerator.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/content/ContentGenerator.java (working copy) @@ -17,12 +17,6 @@ import java.util.Set; -import org.ametys.cms.repository.Content; -import org.ametys.web.repository.content.SharedContent; -import org.ametys.web.repository.content.WebContent; -import org.ametys.web.repository.tag.TagAwareAmetysObject; -import org.ametys.web.tags.Tag; -import org.ametys.web.tags.TagProviderExtensionPoint; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.cocoon.ProcessingException; @@ -31,6 +25,13 @@ import org.apache.cocoon.xml.XMLUtils; import org.xml.sax.SAXException; +import org.ametys.cms.repository.Content; +import org.ametys.web.repository.content.SharedContent; +import org.ametys.web.repository.content.WebContent; +import org.ametys.web.repository.tag.TagAwareAmetysObject; +import org.ametys.web.tags.Tag; +import org.ametys.web.tags.TagProviderExtensionPoint; + /** * {@link Generator} for rendering raw content data. */ @@ -62,9 +63,9 @@ if (tag != null) { AttributesImpl attrs = new AttributesImpl(); - if (tag.getParentId() != null) + if (tag.getParentName() != null) { - attrs.addCDATAAttribute("parent", tag.getParentId()); + attrs.addCDATAAttribute("parent", tag.getParentName()); } XMLUtils.startElement(contentHandler, tagName, attrs); Index: main/plugin-web/src/org/ametys/web/lucene/AbstractLuceneObserver.java =================================================================== --- main/plugin-web/src/org/ametys/web/lucene/AbstractLuceneObserver.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/lucene/AbstractLuceneObserver.java (working copy) @@ -31,8 +31,8 @@ import org.apache.cocoon.environment.Context; import org.apache.cocoon.environment.Request; import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.index.Term; import org.apache.lucene.index.IndexWriter.MaxFieldLength; +import org.apache.lucene.index.Term; import org.apache.lucene.store.FSDirectory; import org.ametys.cms.lucene.FieldNames; Index: main/plugin-web/src/org/ametys/web/lucene/FieldNames.java =================================================================== --- main/plugin-web/src/org/ametys/web/lucene/FieldNames.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/lucene/FieldNames.java (working copy) @@ -34,6 +34,8 @@ public static final String TITLE_FOR_SORTING = "title-for-sorting"; /** Page and content tags field name. */ public static final String TAGS = "tags"; + /** Content tags field name for autoposting */ + public static final String TAGS_WITH_AUTOPOSTING = "tagsWithAutoposting"; /** Service ids field name. */ public static final String SERVICE_IDS = "service-ids"; /** Type field name. */ Index: main/plugin-web/src/org/ametys/web/ObservationConstants.java =================================================================== --- main/plugin-web/src/org/ametys/web/ObservationConstants.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/ObservationConstants.java (working copy) @@ -22,6 +22,8 @@ { /** Event id when a site is added. */ public static final String SITE_ADDED = "site.added"; + /** Event id when a site's configuration is updating. */ + public static final String SITE_UPDATING = "site.updating"; /** Event id when a site's configuration is updated. */ public static final String SITE_UPDATED = "site.updated"; /** Event id when a site is deleted. */ Index: main/plugin-web/src/org/ametys/web/tags/TagHelper.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/TagHelper.java (revision 0) +++ main/plugin-web/src/org/ametys/web/tags/TagHelper.java (revision 0) @@ -0,0 +1,133 @@ +/* + * Copyright 2012 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.tags; + +import java.util.HashSet; +import java.util.Set; + +/** + * Helper class which provides useful methods to operate on {@link Tag} objects. + */ +public final class TagHelper +{ + private TagHelper() + { + // Hide the default constructor. + } + + /** + * Retrieves all descendants (direct and non-direct children) of the current tag. + * @param tag the current tag + * @param includeCurrent true to include the current tag itself + * @return the set of descendant tags. + */ + public static Set getDescendants(Tag tag, boolean includeCurrent) + { + return _getDescendants(tag, includeCurrent, null); + } + + private static Set _getDescendants(Tag tag, boolean includeCurrent, Set accumulator) + { + Set tags = accumulator != null ? accumulator : new HashSet(); + + if (tag != null) + { + if (includeCurrent) + { + tags.add(tag); + } + + for (Tag child : tag.getTags().values()) + { + _getDescendants(child, true, tags); + } + } + + return tags; + } + + /** + * Retrieves all name of the descendants (direct and non-direct children) of the current tag. + * @param tag the current tag + * @param includeCurrent true to include the current tag itself + * @return the set of descendant tag names + */ + public static Set getDescendantNames(Tag tag, boolean includeCurrent) + { + Set descendants = _getDescendants(tag, includeCurrent, null); + Set descendantNames = new HashSet(); + + // Tag to tag names + for (Tag descendant : descendants) + { + descendantNames.add(descendant.getName()); + } + + return descendantNames; + } + + /** + * Retrieves all ancestors of the current tag. + * @param tag the current tag + * @param includeCurrent true to include the current tag itself + * @return the set of ancestor tags. + */ + public static Set getAncestors(Tag tag, boolean includeCurrent) + { + return _getAncestors(tag, includeCurrent, null); + } + + private static Set _getAncestors(Tag tag, boolean includeCurrent, Set accumulator) + { + Set tags = accumulator != null ? accumulator : new HashSet(); + + if (tag != null) + { + if (includeCurrent) + { + tags.add(tag); + } + + Tag parent = tag.getParent(); + if (parent != null) + { + _getAncestors(parent, true, tags); + } + } + + return tags; + } + + /** + * Retrieves all name of the ancestors of the current tag. + * @param tag the current tag + * @param includeCurrent true to include the current tag itself + * @return the set of ancestor tag names + */ + public static Set getAncestorNames(Tag tag, boolean includeCurrent) + { + Set ancestors = _getAncestors(tag, includeCurrent, null); + Set ancestorNames = new HashSet(); + + // Tag to tag names + for (Tag ancestor : ancestors) + { + ancestorNames.add(ancestor.getName()); + } + + return ancestorNames; + } +} Index: main/plugin-web/src/org/ametys/web/tags/TagProvider.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/TagProvider.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/TagProvider.java (working copy) @@ -15,6 +15,7 @@ */ package org.ametys.web.tags; +import java.util.Collection; import java.util.Map; import org.ametys.runtime.util.I18nizableText; @@ -47,24 +48,9 @@ * @param siteName The site name. Can be null for all sites * @return the provider's tags. */ - public Map getTagCategories (String siteName); - - /** - * Returns the provider's tags. - * @param siteName The site name. Can be null for all sites - * @return the provider's tags. - */ public Map getTags (String siteName); /** - * Returns the provider's category. - * @param siteName The site name. Can be null for all sites - * @param categoryID The category id - * @return the provider's category. - */ - public TagCategory getTagCategory(String siteName, String categoryID); - - /** * Returns the provider's tag. * @param siteName The site name. Can be null for all sites * @param tagName The tag name @@ -73,18 +59,18 @@ public Tag getTag(String siteName, String tagName); /** - * Determines if the tag exists. + * Returns the direct children of the provider's tag. * @param siteName The site name. Can be null for all sites - * @param tagName The tag unique name - * @return true if the tag exists. + * @param tagName The tag name + * @return the provider's tag. */ - public boolean hasTag (String siteName, String tagName); + public Collection getTags(String siteName, String tagName); /** * Determines if the tag exists. * @param siteName The site name. Can be null for all sites - * @param categoryID The tag id + * @param tagName The tag unique name * @return true if the tag exists. */ - public boolean hasCategory (String siteName, String categoryID); + public boolean hasTag (String siteName, String tagName); } Index: main/plugin-web/src/org/ametys/web/tags/actions/AddTagAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/actions/AddTagAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/actions/AddTagAction.java (working copy) @@ -86,15 +86,15 @@ result.put("id", jcrTag.getId()); result.put("name", jcrTag.getName()); - result.put("categoryID", parent.getId()); + result.put("parentID", parent.getId()); // Notify observers that the tag has been added. - _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_ADDED, jcrTag)); + _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_ADDED, jcrTag, new Object[] {jcrTag.getName()})); } catch (UnknownAmetysObjectException e) { - getLogger().error("The tag category '" + parentID + "' does not exist anymore", e); - result.put("message", "unknown-category"); + getLogger().error("The tag '" + parentID + "' does not exist anymore", e); + result.put("message", "unknown-parent-tag"); } return result; Index: main/plugin-web/src/org/ametys/web/tags/actions/UpdateTagAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/actions/UpdateTagAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/actions/UpdateTagAction.java (working copy) @@ -65,7 +65,7 @@ result.put("title", tagTitle); // Notify observers that the tag has been modified. - _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_UPDATED, jcrTag)); + _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_UPDATED, jcrTag, new Object[] {jcrTag.getName()})); } catch (UnknownAmetysObjectException e) { Index: main/plugin-web/src/org/ametys/web/tags/actions/UpdateTagCategoryAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/actions/UpdateTagCategoryAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/actions/UpdateTagCategoryAction.java (working copy) @@ -1,78 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags.actions; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.avalon.framework.parameters.Parameters; -import org.apache.avalon.framework.service.ServiceException; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.cocoon.acting.ServiceableAction; -import org.apache.cocoon.environment.ObjectModelHelper; -import org.apache.cocoon.environment.Redirector; -import org.apache.cocoon.environment.Request; -import org.apache.cocoon.environment.SourceResolver; - -import org.ametys.plugins.repository.AmetysObjectResolver; -import org.ametys.plugins.repository.UnknownAmetysObjectException; -import org.ametys.web.tags.jcr.JCRTagCategory; - -/** - * This actions updates the tag category properties - */ -public class UpdateTagCategoryAction extends ServiceableAction -{ - private AmetysObjectResolver _resolver; - - @Override - public void service(ServiceManager serviceManager) throws ServiceException - { - _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); - } - - @Override - public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception - { - Map result = new HashMap(); - - Request request = ObjectModelHelper.getRequest(objectModel); - String categoryID = request.getParameter("id"); - - String catTitle = request.getParameter("title"); - String catDescription = request.getParameter("description"); - - try - { - JCRTagCategory jcrCategory = _resolver.resolveById(categoryID); - jcrCategory.setTitle(catTitle); - jcrCategory.setDescription(catDescription); - - jcrCategory.saveChanges(); - - result.put("id", jcrCategory.getId()); - result.put("title", catTitle); - } - catch (UnknownAmetysObjectException e) - { - getLogger().error("Unable to update tag category : the category '" + categoryID + "' does not exist anymore", e); - result.put("message", "unknown-tag"); - } - - return result; - } - -} Index: main/plugin-web/src/org/ametys/web/tags/actions/AddTagCategoryAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/actions/AddTagCategoryAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/actions/AddTagCategoryAction.java (working copy) @@ -1,120 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags.actions; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.avalon.framework.parameters.Parameters; -import org.apache.avalon.framework.service.ServiceException; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.cocoon.acting.ServiceableAction; -import org.apache.cocoon.environment.ObjectModelHelper; -import org.apache.cocoon.environment.Redirector; -import org.apache.cocoon.environment.Request; -import org.apache.cocoon.environment.SourceResolver; - -import org.ametys.cms.FilterNameHelper; -import org.ametys.plugins.repository.AmetysObjectIterable; -import org.ametys.plugins.repository.AmetysObjectResolver; -import org.ametys.plugins.repository.RepositoryIntegrityViolationException; -import org.ametys.plugins.repository.UnknownAmetysObjectException; -import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; -import org.ametys.web.tags.jcr.JCRTag; -import org.ametys.web.tags.jcr.JCRTagCategory; -import org.ametys.web.tags.jcr.JCRTagProvider; -import org.ametys.web.tags.jcr.TagCategoryFactory; - -/** - * This actions add a new tags category - */ -public class AddTagCategoryAction extends ServiceableAction -{ - private AmetysObjectResolver _resolver; - - @Override - public void service(ServiceManager serviceManager) throws ServiceException - { - _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); - } - - @Override - public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception - { - Map result = new HashMap(); - - Request request = ObjectModelHelper.getRequest(objectModel); - String parentID = request.getParameter("parentID"); - String siteName = request.getParameter("siteName"); - - String title = request.getParameter("title"); - String description = request.getParameter("description"); - String name = FilterNameHelper.filterName(title); - - try - { - if (_hasCategory(siteName, name)) - { - getLogger().error("A category with name '" + name + "' already exist"); - result.put("message", "already-exist"); - - return result; - } - - DefaultTraversableAmetysObject parent = _resolver.resolveById(parentID); - - JCRTagCategory subCategory = parent.createChild(name, TagCategoryFactory.TAG_CATEGORY_NODETYPE); - subCategory.setTitle(title); - subCategory.setDescription(description); - - parent.saveChanges(); - - result.put("id", subCategory.getId()); - result.put("parentID", parent.getId()); - } - catch (UnknownAmetysObjectException e) - { - getLogger().error("Unable to add a new tags category : the tag category '" + parentID + "' does not exist anymore", e); - result.put("message", "unknown-category"); - } - catch (RepositoryIntegrityViolationException e) - { - getLogger().error("Unable to add a new tags category : a category with name '" + name + "' already exist", e); - result.put("message", "already-exist"); - } - - return result; - } - - /** - * Creates the XPath query corresponding to specified tag name - * @param siteName the site name - * @param categoryName the category name - * @return the created XPath query - */ - public static String getXPathQuery(String siteName, String categoryName) - { - return "//element(" + siteName + ", ametys:site)/ametys-internal:plugins/" + JCRTagProvider.PLUGIN_NODE_NAME + "/" + JCRTagProvider.TAGS_NODENAME + "//element(*," + TagCategoryFactory.TAG_CATEGORY_NODETYPE + ")[fn:name()='" + categoryName + "']"; - } - - private boolean _hasCategory (String siteName, String name) - { - String xpathQuery = getXPathQuery (siteName, name); - AmetysObjectIterable tagsIterator = _resolver.query(xpathQuery); - return tagsIterator.hasNext(); - } - -} Index: main/plugin-web/src/org/ametys/web/tags/actions/DeleteTagAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/actions/DeleteTagAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/actions/DeleteTagAction.java (working copy) @@ -15,10 +15,13 @@ */ package org.ametys.web.tags.actions; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.apache.avalon.framework.parameters.Parameters; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Request; @@ -26,9 +29,14 @@ import org.ametys.cms.observation.AbstractNotifierAction; import org.ametys.cms.observation.Event; +import org.ametys.plugins.repository.AmetysObject; import org.ametys.plugins.repository.UnknownAmetysObjectException; import org.ametys.plugins.repository.jcr.SimpleAmetysObject; import org.ametys.web.ObservationConstants; +import org.ametys.web.repository.site.Site; +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; /** @@ -36,6 +44,16 @@ */ public class DeleteTagAction extends AbstractNotifierAction { + /** Tag provider EP */ + protected TagProviderExtensionPoint _tagProviderEP; + + @Override + public void service(ServiceManager serviceManager) throws ServiceException + { + super.service(serviceManager); + _tagProviderEP = (TagProviderExtensionPoint) serviceManager.lookup(TagProviderExtensionPoint.ROLE); + } + @Override public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception { @@ -52,14 +70,15 @@ result.put("id", jcrTag.getId()); result.put("name", jcrTag.getName()); result.put("title", jcrTag.getTitle()); - result.put("categoryID", parent.getId()); - jcrTag.remove(); + // descendant names for the event arguments + Collection descendantNames = getDescendantNames(jcrTag); + jcrTag.remove(); parent.saveChanges(); // Notify observers that the tag has been deleted. - _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_DELETED, parent, new Object[] {tagID})); + _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_DELETED, parent, new Object[] {jcrTag.getName(), tagID, descendantNames})); } catch (UnknownAmetysObjectException e) { @@ -70,4 +89,40 @@ return result; } + /** + * Retrieves the descendant tag names (including the current tag name) + * @param jcrTag The JCR tag + * @return collection of tag names + */ + protected Collection getDescendantNames(JCRTag jcrTag) + { + Site site = _getSite(jcrTag); + Tag tag = _tagProviderEP.getTag(site != null ? site.getName() : null, jcrTag.getName()); + return TagHelper.getDescendantNames(tag, true); + } + + /** + * Get the site of a jcr tag. + * @param ametysObject An ametys object which is inside an ametys site node. + * @return The site + */ + protected Site _getSite(AmetysObject ametysObject) + { + Site site = null; + AmetysObject curr = ametysObject; + + while (curr != null && site == null) + { + if (curr instanceof Site) + { + site = (Site) curr; + } + else + { + curr = curr.getParent(); + } + } + + return site; + } } Index: main/plugin-web/src/org/ametys/web/tags/actions/DeleteTagCategoryAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/actions/DeleteTagCategoryAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/actions/DeleteTagCategoryAction.java (working copy) @@ -1,73 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags.actions; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.avalon.framework.parameters.Parameters; -import org.apache.avalon.framework.service.ServiceException; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.cocoon.acting.ServiceableAction; -import org.apache.cocoon.environment.ObjectModelHelper; -import org.apache.cocoon.environment.Redirector; -import org.apache.cocoon.environment.Request; -import org.apache.cocoon.environment.SourceResolver; - -import org.ametys.plugins.repository.AmetysObjectResolver; -import org.ametys.plugins.repository.UnknownAmetysObjectException; -import org.ametys.plugins.repository.jcr.SimpleAmetysObject; -import org.ametys.web.tags.jcr.JCRTagCategory; - -/** - * This actions removes an existing tag - */ -public class DeleteTagCategoryAction extends ServiceableAction -{ - private AmetysObjectResolver _resolver; - - @Override - public void service(ServiceManager serviceManager) throws ServiceException - { - _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); - } - - @Override - public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception - { - Map result = new HashMap(); - - Request request = ObjectModelHelper.getRequest(objectModel); - String categoryID = request.getParameter("id"); - - try - { - JCRTagCategory jcrCategory = _resolver.resolveById(categoryID); - SimpleAmetysObject parent = jcrCategory.getParent(); - jcrCategory.remove(); - - parent.saveChanges(); - } - catch (UnknownAmetysObjectException e) - { - getLogger().error("Unable to delete tag category : the category '" + categoryID + "' does not exist anymore", e); - result.put("message", "unknown-category"); - } - - return result; - } - -} Index: main/plugin-web/src/org/ametys/web/tags/actions/ImportTagsAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/actions/ImportTagsAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/actions/ImportTagsAction.java (working copy) @@ -52,11 +52,9 @@ import org.ametys.web.tags.Tag; import org.ametys.web.tags.Tag.TagTarget; import org.ametys.web.tags.Tag.TagVisibility; -import org.ametys.web.tags.TagCategory; import org.ametys.web.tags.TagProvider; import org.ametys.web.tags.TagProviderExtensionPoint; import org.ametys.web.tags.jcr.JCRTag; -import org.ametys.web.tags.jcr.JCRTagCategory; import org.ametys.web.tags.jcr.JCRTagProvider; /** @@ -93,7 +91,7 @@ Request request = ObjectModelHelper.getRequest(objectModel); String siteName = parameters.getParameter("siteName", request.getParameter("siteName")); - String categoryId = request.getParameter("categoryId"); + String parentId = request.getParameter("tagId"); Part part = (Part) request.get("importFile"); if (part instanceof RejectedPart) @@ -116,16 +114,14 @@ } Configuration configuration = initializeTags(uploadedFile.getPath()); - Map tagCategories = configureTagCategories(configuration, categoryId, "plugin.web"); - Map tags = configureTags(configuration, categoryId, "plugin.web"); + Map tags = configureTags(configuration, null, "plugin.web"); _createdTagsCount = 0; _updatedTagsCount = 0; _errorCount = 0; - DefaultTraversableAmetysObject parent = _resolver.resolveById(categoryId); + DefaultTraversableAmetysObject parent = _resolver.resolveById(parentId); createOrUpdateTags(parent, tags, siteName); - createOrUpdateTagCategories(parent, tagCategories, siteName); JCRTagProvider provider = (JCRTagProvider) _tagProviderExtPt.getExtension(JCRTagProvider.class.getName()); TraversableAmetysObject rootNode = provider.getRootNode(siteName); @@ -141,7 +137,7 @@ /** * Save or update a tag - * @param parent the JCR parent tag category + * @param parent the JCR parent tag or provider * @param tags the list of tags to add or update * @param siteName the site name */ @@ -172,18 +168,21 @@ jcrTag.setTarget(tag.getTarget()); jcrTag.setVisibility(tag.getVisibility()); + // recursive call to save/update + createOrUpdateTags(jcrTag, tag.getTags(), siteName); + jcrTag.saveChanges(); if (update) { // Notify observers that the tag has been modified. - _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_UPDATED, jcrTag)); + _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_UPDATED, jcrTag, new Object[] {jcrTag.getName()})); _updatedTagsCount++; } else { // Notify observers that the tag has been added. - _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_ADDED, jcrTag)); + _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.TAG_ADDED, jcrTag, new Object[] {jcrTag.getName()})); _createdTagsCount++; } } @@ -196,46 +195,6 @@ } /** - * Save or update tag categories - * @param parent the JCR parent tag categoryï - * @param tagCategories the list of categories to add or update - * @param siteName the site name - */ - protected void createOrUpdateTagCategories(DefaultTraversableAmetysObject parent, Map tagCategories, String siteName) - { - for (TagCategory tagCategory : tagCategories.values()) - { - JCRTagCategory jcrTagCategory = null; - - try - { - if (parent.hasChild(tagCategory.getId())) - { - // Update existing category - jcrTagCategory = parent.getChild(tagCategory.getId()); - } - else - { - // Create new category - jcrTagCategory = parent.createChild(tagCategory.getId(), "ametys:tag-category"); - } - - jcrTagCategory.setTitle(tagCategory.getTitle().getLabel()); - jcrTagCategory.setDescription(tagCategory.getDescription().getLabel()); - - createOrUpdateTagCategories (jcrTagCategory, tagCategory.getCategories(), siteName); - createOrUpdateTags(jcrTagCategory, tagCategory.getTags(), siteName); - - jcrTagCategory.saveChanges(); - } - catch (Exception e) - { - getLogger().error("Unable to add tag category " + tagCategory.getId() + " to JCR tag category of id '" + parent.getId() + "'", e); - } - } - } - - /** * Initialize a configuration tags from the tags file. * @param path the path of the file to initialize tags. * @return The configuration @@ -262,46 +221,14 @@ } /** - * Configure tag category from the passed configuration - * @param configuration The configuration - * @param parentId The parent id - * @param defaultCatalogue The default catalogue for i18n - * @return a Set of {@link TagCategory} - * @throws ConfigurationException - */ - protected Map configureTagCategories (Configuration configuration, String parentId, String defaultCatalogue) throws ConfigurationException - { - Map categories = new HashMap(); - Configuration[] categoriesConfiguration = configuration.getChildren("category"); - for (Configuration categoryConfiguration : categoriesConfiguration) - { - String id = categoryConfiguration.getAttribute("id"); - - I18nizableText label = configureLabel (categoryConfiguration, defaultCatalogue); - I18nizableText description = configureDescription (categoryConfiguration, defaultCatalogue); - TagCategory tagCategory = new TagCategory(id, parentId, label, description); - - Map tags = configureTags(categoryConfiguration, id, defaultCatalogue); - tagCategory.setTags(tags); - - Map subCategories = configureTagCategories(categoryConfiguration, id, defaultCatalogue); - tagCategory.setCategories(subCategories); - - categories.put(id, tagCategory); - } - - return categories; - } - - /** * Configure tag from the passed configuration * @param configuration The configuration - * @param parentId The parent id + * @param parent The parent tag if any * @param defaultCatalogue The default catalogue for i18n * @return a Set of {@link Tag} * @throws ConfigurationException */ - protected Map configureTags (Configuration configuration, String parentId, String defaultCatalogue) throws ConfigurationException + protected Map configureTags (Configuration configuration, Tag parent, String defaultCatalogue) throws ConfigurationException { Map tags = new HashMap(); @@ -327,8 +254,12 @@ } I18nizableText label = configureLabel (tagConfiguration, defaultCatalogue); I18nizableText description = configureDescription (tagConfiguration, defaultCatalogue); - Tag tag = new Tag(id, id, parentId, label, description, tagTarget, visibility); + Tag tag = new Tag(id, id, parent, label, description, tagTarget, visibility); tags.put(id, tag); + + // Recursive configuration + Map childTags = configureTags(tagConfiguration, tag, defaultCatalogue); + tag.setTags(childTags); } return tags; @@ -417,3 +348,4 @@ return providers; } } + Index: main/plugin-web/src/org/ametys/web/tags/jcr/JCRTag.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/jcr/JCRTag.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/jcr/JCRTag.java (working copy) @@ -22,7 +22,7 @@ import org.ametys.plugins.repository.AmetysObject; import org.ametys.plugins.repository.AmetysRepositoryException; import org.ametys.plugins.repository.RepositoryConstants; -import org.ametys.plugins.repository.jcr.SimpleAmetysObject; +import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; import org.ametys.web.tags.Tag; import org.ametys.web.tags.Tag.TagTarget; import org.ametys.web.tags.Tag.TagVisibility; @@ -30,7 +30,7 @@ /** * {@link AmetysObject} for storing tag informations. */ -public class JCRTag extends SimpleAmetysObject +public class JCRTag extends DefaultTraversableAmetysObject { /** Constants for title metadata. */ private static final String __METADATA_TITLE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":title"; Index: main/plugin-web/src/org/ametys/web/tags/jcr/JCRTagCategory.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/jcr/JCRTagCategory.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/jcr/JCRTagCategory.java (working copy) @@ -1,123 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags.jcr; - -import javax.jcr.Node; -import javax.jcr.PathNotFoundException; -import javax.jcr.RepositoryException; - -import org.ametys.plugins.repository.AmetysObject; -import org.ametys.plugins.repository.AmetysRepositoryException; -import org.ametys.plugins.repository.RepositoryConstants; -import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; - -/** - * {@link AmetysObject} for storing tag category informations. - */ -public class JCRTagCategory extends DefaultTraversableAmetysObject -{ - /** Constants for title metadata. */ - private static final String __METADATA_TITLE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":title"; - /** Constants for description metadata. */ - private static final String __METADATA_DESC = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":description"; - - /** - * Creates a {@link JCRTagCategory}. - * @param node the node backing this {@link AmetysObject}. - * @param parentPath the parent path in the Ametys hierarchy. - * @param factory the {@link TagCategoryFactory} which creates the AmetysObject. - */ - public JCRTagCategory (Node node, String parentPath, TagCategoryFactory factory) - { - super(node, parentPath, factory); - } - - /** - * Retrieves the title. - * @return the title. - * @throws AmetysRepositoryException if an error occurs. - */ - public String getTitle() throws AmetysRepositoryException - { - try - { - return getNode().getProperty(__METADATA_TITLE).getString(); - } - catch (PathNotFoundException e) - { - return null; - } - catch (RepositoryException e) - { - throw new AmetysRepositoryException("Unable to get title property", e); - } - } - - /** - * Set the title. - * @param title the title. - * @throws AmetysRepositoryException if an error occurs. - */ - public void setTitle(String title) throws AmetysRepositoryException - { - try - { - getNode().setProperty(__METADATA_TITLE, title); - } - catch (RepositoryException e) - { - throw new AmetysRepositoryException("Unable to set title property", e); - } - } - - /** - * Retrieves the description. - * @return the description. - * @throws AmetysRepositoryException if an error occurs. - */ - public String getDescription() throws AmetysRepositoryException - { - try - { - return getNode().getProperty(__METADATA_DESC).getString(); - } - catch (PathNotFoundException e) - { - return null; - } - catch (RepositoryException e) - { - throw new AmetysRepositoryException("Unable to get description property", e); - } - } - - /** - * Set the description. - * @param description the description. - * @throws AmetysRepositoryException if an error occurs. - */ - public void setDescription(String description) throws AmetysRepositoryException - { - try - { - getNode().setProperty(__METADATA_DESC, description); - } - catch (RepositoryException e) - { - throw new AmetysRepositoryException("Unable to set description property", e); - } - } -} Index: main/plugin-web/src/org/ametys/web/tags/jcr/JCRTagProvider.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/jcr/JCRTagProvider.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/jcr/JCRTagProvider.java (working copy) @@ -30,19 +30,13 @@ import org.ametys.plugins.repository.AmetysObject; import org.ametys.plugins.repository.AmetysObjectIterable; -import org.ametys.plugins.repository.AmetysObjectResolver; -import org.ametys.plugins.repository.AmetysRepositoryException; import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; import org.ametys.plugins.repository.RepositoryConstants; import org.ametys.plugins.repository.TraversableAmetysObject; -import org.ametys.plugins.repository.UnknownAmetysObjectException; -import org.ametys.plugins.repository.jcr.SimpleAmetysObject; import org.ametys.runtime.util.I18nizableText; -import org.ametys.web.repository.site.Site; import org.ametys.web.repository.site.SiteManager; import org.ametys.web.tags.StaticTagProvider; import org.ametys.web.tags.Tag; -import org.ametys.web.tags.TagCategory; /** * Class representing a jcr tag provider.
@@ -58,14 +52,12 @@ private static final String CACHE_REQUEST_ATTRIBUTE = JCRTagProvider.class.getName() + "$cache"; - private AmetysObjectResolver _resolver; private SiteManager _siteManager; @Override public void service(ServiceManager serviceManager) throws ServiceException { super.service(serviceManager); - _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE); } @@ -103,8 +95,8 @@ { siteCache = new HashMap(); - TraversableAmetysObject rootNode = getRootNode(siteName); - _fillCache(rootNode, rootNode, siteCache); + TraversableAmetysObject rootNode = getRootNode(siteName); + _fillCache(rootNode, null, siteCache); cache.put(siteName, siteCache); } @@ -112,19 +104,22 @@ return siteCache; } - private void _fillCache(TraversableAmetysObject rootNode, TraversableAmetysObject parentNode, Map siteCache) throws RepositoryException + private void _fillCache(TraversableAmetysObject parentTagNode, Tag parentTag, Map siteCache) throws RepositoryException { - for (AmetysObject child : parentNode.getChildren()) + for (AmetysObject child : parentTagNode.getChildren()) { if (child instanceof JCRTag) { JCRTag jcrTag = (JCRTag) child; - Tag tag = new Tag(jcrTag.getId(), jcrTag.getName(), rootNode.getId(), new I18nizableText(jcrTag.getTitle()), new I18nizableText(jcrTag.getDescription()), jcrTag.getTarget(), jcrTag.getVisibility()); + Tag tag = new Tag(jcrTag.getId(), jcrTag.getName(), parentTag, new I18nizableText(jcrTag.getTitle()), new I18nizableText(jcrTag.getDescription()), jcrTag.getTarget(), jcrTag.getVisibility()); siteCache.put(child.getName(), tag); - } - else if (child instanceof JCRTagCategory) - { - _fillCache(rootNode, (JCRTagCategory) child, siteCache); + + if (parentTag != null) + { + parentTag.addTag(tag); + } + + _fillCache(jcrTag, tag, siteCache); } } } @@ -162,42 +157,6 @@ } @Override - public boolean hasCategory(String siteName, String categoryID) - { - if (StringUtils.isEmpty(siteName)) - { - return false; - } - - try - { - SimpleAmetysObject object = _resolver.resolveById(categoryID); - if (object instanceof JCRTagCategory) - { - AmetysObject parent = object.getParent(); - while (parent != null) - { - if (parent instanceof Site) - { - return siteName.equals(((Site) parent).getName()); - } - parent = parent.getParent(); - } - - return false; - } - else - { - return false; - } - } - catch (AmetysRepositoryException e) - { - return false; - } - } - - @Override public boolean hasTag(String siteName, String tagName) { if (StringUtils.isEmpty(siteName)) @@ -252,94 +211,6 @@ } } - @Override - public TagCategory getTagCategory(String siteName, String categoryID) - { - try - { - JCRTagCategory category = _resolver.resolveById(categoryID); - AmetysObject parent = category.getParent(); - while (parent != null) - { - if (parent instanceof Site) - { - if (siteName.equals(((Site) parent).getName())) - { - return _getCategory (category, category.getParent().getId()); - } - return null; - } - parent = parent.getParent(); - } - return null; - } - catch (UnknownAmetysObjectException e) - { - return null; - } - } - - - - @Override - public Map getTagCategories(String siteName) - { - if (StringUtils.isEmpty(siteName)) - { - return null; - } - return _searchTagCategories (siteName); - } - - private Map _searchTagCategories (String siteName) - { - Map categories = new HashMap(); - - try - { - TraversableAmetysObject rootNode = getRootNode(siteName); - AmetysObjectIterable it = rootNode.getChildren(); - - for (AmetysObject object : it) - { - if (object instanceof JCRTagCategory) - { - TagCategory category = _getCategory((JCRTagCategory) object, rootNode.getId()); - categories.put(category.getId(), category); - } - } - } - catch (RepositoryException e) - { - getLogger().error("Unable to get the tag categories for site '" + siteName + "'.", e); - } - - return categories; - } - - private TagCategory _getCategory(JCRTagCategory jcrCategory, String parentId) - { - TagCategory tagCategory = new TagCategory(jcrCategory.getId(), parentId, new I18nizableText(jcrCategory.getTitle()), new I18nizableText(jcrCategory.getDescription())); - - AmetysObjectIterable objects = jcrCategory.getChildren(); - for (AmetysObject object : objects) - { - if (object instanceof JCRTag) - { - JCRTag jcrTag = (JCRTag) object; - Tag tag = new Tag(jcrTag.getId(), jcrTag.getName(), parentId, new I18nizableText(jcrTag.getTitle()), new I18nizableText(jcrTag.getDescription()), jcrTag.getTarget(), jcrTag.getVisibility()); - tagCategory.addTag(tag); - } - else if (object instanceof JCRTagCategory) - { - JCRTagCategory jcrSubCat = (JCRTagCategory) object; - tagCategory.addCategory(_getCategory(jcrSubCat, jcrCategory.getId())); - } - } - - return tagCategory; - } - /** * Get the root node for tags * @param siteName The site name Index: main/plugin-web/src/org/ametys/web/tags/jcr/TagCategoryFactory.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/jcr/TagCategoryFactory.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/jcr/TagCategoryFactory.java (working copy) @@ -1,38 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags.jcr; - -import javax.jcr.Node; - -import org.ametys.plugins.repository.AmetysObjectFactory; -import org.ametys.plugins.repository.AmetysRepositoryException; -import org.ametys.plugins.repository.RepositoryConstants; -import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObjectFactory; - -/** - * {@link AmetysObjectFactory} for creating traversable {@link JCRTagCategory}. - */ -public class TagCategoryFactory extends DefaultTraversableAmetysObjectFactory -{ - /** JCR nodetype for resources collection */ - public static final String TAG_CATEGORY_NODETYPE = RepositoryConstants.NAMESPACE_PREFIX + ":tag-category"; - - @Override - public JCRTagCategory getAmetysObject(Node node, String parentPath) throws AmetysRepositoryException - { - return new JCRTagCategory(node, parentPath, this); - } -} Index: main/plugin-web/src/org/ametys/web/tags/jcr/TagFactory.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/jcr/TagFactory.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/jcr/TagFactory.java (working copy) @@ -20,12 +20,12 @@ import org.ametys.plugins.repository.AmetysObjectFactory; import org.ametys.plugins.repository.AmetysRepositoryException; import org.ametys.plugins.repository.RepositoryConstants; -import org.ametys.plugins.repository.jcr.SimpleAmetysObjectFactory; +import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObjectFactory; /** * {@link AmetysObjectFactory} for creating {@link JCRTag}. */ -public class TagFactory extends SimpleAmetysObjectFactory +public class TagFactory extends DefaultTraversableAmetysObjectFactory { /** JCR nodetype for resources collection */ public static final String TAG_NODETYPE = RepositoryConstants.NAMESPACE_PREFIX + ":tag"; Index: main/plugin-web/src/org/ametys/web/tags/SkinTagProvider.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/SkinTagProvider.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/SkinTagProvider.java (working copy) @@ -55,8 +55,6 @@ protected Map> _skinLocalIds; /** The tags */ protected Map> _skinTags; - /** The categories */ - protected Map> _skinTagCategories; private SiteManager _siteManager; private SkinsManager _skinsManager; @@ -106,6 +104,14 @@ } Site site = _siteManager.getSite(siteName); + + if (site == null) + { + String errorMessage = "Unable to load tags configuration values for site " + siteName; + getLogger().error(errorMessage); + return null; + } + String skin = site.getSkinId(); if (!_skinTags.containsKey(skin)) @@ -176,114 +182,16 @@ return src; } - - @Override - public Map getTagCategories(String siteName) - { - if (StringUtils.isEmpty(siteName)) - { - return null; - } - - if (_skinTagCategories == null) - { - _skinTagCategories = new HashMap>(); - } - - Site site = _siteManager.getSite(siteName); - String skin = site.getSkinId(); - - if (_skinTagCategories.containsKey(skin)) - { - return _skinTagCategories.get(skin); - } - - Source src = null; - InputStream is = null; - try - { - SAXParserFactory factory = SAXParserFactory.newInstance(); - - XMLReader reader = factory.newSAXParser().getXMLReader(); - - DefaultConfigurationBuilder confBuilder = new DefaultConfigurationBuilder(reader); - - src = _getTagsFile(skin); - is = src.getInputStream(); - Configuration configuration = confBuilder.build(is); - - if (!_skinLocalIds.containsKey(skin)) - { - _skinLocalIds.put(skin, new ArrayList()); - } - - Map categories = configureTagCategories(configuration, skin, null, "skin." + skin); - _skinTagCategories.put(skin, categories); - - return categories; - } - catch (Exception e) - { - String errorMessage = "Unable to load tags configuration values for skin " + skin; - getLogger().error(errorMessage, e); - } - finally - { - IOUtils.closeQuietly(is); - _resolver.release(src); - } - - return null; - } - - /** - * Configure the tags categories from the passed configuration - * @param configuration The configuration - * @param skinName the skin name - * @param parentId The parent id - * @param defaultCatalogue The default catalog - * @return A Set of {@link TagCategory} - * @throws ConfigurationException - */ - protected Map configureTagCategories (Configuration configuration, String skinName, String parentId, String defaultCatalogue) throws ConfigurationException - { - Map categories = new HashMap(); - Configuration[] categoriesConfiguration = configuration.getChildren("category"); - for (Configuration categoryConfiguration : categoriesConfiguration) - { - String id = categoryConfiguration.getAttribute("id"); - if (_skinLocalIds.get(skinName).contains(id)) - { - throw new ConfigurationException("A category or tag with the id '" + id + "' already exists"); - } - _skinLocalIds.get(skinName).add(id); - - I18nizableText label = configureLabel (categoryConfiguration, defaultCatalogue); - I18nizableText description = configureDescription (categoryConfiguration, defaultCatalogue); - TagCategory tagCategory = new TagCategory(id, parentId, label, description); - - Map tags = configureTags(categoryConfiguration, skinName, id, defaultCatalogue); - tagCategory.setTags(tags); - - Map subCategories = configureTagCategories(categoryConfiguration, skinName, id, defaultCatalogue); - tagCategory.setCategories(subCategories); - - categories.put(id, tagCategory); - } - - return categories; - } - /** * Configure tag from the passed configuration * @param configuration The configuration * @param skinName the skin name - * @param parentId The parent id + * @param parent The parent tag if any * @param defaultCatalogue The default catalog for i18n * @return a Set of {@link Tag} * @throws ConfigurationException */ - protected Map configureTags (Configuration configuration, String skinName, String parentId, String defaultCatalogue) throws ConfigurationException + protected Map configureTags (Configuration configuration, String skinName, Tag parent, String defaultCatalogue) throws ConfigurationException { Map tags = new HashMap(); @@ -297,7 +205,7 @@ } if (_skinLocalIds.get(skinName).contains(id)) { - throw new ConfigurationException("A category or tag with the id '" + id + "' already exists"); + throw new ConfigurationException("A tag with the id '" + id + "' already exists"); } _skinLocalIds.get(skinName).add(id); @@ -314,8 +222,12 @@ } I18nizableText label = configureLabel (tagConfiguration, defaultCatalogue); I18nizableText description = configureDescription (tagConfiguration, defaultCatalogue); - Tag tag = new Tag(id, id, parentId, label, description, tagTarget, visibility); + Tag tag = new Tag(id, id, parent, label, description, tagTarget, visibility); tags.put(id, tag); + + // Recursive configuration + Map childTags = configureTags(tagConfiguration, skinName, tag, defaultCatalogue); + tag.setTags(childTags); } return tags; Index: main/plugin-web/src/org/ametys/web/tags/TagCategory.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/TagCategory.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/TagCategory.java (working copy) @@ -1,219 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags; - -import java.util.HashMap; -import java.util.Map; - -import org.ametys.runtime.util.I18nizableText; - -/** - * This class represents a tag category - */ -public class TagCategory -{ - private String _id; - private I18nizableText _title; - private I18nizableText _description; - private Map _tags; - private Map _categories; - private String _parentId; - - /** - * Constructor - * @param id The id of the category. The id must be unique. - */ - public TagCategory (String id) - { - _id = id; - } - - /** - * Constructor - * @param id The id of the category. The id must be unique. - * @param parentId The parent id - * @param title the category label - * @param description the category description - */ - public TagCategory(String id, String parentId, I18nizableText title, I18nizableText description) - { - _id = id; - _parentId = parentId; - _title = title; - _description = description; - } - - /** - * Get the tag unique id. - * @return The unique id - */ - public String getId () - { - return _id; - } - - /** - * Get the parent id. - * @return The parent id. Can be null - */ - public String getParentId () - { - return _parentId; - } - - /** - * Retrieves the title. - * - * @return the category title. - */ - public I18nizableText getTitle() - { - return _title; - } - - /** - * Set the category title. - * - * @param title the label to set. - */ - public void setTitle(I18nizableText title) - { - _title = title; - } - - /** - * Retrieves the description. - * - * @return the description. - */ - public I18nizableText getDescription() - { - return _description; - } - - /** - * Set the category description. - * - * @param description the description to set. - */ - public void setDescription(I18nizableText description) - { - _description = description; - } - - /** - * Add a sub category to the category - * @param category The category to add - */ - public void addCategory (TagCategory category) - { - if (_categories == null) - { - _categories = new HashMap(); - } - _categories.put(category.getId(), category); - } - - /** - * Set the sub categories - * @param categories a Map of categories to set - */ - public void setCategories (Map categories) - { - _categories = categories; - } - - /** - * Retrieves the sub categories - * @return The sub categories in a Set - */ - public Map getCategories () - { - return _categories; - } - - /** - * Try to get the category by its id - * @param categoryId The id of the category - * @return The category or null if no exists - */ - public TagCategory getCategory (String categoryId) - { - return _categories.get(categoryId); - } - - /** - * Determines if a category exists - * @param categoryId The category id - * @return true if the category exists - */ - public boolean hasCategory (String categoryId) - { - return _categories.containsKey(categoryId); - } - - /** - * Add a new tag to the category - * @param tag The tag to add - */ - public void addTag (Tag tag) - { - if (_tags == null) - { - _tags = new HashMap(); - } - _tags.put(tag.getId(), tag); - } - - /** - * Set the tags - * @param tags The Map of Tag to set - */ - public void setTags (Map tags) - { - _tags = tags; - } - - /** - * Retrieves the Set of tags - * @return The category tags in a Map - */ - public Map getTags () - { - return _tags; - } - - /** - * Try to get the tag by its id - * @param tagId The id of the tag - * @return The tag or null if no exists - */ - public Tag getTag (String tagId) - { - return _tags.get(tagId); - } - - /** - * Determines if a tag exists - * @param tagId The tag id - * @return true if the tag exists - */ - public boolean hasTag (String tagId) - { - return _tags.containsKey(tagId); - } - -} Index: main/plugin-web/src/org/ametys/web/tags/TagProviderExtensionPoint.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/TagProviderExtensionPoint.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/TagProviderExtensionPoint.java (working copy) @@ -28,28 +28,6 @@ public static final String ROLE = TagProviderExtensionPoint.class.getName(); /** - * Get the category - * @param siteName - * @param categoryId - * @return the category or null if not found - */ - public TagCategory getCategory(String siteName, String categoryId) - { - Set extensionsIds = getExtensionsIds(); - - for (String id : extensionsIds) - { - TagProvider tagProvider = getExtension(id); - if (tagProvider.hasCategory(siteName, categoryId)) - { - return tagProvider.getTagCategory(siteName, categoryId); - } - } - - return null; - } - - /** * Get the tag * @param siteName * @param name Index: main/plugin-web/src/org/ametys/web/tags/observers/TagAutopostingSiteParameterObserverPart2.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/observers/TagAutopostingSiteParameterObserverPart2.java (revision 0) +++ main/plugin-web/src/org/ametys/web/tags/observers/TagAutopostingSiteParameterObserverPart2.java (revision 0) @@ -0,0 +1,149 @@ +/* + * Copyright 2014 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.tags.observers; + +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.ContextException; +import org.apache.avalon.framework.context.Contextualizable; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.Serviceable; +import org.apache.cocoon.components.ContextHelper; +import org.apache.cocoon.environment.Request; + +import org.ametys.cms.observation.Event; +import org.ametys.cms.observation.Observer; +import org.ametys.web.ObservationConstants; +import org.ametys.web.cache.CacheHelper; +import org.ametys.web.cache.pageelement.PageElementCache; +import org.ametys.web.lucene.SitemapIndexer; +import org.ametys.web.repository.site.Site; +import org.ametys.web.repository.sitemap.Sitemap; +import org.ametys.web.site.SiteConfigurationExtensionPoint; + +/** + * Re-index site when tag autoposting parameter have changed. + */ +public class TagAutopostingSiteParameterObserverPart2 extends AbstractLogEnabled implements Observer, Contextualizable, Serviceable +{ + /** The avalon context */ + protected Context _context; + + /** The site configuration EP */ + protected SiteConfigurationExtensionPoint _scep; + + /** The sitemap indexer */ + protected SitemapIndexer _sitemapIndexer; + + /** The input data cache */ + protected PageElementCache _inputDataCache; + + /** The zone item cache */ + protected PageElementCache _zoneItemCache; + + @Override + public void contextualize(Context context) throws ContextException + { + _context = context; + } + + @Override + public void service(ServiceManager manager) throws ServiceException + { + _scep = (SiteConfigurationExtensionPoint) manager.lookup(SiteConfigurationExtensionPoint.ROLE); + _sitemapIndexer = (SitemapIndexer) manager.lookup(SitemapIndexer.ROLE); + _inputDataCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/inputData"); + _zoneItemCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/zoneItem"); + } + + @Override + public boolean supports(Event event) + { + return event.getId().equals(ObservationConstants.SITE_UPDATED); + } + + @Override + public int getPriority(Event event) + { + return MAX_PRIORITY + 3000; + } + + @Override + public void observe(Event event) + { + Site site = (Site) event.getTarget(); + Boolean newAutoposting = _scep.getValueAsBoolean(site.getName(), "autoposting"); + + // Saving previous "autoposting" parameter value as a request attribute. + Request request = ContextHelper.getRequest(_context); + Boolean oldAutoposting = (Boolean) request.getAttribute(TagAutopostingSiteParameterObserverPart1.__SITE_AUTOPOSTING_REQUEST_ATTR); + + if (oldAutoposting != null && !oldAutoposting.equals(newAutoposting)) + { + // FIXME autoposting -> reindex site or every (tagged) contents? + _reindexAndClearCache(site); + } + } + + /** + * Reindex and clear the caches for a given site + * @param site + */ + protected void _reindexAndClearCache(Site site) + { + for (Sitemap sitemap : site.getSitemaps()) + { + if (getLogger().isInfoEnabled()) + { + getLogger().info("Indexing sitemap " + sitemap.getName() + " started"); + } + + long t0 = System.currentTimeMillis(); + + try + { + _sitemapIndexer.index(sitemap); + } + catch (Exception e) + { + getLogger().error("Unable to index sitemap '" + sitemap.getName() + "' of site : '" + site.getName() + "'."); + } + + if (getLogger().isInfoEnabled()) + { + getLogger().info("Indexing sitemap " + sitemap.getName() + " ended in " + (System.currentTimeMillis() - t0) + " ms"); + } + } + + if (getLogger().isInfoEnabled()) + { + getLogger().info("Clearing cache for site " + site.getName()); + } + + try + { + CacheHelper.invalidateCache(site, getLogger()); + } + catch (Exception e) + { + getLogger().error("Unable ot invalidate cache for site : " + site.getName()); + } + + _inputDataCache.clear(null, site.getName()); + _zoneItemCache.clear(null, site.getName()); + } +} Index: main/plugin-web/src/org/ametys/web/tags/observers/TagUpdatedObserver.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/observers/TagUpdatedObserver.java (revision 0) +++ main/plugin-web/src/org/ametys/web/tags/observers/TagUpdatedObserver.java (revision 0) @@ -0,0 +1,111 @@ +/* + * Copyright 2014 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.tags.observers; + +import java.util.Collection; +import java.util.Set; + +import org.apache.lucene.index.IndexWriter; + +import org.ametys.cms.observation.Event; +import org.ametys.cms.observation.Observer; +import org.ametys.cms.repository.Content; +import org.ametys.plugins.repository.AmetysObject; +import org.ametys.plugins.repository.AmetysObjectIterable; +import org.ametys.web.ObservationConstants; +import org.ametys.web.repository.site.Site; +import org.ametys.web.repository.sitemap.Sitemap; +import org.ametys.web.tags.Tag; +import org.ametys.web.tags.TagHelper; + +/** + * Tag added {@link Observer}: + * - Clear the cache. + * - Re-index contents tagged with this tag or a descendant tag. + */ +public class TagUpdatedObserver extends AbstractTagObserver +{ + @Override + public boolean supports(Event event) + { + return event.getId().equals(ObservationConstants.TAG_UPDATED); + } + + @Override + protected void observe(Site site, AmetysObject aoTag, String tagName, Event rawEvent) + { + // Re-index content tagged with this tag or a descendant tag + Tag tag = _tagProviderEP.getTag(site != null ? site.getName() : null, tagName); + Set descendantNames = TagHelper.getDescendantNames(tag, true); + + try + { + _reindexTaggedContents(descendantNames); + } + catch (Exception e) + { + getLogger().error("Unable to create or update index for event: " + rawEvent, e); + } + + // Clear cache + _clearCache(site); + } + + /** + * Re-index content tagged with at least of this tags + * @param descendantNames + * @throws Exception + */ + protected void _reindexTaggedContents(Collection descendantNames) throws Exception + { + AmetysObjectIterable contentIt = _retrievesTaggedContents(descendantNames); + + while (contentIt.hasNext()) + { + Content content = contentIt.next(); + _reindexContent(content); + } + } + + /** + * Re-index the given content + * @param content + * @throws Exception if unable to create or update the index + */ + protected void _reindexContent(Content content) throws Exception + { + IndexWriter indexWriter = null; + + try + { + Sitemap sitemap = _getSitemap(content); + + if (sitemap != null) + { + indexWriter = _getIndexWriter(sitemap); + _updatePageDocumentsForContent(indexWriter, content.getId()); + } + } + + finally + { + if (indexWriter != null) + { + indexWriter.close(); + } + } + } +} Index: main/plugin-web/src/org/ametys/web/tags/observers/TagAddedObserver.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/observers/TagAddedObserver.java (revision 0) +++ main/plugin-web/src/org/ametys/web/tags/observers/TagAddedObserver.java (revision 0) @@ -0,0 +1,43 @@ +/* + * Copyright 2014 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.tags.observers; + +import org.ametys.cms.observation.Event; +import org.ametys.cms.observation.Observer; +import org.ametys.plugins.repository.AmetysObject; +import org.ametys.web.ObservationConstants; +import org.ametys.web.repository.site.Site; + +/** + * Tag added {@link Observer}: + * - Clear the cache. + */ +public class TagAddedObserver extends AbstractTagObserver +{ + @Override + public boolean supports(Event event) + { + return event.getId().equals(ObservationConstants.TAG_ADDED); + } + + @Override + protected void observe(Site site, AmetysObject tag, String tagName, Event rawEvent) + { + // Clear cache + _clearCache(site); + } +} + Index: main/plugin-web/src/org/ametys/web/tags/observers/TagAutopostingSiteParameterObserverPart1.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/observers/TagAutopostingSiteParameterObserverPart1.java (revision 0) +++ main/plugin-web/src/org/ametys/web/tags/observers/TagAutopostingSiteParameterObserverPart1.java (revision 0) @@ -0,0 +1,83 @@ +/* + * Copyright 2014 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.tags.observers; + +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.ContextException; +import org.apache.avalon.framework.context.Contextualizable; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.Serviceable; +import org.apache.cocoon.components.ContextHelper; +import org.apache.cocoon.environment.Request; + +import org.ametys.cms.observation.Event; +import org.ametys.cms.observation.Observer; +import org.ametys.web.ObservationConstants; +import org.ametys.web.repository.site.Site; +import org.ametys.web.site.SiteConfigurationExtensionPoint; + +/** + * Memorizes previous value of the autoposting site parameter to be able to compare it later. + */ +public class TagAutopostingSiteParameterObserverPart1 extends AbstractLogEnabled implements Observer, Contextualizable, Serviceable +{ + /** Site autoposting request attribute name */ + protected static final String __SITE_AUTOPOSTING_REQUEST_ATTR = "site.updating.autoposting.old.value"; + + /** The avalon context */ + protected Context _context; + + /** The site configuration EP */ + protected SiteConfigurationExtensionPoint _scep; + + @Override + public void contextualize(Context context) throws ContextException + { + _context = context; + } + + @Override + public void service(ServiceManager manager) throws ServiceException + { + _scep = (SiteConfigurationExtensionPoint) manager.lookup(SiteConfigurationExtensionPoint.ROLE); + } + + @Override + public boolean supports(Event event) + { + return event.getId().equals(ObservationConstants.SITE_UPDATING); + } + + @Override + public int getPriority(Event event) + { + return MAX_PRIORITY + 3000; + } + + @Override + public void observe(Event event) + { + Site site = (Site) event.getTarget(); + Boolean autoposting = _scep.getValueAsBoolean(site.getName(), "autoposting"); + + // Saving previous "autoposting" parameter value as a request attribute. + Request request = ContextHelper.getRequest(_context); + request.setAttribute(__SITE_AUTOPOSTING_REQUEST_ATTR, autoposting); + } +} + Index: main/plugin-web/src/org/ametys/web/tags/observers/AbstractTagObserver.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/observers/AbstractTagObserver.java (revision 0) +++ main/plugin-web/src/org/ametys/web/tags/observers/AbstractTagObserver.java (revision 0) @@ -0,0 +1,161 @@ +/* + * Copyright 2014 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.tags.observers; + +import java.util.Collection; + +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.commons.collections.CollectionUtils; + +import org.ametys.cms.observation.Event; +import org.ametys.cms.observation.Observer; +import org.ametys.cms.repository.Content; +import org.ametys.cms.repository.ContentQueryHelper; +import org.ametys.plugins.repository.AmetysObject; +import org.ametys.plugins.repository.AmetysObjectIterable; +import org.ametys.plugins.repository.EmptyIterable; +import org.ametys.plugins.repository.UnknownAmetysObjectException; +import org.ametys.plugins.repository.query.expression.Expression.Operator; +import org.ametys.web.cache.CacheHelper; +import org.ametys.web.lucene.AbstractLuceneObserver; +import org.ametys.web.repository.site.Site; +import org.ametys.web.repository.sitemap.Sitemap; +import org.ametys.web.tags.TagExpression; +import org.ametys.web.tags.TagExpression.LogicalOperator; +import org.ametys.web.tags.TagProviderExtensionPoint; + +/** + * Abstract tag {@link Observer} + */ +public abstract class AbstractTagObserver extends AbstractLuceneObserver +{ + /** The tag provider EP */ + protected TagProviderExtensionPoint _tagProviderEP; + + @Override + public void service(ServiceManager manager) throws ServiceException + { + super.service(manager); + _tagProviderEP = (TagProviderExtensionPoint) manager.lookup(TagProviderExtensionPoint.ROLE); + } + + @Override + public void observe(Event event) + { + AmetysObject tagOrParent = (AmetysObject) event.getTarget(); + Object[] args = event.getArguments(); + String tagName = (String) args[0]; + observe(_getSite(tagOrParent), tagOrParent, tagName, event); + } + + /** + * Typed observe method + * @param site + * @param tagOrParent + * @param tagName the tag name corresponding the the object tagOrParent when applicable. + * @param rawEvent The raw event from which the previous arguments have been extracted. + */ + protected abstract void observe(Site site, AmetysObject tagOrParent, String tagName, Event rawEvent); + + /** + * Get the site of a jcr tag. + * @param tagOrParent Ametys object which can be a tag or its parent depending on the event type. + * @return The site + */ + protected Site _getSite(AmetysObject tagOrParent) + { + Site site = null; + AmetysObject ao = tagOrParent; + + while (ao != null && site == null) + { + if (ao instanceof Site) + { + site = (Site) ao; + } + else + { + ao = ao.getParent(); + } + } + + return site; + } + + /** + * Retrieves the sitemap of a content + * @param content + * @return The sitemap object or null. + */ + protected Sitemap _getSitemap(Content content) + { + String language = content.getLanguage(); + AmetysObject ao = content.getParent().getParent(); + + if (ao instanceof Site) + { + try + { + return ((Site) ao).getSitemap(language); + } + catch (UnknownAmetysObjectException e) + { + return null; + } + } + + return null; + } + + /** + * Clear site cache + * @param site + */ + protected void _clearCache(Site site) + { + try + { + if (site != null) + { + CacheHelper.invalidateCache(site, getLogger()); + } + } + catch (Exception e) + { + getLogger().error("Unable to invalidate cache for site : " + site, e); + } + } + + /** + * Re-index content tagged with at least of this tags + * @param descendantNames + * @return iterable on contents + * @throws Exception + */ + protected AmetysObjectIterable _retrievesTaggedContents(Collection descendantNames) throws Exception + { + if (CollectionUtils.isEmpty(descendantNames)) + { + return new EmptyIterable(); + } + + TagExpression tagExpression = new TagExpression(Operator.EQ, descendantNames.toArray(new String[descendantNames.size()]), LogicalOperator.OR); + String contentXPathQuery = ContentQueryHelper.getContentXPathQuery(tagExpression); + + return _resolver.query(contentXPathQuery); + } +} Index: main/plugin-web/src/org/ametys/web/tags/observers/TagDeletedObserver.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/observers/TagDeletedObserver.java (revision 0) +++ main/plugin-web/src/org/ametys/web/tags/observers/TagDeletedObserver.java (revision 0) @@ -0,0 +1,135 @@ +/* + * Copyright 2014 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.tags.observers; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; + +import org.ametys.cms.observation.Event; +import org.ametys.cms.observation.ObservationManager; +import org.ametys.cms.observation.Observer; +import org.ametys.cms.repository.Content; +import org.ametys.plugins.repository.AmetysObject; +import org.ametys.plugins.repository.AmetysObjectIterable; +import org.ametys.runtime.user.CurrentUserProvider; +import org.ametys.web.ObservationConstants; +import org.ametys.web.repository.content.ModifiableWebContent; +import org.ametys.web.repository.site.Site; + +/** + * Tag added {@link Observer}: + * - Clear the cache. + * - Update contents tagged with this tag or a descendant tag and send the CONTENT_TAGGED event. + */ +public class TagDeletedObserver extends AbstractTagObserver +{ + /** Observer manager. */ + protected ObservationManager _observationManager; + + /** The current user provider */ + protected CurrentUserProvider _currentUserProvider; + + @Override + public void service(ServiceManager manager) throws ServiceException + { + super.service(manager); + _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE); + _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); + } + @Override + public boolean supports(Event event) + { + return event.getId().equals(ObservationConstants.TAG_DELETED); + } + + @Override + protected void observe(Site site, AmetysObject parent, String tagName, Event rawEvent) + { + // Re-index content tagged with the deleted tag or a descendant tag. + Object[] arguments = rawEvent.getArguments(); + Object arg2 = arguments.length >= 3 ? arguments[2] : null; + Collection descendantNames = (Collection) (arg2 instanceof Collection ? arguments[2] : Collections.EMPTY_SET); + + try + { + _updateTaggedContents(descendantNames); + } + catch (Exception e) + { + getLogger().error("Unable to create or update index for event: " + rawEvent, e); + } + + // Clear cache + _clearCache(site); + } + + /** + * Update content tagged with at least one of the tag names. + * Removes theses tags on the content and send the CONTENT_TAGGED event. + * @param tagNames + * @throws Exception + */ + protected void _updateTaggedContents(Collection tagNames) throws Exception + { + AmetysObjectIterable contentIt = _retrievesTaggedContents(tagNames); + + while (contentIt.hasNext()) + { + _updateTaggedContent(contentIt.next(), tagNames); + } + } + + /** + * Update the tagged content. + * Remove deleted tags on the content and send the CONTENT_TAGGED event. + * @param content + * @param tagNames + */ + protected void _updateTaggedContent(Content content, Collection tagNames) + { + if (content instanceof ModifiableWebContent) + { + ModifiableWebContent webContent = (ModifiableWebContent) content; + Set oldTags = webContent.getTags(); + Set newTags = new HashSet(oldTags); + + // Update tags + for (String oldTagName : oldTags) + { + if (tagNames.contains(oldTagName)) + { + webContent.untag(oldTagName); + newTags.remove(oldTagName); + } + } + + if (oldTags.size() != newTags.size()) + { + webContent.saveChanges(); + } + + // Notify observers that the content has been tagged + _observationManager.notify(new Event(_currentUserProvider.getUser(), ObservationConstants.CONTENT_TAGGED, webContent, + new Object[] {oldTags, newTags})); + } + + } +} Index: main/plugin-web/src/org/ametys/web/tags/inputdata/FilteredContentsInputDataCachePolicy.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/inputdata/FilteredContentsInputDataCachePolicy.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/inputdata/FilteredContentsInputDataCachePolicy.java (working copy) @@ -48,7 +48,9 @@ ObservationConstants.PAGE_CHANGED, ObservationConstants.PAGE_MOVED, ObservationConstants.PAGE_DELETED, - ObservationConstants.ZONEITEM_DELETED); + ObservationConstants.ZONEITEM_DELETED, + ObservationConstants.TAG_ADDED, + ObservationConstants.TAG_DELETED); } else if ("live".equals(workspace)) { @@ -60,7 +62,9 @@ ObservationConstants.PAGE_CHANGED, ObservationConstants.PAGE_MOVED, ObservationConstants.PAGE_DELETED, - ObservationConstants.ZONEITEM_DELETED); + ObservationConstants.ZONEITEM_DELETED, + ObservationConstants.TAG_ADDED, + ObservationConstants.TAG_DELETED); } return Collections.emptyList(); Index: main/plugin-web/src/org/ametys/web/tags/inputdata/FilteredContentsInputData.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/inputdata/FilteredContentsInputData.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/inputdata/FilteredContentsInputData.java (working copy) @@ -50,6 +50,7 @@ import org.ametys.web.repository.page.Page; import org.ametys.web.repository.site.Site; import org.ametys.web.repository.site.SiteManager; +import org.ametys.web.tags.TagProviderExtensionPoint; /** * This class generates an output with all existing filters defined on context's current page. @@ -66,6 +67,8 @@ protected Context _context; /** The site manager */ protected SiteManager _siteManager; + /** The tag provider EP */ + protected TagProviderExtensionPoint _tagProviderEP; private ContentFilterHelper _filterHelper; @@ -76,6 +79,7 @@ _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE); _filterHelper = (ContentFilterHelper) smanager.lookup(ContentFilterHelper.ROLE); _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); + _tagProviderEP = (TagProviderExtensionPoint) smanager.lookup(TagProviderExtensionPoint.ROLE); } @Override @@ -136,7 +140,7 @@ { if ("content".equals(filterConf.getAttribute("target"))) { - StaticWebContentFilter filter = new StaticWebContentFilter (filterConf.getAttribute("id"), _resolver, _siteManager); + StaticWebContentFilter filter = new StaticWebContentFilter (filterConf.getAttribute("id"), _resolver, _siteManager, _tagProviderEP); filter.configure(filterConf); filters.add(filter); Index: main/plugin-web/src/org/ametys/web/tags/StaticTagProvider.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/StaticTagProvider.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/StaticTagProvider.java (working copy) @@ -16,6 +16,7 @@ package org.ametys.web.tags; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,8 +60,6 @@ protected I18nizableText _label; /** The description */ protected I18nizableText _description; - /** The tag categories */ - protected Map _categories; /** The tags */ protected Map _tags; @@ -93,7 +92,6 @@ _id = configuration.getAttribute("id"); _label = configureLabel(configuration, "plugin." + _pluginName); _description = configureDescription(configuration, "plugin." + _pluginName); - _categories = configureTagCategories(configuration, null, "plugin." + _pluginName); _tags = configureTags(configuration, null, "plugin." + _pluginName); } @@ -124,13 +122,6 @@ return _description; } - - @Override - public Map getTagCategories(String siteName) - { - return _categories; - } - @Override public Map getTags(String siteName) { @@ -144,106 +135,38 @@ } @Override - public boolean hasCategory(String siteName, String categoryID) - { - return getTagCategory(siteName, categoryID) != null; - } - - @Override public Tag getTag(String siteName, String tagID) { Map tags = getTags(siteName); - if (tags != null && tags.containsKey(tagID)) - { - return getTags(siteName).get(tagID); - } - - Map tagCategories = getTagCategories(siteName); - if (tagCategories != null) - { - for (TagCategory category : tagCategories.values()) - { - Tag tag = _searchTagInSubCategory (category, tagID); - if (tag != null) - { - return tag; - } - } - } - - return null; + return tags != null ? _recursiveSearchTags(tags, tagID) : null; } - private Tag _searchTagInSubCategory (TagCategory category, String tagID) + private Tag _recursiveSearchTags(Map tags, String tagID) { - if (category.hasTag(tagID)) + if (tags.containsKey(tagID)) { - return category.getTag(tagID); + return tags.get(tagID); } - Map subCategories = category.getCategories(); - if (subCategories != null) + for (Tag child : tags.values()) { - for (TagCategory child : subCategories.values()) + Tag tag = _recursiveSearchTags(child.getTags(), tagID); + if (tag != null) { - Tag tag = _searchTagInSubCategory(child, tagID); - if (tag != null) - { - return tag; - } + return tag; } } return null; } - + @Override - public TagCategory getTagCategory(String siteName, String categoryID) + public Collection getTags(String siteName, String tagID) { - Map categories = getTagCategories(siteName); - if (categories != null && categories.containsKey(categoryID)) - { - return categories.get(categoryID); - } - - if (categories != null) - { - for (TagCategory category : getTagCategories(siteName).values()) - { - TagCategory subCat = _searchInSubCategory (category, categoryID); - if (subCat != null) - { - return subCat; - } - } - } - - return null; + Tag tag = getTag(siteName, tagID); + return tag != null ? tag.getTags().values() : null; } - private TagCategory _searchInSubCategory (TagCategory category, String categoryID) - { - if (category.hasCategory(categoryID)) - { - return category.getCategory(categoryID); - } - - Map subCategories = category.getCategories(); - if (subCategories != null) - { - for (TagCategory child : subCategories.values()) - { - TagCategory subCat = _searchInSubCategory(child, categoryID); - if (subCat != null) - { - return subCat; - } - } - } - return null; - } - - @Override public void setPluginInfo(String pluginName, String featureName) { @@ -261,50 +184,14 @@ } /** - * Configure the tags categories from the passed configuration - * @param configuration The configuration - * @param parentId The parent id - * @param defaultCatalogue The default catalogue - * @return A Set of {@link TagCategory} - * @throws ConfigurationException - */ - protected Map configureTagCategories (Configuration configuration, String parentId, String defaultCatalogue) throws ConfigurationException - { - Map categories = new HashMap(); - Configuration[] categoriesConfiguration = configuration.getChildren("category"); - for (Configuration categoryConfiguration : categoriesConfiguration) - { - String id = categoryConfiguration.getAttribute("id"); - if (_localIds.contains(id)) - { - throw new ConfigurationException("A category or tag with the id '" + id + "' already exists"); - } - _localIds.add(id); - I18nizableText label = configureLabel (categoryConfiguration, defaultCatalogue); - I18nizableText description = configureDescription (categoryConfiguration, defaultCatalogue); - TagCategory tagCategory = new TagCategory(id, parentId, label, description); - - Map tags = configureTags(categoryConfiguration, id, defaultCatalogue); - tagCategory.setTags(tags); - - Map subCategories = configureTagCategories(categoryConfiguration, id, defaultCatalogue); - tagCategory.setCategories(subCategories); - - categories.put(id, tagCategory); - } - - return categories; - } - - /** * Configure tag from the passed configuration * @param configuration The configuration - * @param parentId The parent id + * @param parent The parent tag if any * @param defaultCatalogue The default catalogue for i18n * @return a Set of {@link Tag} * @throws ConfigurationException */ - protected Map configureTags (Configuration configuration, String parentId, String defaultCatalogue) throws ConfigurationException + protected Map configureTags (Configuration configuration, Tag parent, String defaultCatalogue) throws ConfigurationException { Map tags = new HashMap(); @@ -318,7 +205,7 @@ } if (_localIds.contains(id)) { - throw new ConfigurationException("A category or tag with the id '" + id + "' already exists", configuration); + throw new ConfigurationException("A tag with the id '" + id + "' already exists", configuration); } _localIds.add(id); String target = tagConfiguration.getAttribute("target"); @@ -334,8 +221,12 @@ } I18nizableText label = configureLabel (tagConfiguration, defaultCatalogue); I18nizableText description = configureDescription (tagConfiguration, defaultCatalogue); - Tag tag = new Tag(id, id, parentId, label, description, tagTarget, visibility); + Tag tag = new Tag(id, id, parent, label, description, tagTarget, visibility); tags.put(id, tag); + + // Recursive configuration + Map childTags = configureTags(tagConfiguration, tag, defaultCatalogue); + tag.setTags(childTags); } return tags; @@ -382,9 +273,4 @@ return new I18nizableText(descConfiguration.getValue("")); } } - - - - - } Index: main/plugin-web/src/org/ametys/web/tags/generators/JCRTagsGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/generators/JCRTagsGenerator.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/generators/JCRTagsGenerator.java (working copy) @@ -33,11 +33,10 @@ import org.ametys.plugins.repository.TraversableAmetysObject; import org.ametys.web.tags.TagProviderExtensionPoint; import org.ametys.web.tags.jcr.JCRTag; -import org.ametys.web.tags.jcr.JCRTagCategory; import org.ametys.web.tags.jcr.JCRTagProvider; /** - * Sax events for tags and tags categories stored in JCR repository + * Sax events for tags stored in JCR repository * */ public class JCRTagsGenerator extends JCRTagGenerator @@ -56,11 +55,11 @@ public void generate() throws IOException, SAXException, ProcessingException { Request request = ObjectModelHelper.getRequest(objectModel); - String categoryID = request.getParameter("categoryID"); + String tagID = request.getParameter("tagID"); String siteName = request.getParameter("siteName"); contentHandler.startDocument(); - if (StringUtils.isEmpty(categoryID) || categoryID.startsWith("tags://")) + if (StringUtils.isEmpty(tagID) || tagID.startsWith("tags://")) { XMLUtils.startElement(contentHandler, "jcr-tags"); @@ -71,11 +70,7 @@ AmetysObjectIterable it = rootNode.getChildren(); for (AmetysObject object : it) { - if (object instanceof JCRTagCategory) - { - saxCategory((JCRTagCategory) object, true); - } - else if (object instanceof JCRTag) + if (object instanceof JCRTag) { saxTag((JCRTag) object); } @@ -91,8 +86,8 @@ } else { - JCRTagCategory jcrCategory = _resolver.resolveById(categoryID); - saxCategory(jcrCategory, true); + JCRTag jcrTag = _resolver.resolveById(tagID); + saxTag(jcrTag, true); } contentHandler.endDocument(); } Index: main/plugin-web/src/org/ametys/web/tags/generators/JCRTagGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/generators/JCRTagGenerator.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/generators/JCRTagGenerator.java (working copy) @@ -23,9 +23,9 @@ import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Request; import org.apache.cocoon.generation.ServiceableGenerator; +import org.apache.cocoon.xml.AttributesImpl; import org.apache.cocoon.xml.XMLUtils; import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; import org.ametys.plugins.repository.AmetysObject; import org.ametys.plugins.repository.AmetysObjectIterable; @@ -35,10 +35,9 @@ import org.ametys.runtime.util.I18nizableText; import org.ametys.web.tags.Tag.TagVisibility; import org.ametys.web.tags.jcr.JCRTag; -import org.ametys.web.tags.jcr.JCRTagCategory; /** - * Sax events for a tag or a tag category stored in JCR repository + * Sax events for a tag stored in JCR repository * */ public class JCRTagGenerator extends ServiceableGenerator @@ -70,11 +69,6 @@ JCRTag tag = (JCRTag) object; saxTag(tag); } - else if (object instanceof JCRTagCategory) - { - JCRTagCategory category = (JCRTagCategory) object; - saxCategory(category, false); - } } catch (UnknownAmetysObjectException e) { @@ -92,48 +86,33 @@ */ protected void saxTag(JCRTag tag) throws SAXException { - I18nizableText title = new I18nizableText(tag.getTitle()); - I18nizableText description = new I18nizableText(tag.getDescription()); - TagVisibility visibility = tag.getVisibility() != null ? tag.getVisibility() : TagVisibility.PUBLIC; - - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute("", "id", "id", "CDATA", tag.getId()); - attrs.addAttribute("", "name", "name", "CDATA", tag.getName()); - attrs.addAttribute("", "target", "target", "CDATA", tag.getTarget() != null ? tag.getTarget().toString() : "CONTENT"); - attrs.addAttribute("", "visibility", "visibility", "CDATA", visibility.toString()); - XMLUtils.startElement(contentHandler, "tag", attrs); - - XMLUtils.startElement(contentHandler, "title"); - title.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "title"); - - XMLUtils.startElement(contentHandler, "description"); - description.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "description"); - - XMLUtils.endElement(contentHandler, "tag"); + saxTag(tag, false); } /** - * Sax a tag category - * @param jcrCategory The jcr tag category to sax - * @param children true to sax category sub category and tags - * @throws SAXException if an error occurred while saxing + * Sax a tag + * @param tag The tag to sax + * @param children true to tag direct children + * @throws SAXException */ - protected void saxCategory(JCRTagCategory jcrCategory, boolean children) throws SAXException + protected void saxTag(JCRTag tag, boolean children) throws SAXException { - I18nizableText title = new I18nizableText(jcrCategory.getTitle()); - I18nizableText description = new I18nizableText(jcrCategory.getDescription()); + I18nizableText title = new I18nizableText(tag.getTitle()); + I18nizableText description = new I18nizableText(tag.getDescription()); + TagVisibility visibility = tag.getVisibility() != null ? tag.getVisibility() : TagVisibility.PUBLIC; - AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", jcrCategory.getId()); - attr.addAttribute("", "name", "name", "CDATA", jcrCategory.getName()); - if (jcrCategory.getChildren().hasNext()) + AttributesImpl attrs = new AttributesImpl(); + attrs.addCDATAAttribute("id", tag.getId()); + attrs.addCDATAAttribute("name", tag.getName()); + attrs.addCDATAAttribute("target", tag.getTarget() != null ? tag.getTarget().toString() : "CONTENT"); + attrs.addCDATAAttribute("visibility", visibility.toString()); + if (tag.getChildren().hasNext()) { - attr.addAttribute("", "hasChild", "hasChild", "CDATA", "true"); + attrs.addCDATAAttribute("hasChild", "true"); } - XMLUtils.startElement(contentHandler, "category", attr); + XMLUtils.startElement(contentHandler, "tag", attrs); + XMLUtils.startElement(contentHandler, "title"); title.toSAX(contentHandler); XMLUtils.endElement(contentHandler, "title"); @@ -141,10 +120,10 @@ XMLUtils.startElement(contentHandler, "description"); description.toSAX(contentHandler); XMLUtils.endElement(contentHandler, "description"); - + if (children) { - AmetysObjectIterable< ? > objects = jcrCategory.getChildren(); + AmetysObjectIterable objects = tag.getChildren(); for (AmetysObject object : objects) { if (object instanceof JCRTag) @@ -152,15 +131,9 @@ JCRTag jcrTag = (JCRTag) object; saxTag(jcrTag); } - else if (object instanceof JCRTagCategory) - { - JCRTagCategory jcrSubCat = (JCRTagCategory) object; - saxCategory(jcrSubCat, false); - } } } - - XMLUtils.endElement(contentHandler, "category"); + + XMLUtils.endElement(contentHandler, "tag"); } - } Index: main/plugin-web/src/org/ametys/web/tags/generators/TagsListGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/generators/TagsListGenerator.java (revision 26563) +++ main/plugin-web/src/org/ametys/web/tags/generators/TagsListGenerator.java (working copy) @@ -22,16 +22,19 @@ import org.apache.cocoon.ProcessingException; import org.apache.cocoon.environment.ObjectModelHelper; +import org.apache.cocoon.xml.AttributesImpl; import org.apache.cocoon.xml.XMLUtils; +import org.apache.commons.collections.MapUtils; import org.xml.sax.SAXException; +import org.ametys.runtime.util.I18nizableText; import org.ametys.web.tags.Tag; import org.ametys.web.tags.TagProvider; /** * This class SAXes some tags passed in request parameters */ -public class TagsGenerator extends TagCategoriesAndTagsGenerator +public class TagsListGenerator extends TagsGenerator { @Override public void generate() throws IOException, SAXException, ProcessingException @@ -62,11 +65,40 @@ continue; } - if (tagProvider.hasTag(siteName, tagName)) + if (tagName.startsWith("provider_") && id.equals(tagName.substring("provider_".length()))) { - Tag tag = tagProvider.getTag(siteName, tagName); - saxTag(tag, true); nbFound++; + + I18nizableText title = tagProvider.getLabel(); + I18nizableText description = tagProvider.getDescription(); + + AttributesImpl attrs = new AttributesImpl(); + attrs.addCDATAAttribute("id", id); + + Map childTags = tagProvider.getTags(siteName); + if (MapUtils.isNotEmpty(childTags)) + { + attrs.addCDATAAttribute("hasChild", "true"); + } + + XMLUtils.startElement(contentHandler, "tag", attrs); + + XMLUtils.startElement(contentHandler, "title"); + title.toSAX(contentHandler); + XMLUtils.endElement(contentHandler, "title"); + + XMLUtils.startElement(contentHandler, "description"); + description.toSAX(contentHandler); + XMLUtils.endElement(contentHandler, "description"); + + XMLUtils.endElement(contentHandler, "tag"); + } + else if (tagProvider.hasTag(siteName, tagName)) + { + nbFound++; + + Tag tag = tagProvider.getTag(siteName, tagName); + saxTag(tag, false); } } } Property changes on: main\plugin-web\src\org\ametys\web\tags\generators\TagsListGenerator.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Index: main/plugin-web/src/org/ametys/web/tags/generators/TagCategoriesGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/generators/TagCategoriesGenerator.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/generators/TagCategoriesGenerator.java (working copy) @@ -1,93 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags.generators; - -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.cocoon.ProcessingException; -import org.apache.cocoon.environment.ObjectModelHelper; -import org.apache.cocoon.xml.XMLUtils; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; - -import org.ametys.web.tags.TagCategory; -import org.ametys.web.tags.TagProvider; - -/** - * Generates tag categories passed in request parameters - * - */ -public class TagCategoriesGenerator extends TagCategoriesAndTagsGenerator -{ - @Override - public void generate() throws IOException, SAXException, ProcessingException - { - Map jsParameters = (Map) objectModel.get(ObjectModelHelper.PARENT_CONTEXT); - List categories = (List) jsParameters.get("categories"); - String siteName = (String) jsParameters.get("siteName"); - - contentHandler.startDocument(); - XMLUtils.startElement(contentHandler, "TagCategories"); - - int nbCategories = categories.size(); - int nbFound = 0; - Set extensionsIds = _tagProviderExtPt.getExtensionsIds(); - for (String id : extensionsIds) - { - if (nbFound == nbCategories) - { - continue; - } - - TagProvider tagProvider = _tagProviderExtPt.getExtension(id); - - for (String categoryID : categories) - { - if (nbFound == nbCategories) - { - continue; - } - - if (categoryID.startsWith("provider_") && id.equals(categoryID.substring("provider_".length()))) - { - AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", id); - XMLUtils.startElement(contentHandler, "category", attr); - - XMLUtils.startElement(contentHandler, "title"); - tagProvider.getLabel().toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "title"); - - XMLUtils.endElement(contentHandler, "category"); - } - else if (tagProvider.hasCategory(siteName, categoryID)) - { - TagCategory category = tagProvider.getTagCategory(siteName, categoryID); - saxCategory(category, false); - nbFound++; - } - } - } - - XMLUtils.endElement(contentHandler, "TagCategories"); - contentHandler.endDocument(); - - } - -} Index: main/plugin-web/src/org/ametys/web/tags/generators/TagsGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/generators/TagsGenerator.java (revision 26563) +++ main/plugin-web/src/org/ametys/web/tags/generators/TagsGenerator.java (working copy) @@ -31,6 +31,7 @@ import org.apache.cocoon.environment.Request; import org.apache.cocoon.xml.AttributesImpl; import org.apache.cocoon.xml.XMLUtils; +import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.xml.sax.SAXException; @@ -45,16 +46,14 @@ import org.ametys.web.tags.Tag; import org.ametys.web.tags.Tag.TagTarget; import org.ametys.web.tags.Tag.TagVisibility; -import org.ametys.web.tags.TagCategory; import org.ametys.web.tags.TagProvider; import org.ametys.web.tags.TagProviderExtensionPoint; import org.ametys.web.tags.jcr.JCRTagProvider; /** - * This class SAXes the tags and categories - * + * Tags generator. */ -public class TagCategoriesAndTagsGenerator extends CurrentUserProviderServiceableGenerator +public class TagsGenerator extends CurrentUserProviderServiceableGenerator { /** The {@link TagProviderExtensionPoint} */ protected TagProviderExtensionPoint _tagProviderExtPt; @@ -76,6 +75,10 @@ @Override public void generate() throws IOException, SAXException, ProcessingException { + // FIXME tag -> test tag widget in filtered contents service. + + + Request request = ObjectModelHelper.getRequest(objectModel); String parentID = request.getParameter("parentID"); String siteName = request.getParameter("siteName"); @@ -106,14 +109,14 @@ } else { - _saxCategory(parentID, siteName, page, content); + _saxTag(parentID, siteName, page, content); } contentHandler.endDocument(); } /** - * SAX all categories. + * SAX all tags. * @param siteName the site name. * @param page the current page (can be null). * @param content the current content (can be null). @@ -125,7 +128,7 @@ } /** - * SAX all categories. + * SAX all tags. * @param siteName the site name. * @param page the current page (can be null). * @param content the current content (can be null). @@ -142,14 +145,14 @@ TagProvider tagProvider = _tagProviderExtPt.getExtension(id); AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", "provider_" + id); + attr.addCDATAAttribute("id", "provider_" + id); + attr.addCDATAAttribute("name", "provider_" + id); - Map categories = tagProvider.getTagCategories(siteName); Map tags = tagProvider.getTags(siteName); - if ((categories != null && categories.size() > 0) || (tags != null && tags.size() > 0)) + if (MapUtils.isNotEmpty(tags)) { - attr.addAttribute("", "hasChild", "hasChild", "CDATA", "true"); + attr.addCDATAAttribute("hasChild", "true"); } if (forcedProviderIds.contains(id)) { @@ -160,7 +163,7 @@ try { JCRTagProvider jcrProvider = (JCRTagProvider) tagProvider; - attr.addAttribute("", "objectId", "objectId", "CDATA", jcrProvider.getRootNode(siteName).getId()); + attr.addCDATAAttribute("objectId", jcrProvider.getRootNode(siteName).getId()); } catch (RepositoryException e) { @@ -192,7 +195,7 @@ } /** - * SAX a provider's categories and tags. + * SAX a provider's tags. * @param providerId the provider ID. * @param siteName the site name. * @param page the current page (can be null). @@ -202,91 +205,89 @@ protected void _saxProvider(String providerId, String siteName, Page page, Content content) throws SAXException { TagProvider tagProvider = _tagProviderExtPt.getExtension(providerId); - Map tagCategories = tagProvider.getTagCategories(siteName); - if (tagCategories != null) + Map tags = tagProvider.getTags(siteName); + if (tags != null) { XMLUtils.startElement(contentHandler, "tags"); - for (TagCategory tagCategory : tagCategories.values()) + for (Tag tag : tags.values()) { - saxCategory(tagCategory, true, page, content); + saxTag(tag, true, page, content); } XMLUtils.endElement(contentHandler, "tags"); } } /** - * SAX a category and its tags. - * @param categoryId the category ID. + * SAX a tag + * @param tagName the tag name. * @param siteName the site name. * @param page the current page (can be null). * @param content the current content (can be null). * @throws SAXException if an error occurs generating the XML. */ - protected void _saxCategory(String categoryId, String siteName, Page page, Content content) throws SAXException + protected void _saxTag(String tagName, String siteName, Page page, Content content) throws SAXException { Set extensionsIds = _tagProviderExtPt.getExtensionsIds(); for (String id : extensionsIds) { TagProvider tagProvider = _tagProviderExtPt.getExtension(id); - if (tagProvider.hasCategory(siteName, categoryId)) + if (tagProvider.hasTag(siteName, tagName)) { - saxCategory(tagProvider.getTagCategory(siteName, categoryId), true, page, content); + saxTag(tagProvider.getTag(siteName, tagName), true, page, content); } } } private void _saxAll(TagProvider tagProvider, String siteName, Page page, Content content) throws SAXException { - Map tagCategories = tagProvider.getTagCategories(siteName); - if (tagCategories != null) - { - for (TagCategory tagCategory : tagCategories.values()) - { - saxCategory(tagCategory, true, page, content); - } - } - Map tags = tagProvider.getTags(siteName); if (tags != null) { for (Tag tag : tags.values()) { - saxTag(tag, isUserAuthorized(tag, page, content)); + saxTag(tag, true, page, content); } } } /** - * Sax a tag category - * @param category The category to sax + * Sax a tag + * @param tag The tag to sax * @param children true to sax children * @throws SAXException If an error occurred while saxing */ - protected void saxCategory (TagCategory category, boolean children) throws SAXException + protected void saxTag (Tag tag, boolean children) throws SAXException { - saxCategory(category, children, null, null); + saxTag(tag, children, null, null); } /** - * Sax a tag category - * @param category The category to sax + * Sax a tag + * @param tag The tag to sax * @param children true to sax children * @param page the current page (can be null). * @param content the current content (can be null). * @throws SAXException If an error occurred while saxing */ - protected void saxCategory (TagCategory category, boolean children, Page page, Content content) throws SAXException + protected void saxTag (Tag tag, boolean children, Page page, Content content) throws SAXException { - I18nizableText title = category.getTitle(); - I18nizableText description = category.getDescription(); + I18nizableText title = tag.getTitle(); + I18nizableText description = tag.getDescription(); + + AttributesImpl attrs = new AttributesImpl(); + attrs.addCDATAAttribute("id", tag.getId()); + attrs.addCDATAAttribute("name", tag.getName()); + attrs.addCDATAAttribute("target", tag.getTarget() != null ? tag.getTarget().toString() : TagTarget.CONTENT.toString()); + attrs.addCDATAAttribute("authorized", String.valueOf(isUserAuthorized(tag, page, content))); + attrs.addCDATAAttribute("visibility", tag.getVisibility() != null ? tag.getVisibility().toString() : TagVisibility.PUBLIC.toString()); - AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", category.getId()); - if ((category.getCategories() != null && category.getCategories().size() > 0) || (category.getTags() != null && category.getTags().size() > 0)) + Map childTags = tag.getTags(); + if (MapUtils.isNotEmpty(childTags)) { - attr.addAttribute("", "hasChild", "hasChild", "CDATA", "true"); + attrs.addCDATAAttribute("hasChild", "true"); } - XMLUtils.startElement(contentHandler, "category", attr); + + XMLUtils.startElement(contentHandler, "tag", attrs); XMLUtils.startElement(contentHandler, "title"); title.toSAX(contentHandler); @@ -296,58 +297,17 @@ description.toSAX(contentHandler); XMLUtils.endElement(contentHandler, "description"); - - - Map subCategories = category.getCategories(); - if (subCategories != null) + if (childTags != null) { - for (TagCategory subCategory : subCategories.values()) + for (Tag child : childTags.values()) { - saxCategory (subCategory, _all, page, content); + saxTag (child, _all, page, content); } } - Map tags = category.getTags(); - if (tags != null) - { - for (Tag tag : tags.values()) - { - saxTag (tag, isUserAuthorized(tag, page, content)); - } - } - XMLUtils.endElement(contentHandler, "category"); - } - - /** - * SAX a tag - * @param tag The tag to SAX - * @param authorized true if user is authorized to assign tag - * @throws SAXException If an error occurred while SAXing - */ - protected void saxTag (Tag tag, boolean authorized) throws SAXException - { - I18nizableText title = tag.getTitle(); - I18nizableText description = tag.getDescription(); - - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute("", "id", "id", "CDATA", tag.getId()); - attrs.addAttribute("", "name", "name", "CDATA", tag.getName()); - attrs.addAttribute("", "target", "target", "CDATA", tag.getTarget() != null ? tag.getTarget().toString() : TagTarget.CONTENT.toString()); - attrs.addAttribute("", "authorized", "authorized", "CDATA", String.valueOf(authorized)); - attrs.addAttribute("", "visibility", "visibility", "CDATA", tag.getVisibility() != null ? tag.getVisibility().toString() : TagVisibility.PUBLIC.toString()); - XMLUtils.startElement(contentHandler, "tag", attrs); - - XMLUtils.startElement(contentHandler, "title"); - title.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "title"); - - XMLUtils.startElement(contentHandler, "description"); - description.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "description"); - XMLUtils.endElement(contentHandler, "tag"); } - + /** * Determines if a tag is private * @param tag the tag to test Index: main/plugin-web/src/org/ametys/web/tags/generators/TagCategoriesAndTagsGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/generators/TagCategoriesAndTagsGenerator.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/generators/TagCategoriesAndTagsGenerator.java (working copy) @@ -1,405 +0,0 @@ -/* - * Copyright 2010 Anyware Services - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.ametys.web.tags.generators; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import javax.jcr.RepositoryException; - -import org.apache.avalon.framework.service.ServiceException; -import org.apache.avalon.framework.service.ServiceManager; -import org.apache.cocoon.ProcessingException; -import org.apache.cocoon.environment.ObjectModelHelper; -import org.apache.cocoon.environment.Request; -import org.apache.cocoon.xml.AttributesImpl; -import org.apache.cocoon.xml.XMLUtils; -import org.apache.commons.lang.StringUtils; -import org.xml.sax.SAXException; - -import org.ametys.cms.repository.Content; -import org.ametys.plugins.repository.AmetysObjectResolver; -import org.ametys.plugins.repository.AmetysRepositoryException; -import org.ametys.runtime.right.RightsManager; -import org.ametys.runtime.right.RightsManager.RightResult; -import org.ametys.runtime.util.I18nizableText; -import org.ametys.runtime.util.cocoon.CurrentUserProviderServiceableGenerator; -import org.ametys.web.repository.page.Page; -import org.ametys.web.tags.Tag; -import org.ametys.web.tags.Tag.TagTarget; -import org.ametys.web.tags.Tag.TagVisibility; -import org.ametys.web.tags.TagCategory; -import org.ametys.web.tags.TagProvider; -import org.ametys.web.tags.TagProviderExtensionPoint; -import org.ametys.web.tags.jcr.JCRTagProvider; - -/** - * This class SAXes the tags and categories - * - */ -public class TagCategoriesAndTagsGenerator extends CurrentUserProviderServiceableGenerator -{ - /** The {@link TagProviderExtensionPoint} */ - protected TagProviderExtensionPoint _tagProviderExtPt; - /** The rights manager. */ - protected RightsManager _rightsManager; - /** The ametys resolver. */ - protected AmetysObjectResolver _ametysResolver; - private boolean _all; - - @Override - public void service(ServiceManager serviceManager) throws ServiceException - { - super.service(serviceManager); - _tagProviderExtPt = (TagProviderExtensionPoint) serviceManager.lookup(TagProviderExtensionPoint.ROLE); - _rightsManager = (RightsManager) serviceManager.lookup(RightsManager.ROLE); - _ametysResolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); - } - - @Override - public void generate() throws IOException, SAXException, ProcessingException - { - Request request = ObjectModelHelper.getRequest(objectModel); - String parentID = request.getParameter("parentID"); - String siteName = request.getParameter("siteName"); - String contentId = request.getParameter("content"); - String pageId = request.getParameter("page"); - - Content content = StringUtils.isBlank(contentId) ? null : (Content) _ametysResolver.resolveById(contentId); - Page page = StringUtils.isBlank(pageId) ? null : (Page) _ametysResolver.resolveById(pageId); - - _all = request.getParameter("all") != null ? Boolean.valueOf(request.getParameter("all")) : false; - - Set forcedProviderIds = new HashSet(); - String[] forceProvidersArr = request.getParameterValues("forceProvider"); - if (forceProvidersArr != null) - { - forcedProviderIds.addAll(Arrays.asList(forceProvidersArr)); - } - - contentHandler.startDocument(); - - if (StringUtils.isEmpty(parentID)) - { - _saxRoot(siteName, page, content, forcedProviderIds); - } - else if (parentID.startsWith("provider_")) - { - _saxProvider(parentID.substring("provider_".length()), siteName, page, content); - } - else - { - _saxCategory(parentID, siteName, page, content); - } - - contentHandler.endDocument(); - } - - /** - * SAX all categories. - * @param siteName the site name. - * @param page the current page (can be null). - * @param content the current content (can be null). - * @throws SAXException if an error occurs generating the XML. - */ - protected void _saxRoot(String siteName, Page page, Content content) throws SAXException - { - _saxRoot(siteName, page, content, Collections.emptySet()); - } - - /** - * SAX all categories. - * @param siteName the site name. - * @param page the current page (can be null). - * @param content the current content (can be null). - * @param forcedProviderIds - * @throws SAXException if an error occurs generating the XML. - */ - protected void _saxRoot(String siteName, Page page, Content content, Set forcedProviderIds) throws SAXException - { - Set extensionsIds = _tagProviderExtPt.getExtensionsIds(); - XMLUtils.startElement(contentHandler, "tags"); - - for (String id : extensionsIds) - { - TagProvider tagProvider = _tagProviderExtPt.getExtension(id); - - AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", "provider_" + id); - - Map categories = tagProvider.getTagCategories(siteName); - Map tags = tagProvider.getTags(siteName); - - if ((categories != null && categories.size() > 0) || (tags != null && tags.size() > 0)) - { - attr.addAttribute("", "hasChild", "hasChild", "CDATA", "true"); - } - if (forcedProviderIds.contains(id)) - { - attr.addCDATAAttribute("forceDisplay", "true"); - } - if (tagProvider instanceof JCRTagProvider && siteName != null) - { - try - { - JCRTagProvider jcrProvider = (JCRTagProvider) tagProvider; - attr.addAttribute("", "objectId", "objectId", "CDATA", jcrProvider.getRootNode(siteName).getId()); - } - catch (RepositoryException e) - { - throw new AmetysRepositoryException("Unable to get the JCR provider root node for site " + siteName, e); - } - } - XMLUtils.startElement(contentHandler, "tagprovider", attr); - - - I18nizableText label = tagProvider.getLabel(); - I18nizableText description = tagProvider.getDescription(); - - XMLUtils.startElement(contentHandler, "title"); - label.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "title"); - - XMLUtils.startElement(contentHandler, "description"); - description.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "description"); - - if (_all) - { - _saxAll(tagProvider, siteName, page, content); - } - - XMLUtils.endElement(contentHandler, "tagprovider"); - } - XMLUtils.endElement(contentHandler, "tags"); - } - - /** - * SAX a provider's categories and tags. - * @param providerId the provider ID. - * @param siteName the site name. - * @param page the current page (can be null). - * @param content the current content (can be null). - * @throws SAXException if an error occurs generating the XML. - */ - protected void _saxProvider(String providerId, String siteName, Page page, Content content) throws SAXException - { - TagProvider tagProvider = _tagProviderExtPt.getExtension(providerId); - Map tagCategories = tagProvider.getTagCategories(siteName); - if (tagCategories != null) - { - XMLUtils.startElement(contentHandler, "tags"); - for (TagCategory tagCategory : tagCategories.values()) - { - saxCategory(tagCategory, true, page, content); - } - XMLUtils.endElement(contentHandler, "tags"); - } - } - - /** - * SAX a category and its tags. - * @param categoryId the category ID. - * @param siteName the site name. - * @param page the current page (can be null). - * @param content the current content (can be null). - * @throws SAXException if an error occurs generating the XML. - */ - protected void _saxCategory(String categoryId, String siteName, Page page, Content content) throws SAXException - { - Set extensionsIds = _tagProviderExtPt.getExtensionsIds(); - for (String id : extensionsIds) - { - TagProvider tagProvider = _tagProviderExtPt.getExtension(id); - if (tagProvider.hasCategory(siteName, categoryId)) - { - saxCategory(tagProvider.getTagCategory(siteName, categoryId), true, page, content); - } - } - } - - private void _saxAll(TagProvider tagProvider, String siteName, Page page, Content content) throws SAXException - { - Map tagCategories = tagProvider.getTagCategories(siteName); - if (tagCategories != null) - { - for (TagCategory tagCategory : tagCategories.values()) - { - saxCategory(tagCategory, true, page, content); - } - } - - Map tags = tagProvider.getTags(siteName); - if (tags != null) - { - for (Tag tag : tags.values()) - { - saxTag(tag, isUserAuthorized(tag, page, content)); - } - } - } - - /** - * Sax a tag category - * @param category The category to sax - * @param children true to sax children - * @throws SAXException If an error occurred while saxing - */ - protected void saxCategory (TagCategory category, boolean children) throws SAXException - { - saxCategory(category, children, null, null); - } - - /** - * Sax a tag category - * @param category The category to sax - * @param children true to sax children - * @param page the current page (can be null). - * @param content the current content (can be null). - * @throws SAXException If an error occurred while saxing - */ - protected void saxCategory (TagCategory category, boolean children, Page page, Content content) throws SAXException - { - I18nizableText title = category.getTitle(); - I18nizableText description = category.getDescription(); - - AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", category.getId()); - if ((category.getCategories() != null && category.getCategories().size() > 0) || (category.getTags() != null && category.getTags().size() > 0)) - { - attr.addAttribute("", "hasChild", "hasChild", "CDATA", "true"); - } - XMLUtils.startElement(contentHandler, "category", attr); - - XMLUtils.startElement(contentHandler, "title"); - title.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "title"); - - XMLUtils.startElement(contentHandler, "description"); - description.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "description"); - - - - Map subCategories = category.getCategories(); - if (subCategories != null) - { - for (TagCategory subCategory : subCategories.values()) - { - saxCategory (subCategory, _all, page, content); - } - } - - Map tags = category.getTags(); - if (tags != null) - { - for (Tag tag : tags.values()) - { - saxTag (tag, isUserAuthorized(tag, page, content)); - } - } - XMLUtils.endElement(contentHandler, "category"); - } - - /** - * SAX a tag - * @param tag The tag to SAX - * @param authorized true if user is authorized to assign tag - * @throws SAXException If an error occurred while SAXing - */ - protected void saxTag (Tag tag, boolean authorized) throws SAXException - { - I18nizableText title = tag.getTitle(); - I18nizableText description = tag.getDescription(); - - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute("", "id", "id", "CDATA", tag.getId()); - attrs.addAttribute("", "name", "name", "CDATA", tag.getName()); - attrs.addAttribute("", "target", "target", "CDATA", tag.getTarget() != null ? tag.getTarget().toString() : TagTarget.CONTENT.toString()); - attrs.addAttribute("", "authorized", "authorized", "CDATA", String.valueOf(authorized)); - attrs.addAttribute("", "visibility", "visibility", "CDATA", tag.getVisibility() != null ? tag.getVisibility().toString() : TagVisibility.PUBLIC.toString()); - XMLUtils.startElement(contentHandler, "tag", attrs); - - XMLUtils.startElement(contentHandler, "title"); - title.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "title"); - - XMLUtils.startElement(contentHandler, "description"); - description.toSAX(contentHandler); - XMLUtils.endElement(contentHandler, "description"); - - XMLUtils.endElement(contentHandler, "tag"); - } - - /** - * Determines if a tag is private - * @param tag the tag to test - * @return true if a tag is private - */ - protected boolean isPrivate (Tag tag) - { - return tag.getVisibility() == TagVisibility.PRIVATE; - } - - /** - * Test if a tag is visible to the current user. - * @param tag the Tag object. - * @param page the current page (can be null). - * @param content the current content (can be null). - * @return true if the user has access to the tag, false otherwise. - */ - protected boolean isUserAuthorized(Tag tag, Page page, Content content) - { - if (!isPrivate(tag)) - { - return true; - } - - if (content != null && tag.getTarget() == TagTarget.CONTENT) - { - String context = _getContentContext(content); - return _rightsManager.hasRight(_getCurrentUser(), "Web_Rights_Content_Private_Tag", context) == RightResult.RIGHT_OK; - } - - if (page != null && tag.getTarget() == TagTarget.PAGE) - { - String context = "/pages/" + page.getSitemapName() + "/" + page.getPathInSitemap(); - return _rightsManager.hasRight(_getCurrentUser(), "Web_Rights_Page_Private_Tag", context) == RightResult.RIGHT_OK; - } - - return true; - } - - /** - * Get a content's context. - * @param content the content. - * @return the content rights context. - */ - protected String _getContentContext(Content content) - { - String context = ""; - if (content != null) - { - context = "/contents/" + content.getName(); - } - - return context; - } -} Index: main/plugin-web/src/org/ametys/web/tags/Tag.java =================================================================== --- main/plugin-web/src/org/ametys/web/tags/Tag.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/tags/Tag.java (working copy) @@ -15,6 +15,8 @@ */ package org.ametys.web.tags; +import java.util.HashMap; +import java.util.Map; import java.util.regex.Pattern; import org.ametys.plugins.repository.AmetysRepositoryException; @@ -35,7 +37,8 @@ private I18nizableText _description; private TagTarget _target; private TagVisibility _visibility; - private String _parentId; + private Map _tags; + private Tag _parent; /** Tag type. */ public enum TagTarget @@ -68,31 +71,31 @@ * Constructor * @param id The id of the tag. The id must be unique. * @param name The name of the tag. The name must be unique. The name is the same as the id except for JCR tag. - * @param parentId The parent category id + * @param parent The parent tag (can be null if the tag has no parent) * @param title the tag title * @param description the tag description * @param type the tag type */ - public Tag(String id, String name, String parentId, I18nizableText title, I18nizableText description, TagTarget type) + public Tag(String id, String name, Tag parent, I18nizableText title, I18nizableText description, TagTarget type) { - this(id, name, parentId, title, description, type, TagVisibility.PUBLIC); + this(id, name, parent, title, description, type, TagVisibility.PUBLIC); } /** * Constructor * @param id The id of the tag. The id must be unique. * @param name The name of the tag. The name must be unique. The name is the same as the id except for JCR tag. - * @param parentId The parent category id + * @param parent The parent tag (can be null if the tag has no parent) * @param title the tag title * @param description the tag description * @param type the tag type * @param visibility the tag visibility. */ - public Tag(String id, String name, String parentId, I18nizableText title, I18nizableText description, TagTarget type, TagVisibility visibility) + public Tag(String id, String name, Tag parent, I18nizableText title, I18nizableText description, TagTarget type, TagVisibility visibility) { _id = id; _name = name; - _parentId = parentId; + _parent = parent; _title = title; _description = description; _target = type; @@ -110,8 +113,8 @@ } /** - * Get the tag unique id. - * @return The unique id + * Get the tag name. + * @return The tag name */ public String getName () { @@ -119,12 +122,21 @@ } /** - * Get the parent id. - * @return The parent id. + * Get the parent name. + * @return The parent name. + */ + public String getParentName() + { + return _parent != null ? _parent.getName() : null; + } + + /** + * Get the parent tag + * @return The parent tag or null if the tag has no parent. */ - public String getParentId () + public Tag getParent() { - return _parentId; + return _parent; } /** @@ -199,4 +211,71 @@ { _visibility = visibility; } + + /** + * Add a new child tag. + * @param tag The tag to add + */ + public void addTag(Tag tag) + { + if (_tags == null) + { + _tags = new HashMap(); + } + + _tags.put(tag.getId(), tag); + } + + /** + * Set the child tags + * @param tags The Map of Tag to set + */ + public void setTags(Map tags) + { + _tags = tags; + } + + /** + * Retrieves the Set of child tags + * @return The child tags in a Map + */ + public Map getTags() + { + if (_tags == null) + { + _tags = new HashMap(); + } + + return _tags; + } + + /** + * Try to get a child tag by its id + * @param tagId The id of the child tag + * @return The child tag or null if not existing + */ + public Tag getTag(String tagId) + { + if (_tags == null) + { + _tags = new HashMap(); + } + + return _tags.get(tagId); + } + + /** + * Determines if a tag exists + * @param tagId The tag id + * @return true if the tag exists + */ + public boolean hasTag(String tagId) + { + if (_tags == null) + { + _tags = new HashMap(); + } + + return _tags.containsKey(tagId); + } } Index: main/plugin-web/src/org/ametys/web/cache/service/FilteredContentsServiceCachePolicy.java =================================================================== --- main/plugin-web/src/org/ametys/web/cache/service/FilteredContentsServiceCachePolicy.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/cache/service/FilteredContentsServiceCachePolicy.java (working copy) @@ -52,7 +52,9 @@ ObservationConstants.PAGE_CHANGED, ObservationConstants.PAGE_MOVED, ObservationConstants.PAGE_DELETED, - ObservationConstants.ZONEITEM_DELETED); + ObservationConstants.ZONEITEM_DELETED, + ObservationConstants.TAG_ADDED, + ObservationConstants.TAG_DELETED); } else if ("live".equals(workspace)) { @@ -64,7 +66,9 @@ ObservationConstants.PAGE_CHANGED, ObservationConstants.PAGE_MOVED, ObservationConstants.PAGE_DELETED, - ObservationConstants.ZONEITEM_DELETED); + ObservationConstants.ZONEITEM_DELETED, + ObservationConstants.TAG_ADDED, + ObservationConstants.TAG_DELETED); } return Collections.emptyList(); Index: main/plugin-web/src/org/ametys/web/transformation/xslt/AmetysXSLTHelper.java =================================================================== --- main/plugin-web/src/org/ametys/web/transformation/xslt/AmetysXSLTHelper.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/transformation/xslt/AmetysXSLTHelper.java (working copy) @@ -77,7 +77,6 @@ import org.ametys.web.repository.tag.TagAwareAmetysObject; import org.ametys.web.site.SiteConfigurationExtensionPoint; import org.ametys.web.tags.Tag; -import org.ametys.web.tags.TagCategory; import org.ametys.web.tags.TagProviderExtensionPoint; /** @@ -870,61 +869,15 @@ } /** - * Get the id of a tag category + * Get the name of the parent of a tag. * @param siteName * @param tagName * @return The id or empty */ - public static String tagCategory(String siteName, String tagName) + public static String tagParent(String siteName, String tagName) { Tag tag = _tagProviderExtPt.getTag(siteName, tagName); - if (tag == null) - { - return ""; - } - else - { - return tag.getParentId(); - } - } - - /** - * Get the label of a tag category - * @param siteName the current site - * @param lang the lang (if i18n tag) - * @param categoryId the category id - * @return the label of the category or empty if it cannot be found - */ - public static String tagCategoryLabel(String siteName, String lang, String categoryId) - { - TagCategory tagCategory = _tagProviderExtPt.getCategory(siteName, categoryId); - if (tagCategory == null) - { - return ""; - } - else - { - return _i18nUtils.translate(tagCategory.getTitle(), lang); - } - } - - /** - * Get the id of a parent tag category - * @param siteName The site name - * @param categoryId The category id - * @return The id of parent category or empty. - */ - public static String tagCategoryParentCategory (String siteName, String categoryId) - { - TagCategory tagCategory = _tagProviderExtPt.getCategory(siteName, categoryId); - if (tagCategory == null) - { - return ""; - } - else - { - return tagCategory.getParentId() != null ? tagCategory.getParentId() : ""; - } + return tag != null ? tag.getParentName() : StringUtils.EMPTY; } /** Index: main/plugin-web/src/org/ametys/web/frontoffice/SearchServiceCachePolicy.java =================================================================== --- main/plugin-web/src/org/ametys/web/frontoffice/SearchServiceCachePolicy.java (revision 0) +++ main/plugin-web/src/org/ametys/web/frontoffice/SearchServiceCachePolicy.java (revision 0) @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Anyware Services + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.ametys.web.frontoffice; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.ametys.web.ObservationConstants; +import org.ametys.web.cache.pageelement.AbstractSimplePageElementCachePolicy; +import org.ametys.web.cache.pageelement.PageElementCachePolicy; + +/** + * {@link PageElementCachePolicy} for the front search service.
+ */ +public class SearchServiceCachePolicy extends AbstractSimplePageElementCachePolicy +{ + /** The front search service ID. */ + public static final String SERVICE_FRONT_SEARCH_ID = "org.ametys.web.service.FrontSearchService"; + + @Override + public Set getPageElementTypes() + { + return Collections.singleton("SERVICE:" + SERVICE_FRONT_SEARCH_ID); + } + + @Override + protected List _getRemovingCacheEventIds(String workspace) + { + if ("default".equals(workspace)) + { + return Arrays.asList(ObservationConstants.TAG_ADDED, + ObservationConstants.TAG_UPDATED, + ObservationConstants.TAG_DELETED); + } + else if ("live".equals(workspace)) + { + return Arrays.asList(ObservationConstants.TAG_ADDED, + ObservationConstants.TAG_UPDATED, + ObservationConstants.TAG_DELETED); + } + + return Collections.emptyList(); + } + +} Index: main/plugin-web/src/org/ametys/web/frontoffice/SearchGenerator.java =================================================================== --- main/plugin-web/src/org/ametys/web/frontoffice/SearchGenerator.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/frontoffice/SearchGenerator.java (working copy) @@ -55,7 +55,7 @@ import org.ametys.web.repository.page.Page; import org.ametys.web.repository.site.Site; import org.ametys.web.tags.Tag; -import org.ametys.web.tags.TagCategory; +import org.ametys.web.tags.Tag.TagTarget; import org.ametys.web.tags.TagProvider; /** @@ -252,6 +252,20 @@ { return new SortField("last-validation", SortField.STRING, true); } + else + { + // Generic sort field (with hardcorded descending order) + Enumeration paramNames = request.getParameterNames(); + while (paramNames.hasMoreElements()) + { + String param = (String) paramNames.nextElement(); + if (param.startsWith("sort-by-")) + { + String fieldName = StringUtils.removeStart(param, "sort-by-"); + return new SortField(fieldName, SortField.STRING, true); + } + } + } return SortField.FIELD_SCORE; } @@ -482,49 +496,63 @@ String searchByTags = parameters.getParameter("search-by-tags", ""); if (!"".equals(searchByTags)) { - String[] categories = searchByTags.split(","); + String[] tagArray = searchByTags.split(","); XMLUtils.startElement(contentHandler, "tags"); - for (String categoryID : categories) + for (String tagName : tagArray) { + boolean found = false; Set extensionsIds = _tagExtPt.getExtensionsIds(); + for (String id : extensionsIds) { + if (found) + { + continue; + } + + I18nizableText label = null; + Map tags = null; + TagProvider tagProvider = _tagExtPt.getExtension(id); - if (categoryID.startsWith("provider_") && id.equals(categoryID.substring("provider_".length()))) + if (tagName.startsWith("provider_") && id.equals(tagName.substring("provider_".length()))) { - AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", categoryID); - XMLUtils.startElement(contentHandler, "category", attr); + found = true; - tagProvider.getLabel().toSAX(contentHandler, "title"); - - Map tags = tagProvider.getTags(siteName); - for (Tag tag : tags.values()) - { - _saxTag (tag); - } + label = tagProvider.getLabel(); + tags = tagProvider.getTags(siteName); + } + else if (tagProvider.hasTag(siteName, tagName)) + { + found = true; - XMLUtils.endElement(contentHandler, "category"); + Tag tag = tagProvider.getTag(siteName, tagName); + label = tag.getTitle(); + tags = tag.getTags(); } - else if (tagProvider.hasCategory(siteName, categoryID)) + + if (found) { - TagCategory category = tagProvider.getTagCategory(siteName, categoryID); AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", categoryID); - XMLUtils.startElement(contentHandler, "category", attr); + attr.addCDATAAttribute("id", tagName); + XMLUtils.startElement(contentHandler, "tag", attr); - category.getTitle().toSAX(contentHandler, "title"); + if (label != null) + { + label.toSAX(contentHandler, "title"); + } - Map tags = category.getTags(); if (tags != null) { - for (Tag tag : tags.values()) + for (Tag child : tags.values()) { - _saxTag (tag); + if (child.getTarget().equals(TagTarget.CONTENT)) + { + _saxTag(child, true); + } } } - XMLUtils.endElement(contentHandler, "category"); + XMLUtils.endElement(contentHandler, "tag"); } } } @@ -532,12 +560,21 @@ } } - private void _saxTag (Tag tag) throws SAXException + private void _saxTag(Tag tag, boolean recursive) throws SAXException { AttributesImpl attr = new AttributesImpl(); - attr.addAttribute("", "id", "id", "CDATA", tag.getName()); + attr.addCDATAAttribute("id", tag.getName()); XMLUtils.startElement(contentHandler, "tag", attr); - tag.getTitle().toSAX(contentHandler); + tag.getTitle().toSAX(contentHandler, "title"); + + if (recursive) + { + for (Tag child : tag.getTags().values()) + { + _saxTag(child, true); + } + } + XMLUtils.endElement(contentHandler, "tag"); } @@ -732,6 +769,9 @@ String size = request.getParameter("tags-size"); if (!StringUtils.isEmpty(size)) { + boolean isStrictSearch = parameters.getParameterAsBoolean("strict-search-on-tags", true); + String fieldName = isStrictSearch ? "tags" : "tagsWithAutoposting"; + int nbCat = Integer.parseInt(size); for (int i = 1; i < nbCat + 1; i++) { @@ -746,7 +786,7 @@ String[] values = tag.split(","); for (String value : values) { - TermQuery termQuery = new TermQuery(new Term("tags", value)); + TermQuery termQuery = new TermQuery(new Term(fieldName, value)); tagQuery.add(termQuery, BooleanClause.Occur.SHOULD); } } Index: main/plugin-web/src/org/ametys/web/filter/StaticWebContentFilter.java =================================================================== --- main/plugin-web/src/org/ametys/web/filter/StaticWebContentFilter.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/filter/StaticWebContentFilter.java (working copy) @@ -41,6 +41,7 @@ import org.ametys.runtime.plugin.component.PluginAware; import org.ametys.runtime.util.I18nizableText; import org.ametys.web.repository.site.SiteManager; +import org.ametys.web.tags.TagProviderExtensionPoint; /** * This class represents a static filter for contents @@ -67,10 +68,11 @@ * @param id The filter id * @param resolver The ametys object resolver * @param siteManager The site manager + * @param tagProviderEP The tag provider */ - public StaticWebContentFilter(String id, AmetysObjectResolver resolver, SiteManager siteManager) + public StaticWebContentFilter(String id, AmetysObjectResolver resolver, SiteManager siteManager, TagProviderExtensionPoint tagProviderEP) { - super(id, resolver, siteManager); + super(id, resolver, siteManager, tagProviderEP); } @Override @@ -178,6 +180,7 @@ params.addTag(tag.getAttribute("key")); } Condition condition = Condition.valueOf(tagsConf.getAttribute("condition", "AND").toUpperCase()); + boolean strict = tagsConf.getAttributeAsBoolean("strict", true); Context context = _configureContext(configuration.getChild("context", true)); ContextLanguage contextLang = _configureContextLanguage(configuration.getChild("context", true)); int depth = _configureDepth(configuration.getChild("context", true)); @@ -186,6 +189,7 @@ params.setContextLanguage(contextLang); params.setDepth(depth); params.setTagsCondition(condition); + params.setTagsAutoPosting(!strict); } /** Index: main/plugin-web/src/org/ametys/web/filter/WebContentFilter.java =================================================================== --- main/plugin-web/src/org/ametys/web/filter/WebContentFilter.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/filter/WebContentFilter.java (working copy) @@ -251,6 +251,12 @@ public Condition getTagsCondition(); /** + * Is the tag auto posting enabled? + * @return true if it is + */ + public boolean getTagsAutoPosting(); + + /** * Add a tag to the filter * @param tag The tag key to add */ @@ -263,6 +269,12 @@ public void setTagsCondition(Condition condition); /** + * Enable/disable the tag autoposting feature. + * @param enable True to enable the autposting, false to remains in strict match mode. + */ + public void setTagsAutoPosting(boolean enable); + + /** * Get the Expression. * @param siteName * @param language @@ -272,8 +284,9 @@ /** * Get the expression corresponding to the filter's tags + * @param siteName The current site name * @return The expression corresponding to the filter's tags */ - public Expression getTagsExpression(); + public Expression getTagsExpression(String siteName); } } Index: main/plugin-web/src/org/ametys/web/filter/DefaultWebContentFilter.java =================================================================== --- main/plugin-web/src/org/ametys/web/filter/DefaultWebContentFilter.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/filter/DefaultWebContentFilter.java (working copy) @@ -22,6 +22,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Set; import javax.jcr.Node; import javax.jcr.Property; @@ -57,14 +58,17 @@ import org.ametys.web.repository.page.Page; import org.ametys.web.repository.site.Site; import org.ametys.web.repository.site.SiteManager; +import org.ametys.web.tags.Tag; import org.ametys.web.tags.TagExpression; +import org.ametys.web.tags.TagExpression.LogicalOperator; +import org.ametys.web.tags.TagHelper; +import org.ametys.web.tags.TagProviderExtensionPoint; /** * This is the default implementation of a {@Filter}. The filter's property are set by setter function and constructor */ public class DefaultWebContentFilter extends DefaultContentFilter implements WebContentFilter { - /** The search contexts. */ protected List _searchContexts; @@ -80,7 +84,8 @@ protected Logger _logger = LoggerFactory.getLoggerFor(this.getClass()); /** The site manager */ protected SiteManager _siteManager; - + /** The tag provider */ + protected TagProviderExtensionPoint _tagProviderEP; /** * Constructor @@ -96,11 +101,13 @@ * @param id The filter unique identifier * @param resolver The ametys object resolver * @param siteManager The site manager + * @param tagProviderEP The tag provider */ - public DefaultWebContentFilter(String id, AmetysObjectResolver resolver, SiteManager siteManager) + public DefaultWebContentFilter(String id, AmetysObjectResolver resolver, SiteManager siteManager, TagProviderExtensionPoint tagProviderEP) { super(id, resolver); _siteManager = siteManager; + _tagProviderEP = tagProviderEP; _searchContexts = new ArrayList(); } @@ -254,7 +261,7 @@ } else if (context.equals(Context.CHILD_PAGES) && (depth == 0 || depth == 1)) { - xpathQuery = getXPathQuery(page, depth, filterContext); + xpathQuery = getXPathQuery(siteName, page, depth, filterContext); contents = _resolver.query(xpathQuery); } else if (context.equals(Context.CHILD_PAGES)) @@ -262,7 +269,7 @@ List> itList = new ArrayList>(); for (int i = 1; i <= depth; i++) { - xpathQuery = getXPathQuery(page, i, filterContext); + xpathQuery = getXPathQuery(siteName, page, i, filterContext); AmetysObjectIterable it = _resolver.query(xpathQuery); itList.add(it); } @@ -307,12 +314,13 @@ /** * Creates the XPath query corresponding to specified {@link Page}, {@link Expression} and {@link SortCriteria}. + * @param siteName The current site name * @param page The page where to start the search * @param depth the search depth * @param filterContext the filter search context. * @return the created XPath query */ - protected String getXPathQuery(Page page, int depth, FilterSearchContext filterContext) + protected String getXPathQuery(String siteName, Page page, int depth, FilterSearchContext filterContext) { String depthPath = ""; if (depth == 0) @@ -332,7 +340,7 @@ } // Build the content expression - Expression expr = getFilterExpression(filterContext); + Expression expr = getFilterExpression(siteName, filterContext); String xpath = "//element(" + page.getSite().getName() + ", ametys:site)/ametys-internal:sitemaps/" + _encode(page.getSitemap().getName()) + "/" + page.getPathInSitemap() @@ -345,14 +353,15 @@ /** * Get the filter expression for a given search context. + * @param siteName The current site name * @param filterContext the filter search context. * @return the filter expression. */ - protected Expression getFilterExpression(FilterSearchContext filterContext) + protected Expression getFilterExpression(String siteName, FilterSearchContext filterContext) { Expression expr = super.getFilterExpression(); - Expression tagExpr = filterContext.getTagsExpression(); + Expression tagExpr = filterContext.getTagsExpression(siteName); if (tagExpr != null) { expr = expr != null ? new AndExpression(expr, tagExpr) : tagExpr; @@ -388,6 +397,8 @@ protected List _tags; /** The tags condition*/ protected Condition _tagsCondition; + /** The tags auto posting */ + protected boolean _tagsAutoPosting; /** The context for search */ protected Context _context; /** The list of sites to match*/ @@ -432,6 +443,12 @@ } @Override + public boolean getTagsAutoPosting() + { + return _tagsAutoPosting; + } + + @Override public Context getContext() { return _context; @@ -456,6 +473,12 @@ } @Override + public void setTagsAutoPosting(boolean enable) + { + _tagsAutoPosting = enable; + } + + @Override public void setContext(Context context) { _context = context; @@ -508,7 +531,7 @@ exprs.add(sharedExpr); } - Expression tagExpr = getTagsExpression(); + Expression tagExpr = getTagsExpression(siteName); if (tagExpr != null) { exprs.add(tagExpr); @@ -520,14 +543,26 @@ } @Override - public Expression getTagsExpression() + public Expression getTagsExpression(String siteName) { if (_tags != null && _tags.size() > 0) { List tagsExpr = new ArrayList(); - for (String tag : _tags) + for (String tagName : _tags) { - tagsExpr.add(new TagExpression(Operator.EQ, tag)); + if (_tagsAutoPosting) + { + Tag tag = _getTag(siteName, tagName); + if (tag != null) + { + Set descendantNames = TagHelper.getDescendantNames(tag, true); + tagsExpr.add(new TagExpression(Operator.EQ, descendantNames.toArray(new String[descendantNames.size()]), LogicalOperator.OR)); + } + } + else + { + tagsExpr.add(new TagExpression(Operator.EQ, tagName)); + } } if (_tagsCondition == Condition.OR) @@ -544,6 +579,40 @@ } /** + * Internal tag getter given the search context + * @param currentSiteName The name of the current site + * @param tagName the name of the tag + * @return The tag or null + */ + protected Tag _getTag(String currentSiteName, String tagName) + { + Tag tag = null; + + switch (_context) + { + case CURRENT_SITE: + case CHILD_PAGES: + tag = _tagProviderEP.getTag(currentSiteName, tagName); + break; + case SITES_LIST: + if (_sites != null && _sites.size() == 1) + { + tag = _tagProviderEP.getTag(_sites.get(0), tagName); + } + break; + case SITES: + case OTHER_SITES: + tag = _tagProviderEP.getTag(null, tagName); + break; + default: + // nothing + break; + } + + return tag; + } + + /** * Get the {@link Expression} associated with the given site context * @param siteName The current site name * @return a {@link Expression} associated with the given site context Index: main/plugin-web/src/org/ametys/web/contenttype/WebContentIndexer.java =================================================================== --- main/plugin-web/src/org/ametys/web/contenttype/WebContentIndexer.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/contenttype/WebContentIndexer.java (working copy) @@ -15,10 +15,13 @@ */ package org.ametys.web.contenttype; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; +import org.apache.commons.lang.StringUtils; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.Field.Index; @@ -27,18 +30,25 @@ import org.ametys.cms.contenttype.DefaultContentIndexer; import org.ametys.cms.repository.Content; import org.ametys.plugins.explorer.resources.ResourceCollection; +import org.ametys.runtime.util.I18nUtils; import org.ametys.web.lucene.FieldNames; import org.ametys.web.lucene.ResourceIndexer; import org.ametys.web.lucene.WebMetadataIndexer; import org.ametys.web.repository.content.WebContent; import org.ametys.web.repository.page.Page; +import org.ametys.web.repository.site.SiteManager; import org.ametys.web.repository.tag.TagAwareAmetysObject; +import org.ametys.web.site.SiteConfigurationExtensionPoint; +import org.ametys.web.tags.Tag; +import org.ametys.web.tags.TagHelper; +import org.ametys.web.tags.TagProviderExtensionPoint; /** * The web content indexer. */ public class WebContentIndexer extends DefaultContentIndexer { + /** The avalon role. */ @SuppressWarnings("hiding") public static final String ROLE = WebContentIndexer.class.getName(); @@ -46,12 +56,28 @@ /** The resource indexer. */ protected ResourceIndexer _resourceIndexer; + /** The tag provider extension point */ + protected TagProviderExtensionPoint _tagProviderEP; + + /** The site manager */ + protected SiteManager _siteManager; + + /** I18n utils */ + protected I18nUtils _i18nUtils; + + /** The site configuration extension point */ + protected SiteConfigurationExtensionPoint _scep; + @Override public void service(ServiceManager manager) throws ServiceException { super.service(manager); _resourceIndexer = (ResourceIndexer) manager.lookup(ResourceIndexer.ROLE); _metadataIndexer = (WebMetadataIndexer) manager.lookup(WebMetadataIndexer.ROLE); + _tagProviderEP = (TagProviderExtensionPoint) manager.lookup(TagProviderExtensionPoint.ROLE); + _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); + _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); + _scep = (SiteConfigurationExtensionPoint) manager.lookup(SiteConfigurationExtensionPoint.ROLE); } @Override @@ -59,19 +85,18 @@ { super.indexContent(content, document, parameters); - // Content tags - if (content instanceof TagAwareAmetysObject) - { - for (String tag : ((TagAwareAmetysObject) content).getTags()) - { - document.add(new Field(FieldNames.TAGS, tag, Store.NO, Index.NOT_ANALYZED)); - } - } + String siteName = null; if (content instanceof WebContent) { WebContent webContent = (WebContent) content; + siteName = webContent.getSiteName(); + if (!_siteManager.hasSite(siteName)) + { + siteName = null; + } + Page page = (Page) parameters.get("page"); if (page != null) { @@ -82,6 +107,64 @@ } } } + + // Content tags + if (content instanceof TagAwareAmetysObject) + { + Set tagsWithAutposting = new HashSet(); + + for (String tagName : ((TagAwareAmetysObject) content).getTags()) + { + document.add(new Field(FieldNames.TAGS, tagName, Store.NO, Index.NOT_ANALYZED)); + + if (!tagsWithAutposting.contains(tagName)) + { + document.add(new Field(FieldNames.TAGS_WITH_AUTOPOSTING, tagName, Store.NO, Index.NOT_ANALYZED)); + tagsWithAutposting.add(tagName); + } + + Tag tag = _tagProviderEP.getTag(siteName, tagName); + if (tag != null) + { + // plain text + autocompletion + String title = _i18nUtils.translate(tag.getTitle()); + document.add(new Field(org.ametys.cms.lucene.FieldNames.FULL, title, Store.NO, Index.ANALYZED)); + String[] words = StringUtils.split(title); + for (String word : words) + { + document.add(new Field(org.ametys.cms.lucene.FieldNames.ALL_NOT_ANALYZED, StringUtils.strip(word, ",?!:()[].{}=").toLowerCase(), Store.NO, Index.NOT_ANALYZED)); + } + } + + // Ancestors + Set ancestors = TagHelper.getAncestors(tag, true); + boolean autoposting = siteName != null ? _scep.getValueAsBoolean(siteName, "autoposting") : false; + + for (Tag ancestor : ancestors) + { + String ancestorName = ancestor.getName(); + if (!tagsWithAutposting.contains(ancestorName)) + { + // Autoposting + document.add(new Field(FieldNames.TAGS_WITH_AUTOPOSTING, ancestorName, Store.NO, Index.NOT_ANALYZED)); + + // Plain text + autocompletion on ancestors + if (autoposting) + { + String title = _i18nUtils.translate(ancestor.getTitle()); + document.add(new Field(org.ametys.cms.lucene.FieldNames.FULL, title, Store.NO, Index.ANALYZED)); + String[] words = StringUtils.split(title); + for (String word : words) + { + document.add(new Field(org.ametys.cms.lucene.FieldNames.ALL_NOT_ANALYZED, StringUtils.strip(word, ",?!:()[].{}=").toLowerCase(), Store.NO, Index.NOT_ANALYZED)); + } + } + + tagsWithAutposting.add(tagName); + } + } + } + } } } Index: main/plugin-web/src/org/ametys/web/site/ConfigureSiteAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/site/ConfigureSiteAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/site/ConfigureSiteAction.java (working copy) @@ -75,10 +75,11 @@ Site site = _resolver.resolveById(siteId); String siteName = site.getName(); + // Site updating event + _observationManager.notify(new Event("admin", ObservationConstants.SITE_UPDATING, site)); + _setParameters(site, request); - _observationManager.notify(new Event("admin", ObservationConstants.SITE_UPDATED, site)); - ArrayList codes = new ArrayList(); for (int i = 0; i < languages.length; i++) { @@ -111,6 +112,9 @@ // Reload this site's configuration. _siteConfiguration.reloadConfiguration(siteName); + // Site updated event + _observationManager.notify(new Event("admin", ObservationConstants.SITE_UPDATED, site)); + clearCache(site); Map result = new HashMap(); Index: main/plugin-web/src/org/ametys/web/repository/page/actions/SetFilterInRequestAttributesAction.java =================================================================== --- main/plugin-web/src/org/ametys/web/repository/page/actions/SetFilterInRequestAttributesAction.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/repository/page/actions/SetFilterInRequestAttributesAction.java (working copy) @@ -63,6 +63,7 @@ import org.ametys.web.service.Service; import org.ametys.web.service.ServiceExtensionPoint; import org.ametys.web.service.ServiceParameter; +import org.ametys.web.tags.TagProviderExtensionPoint; /** * This action creates a filter from the sitemap parameters or request parameter 'filterId' and set the filter in request attributes. @@ -93,6 +94,7 @@ private ContentFilterExtensionPoint _filterExtPt; private ServiceExtensionPoint _serviceEP; private SiteManager _siteManager; + private TagProviderExtensionPoint _tagProviderEP; @Override public void service(ServiceManager smanager) throws ServiceException @@ -102,6 +104,7 @@ _filterExtPt = (ContentFilterExtensionPoint) smanager.lookup(ContentFilterExtensionPoint.ROLE); _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); _serviceEP = (ServiceExtensionPoint) smanager.lookup(ServiceExtensionPoint.ROLE); + _tagProviderEP = (TagProviderExtensionPoint) smanager.lookup(TagProviderExtensionPoint.ROLE); } @Override @@ -148,7 +151,7 @@ protected WebContentFilter _getFilterFromParams(Parameters parameters, ZoneItem zoneItem, Map parentContextAttributes) { // Creates filter from sitemap parameters - WebContentFilter filter = _createFilter(null, _resolver, _siteManager); + WebContentFilter filter = _createFilter(null, _resolver, _siteManager, _tagProviderEP); try { @@ -325,7 +328,7 @@ */ protected WebContentFilter _getFilterFromZoneItem(ZoneItem zoneItem) throws ParameterException { - WebContentFilter filter = _createFilter(null, _resolver, _siteManager); + WebContentFilter filter = _createFilter(null, _resolver, _siteManager, _tagProviderEP); CompositeMetadata metadata = zoneItem.getServiceParameters(); @@ -388,11 +391,12 @@ * @param id the filter ID. * @param resolver the AmetysObjectResolver. * @param siteManager The site manager + * @param tagProviderEP The tag provider extension point * @return the WebContentFilter. */ - protected WebContentFilter _createFilter(String id, AmetysObjectResolver resolver, SiteManager siteManager) + protected WebContentFilter _createFilter(String id, AmetysObjectResolver resolver, SiteManager siteManager, TagProviderExtensionPoint tagProviderEP) { - return new DefaultWebContentFilter(id, resolver, siteManager); + return new DefaultWebContentFilter(id, resolver, siteManager, tagProviderEP); } /** @@ -453,6 +457,12 @@ filterContext.addTag(tag); } } + + if (parameters.isParameter("strict-search-on-tags")) + { + boolean strictSearchOnTags = parameters.getParameterAsBoolean("strict-search-on-tags"); + filterContext.setTagsAutoPosting(!strictSearchOnTags); + } } /** @@ -506,6 +516,12 @@ filterContext.addTag(tag); } } + + if (entry.containsKey("strict-search-on-tags")) + { + boolean strictSearchOnTags = Boolean.parseBoolean((String) entry.get("strict-search-on-tags")); + filterContext.setTagsAutoPosting(!strictSearchOnTags); + } } } } @@ -565,6 +581,12 @@ filterContext.addTag(tag); } } + + if (entryMeta.hasMetadata("strict-search-on-tags")) + { + boolean strictSearchOnTags = entryMeta.getBoolean("strict-search-on-tags"); + filterContext.setTagsAutoPosting(!strictSearchOnTags); + } } } } Index: main/plugin-web/src/org/ametys/web/repository/site/Site.java =================================================================== --- main/plugin-web/src/org/ametys/web/repository/site/Site.java (revision 26702) +++ main/plugin-web/src/org/ametys/web/repository/site/Site.java (working copy) @@ -18,7 +18,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Set; import javax.jcr.ItemExistsException; import javax.jcr.Node; @@ -27,6 +26,9 @@ import javax.jcr.PropertyIterator; import javax.jcr.RepositoryException; +import org.apache.cocoon.util.HashUtil; +import org.apache.commons.lang.StringUtils; + import org.ametys.cms.repository.Content; import org.ametys.cms.repository.ModifiableContent; import org.ametys.plugins.repository.AmetysObject; @@ -47,9 +49,6 @@ import org.ametys.plugins.repository.metadata.UnknownMetadataException; import org.ametys.web.pageaccess.RestrictedPagePolicy; import org.ametys.web.repository.sitemap.Sitemap; -import org.ametys.web.tags.TagCategory; -import org.apache.cocoon.util.HashUtil; -import org.apache.commons.lang.StringUtils; /** * {@link AmetysObject} for storing site informations. @@ -314,17 +313,6 @@ { return (ModifiableTraversableAmetysObject) getChild(__PLUGINS_NODE_NAME); } - - - /** - * Retrieves tag categories. - * @return the tag categories or an empty {@link AmetysObjectIterable}. - * @throws AmetysRepositoryException if an error occurs. - */ - public Set getTagCategories() throws AmetysRepositoryException - { - return null; - } /** * Set the skin id for this site. Index: main/plugin-web/sitemap-back.xmap =================================================================== --- main/plugin-web/sitemap-back.xmap (revision 26702) +++ main/plugin-web/sitemap-back.xmap (working copy) @@ -62,9 +62,8 @@ - - + @@ -134,9 +133,6 @@ - - - @@ -893,8 +889,8 @@ - - + + @@ -904,16 +900,8 @@ - - - - - - - - - - + + @@ -947,7 +935,7 @@ - + @@ -973,42 +961,6 @@ - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Index: main/workspace-web/src/org/ametys/web/repository/PageGenerator.java =================================================================== --- main/workspace-web/src/org/ametys/web/repository/PageGenerator.java (revision 26702) +++ main/workspace-web/src/org/ametys/web/repository/PageGenerator.java (working copy) @@ -195,9 +195,9 @@ { // tag may be null if it has been registered on the page and then removed from the application AttributesImpl tagattrs = new AttributesImpl(); - if (tag.getParentId() != null) + if (tag.getParentName() != null) { - tagattrs.addCDATAAttribute("parent", tag.getParentId()); + tagattrs.addCDATAAttribute("parent", tag.getParentName()); } XMLUtils.startElement(contentHandler, tagName, tagattrs);