Index: main/plugin-web/i18n/messages_en.xml
===================================================================
--- main/plugin-web/i18n/messages_en.xml	(revision 32549)
+++ main/plugin-web/i18n/messages_en.xml	(working copy)
@@ -213,6 +213,7 @@
 	<message key="PLUGINS_WEB_PAGE_DISALLOW_ROBOTS_CONFIRM">Do you really want to hide this page and all its sub-pages from search engine crawlers (Google, Yahoo, Bing...)</message>
 	<message key="PLUGINS_WEB_PAGE_ALLOW_ROBOTS_ERROR">An error occurred : the page(s) was (were) not made visible to search engines</message>
 	<message key="PLUGINS_WEB_PAGE_DISALLOW_ROBOTS_ERROR">An error occurred : the page(s) was (were) not excluded from search engines</message>
+    <message key="PLUGINS_WEB_PAGE_REFRESH_ROBOTS_ERROR">An error occurred while refreshing the referencing button.</message>
 
     <!-- **************************** -->
     <message key="PLUGINS_WEB_CREATEPAGE_CAPTION">Add a page ...</message>
Index: main/plugin-web/i18n/messages_fr.xml
===================================================================
--- main/plugin-web/i18n/messages_fr.xml	(revision 32549)
+++ main/plugin-web/i18n/messages_fr.xml	(working copy)
@@ -193,7 +193,7 @@
     <message key="PLUGINS_WEB_STORE_EXTERNAL_FILES_EXTENSIONS_INVALID">Vous devez entrer une liste d'extensions de fichier, sans le point (exemple : 'pdf,zip,7z,odt')</message>
 	
 	<message key="PLUGINS_WEB_UITOOL_SEO_ROBOTS_LABEL">Hors référencement</message>
-	<message key="PLUGINS_WEB_UITOOL_SEO_ROBOTS_DESC">Inclu ou exclu la ou les pages sélectionnées des fichiers de référencement (robots.txt et sitemap.xml)</message>
+	<message key="PLUGINS_WEB_UITOOL_SEO_ROBOTS_DESC">Inclure ou exclure la ou les pages sélectionnées des fichiers de référencement (robots.txt et sitemap.xml)</message>
 	<message key="PLUGINS_WEB_UITOOL_SEO_ROBOTS_FOOTER">Voir l'aide pour plus de détails</message>
 	<message key="PLUGINS_WEB_UITOOL_SEO_ROBOTS_START_DESC">La page ou les pages suivantes sont inclues dans les fichiers de référencement : </message>
 	<message key="PLUGINS_WEB_UITOOL_SEO_ROBOTS_PAGE">'{0}'</message>
@@ -213,6 +213,7 @@
 	<message key="PLUGINS_WEB_PAGE_DISALLOW_ROBOTS_CONFIRM">Etes-vous sûr de vouloir supprimer cette page et toutes ses sous-pages du référencement ?</message>
 	<message key="PLUGINS_WEB_PAGE_ALLOW_ROBOTS_ERROR">Une erreur est survenue : la ou les page(s) n'ont pas été inclues dans les fichiers de référencement.</message>
 	<message key="PLUGINS_WEB_PAGE_DISALLOW_ROBOTS_ERROR">Une erreur est survenue : la ou les page(s) n'ont pas été supprimées des fichiers de référencement.</message>
+	<message key="PLUGINS_WEB_PAGE_REFRESH_ROBOTS_ERROR">Une erreur est survenue lors du rafraîchissement du bouton de référencement.</message>

Index: main/plugin-web/plugin.xml
===================================================================
--- main/plugin-web/plugin.xml	(revision 32549)
+++ main/plugin-web/plugin.xml	(working copy)
@@ -3157,51 +3165,57 @@
 			</extension> -->
 			
 			<!-- Manage robots access -->
