Index: main/plugin-odf-web/i18n/messages_en.xml
===================================================================
--- main/plugin-odf-web/i18n/messages_en.xml	(revision 37480)
+++ main/plugin-odf-web/i18n/messages_en.xml	(working copy)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-   Copyright 2010 Anyware Services
+   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.
@@ -33,6 +33,8 @@
     <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_PROGRAMBY_DESCRIPTION">Right to insert the program by criteria services (by domain, by degree, ...)</message>
 	<message key="PLUGINS_ODFWEB_RIGHT_SERVICE_SCHEMA_LABEL">Schema of studies</message>
     <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_SCHEMA_DESCRIPTION">Right to insert the schema of studies</message>
+    <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_CART_LABEL">Cart display</message>
+    <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_CART_DESCRIPTION">Right to create the cart display service.</message>
    
 	<message key="PLUGINS_ODFWEB_ODF_ROOT_PAGE_LABEL">ODF root page</message>
 	<message key="PLUGINS_ODFWEB_ODF_ROOT_PAGE_DESCRIPTION">Sets or remove the ODF root page </message>
@@ -293,6 +295,18 @@
     <message key="PLUGINS_ODFWEB_SERVICE_PROGRAMS_SCHEMA_DERSO">Odontology</message>
     <message key="PLUGINS_ODFWEB_SERVICE_PROGRAMS_SCHEMA_DESF">Midwife degree</message>
     
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_LABEL">Programs and courses cart</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_DESCRIPTION">Display the programs and the courses of the cart.</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_HEADER">Title</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_HEADER_DESCRIPTION">Title of the service (Optional)</message>  
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_XSLT">Display</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_XSLT_DESCRIPTION">The display that will be used for the service.</message>  
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_XSLT_VIEW_LABEL">Default</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_HINT">This service displays the list of programs and courses that have been added to the cart during the navigation session</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_PROGRAM">Programs : </message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_COURSE">Courses : </message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_REMOVE">Remove from cart</message>
+        
     <message key="PLUGINS_ODFWEB_SERVICE_SEARCH_SCHEMA_BO_UNAVAILABLE_TITLE">Unavailable inside CMS</message>
     <message key="PLUGINS_ODFWEB_SERVICE_SEARCH_SCHEMA_BO_UNAVAILABLE_DESC">This feature is not available inside the CMS.&lt;br&gt;You could test it in preview mode or live mode.</message>
 
Index: main/plugin-odf-web/i18n/messages_fr.xml
===================================================================
--- main/plugin-odf-web/i18n/messages_fr.xml	(revision 37480)
+++ main/plugin-odf-web/i18n/messages_fr.xml	(working copy)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-   Copyright 2010 Anyware Services
+   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.
@@ -33,6 +33,8 @@
     <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_PROGRAMBY_DESCRIPTION">Droit de créer les services d'affichage des formations par critère (par domaine, par diplôme, ...)</message>
 	<message key="PLUGINS_ODFWEB_RIGHT_SERVICE_SCHEMA_LABEL">Schéma des formations</message>
     <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_SCHEMA_DESCRIPTION">Droit de créer le service schéma des formations</message>
+    <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_CART_LABEL">Affichage du panier</message>
+    <message key="PLUGINS_ODFWEB_RIGHT_SERVICE_CART_DESCRIPTION">Droit de créer le service d'affichage du panier.</message>
     
 	<message key="PLUGINS_ODFWEB_ODF_ROOT_PAGE_LABEL">Racine de l'ODF</message>
 	<message key="PLUGINS_ODFWEB_ODF_ROOT_PAGE_DESCRIPTION">Positionne ou supprime la racine de l'offre de formation</message>
@@ -293,6 +295,18 @@
     <message key="PLUGINS_ODFWEB_SERVICE_PROGRAMS_SCHEMA_DERSO">Odontologie</message>
     <message key="PLUGINS_ODFWEB_SERVICE_PROGRAMS_SCHEMA_DESF">Diplôme d'Etat de Sage-femmes</message>
     
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_LABEL">Panier de formations et de d'UE</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_DESCRIPTION">Affichage des formations et des UE du panier.</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_HEADER">Titre</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_HEADER_DESCRIPTION">Titre du service (Optionnel)</message>  
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_XSLT">Affichage</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_XSLT_DESCRIPTION">Rendu à utiliser pour l'affichage du service</message>  
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_XSLT_VIEW_LABEL">Par défaut</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_HINT">Ce service permet d\'afficher la liste des formations et des éléments pédagogiques ayant été rajoutés au panier lors d\'une session de navigation.</message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_PROGRAM">Formations : </message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_COURSE">Eléments pédagogiques : </message>
+    <message key="PLUGINS_ODFWEB_SERVICE_CART_REMOVE">Enlever du panier</message>
+    
     <message key="PLUGINS_ODFWEB_SERVICE_SEARCH_SCHEMA_BO_UNAVAILABLE_TITLE">Indisponible dans le CMS</message>
     <message key="PLUGINS_ODFWEB_SERVICE_SEARCH_SCHEMA_BO_UNAVAILABLE_DESC">Cette fonctionnalité n'est pas disponible dans le CMS.&lt;br&gt;Vous pouvez la tester en mode prévisualisation ou mode version en ligne.</message>
     
