--- a/.hgtags Tue Jul 17 15:12:43 2018 +0200
+++ b/.hgtags Thu Sep 06 11:27:55 2018 +0200
@@ -20,3 +20,4 @@
1978e4dad1d8f950411807ed2df23fd030a39b60 0.1.14
fc8fe2dede6309db4a8cfc5b53eb894cca2f6970 0.1.15
9cc7207c1399658ef821a1ecdde86df0b5a1298d 0.1.15.1
+f687b90488819f2dba88ed44a254d7cba1f8c652 0.1.16
--- a/buildout.cfg Tue Jul 17 15:12:43 2018 +0200
+++ b/buildout.cfg Thu Sep 06 11:27:55 2018 +0200
@@ -86,4 +86,4 @@
eggs = pyams_content [test]
[versions]
-pyams_content = 0.1.16
+pyams_content = 0.1.17
--- a/docs/HISTORY.txt Tue Jul 17 15:12:43 2018 +0200
+++ b/docs/HISTORY.txt Thu Sep 06 11:27:55 2018 +0200
@@ -1,6 +1,24 @@
History
=======
+0.1.16
+------
+ - use iterators in all dashboards
+ - updated view content portlet to select and merge several views
+ - handle cache for header and footer
+ - added custom file view to check publication status before giving access
+ - added arguments to avoid using cache when getting view results (for example in preview mode)
+ - added "oid_to_urls" HTML renderer to convert internal "oid://" links to URLs
+ - added Opengraph metas for shared contents
+ - added support for illustration to thesaurus terms
+ - added support for tags and collections, which are specific kinds of themes
+ - added location map paragraph
+ - added redirections manager
+ - added renderer resources management
+ - use locale name in header and footer cache key
+ - updated system manager permissions
+ - updated internal links management
+
0.1.15.1
--------
- added request argument when rendering pictogram image
--- a/setup.py Tue Jul 17 15:12:43 2018 +0200
+++ b/setup.py Thu Sep 06 11:27:55 2018 +0200
@@ -22,7 +22,7 @@
README = os.path.join(DOCS, 'README.txt')
HISTORY = os.path.join(DOCS, 'HISTORY.txt')
-version = '0.1.16'
+version = '0.1.17'
long_description = open(README).read() + '\n\n' + open(HISTORY).read()
tests_require = []
--- a/src/pyams_content.egg-info/PKG-INFO Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content.egg-info/PKG-INFO Thu Sep 06 11:27:55 2018 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pyams-content
-Version: 0.1.15.1
+Version: 0.1.16
Summary: PyAMS base content interfaces and classes
Home-page: http://hg.ztfy.org/pyams/pyams_content
Author: Thierry Florac
@@ -73,6 +73,24 @@
History
=======
+ 0.1.16
+ ------
+ - use iterators in all dashboards
+ - updated view content portlet to select and merge several views
+ - handle cache for header and footer
+ - added custom file view to check publication status before giving access
+ - added arguments to avoid using cache when getting view results (for example in preview mode)
+ - added "oid_to_urls" HTML renderer to convert internal "oid://" links to URLs
+ - added Opengraph metas for shared contents
+ - added support for illustration to thesaurus terms
+ - added support for tags and collections, which are specific kinds of themes
+ - added location map paragraph
+ - added redirections manager
+ - added renderer resources management
+ - use locale name in header and footer cache key
+ - updated system manager permissions
+ - updated internal links management
+
0.1.15.1
--------
- added request argument when rendering pictogram image
--- a/src/pyams_content.egg-info/SOURCES.txt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content.egg-info/SOURCES.txt Thu Sep 06 11:27:55 2018 +0200
@@ -27,6 +27,7 @@
src/pyams_content/component/extfile/interfaces/__init__.py
src/pyams_content/component/extfile/zmi/__init__.py
src/pyams_content/component/extfile/zmi/container.py
+src/pyams_content/component/file/__init__.py
src/pyams_content/component/gallery/__init__.py
src/pyams_content/component/gallery/file.py
src/pyams_content/component/gallery/paragraph.py
@@ -35,12 +36,15 @@
src/pyams_content/component/gallery/zmi/file.py
src/pyams_content/component/gallery/zmi/interfaces.py
src/pyams_content/component/gallery/zmi/paragraph.py
+src/pyams_content/component/gallery/zmi/templates/gallery-media-thumbnail.pt
src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt
src/pyams_content/component/illustration/__init__.py
src/pyams_content/component/illustration/paragraph.py
+src/pyams_content/component/illustration/thesaurus.py
src/pyams_content/component/illustration/interfaces/__init__.py
src/pyams_content/component/illustration/zmi/__init__.py
src/pyams_content/component/illustration/zmi/paragraph.py
+src/pyams_content/component/illustration/zmi/thesaurus.py
src/pyams_content/component/illustration/zmi/templates/illustration-thumbnail.pt
src/pyams_content/component/illustration/zmi/templates/paragraph-illustration-icon.pt
src/pyams_content/component/keynumber/__init__.py
@@ -54,7 +58,6 @@
src/pyams_content/component/links/interfaces/__init__.py
src/pyams_content/component/links/zmi/__init__.py
src/pyams_content/component/links/zmi/container.py
-src/pyams_content/component/links/zmi/reverse.py
src/pyams_content/component/media/__init__.py
src/pyams_content/component/paragraph/__init__.py
src/pyams_content/component/paragraph/audio.py
@@ -65,6 +68,7 @@
src/pyams_content/component/paragraph/html.py
src/pyams_content/component/paragraph/keynumber.py
src/pyams_content/component/paragraph/keypoint.py
+src/pyams_content/component/paragraph/map.py
src/pyams_content/component/paragraph/milestone.py
src/pyams_content/component/paragraph/pictogram.py
src/pyams_content/component/paragraph/verbatim.py
@@ -77,6 +81,7 @@
src/pyams_content/component/paragraph/interfaces/html.py
src/pyams_content/component/paragraph/interfaces/keynumber.py
src/pyams_content/component/paragraph/interfaces/keypoint.py
+src/pyams_content/component/paragraph/interfaces/map.py
src/pyams_content/component/paragraph/interfaces/milestone.py
src/pyams_content/component/paragraph/interfaces/pictogram.py
src/pyams_content/component/paragraph/interfaces/verbatim.py
@@ -91,6 +96,7 @@
src/pyams_content/component/paragraph/zmi/interfaces.py
src/pyams_content/component/paragraph/zmi/keynumber.py
src/pyams_content/component/paragraph/zmi/keypoint.py
+src/pyams_content/component/paragraph/zmi/map.py
src/pyams_content/component/paragraph/zmi/milestone.py
src/pyams_content/component/paragraph/zmi/pictogram.py
src/pyams_content/component/paragraph/zmi/preview.py
@@ -105,7 +111,6 @@
src/pyams_content/component/theme/zmi/__init__.py
src/pyams_content/component/theme/zmi/manager.py
src/pyams_content/component/theme/zmi/portlet.py
-src/pyams_content/component/theme/zmi/templates/themes-info.pt
src/pyams_content/component/video/__init__.py
src/pyams_content/component/video/paragraph.py
src/pyams_content/component/video/interfaces/__init__.py
@@ -141,8 +146,10 @@
src/pyams_content/features/header/__init__.py
src/pyams_content/features/header/interfaces/__init__.py
src/pyams_content/features/header/skin/__init__.py
+src/pyams_content/features/header/skin/interfaces.py
src/pyams_content/features/header/zmi/__init__.py
src/pyams_content/features/header/zmi/templates/renderer-settings.pt
+src/pyams_content/features/html/__init__.py
src/pyams_content/features/menu/__init__.py
src/pyams_content/features/menu/interfaces/__init__.py
src/pyams_content/features/menu/portlet/__init__.py
@@ -164,6 +171,13 @@
src/pyams_content/features/preview/zmi/__init__.py
src/pyams_content/features/preview/zmi/interfaces.py
src/pyams_content/features/preview/zmi/templates/preview.pt
+src/pyams_content/features/redirect/__init__.py
+src/pyams_content/features/redirect/container.py
+src/pyams_content/features/redirect/tween.py
+src/pyams_content/features/redirect/interfaces/__init__.py
+src/pyams_content/features/redirect/zmi/__init__.py
+src/pyams_content/features/redirect/zmi/container.py
+src/pyams_content/features/redirect/zmi/templates/manager-test.pt
src/pyams_content/features/renderer/__init__.py
src/pyams_content/features/renderer/interfaces/__init__.py
src/pyams_content/features/renderer/skin/__init__.py
@@ -233,6 +247,7 @@
src/pyams_content/shared/common/portlet/content/zmi/preview.pt
src/pyams_content/shared/common/skin/__init__.py
src/pyams_content/shared/common/skin/oid.py
+src/pyams_content/shared/common/skin/opengraph.py
src/pyams_content/shared/common/skin/url.py
src/pyams_content/shared/common/zmi/__init__.py
src/pyams_content/shared/common/zmi/dashboard.py
@@ -243,6 +258,7 @@
src/pyams_content/shared/common/zmi/portal.py
src/pyams_content/shared/common/zmi/properties.py
src/pyams_content/shared/common/zmi/rename.py
+src/pyams_content/shared/common/zmi/reverse.py
src/pyams_content/shared/common/zmi/search.py
src/pyams_content/shared/common/zmi/security.py
src/pyams_content/shared/common/zmi/site.py
@@ -321,6 +337,7 @@
src/pyams_content/shared/site/zmi/widget/templates/folders-input.pt
src/pyams_content/shared/view/__init__.py
src/pyams_content/shared/view/manager.py
+src/pyams_content/shared/view/merge.py
src/pyams_content/shared/view/reference.py
src/pyams_content/shared/view/theme.py
src/pyams_content/shared/view/interfaces/__init__.py
--- a/src/pyams_content/component/association/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/association/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -124,11 +124,18 @@
attributes.setdefault('table', {}).update({
'data-ams-location': absolute_url(container, self.request),
'data-ams-tablednd-drag-handle': 'td.sorter',
- 'data-ams-tablednd-drop-target': 'set-associations-order.json',
- 'data-ams-visibility-switcher': 'switch-association-visibility.json'
+ 'data-ams-tablednd-drop-target': 'set-associations-order.json'
+ })
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target
})
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-association-visibility.json'
+
@reify
def values(self):
return list(super(AssociationsTable, self).values)
--- a/src/pyams_content/component/gallery/zmi/interfaces.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/gallery/zmi/interfaces.py Thu Sep 06 11:27:55 2018 +0200
@@ -39,7 +39,7 @@
author = TextLine(title=_("Author"),
description=_("Name of document's author"),
- required=False)
+ required=True)
author_comments = I18nTextField(title=_("Author comments"),
description=_("Comments relatives to author's rights management"),
--- a/src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt Thu Sep 06 11:27:55 2018 +0200
@@ -2,6 +2,7 @@
data-ams-plugins="pyams_content"
tal:define="gallery_images context.values()"
tal:attributes="data-ams-plugin-pyams_content-src tales:resource_path('pyams_content.skin:pyams_content');
+ data-ams-plugin-pyams_content-css tales:resource_path('pyams_content.skin:pyams_content_css');
id string:gallery_medias_${context.__name__};"
data-ams-plugin-pyams_content-async="false">
<fieldset class="margin-top-10 padding-top-5 padding-bottom-0">
--- a/src/pyams_content/component/illustration/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/illustration/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -61,8 +61,8 @@
class IIllustration(IBasicIllustration, IRenderedContent):
"""Illustration paragraph"""
- description = I18nTextField(title=_("Description"),
- description=_(""),
+ description = I18nTextField(title=_("Associated text"),
+ description=_("Illustration description displayed in front-office templates"),
required=False)
author = TextLine(title=_("Author"),
--- a/src/pyams_content/component/illustration/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/illustration/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -51,15 +51,31 @@
css_class = 'form-group'
padding_class = ''
- fieldset_class = 'bordered margin-top-10 padding-y-5'
+ # fieldset_class = 'bordered margin-top-10 padding-y-5'
legend = _("Illustration")
- legend_class = 'illustration switcher no-y-padding padding-right-10'
+ # legend_class = 'illustration switcher no-y-padding padding-right-10'
fields = field.Fields(IBasicIllustration).omit('__parent__', '__name__')
weight = 10
+ @property
+ def legend_class(self):
+ if IBaseParagraph.providedBy(self.context):
+ return 'illustration switcher no-y-padding padding-right-10 pull-left width-auto'
+ else:
+ return 'illustration switcher no-y-padding'
+
+ @property
+ def fieldset_class(self):
+ result = 'margin-top-10 padding-y-5'
+ if not IBaseParagraph.providedBy(self.context):
+ result += ' bordered'
+ return result
+
+ hide_widgets_prefix_div = True
+
def getContent(self):
return IIllustration(self.context)
@@ -69,9 +85,10 @@
@property
def switcher_state(self):
- content = self.getContent()
- if content.has_data():
- return 'open'
+ if not IBaseParagraph.providedBy(self.context):
+ content = self.getContent()
+ if content.has_data():
+ return 'open'
def get_ajax_output(self, changes):
output = super(BasicIllustrationPropertiesInnerEditForm, self).get_ajax_output(changes)
@@ -102,22 +119,6 @@
return _("Header illustration")
@property
- def legend_class(self):
- if IBaseParagraph.providedBy(self.context):
- return 'illustration switcher no-y-padding padding-right-10 pull-left width-auto'
- else:
- return 'illustration switcher no-y-padding'
-
- @property
- def fieldset_class(self):
- result = 'margin-top-10 padding-y-5'
- if not IBaseParagraph.providedBy(self.context):
- result += ' bordered'
- return result
-
- hide_widgets_prefix_div = True
-
- @property
def switcher_state(self):
if not IBaseParagraph.providedBy(self.context):
return 'open'
--- a/src/pyams_content/component/keynumber/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/keynumber/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,6 +16,7 @@
# import standard library
# import interfaces
+from pyams_content.component.paragraph.interfaces import IBaseParagraph
from pyams_content.interfaces.container import IOrderedContainer
from zope.annotation.interfaces import IAttributeAnnotatable
@@ -23,7 +24,7 @@
from pyams_i18n.schema import I18nTextLineField
from zope.container.constraints import containers, contains
from zope.interface import Interface
-from zope.schema import Bool, TextLine
+from zope.schema import Bool, TextLine, Choice
from pyams_content import _
@@ -76,3 +77,21 @@
class IKeyNumberContainerTarget(Interface):
"""Key numbers container target interface"""
+
+
+KEYNUMBER_PARAGRAPH_TYPE = 'KeyNumbers'
+KEYNUMBER_PARAGRAPH_NAME = _("Key numbers")
+KEYNUMBER_PARAGRAPH_RENDERERS = 'PyAMS.keynumbers.renderers'
+
+
+#
+# KeyNumber paragraph
+#
+
+class IKeyNumberParagraph(IKeyNumberContainerTarget, IBaseParagraph):
+ """Key numbers paragraph interface"""
+
+ renderer = Choice(title=_("Key numbers template"),
+ description=_("Presentation template used for key numbers"),
+ vocabulary=KEYNUMBER_PARAGRAPH_RENDERERS,
+ default='default')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/keynumber/paragraph.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2008-2015 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.paragraph.interfaces import IParagraphFactory
+from pyams_content.component.keynumber.interfaces import KEYNUMBER_PARAGRAPH_TYPE, KEYNUMBER_PARAGRAPH_NAME, \
+ KEYNUMBER_PARAGRAPH_RENDERERS, IKeyNumberParagraph
+from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
+from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
+
+# import packages
+from pyams_content.component.paragraph import BaseParagraph, BaseParagraphFactory, BaseParagraphContentChecker
+from pyams_content.features.renderer import RenderersVocabulary
+from pyams_utils.adapter import adapter_config
+from pyams_utils.factory import factory_config
+from pyams_utils.registry import get_utility, utility_config
+from pyams_utils.request import check_request
+from pyams_utils.traversing import get_parent
+from pyams_utils.vocabulary import vocabulary_config
+from zope.interface import implementer
+from zope.schema.fieldproperty import FieldProperty
+
+
+@implementer(IKeyNumberParagraph)
+@factory_config(provided=IKeyNumberParagraph)
+class KeyNumberParagraph(BaseParagraph):
+ """Key numbers paragraph"""
+
+ icon_class = 'fa-dashboard'
+ icon_hint = KEYNUMBER_PARAGRAPH_NAME
+
+ renderer = FieldProperty(IKeyNumberParagraph['renderer'])
+
+
+@utility_config(name=KEYNUMBER_PARAGRAPH_TYPE, provides=IParagraphFactory)
+class KeyNumberParagraphFactory(BaseParagraphFactory):
+ """Key numbers paragraph factory"""
+
+ name = KEYNUMBER_PARAGRAPH_NAME
+ content_type = KeyNumberParagraph
+
+
+@adapter_config(context=IKeyNumberParagraph, provides=IContentChecker)
+class KeyNumberParagraphContentChecker(BaseParagraphContentChecker):
+ """Key numbers paragraph content checker"""
+
+ @property
+ def label(self):
+ request = check_request()
+ translate = request.localizer.translate
+ return II18n(self.context).query_attribute('title', request) or \
+ '({0})'.format(translate(self.context.icon_hint).lower())
+
+ def inner_check(self, request):
+ output = []
+ translate = request.localizer.translate
+ manager = get_parent(self.context, II18nManager)
+ if manager is not None:
+ langs = manager.get_languages()
+ else:
+ negotiator = get_utility(INegotiator)
+ langs = (negotiator.server_language, )
+ i18n = II18n(self.context)
+ for lang in langs:
+ value = i18n.get_attribute('title', lang, request)
+ if not value:
+ field_title = translate(IKeyNumberParagraph['title'].title)
+ if len(langs) == 1:
+ output.append(translate(MISSING_VALUE).format(field=field_title))
+ else:
+ output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang))
+ return output
+
+
+@vocabulary_config(name=KEYNUMBER_PARAGRAPH_RENDERERS)
+class KeyNumberParagraphRendererVocabulary(RenderersVocabulary):
+ """Key numbers paragraph renderers vocabulary"""
+
+ content_interface = IKeyNumberParagraph
--- a/src/pyams_content/component/keynumber/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/keynumber/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -94,11 +94,24 @@
attributes.setdefault('table', {}).update({
'data-ams-location': absolute_url(container, self.request),
'data-ams-tablednd-drag-handle': 'td.sorter',
- 'data-ams-tablednd-drop-target': 'set-keynumbers-order.json',
- 'data-ams-visibility-switcher': 'switch-keynumber-visibility.json'
+ 'data-ams-tablednd-drop-target': 'set-keynumbers-order.json'
+ })
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target,
+ 'data-ams-switcher-attribute-name': self.get_switcher_attribute
})
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-keynumber-visibility.json'
+
+ @staticmethod
+ def get_switcher_attribute(element, column):
+ if column.__name__ == 'show-hide':
+ return 'visible'
+
@reify
def values(self):
return list(super(KeyNumbersTable, self).values)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/keynumber/zmi/paragraph.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,125 @@
+#
+# Copyright (c) 2008-2015 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.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer
+from pyams_content.component.keynumber.interfaces import KEYNUMBER_PARAGRAPH_TYPE, IKeyNumberParagraph
+from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView
+from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
+from pyams_content.shared.common import IWfSharedContent
+from pyams_form.interfaces.form import IInnerForm
+from pyams_i18n.interfaces import II18n
+from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
+from pyams_skin.layer import IPyAMSLayer
+from z3c.form.interfaces import INPUT_MODE
+
+# import packages
+from pyams_content.component.keynumber.zmi import IKeyNumbersParentForm
+from pyams_content.component.keynumber.paragraph import KeyNumberParagraph
+from pyams_content.component.paragraph.zmi import BaseParagraphAddMenu, BaseParagraphAJAXAddForm, \
+ BaseParagraphPropertiesEditForm, BaseParagraphAJAXEditForm, IParagraphEditFormButtons
+from pyams_content.features.renderer.zmi.widget import RendererFieldWidget
+from pyams_form.form import ajax_config
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_skin.event import get_json_widget_refresh_event
+from pyams_utils.adapter import adapter_config
+from pyams_utils.traversing import get_parent
+from pyams_viewlet.viewlet import viewlet_config
+from pyams_zmi.form import AdminDialogAddForm
+from z3c.form import field, button
+from zope.interface import implementer, Interface
+
+from pyams_content import _
+
+
+@viewlet_config(name='add-keynumber-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
+ layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=600)
+class KeyNumberParagraphAddMenu(BaseParagraphAddMenu):
+ """Key number paragraph add menu"""
+
+ label = _("Key numbers...")
+ label_css_class = 'fa fa-fw fa-dashboard'
+ url = 'add-keynumber-paragraph.html'
+ paragraph_type = KEYNUMBER_PARAGRAPH_TYPE
+
+
+@pagelet_config(name='add-keynumber-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION)
+@ajax_config(name='add-keynumber-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ base=BaseParagraphAJAXAddForm)
+class KeyNumberParagraphAddForm(AdminDialogAddForm):
+ """Key number paragraph add form"""
+
+ legend = _("Add new key number paragraph")
+ icon_css_class = 'fa fa-fw fa-dashboard'
+
+ fields = field.Fields(IKeyNumberParagraph).select('title', 'renderer')
+ edit_permission = MANAGE_CONTENT_PERMISSION
+
+ def create(self, data):
+ return KeyNumberParagraph()
+
+ def add(self, object):
+ IParagraphContainer(self.context).append(object)
+
+
+@pagelet_config(name='properties.html', context=IKeyNumberParagraph, layer=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION)
+@ajax_config(name='properties.json', context=IKeyNumberParagraph, layer=IPyAMSLayer,
+ base=BaseParagraphAJAXEditForm)
+@implementer(IKeyNumbersParentForm)
+class KeyNumberParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm):
+ """Key number paragraph properties edit form"""
+
+ prefix = 'keynumbers_properties.'
+
+ @property
+ def title(self):
+ content = get_parent(self.context, IWfSharedContent)
+ return II18n(content).query_attribute('title', request=self.request)
+
+ legend = _("Edit key number paragraph properties")
+ icon_css_class = 'fa fa-fw fa-dashboard'
+
+ fields = field.Fields(IKeyNumberParagraph).select('title', 'renderer')
+ fields['renderer'].widgetFactory = RendererFieldWidget
+
+ edit_permission = MANAGE_CONTENT_PERMISSION
+
+
+@adapter_config(context=(IKeyNumberParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
+@ajax_config(name='inner-properties.json', context=IKeyNumberParagraph, layer=IPyAMSLayer,
+ base=BaseParagraphAJAXEditForm)
+@implementer(IInnerForm, IKeyNumbersParentForm)
+class KeyNumberParagraphInnerEditForm(KeyNumberParagraphPropertiesEditForm):
+ """Key number paragraph inner edit form"""
+
+ legend = None
+
+ @property
+ def buttons(self):
+ if self.mode == INPUT_MODE:
+ return button.Buttons(IParagraphEditFormButtons)
+ else:
+ return button.Buttons()
+
+ def get_ajax_output(self, changes):
+ output = super(self.__class__, self).get_ajax_output(changes)
+ updated = changes.get(IKeyNumberParagraph, ())
+ if 'renderer' in updated:
+ output.setdefault('events', []).append(
+ get_json_widget_refresh_event(self.context, self.request, KeyNumberParagraphInnerEditForm, 'renderer'))
+ return output
--- a/src/pyams_content/component/links/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/links/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,14 +16,16 @@
# import standard library
# import interfaces
-from pyams_content.component.association.interfaces import IAssociationInfo, IAssociationContainerTarget, IAssociationContainer
+from pyams_content.component.association.interfaces import IAssociationInfo, IAssociationContainerTarget, \
+ IAssociationContainer
from pyams_content.component.links.interfaces import IBaseLink, IInternalLink, IExternalLink, IMailtoLink
from pyams_content.features.checker.interfaces import IContentChecker, ERROR_VALUE
from pyams_content.interfaces import IBaseContent, MANAGE_CONTENT_PERMISSION
from pyams_content.reference.pictograms.interfaces import IPictogramTable
from pyams_form.interfaces.form import IFormContextPermissionChecker
from pyams_i18n.interfaces import II18n
-from pyams_sequence.interfaces import ISequentialIdInfo
+from pyams_sequence.interfaces import ISequentialIdInfo, IInternalReference
+from pyams_skin.layer import IPyAMSUserLayer
from pyams_workflow.interfaces import IWorkflow, IWorkflowPublicationInfo
# import packages
@@ -115,8 +117,27 @@
# Internal links
#
+@implementer(IInternalReference)
+class InternalReferenceMixin(object):
+ """Internal reference mixin class"""
+
+ reference = None
+
+ @volatile_property
+ def target(self):
+ return get_reference_target(self.reference)
+
+ def get_target(self, state=None, request=None):
+ if request is None:
+ request = check_request()
+ if (not state) and not IPyAMSUserLayer.providedBy(request):
+ return self.target
+ else:
+ return get_reference_target(self.reference, state, request)
+
+
@implementer(IInternalLink)
-class InternalLink(BaseLink):
+class InternalLink(BaseLink, InternalReferenceMixin):
"""Internal link persistent class"""
icon_class = 'fa-external-link-square fa-rotate-90'
@@ -124,16 +145,6 @@
reference = FieldProperty(IInternalLink['reference'])
- @volatile_property
- def target(self):
- return get_reference_target(self.reference)
-
- def get_target(self, state=None):
- if not state:
- return self.target
- else:
- return get_reference_target(self.reference, state)
-
def is_visible(self, request=None):
target = self.get_target()
if target is not None:
--- a/src/pyams_content/component/links/zmi/reverse.py Tue Jul 17 15:12:43 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-#
-# Copyright (c) 2008-2015 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 hypatia.interfaces import ICatalog
-from pyams_content.shared.common.interfaces import IWfSharedContent
-from pyams_content.shared.common.interfaces.zmi import ISiteRootDashboardTable
-from pyams_content.shared.site.interfaces import ISiteContainer
-from pyams_portal.interfaces import IPortalTemplate
-from pyams_sequence.interfaces import ISequentialIdInfo
-from pyams_skin.interfaces import IInnerPage
-from pyams_skin.layer import IPyAMSLayer
-from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
-from pyams_workflow.interfaces import IWorkflowVersions
-from pyams_zmi.interfaces.menu import IContentManagementMenu
-from pyams_zmi.layer import IAdminLayer
-from z3c.table.interfaces import IValues, IColumn
-
-# import packages
-from hypatia.catalog import CatalogQuery
-from hypatia.query import Eq, Or
-from pyams_catalog.query import CatalogResultSet
-from pyams_pagelet.pagelet import pagelet_config
-from pyams_skin.container import ContainerView
-from pyams_skin.table import BaseTable, NameColumn
-from pyams_skin.viewlet.menu import MenuItem
-from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
-from pyams_utils.list import unique
-from pyams_utils.registry import get_utility
-from pyams_utils.traversing import get_parent
-from pyams_viewlet.viewlet import viewlet_config
-from pyams_zmi.view import AdminView
-from zope.interface import implementer, Interface
-
-from pyams_content import _
-
-
-@viewlet_config(name='reverse-links.menu', context=IWfSharedContent, layer=IAdminLayer,
- manager=IContentManagementMenu, permission=VIEW_SYSTEM_PERMISSION, weight=40)
-class SequentialITargetReverseLinksMenu(MenuItem):
- """Sequential ID target reverse links menu"""
-
- label = _("Reverse links")
- icon_class = 'fa-anchor'
- url = '#reverse-links.html'
-
-
-@implementer(ISiteRootDashboardTable)
-class SequentialIdTargetReverseLinkTable(BaseTable):
- """Sequential ID target reverse links table"""
-
- title = _("Content's internal links")
-
-
-@adapter_config(name='name', context=(Interface, IPyAMSLayer, SequentialIdTargetReverseLinkTable), provides=IColumn)
-class ReverseLinkNameColumn(NameColumn):
- """Reverse link name column"""
-
- _header = _("Title")
-
-
-@adapter_config(context=(IWfSharedContent, IPyAMSLayer, SequentialIdTargetReverseLinkTable), provides=IValues)
-class SequentialIdTargetReverseLinkValues(ContextRequestViewAdapter):
- """Sequential ID target reverse links values"""
-
- @property
- def values(self):
-
- def get_item(result):
- parent = get_parent(result, IWfSharedContent)
- if parent is not None:
- return IWorkflowVersions(parent).get_last_versions(count=1)[0]
- parent = get_parent(result, IPortalTemplate)
- if parent is None:
- parent = get_parent(result, ISiteContainer)
- if parent is None:
- parent = self.request.root
- return parent
-
- catalog = get_utility(ICatalog)
- oid = ISequentialIdInfo(self.context).hex_oid
- params = Or(Eq(catalog['link_reference'], oid),
- Eq(catalog['link_references'], oid))
- return unique(map(get_item,
- CatalogResultSet(CatalogQuery(catalog).query(params,
- sort_index='modified_date'))))
-
-
-@pagelet_config(name='reverse-links.html', context=IWfSharedContent, layer=IPyAMSLayer,
- permission=VIEW_SYSTEM_PERMISSION)
-@implementer(IInnerPage)
-class SequentialIdTargetReverseLinkView(AdminView, ContainerView):
- """Sequential ID target reverse links view"""
-
- table_class = SequentialIdTargetReverseLinkTable
--- a/src/pyams_content/component/paragraph/audio.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/audio.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,7 +16,7 @@
# import standard library
# import interfaces
-from pyams_content.component.illustration.interfaces import IIllustrationTarget
+from pyams_content.component.illustration.interfaces import IBasicIllustrationTarget
from pyams_content.component.paragraph.interfaces import IParagraphFactory
from pyams_content.component.paragraph.interfaces.audio import IAudioParagraph, AUDIO_PARAGRAPH_TYPE, \
AUDIO_PARAGRAPH_RENDERERS, AUDIO_PARAGRAPH_NAME
@@ -36,7 +36,7 @@
from zope.schema.fieldproperty import FieldProperty
-@implementer(IAudioParagraph, IIllustrationTarget)
+@implementer(IAudioParagraph, IBasicIllustrationTarget)
@factory_config(provided=IAudioParagraph)
class AudioParagraph(BaseParagraph):
"""Audio paragraph class"""
--- a/src/pyams_content/component/paragraph/container.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/container.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,8 +16,8 @@
# import standard library
# import interfaces
-from pyams_content.component.paragraph.interfaces import IParagraphContainer, IParagraphContainerTarget, \
- PARAGRAPH_CONTAINER_KEY
+from pyams_content.component.paragraph.interfaces import IParagraphFactory, IParagraphContainer, \
+ IParagraphContainerTarget, PARAGRAPH_CONTAINER_KEY
from pyams_content.features.checker.interfaces import IContentChecker
from zope.location.interfaces import ISublocations
from zope.traversing.interfaces import ITraversable
@@ -26,6 +26,7 @@
from pyams_content.features.checker import BaseContentChecker
from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter
from pyams_utils.container import BTreeOrderedContainer
+from pyams_utils.registry import get_global_registry
from zope.interface import implementer
from pyams_content import _
@@ -42,6 +43,22 @@
self[key] = value
self.last_id += 1
+ def get_visible_paragraphs(self, anchors_only=False, factories=None):
+ for paragraph in self.values():
+ if not paragraph.visible:
+ continue
+ if anchors_only and not paragraph.anchor:
+ continue
+ if factories:
+ registry = get_global_registry()
+ has_factory = False
+ for factory_name in factories:
+ factory = registry.queryUtility(IParagraphFactory, name=factory_name)
+ has_factory = (factory is not None) and (factory.content_type == paragraph.__class__)
+ if not has_factory:
+ continue
+ yield paragraph
+
@adapter_config(context=IParagraphContainerTarget, provides=IParagraphContainer)
def paragraph_container_factory(target):
--- a/src/pyams_content/component/paragraph/frame.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/frame.py Thu Sep 06 11:27:55 2018 +0200
@@ -46,7 +46,7 @@
class FrameParagraph(BaseParagraph):
"""Framed text paragraph"""
- icon_class = 'fa-list-alt'
+ icon_class = 'fa-window-maximize'
icon_hint = FRAME_PARAGRAPH_NAME
body = FieldProperty(IFrameParagraph['body'])
--- a/src/pyams_content/component/paragraph/header.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/header.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,24 +16,23 @@
# import standard library
# import interfaces
-from pyams_content.component.paragraph.interfaces import IParagraphFactory
-from pyams_content.component.paragraph.interfaces.header import IHeaderParagraph, HEADER_PARAGRAPH_TYPE, \
- HEADER_PARAGRAPH_RENDERERS, HEADER_PARAGRAPH_NAME
-from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
-from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
+from pyams_content.component.paragraph.interfaces.header import IHeaderParagraph, HEADER_PARAGRAPH_RENDERERS, \
+ HEADER_PARAGRAPH_NAME
+from pyams_content.features.checker.interfaces import IContentChecker, ERROR_VALUE
+from pyams_i18n.interfaces import II18n
# import packages
-from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory
+from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker
from pyams_content.features.renderer import RenderersVocabulary
from pyams_utils.adapter import adapter_config
from pyams_utils.factory import factory_config
-from pyams_utils.registry import utility_config, get_utility
from pyams_utils.text import get_text_start
-from pyams_utils.traversing import get_parent
from pyams_utils.vocabulary import vocabulary_config
from zope.interface import implementer
from zope.schema.fieldproperty import FieldProperty
+from pyams_content import _
+
@implementer(IHeaderParagraph)
@factory_config(provided=IHeaderParagraph)
@@ -52,37 +51,15 @@
renderer = FieldProperty(IHeaderParagraph['renderer'])
-@utility_config(name=HEADER_PARAGRAPH_TYPE, provides=IParagraphFactory)
-class HeaderParagraphFactory(BaseParagraphFactory):
- """Header paragraph factory"""
-
- name = HEADER_PARAGRAPH_NAME
- content_type = HeaderParagraph
-
-
@adapter_config(context=IHeaderParagraph, provides=IContentChecker)
class HeaderParagraphContentChecker(BaseParagraphContentChecker):
"""Header paragraph content checker"""
def inner_check(self, request):
- output = []
translate = request.localizer.translate
- manager = get_parent(self.context, II18nManager)
- if manager is not None:
- langs = manager.get_languages()
- else:
- negotiator = get_utility(INegotiator)
- langs = (negotiator.server_language, )
- i18n = II18n(self.context)
- for lang in langs:
- value = i18n.get_attribute('header', lang, request)
- if not value:
- field_title = translate(IHeaderParagraph['header'].title)
- if len(langs) == 1:
- output.append(translate(MISSING_VALUE).format(field=field_title))
- else:
- output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang))
- return output
+ field_title = translate(IHeaderParagraph['header'].title)
+ return [translate(ERROR_VALUE).format(field=field_title,
+ message=_("This paragraph type is deprecated and should be removed!")), ]
@vocabulary_config(name=HEADER_PARAGRAPH_RENDERERS)
--- a/src/pyams_content/component/paragraph/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -66,11 +66,17 @@
def append(self, value):
"""Add given value to container"""
+ def get_visible_paragraphs(self, anchors_only=False, factories=None):
+ """Get visible paragraphs matching given arguments"""
+
class IParagraphContainerTarget(IAttributeAnnotatable):
"""Paragraphs container marker interface"""
+PARAGRAPH_FACTORIES_VOCABULARY = 'PyAMS paragraph factories'
+
+
class IParagraphFactory(Interface):
"""Paragraph factory utility interface"""
@@ -93,7 +99,7 @@
auto_created_paragraphs = List(title=_("Default paragraphs"),
description=_("List of paragraphs automatically added to a new content"),
required=False,
- value_type=Choice(vocabulary='PyAMS paragraph factories'))
+ value_type=Choice(vocabulary=PARAGRAPH_FACTORIES_VOCABULARY))
class IParagraphRenderer(IContentProvider):
--- a/src/pyams_content/component/paragraph/interfaces/audio.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/audio.py Thu Sep 06 11:27:55 2018 +0200
@@ -51,7 +51,7 @@
author = TextLine(title=_("Author"),
description=_("Name of document's author"),
- required=True)
+ required=False)
renderer = Choice(title=_("Audio template"),
description=_("Presentation template used for this audio file"),
--- a/src/pyams_content/component/paragraph/interfaces/keynumber.py Tue Jul 17 15:12:43 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#
-# Copyright (c) 2008-2015 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.keynumber.interfaces import IKeyNumberContainerTarget
-from pyams_content.component.paragraph import IBaseParagraph
-
-# import packages
-from zope.schema import Bool, Choice, TextLine
-
-from pyams_content import _
-
-
-KEYNUMBER_PARAGRAPH_TYPE = 'KeyNumbers'
-KEYNUMBER_PARAGRAPH_NAME = _("Key numbers")
-KEYNUMBER_PARAGRAPH_RENDERERS = 'PyAMS.keynumbers.renderers'
-
-
-class IKeyNumberParagraph(IKeyNumberContainerTarget, IBaseParagraph):
- """Key numbers paragraph interface"""
-
- renderer = Choice(title=_("Key numbers template"),
- description=_("Presentation template used for key numbers"),
- vocabulary=KEYNUMBER_PARAGRAPH_RENDERERS,
- default='default')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/paragraph/interfaces/map.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,60 @@
+#
+# 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'
+
+
+try:
+ from pyams_gis.schema import GeoPointField
+except ImportError:
+ have_gis = False
+else:
+ have_gis = True
+
+if have_gis:
+
+ # import standard library
+
+ # import interfaces
+ from pyams_content.component.paragraph.interfaces import IBaseParagraph
+
+ # import packages
+ from zope.schema import Choice, Bool
+
+ from pyams_content import _
+
+
+ #
+ # Map paragraph
+ #
+
+ MAP_PARAGRAPH_TYPE = 'Map'
+ MAP_PARAGRAPH_NAME = _("Location map")
+ MAP_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.map.renderers'
+
+
+ class IMapParagraph(IBaseParagraph):
+ """Map paragraph interface"""
+
+ gps_location = GeoPointField(title=_("GPS location"),
+ description=_("GPS coordinates used to locate map"),
+ required=False)
+
+ display_marker = Bool(title=_("Display location mark?"),
+ description=_("If 'yes', a location marker will be displayed on map"),
+ required=True,
+ default=True)
+
+ renderer = Choice(title=_("Map template"),
+ description=_("Presentation template used for this map"),
+ vocabulary=MAP_PARAGRAPH_RENDERERS,
+ default='default')
--- a/src/pyams_content/component/paragraph/interfaces/video.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/video.py Thu Sep 06 11:27:55 2018 +0200
@@ -45,8 +45,8 @@
title = I18nTextLineField(title=_("Legend"),
required=False)
- description = I18nTextField(title=_("Description"),
- description=_("File description displayed by front-office template"),
+ description = I18nTextField(title=_("Associated text"),
+ description=_("Video description displayed by front-office template"),
required=False)
author = TextLine(title=_("Author"),
--- a/src/pyams_content/component/paragraph/keynumber.py Tue Jul 17 15:12:43 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-#
-# Copyright (c) 2008-2015 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.paragraph.interfaces import IParagraphFactory
-from pyams_content.component.paragraph.interfaces.keynumber import IKeyNumberParagraph, KEYNUMBER_PARAGRAPH_TYPE, \
- KEYNUMBER_PARAGRAPH_RENDERERS, KEYNUMBER_PARAGRAPH_NAME
-from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
-from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
-
-# import packages
-from pyams_content.component.paragraph import BaseParagraph, BaseParagraphFactory, BaseParagraphContentChecker
-from pyams_content.features.renderer import RenderersVocabulary
-from pyams_utils.adapter import adapter_config
-from pyams_utils.factory import factory_config
-from pyams_utils.registry import get_utility, utility_config
-from pyams_utils.request import check_request
-from pyams_utils.traversing import get_parent
-from pyams_utils.vocabulary import vocabulary_config
-from zope.interface import implementer
-from zope.schema.fieldproperty import FieldProperty
-
-
-@implementer(IKeyNumberParagraph)
-@factory_config(provided=IKeyNumberParagraph)
-class KeyNumberParagraph(BaseParagraph):
- """Key numbers paragraph"""
-
- icon_class = 'fa-dashboard'
- icon_hint = KEYNUMBER_PARAGRAPH_NAME
-
- renderer = FieldProperty(IKeyNumberParagraph['renderer'])
-
-
-@utility_config(name=KEYNUMBER_PARAGRAPH_TYPE, provides=IParagraphFactory)
-class KeyNumberParagraphFactory(BaseParagraphFactory):
- """Key numbers paragraph factory"""
-
- name = KEYNUMBER_PARAGRAPH_NAME
- content_type = KeyNumberParagraph
-
-
-@adapter_config(context=IKeyNumberParagraph, provides=IContentChecker)
-class KeyNumberParagraphContentChecker(BaseParagraphContentChecker):
- """Key numbers paragraph content checker"""
-
- @property
- def label(self):
- request = check_request()
- translate = request.localizer.translate
- return II18n(self.context).query_attribute('title', request) or \
- '({0})'.format(translate(self.context.icon_hint).lower())
-
- def inner_check(self, request):
- output = []
- translate = request.localizer.translate
- manager = get_parent(self.context, II18nManager)
- if manager is not None:
- langs = manager.get_languages()
- else:
- negotiator = get_utility(INegotiator)
- langs = (negotiator.server_language, )
- i18n = II18n(self.context)
- for lang in langs:
- value = i18n.get_attribute('title', lang, request)
- if not value:
- field_title = translate(IKeyNumberParagraph['title'].title)
- if len(langs) == 1:
- output.append(translate(MISSING_VALUE).format(field=field_title))
- else:
- output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang))
- return output
-
-
-@vocabulary_config(name=KEYNUMBER_PARAGRAPH_RENDERERS)
-class KeyNumberParagraphRendererVocabulary(RenderersVocabulary):
- """Key numbers paragraph renderers vocabulary"""
-
- content_interface = IKeyNumberParagraph
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/paragraph/map.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,64 @@
+#
+# 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'
+
+
+from pyams_content.component.paragraph.interfaces.map import have_gis
+if have_gis:
+
+ # import standard library
+
+ # import interfaces
+ from pyams_content.component.paragraph.interfaces import IParagraphFactory
+ from pyams_content.component.paragraph.interfaces.map import IMapParagraph, MAP_PARAGRAPH_NAME, have_gis, \
+ MAP_PARAGRAPH_TYPE, MAP_PARAGRAPH_RENDERERS
+
+ # import packages
+ from pyams_content.component.paragraph import BaseParagraph, BaseParagraphFactory
+ from pyams_content.features.renderer import RenderersVocabulary
+ from pyams_utils.factory import factory_config
+ from pyams_utils.registry import utility_config
+ from pyams_utils.vocabulary import vocabulary_config
+ from zope.interface import implementer
+ from zope.schema.fieldproperty import FieldProperty
+
+
+ @implementer(IMapParagraph)
+ @factory_config(provided=IMapParagraph)
+ class MapParagraph(BaseParagraph):
+ """Map paragraph"""
+
+ icon_class = 'fa-map-marker'
+ icon_hint = MAP_PARAGRAPH_NAME
+
+ if have_gis:
+ gps_location = FieldProperty(IMapParagraph['gps_location'])
+ display_marker = FieldProperty(IMapParagraph['display_marker'])
+
+ renderer = FieldProperty(IMapParagraph['renderer'])
+
+
+ @utility_config(name=MAP_PARAGRAPH_TYPE, provides=IParagraphFactory)
+ class MapParagraphFactory(BaseParagraphFactory):
+ """Map paragraph factory"""
+
+ name = MAP_PARAGRAPH_NAME
+ content_type = MapParagraph
+ secondary_menu = True
+
+
+ @vocabulary_config(name=MAP_PARAGRAPH_RENDERERS)
+ class MapParagraphRenderersVocabulary(RenderersVocabulary):
+ """Map paragraph renderers vocabulary"""
+
+ content_interface = IMapParagraph
--- a/src/pyams_content/component/paragraph/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -37,7 +37,7 @@
from pyams_form.schema import ActionButton, CloseButton
from pyams_form.security import ProtectedFormObjectMixin
from pyams_pagelet.pagelet import pagelet_config
-from pyams_skin.event import get_json_switched_table_refresh_event
+from pyams_skin.event import get_json_switched_table_refresh_event, get_json_widget_refresh_event
from pyams_skin.table import get_element_id
from pyams_skin.viewlet.menu import MenuItem, MenuDivider
from pyams_skin.viewlet.toolbar import ToolbarMenuItem
@@ -175,7 +175,7 @@
return MenuDivider.__new__(cls)
for factory_name in settings.allowed_paragraphs or ():
factory = query_utility(IParagraphFactory, name=factory_name)
- if factory.secondary_menu:
+ if (factory is not None) and factory.secondary_menu:
return MenuDivider.__new__(cls)
return None
@@ -241,6 +241,20 @@
if 'title' in changes.get(IBaseParagraph, ()):
output.setdefault('events', []).append(
get_json_paragraph_refresh_event(self.context, self.request))
+ elif 'renderer' in self.widgets:
+ renderer_interface = self.widgets['renderer'].field.interface
+ if 'renderer' in changes.get(renderer_interface):
+ output.setdefault('events', []).append(
+ get_json_widget_refresh_event(self.context, self.request, self.__class__, 'renderer'))
+ renderer = self.context.get_renderer()
+ if (renderer is not None) and \
+ (renderer.settings_interface is not None):
+ output['smallbox'] = {
+ 'status': 'info',
+ 'message': self.request.localizer.translate(_("You changed renderer selection. Don't omit to "
+ "update new renderer properties...")),
+ 'timeout': 5000
+ }
return output
--- a/src/pyams_content/component/paragraph/zmi/container.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/container.py Thu Sep 06 11:27:55 2018 +0200
@@ -44,7 +44,7 @@
from pyams_skin.container import switch_element_visibility, switch_element_attribute
from pyams_skin.page import DefaultPageHeaderAdapter
from pyams_skin.table import BaseTable, I18nColumn, TrashColumn, SorterColumn, ImageColumn, \
- VisibilitySwitcherColumn
+ VisibilitySwitcherColumn, AttributeSwitcherColumn
from pyams_skin.viewlet.menu import MenuItem
from pyams_template.template import template_config
from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, NullAdapter
@@ -108,11 +108,29 @@
'data-ams-post-reload': 'PyAMS_content.paragraphs.postReload',
'data-ams-tablednd-drag-handle': 'td.sorter',
'data-ams-tablednd-drop-target': 'set-paragraphs-order.json',
- 'data-ams-visibility-switcher': 'switch-paragraph-visibility.json',
- 'data-ams-anchor-switcher': 'switch-paragraph-anchor.json'
+ 'data-ams-anchor-icon-on': 'fa fa-fw fa-anchor',
+ 'data-ams-anchor-icon-off': 'fa fa-fw fa-anchor txt-color-silver opacity-50'
+ })
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target,
+ 'data-ams-switcher-attribute-name': self.get_switcher_attribute
})
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-paragraph-visibility.json'
+ elif column.__name__ == 'anchor':
+ return 'switch-paragraph-anchor.json'
+
+ @staticmethod
+ def get_switcher_attribute(element, column):
+ if column.__name__ == 'show-hide':
+ return 'visible'
+ elif column.__name__ == 'anchor':
+ return 'anchor'
+
class ParagraphContainerTable(ParagraphContainerBaseTable):
"""Paragraph container base table"""
@@ -186,16 +204,16 @@
@adapter_config(name='anchor', context=(IParagraphContainerTarget, IPyAMSLayer, ParagraphContainerBaseTable),
provides=IColumn)
-class ParagraphContainerAnchorColumn(ProtectedFormObjectMixin, VisibilitySwitcherColumn):
+class ParagraphContainerAnchorColumn(ProtectedFormObjectMixin, AttributeSwitcherColumn):
"""Paragraphs container anchor switcher column"""
switch_attribute = 'anchor'
- visible_icon_class = 'fa fa-fw fa-anchor'
- hidden_icon_class = 'fa fa-fw fa-anchor txt-color-silver opacity-50'
+
+ on_icon_class = 'fa fa-fw fa-anchor'
+ off_icon_class = 'fa fa-fw fa-anchor txt-color-silver opacity-50'
icon_hint = _("Set navigation anchor")
- url = 'PyAMS_content.paragraphs.switchAnchor'
weight = 6
--- a/src/pyams_content/component/paragraph/zmi/frame.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/frame.py Thu Sep 06 11:27:55 2018 +0200
@@ -69,7 +69,8 @@
'ams-tinymce-plugins': ['lists', ],
'ams-tinymce-toolbar': 'undo redo | bold italic | bullist numlist',
'ams-tinymce-toolbar1': False,
- 'ams-tinymce-toolbar2': False
+ 'ams-tinymce-toolbar2': False,
+ 'ams-tinymce-height': 150
}
@@ -83,7 +84,7 @@
"""Framed text paragraph add menu"""
label = _("Framed text...")
- label_css_class = 'fa fa-fw fa-list-alt'
+ label_css_class = 'fa fa-fw fa-window-maximize'
url = 'add-frame-paragraph.html'
paragraph_type = FRAME_PARAGRAPH_TYPE
@@ -98,7 +99,7 @@
legend = _("Add new framed text paragraph")
dialog_class = 'modal-large'
- icon_css_class = 'fa fa-fw fa-list-alt'
+ icon_css_class = 'fa fa-fw fa-window-maximize'
label_css_class = 'control-label col-md-2'
input_css_class = 'col-md-10'
@@ -124,7 +125,7 @@
legend = _("Edit framed text paragraph properties")
dialog_class = 'modal-large'
- icon_css_class = 'fa fa-fw fa-list-alt'
+ icon_css_class = 'fa fa-fw fa-window-maximize'
label_css_class = 'control-label col-md-2'
input_css_class = 'col-md-10'
--- a/src/pyams_content/component/paragraph/zmi/header.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/header.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,68 +16,27 @@
# import standard library
# import interfaces
-from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer
-from pyams_content.component.paragraph.interfaces.header import IHeaderParagraph, HEADER_PARAGRAPH_TYPE
-from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView
+from pyams_content.component.paragraph.interfaces.header import IHeaderParagraph
+from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor
from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
from pyams_form.interfaces.form import IInnerForm
-from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
from pyams_skin.layer import IPyAMSLayer
from z3c.form.interfaces import INPUT_MODE
# import packages
-from pyams_content.component.paragraph.header import HeaderParagraph
-from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \
- BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, get_json_paragraph_refresh_event, IParagraphEditFormButtons
+from pyams_content.component.paragraph.zmi import BaseParagraphAJAXEditForm, \
+ BaseParagraphPropertiesEditForm, get_json_paragraph_refresh_event, IParagraphEditFormButtons
from pyams_content.features.renderer.zmi.widget import RendererFieldWidget
from pyams_form.form import ajax_config
from pyams_pagelet.pagelet import pagelet_config
from pyams_skin.event import get_json_widget_refresh_event
from pyams_utils.adapter import adapter_config
-from pyams_viewlet.viewlet import viewlet_config
-from pyams_zmi.form import AdminDialogAddForm
from z3c.form import field, button
from zope.interface import implementer
from pyams_content import _
-@viewlet_config(name='add-header-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
- layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=40)
-class HeaderParagraphAddMenu(BaseParagraphAddMenu):
- """Header paragraph add menu"""
-
- label = _("Header...")
- label_css_class = 'fa fa-fw fa-download fa-rotate-180'
- url = 'add-header-paragraph.html'
- paragraph_type = HEADER_PARAGRAPH_TYPE
-
-
-@pagelet_config(name='add-header-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
- permission=MANAGE_CONTENT_PERMISSION)
-@ajax_config(name='add-header-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer,
- base=BaseParagraphAJAXAddForm)
-class HeaderParagraphAddForm(AdminDialogAddForm):
- """Header paragraph add form"""
-
- legend = _("Add new header paragraph")
- icon_css_class = 'fa fa-fw fa-download fa-rotate-180'
-
- fields = field.Fields(IHeaderParagraph).select('header', 'renderer')
- edit_permission = MANAGE_CONTENT_PERMISSION
-
- def updateWidgets(self, prefix=None):
- super(HeaderParagraphAddForm, self).updateWidgets(prefix)
- if 'header' in self.widgets:
- self.widgets['header'].widget_css_class = 'input height-100'
-
- def create(self, data):
- return HeaderParagraph()
-
- def add(self, object):
- IParagraphContainer(self.context).append(object)
-
-
@pagelet_config(name='properties.html', context=IHeaderParagraph, layer=IPyAMSLayer,
permission=MANAGE_CONTENT_PERMISSION)
@ajax_config(name='properties.json', context=IHeaderParagraph, layer=IPyAMSLayer,
--- a/src/pyams_content/component/paragraph/zmi/keynumber.py Tue Jul 17 15:12:43 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-#
-# Copyright (c) 2008-2015 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.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer
-from pyams_content.component.paragraph.interfaces.keynumber import KEYNUMBER_PARAGRAPH_TYPE, IKeyNumberParagraph
-from pyams_content.component.paragraph.zmi import IParagraphContainerView, IParagraphEditFormButtons
-from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor
-from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
-from pyams_content.shared.common import IWfSharedContent
-from pyams_form.interfaces.form import IInnerForm
-from pyams_i18n.interfaces import II18n
-from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
-from pyams_skin.layer import IPyAMSLayer
-from z3c.form.interfaces import INPUT_MODE
-
-# import packages
-from pyams_content.component.keynumber.zmi import IKeyNumbersParentForm
-from pyams_content.component.paragraph.keynumber import KeyNumberParagraph
-from pyams_content.component.paragraph.zmi import BaseParagraphAddMenu, BaseParagraphAJAXAddForm, \
- BaseParagraphPropertiesEditForm, BaseParagraphAJAXEditForm
-from pyams_content.features.renderer.zmi.widget import RendererFieldWidget
-from pyams_form.form import ajax_config
-from pyams_pagelet.pagelet import pagelet_config
-from pyams_skin.event import get_json_widget_refresh_event
-from pyams_utils.adapter import adapter_config
-from pyams_utils.traversing import get_parent
-from pyams_viewlet.viewlet import viewlet_config
-from pyams_zmi.form import AdminDialogAddForm
-from z3c.form import field, button
-from zope.interface import implementer, Interface
-
-from pyams_content import _
-
-
-@viewlet_config(name='add-keynumber-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
- layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=600)
-class KeyNumberParagraphAddMenu(BaseParagraphAddMenu):
- """Key number paragraph add menu"""
-
- label = _("Key numbers...")
- label_css_class = 'fa fa-fw fa-dashboard'
- url = 'add-keynumber-paragraph.html'
- paragraph_type = KEYNUMBER_PARAGRAPH_TYPE
-
-
-@pagelet_config(name='add-keynumber-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
- permission=MANAGE_CONTENT_PERMISSION)
-@ajax_config(name='add-keynumber-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer,
- base=BaseParagraphAJAXAddForm)
-class KeyNumberParagraphAddForm(AdminDialogAddForm):
- """Key number paragraph add form"""
-
- legend = _("Add new key number paragraph")
- icon_css_class = 'fa fa-fw fa-dashboard'
-
- fields = field.Fields(IKeyNumberParagraph).select('title', 'renderer')
- edit_permission = MANAGE_CONTENT_PERMISSION
-
- def create(self, data):
- return KeyNumberParagraph()
-
- def add(self, object):
- IParagraphContainer(self.context).append(object)
-
-
-@pagelet_config(name='properties.html', context=IKeyNumberParagraph, layer=IPyAMSLayer,
- permission=MANAGE_CONTENT_PERMISSION)
-@ajax_config(name='properties.json', context=IKeyNumberParagraph, layer=IPyAMSLayer,
- base=BaseParagraphAJAXEditForm)
-@implementer(IKeyNumbersParentForm)
-class KeyNumberParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm):
- """Key number paragraph properties edit form"""
-
- prefix = 'keynumbers_properties.'
-
- @property
- def title(self):
- content = get_parent(self.context, IWfSharedContent)
- return II18n(content).query_attribute('title', request=self.request)
-
- legend = _("Edit key number paragraph properties")
- icon_css_class = 'fa fa-fw fa-dashboard'
-
- fields = field.Fields(IKeyNumberParagraph).select('title', 'renderer')
- fields['renderer'].widgetFactory = RendererFieldWidget
-
- edit_permission = MANAGE_CONTENT_PERMISSION
-
-
-@adapter_config(context=(IKeyNumberParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
-@ajax_config(name='inner-properties.json', context=IKeyNumberParagraph, layer=IPyAMSLayer,
- base=BaseParagraphAJAXEditForm)
-@implementer(IInnerForm, IKeyNumbersParentForm)
-class KeyNumberParagraphInnerEditForm(KeyNumberParagraphPropertiesEditForm):
- """Key number paragraph inner edit form"""
-
- legend = None
-
- @property
- def buttons(self):
- if self.mode == INPUT_MODE:
- return button.Buttons(IParagraphEditFormButtons)
- else:
- return button.Buttons()
-
- def get_ajax_output(self, changes):
- output = super(self.__class__, self).get_ajax_output(changes)
- updated = changes.get(IKeyNumberParagraph, ())
- if 'renderer' in updated:
- output.setdefault('events', []).append(
- get_json_widget_refresh_event(self.context, self.request, KeyNumberParagraphInnerEditForm, 'renderer'))
- return output
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/paragraph/zmi/map.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,125 @@
+#
+# 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'
+
+
+from pyams_content.component.paragraph.interfaces.map import have_gis
+if have_gis:
+
+ # import standard library
+
+ # import interfaces
+ from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \
+ IBaseParagraph, PARAGRAPH_HIDDEN_FIELDS
+ from pyams_content.component.paragraph.interfaces.map import MAP_PARAGRAPH_TYPE, IMapParagraph
+ from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor
+ from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
+ from pyams_form.interfaces.form import IInnerForm
+ from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
+ from pyams_skin.layer import IPyAMSLayer
+ from z3c.form.interfaces import INPUT_MODE
+
+ # import packages
+ from pyams_content.component.paragraph.map import MapParagraph
+ from pyams_content.component.paragraph.zmi import IParagraphContainerView, BaseParagraphAddMenu, \
+ BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, BaseParagraphPropertiesEditForm, IParagraphEditFormButtons, \
+ get_json_paragraph_refresh_event
+ from pyams_content.features.renderer.zmi.widget import RendererFieldWidget
+ from pyams_form.form import ajax_config
+ from pyams_pagelet.pagelet import pagelet_config
+ from pyams_skin.event import get_json_form_refresh_event
+ from pyams_utils.adapter import adapter_config
+ from pyams_viewlet.viewlet import viewlet_config
+ from pyams_zmi.form import AdminDialogAddForm
+ from z3c.form import field, button
+ from zope.interface import implementer
+
+ from pyams_content import _
+
+
+ @viewlet_config(name='add-map-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
+ layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=600)
+ class MapParagraphAddMenu(BaseParagraphAddMenu):
+ """Map paragraph add menu"""
+
+ label = _("Location map...")
+ label_css_class = 'fa fa-fw fa-map-marker'
+ url = 'add-map-paragraph.html'
+ paragraph_type = MAP_PARAGRAPH_TYPE
+
+
+ @pagelet_config(name='add-map-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION)
+ @ajax_config(name='add-map-paragraph.json', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+ base=BaseParagraphAJAXAddForm)
+ class MapParagraphAddForm(AdminDialogAddForm):
+ """Map paragraph add form"""
+
+ legend = _("Add new location map")
+ dialog_class = 'modal-large'
+ icon_css_class = 'fa fa-fw fa-map-marker'
+
+ fields = field.Fields(IMapParagraph).omit(*PARAGRAPH_HIDDEN_FIELDS)
+ edit_permission = MANAGE_CONTENT_PERMISSION
+
+ def create(self, data):
+ return MapParagraph()
+
+ def add(self, object):
+ IParagraphContainer(self.context).append(object)
+
+
+ @pagelet_config(name='properties.html', context=IMapParagraph, layer=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION)
+ @ajax_config(name='properties.json', context=IMapParagraph, request_type=IPyAMSLayer,
+ base=BaseParagraphAJAXEditForm)
+ class MapParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm):
+ """Map paragraph properties edit form"""
+
+ prefix = 'map_properties.'
+
+ legend = _("Edit location map properties")
+ icon_css_class = 'fa fa-fw fa-map-marker'
+
+ fields = field.Fields(IMapParagraph).omit(*PARAGRAPH_HIDDEN_FIELDS)
+ fields['renderer'].widgetFactory = RendererFieldWidget
+
+ edit_permission = MANAGE_CONTENT_PERMISSION
+
+
+ @adapter_config(context=(IMapParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
+ @ajax_config(name='inner-properties.json', context=IMapParagraph, layer=IPyAMSLayer,
+ base=BaseParagraphAJAXEditForm)
+ @implementer(IInnerForm)
+ class MapParagraphInnerEditForm(MapParagraphPropertiesEditForm):
+ """Map paragraph inner edit form"""
+
+ legend = None
+
+ @property
+ def buttons(self):
+ if self.mode == INPUT_MODE:
+ return button.Buttons(IParagraphEditFormButtons)
+ else:
+ return button.Buttons()
+
+ def get_ajax_output(self, changes):
+ output = super(self.__class__, self).get_ajax_output(changes)
+ updated = changes.get(IBaseParagraph, ())
+ if 'title' in updated:
+ output.setdefault('events', []).append(get_json_paragraph_refresh_event(self.context, self.request))
+ updated = changes.get(IMapParagraph, ())
+ if 'renderer' in updated:
+ output.setdefault('events', []).append(get_json_form_refresh_event(self.context, self.request,
+ MapParagraphInnerEditForm))
+ return output
--- a/src/pyams_content/component/paragraph/zmi/milestone.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/milestone.py Thu Sep 06 11:27:55 2018 +0200
@@ -179,11 +179,18 @@
'id': self.id,
'data-ams-location': absolute_url(IMilestoneContainer(self.context), self.request),
'data-ams-tablednd-drag-handle': 'td.sorter',
- 'data-ams-tablednd-drop-target': 'set-milestones-order.json',
- 'data-ams-visibility-switcher': 'switch-milestone-visibility.json'
+ 'data-ams-tablednd-drop-target': 'set-milestones-order.json'
}
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target
+ })
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-milestone-visibility.json'
+
@reify
def values(self):
return list(super(MilestonesTable, self).values)
--- a/src/pyams_content/component/paragraph/zmi/pictogram.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/pictogram.py Thu Sep 06 11:27:55 2018 +0200
@@ -181,11 +181,18 @@
'id': self.id,
'data-ams-location': absolute_url(IPictogramContainer(self.context), self.request),
'data-ams-tablednd-drag-handle': 'td.sorter',
- 'data-ams-tablednd-drop-target': 'set-pictograms-order.json',
- 'data-ams-visibility-switcher': 'switch-pictogram-visibility.json'
+ 'data-ams-tablednd-drop-target': 'set-pictograms-order.json'
}
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target
+ })
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-pictogram-visibility.json'
+
@reify
def values(self):
return list(super(PictogramsTable, self).values)
@@ -214,6 +221,19 @@
return {'status': 'success'}
+@adapter_config(name='show-hide', context=(IPictogramContainerTarget, IPyAMSLayer, PictogramsTable),
+ provides=IColumn)
+class PictogramsTableShowHideColumn(ProtectedFormObjectMixin, VisibilitySwitcherColumn):
+ """Pictograms container visibility switcher column"""
+
+
+@view_config(name='switch-pictogram-visibility.json', context=IPictogramContainer, request_type=IPyAMSLayer,
+ permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+def switch_pictogram_visibility(request):
+ """Set pictogram visibility"""
+ return switch_element_visibility(request, IPictogramContainer)
+
+
@adapter_config(name='image', context=(IPictogramContainerTarget, IPyAMSLayer, PictogramsTable), provides=IColumn)
class PictogramsTableImageColumn(GetAttrColumn):
"""Pictogram image column"""
@@ -233,19 +253,6 @@
return '--'
-@adapter_config(name='show-hide', context=(IPictogramContainerTarget, IPyAMSLayer, PictogramsTable),
- provides=IColumn)
-class PictogramsTableShowHideColumn(ProtectedFormObjectMixin, VisibilitySwitcherColumn):
- """Pictograms container visibility switcher column"""
-
-
-@view_config(name='switch-pictogram-visibility.json', context=IPictogramContainer, request_type=IPyAMSLayer,
- permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
-def switch_pictogram_visibility(request):
- """Set pictogram visibility"""
- return switch_element_visibility(request, IPictogramContainer)
-
-
@adapter_config(name='name', context=(IPictogramContainerTarget, IPyAMSLayer, PictogramsTable), provides=IColumn)
class PictogramsTableNameColumn(I18nColumn, I18nAttrColumn):
"""Pictograms table name column"""
@@ -257,7 +264,9 @@
def getValue(self, obj):
value = super(PictogramsTableNameColumn, self).getValue(obj)
if not value:
- value = II18n(obj.pictogram).query_attribute('header', request=self.request)
+ pictogram = obj.pictogram
+ if pictogram is not None:
+ value = II18n(pictogram).query_attribute('header', request=self.request)
return value or BaseParagraph.empty_title
--- a/src/pyams_content/component/theme/zmi/manager.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/theme/zmi/manager.py Thu Sep 06 11:27:55 2018 +0200
@@ -9,7 +9,6 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-from pyams_content.component.theme import ICollectionsManagerTarget, ICollectionsManager
__docformat__ = 'restructuredtext'
@@ -17,8 +16,10 @@
# import standard library
# import interfaces
-from pyams_content.component.theme.interfaces import ITagsManagerTarget, ITagsManager, IThemesManagerTarget, \
- IThemesManager
+from pyams_content.component.theme.interfaces import \
+ ITagsManagerTarget, ITagsManager, \
+ IThemesManagerTarget, IThemesManager, \
+ ICollectionsManagerTarget, ICollectionsManager
from pyams_content.interfaces import MANAGE_TOOL_PERMISSION, MANAGE_SITE_ROOT_PERMISSION
from pyams_skin.layer import IPyAMSLayer
from pyams_utils.interfaces.data import IObjectData
@@ -29,7 +30,7 @@
from pyams_content.skin import pyams_content
from pyams_form.form import ajax_config
from pyams_pagelet.pagelet import pagelet_config
-from pyams_skin.viewlet.menu import MenuItem
+from pyams_skin.viewlet.menu import MenuItem, MenuDivider
from pyams_utils.fanstatic import get_resource_path
from pyams_viewlet.viewlet import viewlet_config
from pyams_zmi.form import AdminDialogEditForm
@@ -43,6 +44,12 @@
# Tags management view
#
+@viewlet_config(name='tags.divider', context=ITagsManagerTarget, layer=IAdminLayer,
+ manager=IPropertiesMenu, permission=MANAGE_SITE_ROOT_PERMISSION, weight=39)
+class TagsManagerMenuDivider(MenuDivider):
+ """Tags manager menu divider"""
+
+
@viewlet_config(name='tags-manager.menu', context=ITagsManagerTarget, layer=IAdminLayer,
manager=IPropertiesMenu, permission=MANAGE_SITE_ROOT_PERMISSION, weight=40)
class TagsManagerMenu(MenuItem):
--- a/src/pyams_content/component/video/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/component/video/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -45,8 +45,8 @@
class IExternalVideo(IAttributeAnnotatable):
"""Base interface for external video integration"""
- description = I18nTextField(title=_("Description"),
- description=_("File description displayed by front-office template"),
+ description = I18nTextField(title=_("Associated text"),
+ description=_("Video description displayed by front-office template"),
required=False)
author = TextLine(title=_("Author"),
--- a/src/pyams_content/features/alert/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/alert/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -19,58 +19,28 @@
# import interfaces
from pyams_content.features.alert.interfaces import IAlertItem
from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION
-from pyams_content.reference.pictograms import IPictogramTable
from pyams_form.interfaces.form import IFormContextPermissionChecker
# import packages
-from pyams_sequence.reference import get_reference_target
+from pyams_content.component.links import InternalReferenceMixin
from pyams_utils.adapter import adapter_config, ContextAdapter
-from pyams_utils.registry import query_utility
-from pyams_utils.zodb import volatile_property
from zope.container.contained import Contained
from zope.interface import implementer
from zope.schema.fieldproperty import FieldProperty
@implementer(IAlertItem)
-class AlertItem(Persistent, Contained):
+class AlertItem(Persistent, Contained, InternalReferenceMixin):
"""Alert item persistent class"""
visible = FieldProperty(IAlertItem['visible'])
gravity = FieldProperty(IAlertItem['gravity'])
- header = FieldProperty(IAlertItem['header'])
message = FieldProperty(IAlertItem['message'])
reference = FieldProperty(IAlertItem['reference'])
- _pictogram_name = FieldProperty(IAlertItem['pictogram_name'])
start_date = FieldProperty(IAlertItem['start_date'])
end_date = FieldProperty(IAlertItem['end_date'])
maximum_interval = FieldProperty(IAlertItem['maximum_interval'])
- @property
- def pictogram_name(self):
- return self._pictogram_name
-
- @pictogram_name.setter
- def pictogram_name(self, value):
- if value != self._pictogram_name:
- self._pictogram_name = value
- del self.pictogram
-
- @volatile_property
- def pictogram(self):
- table = query_utility(IPictogramTable)
- return table.get(self.pictogram_name)
-
- @volatile_property
- def target(self):
- return get_reference_target(self.reference)
-
- def get_target(self, state=None):
- if not state:
- return self.target
- else:
- return get_reference_target(self.reference)
-
@adapter_config(context=IAlertItem, provides=IFormContextPermissionChecker)
class AlertitemPermissionChecker(ContextAdapter):
--- a/src/pyams_content/features/alert/interfaces.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/alert/interfaces.py Thu Sep 06 11:27:55 2018 +0200
@@ -18,7 +18,6 @@
# import interfaces
from pyams_content.interfaces.container import IOrderedContainer
-from pyams_content.reference.pictograms.interfaces import PICTOGRAM_VOCABULARY
from pyams_sequence.interfaces import IInternalReference
from zope.annotation import IAttributeAnnotatable
@@ -37,10 +36,11 @@
ALERT_GRAVITY_NAMES = OrderedDict((
- ('success', _("Success")),
+ ('alert', _("Alert")),
+ ('alert_end', _("End of alert")),
('info', _("Information")),
('warning', _("Warning")),
- ('danger', _("Danger"))
+ ('recommend', _("Recommendation"))
))
ALERT_GRAVITY_VOCABULARY = SimpleVocabulary([SimpleTerm(v, title=t) for v, t in ALERT_GRAVITY_NAMES.items()])
@@ -62,27 +62,16 @@
default='info',
vocabulary=ALERT_GRAVITY_VOCABULARY)
- header = I18nTextLineField(title=_('alert-header', default="Heading"),
- description=_("Short alert header (Alert, Important...)"),
- required=False)
-
message = I18nTextLineField(title=_("Message"),
description=_("Alert message"),
required=True)
reference = InternalReferenceField(title=_("Internal reference"),
description=_("Internal link target reference. You can search a reference using "
- "'+' followed by internal number, of by entering text matching "
- "content title."),
+ "'+' followed by internal number, of by entering text matching "
+ "content title."),
required=False)
- pictogram_name = Choice(title=_("Pictogram"),
- description=_("Name of the pictogram to select"),
- required=False,
- vocabulary=PICTOGRAM_VOCABULARY)
-
- pictogram = Attribute("Selected pictogram object")
-
start_date = Datetime(title=_("Display start date"),
description=_("First date at which alert should be displayed"),
required=False)
--- a/src/pyams_content/features/alert/zmi/container.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/alert/zmi/container.py Thu Sep 06 11:27:55 2018 +0200
@@ -75,11 +75,18 @@
'data-ams-plugin-pyams_content-src': get_resource_path(pyams_content),
'data-ams-location': absolute_url(IAlertContainer(self.context), self.request),
'data-ams-tablednd-drag-handle': 'td.sorter',
- 'data-ams-tablednd-drop-target': 'set-alerts-order.json',
- 'data-ams-visibility-switcher': 'switch-alert-visibility.json'
+ 'data-ams-tablednd-drop-target': 'set-alerts-order.json'
+ })
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target
})
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-alert-visibility.json'
+
@reify
def values(self):
return list(super(AlertContainerTable, self).values)
@@ -131,44 +138,13 @@
return {'visible': alert.visible}
-@adapter_config(name='pictogram', context=(IAlertTarget, IPyAMSLayer, AlertContainerTable), provides=IColumn)
-class AlertContainerPictogramColumn(GetAttrColumn):
- """Alert container pictogram image column"""
-
- header = ''
- weight = 10
-
- cssClasses = {'td': 'text-center width-50'}
- dt_sortable = 'false'
-
- def getValue(self, obj):
- pictogram = obj.pictogram
- if pictogram is not None:
- image = II18n(pictogram).query_attribute('image', request=self.request)
- if image:
- return '<img src="{0}" />'.format(absolute_url(image, self.request, '++thumb++32x32'))
- return '--'
-
-
-@adapter_config(name='header', context=(IAlertTarget, IPyAMSLayer, AlertContainerTable), provides=IColumn)
-class AlertContainerHeaderColumn(I18nColumn, I18nAttrColumn):
- """Alert container header column"""
-
- _header = _('alert-header', default="Heading")
- attrName = 'header'
- weight = 20
-
- def getValue(self, obj):
- return super(AlertContainerHeaderColumn, self).getValue(obj) or '--'
-
-
@adapter_config(name='name', context=(IAlertTarget, IPyAMSLayer, AlertContainerTable), provides=IColumn)
class AlertContainerNameColumn(I18nColumn, I18nAttrColumn):
"""Alert container message column"""
_header = _("Message")
attrName = 'message'
- weight = 30
+ weight = 10
def getValue(self, obj):
value = super(AlertContainerNameColumn, self).getValue(obj)
--- a/src/pyams_content/features/footer/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/footer/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -18,16 +18,20 @@
# import interfaces
from pyams_content.features.footer.interfaces import FOOTER_RENDERERS, IFooterRenderer, IFooterSettings, IFooterTarget, \
FOOTER_SETTINGS_KEY, IFooterRendererSettings, FOOTER_RENDERER_SETTINGS_KEY
+from zope.lifecycleevent.interfaces import IObjectModifiedEvent
from zope.traversing.interfaces import ITraversable
# import packages
from persistent import Persistent
+from pyams_cache.beaker import get_cache
from pyams_content.features.renderer import RenderedContentMixin
+from pyams_portal.portlet import PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME
from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter
from pyams_utils.inherit import BaseInheritInfo, InheritedFieldProperty
from pyams_utils.request import check_request
from pyams_utils.traversing import get_parent
from pyams_utils.vocabulary import vocabulary_config
+from pyramid.events import subscriber
from zope.interface import implementer, noLongerProvides, alsoProvides
from zope.location import Location, locate
from zope.schema.fieldproperty import FieldProperty
@@ -77,6 +81,14 @@
return get_annotation_adapter(context, FOOTER_SETTINGS_KEY, FooterSettings, name='++footer++')
+@subscriber(IObjectModifiedEvent, context_selector=IFooterSettings)
+def handle_modified_footer_settings(event):
+ """Clear cache if modified footer settings"""
+ renderer = event.object.get_renderer()
+ portlets_cache = get_cache(PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME)
+ portlets_cache.remove(renderer.cache_key)
+
+
@adapter_config(name='footer', context=IFooterTarget, provides=ITraversable)
class FooterTargetNamespace(ContextAdapter):
"""Footer target '++footer++' namespace traverser"""
--- a/src/pyams_content/features/footer/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/footer/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -54,6 +54,7 @@
name = Attribute("Renderer name")
settings_key = Attribute("Renderer settings key")
+ cache_key = Attribute("Renderer cache key")
class IFooterRendererSettings(IRendererSettings):
--- a/src/pyams_content/features/footer/skin/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/footer/skin/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -32,13 +32,18 @@
from pyams_utils.adapter import adapter_config
from pyams_utils.traversing import get_parent
from pyramid.decorator import reify
+from zope.interface import implementer
from pyams_content import _
+@implementer(IFooterRenderer)
class BaseFooterRenderer(BaseContentRenderer):
"""Base footer renderer"""
+ name = None
+ settings_key = None
+
@reify
def settings_target(self):
context = self.request.annotations.get(DISPLAY_CONTEXT)
@@ -56,23 +61,28 @@
settings = IFooterSettings(settings.parent)
return settings.settings
+ @reify
+ def cache_key(self):
+ return PORTLETS_CACHE_KEY.format(portlet=self.name,
+ context=ICacheKeyValue(self.settings_target),
+ lang=self.request.locale_name)
+
def render(self):
preview_mode = self.request.annotations.get(PREVIEW_MODE, False)
if preview_mode:
return super(BaseFooterRenderer, self).render()
else:
portlets_cache = get_cache(PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME)
- cache_key = PORTLETS_CACHE_KEY.format(portlet=self.name,
- context=ICacheKeyValue(self.settings_target))
+ cache_key = self.cache_key
if self.context is not self.request.context: # display shared content
cache_key = '{0}::shared'.format(cache_key)
try:
result = portlets_cache.get_value(cache_key)
- logger.debug("Retrieving header content from cache key {0}".format(cache_key))
+ logger.debug("Retrieving footer content from cache key {0}".format(cache_key))
except KeyError:
result = super(BaseFooterRenderer, self).render()
portlets_cache.set_value(cache_key, result)
- logger.debug("Storing header content for cache key {0}".format(cache_key))
+ logger.debug("Storing footer content to cache key {0}".format(cache_key))
return result
--- a/src/pyams_content/features/header/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/header/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -18,16 +18,20 @@
# import interfaces
from pyams_content.features.header.interfaces import HEADER_RENDERERS, IHeaderRenderer, IHeaderSettings, IHeaderTarget, \
HEADER_SETTINGS_KEY, IHeaderRendererSettings, HEADER_RENDERER_SETTINGS_KEY
+from zope.lifecycleevent.interfaces import IObjectModifiedEvent
from zope.traversing.interfaces import ITraversable
# import packages
from persistent import Persistent
+from pyams_cache.beaker import get_cache
from pyams_content.features.renderer import RenderedContentMixin
+from pyams_portal.portlet import PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME
from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter
from pyams_utils.inherit import BaseInheritInfo, InheritedFieldProperty
from pyams_utils.request import check_request
from pyams_utils.traversing import get_parent
from pyams_utils.vocabulary import vocabulary_config
+from pyramid.events import subscriber
from zope.interface import implementer, noLongerProvides, alsoProvides
from zope.location import Location, locate
from zope.schema.fieldproperty import FieldProperty
@@ -77,6 +81,14 @@
return get_annotation_adapter(context, HEADER_SETTINGS_KEY, HeaderSettings, name='++header++')
+@subscriber(IObjectModifiedEvent, context_selector=IHeaderSettings)
+def handle_modified_header_settings(event):
+ """Clear cache if modified header settings"""
+ renderer = event.object.get_renderer()
+ portlets_cache = get_cache(PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME)
+ portlets_cache.remove(renderer.cache_key)
+
+
@adapter_config(name='header', context=IHeaderTarget, provides=ITraversable)
class HeaderTargetNamespace(ContextAdapter):
"""Header target '++header++' namespace traverser"""
--- a/src/pyams_content/features/header/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/header/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -54,6 +54,8 @@
name = Attribute("Renderer name")
settings_key = Attribute("Renderer settings key")
+ cache_key = Attribute("Renderer cache key")
+
class IHeaderRendererSettings(IRendererSettings):
--- a/src/pyams_content/features/header/skin/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/header/skin/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -33,13 +33,18 @@
from pyams_utils.adapter import adapter_config
from pyams_utils.traversing import get_parent
from pyramid.decorator import reify
+from zope.interface import implementer
from pyams_content import _
+@implementer(IHeaderRenderer)
class BaseHeaderRenderer(BaseContentRenderer):
"""Base header renderer"""
+ name = None
+ settings_key = None
+
@reify
def settings_target(self):
context = self.request.annotations.get(DISPLAY_CONTEXT)
@@ -57,6 +62,12 @@
settings = IHeaderSettings(settings.parent)
return settings.settings
+ @reify
+ def cache_key(self):
+ return PORTLETS_CACHE_KEY.format(portlet=self.name,
+ context=ICacheKeyValue(self.settings_target),
+ lang=self.request.locale_name)
+
@property
def main_header_class(self):
request = self.request
@@ -68,8 +79,7 @@
return super(BaseHeaderRenderer, self).render()
else:
portlets_cache = get_cache(PORTLETS_CACHE_REGION, PORTLETS_CACHE_NAME)
- cache_key = PORTLETS_CACHE_KEY.format(portlet=self.name,
- context=ICacheKeyValue(self.settings_target))
+ cache_key = self.cache_key
if self.context is not self.request.context: # display shared content
cache_key = '{0}::shared'.format(cache_key)
try:
@@ -78,7 +88,7 @@
except KeyError:
result = super(BaseHeaderRenderer, self).render()
portlets_cache.set_value(cache_key, result)
- logger.debug("Storing header content for cache key {0}".format(cache_key))
+ logger.debug("Storing header content to cache key {0}".format(cache_key))
return result
--- a/src/pyams_content/features/menu/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/menu/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -20,8 +20,7 @@
# import packages
from pyams_content.component.association.container import AssociationContainer
-from pyams_sequence.reference import get_reference_target
-from pyams_utils.zodb import volatile_property
+from pyams_content.component.links import InternalReferenceMixin
from zope.interface import implementer
from zope.schema.fieldproperty import FieldProperty
@@ -31,23 +30,13 @@
#
@implementer(IMenu)
-class Menu(AssociationContainer):
+class Menu(AssociationContainer, InternalReferenceMixin):
"""Associations menu"""
visible = FieldProperty(IMenu['visible'])
title = FieldProperty(IMenu['title'])
reference = FieldProperty(IMenu['reference'])
- @volatile_property
- def target(self):
- return get_reference_target(self.reference)
-
- def get_target(self, state=None):
- if not state:
- return self.target
- else:
- return get_reference_target(self.reference)
-
@implementer(IMenusContainer)
class MenusContainer(AssociationContainer):
--- a/src/pyams_content/features/menu/portlet/navigation/double.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/menu/portlet/navigation/double.py Thu Sep 06 11:27:55 2018 +0200
@@ -46,7 +46,6 @@
"""Double navigation portlet settings"""
title = FieldProperty(IDoubleNavigationPortletSettings['title'])
- subtitle = FieldProperty(IDoubleNavigationPortletSettings['subtitle'])
@property
def menus(self):
--- a/src/pyams_content/features/menu/portlet/navigation/interfaces/double.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/menu/portlet/navigation/interfaces/double.py Thu Sep 06 11:27:55 2018 +0200
@@ -32,10 +32,6 @@
description=_("Portlet main title"),
required=False)
- subtitle = I18nTextLineField(title=_("Subtitle"),
- description=_("Portlet subtitle"),
- required=False)
-
menus = Attribute("Navigation menus")
--- a/src/pyams_content/features/menu/portlet/navigation/zmi/simple.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/menu/portlet/navigation/zmi/simple.py Thu Sep 06 11:27:55 2018 +0200
@@ -35,7 +35,7 @@
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 zope.interface import Interface
from pyams_content import _
@@ -87,4 +87,7 @@
if not IInternalLink.providedBy(link):
return True
target = link.get_target()
- return (target is not None) and IWorkflowPublicationInfo(target).is_published()
+ if target is not None:
+ publication_info = IWorkflowPublicationInfo(target, None)
+ if publication_info is not None:
+ return publication_info.is_published()
--- a/src/pyams_content/features/menu/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/menu/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -17,8 +17,6 @@
import json
# import interfaces
-from pyams_content.component.links.zmi import InternalLinkAddMenu, InternalLinkAddForm, InternalLinkPropertiesEditForm, \
- ExternalLinkAddMenu, ExternalLinkAddForm, ExternalLinkPropertiesEditForm
from pyams_content.features.menu import IMenusContainer, IMenu, Menu, IMenuLink
from pyams_content.features.menu.interfaces import IMenusContainerTarget, IMenuLinksContainer, IMenuInternalLink, \
IMenuExternalLink, IMenuLinksContainerTarget
@@ -33,15 +31,17 @@
# import packages
from pyams_content.component.association.zmi import AssociationsTable, AssociationsTablePublicNameColumn
+from pyams_content.component.links.zmi import \
+ InternalLinkAddMenu, InternalLinkAddForm, InternalLinkPropertiesEditForm, \
+ ExternalLinkAddMenu, ExternalLinkAddForm, ExternalLinkPropertiesEditForm
from pyams_form.form import ajax_config, AJAXAddForm, AJAXEditForm
from pyams_i18n.column import I18nAttrColumn
from pyams_pagelet.pagelet import pagelet_config
from pyams_skin.container import switch_element_visibility, delete_container_element
from pyams_skin.event import get_json_switched_table_refresh_event, get_json_table_row_refresh_event
-from pyams_skin.table import BaseTable, SorterColumn, VisibilitySwitcherColumn, I18nColumn, TrashColumn, NameColumn, \
- get_table_id
+from pyams_skin.table import BaseTable, SorterColumn, VisibilitySwitcherColumn, I18nColumn, TrashColumn, get_table_id
from pyams_skin.viewlet.toolbar import ToolbarAction
-from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextAdapter, NullAdapter
+from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextAdapter
from pyams_utils.traversing import get_parent
from pyams_utils.url import absolute_url
from pyams_viewlet.viewlet import viewlet_config
@@ -170,11 +170,18 @@
attributes.setdefault('table', {}).update({
'data-ams-location': absolute_url(menus, self.request),
'data-ams-tablednd-drag-handle': 'td.sorter',
- 'data-ams-tablednd-drop-target': 'set-menus-order.json',
- 'data-ams-visibility-switcher': 'switch-menu-visibility.json'
+ 'data-ams-tablednd-drop-target': 'set-menus-order.json'
+ })
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target
})
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-menu-visibility.json'
+
@adapter_config(context=(IMenusContainerTarget, IPyAMSLayer, MenusTable), provides=IValues)
class MenusTableValuesAdapter(ContextRequestViewAdapter):
@@ -487,13 +494,3 @@
"""Menu external link properties edit form"""
edit_permission = None # managed by IFormContextPermissionChecker adapter
-
-
-#
-# Custom adapters
-#
-
-@adapter_config(name='size', context=(IMenu, IPyAMSLayer, MenuLinksTable), provides=IColumn)
-@adapter_config(name='size', context=(IMenuLinksContainerTarget, IPyAMSLayer, LinksTable), provides=IColumn)
-class MenuLinksTableSizeColumn(NullAdapter):
- """Menu links table size column"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/redirect/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,78 @@
+#
+# 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 re
+
+# import interfaces
+from pyams_content.features.redirect.interfaces import IRedirectionRule
+from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION
+from pyams_form.interfaces.form import IFormContextPermissionChecker
+
+# import packages
+from persistent import Persistent
+from pyams_content.component.links import InternalReferenceMixin
+from pyams_utils.adapter import adapter_config, ContextAdapter
+from pyams_utils.url import canonical_url
+from pyams_utils.zodb import volatile_property
+from zope.container.contained import Contained
+from zope.interface import implementer
+from zope.schema.fieldproperty import FieldProperty
+
+
+@implementer(IRedirectionRule)
+class RedirectionRule(Persistent, Contained, InternalReferenceMixin):
+ """Redirection rule persistent class"""
+
+ active = FieldProperty(IRedirectionRule['active'])
+ chained = FieldProperty(IRedirectionRule['chained'])
+ permanent = FieldProperty(IRedirectionRule['permanent'])
+ _url_pattern = FieldProperty(IRedirectionRule['url_pattern'])
+ reference = FieldProperty(IRedirectionRule['reference'])
+ target_url = FieldProperty(IRedirectionRule['target_url'])
+
+ @property
+ def url_pattern(self):
+ return self._url_pattern
+
+ @url_pattern.setter
+ def url_pattern(self, value):
+ if value != self._url_pattern:
+ self._url_pattern = value
+ del self.pattern
+
+ @volatile_property
+ def pattern(self):
+ return re.compile(self.url_pattern)
+
+ def match(self, source_url):
+ return self.pattern.match(source_url)
+
+ def rewrite(self, source_url, request):
+ target_url = None
+ if self.reference:
+ target = self.target
+ if target is not None:
+ target_url = canonical_url(target, request)
+ else:
+ target_url = self.pattern.sub(self.target_url, source_url)
+ return target_url
+
+
+@adapter_config(context=IRedirectionRule, provides=IFormContextPermissionChecker)
+class RedirectionRulePermissionChecker(ContextAdapter):
+ """Redirection rule permission checker"""
+
+ edit_permission = MANAGE_SITE_ROOT_PERMISSION
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/redirect/container.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,103 @@
+#
+# 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.features.redirect.interfaces import IRedirectionManager, IRedirectionRule, IRedirectionManagerTarget, \
+ REDIRECT_MANAGER_KEY
+from zope.location.interfaces import ISublocations
+from zope.traversing.interfaces import ITraversable
+
+# import packages
+from pyams_catalog.utils import index_object
+from pyams_utils.adapter import adapter_config, get_annotation_adapter, ContextAdapter
+from pyramid.response import Response
+from zope.container.ordered import OrderedContainer
+from zope.interface import implementer
+from zope.location.location import locate
+
+from pyams_content import _
+
+
+@implementer(IRedirectionManager)
+class RedirectManager(OrderedContainer):
+ """Redirect manager"""
+
+ last_id = 1
+
+ def append(self, value, notify=True):
+ key = str(self.last_id)
+ if not notify:
+ # pre-locate item to avoid multiple notifications
+ locate(value, self, key)
+ self[key] = value
+ self.last_id += 1
+ if not notify:
+ # make sure that item is correctly indexed
+ index_object(value)
+
+ def get_active_items(self):
+ yield from filter(lambda x: IRedirectionRule(x).active, self.values())
+
+ def get_response(self, request):
+ target_url = request.path_qs
+ for rule in self.get_active_items():
+ match = rule.match(target_url)
+ if match:
+ target_url = rule.rewrite(target_url, request)
+ if not rule.chained:
+ response = Response()
+ response.status_code = 301 if rule.permanent else 302
+ response.location = target_url
+ return response
+
+ def test_rules(self, source_url, request, check_inactive_rules=False):
+ if check_inactive_rules:
+ rules = self.values()
+ else:
+ rules = self.get_active_items()
+ for rule in rules:
+ match = rule.match(source_url)
+ if match:
+ target_url = rule.rewrite(source_url, request)
+ yield rule, source_url, target_url
+ if not rule.chained:
+ raise StopIteration
+ source_url = target_url
+ else:
+ yield rule, source_url, request.localizer.translate(_("not matching"))
+
+
+@adapter_config(context=IRedirectionManagerTarget, provides=IRedirectionManager)
+def redirection_manager_factory(context):
+ """Redirection manager factory"""
+ return get_annotation_adapter(context, REDIRECT_MANAGER_KEY, RedirectManager, name='++redirect++')
+
+
+@adapter_config(name='redirect', context=IRedirectionManagerTarget, provides=ITraversable)
+class RedirectionManagerNamespace(ContextAdapter):
+ """Redirection manager ++redirect++ namespace"""
+
+ def traverse(self, name, furtherpath=None):
+ return IRedirectionManager(self.context)
+
+
+@adapter_config(name='redirect', context=IRedirectionManagerTarget, provides=ISublocations)
+class RedirectManagerSublocations(ContextAdapter):
+ """redirection manager sub-locations adapter"""
+
+ def sublocations(self):
+ return IRedirectionManager(self.context).values()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/redirect/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,102 @@
+#
+# 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.interfaces.container import IOrderedContainer
+from pyams_sequence.interfaces import IInternalReference
+
+# import packages
+from pyams_sequence.schema import InternalReferenceField
+from zope.container.constraints import contains, containers
+from zope.interface import Interface, Attribute, invariant, Invalid
+from zope.schema import Bool, TextLine, Choice
+
+from pyams_content import _
+
+
+REDIRECT_MANAGER_KEY = 'pyams_content.redirect'
+
+
+class IRedirectionRule(IInternalReference):
+ """Redirection rule interface"""
+
+ containers('.IRedirectManager')
+
+ active = Bool(title=_("Active rule?"),
+ description=_("If 'no', selected rule is inactive"),
+ required=True,
+ default=False)
+
+ chained = Bool(title=_("Chained rule?"),
+ description=_("If 'no', and if this rule is matching received request URL, the rule "
+ "returns a redirection response; otherwise, the rule just rewrites the "
+ "input URL which is forwarded to the next rule"),
+ required=True,
+ default=False)
+
+ permanent = Bool(title=_("Permanent redirect?"),
+ description=_("Define if this redirection should be permanent or temporary"),
+ required=True,
+ default=True)
+
+ url_pattern = TextLine(title=_("URL pattern"),
+ description=_("Regexp pattern of matching URLs for this redirection rule"),
+ required=True)
+
+ pattern = Attribute("Compiled URL pattern")
+
+ reference = InternalReferenceField(title=_("Internal redirection target"),
+ description=_("Internal redirection reference. You can search a reference using "
+ "'+' followed by internal number, of by entering text matching "
+ "content title."),
+ required=False)
+
+ target_url = TextLine(title=_("Target URL"),
+ description=_("URL to which source URL should be redirected"),
+ required=False)
+
+ @invariant
+ def check_reference_and_target(self):
+ if self.reference and self.target_url:
+ raise Invalid(_("You can only provide an internal reference OR a target URL"))
+ elif not (self.reference or self.target_url):
+ raise Invalid(_("You must provide an internal reference OR a target URL"))
+
+ def match(self, source_url):
+ """Return regexp URL match on given URL"""
+
+ def rewrite(self, source_url, request):
+ """Rewrite given source URL"""
+
+
+class IRedirectionManager(IOrderedContainer):
+ """Redirection manager"""
+
+ contains(IRedirectionRule)
+
+ def get_active_items(self):
+ """Get iterator over active items"""
+
+ def get_response(self, request):
+ """Get new response for given request"""
+
+ def test_rules(self, source_url, request, check_inactive_rules=False):
+ """Test rules against given URL"""
+
+
+class IRedirectionManagerTarget(Interface):
+ """Redirection manager target marker interface"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/redirect/tween.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,49 @@
+#
+# 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.features.redirect.interfaces import IRedirectionManager
+
+# import packages
+from pyramid.exceptions import NotFound
+from pyramid.httpexceptions import HTTPNotFound
+
+
+def redirect_tween_factory(handler, registry):
+ """Redirect tween factory
+
+ This tween is used to handle NotFound errors: when a request which raises
+ a NotFound error is served, we look info redirects configuration to check if
+ given URL is matching any defined redirection, in which case another HTTPRedirect
+ response is returned with a new location; another content using a proxy request
+ can also be returned.
+ """
+
+ def redirect_tween(request):
+ try:
+ response = handler(request)
+ except (NotFound, HTTPNotFound):
+ manager = IRedirectionManager(request.root, None)
+ if manager is not None:
+ response = manager.get_response(request)
+ if response is not None:
+ return response
+ raise
+ else:
+ return response
+
+ return redirect_tween
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/redirect/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,126 @@
+#
+# 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.
+#
+from pyams_form.help import FormHelp
+from pyams_form.interfaces.form import IFormHelp
+from pyams_utils.adapter import adapter_config
+from pyams_zmi.layer import IAdminLayer
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.features.redirect.interfaces import IRedirectionRule, IRedirectionManagerTarget, IRedirectionManager
+from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION
+from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager
+from pyams_skin.layer import IPyAMSLayer
+
+# import packages
+from pyams_content.features.redirect import RedirectionRule
+from pyams_content.features.redirect.zmi.container import RedirectionsContainerView, RedirectionsContainerTable
+from pyams_form.form import ajax_config, AJAXAddForm
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_skin.event import get_json_table_row_refresh_event
+from pyams_skin.viewlet.toolbar import ToolbarAction
+from pyams_utils.traversing import get_parent
+from pyams_utils.url import absolute_url
+from pyams_viewlet.viewlet import viewlet_config
+from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm
+from z3c.form import field
+
+from pyams_content import _
+
+
+@viewlet_config(name='add-rule.action', context=IRedirectionManagerTarget, layer=IPyAMSLayer,
+ view=RedirectionsContainerView, manager=IWidgetTitleViewletManager,
+ permission=MANAGE_SITE_ROOT_PERMISSION, weight=1)
+class RedirectionRuleAddAction(ToolbarAction):
+ """Redirection rule add action"""
+
+ label = _("Add rule")
+ label_css_class = 'fa fa-fw fa-plus'
+ url = 'add-rule.html'
+ modal_target = True
+
+
+@pagelet_config(name='add-rule.html', context=IRedirectionManagerTarget, layer=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION)
+@ajax_config(name='add-rule.json', context=IRedirectionManagerTarget, layer=IPyAMSLayer, base=AJAXAddForm)
+class RedirectionRuleAddForm(AdminDialogAddForm):
+ """Redirection rule add form"""
+
+ dialog_class = 'modal-large'
+ legend = _("Add new redirection rule")
+ icon_css_class = 'fa fa-fw fa-map-signs'
+
+ fields = field.Fields(IRedirectionRule).omit('__parent__', '__name__', 'active', 'chained')
+ edit_permission = MANAGE_SITE_ROOT_PERMISSION
+
+ def create(self, data):
+ return RedirectionRule()
+
+ def add(self, object):
+ IRedirectionManager(self.context).append(object)
+
+ def nextURL(self):
+ return absolute_url(self.context, self.request, 'redirections.html')
+
+
+@pagelet_config(name='properties.html', context=IRedirectionRule, layer=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION)
+@ajax_config(name='properties.json', context=IRedirectionRule, layer=IPyAMSLayer)
+class RedirectionRulePropertiesEditForm(AdminDialogEditForm):
+ """Redirection rule properties edit form"""
+
+ dialog_class = 'modal-large'
+ prefix = 'rule_properties.'
+
+ legend = _("Edit redirection rule properties")
+ icon_css_class = 'fa fa-fw fa-map-signs'
+
+ fields = field.Fields(IRedirectionRule).omit('__parent__', '__name__', 'active', 'chained')
+ edit_permission = MANAGE_SITE_ROOT_PERMISSION
+
+ def get_ajax_output(self, changes):
+ output = super(self.__class__, self).get_ajax_output(changes)
+ updated = changes.get(IRedirectionRule, ())
+ if updated:
+ target = get_parent(self.context, IRedirectionManagerTarget)
+ output.setdefault('events', []).append(
+ get_json_table_row_refresh_event(target, self.request, RedirectionsContainerTable, self.context))
+ return output
+
+
+@adapter_config(context=(IRedirectionManagerTarget, IAdminLayer, RedirectionRuleAddForm), provides=IFormHelp)
+@adapter_config(context=(IRedirectionRule, IAdminLayer, RedirectionRulePropertiesEditForm), provides=IFormHelp)
+class RedirectionRuleFormHelp(FormHelp):
+ """Redirection rule form help"""
+
+ message = _("""URL pattern and target URL are defined by *regular expressions* (see |regexp|).
+
+In URL pattern, you can use any valid regular expression element, notably:
+
+- « .* » to match any list of characters
+
+- « ( ) » to "memorize" parts of the URL which can be replaced into target URL
+
+- special characters (like "+") must be escaped with an « \\\\ ».
+
+In target URL, memorized parts can be reused using « \\\\1 », « \\\\2 » and so on, where given number is
+the order of the matching pattern element.
+
+.. |regexp| raw:: html
+
+ <a href="https://docs.python.org/3/library/re.html" target="_blank">Python Regular Expressions</a>
+""")
+ message_format = 'rest'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/redirect/zmi/container.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,376 @@
+#
+# 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 json
+
+# import interfaces
+from pyams_content.features.redirect.interfaces import IRedirectionManagerTarget, IRedirectionManager
+from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION
+from pyams_form.interfaces.form import IWidgetsSuffixViewletsManager
+from pyams_i18n.interfaces import II18n
+from pyams_sequence.interfaces import ISequentialIdInfo
+from pyams_skin.interfaces import IPageHeader, IUserSkinnable, IContentHelp
+from pyams_skin.interfaces.viewlet import IToolbarViewletManager
+from pyams_skin.layer import IPyAMSLayer
+from pyams_zmi.interfaces.menu import ISiteManagementMenu
+from pyams_zmi.layer import IAdminLayer
+from z3c.table.interfaces import IValues, IColumn
+
+# import packages
+from pyams_content.skin import pyams_content
+from pyams_form.form import AJAXAddForm
+from pyams_form.schema import CloseButton
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_skin.help import ContentHelp
+from pyams_skin.page import DefaultPageHeaderAdapter
+from pyams_skin.skin import apply_skin
+from pyams_skin.table import BaseTable, SorterColumn, TrashColumn, I18nColumn, AttributeSwitcherColumn
+from pyams_skin.viewlet.menu import MenuItem
+from pyams_skin.viewlet.toolbar import ToolbarAction
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+from pyams_utils.fanstatic import get_resource_path
+from pyams_utils.request import copy_request
+from pyams_utils.url import absolute_url
+from pyams_viewlet.viewlet import viewlet_config, Viewlet
+from pyams_zmi.form import AdminDialogAddForm
+from pyams_zmi.view import ContainerAdminView
+from pyramid.decorator import reify
+from pyramid.exceptions import NotFound
+from pyramid.view import view_config
+from z3c.form import field, button
+from z3c.table.column import GetAttrColumn
+from zope.interface import Interface
+from zope.schema import TextLine, Bool
+
+from pyams_content import _
+
+
+@viewlet_config(name='redirections.menu', context=IRedirectionManagerTarget, layer=IPyAMSLayer,
+ manager=ISiteManagementMenu, permission=MANAGE_SITE_ROOT_PERMISSION, weight=35)
+class RedirectionMenu(MenuItem):
+ """Redirection manager menu"""
+
+ label = _("Redirections")
+ icon_class = 'fa-map-signs'
+ url = '#redirections.html'
+
+
+class RedirectionsContainerTable(BaseTable):
+ """Redirections container table"""
+
+ prefix = 'redirections'
+
+ hide_header = True
+ sortOn = None
+
+ cssClasses = {'table': 'table table-bordered table-striped table-hover table-tight table-dnd'}
+
+ @property
+ def data_attributes(self):
+ attributes = super(RedirectionsContainerTable, self).data_attributes
+ attributes.setdefault('table', {}).update({
+ 'data-ams-plugins': 'pyams_content',
+ 'data-ams-plugin-pyams_content-src': get_resource_path(pyams_content),
+ 'data-ams-location': absolute_url(IRedirectionManager(self.context), self.request),
+ 'data-ams-tablednd-drag-handle': 'td.sorter',
+ 'data-ams-tablednd-drop-target': 'set-rules-order.json',
+ 'data-ams-active-icon-on': 'fa fa-fw fa-check-square-o',
+ 'data-ams-active-icon-off': 'fa fa-fw fa-square-o txt-color-silver opacity-75',
+ 'data-ams-chained-icon-on': 'fa fa-fw fa-chain',
+ 'data-ams-chained-icon-off': 'fa fa-fw fa-chain txt-color-silver opacity-50'
+ })
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target,
+ 'data-ams-switcher-attribute-name': self.get_switcher_attribute
+ })
+ return attributes
+
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'enable-disable':
+ return 'switch-rule-activity.json'
+ elif column.__name__ == 'chain-unchain':
+ return 'switch-rule-chain.json'
+
+ @staticmethod
+ def get_switcher_attribute(element, column):
+ if column.__name__ == 'enable-disable':
+ return 'active'
+ elif column.__name__ == 'chain-unchain':
+ return 'chained'
+
+ @reify
+ def values(self):
+ return list(super(RedirectionsContainerTable, self).values)
+
+ def render(self):
+ if not self.values:
+ translate = self.request.localizer.translate
+ return translate(_("No currently defined redirection rule."))
+ return super(RedirectionsContainerTable, self).render()
+
+
+@adapter_config(context=(IRedirectionManagerTarget, IPyAMSLayer, RedirectionsContainerTable), provides=IValues)
+class RedirectionsContainerValues(ContextRequestViewAdapter):
+ """Redirections container values"""
+
+ @property
+ def values(self):
+ return IRedirectionManager(self.context).values()
+
+
+@adapter_config(name='sorter', context=(IRedirectionManagerTarget, IPyAMSLayer, RedirectionsContainerTable),
+ provides=IColumn)
+class RedirectionsContainerSorterColumn(SorterColumn):
+ """Redirections container sorter column"""
+
+
+@view_config(name='set-rules-order.json', context=IRedirectionManager, request_type=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION, renderer='json', xhr=True)
+def set_rules_order(request):
+ """Update redirection rules order"""
+ order = list(map(str, json.loads(request.params.get('names'))))
+ request.context.updateOrder(order)
+ return {'status': 'success'}
+
+
+@adapter_config(name='enable-disable', context=(IRedirectionManagerTarget, IPyAMSLayer, RedirectionsContainerTable),
+ provides=IColumn)
+class RedirectionsContainerEnablerColumn(AttributeSwitcherColumn):
+ """Redirections container enabler switcher column"""
+
+ switch_attribute = 'active'
+
+ on_icon_class = 'fa fa-fw fa-check-square-o'
+ off_icon_class = 'fa fa-fw fa-square-o txt-color-silver opacity-75'
+
+ icon_hint = _("Enable/disable rule")
+
+ weight = 6
+
+
+@view_config(name='switch-rule-activity.json', context=IRedirectionManager, request_type=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION, renderer='json', xhr=True)
+def switch_rule_activity(request):
+ """Switch rule activity"""
+ container = IRedirectionManager(request.context)
+ rule = container.get(str(request.params.get('object_name')))
+ if rule is None:
+ raise NotFound()
+ rule.active = not rule.active
+ return {'on': rule.active}
+
+
+@adapter_config(name='chain-unchain', context=(IRedirectionManagerTarget, IPyAMSLayer, RedirectionsContainerTable),
+ provides=IColumn)
+class RedirectionsContainerChainedColumn(AttributeSwitcherColumn):
+ """Redirections container chained switcher column"""
+
+ switch_attribute = 'chained'
+
+ on_icon_class = 'fa fa-fw fa-chain'
+ off_icon_class = 'fa fa-fw fa-chain txt-color-silver opacity-50'
+
+ icon_hint = _("Chain/unchain rule")
+
+ weight = 7
+
+
+@view_config(name='switch-rule-chain.json', context=IRedirectionManager, request_type=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION, renderer='json', xhr=True)
+def switch_rule_chain(request):
+ """Switch rule chain"""
+ container = IRedirectionManager(request.context)
+ rule = container.get(str(request.params.get('object_name')))
+ if rule is None:
+ raise NotFound()
+ rule.chained = not rule.chained
+ return {'chained': rule.chained}
+
+
+@adapter_config(name='name', context=(IRedirectionManagerTarget, IPyAMSLayer, RedirectionsContainerTable),
+ provides=IColumn)
+class RedirectionsContainerNameColumn(I18nColumn, GetAttrColumn):
+ """Redirections container name column"""
+
+ _header = _("URL pattern")
+ attrName = 'url_pattern'
+ weight = 10
+
+
+@adapter_config(name='target', context=(IRedirectionManagerTarget, IPyAMSLayer, RedirectionsContainerTable),
+ provides=IColumn)
+class RedirectionsContainerTargetColumn(I18nColumn, GetAttrColumn):
+ """Redirections container target column"""
+
+ _header = _("Target")
+ attrName = 'target_url'
+ weight = 20
+
+ def getValue(self, obj):
+ if obj.reference:
+ target = obj.target
+ return '{0} ({1})'.format(II18n(target).query_attribute('title', request=self.request),
+ ISequentialIdInfo(target).get_short_oid())
+ else:
+ return super(RedirectionsContainerTargetColumn, self).getValue(obj)
+
+
+@adapter_config(name='trash', context=(IRedirectionManagerTarget, IPyAMSLayer, RedirectionsContainerTable),
+ provides=IColumn)
+class RedirectionsContainerTrashColumn(TrashColumn):
+ """Redirections container trash column"""
+
+ permission = MANAGE_SITE_ROOT_PERMISSION
+
+
+@pagelet_config(name='redirections.html', context=IRedirectionManagerTarget, layer=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION)
+class RedirectionsContainerView(ContainerAdminView):
+ """Redirections container view"""
+
+ title = _("Redirections list")
+ table_class = RedirectionsContainerTable
+
+
+@adapter_config(context=(IRedirectionManagerTarget, IAdminLayer, RedirectionsContainerView), provides=IPageHeader)
+class RedirectionsContainerViewHeaderAdapter(DefaultPageHeaderAdapter):
+ """Redirections container view header adapter"""
+
+ icon_class = 'fa fa-fw fa-map-signs'
+
+
+@adapter_config(context=(IRedirectionManagerTarget, IAdminLayer, RedirectionsContainerView), provides=IContentHelp)
+class RedirectionsContainerHelpAdapter(ContentHelp):
+ """Redirections container help adapter"""
+
+ header = _("Redirection rules")
+ message = _("""Redirection rules are use to handle redirections responses when a request generates
+a famous « 404 NotFound » error.
+
+Redirections are particularly useful when you are migrating from a previous site and don't want to lose
+your SEO.
+
+You can define a set of rules which will be applied to every \"NotFound\" request; rules are based on
+regular expressions which are applied to input URL: if the rule is \"matching\", the target URL is rewritten
+and a \"Redirect\" response is send.
+
+You can chain rules together: when a rule is chained, it's rewritten URL is passed as input URL to the
+next rule, until a matching rule is found.
+""")
+ message_format = 'rest'
+
+
+#
+# Redirections container test form
+#
+
+@viewlet_config(name='test.action', context=IRedirectionManagerTarget, layer=IAdminLayer,
+ view=RedirectionsContainerView, manager=IToolbarViewletManager,
+ permission=MANAGE_SITE_ROOT_PERMISSION, weight=75)
+class RedirectionsContainerTestAction(ToolbarAction):
+ """redirections container test action"""
+
+ label = _("Test")
+
+ group_css_class = 'btn-group margin-left-5'
+ label_css_class = 'fa fa-fw fa-magic'
+ css_class = 'btn btn-xs btn-default'
+
+ url = 'test-redirection-rules.html'
+ modal_target = True
+
+
+class IRedirectionsContainerTestFields(Interface):
+ """Redirections container test fields"""
+
+ source_url = TextLine(title=_("Test URL"),
+ required=True)
+
+ check_inactive_rules = Bool(title=_("Check inactive rules?"),
+ description=_("If 'yes', inactive rules will also be tested"),
+ required=True,
+ default=False)
+
+
+class IRedirectionsContainerTestButtons(Interface):
+ """Redirections container test form buttons"""
+
+ close = CloseButton(name='close', title=_("Close"))
+ test = button.Button(name='test', title=_("Test rules"))
+
+
+@pagelet_config(name='test-redirection-rules.html', context=IRedirectionManagerTarget, layer=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION)
+class RedirectionsContainerTestForm(AdminDialogAddForm):
+ """Redirections container test form"""
+
+ dialog_class = 'modal-max'
+ legend = _("Test redirection rules")
+ icon_css_class = 'fa fa-fw fa-magic'
+
+ prefix = 'rules_test_form.'
+ fields = field.Fields(IRedirectionsContainerTestFields)
+ buttons = button.Buttons(IRedirectionsContainerTestButtons)
+ ajax_handler = 'test-redirection-rules.json'
+ edit_permission = MANAGE_SITE_ROOT_PERMISSION
+
+ @property
+ def form_target(self):
+ return '#{0}_test_result'.format(self.id)
+
+ def updateActions(self):
+ super(RedirectionsContainerTestForm, self).updateActions()
+ if 'test' in self.actions:
+ self.actions['test'].addClass('btn-primary')
+
+ def createAndAdd(self, data):
+ data = data.get(self, data)
+ request = copy_request(self.request)
+ apply_skin(request, IUserSkinnable(self.context).get_skin())
+ return IRedirectionManager(self.context).test_rules(data['source_url'], request, data['check_inactive_rules'])
+
+
+@viewlet_config(name='test-indexer-process.suffix', layer=IAdminLayer, manager=IWidgetsSuffixViewletsManager,
+ view=RedirectionsContainerTestForm, weight=50)
+@template_config(template='templates/manager-test.pt')
+class RedirectionsContainerTestSuffix(Viewlet):
+ """Redirections container test form suffix"""
+
+
+@view_config(name='test-redirection-rules.json', context=IRedirectionManagerTarget, request_type=IPyAMSLayer,
+ permission=MANAGE_SITE_ROOT_PERMISSION, renderer='json', xhr=True)
+class RedirectionsContainerAJAXTestForm(AJAXAddForm, RedirectionsContainerTestForm):
+ """Redirections container test form, JSON renderer"""
+
+ def get_ajax_output(self, changes):
+ message = []
+ translate = self.request.localizer.translate
+ for rule, source_url, target_url in changes:
+ if not message:
+ message.append('{:<40} | {:<40} | {:<40}'.format(translate(_("Input URL")),
+ translate(_("URL pattern")),
+ translate(_("Output URL"))))
+ message.append('{:<40}-|-{:<40}-|-{:<40}'.format('-' * 40, '-' * 40, '-' * 40))
+ message.append('{:<40} | {:<40} | {:<40}'.format(source_url, rule.url_pattern, target_url))
+ if not message:
+ message.append(translate(_("No matching rule!")))
+ return {
+ 'status': 'success',
+ 'content': {'html': '\n'.join(message)},
+ 'close_form': False
+ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/features/redirect/zmi/templates/manager-test.pt Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,4 @@
+<div class="no-widget-toolbar">
+ <pre class="height-min-200"
+ tal:attributes="id string:${view.__parent__.id}_test_result"></pre>
+</div>
--- a/src/pyams_content/features/renderer/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/renderer/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -45,7 +45,7 @@
request = check_request()
renderer = request.registry.queryMultiAdapter((self, request), self.renderer_interface,
name=self.renderer or '')
- if 'lang' in request.params:
+ if (renderer is not None) and ('lang' in request.params):
renderer.language = request.params['lang']
return renderer
--- a/src/pyams_content/features/renderer/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/renderer/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -39,9 +39,14 @@
"""Content renderer interface"""
label = Attribute("Renderer label")
- weight = Attribute("Renderer weight")
- settings_interface = Attribute("Renderer target interface")
+ weight = Attribute("Renderer weight, used for ordering")
+
+ settings_interface = Attribute("Renderer settings interface")
+ resources = Attribute("Iterable of needed Fanstatic resources")
+
language = Attribute("Renderer language (if forced)")
+ context_attrs = Attribute("Context attributes defined into renderer")
+ i18n_context_attrs = Attribute("I18n context attributes defined into renderer")
class ISharedContentRenderer(IContentRenderer):
--- a/src/pyams_content/features/renderer/skin/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/renderer/skin/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -36,7 +36,9 @@
label = None
weight = 0
+
settings_interface = None
+ resources = ()
language = None
context_attrs = ()
@@ -49,6 +51,8 @@
return IRendererSettings(self.context)
def update(self):
+ for resource in self.resources:
+ resource.need()
for attr in self.context_attrs:
setattr(self, attr, getattr(self.context, attr, None))
if self.i18n_context_attrs:
--- a/src/pyams_content/features/renderer/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/renderer/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -18,6 +18,7 @@
# import interfaces
from pyams_content.features.renderer.interfaces import IRenderedContent, IContentRenderer, IRendererSettings
from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
+from pyams_form.interfaces.form import IFormManager
from pyams_skin.layer import IPyAMSLayer
# import packages
@@ -25,6 +26,7 @@
from pyams_pagelet.pagelet import pagelet_config
from pyams_viewlet.viewlet import BaseContentProvider
from pyams_zmi.form import AdminDialogEditForm
+from pyramid.decorator import reify
from z3c.form import field
from zope.interface import Interface
@@ -70,12 +72,45 @@
legend = _("Edit renderer properties")
icon_css_class = 'fa fa-fw fa-pencil-square-o'
- @property
+ @reify
+ def manager(self):
+ content = self.getContent()
+ return self.request.registry.queryMultiAdapter((content, self.request, self), IFormManager)
+
+ @reify
def fields(self):
- renderer = IContentRenderer(self.context)
- return field.Fields(renderer.settings_interface or Interface)
+ if self.manager is not None:
+ return self.manager.getFields()
+ else:
+ renderer = IContentRenderer(self.context)
+ return field.Fields(renderer.settings_interface or Interface)
edit_permission = MANAGE_CONTENT_PERMISSION
def getContent(self):
return IRendererSettings(self.context)
+
+ def update(self):
+ if self.manager is not None:
+ self.manager.update()
+ else:
+ super(RendererPropertiesEditForm, self).update()
+
+ def updateWidgets(self, prefix=None):
+ if self.manager is not None:
+ self.manager.updateWidgets(prefix)
+ else:
+ super(RendererPropertiesEditForm, self).updateWidgets(prefix)
+
+ def updateActions(self):
+ if self.manager is not None:
+ self.manager.updateActions()
+ else:
+ super(RendererPropertiesEditForm, self).updateActions()
+
+ def updateGroups(self):
+ if self.manager is not None:
+ self.manager.updateGroups()
+ else:
+ super(RendererPropertiesEditForm, self).updateGroups()
+
--- a/src/pyams_content/features/renderer/zmi/templates/renderer-input.pt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/renderer/zmi/templates/renderer-input.pt Thu Sep 06 11:27:55 2018 +0200
@@ -1,6 +1,6 @@
<label class="input bordered with-icon" i18n:domain="pyams_content">
<tal:var define="render view/show_renderer_properties">
- <i class="icon-append fa fa-fw fa-pencil-square-o text-primary hint align-base opaque"
+ <i class="icon-append fa fa-fw fa-pencil-square-o text-primary inverted hint align-base opaque"
title="Edit renderer properties" i18n:attributes="title"
data-ams-hint-gravity="se" data-toggle="modal"
tal:condition="render"
--- a/src/pyams_content/features/renderer/zmi/widget.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/features/renderer/zmi/widget.py Thu Sep 06 11:27:55 2018 +0200
@@ -31,7 +31,7 @@
@property
def show_renderer_properties(self):
- renderer = IContentRenderer(self.context)
+ renderer = IContentRenderer(self.context, None)
return (renderer is not None) and (renderer.settings_interface is not None)
--- a/src/pyams_content/generations/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/generations/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -71,6 +71,8 @@
'pyams_content.component.keynumber KeyNumber',
'pyams_content.component.paragraph.keynumber KeyNumberContainer':
'pyams_content.component.keynumber KeyNumberContainer',
+ 'pyams_content.component.paragraph.keynumber KeyNumberParagraph':
+ 'pyams_content.component.keynumber.paragraph KeyNumberParagraph',
'pyams_content.portlet.content SharedContentPortletSettings':
'pyams_content.shared.common.portlet.content SharedContentPortletSettings',
'pyams_content.portlet.navigation SimpleNavigationPortletSettings':
--- a/src/pyams_content/include.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/include.py Thu Sep 06 11:27:55 2018 +0200
@@ -18,6 +18,7 @@
# import interfaces
# import packages
+from pyramid.tweens import MAIN
def include_package(config):
@@ -26,6 +27,9 @@
# add translations
config.add_translation_dirs('pyams_content:locales')
+ # add custom twwen
+ config.add_tween('pyams_content.features.redirect.tween.redirect_tween_factory', over=MAIN)
+
# add custom routes
config.add_route('oid_access', '/+/{oid}*view')
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 Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po Thu Sep 06 11:27:55 2018 +0200
@@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-07-17 14:54+0200\n"
+"POT-Creation-Date: 2018-09-06 08:55+0200\n"
"PO-Revision-Date: 2015-09-10 10:42+0200\n"
"Last-Translator: Thierry Florac <tflorac@ulthar.net>\n"
"Language-Team: French\n"
@@ -167,15 +167,15 @@
"Commentaires (non publiés mais à conserver) relatifs à l'auteur et à la "
"gestion de ses droits"
-#: src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:11
+#: src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:12
msgid "Gallery medias"
msgstr "Contenu de la galerie"
-#: src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:17
+#: src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:18
msgid "Download medias"
msgstr "Télécharger tous les médias"
-#: src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:41
+#: src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:42
msgid "Zoom image"
msgstr "Agrandir l'image"
@@ -221,13 +221,9 @@
#: src/pyams_content/component/gallery/interfaces/__init__.py:58
#: src/pyams_content/component/gallery/interfaces/__init__.py:101
#: src/pyams_content/component/extfile/interfaces/__init__.py:40
-#: src/pyams_content/component/illustration/interfaces/__init__.py:64
-#: src/pyams_content/component/paragraph/interfaces/video.py:48
#: src/pyams_content/component/paragraph/interfaces/audio.py:48
#: src/pyams_content/component/links/interfaces/__init__.py:39
-#: src/pyams_content/component/video/interfaces/__init__.py:48
-#: src/pyams_content/shared/common/interfaces/__init__.py:154
-#: src/pyams_content/shared/form/interfaces/__init__.py:66
+#: src/pyams_content/shared/form/interfaces/__init__.py:64
msgid "Description"
msgstr "Description"
@@ -281,16 +277,16 @@
#: src/pyams_content/component/gallery/interfaces/__init__.py:97
#: src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:31
-#: src/pyams_content/component/paragraph/zmi/milestone.py:232
-#: src/pyams_content/component/paragraph/zmi/container.py:252
+#: src/pyams_content/component/paragraph/zmi/milestone.py:239
+#: src/pyams_content/component/paragraph/zmi/container.py:270
#: src/pyams_content/component/paragraph/interfaces/milestone.py:45
-#: src/pyams_content/component/links/zmi/reverse.py:73
+#: src/pyams_content/shared/common/zmi/reverse.py:73
#: src/pyams_content/shared/common/zmi/dashboard.py:109
-#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:188
+#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:200
#: src/pyams_content/shared/view/portlet/interfaces.py:56
#: src/pyams_content/shared/imagemap/zmi/container.py:123
-#: src/pyams_content/shared/site/zmi/folder.py:70
-#: src/pyams_content/root/zmi/templates/advanced-search.pt:188
+#: src/pyams_content/shared/site/zmi/folder.py:71
+#: src/pyams_content/root/zmi/templates/advanced-search.pt:197
#: src/pyams_content/interfaces/__init__.py:101
#: src/pyams_content/reference/pictograms/zmi/__init__.py:150
#: src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:31
@@ -411,7 +407,6 @@
#: src/pyams_content/component/extfile/interfaces/__init__.py:36
#: src/pyams_content/component/links/interfaces/__init__.py:35
#: src/pyams_content/shared/imagemap/interfaces/__init__.py:55
-#: src/pyams_content/shared/site/interfaces/__init__.py:114
msgid "Alternate title"
msgstr "Titre de substitution"
@@ -420,9 +415,7 @@
msgstr "Titre présenté aux internautes"
#: src/pyams_content/component/extfile/interfaces/__init__.py:41
-#: src/pyams_content/component/paragraph/interfaces/video.py:49
#: src/pyams_content/component/paragraph/interfaces/audio.py:49
-#: src/pyams_content/component/video/interfaces/__init__.py:49
msgid "File description displayed by front-office template"
msgstr "Description du fichier, présentée aux internautes"
@@ -482,49 +475,64 @@
"Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu"
#: src/pyams_content/component/keynumber/__init__.py:189
-#: src/pyams_content/component/keynumber/zmi/__init__.py:199
+#: src/pyams_content/component/keynumber/zmi/__init__.py:212
#: src/pyams_content/component/keynumber/portlet/zmi/__init__.py:74
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:29
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:83
msgid "Key numbers"
msgstr "Chiffres-clés"
+#: src/pyams_content/component/keynumber/zmi/paragraph.py:53
+msgid "Key numbers..."
+msgstr "Chiffres-clés"
+
+#: src/pyams_content/component/keynumber/zmi/paragraph.py:66
+msgid "Add new key number paragraph"
+msgstr "Ajout de chiffres-clés"
+
+#: src/pyams_content/component/keynumber/zmi/paragraph.py:94
+msgid "Edit key number paragraph properties"
+msgstr "Propriétés des chiffres-clés"
+
#. Default: Header
-#: src/pyams_content/component/keynumber/zmi/__init__.py:147
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:44
+#: src/pyams_content/component/keynumber/zmi/__init__.py:160
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:45
msgid "key-number-label"
msgstr "En-tête"
-#: src/pyams_content/component/keynumber/zmi/__init__.py:159
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:49
+#: src/pyams_content/component/keynumber/zmi/__init__.py:172
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:50
msgid "Number"
msgstr "Chiffre"
#. Default: Unit
-#: src/pyams_content/component/keynumber/zmi/__init__.py:168
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:53
+#: src/pyams_content/component/keynumber/zmi/__init__.py:181
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:54
msgid "key-number-unit"
msgstr "Unité"
-#: src/pyams_content/component/keynumber/zmi/__init__.py:180
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:57
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:268
+#: src/pyams_content/component/keynumber/zmi/__init__.py:193
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:58
+#: src/pyams_content/component/illustration/interfaces/__init__.py:64
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:277
+#: src/pyams_content/component/paragraph/interfaces/video.py:48
#: src/pyams_content/component/paragraph/interfaces/pictogram.py:58
+#: src/pyams_content/component/video/interfaces/__init__.py:48
msgid "Associated text"
msgstr "Texte associé"
-#: src/pyams_content/component/keynumber/zmi/__init__.py:218
+#: src/pyams_content/component/keynumber/zmi/__init__.py:231
msgid "Add keynumber"
msgstr "Ajouter un chiffre-clé"
-#: src/pyams_content/component/keynumber/zmi/__init__.py:230
+#: src/pyams_content/component/keynumber/zmi/__init__.py:243
msgid "Add new keynumber"
msgstr "Ajout d'un chiffre-clé"
-#: src/pyams_content/component/keynumber/zmi/__init__.py:259
+#: src/pyams_content/component/keynumber/zmi/__init__.py:272
msgid "Edit keynumber properties"
msgstr "Propriétés du chiffre-clé"
-#: src/pyams_content/component/keynumber/zmi/__init__.py:245
+#: src/pyams_content/component/keynumber/zmi/__init__.py:258
msgid "Key number was correctly added"
msgstr "Le chiffre-clé a été ajouté."
@@ -538,8 +546,8 @@
msgstr "Liens associés"
#: src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt:31
-#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:11
-#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:8
+#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:10
+#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:7
msgid "Link target is not published!"
msgstr "Le contenu ciblé n'est pas publié"
@@ -555,47 +563,55 @@
msgid "Short text displayed above key numbers"
msgstr "Texte d'introduction des chiffres-clés"
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:39
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:40
#: 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:118
+#: src/pyams_content/shared/form/interfaces/__init__.py:85
+#: src/pyams_content/shared/site/interfaces/__init__.py:144
#: src/pyams_content/features/alert/interfaces.py:54
#: src/pyams_content/features/menu/interfaces/__init__.py:59
msgid "Visible?"
msgstr "Visible ?"
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:40
+#: src/pyams_content/component/keynumber/interfaces/__init__.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/keynumber/interfaces/__init__.py:45
+#: src/pyams_content/component/keynumber/interfaces/__init__.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/keynumber/interfaces/__init__.py:50
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:51
msgid "Key number value"
msgstr "Chiffre"
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:54
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:55
msgid "Displayed unit"
msgstr "Unité affichée"
-#: src/pyams_content/component/keynumber/interfaces/__init__.py:58
+#: src/pyams_content/component/keynumber/interfaces/__init__.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/keynumber/interfaces/__init__.py:94
+msgid "Key numbers template"
+msgstr "Mode de rendu"
+
+#: src/pyams_content/component/keynumber/interfaces/__init__.py:95
+msgid "Presentation template used for key numbers"
+msgstr "Modèle de présentation utilisé par ce bloc de contenu"
+
#: src/pyams_content/component/illustration/__init__.py:177
#: src/pyams_content/component/illustration/thesaurus.py:32
#: src/pyams_content/component/illustration/zmi/paragraph.py:158
#: src/pyams_content/component/illustration/zmi/__init__.py:56
-#: src/pyams_content/component/illustration/zmi/__init__.py:100
+#: src/pyams_content/component/illustration/zmi/__init__.py:117
#: src/pyams_content/component/illustration/interfaces/__init__.py:99
msgid "Illustration"
msgstr "Illustration"
@@ -613,11 +629,11 @@
msgid "Edit illustration properties"
msgstr "Propriétés de l'illustration"
-#: src/pyams_content/component/illustration/zmi/__init__.py:150
+#: src/pyams_content/component/illustration/zmi/__init__.py:151
msgid "Navigation link illustration"
msgstr "Illustration de navigation"
-#: src/pyams_content/component/illustration/zmi/__init__.py:102
+#: src/pyams_content/component/illustration/zmi/__init__.py:119
msgid "Header illustration"
msgstr "Illustration d'en-tête"
@@ -630,6 +646,12 @@
"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:65
+msgid "Illustration description displayed in front-office templates"
+msgstr ""
+"Le texte accompagne l'illustration, en complément de la légende. Attention : "
+"sa présence et sa mise en forme dépendent du mode de rendu choisi."
+
#: src/pyams_content/component/illustration/interfaces/__init__.py:69
msgid "Name of picture's author"
msgstr "Sous la forme \"Prénom Nom / Organisme\""
@@ -653,11 +675,11 @@
msgid "Selected paragraph is not visible"
msgstr "le bloc sélectionné n'est pas visible"
-#: src/pyams_content/component/paragraph/container.py:73
+#: src/pyams_content/component/paragraph/container.py:90
msgid "Paragraphs"
msgstr "Blocs de contenu"
-#: src/pyams_content/component/paragraph/container.py:95
+#: src/pyams_content/component/paragraph/container.py:112
msgid "no visible paragraph"
msgstr "aucun bloc de contenu visible"
@@ -665,6 +687,10 @@
msgid "Selected pictogram is missing"
msgstr "le pictogramme sélectionné est introuvable"
+#: src/pyams_content/component/paragraph/header.py:62
+msgid "This paragraph type is deprecated and should be removed!"
+msgstr "Ce type de paragraphe a été supprimé et ne doit plus être utilisé !"
+
#: src/pyams_content/component/paragraph/zmi/milestone.py:78
msgid "Milestones..."
msgstr "Chronologie"
@@ -677,38 +703,38 @@
msgid "Edit milestone paragraph properties"
msgstr "Propriétés de la chronologie"
-#: src/pyams_content/component/paragraph/zmi/milestone.py:244
+#: src/pyams_content/component/paragraph/zmi/milestone.py:251
#: src/pyams_content/component/paragraph/interfaces/milestone.py:49
msgid "Associated label"
msgstr "Information associée"
-#: src/pyams_content/component/paragraph/zmi/milestone.py:256
+#: src/pyams_content/component/paragraph/zmi/milestone.py:263
#: src/pyams_content/component/paragraph/interfaces/milestone.py:53
msgid "Anchor"
msgstr "Ancre"
-#: src/pyams_content/component/paragraph/zmi/milestone.py:285
+#: src/pyams_content/component/paragraph/zmi/milestone.py:292
#: src/pyams_content/component/paragraph/interfaces/milestone.py:76
msgid "Milestones"
msgstr "Chronologie"
-#: src/pyams_content/component/paragraph/zmi/milestone.py:300
+#: src/pyams_content/component/paragraph/zmi/milestone.py:307
msgid "Add milestone"
msgstr "Ajouter un jalon"
-#: src/pyams_content/component/paragraph/zmi/milestone.py:313
+#: src/pyams_content/component/paragraph/zmi/milestone.py:320
msgid "Add new milestone"
msgstr "Ajout d'un jalon"
-#: src/pyams_content/component/paragraph/zmi/milestone.py:340
+#: src/pyams_content/component/paragraph/zmi/milestone.py:347
msgid "Edit milestone properties"
msgstr "Propriétés du jalon"
-#: src/pyams_content/component/paragraph/zmi/milestone.py:328
+#: src/pyams_content/component/paragraph/zmi/milestone.py:335
msgid "Milestone was correctly added"
msgstr "Le jalon a été ajouté."
-#: src/pyams_content/component/paragraph/zmi/milestone.py:271
+#: src/pyams_content/component/paragraph/zmi/milestone.py:278
msgid "(missing paragraph)"
msgstr "(paragraphe supprimé)"
@@ -784,6 +810,26 @@
msgid "Paragraph was correctly added."
msgstr "Le bloc a été ajouté."
+#: src/pyams_content/component/paragraph/zmi/__init__.py:254
+msgid ""
+"You changed renderer selection. Don't omit to update new renderer "
+"properties..."
+msgstr ""
+"Vous avez changé de mode de rendu. N'oubliez pas de vérifier les propriétés "
+"du nouveau mode de rendu sélectionné..."
+
+#: src/pyams_content/component/paragraph/zmi/map.py:55
+msgid "Location map..."
+msgstr "Carte de situation"
+
+#: src/pyams_content/component/paragraph/zmi/map.py:68
+msgid "Add new location map"
+msgstr "Ajout d'une carte de situation"
+
+#: src/pyams_content/component/paragraph/zmi/map.py:91
+msgid "Edit location map properties"
+msgstr "Propriétés de la carte"
+
#: src/pyams_content/component/paragraph/zmi/video.py:54
msgid "Video paragraph..."
msgstr "Vidéo"
@@ -799,43 +845,43 @@
#: src/pyams_content/component/paragraph/zmi/container.py:74
msgid "Contents..."
-msgstr "Contenu"
-
-#: src/pyams_content/component/paragraph/zmi/container.py:196
+msgstr "Blocs de contenu"
+
+#: src/pyams_content/component/paragraph/zmi/container.py:215
msgid "Set navigation anchor"
msgstr "Ancre de navigation"
-#: src/pyams_content/component/paragraph/zmi/container.py:268
+#: src/pyams_content/component/paragraph/zmi/container.py:286
msgid "Show/hide all paragraphs"
msgstr "Afficher/masquer tous les blocs"
-#: src/pyams_content/component/paragraph/zmi/container.py:316
-#: src/pyams_content/component/paragraph/zmi/container.py:325
-#: src/pyams_content/component/paragraph/zmi/container.py:338
+#: src/pyams_content/component/paragraph/zmi/container.py:334
+#: src/pyams_content/component/paragraph/zmi/container.py:343
+#: src/pyams_content/component/paragraph/zmi/container.py:356
msgid "Content blocks"
msgstr "Blocs de contenu"
-#: src/pyams_content/component/paragraph/zmi/container.py:395
+#: src/pyams_content/component/paragraph/zmi/container.py:413
msgid "Links and attachments..."
msgstr "Récap. liens et PJ"
-#: src/pyams_content/component/paragraph/zmi/container.py:407
+#: src/pyams_content/component/paragraph/zmi/container.py:425
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:145
msgid "No currently defined paragraph."
msgstr "Aucun bloc n'est associé à ce contenu."
-#: src/pyams_content/component/paragraph/zmi/container.py:277
+#: src/pyams_content/component/paragraph/zmi/container.py:295
msgid "Click to open/close all paragraphs editors"
msgstr "Afficher/masquer tous les blocs"
-#: src/pyams_content/component/paragraph/zmi/container.py:290
+#: src/pyams_content/component/paragraph/zmi/container.py:308
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:151
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 "
@@ -854,36 +900,36 @@
msgstr "Propriétés des pictogrammes"
#. Default: Header
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:253
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:260
msgid "pictogram-item-header"
msgstr "En-tête"
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:290
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:299
#: src/pyams_content/component/paragraph/interfaces/pictogram.py:80
msgid "Pictograms"
msgstr "Pictogrammes"
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:305
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:314
#: src/pyams_content/reference/pictograms/zmi/__init__.py:59
msgid "Add pictogram"
msgstr "Ajouter un pictogramme"
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:318
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:327
#: src/pyams_content/reference/pictograms/zmi/__init__.py:71
msgid "Add new pictogram"
msgstr "Ajout d'un pictogramme"
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:360
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:369
#: src/pyams_content/reference/pictograms/zmi/__init__.py:95
msgid "Edit pictogram properties"
msgstr "Propriétés du pictogramme"
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:340
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:349
msgid "Pictogram was correctly added"
msgstr "Le pictogramme a été ajouté."
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:350
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:388
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:359
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:397
msgid "You must select a pictogram!"
msgstr "Vous devez sélectionner un pictogramme !"
@@ -899,27 +945,15 @@
msgid "Edit audio properties"
msgstr "Propriétés de la bande son"
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:55
-msgid "Key numbers..."
-msgstr "Chiffres-clés"
-
-#: 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:96
-msgid "Edit key number paragraph properties"
-msgstr "Propriétés des chiffres-clés"
-
-#: src/pyams_content/component/paragraph/zmi/frame.py:85
+#: src/pyams_content/component/paragraph/zmi/frame.py:86
msgid "Framed text..."
msgstr "Encadré"
-#: src/pyams_content/component/paragraph/zmi/frame.py:99
+#: src/pyams_content/component/paragraph/zmi/frame.py:100
msgid "Add new framed text paragraph"
msgstr "Ajout d'un encadré"
-#: src/pyams_content/component/paragraph/zmi/frame.py:125
+#: src/pyams_content/component/paragraph/zmi/frame.py:126
msgid "Edit framed text paragraph properties"
msgstr "Propriétés de l'encadré"
@@ -971,15 +1005,7 @@
msgid "Edit contact card properties"
msgstr "Propriétés de la fiche contact"
-#: src/pyams_content/component/paragraph/zmi/header.py:50
-msgid "Header..."
-msgstr "Chapô"
-
-#: src/pyams_content/component/paragraph/zmi/header.py:63
-msgid "Add new header paragraph"
-msgstr "Ajout d'un chapô"
-
-#: src/pyams_content/component/paragraph/zmi/header.py:90
+#: src/pyams_content/component/paragraph/zmi/header.py:49
msgid "Edit header paragraph properties"
msgstr "Propriétés du chapô"
@@ -1051,29 +1077,65 @@
msgid "§ Title"
msgstr "Titre §"
-#: src/pyams_content/component/paragraph/interfaces/__init__.py:88
+#: src/pyams_content/component/paragraph/interfaces/__init__.py:94
msgid "Allowed paragraphs"
msgstr "Types de blocs autorisés"
-#: src/pyams_content/component/paragraph/interfaces/__init__.py:89
+#: src/pyams_content/component/paragraph/interfaces/__init__.py:95
msgid "List of paragraphs allowed for this content type"
msgstr "Liste des types de blocs de contenu autorisés pour ce gabarit."
-#: src/pyams_content/component/paragraph/interfaces/__init__.py:93
-#: src/pyams_content/shared/common/zmi/types.py:173
-#: src/pyams_content/shared/common/zmi/types.py:413
+#: src/pyams_content/component/paragraph/interfaces/__init__.py:99
+#: src/pyams_content/shared/common/zmi/types.py:172
+#: src/pyams_content/shared/common/zmi/types.py:412
msgid "Default paragraphs"
msgstr "Types de blocs par défaut"
-#: src/pyams_content/component/paragraph/interfaces/__init__.py:94
+#: src/pyams_content/component/paragraph/interfaces/__init__.py:100
msgid "List of paragraphs automatically added to a new content"
msgstr "Liste des types de blocs ajoutés automatiquement aux nouveaux contenus"
+#: src/pyams_content/component/paragraph/interfaces/map.py:41
+msgid "Location map"
+msgstr "Carte"
+
+#: src/pyams_content/component/paragraph/interfaces/map.py:48
+#: src/pyams_content/component/paragraph/interfaces/contact.py:72
+msgid "GPS location"
+msgstr "Position GPS"
+
+#: src/pyams_content/component/paragraph/interfaces/map.py:49
+msgid "GPS coordinates used to locate map"
+msgstr "Coordonnées GPS de situation de la carte"
+
+#: src/pyams_content/component/paragraph/interfaces/map.py:52
+msgid "Display location mark?"
+msgstr "Marqueur de position ?"
+
+#: src/pyams_content/component/paragraph/interfaces/map.py:53
+msgid "If 'yes', a location marker will be displayed on map"
+msgstr "Si 'oui', un marqueur de position sera placé sur la carte"
+
+#: src/pyams_content/component/paragraph/interfaces/map.py:57
+msgid "Map template"
+msgstr "Mode de rendu"
+
+#: src/pyams_content/component/paragraph/interfaces/map.py:58
+msgid "Presentation template used for this map"
+msgstr "Mode de rendu utilisé par cette carte"
+
#: src/pyams_content/component/paragraph/interfaces/video.py:42
msgid "Video file content"
msgstr ""
"Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu"
+#: src/pyams_content/component/paragraph/interfaces/video.py:49
+#: src/pyams_content/component/video/interfaces/__init__.py:49
+msgid "Video description displayed by front-office template"
+msgstr ""
+"Le texte accompagne la vidéo, en complément de la légende. Attention : sa "
+"présence et sa mise en forme dépendent du mode de rendu choisi."
+
#: src/pyams_content/component/paragraph/interfaces/video.py:56
#: src/pyams_content/component/video/interfaces/__init__.py:78
msgid "Video template"
@@ -1091,12 +1153,10 @@
#: src/pyams_content/component/paragraph/interfaces/pictogram.py:46
#: src/pyams_content/component/links/interfaces/__init__.py:43
#: src/pyams_content/shared/common/interfaces/types.py:75
-#: src/pyams_content/features/alert/interfaces.py:79
msgid "Pictogram"
msgstr "Pictogramme"
#: src/pyams_content/component/paragraph/interfaces/pictogram.py:47
-#: src/pyams_content/features/alert/interfaces.py:80
msgid "Name of the pictogram to select"
msgstr "Sélection du pictogramme à afficher"
@@ -1136,14 +1196,6 @@
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:36
-msgid "Key numbers template"
-msgstr "Mode de rendu"
-
-#: 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"
-
#: src/pyams_content/component/paragraph/interfaces/frame.py:33
msgid "Framed text"
msgstr "Encadré"
@@ -1269,16 +1321,13 @@
msgid "Presentation template used for this contact"
msgstr "Modèle de présentation utilisé pour ce contact"
-#: src/pyams_content/component/paragraph/interfaces/contact.py:72
-msgid "GPS location"
-msgstr "Position GPS"
-
#: src/pyams_content/component/paragraph/interfaces/contact.py:73
msgid "GPS coordinates used to locate contact"
msgstr "Coordonnées GPS de situation du contact"
#: src/pyams_content/component/paragraph/interfaces/header.py:33
#: src/pyams_content/component/paragraph/interfaces/header.py:40
+#: src/pyams_content/shared/common/interfaces/__init__.py:153
msgid "Header"
msgstr "Chapô"
@@ -1296,6 +1345,9 @@
#: src/pyams_content/component/theme/zmi/portlet.py:40
#: src/pyams_content/component/theme/interfaces/__init__.py:47
#: src/pyams_content/component/theme/interfaces/__init__.py:61
+#: src/pyams_content/shared/common/zmi/search.py:189
+#: src/pyams_content/root/zmi/search.py:179
+#: src/pyams_content/root/zmi/templates/advanced-search.pt:181
msgid "Tags"
msgstr "Tags"
@@ -1303,6 +1355,7 @@
#: src/pyams_content/component/theme/zmi/portlet.py:55
#: src/pyams_content/component/theme/interfaces/__init__.py:88
#: src/pyams_content/component/theme/interfaces/__init__.py:102
+#: src/pyams_content/shared/common/zmi/search.py:192
msgid "Themes"
msgstr "Thèmes"
@@ -1310,6 +1363,7 @@
#: src/pyams_content/component/theme/zmi/portlet.py:70
#: src/pyams_content/component/theme/interfaces/__init__.py:129
#: src/pyams_content/component/theme/interfaces/__init__.py:143
+#: src/pyams_content/shared/common/zmi/search.py:195
msgid "Collections"
msgstr "Collections"
@@ -1352,32 +1406,32 @@
msgid "Content collections"
msgstr "Collections associées au contenu"
-#: src/pyams_content/component/theme/zmi/manager.py:51
+#: src/pyams_content/component/theme/zmi/manager.py:58
msgid "Tags settings..."
msgstr "Paramétrage des tags"
-#: src/pyams_content/component/theme/zmi/manager.py:65
+#: src/pyams_content/component/theme/zmi/manager.py:72
msgid "Selected tags"
msgstr "Tags sélectionnés"
-#: src/pyams_content/component/theme/zmi/manager.py:101
+#: src/pyams_content/component/theme/zmi/manager.py:108
msgid "Themes settings..."
msgstr "Paramétrage des thèmes"
-#: src/pyams_content/component/theme/zmi/manager.py:115
+#: src/pyams_content/component/theme/zmi/manager.py:122
msgid "Selected themes"
msgstr "Thèmes sélectionnés"
-#: src/pyams_content/component/theme/zmi/manager.py:151
+#: src/pyams_content/component/theme/zmi/manager.py:158
msgid "Collections settings..."
msgstr "Paramétrage des collections"
-#: src/pyams_content/component/theme/zmi/manager.py:165
+#: src/pyams_content/component/theme/zmi/manager.py:172
msgid "Selected collections"
msgstr "Collections sélectionnées"
#: src/pyams_content/component/association/container.py:91
-#: src/pyams_content/component/association/zmi/__init__.py:296
+#: src/pyams_content/component/association/zmi/__init__.py:303
#: src/pyams_content/component/association/interfaces/__init__.py:93
msgid "Associations"
msgstr "Liens et pièces jointes"
@@ -1395,20 +1449,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:198
+#: src/pyams_content/component/association/zmi/__init__.py:205
msgid "Public title"
msgstr "Libellé public"
-#: src/pyams_content/component/association/zmi/__init__.py:216
+#: src/pyams_content/component/association/zmi/__init__.py:223
msgid "Inner title"
msgstr "Contenu interne"
-#: src/pyams_content/component/association/zmi/__init__.py:232
+#: src/pyams_content/component/association/zmi/__init__.py:239
msgid "Size"
msgstr "Taille"
-#: src/pyams_content/component/association/zmi/__init__.py:273
-#: src/pyams_content/component/association/zmi/__init__.py:283
+#: src/pyams_content/component/association/zmi/__init__.py:280
+#: src/pyams_content/component/association/zmi/__init__.py:290
msgid "Associations list"
msgstr "Liste des liens et pièces jointes"
@@ -1429,19 +1483,19 @@
msgid "Presentation template used for associations"
msgstr "Modèle de présentation utilisé par ce bloc de contenu"
-#: src/pyams_content/component/links/__init__.py:123
+#: src/pyams_content/component/links/__init__.py:144
msgid "Internal link"
msgstr "Lien interne"
-#: src/pyams_content/component/links/__init__.py:219
+#: src/pyams_content/component/links/__init__.py:230
msgid "External link"
msgstr "Lien externe"
-#: src/pyams_content/component/links/__init__.py:272
+#: src/pyams_content/component/links/__init__.py:283
msgid "Mailto link"
msgstr "Lien mailto"
-#: src/pyams_content/component/links/__init__.py:206
+#: src/pyams_content/component/links/__init__.py:217
msgid "target is not published"
msgstr "le contenu ciblé n'est pas publié"
@@ -1493,14 +1547,6 @@
msgid "Edit mailto link properties"
msgstr "Propriétés du lien « mailto »"
-#: src/pyams_content/component/links/zmi/reverse.py:57
-msgid "Reverse links"
-msgstr "Liens amont"
-
-#: src/pyams_content/component/links/zmi/reverse.py:66
-msgid "Content's internal links"
-msgstr "Autres contenus qui pointent vers ce contenu"
-
#: src/pyams_content/component/links/interfaces/__init__.py:36
msgid "Link title, as shown in front-office"
msgstr ""
@@ -1519,6 +1565,7 @@
#: src/pyams_content/component/links/interfaces/__init__.py:61
#: src/pyams_content/shared/logo/interfaces/__init__.py:56
+#: src/pyams_content/features/redirect/interfaces/__init__.py:68
msgid "Target URL"
msgstr "URL cible"
@@ -1845,146 +1892,150 @@
msgid "Name of external platform providing selected video"
msgstr "Nom de la plate-forme externe fournissant la vidéo à afficher"
-#: src/pyams_content/shared/common/__init__.py:240
-#: src/pyams_content/shared/common/zmi/properties.py:70
+#: src/pyams_content/shared/common/__init__.py:242
+#: src/pyams_content/shared/common/zmi/properties.py:69
#: src/pyams_content/shared/common/zmi/manager.py:96
msgid "Properties"
msgstr "Propriétés"
-#: src/pyams_content/shared/common/__init__.py:150
-#: src/pyams_content/shared/common/__init__.py:158
+#: src/pyams_content/shared/common/__init__.py:152
+#: src/pyams_content/shared/common/__init__.py:160
#, python-format
msgid "{date} by {principal}"
msgstr "{date} par {principal}"
-#: src/pyams_content/shared/common/__init__.py:263
+#: src/pyams_content/shared/common/__init__.py:265
#, python-format
msgid "title length should be between 40 and 66 characters ({length} actually)"
msgstr ""
"Le titre devrait être composé de 40 à 66 caractères ({length} actuellement)"
-#: src/pyams_content/shared/common/zmi/search.py:92
-#: src/pyams_content/root/zmi/search.py:91
+#: src/pyams_content/shared/common/zmi/search.py:96
+#: src/pyams_content/root/zmi/search.py:95
msgid "Quick search results"
msgstr "Résultats de la recherche rapide"
-#: src/pyams_content/shared/common/zmi/search.py:157
-#: src/pyams_content/shared/common/zmi/search.py:190
-#: src/pyams_content/root/zmi/search.py:147
-#: src/pyams_content/root/zmi/search.py:180
+#: src/pyams_content/shared/common/zmi/search.py:162
+#: src/pyams_content/shared/common/zmi/search.py:204
+#: src/pyams_content/root/zmi/search.py:152
+#: src/pyams_content/root/zmi/search.py:188
msgid "Advanced search"
msgstr "Recherche avancée"
-#: src/pyams_content/shared/common/zmi/search.py:282
-#: src/pyams_content/root/zmi/search.py:260
+#: src/pyams_content/shared/common/zmi/search.py:332
+#: src/pyams_content/root/zmi/search.py:280
msgid "Advanced search results"
msgstr "Résultats de la recherche avancée"
-#: src/pyams_content/shared/common/zmi/search.py:165
+#: src/pyams_content/shared/common/zmi/search.py:170
#: src/pyams_content/shared/common/zmi/dashboard.py:231
-#: src/pyams_content/root/zmi/search.py:159
+#: src/pyams_content/root/zmi/search.py:164
msgid "Owner"
msgstr "Propriétaire"
-#: src/pyams_content/shared/common/zmi/search.py:168
+#: src/pyams_content/shared/common/zmi/search.py:173
#: src/pyams_content/shared/common/zmi/dashboard.py:154
msgid "Status"
msgstr "Statut"
-#: src/pyams_content/shared/common/zmi/search.py:172
-#: src/pyams_content/root/zmi/search.py:162
+#: src/pyams_content/shared/common/zmi/search.py:177
+#: src/pyams_content/root/zmi/search.py:167
msgid "Created after..."
msgstr "Créé entre le"
-#: src/pyams_content/shared/common/zmi/search.py:175
-#: src/pyams_content/root/zmi/search.py:165
+#: src/pyams_content/shared/common/zmi/search.py:180
+#: src/pyams_content/root/zmi/search.py:170
msgid "Created before..."
msgstr "et le"
-#: src/pyams_content/shared/common/zmi/search.py:178
-#: src/pyams_content/root/zmi/search.py:168
+#: src/pyams_content/shared/common/zmi/search.py:183
+#: src/pyams_content/root/zmi/search.py:173
msgid "Modified after..."
msgstr "Modifié entre le"
-#: src/pyams_content/shared/common/zmi/search.py:181
-#: src/pyams_content/root/zmi/search.py:171
+#: src/pyams_content/shared/common/zmi/search.py:186
+#: src/pyams_content/root/zmi/search.py:176
msgid "Modified before..."
msgstr "et le"
-#: src/pyams_content/shared/common/zmi/properties.py:60
+#: src/pyams_content/shared/common/zmi/properties.py:59
msgid "Composition"
msgstr "Composition"
-#: src/pyams_content/shared/common/zmi/properties.py:83
+#: src/pyams_content/shared/common/zmi/properties.py:82
msgid "Content properties"
msgstr "Propriétés élémentaires"
-#: src/pyams_content/shared/common/zmi/types.py:71
+#: src/pyams_content/shared/common/zmi/types.py:70
msgid "Data types"
msgstr "Types de contenus"
-#: src/pyams_content/shared/common/zmi/types.py:149
+#: src/pyams_content/shared/common/zmi/types.py:148
msgid "Data type label"
msgstr "Libellé du type"
-#: src/pyams_content/shared/common/zmi/types.py:189
-#: src/pyams_content/shared/common/zmi/types.py:429
+#: src/pyams_content/shared/common/zmi/types.py:188
+#: src/pyams_content/shared/common/zmi/types.py:428
msgid "Default associations"
msgstr "Liens et pièces jointes par défaut"
-#: src/pyams_content/shared/common/zmi/types.py:205
+#: src/pyams_content/shared/common/zmi/types.py:204
msgid "Default themes"
msgstr "Thèmes par défaut"
-#: src/pyams_content/shared/common/zmi/types.py:233
+#: src/pyams_content/shared/common/zmi/types.py:232
msgid "Content data types"
msgstr "Types de contenus"
-#: src/pyams_content/shared/common/zmi/types.py:256
+#: src/pyams_content/shared/common/zmi/types.py:255
msgid "Add data type"
msgstr "Ajouter un type"
-#: src/pyams_content/shared/common/zmi/types.py:268
+#: src/pyams_content/shared/common/zmi/types.py:267
msgid "Add new data type"
msgstr "Ajout d'un type de contenu"
-#: src/pyams_content/shared/common/zmi/types.py:311
+#: src/pyams_content/shared/common/zmi/types.py:310
msgid "Data type properties"
msgstr "Propriétés du type de contenu"
-#: src/pyams_content/shared/common/zmi/types.py:392
+#: src/pyams_content/shared/common/zmi/types.py:391
msgid "Subtype label"
msgstr "Libellé du sous-type"
-#: src/pyams_content/shared/common/zmi/types.py:473
+#: src/pyams_content/shared/common/zmi/types.py:472
msgid "Add subtype"
msgstr "Ajouter un sous-type"
-#: src/pyams_content/shared/common/zmi/types.py:485
+#: src/pyams_content/shared/common/zmi/types.py:484
msgid "Add new subtype"
msgstr "Ajout d'un sous-type de contenu"
-#: src/pyams_content/shared/common/zmi/types.py:532
+#: src/pyams_content/shared/common/zmi/types.py:531
msgid "Data subtype properties"
msgstr "Propriétés du fichier standard"
-#: src/pyams_content/shared/common/zmi/types.py:116
+#: src/pyams_content/shared/common/zmi/types.py:573
+msgid "Select content type..."
+msgstr "Sélectionnez un type de contenu..."
+
+#: src/pyams_content/shared/common/zmi/types.py:115
msgid "No currently defined data type."
msgstr "Aucun type de contenu n'est actuellement défini."
-#: src/pyams_content/shared/common/zmi/types.py:301
+#: src/pyams_content/shared/common/zmi/types.py:300
msgid "Specified type name is already used!"
msgstr "Le nom indiqué pour ce type de contenu est déjà utilisé !"
-#: src/pyams_content/shared/common/zmi/types.py:508
+#: src/pyams_content/shared/common/zmi/types.py:507
msgid "Subtype was correctly added."
msgstr "Le sous-type a été ajouté."
-#: src/pyams_content/shared/common/zmi/types.py:522
+#: src/pyams_content/shared/common/zmi/types.py:521
msgid "Specified subtype name is already used!"
msgstr "Le nom indiqué pour ce sous-type de contenu est déjà utilisé !"
-#: src/pyams_content/shared/common/zmi/types.py:161
+#: src/pyams_content/shared/common/zmi/types.py:160
msgid "Click to see subtypes"
msgstr "Montrer ou caher les sous-types"
@@ -2095,8 +2146,7 @@
msgid ""
"You must confirm that you checked this content before requesting "
"publication!!"
-msgstr ""
-"Vous devez avoir audité ce contenu avant de pouvoir le publier !!"
+msgstr "Vous devez avoir audité ce contenu avant de pouvoir le publier !!"
#: src/pyams_content/shared/common/zmi/workflow.py:84
#: src/pyams_content/workflow/__init__.py:648
@@ -2134,45 +2184,45 @@
msgid "Created or modified in this version"
msgstr "Créé ou modifié dans cette version"
-#: src/pyams_content/shared/common/zmi/summary.py:50
+#: src/pyams_content/shared/common/zmi/summary.py:52
msgid "Display content summary"
msgstr "Récapitulatif pour ce contenu"
-#: src/pyams_content/shared/common/zmi/summary.py:74
+#: src/pyams_content/shared/common/zmi/summary.py:76
msgid "Identity card"
msgstr "Carte d'identité"
-#: src/pyams_content/shared/common/zmi/summary.py:86
+#: src/pyams_content/shared/common/zmi/summary.py:94
msgid "Requested action"
msgstr "Évolution demandée"
-#: src/pyams_content/shared/common/zmi/summary.py:127
+#: src/pyams_content/shared/common/zmi/summary.py:135
msgid "Publication and retire dates"
msgstr "Dates de publication et de retrait planifiées"
-#: src/pyams_content/shared/common/zmi/summary.py:146
+#: src/pyams_content/shared/common/zmi/summary.py:154
msgid "Current version"
msgstr "À propos de cette version"
-#: src/pyams_content/shared/common/zmi/summary.py:176
+#: src/pyams_content/shared/common/zmi/summary.py:184
msgid "Content history"
msgstr "Pour mémoire"
-#: src/pyams_content/shared/common/zmi/summary.py:117
+#: src/pyams_content/shared/common/zmi/summary.py:125
msgid "Associated comment"
msgstr "Commentaire associé"
-#: src/pyams_content/shared/common/zmi/summary.py:158
+#: src/pyams_content/shared/common/zmi/summary.py:166
#: src/pyams_content/shared/common/zmi/dashboard.py:198
msgid "Version"
msgstr "Version"
-#: src/pyams_content/shared/common/zmi/summary.py:107
+#: src/pyams_content/shared/common/zmi/summary.py:115
#, python-format
msgid "{state} {date} by {principal}"
msgstr "{state} {date} par {principal}"
-#: src/pyams_content/shared/common/zmi/summary.py:164
+#: src/pyams_content/shared/common/zmi/summary.py:172
#, python-format
msgid "{state} since {date}, by {principal}"
msgstr "{state} depuis {date} par {principal}"
@@ -2276,6 +2326,14 @@
msgid "You must provide an URL for this item!"
msgstr "Vous devez fournir une URL pour ce contenu !"
+#: src/pyams_content/shared/common/zmi/reverse.py:57
+msgid "Reverse links"
+msgstr "Liens amont"
+
+#: src/pyams_content/shared/common/zmi/reverse.py:66
+msgid "Content's internal links"
+msgstr "Autres contenus qui pointent vers ce contenu"
+
#: src/pyams_content/shared/common/zmi/site.py:38
#, python-format
msgid ""
@@ -2284,11 +2342,11 @@
"RECHERCHE - Tous contenus présents dans « {site} » "
"confondus"
-#: src/pyams_content/shared/common/zmi/portal.py:46
+#: src/pyams_content/shared/common/zmi/portal.py:44
msgid "Edit default template properties"
msgstr "Modèle de présentation par défaut"
-#: src/pyams_content/shared/common/zmi/portal.py:56
+#: src/pyams_content/shared/common/zmi/portal.py:54
msgid ""
"**This form allows you to select shared content default template.**\n"
"\n"
@@ -2311,9 +2369,9 @@
"présentation ne pourra pas être réutilisé ailleurs que dans les contenus de "
"ce gabarit."
-#: src/pyams_content/shared/common/zmi/portal.py:72
-msgid "Override tool default template"
-msgstr "Ne pas utiliser le modèle par défaut de ce gabarit"
+#: src/pyams_content/shared/common/zmi/portal.py:70
+msgid "Use tool default template"
+msgstr "Utiliser le modèle de présentation par défaut de ce gabarit"
#: src/pyams_content/shared/common/zmi/dashboard.py:134
msgid "Unique ID"
@@ -2401,8 +2459,8 @@
#: src/pyams_content/shared/common/zmi/dashboard.py:545
#: src/pyams_content/root/zmi/__init__.py:346
-msgid "Your favorites"
-msgstr "Mes favoris"
+msgid "Your favorite contents"
+msgstr "Mes contenus favoris"
#: src/pyams_content/shared/common/zmi/dashboard.py:558
#: src/pyams_content/root/zmi/__init__.py:359
@@ -2610,7 +2668,7 @@
#: src/pyams_content/shared/common/zmi/security.py:118
#: src/pyams_content/shared/common/zmi/security.py:270
msgid "Activated publication checks?"
-msgstr "Tunnel de publication actif ?"
+msgstr "Tunnel de publication activé"
#: src/pyams_content/shared/common/zmi/security.py:218
msgid "Managers restrictions"
@@ -2732,9 +2790,9 @@
#: src/pyams_content/shared/common/zmi/templates/check-input.pt:34
#: src/pyams_content/shared/common/zmi/templates/preview-input.pt:34
#: src/pyams_content/shared/common/interfaces/types.py:47
-#: src/pyams_content/shared/form/zmi/field.py:160
-#: src/pyams_content/shared/form/interfaces/__init__.py:62
-#: src/pyams_content/features/menu/zmi/__init__.py:208
+#: src/pyams_content/shared/form/zmi/field.py:167
+#: src/pyams_content/shared/form/interfaces/__init__.py:60
+#: src/pyams_content/features/menu/zmi/__init__.py:215
msgid "Label"
msgstr "Libellé"
@@ -2846,25 +2904,25 @@
"Un numéro unique lui sera également attribué ; ce numéro sera conservé "
"pendant toute la vie du contenu, quelle que soit la version."
-#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:128
-#: src/pyams_content/root/zmi/templates/advanced-search.pt:128
+#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:130
+#: src/pyams_content/root/zmi/templates/advanced-search.pt:130
msgid "Created between"
msgstr "Créé entre le"
-#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:140
-#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:166
-#: src/pyams_content/root/zmi/templates/advanced-search.pt:140
-#: src/pyams_content/root/zmi/templates/advanced-search.pt:166
+#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:142
+#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:168
+#: src/pyams_content/root/zmi/templates/advanced-search.pt:142
+#: src/pyams_content/root/zmi/templates/advanced-search.pt:168
msgid "and"
msgstr "et le"
-#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:154
-#: src/pyams_content/root/zmi/templates/advanced-search.pt:154
+#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:156
+#: src/pyams_content/root/zmi/templates/advanced-search.pt:156
msgid "Modified between"
msgstr "Modifié entre le"
-#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:202
-#: src/pyams_content/root/zmi/templates/advanced-search.pt:202
+#: src/pyams_content/shared/common/zmi/templates/advanced-search.pt:214
+#: src/pyams_content/root/zmi/templates/advanced-search.pt:211
msgid "Tab label"
msgstr "Libellé de l'onglet"
@@ -2969,12 +3027,12 @@
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
+#: src/pyams_content/shared/common/portlet/content/skin/__init__.py:39
msgid "Default content renderer"
msgstr "Par défaut"
#: src/pyams_content/shared/common/interfaces/types.py:43
-#: src/pyams_content/shared/form/zmi/field.py:149
+#: src/pyams_content/shared/form/zmi/field.py:156
msgid "Name"
msgstr "Nom"
@@ -3057,22 +3115,22 @@
msgid "Type of content data"
msgstr "Type du contenu associé à ce gabarit"
-#: src/pyams_content/shared/common/interfaces/__init__.py:46
+#: src/pyams_content/shared/common/interfaces/__init__.py:45
#: src/pyams_content/root/interfaces/__init__.py:43
msgid "Webmasters"
msgstr "Webmestres"
-#: src/pyams_content/shared/common/interfaces/__init__.py:47
+#: src/pyams_content/shared/common/interfaces/__init__.py:46
msgid "Webmasters can handle all contents, including published ones"
msgstr ""
"Les webmestres peuvent modifier et gérer tous les contenus, y compris ceux "
"qui sont publiés et hormis ceux qui sont archivés"
-#: src/pyams_content/shared/common/interfaces/__init__.py:51
+#: src/pyams_content/shared/common/interfaces/__init__.py:50
msgid "Pilots"
msgstr "Pilotes"
-#: src/pyams_content/shared/common/interfaces/__init__.py:52
+#: src/pyams_content/shared/common/interfaces/__init__.py:51
msgid ""
"Pilots can handle tool configuration, manage access rules, grant users roles "
"and manage managers restrictions"
@@ -3081,13 +3139,13 @@
"et les contributeurs, et limitent si nécessaire l'intervention des "
"responsables à certains contenus"
-#: src/pyams_content/shared/common/interfaces/__init__.py:57
-#: src/pyams_content/shared/common/interfaces/__init__.py:191
+#: src/pyams_content/shared/common/interfaces/__init__.py:56
+#: src/pyams_content/shared/common/interfaces/__init__.py:196
msgid "Managers"
msgstr "Responsables"
-#: src/pyams_content/shared/common/interfaces/__init__.py:58
-#: src/pyams_content/shared/common/interfaces/__init__.py:192
+#: src/pyams_content/shared/common/interfaces/__init__.py:57
+#: src/pyams_content/shared/common/interfaces/__init__.py:197
msgid ""
"Managers can handle main operations in tool's workflow, like publish or "
"retire contents"
@@ -3096,38 +3154,38 @@
"(comme la publication ou le retrait des contenus), dans la limite des "
"restrictions qui leur sont imposées"
-#: src/pyams_content/shared/common/interfaces/__init__.py:63
-#: src/pyams_content/shared/common/interfaces/__init__.py:197
+#: src/pyams_content/shared/common/interfaces/__init__.py:62
+#: src/pyams_content/shared/common/interfaces/__init__.py:202
msgid "Contributors"
msgstr "Contributeurs"
-#: src/pyams_content/shared/common/interfaces/__init__.py:64
+#: src/pyams_content/shared/common/interfaces/__init__.py:63
msgid "Contributors are users which are allowed to create new contents"
msgstr "Les contributeurs sont autorisés à créer de nouveaux contenus"
-#: src/pyams_content/shared/common/interfaces/__init__.py:68
-#: src/pyams_content/shared/common/interfaces/__init__.py:203
+#: src/pyams_content/shared/common/interfaces/__init__.py:67
+#: src/pyams_content/shared/common/interfaces/__init__.py:208
msgid "Designers"
msgstr "Designers"
-#: src/pyams_content/shared/common/interfaces/__init__.py:69
-#: src/pyams_content/shared/common/interfaces/__init__.py:204
+#: src/pyams_content/shared/common/interfaces/__init__.py:68
+#: src/pyams_content/shared/common/interfaces/__init__.py:209
msgid "Designers are users which are allowed to manage presentation templates"
msgstr "Les designers sont autorisés à configurer les modèles de présentation"
-#: src/pyams_content/shared/common/interfaces/__init__.py:95
+#: src/pyams_content/shared/common/interfaces/__init__.py:94
msgid "Workflow name"
msgstr "Nom du workflow"
-#: src/pyams_content/shared/common/interfaces/__init__.py:96
+#: src/pyams_content/shared/common/interfaces/__init__.py:95
msgid "Name of workflow utility used to manage tool contents"
msgstr "Nom du workflow qui gère le cycle de vie des contenus de cet outil"
+#: src/pyams_content/shared/common/interfaces/__init__.py:123
+msgid "Content URL"
+msgstr "URL du contenu"
+
#: src/pyams_content/shared/common/interfaces/__init__.py:124
-msgid "Content URL"
-msgstr "URL du contenu"
-
-#: src/pyams_content/shared/common/interfaces/__init__.py:125
msgid ""
"URL used to access this content; this is important for SEO and should "
"include most important words describing content; spaces and underscores will "
@@ -3141,11 +3199,11 @@
"d'union, les lettres accentuées par leur équivalent sans accent, et les mots "
"de moins de trois lettres sont supprimés."
-#: src/pyams_content/shared/common/interfaces/__init__.py:130
+#: src/pyams_content/shared/common/interfaces/__init__.py:129
msgid "Version creator"
msgstr "À l'origine de cette version"
-#: src/pyams_content/shared/common/interfaces/__init__.py:131
+#: src/pyams_content/shared/common/interfaces/__init__.py:130
msgid ""
"Name of content's version creator. The creator of the first version is also "
"it's owner."
@@ -3153,74 +3211,84 @@
"Nom du créateur de cette version. Le créateur de la première version d'un "
"contenu est aussi son propriétaire."
-#: src/pyams_content/shared/common/interfaces/__init__.py:135
+#: src/pyams_content/shared/common/interfaces/__init__.py:134
msgid "First owner"
msgstr "Premier propriétaire"
-#: src/pyams_content/shared/common/interfaces/__init__.py:136
+#: src/pyams_content/shared/common/interfaces/__init__.py:135
msgid "Name of content's first version owner"
msgstr "Nom de l'utilisateur ayant créé la première version"
-#: src/pyams_content/shared/common/interfaces/__init__.py:140
+#: src/pyams_content/shared/common/interfaces/__init__.py:139
msgid "Version creation"
msgstr "Date de création"
-#: src/pyams_content/shared/common/interfaces/__init__.py:143
+#: src/pyams_content/shared/common/interfaces/__init__.py:142
msgid "Version modifiers"
msgstr "Intervenants"
-#: src/pyams_content/shared/common/interfaces/__init__.py:144
+#: src/pyams_content/shared/common/interfaces/__init__.py:143
msgid "List of principals who modified this content"
msgstr "Liste des utilisateurs qui sont intervenus sur cette version"
-#: src/pyams_content/shared/common/interfaces/__init__.py:147
+#: src/pyams_content/shared/common/interfaces/__init__.py:146
msgid "Last modifier"
msgstr "Dernier intervenant"
-#: src/pyams_content/shared/common/interfaces/__init__.py:148
+#: src/pyams_content/shared/common/interfaces/__init__.py:147
msgid "Last principal who modified this content"
msgstr "Dernier utilisateur étant intervenu sur ce contenu"
-#: src/pyams_content/shared/common/interfaces/__init__.py:151
+#: src/pyams_content/shared/common/interfaces/__init__.py:150
msgid "Last update"
msgstr "Dernière modification"
-#: src/pyams_content/shared/common/interfaces/__init__.py:155
+#: src/pyams_content/shared/common/interfaces/__init__.py:154
+msgid "Content's header is generally displayed in page header"
+msgstr "Le chapô du contenu est généralement affiché en tête de page"
+
+#: src/pyams_content/shared/common/interfaces/__init__.py:159
+msgid "Meta-description"
+msgstr "Méta-description"
+
+#: src/pyams_content/shared/common/interfaces/__init__.py:160
msgid ""
"The content's description is 'hidden' into HTML's page headers; but it can "
-"be seen, for example, in some search engines results as content's description"
+"be seen, for example, in some search engines results as content's "
+"description; if description is empty, content's header will be used."
msgstr ""
"La description du contenu est 'masquée' dans les en-têtes des pages HTML ; "
"mais on peut la retrouver, par exemple, dans les listes de résultats des "
-"moteurs de recherche"
-
-#: src/pyams_content/shared/common/interfaces/__init__.py:160
+"moteurs de recherche ; si la description n'est pas renseignée, le chapô "
+"(s'il existe pour ce contenu) sera utilisé."
+
+#: src/pyams_content/shared/common/interfaces/__init__.py:165
msgid "Keywords"
msgstr "Mots-clés"
-#: src/pyams_content/shared/common/interfaces/__init__.py:161
+#: src/pyams_content/shared/common/interfaces/__init__.py:166
msgid "They will be included into HTML pages metadata"
msgstr "Ces mots-clés seront intégrés dans les métadonnées des pages HTML"
-#: src/pyams_content/shared/common/interfaces/__init__.py:164
-#: src/pyams_content/shared/site/zmi/folder.py:78
-#: src/pyams_content/shared/site/interfaces/__init__.py:67
+#: src/pyams_content/shared/common/interfaces/__init__.py:169
+#: src/pyams_content/shared/site/zmi/folder.py:79
+#: src/pyams_content/shared/site/interfaces/__init__.py:76
msgid "Notepad"
msgstr "Bloc-notes"
-#: src/pyams_content/shared/common/interfaces/__init__.py:165
-#: src/pyams_content/shared/site/zmi/folder.py:79
-#: src/pyams_content/shared/site/interfaces/__init__.py:68
+#: src/pyams_content/shared/common/interfaces/__init__.py:170
+#: src/pyams_content/shared/site/zmi/folder.py:80
+#: src/pyams_content/shared/site/interfaces/__init__.py:77
msgid "Internal information to be known about this content"
msgstr ""
"Pour prendre note d'informations internes utiles ou importantes à propos de "
"ce contenu ; ces notes ne seront pas publiées sur internet."
-#: src/pyams_content/shared/common/interfaces/__init__.py:184
+#: src/pyams_content/shared/common/interfaces/__init__.py:189
msgid "Content owner"
msgstr "Propriétaire"
-#: src/pyams_content/shared/common/interfaces/__init__.py:185
+#: src/pyams_content/shared/common/interfaces/__init__.py:190
msgid ""
"The owner is the creator of content's first version, except if it was "
"transferred afterwards to another owner"
@@ -3229,7 +3297,7 @@
"lorsque cette propriété a été transférée à un autre utilisateur après coup. "
"Les contenus archivés ne sont plus transférables."
-#: src/pyams_content/shared/common/interfaces/__init__.py:198
+#: src/pyams_content/shared/common/interfaces/__init__.py:203
msgid ""
"Contributors are users which are allowed to update this content in addition "
"to it's owner"
@@ -3237,11 +3305,11 @@
"Les contributeurs sont autorisés, en plus du propriétaire, à modifier ce "
"contenu"
-#: src/pyams_content/shared/common/interfaces/__init__.py:208
+#: src/pyams_content/shared/common/interfaces/__init__.py:213
msgid "Readers"
msgstr "Relecteurs"
-#: src/pyams_content/shared/common/interfaces/__init__.py:209
+#: src/pyams_content/shared/common/interfaces/__init__.py:214
msgid ""
"Readers are users which are asked to verify and comment contents before they "
"are published"
@@ -3249,27 +3317,27 @@
"Les relecteurs sont des utilisateurs qui sont sollicités pour vérifier et "
"commenter un contenu avant sa publication"
-#: src/pyams_content/shared/common/interfaces/__init__.py:214
+#: src/pyams_content/shared/common/interfaces/__init__.py:219
msgid "Guests"
msgstr "Invités"
-#: src/pyams_content/shared/common/interfaces/__init__.py:215
+#: src/pyams_content/shared/common/interfaces/__init__.py:220
msgid ""
"Guests are users which are allowed to view contents with restricted access"
msgstr ""
"Les invités sont autorisés à consulter des contenus dont l'accès a été "
"restreint"
-#: src/pyams_content/shared/common/interfaces/__init__.py:235
+#: src/pyams_content/shared/common/interfaces/__init__.py:243
msgid "Principal ID"
msgstr "ID utilisateur"
-#: src/pyams_content/shared/common/interfaces/__init__.py:274
-#: src/pyams_content/shared/common/interfaces/__init__.py:299
+#: src/pyams_content/shared/common/interfaces/__init__.py:282
+#: src/pyams_content/shared/common/interfaces/__init__.py:307
msgid "Publication checks"
msgstr "Activer le tunnel de publication"
-#: src/pyams_content/shared/common/interfaces/__init__.py:275
+#: src/pyams_content/shared/common/interfaces/__init__.py:283
msgid ""
"If 'yes', this contributor will have to confirm that contents have been "
"previewed and checked before asking for publication"
@@ -3277,7 +3345,7 @@
"Si 'oui', ce contributeur devra confirmer qu'il a bien prévisualisé et "
"audité chaque contenu avant de pouvoir effectuer une demande de publication"
-#: src/pyams_content/shared/common/interfaces/__init__.py:300
+#: src/pyams_content/shared/common/interfaces/__init__.py:308
msgid ""
"If 'yes', this manager will have to confirm that contents have been "
"previewed and checked before publishing a content"
@@ -3285,11 +3353,11 @@
"Si 'oui', ce responsable devra confirmer qu'il a bien prévisualisé et audité "
"chaque contenu avant de pouvoir effectuer une publication"
-#: src/pyams_content/shared/common/interfaces/__init__.py:305
+#: src/pyams_content/shared/common/interfaces/__init__.py:313
msgid "Restricted contents"
msgstr "Accès restreints"
-#: src/pyams_content/shared/common/interfaces/__init__.py:306
+#: src/pyams_content/shared/common/interfaces/__init__.py:314
msgid ""
"If 'yes', this manager will get restricted access to manage contents based "
"on selected settings"
@@ -3297,21 +3365,21 @@
"Si 'oui', ce responsable n'aura qu'un accès restreint à certains contenus en "
"fonction de paramètres spécifiques"
-#: src/pyams_content/shared/common/interfaces/__init__.py:311
+#: src/pyams_content/shared/common/interfaces/__init__.py:319
msgid "Selected owners"
msgstr "Propriétaires"
-#: src/pyams_content/shared/common/interfaces/__init__.py:312
+#: src/pyams_content/shared/common/interfaces/__init__.py:320
msgid "Manager will have access to contents owned by these principals"
msgstr ""
"Le responsable n'aura accès qu'aux contenus dont ces utilisateurs sont "
"propriétaires"
-#: src/pyams_content/shared/form/__init__.py:99
+#: src/pyams_content/shared/form/__init__.py:97
msgid "Form fields"
msgstr "Champs de saisie"
-#: src/pyams_content/shared/form/__init__.py:100
+#: src/pyams_content/shared/form/__init__.py:98
msgid "no field defined"
msgstr "aucun champ défini"
@@ -3389,179 +3457,175 @@
msgid "Form fields..."
msgstr "Champs de saisie"
-#: src/pyams_content/shared/form/zmi/field.py:171
-#: src/pyams_content/shared/form/interfaces/__init__.py:57
+#: src/pyams_content/shared/form/zmi/field.py:178
+#: src/pyams_content/shared/form/interfaces/__init__.py:55
msgid "Field type"
msgstr "Type de champ"
-#: src/pyams_content/shared/form/zmi/field.py:204
+#: src/pyams_content/shared/form/zmi/field.py:211
msgid "Form fields list"
msgstr "Liste des champs du formulaire"
-#: src/pyams_content/shared/form/zmi/field.py:227
-#: src/pyams_content/shared/form/zmi/field.py:240
+#: src/pyams_content/shared/form/zmi/field.py:234
+#: src/pyams_content/shared/form/zmi/field.py:247
msgid "Add form field"
msgstr "Ajouter un champ"
-#: src/pyams_content/shared/form/zmi/field.py:278
+#: src/pyams_content/shared/form/zmi/field.py:285
msgid "Edit form field properties"
msgstr "Propriétés du champ"
-#: src/pyams_content/shared/form/zmi/field.py:180
+#: src/pyams_content/shared/form/zmi/field.py:187
msgid "-- unknown field type --"
msgstr "-- type de champ inconnu --"
-#: src/pyams_content/shared/form/zmi/field.py:115
+#: src/pyams_content/shared/form/zmi/field.py:122
msgid "No currently defined form field."
msgstr "Ce formulaire ne comporte aucun champ."
-#: src/pyams_content/shared/form/zmi/field.py:262
+#: src/pyams_content/shared/form/zmi/field.py:269
msgid "Specified name is already used!"
msgstr "Le nom indiqué pour ce champ est déjà utilisé !"
-#: src/pyams_content/shared/form/interfaces/__init__.py:35
+#: src/pyams_content/shared/form/interfaces/__init__.py:33
msgid "Form"
msgstr "Formulaire"
-#: src/pyams_content/shared/form/interfaces/__init__.py:53
+#: src/pyams_content/shared/form/interfaces/__init__.py:51
msgid "Field name"
msgstr "Nom du champ"
-#: src/pyams_content/shared/form/interfaces/__init__.py:54
+#: src/pyams_content/shared/form/interfaces/__init__.py:52
msgid "Field internal name; must be unique for a given form"
msgstr ""
"Nom interne du champ ; ce nom doit être unique pour un formulaire donné"
-#: src/pyams_content/shared/form/interfaces/__init__.py:58
+#: src/pyams_content/shared/form/interfaces/__init__.py:56
msgid "Selected field type"
msgstr "Type de champ proposé à l'internaute"
-#: src/pyams_content/shared/form/interfaces/__init__.py:63
+#: src/pyams_content/shared/form/interfaces/__init__.py:61
msgid "User field label"
msgstr "Libellé affiché à l'internaute"
-#: src/pyams_content/shared/form/interfaces/__init__.py:67
+#: src/pyams_content/shared/form/interfaces/__init__.py:65
msgid "Field description can be displayed as hint"
msgstr ""
"Description du champ, qui pourra être affichée sous la forme d'une info-bulle"
-#: src/pyams_content/shared/form/interfaces/__init__.py:70
+#: src/pyams_content/shared/form/interfaces/__init__.py:68
msgid "Placeholder"
msgstr "Espace réservé"
-#: src/pyams_content/shared/form/interfaces/__init__.py:71
+#: src/pyams_content/shared/form/interfaces/__init__.py:69
msgid "Some field types like textline can display a placeholder"
msgstr ""
"Certains champs tels que les zones de texte peuvent afficher ce texte tant "
"qu'aucune valeur n'y a été saisie"
-#: src/pyams_content/shared/form/interfaces/__init__.py:74
+#: src/pyams_content/shared/form/interfaces/__init__.py:72
msgid "Optional values"
msgstr "Liste de valeurs"
-#: src/pyams_content/shared/form/interfaces/__init__.py:75
+#: src/pyams_content/shared/form/interfaces/__init__.py:73
msgid "List of available values (for 'choice' and 'list' field types)"
msgstr ""
"Liste des valeurs disponibles (pour les champs de types 'Sélection simple' "
"ou 'Sélection multiple')"
-#: src/pyams_content/shared/form/interfaces/__init__.py:78
+#: src/pyams_content/shared/form/interfaces/__init__.py:76
msgid "Default value"
msgstr "Valeur par défaut"
-#: src/pyams_content/shared/form/interfaces/__init__.py:79
+#: src/pyams_content/shared/form/interfaces/__init__.py:77
msgid "Give default value if field type can use it"
msgstr ""
"Donner la valeur par défaut du champ ; attention, tous les types de champs "
"ne peuvent pas utiliser une valeur par défaut !"
-#: src/pyams_content/shared/form/interfaces/__init__.py:82
+#: src/pyams_content/shared/form/interfaces/__init__.py:80
msgid "Required?"
msgstr "Obligatoire ?"
-#: src/pyams_content/shared/form/interfaces/__init__.py:83
+#: src/pyams_content/shared/form/interfaces/__init__.py:81
msgid "Select 'yes' to set field as mandatory"
msgstr "Sélectionnez 'oui' pour que la saisie de ce champ soit obligatoire"
-#: src/pyams_content/shared/form/interfaces/__init__.py:88
+#: src/pyams_content/shared/form/interfaces/__init__.py:86
msgid "Select 'no' to hide given field..."
msgstr "Sélectionnez 'non' pour masquer ce champ"
-#: src/pyams_content/shared/form/interfaces/__init__.py:122
+#: src/pyams_content/shared/form/interfaces/__init__.py:120
msgid "Form title"
msgstr "Titre du formulaire"
-#: src/pyams_content/shared/form/interfaces/__init__.py:125
-msgid "Form header"
-msgstr "En-tête du formulaire"
-
-#: src/pyams_content/shared/form/interfaces/__init__.py:128
+#: src/pyams_content/shared/form/interfaces/__init__.py:123
msgid "Form handler"
msgstr "Gestionnaire du formulaire"
-#: src/pyams_content/shared/form/interfaces/__init__.py:129
+#: src/pyams_content/shared/form/interfaces/__init__.py:124
msgid "Select how form data is transmitted"
msgstr ""
"Le gestionnaire sélectionné détermine la façon dont les données saisies par "
"les internautes seront stockées ou envoyées"
-#: src/pyams_content/shared/form/interfaces/__init__.py:132
+#: src/pyams_content/shared/form/interfaces/__init__.py:127
msgid "Authenticated only?"
msgstr "Authentification requise ?"
-#: src/pyams_content/shared/form/interfaces/__init__.py:133
+#: src/pyams_content/shared/form/interfaces/__init__.py:128
msgid "If 'yes', only authenticated users will be able to see and submit form"
msgstr ""
"Si 'oui', seuls les utilisateurs authentifiés pourront saisir des données "
"dans le formulaire et les soumettre"
-#: src/pyams_content/shared/form/interfaces/__init__.py:137
+#: src/pyams_content/shared/form/interfaces/__init__.py:132
msgid "Use captcha?"
msgstr "Ajouter un captcha ?"
-#: src/pyams_content/shared/form/interfaces/__init__.py:138
+#: src/pyams_content/shared/form/interfaces/__init__.py:133
msgid "If 'yes', a captcha will be added automatically to the form"
msgstr "Si 'oui', un captcha sera ajouté automatiquement au formulaire"
-#: src/pyams_content/shared/form/interfaces/__init__.py:142
+#: src/pyams_content/shared/form/interfaces/__init__.py:137
msgid "Submit label"
msgstr "Libellé de soumission"
-#: src/pyams_content/shared/form/interfaces/__init__.py:143
+#: src/pyams_content/shared/form/interfaces/__init__.py:138
msgid "Label of form submit button"
msgstr "Libellé du bouton de soumission du formulaire"
-#: src/pyams_content/shared/form/interfaces/__init__.py:180
+#: src/pyams_content/shared/form/interfaces/__init__.py:175
msgid "Source address"
msgstr "Adresse source"
-#: src/pyams_content/shared/form/interfaces/__init__.py:181
+#: src/pyams_content/shared/form/interfaces/__init__.py:176
msgid "Mail address from which form data is sent"
msgstr "Adresse de messagerie émettrice des données"
-#: src/pyams_content/shared/form/interfaces/__init__.py:184
+#: src/pyams_content/shared/form/interfaces/__init__.py:179
msgid "Source name"
msgstr "Nom de la source"
-#: src/pyams_content/shared/form/interfaces/__init__.py:185
+#: src/pyams_content/shared/form/interfaces/__init__.py:180
msgid "Name of mail data sender"
msgstr "Nom de l'émetteur des données"
-#: src/pyams_content/shared/form/interfaces/__init__.py:188
+#: src/pyams_content/shared/form/interfaces/__init__.py:183
msgid "Recipient address"
msgstr "Adresse de destination"
-#: src/pyams_content/shared/form/interfaces/__init__.py:189
+#: src/pyams_content/shared/form/interfaces/__init__.py:184
msgid "Mail address to which form data is sent"
msgstr ""
"Adresse d'envoi des données; vous pouvez indiquer plusieurs adresses en les "
"séparant par des point-virgules"
-#: src/pyams_content/shared/form/interfaces/__init__.py:192
+#: src/pyams_content/shared/form/interfaces/__init__.py:187
msgid "Recipient name"
msgstr "Nom du destinataire"
-#: src/pyams_content/shared/form/interfaces/__init__.py:193
+#: src/pyams_content/shared/form/interfaces/__init__.py:188
msgid "Name of data recipient"
msgstr "Nom du destinataire des messages"
@@ -3625,7 +3689,7 @@
"Trier tous les résultats sur la date de première publication (du plus récent "
"au plus ancien)"
-#: src/pyams_content/shared/view/zmi/properties.py:40
+#: src/pyams_content/shared/view/zmi/properties.py:45
msgid "Main view settings"
msgstr "Paramètres de la vue"
@@ -3726,7 +3790,7 @@
"uniquement sur les paramètres de la vue."
#: src/pyams_content/shared/view/portlet/interfaces.py:91
-#: src/pyams_content/shared/view/interfaces/__init__.py:86
+#: src/pyams_content/shared/view/interfaces/__init__.py:102
msgid "Results count limit"
msgstr "Limite de résultats"
@@ -3745,152 +3809,174 @@
msgid "No selected view"
msgstr "Aucune vue sélectionnée."
-#: src/pyams_content/shared/view/interfaces/__init__.py:32
+#: src/pyams_content/shared/view/interfaces/__init__.py:34
msgid "View"
msgstr "Vue"
-#: src/pyams_content/shared/view/interfaces/__init__.py:150
+#: src/pyams_content/shared/view/interfaces/__init__.py:166
msgid "Always include selected internal references"
msgstr "Toujours inclure toutes les références internes"
-#: src/pyams_content/shared/view/interfaces/__init__.py:151
+#: src/pyams_content/shared/view/interfaces/__init__.py:167
msgid "Include selected internal references only if empty"
msgstr "Inclure les références internes seulement lorsque la vue est vide"
-#: src/pyams_content/shared/view/interfaces/__init__.py:41
+#: src/pyams_content/shared/view/interfaces/__init__.py:43
#: src/pyams_content/interfaces/__init__.py:113
#: src/pyams_content/features/review/interfaces.py:74
msgid "Creation date"
msgstr "Date de création"
-#: src/pyams_content/shared/view/interfaces/__init__.py:42
+#: src/pyams_content/shared/view/interfaces/__init__.py:44
msgid "Last update date"
msgstr "Date de dernière modification"
-#: src/pyams_content/shared/view/interfaces/__init__.py:43
+#: src/pyams_content/shared/view/interfaces/__init__.py:45
msgid "Current publication date"
msgstr "Date de publication de la version actuelle"
-#: src/pyams_content/shared/view/interfaces/__init__.py:44
+#: src/pyams_content/shared/view/interfaces/__init__.py:46
msgid "First publication date"
msgstr "Date de première publication"
-#: src/pyams_content/shared/view/interfaces/__init__.py:62
+#: src/pyams_content/shared/view/interfaces/__init__.py:64
msgid "Select context type?"
-msgstr "Type du contexte ?"
-
-#: src/pyams_content/shared/view/interfaces/__init__.py:63
+msgstr "Gabarit du contexte ?"
+
+#: src/pyams_content/shared/view/interfaces/__init__.py:65
msgid "If 'yes', content type will be extracted from context"
msgstr ""
-"Si 'oui', seuls des contenus du même type que le contexte seront "
+"Si 'oui', seuls des contenus du même gabarit que le contexte seront "
"automatiquement sélectionnés"
-#: src/pyams_content/shared/view/interfaces/__init__.py:67
+#: src/pyams_content/shared/view/interfaces/__init__.py:69
msgid "Other content types"
-msgstr "Autres types de contenus"
-
-#: src/pyams_content/shared/view/interfaces/__init__.py:68
+msgstr "Autres gabarits"
+
+#: src/pyams_content/shared/view/interfaces/__init__.py:70
msgid "Selected content types; leave empty for all"
msgstr ""
+"Autres gabarits sélectionnés ; si l'on n'extrait pas le gabarit du contexte "
+"et si cette sélection est vide, tous les gabarits seront pris en charge"
+
+#: src/pyams_content/shared/view/interfaces/__init__.py:77
+msgid "Select context data type?"
+msgstr "Type du contexte ?"
+
+#: src/pyams_content/shared/view/interfaces/__init__.py:78
+msgid ""
+"If 'yes', content data type (if available) will be extracted from context"
+msgstr ""
+"Si 'oui', et si le contexte de la vue est \"typé\", seuls des contenus du "
+"même type que le contexte seront automatiquement sélectionnés"
+
+#: src/pyams_content/shared/view/interfaces/__init__.py:83
+msgid "Other data types"
+msgstr "Autres types de contenus"
+
+#: src/pyams_content/shared/view/interfaces/__init__.py:84
+msgid "Selected data types; leave empty for all"
+msgstr ""
"Autres types de contenus sélectionnés ; si l'on n'extrait pas le type du "
-"contexte et si cette sélection est vide, tous les types seront pris en charge"
-
-#: src/pyams_content/shared/view/interfaces/__init__.py:75
+"contexte et si cette sélection est vide, tous les contenus (typés ou non) "
+"seront pris en charge"
+
+#: src/pyams_content/shared/view/interfaces/__init__.py:91
msgid "Order by"
msgstr "Ordre de tri"
-#: src/pyams_content/shared/view/interfaces/__init__.py:76
+#: src/pyams_content/shared/view/interfaces/__init__.py:92
msgid "Property to use to sort results"
msgstr ""
"Propriété utilisée pour trier les résultats ; par défaut, le tri se fait en "
"ordre inverse, donc du plus récent au plus ancien"
-#: src/pyams_content/shared/view/interfaces/__init__.py:81
+#: src/pyams_content/shared/view/interfaces/__init__.py:97
msgid "Reversed order?"
msgstr "Ordre inverse ?"
-#: src/pyams_content/shared/view/interfaces/__init__.py:82
+#: src/pyams_content/shared/view/interfaces/__init__.py:98
msgid "If 'yes', items order will be reversed"
msgstr ""
"Si 'non', le tri se fera en ordre \"naturel\", donc du plus ancien au plus "
"récent"
-#: src/pyams_content/shared/view/interfaces/__init__.py:87
+#: src/pyams_content/shared/view/interfaces/__init__.py:103
msgid "Maximum number of results that the view may retrieve"
msgstr "Nombre maximal de résultats que la vue doit renvoyer"
-#: src/pyams_content/shared/view/interfaces/__init__.py:160
+#: src/pyams_content/shared/view/interfaces/__init__.py:176
msgid "Internal references usage"
msgstr "Utilisation des références internes"
-#: src/pyams_content/shared/view/interfaces/__init__.py:161
+#: src/pyams_content/shared/view/interfaces/__init__.py:177
msgid "Specify how selected references are included into view results"
msgstr ""
"Indique comment les références internes indiquées seront intégrées à la "
"liste des résultats"
-#: src/pyams_content/shared/view/interfaces/__init__.py:166
+#: src/pyams_content/shared/view/interfaces/__init__.py:182
msgid "Exclude context?"
msgstr "Exclure le contexte ?"
-#: src/pyams_content/shared/view/interfaces/__init__.py:167
+#: src/pyams_content/shared/view/interfaces/__init__.py:183
msgid "If 'yes', context will be excluded from results list"
msgstr ""
"Si 'oui', le contexte d'application de la vue sera automatiquement exclus de "
"la liste des résultats"
-#: src/pyams_content/shared/view/interfaces/__init__.py:178
+#: src/pyams_content/shared/view/interfaces/__init__.py:194
msgid "Select context tags?"
msgstr "Tags du contexte ?"
-#: src/pyams_content/shared/view/interfaces/__init__.py:179
+#: src/pyams_content/shared/view/interfaces/__init__.py:195
msgid "If 'yes', tags will be extracted from context"
msgstr ""
"Si 'oui', les tags associés au contexte d'application de la vue seront "
"automatiquement sélectionnés"
-#: src/pyams_content/shared/view/interfaces/__init__.py:183
+#: src/pyams_content/shared/view/interfaces/__init__.py:199
msgid "Other tags"
msgstr "Autres tags"
-#: src/pyams_content/shared/view/interfaces/__init__.py:199
+#: src/pyams_content/shared/view/interfaces/__init__.py:215
msgid "Select context themes?"
msgstr "Thèmes du contexte ?"
-#: src/pyams_content/shared/view/interfaces/__init__.py:200
+#: src/pyams_content/shared/view/interfaces/__init__.py:216
msgid "If 'yes', themes will be extracted from context"
msgstr ""
"Si 'oui', les thèmes associés au contexte d'application de la vue seront "
"automatiquement sélectionnés"
-#: src/pyams_content/shared/view/interfaces/__init__.py:204
+#: src/pyams_content/shared/view/interfaces/__init__.py:220
msgid "Other themes"
msgstr "Autres thèmes"
-#: src/pyams_content/shared/view/interfaces/__init__.py:220
+#: src/pyams_content/shared/view/interfaces/__init__.py:236
msgid "Select context collections?"
msgstr "Collections du contexte ?"
-#: src/pyams_content/shared/view/interfaces/__init__.py:221
+#: src/pyams_content/shared/view/interfaces/__init__.py:237
msgid "If 'yes', collections will be extracted from context"
msgstr ""
"Si 'oui', les collections associées au contexte d'application de la vue "
"seront automatiquement sélectionnés"
-#: src/pyams_content/shared/view/interfaces/__init__.py:225
+#: src/pyams_content/shared/view/interfaces/__init__.py:241
msgid "Other collections"
msgstr "Autres collections"
-#: src/pyams_content/shared/imagemap/paragraph.py:99
+#: src/pyams_content/shared/imagemap/paragraph.py:88
msgid "no selected image map"
msgstr "aucune image cliquable sélectionnée"
-#: src/pyams_content/shared/imagemap/paragraph.py:105
+#: src/pyams_content/shared/imagemap/paragraph.py:94
#, python-format
msgid "image map '{0}' can't be found"
msgstr "l'image cliquable '{0}' est introuvable"
-#: src/pyams_content/shared/imagemap/paragraph.py:113
+#: src/pyams_content/shared/imagemap/paragraph.py:102
#, python-format
msgid "image map '{0}' is not published"
msgstr "l'image cliquable '{0}' n'est pas publiée"
@@ -3940,7 +4026,7 @@
#: src/pyams_content/shared/imagemap/zmi/container.py:65
#: src/pyams_content/shared/imagemap/interfaces/__init__.py:71
msgid "Image map areas"
-msgstr "Zones cliquables de l'images"
+msgstr "Zones cliquables de l'image"
#: src/pyams_content/shared/imagemap/zmi/container.py:140
#: src/pyams_content/shared/imagemap/interfaces/__init__.py:50
@@ -4010,7 +4096,7 @@
msgstr "Liste des zones cliquables définies sur l'image"
#: src/pyams_content/shared/imagemap/interfaces/__init__.py:96
-#: src/pyams_content/features/alert/interfaces.py:73
+#: src/pyams_content/features/alert/interfaces.py:69
#: src/pyams_content/features/menu/interfaces/__init__.py:68
msgid "Internal reference"
msgstr "Référence interne"
@@ -4025,7 +4111,7 @@
msgid "Image map template"
msgstr "Mode de rendu"
-#: src/pyams_content/shared/site/folder.py:59
+#: src/pyams_content/shared/site/folder.py:62
msgid "Site folder"
msgstr "Rubrique"
@@ -4038,39 +4124,43 @@
msgid "Site manager"
msgstr "Site"
-#: src/pyams_content/shared/site/zmi/folder.py:61
+#: src/pyams_content/shared/site/zmi/folder.py:62
msgid "Add site folder..."
msgstr "Ajouter une rubrique"
-#: src/pyams_content/shared/site/zmi/folder.py:93
+#: src/pyams_content/shared/site/zmi/folder.py:94
msgid "Add site folder"
msgstr "Ajout d'une rubrique"
-#: src/pyams_content/shared/site/zmi/folder.py:160
+#: src/pyams_content/shared/site/zmi/folder.py:161
msgid "Site folder management"
msgstr "Gérer cette rubrique"
-#: src/pyams_content/shared/site/zmi/folder.py:188
+#: src/pyams_content/shared/site/zmi/folder.py:190
msgid "Site folder properties"
msgstr "Propriétés de la rubrique"
-#: src/pyams_content/shared/site/zmi/folder.py:71
+#: src/pyams_content/shared/site/zmi/folder.py:208
+msgid "Navigation properties"
+msgstr "Propriétés de navigation"
+
+#: src/pyams_content/shared/site/zmi/folder.py:72
#: src/pyams_content/interfaces/__init__.py:102
msgid "Visible label used to display content"
msgstr "Le titre présenté aux internautes"
-#: src/pyams_content/shared/site/zmi/folder.py:74
+#: src/pyams_content/shared/site/zmi/folder.py:75
#: src/pyams_content/shared/site/zmi/__init__.py:72
-#: src/pyams_content/shared/site/zmi/link.py:66
+#: src/pyams_content/shared/site/zmi/link.py:65
msgid "Parent"
msgstr "Niveau parent"
-#: src/pyams_content/shared/site/zmi/folder.py:75
-#: src/pyams_content/shared/site/zmi/link.py:67
+#: src/pyams_content/shared/site/zmi/folder.py:76
+#: src/pyams_content/shared/site/zmi/link.py:66
msgid "Folder's parent"
msgstr "Niveau de rattachement de cette rubrique"
-#: src/pyams_content/shared/site/zmi/folder.py:153
+#: src/pyams_content/shared/site/zmi/folder.py:154
msgid "You must provide a folder name for default server language!"
msgstr ""
"Vous devez fournir un nom pour ce dossier pour la langue par défaut du "
@@ -4092,15 +4182,15 @@
msgid "Topic's parent"
msgstr "Niveau parent"
-#: src/pyams_content/shared/site/zmi/link.py:57
+#: src/pyams_content/shared/site/zmi/link.py:56
msgid "Rent content..."
msgstr "Lier un contenu"
-#: src/pyams_content/shared/site/zmi/link.py:77
+#: src/pyams_content/shared/site/zmi/link.py:76
msgid "Rent existing content"
msgstr "Lier un contenu existant"
-#: src/pyams_content/shared/site/zmi/link.py:135
+#: src/pyams_content/shared/site/zmi/link.py:134
msgid "Edit content link properties"
msgstr "Propriétés du lien"
@@ -4180,57 +4270,91 @@
msgid "A site manager is already registered with this name!!"
msgstr "Un site est déjà inscrit dans le registre avec ce nom !"
-#: src/pyams_content/shared/site/interfaces/__init__.py:96
+#: src/pyams_content/shared/site/interfaces/__init__.py:121
msgid "Topic"
msgstr "Article"
-#: src/pyams_content/shared/site/interfaces/__init__.py:59
+#: src/pyams_content/shared/site/interfaces/__init__.py:42
+msgid "Redirect to first visible sub-folder or content"
+msgstr "Re-diriger vers le premier contenu publié"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:43
+msgid "Use presentation template"
+msgstr "Afficher le modèle de présentation de la rubrique"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:72
msgid "Heading"
msgstr "Chapô"
-#: src/pyams_content/shared/site/interfaces/__init__.py:60
+#: src/pyams_content/shared/site/interfaces/__init__.py:73
msgid "Heading displayed according to presentation template"
msgstr ""
"Ce chapô pourra être affiché ou non en fonction du modèle de présentation "
"retenu"
-#: src/pyams_content/shared/site/interfaces/__init__.py:63
+#: src/pyams_content/shared/site/interfaces/__init__.py:80
+msgid "Visible in folders list"
+msgstr "Visible dans la liste des rubriques ?"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:81
+msgid "If 'no', folder will not be displayed into folders list"
+msgstr ""
+"Si 'non', cette rubrique ne sera pas affichée dans la liste des rubriques "
+"affichée par un composant de navigation"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:85
+#: src/pyams_content/shared/site/interfaces/__init__.py:139
msgid "Navigation title"
msgstr "Titre de navigation"
-#: src/pyams_content/shared/site/interfaces/__init__.py:64
-msgid "Title displayed in navigation items"
+#: src/pyams_content/shared/site/interfaces/__init__.py:86
+msgid ""
+"Folder's title displayed in navigation pages; original title will be used if "
+"none is specified"
msgstr ""
-"Libellé utilisé en lieu et place du titre dans les blocs de navigation, "
-"notamment dans les pages carrefours"
-
-#: src/pyams_content/shared/site/interfaces/__init__.py:115
-msgid "Content title, as shown in front-office"
-msgstr "Titre présenté aux internautes"
-
-#: src/pyams_content/shared/site/interfaces/__init__.py:119
+"Titre de substitution affiché dans les composants de navigation ; si rien "
+"n'est indiqué, le titre original de la rubrique sera utilisé"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:90
+msgid "Navigation mode"
+msgstr "Mode de navigation"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:91
+msgid "Folder behaviour when navigating to folder URL"
+msgstr "Comportement à adopter lorsqu'un internaute accède à cette rubrique"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:140
+msgid ""
+"Alternate content's title displayed in navigation pages; original title will "
+"be used if none is specified"
+msgstr ""
+"Titre de substitution affiché dans les composants de navigation ; si rien "
+"n'est indiqué, le titre original du contenu référencé sera utilisé"
+
+#: src/pyams_content/shared/site/interfaces/__init__.py:145
msgid "If 'no', link is not visible"
-msgstr "Si 'non', le lien ne sera pas visible"
-
-#: src/pyams_content/shared/logo/paragraph.py:96
+msgstr ""
+"Si 'non', le lien ne sera pas visible même si le contenu référencé est publié"
+
+#: src/pyams_content/shared/logo/paragraph.py:95
msgid "no selected logo"
msgstr "aucun logo sélectionné"
-#: src/pyams_content/shared/logo/paragraph.py:102
+#: src/pyams_content/shared/logo/paragraph.py:101
#, python-format
msgid "logo '{0}' can't be found"
msgstr "le logo '{0}' est introuvable"
-#: src/pyams_content/shared/logo/paragraph.py:110
+#: src/pyams_content/shared/logo/paragraph.py:109
#, python-format
msgid "logo '{0}' is not published"
msgstr "le logo '{0}' n'est pas publié"
-#: src/pyams_content/shared/logo/__init__.py:68
+#: src/pyams_content/shared/logo/__init__.py:69
msgid "no image defined"
msgstr "aucune image définie"
-#: src/pyams_content/shared/logo/__init__.py:71
+#: src/pyams_content/shared/logo/__init__.py:72
msgid "no URL defined"
msgstr "aucune URL définie"
@@ -4294,16 +4418,16 @@
msgid "Logos template"
msgstr "Mode de rendu"
-#: src/pyams_content/shared/blog/zmi/__init__.py:52
+#: src/pyams_content/shared/blog/zmi/__init__.py:53
msgid "This blog post"
msgstr "Cet article"
-#: src/pyams_content/shared/blog/zmi/__init__.py:71
-#: src/pyams_content/shared/blog/zmi/__init__.py:81
+#: src/pyams_content/shared/blog/zmi/__init__.py:72
+#: src/pyams_content/shared/blog/zmi/__init__.py:82
msgid "Add blog post"
msgstr "Ajouter un article"
-#: src/pyams_content/shared/blog/zmi/__init__.py:62
+#: src/pyams_content/shared/blog/zmi/__init__.py:63
#, python-format
msgid "Blog post « {title} »"
msgstr "Article de blog « {title} »"
@@ -4353,7 +4477,7 @@
msgid "Default length used for inner tables and dashboards"
msgstr "Longueur par défaut des tableaux internes et des tableaux de bord"
-#: src/pyams_content/root/__init__.py:68
+#: src/pyams_content/root/__init__.py:69
msgid "Site root"
msgstr "Racine du site"
@@ -4377,7 +4501,7 @@
msgid "Given element name doesn't exist!"
msgstr "Le nom de l'élément indiqué n'existe pas !"
-#: src/pyams_content/root/zmi/search.py:155
+#: src/pyams_content/root/zmi/search.py:160
msgid "Content types"
msgstr "Types de contenus"
@@ -4858,14 +4982,14 @@
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:70
+#: src/pyams_content/features/renderer/zmi/__init__.py:72
#: src/pyams_content/features/renderer/zmi/templates/renderer-input.pt:4
msgid "Edit renderer properties"
-msgstr "Propriétés du mode de rendu"
-
-#: src/pyams_content/features/renderer/skin/__init__.py:67
+msgstr "Propriétés de ce mode de rendu"
+
+#: src/pyams_content/features/renderer/skin/__init__.py:71
msgid "Hidden content"
-msgstr "Contenu non affiché"
+msgstr "NON affiché"
#: src/pyams_content/features/checker/interfaces.py:27
#, python-format
@@ -4888,7 +5012,7 @@
#: src/pyams_content/features/checker/zmi/__init__.py:82
msgid "No checker available. This content is clean!"
-msgstr "Pas de vérificateur disponible. Ce contenu est propre !"
+msgstr "Pas de vérificateur disponible pour ce contenu."
#: src/pyams_content/features/checker/zmi/__init__.py:78
#, python-format
@@ -4908,8 +5032,12 @@
msgid "preview"
msgstr "aperçu"
+#: src/pyams_content/features/alert/interfaces.py:39
+msgid "Alert"
+msgstr "Alerte"
+
#: src/pyams_content/features/alert/interfaces.py:40
-msgid "Success"
+msgid "End of alert"
msgstr "Levée d'alerte"
#: src/pyams_content/features/alert/interfaces.py:41
@@ -4921,8 +5049,8 @@
msgstr "Avertissement"
#: src/pyams_content/features/alert/interfaces.py:43
-msgid "Danger"
-msgstr "Danger !"
+msgid "Recommendation"
+msgstr "Recommandation"
#: src/pyams_content/features/alert/interfaces.py:55
msgid "Is this alert visible in front-office?"
@@ -4936,26 +5064,16 @@
msgid "Alert gravity will affect rendered alert style"
msgstr "Le niveau de gravité choisi affectera le style de rendu de l'alerte"
-#. Default: Heading
#: src/pyams_content/features/alert/interfaces.py:65
-#: src/pyams_content/features/alert/zmi/container.py:157
-msgid "alert-header"
-msgstr "En-tête"
+#: src/pyams_content/features/alert/zmi/container.py:145
+msgid "Message"
+msgstr "Message"
#: src/pyams_content/features/alert/interfaces.py:66
-msgid "Short alert header (Alert, Important...)"
-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:169
-msgid "Message"
-msgstr "Message"
+msgid "Alert message"
+msgstr "Le message d'alerte doit être assez court et explicite"
#: src/pyams_content/features/alert/interfaces.py:70
-msgid "Alert message"
-msgstr "Le message d'alerte doit être assez court et explicite"
-
-#: src/pyams_content/features/alert/interfaces.py:74
msgid ""
"Internal link target reference. You can search a reference using '+' "
"followed by internal number, of by entering text matching content title."
@@ -4964,31 +5082,31 @@
"mots de son titre, ou par son numéro interne (précédé d'un '+') ; le titre "
"d'origine peut être modifié en utilisant le titre de substitution."
-#: src/pyams_content/features/alert/interfaces.py:86
+#: src/pyams_content/features/alert/interfaces.py:75
msgid "Display start date"
msgstr "Date d'affichage"
-#: src/pyams_content/features/alert/interfaces.py:87
+#: src/pyams_content/features/alert/interfaces.py:76
msgid "First date at which alert should be displayed"
msgstr ""
"Première date à laquelle l'alerte sera affichée. Laissez la zone vide pour "
"qu'elle soit affichée immédiatement."
-#: src/pyams_content/features/alert/interfaces.py:90
+#: src/pyams_content/features/alert/interfaces.py:79
msgid "Display end date"
msgstr "Date de retrait"
-#: src/pyams_content/features/alert/interfaces.py:91
+#: src/pyams_content/features/alert/interfaces.py:80
msgid "Last date at which alert should be displayed"
msgstr ""
"Dernière date à laquelle l'alerte sera affichée. Laissez la zone vide pour "
"qu'elle ne soit pas retirée."
-#: src/pyams_content/features/alert/interfaces.py:94
+#: src/pyams_content/features/alert/interfaces.py:83
msgid "Maximum interval"
msgstr "Intervalle d'affichage"
-#: src/pyams_content/features/alert/interfaces.py:95
+#: src/pyams_content/features/alert/interfaces.py:84
msgid ""
"Maximum interval between alert displays on a given device, given in hours; "
"set to 0 to always display the alert"
@@ -5013,14 +5131,256 @@
msgid "Alerts"
msgstr "Alertes"
-#: src/pyams_content/features/alert/zmi/container.py:191
+#: src/pyams_content/features/alert/zmi/container.py:167
msgid "Alert list"
msgstr "Liste des alertes"
-#: src/pyams_content/features/alert/zmi/container.py:90
+#: src/pyams_content/features/alert/zmi/container.py:97
msgid "No currently defined alert."
msgstr "Aucune alerte n'est définie actuellement."
+#: src/pyams_content/features/redirect/container.py:81
+msgid "not matching"
+msgstr "pas de correspondance"
+
+#: src/pyams_content/features/redirect/zmi/__init__.py:50
+msgid "Add rule"
+msgstr "Ajouter une règle"
+
+#: src/pyams_content/features/redirect/zmi/__init__.py:63
+msgid "Add new redirection rule"
+msgstr "Ajout d'une règle de redirection"
+
+#: src/pyams_content/features/redirect/zmi/__init__.py:88
+msgid "Edit redirection rule properties"
+msgstr "Propriétés de la règle de redirection"
+
+#: src/pyams_content/features/redirect/zmi/__init__.py:109
+msgid ""
+"URL pattern and target URL are defined by *regular expressions* (see |"
+"regexp|).\n"
+" \n"
+"In URL pattern, you can use any valid regular expression element, notably:\n"
+"\n"
+"- « .* » to match any list of characters \n"
+"\n"
+"- « ( ) » to \"memorize\" parts of the URL which can be replaced into target "
+"URL\n"
+"\n"
+"- special characters (like \"+\") must be escaped with an « \\\\ ».\n"
+"\n"
+"In target URL, memorized parts can be reused using « \\\\1 », « \\\\2 » and "
+"so on, where given number is\n"
+"the order of the matching pattern element.\n"
+"\n"
+".. |regexp| raw:: html\n"
+"\n"
+" <a href=\"https://docs.python.org/3/library/re.html\" target=\"_blank"
+"\">Python Regular Expressions</a>\n"
+msgstr ""
+"Le schéma d'URL et l'URL cible sont définis en tant que « expressions "
+"rationelles » (voir |regexp|).\n"
+"\n"
+"Dans le schéma d'URL utilisé pour identifier les requêtes en entrée, vous "
+"pouvez utiliser tout élément d'une expression rationnelle valide, "
+"notamment :\n"
+"\n"
+"- « .* » pour rechercher n'importe quelle suite de caractères\n"
+"\n"
+"- « ^ » et « $ » pour identifier le début ou la fin de l'URL\n"
+"\n"
+"- « ( ) » pour \"mémoriser\" certains éléments de l'URL qui pourront être "
+"repris dans l'URL cible\n"
+"\n"
+"- les caractères spéciaux (comme les \"+\") doivent être protégés par un "
+"caractère « \\\\ ».\n"
+"\n"
+"For exemple : dans le schéma « ^/.*?oid=([a-z0-9]+)$ », toute URL contenant "
+"un paramètre \"oid\" composé de minuscules et/ou de chiffres sera mémorisé "
+"pour pouvoir être réutilisé dans l'URL cible.\n"
+"\n"
+"Dans l'URL cible, les éléments mémorisés peuvent être réutilisés en "
+"utilisant une expression comme « \\\\1 », « \\\\2 » (et ainsi de suite), le "
+"chiffre indiquant la position de l'élément dans la liste des éléments "
+"mémorisés.\n"
+"\n"
+".. |regexp| raw:: html\n"
+"\n"
+" <a href=\"https://docs.python.org/fr/3/library/re.html\" target=\"_blank"
+"\">Expressions rationnelles en Python</a>\n"
+
+#: src/pyams_content/features/redirect/zmi/container.py:67
+msgid "Redirections"
+msgstr "Redirections"
+
+#: src/pyams_content/features/redirect/zmi/container.py:161
+msgid "Enable/disable rule"
+msgstr "Activer/désactiver la règle"
+
+#: src/pyams_content/features/redirect/zmi/container.py:188
+msgid "Chain/unchain rule"
+msgstr "Enchaîner la règle avec la suivante"
+
+#: src/pyams_content/features/redirect/zmi/container.py:210
+#: src/pyams_content/features/redirect/zmi/container.py:366
+#: src/pyams_content/features/redirect/interfaces/__init__.py:56
+msgid "URL pattern"
+msgstr "Schéma d'URL"
+
+#: src/pyams_content/features/redirect/zmi/container.py:220
+msgid "Target"
+msgstr "Cible"
+
+#: src/pyams_content/features/redirect/zmi/container.py:246
+msgid "Redirections list"
+msgstr "Liste des règles de redirection"
+
+#: src/pyams_content/features/redirect/zmi/container.py:261
+msgid "Redirection rules"
+msgstr "Règles de redirection"
+
+#: src/pyams_content/features/redirect/zmi/container.py:262
+msgid ""
+"Redirection rules are use to handle redirections responses when a request "
+"generates \n"
+"a famous « 404 NotFound » error.\n"
+"\n"
+"Redirections are particularly useful when you are migrating from a previous "
+"site and don't want to lose \n"
+"your SEO.\n"
+"\n"
+"You can define a set of rules which will be applied to every \"NotFound\" "
+"request; rules are based on \n"
+"regular expressions which are applied to input URL: if the rule is \"matching"
+"\", the target URL is rewritten\n"
+"and a \"Redirect\" response is send.\n"
+"\n"
+"You can chain rules together: when a rule is chained, it's rewritten URL is "
+"passed as input URL to the \n"
+"next rule, until a matching rule is found.\n"
+msgstr ""
+"Les règles de redirection sont utilisées pour transmettre des réponses de "
+"redirection au lieu de la fameuse erreur « 404 - Page non trouvée ».\n"
+"\n"
+"La gestion des redirections est particulièrement importante en phase de "
+"migration d'un site web, pour éviter les liens cassés, ne pas perdre votre "
+"référencement et faciliter la mise à jour des moteurs de recherche.\n"
+"\n"
+"Vous pouvez définir un ensemble de règles qui seront appliquées dès lors "
+"qu'une requête adressée au serveur génère une erreur de page non trouvée ; "
+"les règles sont basées sur des expressions rationnelles que l'on applique à "
+"l'URL de la requête reçue : si la règle correspond, l'URL est réécrite et "
+"une réponse de redirection vers cette nouvelle URL est renvoyée.\n"
+"\n"
+"Vous pouvez également enchaîner les règles : lorsqu'une règle est \"chaînée"
+"\", la nouvelle URL qu'elle génère est passée aux règles suivantes, jusqu'à "
+"ce qu'une règle s'applique à cette nouvelle URL.\n"
+
+#: src/pyams_content/features/redirect/zmi/container.py:288
+msgid "Test"
+msgstr "Tester !"
+
+#: src/pyams_content/features/redirect/zmi/container.py:323
+msgid "Test redirection rules"
+msgstr "Test des règles de redirection"
+
+#: src/pyams_content/features/redirect/zmi/container.py:301
+msgid "Test URL"
+msgstr "URL à tester"
+
+#: src/pyams_content/features/redirect/zmi/container.py:304
+msgid "Check inactive rules?"
+msgstr "Tester les règles inactive ?"
+
+#: src/pyams_content/features/redirect/zmi/container.py:305
+msgid "If 'yes', inactive rules will also be tested"
+msgstr "Si 'oui', les règles inactives seront également testées"
+
+#: src/pyams_content/features/redirect/zmi/container.py:313
+msgid "Close"
+msgstr "Fermer"
+
+#: src/pyams_content/features/redirect/zmi/container.py:314
+msgid "Test rules"
+msgstr "Tester cette URL"
+
+#: src/pyams_content/features/redirect/zmi/container.py:123
+msgid "No currently defined redirection rule."
+msgstr "Aucune règle de redirection n'est définie actuellement."
+
+#: src/pyams_content/features/redirect/zmi/container.py:371
+msgid "No matching rule!"
+msgstr "Aucune règle ne correspond !"
+
+#: src/pyams_content/features/redirect/zmi/container.py:365
+msgid "Input URL"
+msgstr "URL en entrée"
+
+#: src/pyams_content/features/redirect/zmi/container.py:367
+msgid "Output URL"
+msgstr "URL générée"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:39
+msgid "Active rule?"
+msgstr "Règle active ?"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:40
+msgid "If 'no', selected rule is inactive"
+msgstr "Si 'non', la règle est inactive"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:44
+msgid "Chained rule?"
+msgstr "Règle chaînée ?"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:45
+msgid ""
+"If 'no', and if this rule is matching received request URL, the rule returns "
+"a redirection response; otherwise, the rule just rewrites the input URL "
+"which is forwarded to the next rule"
+msgstr ""
+"Si 'non', et si cette règle correspond à l'URL reçue en entrée, une réponde "
+"de redirection est renvoyée directement ; dans le cas contraire, l'URL "
+"générée par cette règle est passée en entrée de la règle suivante"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:51
+msgid "Permanent redirect?"
+msgstr "Redirection permanente ?"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:52
+msgid "Define if this redirection should be permanent or temporary"
+msgstr ""
+"Indique si cette redirection doit être considérée comme permanente ou "
+"temporaire"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:57
+msgid "Regexp pattern of matching URLs for this redirection rule"
+msgstr "Modèle de l'URL d'origine de cette règle de redirection"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:62
+msgid "Internal redirection target"
+msgstr "Redirection interne"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:63
+msgid ""
+"Internal redirection reference. You can search a reference using '+' "
+"followed by internal number, of by entering text matching content title."
+msgstr ""
+"Référence interne vers une cible de redirection. Vous pouvez la rechercher "
+"par des mots de son titre, ou par son numéro interne (précédé d'un '+')"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:69
+msgid "URL to which source URL should be redirected"
+msgstr "URL vers laquelle l'URL d'origine doit être redirigée"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:75
+msgid "You can only provide an internal reference OR a target URL"
+msgstr ""
+"Vous ne pouvez fournir qu'une référence interne OU une URL de redirection !"
+
+#: src/pyams_content/features/redirect/interfaces/__init__.py:77
+msgid "You must provide an internal reference OR a target URL"
+msgstr "Vous devez fournir une référence interne OU une URL de redirection !"
+
#: src/pyams_content/features/menu/zmi/__init__.py:81
msgid "Add menu..."
msgstr "Ajouter un menu"
@@ -5037,7 +5397,7 @@
msgid "Menu was correctly added."
msgstr "Le menu a été ajouté."
-#: src/pyams_content/features/menu/zmi/__init__.py:388
+#: src/pyams_content/features/menu/zmi/__init__.py:395
msgid "Link was correctly added."
msgstr "Le lien a été ajouté."
@@ -5045,11 +5405,11 @@
msgid "Click to see menu items"
msgstr "Montrer ou cacher les éléments du menu"
-#: src/pyams_content/features/menu/portlet/navigation/simple.py:68
+#: src/pyams_content/features/menu/portlet/navigation/simple.py:67
msgid "Simple navigation"
msgstr "Navigation à un niveau"
-#: src/pyams_content/features/menu/portlet/navigation/double.py:68
+#: src/pyams_content/features/menu/portlet/navigation/double.py:67
msgid "Double navigation"
msgstr "Navigation à deux niveaux"
@@ -5061,8 +5421,8 @@
msgid "Navigation menus"
msgstr "Menus de navigation"
-#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:15
-#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:12
+#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:14
+#: src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:11
msgid "Link has no illustration"
msgstr "Le lien n'a pas d'illustration"
@@ -5071,16 +5431,6 @@
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:64
msgid "Menu title"
msgstr "Libellé"
@@ -5115,13 +5465,13 @@
#: src/pyams_content/features/footer/zmi/__init__.py:220
msgid "Footer renderer settings"
-msgstr "Propriétés du mode de rendu"
+msgstr "Propriétés de ce mode de rendu"
#: src/pyams_content/features/footer/zmi/__init__.py:107
msgid "Don't inherit parent footer"
msgstr "Ne pas hériter du pied de pages du parent"
-#: src/pyams_content/features/footer/skin/__init__.py:84
+#: src/pyams_content/features/footer/skin/__init__.py:94
msgid "Hidden footer"
msgstr "Ne pas afficher de pied de pages"
@@ -5347,16 +5697,69 @@
#: src/pyams_content/features/header/zmi/__init__.py:229
msgid "Header renderer settings"
-msgstr "Propriétés du mode de rendu"
+msgstr "Propriétés de ce mode de rendu"
#: src/pyams_content/features/header/zmi/__init__.py:113
msgid "Don't inherit parent header"
msgstr "Ne pas hériter de l'en-tête de pages du parent"
-#: src/pyams_content/features/header/skin/__init__.py:90
+#: src/pyams_content/features/header/skin/__init__.py:100
msgid "Hidden header"
msgstr "Ne pas afficher d'en-tête de pages"
+#~ msgid "Form header"
+#~ msgstr "En-tête du formulaire"
+
+#~ msgid "Title displayed in navigation items"
+#~ msgstr ""
+#~ "Libellé utilisé en lieu et place du titre dans les blocs de navigation, "
+#~ "notamment dans les pages carrefours"
+
+#~ msgid "Content title, as shown in front-office"
+#~ msgstr "Titre présenté aux internautes"
+
+#~ msgid "Success"
+#~ msgstr "Levée d'alerte"
+
+#~ msgid "Danger"
+#~ msgstr "Danger !"
+
+#~ msgid "alert-header"
+#~ msgstr "En-tête"
+
+#~ msgid "Short alert header (Alert, Important...)"
+#~ msgstr "En-tête de l'alerte (« Alerte », « Important », « Prudence »...)"
+
+#~ msgid "Header..."
+#~ msgstr "Chapô"
+
+#~ msgid "Add new header paragraph"
+#~ msgstr "Ajout d'un chapô"
+
+#~ msgid "Your favorites"
+#~ msgstr "Mes favoris"
+
+#~ msgid "Rewrite to another internal reference or URL"
+#~ msgstr "Rediriger vers une autre référence ou URL interne"
+
+#~ msgid "Redirect to another external URL"
+#~ msgstr "Rediriger vers une URL externe"
+
+#~ msgid "Return content in proxy mode without redirection"
+#~ msgstr "Charger le contenu ciblé sans redirection"
+
+#~ msgid "Redirect mode"
+#~ msgstr "Mode de redirection"
+
+#~ msgid "Mode of redirection for this URL pattern"
+#~ msgstr "Mode de redirection utilisé par cette règle"
+
+#~ msgid "Subtitle"
+#~ msgstr "Sous-titre"
+
+#~ msgid "Portlet subtitle"
+#~ msgstr "Sous-titre du composant"
+
#~ msgid "Image associated to this data type"
#~ msgstr "Image associée à ce type"
@@ -5651,9 +6054,6 @@
#~ msgid "Visible gallery?"
#~ msgstr "Galerie visible ?"
-#~ msgid "If 'no', this gallery won't be displayed in front office"
-#~ msgstr "Si 'non', cette galerie ne sera pas affichée en front-office"
-
#~ msgid "Contained galleries"
#~ msgstr "Galeries d'images"
--- a/src/pyams_content/locales/pyams_content.pot Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/locales/pyams_content.pot Thu Sep 06 11:27:55 2018 +0200
@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-07-17 14:54+0200\n"
+"POT-Creation-Date: 2018-09-06 08:55+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"
@@ -164,15 +164,15 @@
msgid "Comments relatives to author's rights management"
msgstr ""
-#: ./src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:11
+#: ./src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:12
msgid "Gallery medias"
msgstr ""
-#: ./src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:17
+#: ./src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:18
msgid "Download medias"
msgstr ""
-#: ./src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:41
+#: ./src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt:42
msgid "Zoom image"
msgstr ""
@@ -213,13 +213,9 @@
#: ./src/pyams_content/component/gallery/interfaces/__init__.py:58
#: ./src/pyams_content/component/gallery/interfaces/__init__.py:101
#: ./src/pyams_content/component/extfile/interfaces/__init__.py:40
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:64
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:48
#: ./src/pyams_content/component/paragraph/interfaces/audio.py:48
#: ./src/pyams_content/component/links/interfaces/__init__.py:39
-#: ./src/pyams_content/component/video/interfaces/__init__.py:48
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:154
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:66
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:64
msgid "Description"
msgstr ""
@@ -271,16 +267,16 @@
#: ./src/pyams_content/component/gallery/interfaces/__init__.py:97
#: ./src/pyams_content/component/keynumber/portlet/interfaces/__init__.py:31
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:232
-#: ./src/pyams_content/component/paragraph/zmi/container.py:252
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:239
+#: ./src/pyams_content/component/paragraph/zmi/container.py:270
#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:45
-#: ./src/pyams_content/component/links/zmi/reverse.py:73
+#: ./src/pyams_content/shared/common/zmi/reverse.py:73
#: ./src/pyams_content/shared/common/zmi/dashboard.py:109
-#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:188
+#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:200
#: ./src/pyams_content/shared/view/portlet/interfaces.py:56
#: ./src/pyams_content/shared/imagemap/zmi/container.py:123
-#: ./src/pyams_content/shared/site/zmi/folder.py:70
-#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:188
+#: ./src/pyams_content/shared/site/zmi/folder.py:71
+#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:197
#: ./src/pyams_content/interfaces/__init__.py:101
#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:150
#: ./src/pyams_content/features/menu/portlet/navigation/interfaces/simple.py:31
@@ -398,7 +394,6 @@
#: ./src/pyams_content/component/extfile/interfaces/__init__.py:36
#: ./src/pyams_content/component/links/interfaces/__init__.py:35
#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:55
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:114
msgid "Alternate title"
msgstr ""
@@ -407,9 +402,7 @@
msgstr ""
#: ./src/pyams_content/component/extfile/interfaces/__init__.py:41
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:49
#: ./src/pyams_content/component/paragraph/interfaces/audio.py:49
-#: ./src/pyams_content/component/video/interfaces/__init__.py:49
msgid "File description displayed by front-office template"
msgstr ""
@@ -462,49 +455,64 @@
msgstr ""
#: ./src/pyams_content/component/keynumber/__init__.py:189
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:199
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:212
#: ./src/pyams_content/component/keynumber/portlet/zmi/__init__.py:74
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:29
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:83
msgid "Key numbers"
msgstr ""
+#: ./src/pyams_content/component/keynumber/zmi/paragraph.py:53
+msgid "Key numbers..."
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/paragraph.py:66
+msgid "Add new key number paragraph"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/zmi/paragraph.py:94
+msgid "Edit key number paragraph properties"
+msgstr ""
+
#. Default: Header
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:147
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:44
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:160
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:45
msgid "key-number-label"
msgstr ""
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:159
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:49
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:172
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:50
msgid "Number"
msgstr ""
#. Default: Unit
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:168
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:53
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:181
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:54
msgid "key-number-unit"
msgstr ""
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:180
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:57
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:268
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:193
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:58
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:64
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:277
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:48
#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:58
+#: ./src/pyams_content/component/video/interfaces/__init__.py:48
msgid "Associated text"
msgstr ""
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:218
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:231
msgid "Add keynumber"
msgstr ""
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:230
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:243
msgid "Add new keynumber"
msgstr ""
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:259
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:272
msgid "Edit keynumber properties"
msgstr ""
-#: ./src/pyams_content/component/keynumber/zmi/__init__.py:245
+#: ./src/pyams_content/component/keynumber/zmi/__init__.py:258
msgid "Key number was correctly added"
msgstr ""
@@ -518,8 +526,8 @@
msgstr ""
#: ./src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt:31
-#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:11
-#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:8
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:10
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:7
msgid "Link target is not published!"
msgstr ""
@@ -535,44 +543,52 @@
msgid "Short text displayed above key numbers"
msgstr ""
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:39
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:40
#: ./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:118
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:85
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:144
#: ./src/pyams_content/features/alert/interfaces.py:54
#: ./src/pyams_content/features/menu/interfaces/__init__.py:59
msgid "Visible?"
msgstr ""
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:40
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:41
msgid "Is this key number visible in front-office?"
msgstr ""
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:45
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:46
msgid ""
"Small text to be displayed above number (according to selected renderer)"
msgstr ""
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:50
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:51
msgid "Key number value"
msgstr ""
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:54
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:55
msgid "Displayed unit"
msgstr ""
-#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:58
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:59
msgid "The way this text will be rendered depends on presentation template"
msgstr ""
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:94
+msgid "Key numbers template"
+msgstr ""
+
+#: ./src/pyams_content/component/keynumber/interfaces/__init__.py:95
+msgid "Presentation template used for key numbers"
+msgstr ""
+
#: ./src/pyams_content/component/illustration/__init__.py:177
#: ./src/pyams_content/component/illustration/thesaurus.py:32
#: ./src/pyams_content/component/illustration/zmi/paragraph.py:158
#: ./src/pyams_content/component/illustration/zmi/__init__.py:56
-#: ./src/pyams_content/component/illustration/zmi/__init__.py:100
+#: ./src/pyams_content/component/illustration/zmi/__init__.py:117
#: ./src/pyams_content/component/illustration/interfaces/__init__.py:99
msgid "Illustration"
msgstr ""
@@ -590,11 +606,11 @@
msgid "Edit illustration properties"
msgstr ""
-#: ./src/pyams_content/component/illustration/zmi/__init__.py:150
+#: ./src/pyams_content/component/illustration/zmi/__init__.py:151
msgid "Navigation link illustration"
msgstr ""
-#: ./src/pyams_content/component/illustration/zmi/__init__.py:102
+#: ./src/pyams_content/component/illustration/zmi/__init__.py:119
msgid "Header illustration"
msgstr ""
@@ -603,6 +619,10 @@
msgid "Alternate title used to describe image content"
msgstr ""
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:65
+msgid "Illustration description displayed in front-office templates"
+msgstr ""
+
#: ./src/pyams_content/component/illustration/interfaces/__init__.py:69
msgid "Name of picture's author"
msgstr ""
@@ -623,11 +643,11 @@
msgid "Selected paragraph is not visible"
msgstr ""
-#: ./src/pyams_content/component/paragraph/container.py:73
+#: ./src/pyams_content/component/paragraph/container.py:90
msgid "Paragraphs"
msgstr ""
-#: ./src/pyams_content/component/paragraph/container.py:95
+#: ./src/pyams_content/component/paragraph/container.py:112
msgid "no visible paragraph"
msgstr ""
@@ -635,6 +655,10 @@
msgid "Selected pictogram is missing"
msgstr ""
+#: ./src/pyams_content/component/paragraph/header.py:62
+msgid "This paragraph type is deprecated and should be removed!"
+msgstr ""
+
#: ./src/pyams_content/component/paragraph/zmi/milestone.py:78
msgid "Milestones..."
msgstr ""
@@ -647,38 +671,38 @@
msgid "Edit milestone paragraph properties"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:244
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:251
#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:49
msgid "Associated label"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:256
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:263
#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:53
msgid "Anchor"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:285
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:292
#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:76
msgid "Milestones"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:300
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:307
msgid "Add milestone"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:313
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:320
msgid "Add new milestone"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:340
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:347
msgid "Edit milestone properties"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:328
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:335
msgid "Milestone was correctly added"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:271
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:278
msgid "(missing paragraph)"
msgstr ""
@@ -744,6 +768,24 @@
msgid "Paragraph was correctly added."
msgstr ""
+#: ./src/pyams_content/component/paragraph/zmi/__init__.py:254
+msgid ""
+"You changed renderer selection. Don't omit to update new renderer "
+"properties..."
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/zmi/map.py:55
+msgid "Location map..."
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/zmi/map.py:68
+msgid "Add new location map"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/zmi/map.py:91
+msgid "Edit location map properties"
+msgstr ""
+
#: ./src/pyams_content/component/paragraph/zmi/video.py:54
msgid "Video paragraph..."
msgstr ""
@@ -761,41 +803,41 @@
msgid "Contents..."
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:196
+#: ./src/pyams_content/component/paragraph/zmi/container.py:215
msgid "Set navigation anchor"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:268
+#: ./src/pyams_content/component/paragraph/zmi/container.py:286
msgid "Show/hide all paragraphs"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:316
-#: ./src/pyams_content/component/paragraph/zmi/container.py:325
-#: ./src/pyams_content/component/paragraph/zmi/container.py:338
+#: ./src/pyams_content/component/paragraph/zmi/container.py:334
+#: ./src/pyams_content/component/paragraph/zmi/container.py:343
+#: ./src/pyams_content/component/paragraph/zmi/container.py:356
msgid "Content blocks"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:395
+#: ./src/pyams_content/component/paragraph/zmi/container.py:413
msgid "Links and attachments..."
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:407
+#: ./src/pyams_content/component/paragraph/zmi/container.py:425
msgid "Content blocks links and attachments"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:127
+#: ./src/pyams_content/component/paragraph/zmi/container.py:145
msgid "No currently defined paragraph."
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:277
+#: ./src/pyams_content/component/paragraph/zmi/container.py:295
msgid "Click to open/close all paragraphs editors"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/container.py:290
+#: ./src/pyams_content/component/paragraph/zmi/container.py:308
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:151
msgid "Check allowed paragraph types to be able to create new paragraphs."
msgstr ""
@@ -812,36 +854,36 @@
msgstr ""
#. Default: Header
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:253
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:260
msgid "pictogram-item-header"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:290
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:299
#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:80
msgid "Pictograms"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:305
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:314
#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:59
msgid "Add pictogram"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:318
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:327
#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:71
msgid "Add new pictogram"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:360
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:369
#: ./src/pyams_content/reference/pictograms/zmi/__init__.py:95
msgid "Edit pictogram properties"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:340
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:349
msgid "Pictogram was correctly added"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:350
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:388
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:359
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:397
msgid "You must select a pictogram!"
msgstr ""
@@ -857,27 +899,15 @@
msgid "Edit audio properties"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:55
-msgid "Key numbers..."
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:68
-msgid "Add new key number paragraph"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:96
-msgid "Edit key number paragraph properties"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/frame.py:85
+#: ./src/pyams_content/component/paragraph/zmi/frame.py:86
msgid "Framed text..."
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/frame.py:99
+#: ./src/pyams_content/component/paragraph/zmi/frame.py:100
msgid "Add new framed text paragraph"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/frame.py:125
+#: ./src/pyams_content/component/paragraph/zmi/frame.py:126
msgid "Edit framed text paragraph properties"
msgstr ""
@@ -929,15 +959,7 @@
msgid "Edit contact card properties"
msgstr ""
-#: ./src/pyams_content/component/paragraph/zmi/header.py:50
-msgid "Header..."
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/header.py:63
-msgid "Add new header paragraph"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/zmi/header.py:90
+#: ./src/pyams_content/component/paragraph/zmi/header.py:49
msgid "Edit header paragraph properties"
msgstr ""
@@ -1004,28 +1026,62 @@
msgid "§ Title"
msgstr ""
-#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:88
+#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:94
msgid "Allowed paragraphs"
msgstr ""
-#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:89
+#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:95
msgid "List of paragraphs allowed for this content type"
msgstr ""
-#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:93
-#: ./src/pyams_content/shared/common/zmi/types.py:173
-#: ./src/pyams_content/shared/common/zmi/types.py:413
+#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:99
+#: ./src/pyams_content/shared/common/zmi/types.py:172
+#: ./src/pyams_content/shared/common/zmi/types.py:412
msgid "Default paragraphs"
msgstr ""
-#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:94
+#: ./src/pyams_content/component/paragraph/interfaces/__init__.py:100
msgid "List of paragraphs automatically added to a new content"
msgstr ""
+#: ./src/pyams_content/component/paragraph/interfaces/map.py:41
+msgid "Location map"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/map.py:48
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:72
+msgid "GPS location"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/map.py:49
+msgid "GPS coordinates used to locate map"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/map.py:52
+msgid "Display location mark?"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/map.py:53
+msgid "If 'yes', a location marker will be displayed on map"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/map.py:57
+msgid "Map template"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/map.py:58
+msgid "Presentation template used for this map"
+msgstr ""
+
#: ./src/pyams_content/component/paragraph/interfaces/video.py:42
msgid "Video file content"
msgstr ""
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:49
+#: ./src/pyams_content/component/video/interfaces/__init__.py:49
+msgid "Video description displayed by front-office template"
+msgstr ""
+
#: ./src/pyams_content/component/paragraph/interfaces/video.py:56
#: ./src/pyams_content/component/video/interfaces/__init__.py:78
msgid "Video template"
@@ -1043,12 +1099,10 @@
#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:46
#: ./src/pyams_content/component/links/interfaces/__init__.py:43
#: ./src/pyams_content/shared/common/interfaces/types.py:75
-#: ./src/pyams_content/features/alert/interfaces.py:79
msgid "Pictogram"
msgstr ""
#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:47
-#: ./src/pyams_content/features/alert/interfaces.py:80
msgid "Name of the pictogram to select"
msgstr ""
@@ -1086,14 +1140,6 @@
msgid "Presentation template used for this audio file"
msgstr ""
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:36
-msgid "Key numbers template"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:37
-msgid "Presentation template used for key numbers"
-msgstr ""
-
#: ./src/pyams_content/component/paragraph/interfaces/frame.py:33
msgid "Framed text"
msgstr ""
@@ -1217,16 +1263,13 @@
msgid "Presentation template used for this contact"
msgstr ""
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:72
-msgid "GPS location"
-msgstr ""
-
#: ./src/pyams_content/component/paragraph/interfaces/contact.py:73
msgid "GPS coordinates used to locate contact"
msgstr ""
#: ./src/pyams_content/component/paragraph/interfaces/header.py:33
#: ./src/pyams_content/component/paragraph/interfaces/header.py:40
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:153
msgid "Header"
msgstr ""
@@ -1244,6 +1287,9 @@
#: ./src/pyams_content/component/theme/zmi/portlet.py:40
#: ./src/pyams_content/component/theme/interfaces/__init__.py:47
#: ./src/pyams_content/component/theme/interfaces/__init__.py:61
+#: ./src/pyams_content/shared/common/zmi/search.py:189
+#: ./src/pyams_content/root/zmi/search.py:179
+#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:181
msgid "Tags"
msgstr ""
@@ -1251,6 +1297,7 @@
#: ./src/pyams_content/component/theme/zmi/portlet.py:55
#: ./src/pyams_content/component/theme/interfaces/__init__.py:88
#: ./src/pyams_content/component/theme/interfaces/__init__.py:102
+#: ./src/pyams_content/shared/common/zmi/search.py:192
msgid "Themes"
msgstr ""
@@ -1258,6 +1305,7 @@
#: ./src/pyams_content/component/theme/zmi/portlet.py:70
#: ./src/pyams_content/component/theme/interfaces/__init__.py:129
#: ./src/pyams_content/component/theme/interfaces/__init__.py:143
+#: ./src/pyams_content/shared/common/zmi/search.py:195
msgid "Collections"
msgstr ""
@@ -1300,32 +1348,32 @@
msgid "Content collections"
msgstr ""
-#: ./src/pyams_content/component/theme/zmi/manager.py:51
+#: ./src/pyams_content/component/theme/zmi/manager.py:58
msgid "Tags settings..."
msgstr ""
-#: ./src/pyams_content/component/theme/zmi/manager.py:65
+#: ./src/pyams_content/component/theme/zmi/manager.py:72
msgid "Selected tags"
msgstr ""
-#: ./src/pyams_content/component/theme/zmi/manager.py:101
+#: ./src/pyams_content/component/theme/zmi/manager.py:108
msgid "Themes settings..."
msgstr ""
-#: ./src/pyams_content/component/theme/zmi/manager.py:115
+#: ./src/pyams_content/component/theme/zmi/manager.py:122
msgid "Selected themes"
msgstr ""
-#: ./src/pyams_content/component/theme/zmi/manager.py:151
+#: ./src/pyams_content/component/theme/zmi/manager.py:158
msgid "Collections settings..."
msgstr ""
-#: ./src/pyams_content/component/theme/zmi/manager.py:165
+#: ./src/pyams_content/component/theme/zmi/manager.py:172
msgid "Selected collections"
msgstr ""
#: ./src/pyams_content/component/association/container.py:91
-#: ./src/pyams_content/component/association/zmi/__init__.py:296
+#: ./src/pyams_content/component/association/zmi/__init__.py:303
#: ./src/pyams_content/component/association/interfaces/__init__.py:93
msgid "Associations"
msgstr ""
@@ -1343,20 +1391,20 @@
msgid "Edit association paragraph properties"
msgstr ""
-#: ./src/pyams_content/component/association/zmi/__init__.py:198
+#: ./src/pyams_content/component/association/zmi/__init__.py:205
msgid "Public title"
msgstr ""
-#: ./src/pyams_content/component/association/zmi/__init__.py:216
+#: ./src/pyams_content/component/association/zmi/__init__.py:223
msgid "Inner title"
msgstr ""
-#: ./src/pyams_content/component/association/zmi/__init__.py:232
+#: ./src/pyams_content/component/association/zmi/__init__.py:239
msgid "Size"
msgstr ""
-#: ./src/pyams_content/component/association/zmi/__init__.py:273
-#: ./src/pyams_content/component/association/zmi/__init__.py:283
+#: ./src/pyams_content/component/association/zmi/__init__.py:280
+#: ./src/pyams_content/component/association/zmi/__init__.py:290
msgid "Associations list"
msgstr ""
@@ -1377,19 +1425,19 @@
msgid "Presentation template used for associations"
msgstr ""
-#: ./src/pyams_content/component/links/__init__.py:123
+#: ./src/pyams_content/component/links/__init__.py:144
msgid "Internal link"
msgstr ""
-#: ./src/pyams_content/component/links/__init__.py:219
+#: ./src/pyams_content/component/links/__init__.py:230
msgid "External link"
msgstr ""
-#: ./src/pyams_content/component/links/__init__.py:272
+#: ./src/pyams_content/component/links/__init__.py:283
msgid "Mailto link"
msgstr ""
-#: ./src/pyams_content/component/links/__init__.py:206
+#: ./src/pyams_content/component/links/__init__.py:217
msgid "target is not published"
msgstr ""
@@ -1441,14 +1489,6 @@
msgid "Edit mailto link properties"
msgstr ""
-#: ./src/pyams_content/component/links/zmi/reverse.py:57
-msgid "Reverse links"
-msgstr ""
-
-#: ./src/pyams_content/component/links/zmi/reverse.py:66
-msgid "Content's internal links"
-msgstr ""
-
#: ./src/pyams_content/component/links/interfaces/__init__.py:36
msgid "Link title, as shown in front-office"
msgstr ""
@@ -1463,6 +1503,7 @@
#: ./src/pyams_content/component/links/interfaces/__init__.py:61
#: ./src/pyams_content/shared/logo/interfaces/__init__.py:56
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:68
msgid "Target URL"
msgstr ""
@@ -1761,145 +1802,149 @@
msgid "Name of external platform providing selected video"
msgstr ""
-#: ./src/pyams_content/shared/common/__init__.py:240
-#: ./src/pyams_content/shared/common/zmi/properties.py:70
+#: ./src/pyams_content/shared/common/__init__.py:242
+#: ./src/pyams_content/shared/common/zmi/properties.py:69
#: ./src/pyams_content/shared/common/zmi/manager.py:96
msgid "Properties"
msgstr ""
-#: ./src/pyams_content/shared/common/__init__.py:150
-#: ./src/pyams_content/shared/common/__init__.py:158
+#: ./src/pyams_content/shared/common/__init__.py:152
+#: ./src/pyams_content/shared/common/__init__.py:160
#, python-format
msgid "{date} by {principal}"
msgstr ""
-#: ./src/pyams_content/shared/common/__init__.py:263
+#: ./src/pyams_content/shared/common/__init__.py:265
#, python-format
msgid "title length should be between 40 and 66 characters ({length} actually)"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:92
-#: ./src/pyams_content/root/zmi/search.py:91
+#: ./src/pyams_content/shared/common/zmi/search.py:96
+#: ./src/pyams_content/root/zmi/search.py:95
msgid "Quick search results"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:157
-#: ./src/pyams_content/shared/common/zmi/search.py:190
-#: ./src/pyams_content/root/zmi/search.py:147
-#: ./src/pyams_content/root/zmi/search.py:180
+#: ./src/pyams_content/shared/common/zmi/search.py:162
+#: ./src/pyams_content/shared/common/zmi/search.py:204
+#: ./src/pyams_content/root/zmi/search.py:152
+#: ./src/pyams_content/root/zmi/search.py:188
msgid "Advanced search"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:282
-#: ./src/pyams_content/root/zmi/search.py:260
+#: ./src/pyams_content/shared/common/zmi/search.py:332
+#: ./src/pyams_content/root/zmi/search.py:280
msgid "Advanced search results"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:165
+#: ./src/pyams_content/shared/common/zmi/search.py:170
#: ./src/pyams_content/shared/common/zmi/dashboard.py:231
-#: ./src/pyams_content/root/zmi/search.py:159
+#: ./src/pyams_content/root/zmi/search.py:164
msgid "Owner"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:168
+#: ./src/pyams_content/shared/common/zmi/search.py:173
#: ./src/pyams_content/shared/common/zmi/dashboard.py:154
msgid "Status"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:172
-#: ./src/pyams_content/root/zmi/search.py:162
+#: ./src/pyams_content/shared/common/zmi/search.py:177
+#: ./src/pyams_content/root/zmi/search.py:167
msgid "Created after..."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:175
-#: ./src/pyams_content/root/zmi/search.py:165
+#: ./src/pyams_content/shared/common/zmi/search.py:180
+#: ./src/pyams_content/root/zmi/search.py:170
msgid "Created before..."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:178
-#: ./src/pyams_content/root/zmi/search.py:168
+#: ./src/pyams_content/shared/common/zmi/search.py:183
+#: ./src/pyams_content/root/zmi/search.py:173
msgid "Modified after..."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/search.py:181
-#: ./src/pyams_content/root/zmi/search.py:171
+#: ./src/pyams_content/shared/common/zmi/search.py:186
+#: ./src/pyams_content/root/zmi/search.py:176
msgid "Modified before..."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/properties.py:60
+#: ./src/pyams_content/shared/common/zmi/properties.py:59
msgid "Composition"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/properties.py:83
+#: ./src/pyams_content/shared/common/zmi/properties.py:82
msgid "Content properties"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:71
+#: ./src/pyams_content/shared/common/zmi/types.py:70
msgid "Data types"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:149
+#: ./src/pyams_content/shared/common/zmi/types.py:148
msgid "Data type label"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:189
-#: ./src/pyams_content/shared/common/zmi/types.py:429
+#: ./src/pyams_content/shared/common/zmi/types.py:188
+#: ./src/pyams_content/shared/common/zmi/types.py:428
msgid "Default associations"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:205
+#: ./src/pyams_content/shared/common/zmi/types.py:204
msgid "Default themes"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:233
+#: ./src/pyams_content/shared/common/zmi/types.py:232
msgid "Content data types"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:256
+#: ./src/pyams_content/shared/common/zmi/types.py:255
msgid "Add data type"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:268
+#: ./src/pyams_content/shared/common/zmi/types.py:267
msgid "Add new data type"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:311
+#: ./src/pyams_content/shared/common/zmi/types.py:310
msgid "Data type properties"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:392
+#: ./src/pyams_content/shared/common/zmi/types.py:391
msgid "Subtype label"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:473
+#: ./src/pyams_content/shared/common/zmi/types.py:472
msgid "Add subtype"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:485
+#: ./src/pyams_content/shared/common/zmi/types.py:484
msgid "Add new subtype"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:532
+#: ./src/pyams_content/shared/common/zmi/types.py:531
msgid "Data subtype properties"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:116
+#: ./src/pyams_content/shared/common/zmi/types.py:573
+msgid "Select content type..."
+msgstr ""
+
+#: ./src/pyams_content/shared/common/zmi/types.py:115
msgid "No currently defined data type."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:301
+#: ./src/pyams_content/shared/common/zmi/types.py:300
msgid "Specified type name is already used!"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:508
+#: ./src/pyams_content/shared/common/zmi/types.py:507
msgid "Subtype was correctly added."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:522
+#: ./src/pyams_content/shared/common/zmi/types.py:521
msgid "Specified subtype name is already used!"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/types.py:161
+#: ./src/pyams_content/shared/common/zmi/types.py:160
msgid "Click to see subtypes"
msgstr ""
@@ -2044,45 +2089,45 @@
msgid "Created or modified in this version"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:50
+#: ./src/pyams_content/shared/common/zmi/summary.py:52
msgid "Display content summary"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:74
+#: ./src/pyams_content/shared/common/zmi/summary.py:76
msgid "Identity card"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:86
+#: ./src/pyams_content/shared/common/zmi/summary.py:94
msgid "Requested action"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:127
+#: ./src/pyams_content/shared/common/zmi/summary.py:135
msgid "Publication and retire dates"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:146
+#: ./src/pyams_content/shared/common/zmi/summary.py:154
msgid "Current version"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:176
+#: ./src/pyams_content/shared/common/zmi/summary.py:184
msgid "Content history"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:117
+#: ./src/pyams_content/shared/common/zmi/summary.py:125
msgid "Associated comment"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:158
+#: ./src/pyams_content/shared/common/zmi/summary.py:166
#: ./src/pyams_content/shared/common/zmi/dashboard.py:198
msgid "Version"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:107
+#: ./src/pyams_content/shared/common/zmi/summary.py:115
#, python-format
msgid "{state} {date} by {principal}"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/summary.py:164
+#: ./src/pyams_content/shared/common/zmi/summary.py:172
#, python-format
msgid "{state} since {date}, by {principal}"
msgstr ""
@@ -2177,17 +2222,25 @@
msgid "You must provide an URL for this item!"
msgstr ""
+#: ./src/pyams_content/shared/common/zmi/reverse.py:57
+msgid "Reverse links"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/zmi/reverse.py:66
+msgid "Content's internal links"
+msgstr ""
+
#: ./src/pyams_content/shared/common/zmi/site.py:38
#, python-format
msgid ""
"SEARCH - Between all contents published into « {site} »"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/portal.py:46
+#: ./src/pyams_content/shared/common/zmi/portal.py:44
msgid "Edit default template properties"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/portal.py:56
+#: ./src/pyams_content/shared/common/zmi/portal.py:54
msgid ""
"**This form allows you to select shared content default template.**\n"
"\n"
@@ -2196,8 +2249,8 @@
"If you use a local template, you can define a whole custom configuration but the template definition can't be reused anywhere..."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/portal.py:72
-msgid "Override tool default template"
+#: ./src/pyams_content/shared/common/zmi/portal.py:70
+msgid "Use tool default template"
msgstr ""
#: ./src/pyams_content/shared/common/zmi/dashboard.py:134
@@ -2286,7 +2339,7 @@
#: ./src/pyams_content/shared/common/zmi/dashboard.py:545
#: ./src/pyams_content/root/zmi/__init__.py:346
-msgid "Your favorites"
+msgid "Your favorite contents"
msgstr ""
#: ./src/pyams_content/shared/common/zmi/dashboard.py:558
@@ -2606,9 +2659,9 @@
#: ./src/pyams_content/shared/common/zmi/templates/check-input.pt:34
#: ./src/pyams_content/shared/common/zmi/templates/preview-input.pt:34
#: ./src/pyams_content/shared/common/interfaces/types.py:47
-#: ./src/pyams_content/shared/form/zmi/field.py:160
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:62
-#: ./src/pyams_content/features/menu/zmi/__init__.py:208
+#: ./src/pyams_content/shared/form/zmi/field.py:167
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:60
+#: ./src/pyams_content/features/menu/zmi/__init__.py:215
msgid "Label"
msgstr ""
@@ -2700,25 +2753,25 @@
"shared by all content's versions."
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:128
-#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:128
+#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:130
+#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:130
msgid "Created between"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:140
-#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:166
-#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:140
-#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:166
+#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:142
+#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:168
+#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:142
+#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:168
msgid "and"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:154
-#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:154
+#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:156
+#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:156
msgid "Modified between"
msgstr ""
-#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:202
-#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:202
+#: ./src/pyams_content/shared/common/zmi/templates/advanced-search.pt:214
+#: ./src/pyams_content/root/zmi/templates/advanced-search.pt:211
msgid "Tab label"
msgstr ""
@@ -2808,12 +2861,12 @@
msgid "This is where the content will be displayed!!"
msgstr ""
-#: ./src/pyams_content/shared/common/portlet/content/skin/__init__.py:36
+#: ./src/pyams_content/shared/common/portlet/content/skin/__init__.py:39
msgid "Default content renderer"
msgstr ""
#: ./src/pyams_content/shared/common/interfaces/types.py:43
-#: ./src/pyams_content/shared/form/zmi/field.py:149
+#: ./src/pyams_content/shared/form/zmi/field.py:156
msgid "Name"
msgstr ""
@@ -2891,222 +2944,231 @@
msgid "Type of content data"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:46
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:45
#: ./src/pyams_content/root/interfaces/__init__.py:43
msgid "Webmasters"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:47
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:46
msgid "Webmasters can handle all contents, including published ones"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:50
+msgid "Pilots"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:51
-msgid "Pilots"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:52
msgid ""
"Pilots can handle tool configuration, manage access rules, grant users roles "
"and manage managers restrictions"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:56
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:196
+msgid "Managers"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:57
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:191
-msgid "Managers"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:58
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:192
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:197
msgid ""
"Managers can handle main operations in tool's workflow, like publish or "
"retire contents"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:62
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:202
+msgid "Contributors"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:63
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:197
-msgid "Contributors"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:64
msgid "Contributors are users which are allowed to create new contents"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:67
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:208
+msgid "Designers"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:68
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:203
-msgid "Designers"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:69
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:204
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:209
msgid "Designers are users which are allowed to manage presentation templates"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:94
+msgid "Workflow name"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:95
-msgid "Workflow name"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:96
msgid "Name of workflow utility used to manage tool contents"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:123
+msgid "Content URL"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:124
-msgid "Content URL"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:125
msgid ""
"URL used to access this content; this is important for SEO and should include"
" most important words describing content; spaces and underscores will be "
"automatically replaced by hyphens"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:130
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:129
msgid "Version creator"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:131
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:130
msgid ""
"Name of content's version creator. The creator of the first version is also "
"it's owner."
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:135
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:134
msgid "First owner"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:136
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:135
msgid "Name of content's first version owner"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:140
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:139
msgid "Version creation"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:142
+msgid "Version modifiers"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:143
-msgid "Version modifiers"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:144
msgid "List of principals who modified this content"
msgstr ""
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:146
+msgid "Last modifier"
+msgstr ""
+
#: ./src/pyams_content/shared/common/interfaces/__init__.py:147
-msgid "Last modifier"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:148
msgid "Last principal who modified this content"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:151
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:150
msgid "Last update"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:155
-msgid ""
-"The content's description is 'hidden' into HTML's page headers; but it can be"
-" seen, for example, in some search engines results as content's description"
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:154
+msgid "Content's header is generally displayed in page header"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:159
+msgid "Meta-description"
msgstr ""
#: ./src/pyams_content/shared/common/interfaces/__init__.py:160
-msgid "Keywords"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:161
-msgid "They will be included into HTML pages metadata"
-msgstr ""
-
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:164
-#: ./src/pyams_content/shared/site/zmi/folder.py:78
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:67
-msgid "Notepad"
+msgid ""
+"The content's description is 'hidden' into HTML's page headers; but it can be"
+" seen, for example, in some search engines results as content's description; "
+"if description is empty, content's header will be used."
msgstr ""
#: ./src/pyams_content/shared/common/interfaces/__init__.py:165
+msgid "Keywords"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:166
+msgid "They will be included into HTML pages metadata"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:169
#: ./src/pyams_content/shared/site/zmi/folder.py:79
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:68
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:76
+msgid "Notepad"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:170
+#: ./src/pyams_content/shared/site/zmi/folder.py:80
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:77
msgid "Internal information to be known about this content"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:184
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:189
msgid "Content owner"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:185
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:190
msgid ""
"The owner is the creator of content's first version, except if it was "
"transferred afterwards to another owner"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:198
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:203
msgid ""
"Contributors are users which are allowed to update this content in addition "
"to it's owner"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:208
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:213
msgid "Readers"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:209
-msgid ""
-"Readers are users which are asked to verify and comment contents before they "
-"are published"
-msgstr ""
-
#: ./src/pyams_content/shared/common/interfaces/__init__.py:214
+msgid ""
+"Readers are users which are asked to verify and comment contents before they "
+"are published"
+msgstr ""
+
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:219
msgid "Guests"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:215
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:220
msgid ""
"Guests are users which are allowed to view contents with restricted access"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:235
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:243
msgid "Principal ID"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:274
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:299
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:282
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:307
msgid "Publication checks"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:275
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:283
msgid ""
"If 'yes', this contributor will have to confirm that contents have been "
"previewed and checked before asking for publication"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:300
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:308
msgid ""
"If 'yes', this manager will have to confirm that contents have been previewed"
" and checked before publishing a content"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:305
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:313
msgid "Restricted contents"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:306
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:314
msgid ""
"If 'yes', this manager will get restricted access to manage contents based on"
" selected settings"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:311
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:319
msgid "Selected owners"
msgstr ""
-#: ./src/pyams_content/shared/common/interfaces/__init__.py:312
+#: ./src/pyams_content/shared/common/interfaces/__init__.py:320
msgid "Manager will have access to contents owned by these principals"
msgstr ""
-#: ./src/pyams_content/shared/form/__init__.py:99
+#: ./src/pyams_content/shared/form/__init__.py:97
msgid "Form fields"
msgstr ""
-#: ./src/pyams_content/shared/form/__init__.py:100
+#: ./src/pyams_content/shared/form/__init__.py:98
msgid "no field defined"
msgstr ""
@@ -3184,165 +3246,161 @@
msgid "Form fields..."
msgstr ""
-#: ./src/pyams_content/shared/form/zmi/field.py:171
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:57
+#: ./src/pyams_content/shared/form/zmi/field.py:178
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:55
msgid "Field type"
msgstr ""
-#: ./src/pyams_content/shared/form/zmi/field.py:204
+#: ./src/pyams_content/shared/form/zmi/field.py:211
msgid "Form fields list"
msgstr ""
-#: ./src/pyams_content/shared/form/zmi/field.py:227
-#: ./src/pyams_content/shared/form/zmi/field.py:240
+#: ./src/pyams_content/shared/form/zmi/field.py:234
+#: ./src/pyams_content/shared/form/zmi/field.py:247
msgid "Add form field"
msgstr ""
-#: ./src/pyams_content/shared/form/zmi/field.py:278
+#: ./src/pyams_content/shared/form/zmi/field.py:285
msgid "Edit form field properties"
msgstr ""
-#: ./src/pyams_content/shared/form/zmi/field.py:180
+#: ./src/pyams_content/shared/form/zmi/field.py:187
msgid "-- unknown field type --"
msgstr ""
-#: ./src/pyams_content/shared/form/zmi/field.py:115
+#: ./src/pyams_content/shared/form/zmi/field.py:122
msgid "No currently defined form field."
msgstr ""
-#: ./src/pyams_content/shared/form/zmi/field.py:262
+#: ./src/pyams_content/shared/form/zmi/field.py:269
msgid "Specified name is already used!"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:35
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:33
msgid "Form"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:53
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:51
msgid "Field name"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:54
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:52
msgid "Field internal name; must be unique for a given form"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:58
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:56
msgid "Selected field type"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:63
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:61
msgid "User field label"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:67
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:65
msgid "Field description can be displayed as hint"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:70
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:68
msgid "Placeholder"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:71
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:69
msgid "Some field types like textline can display a placeholder"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:74
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:72
msgid "Optional values"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:75
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:73
msgid "List of available values (for 'choice' and 'list' field types)"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:78
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:76
msgid "Default value"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:79
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:77
msgid "Give default value if field type can use it"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:82
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:80
msgid "Required?"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:83
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:81
msgid "Select 'yes' to set field as mandatory"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:88
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:86
msgid "Select 'no' to hide given field..."
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:122
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:120
msgid "Form title"
msgstr ""
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:125
-msgid "Form header"
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:123
+msgid "Form handler"
+msgstr ""
+
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:124
+msgid "Select how form data is transmitted"
+msgstr ""
+
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:127
+msgid "Authenticated only?"
msgstr ""
#: ./src/pyams_content/shared/form/interfaces/__init__.py:128
-msgid "Form handler"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:129
-msgid "Select how form data is transmitted"
+msgid "If 'yes', only authenticated users will be able to see and submit form"
msgstr ""
#: ./src/pyams_content/shared/form/interfaces/__init__.py:132
-msgid "Authenticated only?"
+msgid "Use captcha?"
msgstr ""
#: ./src/pyams_content/shared/form/interfaces/__init__.py:133
-msgid "If 'yes', only authenticated users will be able to see and submit form"
+msgid "If 'yes', a captcha will be added automatically to the form"
msgstr ""
#: ./src/pyams_content/shared/form/interfaces/__init__.py:137
-msgid "Use captcha?"
+msgid "Submit label"
msgstr ""
#: ./src/pyams_content/shared/form/interfaces/__init__.py:138
-msgid "If 'yes', a captcha will be added automatically to the form"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:142
-msgid "Submit label"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:143
msgid "Label of form submit button"
msgstr ""
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:175
+msgid "Source address"
+msgstr ""
+
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:176
+msgid "Mail address from which form data is sent"
+msgstr ""
+
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:179
+msgid "Source name"
+msgstr ""
+
#: ./src/pyams_content/shared/form/interfaces/__init__.py:180
-msgid "Source address"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:181
-msgid "Mail address from which form data is sent"
+msgid "Name of mail data sender"
+msgstr ""
+
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:183
+msgid "Recipient address"
msgstr ""
#: ./src/pyams_content/shared/form/interfaces/__init__.py:184
-msgid "Source name"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:185
-msgid "Name of mail data sender"
+msgid "Mail address to which form data is sent"
+msgstr ""
+
+#: ./src/pyams_content/shared/form/interfaces/__init__.py:187
+msgid "Recipient name"
msgstr ""
#: ./src/pyams_content/shared/form/interfaces/__init__.py:188
-msgid "Recipient address"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:189
-msgid "Mail address to which form data is sent"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:192
-msgid "Recipient name"
-msgstr ""
-
-#: ./src/pyams_content/shared/form/interfaces/__init__.py:193
msgid "Name of data recipient"
msgstr ""
@@ -3396,7 +3454,7 @@
msgid "Sort all results by first publication date"
msgstr ""
-#: ./src/pyams_content/shared/view/zmi/properties.py:40
+#: ./src/pyams_content/shared/view/zmi/properties.py:45
msgid "Main view settings"
msgstr ""
@@ -3482,7 +3540,7 @@
msgstr ""
#: ./src/pyams_content/shared/view/portlet/interfaces.py:91
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:86
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:102
msgid "Results count limit"
msgstr ""
@@ -3499,134 +3557,151 @@
msgid "No selected view"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:32
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:34
msgid "View"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:150
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:166
msgid "Always include selected internal references"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:151
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:167
msgid "Include selected internal references only if empty"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:41
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:43
#: ./src/pyams_content/interfaces/__init__.py:113
#: ./src/pyams_content/features/review/interfaces.py:74
msgid "Creation date"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:42
-msgid "Last update date"
-msgstr ""
-
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:43
-msgid "Current publication date"
-msgstr ""
-
#: ./src/pyams_content/shared/view/interfaces/__init__.py:44
+msgid "Last update date"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:45
+msgid "Current publication date"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:46
msgid "First publication date"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:62
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:64
msgid "Select context type?"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:63
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:65
msgid "If 'yes', content type will be extracted from context"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:67
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:69
msgid "Other content types"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:68
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:70
msgid "Selected content types; leave empty for all"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:75
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:77
+msgid "Select context data type?"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:78
+msgid ""
+"If 'yes', content data type (if available) will be extracted from context"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:83
+msgid "Other data types"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:84
+msgid "Selected data types; leave empty for all"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:91
msgid "Order by"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:76
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:92
msgid "Property to use to sort results"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:81
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:97
msgid "Reversed order?"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:82
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:98
msgid "If 'yes', items order will be reversed"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:87
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:103
msgid "Maximum number of results that the view may retrieve"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:160
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:176
msgid "Internal references usage"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:161
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:177
msgid "Specify how selected references are included into view results"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:166
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:182
msgid "Exclude context?"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:167
-msgid "If 'yes', context will be excluded from results list"
-msgstr ""
-
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:178
-msgid "Select context tags?"
-msgstr ""
-
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:179
-msgid "If 'yes', tags will be extracted from context"
-msgstr ""
-
#: ./src/pyams_content/shared/view/interfaces/__init__.py:183
-msgid "Other tags"
+msgid "If 'yes', context will be excluded from results list"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:194
+msgid "Select context tags?"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:195
+msgid "If 'yes', tags will be extracted from context"
msgstr ""
#: ./src/pyams_content/shared/view/interfaces/__init__.py:199
+msgid "Other tags"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:215
msgid "Select context themes?"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:200
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:216
msgid "If 'yes', themes will be extracted from context"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:204
-msgid "Other themes"
-msgstr ""
-
#: ./src/pyams_content/shared/view/interfaces/__init__.py:220
+msgid "Other themes"
+msgstr ""
+
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:236
msgid "Select context collections?"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:221
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:237
msgid "If 'yes', collections will be extracted from context"
msgstr ""
-#: ./src/pyams_content/shared/view/interfaces/__init__.py:225
+#: ./src/pyams_content/shared/view/interfaces/__init__.py:241
msgid "Other collections"
msgstr ""
-#: ./src/pyams_content/shared/imagemap/paragraph.py:99
+#: ./src/pyams_content/shared/imagemap/paragraph.py:88
msgid "no selected image map"
msgstr ""
-#: ./src/pyams_content/shared/imagemap/paragraph.py:105
+#: ./src/pyams_content/shared/imagemap/paragraph.py:94
#, python-format
msgid "image map '{0}' can't be found"
msgstr ""
-#: ./src/pyams_content/shared/imagemap/paragraph.py:113
+#: ./src/pyams_content/shared/imagemap/paragraph.py:102
#, python-format
msgid "image map '{0}' is not published"
msgstr ""
@@ -3746,7 +3821,7 @@
msgstr ""
#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:96
-#: ./src/pyams_content/features/alert/interfaces.py:73
+#: ./src/pyams_content/features/alert/interfaces.py:69
#: ./src/pyams_content/features/menu/interfaces/__init__.py:68
msgid "Internal reference"
msgstr ""
@@ -3759,7 +3834,7 @@
msgid "Image map template"
msgstr ""
-#: ./src/pyams_content/shared/site/folder.py:59
+#: ./src/pyams_content/shared/site/folder.py:62
msgid "Site folder"
msgstr ""
@@ -3772,39 +3847,43 @@
msgid "Site manager"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/folder.py:61
+#: ./src/pyams_content/shared/site/zmi/folder.py:62
msgid "Add site folder..."
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/folder.py:93
+#: ./src/pyams_content/shared/site/zmi/folder.py:94
msgid "Add site folder"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/folder.py:160
+#: ./src/pyams_content/shared/site/zmi/folder.py:161
msgid "Site folder management"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/folder.py:188
+#: ./src/pyams_content/shared/site/zmi/folder.py:190
msgid "Site folder properties"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/folder.py:71
+#: ./src/pyams_content/shared/site/zmi/folder.py:208
+msgid "Navigation properties"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/zmi/folder.py:72
#: ./src/pyams_content/interfaces/__init__.py:102
msgid "Visible label used to display content"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/folder.py:74
-#: ./src/pyams_content/shared/site/zmi/__init__.py:72
-#: ./src/pyams_content/shared/site/zmi/link.py:66
-msgid "Parent"
-msgstr ""
-
#: ./src/pyams_content/shared/site/zmi/folder.py:75
-#: ./src/pyams_content/shared/site/zmi/link.py:67
+#: ./src/pyams_content/shared/site/zmi/__init__.py:72
+#: ./src/pyams_content/shared/site/zmi/link.py:65
+msgid "Parent"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/zmi/folder.py:76
+#: ./src/pyams_content/shared/site/zmi/link.py:66
msgid "Folder's parent"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/folder.py:153
+#: ./src/pyams_content/shared/site/zmi/folder.py:154
msgid "You must provide a folder name for default server language!"
msgstr ""
@@ -3824,15 +3903,15 @@
msgid "Topic's parent"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/link.py:57
+#: ./src/pyams_content/shared/site/zmi/link.py:56
msgid "Rent content..."
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/link.py:77
+#: ./src/pyams_content/shared/site/zmi/link.py:76
msgid "Rent existing content"
msgstr ""
-#: ./src/pyams_content/shared/site/zmi/link.py:135
+#: ./src/pyams_content/shared/site/zmi/link.py:134
msgid "Edit content link properties"
msgstr ""
@@ -3910,53 +3989,82 @@
msgid "A site manager is already registered with this name!!"
msgstr ""
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:96
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:121
msgid "Topic"
msgstr ""
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:59
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:42
+msgid "Redirect to first visible sub-folder or content"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:43
+msgid "Use presentation template"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:72
msgid "Heading"
msgstr ""
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:60
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:73
msgid "Heading displayed according to presentation template"
msgstr ""
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:63
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:80
+msgid "Visible in folders list"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:81
+msgid "If 'no', folder will not be displayed into folders list"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:85
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:139
msgid "Navigation title"
msgstr ""
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:64
-msgid "Title displayed in navigation items"
-msgstr ""
-
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:115
-msgid "Content title, as shown in front-office"
-msgstr ""
-
-#: ./src/pyams_content/shared/site/interfaces/__init__.py:119
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:86
+msgid ""
+"Folder's title displayed in navigation pages; original title will be used if "
+"none is specified"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:90
+msgid "Navigation mode"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:91
+msgid "Folder behaviour when navigating to folder URL"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:140
+msgid ""
+"Alternate content's title displayed in navigation pages; original title will "
+"be used if none is specified"
+msgstr ""
+
+#: ./src/pyams_content/shared/site/interfaces/__init__.py:145
msgid "If 'no', link is not visible"
msgstr ""
-#: ./src/pyams_content/shared/logo/paragraph.py:96
+#: ./src/pyams_content/shared/logo/paragraph.py:95
msgid "no selected logo"
msgstr ""
-#: ./src/pyams_content/shared/logo/paragraph.py:102
+#: ./src/pyams_content/shared/logo/paragraph.py:101
#, python-format
msgid "logo '{0}' can't be found"
msgstr ""
-#: ./src/pyams_content/shared/logo/paragraph.py:110
+#: ./src/pyams_content/shared/logo/paragraph.py:109
#, python-format
msgid "logo '{0}' is not published"
msgstr ""
-#: ./src/pyams_content/shared/logo/__init__.py:68
+#: ./src/pyams_content/shared/logo/__init__.py:69
msgid "no image defined"
msgstr ""
-#: ./src/pyams_content/shared/logo/__init__.py:71
+#: ./src/pyams_content/shared/logo/__init__.py:72
msgid "no URL defined"
msgstr ""
@@ -4018,16 +4126,16 @@
msgid "Logos template"
msgstr ""
-#: ./src/pyams_content/shared/blog/zmi/__init__.py:52
+#: ./src/pyams_content/shared/blog/zmi/__init__.py:53
msgid "This blog post"
msgstr ""
-#: ./src/pyams_content/shared/blog/zmi/__init__.py:71
-#: ./src/pyams_content/shared/blog/zmi/__init__.py:81
+#: ./src/pyams_content/shared/blog/zmi/__init__.py:72
+#: ./src/pyams_content/shared/blog/zmi/__init__.py:82
msgid "Add blog post"
msgstr ""
-#: ./src/pyams_content/shared/blog/zmi/__init__.py:62
+#: ./src/pyams_content/shared/blog/zmi/__init__.py:63
#, python-format
msgid "Blog post « {title} »"
msgstr ""
@@ -4077,7 +4185,7 @@
msgid "Default length used for inner tables and dashboards"
msgstr ""
-#: ./src/pyams_content/root/__init__.py:68
+#: ./src/pyams_content/root/__init__.py:69
msgid "Site root"
msgstr ""
@@ -4101,7 +4209,7 @@
msgid "Given element name doesn't exist!"
msgstr ""
-#: ./src/pyams_content/root/zmi/search.py:155
+#: ./src/pyams_content/root/zmi/search.py:160
msgid "Content types"
msgstr ""
@@ -4574,12 +4682,12 @@
msgid "List of selected pictograms which will be available to shared contents"
msgstr ""
-#: ./src/pyams_content/features/renderer/zmi/__init__.py:70
+#: ./src/pyams_content/features/renderer/zmi/__init__.py:72
#: ./src/pyams_content/features/renderer/zmi/templates/renderer-input.pt:4
msgid "Edit renderer properties"
msgstr ""
-#: ./src/pyams_content/features/renderer/skin/__init__.py:67
+#: ./src/pyams_content/features/renderer/skin/__init__.py:71
msgid "Hidden content"
msgstr ""
@@ -4624,8 +4732,12 @@
msgid "preview"
msgstr ""
+#: ./src/pyams_content/features/alert/interfaces.py:39
+msgid "Alert"
+msgstr ""
+
#: ./src/pyams_content/features/alert/interfaces.py:40
-msgid "Success"
+msgid "End of alert"
msgstr ""
#: ./src/pyams_content/features/alert/interfaces.py:41
@@ -4637,7 +4749,7 @@
msgstr ""
#: ./src/pyams_content/features/alert/interfaces.py:43
-msgid "Danger"
+msgid "Recommendation"
msgstr ""
#: ./src/pyams_content/features/alert/interfaces.py:55
@@ -4652,52 +4764,42 @@
msgid "Alert gravity will affect rendered alert style"
msgstr ""
-#. Default: Heading
#: ./src/pyams_content/features/alert/interfaces.py:65
-#: ./src/pyams_content/features/alert/zmi/container.py:157
-msgid "alert-header"
+#: ./src/pyams_content/features/alert/zmi/container.py:145
+msgid "Message"
msgstr ""
#: ./src/pyams_content/features/alert/interfaces.py:66
-msgid "Short alert header (Alert, Important...)"
-msgstr ""
-
-#: ./src/pyams_content/features/alert/interfaces.py:69
-#: ./src/pyams_content/features/alert/zmi/container.py:169
-msgid "Message"
+msgid "Alert message"
msgstr ""
#: ./src/pyams_content/features/alert/interfaces.py:70
-msgid "Alert message"
-msgstr ""
-
-#: ./src/pyams_content/features/alert/interfaces.py:74
msgid ""
"Internal link target reference. You can search a reference using '+' followed"
" by internal number, of by entering text matching content title."
msgstr ""
-#: ./src/pyams_content/features/alert/interfaces.py:86
+#: ./src/pyams_content/features/alert/interfaces.py:75
msgid "Display start date"
msgstr ""
-#: ./src/pyams_content/features/alert/interfaces.py:87
+#: ./src/pyams_content/features/alert/interfaces.py:76
msgid "First date at which alert should be displayed"
msgstr ""
-#: ./src/pyams_content/features/alert/interfaces.py:90
+#: ./src/pyams_content/features/alert/interfaces.py:79
msgid "Display end date"
msgstr ""
-#: ./src/pyams_content/features/alert/interfaces.py:91
+#: ./src/pyams_content/features/alert/interfaces.py:80
msgid "Last date at which alert should be displayed"
msgstr ""
-#: ./src/pyams_content/features/alert/interfaces.py:94
+#: ./src/pyams_content/features/alert/interfaces.py:83
msgid "Maximum interval"
msgstr ""
-#: ./src/pyams_content/features/alert/interfaces.py:95
+#: ./src/pyams_content/features/alert/interfaces.py:84
msgid ""
"Maximum interval between alert displays on a given device, given in hours; "
"set to 0 to always display the alert"
@@ -4719,14 +4821,193 @@
msgid "Alerts"
msgstr ""
-#: ./src/pyams_content/features/alert/zmi/container.py:191
+#: ./src/pyams_content/features/alert/zmi/container.py:167
msgid "Alert list"
msgstr ""
-#: ./src/pyams_content/features/alert/zmi/container.py:90
+#: ./src/pyams_content/features/alert/zmi/container.py:97
msgid "No currently defined alert."
msgstr ""
+#: ./src/pyams_content/features/redirect/container.py:81
+msgid "not matching"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/__init__.py:50
+msgid "Add rule"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/__init__.py:63
+msgid "Add new redirection rule"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/__init__.py:88
+msgid "Edit redirection rule properties"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/__init__.py:109
+msgid ""
+"URL pattern and target URL are defined by *regular expressions* (see |regexp|).\n"
+" \n"
+"In URL pattern, you can use any valid regular expression element, notably:\n"
+"\n"
+"- « .* » to match any list of characters \n"
+"\n"
+"- « ( ) » to \"memorize\" parts of the URL which can be replaced into target URL\n"
+"\n"
+"- special characters (like \"+\") must be escaped with an « \\\\ ».\n"
+"\n"
+"In target URL, memorized parts can be reused using « \\\\1 », « \\\\2 » and so on, where given number is\n"
+"the order of the matching pattern element.\n"
+"\n"
+".. |regexp| raw:: html\n"
+"\n"
+" <a href=\"https://docs.python.org/3/library/re.html\" target=\"_blank\">Python Regular Expressions</a>\n"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:67
+msgid "Redirections"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:161
+msgid "Enable/disable rule"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:188
+msgid "Chain/unchain rule"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:210
+#: ./src/pyams_content/features/redirect/zmi/container.py:366
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:56
+msgid "URL pattern"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:220
+msgid "Target"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:246
+msgid "Redirections list"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:261
+msgid "Redirection rules"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:262
+msgid ""
+"Redirection rules are use to handle redirections responses when a request generates \n"
+"a famous « 404 NotFound » error.\n"
+"\n"
+"Redirections are particularly useful when you are migrating from a previous site and don't want to lose \n"
+"your SEO.\n"
+"\n"
+"You can define a set of rules which will be applied to every \"NotFound\" request; rules are based on \n"
+"regular expressions which are applied to input URL: if the rule is \"matching\", the target URL is rewritten\n"
+"and a \"Redirect\" response is send.\n"
+"\n"
+"You can chain rules together: when a rule is chained, it's rewritten URL is passed as input URL to the \n"
+"next rule, until a matching rule is found.\n"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:288
+msgid "Test"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:323
+msgid "Test redirection rules"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:301
+msgid "Test URL"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:304
+msgid "Check inactive rules?"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:305
+msgid "If 'yes', inactive rules will also be tested"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:313
+msgid "Close"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:314
+msgid "Test rules"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:123
+msgid "No currently defined redirection rule."
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:371
+msgid "No matching rule!"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:365
+msgid "Input URL"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/zmi/container.py:367
+msgid "Output URL"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:39
+msgid "Active rule?"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:40
+msgid "If 'no', selected rule is inactive"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:44
+msgid "Chained rule?"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:45
+msgid ""
+"If 'no', and if this rule is matching received request URL, the rule returns "
+"a redirection response; otherwise, the rule just rewrites the input URL which"
+" is forwarded to the next rule"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:51
+msgid "Permanent redirect?"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:52
+msgid "Define if this redirection should be permanent or temporary"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:57
+msgid "Regexp pattern of matching URLs for this redirection rule"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:62
+msgid "Internal redirection target"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:63
+msgid ""
+"Internal redirection reference. You can search a reference using '+' followed"
+" by internal number, of by entering text matching content title."
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:69
+msgid "URL to which source URL should be redirected"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:75
+msgid "You can only provide an internal reference OR a target URL"
+msgstr ""
+
+#: ./src/pyams_content/features/redirect/interfaces/__init__.py:77
+msgid "You must provide an internal reference OR a target URL"
+msgstr ""
+
#: ./src/pyams_content/features/menu/zmi/__init__.py:81
msgid "Add menu..."
msgstr ""
@@ -4743,7 +5024,7 @@
msgid "Menu was correctly added."
msgstr ""
-#: ./src/pyams_content/features/menu/zmi/__init__.py:388
+#: ./src/pyams_content/features/menu/zmi/__init__.py:395
msgid "Link was correctly added."
msgstr ""
@@ -4751,11 +5032,11 @@
msgid "Click to see menu items"
msgstr ""
-#: ./src/pyams_content/features/menu/portlet/navigation/simple.py:68
+#: ./src/pyams_content/features/menu/portlet/navigation/simple.py:67
msgid "Simple navigation"
msgstr ""
-#: ./src/pyams_content/features/menu/portlet/navigation/double.py:68
+#: ./src/pyams_content/features/menu/portlet/navigation/double.py:67
msgid "Double navigation"
msgstr ""
@@ -4767,8 +5048,8 @@
msgid "Navigation menus"
msgstr ""
-#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:15
-#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:12
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/double-preview.pt:14
+#: ./src/pyams_content/features/menu/portlet/navigation/zmi/templates/simple-preview.pt:11
msgid "Link has no illustration"
msgstr ""
@@ -4777,16 +5058,6 @@
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:64
msgid "Menu title"
msgstr ""
@@ -4821,7 +5092,7 @@
msgid "Don't inherit parent footer"
msgstr ""
-#: ./src/pyams_content/features/footer/skin/__init__.py:84
+#: ./src/pyams_content/features/footer/skin/__init__.py:94
msgid "Hidden footer"
msgstr ""
@@ -5037,6 +5308,6 @@
msgid "Don't inherit parent header"
msgstr ""
-#: ./src/pyams_content/features/header/skin/__init__.py:90
+#: ./src/pyams_content/features/header/skin/__init__.py:100
msgid "Hidden header"
msgstr ""
--- a/src/pyams_content/reference/zmi/table.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/reference/zmi/table.py Thu Sep 06 11:27:55 2018 +0200
@@ -58,7 +58,7 @@
@property
def label(self):
- return II18n(self.context).query_attribute('short_name', request=self.request)
+ return II18n(self.context).query_attribute('title', request=self.request)
css_class = 'strong'
--- a/src/pyams_content/root/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/root/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -24,14 +24,14 @@
from pyams_content.features.footer.interfaces import IFooterTarget
from pyams_content.features.header.interfaces import IHeaderTarget
from pyams_content.features.preview.interfaces import IPreviewTarget
-from pyams_content.interfaces import WEBMASTER_ROLE, OPERATOR_ROLE
+from pyams_content.features.redirect.interfaces import IRedirectionManagerTarget
+from pyams_content.interfaces import WEBMASTER_ROLE, OPERATOR_ROLE, MANAGE_SITE_ROOT_PERMISSION
from pyams_content.root.interfaces import ISiteRootRoles, ISiteRootConfiguration, ISiteRoot, \
ISiteRootToolsConfiguration, ISiteRootBackOfficeConfiguration
from pyams_form.interfaces.form import IFormContextPermissionChecker
from pyams_portal.interfaces import IPortalContext, DESIGNER_ROLE
from pyams_security.interfaces import IDefaultProtectionPolicy, IGrantedRoleEvent, ISecurityManager, SYSTEM_ADMIN_ROLE
from pyams_skin.interfaces.configuration import IConfiguration, IBackOfficeConfiguration
-from pyams_utils.interfaces import MANAGE_SYSTEM_PERMISSION
from pyams_utils.interfaces.site import ISiteRootFactory
# import packages
@@ -52,7 +52,8 @@
@implementer(IDefaultProtectionPolicy, ISiteRoot, ISiteRootRoles, IPortalContext, ITagsManagerTarget,
- IIllustrationTarget, IHeaderTarget, IFooterTarget, IAlertTarget, IPreviewTarget)
+ IIllustrationTarget, IHeaderTarget, IFooterTarget, IAlertTarget, IRedirectionManagerTarget,
+ IPreviewTarget)
class SiteRoot(ProtectedObject, BaseSiteRoot, UserSkinnableContent):
"""Main site root"""
@@ -110,9 +111,7 @@
class SiteRootPermissionChecker(ContextAdapter):
"""Site root permission checker"""
- @property
- def edit_permission(self):
- return MANAGE_SYSTEM_PERMISSION
+ edit_permission = MANAGE_SITE_ROOT_PERMISSION
#
--- a/src/pyams_content/root/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/root/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -343,7 +343,7 @@
icon_class = 'fa fa-fw fa-star'
- title = _("Your favorites")
+ title = _("Your favorite contents")
#
--- a/src/pyams_content/root/zmi/search.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/root/zmi/search.py Thu Sep 06 11:27:55 2018 +0200
@@ -17,8 +17,10 @@
# import interfaces
from hypatia.interfaces import ICatalog
+from pyams_content.component.theme.interfaces import ITagsManager
from pyams_content.profile.interfaces import IAdminProfile
from pyams_content.root import ISiteRoot
+from pyams_content.shared.common.interfaces import CONTENT_TYPES_VOCABULARY
from pyams_content.shared.common.interfaces.zmi import ISiteRootDashboardTable
from pyams_content.skin.zmi.interfaces import IAllContentsMenu
from pyams_form.search import ISearchFields, SearchForm, SearchView, SearchResultsView
@@ -45,6 +47,8 @@
from pyams_skin.table import BaseTable
from pyams_skin.viewlet.menu import MenuItem
from pyams_template.template import template_config
+from pyams_thesaurus.schema import ThesaurusTermsListField
+from pyams_thesaurus.zmi.widget import ThesaurusTermsTreeFieldWidget
from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
from pyams_utils.list import unique
from pyams_utils.registry import get_utility
@@ -91,12 +95,13 @@
title = _("Quick search results")
sortOn = None
+ dt_sort_order = 'desc'
@property
def data_attributes(self):
attributes = super(SiteRootQuickSearchResults, self).data_attributes
attributes['table'] = {
- 'data-ams-datatable-sorting': '[]',
+ 'data-ams-datatable-sorting': '{0},{1}'.format(len(self.columns) - 1, self.dt_sort_order),
'data-ams-datatable-display-length': IAdminProfile(self.request.principal).table_page_length
}
return attributes
@@ -153,7 +158,7 @@
"""Site root advanced search fields"""
content_type = List(title=_("Content types"),
- value_type=Choice(vocabulary='PyAMS content types'),
+ value_type=Choice(vocabulary=CONTENT_TYPES_VOCABULARY),
required=False)
owner = Principal(title=_("Owner"),
@@ -171,6 +176,9 @@
modified_before = Datetime(title=_("Modified before..."),
required=False)
+ tags = ThesaurusTermsListField(title=_("Tags"),
+ required=False)
+
@template_config(template='templates/advanced-search.pt', layer=IPyAMSLayer)
@implementer(IInnerPage)
@@ -185,8 +193,17 @@
apply_skin(self.request, 'PyAMS admin skin')
fields = field.Fields(ISiteRootAdvancedSearchFields)
+ fields['tags'].widgetFactory = ThesaurusTermsTreeFieldWidget
ajax_handler = 'advanced-search-results.html'
+ def updateWidgets(self, prefix=None):
+ super(SiteRootAdvancedSearchForm, self).updateWidgets(prefix)
+ if 'tags' in self.widgets:
+ widget = self.widgets['tags']
+ manager = ITagsManager(self.request.root)
+ widget.thesaurus_name = manager.thesaurus_name
+ widget.extract_name = manager.extract_name
+
@adapter_config(context=(ISiteRoot, IPyAMSLayer, SiteRootAdvancedSearchForm), provides=IContentSearch)
class SiteRootAdvancedSearchFormSearchAdapter(ContextRequestViewAdapter):
@@ -227,6 +244,9 @@
params &= Ge(catalog['modified_date'], data['modified_after'])
if data.get('modified_before'):
params &= Le(catalog['modified_date'], data['modified_before'])
+ if data.get('tags'):
+ tags = [intids.register(term) for term in data['tags']]
+ params &= Any(catalog['tags'], tags)
return unique(map(lambda x: IWorkflowVersions(x).get_last_versions()[0],
CatalogResultSet(CatalogQuery(catalog).query(params,
sort_index='modified_date',
--- a/src/pyams_content/root/zmi/templates/advanced-search.pt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/root/zmi/templates/advanced-search.pt Thu Sep 06 11:27:55 2018 +0200
@@ -73,12 +73,12 @@
</span>
</label>
<div class="col-md-9">
- <label class="input"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</div>
<div class="form-group">
@@ -94,16 +94,18 @@
</span>
</label>
<div class="col-md-4">
- <label class="input"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</tal:var>
+ </div>
+ <div class="form-group">
<tal:var define="widget view.widgets['content_type']">
- <label class="control-label col-md-2">
+ <label class="control-label col-md-3">
<span>
<tal:var content="widget.label" />
<i class="fa fa-question-circle hint" title="Input hint"
@@ -113,13 +115,13 @@
data-ams-hint-html '<' in description;"></i>
</span>
</label>
- <div class="col-md-3">
- <label class="input"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="col-md-4">
+ <div class="input"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</tal:var>
</div>
@@ -128,25 +130,25 @@
<span i18n:translate="">Created between</span>
</label>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['created_after']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['created_after']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
<div class="control-label col-md-1 text-align-center">
<i18n:var translate=""> and </i18n:var>
</div>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['created_before']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['created_before']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</div>
<div class="form-group">
@@ -154,27 +156,34 @@
<span i18n:translate="">Modified between</span>
</label>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['modified_after']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['modified_after']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
<div class="control-label col-md-1 text-align-center">
<i18n:var translate=""> and </i18n:var>
</div>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['modified_before']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['modified_before']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</div>
+ <fieldset tal:condition="'tags' in view.widgets">
+ <legend class="switcher" i18n:translate="">Tags</legend>
+ <div class="input"
+ tal:define="widget view.widgets['tags']">
+ <input tal:replace="structure widget.render()" />
+ </div>
+ </fieldset>
</fieldset>
</tal:loop>
<div class="widgets-suffix"
--- a/src/pyams_content/root/zmi/templates/dashboard.pt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/root/zmi/templates/dashboard.pt Thu Sep 06 11:27:55 2018 +0200
@@ -22,13 +22,13 @@
data-async data-ams-form-submit-target="#search_results">
<div class="form-group">
<div class="col-md-6">
- <label class="input">
+ <div class="input">
<button type="submit" class="icon-append fa fa-fw fa-search no-border no-padding"
data-ams-form-hide-loading="true"></button>
<input type="text" name="query"
placeholder="Quick search..." i18n:attributes="placeholder"
data-ams-events-handlers='{"keyup": "MyAMS.helpers.clearSearchTarget"}' />
- </label>
+ </div>
</div>
<div class="col-md-6">
<a class="nowrap btn-sm col-md-2" href="#advanced-search.html"
--- a/src/pyams_content/shared/blog/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/blog/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -19,7 +19,7 @@
# import interfaces
from pyams_content.interfaces import CREATE_CONTENT_PERMISSION
from pyams_content.shared.blog.interfaces import IWfBlogPost, IBlogManager
-from pyams_i18n.interfaces import II18n, II18nManager
+from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
from pyams_skin.interfaces.viewlet import IMenuHeader, IWidgetTitleViewletManager
from pyams_skin.layer import IPyAMSLayer
from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowInfo
@@ -32,9 +32,10 @@
from pyams_skin.interfaces import IContentTitle
from pyams_skin.viewlet.toolbar import ToolbarAction
from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter
+from pyams_utils.registry import get_utility
from pyams_utils.traversing import get_parent
from pyams_utils.unicode import translate_string
-from pyams_utils.url import absolute_url
+from pyams_utils.url import absolute_url, generate_url
from pyams_viewlet.viewlet import viewlet_config
from pyramid.decorator import reify
from pyramid.path import DottedNameResolver
@@ -98,11 +99,13 @@
def update_content(self, content, data):
data = data.get(self, data)
# initialize content fields
+ lang = get_utility(INegotiator).server_language
+ content.creator = self.request.principal.id
+ content.owner = self.request.principal.id
content.title = data['title']
content.short_name = content.title.copy()
+ content.content_url = generate_url(content.title.get(lang, ''))
content.notepad = data.get('notepad')
- content.creator = self.request.principal.id
- content.owner = self.request.principal.id
# check blog folders
now = datetime.utcnow()
year, month = now.strftime('%Y:%m').split(':')
--- a/src/pyams_content/shared/common/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -17,47 +17,46 @@
# import interfaces
from hypatia.interfaces import ICatalog
+# import packages
+from persistent import Persistent
+from pyramid.events import subscriber
+from pyramid.interfaces import IWSGIApplicationCreatedEvent
+from pyramid.settings import asbool
+from pyramid.threadlocal import get_current_registry
+from zope.container.contained import Contained
+from zope.dublincore.interfaces import IZopeDublinCore
+from zope.interface import implementer
+from zope.intid.interfaces import IIntIds
+from zope.lifecycleevent.interfaces import IObjectModifiedEvent
+from zope.schema.fieldproperty import FieldProperty
+from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
+
+from pyams_content import _
+from pyams_content.features.checker import BaseContentChecker
+from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE
+from pyams_content.features.review.interfaces import IReviewComments
from pyams_content.interfaces import IBaseContentInfo, OWNER_ROLE, MANAGER_ROLE, CONTRIBUTOR_ROLE, READER_ROLE, \
GUEST_ROLE
-from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE
-from pyams_content.features.review.interfaces import IReviewComments
from pyams_content.shared.common.interfaces import IWfSharedContent, IWfSharedContentRoles, ISharedContent, \
- IBaseSharedTool, ISharedSite, IWfSharedContentFactory
+ IBaseSharedTool, ISharedSite, IWfSharedContentFactory, CONTENT_TYPES_VOCABULARY
+from pyams_i18n.content import I18nManagerMixin
from pyams_i18n.interfaces import II18nManager, II18n
from pyams_portal.interfaces import DESIGNER_ROLE
from pyams_security.interfaces import IDefaultProtectionPolicy
-from pyams_sequence.interfaces import ISequentialIdTarget, ISequentialIdInfo
-from pyams_utils.interfaces import VIEW_PERMISSION
-from pyams_workflow.interfaces import IWorkflowPublicationSupport, IWorkflow, IObjectClonedEvent, IWorkflowVersions
-from pyramid.interfaces import IWSGIApplicationCreatedEvent
-from zope.dublincore.interfaces import IZopeDublinCore
-from zope.intid.interfaces import IIntIds
-from zope.lifecycleevent.interfaces import IObjectModifiedEvent
-
-# import packages
-from persistent import Persistent
-from pyams_content.features.checker import BaseContentChecker
-from pyams_i18n.content import I18nManagerMixin
from pyams_security.property import RolePrincipalsFieldProperty
from pyams_security.security import ProtectedObject
from pyams_security.utility import get_principal
+from pyams_sequence.interfaces import ISequentialIdTarget, ISequentialIdInfo
from pyams_utils.adapter import adapter_config, ContextAdapter
from pyams_utils.date import format_datetime
+from pyams_utils.interfaces import VIEW_PERMISSION
from pyams_utils.property import classproperty, classproperty_support
from pyams_utils.registry import query_utility, get_utilities_for
from pyams_utils.request import query_request, check_request
from pyams_utils.timezone import tztime
from pyams_utils.traversing import get_parent
from pyams_utils.vocabulary import vocabulary_config
-from pyramid.events import subscriber
-from pyramid.settings import asbool
-from pyramid.threadlocal import get_current_registry
-from zope.container.contained import Contained
-from zope.interface import implementer
-from zope.schema.fieldproperty import FieldProperty
-from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
-
-from pyams_content import _
+from pyams_workflow.interfaces import IWorkflowPublicationSupport, IWorkflow, IObjectClonedEvent, IWorkflowVersions
@vocabulary_config(name='PyAMS shared sites')
@@ -94,7 +93,7 @@
del CONTENT_TYPES[key]
-@vocabulary_config(name='PyAMS content types')
+@vocabulary_config(name=CONTENT_TYPES_VOCABULARY)
class ContentTypesVocabulary(SimpleVocabulary):
"""Content types vocabulary"""
@@ -128,12 +127,15 @@
content_type = None
content_name = None
+ handle_header = True
+
title = FieldProperty(IWfSharedContent['title'])
short_name = FieldProperty(IWfSharedContent['short_name'])
content_url = FieldProperty(IWfSharedContent['content_url'])
creator = FieldProperty(IWfSharedContent['creator'])
modifiers = FieldProperty(IWfSharedContent['modifiers'])
last_modifier = FieldProperty(IWfSharedContent['last_modifier'])
+ header = FieldProperty(IWfSharedContent['header'])
description = FieldProperty(IWfSharedContent['description'])
keywords = FieldProperty(IWfSharedContent['keywords'])
notepad = FieldProperty(IWfSharedContent['notepad'])
--- a/src/pyams_content/shared/common/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -15,22 +15,21 @@
# import standard library
-# import interfaces
-from pyams_content.interfaces import IBaseContent, MANAGE_CONTENT_PERMISSION, OWNER_ROLE, MANAGER_ROLE, \
- READER_ROLE, GUEST_ROLE, WEBMASTER_ROLE, PILOT_ROLE, CONTRIBUTOR_ROLE
-from pyams_portal.interfaces import IPortalContext, DESIGNER_ROLE
-from pyams_workflow.interfaces import IWorkflowManagedContent
+from zope.container.constraints import containers, contains
from zope.container.interfaces import IContainer
-
-# import packages
-from pyams_i18n.schema import I18nTextField
-from pyams_security.schema import Principal, PrincipalsSet
-from pyams_utils.schema import TextLineListField
-from zope.container.constraints import containers, contains
from zope.interface import Interface, Attribute
from zope.schema import Choice, Bool, Text, TextLine
from pyams_content import _
+# import interfaces
+from pyams_content.interfaces import IBaseContent, MANAGE_CONTENT_PERMISSION, OWNER_ROLE, MANAGER_ROLE, \
+ READER_ROLE, GUEST_ROLE, WEBMASTER_ROLE, PILOT_ROLE, CONTRIBUTOR_ROLE
+# import packages
+from pyams_i18n.schema import I18nTextField
+from pyams_portal.interfaces import IPortalContext, DESIGNER_ROLE
+from pyams_security.schema import Principal, PrincipalsSet
+from pyams_utils.schema import TextLineListField
+from pyams_workflow.interfaces import IWorkflowManagedContent
class IDeletableElement(Interface):
@@ -151,10 +150,16 @@
last_update_label = TextLine(title=_("Last update"),
readonly=True)
- description = I18nTextField(title=_("Description"),
+ header = I18nTextField(title=_("Header"),
+ description=_("Content's header is generally displayed in page header"),
+ required=False)
+
+ handle_header = Attribute("Static boolean value to specify if header is supported by this content type")
+
+ description = I18nTextField(title=_("Meta-description"),
description=_("The content's description is 'hidden' into HTML's page headers; but it "
"can be seen, for example, in some search engines results as content's "
- "description"),
+ "description; if description is empty, content's header will be used."),
required=False)
keywords = TextLineListField(title=_("Keywords"),
@@ -225,6 +230,9 @@
"""Workflow managed shared content factory interface"""
+CONTENT_TYPES_VOCABULARY = 'PyAMS content types'
+
+
#
# Generic restrictions interfaces
#
--- a/src/pyams_content/shared/common/portlet/content/skin/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/portlet/content/skin/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -12,6 +12,7 @@
__docformat__ = 'restructuredtext'
+
# import standard library
# import interfaces
@@ -22,6 +23,7 @@
# import packages
from pyams_portal.portlet import PortletRenderer
+from pyams_template.template import template_config
from pyams_utils.adapter import adapter_config
from zope.interface import Interface
@@ -30,6 +32,7 @@
@adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, ISharedContentPortletSettings),
provides=IPortletRenderer)
+@template_config(template='templates/content.pt', layer=IPyAMSLayer)
class SharedContentPortletRenderer(PortletRenderer):
"""Shared content portlet renderer"""
@@ -45,10 +48,3 @@
def update(self):
super(SharedContentPortletRenderer, self).update()
[renderer.update() for renderer in self.renderers]
-
- def render(self):
- result = ''
- for renderer in self.renderers:
- if renderer is not None:
- result += renderer.render()
- return result
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/shared/common/portlet/content/skin/templates/content.pt Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,7 @@
+<div class="edito"
+ tal:condition="view.renderers">
+ <tal:loop repeat="renderer view.renderers">
+ <tal:if condition="renderer"
+ content="structure renderer.render()">Renderer</tal:if>
+ </tal:loop>
+</div>
--- a/src/pyams_content/shared/common/types.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/types.py Thu Sep 06 11:27:55 2018 +0200
@@ -21,9 +21,10 @@
from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget
from pyams_content.component.theme.interfaces import IThemesTarget, IThemesInfo
from pyams_content.interfaces import MANAGE_TOOL_PERMISSION
+from pyams_content.shared.common.interfaces import ISharedContentFactory
from pyams_content.shared.common.interfaces.types import IDataType, ISubType, IBaseDataType, ITypedSharedTool, \
ITypedDataManager, DATA_MANAGER_ANNOTATION_KEY, DATA_TYPES_VOCABULARY, DATA_TYPE_FIELDS_VOCABULARY, \
- IWfTypedSharedContent, DATA_SUBTYPES_VOCABULARY
+ IWfTypedSharedContent, DATA_SUBTYPES_VOCABULARY, ALL_DATA_TYPES_VOCABULARY
from pyams_form.interfaces.form import IFormContextPermissionChecker
from pyams_i18n.interfaces import II18n
from zope.lifecycleevent.interfaces import IObjectAddedEvent
@@ -32,9 +33,10 @@
# import packages
from persistent import Persistent
-from pyams_content.shared.common import WfSharedContent
+from pyams_content.shared.common import WfSharedContent, IWfSharedContentFactory
from pyams_content.shared.common.manager import SharedTool
from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter
+from pyams_utils.registry import get_local_registry
from pyams_utils.request import check_request
from pyams_utils.traversing import get_parent
from pyams_utils.vocabulary import vocabulary_config
@@ -147,6 +149,43 @@
# Data types vocabularies
#
+@vocabulary_config(name=ALL_DATA_TYPES_VOCABULARY)
+class AllTypedSharedToolDataTypesVocabulary(SimpleVocabulary):
+ """Vocabulary consolidating all data types"""
+
+ def __init__(self, context):
+ terms = []
+ request = check_request()
+ registry = get_local_registry()
+ for tool in registry.getAllUtilitiesRegisteredFor(ITypedSharedTool):
+ manager = ITypedDataManager(tool)
+ terms.extend([SimpleTerm(datatype.__name__,
+ title=II18n(datatype).query_attribute('label', request=request))
+ for datatype in manager.values()])
+ terms.sort(key=lambda x: x.title)
+ super(AllTypedSharedToolDataTypesVocabulary, self).__init__(terms)
+
+
+def get_all_data_types(request):
+ """Get list of all registered data types as JSON object"""
+ results = []
+ registry = get_local_registry()
+ for tool in sorted(registry.getAllUtilitiesRegisteredFor(ITypedSharedTool),
+ key=lambda x: II18n(x).query_attribute('title', request=request)):
+ manager = ITypedDataManager(tool)
+ terms = [{
+ 'id': datatype.__name__,
+ 'text': II18n(datatype).query_attribute('label', request=request)
+ } for datatype in manager.values()]
+ content_factory = IWfSharedContentFactory(ISharedContentFactory(tool))
+ results.append({
+ 'text': request.localizer.translate(content_factory.content_name),
+ 'disabled': True,
+ 'children': terms
+ })
+ return results
+
+
@vocabulary_config(name=DATA_TYPES_VOCABULARY)
class TypedSharedToolDataTypesVocabulary(SimpleVocabulary):
"""Typed shared tool data types vocabulary"""
--- a/src/pyams_content/shared/common/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -87,12 +87,12 @@
return self.context.shared_content_factory.content_class()
def update_content(self, content, data):
- # generic content update
changes = super(SharedContentAddForm, self).update_content(content, data)
+ # initialize content fields
+ lang = get_utility(INegotiator).server_language
content.creator = self.request.principal.id
content.owner = self.request.principal.id
content.short_name = content.title.copy()
- lang = get_utility(INegotiator).server_language
content.content_url = generate_url(content.title.get(lang, ''))
# init content languages
languages = II18nManager(self.context).languages
--- a/src/pyams_content/shared/common/zmi/dashboard.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/dashboard.py Thu Sep 06 11:27:55 2018 +0200
@@ -542,7 +542,7 @@
def title(self):
return II18n(self.context).query_attribute('title', request=self.request)
- subtitle = _("Your favorites")
+ subtitle = _("Your favorite contents")
#
--- a/src/pyams_content/shared/common/zmi/manager.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/manager.py Thu Sep 06 11:27:55 2018 +0200
@@ -56,7 +56,7 @@
@property
def label(self):
- return II18n(self.context).query_attribute('short_name', request=self.request)
+ return II18n(self.context).query_attribute('title', request=self.request)
css_class = 'strong'
@@ -87,7 +87,7 @@
#
@viewlet_config(name='properties.menu', context=IBaseSharedTool, layer=IAdminLayer,
- manager=ISiteManagementMenu, permission=MANAGE_TOOL_PERMISSION, weight=40)
+ manager=ISiteManagementMenu, permission=MANAGE_TOOL_PERMISSION, weight=15)
@viewletmanager_config(name='properties.menu', layer=IAdminLayer, provides=IPropertiesMenu)
@implementer(IPropertiesMenu)
class SharedToolPropertiesMenu(MenuItem):
--- a/src/pyams_content/shared/common/zmi/portal.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/portal.py Thu Sep 06 11:27:55 2018 +0200
@@ -15,23 +15,21 @@
# import standard library
+from pyams_content import _
# import interfaces
from pyams_content.shared.common import IWfSharedContent
-from pyams_content.shared.common.interfaces import IWfSharedContentPortalContext, ISharedToolPortalContext, ISharedTool
+from pyams_content.shared.common.interfaces import IWfSharedContentPortalContext, ISharedToolPortalContext
from pyams_content.shared.common.interfaces.types import ITypedSharedToolPortalContext
-from pyams_form.interfaces.form import IFormHelp
-from pyams_portal.interfaces import MANAGE_TEMPLATE_PERMISSION
-from pyams_skin.layer import IPyAMSLayer
-from pyams_zmi.layer import IAdminLayer
-
# import packages
from pyams_form.form import ajax_config
from pyams_form.help import FormHelp
+from pyams_form.interfaces.form import IFormHelp
from pyams_pagelet.pagelet import pagelet_config
+from pyams_portal.interfaces import MANAGE_TEMPLATE_PERMISSION
from pyams_portal.zmi.page import PortalContextTemplatePropertiesEditForm
+from pyams_skin.layer import IPyAMSLayer
from pyams_utils.adapter import adapter_config
-
-from pyams_content import _
+from pyams_zmi.layer import IAdminLayer
@pagelet_config(name='template-properties.html', context=ISharedToolPortalContext, layer=IPyAMSLayer,
@@ -69,4 +67,4 @@
class SharedContentTemplatePropertiesEditForm(PortalContextTemplatePropertiesEditForm):
"""Shared content template properties edit form"""
- override_legend = _("Override tool default template")
+ inherit_legend = _("Use tool default template")
--- a/src/pyams_content/shared/common/zmi/properties.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/properties.py Thu Sep 06 11:27:55 2018 +0200
@@ -15,35 +15,34 @@
# import standard library
+from pyramid.events import subscriber
+from z3c.form import field
+from z3c.form.interfaces import IDataExtractedEvent, HIDDEN_MODE
+from zope.interface import implementer
+
+from pyams_content import _
# import interfaces
from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION, IBaseContent
from pyams_content.shared.common.interfaces import IWfSharedContent
-from pyams_form.interfaces.form import IWidgetForm
-from pyams_skin.interfaces import IInnerPage, IPageHeader
-from pyams_skin.layer import IPyAMSLayer
-from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
-from pyams_zmi.interfaces import IPropertiesEditForm
-from pyams_zmi.interfaces.menu import IContentManagementMenu, IPropertiesMenu
-from pyams_zmi.layer import IAdminLayer
-from z3c.form.interfaces import IDataExtractedEvent, HIDDEN_MODE
-
# import packages
from pyams_content.shared.common.zmi import WfSharedContentHeaderAdapter
from pyams_form.form import ajax_config
+from pyams_form.interfaces.form import IWidgetForm
from pyams_i18n.widget import I18nSEOTextLineFieldWidget
from pyams_pagelet.pagelet import pagelet_config
from pyams_skin.event import get_json_widget_refresh_event
+from pyams_skin.interfaces import IInnerPage, IPageHeader
+from pyams_skin.layer import IPyAMSLayer
from pyams_skin.viewlet.menu import MenuItem
from pyams_utils.adapter import adapter_config
+from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
from pyams_utils.url import generate_url
from pyams_viewlet.manager import viewletmanager_config
from pyams_viewlet.viewlet import viewlet_config
from pyams_zmi.form import AdminEditForm
-from pyramid.events import subscriber
-from z3c.form import field
-from zope.interface import implementer
-
-from pyams_content import _
+from pyams_zmi.interfaces import IPropertiesEditForm
+from pyams_zmi.interfaces.menu import IContentManagementMenu, IPropertiesMenu
+from pyams_zmi.layer import IAdminLayer
#
@@ -82,9 +81,14 @@
legend = _("Content properties")
- fields = field.Fields(IWfSharedContent).select('title', 'short_name', 'content_url',
- 'description', 'notepad')
- fields['title'].widgetFactory = I18nSEOTextLineFieldWidget
+ @property
+ def fields(self):
+ fields = field.Fields(IWfSharedContent).select('title', 'short_name', 'content_url',
+ 'header', 'description', 'notepad')
+ fields['title'].widgetFactory = I18nSEOTextLineFieldWidget
+ if not self.context.handle_header:
+ fields = fields.omit('header')
+ return fields
def updateWidgets(self, prefix=None):
super(SharedContentPropertiesEditForm, self).updateWidgets(prefix)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/shared/common/zmi/reverse.py Thu Sep 06 11:27:55 2018 +0200
@@ -0,0 +1,109 @@
+#
+# Copyright (c) 2008-2015 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 hypatia.interfaces import ICatalog
+from pyams_content.shared.common.interfaces import IWfSharedContent
+from pyams_content.shared.common.interfaces.zmi import ISiteRootDashboardTable
+from pyams_content.shared.site.interfaces import ISiteContainer
+from pyams_portal.interfaces import IPortalTemplate
+from pyams_sequence.interfaces import ISequentialIdInfo
+from pyams_skin.interfaces import IInnerPage
+from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
+from pyams_workflow.interfaces import IWorkflowVersions
+from pyams_zmi.interfaces.menu import IContentManagementMenu
+from pyams_zmi.layer import IAdminLayer
+from z3c.table.interfaces import IValues, IColumn
+
+# import packages
+from hypatia.catalog import CatalogQuery
+from hypatia.query import Eq, Or, Any
+from pyams_catalog.query import CatalogResultSet
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_skin.container import ContainerView
+from pyams_skin.table import BaseTable, NameColumn
+from pyams_skin.viewlet.menu import MenuItem
+from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+from pyams_utils.list import unique_iter
+from pyams_utils.registry import get_utility
+from pyams_utils.traversing import get_parent
+from pyams_viewlet.viewlet import viewlet_config
+from pyams_zmi.view import AdminView
+from zope.interface import implementer, Interface
+
+from pyams_content import _
+
+
+@viewlet_config(name='reverse-links.menu', context=IWfSharedContent, layer=IAdminLayer,
+ manager=IContentManagementMenu, permission=VIEW_SYSTEM_PERMISSION, weight=40)
+class SequentialITargetReverseLinksMenu(MenuItem):
+ """Sequential ID target reverse links menu"""
+
+ label = _("Reverse links")
+ icon_class = 'fa-anchor'
+ url = '#reverse-links.html'
+
+
+@implementer(ISiteRootDashboardTable)
+class SequentialIdTargetReverseLinkTable(BaseTable):
+ """Sequential ID target reverse links table"""
+
+ title = _("Content's internal links")
+
+
+@adapter_config(name='name', context=(Interface, IPyAMSLayer, SequentialIdTargetReverseLinkTable), provides=IColumn)
+class ReverseLinkNameColumn(NameColumn):
+ """Reverse link name column"""
+
+ _header = _("Title")
+
+
+@adapter_config(context=(IWfSharedContent, IPyAMSLayer, SequentialIdTargetReverseLinkTable), provides=IValues)
+class SequentialIdTargetReverseLinkValues(ContextRequestViewAdapter):
+ """Sequential ID target reverse links values"""
+
+ @property
+ def values(self):
+
+ def get_item(result):
+ parent = get_parent(result, IWfSharedContent)
+ if parent is not None:
+ return IWorkflowVersions(parent).get_last_versions(count=1)[0]
+ parent = get_parent(result, IPortalTemplate)
+ if parent is None:
+ parent = get_parent(result, ISiteContainer)
+ if parent is None:
+ parent = self.request.root
+ return parent
+
+ catalog = get_utility(ICatalog)
+ oid = ISequentialIdInfo(self.context).hex_oid
+ params = Or(Eq(catalog['link_reference'], oid),
+ Any(catalog['link_references'], {oid}))
+ return unique_iter(map(get_item,
+ CatalogResultSet(CatalogQuery(catalog).query(params,
+ sort_index='modified_date'))))
+
+
+@pagelet_config(name='reverse-links.html', context=IWfSharedContent, layer=IPyAMSLayer,
+ permission=VIEW_SYSTEM_PERMISSION)
+@implementer(IInnerPage)
+class SequentialIdTargetReverseLinkView(AdminView, ContainerView):
+ """Sequential ID target reverse links view"""
+
+ table_class = SequentialIdTargetReverseLinkTable
--- a/src/pyams_content/shared/common/zmi/search.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/search.py Thu Sep 06 11:27:55 2018 +0200
@@ -17,6 +17,8 @@
# import interfaces
from hypatia.interfaces import ICatalog
+from pyams_content.component.theme.interfaces import ITagsManager, IThemesManagerTarget, IThemesManager, \
+ ICollectionsManagerTarget, ICollectionsManager
from pyams_content.profile.interfaces import IAdminProfile
from pyams_content.shared.common.interfaces import IBaseSharedTool
from pyams_content.shared.common.interfaces.zmi import ISharedToolDashboardTable
@@ -46,6 +48,8 @@
from pyams_skin.table import BaseTable
from pyams_skin.viewlet.menu import MenuItem
from pyams_template.template import template_config
+from pyams_thesaurus.schema import ThesaurusTermsListField
+from pyams_thesaurus.zmi.widget import ThesaurusTermsTreeFieldWidget
from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
from pyams_utils.list import unique
from pyams_utils.registry import get_utility
@@ -92,12 +96,13 @@
title = _("Quick search results")
sortOn = None
+ dt_sort_order = 'desc'
@property
def data_attributes(self):
attributes = super(SharedToolQuickSearchResults, self).data_attributes
attributes['table'] = {
- 'data-ams-datatable-sorting': '[]',
+ 'data-ams-datatable-sorting': '{0},{1}'.format(len(self.columns) - 1, self.dt_sort_order),
'data-ams-datatable-display-length': IAdminProfile(self.request.principal).table_page_length
}
return attributes
@@ -181,6 +186,15 @@
modified_before = Datetime(title=_("Modified before..."),
required=False)
+ tags = ThesaurusTermsListField(title=_("Tags"),
+ required=False)
+
+ themes = ThesaurusTermsListField(title=_("Themes"),
+ required=False)
+
+ collections = ThesaurusTermsListField(title=_("Collections"),
+ required=False)
+
@template_config(template='templates/advanced-search.pt', layer=IPyAMSLayer)
@implementer(IInnerPage)
@@ -201,8 +215,35 @@
workflow = IWorkflow(self.context)
fields = field.Fields(ISharedToolAdvancedSearchFields)
fields['status'].vocabulary = workflow.states
+ fields['tags'].widgetFactory = ThesaurusTermsTreeFieldWidget
+ if IThemesManagerTarget.providedBy(self.context):
+ fields['themes'].widgetFactory = ThesaurusTermsTreeFieldWidget
+ else:
+ fields = fields.omit('themes')
+ if ICollectionsManagerTarget.providedBy(self.context):
+ fields['collections'].widgetFactory = ThesaurusTermsTreeFieldWidget
+ else:
+ fields = fields.omit('collections')
return fields
+ def updateWidgets(self, prefix=None):
+ super(SharedToolAdvancedSearchForm, self).updateWidgets(prefix)
+ if 'tags' in self.widgets:
+ widget = self.widgets['tags']
+ manager = ITagsManager(self.request.root)
+ widget.thesaurus_name = manager.thesaurus_name
+ widget.extract_name = manager.extract_name
+ if 'themes' in self.widgets:
+ widget = self.widgets['themes']
+ manager = IThemesManager(self.context)
+ widget.thesaurus_name = manager.thesaurus_name
+ widget.extract_name = manager.extract_name
+ if 'collections' in self.widgets:
+ widget = self.widgets['collections']
+ manager = ICollectionsManager(self.context)
+ widget.thesaurus_name = manager.thesaurus_name
+ widget.extract_name = manager.extract_name
+
@adapter_config(context=(IBaseSharedTool, IPyAMSLayer, SharedToolAdvancedSearchForm), provides=IContentSearch)
class SharedToolAdvancedSearchFormSearchAdapter(ContextRequestViewAdapter):
@@ -242,6 +283,15 @@
params &= Ge(catalog['modified_date'], data['modified_after'])
if data.get('modified_before'):
params &= Le(catalog['modified_date'], data['modified_before'])
+ if data.get('tags'):
+ tags = [intids.register(term) for term in data['tags']]
+ params &= Any(catalog['tags'], tags)
+ if data.get('themes'):
+ tags = [intids.register(term) for term in data['themes']]
+ params &= Any(catalog['themes'], tags)
+ if data.get('collections'):
+ tags = [intids.register(term) for term in data['collections']]
+ params &= Any(catalog['collections'], tags)
if data.get('status'):
return unique(map(lambda x: sorted(IWorkflowVersions(x).get_versions(data['status']),
key=lambda y: IZopeDublinCore(y).modified)[0],
--- a/src/pyams_content/shared/common/zmi/summary.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/summary.py Thu Sep 06 11:27:55 2018 +0200
@@ -9,6 +9,8 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
+from pyams_content.shared.common.interfaces.types import IWfTypedSharedContent
+from pyams_sequence.interfaces import ISequentialIdInfo
__docformat__ = 'restructuredtext'
@@ -74,7 +76,13 @@
tab_label = _("Identity card")
css_class = 'form-tight'
- fields = field.Fields(Interface)
+ @property
+ def fields(self):
+ fields = field.Fields(IWfSharedContent).select('title')
+ if IWfTypedSharedContent.providedBy(self.context):
+ fields += field.Fields(IWfTypedSharedContent).select('data_type')
+ fields += field.Fields(ISequentialIdInfo).select('public_oid')
+ return fields
@adapter_config(name='workflow-waiting-state',
--- a/src/pyams_content/shared/common/zmi/templates/advanced-search.pt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/templates/advanced-search.pt Thu Sep 06 11:27:55 2018 +0200
@@ -73,12 +73,12 @@
</span>
</label>
<div class="col-md-9">
- <label class="input"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</div>
<div class="form-group">
@@ -94,16 +94,18 @@
</span>
</label>
<div class="col-md-4">
- <label class="input"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</tal:var>
+ </div>
+ <div class="form-group">
<tal:var define="widget view.widgets['status']">
- <label class="control-label col-md-1">
+ <label class="control-label col-md-3">
<span>
<tal:var content="widget.label" />
<i class="fa fa-question-circle hint" title="Input hint"
@@ -114,12 +116,12 @@
</span>
</label>
<div class="col-md-4">
- <label class="input"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</tal:var>
</div>
@@ -128,25 +130,25 @@
<span i18n:translate="">Created between</span>
</label>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['created_after']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['created_after']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
<div class="control-label col-md-1 text-align-center">
<i18n:var translate=""> and </i18n:var>
</div>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['created_before']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['created_before']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</div>
<div class="form-group">
@@ -154,27 +156,37 @@
<span i18n:translate="">Modified between</span>
</label>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['modified_after']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['modified_after']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
<div class="control-label col-md-1 text-align-center">
<i18n:var translate=""> and </i18n:var>
</div>
<div class="col-md-4">
- <label class="input"
- tal:define="widget view.widgets['modified_before']"
- tal:attributes="class widget.widget_css_class | default;
- data-ams-data tales:object_data(widget);
- data-ams-form-validator view.get_widget_callback(widget.field.getName())">
+ <div class="input"
+ tal:define="widget view.widgets['modified_before']"
+ tal:attributes="class widget.widget_css_class | default;
+ data-ams-data tales:object_data(widget);
+ data-ams-form-validator view.get_widget_callback(widget.field.getName())">
<input tal:replace="structure widget.render()" />
- </label>
+ </div>
</div>
</div>
+ <tal:loop repeat="fieldname ('tags', 'themes', 'collections')">
+ <fieldset tal:condition="fieldname in view.widgets">
+ <tal:var define="widget view.widgets[fieldname]">
+ <legend class="switcher">${widget.label}</legend>
+ <div class="input">
+ <input tal:replace="structure widget.render()" />
+ </div>
+ </tal:var>
+ </fieldset>
+ </tal:loop>
</fieldset>
</tal:loop>
<div class="widgets-suffix"
--- a/src/pyams_content/shared/common/zmi/templates/dashboard.pt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/templates/dashboard.pt Thu Sep 06 11:27:55 2018 +0200
@@ -22,13 +22,13 @@
data-async data-ams-form-submit-target="#search_results">
<div class="form-group">
<div class="col-md-6">
- <label class="input">
+ <div class="input">
<button type="submit" class="icon-append fa fa-fw fa-search no-border no-padding"
data-ams-form-hide-loading="true"></button>
<input type="text" name="query"
placeholder="Quick search..." i18n:attributes="placeholder"
data-ams-events-handlers='{"keyup": "MyAMS.helpers.clearSearchTarget"}' />
- </label>
+ </div>
</div>
<div class="col-md-6">
<a class="nowrap btn-sm col-md-2" href="#advanced-search.html"
--- a/src/pyams_content/shared/common/zmi/types.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/common/zmi/types.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,32 +16,36 @@
# import standard library
import json
+from pyramid.decorator import reify
+from pyramid.events import subscriber
+from pyramid.exceptions import NotFound
+from pyramid.view import view_config
+from z3c.form import field
+from z3c.form.interfaces import DISPLAY_MODE, IDataExtractedEvent
+from z3c.table.interfaces import IValues, IColumn
+from zope.interface import Invalid
+
+from pyams_content import _
# import interfaces
from pyams_content.interfaces import MANAGE_TOOL_PERMISSION, MANAGE_CONTENT_PERMISSION
+# import packages
+from pyams_content.reference.pictograms.zmi.widget import PictogramSelectFieldWidget
from pyams_content.shared.common.interfaces.types import ITypedSharedTool, ITypedDataManager, \
IBaseDataType, IDataType, ISubType, IWfTypedSharedContent
-from pyams_content.skin import pyams_content
-from pyams_i18n.interfaces import II18n
-from pyams_skin.interfaces.container import ITableElementName
-from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager
-from pyams_skin.layer import IPyAMSLayer
-from pyams_viewlet.interfaces import IViewletManager
-from pyams_zmi.interfaces.menu import IPropertiesMenu
-from pyams_zmi.layer import IAdminLayer
-from z3c.form.interfaces import DISPLAY_MODE, IDataExtractedEvent
-from z3c.table.interfaces import IValues, IColumn
-
-# import packages
-from pyams_content.reference.pictograms.zmi.widget import PictogramSelectFieldWidget
from pyams_content.shared.common.types import DataType, SubType
from pyams_content.shared.common.zmi import SharedContentAddForm
from pyams_content.shared.common.zmi.properties import SharedContentPropertiesEditForm
+from pyams_content.skin import pyams_content
from pyams_form.form import AJAXAddForm, ajax_config
from pyams_form.security import ProtectedFormObjectMixin
+from pyams_i18n.interfaces import II18n
from pyams_i18n.widget import I18nSEOTextLineFieldWidget
from pyams_pagelet.pagelet import pagelet_config
from pyams_skin.container import delete_container_element
from pyams_skin.event import get_json_table_refresh_event
+from pyams_skin.interfaces.container import ITableElementName
+from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager
+from pyams_skin.layer import IPyAMSLayer
from pyams_skin.table import BaseTable, SorterColumn, TrashColumn, NameColumn, ActionColumn
from pyams_skin.viewlet.menu import MenuItem
from pyams_skin.viewlet.toolbar import ToolbarAction
@@ -50,17 +54,12 @@
from pyams_utils.traversing import get_parent
from pyams_utils.unicode import translate_string
from pyams_utils.url import absolute_url
+from pyams_viewlet.interfaces import IViewletManager
from pyams_viewlet.viewlet import viewlet_config
from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm
+from pyams_zmi.interfaces.menu import IPropertiesMenu
+from pyams_zmi.layer import IAdminLayer
from pyams_zmi.view import ContainerAdminView
-from pyramid.decorator import reify
-from pyramid.events import subscriber
-from pyramid.exceptions import NotFound
-from pyramid.view import view_config
-from z3c.form import field
-from zope.interface import Invalid
-
-from pyams_content import _
@viewlet_config(name='data-types.menu', context=ITypedSharedTool, layer=IAdminLayer,
@@ -567,6 +566,12 @@
fields = field.Fields(IWfTypedSharedContent).select('title', 'data_type', 'notepad')
+ def updateWidgets(self, prefix=None):
+ super(TypedSharedContentAddForm, self).updateWidgets(prefix)
+ if 'data_type' in self.widgets:
+ self.widgets['data_type'].prompt = True
+ self.widgets['data_type'].promptMessage = _("Select content type...")
+
@pagelet_config(name='properties.html', context=IWfTypedSharedContent, layer=IPyAMSLayer,
permission=MANAGE_CONTENT_PERMISSION)
--- a/src/pyams_content/shared/form/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/form/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -15,22 +15,21 @@
# import standard library
+from zope.interface import implementer, provider, alsoProvides, noLongerProvides
+from zope.schema.fieldproperty import FieldProperty
+
+from pyams_content import _
# import interfaces
from pyams_content.features.checker.interfaces import IContentChecker, ERROR_VALUE
from pyams_content.features.preview.interfaces import IPreviewTarget
from pyams_content.features.review.interfaces import IReviewTarget
-from pyams_content.shared.form.interfaces import IWfForm, IForm, FORM_CONTENT_TYPE, FORM_CONTENT_NAME, \
- IFormFieldContainerTarget, IFormHandler, IFormFieldContainer, IWfFormFactory
-
# import packages
from pyams_content.shared.common import WfSharedContent, SharedContent, register_content_type, WfSharedContentChecker, \
IWfSharedContentFactory
+from pyams_content.shared.form.interfaces import IWfForm, IForm, FORM_CONTENT_TYPE, FORM_CONTENT_NAME, \
+ IFormFieldContainerTarget, IFormHandler, IFormFieldContainer, IWfFormFactory
from pyams_utils.adapter import adapter_config
from pyams_utils.registry import get_global_registry
-from zope.interface import implementer, provider, alsoProvides, noLongerProvides
-from zope.schema.fieldproperty import FieldProperty
-
-from pyams_content import _
@implementer(IWfForm, IFormFieldContainerTarget,
@@ -42,7 +41,6 @@
content_name = FORM_CONTENT_NAME
user_title = FieldProperty(IWfForm['user_title'])
- header = FieldProperty(IWfForm['header'])
_handler = FieldProperty(IWfForm['handler'])
auth_only = FieldProperty(IWfForm['auth_only'])
use_captcha = FieldProperty(IWfForm['use_captcha'])
--- a/src/pyams_content/shared/form/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/form/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -15,21 +15,19 @@
# import standard library
-# import interfaces
-from pyams_content.shared.common.interfaces import ISharedContent, IWfSharedContentPortalContext, \
- ISharedToolPortalContext
from zope.annotation.interfaces import IAttributeAnnotatable
+from zope.container.constraints import containers, contains
from zope.container.interfaces import IContainer, IContained
-
-# import packages
-from pyams_i18n.schema import I18nTextLineField, I18nTextField
-from pyams_utils.schema import MailAddressField, TextLineListField
-from zope.container.constraints import containers, contains
from zope.interface import Interface, Attribute
from zope.schema import TextLine, Choice, Bool
from pyams_content import _
-
+# import interfaces
+from pyams_content.shared.common.interfaces import ISharedContent, IWfSharedContentPortalContext, \
+ ISharedToolPortalContext
+# import packages
+from pyams_i18n.schema import I18nTextLineField, I18nTextField
+from pyams_utils.schema import MailAddressField, TextLineListField
FORM_CONTENT_TYPE = 'form'
FORM_CONTENT_NAME = _('Form')
@@ -122,9 +120,6 @@
user_title = I18nTextLineField(title=_("Form title"),
required=True)
- header = I18nTextField(title=_("Form header"),
- required=False)
-
handler = Choice(title=_("Form handler"),
description=_("Select how form data is transmitted"),
vocabulary='PyAMS form handlers')
--- a/src/pyams_content/shared/form/zmi/field.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/form/zmi/field.py Thu Sep 06 11:27:55 2018 +0200
@@ -100,11 +100,18 @@
'data-ams-plugin-pyams_content-src': get_resource_path(pyams_content),
'data-ams-location': absolute_url(IFormFieldContainer(self.context), self.request),
'data-ams-tablednd-drag-handle': 'td.sorter',
- 'data-ams-tablednd-drop-target': 'set-form-fields-order.json',
- 'data-ams-visibility-switcher': 'switch-form-field-visibility.json'
+ 'data-ams-tablednd-drop-target': 'set-form-fields-order.json'
}
+ attributes.setdefault('td', {}).update({
+ 'data-ams-attribute-switcher': self.get_switcher_target
+ })
return attributes
+ @staticmethod
+ def get_switcher_target(element, column):
+ if column.__name__ == 'show-hide':
+ return 'switch-form-field-visibility.json'
+
@reify
def values(self):
return list(super(FormFieldsContainerTable, self).values)
--- a/src/pyams_content/shared/imagemap/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/imagemap/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,7 +16,17 @@
# import standard library
from persistent import Persistent
from persistent.mapping import PersistentMapping
+from pyramid.threadlocal import get_current_registry
+from z3c.form.interfaces import NOT_CHANGED
+from zope.container.contained import Contained
+from zope.interface import implementer, provider
+from zope.lifecycleevent import ObjectModifiedEvent
+from zope.location import locate
+from zope.location.interfaces import ISublocations
+from zope.schema.fieldproperty import FieldProperty
+from zope.traversing.interfaces import ITraversable
+from pyams_content import _
# import interfaces
from pyams_content.component.association.interfaces import IAssociationContainer
from pyams_content.component.extfile.interfaces import IExtFileContainerTarget
@@ -24,26 +34,14 @@
from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE
from pyams_content.features.preview.interfaces import IPreviewTarget
from pyams_content.features.review.interfaces import IReviewTarget
-from pyams_content.shared.imagemap.interfaces import IMAGEMAP_CONTENT_TYPE, IMAGEMAP_CONTENT_NAME, \
- IWfImageMap, IImageMap, IImageMapArea, IWfImageMapFactory
-from pyams_i18n.interfaces import II18n, II18nManager
-from z3c.form.interfaces import NOT_CHANGED
-from zope.location.interfaces import ISublocations
-from zope.traversing.interfaces import ITraversable
-
# import packages
from pyams_content.shared.common import WfSharedContent, register_content_type, SharedContent, WfSharedContentChecker, \
IWfSharedContentFactory
+from pyams_content.shared.imagemap.interfaces import IMAGEMAP_CONTENT_TYPE, IMAGEMAP_CONTENT_NAME, \
+ IWfImageMap, IImageMap, IImageMapArea, IWfImageMapFactory
+from pyams_i18n.interfaces import II18n, II18nManager
from pyams_i18n.property import I18nFileProperty
from pyams_utils.adapter import adapter_config, ContextAdapter
-from pyramid.threadlocal import get_current_registry
-from zope.container.contained import Contained
-from zope.interface import implementer, provider
-from zope.lifecycleevent import ObjectModifiedEvent
-from zope.location import locate
-from zope.schema.fieldproperty import FieldProperty
-
-from pyams_content import _
@implementer(IImageMapArea)
@@ -63,6 +61,8 @@
content_type = IMAGEMAP_CONTENT_TYPE
content_name = IMAGEMAP_CONTENT_NAME
+ handle_header = False
+
_image = I18nFileProperty(IWfImageMap['image'])
areas = FieldProperty(IWfImageMap['areas'])
--- a/src/pyams_content/shared/imagemap/paragraph.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/imagemap/paragraph.py Thu Sep 06 11:27:55 2018 +0200
@@ -24,15 +24,14 @@
from pyams_workflow.interfaces import IWorkflow, IWorkflowState
# import packages
+from pyams_content.component.links import InternalReferenceMixin
from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory
from pyams_content.features.renderer import RenderersVocabulary
-from pyams_sequence.reference import get_reference_target
from pyams_utils.adapter import adapter_config
from pyams_utils.factory import factory_config
from pyams_utils.registry import utility_config, get_utility
from pyams_utils.traversing import get_parent
from pyams_utils.vocabulary import vocabulary_config
-from pyams_utils.zodb import volatile_property
from zope.interface import implementer
from zope.schema.fieldproperty import FieldProperty
@@ -41,7 +40,7 @@
@implementer(IImageMapParagraph)
@factory_config(provided=IImageMapParagraph)
-class ImageMapParagraph(BaseParagraph):
+class ImageMapParagraph(BaseParagraph, InternalReferenceMixin):
"""Image map paragraph"""
icon_class = 'fa-location-arrow'
@@ -50,16 +49,6 @@
reference = FieldProperty(IImageMapParagraph['reference'])
renderer = FieldProperty(IImageMapParagraph['renderer'])
- @volatile_property
- def target(self):
- return get_reference_target(self.reference)
-
- def get_target(self, state=None):
- if not state:
- return self.target
- else:
- return get_reference_target(self.reference, state)
-
@utility_config(name=IMAGEMAP_PARAGRAPH_TYPE, provides=IParagraphFactory)
class ImageMapParagraphFactory(BaseParagraphFactory):
--- a/src/pyams_content/shared/imagemap/zmi/templates/imagemap-preview.pt Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/imagemap/zmi/templates/imagemap-preview.pt Thu Sep 06 11:27:55 2018 +0200
@@ -1,8 +1,11 @@
<div class="form-group" i18n:domain="pyams_content">
<div class="col-md-3"><!-- empty marker --></div>
<div class="col-md-9">
- <img tal:define="map context.get_target();
- image i18n:map.image;"
- tal:attributes="src tales:absolute_url(image, '++thumb++600x480')" />
+ <tal:if define="map context.get_target()"
+ condition="map is not None">
+ <img tal:define="image i18n:map.image;"
+ tal:condition="image"
+ tal:attributes="src tales:absolute_url(image, '++thumb++600x480')" />
+ </tal:if>
</div>
</div>
--- a/src/pyams_content/shared/logo/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/logo/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -15,20 +15,19 @@
# import standard library
-# import interfaces
-from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE
-from pyams_content.shared.logo.interfaces import IWfLogo, LOGO_CONTENT_TYPE, LOGO_CONTENT_NAME, ILogo, IWfLogoFactory
-from pyams_content.features.review import IReviewTarget
-
-# import packages
-from pyams_content.shared.common import WfSharedContent, register_content_type, SharedContent, WfSharedContentChecker, \
- IWfSharedContentFactory
-from pyams_file.property import FileProperty
-from pyams_utils.adapter import adapter_config
from zope.interface import implementer, provider
from zope.schema.fieldproperty import FieldProperty
from pyams_content import _
+# import interfaces
+from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE
+from pyams_content.features.review import IReviewTarget
+# import packages
+from pyams_content.shared.common import WfSharedContent, register_content_type, SharedContent, WfSharedContentChecker, \
+ IWfSharedContentFactory
+from pyams_content.shared.logo.interfaces import IWfLogo, LOGO_CONTENT_TYPE, LOGO_CONTENT_NAME, ILogo, IWfLogoFactory
+from pyams_file.property import FileProperty
+from pyams_utils.adapter import adapter_config
@implementer(IWfLogo, IReviewTarget)
@@ -38,6 +37,8 @@
content_type = LOGO_CONTENT_TYPE
content_name = LOGO_CONTENT_NAME
+ handle_header = False
+
image = FileProperty(IWfLogo['image'])
monochrome_image = FileProperty(IWfLogo['monochrome_image'])
url = FieldProperty(IWfLogo['url'])
--- a/src/pyams_content/shared/logo/paragraph.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/logo/paragraph.py Thu Sep 06 11:27:55 2018 +0200
@@ -9,7 +9,6 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-from pyams_utils.zodb import volatile_property
__docformat__ = 'restructuredtext'
--- a/src/pyams_content/shared/site/folder.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/folder.py Thu Sep 06 11:27:55 2018 +0200
@@ -53,8 +53,11 @@
roles_interface = ISiteFolderRoles
heading = FieldProperty(ISiteFolder['heading'])
+ notepad = FieldProperty(ISiteFolder['notepad'])
+
+ visible_in_list = FieldProperty(ISiteFolder['visible_in_list'])
navigation_title = FieldProperty(ISiteFolder['navigation_title'])
- notepad = FieldProperty(ISiteFolder['notepad'])
+ navigation_mode = FieldProperty(ISiteFolder['navigation_mode'])
content_name = _("Site folder")
--- a/src/pyams_content/shared/site/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -14,6 +14,7 @@
# import standard library
+from collections import OrderedDict
# import interfaces
from pyams_content.interfaces import IBaseContent
@@ -28,11 +29,23 @@
from pyams_i18n.schema import I18nTextLineField, I18nTextField
from zope.container.constraints import containers, contains
from zope.interface import Interface, Attribute
-from zope.schema import Text, Bool
+from zope.schema import Text, Bool, Choice
+from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
from pyams_content import _
+FOLDER_REDIRECT_DISPLAY_MODE = 'redirect'
+FOLDER_TEMPLATE_DISPLAY_MODE = 'template'
+
+FOLDER_DISPLAY_MODES = OrderedDict((
+ (FOLDER_REDIRECT_DISPLAY_MODE, _("Redirect to first visible sub-folder or content")),
+ (FOLDER_TEMPLATE_DISPLAY_MODE, _("Use presentation template"))
+))
+
+FOLDER_DISPLAY_MODE_VOCABULARY = SimpleVocabulary([SimpleTerm(v, title=t) for v, t in FOLDER_DISPLAY_MODES.items()])
+
+
class ISiteElement(IContained, IDeletableElement):
"""Base site element interface"""
@@ -60,14 +73,26 @@
description=_("Heading displayed according to presentation template"),
required=False)
- navigation_title = I18nTextLineField(title=_("Navigation title"),
- description=_("Title displayed in navigation items"),
- required=False)
-
notepad = Text(title=_("Notepad"),
description=_("Internal information to be known about this content"),
required=False)
+ visible_in_list = Bool(title=_("Visible in folders list"),
+ description=_("If 'no', folder will not be displayed into folders list"),
+ required=True,
+ default=True)
+
+ navigation_title = I18nTextLineField(title=_("Navigation title"),
+ description=_("Folder's title displayed in navigation pages; "
+ "original title will be used if none is specified"),
+ required=False)
+
+ navigation_mode = Choice(title=_("Navigation mode"),
+ description=_("Folder behaviour when navigating to folder URL"),
+ required=True,
+ vocabulary=FOLDER_DISPLAY_MODE_VOCABULARY,
+ default=FOLDER_REDIRECT_DISPLAY_MODE)
+
class ISiteFolderFactory(Interface):
"""Site folder factory interface"""
@@ -111,9 +136,10 @@
class IContentLink(ISiteElement, IInternalReference, IAttributeAnnotatable):
"""Rented content interface"""
- alt_title = I18nTextLineField(title=_("Alternate title"),
- description=_("Content title, as shown in front-office"),
- required=False)
+ navigation_title = I18nTextLineField(title=_("Navigation title"),
+ description=_("Alternate content's title displayed in navigation pages; "
+ "original title will be used if none is specified"),
+ required=False)
visible = Bool(title=_("Visible?"),
description=_("If 'no', link is not visible"),
--- a/src/pyams_content/shared/site/link.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/link.py Thu Sep 06 11:27:55 2018 +0200
@@ -43,7 +43,7 @@
"""
reference = FieldProperty(IContentLink['reference'])
- alt_title = FieldProperty(IContentLink['alt_title'])
+ navigation_title = FieldProperty(IContentLink['navigation_title'])
visible = FieldProperty(IContentLink['visible'])
content_name = _("Content link")
--- a/src/pyams_content/shared/site/zmi/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/zmi/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -20,7 +20,7 @@
from pyams_content.interfaces import CREATE_CONTENT_PERMISSION
from pyams_content.shared.common.interfaces import IWfSharedContent
from pyams_content.shared.site.interfaces import ISiteContainer, ISiteManager, IWfTopic
-from pyams_i18n.interfaces import II18nManager
+from pyams_i18n.interfaces import II18nManager, INegotiator
from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader
from pyams_skin.layer import IPyAMSLayer
from pyams_workflow.interfaces import IWorkflowInfo, IWorkflowVersions
@@ -37,7 +37,7 @@
from pyams_utils.adapter import adapter_config, ContextRequestAdapter
from pyams_utils.registry import get_utility
from pyams_utils.traversing import get_parent
-from pyams_utils.url import absolute_url
+from pyams_utils.url import absolute_url, generate_url
from pyams_viewlet.viewlet import viewlet_config
from pyramid.decorator import reify
from pyramid.path import DottedNameResolver
@@ -114,11 +114,13 @@
def update_content(self, content, data):
data = data.get(self, data)
# initialize content fields
+ lang = get_utility(INegotiator).server_language
+ content.creator = self.request.principal.id
+ content.owner = self.request.principal.id
content.title = data['title']
content.short_name = content.title.copy()
+ content.content_url = generate_url(content.title.get(lang, ''))
content.notepad = data.get('notepad')
- content.creator = self.request.principal.id
- content.owner = self.request.principal.id
# get parent
intids = get_utility(IIntIds)
parent = intids.queryObject(data.get('parent'))
--- a/src/pyams_content/shared/site/zmi/container.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/zmi/container.py Thu Sep 06 11:27:55 2018 +0200
@@ -80,7 +80,7 @@
@property
def label(self):
- return II18n(self.context).query_attribute('short_name', request=self.request)
+ return II18n(self.context).query_attribute('title', request=self.request)
@adapter_config(context=(ISiteContainer, IAdminLayer), provides=IUserAddingsMenuLabel)
@@ -334,7 +334,7 @@
icon_class = 'fa-eye-slash text-danger opaque'
return '<i class="fa fa-fw {icon_class} hint align-base" title="{title}" data-ams-hint-gravity="e"></i>'.format(
icon_class=icon_class,
- title=self.request.localizer.translate(self.icon_hint))
+ title=self.request.localizer.translate(self.get_icon_hint(item)))
def get_icon_hint(self, item):
translate = self.request.localizer.translate
--- a/src/pyams_content/shared/site/zmi/folder.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/zmi/folder.py Thu Sep 06 11:27:55 2018 +0200
@@ -9,6 +9,8 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
+from pyams_form.group import NamedWidgetsGroup
+from pyams_form.interfaces.form import IInnerSubForm
__docformat__ = 'restructuredtext'
@@ -31,7 +33,7 @@
# import packages
from pyams_content.shared.common.zmi.manager import SharedToolPropertiesEditForm
from pyams_content.shared.site.zmi.widget import SiteManagerFoldersSelectorFieldWidget
-from pyams_form.form import AJAXAddForm, AJAXEditForm, ajax_config
+from pyams_form.form import AJAXAddForm, ajax_config
from pyams_i18n.schema import I18nTextLineField
from pyams_pagelet.pagelet import pagelet_config
from pyams_skin.table import DefaultElementEditorAdapter
@@ -42,10 +44,9 @@
from pyams_utils.unicode import translate_string
from pyams_utils.url import absolute_url
from pyams_viewlet.viewlet import viewlet_config
-from pyams_zmi.form import AdminDialogAddForm
+from pyams_zmi.form import AdminDialogAddForm, InnerAdminEditForm
from pyramid.events import subscriber
from pyramid.path import DottedNameResolver
-from pyramid.view import view_config
from z3c.form import field
from zope.interface import Interface, Invalid
from zope.schema import Text, Int
@@ -182,16 +183,45 @@
@pagelet_config(name='properties.html', context=ISiteFolder, layer=IPyAMSLayer, permission=MANAGE_TOOL_PERMISSION)
+@ajax_config(name='properties.json', context=ISiteFolder, layer=IPyAMSLayer)
class SiteFolderPropertiesEditForm(SharedToolPropertiesEditForm):
"""Site folder properties edit form"""
legend = _("Site folder properties")
- fields = field.Fields(ISiteFolder).select('title', 'short_name', 'heading', 'navigation_title', 'notepad') + \
+ fields = field.Fields(ISiteFolder).select('title', 'short_name', 'heading', 'notepad') + \
field.Fields(IBaseSharedTool).select('shared_content_workflow')
-@view_config(name='properties.json', context=ISiteFolder, request_type=IPyAMSLayer,
- permission=MANAGE_TOOL_PERMISSION, renderer='json', xhr=True)
-class SiteFolderPropertiesAJAXEditForm(AJAXEditForm, SiteFolderPropertiesEditForm):
- """Site folder properties edit form, JSON renderer"""
+@adapter_config(name='navigation', context=(ISiteFolder, IPyAMSLayer, SiteFolderPropertiesEditForm),
+ provides=IInnerSubForm)
+class SiteFolderNavigationPropertiesEditForm(InnerAdminEditForm):
+ """Site folder navigation properties edit form"""
+
+ prefix = 'navigation_form.'
+
+ css_class = 'form-group'
+ padding_class = ''
+ fieldset_class = 'bordered margin-top-10 padding-y-5'
+
+ legend = None
+ main_group_legend = _("Navigation properties")
+ main_group_class = 'inner switcher no-y-padding'
+
+ fields = field.Fields(ISiteFolder).select('visible_in_list', 'navigation_title', 'navigation_mode')
+
+ weight = 5
+
+ def check_mode(self):
+ if self.parent_form is not None:
+ self.mode = self.parent_form.mode
+
+ def updateGroups(self):
+ self.add_group(NamedWidgetsGroup(self, 'navigation', self.widgets,
+ ('visible_in_list', 'navigation_title', 'navigation_mode'),
+ fieldset_class=self.fieldset_class,
+ legend=self.main_group_legend,
+ css_class=self.main_group_class,
+ switch=True,
+ display_mode='auto'))
+ super(SiteFolderNavigationPropertiesEditForm, self).updateGroups()
--- a/src/pyams_content/shared/site/zmi/link.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/zmi/link.py Thu Sep 06 11:27:55 2018 +0200
@@ -9,7 +9,6 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-from pyams_skin.event import get_json_table_row_refresh_event
__docformat__ = 'restructuredtext'
@@ -76,7 +75,7 @@
legend = _("Rent existing content")
- fields = field.Fields(IContentLinkAddFormFields).select('reference', 'alt_title', 'parent')
+ fields = field.Fields(IContentLinkAddFormFields).select('reference', 'navigation_title', 'parent')
fields['parent'].widgetFactory = SiteManagerFoldersSelectorFieldWidget
edit_permission = CREATE_CONTENT_PERMISSION
@@ -94,7 +93,7 @@
def update_content(self, content, data):
data = data.get(self, data)
content.reference = data.get('reference')
- content.alt_title = data['alt_title']
+ content.navigation_title = data['navigation_title']
intids = get_utility(IIntIds)
parent = intids.queryObject(data.get('parent'))
if parent is not None:
@@ -115,7 +114,7 @@
@property
def name(self):
- title = II18n(self.context).query_attribute('alt_title', request=self.request)
+ title = II18n(self.context).query_attribute('navigation_title', request=self.request)
if not title:
target = self.context.get_target()
if target is not None:
@@ -134,7 +133,7 @@
legend = _("Edit content link properties")
- fields = field.Fields(IContentLink).omit('__parent__', '__name__')
+ fields = field.Fields(IContentLink).omit('__parent__', '__name__', 'visible')
edit_permission = MANAGE_CONTENT_PERMISSION
def get_ajax_output(self, changes):
--- a/src/pyams_content/shared/site/zmi/manager.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/site/zmi/manager.py Thu Sep 06 11:27:55 2018 +0200
@@ -63,7 +63,7 @@
@property
def label(self):
- return II18n(self.context).query_attribute('short_name', request=self.request)
+ return II18n(self.context).query_attribute('title', request=self.request)
css_class = 'strong'
--- a/src/pyams_content/shared/view/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/view/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -24,6 +24,7 @@
from hypatia.interfaces import ICatalog
from pyams_content.features.preview.interfaces import IPreviewTarget
from pyams_content.features.review.interfaces import IReviewTarget
+from pyams_content.shared.common.interfaces.types import IWfTypedSharedContent
from pyams_content.shared.view.interfaces import IView, IWfView, IWfViewFactory, IViewQuery, \
IViewQueryParamsExtension, IViewQueryFilterExtension, VIEW_CONTENT_TYPE, VIEW_CONTENT_NAME, IViewSettings
from pyams_utils.interfaces import ICacheKeyValue
@@ -63,8 +64,12 @@
content_type = VIEW_CONTENT_TYPE
content_name = VIEW_CONTENT_NAME
+ handle_header = False
+
select_context_type = FieldProperty(IWfView['select_context_type'])
selected_content_types = FieldProperty(IWfView['selected_content_types'])
+ select_context_datatype = FieldProperty(IWfView['select_context_datatype'])
+ selected_datatypes = FieldProperty(IWfView['selected_datatypes'])
order_by = FieldProperty(IWfView['order_by'])
reversed_order = FieldProperty(IWfView['reversed_order'])
limit = FieldProperty(IWfView['limit'])
@@ -89,6 +94,16 @@
content_types |= set(self.selected_content_types)
return list(content_types)
+ def get_data_types(self, context):
+ data_types = set()
+ if self.select_context_datatype:
+ content = IWfTypedSharedContent(context, None)
+ if content is not None:
+ data_types.add(content.data_type)
+ if self.selected_datatypes:
+ data_types |= set(self.selected_datatypes)
+ return list(data_types)
+
def get_results(self, context, sort_index=None, reverse=None, limit=None, ignore_cache=False):
results = _MARKER
if not ignore_cache:
@@ -153,6 +168,10 @@
content_types = view.get_content_types(context)
if content_types:
params &= Any(catalog['content_type'], content_types)
+ # check data types
+ data_types = view.get_data_types(context)
+ if data_types:
+ params &= Any(catalog['data_type'], data_types)
# check workflow states
wf_params = None
for workflow in registry.getAllUtilitiesRegisteredFor(IWorkflow):
--- a/src/pyams_content/shared/view/interfaces/__init__.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/view/interfaces/__init__.py Thu Sep 06 11:27:55 2018 +0200
@@ -16,13 +16,15 @@
# import standard library
# import interfaces
-from pyams_content.shared.common.interfaces import ISharedContent, IWfSharedContent, ISharedTool
+from pyams_content.shared.common.interfaces import ISharedContent, IWfSharedContent, ISharedTool, \
+ CONTENT_TYPES_VOCABULARY
+from pyams_content.shared.common.interfaces.types import ALL_DATA_TYPES_VOCABULARY
from pyams_sequence.interfaces import IInternalReferencesList
# import packages
from pyams_thesaurus.schema import ThesaurusTermsListField
from zope.interface import Interface, Attribute
-from zope.schema import List, Choice, Bool, Int
+from zope.schema import List, Set, Choice, Bool, Int
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
from pyams_content import _
@@ -64,14 +66,28 @@
required=True,
default=False)
- selected_content_types = List(title=_("Other content types"),
- description=_("Selected content types; leave empty for all"),
- value_type=Choice(vocabulary='PyAMS content types'),
- required=False)
+ selected_content_types = Set(title=_("Other content types"),
+ description=_("Selected content types; leave empty for all"),
+ value_type=Choice(vocabulary=CONTENT_TYPES_VOCABULARY),
+ required=False)
def get_content_types(self, context):
"""Get content types for given context"""
+ select_context_datatype = Bool(title=_("Select context data type?"),
+ description=_("If 'yes', content data type (if available) will be extracted from "
+ "context"),
+ required=True,
+ default=False)
+
+ selected_datatypes = Set(title=_("Other data types"),
+ description=_("Selected data types; leave empty for all"),
+ value_type=Choice(vocabulary=ALL_DATA_TYPES_VOCABULARY),
+ required=False)
+
+ def get_data_types(self, context):
+ """Get data types for given context"""
+
order_by = Choice(title=_("Order by"),
description=_("Property to use to sort results"),
vocabulary=VIEW_ORDER_VOCABULARY,
--- a/src/pyams_content/shared/view/zmi/properties.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/shared/view/zmi/properties.py Thu Sep 06 11:27:55 2018 +0200
@@ -14,17 +14,22 @@
# import standard library
+import json
# import interfaces
from pyams_content.shared.view.interfaces import IWfView
from pyams_form.interfaces.form import IInnerSubForm
from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.interfaces.data import IObjectData
# import packages
+from pyams_content.shared.common.types import get_all_data_types
from pyams_content.shared.common.zmi.properties import SharedContentPropertiesEditForm
+from pyams_form.widget import HiddenSelect2FieldWidget
from pyams_utils.adapter import adapter_config
from pyams_zmi.form import InnerAdminEditForm
from z3c.form import field
+from zope.interface import alsoProvides
from pyams_content import _
@@ -41,5 +46,19 @@
fieldset_class = 'bordered no-x-margin margin-y-10'
fields = field.Fields(IWfView).select('select_context_type', 'selected_content_types',
+ 'select_context_datatype', 'selected_datatypes',
'order_by', 'reversed_order', 'limit')
+ fields['selected_datatypes'].widgetFactory = HiddenSelect2FieldWidget
+
weight = 1
+
+ def updateWidgets(self, prefix=None):
+ super(ViewPropertiesEditForm, self).updateWidgets(prefix)
+ if 'selected_datatypes' in self.widgets:
+ widget = self.widgets['selected_datatypes']
+ # widget.multiple = True
+ widget.object_data = {
+ 'ams-select2-multiple': True,
+ 'ams-select2-data': json.dumps(get_all_data_types(self.request))
+ }
+ alsoProvides(widget, IObjectData)
--- a/src/pyams_content/site.py Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/site.py Thu Sep 06 11:27:55 2018 +0200
@@ -18,14 +18,13 @@
# import interfaces
from hypatia.interfaces import ICatalog
-from pyams_content.shared.common.interfaces import IWfSharedContent
-from pyams_content.shared.site.interfaces import IContentLink
from zope.intid.interfaces import IIntIds
# import packages
from pyams_utils.container import find_objects_providing
from pyams_utils.registry import set_local_registry, get_utility
from pyams_utils.site import site_factory
+from zope.interface import Interface
def site_index(request):
@@ -35,13 +34,14 @@
try:
set_local_registry(application.getSiteManager())
catalog = get_utility(ICatalog)
+ catalog.reset()
+ transaction.savepoint()
intids = get_utility(IIntIds)
- for document in find_objects_providing(application, IWfSharedContent):
+ for index, document in enumerate(find_objects_providing(application, Interface)):
print("Indexing: {0!r}".format(document))
catalog.reindex_doc(intids.register(document), document)
- for document in find_objects_providing(application, IContentLink):
- print("Indexing: {0!r}".format(document))
- catalog.reindex_doc(intids.register(document), document)
+ if not index % 100:
+ transaction.savepoint()
finally:
set_local_registry(None)
transaction.commit()
--- a/src/pyams_content/skin/resources/css/pyams_content.css Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/skin/resources/css/pyams_content.css Thu Sep 06 11:27:55 2018 +0200
@@ -46,3 +46,6 @@
.pictograms-manager .pictogram:last-child {
border-bottom: none;
}
+.sortable.gallery {
+ max-height: 550px;
+}
--- a/src/pyams_content/skin/resources/css/pyams_content.min.css Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/skin/resources/css/pyams_content.min.css Thu Sep 06 11:27:55 2018 +0200
@@ -1,1 +1,1 @@
-.ams-widget.comments .widget-body{position:fixed;height:calc(100% - 337px)}.ams-widget.comments .widget-body .chat-body{position:relative;height:100%}.ams-widget.comments .widget-body .chat-footer{position:fixed;bottom:10px}.ams-widget.comments .widget-body,.ams-widget.comments .widget-body .chat-footer{width:calc(100% - 240px)}@media (max-width:767px){.ams-widget.comments .widget-body,.ams-widget.comments .widget-body .chat-footer{width:calc(100% - 10px)}}@media (min-width:768px) and (max-width:979px){.ams-widget.comments .widget-body,.ams-widget.comments .widget-body .chat-footer{width:calc(100% - 20px)}}.minified .ams-widget.comments .widget-body,.minified .ams-widget.comments .widget-body .chat-footer{width:calc(100% - 65px)}@media (max-width:767px){.minified .ams-widget.comments .widget-body,.minified .ams-widget.comments .widget-body .chat-footer{width:calc(100% - 55px)}}.hidden-menu .ams-widget.comments .widget-body,.hidden-menu .ams-widget.comments .widget-body .chat-footer{width:calc(100% - 30px)}.pictograms-manager .pictogram{border-bottom:1px solid silver}.pictograms-manager .pictogram:last-child{border-bottom:none}
+.ams-widget.comments .widget-body{position:fixed;height:calc(100% - 337px)}.ams-widget.comments .widget-body .chat-body{position:relative;height:100%}.ams-widget.comments .widget-body .chat-footer{position:fixed;bottom:10px}.ams-widget.comments .widget-body,.ams-widget.comments .widget-body .chat-footer{width:calc(100% - 240px)}@media (max-width:767px){.ams-widget.comments .widget-body,.ams-widget.comments .widget-body .chat-footer{width:calc(100% - 10px)}}@media (min-width:768px) and (max-width:979px){.ams-widget.comments .widget-body,.ams-widget.comments .widget-body .chat-footer{width:calc(100% - 20px)}}.minified .ams-widget.comments .widget-body,.minified .ams-widget.comments .widget-body .chat-footer{width:calc(100% - 65px)}@media (max-width:767px){.minified .ams-widget.comments .widget-body,.minified .ams-widget.comments .widget-body .chat-footer{width:calc(100% - 55px)}}.hidden-menu .ams-widget.comments .widget-body,.hidden-menu .ams-widget.comments .widget-body .chat-footer{width:calc(100% - 30px)}.pictograms-manager .pictogram{border-bottom:1px solid silver}.pictograms-manager .pictogram:last-child{border-bottom:none}.sortable.gallery{max-height:550px}
--- a/src/pyams_content/skin/resources/js/pyams_content.js Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/skin/resources/js/pyams_content.js Thu Sep 06 11:27:55 2018 +0200
@@ -173,6 +173,7 @@
var source = $(this);
var media = source.parents('.media');
var gallery = media.parents('.gallery');
+ $('i', source).attr('class', 'fa fa-fw fa-spinner fa-pulse');
MyAMS.ajax.post(gallery.data('ams-location') + '/set-media-visibility.json',
{object_name: media.data('ams-element-name')},
function(result, status) {
@@ -350,24 +351,6 @@
MyAMS.initContent(marker);
}
MyAMS.helpers.sort(toolbar, 'weight');
- },
-
- switchAnchor: function() {
- return function () {
- var source = $(this);
- var element = source.parents('tr').first();
- var container = element.parents('table');
- MyAMS.ajax.post(container.data('ams-location') + '/' +
- container.data('ams-anchor-switcher'),
- {object_name: element.data('ams-element-name')},
- function (result, status) {
- if (result.anchor) {
- $('i', source).attr('class', 'fa fa-fw fa-anchor');
- } else {
- $('i', source).attr('class', 'fa fa-fw fa-anchor txt-color-silver opacity-50');
- }
- });
- }
}
},
--- a/src/pyams_content/skin/resources/js/pyams_content.min.js Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/skin/resources/js/pyams_content.min.js Thu Sep 06 11:27:55 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> '+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")},switchAnchor:function(){return function(){var e=t(this),i=e.parents("tr").first(),n=i.parents("table");a.ajax.post(n.data("ams-location")+"/"+n.data("ams-anchor-switcher"),{object_name:i.data("ams-element-name")},function(a,i){a.anchor?t("i",e).attr("class","fa fa-fw fa-anchor"):t("i",e).attr("class","fa fa-fw fa-anchor txt-color-silver opacity-50")})}}},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="manager_themes.widgets.thesaurus_name:list"]',e).val(),n=t('select[name="manager_themes.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)})})},getExtracts:function(e){var i=t(e.currentTarget).parents("form"),n=t('select[name="manager_themes.widgets.thesaurus_name:list"]',i).val(),s=t('select[name="manager_themes.widgets.extract_name:list"]',i),r=s.data("select2");n&&"--NOVALUE--"!==n?a.jsonrpc.post("getExtracts",{thesaurus_name:n},{url:"/api/thesaurus/json"},function(t){r.results.empty(),r.opts.populateResults.call(r,r.results,t.result,{term:""})}):(s.select2("data",null),r.results.empty(),r.opts.populateResults.call(r,r.results,[],{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")}},header:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},footer:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},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(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");t("i",e).attr("class","fa fa-fw fa-spinner fa-pulse"),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> '+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="manager_themes.widgets.thesaurus_name:list"]',e).val(),n=t('select[name="manager_themes.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)})})},getExtracts:function(e){var i=t(e.currentTarget).parents("form"),n=t('select[name="manager_themes.widgets.thesaurus_name:list"]',i).val(),s=t('select[name="manager_themes.widgets.extract_name:list"]',i),r=s.data("select2");n&&"--NOVALUE--"!==n?a.jsonrpc.post("getExtracts",{thesaurus_name:n},{url:"/api/thesaurus/json"},function(t){r.results.empty(),r.opts.populateResults.call(r,r.results,t.result,{term:""})}):(s.select2("data",null),r.results.empty(),r.opts.populateResults.call(r,r.results,[],{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")}},header:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},footer:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},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);
--- a/src/pyams_content/skin/resources/less/pyams_content.less Tue Jul 17 15:12:43 2018 +0200
+++ b/src/pyams_content/skin/resources/less/pyams_content.less Thu Sep 06 11:27:55 2018 +0200
@@ -50,3 +50,10 @@
border-bottom: none;
}
}
+
+
+.sortable {
+ &.gallery {
+ max-height: 550px;
+ }
+}
\ No newline at end of file