merge default doc-dc
authorDamien Correia
Fri, 15 Jun 2018 14:12:29 +0200
branchdoc-dc
changeset 699 49609728216b
parent 698 9d60cec4b172 (current diff)
parent 692 58f3c1b9bcfc (diff)
child 700 c2a4aa515526
merge default
--- a/src/pyams_content/component/illustration/__init__.py	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/component/illustration/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -66,6 +66,14 @@
             if IImage.providedBy(data):
                 alsoProvides(data, IResponsiveImage)
 
+    def has_data(self):
+        if not self._data:
+            return False
+        for data in self._data.values():
+            if bool(data):
+                return True
+        return False
+
 
 @adapter_config(context=IBasicIllustrationTarget, provides=IIllustration)
 def basic_illustration_factory(context):
--- a/src/pyams_content/component/illustration/interfaces/__init__.py	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/component/illustration/interfaces/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -45,6 +45,9 @@
                                    description=_("Image or video content"),
                                    required=False)
 
+    def has_data(self):
+        """Check if data is provided in any language"""
+
     title = I18nTextLineField(title=_("Legend"),
                               required=False)
 
--- a/src/pyams_content/component/links/zmi/__init__.py	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/component/links/zmi/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -223,6 +223,7 @@
 
     legend = _("Edit external link properties")
     icon_css_class = 'fa fa-fw fa-external-link'
+    dialog_class = 'modal-large'
 
     fields = field.Fields(IExternalLink).select('url', 'title', 'description', 'pictogram_name', 'language')
     fields['pictogram_name'].widgetFactory = PictogramSelectFieldWidget
--- a/src/pyams_content/features/menu/interfaces/__init__.py	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/features/menu/interfaces/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -71,5 +71,5 @@
     contains(IMenu)
 
 