Index: main/plugin-odf-web/pages/services/cart/cart.xml
===================================================================
--- main/plugin-odf-web/pages/services/cart/cart.xml	(revision 0)
+++ main/plugin-odf-web/pages/services/cart/cart.xml	(revision 0)
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+   -->
+<service>
+    <label i18n="true">PLUGINS_ODFWEB_SERVICE_CART_XSLT_VIEW_LABEL</label>
+</service>
Index: main/plugin-odf-web/pages/services/cart/cart.xsl
===================================================================
--- main/plugin-odf-web/pages/services/cart/cart.xsl	(revision 0)
+++ main/plugin-odf-web/pages/services/cart/cart.xsl	(revision 0)
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+   -->
+<xsl:stylesheet version="1.0" 
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:i18n="http://apache.org/cocoon/i18n/2.1"
+                xmlns:ametys="org.ametys.web.transformation.xslt.AmetysXSLTHelper"
+                extension-element-prefixes="ametys">
+    
+    <xsl:import href="service:web://pages/services/common.xsl"/>
+
+    <xsl:param name="header" select="ametys:serviceParameter('header')"/>
+    
+    <!-- Used in common.xsl -->
+    <xsl:variable name="common-service-css-class-name">odf-cart</xsl:variable>
+    <xsl:variable name="common-service-name">service-odf-cart</xsl:variable> 
+
+    <!-- +
+         | HEAD
+         + -->
+    
+    <!-- Used in common.xsl -->
+    <xsl:template name="common-service-head-css">
+        <link rel="stylesheet" type="text/css" href="{ametys:pluginResourceURL('odf-web', 'css/services/cart.css')}" media="screen, print, handheld"/> 
+    </xsl:template>
+    
+    <!-- Used in common.xsl -->
+    <xsl:template name="common-service-head-title">
+        <xsl:call-template name="common-service-head-title-content">
+            <xsl:with-param name="title" select="$header"/>        
+        </xsl:call-template>
+    </xsl:template>   
+    
+    <!-- Used in common.xsl -->
+    <xsl:template name="common-service-head-js">
+        <script type="text/javascript" src="{ametys:pluginResourceURL('odf-web', 'js/org/helper/cart-helper.js')}"></script>
+        <script type="text/javascript">
+            function renderList(list)
+            {
+                function renderListItem(id, listItem)
+                {
+                    document.write('&lt;li&gt;');
+	                    document.writeln('&lt;div&gt;');
+	                           
+	                        <!-- Delete from cart button -->
+		                    document.writeln('&lt;img onclick=\"remove(\'' + id + '\');document.location.reload(false);\" src=\"<xsl:value-of select="ametys:pluginResourceURL('odf-web', 'img/services/delete_cart_16.png')"/>\" type=\"image/png\" title=\"<i18n:text i18n:key="PLUGINS_ODFWEB_SERVICE_CART_REMOVE"/>\" alt=\"<i18n:text i18n:key="PLUGINS_ODFWEB_SERVICE_CART_REMOVE"/>\"/&gt;');
+		                    
+		                    <!-- Link -->
+		                    <xsl:choose>
+		                        <xsl:when test="$rendering-context = 'back'">
+		                            document.writeln('&lt;a onclick=\"javascript:parent.org.ametys.uitool.ToolsManager.getInstance().openTool(\'uitool-page\', {id: \'' + listItem.pageId + '\'});\"&gt;' + listItem.title + '&lt;/a&gt;');
+		                        </xsl:when>
+		                        <xsl:otherwise>
+		                            document.writeln('&lt;a href=\"' + listItem.pageURL + '\" title=\"' + listItem.title + '\"&gt;' + listItem.title + '&lt;/a&gt;');
+		                        </xsl:otherwise>                    
+		                    </xsl:choose>
+	                    document.writeln('&lt;/div&gt;')
+                    document.write('&lt;/li&gt;');
+                }
+                                
+                document.write('&lt;ul&gt;');  
+                for (var id in list)
+                {
+                 renderListItem(id, list[id]); 
+                }
+                document.write('&lt;/ul&gt;');
+            }
+        </script>
+        
+    </xsl:template>
+    
+    <!-- Used in common.xsl --> 
+    <xsl:template name="common-service-body-nonempty-content-title">
+        <xsl:call-template name="common-service-body-nonempty-content-title-content">
+            <xsl:with-param name="title" select="$header"/>
+        </xsl:call-template>    
+    </xsl:template>
+    
+    <!-- Used in common.xsl --> 
+    <xsl:template name="common-service-body-nonempty-content-content">
+        <xsl:call-template name="cart"/>
+    </xsl:template>
+    
+    <!-- Rendering of the stored contents -->
+    <xsl:template name="cart">
+        <script type="text/javascript">
+            document.writeln('&lt;div&gt;<i18n:text i18n:key="PLUGINS_ODFWEB_SERVICE_CART_HINT"/>&lt;/div&gt; &lt;br /&gt;');
+            
+            var programs = getPrograms();
+            var courses = getCourses();
+            
+            if (Object.keys(programs).length &gt; 0)
+            {
+                document.writeln('&lt;div&gt;');
+                    document.writeln('&lt;strong&gt;<i18n:text i18n:key="PLUGINS_ODFWEB_SERVICE_CART_PROGRAM"/>&lt;/strong&gt;');
+                    renderList(programs);
+                document.writeln('&lt;/div&gt;');
+            }
+            
+            if (Object.keys(courses).length &gt; 0)
+            {
+                document.writeln('&lt;div&gt;');
+	                document.writeln('&lt;strong&gt;<i18n:text i18n:key="PLUGINS_ODFWEB_SERVICE_CART_COURSE"/>&lt;/strong&gt;');
+	                renderList(courses);
+                document.writeln('&lt;/div&gt;');
+            }
+        </script>            
+    </xsl:template>
+</xsl:stylesheet>
Index: main/plugin-odf-web/plugin.xml
===================================================================
--- main/plugin-odf-web/plugin.xml	(revision 37480)
+++ main/plugin-odf-web/plugin.xml	(working copy)
@@ -704,6 +704,59 @@
         </extensions>
     </feature>
     
