Index: ivy.xml
===================================================================
--- ivy.xml	(revision 6976)
+++ ivy.xml	(working copy)
@@ -52,6 +52,7 @@
     
     <dependency org="ezmorph" name="ezmorph" rev="1.0.5" conf="default->default"/>
     <dependency org="json-lib" name="json-lib" rev="2.2.2" conf="default->default"/>
+    <dependency org="jquery" name="jquery-ui" rev="1.8.5" conf="runtime->default"/>
 
     <!-- exclude servlet.jar from runtime configuration -->
     <exclude org="javax.servlet" module="servlet-api" conf="runtime"/>
Index: main/workspace-web/src/org/ametys/web/repository/PageGenerator.java
===================================================================
--- main/workspace-web/src/org/ametys/web/repository/PageGenerator.java	(revision 6976)
+++ main/workspace-web/src/org/ametys/web/repository/PageGenerator.java	(working copy)
@@ -43,6 +43,7 @@
 import org.ametys.plugins.repository.metadata.CompositeMetadata;
 import org.ametys.plugins.repository.metadata.MetadataSaxer;
 import org.ametys.runtime.util.IgnoreRootHandler;
+import org.ametys.web.repository.page.ModifiablePage;
 import org.ametys.web.repository.page.Page;
 import org.ametys.web.repository.page.PagesContainer;
 import org.ametys.web.repository.page.Zone;
@@ -105,6 +106,7 @@
         AttributesImpl attrs = new AttributesImpl();
         attrs.addCDATAAttribute("title", title);
         attrs.addCDATAAttribute("long-title", page.getLongTitle());
+        attrs.addCDATAAttribute("id", page.getId());
         XMLUtils.startElement(contentHandler, "page", attrs);
 
         try
@@ -141,7 +143,9 @@
             throw new ProcessingException("Unable to SAX page metadata", e);
         }
 