-class IMenusContainerTarget(IAttributeAnnotatable):
+class IMenusContainerTarget(IAssociationContainerTarget):
     """Menus container target marker interface"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+
+# import packages
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+
+# import packages
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/double.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,84 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.association.interfaces import ASSOCIATION_CONTAINER_KEY
+from pyams_content.component.illustration.interfaces import IBasicIllustrationTarget
+from pyams_content.features.menu.interfaces import IMenusContainer, IMenusContainerTarget
+from pyams_content.features.menu.portlet.navigation.interfaces.double import IDoubleNavigationPortletSettings, \
+    IDoubleNavigationMenu, IDoubleNavigationMenusContainer
+from pyams_utils.interfaces import VIEW_PERMISSION
+from zope.lifecycleevent.interfaces import IObjectAddedEvent
+
+# import packages
+from pyams_content.features.menu import MenusContainer
+from pyams_portal.portlet import PortletSettings, portlet_config, Portlet
+from pyams_utils.adapter import get_annotation_adapter, adapter_config
+from pyams_utils.factory import factory_config
+from pyramid.events import subscriber
+from zope.interface import implementer, alsoProvides
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
+
+
+DOUBLE_NAVIGATION_PORTLET_NAME = 'pyams_content.portlet.navigation.double'
+DOUBLE_NAVIGATION_LINKS_KEY = '{0}::menus'.format(ASSOCIATION_CONTAINER_KEY)
+
+
+@implementer(IDoubleNavigationPortletSettings, IMenusContainerTarget)
+@factory_config(provided=IDoubleNavigationPortletSettings)
+class DoubleNavigationPortletSettings(PortletSettings):
+    """Double navigation portlet settings"""
+
+    title = FieldProperty(IDoubleNavigationPortletSettings['title'])
+    subtitle = FieldProperty(IDoubleNavigationPortletSettings['subtitle'])
+
+    @property
+    def menus(self):
+        return get_annotation_adapter(self, DOUBLE_NAVIGATION_LINKS_KEY, MenusContainer,
+                                      markers=IDoubleNavigationMenusContainer, name='++ass++menus')
+
+
+@adapter_config(name='menus', context=IDoubleNavigationPortletSettings, provides=IMenusContainer)
+def simple_navigation_links_adapter(context):
+    """Double navigation menus factory"""
+    return context.menus
+
+
+@portlet_config(permission=VIEW_PERMISSION)
+class DoubleNavigationPortlet(Portlet):
+    """Double navigation portlet"""
+
+    name = DOUBLE_NAVIGATION_PORTLET_NAME
+    label = _("Double navigation")
+
+    toolbar_css_class = 'fa fa-fw fa-2x fa-list-alt'
+
+    settings_factory = IDoubleNavigationPortletSettings
+
+
+@subscriber(IObjectAddedEvent, parent_selector=IDoubleNavigationMenusContainer)
+def handle_added_navigation_menu(event):
+    """Add marker interface to added menus container"""
+    alsoProvides(event.object, IDoubleNavigationMenu, IBasicIllustrationTarget)
+
+
+@subscriber(IObjectAddedEvent, parent_selector=IDoubleNavigationMenu)
+def handle_added_navigation_menu_link(event):
+    """Add marker interface to added menu link"""
+    alsoProvides(event.object, IBasicIllustrationTarget)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/interfaces/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,1 @@
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/interfaces/double.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_portal.interfaces import IPortletSettings
+
+# import packages
+from pyams_i18n.schema import I18nTextLineField
+from zope.interface import Interface, Attribute
+
+from pyams_content import _
+
+
+class IDoubleNavigationPortletSettings(IPortletSettings):
+    """Double navigation portlet settings interface"""
+
+    title = I18nTextLineField(title=_("Title"),
+                              description=_("Portlet main title"),
+                              required=False)
+
+    subtitle = I18nTextLineField(title=_("Subtitle"),
+                                 description=_("Portlet subtitle"),
+                                 required=False)
+
+    menus = Attribute("Navigation menus")
+
+
+class IDoubleNavigationMenusContainer(Interface):
+    """Double navigation menus container marker interface"""
+
+
+class IDoubleNavigationMenu(Interface):
+    """Double navigation menu marker interface"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_portal.interfaces import IPortletSettings
+
+# import packages
+from pyams_i18n.schema import I18nTextLineField
+from zope.interface import Interface, Attribute
+
+from pyams_content import _
+
+
+class ISimpleNavigationPortletSettings(IPortletSettings):
+    """Simple navigation portlet settings interface"""
+
+    title = I18nTextLineField(title=_("Title"),
+                              description=_("Portlet main title"),
+                              required=False)
+
+    subtitle = I18nTextLineField(title=_("Subtitle"),
+                                 description=_("Portlet subtitle"),
+                                 required=False)
+
+    links = Attribute("Navigation links")
+
+
+class ISimpleNavigationMenu(Interface):
+    """Simple navigation menu marker interface"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/simple.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,77 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.association.interfaces import ASSOCIATION_CONTAINER_KEY
+from pyams_content.component.illustration import IBasicIllustrationTarget
+from pyams_content.features.menu.interfaces import IMenuLinksContainer, IMenuLinksContainerTarget
+from pyams_content.features.menu.portlet.navigation.interfaces.simple import ISimpleNavigationPortletSettings, \
+    ISimpleNavigationMenu
+from pyams_utils.interfaces import VIEW_PERMISSION
+from zope.lifecycleevent.interfaces import IObjectAddedEvent
+
+# import packages
+from pyams_content.features.menu import Menu
+from pyams_portal.portlet import PortletSettings, portlet_config, Portlet
+from pyams_utils.adapter import get_annotation_adapter, adapter_config
+from pyams_utils.factory import factory_config
+from pyramid.events import subscriber
+from zope.interface import implementer, alsoProvides
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
+
+
+SIMPLE_NAVIGATION_PORTLET_NAME = 'pyams_content.portlet.navigation.simple'
+SIMPLE_NAVIGATION_LINKS_KEY = '{0}::links'.format(ASSOCIATION_CONTAINER_KEY)
+
+
+@implementer(ISimpleNavigationPortletSettings, IMenuLinksContainerTarget)
+@factory_config(provided=ISimpleNavigationPortletSettings)
+class SimpleNavigationPortletSettings(PortletSettings):
+    """Simple navigation portlet settings"""
+
+    title = FieldProperty(ISimpleNavigationPortletSettings['title'])
+    subtitle = FieldProperty(ISimpleNavigationPortletSettings['subtitle'])
+
+    @property
+    def links(self):
+        return get_annotation_adapter(self, SIMPLE_NAVIGATION_LINKS_KEY, Menu,
+                                      markers=ISimpleNavigationMenu, name='++ass++links')
+
+
+@adapter_config(name='links', context=ISimpleNavigationPortletSettings, provides=IMenuLinksContainer)
+def simple_navigation_links_adapter(context):
+    """Simple navigation links factory"""
+    return context.links
+
+
+@portlet_config(permission=VIEW_PERMISSION)
+class SimpleNavigationPortlet(Portlet):
+    """Simple navigation portlet"""
+
+    name = SIMPLE_NAVIGATION_PORTLET_NAME
+    label = _("Simple navigation")
+
+    toolbar_css_class = 'fa fa-fw fa-2x fa-bars'
+
+    settings_factory = ISimpleNavigationPortletSettings
+
+
+@subscriber(IObjectAddedEvent, parent_selector=ISimpleNavigationMenu)
+def handle_added_navigation_link(event):
+    alsoProvides(event.object, IBasicIllustrationTarget)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/zmi/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+
+# import packages
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/zmi/double.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,100 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.illustration.interfaces import IIllustration
+from pyams_content.component.links.interfaces import IInternalLink
+from pyams_content.features.menu.portlet.navigation.interfaces.double import IDoubleNavigationPortletSettings, \
+    IDoubleNavigationMenu, IDoubleNavigationMenusContainer
+from pyams_form.interfaces.form import IInnerSubForm
+from pyams_pagelet.interfaces import IPagelet
+from pyams_portal.interfaces import IPortletPreviewer
+from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
+from pyams_workflow.interfaces import IWorkflowPublicationInfo
+
+# import packages
+from pyams_content.component.association.interfaces import IAssociationInfo
+from pyams_content.features.menu.zmi import MenusTable, IMenusView, MenusView
+from pyams_form.form import AJAXEditForm
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_portal.portlet import PortletPreviewer
+from pyams_portal.zmi.portlet import PortletSettingsEditor, PortletSettingsPropertiesEditor
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config
+from zope.interface import alsoProvides, Interface
+
+from pyams_content import _
+
+
+@pagelet_config(name='properties.html', context=IDoubleNavigationPortletSettings, layer=IPyAMSLayer,
+                permission=VIEW_SYSTEM_PERMISSION)
+class DoubleNavigationPortletSettingsEditor(PortletSettingsEditor):
+    """Double navigation portlet settings editor"""
+
+    settings = IDoubleNavigationPortletSettings
+
+
+@adapter_config(name='properties.json', context=(IDoubleNavigationPortletSettings, IPyAMSLayer), provides=IPagelet)
+class DoubleNavigationPortletSettingsAJAXEditor(AJAXEditForm, DoubleNavigationPortletSettingsEditor):
+    """Double navigation portlet settings editor, JSON renderer"""
+
+
+class DoubleNavigationPortletMenusTable(MenusTable):
+    """Double navigation portlet menus table"""
+
+    associations_name = 'menus'
+
+
+@adapter_config(name='double-navigation-menus',
+                context=(IDoubleNavigationPortletSettings, IPyAMSLayer, PortletSettingsPropertiesEditor),
+                provides=IInnerSubForm)
+@adapter_config(name='++ass++menus', context=(IDoubleNavigationMenusContainer, IPyAMSLayer), provides=IMenusView)
+class DoubleNavigationPortletLinksView(MenusView):
+    """Double navigation portlet menus view"""
+
+    title = _("Navigation menus")
+
+    table_class = DoubleNavigationPortletMenusTable
+    weight = 10
+
+
+@adapter_config(context=(Interface, IPyAMSLayer, Interface, IDoubleNavigationPortletSettings),
+                provides=IPortletPreviewer)
+@template_config(template='templates/double-preview.pt', layer=IPyAMSLayer)
+class DoubleNavigationPortletPreviewer(PortletPreviewer):
+    """Double navigation portlet previewer"""
+
+    @classmethod
+    def get_link_info(cls, link):
+        return IAssociationInfo(link)
+
+    @classmethod
+    def get_link_status(cls, link):
+        if not IInternalLink.providedBy(link):
+            return True
+        target = link.get_target()
+        return (target is not None) and IWorkflowPublicationInfo(target).is_published()
+
+    @classmethod
+    def get_link_illustration(cls, link):
+        illustration = IIllustration(link, None)
+        if (illustration is None) or not illustration.has_data():
+            if IInternalLink.providedBy(link):
+                target = link.get_target()
+                illustration = IIllustration(target)
+        return illustration
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/zmi/simple.py	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,100 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.illustration.interfaces import IIllustration
+from pyams_content.component.links.interfaces import IInternalLink
+from pyams_content.features.menu.portlet.navigation.interfaces.simple import ISimpleNavigationPortletSettings, \
+    ISimpleNavigationMenu
+from pyams_form.interfaces.form import IInnerSubForm
+from pyams_pagelet.interfaces import IPagelet
+from pyams_portal.interfaces import IPortletPreviewer
+from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
+from pyams_workflow.interfaces import IWorkflowPublicationInfo
+
+# import packages
+from pyams_content.component.association.interfaces import IAssociationInfo
+from pyams_content.features.menu.zmi import LinksTable, IMenuLinksView, MenuLinksView
+from pyams_form.form import AJAXEditForm
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_portal.portlet import PortletPreviewer
+from pyams_portal.zmi.portlet import PortletSettingsEditor, PortletSettingsPropertiesEditor
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config
+from zope.interface import alsoProvides, Interface
+
+from pyams_content import _
+
+
+@pagelet_config(name='properties.html', context=ISimpleNavigationPortletSettings, layer=IPyAMSLayer,
+                permission=VIEW_SYSTEM_PERMISSION)
+class SimpleNavigationPortletSettingsEditor(PortletSettingsEditor):
+    """Simple navigation portlet settings editor"""
+
+    settings = ISimpleNavigationPortletSettings
+
+
+@adapter_config(name='properties.json', context=(ISimpleNavigationPortletSettings, IPyAMSLayer), provides=IPagelet)
+class SimpleNavigationPortletSettingsAJAXEditor(AJAXEditForm, SimpleNavigationPortletSettingsEditor):
+    """Simple navigation portlet settings editor, JSON renderer"""
+
+
+class SimpleNavigationPortletLinksTable(LinksTable):
+    """Simple navigation portlet links table"""
+
+    associations_name = 'links'
+
+
+@adapter_config(name='simple-navigation-links',
+                context=(ISimpleNavigationPortletSettings, IPyAMSLayer, PortletSettingsPropertiesEditor),
+                provides=IInnerSubForm)
+@adapter_config(name='++ass++links', context=(ISimpleNavigationMenu, IPyAMSLayer), provides=IMenuLinksView)
+class SimpleNavigationPortletLinksView(MenuLinksView):
+    """Simple navigation portlet links view"""
+
+    title = _("Navigation links")
+
+    table_class = SimpleNavigationPortletLinksTable
+    weight = 10
+
+
+@adapter_config(context=(Interface, IPyAMSLayer, Interface, ISimpleNavigationPortletSettings),
+                provides=IPortletPreviewer)
+@template_config(template='templates/simple-preview.pt', layer=IPyAMSLayer)
+class SimpleNavigationPortletPreviewer(PortletPreviewer):
+    """Simple navigation portlet previewer"""
+
+    @classmethod
+    def get_link_info(cls, link):
+        return IAssociationInfo(link)
+
+    @classmethod
+    def get_link_status(cls, link):
+        if not IInternalLink.providedBy(link):
+            return True
+        target = link.get_target()
+        return (target is not None) and IWorkflowPublicationInfo(target).is_published()
+
+    @classmethod
+    def get_link_illustration(cls, link):
+        illustration = IIllustration(link, None)
+        if (illustration is None) or not illustration.has_data():
+            if IInternalLink.providedBy(link):
+                target = link.get_target()
+                illustration = IIllustration(target)
+        return illustration
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,26 @@
+<div tal:define="settings view.settings">
+	<strong tal:content="i18n:settings.title">Title</strong>
+	<tal:var define="subtitle i18n:settings.subtitle" condition="subtitle" content="subtitle" />
+	<ul>
+		<li tal:repeat="menu settings.menus.get_visible_items()">
+			<span tal:content="i18n:menu.title">Title</span>
+			<ul>
+				<li tal:repeat="link menu.get_visible_items()"
+					tal:attributes="illustration view.get_link_illustration(link);">
+					<i class="fa fa-fw fa-eye-slash text-danger hint opaque align-base"
+					   tal:condition="not:view.get_link_status(link)"
+					   title="Link target is not published!" i18n:attributes="title"></i>
+					<i class="fa fa-fw fa-file-image-o text-danger hint opaque align-base"
+					   tal:define="illustration view.get_link_illustration(link)"
+					   tal:condition="not:illustration and illustration.has_data()"
+					   title="Link has no illustration"></i>
+					<tal:var define="info view.get_link_info(link)">
+						<span tal:content="info.user_title">User title</span>
+						&ndash;
+						<span tal:content="info.inner_title">Inner title</span>
+					</tal:var>
+				</li>
+			</ul>
+		</li>
+	</ul>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,21 @@
+<div tal:define="settings view.settings">
+	<strong tal:content="i18n:settings.title">Title</strong>
+	<tal:var define="subtitle i18n:settings.subtitle" condition="subtitle" content="subtitle" />
+	<ul>
+		<li tal:repeat="link settings.links.get_visible_items()"
+			tal:attributes="illustration view.get_link_illustration(link);">
+			<i class="fa fa-fw fa-eye-slash text-danger hint opaque align-base"
+			   tal:condition="not:view.get_link_status(link)"
+			   title="Link target is not published!" i18n:attributes="title"></i>
+			<i class="fa fa-fw fa-file-image-o text-danger hint opaque align-base"
+			   tal:define="illustration view.get_link_illustration(link)"
+			   tal:condition="not:illustration and illustration.has_data()"
+			   title="Link has no illustration"></i>
+			<tal:var define="info view.get_link_info(link)">
+				<span tal:content="info.user_title">User title</span>
+				&ndash;
+				<span tal:content="info.inner_title">Inner title</span>
+			</tal:var>
+		</li>
+	</ul>
+</div>
--- a/src/pyams_content/features/menu/zmi/__init__.py	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/features/menu/zmi/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -28,6 +28,7 @@
 from pyams_skin.layer import IPyAMSLayer
 from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
 from pyams_viewlet.interfaces import IViewletManager
+from pyams_zmi.interfaces import IPropertiesEditForm
 from z3c.table.interfaces import IValues, IColumn
 
 # import packages
@@ -48,6 +49,7 @@
 from pyams_zmi.zmi.table import InnerTableView
 from pyramid.decorator import reify
 from pyramid.exceptions import NotFound
+from pyramid.renderers import render
 from pyramid.view import view_config
 from z3c.form import field
 from zope.interface import implementer, alsoProvides, Interface
@@ -114,12 +116,15 @@
 
 @pagelet_config(name='properties.html', context=IMenu, layer=IPyAMSLayer, permission=MANAGE_TEMPLATE_PERMISSION)
 @ajax_config(name='properties.json', context=IMenu, layer=IPyAMSLayer)
+@implementer(IPropertiesEditForm)
 class MenuPropertiesEditForm(AdminDialogEditForm):
     """Menu properties edit form"""
 
     legend = _("Edit menu properties")
     icon_css_class = 'fa fa-fw fa-bars'
 
+    dialog_class = 'modal-large'
+
     fields = field.Fields(IMenu).select('title')
     edit_permission = MANAGE_TEMPLATE_PERMISSION
 
@@ -205,17 +210,7 @@
     weight = 10
 
     def renderCell(self, item):
-        return '<span data-ams-stop-propagation="true" ' \
-               '      data-ams-click-handler="MyAMS.skin.switchCellContent" ' \
-               '      data-ams-switch-handler="get-menu-items.json" ' \
-               '      data-ams-switch-target=".menus">' \
-               '    <span class="small hint" title="{hint}" data-ams-hint-gravity="e">' \
-               '        <i class="fa fa-plus-square-o switch"></i>' \
-               '    </span>' \
-               '</span>&nbsp;&nbsp;&nbsp;<span class="title">{title}</span>' \
-               '<div class="inner-table-form menus margin-x-10 margin-bottom-0 padding-left-5"></div>'.format(
-            hint=self.request.localizer.translate(_("Click to see menu items")),
-            title=super(MenusTableNameColumn, self).renderCell(item))
+        return render('templates/menu-name-cell.pt', {'context': item}, request=self.request)
 
 
 @adapter_config(name='trash', context=(IMenusContainerTarget, IPyAMSLayer, MenusTable), provides=IColumn)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/menu/zmi/templates/menu-name-cell.pt	Fri Jun 15 14:12:29 2018 +0200
@@ -0,0 +1,13 @@
+<i18n:v domain="pyams_content">
+	<span data-ams-stop-propagation="true"
+		  data-ams-click-handler="MyAMS.skin.switchCellContent"
+		  data-ams-switch-handler="get-menu-items.json"
+		  data-ams-switch-target=".menus">
+		<span class="small hint"
+			  title="Click to see menu items" i18n:attributes="title"
+			  data-ams-hint-gravity="e">
+			<i class="fa fa-plus-square-o switch"></i>
+		</span>
+	</span>&nbsp;&nbsp;&nbsp;<span class="title" tal:content="i18n:context.title">title</span>
+	<div class="inner-table-form menus margin-x-10 margin-bottom-0 padding-left-5"></div>
+</i18n:v>
Binary file src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.mo has changed
--- a/src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po	Fri Jun 15 14:12:29 2018 +0200
@@ -5,7 +5,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-13 11:31+0200\n"
+"POT-Creation-Date: 2018-06-15 11:05+0200\n"
 "PO-Revision-Date: 2015-09-10 10:42+0200\n"
 "Last-Translator: Thierry Florac <tflorac@ulthar.net>\n"
 "Language-Team: French\n"
@@ -135,7 +135,7 @@
 #: src/pyams_content/component/gallery/zmi/interfaces.py:40
 #: src/pyams_content/component/gallery/interfaces/__init__.py:61
 #: src/pyams_content/component/extfile/interfaces/__init__.py:44
-#: src/pyams_content/component/illustration/interfaces/__init__.py:56
+#: src/pyams_content/component/illustration/interfaces/__init__.py:66
 #: src/pyams_content/component/paragraph/interfaces/video.py:52
 #: src/pyams_content/component/paragraph/interfaces/audio.py:48
 #: src/pyams_content/component/paragraph/interfaces/verbatim.py:44
@@ -180,27 +180,27 @@
 msgstr "Galerie de médias"
 
 #: src/pyams_content/component/gallery/interfaces/__init__.py:47
-#: src/pyams_content/component/illustration/interfaces/__init__.py:41
-#: src/pyams_content/component/illustration/interfaces/__init__.py:77
+#: src/pyams_content/component/illustration/interfaces/__init__.py:44
+#: src/pyams_content/component/illustration/interfaces/__init__.py:91
 msgid "Image or video data"
 msgstr "Fichier"
 
 #: src/pyams_content/component/gallery/interfaces/__init__.py:48
-#: src/pyams_content/component/illustration/interfaces/__init__.py:42
-#: src/pyams_content/component/illustration/interfaces/__init__.py:78
+#: src/pyams_content/component/illustration/interfaces/__init__.py:45
+#: src/pyams_content/component/illustration/interfaces/__init__.py:92
 msgid "Image or video content"
 msgstr ""
 "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu..."
 
 #: src/pyams_content/component/gallery/interfaces/__init__.py:51
-#: src/pyams_content/component/illustration/interfaces/__init__.py:45
+#: src/pyams_content/component/illustration/interfaces/__init__.py:51
 #: src/pyams_content/component/paragraph/interfaces/video.py:45
 #: src/pyams_content/component/video/interfaces/__init__.py:75
 msgid "Legend"
 msgstr "Légende"
 
 #: src/pyams_content/component/gallery/interfaces/__init__.py:54
-#: src/pyams_content/component/illustration/interfaces/__init__.py:48
+#: src/pyams_content/component/illustration/interfaces/__init__.py:54
 #: src/pyams_content/reference/pictograms/interfaces/__init__.py:48
 msgid "Accessibility title"
 msgstr "Alternative (accessibilité)"
@@ -216,7 +216,7 @@
 #: src/pyams_content/component/gallery/interfaces/__init__.py:58
 #: src/pyams_content/component/gallery/interfaces/__init__.py:98
 #: src/pyams_content/component/extfile/interfaces/__init__.py:40
-#: src/pyams_content/component/illustration/interfaces/__init__.py:52
+#: src/pyams_content/component/illustration/interfaces/__init__.py:62
 #: src/pyams_content/component/paragraph/interfaces/video.py:48
 #: src/pyams_content/component/paragraph/interfaces/audio.py:44
 #: src/pyams_content/component/links/interfaces/__init__.py:39
@@ -276,7 +276,7 @@
 
 #: src/pyams_content/component/gallery/interfaces/__init__.py:94
 #: src/pyams_content/component/paragraph/zmi/milestone.py:231
-#: src/pyams_content/component/paragraph/zmi/container.py:224
+#: src/pyams_content/component/paragraph/zmi/container.py:223
 #: src/pyams_content/component/paragraph/interfaces/milestone.py:45
 #: src/pyams_content/component/links/zmi/reverse.py:71
 #: src/pyams_content/shared/common/zmi/dashboard.py:109
@@ -286,6 +286,8 @@
 #: src/pyams_content/root/zmi/templates/advanced-search.pt:188
 #: src/pyams_content/interfaces/__init__.py:99
 #: src/pyams_content/reference/pictograms/zmi/__init__.py:153
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:31
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:31
 msgid "Title"
 msgstr "Titre"
 
@@ -473,10 +475,93 @@
 msgstr ""
 "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu"
 
-#: src/pyams_content/component/illustration/__init__.py:133
-#: src/pyams_content/component/illustration/zmi/__init__.py:54
-#: src/pyams_content/component/illustration/zmi/__init__.py:81
-#: src/pyams_content/component/illustration/interfaces/__init__.py:71
+#: src/pyams_content/component/keynumber/__init__.py:180
+#: src/pyams_content/component/keynumber/zmi/__init__.py:198
+#: src/pyams_content/component/paragraph/interfaces/keynumber.py:29
+msgid "Key numbers"
+msgstr "Chiffres-clés"
+
+#. Default: Header
+#: src/pyams_content/component/keynumber/zmi/__init__.py:146
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:44
+msgid "key-number-label"
+msgstr "En-tête"
+
+#: src/pyams_content/component/keynumber/zmi/__init__.py:158
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:49
+msgid "Number"
+msgstr "Chiffre"
+
+#. Default: Unit
+#: src/pyams_content/component/keynumber/zmi/__init__.py:167
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:53
+msgid "key-number-unit"
+msgstr "Unité"
+
+#: src/pyams_content/component/keynumber/zmi/__init__.py:179
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:57
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:266
+#: src/pyams_content/component/paragraph/interfaces/pictogram.py:58
+msgid "Associated text"
+msgstr "Texte associé"
+
+#: src/pyams_content/component/keynumber/zmi/__init__.py:217
+msgid "Add keynumber"
+msgstr "Ajouter un chiffre-clé"
+
+#: src/pyams_content/component/keynumber/zmi/__init__.py:230
+msgid "Add new keynumber"
+msgstr "Ajout d'un chiffre-clé"
+
+#: src/pyams_content/component/keynumber/zmi/__init__.py:259
+msgid "Edit keynumber properties"
+msgstr "Propriétés du chiffre-clé"
+
+#: src/pyams_content/component/keynumber/zmi/__init__.py:245
+msgid "Key number was correctly added"
+msgstr "Le chiffre-clé a été ajouté."
+
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:39
+#: src/pyams_content/component/paragraph/interfaces/milestone.py:40
+#: src/pyams_content/component/paragraph/interfaces/__init__.py:44
+#: src/pyams_content/component/paragraph/interfaces/pictogram.py:41
+#: src/pyams_content/component/association/interfaces/__init__.py:42
+#: src/pyams_content/shared/form/interfaces/__init__.py:87
+#: src/pyams_content/shared/site/interfaces/__init__.py:117
+#: src/pyams_content/features/alert/interfaces.py:54
+#: src/pyams_content/features/menu/interfaces/__init__.py:58
+msgid "Visible?"
+msgstr "Visible ?"
+
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:40
+msgid "Is this key number visible in front-office?"
+msgstr "Si 'non', ce chiffre-clé ne sera pas présenté aux internautes"
+
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:45
+msgid ""
+"Small text to be displayed above number (according to selected renderer)"
+msgstr ""
+"Texte court affiché au-dessus du chiffre (selon le mode de rendu sélectionné)"
+
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:50
+msgid "Key number value"
+msgstr "Chiffre"
+
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:54
+msgid "Displayed unit"
+msgstr "Unité affichée"
+
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:58
+msgid "The way this text will be rendered depends on presentation template"
+msgstr ""
+"La présentation de cette information peut varier en fonction du mode de "
+"rendu choisi"
+
+#: src/pyams_content/component/illustration/__init__.py:162
+#: src/pyams_content/component/illustration/zmi/__init__.py:55
+#: src/pyams_content/component/illustration/zmi/__init__.py:79
+#: src/pyams_content/component/illustration/zmi/__init__.py:119
+#: src/pyams_content/component/illustration/interfaces/__init__.py:85
 msgid "Illustration"
 msgstr "Illustration"
 
@@ -492,11 +577,11 @@
 msgid "Edit illustration properties"
 msgstr "Propriétés de l'illustration"
 
-#: src/pyams_content/component/illustration/zmi/__init__.py:83
+#: src/pyams_content/component/illustration/zmi/__init__.py:121
 msgid "Header illustration"
 msgstr "Illustration d'en-tête"
 
-#: src/pyams_content/component/illustration/interfaces/__init__.py:49
+#: src/pyams_content/component/illustration/interfaces/__init__.py:55
 #: src/pyams_content/reference/pictograms/interfaces/__init__.py:49
 msgid "Alternate title used to describe image content"
 msgstr ""
@@ -505,15 +590,15 @@
 "déficiences visuelles. Il doit donc décrire le contenu, pour se conformer "
 "aux normes d'accessibilité."
 
-#: src/pyams_content/component/illustration/interfaces/__init__.py:57
+#: src/pyams_content/component/illustration/interfaces/__init__.py:67
 msgid "Name of picture's author"
 msgstr "Sous la forme \"Prénom Nom / Organisme\""
 
-#: src/pyams_content/component/illustration/interfaces/__init__.py:60
+#: src/pyams_content/component/illustration/interfaces/__init__.py:70
 msgid "Illustration template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/illustration/interfaces/__init__.py:61
+#: src/pyams_content/component/illustration/interfaces/__init__.py:71
 msgid "Presentation template used for illustration"
 msgstr ""
 "<span>Modèle de présentation utilisé par cette illustration.<br /"
@@ -676,37 +761,37 @@
 msgid "Contents..."
 msgstr "Contenu"
 
-#: src/pyams_content/component/paragraph/zmi/container.py:240
+#: src/pyams_content/component/paragraph/zmi/container.py:239
 msgid "Show/hide all paragraphs"
 msgstr "Afficher/masquer tous les blocs"
 
-#: src/pyams_content/component/paragraph/zmi/container.py:288
-#: src/pyams_content/component/paragraph/zmi/container.py:297
-#: src/pyams_content/component/paragraph/zmi/container.py:310
+#: src/pyams_content/component/paragraph/zmi/container.py:287
+#: src/pyams_content/component/paragraph/zmi/container.py:296
+#: src/pyams_content/component/paragraph/zmi/container.py:309
 msgid "Content blocks"
 msgstr "Blocs de contenu"
 
-#: src/pyams_content/component/paragraph/zmi/container.py:367
+#: src/pyams_content/component/paragraph/zmi/container.py:366
 msgid "Links and attachments..."
 msgstr "Récap. liens et PJ"
 
-#: src/pyams_content/component/paragraph/zmi/container.py:379
+#: src/pyams_content/component/paragraph/zmi/container.py:378
 msgid "Content blocks links and attachments"
 msgstr "Récapitulatif des liens et pièces jointes par bloc de contenu"
 
-#: src/pyams_content/component/paragraph/zmi/container.py:127
+#: src/pyams_content/component/paragraph/zmi/container.py:126
 msgid "No currently defined paragraph."
 msgstr "Aucun bloc n'est associé à ce contenu."
 
-#: src/pyams_content/component/paragraph/zmi/container.py:249
+#: src/pyams_content/component/paragraph/zmi/container.py:248
 msgid "Click to open/close all paragraphs editors"
 msgstr "Afficher/masquer tous les blocs"
 
-#: src/pyams_content/component/paragraph/zmi/container.py:262
+#: src/pyams_content/component/paragraph/zmi/container.py:261
 msgid "Click to open/close paragraph editor"
 msgstr "Afficher/masquer ce bloc"
 
-#: src/pyams_content/component/paragraph/zmi/container.py:133
+#: src/pyams_content/component/paragraph/zmi/container.py:132
 msgid "Check allowed paragraph types to be able to create new paragraphs."
 msgstr ""
 "Vérifiez le paramétrage des types de blocs de contenu autorisés pour pouvoir "
@@ -729,13 +814,6 @@
 msgid "pictogram-item-header"
 msgstr "En-tête"
 
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:266
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:260
-#: src/pyams_content/component/paragraph/interfaces/pictogram.py:58
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:58
-msgid "Associated text"
-msgstr "Texte associé"
-
 #: src/pyams_content/component/paragraph/zmi/pictogram.py:288
 #: src/pyams_content/component/paragraph/interfaces/pictogram.py:80
 msgid "Pictograms"
@@ -782,56 +860,18 @@
 msgid "HTML content"
 msgstr "Contenu HTML"
 
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:76
+#: src/pyams_content/component/paragraph/zmi/keynumber.py:55
 msgid "Key numbers..."
 msgstr "Chiffres-clés"
 
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:89
+#: src/pyams_content/component/paragraph/zmi/keynumber.py:68
 msgid "Add new key number paragraph"
 msgstr "Ajout de chiffres-clés"
 
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:116
+#: src/pyams_content/component/paragraph/zmi/keynumber.py:96
 msgid "Edit key number paragraph properties"
 msgstr "Propriétés des chiffres-clés"
 
-#. Default: Header
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:227
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:45
-msgid "key-number-label"
-msgstr "En-tête"
-
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:239
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:50
-msgid "Number"
-msgstr "Chiffre"
-
-#. Default: Unit
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:248
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:54
-msgid "key-number-unit"
-msgstr "Unité"
-
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:279
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:80
-msgid "Key numbers"
-msgstr "Chiffres-clés"
-
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:294
-msgid "Add keynumber"
-msgstr "Ajouter un chiffre-clé"
-
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:307
-msgid "Add new keynumber"
-msgstr "Ajout d'un chiffre-clé"
-
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:334
-msgid "Edit keynumber properties"
-msgstr "Propriétés du chiffre-clé"
-
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:322
-msgid "Key number was correctly added"
-msgstr "Le chiffre-clé a été ajouté."
-
 #: src/pyams_content/component/paragraph/zmi/frame.py:84
 msgid "Framed text..."
 msgstr "Encadré"
@@ -904,18 +944,6 @@
 msgid "Edit header paragraph properties"
 msgstr "Propriétés du chapô"
 
-#: src/pyams_content/component/paragraph/interfaces/milestone.py:40
-#: src/pyams_content/component/paragraph/interfaces/__init__.py:44
-#: src/pyams_content/component/paragraph/interfaces/pictogram.py:41
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:40
-#: src/pyams_content/component/association/interfaces/__init__.py:42
-#: src/pyams_content/shared/form/interfaces/__init__.py:87
-#: src/pyams_content/shared/site/interfaces/__init__.py:117
-#: src/pyams_content/features/alert/interfaces.py:54
-#: src/pyams_content/features/menu/interfaces/__init__.py:58
-msgid "Visible?"
-msgstr "Visible ?"
-
 #: src/pyams_content/component/paragraph/interfaces/milestone.py:41
 msgid "Is this milestone visible in front-office?"
 msgstr "Si 'non', ce jalon ne sera pas présenté aux internautes"
@@ -1065,35 +1093,11 @@
 msgid "Presentation template used for this audio file"
 msgstr "Mode de rendu utilisé pour cette bande son"
 
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:41
-msgid "Is this key number visible in front-office?"
-msgstr "Si 'non', ce chiffre-clé ne sera pas présenté aux internautes"
-
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:46
-msgid ""
-"Small text to be displayed above number (according to selected renderer)"
-msgstr ""
-"Texte court affiché au-dessus du chiffre (selon le mode de rendu sélectionné)"
-
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:51
-msgid "Key number value"
-msgstr "Chiffre"
-
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:55
-msgid "Displayed unit"
-msgstr "Unité affichée"
-
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:59
-msgid "The way this text will be rendered depends on presentation template"
-msgstr ""
-"La présentation de cette information peut varier en fonction du mode de "
-"rendu choisi"
-
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:87
+#: src/pyams_content/component/paragraph/interfaces/keynumber.py:36
 msgid "Key numbers template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:88
+#: src/pyams_content/component/paragraph/interfaces/keynumber.py:37
 msgid "Presentation template used for key numbers"
 msgstr "Modèle de présentation utilisé par ce bloc de contenu"
 
@@ -1269,7 +1273,7 @@
 msgstr "Thèmes sélectionnés"
 
 #: src/pyams_content/component/association/container.py:88
-#: src/pyams_content/component/association/zmi/__init__.py:297
+#: src/pyams_content/component/association/zmi/__init__.py:296
 #: src/pyams_content/component/association/interfaces/__init__.py:90
 msgid "Associations"
 msgstr "Liens et pièces jointes"
@@ -1287,20 +1291,20 @@
 msgid "Edit association paragraph properties"
 msgstr "Propriétés du bloc « liens et pièces jointes »"
 
-#: src/pyams_content/component/association/zmi/__init__.py:199
+#: src/pyams_content/component/association/zmi/__init__.py:198
 msgid "Public title"
 msgstr "Libellé public"
 
-#: src/pyams_content/component/association/zmi/__init__.py:217
+#: src/pyams_content/component/association/zmi/__init__.py:216
 msgid "Inner title"
 msgstr "Contenu interne"
 
-#: src/pyams_content/component/association/zmi/__init__.py:233
+#: src/pyams_content/component/association/zmi/__init__.py:232
 msgid "Size"
 msgstr "Taille"
 
-#: src/pyams_content/component/association/zmi/__init__.py:274
-#: src/pyams_content/component/association/zmi/__init__.py:284
+#: src/pyams_content/component/association/zmi/__init__.py:273
+#: src/pyams_content/component/association/zmi/__init__.py:283
 msgid "Associations list"
 msgstr "Liste des liens et pièces jointes"
 
@@ -1337,51 +1341,51 @@
 msgid "target is not published"
 msgstr "le contenu ciblé n'est pas publié"
 
-#: src/pyams_content/component/links/zmi/__init__.py:58
+#: src/pyams_content/component/links/zmi/__init__.py:60
 msgid "Internal links"
 msgstr "Liens internes"
 
-#: src/pyams_content/component/links/zmi/__init__.py:73
+#: src/pyams_content/component/links/zmi/__init__.py:75
 msgid "Add internal link"
 msgstr "Lien interne"
 
-#: src/pyams_content/component/links/zmi/__init__.py:87
+#: src/pyams_content/component/links/zmi/__init__.py:89
 msgid "Add new internal link"
 msgstr "Ajout d'un lien interne"
 
-#: src/pyams_content/component/links/zmi/__init__.py:122
+#: src/pyams_content/component/links/zmi/__init__.py:125
 msgid "Edit internal link properties"
 msgstr "Propriétés du lien interne"
 
-#: src/pyams_content/component/links/zmi/__init__.py:155
+#: src/pyams_content/component/links/zmi/__init__.py:159
 msgid "External links"
 msgstr "Liens externes"
 
-#: src/pyams_content/component/links/zmi/__init__.py:170
+#: src/pyams_content/component/links/zmi/__init__.py:174
 msgid "Add external link"
 msgstr "Lien externe"
 
-#: src/pyams_content/component/links/zmi/__init__.py:184
+#: src/pyams_content/component/links/zmi/__init__.py:188
 msgid "Add new external link"
 msgstr "Ajout d'un lien externe"
 
-#: src/pyams_content/component/links/zmi/__init__.py:219
+#: src/pyams_content/component/links/zmi/__init__.py:224
 msgid "Edit external link properties"
 msgstr "Propriétés du lien externe"
 
-#: src/pyams_content/component/links/zmi/__init__.py:252
+#: src/pyams_content/component/links/zmi/__init__.py:258
 msgid "Mailto links"
 msgstr "Liens mailto"
 
-#: src/pyams_content/component/links/zmi/__init__.py:267
+#: src/pyams_content/component/links/zmi/__init__.py:273
 msgid "Add mailto link"
 msgstr "Lien mailto"
 
-#: src/pyams_content/component/links/zmi/__init__.py:281
+#: src/pyams_content/component/links/zmi/__init__.py:287
 msgid "Add new mailto link"
 msgstr "Ajout d'un lien « mailto »"
 
-#: src/pyams_content/component/links/zmi/__init__.py:316
+#: src/pyams_content/component/links/zmi/__init__.py:323
 msgid "Edit mailto link properties"
 msgstr "Propriétés du lien « mailto »"
 
@@ -2595,7 +2599,7 @@
 #: src/pyams_content/shared/common/interfaces/types.py:40
 #: src/pyams_content/shared/form/zmi/field.py:159
 #: src/pyams_content/shared/form/interfaces/__init__.py:62
-#: src/pyams_content/features/menu/zmi/__init__.py:204
+#: src/pyams_content/features/menu/zmi/__init__.py:208
 msgid "Label"
 msgstr "Libellé"
 
@@ -2822,6 +2826,18 @@
 msgid "This content is already retired and not visible."
 msgstr "Ce contenu est déjà retiré et n'est plus visible des internautes."
 
+#: src/pyams_content/shared/common/portlet/content/__init__.py:42
+msgid "Context content"
+msgstr "Contenu partagé"
+
+#: src/pyams_content/shared/common/portlet/content/zmi/preview.pt:2
+msgid "This is where the content will be displayed!!"
+msgstr "C'est ici que seront affichés les éléments du contenu."
+
+#: src/pyams_content/shared/common/portlet/content/skin/__init__.py:36
+msgid "Default content renderer"
+msgstr "Par défaut"
+
 #: src/pyams_content/shared/common/interfaces/types.py:36
 #: src/pyams_content/shared/form/zmi/field.py:148
 msgid "Name"
@@ -3439,16 +3455,6 @@
 msgid "View internal references settings"
 msgstr "Références internes de la vue"
 
-#: src/pyams_content/shared/view/zmi/templates/render.pt:2
-msgid "View result items"
-msgstr "Contenus extraits par la vue"
-
-#: src/pyams_content/shared/view/zmi/templates/render.pt:3
-msgid "WARNING: items displayed in this preview are out of context!!"
-msgstr ""
-"ATTENTION : les résultats affichés dans cet aperçu ne tiennent pas compte du "
-"contexte pouvant être paramétré dans la vue !!!"
-
 #: src/pyams_content/shared/view/portlet/__init__.py:56
 msgid "View items"
 msgstr "Contenu d'une vue"
@@ -3656,15 +3662,15 @@
 msgid "Bad query object_name parameter value!"
 msgstr "Valeur incorrecte du paramètre object_name !"
 
-#: src/pyams_content/shared/imagemap/zmi/area.py:45
+#: src/pyams_content/shared/imagemap/zmi/area.py:47
 msgid "Add image area"
 msgstr "Ajouter une zone"
 
-#: src/pyams_content/shared/imagemap/zmi/area.py:64
+#: src/pyams_content/shared/imagemap/zmi/area.py:66
 msgid "Add new image area"
 msgstr "Ajout d'une zone cliquable"
 
-#: src/pyams_content/shared/imagemap/zmi/area.py:102
+#: src/pyams_content/shared/imagemap/zmi/area.py:107
 msgid "Edit image map properties"
 msgstr "Propriétés de l'image"
 
@@ -4427,18 +4433,6 @@
 msgid "Create new content"
 msgstr "Créer un nouveau contenu"
 
-#: src/pyams_content/portlet/content/__init__.py:42
-msgid "Context content"
-msgstr "Contenu partagé"
-
-#: src/pyams_content/portlet/content/zmi/preview.pt:3
-msgid "This is where the content will be displayed!!"
-msgstr "C'est ici que seront affichés les éléments du contenu."
-
-#: src/pyams_content/portlet/content/skin/__init__.py:36
-msgid "Default content renderer"
-msgstr "Par défaut"
-
 #: src/pyams_content/interfaces/__init__.py:95
 msgid "Unique key"
 msgstr "Clé unique"
@@ -4533,7 +4527,7 @@
 msgid "List of selected pictograms which will be available to shared contents"
 msgstr "Liste des pictogrammes proposés dans les contenus partagés"
 
-#: src/pyams_content/features/renderer/zmi/__init__.py:72
+#: src/pyams_content/features/renderer/zmi/__init__.py:70
 #: src/pyams_content/features/renderer/zmi/templates/renderer-input.pt:4
 msgid "Edit renderer properties"
 msgstr "Propriétés du mode de rendu"
@@ -4613,7 +4607,7 @@
 
 #. Default: Heading
 #: src/pyams_content/features/alert/interfaces.py:65
-#: src/pyams_content/features/alert/zmi/container.py:158
+#: src/pyams_content/features/alert/zmi/container.py:157
 msgid "alert-header"
 msgstr "En-tête"
 
@@ -4622,7 +4616,7 @@
 msgstr "En-tête de l'alerte (« Alerte », « Important », « Prudence »...)"
 
 #: src/pyams_content/features/alert/interfaces.py:69
-#: src/pyams_content/features/alert/zmi/container.py:170
+#: src/pyams_content/features/alert/zmi/container.py:169
 msgid "Message"
 msgstr "Message"
 
@@ -4688,38 +4682,74 @@
 msgid "Alerts"
 msgstr "Alertes"
 
-#: src/pyams_content/features/alert/zmi/container.py:192
+#: src/pyams_content/features/alert/zmi/container.py:191
 msgid "Alert list"
 msgstr "Liste des alertes"
 
-#: src/pyams_content/features/alert/zmi/container.py:91
+#: src/pyams_content/features/alert/zmi/container.py:90
 msgid "No currently defined alert."
 msgstr "Aucune alerte n'est définie actuellement."
 
-#: src/pyams_content/features/menu/zmi/__init__.py:79
+#: src/pyams_content/features/menu/zmi/__init__.py:81
 msgid "Add menu..."
 msgstr "Ajouter un menu"
 
-#: src/pyams_content/features/menu/zmi/__init__.py:90
+#: src/pyams_content/features/menu/zmi/__init__.py:92
 msgid "Add new menu"
 msgstr "Ajout d'un menu"
 
-#: src/pyams_content/features/menu/zmi/__init__.py:120
+#: src/pyams_content/features/menu/zmi/__init__.py:123
 msgid "Edit menu properties"
 msgstr "Propriétés du menu"
 
-#: src/pyams_content/features/menu/zmi/__init__.py:108
+#: src/pyams_content/features/menu/zmi/__init__.py:110
 msgid "Menu was correctly added."
 msgstr "Le menu a été ajouté."
 
-#: src/pyams_content/features/menu/zmi/__init__.py:394
+#: src/pyams_content/features/menu/zmi/__init__.py:388
 msgid "Link was correctly added."
 msgstr "Le lien a été ajouté."
 
-#: src/pyams_content/features/menu/zmi/__init__.py:218
+#: src/pyams_content/features/menu/zmi/templates/menu-name-cell.pt:7
 msgid "Click to see menu items"
 msgstr "Montrer ou cacher les éléments du menu"
 
+#: src/pyams_content/features/menu/portlet/navigation/simple.py:66
+msgid "Simple navigation"
+msgstr "Navigation à un niveau"
+
+#: src/pyams_content/features/menu/portlet/navigation/double.py:66
+msgid "Double navigation"
+msgstr "Navigation à deux niveaux"
+
+#: src/pyams_content/features/menu/portlet/navigation/zmi/simple.py:70
+msgid "Navigation links"
+msgstr "Liens de navigation"
+
+#: src/pyams_content/features/menu/portlet/navigation/zmi/double.py:70
+msgid "Navigation menus"
+msgstr "Menus de navigation"
+
+#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:12
+#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:9
+msgid "Link target is not published!"
+msgstr "Le contenu ciblé n'est pas publié"
+
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:32
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:32
+msgid "Portlet main title"
+msgstr "Titre du composant"
+
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:35
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:35
+msgid "Subtitle"
+msgstr "Sous-titre"
+
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:36
+#: src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:36
+msgid "Portlet subtitle"
+msgstr "Sous-titre du composant"
+
 #: src/pyams_content/features/menu/interfaces/__init__.py:63
 msgid "Menu title"
 msgstr "Libellé"
@@ -4972,6 +5002,14 @@
 msgid "Hidden header"
 msgstr "Ne pas afficher d'en-tête de pages"
 
+#~ msgid "View result items"
+#~ msgstr "Contenus extraits par la vue"
+
+#~ msgid "WARNING: items displayed in this preview are out of context!!"
+#~ msgstr ""
+#~ "ATTENTION : les résultats affichés dans cet aperçu ne tiennent pas compte "
+#~ "du contexte pouvant être paramétré dans la vue !!!"
+
 #~ msgid "Milestones paragraph"
 #~ msgstr "Chronologie"
 
@@ -5005,9 +5043,6 @@
 #~ msgid "Check content..."
 #~ msgstr "Auditer le contenu"
 
-#~ msgid "Simple list view"
-#~ msgstr "Vue simple d'une liste d'éléments"
-
 #~ msgid "Paragraphs types..."
 #~ msgstr "Types de paragraphes"
 
--- a/src/pyams_content/locales/pyams_content.pot	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/locales/pyams_content.pot	Fri Jun 15 14:12:29 2018 +0200
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-13 11:31+0200\n"
+"POT-Creation-Date: 2018-06-15 11:05+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -134,7 +134,7 @@
 #: ./src/pyams_content/component/gallery/zmi/interfaces.py:40
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:61
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:44
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:56
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:66
 #: ./src/pyams_content/component/paragraph/interfaces/video.py:52
 #: ./src/pyams_content/component/paragraph/interfaces/audio.py:48
 #: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:44
@@ -177,26 +177,26 @@
 msgstr ""
 
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:47
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:41
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:77
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:44
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:91
 msgid "Image or video data"
 msgstr ""
 
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:48
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:42
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:78
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:45
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:92
 msgid "Image or video content"
 msgstr ""
 
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:51
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:45
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:51
 #: ./src/pyams_content/component/paragraph/interfaces/video.py:45
 #: ./src/pyams_content/component/video/interfaces/__init__.py:75
 msgid "Legend"
 msgstr ""
 
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:54
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:48
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:54
 #: ./src/pyams_content/reference/pictograms/interfaces/__init__.py:48
 msgid "Accessibility title"
 msgstr ""
@@ -208,7 +208,7 @@
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:58
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:98
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:40
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:52
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:62
 #: ./src/pyams_content/component/paragraph/interfaces/video.py:48
 #: ./src/pyams_content/component/paragraph/interfaces/audio.py:44
 #: ./src/pyams_content/component/links/interfaces/__init__.py:39
@@ -266,7 +266,7 @@
 
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:94
 #: ./src/pyams_content/component/paragraph/zmi/milestone.py:231
-#: ./src/pyams_content/component/paragraph/zmi/container.py:224
+#: ./src/pyams_content/component/paragraph/zmi/container.py:223
 #: ./src/pyams_content/component/paragraph/interfaces/milestone.py:45
 #: ./src/pyams_content/component/links/zmi/reverse.py:71
 #: ./src/pyams_content/shared/common/zmi/dashboard.py:109
@@ -276,6 +276,8 @@
 #: ./src/pyams_content/root/zmi/templates/advanced-search.pt:188
 #: ./src/pyams_content/interfaces/__init__.py:99
 #: ./src/pyams_content/reference/pictograms/zmi/__init__.py:153
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:31
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:31
 msgid "Title"
 msgstr ""
 
@@ -453,10 +455,90 @@
 msgid "Audio file content"
 msgstr ""
 
-#: ./src/pyams_content/component/illustration/__init__.py:133
-#: ./src/pyams_content/component/illustration/zmi/__init__.py:54
-#: ./src/pyams_content/component/illustration/zmi/__init__.py:81
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:71
+#: ./src/pyams_content/component/keynumber/__init__.py:180
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:198
+#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:29
+msgid "Key numbers"
+msgstr ""
+
+#. Default: Header
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:146
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:44
+msgid "key-number-label"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:158
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:49
+msgid "Number"
+msgstr ""
+
+#. Default: Unit
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:167
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:53
+msgid "key-number-unit"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:179
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:57
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:266
+#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:58
+msgid "Associated text"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:217
+msgid "Add keynumber"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:230
+msgid "Add new keynumber"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:259
+msgid "Edit keynumber properties"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:245
+msgid "Key number was correctly added"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:39
+#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:40
+#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:44
+#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:41
+#: ./src/pyams_content/component/association/interfaces/__init__.py:42
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:87
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:117
+#: ./src/pyams_content/features/alert/interfaces.py:54
+#: ./src/pyams_content/features/menu/interfaces/__init__.py:58
+msgid "Visible?"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:40
+msgid "Is this key number visible in front-office?"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:45
+msgid ""
+"Small text to be displayed above number (according to selected renderer)"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:50
+msgid "Key number value"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:54
+msgid "Displayed unit"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:58
+msgid "The way this text will be rendered depends on presentation template"
+msgstr ""
+
+#: ./src/pyams_content/component/illustration/__init__.py:162
+#: ./src/pyams_content/component/illustration/zmi/__init__.py:55
+#: ./src/pyams_content/component/illustration/zmi/__init__.py:79
+#: ./src/pyams_content/component/illustration/zmi/__init__.py:119
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:85
 msgid "Illustration"
 msgstr ""
 
@@ -472,24 +554,24 @@
 msgid "Edit illustration properties"
 msgstr ""
 
-#: ./src/pyams_content/component/illustration/zmi/__init__.py:83
+#: ./src/pyams_content/component/illustration/zmi/__init__.py:121
 msgid "Header illustration"
 msgstr ""
 
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:49
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:55
 #: ./src/pyams_content/reference/pictograms/interfaces/__init__.py:49
 msgid "Alternate title used to describe image content"
 msgstr ""
 
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:57
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:67
 msgid "Name of picture's author"
 msgstr ""
 
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:60
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:70
 msgid "Illustration template"
 msgstr ""
 
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:61
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:71
 msgid "Presentation template used for illustration"
 msgstr ""
 
@@ -639,37 +721,37 @@
 msgid "Contents..."
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:240
+#: ./src/pyams_content/component/paragraph/zmi/container.py:239
 msgid "Show/hide all paragraphs"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:288
-#: ./src/pyams_content/component/paragraph/zmi/container.py:297
-#: ./src/pyams_content/component/paragraph/zmi/container.py:310
+#: ./src/pyams_content/component/paragraph/zmi/container.py:287
+#: ./src/pyams_content/component/paragraph/zmi/container.py:296
+#: ./src/pyams_content/component/paragraph/zmi/container.py:309
 msgid "Content blocks"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:367
+#: ./src/pyams_content/component/paragraph/zmi/container.py:366
 msgid "Links and attachments..."
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:379
+#: ./src/pyams_content/component/paragraph/zmi/container.py:378
 msgid "Content blocks links and attachments"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:127
+#: ./src/pyams_content/component/paragraph/zmi/container.py:126
 msgid "No currently defined paragraph."
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:249
+#: ./src/pyams_content/component/paragraph/zmi/container.py:248
 msgid "Click to open/close all paragraphs editors"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:262
+#: ./src/pyams_content/component/paragraph/zmi/container.py:261
 msgid "Click to open/close paragraph editor"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/container.py:133
+#: ./src/pyams_content/component/paragraph/zmi/container.py:132
 msgid "Check allowed paragraph types to be able to create new paragraphs."
 msgstr ""
 
@@ -690,13 +772,6 @@
 msgid "pictogram-item-header"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:266
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:260
-#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:58
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:58
-msgid "Associated text"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/zmi/pictogram.py:288
 #: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:80
 msgid "Pictograms"
@@ -743,56 +818,18 @@
 msgid "HTML content"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:76
+#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:55
 msgid "Key numbers..."
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:89
+#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:68
 msgid "Add new key number paragraph"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:116
+#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:96
 msgid "Edit key number paragraph properties"
 msgstr ""
 
-#. Default: Header
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:227
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:45
-msgid "key-number-label"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:239
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:50
-msgid "Number"
-msgstr ""
-
-#. Default: Unit
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:248
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:54
-msgid "key-number-unit"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:279
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:80
-msgid "Key numbers"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:294
-msgid "Add keynumber"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:307
-msgid "Add new keynumber"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:334
-msgid "Edit keynumber properties"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:322
-msgid "Key number was correctly added"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/zmi/frame.py:84
 msgid "Framed text..."
 msgstr ""
@@ -865,18 +902,6 @@
 msgid "Edit header paragraph properties"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:40
-#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:44
-#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:41
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:40
-#: ./src/pyams_content/component/association/interfaces/__init__.py:42
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:87
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:117
-#: ./src/pyams_content/features/alert/interfaces.py:54
-#: ./src/pyams_content/features/menu/interfaces/__init__.py:58
-msgid "Visible?"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/milestone.py:41
 msgid "Is this milestone visible in front-office?"
 msgstr ""
@@ -1019,32 +1044,11 @@
 msgid "Presentation template used for this audio file"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:41
-msgid "Is this key number visible in front-office?"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:46
-msgid ""
-"Small text to be displayed above number (according to selected renderer)"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:51
-msgid "Key number value"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:55
-msgid "Displayed unit"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:59
-msgid "The way this text will be rendered depends on presentation template"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:87
+#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:36
 msgid "Key numbers template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:88
+#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:37
 msgid "Presentation template used for key numbers"
 msgstr ""
 
@@ -1218,7 +1222,7 @@
 msgstr ""
 
 #: ./src/pyams_content/component/association/container.py:88
-#: ./src/pyams_content/component/association/zmi/__init__.py:297
+#: ./src/pyams_content/component/association/zmi/__init__.py:296
 #: ./src/pyams_content/component/association/interfaces/__init__.py:90
 msgid "Associations"
 msgstr ""
@@ -1236,20 +1240,20 @@
 msgid "Edit association paragraph properties"
 msgstr ""
 
-#: ./src/pyams_content/component/association/zmi/__init__.py:199
+#: ./src/pyams_content/component/association/zmi/__init__.py:198
 msgid "Public title"
 msgstr ""
 
-#: ./src/pyams_content/component/association/zmi/__init__.py:217
+#: ./src/pyams_content/component/association/zmi/__init__.py:216
 msgid "Inner title"
 msgstr ""
 
-#: ./src/pyams_content/component/association/zmi/__init__.py:233
+#: ./src/pyams_content/component/association/zmi/__init__.py:232
 msgid "Size"
 msgstr ""
 
-#: ./src/pyams_content/component/association/zmi/__init__.py:274
-#: ./src/pyams_content/component/association/zmi/__init__.py:284
+#: ./src/pyams_content/component/association/zmi/__init__.py:273
+#: ./src/pyams_content/component/association/zmi/__init__.py:283
 msgid "Associations list"
 msgstr ""
 
@@ -1286,51 +1290,51 @@
 msgid "target is not published"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:58
+#: ./src/pyams_content/component/links/zmi/__init__.py:60
 msgid "Internal links"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:73
+#: ./src/pyams_content/component/links/zmi/__init__.py:75
 msgid "Add internal link"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:87
+#: ./src/pyams_content/component/links/zmi/__init__.py:89
 msgid "Add new internal link"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:122
+#: ./src/pyams_content/component/links/zmi/__init__.py:125
 msgid "Edit internal link properties"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:155
+#: ./src/pyams_content/component/links/zmi/__init__.py:159
 msgid "External links"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:170
+#: ./src/pyams_content/component/links/zmi/__init__.py:174
 msgid "Add external link"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:184
+#: ./src/pyams_content/component/links/zmi/__init__.py:188
 msgid "Add new external link"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:219
+#: ./src/pyams_content/component/links/zmi/__init__.py:224
 msgid "Edit external link properties"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:252
+#: ./src/pyams_content/component/links/zmi/__init__.py:258
 msgid "Mailto links"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:267
+#: ./src/pyams_content/component/links/zmi/__init__.py:273
 msgid "Add mailto link"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:281
+#: ./src/pyams_content/component/links/zmi/__init__.py:287
 msgid "Add new mailto link"
 msgstr ""
 
-#: ./src/pyams_content/component/links/zmi/__init__.py:316
+#: ./src/pyams_content/component/links/zmi/__init__.py:323
 msgid "Edit mailto link properties"
 msgstr ""
 
@@ -2473,7 +2477,7 @@
 #: ./src/pyams_content/shared/common/interfaces/types.py:40
 #: ./src/pyams_content/shared/form/zmi/field.py:159
 #: ./src/pyams_content/shared/form/interfaces/__init__.py:62
-#: ./src/pyams_content/features/menu/zmi/__init__.py:204
+#: ./src/pyams_content/features/menu/zmi/__init__.py:208
 msgid "Label"
 msgstr ""
 
@@ -2665,6 +2669,18 @@
 msgid "This content is already retired and not visible."
 msgstr ""
 
+#: ./src/pyams_content/shared/common/portlet/content/__init__.py:42
+msgid "Context content"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/portlet/content/zmi/preview.pt:2
+msgid "This is where the content will be displayed!!"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/portlet/content/skin/__init__.py:36
+msgid "Default content renderer"
+msgstr ""
+
 #: ./src/pyams_content/shared/common/interfaces/types.py:36
 #: ./src/pyams_content/shared/form/zmi/field.py:148
 msgid "Name"
@@ -3224,14 +3240,6 @@
 msgid "View internal references settings"
 msgstr ""
 
-#: ./src/pyams_content/shared/view/zmi/templates/render.pt:2
-msgid "View result items"
-msgstr ""
-
-#: ./src/pyams_content/shared/view/zmi/templates/render.pt:3
-msgid "WARNING: items displayed in this preview are out of context!!"
-msgstr ""
-
 #: ./src/pyams_content/shared/view/portlet/__init__.py:56
 msgid "View items"
 msgstr ""
@@ -3429,15 +3437,15 @@
 msgid "Bad query object_name parameter value!"
 msgstr ""
 
-#: ./src/pyams_content/shared/imagemap/zmi/area.py:45
+#: ./src/pyams_content/shared/imagemap/zmi/area.py:47
 msgid "Add image area"
 msgstr ""
 
-#: ./src/pyams_content/shared/imagemap/zmi/area.py:64
+#: ./src/pyams_content/shared/imagemap/zmi/area.py:66
 msgid "Add new image area"
 msgstr ""
 
-#: ./src/pyams_content/shared/imagemap/zmi/area.py:102
+#: ./src/pyams_content/shared/imagemap/zmi/area.py:107
 msgid "Edit image map properties"
 msgstr ""
 
@@ -4185,18 +4193,6 @@
 msgid "Create new content"
 msgstr ""
 
-#: ./src/pyams_content/portlet/content/__init__.py:42
-msgid "Context content"
-msgstr ""
-
-#: ./src/pyams_content/portlet/content/zmi/preview.pt:3
-msgid "This is where the content will be displayed!!"
-msgstr ""
-
-#: ./src/pyams_content/portlet/content/skin/__init__.py:36
-msgid "Default content renderer"
-msgstr ""
-
 #: ./src/pyams_content/interfaces/__init__.py:95
 msgid "Unique key"
 msgstr ""
@@ -4291,7 +4287,7 @@
 msgid "List of selected pictograms which will be available to shared contents"
 msgstr ""
 
-#: ./src/pyams_content/features/renderer/zmi/__init__.py:72
+#: ./src/pyams_content/features/renderer/zmi/__init__.py:70
 #: ./src/pyams_content/features/renderer/zmi/templates/renderer-input.pt:4
 msgid "Edit renderer properties"
 msgstr ""
@@ -4371,7 +4367,7 @@
 
 #. Default: Heading
 #: ./src/pyams_content/features/alert/interfaces.py:65
-#: ./src/pyams_content/features/alert/zmi/container.py:158
+#: ./src/pyams_content/features/alert/zmi/container.py:157
 msgid "alert-header"
 msgstr ""
 
@@ -4380,7 +4376,7 @@
 msgstr ""
 
 #: ./src/pyams_content/features/alert/interfaces.py:69
-#: ./src/pyams_content/features/alert/zmi/container.py:170
+#: ./src/pyams_content/features/alert/zmi/container.py:169
 msgid "Message"
 msgstr ""
 
@@ -4436,38 +4432,74 @@
 msgid "Alerts"
 msgstr ""
 
-#: ./src/pyams_content/features/alert/zmi/container.py:192
+#: ./src/pyams_content/features/alert/zmi/container.py:191
 msgid "Alert list"
 msgstr ""
 
-#: ./src/pyams_content/features/alert/zmi/container.py:91
+#: ./src/pyams_content/features/alert/zmi/container.py:90
 msgid "No currently defined alert."
 msgstr ""
 
-#: ./src/pyams_content/features/menu/zmi/__init__.py:79
+#: ./src/pyams_content/features/menu/zmi/__init__.py:81
 msgid "Add menu..."
 msgstr ""
 
-#: ./src/pyams_content/features/menu/zmi/__init__.py:90
+#: ./src/pyams_content/features/menu/zmi/__init__.py:92
 msgid "Add new menu"
 msgstr ""
 
-#: ./src/pyams_content/features/menu/zmi/__init__.py:120
+#: ./src/pyams_content/features/menu/zmi/__init__.py:123
 msgid "Edit menu properties"
 msgstr ""
 
-#: ./src/pyams_content/features/menu/zmi/__init__.py:108
+#: ./src/pyams_content/features/menu/zmi/__init__.py:110
 msgid "Menu was correctly added."
 msgstr ""
 
-#: ./src/pyams_content/features/menu/zmi/__init__.py:394
+#: ./src/pyams_content/features/menu/zmi/__init__.py:388
 msgid "Link was correctly added."
 msgstr ""
 
-#: ./src/pyams_content/features/menu/zmi/__init__.py:218
+#: ./src/pyams_content/features/menu/zmi/templates/menu-name-cell.pt:7
 msgid "Click to see menu items"
 msgstr ""
 
+#: ./src/pyams_content/features/menu/portlet/navigation/simple.py:66
+msgid "Simple navigation"
+msgstr ""
+
+#: ./src/pyams_content/features/menu/portlet/navigation/double.py:66
+msgid "Double navigation"
+msgstr ""
+
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/simple.py:70
+msgid "Navigation links"
+msgstr ""
+
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/double.py:70
+msgid "Navigation menus"
+msgstr ""
+
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:12
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:9
+msgid "Link target is not published!"
+msgstr ""
+
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:32
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:32
+msgid "Portlet main title"
+msgstr ""
+
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:35
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:35
+msgid "Subtitle"
+msgstr ""
+
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:36
+#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/double.py:36
+msgid "Portlet subtitle"
+msgstr ""
+
 #: ./src/pyams_content/features/menu/interfaces/__init__.py:63
 msgid "Menu title"
 msgstr ""
--- a/src/pyams_content/shared/common/portlet/content/__init__.py	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/shared/common/portlet/content/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -21,6 +21,7 @@
 
 # import packages
 from pyams_portal.portlet import PortletSettings, portlet_config, Portlet
+from pyams_utils.factory import factory_config
 from zope.interface import implementer
 
 from pyams_content import _
@@ -30,6 +31,7 @@
 
 
 @implementer(ISharedContentPortletSettings)
+@factory_config(provided=ISharedContentPortletSettings)
 class SharedContentPortletSettings(PortletSettings):
     """Shared content portlet persistent settings"""
 
@@ -41,4 +43,4 @@
     name = SHARED_CONTENT_PORTLET_NAME
     label = _("Context content")
 
-    settings_class = SharedContentPortletSettings
+    settings_factory = ISharedContentPortletSettings
--- a/src/pyams_content/shared/view/portlet/__init__.py	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/shared/view/portlet/__init__.py	Fri Jun 15 14:12:29 2018 +0200
@@ -23,6 +23,7 @@
 from pyams_content.workflow import PUBLISHED_STATES
 from pyams_portal.portlet import PortletSettings, portlet_config, Portlet
 from pyams_sequence.utility import get_sequence_target
+from pyams_utils.factory import factory_config
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
@@ -33,6 +34,7 @@
 
 
 @implementer(IViewItemsPortletSettings)
+@factory_config(provided=IViewItemsPortletSettings)
 class ViewItemsPortletSettings(PortletSettings):
     """View items portlet settings"""
 
@@ -58,4 +60,4 @@
     toolbar_image = None
     toolbar_css_class = 'fa fa-fw fa-2x fa-th-list'
 
-    settings_class = ViewItemsPortletSettings
+    settings_factory = IViewItemsPortletSettings
--- a/src/pyams_content/skin/resources/js/pyams_content.min.js	Thu Jun 14 17:50:28 2018 +0200
+++ b/src/pyams_content/skin/resources/js/pyams_content.min.js	Fri Jun 15 14:12:29 2018 +0200
@@ -1,1 +1,1 @@
-!function(t,e){"use strict";var a=e.MyAMS,i={widget:{treeview:{selectFolder:function(e,a){t(e.target).siblings('input[type="hidden"]').val(a.id)},unselectFolder:function(e,a){t(e.target).siblings('input[type="hidden"]').val(null)}}},TinyMCE:{initEditor:function(t){return tinyMCE.addI18n("fr",{"Link list":"Liste de liens","Toggle h3 header":"En-tête H3","Toggle h4 header":"En-tête H4","Insert internal link":"Insérer un lien interne","Link title":"Texte à afficher","Internal number":"N° interne"}),tinymce.PluginManager.add("internal_links",function(t,e){t.addButton("internal_links",{icon:"cloud-check",tooltip:"Insert internal link",image:"/--static--/pyams_content/img/internal-link.png",onclick:function(){t.windowManager.open({title:"Insert internal link",body:[{type:"textbox",name:"oid",label:"Internal number"},{type:"textbox",name:"title",label:"Link title",value:t.selection.getContent()}],onsubmit:function(e){t.insertContent('<a href="oid://'+e.data.oid+'">'+e.data.title+"</a>")}})}})}),tinyMCE.PluginManager.add("headers",function(t,e){["h3","h4"].forEach(function(e){t.addButton("header-"+e,{tooltip:"Toggle "+e+" header",text:e.toUpperCase(),onClick:function(){t.execCommand("mceToggleFormat",!1,e)},onPostRender:function(){var a=this,i=function(){t.formatter.formatChanged(e,function(t){a.active(t)})};t.formatter?i():t.on("init",i)}})})}),t.image_list=i.TinyMCE.getImagesList,t.link_list=i.TinyMCE.getLinksList,t.style_formats=[{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}],t.plugins+=" internal_links headers",t.toolbar1&&(t.toolbar1="undo redo | header-h3 header-h4 styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent"),t.toolbar2&&(t.toolbar2="forecolor backcolor | charmap internal_links link | fullscreen preview print | code"),t},getImagesList:function(e){var i=t(document.activeElement).parents("form");if(i.exists()){var n=i.attr("data-ams-form-handler")||i.attr("action"),s=n.substr(0,n.lastIndexOf("/")+1);return a.ajax.post(s+"get-images-list.json",{},e)}},getLinksList:function(e){var i=t(document.activeElement).parents("form");if(i.exists()){var n=i.attr("data-ams-form-handler")||i.attr("action"),s=n.substr(0,n.lastIndexOf("/")+1);return a.ajax.post(s+"get-links-list.json",{},e)}}},galleries:{updateMediaTitle:function(e){t('img[id="'+e.media_id+'"]').attr("original-title",e.title)},switchMediaVisibility:function(e){return function(){var e=t(this),i=e.parents(".media"),n=i.parents(".gallery");a.ajax.post(n.data("ams-location")+"/set-media-visibility.json",{object_name:i.data("ams-element-name")},function(a,i){a.visible?(t("i",e).attr("class","fa fa-fw fa-eye"),e.parents(".btn-group").siblings("a.fancyimg").removeClass("not-visible")):(t("i",e).attr("class","fa fa-fw fa-eye-slash text-danger"),e.parents(".btn-group").siblings("a.fancyimg").addClass("not-visible"))})}},setOrder:function(e,i){if(!i||!i.item.hasClass("already-dropped")){var n=i.item.parents(".gallery"),s=t(".media",n).listattr("data-ams-element-name");a.ajax.post(n.data("ams-location")+"/set-medias-order.json",{medias:JSON.stringify(s)})}},removeMedia:function(e){return function(){var e=t(this);a.skin.bigBox({title:a.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(t){if(t===a.i18n.BTN_OK){var i=e.parents(".gallery").data("ams-location"),n=e.parents(".media"),s=n.data("ams-element-name");a.ajax.post(i+"/delete-element.json",{object_name:s},function(t,e){n.remove()})}})}},afterFancyboxLoad:function(t,e){t.element.hasClass("not-visible")&&t.inner.prepend('<div class="hidden-mask"></div>')}},paragraphs:{preReload:function(){i.paragraphs.switched=t("i.switch.fa-minus-square-o","#paragraphs_list").parents("tr").listattr("id")},postReload:function(){t(i.paragraphs.switched).each(function(){t("i.switch.fa-plus-square-o",'[id="'+this+'"]').parents("div").first().click()}),delete i.paragraphs.switched},refreshParagraph:function(e){var a=t('tr[id="'+e.object_id+'"]');t("span.title",a).html(e.title||" - - - - - - - -")},switchEditor:function(e){var i=t(this),n=t("i.switch",i),s=i.parents("td"),r=t(".editor",s),o=i.parents("tr");if(n.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('<h1 class="loading"><i class="fa fa-2x fa-gear fa-spin"></i></h1>'),a.ajax.post(l.data("ams-location")+"/get-paragraph-editor.json",{object_name:o.data("ams-element-name")},function(t){r.html(t),t&&(a.initContent(r),n.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),o.data("ams-disabled-handlers",!0),a.skin.scrollTo(r,{offset:r.height()-o.height()}))})}else a.skin.cleanContainer(r),r.empty(),n.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o.removeData("ams-disabled-handlers")},switchLastEditor:function(e){var a=t('table[id="'+e+'"]'),i=t("tr:last",a);t('[data-ams-click-handler="PyAMS_content.paragraphs.switchEditor"]',i).click()},switchAllEditors:function(e){var i=t(this),n=t("i",i),s=i.parents("table");n.hasClass("fa-plus-square-o")?(n.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),a.ajax.post(s.data("ams-location")+"/get-paragraphs-editors.json",{},function(e){for(var i in e)if(e.hasOwnProperty(i)){var r=t('tr[data-ams-element-name="'+i+'"]',s),o=t(".editor",r);o.is(":empty")&&o.html(e[i]),t(".fa-plus-square-o",r).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),r.data("ams-disabled-handlers",!0)}t("i.fa-plus-square-o",t("tbody",s)).exists()||n.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o"),a.initContent(s)})):(t(".editor",s).each(function(){a.skin.cleanContainer(t(this)),t(this).empty()}),t(".fa-minus-square-o",s).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),t("tr",s).removeData("ams-disabled-handlers"))},updateToolbar:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i);n.replaceWith(e.toolbar_tag),n=t(".title-toolbar",i),a.initContent(n)},updateMarkers:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i),s=t("DIV.action."+e.marker_type,n);s.exists()?s.replaceWith(e.marker_tag):t(e.marker_tag).appendTo(n),e.marker_tag&&(s=t("DIV.action."+e.marker_type,n),a.initContent(s)),a.helpers.sort(n,"weight")}},pictograms:{initManagerSelection:function(){var e=t(this),a=t('input[type="hidden"]',t(".selected-pictograms",e)).listattr("value");return{selected:JSON.stringify(a)}},switchPictogram:function(){var e=t(this),a=e.parents(".pictograms"),i=a.parents(".pictograms-manager");a.hasClass("available-pictograms")?t(".selected-pictograms",i).append(e):t(".available-pictograms",i).append(e)}},themes:{initExtracts:function(e){var i=t('select[name="form.widgets.thesaurus_name:list"]',e).val(),n=t('select[name="form.widgets.extract_name:list"]',e),s=n.val();i&&a.jsonrpc.post("getExtracts",{thesaurus_name:i},{url:"/api/thesaurus/json"},function(e){n.empty(),t(e.result).each(function(){t("<option></option>").attr("value",this.id).attr("selected",this.id===s).text(this.text).appendTo(n)})}),n.attr("data-ams-events-handlers",'{"select2-open": "PyAMS_content.themes.getExtracts"}')},getExtracts:function(e){var i=t(e.currentTarget).parents("form"),n=t('select[name="form.widgets.thesaurus_name:list"]',i).val();n&&a.jsonrpc.post("getExtracts",{thesaurus_name:n},{url:"/api/thesaurus/json"},function(e){var a=t('select[name="form.widgets.extract_name:list"]',i).data("select2");a.results.empty(),a.opts.populateResults.call(a,a.results,e.result,{term:""})})}},fields:{refreshField:function(e){var a=t('table[id="form_fields_list"]'),i=t('tr[data-ams-element-name="'+e.object_name+'"]',a);t("td:nth-child(4)",i).html(e.title)}},imgmap:{init:function(){var e=t(this);a.ajax.check(t.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+a.devext+".js",function(){e.canvasAreaDraw({imageUrl:e.data("ams-image-url")})})},initPreview:function(){var e=t(this);a.ajax.check(t.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+a.devext+".js",function(){e.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},site:{switchVisibility:function(){return function(){var e=t(this),i=e.parents("tr").first();a.ajax.post(i.data("ams-location")+"/switch-content-visibility.json",{object_name:i.data("ams-element-name")},function(a,i){var n="fa-eye";a.visible||(n+="-slash"),a.published||(n+=" text-danger"),t("i",e).attr("class","fa fa-fw "+n)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(e){var n=t(".chat-body",e);n.animate({scrollTop:n[0].scrollHeight},1e3),clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.chat),a.skin.registerCleanCallback(i.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)},updateComments:function(){var e,i=t(".badge",'nav a[href="#review-comments.html"]'),n=t(".chat-body",".widget-body");e=n.exists()?t(".message",n).length:parseInt(i.text()),a.ajax.post("get-last-review-comments.json",{count:e},function(a){n.exists()&&i.removeClass("bg-color-danger").addClass("bg-color-info"),e!==a.count&&(i.text(a.count).removeClass("hidden"),n.exists()&&(t(".messages",n).append(a.content),n.animate({scrollTop:n[0].scrollHeight},1e3)),n.exists()||i.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){t(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(e){var a=t(".chat-body",".widget-body");return{count:t(".message",a).length}},addCommentAction:function(){return function(){t('textarea[name="comment"]').focus()}},addCommentCallback:function(e){var a=t(this),i=a.parents(".widget-body");t(".messages",i).append(e.content),t('textarea[name="comment"]',a).val("");var n=t(".chat-body",i);n.animate({scrollTop:n[0].scrollHeight},1e3),t(".badge",'nav a[href="#review-comments.html"]').text(e.count).removeClass("hidden")}},profile:{switchFavorite:function(){var e=t(this),i=e.data("sequence-oid");a.ajax.post("switch-user-favorite.json",{oid:i},function(t,a){t.favorite?e.removeClass("fa-star-o").addClass("fa-star"):e.removeClass("fa-star").addClass("fa-star-o")})}}};t(".badge",'nav a[href="#review-comments.html"]').exists()&&(i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)),e.PyAMS_content=i}(jQuery,this);
+!function(o,t){"use strict";var l=t.MyAMS,a={widget:{treeview:{selectFolder:function(t,e){o(t.target).siblings('input[type="hidden"]').val(e.id)},unselectFolder:function(t,e){o(t.target).siblings('input[type="hidden"]').val(null)}}},TinyMCE:{initEditor:function(t){return tinyMCE.addI18n("fr",{"Link list":"Liste de liens","Toggle h3 header":"En-tête H3","Toggle h4 header":"En-tête H4","Insert internal link":"Insérer un lien interne","Link title":"Texte à afficher","Internal number":"N° interne"}),tinymce.PluginManager.add("internal_links",function(e,t){e.addButton("internal_links",{icon:"cloud-check",tooltip:"Insert internal link",image:"/--static--/pyams_content/img/internal-link.png",onclick:function(){e.windowManager.open({title:"Insert internal link",body:[{type:"textbox",name:"oid",label:"Internal number"},{type:"textbox",name:"title",label:"Link title",value:e.selection.getContent()}],onsubmit:function(t){e.insertContent('<a href="oid://'+t.data.oid+'">'+t.data.title+"</a>")}})}})}),tinyMCE.PluginManager.add("headers",function(i,t){["h3","h4"].forEach(function(a){i.addButton("header-"+a,{tooltip:"Toggle "+a+" header",text:a.toUpperCase(),onClick:function(){i.execCommand("mceToggleFormat",!1,a)},onPostRender:function(){var e=this,t=function(){i.formatter.formatChanged(a,function(t){e.active(t)})};i.formatter?t():i.on("init",t)}})})}),t.image_list=a.TinyMCE.getImagesList,t.link_list=a.TinyMCE.getLinksList,t.style_formats=[{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}],t.plugins+=" internal_links headers",t.toolbar1&&(t.toolbar1="undo redo | header-h3 header-h4 styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent"),t.toolbar2&&(t.toolbar2="forecolor backcolor | charmap internal_links link | fullscreen preview print | code"),t},getImagesList:function(t){var e=o(document.activeElement).parents("form");if(e.exists()){var a=e.attr("data-ams-form-handler")||e.attr("action"),i=a.substr(0,a.lastIndexOf("/")+1);return l.ajax.post(i+"get-images-list.json",{},t)}},getLinksList:function(t){var e=o(document.activeElement).parents("form");if(e.exists()){var a=e.attr("data-ams-form-handler")||e.attr("action"),i=a.substr(0,a.lastIndexOf("/")+1);return l.ajax.post(i+"get-links-list.json",{},t)}}},galleries:{updateMediaTitle:function(t){o('img[id="'+t.media_id+'"]').attr("original-title",t.title)},switchMediaVisibility:function(t){return function(){var a=o(this),t=a.parents(".media"),e=t.parents(".gallery");l.ajax.post(e.data("ams-location")+"/set-media-visibility.json",{object_name:t.data("ams-element-name")},function(t,e){t.visible?(o("i",a).attr("class","fa fa-fw fa-eye"),a.parents(".btn-group").siblings("a.fancyimg").removeClass("not-visible")):(o("i",a).attr("class","fa fa-fw fa-eye-slash text-danger"),a.parents(".btn-group").siblings("a.fancyimg").addClass("not-visible"))})}},setOrder:function(t,e){if(!e||!e.item.hasClass("already-dropped")){var a=e.item.parents(".gallery"),i=o(".media",a).listattr("data-ams-element-name");l.ajax.post(a.data("ams-location")+"/set-medias-order.json",{medias:JSON.stringify(i)})}},removeMedia:function(t){return function(){var n=o(this);l.skin.bigBox({title:l.i18n.WARNING,content:'<i class="text-danger fa fa-2x fa-bell shake animated"></i>&nbsp; '+l.i18n.DELETE_WARNING,buttons:l.i18n.BTN_OK_CANCEL},function(t){if(t===l.i18n.BTN_OK){var e=n.parents(".gallery").data("ams-location"),a=n.parents(".media"),i=a.data("ams-element-name");l.ajax.post(e+"/delete-element.json",{object_name:i},function(t,e){a.remove()})}})}},afterFancyboxLoad:function(t,e){t.element.hasClass("not-visible")&&t.inner.prepend('<div class="hidden-mask"></div>')}},paragraphs:{preReload:function(){a.paragraphs.switched=o("i.switch.fa-minus-square-o","#paragraphs_list").parents("tr").listattr("id")},postReload:function(){o(a.paragraphs.switched).each(function(){o("i.switch.fa-plus-square-o",'[id="'+this+'"]').parents("div").first().click()}),delete a.paragraphs.switched},refreshParagraph:function(t){var e=o('tr[id="'+t.object_id+'"]');o("span.title",e).html(t.title||" - - - - - - - -")},switchEditor:function(t){var e=o(this),a=o("i.switch",e),i=e.parents("td"),n=o(".editor",i),s=e.parents("tr");if(a.hasClass("fa-plus-square-o")){var r=s.parents("table");n.html('<h1 class="loading"><i class="fa fa-2x fa-gear fa-spin"></i></h1>'),l.ajax.post(r.data("ams-location")+"/get-paragraph-editor.json",{object_name:s.data("ams-element-name")},function(t){n.html(t),t&&(l.initContent(n),a.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),s.data("ams-disabled-handlers",!0),l.skin.scrollTo(n,{offset:n.height()-s.height()}))})}else l.skin.cleanContainer(n),n.empty(),a.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),s.removeData("ams-disabled-handlers")},switchLastEditor:function(t){var e=o('table[id="'+t+'"]'),a=o("tr:last",e);o('[data-ams-click-handler="PyAMS_content.paragraphs.switchEditor"]',a).click()},switchAllEditors:function(t){var e=o(this),n=o("i",e),s=e.parents("table");n.hasClass("fa-plus-square-o")?(n.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),l.ajax.post(s.data("ams-location")+"/get-paragraphs-editors.json",{},function(t){for(var e in t)if(t.hasOwnProperty(e)){var a=o('tr[data-ams-element-name="'+e+'"]',s),i=o(".editor",a);i.is(":empty")&&i.html(t[e]),o(".fa-plus-square-o",a).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),a.data("ams-disabled-handlers",!0)}o("i.fa-plus-square-o",o("tbody",s)).exists()||n.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o"),l.initContent(s)})):(o(".editor",s).each(function(){l.skin.cleanContainer(o(this)),o(this).empty()}),o(".fa-minus-square-o",s).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o("tr",s).removeData("ams-disabled-handlers"))},updateToolbar:function(t){var e=o('tr[id="'+t.object_id+'"]'),a=o(".title-toolbar",e);a.replaceWith(t.toolbar_tag),a=o(".title-toolbar",e),l.initContent(a)},updateMarkers:function(t){var e=o('tr[id="'+t.object_id+'"]'),a=o(".title-toolbar",e),i=o("DIV.action."+t.marker_type,a);i.exists()?i.replaceWith(t.marker_tag):o(t.marker_tag).appendTo(a),t.marker_tag&&(i=o("DIV.action."+t.marker_type,a),l.initContent(i)),l.helpers.sort(a,"weight")}},pictograms:{initManagerSelection:function(){var t=o(this),e=o('input[type="hidden"]',o(".selected-pictograms",t)).listattr("value");return{selected:JSON.stringify(e)}},switchPictogram:function(){var t=o(this),e=t.parents(".pictograms"),a=e.parents(".pictograms-manager");e.hasClass("available-pictograms")?o(".selected-pictograms",a).append(t):o(".available-pictograms",a).append(t)}},themes:{initExtracts:function(t){var e=o('select[name="form.widgets.thesaurus_name:list"]',t).val(),a=o('select[name="form.widgets.extract_name:list"]',t),i=a.val();e&&l.jsonrpc.post("getExtracts",{thesaurus_name:e},{url:"/api/thesaurus/json"},function(t){a.empty(),o(t.result).each(function(){o("<option></option>").attr("value",this.id).attr("selected",this.id===i).text(this.text).appendTo(a)})}),a.attr("data-ams-events-handlers",'{"select2-open": "PyAMS_content.themes.getExtracts"}')},getExtracts:function(t){var a=o(t.currentTarget).parents("form"),e=o('select[name="form.widgets.thesaurus_name:list"]',a).val();e&&l.jsonrpc.post("getExtracts",{thesaurus_name:e},{url:"/api/thesaurus/json"},function(t){var e=o('select[name="form.widgets.extract_name:list"]',a).data("select2");e.results.empty(),e.opts.populateResults.call(e,e.results,t.result,{term:""})})}},fields:{refreshField:function(t){var e=o('table[id="form_fields_list"]'),a=o('tr[data-ams-element-name="'+t.object_name+'"]',e);o("td:nth-child(4)",a).html(t.title)}},imgmap:{init:function(){var t=o(this);l.ajax.check(o.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+l.devext+".js",function(){t.canvasAreaDraw({imageUrl:t.data("ams-image-url")})})},initPreview:function(){var t=o(this);l.ajax.check(o.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+l.devext+".js",function(){t.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},site:{switchVisibility:function(){return function(){var i=o(this),t=i.parents("tr").first();l.ajax.post(t.data("ams-location")+"/switch-content-visibility.json",{object_name:t.data("ams-element-name")},function(t,e){var a="fa-eye";t.visible||(a+="-slash"),t.published||(a+=" text-danger"),o("i",i).attr("class","fa fa-fw "+a)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(t){var e=o(".chat-body",t);e.animate({scrollTop:e[0].scrollHeight},1e3),clearInterval(a.review.timer),a.review.timer=setInterval(a.review.updateComments,a.review.timer_duration.chat),l.skin.registerCleanCallback(a.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(a.review.timer),a.review.timer=setInterval(a.review.updateComments,a.review.timer_duration.general)},updateComments:function(){var e,a=o(".badge",'nav a[href="#review-comments.html"]'),i=o(".chat-body",".widget-body");e=i.exists()?o(".message",i).length:parseInt(a.text()),l.ajax.post("get-last-review-comments.json",{count:e},function(t){i.exists()&&a.removeClass("bg-color-danger").addClass("bg-color-info"),e!==t.count&&(a.text(t.count).removeClass("hidden"),i.exists()&&(o(".messages",i).append(t.content),i.animate({scrollTop:i[0].scrollHeight},1e3)),i.exists()||a.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){o(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(t){var e=o(".chat-body",".widget-body");return{count:o(".message",e).length}},addCommentAction:function(){return function(){o('textarea[name="comment"]').focus()}},addCommentCallback:function(t){var e=o(this),a=e.parents(".widget-body");o(".messages",a).append(t.content),o('textarea[name="comment"]',e).val("");var i=o(".chat-body",a);i.animate({scrollTop:i[0].scrollHeight},1e3),o(".badge",'nav a[href="#review-comments.html"]').text(t.count).removeClass("hidden")}},profile:{switchFavorite:function(){var a=o(this),t=a.data("sequence-oid");l.ajax.post("switch-user-favorite.json",{oid:t},function(t,e){t.favorite?a.removeClass("fa-star-o").addClass("fa-star"):a.removeClass("fa-star").addClass("fa-star-o")})}}};o(".badge",'nav a[href="#review-comments.html"]').exists()&&(a.review.timer=setInterval(a.review.updateComments,a.review.timer_duration.general)),t.PyAMS_content=a}(jQuery,this);