-    		<!-- <extension id="org.ametys.web.userinterface.Robots"
-					   point="org.ametys.core.ui.RibbonControlsManager" 
-					   class="org.ametys.web.clientsideelement.ToggleRobotsClientSideElement">
-				<action class="org.ametys.ribbon.control.button.ToggleRobotsActionButton">
-					<param name="action">org.ametys.web.tool.page.DisallowRobots.act</param>
-					<param name="target-type">^page$</param>
-
-					<param name="label" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_LABEL</param>
-					<param name="default-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_DESC</param>
-					<param name="footer" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_FOOTER</param>
-					
-					<param name="page-included-start-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_START_DESC</param>
-					<param name="page-included-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PAGE</param>
-					<param name="page-included-end-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_END_DESC</param>
-					
-					<param name="page-excluded-start-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXLUDED_START_DESC</param>
-					<param name="page-excluded-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXLUDED_PAGE</param>
-					<param name="page-excluded-end-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXLUDED_END_DESC</param>
-					
-					<param name="page-parent-excluded-start-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXLUDED_START_DESC</param>
-					<param name="page-parent-excluded-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXLUDED_PAGE</param>
-					<param name="page-parent-excluded-end-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXLUDED_END_DESC</param>
-					
-					<param name="page-exclude-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXCLUDE</param>
-					<param name="page-include-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_INCLUDE</param>
-					<param name="page-parent-exclude-description" i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXCLUDE</param>
-					
-					<param name="no-right-description" i18n="true">PLUGINS_WEB_UITOOL_PAGE_NORIGHT_DESC</param>
-					<param name="no-selection-description" i18n="true">PLUGINS_WEB_UITOOL_PAGE_NOSELECTION_DESC</param>
-					<param name="refresh-description" i18n="true">PLUGINS_WEB_UITOOL_PAGE_REFRESH_DESC</param>
-					
-					<param name="icon-small" file="true">img/seo/robots_16.png</param>
-					<param name="icon-medium" file="true">img/seo/robots_32.png</param>
-					<param name="icon-large" file="true">img/seo/robots_48.png</param>
-					
-					<param name="excluded-icon-small" file="true">img/seo/excluded_robots_16.png</param>
-					<param name="excluded-icon-medium" file="true">img/seo/excluded_robots_32.png</param>
-					<param name="excluded-icon-large" file="true">img/seo/excluded_robots_48.png</param>
-				</action>
-				<scripts>
-					<file>js/org/ametys/web/tool/page/Actions.js</file>
-					<file>js/org/ametys/ribbon/control/button/ToggleRobotsActionButton.js</file>
-				</scripts>
-				<right>Web_Rights_Page_SEO</right>
-			</extension> -->
+			<extension id="org.ametys.web.userinterface.Robots"  
+                       point="org.ametys.core.ui.RibbonControlsManager" 
+                       class="org.ametys.web.clientsideelement.ToggleRobotsClientSideElement">
+                 <class name="Ametys.plugins.web.page.controller.RobotsController">
+                    <action>Ametys.plugins.web.page.PageActions.disallowRobots</action>
+                    <selection-target-type>^page$</selection-target-type>
+                    <selection-target-parameter>
+                        <name>isModifiable</name>
+                        <value>true</value>
+                    </selection-target-parameter>
+                    
+                    <toggle-enabled>true</toggle-enabled>
+                    
+                    <label i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_LABEL</label>
+                    <description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_DESC</description>
+                    
+                    <page-included-start-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_START_DESC</page-included-start-description>
+                    <page-included-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PAGE</page-included-description>
+                    <page-included-end-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_END_DESC</page-included-end-description>
+                    
+                    <page-excluded-start-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXLUDED_START_DESC</page-excluded-start-description>
+                    <page-excluded-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXLUDED_PAGE</page-excluded-description>
+                    <page-excluded-end-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXLUDED_END_DESC</page-excluded-end-description>
+                    
+                    <page-parent-excluded-start-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXLUDED_START_DESC</page-parent-excluded-start-description>
+                    <page-parent-excluded-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXLUDED_PAGE</page-parent-excluded-description>
+                    <page-parent-excluded-end-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXLUDED_END_DESC</page-parent-excluded-end-description>
+                    
+                    <page-exclude-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_EXCLUDE</page-exclude-description>
+                    <page-include-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_INCLUDE</page-include-description>
+                    <page-parent-exclude-description i18n="true">PLUGINS_WEB_UITOOL_SEO_ROBOTS_PARENT_EXCLUDE</page-parent-exclude-description>
+                    
+                    <noright-page-description i18n="true">PLUGINS_WEB_UITOOL_PAGE_NORIGHT_DESC</noright-page-description>
+                    <selection-description-empty i18n="true">PLUGINS_WEB_UITOOL_PAGE_NOSELECTION_DESC</selection-description-empty>
+                    
+                    <rights>Web_Rights_Page_SEO</rights>
+                    
+                    <icon-small file="true">img/seo/robots_16.png</icon-small>
+                    <icon-medium file="true">img/seo/robots_32.png</icon-medium>
+                    <icon-large file="true">img/seo/robots_48.png</icon-large>
+                    
+                    <excluded-icon-small file="true">img/seo/excluded_robots_16.png</excluded-icon-small>
+                    <excluded-icon-medium file="true">img/seo/excluded_robots_32.png</excluded-icon-medium>
+                    <excluded-icon-large file="true">img/seo/excluded_robots_48.png</excluded-icon-large>
+                </class>
+                <scripts>
+                    <file>js/Ametys/plugins/web/page/PageActions.js</file>
+                    <file>js/Ametys/plugins/web/page/controller/RobotsController.js</file>
+                </scripts>
+                <right>Web_Rights_Page_SEO</right>
+            </extension> 
 			
 			<!-- Renommer une page -->
     		<!-- <extension id="org.ametys.web.userinterface.RenamePage"
 		