-        XMLUtils.startElement(contentHandler, "pageContents");
+        AttributesImpl pcattrs = new AttributesImpl(); 
+        pcattrs.addCDATAAttribute("modifiable", Boolean.toString(page instanceof ModifiablePage));
+        XMLUtils.startElement(contentHandler, "pageContents", pcattrs);
 
         try
         {
Index: main/workspace-web/stylesheets/page.xsl
===================================================================
--- main/workspace-web/stylesheets/page.xsl	(revision 6976)
+++ main/workspace-web/stylesheets/page.xsl	(working copy)
@@ -106,6 +106,8 @@
 	    					{
 		    					parent.org.ametys.web.skin.UIZone.register(
 		    						window, 
+									"<xsl:value-of select="$datas/cms/page/@id"/>",
+									"<xsl:value-of select="$datas/cms/page/pageContents/@modifiable"/>",
 		    						"<xsl:value-of select="$name"/>", 
 		    						"<xsl:copy-of select="$zone-information/label/node()"/>",
 		    						"<xsl:copy-of select="$zone-information/description/node()"/>",
@@ -189,6 +191,8 @@
 				{
 					parent.org.ametys.web.skin.UIZoneItem.register(
 						window, 
+						"<xsl:value-of select="../../../@id"/>",
+						"<xsl:value-of select="../../@modifiable"/>",
 						"<xsl:value-of select="$zone-name"/>", 
 						"<xsl:value-of select="$zone-item-htmlid"/>",
 						"<xsl:value-of select="@id"/>", 
Index: main/workspace-web/stylesheets/wrapper.xsl
===================================================================
--- main/workspace-web/stylesheets/wrapper.xsl	(revision 6976)
+++ main/workspace-web/stylesheets/wrapper.xsl	(working copy)
@@ -99,6 +99,11 @@
                     }
                 </script>
                 
+                <script type="text/javascript" src="{$contextPath}/plugins/jquery/resources/js/jquery.js"></script>
+                <script type="text/javascript" src="{$contextPath}/plugins/jquery-ui/resources/js/jquery-ui.js"></script>
+				<script type="text/javascript" src="{$contextPath}/plugins/jquery-ui/resources/js/i18n/jquery.ui.datepicker-{$lang}.js"></script>
+                <link type="text/css" href="{$contextPath}/plugins/jquery-ui/resources/css/ui-lightness/jquery-ui.css" rel="stylesheet" media="screen, print" />
+                
 				<xsl:copy-of select="$skin-template/html/head/node()"/>
 				<xsl:for-each select="$skin-template//zone">
 					<xsl:copy-of select="head/node()"/>
Index: main/plugin-web/resources/css/inframe-page.css
===================================================================
--- main/plugin-web/resources/css/inframe-page.css	(revision 6976)
+++ main/plugin-web/resources/css/inframe-page.css	(working copy)
@@ -20,6 +20,50 @@
 	padding: 6px;
 }
 
+div.ametys-cms-zone-droptarget
+{
+	border-color: #BCE8F3;
+	background-color: #BCE8F3 !important;
+}
+div.ametys-cms-zone-droptarget div.ametys-cms-zoneitem-droptarget
+{
+	border: 1px solid #27b1d3;
+	background-color: #53c4df;
+	height: 30px !important;
+	margin-top: 2px;
+}
+
+div.ametys-cms-zone-dragtarget
+{
+	border: 1px dotted black !important; 
+	background-color: #ffffff !important;
+	padding: 5px !important;
+	height: 20px !important;
+	overflow: hidden;
+}
+div.ametys-cms-zone-dragtarget img
+{
+	width: 16px; 
+	height: 16px;
+	margin: 2px; 
+	margin-top: 4px;
+	margin-right: 4px;
+	float: left;
+}
+div.ametys-cms-zone-dragtarget div
+{
+	font-size: 11px !important;
+	font-variant: none !important;
+	font-weight: bold !important;
+	font-family: "Tahoma","Helvetica","Arial",sans-serif !important;
+	color: #023A69 !important;
+	position: static !important;
+	border-style: none !important;
+	background-image: none !important;
+	line-height: 24px !important;
+	vertical-align: middle !important;
+}
+
 div.ametys-cms-zone-published
 {
 	border: 1px dashed #8bdb5a;
Index: main/plugin-web/resources/js/org/ametys/web/zone/MoveZoneItemAction.i18n.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/zone/MoveZoneItemAction.i18n.js	(revision 0)
+++ main/plugin-web/resources/js/org/ametys/web/zone/MoveZoneItemAction.i18n.js	(revision 0)
@@ -0,0 +1,61 @@
+/*
+ *  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.content');
+
+org.ametys.web.content.MoveZoneItemAction = function (up)
+{
+	var currentTargets = org.ametys.ribbon.RibbonManager.getInstance().getCurrentSelectionTargets();
+	var target = org.ametys.messagebus.message.MessageTargetHelper.findFirst(currentTargets, function(target) {return target.getType() == 'page'});
+	
+	if (target == null || target.getParameters()["zoneitem-id"] == null)
+	{
+		new org.ametys.msg.ErrorDialog("<i18n:text i18n:key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_SELECTION_ERROR"/>", "<i18n:text i18n:key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_SELECTION_ERROR_DESC"/>", "", "org.ametys.web.content.MoveZoneItemAction");
+		return;
+	}
+
+	var pageId = target.getParameters()["id"];
+	var zoneItemId = target.getParameters()["zoneitem-id"];
+	
+	var params = {'zoneItemId': zoneItemId};
+	var serverMessage = new org.ametys.servercomm.ServerMessage('web', 'zoneitem/move' + (up ? 'Up' : 'Down'), params, org.ametys.servercomm.ServerComm.PRIORITY_MAJOR, org.ametys.web.content.MoveZoneItemAction._callback , this, [pageId, zoneItemId], "xml");
+	org.ametys.servercomm.ServerComm.getInstance().send(serverMessage);
+}
+
+org.ametys.web.content.MoveUpZoneItemAction = function (controlId, controlConfiguration, controlPluginName)
+{
+	org.ametys.web.content.MoveZoneItemAction(true);
+}
+
+org.ametys.web.content.MoveDownZoneItemAction = function (controlId, controlConfiguration, controlPluginName)
+{
+	org.ametys.web.content.MoveZoneItemAction(false);
+}
+
+org.ametys.web.content.MoveZoneItemAction._callback = function(response, args)
+{
+	if (org.ametys.servercomm.ServerComm.handleBadResponse("<i18n:text i18n:key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_ERROR"/>", response, "org.ametys.web.buttons.zoneitem.MoveAction"))
+	{
+		return;
+	}
+	
+	var pageId = args[0];
+	var zoneItemId = args[1];
+
+	var targets = [org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("page", {'id': pageId, 'zoneitem-id': zoneItemId})];
+	var events = [org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage("zoningChanged", null, targets)];
+	org.ametys.messagebus.MessageBus.getInstance().fireMessages(events);
+}
Index: main/plugin-web/resources/js/org/ametys/web/skin/UIZoneItem.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/skin/UIZoneItem.js	(revision 6976)
+++ main/plugin-web/resources/js/org/ametys/web/skin/UIZoneItem.js	(working copy)
@@ -19,6 +19,8 @@
 /**
  * Register the html element zoneName in the document doc as a zone. If empty do some additional graphic.
  * @param {HTMLWindow} win The window where to work in
+ * @param {String} pageId The page identifier 
+ * @param {boolean} modifiable Is the zone modifiable ?
  * @param {String} zoneName The id of the html element surrounding the zone
  * @param {String} zoneItemHTMLId The id of the html element surrounding the zone
  * @param {String} zoneItemId The id of the repository zone item
@@ -29,7 +31,7 @@
  * @param {String} mediumIcon The path to the medium icon
  * @param {String} largeIcon The path to the large icon
  */
-org.ametys.web.skin.UIZoneItem.register = function(win, zoneName, zoneItemHTMLId, zoneItemId, contentName, label, description, smallIcon, mediumIcon, largeIcon)
+org.ametys.web.skin.UIZoneItem.register = function(win, pageId, modifiable, zoneName, zoneItemHTMLId, zoneItemId, contentName, label, description, smallIcon, mediumIcon, largeIcon)
 {
 	var doc = win.document;
 	if (doc.zoneItems == null){ doc.zoneItems = []; }
@@ -61,6 +63,20 @@
 	}
 
 	div.insertBefore(img, div.firstChild);
+	
+	if (modifiable)
+	{
+		org.ametys.web.skin.UIZoneItem.makesDraggable(win, pageId, div, img, label, contentName, zoneItemId);
+	}
+}
+
+if (!org.ametys.web.skin.UIZoneItem.makesDraggable)
+{
+	org.ametys.web.skin.UIZoneItem.makesDraggable = function(win, pageId, div, img, label, contentName, zoneItemId)
+	{
+		// Default behavior : Nothing to do
+		// Has to be overriden
+	}
 }
 
 /**
Index: main/plugin-web/resources/js/org/ametys/web/skin/DDZoneItem.i18n.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/skin/DDZoneItem.i18n.js	(revision 0)
+++ main/plugin-web/resources/js/org/ametys/web/skin/DDZoneItem.i18n.js	(revision 0)
@@ -0,0 +1,142 @@
+/*
+ *  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.skin.UIZone');
+Ext.namespace('org.ametys.web.skin.UIZoneItem');
+Ext.namespace('org.ametys.web.skin.DDZoneItem');
+
+org.ametys.web.skin.UIZoneItem.makesDraggable = function(win, pageId, div, img, label, contentName, zoneItemId)
+{
+	win.$(div).draggable({ 
+		cursorAt: {left: 10, top: 10},
+		iframeFix: true, 
+		revert: "invalid", 
+		appendTo: 'body',
+		helper: function() 
+			{
+				// Create the floating element
+				var i = win.$(img);
+				
+				var css = " width: " + i.parent().width() + "px;";
+				if (i.parent().hasClass("ametys-cms-zone-item-selected"))
+				{
+					css += " border-width: 2px;";
+				}
+				
+				var imgCloned = i.clone().wrap("&lt;div zonteclass='ametys-cms-zone-dragtarget' style='"+ css + "'/&gt;").after("&lt;div&gt;" + label + (contentName != "" ? (" (" + contentName + ")") : "") + "&lt;/div&gt;");
+				imgCloned.parent().attr("zoneitemid", zoneItemId);
+				return imgCloned.parent();
+			},
+		scope: 'ametys-zones', 
+		zIndex: 99999, 
+		handle: img, 
+		refreshPositions: true,
+		distance: 6,
+		start: function() { img.oldonclick = img.onclick; img.onclick = null; win.$(img).parent().slideUp(); },
+		stop: function() 
+			{ 
+				img.onclick = img.oldonclick; 
+				img.oldonclick = null; 
+				win.$(img).parent().slideDown();
+	
+				win.$("body").find(".ametys-cms-zone-empty").each(function (index, zone)
+					{
+						zone = win.$(zone);
+					
+						if (zone.children(".ametys-cms-zone-item").size() == 0)
+						{
+							zone.children(".ametys-cms-zone-empty-desc").show();
+						}
+						else
+						{
+							zone.children(".ametys-cms-zone-empty-desc").hide();
+						}
+					}
+				);
+			}
+	});
+}
+
+org.ametys.web.skin.UIZone.makesDroppable = function(win, pageId, div, zoneName)
+{
+	win.$(div).droppable({
+		scope: 'ametys-zones',
+		hoverClass: 'ametys-cms-zone-droptarget',
+		tolerance: 'pointer',
+		greedy: true,
+		over: function(event, ui)
+		{
+			// Draw a drop zone
+			if (ui.helper.dropzone)
+			{
+				ui.helper.dropzone.detach();
+				ui.helper.dropzone = null;
+			}
+			
+			var zone = win.$(this);
+			
+			var id = Ext.id();
+			var css = "width: " + (zone.width() - 2) + "px";
+			zone.append("&lt;div id='" + id + "' class='ametys-cms-zoneitem-droptarget' style='" + css + "'&gt;&lt;/div&gt;");
+			
+			ui.helper.dropzone = win.$("#" + id);
+		},
+		out: function(event, ui)
+		{
+			// Remove the drop zone display
+			if (ui.helper.dropzone &amp;&amp; ui.helper.dropzone.parent() == win.$(this))
+			{
+				ui.helper.dropzone.detach();
+				ui.helper.dropzone = null;
+			}
+		},
+		drop: function(event, ui) 
+		{
+			if (ui.helper.dropzone)
+			{
+				ui.helper.dropzone.after(ui.draggable)
+				
+				ui.helper.dropzone.detach();
+				ui.helper.dropzone = null;
+			}
+			else
+			{
+				// this should never happens
+				win.$(this).append(ui.draggable);
+			}
+
+			// there is a modification
+			var params = {
+					'zoneItemId': ui.helper.attr("zoneitemid"),
+					'zoneName': zoneName,
+					'pageId': pageId};
+			var serverMessage = new org.ametys.servercomm.ServerMessage('web', 'zoneitem/moveTo', params, org.ametys.servercomm.ServerComm.PRIORITY_MAJOR, org.ametys.web.skin.DDZoneItem._dropDone, this, params, "xml");
+			org.ametys.servercomm.ServerComm.getInstance().send(serverMessage);
+		}
+	});
+}
+
+org.ametys.web.skin.DDZoneItem._dropDone = function(response, params)
+{
+	if (org.ametys.servercomm.ServerComm.handleBadResponse("<i18n:text i18n:key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_ERROR"/>", response, "org.ametys.web.skin.DDZoneItem"))
+	{
+		return;
+	}
+	
+	var targets = [org.ametys.messagebus.bus.MessageBuilder.getInstance().createTarget("page", {'id': params.pageId})];
+	var events = [org.ametys.messagebus.bus.MessageBuilder.getInstance().createMessage("zoningChanged", null, targets)];
+	org.ametys.messagebus.MessageBus.getInstance().fireMessages(events);
+}
Index: main/plugin-web/resources/js/org/ametys/web/skin/UIZone.i18n.js
===================================================================
--- main/plugin-web/resources/js/org/ametys/web/skin/UIZone.i18n.js	(revision 6976)
+++ main/plugin-web/resources/js/org/ametys/web/skin/UIZone.i18n.js	(working copy)
@@ -19,6 +19,8 @@
 /**
  * Register the html element zoneName in the document doc as a zone. If empty do some additional graphic.
  * @param {HTMLWindow} win The document where to work in
+ * @param {String} pageId The page identifier
+ * @param {boolean} modifiable Is the zone modifiable ?
  * @param {String} zoneName The id of the html element surrounding the zone
  * @param {String} zoneTitle The title of the zone
  * @param {String} zoneDesc The description of the zone
@@ -27,7 +29,7 @@
  * @param {String} largeImg The path for the small image
  * @param {boolean/String} emptyZone Optional boolean to indicate if zone is empty. false is the default value. Or can be a string (when not really empty - to indicate the page id that the zone items are inherited from)
  */
-org.ametys.web.skin.UIZone.register = function(win, zoneName, zoneTitle, zoneDesc, smallImg, mediumImg, largeImg, emptyZone)
+org.ametys.web.skin.UIZone.register = function(win, pageId, modifiable, zoneName, zoneTitle, zoneDesc, smallImg, mediumImg, largeImg, emptyZone)
 {
 	var doc = win.document;
 	
@@ -101,6 +103,20 @@
 		div.insertBefore(img, div.firstChild);
 		img.src = context.contextPath + smallImg;
 	}
+	
+	if (modifiable)
+	{
+		org.ametys.web.skin.UIZone.makesDroppable(win, pageId, div, zoneName);
+	}
+}
+
+if (!org.ametys.web.skin.UIZone.makesDroppable)
+{
+	org.ametys.web.skin.UIZone.makesDroppable = function(win, pageId, div, zoneName)
+	{
+		// Default behavior : Nothing to do
+		// Has to be overridden
+	}
 }
 
 /**
Index: main/plugin-web/plugin.xml
===================================================================
--- main/plugin-web/plugin.xml	(revision 6976)
+++ main/plugin-web/plugin.xml	(working copy)
@@ -579,6 +579,15 @@
             </extension>
             
             <extension point="org.ametys.runtime.plugins.core.right.RightsExtensionPoint"
+                       id="web.rights.page.organize.zoneitem">
+                <right id="Web_Rights_Page_OrganizeZoneItem">
+                    <label>PLUGINS_WEB_RIGHTS_PAGE_ORGANIZE_ZONEITEM_LABEL</label>
+        			<description>PLUGINS_WEB_RIGHTS_PAGE_ORGANIZE_ZONEITEM_DESCRIPTION</description>
+        			<category>PLUGINS_CMS_RIGHTS_PAGE_CATEGORY</category>
+                </right>
+            </extension>
+            
+            <extension point="org.ametys.runtime.plugins.core.right.RightsExtensionPoint"
                        id="web.rights.page.delete.zoneitem">
                 <right id="Web_Rights_Page_DeleteZoneItem">
                     <label>PLUGINS_WEB_RIGHTS_PAGE_DELETE_ZONEITEM_LABEL</label>
@@ -750,6 +759,66 @@
 		</extensions>
 	</feature>
     
+    <feature name="userinterface.web.moviongzoneitems">
+		<extensions>
+			<extension id="org.ametys.plugins.web.MovingZoneItems"
+    				   point="org.ametys.cms.workspace.uitool.StaticFileImportsManager"
+    				   class="org.ametys.cms.workspace.uitool.StaticFileImportsClientSideElement">
+    				   
+    			<scripts>
+					<file>js/org/ametys/web/skin/DDZoneItem.i18n.js</file>
+				</scripts>
+				<right>Web_Rights_Page_OrganizeZoneItem</right>
+    		</extension>
+    		
+    		<extension id="org.ametys.web.movezoneitem.up" 
+    				   point="org.ametys.cms.workspace.ribbon.RibbonControlsManager" 
+    				   class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
+				<action class="org.ametys.ribbon.control.button.ModifiableZoneItemActionButton">
+					<param name="action">org.ametys.web.content.MoveUpZoneItemAction</param>
+					
+					<param name="label" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_LABEL</param>
+					<param name="default-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_DESCRIPTION</param>
+					<param name="no-selection-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NOSELECTION_DESCRIPTION</param>
+					<param name="no-right-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NORIGHT_DESCRIPTION</param>
+					<param name="no-modifiable-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NOMODIFIABLE_DESCRIPTION</param>
+					<param name="icon-small" file="true">img/skin/zoneitem_moveup_16.png</param>
+					<param name="icon-medium" file="true">img/skin/zoneitem_moveup_32.png</param>
+					<param name="icon-large" file="true">img/skin/zoneitem_moveup_48.png</param>
+				</action>
+				<scripts>
+					<file>js/org/ametys/web/zone/MoveZoneItemAction.i18n.js</file>
+					<file>js/org/ametys/ribbon/control/button/ZoneItemActionButton.js</file>
+					<file>js/org/ametys/ribbon/control/button/ModifiableZoneItemActionButton.js</file>
+				</scripts>
+				<right>Web_Rights_Page_OrganizeZoneItem</right>
+    		</extension>
+
+    		<extension id="org.ametys.web.movezoneitem.down" 
+    				   point="org.ametys.cms.workspace.ribbon.RibbonControlsManager" 
+    				   class="org.ametys.runtime.ui.impl.StaticContextualClientSideElement">
+				<action class="org.ametys.ribbon.control.button.ModifiableZoneItemActionButton">
+					<param name="action">org.ametys.web.content.MoveDownZoneItemAction</param>
+					
+					<param name="label" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_LABEL</param>
+					<param name="default-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_DESCRIPTION</param>
+					<param name="no-selection-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NOSELECTION_DESCRIPTION</param>
+					<param name="no-right-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NORIGHT_DESCRIPTION</param>
+					<param name="no-modifiable-description" i18n="true">PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NOMODIFIABLE_DESCRIPTION</param>
+					<param name="icon-small" file="true">img/skin/zoneitem_movedown_16.png</param>
+					<param name="icon-medium" file="true">img/skin/zoneitem_movedown_32.png</param>
+					<param name="icon-large" file="true">img/skin/zoneitem_movedown_48.png</param>
+				</action>
+				<scripts>
+					<file>js/org/ametys/web/zone/MoveZoneItemAction.i18n.js</file>
+					<file>js/org/ametys/ribbon/control/button/ZoneItemActionButton.js</file>
+					<file>js/org/ametys/ribbon/control/button/ModifiableZoneItemActionButton.js</file>
+				</scripts>
+				<right>Web_Rights_Page_OrganizeZoneItem</right>
+    		</extension>
+		</extensions>
+	</feature>
+    
     <!-- +
     	 | OBSERVATION
     	 + -->
Index: main/plugin-web/src/org/ametys/web/live/SynchronizePageChangeObserver.java
===================================================================
--- main/plugin-web/src/org/ametys/web/live/SynchronizePageChangeObserver.java	(revision 6976)
+++ main/plugin-web/src/org/ametys/web/live/SynchronizePageChangeObserver.java	(working copy)
@@ -34,7 +34,7 @@
     {
         String id = event.getId();
         return id.equals(ObservationConstants.PAGE_ADDED) || id.equals(ObservationConstants.PAGE_CHANGED) 
-            || id.equals(ObservationConstants.ZONEITEM_ADDED) || id.equals(ObservationConstants.ZONEITEM_DELETED);
+            || id.equals(ObservationConstants.ZONEITEM_ADDED) || id.equals(ObservationConstants.ZONEITEM_MOVED) || id.equals(ObservationConstants.ZONEITEM_DELETED);
     }
     
     @Override
Index: main/plugin-web/src/org/ametys/web/observation/ObservationConstants.java
===================================================================
--- main/plugin-web/src/org/ametys/web/observation/ObservationConstants.java	(revision 6976)
+++ main/plugin-web/src/org/ametys/web/observation/ObservationConstants.java	(working copy)
@@ -47,6 +47,8 @@
 
     /** Event id when a zone item is added. */
     public static final String ZONEITEM_ADDED = "zoneitem.added";
+    /** Event id when a zone item is moved. */
+    public static final String ZONEITEM_MOVED = "zoneitem.moved";
     /** Event id when a zone item is deleted. */
     public static final String ZONEITEM_DELETED = "zoneitem.deleted";
     
Index: main/plugin-web/src/org/ametys/web/lucene/LucenePageChangePart1Observer.java
===================================================================
--- main/plugin-web/src/org/ametys/web/lucene/LucenePageChangePart1Observer.java	(revision 6976)
+++ main/plugin-web/src/org/ametys/web/lucene/LucenePageChangePart1Observer.java	(working copy)
@@ -54,7 +54,7 @@
     {
         String id = event.getId();
         return id.equals(ObservationConstants.PAGE_ADDED) || id.equals(ObservationConstants.PAGE_CHANGED) 
-            || id.equals(ObservationConstants.ZONEITEM_ADDED) || id.equals(ObservationConstants.ZONEITEM_DELETED);
+            || id.equals(ObservationConstants.ZONEITEM_ADDED) || id.equals(ObservationConstants.ZONEITEM_MOVED) || id.equals(ObservationConstants.ZONEITEM_DELETED);
     }
     
     @Override
Index: main/plugin-web/src/org/ametys/web/lucene/LucenePageChangePart2Observer.java
===================================================================
--- main/plugin-web/src/org/ametys/web/lucene/LucenePageChangePart2Observer.java	(revision 6976)
+++ main/plugin-web/src/org/ametys/web/lucene/LucenePageChangePart2Observer.java	(working copy)
@@ -55,7 +55,7 @@
     {
         String id = event.getId();
         return id.equals(ObservationConstants.PAGE_ADDED) || id.equals(ObservationConstants.PAGE_CHANGED) 
-            || id.equals(ObservationConstants.ZONEITEM_ADDED) || id.equals(ObservationConstants.ZONEITEM_DELETED);
+            || id.equals(ObservationConstants.ZONEITEM_ADDED) || id.equals(ObservationConstants.ZONEITEM_MOVED) || id.equals(ObservationConstants.ZONEITEM_DELETED);
     }
     
     @Override
Index: main/plugin-web/src/org/ametys/web/repository/page/jcr/DefaultZoneItem.java
===================================================================
--- main/plugin-web/src/org/ametys/web/repository/page/jcr/DefaultZoneItem.java	(revision 6976)
+++ main/plugin-web/src/org/ametys/web/repository/page/jcr/DefaultZoneItem.java	(working copy)
@@ -155,7 +155,6 @@
             throw new AmetysRepositoryException("Can not move a zone item " + getId() + " of type DefaultZoneItem to something that is not a DefaultZone " + newParent.getId());
         }
         
-
         Node node = getNode();
 
         try
@@ -163,14 +162,14 @@
             if (getParent().equals(newParent))
             {
                 // Just order current node to the end
-                node.getParent().orderBefore(node.getName(), null);
+                node.getParent().orderBefore(node.getName() + "[" + node.getIndex() + "]", null);
             }
             else
             {
                 DefaultZone newParentZone = (DefaultZone) newParent;
                 
                 // Move node
-                node.getSession().move(node.getPath(), newParentZone.getNode().getPath() + "/" + node.getName());
+                node.getSession().move(node.getPath(), newParentZone.getNode().getPath() + "/" + DefaultZone.ZONEITEMS_NODE_NAME + "/" + node.getName());
             }
         }
         catch (RepositoryException e)