+    <feature name="odf.services.cart">
+        <extensions>
+            <extension point="org.ametys.runtime.plugins.core.right.RightsExtensionPoint"
+                       id="org.ametys.odf.service.cart.rights">
+                <right id="Odf_Right_Service_Cart">
+                    <label i18n="true">PLUGINS_ODFWEB_RIGHT_SERVICE_CART_LABEL</label>
+                    <description i18n="true">PLUGINS_ODFWEB_RIGHT_SERVICE_CART_DESCRIPTION</description>
+                    <category i18n="true">plugin.web:PLUGINS_WEB_RIGHTS_SERVICE_CREATE_CATEGORY</category>
+                </right>
+            </extension>
+            
+            <extension point="org.ametys.web.service.ServiceExtensionPoint"
+                       class="org.ametys.web.service.StaticService"
+                       id="org.ametys.odf.service.CartService">
+
+                <url>service/cart.html</url>
+                <right>Odf_Right_Service_Cart</right>
+                
+                <label i18n="true">PLUGINS_ODFWEB_SERVICE_CART_LABEL</label>
+                <description i18n="true">PLUGINS_ODFWEB_SERVICE_CART_DESCRIPTION</description>
+                <category i18n="true">PLUGINS_WEB_SERVICE_CATEGORY_31_ODF</category>
+                <thumbnail>
+                    <small>img/services/cart_16.png</small>
+                    <medium>img/services/cart_32.png</medium>
+                    <large>img/services/cart_48.png</large>
+                </thumbnail>
+                
+                <parameters>
+                    <parameter name="header" type="string">
+                        <label i18n="true">PLUGINS_ODFWEB_SERVICE_CART_HEADER</label>
+                        <description i18n="true">PLUGINS_ODFWEB_SERVICE_CART_HEADER_DESCRIPTION</description>
+                    </parameter>
+                    <parameter name="xslt" type="string">
+                        <label i18n="true">PLUGINS_ODFWEB_SERVICE_CART_XSLT</label>
+                        <description i18n="true">PLUGINS_ODFWEB_SERVICE_CART_XSLT_DESCRIPTION</description>
+                        <default-value>pages/services/cart/cart.xsl</default-value>
+                        <enumeration>
+                            <custom-enumerator class="org.ametys.web.service.ServiceXSLTEnumerator">
+                                <path>pages/services/cart</path>
+                                <values>
+                                    <value>pages/services/cart/cart.xsl</value>
+                                </values>
+                            </custom-enumerator>
+                        </enumeration>
+                    </parameter>
+                </parameters>
+                <indexation>
+                    <parameter>header</parameter>
+                </indexation>
+            </extension>
+        </extensions>  
+    </feature>
+    
     <feature name="insert-program-service">
         <extensions>
             <extension point="org.ametys.runtime.plugins.core.right.RightsExtensionPoint"