Index: main/plugin-web/resources/js/Ametys/plugins/web/page/PageActions.js
===================================================================
--- main/plugin-web/resources/js/Ametys/plugins/web/page/PageActions.js	(revision 32551)
+++ main/plugin-web/resources/js/Ametys/plugins/web/page/PageActions.js	(working copy)
@@ -343,4 +343,94 @@
 		}
 	},
 	
-});
\ No newline at end of file
+	/**********************************************************************************/
+	/************************************  ROBOTS  ************************************/
+	/**********************************************************************************/
+	
+	/**
+	 * Allows or disallows the selected pages for referencing
+	 * @param {Ametys.ribbon.element.ui.ButtonController} controller the controller calling this function
+	 */
+	disallowRobots: function(controller)
+	{
+		var me = this;
+		var allow = controller.isPressed();
+		var params = {};
+
+		// to check rights
+		params.allow = allow;
+		params.pages = allow ? controller._currentIncludedPagesId : controller._currentExcludedPagesId;
+
+		var text = allow ?  "<i18n:text i18n:key='PLUGINS_WEB_PAGE_ALLOW_ROBOTS_CONFIRM'/>" : "<i18n:text i18n:key='PLUGINS_WEB_PAGE_DISALLOW_ROBOTS_CONFIRM'/>";
+		
+		
+		Ametys.Msg.confirm("<i18n:text i18n:key='PLUGINS_WEB_PAGE_DISALLOW_ROBOTS_LABEL'/>",
+						   text,
+					   	   function (answer)
+					   	   {
+						   		if (answer == 'yes')
+					   			{
+						   			me._disallowRobots(params, controller);
+					   			}
+					   	   }
+		);
+	},
+	
+	/**
+	 * @private
+	 * Actual allowing/disallowing of the robots with a server call
+	 * @param {Object[]} params the parameters
+	 * @param {Boolean} params.allow true if the controller is pressed, false otherwise
+	 * @param {String[]} params.pages the pages currently included/excluded  
+     * @param {Ametys.ribbon.element.ui.ButtonController} controller the button controller
+	 */
+	_disallowRobots: function(params, controller)
+	{
+		controller.serverCall('disallowRobots',
+				[params.pages, params.allow], 
+				Ext.bind(this._disallowRobotsCb, this),
+				{ 
+					errorMessage: { 
+						msg: params.allow ? "<i18n:text i18n:key='PLUGINS_WEB_PAGE_ALLOW_ROBOTS_ERROR'/>" : "<i18n:text i18n:key='PLUGINS_WEB_PAGE_DISALLOW_ROBOTS_ERROR'/>", 
+						category: this.self.getName() 
+					},
+					arguments: {
+						pages: params.pages
+					}
+				},
+				true
+		);
+	},
+
+	/**
+	 * Callback for the robots allowing/disallowing process
+	 * @param {Object} response the server's response
+	 * @param {Object} args the callback arguments
+	 */
+	_disallowRobotsCb: function(response, args)
+	{
+		var pageIds = args.pages;
+		
+		var targets = [];
+		Ext.Array.each(pageIds, function (pageId) {
+			
+			var target = Ext.create('Ametys.message.MessageTarget', {
+				type: Ametys.message.MessageTarget.PAGE,
+				parameters: {id: pageId}
+			});
+			
+			targets.push(target);
+		});
+		
+		if (targets.length > 0)
+		{
+			Ext.create('Ametys.message.Message', {
+				type: Ametys.message.Message.MODIFIED,
+				targets: targets,
+				parameters: {
+					major: false
+				}
+			});
+		}
+	}
+});
Index: main/plugin-web/resources/js/Ametys/plugins/web/page/controller/RobotsController.js
===================================================================
--- main/plugin-web/resources/js/Ametys/plugins/web/page/controller/RobotsController.js	(revision 0)
+++ main/plugin-web/resources/js/Ametys/plugins/web/page/controller/RobotsController.js	(revision 0)
@@ -0,0 +1,257 @@
+/*
+ *  Copyright 2015 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.define('Ametys.plugins.web.page.controller.RobotsController', {
+	extend: 'Ametys.ribbon.element.ui.ButtonController',
+		
+	/**
+	 * @private
+	 * @property {String[]} _currentPagesId The pages id currently selected or null. 
+	 */
+	/**
+	 * @private
+	 * @property {String[]} _currentIncludedPagesId The page id currently included in seo files 
+	 */
+	/**
+	 * @private
+	 * @property {String[]} _currentExcludedPagesId The page id currently excluded from seo files 
+	 */
+	
+	
+	/**
+	 * @cfg {String} [icon-small] The path to the icon of the button in size 16x16 pixels when the current page has robots allowed
+	 */
+	/**
+	 * @cfg {String} [icon-medium] The path to the icon of the button in size 32x32 pixels when the current page has robots allowed
+	 */
+	/**
+	 * @cfg {String} [icon-large] The path to the icon of the button in size 48x48 pixels when the current page has robots allowed
+	 */
+	/**
+	 * @cfg {String} [excluded-icon-small] The path to the icon of the button in size 16x16 pixels when the current page has robots disallowed
+	 */
+	/**
+	 * @cfg {String} [excluded-icon-medium] The path to the icon of the button in size 32x32 pixels when the current page has robots disallowed
+	 */
+	/**
+	 * @cfg {String} [excluded-icon-large] The path to the icon of the button in size 48x48 pixels when the current page has robots disallowed
+	 */
+	constructor: function(config)
+	{
+		this.callParent(arguments);
+		
+		Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onModified, this);
+	},
+	
+	/**
+	 * Listener handler for modified messages
+	 * @param {Ametys.message.Message} message the message
+	 */
+	 _onModified: function(message)
+	 { 
+		 this.refresh();
+	 },
+	 
+	updateState: function()
+	{
+		this._getStatus(this.getMatchingTargets());
+	},
+	
+	/**
+	 * @private
+	 * Get the status
+	 * @param targets The page targets
+	 */
+	_getStatus: function (targets)
+	{
+		if (targets.length > 0)
+		{
+			var pageIds = [];
+			Ext.Array.each(targets, function(target) {
+				pageIds.push(target.getParameters().id);
+			});
+
+			this.serverCall('getStatus',
+					[pageIds], 
+					Ext.bind(this._getStatusCb, this),
+					{ 
+						errorMessage: { 
+							msg: "<i18n:text i18n:key='PLUGINS_WEB_PAGE_REFRESH_ROBOTS_ERROR'/>",
+							category: this.self.getName() 
+						}
+					},
+					true
+			);
+		}
+	},
+	
+	/**
+	 * Callback for the button reloading process
+	 * @param {Object} response the server's response
+	 */
+	_getStatusCb: function(response)
+	{
+		this._setAdditionalDescription(response);
+		this._setIcons(response);
+		
+		var isDisabled = this._isDisabled(response);
+		var nbExcludedPages = response['excluded-pages'].length;
+		var nbParentExcludedPages = response['parent-excluded-pages'].length;
+		
+		this.toggle(nbExcludedPages > 0 || nbParentExcludedPages > 0);
+		this.setDisabled(isDisabled);
+	},
+	
+	
+	/**
+	 * Set additional description on the button's tooltip
+	 * @param {String} params the server's parameters
+	 */
+	_setAdditionalDescription: function (params)
+	{
+		var tooltip = '';
+		this._currentIncludedPagesId = [];
+		this._currentExcludedPagesId = [];
+		
+		var includedPages = params['included-pages'];
+		if (includedPages.length > 0)
+		{
+			tooltip += this.getInitialConfig()["page-included-start-description"];
+			for (var i=0; i < includedPages.length; i++)
+			{
+				if (i != 0) 
+				{
+					tooltip += ", ";
+				}
+				tooltip += includedPages[i].description;
+				this._currentIncludedPagesId.push(includedPages[i].id);
+			}
+			tooltip += this.getInitialConfig()["page-included-end-description"];
+		}
+		
+		
+		var excludedPages = params['excluded-pages'];
+		if (excludedPages.length > 0)
+		{
+			if (tooltip != "")
+			{
+				tooltip += "<br/><br/>";
+			}
+			
+			tooltip += this.getInitialConfig()["page-excluded-start-description"];
+			for (var i=0; i < excludedPages.length; i++)
+			{
+				if (i != 0) 
+				{
+					tooltip += ", ";
+				}
+				tooltip += excludedPages[i].description;
+				this._currentExcludedPagesId.push(excludedPages[i].id);
+			}
+			tooltip += this.getInitialConfig()["page-excluded-end-description"];
+		}
+		
+		var parentExcludedPages = params['parent-excluded-pages'];
+		if (parentExcludedPages.length > 0)
+		{
+			if (tooltip != "")
+			{
+				tooltip += "<br/><br/>";
+			}
+			
+			tooltip += this.getInitialConfig()["page-parent-excluded-start-description"];
+			for (var i=0; i < parentExcludedPages.length; i++)
+			{
+				if (i != 0) 
+				{
+					tooltip += ", ";
+				}
+				tooltip += parentExcludedPages[i].description;
+				this._currentExcludedPagesId.push(parentExcludedPages[i].id);
+			}
+			tooltip += this.getInitialConfig()["page-parent-excluded-end-description"];
+		}
+		
+		if (params['noright-pages'].length > 0)
+		{
+			tooltip += "<br/><br/>";
+			tooltip += this.getInitialConfig()['noright-page-description'];
+		}
+		else if (params['excluded-pages'].length > 0)
+		{
+			tooltip += "<br/><br/>";
+			tooltip += this.getInitialConfig()["page-include-description"];
+		}
+		else if (params['included-pages'].length > 0)
+		{
+			tooltip += "<br/><br/>";
+			tooltip += this.getInitialConfig()["page-exclude-description"];
+		}
+		else if (params['parent-excluded-pages'].length > 0)
+		{
+			tooltip += "<br/><br/>";
+			tooltip += this.getInitialConfig()["page-parent-exclude-description"];
+		}
+		
+		this.setAdditionalDescription(tooltip);
+	},
+	
+	/**
+	 * Set the icons of the button
+	 * @param {Object} params the server's parameters
+	 */
+	_setIcons: function(params)
+	{
+		var contextPath = Ametys.getPluginResourcesPrefix('web');
+		
+		var nbIncludedPages = params['included-pages'].length;
+		var nbExcludedPages = params['excluded-pages'].length;
+		var nbParentExcludedPages = params['parent-excluded-pages'].length;
+		
+		if (nbIncludedPages > 0 && nbExcludedPages == 0 && nbParentExcludedPages == 0)
+		{
+			var iconSmall = this.getInitialConfig()['icon-small'];
+			var iconMedium = this.getInitialConfig()['icon-medium'];
+			var iconLarge = this.getInitialConfig()['icon-large'];
+			
+			this.setIcons(iconSmall, iconMedium, iconLarge);
+		}
+		
+		if (nbExcludedPages > 0 || nbParentExcludedPages > 0)
+		{
+			var iconSmall = this.getInitialConfig()['excluded-icon-small'];
+			var iconMedium = this.getInitialConfig()['excluded-icon-medium'];
+			var iconLarge = this.getInitialConfig()['excluded-icon-large'];
+
+			this.setIcons(iconSmall, iconMedium, iconLarge);
+		}
+	},
+	
+	/**
+	 * Is the button disabled ?
+	 * @param {Object} params the server's parameters
+	 */
+	_isDisabled: function (params)
+	{
+		var nbIncludedPages = params['included-pages'].length;
+		var nbExcludedPages = params['excluded-pages'].length;
+		var nbParentExcludedPages = params['parent-excluded-pages'].length;
+		var nbNorightsPages = params['noright-pages'].length;
+		
+		return (nbIncludedPages == 0 && nbExcludedPages == 0 && nbParentExcludedPages > 0) || nbNorightsPages > 0;
+	}
+});
+
Index: main/plugin-web/resources/js/org/ametys/ribbon/control/button/ToggleRobotsActionButton.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/ribbon/control/button/ToggleRobotsActionButton.js	(revision 32509)
+++ main/plugin-web/resources/js/org/ametys/ribbon/control/button/ToggleRobotsActionButton.js	(nonexistent)
@@ -1,321 +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');
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton = function(id, configuration, pluginName) 
-{
-	org.ametys.ribbon.control.button.ToggleRobotsActionButton.superclass.constructor.call(this, id, configuration, pluginName);
-};
-
-Ext.extend(org.ametys.ribbon.control.button.ToggleRobotsActionButton, org.ametys.ribbon.control.button.ActionButton, {});
-
-/**
- * @private
- * @property {Map<String, String>} _lastParams The parameters received on the last refresh
- */
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._lastParams;
-
-/**
- * @private
- * @property {String[]} _currentPagesId The pages id currently selected or null. 
- */
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._currentPagesId;
-/**
- * @private
- * @property {String[]} _currentIncludedPagesId The page id currently included in seo files 
- */
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._currentIncludedPagesId;
-/**
- * @private
- * @property {String[]} _currentIncludedPagesId The page id currently excluded from seo files 
- */
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._currentExcludedPagesId;
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._areTheSame = function (tab1, tab2)
-{
-	if (tab1 == tab2)
-	{
-		return true;
-	}
-
-	if (tab1 == null || tab2 == null || tab1.length != tab2.length)
-	{
-		return false;
-	}	
-	
-	for (var i=0; i < tab1.length; i++)
-	{
-		if (tab2.indexOf(tab1[i]) == -1)
-		{
-			return false;
-		}
-	}
-	
-	return true;
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._isInSelection = function (tab1, tab2)
-{
-	if (tab1 == tab2)
-	{
-		return true;
-	}
-	
-	if (tab1 == null || tab1.length == 0 || tab2 == null || tab2.length == 0)
-	{
-		return false;
-	}
-	
-	for (var i=0; i < tab2.length; i++)
-	{
-		if (tab1.indexOf(tab1[i]) != -1)
-		{
-			return true;
-		}
-	}
-	return false;
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._doReload = function(allTargets)
-{
-	this._currentPagesId = allTargets;
-	this.getElements().each(function(element) { element.refreshing(); element.setDisabled(true); });
-	this.updateTooltip(this.getConfiguration()["refresh-description"]);
-	org.ametys.ribbon.RibbonManager.getInstance().refreshElement('control', this, {targets: allTargets});
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype.onMessage = function (messages)
-{
-	for (var i=messages.length - 1; i >= 0; i--)
-	{
-		// SELECTION
-		if (messages[i].getType().getName() == org.ametys.ribbon.RibbonManager.EVENTTYPE_SELECTIONCHANGED)
-		{
-			var targets = messages[i].getTargets();
-			var allTargets = this._convertToId(org.ametys.messagebus.message.MessageTargetHelper.findAll(targets, this.checkTarget()));
-			
-			// No page selected
-			if (allTargets.length == 0)
-			{
-				this.getElements().each(function(element) { element.setDisabled(true); });
-				this.updateTooltip(this.getConfiguration()["default-description"]);
-				
-				this._currentPagesId = [];
-			}
-			else
-			{
-				if (!this._areTheSame(this._currentPagesId, allTargets))
-				{
-					this._doReload(allTargets);
-				}
-			}
-		}
-		else if (messages[i].getType().getName() == org.ametys.ribbon.RibbonManager.EVENTTYPE_METADATACHANGED
-		        || messages[i].getType().getName() == org.ametys.ribbon.RibbonManager.EVENTTYPE_MINORMETADATACHANGED)
-		{
-			var targets = messages[i].getTargets();
-			var allTargets = this._convertToId(org.ametys.messagebus.message.MessageTargetHelper.findAll(targets, this.checkTarget()));
-			
-			if (allTargets.length != 0 && this._isInSelection (this._currentPagesId, allTargets))
-			{
-				this._doReload(allTargets);
-			}
-		}
-	}
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._convertToId = function (targets)
-{
-	var targetsIds = [];
-	for (var i = 0; i < targets.length; i++)
-	{
-		targetsIds.push(targets[i].getParameters()['id']);
-	}
-	return targetsIds;
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype.checkTarget = function ()
-{
-	return function (target) { return target.getType() == 'page' && target.getParameters().isModifiable == 'true'};
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._getTooltip = function (tooltip, params)
-{
-	this._currentIncludedPagesId = [];
-	this._currentExcludedPagesId = [];
-	
-	var count = parseInt(params['page-included-size']);
-	if (count > 0)
-	{
-		if (tooltip != "")
-		{
-			tooltip += "<br/><br/>";
-		}
-		
-		tooltip += this.getConfiguration()["page-included-start-description"];
-		for (var i=0; i < count; i++)
-		{
-			if (i != 0) 
-			{
-				tooltip += ", ";
-			}
-			tooltip += params["page-included-description-" + i];
-			this._currentIncludedPagesId.push(params["page-included-" + i]);
-		}
-		tooltip += this.getConfiguration()["page-included-end-description"];
-	}
-	
-	var count = parseInt(params['page-excluded-size']);
-	if (count > 0)
-	{
-		if (tooltip != "")
-		{
-			tooltip += "<br/><br/>";
-		}
-		
-		tooltip += this.getConfiguration()["page-excluded-start-description"];
-		for (var i=0; i < count; i++)
-		{
-			if (i != 0) 
-			{
-				tooltip += ", ";
-			}
-			tooltip += params["page-excluded-description-" + i];
-			this._currentExcludedPagesId.push(params["page-excluded-" + i]);
-		}
-		tooltip += this.getConfiguration()["page-excluded-end-description"];
-	}
-	
-	var count = parseInt(params['page-parent-excluded-size']);
-	if (count > 0)
-	{
-		if (tooltip != "")
-		{
-			tooltip += "<br/><br/>";
-		}
-		
-		tooltip += this.getConfiguration()["page-parent-excluded-start-description"];
-		for (var i=0; i < count; i++)
-		{
-			if (i != 0) 
-			{
-				tooltip += ", ";
-			}
-			tooltip += params["page-parent-excluded-description-" + i];
-			this._currentExcludedPagesId.push(params["page-parent-excluded-" + i]);
-		}
-		tooltip += this.getConfiguration()["page-parent-excluded-end-description"];
-	}
-	
-	if (parseInt(params['page-noright-size']) > 0)
-	{
-		tooltip += "<br/><br/>";
-		tooltip += this.getConfiguration()['no-right-description'];
-	}
-	else if (parseInt(params['page-excluded-size']) > 0)
-	{
-		tooltip += "<br/><br/>";
-		tooltip += this.getConfiguration()["page-include-description"];
-	}
-	else if (parseInt(params['page-included-size']) > 0)
-	{
-		tooltip += "<br/><br/>";
-		tooltip += this.getConfiguration()["page-exclude-description"];
-	}
-	else if (parseInt(params['page-parent-excluded-size']) > 0)
-	{
-		tooltip += "<br/><br/>";
-		tooltip += this.getConfiguration()["page-parent-exclude-description"];
-	}
-		
-	return tooltip;
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._getIcon = function(params)
-{
-	var nbIncludedPages = parseInt(params['page-included-size']);
-	var nbExcludedPages = parseInt(params['page-excluded-size']);
-	var nbParentExcludedPages = parseInt(params['page-parent-excluded-size']);
-	
-	if (nbIncludedPages > 0 && nbExcludedPages == 0 && nbParentExcludedPages == 0)
-	{
-		var iconSmall = context.contextPath + this.getConfiguration()['icon-small'];
-		var iconLarge = context.contextPath + this.getConfiguration()['icon-medium'];
-		this.getElements().each(
-			function (element) 
-			{
-				element.iconSmall = iconSmall;
-				element.iconLarge = iconLarge;
-			}
-		);
-	}
-	
-	if (nbExcludedPages > 0 || nbParentExcludedPages > 0)
-	{
-		var iconSmall = context.contextPath + this.getConfiguration()['excluded-icon-small'];
-		var iconLarge = context.contextPath + this.getConfiguration()['excluded-icon-medium'];
-		this.getElements().each(
-			function (element) 
-			{
-				element.iconSmall = iconSmall;
-				element.iconLarge = iconLarge;
-			}
-		);
-	}
-}
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype._isDisabled = function (params)
-{
-	var nbIncludedPages = parseInt(params['page-included-size']);
-	var nbExcludedPages = parseInt(params['page-excluded-size']);
-	var nbParentExcludedPages = parseInt(params['page-parent-excluded-size']);
-	var nbNorightsPages = parseInt(params['page-noright-size']);
-	
-	return (nbIncludedPages == 0 && nbExcludedPages == 0 && nbParentExcludedPages > 0) || nbNorightsPages > 0;
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype.configurationError = function(response)
-{
-	this.getElements().each(function(element) { element.stopRefreshing(); element.setDisabled(true); });
-	this.updateTooltip(this.getConfiguration()["default-description"]);
-}
-
-org.ametys.ribbon.control.button.ToggleRobotsActionButton.prototype.configurationChanged = function(params)
-{
-	this.getElements().each(function(element) { element.stopRefreshing(); });
-	
-	var tooltip = this._getTooltip ("", params);
-	
-	var hasOneContent = tooltip.length > 0; 
-	if (!hasOneContent)
-	{
-		tooltip += this.getConfiguration()['no-selection-description'];
-	}
-	
-	// Icon
-	this._getIcon(params);
-	
-	this.getElements().each(function(element) { element.updateIcon(); });
-	this.updateTooltip(tooltip, this.getElements().get(0).iconLarge, null);
-	
-	var disabled = this._isDisabled(params);
-	var nbExcludedPages = parseInt(params['page-excluded-size']);
-	var nbParentExcludedPages = parseInt(params['page-parent-excluded-size']);
-	this.getElements().each(function(element) { element.toggle(nbExcludedPages > 0 || nbParentExcludedPages > 0); });
-	this.getElements().each(function(element) { element.setDisabled(!hasOneContent || disabled); });
-	
-	this._lastParams = params;
-}
Index: main/plugin-web/sitemap-back.xmap
===================================================================
--- main/plugin-web/sitemap-back.xmap	(revision 32549)
+++ main/plugin-web/sitemap-back.xmap	(working copy)

@@ -117,9 +115,7 @@
             
             <map:action name="administrator-is-system-user" src="org.ametys.runtime.plugins.admin.IsAdminAction" logger="org.ametys.runtime.plugins.web.administrator.sitemap.action.isAdmin"/>
 
-		  	<map:action name="disallow-robots" src="org.ametys.web.repository.page.actions.DisallowRobotsAction"/>
 		  	<map:action name="tag" src="org.ametys.web.repository.tag.actions.TagAction"/>
-		  	<map:action name="edit-metadata" src="org.ametys.web.repository.page.actions.EditMetadataAction"/>
 
 		  	<map:action name="page-path" src="org.ametys.web.repository.page.actions.GetPagePathAction"/>
 		  	
@@ -434,13 +430,6 @@
 				<map:serialize type="xml"/>
 			</map:match>
 			
-			<map:match pattern="repository/disallow-robots">
-				<map:act type="disallow-robots">
-					<map:generate type="action-result"/>
-					<map:serialize type="xml"/>
-				</map:act>
-			</map:match>
-			
 			<map:match pattern="repository/tag">
 				<map:act type="tag">
 					<map:generate type="action-result"/>

Index: main/plugin-web/src/org/ametys/web/clientsideelement/ToggleRobotsClientSideElement.java
===================================================================
--- main/plugin-web/src/org/ametys/web/clientsideelement/ToggleRobotsClientSideElement.java	(revision 32542)
+++ main/plugin-web/src/org/ametys/web/clientsideelement/ToggleRobotsClientSideElement.java	(working copy)
@@ -20,9 +20,16 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+
+import org.ametys.core.observation.Event;
+import org.ametys.core.observation.ObservationManager;
 import org.ametys.core.ui.Callable;
 import org.ametys.core.util.I18nizableText;
 import org.ametys.plugins.repository.AmetysObject;
+import org.ametys.web.ObservationConstants;
+import org.ametys.web.repository.page.ModifiablePage;
 import org.ametys.web.repository.page.Page;
 import org.ametys.web.repository.page.jcr.DefaultPage;
 
@@ -31,11 +38,22 @@
  */
 public class ToggleRobotsClientSideElement extends AbstractPageClientSideElement
 {
+    /** The observer manager */
+    private ObservationManager _observationManager;
+    
+    @Override
+    public void service(ServiceManager smanager) throws ServiceException
+    {
+        super.service(smanager);
+        _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE);
+    }
+    
     /**
      * Get the robots status of given pages
      * @param pageIds The page id
      * @return the result
      */
+    @SuppressWarnings("unchecked")
     @Callable
     public Map<String, Object> getStatus (List<String> pageIds)
     {
@@ -52,7 +70,7 @@
             
             Map<String, Object> pageParams = getPageDefaultParameters(page);
             
-            if (hasRight(page))
+            if (!hasRight(page))
             {
                 pageParams.put("description", getNoRightPageDescription(page));
 
@@ -89,6 +107,30 @@
         return results;
     }
     
+    /**
+     * Allow/Disallow the robots on a page 
+     * @param pageIds the selected pages
+     * @param exclude true to disallow the robots on the selected pages, false otherwise 
+     * @return an empty map
+     */
+    @Callable
+    public Map disallowRobots(List<String> pageIds, boolean exclude)
+    {
+        for (String id : pageIds)
+        {
+            ModifiablePage page = _resolver.resolveById(id);
+            
+            page.getMetadataHolder().setMetadata(DefaultPage.METADATA_ROBOTS_DISALLOW, exclude);
+            page.saveChanges();
+            
+            Map<String, Object> eventParams = new HashMap<>();
+            eventParams.put(ObservationConstants.ARGS_PAGE, page);
+            _observationManager.notify(new Event(ObservationConstants.EVENT_ROBOTS_CHANGED, _currentUserProvider.getUser(), eventParams));
+        } 
+        
+        return java.util.Collections.EMPTY_MAP;
+    }
+    
     private I18nizableText _getExcludedDescription (Page page)
     {
         List<String> i18nParameters = new ArrayList<>();