@@ -180,18 +179,23 @@
     }
     
     @Override
-    public void orderBefore(AmetysObject siblingNode) throws AmetysRepositoryException
+    public void orderBefore(AmetysObject siblingObject) throws AmetysRepositoryException
     {
+        if (siblingObject != null && !(siblingObject instanceof JCRAmetysObject))
+        {
+            throw new AmetysRepositoryException(String.format("Unable to order zone item '%s' before sibling '%s' (sibling is not a JCRAmetysObject)", this.getId(), siblingObject.getId()));
+        }
+        
         Node node = getNode();
-        String name = "";
+        Node siblingNode = siblingObject != null ? ((JCRAmetysObject) siblingObject).getNode() : null;
+        
         try
         {
-            name = siblingNode.getName();
-            node.getParent().orderBefore(node.getName(), name);
+            node.getParent().orderBefore(node.getName() + "[" + node.getIndex() + "]", siblingNode != null ? siblingNode.getName() + "[" + siblingNode.getIndex() + "]" : null);
         }
         catch (RepositoryException e)
         {
-            throw new AmetysRepositoryException(String.format("Unable to order zone item '%s' before sibling '%s'", this, name), e);
+            throw new AmetysRepositoryException(String.format("Unable to order zone item '%s' before sibling '%s'", this.getId(), siblingObject != null ? siblingObject.getId() : ""), e);
         }
     }
     