Index: main/plugin-odf-web/resources/css/services/cart.css
===================================================================
--- main/plugin-odf-web/resources/css/services/cart.css	(revision 0)
+++ main/plugin-odf-web/resources/css/services/cart.css	(revision 0)
@@ -0,0 +1,30 @@
+/*
+ *  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.
+ */
+
+.odf-cart div ul li
+{
+	margin: 5px;
+}
+
+.odf-cart div ul li div img 
+{
+    cursor: pointer;
+}
+
+.odf-cart div ul li div a
+{
+	cursor: pointer;
+}
\ No newline at end of file
Index: main/plugin-odf-web/resources/js/org/helper/cart-helper.js
===================================================================
--- main/plugin-odf-web/resources/js/org/helper/cart-helper.js	(revision 0)
+++ main/plugin-odf-web/resources/js/org/helper/cart-helper.js	(revision 0)
@@ -0,0 +1,92 @@
+/*
+ *  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.
+ */
+
+/**
+ * Add a program to the cart
+ * @param {String} id the id of the program to add
+ * @param {String} pageId the id of the corresponding page
+ * @param {String} pageURL the URL of the corresponding page
+ * @param {String} title the title of the program
+ */
+function addProgram (id, pageId, pageURL, title)
+{
+	_addInternal(id, pageId, pageURL, title, 'programs');
+}
+
+/**
+ * Add a course to the cart
+ * @param {String} id the id of the program to add
+ * @param {String} pageId the id of the corresponding page
+ * @param {String} pageURL the URL of the corresponding page
+ * @param {String} title the title of the course
+ */
+function addCourse (id, pageId, pageURL, title)
+{
+	_addInternal(id, pageId, pageURL, title, 'courses');
+}
+
+/**
+ * Get the program ids of the cart
+ * @return {String[]} the list of program ids of the cart
+ */
+function getPrograms ()
+{
+	return sessionStorage.programs ? JSON.parse(sessionStorage.programs) : {}; 
+}
+
+/**
+ * Get the course ids of the cart
+ * @return {String[]} the list of course ids of the cart
+ */
+function getCourses ()
+{
+	return sessionStorage.courses ? JSON.parse(sessionStorage.courses) : {};
+}
+
+/**
+ * Remove the element corresponding to the given id
+ * @param {String} id the id of the program/course to remove from the cart  
+ */
+function remove (id)
+{
+	if (sessionStorage.programs)
+	{
+		var storedPrograms = JSON.parse(sessionStorage.programs);
+		delete storedPrograms[id];
+		sessionStorage.programs = JSON.stringify(storedPrograms);
+	}
+	
+	if (sessionStorage.courses)
+	{
+		var storedCourses = JSON.parse(sessionStorage.courses);
+		delete storedCourses[id];
+		sessionStorage.courses = JSON.stringify(storedCourses);
+	}
+}
+
+function _addInternal (id, pageId, pageURL, title, type)
+{
+	if (!sessionStorage[type])
+	{
+		sessionStorage[type] = '{}';
+	}
+	
+	var storedEntities = JSON.parse(sessionStorage[type]);
+	storedEntities[id] = {pageId, pageURL, title};
+	
+	sessionStorage[type] = JSON.stringify(storedEntities);
+}
+
Index: main/plugin-odf-web/sitemap.xmap
===================================================================
--- main/plugin-odf-web/sitemap.xmap	(revision 37480)
+++ main/plugin-odf-web/sitemap.xmap	(working copy)
@@ -172,6 +172,20 @@
 				<map:serialize type="xhtml"/>
 			</map:match>
 			
+			<!-- +
+			     | CART
+			     + -->
+           <map:match pattern="service/cart.html">
+                <map:generate type="action-result">
+                </map:generate>
+                <map:transform src="service://@xslt" type="xslt"/>
+                <map:transform type="i18n">
+                    <map:parameter name="locale" value="{request-attr:sitemapLanguage}"/>
+                    <map:parameter name="plugin" value="{request-attr:pluginName}"/>
+                </map:transform>
+                <map:serialize type="xhtml"/>
+           </map:match>
+
             <!-- +
                  | CDM-fr
                  +  -->