Index: main/plugin-web/src/org/ametys/web/repository/page/actions/MoveIntoZoneItemAction.java
===================================================================
--- main/plugin-web/src/org/ametys/web/repository/page/actions/MoveIntoZoneItemAction.java	(revision 0)
+++ main/plugin-web/src/org/ametys/web/repository/page/actions/MoveIntoZoneItemAction.java	(revision 0)
@@ -0,0 +1,131 @@
+/*
+ *  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.repository.page.actions;
+
+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.SourceResolver;
+
+import org.ametys.plugins.repository.AmetysObjectIterable;
+import org.ametys.runtime.right.RightsManager;
+import org.ametys.runtime.right.RightsManager.RightResult;
+import org.ametys.web.observation.AbstractNotifierAction;
+import org.ametys.web.observation.Event;
+import org.ametys.web.observation.ObservationConstants;
+import org.ametys.web.repository.page.ModifiableZone;
+import org.ametys.web.repository.page.ModifiableZoneItem;
+import org.ametys.web.repository.page.Page;
+import org.ametys.web.repository.page.Zone;
+import org.ametys.web.repository.page.ZoneItem;
+
+/**
+ * This action removes a {@link ZoneItem}
+ */
+public class MoveIntoZoneItemAction extends AbstractNotifierAction
+{
+    /** The rights manager */
+    protected RightsManager _rightsManager;
+    
+    @Override
+    public void service(ServiceManager serviceManager) throws ServiceException
+    {
+        super.service(serviceManager);
+        
+        _rightsManager = (RightsManager) manager.lookup(RightsManager.ROLE);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
+    {
+        Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
+        
+        String zoneItemId = (String) jsParameters.get("zoneItemId");
+        
+        boolean up = "up".equalsIgnoreCase(parameters.getParameter("direction", "up"));
+        
+        String userName;
+        if (_isSuperUser())
+        {
+            userName = "<admin>";
+        }
+        else
+        {
+            userName = _getCurrentUser();
+        }
+        
+        
+        ZoneItem zoneItem = _resolver.resolveById(zoneItemId);
+        Zone zone = zoneItem.getZone();
+        Page page = zone.getPage();
+
+        if (!_isSuperUser() && _rightsManager.hasRight(userName, "Web_Rights_Page_OrganizeZoneItem", "/pages/" + page.getSitemapName() + "/" + page.getPathInSitemap()) != RightResult.RIGHT_OK)
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed without convinient privileges to move zone item '" + zoneItemId + "' to the zone '" + zone.getName() + "' of the page '" + page.getId() + "' !");
+        }
+        else if (zoneItem == null)
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed to move unexisting zone item '" + zoneItemId + "' to the zone '" + zone.getName() + "' of the page '" + page.getId() + "' !");
+        }
+        else if (!(zone instanceof ModifiableZone))
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed to move zone item '" + zoneItemId + "' to the zone '" + zone.getName() + "' of the page '" + page.getId() + "' but this zone is not modifiable !");
+        }
+        else if (!(zoneItem instanceof ModifiableZoneItem))
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed to move zone item '" + zoneItemId + "' to the zone '" + zone.getName() + "' of the page '" + page.getId() + "' but this zone item is not modifiable !");
+        }
+        
+        ZoneItem preceding = null;
+        
+        AmetysObjectIterable<? extends ZoneItem> ziI = zone.getZoneItems();
+        while (ziI.hasNext())
+        {
+            ZoneItem zi = ziI.next(); 
+            if (zi.getId().equals(zoneItemId))
+            {
+                if (up && preceding != null)
+                {
+                    ((ModifiableZoneItem) zoneItem).orderBefore(preceding);
+                    break;
+                }
+                else if (!up && ziI.hasNext())
+                {
+                    ziI.next();
+                    ((ModifiableZoneItem) zoneItem).orderBefore(ziI.hasNext() ? ziI.next() : null);
+                    break;
+                }
+            }
+            
+            preceding = zi;
+        }
+
+        if (page.getSitemap().needsSave())
+        {
+            page.getSitemap().saveChanges();
+        }
+        
+        _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.ZONEITEM_MOVED, page, new String[]{zoneItemId}));
+        
+        return EMPTY_MAP;
+    }
+
+}
Index: main/plugin-web/src/org/ametys/web/repository/page/actions/MoveZoneItemAction.java
===================================================================
--- main/plugin-web/src/org/ametys/web/repository/page/actions/MoveZoneItemAction.java	(revision 0)
+++ main/plugin-web/src/org/ametys/web/repository/page/actions/MoveZoneItemAction.java	(revision 0)
@@ -0,0 +1,113 @@
+/*
+ *  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.repository.page.actions;
+
+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.SourceResolver;
+
+import org.ametys.runtime.right.RightsManager;
+import org.ametys.runtime.right.RightsManager.RightResult;
+import org.ametys.web.observation.AbstractNotifierAction;
+import org.ametys.web.observation.Event;
+import org.ametys.web.observation.ObservationConstants;
+import org.ametys.web.repository.page.ModifiableZone;
+import org.ametys.web.repository.page.ModifiableZoneItem;
+import org.ametys.web.repository.page.Page;
+import org.ametys.web.repository.page.Zone;
+import org.ametys.web.repository.page.ZoneItem;
+import org.ametys.web.repository.sitemap.Sitemap;
+
+/**
+ * This action removes a {@link ZoneItem}
+ */
+public class MoveZoneItemAction extends AbstractNotifierAction
+{
+    /** The rights manager */
+    protected RightsManager _rightsManager;
+    
+    @Override
+    public void service(ServiceManager serviceManager) throws ServiceException
+    {
+        super.service(serviceManager);
+        
+        _rightsManager = (RightsManager) manager.lookup(RightsManager.ROLE);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
+    {
+        Map<String, Object> jsParameters = (Map<String, Object>) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
+        
+        String zoneItemId = (String) jsParameters.get("zoneItemId");
+        String zoneName = (String) jsParameters.get("zoneName");
+        String pageId = (String) jsParameters.get("pageId");
+        
+        String userName;
+        if (_isSuperUser())
+        {
+            userName = "<admin>";
+        }
+        else
+        {
+            userName = _getCurrentUser();
+        }
+        
+        
+        Page page = _resolver.resolveById(pageId);
+        Zone zone = page.getZone(zoneName);
+        ZoneItem zoneItem = _resolver.resolveById(zoneItemId);
+
+        if (!_isSuperUser() && _rightsManager.hasRight(userName, "Web_Rights_Page_OrganizeZoneItem", "/pages/" + page.getSitemapName() + "/" + page.getPathInSitemap()) != RightResult.RIGHT_OK)
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed without convinient privileges to move zone item '" + zoneItemId + "' to the zone '" + zoneName + "' of the page '" + pageId + "' !");
+        }
+        else if (zoneItem == null)
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed to move unexisting zone item '" + zoneItemId + "' to the zone '" + zoneName + "' of the page '" + pageId + "' !");
+        }
+        else if (zone == null)
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed to move zone item '" + zoneItemId + "' to an unexisting zone '" + zoneName + "' of the page '" + pageId + "' !");
+        }
+        else if (!(zone instanceof ModifiableZone))
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed to move zone item '" + zoneItemId + "' to the zone '" + zoneName + "' of the page '" + pageId + "' but this zone is not modifiable !");
+        }
+        else if (!(zoneItem instanceof ModifiableZoneItem))
+        {
+            throw new IllegalArgumentException("User '" + userName + "' tryed to move zone item '" + zoneItemId + "' to the zone '" + zoneName + "' of the page '" + pageId + "' but this zone item is not modifiable !");
+        }
+        
+        ((ModifiableZoneItem) zoneItem).moveTo(zone, false);
+        Sitemap sitemap = zoneItem.getZone().getPage().getSitemap();
+        if (sitemap.needsSave())
+        {
+            sitemap.saveChanges();
+        }
+        
+        _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.ZONEITEM_MOVED, page, new String[]{zoneItemId}));
+        
+        return EMPTY_MAP;
+    }
+
+}
Index: main/plugin-web/src/org/ametys/web/repository/page/actions/ServiceAffectAction.java
===================================================================
--- main/plugin-web/src/org/ametys/web/repository/page/actions/ServiceAffectAction.java	(revision 6976)
+++ main/plugin-web/src/org/ametys/web/repository/page/actions/ServiceAffectAction.java	(working copy)
@@ -124,7 +124,7 @@
             
             ((JCRAmetysObject) page).getNode().save();
             
-            _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.ZONEITEM_ADDED, page));
+            _observationManager.notify(new Event(_getCurrentUser(), ObservationConstants.ZONEITEM_MOVED, page));
         }
         catch (UnknownAmetysObjectException e)
         {
Index: main/plugin-web/src/org/ametys/web/cache/InvalidateCacheOnPageContentChangeObserver.java
===================================================================
--- main/plugin-web/src/org/ametys/web/cache/InvalidateCacheOnPageContentChangeObserver.java	(revision 6976)
+++ main/plugin-web/src/org/ametys/web/cache/InvalidateCacheOnPageContentChangeObserver.java	(working copy)
@@ -33,7 +33,8 @@
     @Override
     public boolean supports(Event event)
     {
-        return event.getId().equals(ObservationConstants.ZONEITEM_ADDED) 
+        return event.getId().equals(ObservationConstants.ZONEITEM_ADDED)
+            || event.getId().equals(ObservationConstants.ZONEITEM_MOVED)
             || event.getId().equals(ObservationConstants.ZONEITEM_DELETED);
     }
     
Index: main/plugin-web/i18n/messages_en.xml
===================================================================
--- main/plugin-web/i18n/messages_en.xml	(revision 6976)
+++ main/plugin-web/i18n/messages_en.xml	(working copy)
@@ -47,6 +47,8 @@
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_ADDSERVICE_DESCRIPTION">Create and add service to a zone in pages</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_CONFIGURE_SERVICE_LABEL">Service configuration</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_CONFIGURE_SERVICE_DESCRIPTION">Update the configuration of an existing service</message>
+	<message key="PLUGINS_WEB_RIGHTS_PAGE_ORGANIZE_ZONEITEM_LABEL">Re-organize items in page areas</message>
+	<message key="PLUGINS_WEB_RIGHTS_PAGE_ORGANIZE_ZONEITEM_DESCRIPTION">Re-organize contents or services in the page (moving in the same area or in another area)</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_DELETE_ZONEITEM_LABEL">Delete an item in page areas</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_DELETE_ZONEITEM_DESCRIPTION">Delete a content or a service previously added to an area</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_BLANK_LABEL">Blank page</message>
@@ -651,8 +653,21 @@
 	<message key="PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_DIALOG_TITLE">Insert an existing content ...</message>
 	<message key="PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR">Unable to insert content.</message>
 	
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_LABEL">Move up item</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_DESCRIPTION">This action move up the selected content or service</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NOSELECTION_DESCRIPTION">This button is disabled because any content or service is selected.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NORIGHT_DESCRIPTION">This button is disabled because your rights are insufficient.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NOMODIFIABLE_DESCRIPTION">This button is disabled because the properties of the selected content or service do not allow to move it</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_LABEL">Move down item</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_DESCRIPTION">This action move down the selected content or service</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NOSELECTION_DESCRIPTION">This button is disabled because any content or service is selected.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NORIGHT_DESCRIPTION">This button is disabled because your rights are insufficient.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NOMODIFIABLE_DESCRIPTION">This button is disabled because the properties of the selected content or service do not allow to move it</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_ERROR">Unable to move the content or the service. Please reload the page before proceding.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_SELECTION_ERROR">Incorrect selection</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_SELECTION_ERROR_DESC">Selection should be a content or a service.</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_LABEL">Delete item</message>
-	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_DESCRIPTION">Using this action delete selected content or service</message>
+	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_DESCRIPTION">Use this action to delete the selected content or service</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_NOSELECTION_DESCRIPTION">This button is disabled because any content or service is selected.</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_NORIGHT_DESCRIPTION">This button is disabled because your rights are insufficient.</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_NOMODIFIABLE_DESCRIPTION">This button is disabled because the properties of the selected content or service do not allow to delete it</message>
Index: main/plugin-web/i18n/messages_fr.xml
===================================================================
--- main/plugin-web/i18n/messages_fr.xml	(revision 6976)
+++ main/plugin-web/i18n/messages_fr.xml	(working copy)
@@ -47,6 +47,8 @@
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_ADDSERVICE_DESCRIPTION">>Autorise à ajouter un service à une zone d'une page</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_CONFIGURE_SERVICE_LABEL">Paramétrer un service</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_CONFIGURE_SERVICE_DESCRIPTION">Autorise la modification des paramètres d'un service</message>
+	<message key="PLUGINS_WEB_RIGHTS_PAGE_ORGANIZE_ZONEITEM_LABEL">Réorganiser les élements des zones</message>
+	<message key="PLUGINS_WEB_RIGHTS_PAGE_ORGANIZE_ZONEITEM_DESCRIPTION">Autorise à réorganiser les contenus ou les services dans la page (déplacement dans la zone ou d'une zone à l'autre)</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_DELETE_ZONEITEM_LABEL">Supprimer un élement d'une zone</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_DELETE_ZONEITEM_DESCRIPTION">Autorise à supprimer un contenu ou un service</message>
 	<message key="PLUGINS_WEB_RIGHTS_PAGE_BLANK_LABEL">Page vierge</message>
@@ -650,6 +652,19 @@
 	<message key="PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_DIALOG_TITLE">Insérer un contenu existant ...</message>
 	<message key="PLUGINS_WEB_CONTENT_ADDSHAREDCONTENT_ERROR">L'insertion du contenu a échoué.</message>
 	
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_LABEL">Déplacer vers le haut</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_DESCRIPTION">Ce bouton permet de déplacer vers le haut le contenu ou service sélectionné</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NOSELECTION_DESCRIPTION">Ce bouton est désactivé car aucun contenu ou service n'est sélectionné.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NORIGHT_DESCRIPTION">Ce bouton est désactivé car vos droits sont insuffisants.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_UP_NOMODIFIABLE_DESCRIPTION">Ce bouton est désactivé car les propriétés du contenu ou service sélectionné ne permettent pas de le déplacer.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_LABEL">Déplacer vers le bas</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_DESCRIPTION">Ce bouton permet de déplacer vers le bas le contenu ou service sélectionné</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NOSELECTION_DESCRIPTION">Ce bouton est désactivé car aucun contenu ou service n'est sélectionné.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NORIGHT_DESCRIPTION">Ce bouton est désactivé car vos droits sont insuffisants.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_DOWN_NOMODIFIABLE_DESCRIPTION">Ce bouton est désactivé car les propriétés du contenu ou service sélectionné ne permettent pas de le déplacer.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_ERROR">Le déplacement du contenu / service a échoué. Veuillez recharger la page avant de continuer.</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_SELECTION_ERROR">Selection courante incorrecte</message>
+	<message key="PLUGINS_WEB_CONTENT_MOVEZONEITEM_SELECTION_ERROR_DESC">La sélection courante doit être la zone de contenu ou de service.</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_LABEL">Supprimer l'élément</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_DESCRIPTION">Ce bouton permet de supprimer le contenu ou service sélectionné</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_NOSELECTION_DESCRIPTION">Ce bouton est désactivé car aucun contenu ou service n'est sélectionné.</message>
@@ -657,7 +672,7 @@
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_NOMODIFIABLE_DESCRIPTION">Ce bouton est désactivé car les propriétés du contenu ou service sélectionné ne permettent pas de le supprimer.</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_CONFIRM">Etes-vous sûr de vouloir supprimer ce contenu ou service ?&lt;br/&gt;Cette action ne pourra être annulée.</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_ERROR">La suppression du contenu /service a échoué.</message>
-	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_SELECTION_ERROR">Selection courrant incorrecte</message>
+	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_SELECTION_ERROR">Selection courante incorrecte</message>
 	<message key="PLUGINS_WEB_CONTENT_REMOVEZONEITEM_SELECTION_ERROR_DESC">La sélection courante doit être la zone de contenu ou de service.</message>
 	
 	<!-- SITEMAP service -->
Index: main/plugin-web/sitemap.xmap
===================================================================
--- main/plugin-web/sitemap.xmap	(revision 6976)
+++ main/plugin-web/sitemap.xmap	(working copy)
@@ -125,6 +125,8 @@
 		  	
 		  	<map:action name="delete-content" src="org.ametys.web.repository.content.actions.DeleteContentAction"/>
 		  	
+		  	<map:action name="zoneitem-moveto" src="org.ametys.web.repository.page.actions.MoveZoneItemAction"/>
+		  	<map:action name="zoneitem-moveinto" src="org.ametys.web.repository.page.actions.MoveIntoZoneItemAction"/>
 		  	<map:action name="zoneitem-remove" src="org.ametys.web.repository.page.actions.RemoveZoneItemAction"/>
 		  	
 		  	<map:action name="create-site" src="org.ametys.web.site.CreateSiteAction"/>
@@ -591,6 +593,36 @@
 				</map:act>
 			</map:match>
 			
+			<map:match pattern="zoneitem/moveTo">
+				<map:act type="zoneitem-moveto">
+					<map:generate type="action-result"/>
+					<map:serialize type="xml"/>
+				</map:act>
+			</map:match>
+			
+			<map:match pattern="zoneitem/moveUp">
+				<map:act type="zoneitem-moveinto">
+					<map:parameter name="direction" value="up"/>
+				
+					<map:generate type="action-result"/>
+					<map:serialize type="xml"/>
+				</map:act>
+			</map:match>
+			<map:match pattern="zoneitem/moveDown">
+				<map:act type="zoneitem-moveinto">
+					<map:parameter name="direction" value="down"/>
+				
+					<map:generate type="action-result"/>
+					<map:serialize type="xml"/>
+				</map:act>
+			</map:match>
+			<map:match pattern="zoneitem/moveTo">
+				<map:act type="zoneitem-moveto">
+					<map:generate type="action-result"/>
+					<map:serialize type="xml"/>
+				</map:act>
+			</map:match>
+			
 			<map:match pattern="zoneitem/service">
 				<map:generate type="zoneitem-service"/>
 				<map:serialize type="xml"/>